1// [The "BSD licence"]
2// Copyright (c) 2006-2007 Kay Roepke 2010 Alan Condit
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 "ANTLRTreeParser.h"
28
29@implementation ANTLRTreeParser
30
31@synthesize input;
32
33+ (id) newANTLRTreeParser:(id<ANTLRTreeNodeStream>)anInput
34{
35    return [[ANTLRTreeParser alloc] initWithStream:anInput];
36}
37
38+ (id) newANTLRTreeParser:(id<ANTLRTreeNodeStream>)anInput State:(ANTLRRecognizerSharedState *)theState
39{
40    return [[ANTLRTreeParser alloc] initWithStream:anInput State:theState];
41}
42
43- (id) initWithStream:(id<ANTLRTreeNodeStream>)theInput
44{
45	if ((self = [super init]) != nil) {
46		[self setInput:theInput];
47	}
48	return self;
49}
50
51- (id) initWithStream:(id<ANTLRTreeNodeStream>)theInput State:(ANTLRRecognizerSharedState *)theState
52{
53	if ((self = [super init]) != nil) {
54		[self setInput:theInput];
55        state = theState;
56	}
57	return self;
58}
59
60- (void) dealloc
61{
62#ifdef DEBUG_DEALLOC
63    NSLog( @"called dealloc in ANTLRTreeParser" );
64#endif
65	if ( input ) [input release];
66	[super dealloc];
67}
68
69- (void) reset
70{
71    [super reset]; // reset all recognizer state variables
72    if ( input != nil ) {
73        [input seek:0]; // rewind the input
74    }
75}
76
77- (void) mismatch:(id<ANTLRIntStream>)aStream tokenType:(ANTLRTokenType)aTType follow:(ANTLRBitSet *)aBitset
78{
79	ANTLRMismatchedTreeNodeException *mte = [ANTLRMismatchedTreeNodeException newException:aTType Stream:aStream];
80    [mte setNode:[((id<ANTLRTreeNodeStream>)aStream) LT:1]];
81	[self recoverFromMismatchedToken:aStream Type:aTType Follow:aBitset];
82}
83
84- (void) setTreeNodeStream:(id<ANTLRTreeNodeStream>) anInput
85{
86    input = anInput;
87}
88
89- (id<ANTLRTreeNodeStream>) getTreeNodeStream
90{
91    return input;
92}
93
94- (NSString *)getSourceName
95{
96    return [input getSourceName];
97}
98
99- (id) getCurrentInputSymbol:(id<ANTLRIntStream>) anInput
100{
101    return [(id<ANTLRTreeNodeStream>)anInput LT:1];
102}
103
104- (id) getMissingSymbol:(id<ANTLRIntStream>)anInput
105              Exception:(ANTLRRecognitionException *)e
106          ExpectedToken:(NSInteger)expectedTokenType
107                 BitSet:(ANTLRBitSet *)follow
108{
109    NSString *tokenText =[NSString stringWithFormat:@"<missing %@ %d>", [self getTokenNames], expectedTokenType];
110    //id<ANTLRTreeAdaptor> anAdaptor = (id<ANTLRTreeAdaptor>)[((id<ANTLRTreeNodeStream>)e.input) getTreeAdaptor];
111    //return [anAdaptor createToken:expectedTokenType Text:tokenText];
112    return [ANTLRCommonToken newToken:expectedTokenType Text:tokenText];
113}
114
115/** Match '.' in tree parser has special meaning.  Skip node or
116 *  entire tree if node has children.  If children, scan until
117 *  corresponding UP node.
118 */
119- (void) matchAny:(id<ANTLRIntStream>)ignore
120{ // ignore stream, copy of input
121    state.errorRecovery = NO;
122    state.failed = NO;
123    id look = [input LT:1];
124    if ( [((ANTLRCommonTreeAdaptor *)[input getTreeAdaptor]) getChildCount:look] == 0) {
125        [input consume]; // not subtree, consume 1 node and return
126        return;
127    }
128    // current node is a subtree, skip to corresponding UP.
129    // must count nesting level to get right UP
130    int level=0;
131    int tokenType = [((id<ANTLRTreeAdaptor>)[input getTreeAdaptor]) getType:look];
132    while ( tokenType != ANTLRTokenTypeEOF && !( tokenType == ANTLRTokenTypeUP && level == 0) ) {
133        [input consume];
134        look = [input LT:1];
135        tokenType = [((id<ANTLRTreeAdaptor>)[input getTreeAdaptor]) getType:look];
136        if ( tokenType == ANTLRTokenTypeDOWN ) {
137            level++;
138        }
139        else if ( tokenType == ANTLRTokenTypeUP ) {
140            level--;
141        }
142    }
143    [input consume]; // consume UP
144}
145
146/** We have DOWN/UP nodes in the stream that have no line info; override.
147 *  plus we want to alter the exception type.  Don't try to recover
148 *  from tree parser errors inline...
149 */
150- (id) recoverFromMismatchedToken:(id<ANTLRIntStream>)anInput Type:(NSInteger)ttype Follow:(ANTLRBitSet *)follow
151{
152    @throw [ANTLRMismatchedTreeNodeException newException:ttype Stream:anInput];
153}
154
155/** Prefix error message with the grammar name because message is
156 *  always intended for the programmer because the parser built
157 *  the input tree not the user.
158 */
159- (NSString *)getErrorHeader:(ANTLRRecognitionException *)e
160{
161     return [NSString stringWithFormat:@"%@: node after line %@:%@",
162            [self getGrammarFileName], e.line, e.charPositionInLine];
163}
164
165/** Tree parsers parse nodes they usually have a token object as
166 *  payload. Set the exception token and do the default behavior.
167 */
168- (NSString *)getErrorMessage:(ANTLRRecognitionException *)e  TokenNames:(AMutableArray *) theTokNams
169{
170    if ( [self isKindOfClass:[ANTLRTreeParser class]] ) {
171        ANTLRCommonTreeAdaptor *adaptor = (ANTLRCommonTreeAdaptor *)[((id<ANTLRTreeNodeStream>)e.input) getTreeAdaptor];
172        e.token = [adaptor getToken:((id<ANTLRBaseTree>)e.node)];
173        if ( e.token == nil ) { // could be an UP/DOWN node
174            e.token = [ANTLRCommonToken newToken:[adaptor getType:e.node]
175                                                        Text:[adaptor getText:e.node]];
176        }
177    }
178    return [super getErrorMessage:e TokenNames:theTokNams];
179}
180
181- (void) traceIn:(NSString *)ruleName Index:(NSInteger)ruleIndex
182{
183    [super traceIn:ruleName Index:ruleIndex Object:[input LT:1]];
184}
185
186- (void) traceOut:(NSString *)ruleName Index:(NSInteger)ruleIndex
187{
188    [super traceOut:ruleName Index:ruleIndex  Object:[input LT:1]];
189}
190
191
192@end
193