protected virtual void OptimizeExitBranches(DFAState d) { int sI = d.stateNumber; if (_visited.Contains(sI)) { return; // already visited } _visited.Add(sI); int nAlts = d.dfa.NumberOfAlts; for (int i = 0; i < d.NumberOfTransitions; i++) { Transition edge = (Transition)d.Transition(i); DFAState edgeTarget = ((DFAState)edge.target); /* * [email protected](d.stateNumber+"-"+ * edge.label.toString(d.dfa.nfa.grammar)+"->"+ * edgeTarget.stateNumber); */ // if target is an accept state and that alt is the exit alt if (edgeTarget.IsAcceptState && edgeTarget.GetUniquelyPredictedAlt() == nAlts) { /* * [email protected]("ignoring transition "+i+" to max alt "+ * d.dfa.getNumberOfAlts()); */ d.RemoveTransition(i); i--; // back up one so that i++ of loop iteration stays within bounds } OptimizeExitBranches(edgeTarget); } }
// S U P P O R T /** Given a start state and a target state, return true if start can reach * target state. Also, compute the set of DFA states * that are on a path from start to target; return in states parameter. */ protected virtual bool ReachesState(DFAState startState, DFAState targetState, HashSet <object> states) { if (startState == targetState) { states.Add(targetState); //[email protected]("found target DFA state "+targetState.getStateNumber()); _stateReachable[startState.stateNumber] = REACHABLE_YES; return(true); } DFAState s = startState; // avoid infinite loops _stateReachable[s.stateNumber] = REACHABLE_BUSY; // look for a path to targetState among transitions for this state // stop when you find the first one; I'm pretty sure there is // at most one path to any DFA state with conflicting predictions for (int i = 0; i < s.NumberOfTransitions; i++) { Transition t = s.Transition(i); DFAState edgeTarget = (DFAState)t.target; int targetStatus; //= stateReachable.get( edgeTarget.stateNumber ); if (_stateReachable.TryGetValue(edgeTarget.stateNumber, out targetStatus)) { if (targetStatus == REACHABLE_BUSY) { // avoid cycles; they say nothing continue; } if (targetStatus == REACHABLE_YES) { // return success! _stateReachable[s.stateNumber] = REACHABLE_YES; return(true); } if (targetStatus == REACHABLE_NO) { // try another transition continue; } } // if null, target must be REACHABLE_UNKNOWN (i.e., unvisited) if (ReachesState(edgeTarget, targetState, states)) { states.Add(s); _stateReachable[s.stateNumber] = REACHABLE_YES; return(true); } } _stateReachable[s.stateNumber] = REACHABLE_NO; return(false); // no path to targetState found. }
protected virtual void OptimizeEOTBranches(DFAState d) { int sI = d.stateNumber; if (_visited.Contains(sI)) { return; // already visited } _visited.Add(sI); for (int i = 0; i < d.NumberOfTransitions; i++) { Transition edge = (Transition)d.Transition(i); DFAState edgeTarget = ((DFAState)edge.target); /* * [email protected](d.stateNumber+"-"+ * edge.label.toString(d.dfa.nfa.grammar)+"->"+ * edgeTarget.stateNumber); */ // if only one edge coming out, it is EOT, and target is accept prune if (PRUNE_TOKENS_RULE_SUPERFLUOUS_EOT_EDGES && edgeTarget.IsAcceptState && d.NumberOfTransitions == 1 && edge.label.IsAtom && edge.label.Atom == Label.EOT) { //[email protected]("state "+d+" can be pruned"); // remove the superfluous EOT edge d.RemoveTransition(i); d.IsAcceptState = true; // make it an accept state // force it to uniquely predict the originally predicted state d.cachedUniquelyPredicatedAlt = edgeTarget.GetUniquelyPredictedAlt(); i--; // back up one so that i++ of loop iteration stays within bounds } OptimizeEOTBranches(edgeTarget); } }
/** Do a depth-first walk of the state machine graph and * fill a DOT description template. Keep filling the * states and edges attributes. */ protected virtual void WalkCreatingDFADOT( StringTemplate dot, DFAState s ) { if ( markedStates.Contains( s.stateNumber ) ) { return; // already visited this node } markedStates.Add( s.stateNumber ); // mark this node as completed. // first add this node StringTemplate st; if ( s.IsAcceptState ) { st = stlib.GetInstanceOf( Path.Combine( dfaTemplateDirectoryName, "stopstate" ) ); } else { st = stlib.GetInstanceOf( Path.Combine( dfaTemplateDirectoryName, "state" ) ); } st.SetAttribute( "name", GetStateLabel( s ) ); dot.SetAttribute( "states", st ); // make a DOT edge for each transition for ( int i = 0; i < s.NumberOfTransitions; i++ ) { Transition edge = (Transition)s.Transition( i ); //Console.Out.WriteLine( "dfa " + s.dfa.decisionNumber + " edge from s" // + s.stateNumber + " [" + i + "] of " + s.NumberOfTransitions ); if ( StripNonreducedStates ) { if ( edge.target is DFAState && ( (DFAState)edge.target ).AcceptStateReachable != DFA.REACHABLE_YES ) { continue; // don't generate nodes for terminal states } } st = stlib.GetInstanceOf( Path.Combine( dfaTemplateDirectoryName, "edge" ) ); st.SetAttribute( "label", GetEdgeLabel( edge ) ); st.SetAttribute( "src", GetStateLabel( s ) ); st.SetAttribute( "target", GetStateLabel( edge.target ) ); st.SetAttribute( "arrowhead", arrowhead ); dot.SetAttribute( "edges", st ); WalkCreatingDFADOT( dot, (DFAState)edge.target ); // keep walkin' } }
protected virtual void OptimizeExitBranches( DFAState d ) { int sI = d.stateNumber; if ( _visited.Contains( sI ) ) { return; // already visited } _visited.Add( sI ); int nAlts = d.dfa.NumberOfAlts; for ( int i = 0; i < d.NumberOfTransitions; i++ ) { Transition edge = (Transition)d.Transition( i ); DFAState edgeTarget = ( (DFAState)edge.target ); /* [email protected](d.stateNumber+"-"+ edge.label.toString(d.dfa.nfa.grammar)+"->"+ edgeTarget.stateNumber); */ // if target is an accept state and that alt is the exit alt if ( edgeTarget.IsAcceptState && edgeTarget.GetUniquelyPredictedAlt() == nAlts ) { /* [email protected]("ignoring transition "+i+" to max alt "+ d.dfa.getNumberOfAlts()); */ d.RemoveTransition( i ); i--; // back up one so that i++ of loop iteration stays within bounds } OptimizeExitBranches( edgeTarget ); } }
protected virtual void OptimizeEOTBranches( DFAState d ) { int sI = d.stateNumber; if ( _visited.Contains( sI ) ) { return; // already visited } _visited.Add( sI ); for ( int i = 0; i < d.NumberOfTransitions; i++ ) { Transition edge = (Transition)d.Transition( i ); DFAState edgeTarget = ( (DFAState)edge.target ); /* [email protected](d.stateNumber+"-"+ edge.label.toString(d.dfa.nfa.grammar)+"->"+ edgeTarget.stateNumber); */ // if only one edge coming out, it is EOT, and target is accept prune if ( PRUNE_TOKENS_RULE_SUPERFLUOUS_EOT_EDGES && edgeTarget.IsAcceptState && d.NumberOfTransitions == 1 && edge.label.IsAtom && edge.label.Atom == Label.EOT ) { //[email protected]("state "+d+" can be pruned"); // remove the superfluous EOT edge d.RemoveTransition( i ); d.IsAcceptState = true; // make it an accept state // force it to uniquely predict the originally predicted state d.cachedUniquelyPredicatedAlt = edgeTarget.GetUniquelyPredictedAlt(); i--; // back up one so that i++ of loop iteration stays within bounds } OptimizeEOTBranches( edgeTarget ); } }
/** A special state is huge (too big for state tables) or has a predicated * edge. Generate a simple if-then-else. Cannot be an accept state as * they have no emanating edges. Don't worry about switch vs if-then-else * because if you get here, the state is super complicated and needs an * if-then-else. This is used by the new DFA scheme created June 2006. */ public virtual StringTemplate GenerateSpecialState( DFAState s ) { StringTemplate stateST; stateST = templates.GetInstanceOf( "cyclicDFAState" ); stateST.SetAttribute( "needErrorClause", true ); stateST.SetAttribute( "semPredState", s.IsResolvedWithPredicates ); stateST.SetAttribute( "stateNumber", s.stateNumber ); stateST.SetAttribute( "decisionNumber", s.dfa.decisionNumber ); bool foundGatedPred = false; StringTemplate eotST = null; for ( int i = 0; i < s.NumberOfTransitions; i++ ) { Transition edge = (Transition)s.Transition( i ); StringTemplate edgeST; if ( edge.label.Atom == Label.EOT ) { // this is the default clause; has to held until last edgeST = templates.GetInstanceOf( "eotDFAEdge" ); stateST.RemoveAttribute( "needErrorClause" ); eotST = edgeST; } else { edgeST = templates.GetInstanceOf( "cyclicDFAEdge" ); StringTemplate exprST = GenLabelExpr( templates, edge, 1 ); edgeST.SetAttribute( "labelExpr", exprST ); } edgeST.SetAttribute( "edgeNumber", i + 1 ); edgeST.SetAttribute( "targetStateNumber", edge.target.stateNumber ); // stick in any gated predicates for any edge if not already a pred if ( !edge.label.IsSemanticPredicate ) { DFAState t = (DFAState)edge.target; SemanticContext preds = t.GetGatedPredicatesInNFAConfigurations(); if ( preds != null ) { foundGatedPred = true; StringTemplate predST = preds.GenExpr( this, Templates, t.dfa ); edgeST.SetAttribute( "predicates", predST.ToString() ); } } if ( edge.label.Atom != Label.EOT ) { stateST.SetAttribute( "edges", edgeST ); } } if ( foundGatedPred ) { // state has >= 1 edge with a gated pred (syn or sem) // must rewind input first, set flag. stateST.SetAttribute( "semPredState", foundGatedPred ); } if ( eotST != null ) { stateST.SetAttribute( "edges", eotST ); } return stateST; }
/** You can generate a switch rather than if-then-else for a DFA state * if there are no semantic predicates and the number of edge label * values is small enough; e.g., don't generate a switch for a state * containing an edge label such as 20..52330 (the resulting byte codes * would overflow the method 65k limit probably). */ protected internal virtual bool CanGenerateSwitch( DFAState s ) { if ( !GenerateSwitchesWhenPossible ) { return false; } int size = 0; for ( int i = 0; i < s.NumberOfTransitions; i++ ) { Transition edge = (Transition)s.Transition( i ); if ( edge.label.IsSemanticPredicate ) { return false; } // can't do a switch if the edges are going to require predicates if ( edge.label.Atom == Label.EOT ) { int EOTPredicts = ( (DFAState)edge.target ).GetUniquelyPredictedAlt(); if ( EOTPredicts == NFA.INVALID_ALT_NUMBER ) { // EOT target has to be a predicate then; no unique alt return false; } } // if target is a state with gated preds, we need to use preds on // this edge then to reach it. if ( ( (DFAState)edge.target ).GetGatedPredicatesInNFAConfigurations() != null ) { return false; } size += edge.label.Set.Count; } if ( s.NumberOfTransitions < MinSwitchAlts || size > MaxSwitchCaseLabels ) { return false; } return true; }
protected virtual StringTemplate WalkFixedDFAGeneratingStateMachine( StringTemplateGroup templates, DFA dfa, DFAState s, int k ) { //System.Console.Out.WriteLine( "walk " + s.stateNumber + " in dfa for decision " + dfa.decisionNumber ); if ( s.IsAcceptState ) { StringTemplate dfaST2 = templates.GetInstanceOf( "dfaAcceptState" ); dfaST2.SetAttribute( "alt", s.GetUniquelyPredictedAlt() ); return dfaST2; } // the default templates for generating a state and its edges // can be an if-then-else structure or a switch string dfaStateName = "dfaState"; string dfaLoopbackStateName = "dfaLoopbackState"; string dfaOptionalBlockStateName = "dfaOptionalBlockState"; string dfaEdgeName = "dfaEdge"; if ( parentGenerator.CanGenerateSwitch( s ) ) { dfaStateName = "dfaStateSwitch"; dfaLoopbackStateName = "dfaLoopbackStateSwitch"; dfaOptionalBlockStateName = "dfaOptionalBlockStateSwitch"; dfaEdgeName = "dfaEdgeSwitch"; } StringTemplate dfaST = templates.GetInstanceOf( dfaStateName ); if ( dfa.NFADecisionStartState.decisionStateType == NFAState.LOOPBACK ) { dfaST = templates.GetInstanceOf( dfaLoopbackStateName ); } else if ( dfa.NFADecisionStartState.decisionStateType == NFAState.OPTIONAL_BLOCK_START ) { dfaST = templates.GetInstanceOf( dfaOptionalBlockStateName ); } dfaST.SetAttribute( "k", k ); dfaST.SetAttribute( "stateNumber", s.stateNumber ); dfaST.SetAttribute( "semPredState", s.IsResolvedWithPredicates ); /* string description = dfa.getNFADecisionStartState().Description; description = parentGenerator.target.getTargetStringLiteralFromString( description ); //System.Console.Out.WriteLine( "DFA: " + description + " associated with AST " + dfa.getNFADecisionStartState() ); if ( description != null ) { dfaST.SetAttribute( "description", description ); } */ int EOTPredicts = NFA.INVALID_ALT_NUMBER; DFAState EOTTarget = null; //System.Console.Out.WriteLine( "DFA state " + s.stateNumber ); for ( int i = 0; i < s.NumberOfTransitions; i++ ) { Transition edge = (Transition)s.Transition( i ); //System.Console.Out.WriteLine( "edge " + s.stateNumber + "-" + edge.label.ToString() + "->" + edge.target.stateNumber ); if ( edge.label.Atom == Label.EOT ) { // don't generate a real edge for EOT; track alt EOT predicts // generate that prediction in the else clause as default case EOTTarget = (DFAState)edge.target; EOTPredicts = EOTTarget.GetUniquelyPredictedAlt(); /* System.Console.Out.WriteLine("DFA s"+s.stateNumber+" EOT goes to s"+ edge.target.stateNumber+" predicates alt "+ EOTPredicts); */ continue; } StringTemplate edgeST = templates.GetInstanceOf( dfaEdgeName ); // If the template wants all the label values delineated, do that if ( edgeST.GetFormalArgument( "labels" ) != null ) { List<string> labels = edge.Label.Set.Select( value => parentGenerator.GetTokenTypeAsTargetLabel( value ) ).ToList(); edgeST.SetAttribute( "labels", labels ); } else { // else create an expression to evaluate (the general case) edgeST.SetAttribute( "labelExpr", parentGenerator.GenLabelExpr( templates, edge, k ) ); } // stick in any gated predicates for any edge if not already a pred if ( !edge.label.IsSemanticPredicate ) { DFAState target = (DFAState)edge.target; SemanticContext preds = target.GetGatedPredicatesInNFAConfigurations(); if ( preds != null ) { //System.Console.Out.WriteLine( "preds=" + target.getGatedPredicatesInNFAConfigurations() ); StringTemplate predST = preds.GenExpr( parentGenerator, parentGenerator.Templates, dfa ); edgeST.SetAttribute( "predicates", predST ); } } StringTemplate targetST = WalkFixedDFAGeneratingStateMachine( templates, dfa, (DFAState)edge.target, k + 1 ); edgeST.SetAttribute( "targetState", targetST ); dfaST.SetAttribute( "edges", edgeST ); //System.Console.Out.WriteLine( "back to DFA " + dfa.decisionNumber + "." + s.stateNumber ); } // HANDLE EOT EDGE if ( EOTPredicts != NFA.INVALID_ALT_NUMBER ) { // EOT unique predicts an alt dfaST.SetAttribute( "eotPredictsAlt", EOTPredicts ); } else if ( EOTTarget != null && EOTTarget.NumberOfTransitions > 0 ) { // EOT state has transitions so must split on predicates. // Generate predicate else-if clauses and then generate // NoViableAlt exception as else clause. // Note: these predicates emanate from the EOT target state // rather than the current DFAState s so the error message // might be slightly misleading if you are looking at the // state number. Predicates emanating from EOT targets are // hoisted up to the state that has the EOT edge. for ( int i = 0; i < EOTTarget.NumberOfTransitions; i++ ) { Transition predEdge = (Transition)EOTTarget.Transition( i ); StringTemplate edgeST = templates.GetInstanceOf( dfaEdgeName ); edgeST.SetAttribute( "labelExpr", parentGenerator.GenSemanticPredicateExpr( templates, predEdge ) ); // the target must be an accept state //System.Console.Out.WriteLine( "EOT edge" ); StringTemplate targetST = WalkFixedDFAGeneratingStateMachine( templates, dfa, (DFAState)predEdge.target, k + 1 ); edgeST.SetAttribute( "targetState", targetST ); dfaST.SetAttribute( "edges", edgeST ); } } return dfaST; }