xref: /aosp_15_r20/external/antlr/runtime/ObjC/Framework/Lexer.m (revision 16467b971bd3e2009fad32dd79016f2c7e421deb)
1*16467b97STreehugger Robot// [The "BSD licence"]
2*16467b97STreehugger Robot// Copyright (c) 2006-2007 Kay Roepke 2010 Alan Condit
3*16467b97STreehugger Robot// All rights reserved.
4*16467b97STreehugger Robot//
5*16467b97STreehugger Robot// Redistribution and use in source and binary forms, with or without
6*16467b97STreehugger Robot// modification, are permitted provided that the following conditions
7*16467b97STreehugger Robot// are met:
8*16467b97STreehugger Robot// 1. Redistributions of source code must retain the above copyright
9*16467b97STreehugger Robot//    notice, this list of conditions and the following disclaimer.
10*16467b97STreehugger Robot// 2. Redistributions in binary form must reproduce the above copyright
11*16467b97STreehugger Robot//    notice, this list of conditions and the following disclaimer in the
12*16467b97STreehugger Robot//    documentation and/or other materials provided with the distribution.
13*16467b97STreehugger Robot// 3. The name of the author may not be used to endorse or promote products
14*16467b97STreehugger Robot//    derived from this software without specific prior written permission.
15*16467b97STreehugger Robot//
16*16467b97STreehugger Robot// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17*16467b97STreehugger Robot// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18*16467b97STreehugger Robot// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19*16467b97STreehugger Robot// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20*16467b97STreehugger Robot// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21*16467b97STreehugger Robot// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22*16467b97STreehugger Robot// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23*16467b97STreehugger Robot// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*16467b97STreehugger Robot// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25*16467b97STreehugger Robot// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*16467b97STreehugger Robot
27*16467b97STreehugger Robot#import <ANTLR/antlr.h>
28*16467b97STreehugger Robot#import "Lexer.h"
29*16467b97STreehugger Robot
30*16467b97STreehugger Robot@implementation Lexer
31*16467b97STreehugger Robot
32*16467b97STreehugger Robot@synthesize input;
33*16467b97STreehugger Robot@synthesize ruleNestingLevel;
34*16467b97STreehugger Robot#pragma mark Initializer
35*16467b97STreehugger Robot
36*16467b97STreehugger Robot- (id) initWithCharStream:(id<CharStream>)anInput
37*16467b97STreehugger Robot{
38*16467b97STreehugger Robot    self = [super initWithState:[[RecognizerSharedState alloc] init]];
39*16467b97STreehugger Robot    if ( self != nil ) {
40*16467b97STreehugger Robot        input = [anInput retain];
41*16467b97STreehugger Robot        if (state.token != nil)
42*16467b97STreehugger Robot            [((CommonToken *)state.token) setInput:anInput];
43*16467b97STreehugger Robot        ruleNestingLevel = 0;
44*16467b97STreehugger Robot    }
45*16467b97STreehugger Robot    return self;
46*16467b97STreehugger Robot}
47*16467b97STreehugger Robot
48*16467b97STreehugger Robot- (id) initWithCharStream:(id<CharStream>)anInput State:(RecognizerSharedState *)aState
49*16467b97STreehugger Robot{
50*16467b97STreehugger Robot    self = [super initWithState:aState];
51*16467b97STreehugger Robot    if ( self != nil ) {
52*16467b97STreehugger Robot        input = [anInput retain];
53*16467b97STreehugger Robot        if (state.token != nil)
54*16467b97STreehugger Robot            [((CommonToken *)state.token) setInput:anInput];
55*16467b97STreehugger Robot        ruleNestingLevel = 0;
56*16467b97STreehugger Robot    }
57*16467b97STreehugger Robot    return self;
58*16467b97STreehugger Robot}
59*16467b97STreehugger Robot
60*16467b97STreehugger Robot- (void) dealloc
61*16467b97STreehugger Robot{
62*16467b97STreehugger Robot    if ( input ) [input release];
63*16467b97STreehugger Robot    [super dealloc];
64*16467b97STreehugger Robot}
65*16467b97STreehugger Robot
66*16467b97STreehugger Robot- (id) copyWithZone:(NSZone *)aZone
67*16467b97STreehugger Robot{
68*16467b97STreehugger Robot    Lexer *copy;
69*16467b97STreehugger Robot
70*16467b97STreehugger Robot    copy = [[[self class] allocWithZone:aZone] init];
71*16467b97STreehugger Robot    //    copy = [super copyWithZone:aZone]; // allocation occurs here
72*16467b97STreehugger Robot    if ( input != nil )
73*16467b97STreehugger Robot        copy.input = input;
74*16467b97STreehugger Robot    copy.ruleNestingLevel = ruleNestingLevel;
75*16467b97STreehugger Robot    return copy;
76*16467b97STreehugger Robot}
77*16467b97STreehugger Robot
78*16467b97STreehugger Robot- (void) reset
79*16467b97STreehugger Robot{
80*16467b97STreehugger Robot    [super reset]; // reset all recognizer state variables
81*16467b97STreehugger Robot                   // wack Lexer state variables
82*16467b97STreehugger Robot    if ( input != nil ) {
83*16467b97STreehugger Robot        [input seek:0]; // rewind the input
84*16467b97STreehugger Robot    }
85*16467b97STreehugger Robot    if ( state == nil ) {
86*16467b97STreehugger Robot        return; // no shared state work to do
87*16467b97STreehugger Robot    }
88*16467b97STreehugger Robot    state.token = nil;
89*16467b97STreehugger Robot    state.type = CommonToken.INVALID_TOKEN_TYPE;
90*16467b97STreehugger Robot    state.channel = CommonToken.DEFAULT_CHANNEL;
91*16467b97STreehugger Robot    state.tokenStartCharIndex = -1;
92*16467b97STreehugger Robot    state.tokenStartCharPositionInLine = -1;
93*16467b97STreehugger Robot    state.tokenStartLine = -1;
94*16467b97STreehugger Robot    state.text = nil;
95*16467b97STreehugger Robot}
96*16467b97STreehugger Robot
97*16467b97STreehugger Robot// token stuff
98*16467b97STreehugger Robot#pragma mark Tokens
99*16467b97STreehugger Robot
100*16467b97STreehugger Robot- (id<Token>)getToken
101*16467b97STreehugger Robot{
102*16467b97STreehugger Robot    return [state getToken];
103*16467b97STreehugger Robot}
104*16467b97STreehugger Robot
105*16467b97STreehugger Robot- (void) setToken: (id<Token>) aToken
106*16467b97STreehugger Robot{
107*16467b97STreehugger Robot    if (state.token != aToken) {
108*16467b97STreehugger Robot        [aToken retain];
109*16467b97STreehugger Robot        state.token = aToken;
110*16467b97STreehugger Robot    }
111*16467b97STreehugger Robot}
112*16467b97STreehugger Robot
113*16467b97STreehugger Robot
114*16467b97STreehugger Robot// this method may be overridden in the generated lexer if we generate a filtering lexer.
115*16467b97STreehugger Robot- (id<Token>) nextToken
116*16467b97STreehugger Robot{
117*16467b97STreehugger Robot    while (YES) {
118*16467b97STreehugger Robot        [self setToken:nil];
119*16467b97STreehugger Robot        state.channel = CommonToken.DEFAULT_CHANNEL;
120*16467b97STreehugger Robot        state.tokenStartCharIndex = input.index;
121*16467b97STreehugger Robot        state.tokenStartCharPositionInLine = input.getCharPositionInLine;
122*16467b97STreehugger Robot        state.tokenStartLine = input.getLine;
123*16467b97STreehugger Robot        state.text = nil;
124*16467b97STreehugger Robot
125*16467b97STreehugger Robot        // [self setText:[self text]];
126*16467b97STreehugger Robot        if ([input LA:1] == CharStreamEOF) {
127*16467b97STreehugger Robot            CommonToken *eof = [CommonToken newToken:input
128*16467b97STreehugger Robot                                                          Type:TokenTypeEOF
129*16467b97STreehugger Robot                                                       Channel:CommonToken.DEFAULT_CHANNEL
130*16467b97STreehugger Robot                                                         Start:input.index
131*16467b97STreehugger Robot                                                          Stop:input.index];
132*16467b97STreehugger Robot            [eof setLine:input.getLine];
133*16467b97STreehugger Robot            [eof setCharPositionInLine:input.getCharPositionInLine];
134*16467b97STreehugger Robot            return eof;
135*16467b97STreehugger Robot        }
136*16467b97STreehugger Robot        @try {
137*16467b97STreehugger Robot            [self mTokens];
138*16467b97STreehugger Robot            // SEL aMethod = @selector(mTokens);
139*16467b97STreehugger Robot            // [[self class] instancesRespondToSelector:aMethod];
140*16467b97STreehugger Robot            if ( state.token == nil)
141*16467b97STreehugger Robot                [self emit];
142*16467b97STreehugger Robot            else if ( state.token == [CommonToken skipToken] ) {
143*16467b97STreehugger Robot                continue;
144*16467b97STreehugger Robot            }
145*16467b97STreehugger Robot            return state.token;
146*16467b97STreehugger Robot        }
147*16467b97STreehugger Robot        @catch (MismatchedRangeException *re) {
148*16467b97STreehugger Robot            [self reportError:re];
149*16467b97STreehugger Robot            // [self recover:re];
150*16467b97STreehugger Robot        }
151*16467b97STreehugger Robot        @catch (MismatchedTokenException *re) {
152*16467b97STreehugger Robot            [self reportError:re];
153*16467b97STreehugger Robot            // [self recover:re];
154*16467b97STreehugger Robot        }
155*16467b97STreehugger Robot        @catch (RecognitionException *re) {
156*16467b97STreehugger Robot            [self reportError:re];
157*16467b97STreehugger Robot            [self recover:re];
158*16467b97STreehugger Robot        }
159*16467b97STreehugger Robot    }
160*16467b97STreehugger Robot}
161*16467b97STreehugger Robot
162*16467b97STreehugger Robot- (void) mTokens
163*16467b97STreehugger Robot{   // abstract, defined in generated source as a starting point for matching
164*16467b97STreehugger Robot    [self doesNotRecognizeSelector:_cmd];
165*16467b97STreehugger Robot}
166*16467b97STreehugger Robot
167*16467b97STreehugger Robot- (void) skip
168*16467b97STreehugger Robot{
169*16467b97STreehugger Robot    state.token = [CommonToken skipToken];
170*16467b97STreehugger Robot}
171*16467b97STreehugger Robot
172*16467b97STreehugger Robot- (id<CharStream>) input
173*16467b97STreehugger Robot{
174*16467b97STreehugger Robot    return input;
175*16467b97STreehugger Robot}
176*16467b97STreehugger Robot
177*16467b97STreehugger Robot- (void) setInput:(id<CharStream>) anInput
178*16467b97STreehugger Robot{
179*16467b97STreehugger Robot    if ( anInput != input ) {
180*16467b97STreehugger Robot        if ( input ) [input release];
181*16467b97STreehugger Robot    }
182*16467b97STreehugger Robot    input = nil;
183*16467b97STreehugger Robot    [self reset];
184*16467b97STreehugger Robot    input = anInput;
185*16467b97STreehugger Robot    [input retain];
186*16467b97STreehugger Robot}
187*16467b97STreehugger Robot
188*16467b97STreehugger Robot/** Currently does not support multiple emits per nextToken invocation
189*16467b97STreehugger Robot *  for efficiency reasons.  Subclass and override this method and
190*16467b97STreehugger Robot *  nextToken (to push tokens into a list and pull from that list rather
191*16467b97STreehugger Robot *  than a single variable as this implementation does).
192*16467b97STreehugger Robot */
193*16467b97STreehugger Robot- (void) emit:(id<Token>)aToken
194*16467b97STreehugger Robot{
195*16467b97STreehugger Robot    state.token = aToken;
196*16467b97STreehugger Robot}
197*16467b97STreehugger Robot
198*16467b97STreehugger Robot/** The standard method called to automatically emit a token at the
199*16467b97STreehugger Robot *  outermost lexical rule.  The token object should point into the
200*16467b97STreehugger Robot *  char buffer start..stop.  If there is a text override in 'text',
201*16467b97STreehugger Robot *  use that to set the token's text.  Override this method to emit
202*16467b97STreehugger Robot *  custom Token objects.
203*16467b97STreehugger Robot *
204*16467b97STreehugger Robot *  If you are building trees, then you should also override
205*16467b97STreehugger Robot *  Parser or TreeParser.getMissingSymbol().
206*16467b97STreehugger Robot */
207*16467b97STreehugger Robot- (void) emit
208*16467b97STreehugger Robot{
209*16467b97STreehugger Robot    id<Token> aToken = [CommonToken newToken:input
210*16467b97STreehugger Robot                                                  Type:state.type
211*16467b97STreehugger Robot                                               Channel:state.channel
212*16467b97STreehugger Robot                                                 Start:state.tokenStartCharIndex
213*16467b97STreehugger Robot                                                  Stop:input.index-1];
214*16467b97STreehugger Robot    aToken.text = [self text];
215*16467b97STreehugger Robot    [aToken setCharPositionInLine:state.tokenStartCharPositionInLine];
216*16467b97STreehugger Robot    [aToken setLine:state.tokenStartLine];
217*16467b97STreehugger Robot    [aToken retain];
218*16467b97STreehugger Robot    [self emit:aToken];
219*16467b97STreehugger Robot    // [aToken release];
220*16467b97STreehugger Robot}
221*16467b97STreehugger Robot
222*16467b97STreehugger Robot// matching
223*16467b97STreehugger Robot#pragma mark Matching
224*16467b97STreehugger Robot- (void) matchString:(NSString *)aString
225*16467b97STreehugger Robot{
226*16467b97STreehugger Robot    unichar c;
227*16467b97STreehugger Robot    unsigned int i = 0;
228*16467b97STreehugger Robot    unsigned int stringLength = [aString length];
229*16467b97STreehugger Robot    while ( i < stringLength ) {
230*16467b97STreehugger Robot        c = [input LA:1];
231*16467b97STreehugger Robot        if ( c != [aString characterAtIndex:i] ) {
232*16467b97STreehugger Robot            if ([state getBacktracking] > 0) {
233*16467b97STreehugger Robot                state.failed = YES;
234*16467b97STreehugger Robot                return;
235*16467b97STreehugger Robot            }
236*16467b97STreehugger Robot            MismatchedTokenException *mte = [MismatchedTokenException newExceptionChar:[aString characterAtIndex:i] Stream:input];
237*16467b97STreehugger Robot            mte.c = c;
238*16467b97STreehugger Robot            [self recover:mte];
239*16467b97STreehugger Robot            @throw mte;
240*16467b97STreehugger Robot        }
241*16467b97STreehugger Robot        i++;
242*16467b97STreehugger Robot        [input consume];
243*16467b97STreehugger Robot        state.failed = NO;
244*16467b97STreehugger Robot    }
245*16467b97STreehugger Robot}
246*16467b97STreehugger Robot
247*16467b97STreehugger Robot- (void) matchAny
248*16467b97STreehugger Robot{
249*16467b97STreehugger Robot    [input consume];
250*16467b97STreehugger Robot}
251*16467b97STreehugger Robot
252*16467b97STreehugger Robot- (void) matchChar:(unichar) aChar
253*16467b97STreehugger Robot{
254*16467b97STreehugger Robot    // TODO: -LA: is returning an int because it sometimes is used in the generated parser to compare lookahead with a tokentype.
255*16467b97STreehugger Robot    //       try to change all those occurrences to -LT: if possible (i.e. if ANTLR can be made to generate LA only for lexer code)
256*16467b97STreehugger Robot    unichar charLA;
257*16467b97STreehugger Robot    charLA = [input LA:1];
258*16467b97STreehugger Robot    if ( charLA != aChar) {
259*16467b97STreehugger Robot        if ([state getBacktracking] > 0) {
260*16467b97STreehugger Robot            state.failed = YES;
261*16467b97STreehugger Robot            return;
262*16467b97STreehugger Robot        }
263*16467b97STreehugger Robot        MismatchedTokenException  *mte = [MismatchedTokenException newExceptionChar:aChar Stream:input];
264*16467b97STreehugger Robot        mte.c = charLA;
265*16467b97STreehugger Robot        [self recover:mte];
266*16467b97STreehugger Robot        @throw mte;
267*16467b97STreehugger Robot    }
268*16467b97STreehugger Robot    [input consume];
269*16467b97STreehugger Robot    state.failed = NO;
270*16467b97STreehugger Robot}
271*16467b97STreehugger Robot
272*16467b97STreehugger Robot- (void) matchRangeFromChar:(unichar)fromChar to:(unichar)toChar
273*16467b97STreehugger Robot{
274*16467b97STreehugger Robot    unichar charLA = (unichar)[input LA:1];
275*16467b97STreehugger Robot    if ( charLA < fromChar || charLA > toChar ) {
276*16467b97STreehugger Robot        if ([state getBacktracking] > 0) {
277*16467b97STreehugger Robot            state.failed = YES;
278*16467b97STreehugger Robot            return;
279*16467b97STreehugger Robot        }
280*16467b97STreehugger Robot        MismatchedRangeException  *mre = [MismatchedRangeException
281*16467b97STreehugger Robot                    newException:NSMakeRange((NSUInteger)fromChar,(NSUInteger)toChar)
282*16467b97STreehugger Robot                               stream:input];
283*16467b97STreehugger Robot        mre.c = charLA;
284*16467b97STreehugger Robot        [self recover:mre];
285*16467b97STreehugger Robot        @throw mre;
286*16467b97STreehugger Robot    }
287*16467b97STreehugger Robot    [input consume];
288*16467b97STreehugger Robot    state.failed = NO;
289*16467b97STreehugger Robot}
290*16467b97STreehugger Robot
291*16467b97STreehugger Robot    // info
292*16467b97STreehugger Robot#pragma mark Informational
293*16467b97STreehugger Robot
294*16467b97STreehugger Robot- (NSUInteger) line
295*16467b97STreehugger Robot{
296*16467b97STreehugger Robot    return input.getLine;
297*16467b97STreehugger Robot}
298*16467b97STreehugger Robot
299*16467b97STreehugger Robot- (NSUInteger) charPositionInLine
300*16467b97STreehugger Robot{
301*16467b97STreehugger Robot    return input.getCharPositionInLine;
302*16467b97STreehugger Robot}
303*16467b97STreehugger Robot
304*16467b97STreehugger Robot- (NSInteger) index
305*16467b97STreehugger Robot{
306*16467b97STreehugger Robot    return 0;
307*16467b97STreehugger Robot}
308*16467b97STreehugger Robot
309*16467b97STreehugger Robot- (NSString *) text
310*16467b97STreehugger Robot{
311*16467b97STreehugger Robot    if (state.text != nil) {
312*16467b97STreehugger Robot        return state.text;
313*16467b97STreehugger Robot    }
314*16467b97STreehugger Robot    return [input substringWithRange:NSMakeRange(state.tokenStartCharIndex, input.index-state.tokenStartCharIndex)];
315*16467b97STreehugger Robot}
316*16467b97STreehugger Robot
317*16467b97STreehugger Robot- (void) setText:(NSString *) theText
318*16467b97STreehugger Robot{
319*16467b97STreehugger Robot    state.text = theText;
320*16467b97STreehugger Robot}
321*16467b97STreehugger Robot
322*16467b97STreehugger Robot    // error handling
323*16467b97STreehugger Robot- (void) reportError:(RecognitionException *)e
324*16467b97STreehugger Robot{
325*16467b97STreehugger Robot    /** TODO: not thought about recovery in lexer yet.
326*16467b97STreehugger Robot     *
327*16467b97STreehugger Robot     // if we've already reported an error and have not matched a token
328*16467b97STreehugger Robot     // yet successfully, don't report any errors.
329*16467b97STreehugger Robot     if ( errorRecovery ) {
330*16467b97STreehugger Robot     //System.err.print("[SPURIOUS] ");
331*16467b97STreehugger Robot     return;
332*16467b97STreehugger Robot     }
333*16467b97STreehugger Robot     errorRecovery = true;
334*16467b97STreehugger Robot     */
335*16467b97STreehugger Robot
336*16467b97STreehugger Robot    [self displayRecognitionError:[self getTokenNames] Exception:e];
337*16467b97STreehugger Robot}
338*16467b97STreehugger Robot
339*16467b97STreehugger Robot- (NSString *)getErrorMessage:(RecognitionException *)e TokenNames:(AMutableArray *)tokenNames
340*16467b97STreehugger Robot{
341*16467b97STreehugger Robot/*    NSString *msg = [NSString stringWithFormat:@"Gotta fix getErrorMessage in Lexer.m--%@\n",
342*16467b97STreehugger Robot                     e.name];
343*16467b97STreehugger Robot */
344*16467b97STreehugger Robot    NSString *msg = nil;
345*16467b97STreehugger Robot    if ( [e isKindOfClass:[MismatchedTokenException class]] ) {
346*16467b97STreehugger Robot        MismatchedTokenException *mte = (MismatchedTokenException *)e;
347*16467b97STreehugger Robot        msg = [NSString stringWithFormat:@"mismatched character \"%@\" expecting \"%@\"",
348*16467b97STreehugger Robot            [self getCharErrorDisplay:mte.c], [self getCharErrorDisplay:mte.expectingChar]];
349*16467b97STreehugger Robot    }
350*16467b97STreehugger Robot    else if ( [e isKindOfClass:[NoViableAltException class]] ) {
351*16467b97STreehugger Robot        NoViableAltException *nvae = (NoViableAltException *)e;
352*16467b97STreehugger Robot        // for development, can add "decision=<<"+nvae.grammarDecisionDescription+">>"
353*16467b97STreehugger Robot        // and "(decision="+nvae.decisionNumber+") and
354*16467b97STreehugger Robot        // "state "+nvae.stateNumber
355*16467b97STreehugger Robot        msg = [NSString stringWithFormat:@"no viable alternative decision:%d state:%d at character \"%@\"",
356*16467b97STreehugger Robot               nvae.decisionNumber, nvae.stateNumber, [self getCharErrorDisplay:(nvae.c)]];
357*16467b97STreehugger Robot    }
358*16467b97STreehugger Robot    else if ( [e isKindOfClass:[EarlyExitException class]] ) {
359*16467b97STreehugger Robot        EarlyExitException *eee = (EarlyExitException *)e;
360*16467b97STreehugger Robot        // for development, can add "(decision="+eee.decisionNumber+")"
361*16467b97STreehugger Robot        msg = [NSString stringWithFormat:@"required (...)+ loop did not match anything at character \"%@\"",
362*16467b97STreehugger Robot               [self getCharErrorDisplay:(eee.c)]];
363*16467b97STreehugger Robot    }
364*16467b97STreehugger Robot    else if ( [e isKindOfClass:[MismatchedNotSetException class]] ) {
365*16467b97STreehugger Robot        MismatchedNotSetException *mse = (MismatchedNotSetException *)e;
366*16467b97STreehugger Robot        msg = [NSString stringWithFormat:@"mismatched character \"%@\"  expecting set \"%@\"",
367*16467b97STreehugger Robot               [self getCharErrorDisplay:(mse.c)], mse.expecting];
368*16467b97STreehugger Robot    }
369*16467b97STreehugger Robot    else if ( [e isKindOfClass:[MismatchedSetException class]] ) {
370*16467b97STreehugger Robot        MismatchedSetException *mse = (MismatchedSetException *)e;
371*16467b97STreehugger Robot        msg = [NSString stringWithFormat:@"mismatched character \"%@\" expecting set \"%@\"",
372*16467b97STreehugger Robot               [self getCharErrorDisplay:(mse.c)], mse.expecting];
373*16467b97STreehugger Robot    }
374*16467b97STreehugger Robot    else if ( [e isKindOfClass:[MismatchedRangeException class]] ) {
375*16467b97STreehugger Robot        MismatchedRangeException *mre = (MismatchedRangeException *)e;
376*16467b97STreehugger Robot        msg = [NSString stringWithFormat:@"mismatched character \"%@\" \"%@..%@\"",
377*16467b97STreehugger Robot               [self getCharErrorDisplay:(mre.c)], [self getCharErrorDisplay:(mre.range.location)],
378*16467b97STreehugger Robot               [self getCharErrorDisplay:(mre.range.location+mre.range.length-1)]];
379*16467b97STreehugger Robot    }
380*16467b97STreehugger Robot    else {
381*16467b97STreehugger Robot        msg = [super getErrorMessage:e TokenNames:[self getTokenNames]];
382*16467b97STreehugger Robot    }
383*16467b97STreehugger Robot    return msg;
384*16467b97STreehugger Robot}
385*16467b97STreehugger Robot
386*16467b97STreehugger Robot- (NSString *)getCharErrorDisplay:(NSInteger)c
387*16467b97STreehugger Robot{
388*16467b97STreehugger Robot    NSString *s;
389*16467b97STreehugger Robot    switch ( c ) {
390*16467b97STreehugger Robot        case 0:
391*16467b97STreehugger Robot            s = @"char=<nil>";
392*16467b97STreehugger Robot            break;
393*16467b97STreehugger Robot        case TokenTypeEOF :
394*16467b97STreehugger Robot        case 65535:
395*16467b97STreehugger Robot            s = @"<EOF>";
396*16467b97STreehugger Robot            break;
397*16467b97STreehugger Robot        case '\n' :
398*16467b97STreehugger Robot            s = @"\\n";
399*16467b97STreehugger Robot            break;
400*16467b97STreehugger Robot        case '\t' :
401*16467b97STreehugger Robot            s = @"\\t";
402*16467b97STreehugger Robot            break;
403*16467b97STreehugger Robot        case '\r' :
404*16467b97STreehugger Robot            s = @"\\r";
405*16467b97STreehugger Robot            break;
406*16467b97STreehugger Robot        default:
407*16467b97STreehugger Robot            s = [NSString stringWithFormat:@"%c", (char)c];
408*16467b97STreehugger Robot            break;
409*16467b97STreehugger Robot    }
410*16467b97STreehugger Robot    return s;
411*16467b97STreehugger Robot}
412*16467b97STreehugger Robot
413*16467b97STreehugger Robot/** Lexers can normally match any char in it's vocabulary after matching
414*16467b97STreehugger Robot *  a token, so do the easy thing and just kill a character and hope
415*16467b97STreehugger Robot *  it all works out.  You can instead use the rule invocation stack
416*16467b97STreehugger Robot *  to do sophisticated error recovery if you are in a fragment rule.
417*16467b97STreehugger Robot */
418*16467b97STreehugger Robot- (void)recover:(RecognitionException *)re
419*16467b97STreehugger Robot{
420*16467b97STreehugger Robot    //System.out.println("consuming char "+(char)input.LA(1)+" during recovery");
421*16467b97STreehugger Robot    //re.printStackTrace();
422*16467b97STreehugger Robot    [input consume];
423*16467b97STreehugger Robot}
424*16467b97STreehugger Robot
425*16467b97STreehugger Robot- (void)traceIn:(NSString *)ruleName Index:(NSInteger)ruleIndex
426*16467b97STreehugger Robot{
427*16467b97STreehugger Robot    NSString *inputSymbol = [NSString stringWithFormat:@"%c line=%d:%d\n", [input LT:1], input.getLine, input.getCharPositionInLine];
428*16467b97STreehugger Robot    [super traceIn:ruleName Index:ruleIndex Object:inputSymbol];
429*16467b97STreehugger Robot}
430*16467b97STreehugger Robot
431*16467b97STreehugger Robot- (void)traceOut:(NSString *)ruleName Index:(NSInteger)ruleIndex
432*16467b97STreehugger Robot{
433*16467b97STreehugger Robot    NSString *inputSymbol = [NSString stringWithFormat:@"%c line=%d:%d\n", [input LT:1], input.getLine, input.getCharPositionInLine];
434*16467b97STreehugger Robot    [super traceOut:ruleName Index:ruleIndex Object:inputSymbol];
435*16467b97STreehugger Robot}
436*16467b97STreehugger Robot
437*16467b97STreehugger Robot@end
438