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