public virtual string Serialize( State s ) { if ( s == null ) { return "<no automaton>"; } return Serialize( s, true ); }
protected virtual string GetStateLabel( State s ) { if ( s == null ) { return "null"; } string stateLabel = s.stateNumber.ToString(); if ( s is DFAState ) { StringBuffer buf = new StringBuffer( 250 ); buf.Append( 's' ); buf.Append( s.stateNumber ); if ( AntlrTool.internalOption_ShowNFAConfigsInDFA ) { if ( s is DFAState ) { if ( ( (DFAState)s ).abortedDueToRecursionOverflow ) { buf.Append( "\\n" ); buf.Append( "abortedDueToRecursionOverflow" ); } } var alts = ( (DFAState)s ).AltSet; if ( alts != null ) { buf.Append( "\\n" ); // separate alts //List altList = new ArrayList(); //altList.addAll( alts ); //Collections.sort( altList ); List<int> altList = alts.OrderBy( i => i ).ToList(); ICollection<NFAConfiguration> configurations = ( (DFAState)s ).nfaConfigurations; for ( int altIndex = 0; altIndex < altList.Count; altIndex++ ) { object altI = altList[altIndex]; int alt = (int)altI; if ( altIndex > 0 ) { buf.Append( "\\n" ); } buf.Append( "alt" ); buf.Append( alt ); buf.Append( ':' ); // get a list of configs for just this alt // it will help us print better later IList configsInAlt = new List<object>(); foreach ( NFAConfiguration c in configurations ) { if ( c.alt != alt ) continue; configsInAlt.Add( c ); } int n = 0; for ( int cIndex = 0; cIndex < configsInAlt.Count; cIndex++ ) { NFAConfiguration c = (NFAConfiguration)configsInAlt[cIndex]; n++; buf.Append( c.ToString( false ) ); if ( ( cIndex + 1 ) < configsInAlt.Count ) { buf.Append( ", " ); } if ( n % 5 == 0 && ( configsInAlt.Count - cIndex ) > 3 ) { buf.Append( "\\n" ); } } } } } stateLabel = buf.ToString(); } if ( ( s is NFAState ) && ( (NFAState)s ).IsDecisionState ) { stateLabel = stateLabel + ",d=" + ( (NFAState)s ).DecisionNumber; if ( ( (NFAState)s ).endOfBlockStateNumber != State.INVALID_STATE_NUMBER ) { stateLabel += ",eob=" + ( (NFAState)s ).endOfBlockStateNumber; } } else if ( ( s is NFAState ) && ( (NFAState)s ).endOfBlockStateNumber != State.INVALID_STATE_NUMBER ) { NFAState n = ( (NFAState)s ); stateLabel = stateLabel + ",eob=" + n.endOfBlockStateNumber; } else if ( s is DFAState && ( (DFAState)s ).IsAcceptState ) { stateLabel = stateLabel + "=>" + ( (DFAState)s ).GetUniquelyPredictedAlt(); } return '"' + stateLabel + '"'; }
/** Return a String containing a DOT description that, when displayed, * will show the incoming state machine visually. All nodes reachable * from startState will be included. */ public virtual string GetDOT( State startState ) { if ( startState == null ) { return null; } // The output DOT graph for visualization StringTemplate dot = null; markedStates = new HashSet<int>(); if ( startState is DFAState ) { dot = stlib.GetInstanceOf( Path.Combine( dfaTemplateDirectoryName, "dfa" ) ); dot.SetAttribute( "startState", startState.stateNumber ); dot.SetAttribute( "useBox", AntlrTool.internalOption_ShowNFAConfigsInDFA ); WalkCreatingDFADOT( dot, (DFAState)startState ); } else { dot = stlib.GetInstanceOf( Path.Combine( dfaTemplateDirectoryName, "nfa" ) ); dot.SetAttribute( "startState", startState.stateNumber ); WalkRuleNFACreatingDOT( dot, startState ); } dot.SetAttribute( "rankdir", rankdir ); return dot.ToString(); }
/** Return a String containing a DOT description that, when displayed, * will show the incoming state machine visually. All nodes reachable * from startState will be included. */ public string GetRuleNFADOT( State startState ) { // The output DOT graph for visualization StringTemplate dot = GetTemplates().GetInstanceOf( "nfa" ); markedStates = new HashSet<object>(); dot.SetAttribute( "startState", startState.stateNumber ); walkRuleNFACreatingDOT( dot, startState ); return dot.Render(); }
/** Return a String containing a DOT description that, when displayed, * will show the incoming state machine visually. All nodes reachable * from startState will be included. */ public virtual string GenerateGraph( State startState ) { if ( startState == null ) { return null; } // The output DOT graph for visualization StringTemplate dot = null; markedStates = new HashSet<int>(); if ( startState is DFAState ) { dot = GetTemplates().GetInstanceOf( "dfa" ); dot.SetAttribute( "startState", startState.StateNumber ); dot.SetAttribute( "useBox", AntlrTool.internalOption_ShowNFAConfigsInDFA ); WalkCreatingDFADOT( dot, (DFAState)startState ); } else { dot = GetTemplates().GetInstanceOf( "nfa" ); dot.SetAttribute( "startState", startState.StateNumber ); WalkRuleNFACreatingDOT( dot, startState ); } dot.SetAttribute( "rankdir", rankdir ); return dot.Render(); }
/** Given a collapsed block of alts (a set of atoms), pull out * the set and return it. */ protected virtual IIntSet GetCollapsedBlockAsSet( State blk ) { State s0 = blk; if ( s0 != null && s0.GetTransition( 0 ) != null ) { State s1 = s0.GetTransition( 0 ).Target; if ( s1 != null && s1.GetTransition( 0 ) != null ) { Label label = s1.GetTransition( 0 ).Label; if ( label.IsSet ) { return label.Set; } } } return null; }
/** Return a string representation of a state machine. Two identical * NFAs or DFAs will have identical serialized representations. The * state numbers inside the state are not used; instead, a new number * is computed and because the serialization will walk the two * machines using the same specific algorithm, then the state numbers * will be identical. Accept states are distinguished from regular * states. */ public virtual string Serialize( State s, bool renumber ) { markedStates = new HashSet<State>(); stateCounter = 0; if ( renumber ) { stateNumberTranslator = new Dictionary<State, int>(); WalkFANormalizingStateNumbers( s ); } List<string> lines = new List<string>(); if ( s.NumberOfTransitions > 0 ) { WalkSerializingFA( lines, s ); } else { // special case: s0 is an accept string s0 = GetStateString( 0, s ); lines.Add( s0 + "\n" ); } StringBuilder buf = new StringBuilder( 0 ); // sort lines to normalize; makes states come out ordered // and then ordered by edge labels then by target state number :) lines.Sort( System.StringComparer.Ordinal ); for ( int i = 0; i < lines.Count; i++ ) { string line = (string)lines[i]; buf.Append( line ); } return buf.ToString(); }
private string GetStateLabel(State state) { if (state == null) return "null"; string stateLabel = state.StateNumber.ToString(); DFAState dfaState = state as DFAState; NFAState nfaState = state as NFAState; if (dfaState != null) { StringBuilder builder = new StringBuilder(250); builder.Append('s'); builder.Append(state.StateNumber); if (AntlrTool.internalOption_ShowNFAConfigsInDFA) { if (dfaState.AbortedDueToRecursionOverflow) { builder.AppendLine(); builder.AppendLine("AbortedDueToRecursionOverflow"); } var alts = dfaState.AltSet; if (alts != null) { builder.AppendLine(); List<int> altList = alts.OrderBy(i => i).ToList(); ICollection<NFAConfiguration> configurations = dfaState.NfaConfigurations; for (int i = 0; i < altList.Count; i++) { int alt = altList[i]; if (i > 0) builder.AppendLine(); builder.AppendFormat("alt{0}:", alt); // get a list of configs for just this alt // it will help us print better later List<NFAConfiguration> configsInAlt = new List<NFAConfiguration>(); foreach (NFAConfiguration c in configurations) { if (c.Alt != alt) continue; configsInAlt.Add(c); } int n = 0; for (int cIndex = 0; cIndex < configsInAlt.Count; cIndex++) { NFAConfiguration c = configsInAlt[cIndex]; n++; builder.Append(c.ToString(false)); if ((cIndex + 1) < configsInAlt.Count) { builder.Append(", "); } if (n % 5 == 0 && (configsInAlt.Count - cIndex) > 3) { builder.Append("\\n"); } } } } } if (dfaState.IsAcceptState) { builder.Append("⇒" + dfaState.GetUniquelyPredictedAlt()); } stateLabel = builder.ToString(); } else if (nfaState != null) { if (nfaState.IsDecisionState) stateLabel += ",d=" + nfaState.DecisionNumber; if (nfaState.endOfBlockStateNumber != State.INVALID_STATE_NUMBER) stateLabel += ",eob=" + nfaState.endOfBlockStateNumber; } return stateLabel; }
private string GetStateString( int n, State s ) { string stateStr = ".s" + n; if ( s.IsAcceptState ) { if ( s is DFAState ) { stateStr = ":s" + n + "=>" + ( (DFAState)s ).GetUniquelyPredictedAlt(); } else { stateStr = ":s" + n; } } return stateStr; }
protected virtual void WalkSerializingFA( IList lines, State s ) { if ( markedStates.Contains( s ) ) { return; // already visited this node } markedStates.Add( s ); // mark this node as completed. int normalizedStateNumber = s.stateNumber; if ( stateNumberTranslator != null ) { normalizedStateNumber = stateNumberTranslator[s]; } string stateStr = GetStateString( normalizedStateNumber, s ); // depth first walk each transition, printing its edge first for ( int i = 0; i < s.NumberOfTransitions; i++ ) { Transition edge = (Transition)s.GetTransition( i ); StringBuilder buf = new StringBuilder(); buf.Append( stateStr ); if ( edge.IsAction ) { buf.Append( "-{}->" ); } else if ( edge.IsEpsilon ) { buf.Append( "->" ); } else if ( edge.IsSemanticPredicate ) { buf.Append( "-{" + edge.label.SemanticContext + "}?->" ); } else { string predsStr = ""; if ( edge.target is DFAState ) { // look for gated predicates; don't add gated to simple sempred edges SemanticContext preds = ( (DFAState)edge.target ).GetGatedPredicatesInNFAConfigurations(); if ( preds != null ) { predsStr = "&&{" + preds.GenExpr( grammar.generator, grammar.generator.Templates, null ).ToString() + "}?"; } } buf.Append( "-" + edge.label.ToString( grammar ) + predsStr + "->" ); } int normalizedTargetStateNumber = edge.target.stateNumber; if ( stateNumberTranslator != null ) { normalizedTargetStateNumber = stateNumberTranslator[edge.target]; } buf.Append( GetStateString( normalizedTargetStateNumber, edge.target ) ); buf.Append( "\n" ); lines.Add( buf.ToString() ); // walk this transition WalkSerializingFA( lines, edge.target ); // if this transition is a rule reference, the node "following" this state // will not be found and appear to be not in graph. Must explicitly jump // to it, but don't "draw" an edge. if ( edge is RuleClosureTransition ) { WalkSerializingFA( lines, ( (RuleClosureTransition)edge ).followState ); } } }
/** In stateNumberTranslator, get a map from State to new, normalized * state number. Used by walkSerializingFA to make sure any two * identical state machines will serialize the same way. */ protected virtual void WalkFANormalizingStateNumbers( State s ) { if ( s == null ) { ErrorManager.InternalError( "null state s" ); return; } if ( stateNumberTranslator.ContainsKey( s ) ) { return; // already did this state } // assign a new state number for this node if there isn't one stateNumberTranslator[s] = stateCounter; stateCounter++; // visit nodes pointed to by each transition; for ( int i = 0; i < s.NumberOfTransitions; i++ ) { Transition edge = (Transition)s.GetTransition( i ); WalkFANormalizingStateNumbers( edge.target ); // keep walkin' // if this transition is a rule reference, the node "following" this state // will not be found and appear to be not in graph. Must explicitly jump // to it, but don't "draw" an edge. if ( edge is RuleClosureTransition ) { WalkFANormalizingStateNumbers( ( (RuleClosureTransition)edge ).followState ); } } }
public string GenerateGraph(State state) { _nodes.Clear(); _links.Clear(); _extraNodes.Clear(); _extraLinks.Clear(); _markedStates.Clear(); _canSkipStates.Clear(); DFAState dfaState = state as DFAState; if (GroupNodes) { if (dfaState != null) { _groupId = "decision_"; _extraNodes.Add(new XElement(Elements.Node, new XAttribute(Attributes.Id, _groupId), new XAttribute(Attributes.Label, dfaState.StateNumber.ToString()), new XAttribute(Attributes.Group, "Collapsed"))); } else { NFAState nfaState = (NFAState)state; _groupId = "rule_" + nfaState.enclosingRule.Name; _extraNodes.Add(new XElement(Elements.Node, new XAttribute(Attributes.Id, _groupId), new XAttribute(Attributes.Label, nfaState.enclosingRule.Name), new XAttribute(Attributes.Group, "Collapsed"))); } } if (dfaState != null) { WalkCreatingDfaDgml(dfaState); } else { WalkRuleNfaCreatingDgml(state); LocateVerboseStates(state); } XDocument document = new XDocument( new XDeclaration("1.0", "utf-8", "yes"), new XElement(Elements.DirectedGraph, new XAttribute(Attributes.GraphDirection, GraphDirection.TopToBottom), new XAttribute(Attributes.Layout, Layout.Sugiyama), GetNodes(), GetLinks(), GetCategories(), GetProperties(), GetStyles())); return document.ToString(); }
private void WalkRuleNfaCreatingDgml(State state) { if (!_markedStates.Add(state.StateNumber)) return; NFAState nfaState = state as NFAState; // create the node string nodeCategory; if (state.IsAcceptState) nodeCategory = Categories.StopState; else if (nfaState != null && nfaState.IsDecisionState) nodeCategory = Categories.DecisionState; else nodeCategory = Categories.State; XElement node = new XElement(Elements.Node, new XAttribute(Attributes.Id, "state_" + state.StateNumber), new XAttribute(Attributes.Label, GetStateLabel(state)), new XAttribute(Attributes.Category, nodeCategory)); if (nfaState != null && nfaState.IsDecisionState) { string baseFileName = _grammar.name; if (_grammar.implicitLexer) baseFileName += Grammar.grammarTypeToFileNameSuffix[(int)_grammar.type]; string decisionPath = string.Format("{0}.dec-{1}.dgml", baseFileName, nfaState.DecisionNumber); node.Add(new XAttribute(Attributes.Reference, decisionPath)); } _nodes.Add(state, node); if (GroupNodes) _extraLinks.Add(CreateContainmentLink(_groupId, "state_" + state.StateNumber)); // don't go past end of rule if (state.IsAcceptState) return; // create links for each transition for (int i = 0; i < state.NumberOfTransitions; i++) { Transition edge = state.GetTransition(i); RuleClosureTransition rr = edge as RuleClosureTransition; if (rr != null) { string label; if (rr.Rule.Grammar != _grammar) label = string.Format("<{0}.{1}>", rr.Rule.Grammar.name, rr.Rule.Name); else label = string.Format("<{0}>", rr.Rule.Name); XElement link = new XElement(Elements.Link, new XAttribute(Attributes.Source, "state_" + state.StateNumber), new XAttribute(Attributes.Target, "state_" + rr.FollowState), new XAttribute(Attributes.Category, Categories.RuleClosureEdge), new XAttribute(Attributes.Label, label)); _links.Add(new KeyValuePair<State, Transition>(state, edge), link); WalkRuleNfaCreatingDgml(rr.FollowState); } else { string edgeCategory; if (edge.IsAction) edgeCategory = Categories.ActionEdge; else if (edge.IsEpsilon) edgeCategory = Categories.EpsilonEdge; else if (edge.Label.IsSet || edge.Label.IsAtom) edgeCategory = Categories.AtomEdge; else edgeCategory = Categories.Edge; XElement link = new XElement(Elements.Link, new XAttribute(Attributes.Source, "state_" + state.StateNumber), new XAttribute(Attributes.Target, "state_" + edge.Target.StateNumber), new XAttribute(Attributes.Category, edgeCategory), new XAttribute(Attributes.Label, GetEdgeLabel(edge))); _links.Add(new KeyValuePair<State, Transition>(state, edge), link); WalkRuleNfaCreatingDgml(edge.Target); } } }
private void LocateVerboseStates(State startState) { Dictionary<State, XElement> verboseNodes = _nodes.Where(IsVerboseNode).ToDictionary(i => i.Key, i => i.Value); verboseNodes.Remove(startState); foreach (var verboseNode in verboseNodes) { verboseNode.Value.Add(new XElement(Elements.Category, new XAttribute(Attributes.Ref, Categories.VerboseNode))); } Dictionary<State, List<State>> shortcuts = new Dictionary<State, List<State>>(); foreach (var link in _links) { State source = link.Key.Key; State target = link.Key.Value.Target; if (!verboseNodes.ContainsKey(source) && verboseNodes.ContainsKey(target)) { List<State> newTargets = new List<State>(); Stack<State> remaining = new Stack<State>(); remaining.Push(target); while (remaining.Count > 0) { State current = remaining.Pop(); if (!verboseNodes.ContainsKey(current)) { if (_nodes.ContainsKey(current)) newTargets.Add(current); } else { for (int i = 0; i < current.NumberOfTransitions; i++) { remaining.Push(current.GetTransition(i).Target); } } } foreach (var newTarget in newTargets) { XElement newLink = new XElement(link.Value); newLink.Attribute(Attributes.Target).Remove(); newLink.Add(new XAttribute(Attributes.Target, "state_" + newTarget.StateNumber)); newLink.Add(new XElement(Elements.Category, new XAttribute(Attributes.Ref, Categories.OptimizedEdge))); _extraLinks.Add(newLink); } } } }
/** Do a depth-first walk of the state machine graph and * fill a DOT description template. Keep filling the * states and edges attributes. We know this is an NFA * for a rule so don't traverse edges to other rules and * don't go past rule end state. */ protected virtual void WalkRuleNFACreatingDOT( StringTemplate dot, State 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 stateST; if ( s.IsAcceptState ) { stateST = stlib.GetInstanceOf( Path.Combine( dfaTemplateDirectoryName, "stopstate" ) ); } else { stateST = stlib.GetInstanceOf( Path.Combine( dfaTemplateDirectoryName, "state" ) ); } stateST.SetAttribute( "name", GetStateLabel( s ) ); dot.SetAttribute( "states", stateST ); if ( s.IsAcceptState ) { return; // don't go past end of rule node to the follow states } // special case: if decision point, then line up the alt start states // unless it's an end of block if ( ( (NFAState)s ).IsDecisionState ) { GrammarAST n = ( (NFAState)s ).associatedASTNode; if ( n != null && n.Type != ANTLRParser.EOB ) { StringTemplate rankST = stlib.GetInstanceOf( Path.Combine( dfaTemplateDirectoryName, "decision-rank" ) ); NFAState alt = (NFAState)s; while ( alt != null ) { rankST.SetAttribute( "states", GetStateLabel( alt ) ); if ( alt.transition[1] != null ) { alt = (NFAState)alt.transition[1].target; } else { alt = null; } } dot.SetAttribute( "decisionRanks", rankST ); } } // make a DOT edge for each transition StringTemplate edgeST = null; for ( int i = 0; i < s.NumberOfTransitions; i++ ) { Transition edge = (Transition)s.GetTransition( i ); if ( edge is RuleClosureTransition ) { RuleClosureTransition rr = ( (RuleClosureTransition)edge ); // don't jump to other rules, but display edge to follow node edgeST = stlib.GetInstanceOf( Path.Combine( dfaTemplateDirectoryName, "edge" ) ); if ( rr.rule.grammar != grammar ) { edgeST.SetAttribute( "label", "<" + rr.rule.grammar.name + "." + rr.rule.Name + ">" ); } else { edgeST.SetAttribute( "label", "<" + rr.rule.Name + ">" ); } edgeST.SetAttribute( "src", GetStateLabel( s ) ); edgeST.SetAttribute( "target", GetStateLabel( rr.followState ) ); edgeST.SetAttribute( "arrowhead", arrowhead ); dot.SetAttribute( "edges", edgeST ); WalkRuleNFACreatingDOT( dot, rr.followState ); continue; } if ( edge.IsAction ) { edgeST = stlib.GetInstanceOf( Path.Combine( dfaTemplateDirectoryName, "action-edge" ) ); } else if ( edge.IsEpsilon ) { edgeST = stlib.GetInstanceOf( Path.Combine( dfaTemplateDirectoryName, "epsilon-edge" ) ); } else { edgeST = stlib.GetInstanceOf( Path.Combine( dfaTemplateDirectoryName, "edge" ) ); } edgeST.SetAttribute( "label", GetEdgeLabel( edge ) ); edgeST.SetAttribute( "src", GetStateLabel( s ) ); edgeST.SetAttribute( "target", GetStateLabel( edge.target ) ); edgeST.SetAttribute( "arrowhead", arrowhead ); dot.SetAttribute( "edges", edgeST ); WalkRuleNFACreatingDOT( dot, edge.target ); // keep walkin' } }
/** Return a String containing a DOT description that, when displayed, * will show the incoming state machine visually. All nodes reachable * from startState will be included. */ public string GetRuleNFADOT( State startState ) { // The output DOT graph for visualization StringTemplate dot = stlib.GetInstanceOf( Path.Combine( dfaTemplateDirectoryName, "nfa" ) ); markedStates = new HashSet<object>(); dot.SetAttribute( "startState", startState.stateNumber ); walkRuleNFACreatingDOT( dot, startState ); return dot.ToString(); }
/** Given a start state and a final state, find a list of edge labels * between the two ignoring epsilon. Limit your scan to a set of states * passed in. This is used to show a sample input sequence that is * nondeterministic with respect to this decision. Return IList<Label> as * a parameter. The incoming states set must be all states that lead * from startState to targetState and no others so this algorithm doesn't * take a path that eventually leads to a state other than targetState. * Don't follow loops, leading to short (possibly shortest) path. */ protected virtual void GetSampleInputSequenceUsingStateSet( State startState, State targetState, HashSet<object> states, IList<Label> labels ) { _statesVisitedDuringSampleSequence.Add( startState.StateNumber ); // pick the first edge in states as the one to traverse for ( int i = 0; i < startState.NumberOfTransitions; i++ ) { Transition t = startState.GetTransition( i ); DFAState edgeTarget = (DFAState)t.Target; if ( states.Contains( edgeTarget ) && !_statesVisitedDuringSampleSequence.Contains( edgeTarget.StateNumber ) ) { labels.Add( t.Label ); // traverse edge and track label if ( edgeTarget != targetState ) { // get more labels if not at target GetSampleInputSequenceUsingStateSet( edgeTarget, targetState, states, labels ); } // done with this DFA state as we've found a good path to target return; } } labels.Add( new Label( Label.EPSILON ) ); // indicate no input found // this happens on a : {p1}? a | A ; //ErrorManager.error(ErrorManager.MSG_CANNOT_COMPUTE_SAMPLE_INPUT_SEQ); }