// [The "BSD licence"] // Copyright (c) 2006-2007 Kay Roepke 2010 Alan Condit // 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 "TreeParser.h" @implementation TreeParser @synthesize input; + (id) newTreeParser:(id)anInput { return [[TreeParser alloc] initWithStream:anInput]; } + (id) newTreeParser:(id)anInput State:(RecognizerSharedState *)theState { return [[TreeParser alloc] initWithStream:anInput State:theState]; } - (id) initWithStream:(id)theInput { if ((self = [super init]) != nil) { [self setInput:theInput]; } return self; } - (id) initWithStream:(id)theInput State:(RecognizerSharedState *)theState { if ((self = [super init]) != nil) { [self setInput:theInput]; state = theState; } return self; } - (void) dealloc { #ifdef DEBUG_DEALLOC NSLog( @"called dealloc in TreeParser" ); #endif if ( input ) [input release]; [super dealloc]; } - (void) reset { [super reset]; // reset all recognizer state variables if ( input != nil ) { [input seek:0]; // rewind the input } } - (void) mismatch:(id)aStream tokenType:(TokenType)aTType follow:(ANTLRBitSet *)aBitset { MismatchedTreeNodeException *mte = [MismatchedTreeNodeException newException:aTType Stream:aStream]; [mte setNode:[((id)aStream) LT:1]]; [self recoverFromMismatchedToken:aStream Type:aTType Follow:aBitset]; } - (void) setTreeNodeStream:(id) anInput { input = anInput; } - (id) getTreeNodeStream { return input; } - (NSString *)getSourceName { return [input getSourceName]; } - (id) getCurrentInputSymbol:(id) anInput { return [(id)anInput LT:1]; } - (id) getMissingSymbol:(id)anInput Exception:(RecognitionException *)e ExpectedToken:(NSInteger)expectedTokenType BitSet:(ANTLRBitSet *)follow { NSString *tokenText =[NSString stringWithFormat:@"", [self getTokenNames], expectedTokenType]; //id anAdaptor = (id)[((id)e.input) getTreeAdaptor]; //return [anAdaptor createToken:expectedTokenType Text:tokenText]; return [CommonToken newToken:expectedTokenType Text:tokenText]; } /** Match '.' in tree parser has special meaning. Skip node or * entire tree if node has children. If children, scan until * corresponding UP node. */ - (void) matchAny:(id)ignore { // ignore stream, copy of input state.errorRecovery = NO; state.failed = NO; id look = [input LT:1]; if ( [((CommonTreeAdaptor *)[input getTreeAdaptor]) getChildCount:look] == 0) { [input consume]; // not subtree, consume 1 node and return return; } // current node is a subtree, skip to corresponding UP. // must count nesting level to get right UP int level=0; int tokenType = [((id)[input getTreeAdaptor]) getType:look]; while ( tokenType != TokenTypeEOF && !( tokenType == TokenTypeUP && level == 0) ) { [input consume]; look = [input LT:1]; tokenType = [((id)[input getTreeAdaptor]) getType:look]; if ( tokenType == TokenTypeDOWN ) { level++; } else if ( tokenType == TokenTypeUP ) { level--; } } [input consume]; // consume UP } /** We have DOWN/UP nodes in the stream that have no line info; override. * plus we want to alter the exception type. Don't try to recover * from tree parser errors inline... */ - (id) recoverFromMismatchedToken:(id)anInput Type:(NSInteger)ttype Follow:(ANTLRBitSet *)follow { @throw [MismatchedTreeNodeException newException:ttype Stream:anInput]; } /** Prefix error message with the grammar name because message is * always intended for the programmer because the parser built * the input tree not the user. */ - (NSString *)getErrorHeader:(RecognitionException *)e { return [NSString stringWithFormat:@"%@: node after line %@:%@", [self getGrammarFileName], e.line, e.charPositionInLine]; } /** Tree parsers parse nodes they usually have a token object as * payload. Set the exception token and do the default behavior. */ - (NSString *)getErrorMessage:(RecognitionException *)e TokenNames:(AMutableArray *) theTokNams { if ( [self isKindOfClass:[TreeParser class]] ) { CommonTreeAdaptor *adaptor = (CommonTreeAdaptor *)[((id)e.input) getTreeAdaptor]; e.token = [adaptor getToken:((CommonTree *)e.node)]; if ( e.token == nil ) { // could be an UP/DOWN node e.token = [CommonToken newToken:[adaptor getType:(CommonTree *)e.node] Text:[adaptor getText:(CommonTree *)e.node]]; } } return [super getErrorMessage:e TokenNames:theTokNams]; } - (void) traceIn:(NSString *)ruleName Index:(NSInteger)ruleIndex { [super traceIn:ruleName Index:ruleIndex Object:[input LT:1]]; } - (void) traceOut:(NSString *)ruleName Index:(NSInteger)ruleIndex { [super traceOut:ruleName Index:ruleIndex Object:[input LT:1]]; } @end