• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * [The "BSD licence"]
3  * Copyright (c) 2005-2008 Terence Parr
4  * All rights reserved.
5  *
6  * Conversion to C#:
7  * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc.
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 
33 namespace Antlr.Runtime
34 {
35     using ArgumentNullException = System.ArgumentNullException;
36     using ConditionalAttribute = System.Diagnostics.ConditionalAttribute;
37     using Console = System.Console;
38     using IDebugEventListener = Antlr.Runtime.Debug.IDebugEventListener;
39 
SpecialStateTransitionHandler( DFA dfa, int s, IIntStream input )40     public delegate int SpecialStateTransitionHandler( DFA dfa, int s, IIntStream input );
41 
42     /** <summary>A DFA implemented as a set of transition tables.</summary>
43      *
44      *  <remarks>
45      *  Any state that has a semantic predicate edge is special; those states
46      *  are generated with if-then-else structures in a specialStateTransition()
47      *  which is generated by cyclicDFA template.
48      *
49      *  There are at most 32767 states (16-bit signed short).
50      *  Could get away with byte sometimes but would have to generate different
51      *  types and the simulation code too.  For a point of reference, the Java
52      *  lexer's Tokens rule DFA has 326 states roughly.
53      *  </remarks>
54      */
55     public class DFA
56     {
57         protected short[] eot;
58         protected short[] eof;
59         protected char[] min;
60         protected char[] max;
61         protected short[] accept;
62         protected short[] special;
63         protected short[][] transition;
64 
65         protected int decisionNumber;
66 
67         /** <summary>Which recognizer encloses this DFA?  Needed to check backtracking</summary> */
68         protected BaseRecognizer recognizer;
69 
70         public bool debug = false;
71 
DFA()72         public DFA()
73             : this(SpecialStateTransitionDefault)
74         {
75         }
76 
DFA( SpecialStateTransitionHandler specialStateTransition )77         public DFA( SpecialStateTransitionHandler specialStateTransition )
78         {
79             this.SpecialStateTransition = specialStateTransition ?? SpecialStateTransitionDefault;
80         }
81 
82         public virtual string Description
83         {
84             get
85             {
86                 return "n/a";
87             }
88         }
89 
90         /** <summary>
91          *  From the input stream, predict what alternative will succeed
92          *  using this DFA (representing the covering regular approximation
93          *  to the underlying CFL).  Return an alternative number 1..n.  Throw
94          *  an exception upon error.
95          *  </summary>
96          */
Predict( IIntStream input )97         public virtual int Predict( IIntStream input )
98         {
99             if (input == null)
100                 throw new ArgumentNullException("input");
101 
102             DfaDebugMessage("Enter DFA.Predict for decision {0}", decisionNumber);
103 
104             int mark = input.Mark(); // remember where decision started in input
105             int s = 0; // we always start at s0
106             try
107             {
108                 while (true)
109                 {
110                     DfaDebugMessage("DFA {0} state {1} LA(1)={2}({3}), index={4}", decisionNumber, s, (char)input.LA(1), input.LA(1), input.Index);
111 
112                     int specialState = special[s];
113                     if ( specialState >= 0 )
114                     {
115                         DfaDebugMessage("DFA {0} state {1} is special state {2}", decisionNumber, s, specialState);
116 
117                         s = SpecialStateTransition( this, specialState, input );
118 
119                         DfaDebugMessage("DFA {0} returns from special state {1} to {2}", decisionNumber, specialState, s);
120 
121                         if ( s == -1 )
122                         {
123                             NoViableAlt( s, input );
124                             return 0;
125                         }
126 
127                         input.Consume();
128                         continue;
129                     }
130 
131                     if ( accept[s] >= 1 )
132                     {
133                         DfaDebugMessage("accept; predict {0} from state {1}", accept[s], s);
134                         return accept[s];
135                     }
136 
137                     // look for a normal char transition
138                     char c = (char)input.LA( 1 ); // -1 == \uFFFF, all tokens fit in 65000 space
139                     if ( c >= min[s] && c <= max[s] )
140                     {
141                         int snext = transition[s][c - min[s]]; // move to next state
142                         if ( snext < 0 )
143                         {
144                             // was in range but not a normal transition
145                             // must check EOT, which is like the else clause.
146                             // eot[s]>=0 indicates that an EOT edge goes to another
147                             // state.
148                             if ( eot[s] >= 0 )
149                             {
150                                 // EOT Transition to accept state?
151                                 DfaDebugMessage("EOT transition");
152                                 s = eot[s];
153                                 input.Consume();
154                                 // TODO: I had this as return accept[eot[s]]
155                                 // which assumed here that the EOT edge always
156                                 // went to an accept...faster to do this, but
157                                 // what about predicated edges coming from EOT
158                                 // target?
159                                 continue;
160                             }
161 
162                             NoViableAlt( s, input );
163                             return 0;
164                         }
165 
166                         s = snext;
167                         input.Consume();
168                         continue;
169                     }
170 
171                     if ( eot[s] >= 0 )
172                     {
173                         // EOT Transition?
174                         DfaDebugMessage("EOT transition");
175                         s = eot[s];
176                         input.Consume();
177                         continue;
178                     }
179 
180                     if ( c == unchecked( (char)TokenTypes.EndOfFile ) && eof[s] >= 0 )
181                     {
182                         // EOF Transition to accept state?
183                         DfaDebugMessage("accept via EOF; predict {0} from {1}", accept[eof[s]], eof[s]);
184                         return accept[eof[s]];
185                     }
186 
187                     // not in range and not EOF/EOT, must be invalid symbol
188                     DfaDebugInvalidSymbol(s);
189 
190                     NoViableAlt( s, input );
191                     return 0;
192                 }
193             }
194             finally
195             {
196                 input.Rewind( mark );
197             }
198         }
199 
200         [Conditional("DEBUG_DFA")]
DfaDebugMessage(string format, params object[] args)201         private void DfaDebugMessage(string format, params object[] args)
202         {
203             Console.Error.WriteLine(format, args);
204         }
205 
206         [Conditional("DEBUG_DFA")]
DfaDebugInvalidSymbol(int s)207         private void DfaDebugInvalidSymbol(int s)
208         {
209             Console.Error.WriteLine("min[{0}]={1}", s, min[s]);
210             Console.Error.WriteLine("max[{0}]={1}", s, max[s]);
211             Console.Error.WriteLine("eot[{0}]={1}", s, eot[s]);
212             Console.Error.WriteLine("eof[{0}]={1}", s, eof[s]);
213 
214             for (int p = 0; p < transition[s].Length; p++)
215                 Console.Error.Write(transition[s][p] + " ");
216 
217             Console.Error.WriteLine();
218         }
219 
NoViableAlt( int s, IIntStream input )220         protected virtual void NoViableAlt( int s, IIntStream input )
221         {
222             if ( recognizer.state.backtracking > 0 )
223             {
224                 recognizer.state.failed = true;
225                 return;
226             }
227             NoViableAltException nvae =
228                 new NoViableAltException( Description,
229                                          decisionNumber,
230                                          s,
231                                          input );
232             Error( nvae );
233             throw nvae;
234         }
235 
236         /** <summary>A hook for debugging interface</summary> */
Error( NoViableAltException nvae )237         public virtual void Error( NoViableAltException nvae )
238         {
239         }
240 
241         public SpecialStateTransitionHandler SpecialStateTransition
242         {
243             get;
244             private set;
245         }
246         //public virtual int specialStateTransition( int s, IntStream input )
247         //{
248         //    return -1;
249         //}
250 
SpecialStateTransitionDefault( DFA dfa, int s, IIntStream input )251         static int SpecialStateTransitionDefault( DFA dfa, int s, IIntStream input )
252         {
253             return -1;
254         }
255 
256         /** <summary>
257          *  Given a String that has a run-length-encoding of some unsigned shorts
258          *  like "\1\2\3\9", convert to short[] {2,9,9,9}.  We do this to avoid
259          *  static short[] which generates so much init code that the class won't
260          *  compile. :(
261          *  </summary>
262          */
UnpackEncodedString( string encodedString )263         public static short[] UnpackEncodedString( string encodedString )
264         {
265             // walk first to find how big it is.
266             int size = 0;
267             for ( int i = 0; i < encodedString.Length; i += 2 )
268             {
269                 size += encodedString[i];
270             }
271             short[] data = new short[size];
272             int di = 0;
273             for ( int i = 0; i < encodedString.Length; i += 2 )
274             {
275                 char n = encodedString[i];
276                 char v = encodedString[i + 1];
277                 // add v n times to data
278                 for ( int j = 1; j <= n; j++ )
279                 {
280                     data[di++] = (short)v;
281                 }
282             }
283             return data;
284         }
285 
286         /** <summary>Hideous duplication of code, but I need different typed arrays out :(</summary> */
UnpackEncodedStringToUnsignedChars( string encodedString )287         public static char[] UnpackEncodedStringToUnsignedChars( string encodedString )
288         {
289             // walk first to find how big it is.
290             int size = 0;
291             for ( int i = 0; i < encodedString.Length; i += 2 )
292             {
293                 size += encodedString[i];
294             }
295             char[] data = new char[size];
296             int di = 0;
297             for ( int i = 0; i < encodedString.Length; i += 2 )
298             {
299                 char n = encodedString[i];
300                 char v = encodedString[i + 1];
301                 // add v n times to data
302                 for ( int j = 1; j <= n; j++ )
303                 {
304                     data[di++] = v;
305                 }
306             }
307             return data;
308         }
309 
310         [Conditional("ANTLR_DEBUG")]
DebugRecognitionException(RecognitionException ex)311         protected virtual void DebugRecognitionException(RecognitionException ex)
312         {
313             IDebugEventListener dbg = recognizer.DebugListener;
314             if (dbg != null)
315                 dbg.RecognitionException(ex);
316         }
317     }
318 }
319