1 // [The "BSD licence"] 2 // Copyright (c) 2006-2007 Kay Roepke 3 // All rights reserved. 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions 7 // are met: 8 // 1. Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // 2. Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // 3. The name of the author may not be used to endorse or promote products 14 // derived from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 // IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 // NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 27 #import "ANTLRDebugEventProxy.h" 28 #import "ANTLRToken+DebuggerSupport.h" 29 #include <string.h> 30 31 static NSData *newlineData = nil; 32 static unsigned lengthOfUTF8Ack = 0; 33 34 @implementation ANTLRDebugEventProxy 35 36 + (void) initialize 37 { 38 if (!newlineData) newlineData = [@"\n" dataUsingEncoding:NSUTF8StringEncoding]; 39 if (!lengthOfUTF8Ack) lengthOfUTF8Ack = [[@"ack\n" dataUsingEncoding:NSUTF8StringEncoding] length]; 40 } 41 42 - (id) init 43 { 44 return [self initWithGrammarName:nil debuggerPort:DEFAULT_DEBUGGER_PORT]; 45 } 46 47 - (id) initWithGrammarName:(NSString *)aGrammarName debuggerPort:(NSInteger)aPort 48 { 49 self = [super init]; 50 if (self) { 51 serverSocket = -1; 52 [self setGrammarName:aGrammarName]; 53 if (aPort == -1) aPort = DEFAULT_DEBUGGER_PORT; 54 [self setDebuggerPort:aPort]; 55 } 56 return self; 57 } 58 59 - (void) dealloc 60 { 61 if (serverSocket != -1) 62 shutdown(serverSocket,SHUT_RDWR); 63 serverSocket = -1; 64 [debuggerFH release]; 65 [self setGrammarName:nil]; 66 [super dealloc]; 67 } 68 69 - (void) waitForDebuggerConnection 70 { 71 if (serverSocket == -1) { 72 serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 73 74 NSAssert1(serverSocket != -1, @"Failed to create debugger socket. %s", strerror(errno)); 75 76 int yes = 1; 77 setsockopt(serverSocket, SOL_SOCKET, SO_KEEPALIVE|SO_REUSEPORT|SO_REUSEADDR|TCP_NODELAY, (void *)&yes, sizeof(NSInteger)); 78 79 struct sockaddr_in server_addr; 80 bzero(&server_addr, sizeof(struct sockaddr_in)); 81 server_addr.sin_family = AF_INET; 82 server_addr.sin_port = htons([self debuggerPort]); 83 server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 84 NSAssert1( bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) != -1, @"bind(2) failed. %s", strerror(errno)); 85 86 NSAssert1(listen(serverSocket,50) == 0, @"listen(2) failed. %s", strerror(errno)); 87 88 NSLog(@"ANTLR waiting for debugger attach (grammar %@)", [self grammarName]); 89 90 debuggerSocket = accept(serverSocket, &debugger_sockaddr, &debugger_socklen); 91 NSAssert1( debuggerSocket != -1, @"accept(2) failed. %s", strerror(errno)); 92 93 debuggerFH = [[NSFileHandle alloc] initWithFileDescriptor:debuggerSocket]; 94 [self sendToDebugger:[NSString stringWithFormat:@"ANTLR %d", ANTLRDebugProtocolVersion] waitForResponse:NO]; 95 [self sendToDebugger:[NSString stringWithFormat:@"grammar \"%@", [self grammarName]] waitForResponse:NO]; 96 } 97 } 98 99 - (void) waitForAck 100 { 101 NSString *response; 102 @try { 103 NSData *newLine = [debuggerFH readDataOfLength:lengthOfUTF8Ack]; 104 response = [[NSString alloc] initWithData:newLine encoding:NSUTF8StringEncoding]; 105 if (![response isEqualToString:@"ack\n"]) @throw [NSException exceptionWithName:@"ANTLRDebugEventProxy" reason:@"illegal response from debugger" userInfo:nil]; 106 } 107 @catch (NSException *e) { 108 NSLog(@"socket died or debugger misbehaved: %@ read <%@>", e, response); 109 } 110 @finally { 111 [response release]; 112 } 113 } 114 115 - (void) sendToDebugger:(NSString *)message 116 { 117 [self sendToDebugger:message waitForResponse:YES]; 118 } 119 120 - (void) sendToDebugger:(NSString *)message waitForResponse:(BOOL)wait 121 { 122 if (! debuggerFH ) return; 123 [debuggerFH writeData:[message dataUsingEncoding:NSUTF8StringEncoding]]; 124 [debuggerFH writeData:newlineData]; 125 if (wait) [self waitForAck]; 126 } 127 128 - (NSInteger) serverSocket 129 { 130 return serverSocket; 131 } 132 133 - (void) setServerSocket: (NSInteger) aServerSocket 134 { 135 serverSocket = aServerSocket; 136 } 137 138 - (NSInteger) debuggerSocket 139 { 140 return debuggerSocket; 141 } 142 143 - (void) setDebuggerSocket: (NSInteger) aDebuggerSocket 144 { 145 debuggerSocket = aDebuggerSocket; 146 } 147 148 - (NSString *) grammarName 149 { 150 return grammarName; 151 } 152 153 - (void) setGrammarName: (NSString *) aGrammarName 154 { 155 if (grammarName != aGrammarName) { 156 [aGrammarName retain]; 157 [grammarName release]; 158 grammarName = aGrammarName; 159 } 160 } 161 162 - (NSInteger) debuggerPort 163 { 164 return debuggerPort; 165 } 166 167 - (void) setDebuggerPort: (NSInteger) aDebuggerPort 168 { 169 debuggerPort = aDebuggerPort; 170 } 171 172 - (NSString *) escapeNewlines:(NSString *)aString 173 { 174 NSMutableString *escapedText; 175 if (aString) { 176 escapedText = [NSMutableString stringWithString:aString]; 177 NSRange wholeString = NSMakeRange(0,[escapedText length]); 178 [escapedText replaceOccurrencesOfString:@"%" withString:@"%25" options:0 range:wholeString]; 179 [escapedText replaceOccurrencesOfString:@"\n" withString:@"%0A" options:0 range:wholeString]; 180 [escapedText replaceOccurrencesOfString:@"\r" withString:@"%0D" options:0 range:wholeString]; 181 } else { 182 escapedText = [NSMutableString stringWithString:@""]; 183 } 184 return escapedText; 185 } 186 187 #pragma mark - 188 189 #pragma mark DebugEventListener Protocol 190 - (void) enterRule:(NSString *)ruleName 191 { 192 [self sendToDebugger:[NSString stringWithFormat:@"enterRule %@", ruleName]]; 193 } 194 195 - (void) enterAlt:(NSInteger)alt 196 { 197 [self sendToDebugger:[NSString stringWithFormat:@"enterAlt %d", alt]]; 198 } 199 200 - (void) exitRule:(NSString *)ruleName 201 { 202 [self sendToDebugger:[NSString stringWithFormat:@"exitRule %@", ruleName]]; 203 } 204 205 - (void) enterSubRule:(NSInteger)decisionNumber 206 { 207 [self sendToDebugger:[NSString stringWithFormat:@"enterSubRule %d", decisionNumber]]; 208 } 209 210 - (void) exitSubRule:(NSInteger)decisionNumber 211 { 212 [self sendToDebugger:[NSString stringWithFormat:@"exitSubRule %d", decisionNumber]]; 213 } 214 215 - (void) enterDecision:(NSInteger)decisionNumber 216 { 217 [self sendToDebugger:[NSString stringWithFormat:@"enterDecision %d", decisionNumber]]; 218 } 219 220 - (void) exitDecision:(NSInteger)decisionNumber 221 { 222 [self sendToDebugger:[NSString stringWithFormat:@"exitDecision %d", decisionNumber]]; 223 } 224 225 - (void) consumeToken:(id<ANTLRToken>)t 226 { 227 [self sendToDebugger:[NSString stringWithFormat:@"consumeToken %@", [self escapeNewlines:[t description]]]]; 228 } 229 230 - (void) consumeHiddenToken:(id<ANTLRToken>)t 231 { 232 [self sendToDebugger:[NSString stringWithFormat:@"consumeHiddenToken %@", [self escapeNewlines:[t description]]]]; 233 } 234 235 - (void) LT:(NSInteger)i foundToken:(id<ANTLRToken>)t 236 { 237 [self sendToDebugger:[NSString stringWithFormat:@"LT %d %@", i, [self escapeNewlines:[t description]]]]; 238 } 239 240 - (void) mark:(NSInteger)marker 241 { 242 [self sendToDebugger:[NSString stringWithFormat:@"mark %d", marker]]; 243 } 244 - (void) rewind:(NSInteger)marker 245 { 246 [self sendToDebugger:[NSString stringWithFormat:@"rewind %d", marker]]; 247 } 248 249 - (void) rewind 250 { 251 [self sendToDebugger:@"rewind"]; 252 } 253 254 - (void) beginBacktrack:(NSInteger)level 255 { 256 [self sendToDebugger:[NSString stringWithFormat:@"beginBacktrack %d", level]]; 257 } 258 259 - (void) endBacktrack:(NSInteger)level wasSuccessful:(BOOL)successful 260 { 261 [self sendToDebugger:[NSString stringWithFormat:@"endBacktrack %d %d", level, successful ? 1 : 0]]; 262 } 263 264 - (void) locationLine:(NSInteger)line column:(NSInteger)pos 265 { 266 [self sendToDebugger:[NSString stringWithFormat:@"location %d %d", line, pos]]; 267 } 268 269 - (void) recognitionException:(ANTLRRecognitionException *)e 270 { 271 #warning TODO: recognition exceptions 272 // these must use the names of the corresponding Java exception classes, because ANTLRWorks recreates the exception 273 // objects on the Java side. 274 // Write categories for Objective-C exceptions to provide those names 275 } 276 277 - (void) beginResync 278 { 279 [self sendToDebugger:@"beginResync"]; 280 } 281 282 - (void) endResync 283 { 284 [self sendToDebugger:@"endResync"]; 285 } 286 287 - (void) semanticPredicate:(NSString *)predicate matched:(BOOL)result 288 { 289 [self sendToDebugger:[NSString stringWithFormat:@"semanticPredicate %d %@", result?1:0, [self escapeNewlines:predicate]]]; 290 } 291 292 - (void) commence 293 { 294 // no need to send event 295 } 296 297 - (void) terminate 298 { 299 [self sendToDebugger:@"terminate"]; 300 @try { 301 [debuggerFH closeFile]; 302 } 303 @finally { 304 #warning TODO: make socket handling robust. too lazy now... 305 shutdown(serverSocket,SHUT_RDWR); 306 serverSocket = -1; 307 } 308 } 309 310 311 #pragma mark Tree Parsing 312 - (void) consumeNode:(unsigned)nodeHash ofType:(NSInteger)type text:(NSString *)text 313 { 314 [self sendToDebugger:[NSString stringWithFormat:@"consumeNode %u %d %@", 315 nodeHash, 316 type, 317 [self escapeNewlines:text] 318 ]]; 319 } 320 321 - (void) LT:(NSInteger)i foundNode:(unsigned)nodeHash ofType:(NSInteger)type text:(NSString *)text 322 { 323 [self sendToDebugger:[NSString stringWithFormat:@"LN %d %u %d %@", 324 i, 325 nodeHash, 326 type, 327 [self escapeNewlines:text] 328 ]]; 329 } 330 331 332 #pragma mark AST Events 333 334 - (void) createNilNode:(unsigned)hash 335 { 336 [self sendToDebugger:[NSString stringWithFormat:@"nilNode %u", hash]]; 337 } 338 339 - (void) createNode:(unsigned)hash text:(NSString *)text type:(NSInteger)type 340 { 341 [self sendToDebugger:[NSString stringWithFormat:@"createNodeFromToken %u %d %@", 342 hash, 343 type, 344 [self escapeNewlines:text] 345 ]]; 346 } 347 348 - (void) createNode:(unsigned)hash fromTokenAtIndex:(NSInteger)tokenIndex 349 { 350 [self sendToDebugger:[NSString stringWithFormat:@"createNode %u %d", hash, tokenIndex]]; 351 } 352 353 - (void) becomeRoot:(unsigned)newRootHash old:(unsigned)oldRootHash 354 { 355 [self sendToDebugger:[NSString stringWithFormat:@"becomeRoot %u %u", newRootHash, oldRootHash]]; 356 } 357 358 - (void) addChild:(unsigned)childHash toTree:(unsigned)treeHash 359 { 360 [self sendToDebugger:[NSString stringWithFormat:@"addChild %u %u", treeHash, childHash]]; 361 } 362 363 - (void) setTokenBoundariesForTree:(unsigned)nodeHash From:(NSInteger)tokenStartIndex To:(NSInteger)tokenStopIndex 364 { 365 [self sendToDebugger:[NSString stringWithFormat:@"setTokenBoundaries %u %d %d", nodeHash, tokenStartIndex, tokenStopIndex]]; 366 } 367 368 369 370 @end 371