xref: /aosp_15_r20/external/antlr/runtime/ObjC/Framework/DFA.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 "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