• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1//
2//  ANTLRBaseRecognizer.m
3//  ANTLR
4//
5//  Created by Alan Condit on 6/16/10.
6// [The "BSD licence"]
7// Copyright (c) 2010 Alan Condit
8// All rights reserved.
9//
10// Redistribution and use in source and binary forms, with or without
11// modification, are permitted provided that the following conditions
12// are met:
13// 1. Redistributions of source code must retain the above copyright
14//    notice, this list of conditions and the following disclaimer.
15// 2. Redistributions in binary form must reproduce the above copyright
16//    notice, this list of conditions and the following disclaimer in the
17//    documentation and/or other materials provided with the distribution.
18// 3. The name of the author may not be used to endorse or promote products
19//    derived from this software without specific prior written permission.
20//
21// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32#import "ANTLRBaseRecognizer.h"
33#import "ANTLRHashRule.h"
34#import "ANTLRRuleMemo.h"
35#import "ANTLRCommonToken.h"
36#import "ANTLRMap.h"
37
38extern NSInteger debug;
39
40@implementation ANTLRBaseRecognizer
41
42static AMutableArray *_tokenNames;
43static NSString *_grammarFileName;
44static NSString *NEXT_TOKEN_RULE_NAME;
45
46@synthesize state;
47@synthesize grammarFileName;
48//@synthesize failed;
49@synthesize sourceName;
50//@synthesize numberOfSyntaxErrors;
51@synthesize tokenNames;
52
53+ (void) initialize
54{
55    NEXT_TOKEN_RULE_NAME = [NSString stringWithString:@"nextToken"];
56    [NEXT_TOKEN_RULE_NAME retain];
57}
58
59+ (ANTLRBaseRecognizer *) newANTLRBaseRecognizer
60{
61    return [[ANTLRBaseRecognizer alloc] init];
62}
63
64+ (ANTLRBaseRecognizer *) newANTLRBaseRecognizerWithRuleLen:(NSInteger)aLen
65{
66    return [[ANTLRBaseRecognizer alloc] initWithLen:aLen];
67}
68
69+ (ANTLRBaseRecognizer *) newANTLRBaseRecognizer:(ANTLRRecognizerSharedState *)aState
70{
71	return [[ANTLRBaseRecognizer alloc] initWithState:aState];
72}
73
74+ (AMutableArray *)getTokenNames
75{
76    return _tokenNames;
77}
78
79+ (void)setTokenNames:(AMutableArray *)theTokNams
80{
81    if ( _tokenNames != theTokNams ) {
82        if ( _tokenNames ) [_tokenNames release];
83        [theTokNams retain];
84    }
85    _tokenNames = theTokNams;
86}
87
88+ (void)setGrammarFileName:(NSString *)aFileName
89{
90    if ( _grammarFileName != aFileName ) {
91        if ( _grammarFileName ) [_grammarFileName release];
92        [aFileName retain];
93    }
94    [_grammarFileName retain];
95}
96
97- (id) init
98{
99	if ((self = [super init]) != nil) {
100        if (state == nil) {
101            state = [[ANTLRRecognizerSharedState newANTLRRecognizerSharedState] retain];
102        }
103        tokenNames = _tokenNames;
104        if ( tokenNames ) [tokenNames retain];
105        grammarFileName = _grammarFileName;
106        if ( grammarFileName ) [grammarFileName retain];
107        state._fsp = -1;
108        state.errorRecovery = NO;		// are we recovering?
109        state.lastErrorIndex = -1;
110        state.failed = NO;				// indicate that some match failed
111        state.syntaxErrors = 0;
112        state.backtracking = 0;			// the level of backtracking
113        state.tokenStartCharIndex = -1;
114	}
115	return self;
116}
117
118- (id) initWithLen:(NSInteger)aLen
119{
120	if ((self = [super init]) != nil) {
121        if (state == nil) {
122            state = [[ANTLRRecognizerSharedState newANTLRRecognizerSharedStateWithRuleLen:aLen] retain];
123        }
124        tokenNames = _tokenNames;
125        if ( tokenNames ) [tokenNames retain];
126        grammarFileName = _grammarFileName;
127        if ( grammarFileName ) [grammarFileName retain];
128        state._fsp = -1;
129        state.errorRecovery = NO;		// are we recovering?
130        state.lastErrorIndex = -1;
131        state.failed = NO;				// indicate that some match failed
132        state.syntaxErrors = 0;
133        state.backtracking = 0;			// the level of backtracking
134        state.tokenStartCharIndex = -1;
135	}
136	return self;
137}
138
139- (id) initWithState:(ANTLRRecognizerSharedState *)aState
140{
141	if ((self = [super init]) != nil) {
142		state = aState;
143        if (state == nil) {
144            state = [ANTLRRecognizerSharedState newANTLRRecognizerSharedState];
145        }
146        [state retain];
147        tokenNames = _tokenNames;
148        if ( tokenNames ) [tokenNames retain];
149        grammarFileName = _grammarFileName;
150        if ( grammarFileName ) [grammarFileName retain];
151        state._fsp = -1;
152        state.errorRecovery = NO;		// are we recovering?
153        state.lastErrorIndex = -1;
154        state.failed = NO;				// indicate that some match failed
155        state.syntaxErrors = 0;
156        state.backtracking = 0;			// the level of backtracking
157        state.tokenStartCharIndex = -1;
158	}
159	return self;
160}
161
162- (void)dealloc
163{
164#ifdef DEBUG_DEALLOC
165    NSLog( @"called dealloc in ANTLRBaseRecognizer" );
166#endif
167	if ( grammarFileName ) [grammarFileName release];
168	if ( tokenNames ) [tokenNames release];
169	if ( state ) [state release];
170	[super dealloc];
171}
172
173// reset the recognizer to the initial state. does not touch the token source!
174// this can be extended by the grammar writer to reset custom ivars
175- (void) reset
176{
177    if ( state == nil )
178        return;
179    if ( state.following != nil ) {
180        if ( [state.following count] )
181            [state.following removeAllObjects];
182    }
183    state._fsp = -1;
184    state.errorRecovery = NO;		// are we recovering?
185    state.lastErrorIndex = -1;
186    state.failed = NO;				// indicate that some match failed
187    state.syntaxErrors = 0;
188    state.backtracking = 0;			// the level of backtracking
189    state.tokenStartCharIndex = -1;
190    if ( state.ruleMemo != nil ) {
191        if ( [state.ruleMemo count] )
192            [state.ruleMemo removeAllObjects];
193    }
194}
195
196- (BOOL) getFailed
197{
198	return [state getFailed];
199}
200
201- (void) setFailed:(BOOL)flag
202{
203	[state setFailed:flag];
204}
205
206- (ANTLRRecognizerSharedState *) getState
207{
208	return state;
209}
210
211- (void) setState:(ANTLRRecognizerSharedState *) theState
212{
213	if (state != theState) {
214		if ( state ) [state release];
215		state = theState;
216		[state retain];
217	}
218}
219
220- (id)input
221{
222    return nil; // Must be overriden in inheriting class
223}
224
225- (void)skip // override in inheriting class
226{
227    return;
228}
229
230-(id) match:(id<ANTLRIntStream>)anInput TokenType:(NSInteger)ttype Follow:(ANTLRBitSet *)follow
231{
232	id matchedSymbol = [self getCurrentInputSymbol:anInput];
233	if ([anInput LA:1] == ttype) {
234		[anInput consume];
235		state.errorRecovery = NO;
236		state.failed = NO;
237		return matchedSymbol;
238	}
239	if (state.backtracking > 0) {
240		state.failed = YES;
241		return matchedSymbol;
242	}
243	matchedSymbol = [self recoverFromMismatchedToken:anInput TokenType:ttype Follow:follow];
244	return matchedSymbol;
245}
246
247-(void) matchAny:(id<ANTLRIntStream>)anInput
248{
249    state.errorRecovery = NO;
250    state.failed = NO;
251    [anInput consume];
252}
253
254-(BOOL) mismatchIsUnwantedToken:(id<ANTLRIntStream>)anInput TokenType:(NSInteger)ttype
255{
256    return [anInput LA:2] == ttype;
257}
258
259-(BOOL) mismatchIsMissingToken:(id<ANTLRIntStream>)anInput Follow:(ANTLRBitSet *) follow
260{
261    if ( follow == nil ) {
262        // we have no information about the follow; we can only consume
263        // a single token and hope for the best
264        return NO;
265    }
266    // compute what can follow this grammar element reference
267    if ( [follow member:ANTLRTokenTypeEOR] ) {
268        ANTLRBitSet *viableTokensFollowingThisRule = [self computeContextSensitiveRuleFOLLOW];
269        follow = [follow or:viableTokensFollowingThisRule];
270        if ( state._fsp >= 0 ) { // remove EOR if we're not the start symbol
271            [follow remove:(ANTLRTokenTypeEOR)];
272        }
273    }
274    // if current token is consistent with what could come after set
275    // then we know we're missing a token; error recovery is free to
276    // "insert" the missing token
277
278    //System.out.println("viable tokens="+follow.toString(getTokenNames()));
279    //System.out.println("LT(1)="+((TokenStream)input).LT(1));
280
281    // BitSet cannot handle negative numbers like -1 (EOF) so I leave EOR
282    // in follow set to indicate that the fall of the start symbol is
283    // in the set (EOF can follow).
284    if ( [follow member:[anInput LA:1]] || [follow member:ANTLRTokenTypeEOR] ) {
285        //System.out.println("LT(1)=="+((TokenStream)input).LT(1)+" is consistent with what follows; inserting...");
286        return YES;
287    }
288    return NO;
289}
290
291/** Report a recognition problem.
292 *
293 *  This method sets errorRecovery to indicate the parser is recovering
294 *  not parsing.  Once in recovery mode, no errors are generated.
295 *  To get out of recovery mode, the parser must successfully match
296 *  a token (after a resync).  So it will go:
297 *
298 * 		1. error occurs
299 * 		2. enter recovery mode, report error
300 * 		3. consume until token found in resynch set
301 * 		4. try to resume parsing
302 * 		5. next match() will reset errorRecovery mode
303 *
304 *  If you override, make sure to update syntaxErrors if you care about that.
305 */
306-(void) reportError:(ANTLRRecognitionException *) e
307{
308    // if we've already reported an error and have not matched a token
309    // yet successfully, don't report any errors.
310    if ( state.errorRecovery ) {
311        //System.err.print("[SPURIOUS] ");
312        return;
313    }
314    state.syntaxErrors++; // don't count spurious
315    state.errorRecovery = YES;
316
317    [self displayRecognitionError:[self getTokenNames] Exception:e];
318}
319
320-(void) displayRecognitionError:(AMutableArray *)theTokNams Exception:(ANTLRRecognitionException *)e
321{
322    NSString *hdr = [self getErrorHeader:e];
323    NSString *msg = [self getErrorMessage:e TokenNames:theTokNams];
324    [self emitErrorMessage:[NSString stringWithFormat:@" %@ %@", hdr, msg]];
325}
326
327/** What error message should be generated for the various
328 *  exception types?
329 *
330 *  Not very object-oriented code, but I like having all error message
331 *  generation within one method rather than spread among all of the
332 *  exception classes. This also makes it much easier for the exception
333 *  handling because the exception classes do not have to have pointers back
334 *  to this object to access utility routines and so on. Also, changing
335 *  the message for an exception type would be difficult because you
336 *  would have to subclassing exception, but then somehow get ANTLR
337 *  to make those kinds of exception objects instead of the default.
338 *  This looks weird, but trust me--it makes the most sense in terms
339 *  of flexibility.
340 *
341 *  For grammar debugging, you will want to override this to add
342 *  more information such as the stack frame with
343 *  getRuleInvocationStack(e, this.getClass().getName()) and,
344 *  for no viable alts, the decision description and state etc...
345 *
346 *  Override this to change the message generated for one or more
347 *  exception types.
348 */
349- (NSString *)getErrorMessage:(ANTLRRecognitionException *)e TokenNames:(AMutableArray *)theTokNams
350{
351    // NSString *msg = [e getMessage];
352    NSString *msg;
353    if ( [e isKindOfClass:[ANTLRUnwantedTokenException class]] ) {
354        ANTLRUnwantedTokenException *ute = (ANTLRUnwantedTokenException *)e;
355        NSString *tokenName=@"<unknown>";
356        if ( ute.expecting == ANTLRTokenTypeEOF ) {
357            tokenName = @"EOF";
358        }
359        else {
360            tokenName = (NSString *)[theTokNams objectAtIndex:ute.expecting];
361        }
362        msg = [NSString stringWithFormat:@"extraneous input %@ expecting %@", [self getTokenErrorDisplay:[ute getUnexpectedToken]],
363               tokenName];
364    }
365    else if ( [e isKindOfClass:[ANTLRMissingTokenException class] ] ) {
366        ANTLRMissingTokenException *mte = (ANTLRMissingTokenException *)e;
367        NSString *tokenName=@"<unknown>";
368        if ( mte.expecting== ANTLRTokenTypeEOF ) {
369            tokenName = @"EOF";
370        }
371        else {
372            tokenName = [theTokNams objectAtIndex:mte.expecting];
373        }
374        msg = [NSString stringWithFormat:@"missing %@ at %@", tokenName, [self getTokenErrorDisplay:(e.token)] ];
375    }
376    else if ( [e isKindOfClass:[ANTLRMismatchedTokenException class]] ) {
377        ANTLRMismatchedTokenException *mte = (ANTLRMismatchedTokenException *)e;
378        NSString *tokenName=@"<unknown>";
379        if ( mte.expecting== ANTLRTokenTypeEOF ) {
380            tokenName = @"EOF";
381        }
382        else {
383            tokenName = [theTokNams objectAtIndex:mte.expecting];
384        }
385        msg = [NSString stringWithFormat:@"mismatched input %@ expecting %@",[self getTokenErrorDisplay:(e.token)], tokenName];
386    }
387    else if ( [e isKindOfClass:[ANTLRMismatchedTreeNodeException class]] ) {
388        ANTLRMismatchedTreeNodeException *mtne = (ANTLRMismatchedTreeNodeException *)e;
389        NSString *tokenName=@"<unknown>";
390        if ( mtne.expecting==ANTLRTokenTypeEOF ) {
391            tokenName = @"EOF";
392        }
393        else {
394            tokenName = [theTokNams objectAtIndex:mtne.expecting];
395        }
396        msg = [NSString stringWithFormat:@"mismatched tree node: %@ expecting %@", mtne.node, tokenName];
397    }
398    else if ( [e isKindOfClass:[ANTLRNoViableAltException class]] ) {
399        //NoViableAltException *nvae = (NoViableAltException *)e;
400        // for development, can add "decision=<<"+nvae.grammarDecisionDescription+">>"
401        // and "(decision="+nvae.decisionNumber+") and
402        // "state "+nvae.stateNumber
403        msg = [NSString stringWithFormat:@"no viable alternative at input %@", [self getTokenErrorDisplay:e.token]];
404    }
405    else if ( [e isKindOfClass:[ANTLREarlyExitException class]] ) {
406        //ANTLREarlyExitException *eee = (ANTLREarlyExitException *)e;
407        // for development, can add "(decision="+eee.decisionNumber+")"
408        msg =[NSString stringWithFormat: @"required (...)+ loop did not match anything at input ", [self getTokenErrorDisplay:e.token]];
409    }
410    else if ( [e isKindOfClass:[ANTLRMismatchedSetException class]] ) {
411        ANTLRMismatchedSetException *mse = (ANTLRMismatchedSetException *)e;
412        msg = [NSString stringWithFormat:@"mismatched input %@ expecting set %@",
413               [self getTokenErrorDisplay:(e.token)],
414               mse.expecting];
415    }
416#pragma warning NotSet not yet implemented.
417    else if ( [e isKindOfClass:[ANTLRMismatchedNotSetException class] ] ) {
418        ANTLRMismatchedNotSetException *mse = (ANTLRMismatchedNotSetException *)e;
419        msg = [NSString stringWithFormat:@"mismatched input %@ expecting set %@",
420               [self getTokenErrorDisplay:(e.token)],
421               mse.expecting];
422    }
423    else if ( [e isKindOfClass:[ANTLRFailedPredicateException class]] ) {
424        ANTLRFailedPredicateException *fpe = (ANTLRFailedPredicateException *)e;
425        msg = [NSString stringWithFormat:@"rule %@ failed predicate: { %@ }?", fpe.ruleName, fpe.predicate];
426    }
427    else {
428        msg = [NSString stringWithFormat:@"Exception= %@\n", e.name];
429    }
430    return msg;
431}
432
433/** Get number of recognition errors (lexer, parser, tree parser).  Each
434 *  recognizer tracks its own number.  So parser and lexer each have
435 *  separate count.  Does not count the spurious errors found between
436 *  an error and next valid token match
437 *
438 *  See also reportError()
439 */
440- (NSInteger) getNumberOfSyntaxErrors
441{
442    return state.syntaxErrors;
443}
444
445/** What is the error header, normally line/character position information? */
446- (NSString *)getErrorHeader:(ANTLRRecognitionException *)e
447{
448    return [NSString stringWithFormat:@"line %d:%d", e.line, e.charPositionInLine];
449}
450
451/** How should a token be displayed in an error message? The default
452 *  is to display just the text, but during development you might
453 *  want to have a lot of information spit out.  Override in that case
454 *  to use t.toString() (which, for CommonToken, dumps everything about
455 *  the token). This is better than forcing you to override a method in
456 *  your token objects because you don't have to go modify your lexer
457 *  so that it creates a new Java type.
458 */
459- (NSString *)getTokenErrorDisplay:(id<ANTLRToken>)t
460{
461    NSString *s = t.text;
462    if ( s == nil ) {
463        if ( t.type == ANTLRTokenTypeEOF ) {
464            s = @"<EOF>";
465        }
466        else {
467            s = [NSString stringWithFormat:@"<%@>", t.type];
468        }
469    }
470    s = [s stringByReplacingOccurrencesOfString:@"\n" withString:@"\\\\n"];
471    s = [s stringByReplacingOccurrencesOfString:@"\r" withString:@"\\\\r"];
472    s = [s stringByReplacingOccurrencesOfString:@"\t" withString:@"\\\\t"];
473    return [NSString stringWithFormat:@"\'%@\'", s];
474}
475
476/** Override this method to change where error messages go */
477- (void) emitErrorMessage:(NSString *) msg
478{
479//    System.err.println(msg);
480    NSLog(@"%@", msg);
481}
482
483/** Recover from an error found on the input stream.  This is
484 *  for NoViableAlt and mismatched symbol exceptions.  If you enable
485 *  single token insertion and deletion, this will usually not
486 *  handle mismatched symbol exceptions but there could be a mismatched
487 *  token that the match() routine could not recover from.
488 */
489- (void)recover:(id<ANTLRIntStream>)anInput Exception:(ANTLRRecognitionException *)re
490{
491    if ( state.lastErrorIndex == anInput.index ) {
492        // uh oh, another error at same token index; must be a case
493        // where LT(1) is in the recovery token set so nothing is
494        // consumed; consume a single token so at least to prevent
495        // an infinite loop; this is a failsafe.
496        [anInput consume];
497    }
498    state.lastErrorIndex = anInput.index;
499    ANTLRBitSet *followSet = [self computeErrorRecoverySet];
500    [self beginResync];
501    [self consumeUntilFollow:anInput Follow:followSet];
502    [self endResync];
503}
504
505- (void) beginResync
506{
507
508}
509
510- (void) endResync
511{
512
513}
514
515/*  Compute the error recovery set for the current rule.  During
516 *  rule invocation, the parser pushes the set of tokens that can
517 *  follow that rule reference on the stack; this amounts to
518 *  computing FIRST of what follows the rule reference in the
519 *  enclosing rule. This local follow set only includes tokens
520 *  from within the rule; i.e., the FIRST computation done by
521 *  ANTLR stops at the end of a rule.
522 *
523 *  EXAMPLE
524 *
525 *  When you find a "no viable alt exception", the input is not
526 *  consistent with any of the alternatives for rule r.  The best
527 *  thing to do is to consume tokens until you see something that
528 *  can legally follow a call to r *or* any rule that called r.
529 *  You don't want the exact set of viable next tokens because the
530 *  input might just be missing a token--you might consume the
531 *  rest of the input looking for one of the missing tokens.
532 *
533 *  Consider grammar:
534 *
535 *  a : '[' b ']'
536 *    | '(' b ')'
537 *    ;
538 *  b : c '^' INT ;
539 *  c : ID
540 *    | INT
541 *    ;
542 *
543 *  At each rule invocation, the set of tokens that could follow
544 *  that rule is pushed on a stack.  Here are the various "local"
545 *  follow sets:
546 *
547 *  FOLLOW(b1_in_a) = FIRST(']') = ']'
548 *  FOLLOW(b2_in_a) = FIRST(')') = ')'
549 *  FOLLOW(c_in_b) = FIRST('^') = '^'
550 *
551 *  Upon erroneous input "[]", the call chain is
552 *
553 *  a -> b -> c
554 *
555 *  and, hence, the follow context stack is:
556 *
557 *  depth  local follow set     after call to rule
558 *    0         <EOF>                    a (from main())
559 *    1          ']'                     b
560 *    3          '^'                     c
561 *
562 *  Notice that ')' is not included, because b would have to have
563 *  been called from a different context in rule a for ')' to be
564 *  included.
565 *
566 *  For error recovery, we cannot consider FOLLOW(c)
567 *  (context-sensitive or otherwise).  We need the combined set of
568 *  all context-sensitive FOLLOW sets--the set of all tokens that
569 *  could follow any reference in the call chain.  We need to
570 *  resync to one of those tokens.  Note that FOLLOW(c)='^' and if
571 *  we resync'd to that token, we'd consume until EOF.  We need to
572 *  sync to context-sensitive FOLLOWs for a, b, and c: {']','^'}.
573 *  In this case, for input "[]", LA(1) is in this set so we would
574 *  not consume anything and after printing an error rule c would
575 *  return normally.  It would not find the required '^' though.
576 *  At this point, it gets a mismatched token error and throws an
577 *  exception (since LA(1) is not in the viable following token
578 *  set).  The rule exception handler tries to recover, but finds
579 *  the same recovery set and doesn't consume anything.  Rule b
580 *  exits normally returning to rule a.  Now it finds the ']' (and
581 *  with the successful match exits errorRecovery mode).
582 *
583 *  So, you cna see that the parser walks up call chain looking
584 *  for the token that was a member of the recovery set.
585 *
586 *  Errors are not generated in errorRecovery mode.
587 *
588 *  ANTLR's error recovery mechanism is based upon original ideas:
589 *
590 *  "Algorithms + Data Structures = Programs" by Niklaus Wirth
591 *
592 *  and
593 *
594 *  "A note on error recovery in recursive descent parsers":
595 *  http://portal.acm.org/citation.cfm?id=947902.947905
596 *
597 *  Later, Josef Grosch had some good ideas:
598 *
599 *  "Efficient and Comfortable Error Recovery in Recursive Descent
600 *  Parsers":
601 *  ftp://www.cocolab.com/products/cocktail/doca4.ps/ell.ps.zip
602 *
603 *  Like Grosch I implemented local FOLLOW sets that are combined
604 *  at run-time upon error to avoid overhead during parsing.
605 */
606- (ANTLRBitSet *) computeErrorRecoverySet
607{
608    return [self combineFollows:NO];
609}
610
611/** Compute the context-sensitive FOLLOW set for current rule.
612 *  This is set of token types that can follow a specific rule
613 *  reference given a specific call chain.  You get the set of
614 *  viable tokens that can possibly come next (lookahead depth 1)
615 *  given the current call chain.  Contrast this with the
616 *  definition of plain FOLLOW for rule r:
617 *
618 *   FOLLOW(r)={x | S=>*alpha r beta in G and x in FIRST(beta)}
619 *
620 *  where x in T* and alpha, beta in V*; T is set of terminals and
621 *  V is the set of terminals and nonterminals.  In other words,
622 *  FOLLOW(r) is the set of all tokens that can possibly follow
623 *  references to r in *any* sentential form (context).  At
624 *  runtime, however, we know precisely which context applies as
625 *  we have the call chain.  We may compute the exact (rather
626 *  than covering superset) set of following tokens.
627 *
628 *  For example, consider grammar:
629 *
630 *  stat : ID '=' expr ';'      // FOLLOW(stat)=={EOF}
631 *       | "return" expr '.'
632 *       ;
633 *  expr : atom ('+' atom)* ;   // FOLLOW(expr)=={';','.',')'}
634 *  atom : INT                  // FOLLOW(atom)=={'+',')',';','.'}
635 *       | '(' expr ')'
636 *       ;
637 *
638 *  The FOLLOW sets are all inclusive whereas context-sensitive
639 *  FOLLOW sets are precisely what could follow a rule reference.
640 *  For input input "i=(3);", here is the derivation:
641 *
642 *  stat => ID '=' expr ';'
643 *       => ID '=' atom ('+' atom)* ';'
644 *       => ID '=' '(' expr ')' ('+' atom)* ';'
645 *       => ID '=' '(' atom ')' ('+' atom)* ';'
646 *       => ID '=' '(' INT ')' ('+' atom)* ';'
647 *       => ID '=' '(' INT ')' ';'
648 *
649 *  At the "3" token, you'd have a call chain of
650 *
651 *    stat -> expr -> atom -> expr -> atom
652 *
653 *  What can follow that specific nested ref to atom?  Exactly ')'
654 *  as you can see by looking at the derivation of this specific
655 *  input.  Contrast this with the FOLLOW(atom)={'+',')',';','.'}.
656 *
657 *  You want the exact viable token set when recovering from a
658 *  token mismatch.  Upon token mismatch, if LA(1) is member of
659 *  the viable next token set, then you know there is most likely
660 *  a missing token in the input stream.  "Insert" one by just not
661 *  throwing an exception.
662 */
663- (ANTLRBitSet *)computeContextSensitiveRuleFOLLOW
664{
665    return [self combineFollows:YES];
666}
667
668// what is exact? it seems to only add sets from above on stack
669// if EOR is in set i.  When it sees a set w/o EOR, it stops adding.
670// Why would we ever want them all?  Maybe no viable alt instead of
671// mismatched token?
672- (ANTLRBitSet *)combineFollows:(BOOL) exact
673{
674    NSInteger top = state._fsp;
675    ANTLRBitSet *followSet = [[ANTLRBitSet newANTLRBitSet] retain];
676    for (int i = top; i >= 0; i--) {
677        ANTLRBitSet *localFollowSet = (ANTLRBitSet *)[state.following objectAtIndex:i];
678        /*
679         System.out.println("local follow depth "+i+"="+
680         localFollowSet.toString(getTokenNames())+")");
681         */
682        [followSet orInPlace:localFollowSet];
683        if ( exact ) {
684            // can we see end of rule?
685            if ( [localFollowSet member:ANTLRTokenTypeEOR] ) {
686                // Only leave EOR in set if at top (start rule); this lets
687                // us know if have to include follow(start rule); i.e., EOF
688                if ( i > 0 ) {
689                    [followSet remove:ANTLRTokenTypeEOR];
690                }
691            }
692            else { // can't see end of rule, quit
693                break;
694            }
695        }
696    }
697    return followSet;
698}
699
700/** Attempt to recover from a single missing or extra token.
701 *
702 *  EXTRA TOKEN
703 *
704 *  LA(1) is not what we are looking for.  If LA(2) has the right token,
705 *  however, then assume LA(1) is some extra spurious token.  Delete it
706 *  and LA(2) as if we were doing a normal match(), which advances the
707 *  input.
708 *
709 *  MISSING TOKEN
710 *
711 *  If current token is consistent with what could come after
712 *  ttype then it is ok to "insert" the missing token, else throw
713 *  exception For example, Input "i=(3;" is clearly missing the
714 *  ')'.  When the parser returns from the nested call to expr, it
715 *  will have call chain:
716 *
717 *    stat -> expr -> atom
718 *
719 *  and it will be trying to match the ')' at this point in the
720 *  derivation:
721 *
722 *       => ID '=' '(' INT ')' ('+' atom)* ';'
723 *                          ^
724 *  match() will see that ';' doesn't match ')' and report a
725 *  mismatched token error.  To recover, it sees that LA(1)==';'
726 *  is in the set of tokens that can follow the ')' token
727 *  reference in rule atom.  It can assume that you forgot the ')'.
728 */
729- (id<ANTLRToken>)recoverFromMismatchedToken:(id<ANTLRIntStream>)anInput
730                       TokenType:(NSInteger)ttype
731                          Follow:(ANTLRBitSet *)follow
732{
733    ANTLRRecognitionException *e = nil;
734    // if next token is what we are looking for then "delete" this token
735    if ( [self mismatchIsUnwantedToken:anInput TokenType:ttype] ) {
736        e = [ANTLRUnwantedTokenException newException:ttype Stream:anInput];
737        /*
738         System.err.println("recoverFromMismatchedToken deleting "+
739         ((TokenStream)input).LT(1)+
740         " since "+((TokenStream)input).LT(2)+" is what we want");
741         */
742        [self beginResync];
743        [anInput consume]; // simply delete extra token
744        [self endResync];
745        [self reportError:e];  // report after consuming so AW sees the token in the exception
746                         // we want to return the token we're actually matching
747        id matchedSymbol = [self getCurrentInputSymbol:anInput];
748        [anInput consume]; // move past ttype token as if all were ok
749        return matchedSymbol;
750    }
751    // can't recover with single token deletion, try insertion
752    if ( [self mismatchIsMissingToken:anInput Follow:follow] ) {
753        id<ANTLRToken> inserted = [self getMissingSymbol:anInput Exception:e TokenType:ttype Follow:follow];
754        e = [ANTLRMissingTokenException newException:ttype Stream:anInput With:inserted];
755        [self reportError:e];  // report after inserting so AW sees the token in the exception
756        return inserted;
757    }
758    // even that didn't work; must throw the exception
759    e = [ANTLRMismatchedTokenException newException:ttype Stream:anInput];
760    @throw e;
761}
762
763/** Not currently used */
764-(id) recoverFromMismatchedSet:(id<ANTLRIntStream>)anInput
765                     Exception:(ANTLRRecognitionException *)e
766                        Follow:(ANTLRBitSet *) follow
767{
768    if ( [self mismatchIsMissingToken:anInput Follow:follow] ) {
769        // System.out.println("missing token");
770        [self reportError:e];
771        // we don't know how to conjure up a token for sets yet
772        return [self getMissingSymbol:anInput Exception:e TokenType:ANTLRTokenTypeInvalid Follow:follow];
773    }
774    // TODO do single token deletion like above for Token mismatch
775    @throw e;
776}
777
778/** Match needs to return the current input symbol, which gets put
779 *  into the label for the associated token ref; e.g., x=ID.  Token
780 *  and tree parsers need to return different objects. Rather than test
781 *  for input stream type or change the IntStream interface, I use
782 *  a simple method to ask the recognizer to tell me what the current
783 *  input symbol is.
784 *
785 *  This is ignored for lexers.
786 */
787- (id) getCurrentInputSymbol:(id<ANTLRIntStream>)anInput
788{
789    return nil;
790}
791
792/** Conjure up a missing token during error recovery.
793 *
794 *  The recognizer attempts to recover from single missing
795 *  symbols. But, actions might refer to that missing symbol.
796 *  For example, x=ID {f($x);}. The action clearly assumes
797 *  that there has been an identifier matched previously and that
798 *  $x points at that token. If that token is missing, but
799 *  the next token in the stream is what we want we assume that
800 *  this token is missing and we keep going. Because we
801 *  have to return some token to replace the missing token,
802 *  we have to conjure one up. This method gives the user control
803 *  over the tokens returned for missing tokens. Mostly,
804 *  you will want to create something special for identifier
805 *  tokens. For literals such as '{' and ',', the default
806 *  action in the parser or tree parser works. It simply creates
807 *  a CommonToken of the appropriate type. The text will be the token.
808 *  If you change what tokens must be created by the lexer,
809 *  override this method to create the appropriate tokens.
810 */
811- (id)getMissingSymbol:(id<ANTLRIntStream>)anInput
812             Exception:(ANTLRRecognitionException *)e
813             TokenType:(NSInteger)expectedTokenType
814                Follow:(ANTLRBitSet *)follow
815{
816    return nil;
817}
818
819
820-(void) consumeUntilTType:(id<ANTLRIntStream>)anInput TokenType:(NSInteger)tokenType
821{
822    //System.out.println("consumeUntil "+tokenType);
823    int ttype = [anInput LA:1];
824    while (ttype != ANTLRTokenTypeEOF && ttype != tokenType) {
825        [anInput consume];
826        ttype = [anInput LA:1];
827    }
828}
829
830/** Consume tokens until one matches the given token set */
831-(void) consumeUntilFollow:(id<ANTLRIntStream>)anInput Follow:(ANTLRBitSet *)set
832{
833    //System.out.println("consumeUntil("+set.toString(getTokenNames())+")");
834    int ttype = [anInput LA:1];
835    while (ttype != ANTLRTokenTypeEOF && ![set member:ttype] ) {
836        //System.out.println("consume during recover LA(1)="+getTokenNames()[input.LA(1)]);
837        [anInput consume];
838        ttype = [anInput LA:1];
839    }
840}
841
842/** Push a rule's follow set using our own hardcoded stack */
843- (void)pushFollow:(ANTLRBitSet *)fset
844{
845    if ( (state._fsp +1) >= [state.following count] ) {
846        //        AMutableArray *f = [AMutableArray arrayWithCapacity:[[state.following] count]*2];
847        //        System.arraycopy(state.following, 0, f, 0, state.following.length);
848        //        state.following = f;
849        [state.following addObject:fset];
850        [fset retain];
851        state._fsp++;
852    }
853    else {
854        [state.following replaceObjectAtIndex:++state._fsp withObject:fset];
855    }
856}
857
858- (ANTLRBitSet *)popFollow
859{
860    ANTLRBitSet *fset;
861
862    if ( state._fsp >= 0 && [state.following count] > 0 ) {
863        fset = [state.following objectAtIndex:state._fsp--];
864        [state.following removeLastObject];
865        return fset;
866    }
867    else {
868        NSLog( @"Attempted to pop a follow when none exists on the stack\n" );
869    }
870    return nil;
871}
872
873/** Return List<String> of the rules in your parser instance
874 *  leading up to a call to this method.  You could override if
875 *  you want more details such as the file/line info of where
876 *  in the parser java code a rule is invoked.
877 *
878 *  This is very useful for error messages and for context-sensitive
879 *  error recovery.
880 */
881- (AMutableArray *)getRuleInvocationStack
882{
883    NSString *parserClassName = [[self className] retain];
884    return [self getRuleInvocationStack:[ANTLRRecognitionException newException] Recognizer:parserClassName];
885}
886
887/** A more general version of getRuleInvocationStack where you can
888 *  pass in, for example, a RecognitionException to get it's rule
889 *  stack trace.  This routine is shared with all recognizers, hence,
890 *  static.
891 *
892 *  TODO: move to a utility class or something; weird having lexer call this
893 */
894- (AMutableArray *)getRuleInvocationStack:(ANTLRRecognitionException *)e
895                                Recognizer:(NSString *)recognizerClassName
896{
897    // char *name;
898    AMutableArray *rules = [[AMutableArray arrayWithCapacity:20] retain];
899    NSArray *stack = [e callStackSymbols];
900    int i = 0;
901    for (i = [stack count]-1; i >= 0; i--) {
902        NSString *t = [stack objectAtIndex:i];
903        // NSLog(@"stack %d = %@\n", i, t);
904        if ( [t commonPrefixWithString:@"org.antlr.runtime." options:NSLiteralSearch] ) {
905            // id aClass = objc_getClass( [t UTF8String] );
906            continue; // skip support code such as this method
907        }
908        if ( [t isEqualTo:NEXT_TOKEN_RULE_NAME] ) {
909            // name = sel_getName(method_getName(method));
910            // NSString *aMethod = [NSString stringWithFormat:@"%s", name];
911            continue;
912        }
913        if ( ![t isEqualTo:recognizerClassName] ) {
914            // name = class_getName( [t UTF8String] );
915            continue; // must not be part of this parser
916        }
917        [rules addObject:t];
918    }
919#ifdef DONTUSEYET
920    StackTraceElement[] stack = e.getStackTrace();
921    int i = 0;
922    for (i=stack.length-1; i>=0; i--) {
923        StackTraceElement t = stack[i];
924        if ( [t getClassName().startsWith("org.antlr.runtime.") ) {
925            continue; // skip support code such as this method
926        }
927              if ( [[t getMethodName] equals:NEXT_TOKEN_RULE_NAME] ) {
928            continue;
929        }
930              if ( ![[t getClassName] equals:recognizerClassName] ) {
931            continue; // must not be part of this parser
932        }
933              [rules addObject:[t getMethodName]];
934    }
935#endif
936    [stack release];
937    return rules;
938}
939
940- (NSInteger) getBacktrackingLevel
941{
942    return [state getBacktracking];
943}
944
945- (void) setBacktrackingLevel:(NSInteger)level
946{
947    [state setBacktracking:level];
948}
949
950        /** Used to print out token names like ID during debugging and
951 *  error reporting.  The generated parsers implement a method
952 *  that overrides this to point to their String[] tokenNames.
953 */
954- (NSArray *)getTokenNames
955{
956    return tokenNames;
957}
958
959/** For debugging and other purposes, might want the grammar name.
960 *  Have ANTLR generate an implementation for this method.
961 */
962- (NSString *)getGrammarFileName
963{
964    return grammarFileName;
965}
966
967- (NSString *)getSourceName
968{
969    return nil;
970}
971
972/** A convenience method for use most often with template rewrites.
973 *  Convert a List<Token> to List<String>
974 */
975- (AMutableArray *)toStrings:(AMutableArray *)tokens
976{
977    if ( tokens == nil )
978        return nil;
979    AMutableArray *strings = [AMutableArray arrayWithCapacity:[tokens count]];
980    id object;
981    NSInteger i = 0;
982    for (object in tokens) {
983        [strings addObject:[object text]];
984        i++;
985    }
986    return strings;
987}
988
989/** Given a rule number and a start token index number, return
990 *  ANTLR_MEMO_RULE_UNKNOWN if the rule has not parsed input starting from
991 *  start index.  If this rule has parsed input starting from the
992 *  start index before, then return where the rule stopped parsing.
993 *  It returns the index of the last token matched by the rule.
994 *
995 *  For now we use a hashtable and just the slow Object-based one.
996 *  Later, we can make a special one for ints and also one that
997 *  tosses out data after we commit past input position i.
998 */
999- (NSInteger)getRuleMemoization:(NSInteger)ruleIndex StartIndex:(NSInteger)ruleStartIndex
1000{
1001    NSNumber *stopIndexI;
1002    ANTLRHashRule *aHashRule;
1003    if ( (aHashRule = [state.ruleMemo objectAtIndex:ruleIndex]) == nil ) {
1004        aHashRule = [ANTLRHashRule newANTLRHashRuleWithLen:17];
1005        [state.ruleMemo insertObject:aHashRule atIndex:ruleIndex];
1006    }
1007    stopIndexI = [aHashRule getRuleMemoStopIndex:ruleStartIndex];
1008    if ( stopIndexI == nil ) {
1009        return ANTLR_MEMO_RULE_UNKNOWN;
1010    }
1011    return [stopIndexI integerValue];
1012}
1013
1014/** Has this rule already parsed input at the current index in the
1015 *  input stream?  Return the stop token index or MEMO_RULE_UNKNOWN.
1016 *  If we attempted but failed to parse properly before, return
1017 *  MEMO_RULE_FAILED.
1018 *
1019 *  This method has a side-effect: if we have seen this input for
1020 *  this rule and successfully parsed before, then seek ahead to
1021 *  1 past the stop token matched for this rule last time.
1022 */
1023- (BOOL)alreadyParsedRule:(id<ANTLRIntStream>)anInput RuleIndex:(NSInteger)ruleIndex
1024{
1025    NSInteger aStopIndex = [self getRuleMemoization:ruleIndex StartIndex:anInput.index];
1026    if ( aStopIndex == ANTLR_MEMO_RULE_UNKNOWN ) {
1027        // NSLog(@"rule %d not yet encountered\n", ruleIndex);
1028        return NO;
1029    }
1030    if ( aStopIndex == ANTLR_MEMO_RULE_FAILED ) {
1031        if (debug) NSLog(@"rule %d will never succeed\n", ruleIndex);
1032        state.failed = YES;
1033    }
1034    else {
1035        if (debug) NSLog(@"seen rule %d before; skipping ahead to %d failed = %@\n", ruleIndex, aStopIndex+1, state.failed?@"YES":@"NO");
1036        [anInput seek:(aStopIndex+1)]; // jump to one past stop token
1037    }
1038    return YES;
1039}
1040
1041/** Record whether or not this rule parsed the input at this position
1042 *  successfully.  Use a standard java hashtable for now.
1043 */
1044- (void)memoize:(id<ANTLRIntStream>)anInput
1045      RuleIndex:(NSInteger)ruleIndex
1046     StartIndex:(NSInteger)ruleStartIndex
1047{
1048    ANTLRRuleStack *aRuleStack;
1049    NSInteger stopTokenIndex;
1050
1051    aRuleStack = state.ruleMemo;
1052    stopTokenIndex = (state.failed ? ANTLR_MEMO_RULE_FAILED : (anInput.index-1));
1053    if ( aRuleStack == nil ) {
1054        if (debug) NSLog(@"!!!!!!!!! memo array is nil for %@", [self getGrammarFileName]);
1055        return;
1056    }
1057    if ( ruleIndex >= [aRuleStack length] ) {
1058        if (debug) NSLog(@"!!!!!!!!! memo size is %d, but rule index is %d", [state.ruleMemo length], ruleIndex);
1059        return;
1060    }
1061    if ( [aRuleStack objectAtIndex:ruleIndex] != nil ) {
1062        [aRuleStack putHashRuleAtRuleIndex:ruleIndex StartIndex:ruleStartIndex StopIndex:stopTokenIndex];
1063    }
1064    return;
1065}
1066
1067/** return how many rule/input-index pairs there are in total.
1068 *  TODO: this includes synpreds. :(
1069 */
1070- (NSInteger)getRuleMemoizationCacheSize
1071{
1072    ANTLRRuleStack *aRuleStack;
1073    ANTLRHashRule *aHashRule;
1074
1075    int aCnt = 0;
1076    aRuleStack = state.ruleMemo;
1077    for (NSUInteger i = 0; aRuleStack != nil && i < [aRuleStack length]; i++) {
1078        aHashRule = [aRuleStack objectAtIndex:i];
1079        if ( aHashRule != nil ) {
1080            aCnt += [aHashRule count]; // how many input indexes are recorded?
1081        }
1082    }
1083    return aCnt;
1084}
1085
1086#pragma warning Have to fix traceIn and traceOut.
1087- (void)traceIn:(NSString *)ruleName Index:(NSInteger)ruleIndex Object:(id)inputSymbol
1088{
1089    NSLog(@"enter %@ %@", ruleName, inputSymbol);
1090    if ( state.backtracking > 0 ) {
1091        NSLog(@" backtracking=%s", ((state.backtracking==YES)?"YES":"NO"));
1092    }
1093    NSLog(@"\n");
1094}
1095
1096- (void)traceOut:(NSString *)ruleName Index:(NSInteger)ruleIndex Object:(id)inputSymbol
1097{
1098    NSLog(@"exit %@ -- %@", ruleName, inputSymbol);
1099    if ( state.backtracking > 0 ) {
1100        NSLog(@" backtracking=%s %s", state.backtracking?"YES":"NO", state.failed ? "failed":"succeeded");
1101    }
1102    NSLog(@"\n");
1103}
1104
1105
1106// call a syntactic predicate methods using its selector. this way we can support arbitrary synpreds.
1107- (BOOL) evaluateSyntacticPredicate:(SEL)synpredFragment // stream:(id<ANTLRIntStream>)input
1108{
1109    id<ANTLRIntStream> input;
1110
1111    state.backtracking++;
1112    // input = state.token.input;
1113    input = self.input;
1114    int start = [input mark];
1115    @try {
1116        [self performSelector:synpredFragment];
1117    }
1118    @catch (ANTLRRecognitionException *re) {
1119        NSLog(@"impossible synpred: %@", re.name);
1120    }
1121    BOOL success = (state.failed == NO);
1122    [input rewind:start];
1123    state.backtracking--;
1124    state.failed = NO;
1125    return success;
1126}
1127
1128@end
1129
1130