| // [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 "ANTLRDFA.h" |
| #import <ANTLRToken.h> |
| #import <ANTLRNoViableAltException.h> |
| |
| NSInteger debug = 0; |
| |
| @implementation ANTLRDFA |
| @synthesize recognizer; |
| @synthesize decisionNumber; |
| @synthesize len; |
| |
| - (id) initWithRecognizer:(ANTLRBaseRecognizer *) theRecognizer |
| { |
| if ((self = [super init]) != nil) { |
| recognizer = theRecognizer; |
| [recognizer retain]; |
| debug = 0; |
| } |
| return self; |
| } |
| |
| // using the tables ANTLR generates for the DFA based prediction this method simulates the DFA |
| // and returns the prediction of the alternative to be used. |
| - (NSInteger) predict:(id<ANTLRIntStream>)input |
| { |
| if ( debug > 2 ) { |
| NSLog(@"Enter DFA.predict for decision %d", decisionNumber); |
| } |
| int aMark = [input mark]; |
| int s = 0; |
| @try { |
| while (YES) { |
| if ( debug > 2 ) |
| NSLog(@"DFA %d state %d LA(1)='%c'(%x)", decisionNumber, s, (unichar)[input LA:1], [input LA:1]); |
| NSInteger specialState = special[s]; |
| if (specialState >= 0) { |
| // this state is special in that it has some code associated with it. we cannot do this in a pure DFA so |
| // we signal the caller accordingly. |
| if ( debug > 2 ) { |
| NSLog(@"DFA %d state %d is special state %d", decisionNumber, s, specialState); |
| } |
| s = [self specialStateTransition:specialState Stream:input]; |
| if ( debug > 2 ) { |
| NSLog(@"DFA %d returns from special state %d to %d", decisionNumber, specialState, s); |
| } |
| if (s == -1 ) { |
| [self noViableAlt:s Stream:input]; |
| return 0; |
| } |
| [input consume]; |
| continue; |
| } |
| if (accept[s] >= 1) { // if this is an accepting state return the prediction |
| if ( debug > 2 ) NSLog(@"accept; predict %d from state %d", accept[s], s); |
| return accept[s]; |
| } |
| // based on the lookahead lookup the next transition, consume and do transition |
| // or signal that we have no viable alternative |
| int c = [input LA:1]; |
| if ( (unichar)c >= min[s] && (unichar)c <= max[s]) { |
| int snext = transition[s][c-min[s]]; |
| if (snext < 0) { |
| // was in range but not a normal transition |
| // must check EOT, which is like the else clause. |
| // eot[s]>=0 indicates that an EOT edge goes to another |
| // state. |
| if (eot[s] >= 0) { |
| if ( debug > 2 ) NSLog(@"EOT transition"); |
| s = eot[s]; |
| [input consume]; |
| // TODO: I had this as return accept[eot[s]] |
| // which assumed here that the EOT edge always |
| // went to an accept...faster to do this, but |
| // what about predicated edges coming from EOT |
| // target? |
| continue; |
| } |
| [self noViableAlt:s Stream:input]; |
| return 0; |
| } |
| s = snext; |
| [input consume]; |
| continue; |
| } |
| |
| if (eot[s] >= 0) {// EOT transition? we may still accept the input in the next state |
| if ( debug > 2 ) NSLog(@"EOT transition"); |
| s = eot[s]; |
| [input consume]; |
| continue; |
| } |
| if ( c == ANTLRTokenTypeEOF && eof[s] >= 0) { // we are at EOF and may even accept the input. |
| if ( debug > 2 ) NSLog(@"accept via EOF; predict %d from %d", accept[eof[s]], eof[s]); |
| return accept[eof[s]]; |
| } |
| if ( debug > 2 ) { |
| NSLog(@"no viable alt!\n"); |
| NSLog(@"min[%d] = %d\n", s, min[s]); |
| NSLog(@"max[%d] = %d\n", s, min[s]); |
| NSLog(@"eot[%d] = %d\n", s, min[s]); |
| NSLog(@"eof[%d] = %d\n", s, min[s]); |
| for (NSInteger p = 0; p < self.len; p++) { |
| NSLog(@"%d ", transition[s][p]); |
| } |
| NSLog(@"\n"); |
| } |
| [self noViableAlt:s Stream:input]; |
| return 0; |
| } |
| } |
| @finally { |
| [input rewind:aMark]; |
| } |
| return 0; // silence warning |
| } |
| |
| - (void) noViableAlt:(NSInteger)state Stream:(id<ANTLRIntStream>)anInput |
| { |
| if ([recognizer.state isBacktracking]) { |
| [recognizer.state setFailed:YES]; |
| return; |
| } |
| ANTLRNoViableAltException *nvae = [ANTLRNoViableAltException newException:decisionNumber state:state stream:anInput]; |
| [self error:nvae]; |
| @throw nvae; |
| } |
| |
| - (NSInteger) specialStateTransition:(NSInteger)state Stream:(id<ANTLRIntStream>)anInput |
| { |
| @throw [ANTLRNoViableAltException newException:-1 state:state stream:anInput]; |
| return -1; |
| } |
| |
| - (void) error:(ANTLRNoViableAltException *)nvae |
| { |
| // empty, hook for debugger support |
| } |
| |
| - (NSString *) description |
| { |
| return @"subclass responsibility"; |
| } |
| |
| - (BOOL) evaluateSyntacticPredicate:(SEL)synpredFragment |
| { |
| return [recognizer evaluateSyntacticPredicate:synpredFragment]; |
| } |
| |
| + (void) setIsEmittingDebugInfo:(BOOL) shouldEmitDebugInfo |
| { |
| debug = shouldEmitDebugInfo; |
| } |
| |
| /** Given a String that has a run-length-encoding of some unsigned shorts |
| * like "\1\2\3\9", convert to short[] {2,9,9,9}. We do this to avoid |
| * static short[] which generates so much init code that the class won't |
| * compile. :( |
| */ |
| - (short *) unpackEncodedString:(NSString *)encodedString |
| { |
| // walk first to find how big it is. |
| int size = 0; |
| for (int i=0; i < [encodedString length]; i+=2) { |
| size += [encodedString characterAtIndex:i]; |
| } |
| __strong short *data = (short *)calloc(size, sizeof(short)); |
| int di = 0; |
| for (int i=0; i < [encodedString length]; i+=2) { |
| char n = [encodedString characterAtIndex:i]; |
| char v = [encodedString characterAtIndex:i+1]; |
| // add v n times to data |
| for (int j = 0; j < n; j++) { |
| data[di++] = v; |
| } |
| } |
| return data; |
| } |
| |
| /** Hideous duplication of code, but I need different typed arrays out :( */ |
| - (char *) unpackEncodedStringToUnsignedChars:(NSString *)encodedString |
| { |
| // walk first to find how big it is. |
| int size = 0; |
| for (int i=0; i < [encodedString length]; i+=2) { |
| size += [encodedString characterAtIndex:i]; |
| } |
| __strong short *data = (short *)calloc(size, sizeof(short)); |
| int di = 0; |
| for (int i=0; i < [encodedString length]; i+=2) { |
| char n = [encodedString characterAtIndex:i]; |
| char v = [encodedString characterAtIndex:i+1]; |
| // add v n times to data |
| for (int j = 0; j < n; j++) { |
| data[di++] = v; |
| } |
| } |
| return (char *)data; |
| } |
| |
| - (NSInteger)getDecision |
| { |
| return decisionNumber; |
| } |
| |
| - (void)setDecision:(NSInteger)aDecison |
| { |
| decisionNumber = aDecison; |
| } |
| |
| - (ANTLRBaseRecognizer *)getRecognizer |
| { |
| return recognizer; |
| } |
| |
| - (void)setRecognizer:(ANTLRBaseRecognizer *)aRecognizer |
| { |
| if ( recognizer != aRecognizer ) { |
| if ( recognizer ) [recognizer release]; |
| [aRecognizer retain]; |
| } |
| recognizer = aRecognizer; |
| } |
| |
| - (NSInteger)length |
| { |
| return len; |
| } |
| |
| @synthesize eot; |
| @synthesize eof; |
| @synthesize min; |
| @synthesize max; |
| @synthesize accept; |
| @synthesize special; |
| @synthesize transition; |
| @end |