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 "DFA.h" 28*16467b97STreehugger Robot#import <Token.h> 29*16467b97STreehugger Robot#import <NoViableAltException.h> 30*16467b97STreehugger Robot 31*16467b97STreehugger RobotNSInteger debug = 0; 32*16467b97STreehugger Robot 33*16467b97STreehugger Robot@implementation DFA 34*16467b97STreehugger Robot@synthesize recognizer; 35*16467b97STreehugger Robot@synthesize decisionNumber; 36*16467b97STreehugger Robot@synthesize len; 37*16467b97STreehugger Robot 38*16467b97STreehugger Robot- (id) initWithRecognizer:(BaseRecognizer *) theRecognizer 39*16467b97STreehugger Robot{ 40*16467b97STreehugger Robot if ((self = [super init]) != nil) { 41*16467b97STreehugger Robot recognizer = theRecognizer; 42*16467b97STreehugger Robot [recognizer retain]; 43*16467b97STreehugger Robot debug = 0; 44*16467b97STreehugger Robot } 45*16467b97STreehugger Robot return self; 46*16467b97STreehugger Robot} 47*16467b97STreehugger Robot 48*16467b97STreehugger Robot// using the tables ANTLR generates for the DFA based prediction this method simulates the DFA 49*16467b97STreehugger Robot// and returns the prediction of the alternative to be used. 50*16467b97STreehugger Robot- (NSInteger) predict:(id<IntStream>)input 51*16467b97STreehugger Robot{ 52*16467b97STreehugger Robot if ( debug > 2 ) { 53*16467b97STreehugger Robot NSLog(@"Enter DFA.predict for decision %d", decisionNumber); 54*16467b97STreehugger Robot } 55*16467b97STreehugger Robot int aMark = [input mark]; 56*16467b97STreehugger Robot int s = 0; 57*16467b97STreehugger Robot @try { 58*16467b97STreehugger Robot while (YES) { 59*16467b97STreehugger Robot if ( debug > 2 ) 60*16467b97STreehugger Robot NSLog(@"DFA %d state %d LA(1)='%c'(%x)", decisionNumber, s, (unichar)[input LA:1], [input LA:1]); 61*16467b97STreehugger Robot NSInteger specialState = special[s]; 62*16467b97STreehugger Robot if (specialState >= 0) { 63*16467b97STreehugger Robot // this state is special in that it has some code associated with it. we cannot do this in a pure DFA so 64*16467b97STreehugger Robot // we signal the caller accordingly. 65*16467b97STreehugger Robot if ( debug > 2 ) { 66*16467b97STreehugger Robot NSLog(@"DFA %d state %d is special state %d", decisionNumber, s, specialState); 67*16467b97STreehugger Robot } 68*16467b97STreehugger Robot s = [self specialStateTransition:specialState Stream:input]; 69*16467b97STreehugger Robot if ( debug > 2 ) { 70*16467b97STreehugger Robot NSLog(@"DFA %d returns from special state %d to %d", decisionNumber, specialState, s); 71*16467b97STreehugger Robot } 72*16467b97STreehugger Robot if (s == -1 ) { 73*16467b97STreehugger Robot [self noViableAlt:s Stream:input]; 74*16467b97STreehugger Robot return 0; 75*16467b97STreehugger Robot } 76*16467b97STreehugger Robot [input consume]; 77*16467b97STreehugger Robot continue; 78*16467b97STreehugger Robot } 79*16467b97STreehugger Robot if (accept[s] >= 1) { // if this is an accepting state return the prediction 80*16467b97STreehugger Robot if ( debug > 2 ) NSLog(@"accept; predict %d from state %d", accept[s], s); 81*16467b97STreehugger Robot return accept[s]; 82*16467b97STreehugger Robot } 83*16467b97STreehugger Robot // based on the lookahead lookup the next transition, consume and do transition 84*16467b97STreehugger Robot // or signal that we have no viable alternative 85*16467b97STreehugger Robot NSInteger c = [input LA:1]; 86*16467b97STreehugger Robot if ( (unichar)c >= min[s] && (unichar)c <= max[s]) { 87*16467b97STreehugger Robot int snext = transition[s][c-min[s]]; 88*16467b97STreehugger Robot if (snext < 0) { 89*16467b97STreehugger Robot // was in range but not a normal transition 90*16467b97STreehugger Robot // must check EOT, which is like the else clause. 91*16467b97STreehugger Robot // eot[s]>=0 indicates that an EOT edge goes to another 92*16467b97STreehugger Robot // state. 93*16467b97STreehugger Robot if (eot[s] >= 0) { 94*16467b97STreehugger Robot if ( debug > 2 ) NSLog(@"EOT transition"); 95*16467b97STreehugger Robot s = eot[s]; 96*16467b97STreehugger Robot [input consume]; 97*16467b97STreehugger Robot // TODO: I had this as return accept[eot[s]] 98*16467b97STreehugger Robot // which assumed here that the EOT edge always 99*16467b97STreehugger Robot // went to an accept...faster to do this, but 100*16467b97STreehugger Robot // what about predicated edges coming from EOT 101*16467b97STreehugger Robot // target? 102*16467b97STreehugger Robot continue; 103*16467b97STreehugger Robot } 104*16467b97STreehugger Robot [self noViableAlt:s Stream:input]; 105*16467b97STreehugger Robot return 0; 106*16467b97STreehugger Robot } 107*16467b97STreehugger Robot s = snext; 108*16467b97STreehugger Robot [input consume]; 109*16467b97STreehugger Robot continue; 110*16467b97STreehugger Robot } 111*16467b97STreehugger Robot 112*16467b97STreehugger Robot if (eot[s] >= 0) {// EOT transition? we may still accept the input in the next state 113*16467b97STreehugger Robot if ( debug > 2 ) NSLog(@"EOT transition"); 114*16467b97STreehugger Robot s = eot[s]; 115*16467b97STreehugger Robot [input consume]; 116*16467b97STreehugger Robot continue; 117*16467b97STreehugger Robot } 118*16467b97STreehugger Robot if ( c == TokenTypeEOF && eof[s] >= 0) { // we are at EOF and may even accept the input. 119*16467b97STreehugger Robot if ( debug > 2 ) NSLog(@"accept via EOF; predict %d from %d", accept[eof[s]], eof[s]); 120*16467b97STreehugger Robot return accept[eof[s]]; 121*16467b97STreehugger Robot } 122*16467b97STreehugger Robot if ( debug > 2 ) { 123*16467b97STreehugger Robot NSLog(@"no viable alt!\n"); 124*16467b97STreehugger Robot NSLog(@"min[%d] = %d\n", s, min[s]); 125*16467b97STreehugger Robot NSLog(@"max[%d] = %d\n", s, min[s]); 126*16467b97STreehugger Robot NSLog(@"eot[%d] = %d\n", s, min[s]); 127*16467b97STreehugger Robot NSLog(@"eof[%d] = %d\n", s, min[s]); 128*16467b97STreehugger Robot for (NSInteger p = 0; p < self.len; p++) { 129*16467b97STreehugger Robot NSLog(@"%d ", transition[s][p]); 130*16467b97STreehugger Robot } 131*16467b97STreehugger Robot NSLog(@"\n"); 132*16467b97STreehugger Robot } 133*16467b97STreehugger Robot [self noViableAlt:s Stream:input]; 134*16467b97STreehugger Robot return 0; 135*16467b97STreehugger Robot } 136*16467b97STreehugger Robot } 137*16467b97STreehugger Robot @finally { 138*16467b97STreehugger Robot [input rewind:aMark]; 139*16467b97STreehugger Robot } 140*16467b97STreehugger Robot return 0; // silence warning 141*16467b97STreehugger Robot} 142*16467b97STreehugger Robot 143*16467b97STreehugger Robot- (void) noViableAlt:(NSInteger)state Stream:(id<IntStream>)anInput 144*16467b97STreehugger Robot{ 145*16467b97STreehugger Robot if ([recognizer.state isBacktracking]) { 146*16467b97STreehugger Robot [recognizer.state setFailed:YES]; 147*16467b97STreehugger Robot return; 148*16467b97STreehugger Robot } 149*16467b97STreehugger Robot NoViableAltException *nvae = [NoViableAltException newException:decisionNumber state:state stream:anInput]; 150*16467b97STreehugger Robot [self error:nvae]; 151*16467b97STreehugger Robot @throw nvae; 152*16467b97STreehugger Robot} 153*16467b97STreehugger Robot 154*16467b97STreehugger Robot- (NSInteger) specialStateTransition:(NSInteger)state Stream:(id<IntStream>)anInput 155*16467b97STreehugger Robot{ 156*16467b97STreehugger Robot @throw [NoViableAltException newException:-1 state:state stream:anInput]; 157*16467b97STreehugger Robot return -1; 158*16467b97STreehugger Robot} 159*16467b97STreehugger Robot 160*16467b97STreehugger Robot- (void) error:(NoViableAltException *)nvae 161*16467b97STreehugger Robot{ 162*16467b97STreehugger Robot // empty, hook for debugger support 163*16467b97STreehugger Robot} 164*16467b97STreehugger Robot 165*16467b97STreehugger Robot- (NSString *) description 166*16467b97STreehugger Robot{ 167*16467b97STreehugger Robot return @"subclass responsibility"; 168*16467b97STreehugger Robot} 169*16467b97STreehugger Robot 170*16467b97STreehugger Robot- (BOOL) evaluateSyntacticPredicate:(SEL)synpredFragment 171*16467b97STreehugger Robot{ 172*16467b97STreehugger Robot return [recognizer evaluateSyntacticPredicate:synpredFragment]; 173*16467b97STreehugger Robot} 174*16467b97STreehugger Robot 175*16467b97STreehugger Robot+ (void) setIsEmittingDebugInfo:(BOOL) shouldEmitDebugInfo 176*16467b97STreehugger Robot{ 177*16467b97STreehugger Robot debug = shouldEmitDebugInfo; 178*16467b97STreehugger Robot} 179*16467b97STreehugger Robot 180*16467b97STreehugger Robot/** Given a String that has a run-length-encoding of some unsigned shorts 181*16467b97STreehugger Robot * like "\1\2\3\9", convert to short[] {2,9,9,9}. We do this to avoid 182*16467b97STreehugger Robot * static short[] which generates so much init code that the class won't 183*16467b97STreehugger Robot * compile. :( 184*16467b97STreehugger Robot */ 185*16467b97STreehugger Robot- (NSInteger *) unpackEncodedString:(NSString *)encodedString 186*16467b97STreehugger Robot{ 187*16467b97STreehugger Robot // walk first to find how big it is. 188*16467b97STreehugger Robot int size = 0; 189*16467b97STreehugger Robot for (int i=0; i < [encodedString length]; i+=2) { 190*16467b97STreehugger Robot size += [encodedString characterAtIndex:i]; 191*16467b97STreehugger Robot } 192*16467b97STreehugger Robot __strong NSInteger *data = (NSInteger *)calloc(size, sizeof(NSInteger)); 193*16467b97STreehugger Robot int di = 0; 194*16467b97STreehugger Robot for (int i=0; i < [encodedString length]; i+=2) { 195*16467b97STreehugger Robot char n = [encodedString characterAtIndex:i]; 196*16467b97STreehugger Robot char v = [encodedString characterAtIndex:i+1]; 197*16467b97STreehugger Robot // add v n times to data 198*16467b97STreehugger Robot for (int j = 0; j < n; j++) { 199*16467b97STreehugger Robot data[di++] = v; 200*16467b97STreehugger Robot } 201*16467b97STreehugger Robot } 202*16467b97STreehugger Robot return data; 203*16467b97STreehugger Robot} 204*16467b97STreehugger Robot 205*16467b97STreehugger Robot/** Hideous duplication of code, but I need different typed arrays out :( */ 206*16467b97STreehugger Robot- (short *) unpackEncodedStringToUnsignedChars:(NSString *)encodedString 207*16467b97STreehugger Robot{ 208*16467b97STreehugger Robot // walk first to find how big it is. 209*16467b97STreehugger Robot int size = 0; 210*16467b97STreehugger Robot for (int i=0; i < [encodedString length]; i+=2) { 211*16467b97STreehugger Robot size += [encodedString characterAtIndex:i]; 212*16467b97STreehugger Robot } 213*16467b97STreehugger Robot __strong short *data = (short *)calloc(size, sizeof(short)); 214*16467b97STreehugger Robot int di = 0; 215*16467b97STreehugger Robot for (int i=0; i < [encodedString length]; i+=2) { 216*16467b97STreehugger Robot char n = [encodedString characterAtIndex:i]; 217*16467b97STreehugger Robot char v = [encodedString characterAtIndex:i+1]; 218*16467b97STreehugger Robot // add v n times to data 219*16467b97STreehugger Robot for (int j = 0; j < n; j++) { 220*16467b97STreehugger Robot data[di++] = v; 221*16467b97STreehugger Robot } 222*16467b97STreehugger Robot } 223*16467b97STreehugger Robot return (short *)data; 224*16467b97STreehugger Robot} 225*16467b97STreehugger Robot 226*16467b97STreehugger Robot- (NSInteger)getDecision 227*16467b97STreehugger Robot{ 228*16467b97STreehugger Robot return decisionNumber; 229*16467b97STreehugger Robot} 230*16467b97STreehugger Robot 231*16467b97STreehugger Robot- (void)setDecision:(NSInteger)aDecison 232*16467b97STreehugger Robot{ 233*16467b97STreehugger Robot decisionNumber = aDecison; 234*16467b97STreehugger Robot} 235*16467b97STreehugger Robot 236*16467b97STreehugger Robot- (BaseRecognizer *)getRecognizer 237*16467b97STreehugger Robot{ 238*16467b97STreehugger Robot return recognizer; 239*16467b97STreehugger Robot} 240*16467b97STreehugger Robot 241*16467b97STreehugger Robot- (void)setRecognizer:(BaseRecognizer *)aRecognizer 242*16467b97STreehugger Robot{ 243*16467b97STreehugger Robot if ( recognizer != aRecognizer ) { 244*16467b97STreehugger Robot if ( recognizer ) [recognizer release]; 245*16467b97STreehugger Robot [aRecognizer retain]; 246*16467b97STreehugger Robot } 247*16467b97STreehugger Robot recognizer = aRecognizer; 248*16467b97STreehugger Robot} 249*16467b97STreehugger Robot 250*16467b97STreehugger Robot- (NSInteger)length 251*16467b97STreehugger Robot{ 252*16467b97STreehugger Robot return len; 253*16467b97STreehugger Robot} 254*16467b97STreehugger Robot 255*16467b97STreehugger Robot@synthesize eot; 256*16467b97STreehugger Robot@synthesize eof; 257*16467b97STreehugger Robot@synthesize min; 258*16467b97STreehugger Robot@synthesize max; 259*16467b97STreehugger Robot@synthesize accept; 260*16467b97STreehugger Robot@synthesize special; 261*16467b97STreehugger Robot@synthesize transition; 262*16467b97STreehugger Robot@end 263