aboutsummaryrefslogtreecommitdiff
path: root/antlr-3.4/runtime/ObjC/Framework/ANTLRDebugEventProxy.m
diff options
context:
space:
mode:
Diffstat (limited to 'antlr-3.4/runtime/ObjC/Framework/ANTLRDebugEventProxy.m')
-rw-r--r--antlr-3.4/runtime/ObjC/Framework/ANTLRDebugEventProxy.m370
1 files changed, 370 insertions, 0 deletions
diff --git a/antlr-3.4/runtime/ObjC/Framework/ANTLRDebugEventProxy.m b/antlr-3.4/runtime/ObjC/Framework/ANTLRDebugEventProxy.m
new file mode 100644
index 0000000..f68059a
--- /dev/null
+++ b/antlr-3.4/runtime/ObjC/Framework/ANTLRDebugEventProxy.m
@@ -0,0 +1,370 @@
+// [The "BSD licence"]
+// Copyright (c) 2006-2007 Kay Roepke
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// 3. The name of the author may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "ANTLRDebugEventProxy.h"
+#import "ANTLRToken+DebuggerSupport.h"
+#include <string.h>
+
+static NSData *newlineData = nil;
+static unsigned lengthOfUTF8Ack = 0;
+
+@implementation ANTLRDebugEventProxy
+
++ (void) initialize
+{
+ if (!newlineData) newlineData = [@"\n" dataUsingEncoding:NSUTF8StringEncoding];
+ if (!lengthOfUTF8Ack) lengthOfUTF8Ack = [[@"ack\n" dataUsingEncoding:NSUTF8StringEncoding] length];
+}
+
+- (id) init
+{
+ return [self initWithGrammarName:nil debuggerPort:DEFAULT_DEBUGGER_PORT];
+}
+
+- (id) initWithGrammarName:(NSString *)aGrammarName debuggerPort:(NSInteger)aPort
+{
+ self = [super init];
+ if (self) {
+ serverSocket = -1;
+ [self setGrammarName:aGrammarName];
+ if (aPort == -1) aPort = DEFAULT_DEBUGGER_PORT;
+ [self setDebuggerPort:aPort];
+ }
+ return self;
+}
+
+- (void) dealloc
+{
+ if (serverSocket != -1)
+ shutdown(serverSocket,SHUT_RDWR);
+ serverSocket = -1;
+ [debuggerFH release];
+ [self setGrammarName:nil];
+ [super dealloc];
+}
+
+- (void) waitForDebuggerConnection
+{
+ if (serverSocket == -1) {
+ serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+ NSAssert1(serverSocket != -1, @"Failed to create debugger socket. %s", strerror(errno));
+
+ int yes = 1;
+ setsockopt(serverSocket, SOL_SOCKET, SO_KEEPALIVE|SO_REUSEPORT|SO_REUSEADDR|TCP_NODELAY, (void *)&yes, sizeof(NSInteger));
+
+ struct sockaddr_in server_addr;
+ bzero(&server_addr, sizeof(struct sockaddr_in));
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = htons([self debuggerPort]);
+ server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ NSAssert1( bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) != -1, @"bind(2) failed. %s", strerror(errno));
+
+ NSAssert1(listen(serverSocket,50) == 0, @"listen(2) failed. %s", strerror(errno));
+
+ NSLog(@"ANTLR waiting for debugger attach (grammar %@)", [self grammarName]);
+
+ debuggerSocket = accept(serverSocket, &debugger_sockaddr, &debugger_socklen);
+ NSAssert1( debuggerSocket != -1, @"accept(2) failed. %s", strerror(errno));
+
+ debuggerFH = [[NSFileHandle alloc] initWithFileDescriptor:debuggerSocket];
+ [self sendToDebugger:[NSString stringWithFormat:@"ANTLR %d", ANTLRDebugProtocolVersion] waitForResponse:NO];
+ [self sendToDebugger:[NSString stringWithFormat:@"grammar \"%@", [self grammarName]] waitForResponse:NO];
+ }
+}
+
+- (void) waitForAck
+{
+ NSString *response;
+ @try {
+ NSData *newLine = [debuggerFH readDataOfLength:lengthOfUTF8Ack];
+ response = [[NSString alloc] initWithData:newLine encoding:NSUTF8StringEncoding];
+ if (![response isEqualToString:@"ack\n"]) @throw [NSException exceptionWithName:@"ANTLRDebugEventProxy" reason:@"illegal response from debugger" userInfo:nil];
+ }
+ @catch (NSException *e) {
+ NSLog(@"socket died or debugger misbehaved: %@ read <%@>", e, response);
+ }
+ @finally {
+ [response release];
+ }
+}
+
+- (void) sendToDebugger:(NSString *)message
+{
+ [self sendToDebugger:message waitForResponse:YES];
+}
+
+- (void) sendToDebugger:(NSString *)message waitForResponse:(BOOL)wait
+{
+ if (! debuggerFH ) return;
+ [debuggerFH writeData:[message dataUsingEncoding:NSUTF8StringEncoding]];
+ [debuggerFH writeData:newlineData];
+ if (wait) [self waitForAck];
+}
+
+- (NSInteger) serverSocket
+{
+ return serverSocket;
+}
+
+- (void) setServerSocket: (NSInteger) aServerSocket
+{
+ serverSocket = aServerSocket;
+}
+
+- (NSInteger) debuggerSocket
+{
+ return debuggerSocket;
+}
+
+- (void) setDebuggerSocket: (NSInteger) aDebuggerSocket
+{
+ debuggerSocket = aDebuggerSocket;
+}
+
+- (NSString *) grammarName
+{
+ return grammarName;
+}
+
+- (void) setGrammarName: (NSString *) aGrammarName
+{
+ if (grammarName != aGrammarName) {
+ [aGrammarName retain];
+ [grammarName release];
+ grammarName = aGrammarName;
+ }
+}
+
+- (NSInteger) debuggerPort
+{
+ return debuggerPort;
+}
+
+- (void) setDebuggerPort: (NSInteger) aDebuggerPort
+{
+ debuggerPort = aDebuggerPort;
+}
+
+- (NSString *) escapeNewlines:(NSString *)aString
+{
+ NSMutableString *escapedText;
+ if (aString) {
+ escapedText = [NSMutableString stringWithString:aString];
+ NSRange wholeString = NSMakeRange(0,[escapedText length]);
+ [escapedText replaceOccurrencesOfString:@"%" withString:@"%25" options:0 range:wholeString];
+ [escapedText replaceOccurrencesOfString:@"\n" withString:@"%0A" options:0 range:wholeString];
+ [escapedText replaceOccurrencesOfString:@"\r" withString:@"%0D" options:0 range:wholeString];
+ } else {
+ escapedText = [NSMutableString stringWithString:@""];
+ }
+ return escapedText;
+}
+
+#pragma mark -
+
+#pragma mark DebugEventListener Protocol
+- (void) enterRule:(NSString *)ruleName
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"enterRule %@", ruleName]];
+}
+
+- (void) enterAlt:(NSInteger)alt
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"enterAlt %d", alt]];
+}
+
+- (void) exitRule:(NSString *)ruleName
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"exitRule %@", ruleName]];
+}
+
+- (void) enterSubRule:(NSInteger)decisionNumber
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"enterSubRule %d", decisionNumber]];
+}
+
+- (void) exitSubRule:(NSInteger)decisionNumber
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"exitSubRule %d", decisionNumber]];
+}
+
+- (void) enterDecision:(NSInteger)decisionNumber
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"enterDecision %d", decisionNumber]];
+}
+
+- (void) exitDecision:(NSInteger)decisionNumber
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"exitDecision %d", decisionNumber]];
+}
+
+- (void) consumeToken:(id<ANTLRToken>)t
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"consumeToken %@", [self escapeNewlines:[t description]]]];
+}
+
+- (void) consumeHiddenToken:(id<ANTLRToken>)t
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"consumeHiddenToken %@", [self escapeNewlines:[t description]]]];
+}
+
+- (void) LT:(NSInteger)i foundToken:(id<ANTLRToken>)t
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"LT %d %@", i, [self escapeNewlines:[t description]]]];
+}
+
+- (void) mark:(NSInteger)marker
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"mark %d", marker]];
+}
+- (void) rewind:(NSInteger)marker
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"rewind %d", marker]];
+}
+
+- (void) rewind
+{
+ [self sendToDebugger:@"rewind"];
+}
+
+- (void) beginBacktrack:(NSInteger)level
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"beginBacktrack %d", level]];
+}
+
+- (void) endBacktrack:(NSInteger)level wasSuccessful:(BOOL)successful
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"endBacktrack %d %d", level, successful ? 1 : 0]];
+}
+
+- (void) locationLine:(NSInteger)line column:(NSInteger)pos
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"location %d %d", line, pos]];
+}
+
+- (void) recognitionException:(ANTLRRecognitionException *)e
+{
+#warning TODO: recognition exceptions
+ // these must use the names of the corresponding Java exception classes, because ANTLRWorks recreates the exception
+ // objects on the Java side.
+ // Write categories for Objective-C exceptions to provide those names
+}
+
+- (void) beginResync
+{
+ [self sendToDebugger:@"beginResync"];
+}
+
+- (void) endResync
+{
+ [self sendToDebugger:@"endResync"];
+}
+
+- (void) semanticPredicate:(NSString *)predicate matched:(BOOL)result
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"semanticPredicate %d %@", result?1:0, [self escapeNewlines:predicate]]];
+}
+
+- (void) commence
+{
+ // no need to send event
+}
+
+- (void) terminate
+{
+ [self sendToDebugger:@"terminate"];
+ @try {
+ [debuggerFH closeFile];
+ }
+ @finally {
+#warning TODO: make socket handling robust. too lazy now...
+ shutdown(serverSocket,SHUT_RDWR);
+ serverSocket = -1;
+ }
+}
+
+
+#pragma mark Tree Parsing
+- (void) consumeNode:(unsigned)nodeHash ofType:(NSInteger)type text:(NSString *)text
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"consumeNode %u %d %@",
+ nodeHash,
+ type,
+ [self escapeNewlines:text]
+ ]];
+}
+
+- (void) LT:(NSInteger)i foundNode:(unsigned)nodeHash ofType:(NSInteger)type text:(NSString *)text
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"LN %d %u %d %@",
+ i,
+ nodeHash,
+ type,
+ [self escapeNewlines:text]
+ ]];
+}
+
+
+#pragma mark AST Events
+
+- (void) createNilNode:(unsigned)hash
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"nilNode %u", hash]];
+}
+
+- (void) createNode:(unsigned)hash text:(NSString *)text type:(NSInteger)type
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"createNodeFromToken %u %d %@",
+ hash,
+ type,
+ [self escapeNewlines:text]
+ ]];
+}
+
+- (void) createNode:(unsigned)hash fromTokenAtIndex:(NSInteger)tokenIndex
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"createNode %u %d", hash, tokenIndex]];
+}
+
+- (void) becomeRoot:(unsigned)newRootHash old:(unsigned)oldRootHash
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"becomeRoot %u %u", newRootHash, oldRootHash]];
+}
+
+- (void) addChild:(unsigned)childHash toTree:(unsigned)treeHash
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"addChild %u %u", treeHash, childHash]];
+}
+
+- (void) setTokenBoundariesForTree:(unsigned)nodeHash From:(NSInteger)tokenStartIndex To:(NSInteger)tokenStopIndex
+{
+ [self sendToDebugger:[NSString stringWithFormat:@"setTokenBoundaries %u %d %d", nodeHash, tokenStartIndex, tokenStopIndex]];
+}
+
+
+
+@end