Home | History | Annotate | Download | only in runtime
      1 package org.antlr.runtime {
      2 	
      3 	/** A DFA implemented as a set of transition tables.
      4 	 *
      5 	 *  Any state that has a semantic predicate edge is special; those states
      6 	 *  are generated with if-then-else structures in a specialStateTransition()
      7 	 *  which is generated by cyclicDFA template.
      8 	 *
      9 	 *  There are at most 32767 states (16-bit signed short).
     10 	 *  Could get away with byte sometimes but would have to generate different
     11 	 *  types and the simulation code too.  For a point of reference, the Java
     12 	 *  lexer's Tokens rule DFA has 326 states roughly.
     13 	 */
     14 	public class DFA {
     15 		protected var eot:Array; // short[]
     16 		protected var eof:Array; // short[]
     17 		protected var min:Array; // char[]
     18 	    protected var max:Array; // char[]
     19 	    protected var accept:Array; //short[]
     20 	    protected var special:Array; // short[]
     21 	    protected var transition:Array; // short[][]
     22 	
     23 		protected var decisionNumber:int;
     24 	
     25 		/** Which recognizer encloses this DFA?  Needed to check backtracking */
     26 		protected var recognizer:BaseRecognizer;
     27 	
     28 		private var _description:String;
     29 		
     30 		public static const debug:Boolean = false;
     31 
     32 		public function DFA(recognizer:BaseRecognizer, decisionNumber:int, description:String,
     33 							eot:Array, eof:Array, min:Array, max:Array, accept:Array, special:Array, transition:Array,
     34 							specialStateTransitionFunction:Function = null, errorFunction:Function = null) {			
     35 			this.recognizer = recognizer;
     36 			this.decisionNumber = decisionNumber;
     37 			this._description = description;
     38 			
     39 			this.eot = eot;
     40 			this.eof = eof;
     41 			this.min = min;
     42 			this.max = max;
     43 			this.accept = accept;
     44 			this.special = special;
     45             this.transition = transition;
     46 						
     47 			if (specialStateTransitionFunction != null) {
     48 				specialStateTransition = specialStateTransitionFunction;
     49 			}
     50 			
     51 			if (errorFunction != null) {
     52 				error = errorFunction;
     53 			}
     54 						
     55 		}
     56 		/** From the input stream, predict what alternative will succeed
     57 		 *  using this DFA (representing the covering regular approximation
     58 		 *  to the underlying CFL).  Return an alternative number 1..n.  Throw
     59 		 *  an exception upon error.
     60 		 */
     61 		public function predict(input:IntStream):int	{
     62     		if ( debug ) {
     63     			trace("Enter DFA.predict for decision "+decisionNumber);
     64     		}
     65 
     66 			var mark:int = input.mark(); // remember where decision started in input
     67 			var s:int = 0; // we always start at s0
     68 			try {
     69 				while ( true ) {
     70 					if ( debug ) trace("DFA "+decisionNumber+" state "+s+" LA(1)="+String.fromCharCode(input.LA(1))+"("+input.LA(1)+
     71 													"), index="+input.index);
     72 					var specialState:int = special[s];
     73 					if ( specialState>=0 ) {
     74 						if ( debug ) {
     75 						    trace("DFA "+decisionNumber+
     76 							" state "+s+" is special state "+specialState);
     77 						}
     78 						s = specialStateTransition(this, specialState,input);
     79 						if ( debug ) {
     80 						    trace("DFA "+decisionNumber+
     81 							" returns from special state "+specialState+" to "+s);
     82 					    }
     83 						if ( s==-1 ) {
     84 						    noViableAlt(s,input);
     85 						    return 0;
     86 					    }
     87 						input.consume();
     88 						continue;
     89 					}
     90 					if ( accept[s] >= 1 ) {
     91 						if ( debug ) trace("accept; predict "+accept[s]+" from state "+s);
     92 						return accept[s];
     93 					}
     94 					// look for a normal char transition
     95 					var c:int = input.LA(1); // -1 == \uFFFF, all tokens fit in 65000 space
     96 					if (c>=min[s] && c<=max[s]) {
     97 						var snext:int = transition[s][c-min[s]]; // move to next state
     98 						if ( snext < 0 ) {
     99 							// was in range but not a normal transition
    100 							// must check EOT, which is like the else clause.
    101 							// eot[s]>=0 indicates that an EOT edge goes to another
    102 							// state.
    103 							if ( eot[s]>=0 ) {  // EOT Transition to accept state?
    104 								if ( debug ) trace("EOT transition");
    105 								s = eot[s];
    106 								input.consume();
    107 								// TODO: I had this as return accept[eot[s]]
    108 								// which assumed here that the EOT edge always
    109 								// went to an accept...faster to do this, but
    110 								// what about predicated edges coming from EOT
    111 								// target?
    112 								continue;
    113 							}
    114 							noViableAlt(s,input);
    115 							return 0;
    116 						}
    117 						s = snext;
    118 						input.consume();
    119 						continue;
    120 					}
    121 					if ( eot[s]>=0 ) {  // EOT Transition?
    122 						if ( debug ) trace("EOT transition");
    123 						s = eot[s];
    124 						input.consume();
    125 						continue;
    126 					}
    127 					if ( c==TokenConstants.EOF && eof[s]>=0 ) {  // EOF Transition to accept state?
    128 						if ( debug ) trace("accept via EOF; predict "+accept[eof[s]]+" from "+eof[s]);
    129 						return accept[eof[s]];
    130 					}
    131 					// not in range and not EOF/EOT, must be invalid symbol
    132 					if ( debug ) {
    133 						trace("min["+s+"]="+min[s]);
    134 						trace("max["+s+"]="+max[s]);
    135 						trace("eot["+s+"]="+eot[s]);
    136 						trace("eof["+s+"]="+eof[s]);
    137 						for (var p:int=0; p<transition[s].length; p++) {
    138 							trace(transition[s][p]+" ");
    139 						}
    140 						trace();
    141 					}
    142 					noViableAlt(s,input);
    143 					return 0;
    144 				}
    145 			}
    146 			finally {
    147 				input.rewindTo(mark);
    148 			}
    149 			// not reached -- added due to bug in Flex compiler reachability analysis of while loop with no breaks
    150 			return -1;
    151 		}
    152 	
    153 		protected function noViableAlt(s:int, input:IntStream):void {
    154 			if (recognizer.state.backtracking>0) {
    155 				recognizer.state.failed=true;
    156 				return;
    157 			}
    158 			var nvae:NoViableAltException =
    159 				new NoViableAltException(description,
    160 										 decisionNumber,
    161 										 s,
    162 										 input);
    163 			error(nvae);
    164 			throw nvae;
    165 		}
    166 	
    167 		/** A hook for debugging interface */
    168 		public var error:Function = function(nvae:NoViableAltException):NoViableAltException { return nvae; }
    169 	
    170 		public var specialStateTransition:Function = function(dfa:DFA, s:int, input:IntStream):int {
    171 			return -1;
    172 		}
    173 	
    174 		public function get description():String {
    175 			return _description;	
    176 		}
    177 	
    178 		/** Given a String that has a run-length-encoding of some unsigned shorts
    179 		 *  like "\1\2\3\9", convert to short[] {2,9,9,9}.  We do this to avoid
    180 		 *  static short[] which generates so much init code that the class won't
    181 		 *  compile. :(
    182 		 */
    183 		public static function unpackEncodedString(encodedString:String, unsigned:Boolean = false):Array {
    184 			// walk first to find how big it is.
    185 			/* Don't pre-allocate
    186 			var size:int = 0;
    187 			for (var i:int=0; i<encodedString.length; i+=2) {
    188 				size += encodedString.charCodeAt(i);
    189 			}
    190 			*/
    191 			var data:Array = new Array();
    192 			var di:int = 0;
    193 			for (var i:int=0; i<encodedString.length; i+=2) {
    194 				var n:int = encodedString.charCodeAt(i);
    195 				if (n > 0x8000) {
    196 				    // need to read another byte
    197 				    i++;
    198 				    var lowBits:int = encodedString.charCodeAt(i);
    199 				    n &= 0xff;
    200 				    n <<= 8;
    201 				    n |= lowBits;
    202 				}
    203 				var v:int = encodedString.charCodeAt(i+1);
    204 				if (v > 0x8000) {
    205 				    // need to read another byte
    206 				    i++;
    207 				    lowBits = encodedString.charCodeAt(i);
    208 				    v &= 0xff;
    209 				    v <<= 8;
    210 				    v |= lowBits;
    211 				}
    212 				if (!unsigned && v > 0x7fff) {
    213 				    v = -(0xffff - v + 1);
    214 				}
    215 				// add v n times to data
    216 				for (var j:int=1; j<=n; j++) {
    217 					data[di++] = v;
    218 				}
    219 			}
    220 			return data;
    221 		}
    222 	
    223 	}
    224 
    225 }