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