1324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver/* 2324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * [The "BSD license"] 3324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Copyright (c) 2010 Terence Parr 4324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * All rights reserved. 5324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 6324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Redistribution and use in source and binary forms, with or without 7324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * modification, are permitted provided that the following conditions 8324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * are met: 9324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 1. Redistributions of source code must retain the above copyright 10324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * notice, this list of conditions and the following disclaimer. 11324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 2. Redistributions in binary form must reproduce the above copyright 12324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * notice, this list of conditions and the following disclaimer in the 13324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * documentation and/or other materials provided with the distribution. 14324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 3. The name of the author may not be used to endorse or promote products 15324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * derived from this software without specific prior written permission. 16324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 17324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 28324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverpackage org.antlr.tool; 29324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 30324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.antlr.Tool; 31324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.antlr.analysis.*; 32324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.antlr.grammar.v3.ANTLRParser; 33324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.antlr.misc.Utils; 34324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.stringtemplate.v4.ST; 35324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.stringtemplate.v4.STGroup; 36324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.stringtemplate.v4.STGroupDir; 37324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 38324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport java.util.*; 39324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 40324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver/** The DOT (part of graphviz) generation aspect. */ 41324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverpublic class DOTGenerator { 42324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public static final boolean STRIP_NONREDUCED_STATES = false; 43324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 44324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected String arrowhead="normal"; 45324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected String rankdir="LR"; 46324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 47324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Library of output templates; use <attrname> format */ 48324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public static STGroup stlib = new STGroupDir("org/antlr/tool/templates/dot/dfa"); 49324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 50324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** To prevent infinite recursion when walking state machines, record 51324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * which states we've visited. Make a new set every time you start 52324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * walking in case you reuse this object. 53324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 54324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected Set markedStates = null; 55324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 56324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected Grammar grammar; 57324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 58324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** This aspect is associated with a grammar */ 59324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public DOTGenerator(Grammar grammar) { 60324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver this.grammar = grammar; 61324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 62324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 63324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Return a String containing a DOT description that, when displayed, 64324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * will show the incoming state machine visually. All nodes reachable 65324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * from startState will be included. 66324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 67324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public String getDOT(State startState) { 68324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( startState==null ) { 69324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return null; 70324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 71324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // The output DOT graph for visualization 72324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST dot = null; 73324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver markedStates = new HashSet(); 74324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( startState instanceof DFAState ) { 75324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dot = stlib.getInstanceOf("dfa"); 76324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dot.add("startState", 77324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Utils.integer(startState.stateNumber)); 78324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dot.add("useBox", 79324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Boolean.valueOf(Tool.internalOption_ShowNFAConfigsInDFA)); 80324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver walkCreatingDFADOT(dot, (DFAState)startState); 81324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 82324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else { 83324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dot = stlib.getInstanceOf("nfa"); 84324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dot.add("startState", 85324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Utils.integer(startState.stateNumber)); 86324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver walkRuleNFACreatingDOT(dot, startState); 87324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 88324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dot.add("rankdir", rankdir); 89324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return dot.toString(); 90324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 91324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 92324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Return a String containing a DOT description that, when displayed, 93324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * will show the incoming state machine visually. All nodes reachable 94324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * from startState will be included. 95324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public String getRuleNFADOT(State startState) { 96324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // The output DOT graph for visualization 97324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST dot = stlib.getInstanceOf("nfa"); 98324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 99324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver markedStates = new HashSet(); 100324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dot.add("startState", 101324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Utils.integer(startState.stateNumber)); 102324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver walkRuleNFACreatingDOT(dot, startState); 103324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return dot.toString(); 104324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 105324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 106324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 107324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Do a depth-first walk of the state machine graph and 108324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * fill a DOT description template. Keep filling the 109324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * states and edges attributes. 110324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 111324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected void walkCreatingDFADOT(ST dot, 112324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver DFAState s) 113324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 114324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( markedStates.contains(Utils.integer(s.stateNumber)) ) { 115324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return; // already visited this node 116324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 117324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 118324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver markedStates.add(Utils.integer(s.stateNumber)); // mark this node as completed. 119324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 120324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // first add this node 121324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST st; 122324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( s.isAcceptState() ) { 123324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver st = stlib.getInstanceOf("stopstate"); 124324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 125324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else { 126324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver st = stlib.getInstanceOf("state"); 127324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 128324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver st.add("name", getStateLabel(s)); 129324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dot.add("states", st); 130324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 131324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // make a DOT edge for each transition 132324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver for (int i = 0; i < s.getNumberOfTransitions(); i++) { 133324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Transition edge = (Transition) s.transition(i); 134324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /* 135324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver System.out.println("dfa "+s.dfa.decisionNumber+ 136324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver " edge from s"+s.stateNumber+" ["+i+"] of "+s.getNumberOfTransitions()); 137324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 138324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( STRIP_NONREDUCED_STATES ) { 139324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( edge.target instanceof DFAState && 140324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ((DFAState)edge.target).getAcceptStateReachable()!=DFA.REACHABLE_YES ) 141324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 142324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver continue; // don't generate nodes for terminal states 143324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 144324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 145324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver st = stlib.getInstanceOf("edge"); 146324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver st.add("label", getEdgeLabel(edge)); 147324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver st.add("src", getStateLabel(s)); 148324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver st.add("target", getStateLabel(edge.target)); 149324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver st.add("arrowhead", arrowhead); 150324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dot.add("edges", st); 151324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver walkCreatingDFADOT(dot, (DFAState)edge.target); // keep walkin' 152324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 153324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 154324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 155324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Do a depth-first walk of the state machine graph and 156324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * fill a DOT description template. Keep filling the 157324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * states and edges attributes. We know this is an NFA 158324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * for a rule so don't traverse edges to other rules and 159324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * don't go past rule end state. 160324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 161324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected void walkRuleNFACreatingDOT(ST dot, 162324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver State s) 163324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 164324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( markedStates.contains(s) ) { 165324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return; // already visited this node 166324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 167324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 168324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver markedStates.add(s); // mark this node as completed. 169324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 170324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // first add this node 171324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST stateST; 172324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( s.isAcceptState() ) { 173324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver stateST = stlib.getInstanceOf("stopstate"); 174324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 175324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else { 176324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver stateST = stlib.getInstanceOf("state"); 177324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 178324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver stateST.add("name", getStateLabel(s)); 179324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dot.add("states", stateST); 180324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 181324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( s.isAcceptState() ) { 182324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return; // don't go past end of rule node to the follow states 183324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 184324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 185324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // special case: if decision point, then line up the alt start states 186324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // unless it's an end of block 187324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( ((NFAState)s).isDecisionState() ) { 188324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver GrammarAST n = ((NFAState)s).associatedASTNode; 189324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( n!=null && n.getType()!=ANTLRParser.EOB ) { 190324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST rankST = stlib.getInstanceOf("decision-rank"); 191324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver NFAState alt = (NFAState)s; 192324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver while ( alt!=null ) { 193324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver rankST.add("states", getStateLabel(alt)); 194324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( alt.transition[1] !=null ) { 195324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver alt = (NFAState)alt.transition[1].target; 196324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 197324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else { 198324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver alt=null; 199324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 200324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 201324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dot.add("decisionRanks", rankST); 202324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 203324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 204324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 205324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // make a DOT edge for each transition 206324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST edgeST = null; 207324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver for (int i = 0; i < s.getNumberOfTransitions(); i++) { 208324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Transition edge = (Transition) s.transition(i); 209324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( edge instanceof RuleClosureTransition ) { 210324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver RuleClosureTransition rr = ((RuleClosureTransition)edge); 211324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // don't jump to other rules, but display edge to follow node 212324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver edgeST = stlib.getInstanceOf("edge"); 213324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( rr.rule.grammar != grammar ) { 214324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver edgeST.add("label", "<" + rr.rule.grammar.name + "." + rr.rule.name + ">"); 215324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 216324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else { 217324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver edgeST.add("label", "<" + rr.rule.name + ">"); 218324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 219324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver edgeST.add("src", getStateLabel(s)); 220324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver edgeST.add("target", getStateLabel(rr.followState)); 221324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver edgeST.add("arrowhead", arrowhead); 222324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dot.add("edges", edgeST); 223324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver walkRuleNFACreatingDOT(dot, rr.followState); 224324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver continue; 225324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 226324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( edge.isAction() ) { 227324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver edgeST = stlib.getInstanceOf("action-edge"); 228324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 229324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else if ( edge.isEpsilon() ) { 230324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver edgeST = stlib.getInstanceOf("epsilon-edge"); 231324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 232324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else { 233324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver edgeST = stlib.getInstanceOf("edge"); 234324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 235324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver edgeST.add("label", getEdgeLabel(edge)); 236324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver edgeST.add("src", getStateLabel(s)); 237324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver edgeST.add("target", getStateLabel(edge.target)); 238324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver edgeST.add("arrowhead", arrowhead); 239324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dot.add("edges", edgeST); 240324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver walkRuleNFACreatingDOT(dot, edge.target); // keep walkin' 241324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 242324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 243324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 244324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /* 245324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public void writeDOTFilesForAllRuleNFAs() throws IOException { 246324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Collection rules = grammar.getRules(); 247324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver for (Iterator itr = rules.iterator(); itr.hasNext();) { 248324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Grammar.Rule r = (Grammar.Rule) itr.next(); 249324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String ruleName = r.name; 250324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver writeDOTFile( 251324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ruleName, 252324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver getRuleNFADOT(grammar.getRuleStartState(ruleName))); 253324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 254324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 255324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 256324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 257324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /* 258324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public void writeDOTFilesForAllDecisionDFAs() throws IOException { 259324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // for debugging, create a DOT file for each decision in 260324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // a directory named for the grammar. 261324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver File grammarDir = new File(grammar.name+"_DFAs"); 262324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammarDir.mkdirs(); 263324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver List decisionList = grammar.getDecisionNFAStartStateList(); 264324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( decisionList==null ) { 265324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return; 266324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 267324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int i = 1; 268324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Iterator iter = decisionList.iterator(); 269324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver while (iter.hasNext()) { 270324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver NFAState decisionState = (NFAState)iter.next(); 271324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver DFA dfa = decisionState.getDecisionASTNode().getLookaheadDFA(); 272324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( dfa!=null ) { 273324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String dot = getDOT( dfa.startState ); 274324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver writeDOTFile(grammarDir+"/dec-"+i, dot); 275324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 276324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver i++; 277324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 278324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 279324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 280324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 281324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Fix edge strings so they print out in DOT properly; 282324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * generate any gated predicates on edge too. 283324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 284324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected String getEdgeLabel(Transition edge) { 285324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String label = edge.label.toString(grammar); 286324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver label = Utils.replace(label,"\\", "\\\\"); 287324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver label = Utils.replace(label,"\"", "\\\""); 288324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver label = Utils.replace(label,"\n", "\\\\n"); 289324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver label = Utils.replace(label,"\r", ""); 290324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( label.equals(Label.EPSILON_STR) ) { 291324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver label = "e"; 292324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 293324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver State target = edge.target; 294324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( !edge.isSemanticPredicate() && target instanceof DFAState ) { 295324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // look for gated predicates; don't add gated to simple sempred edges 296324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver SemanticContext preds = 297324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ((DFAState)target).getGatedPredicatesInNFAConfigurations(); 298324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( preds!=null ) { 299324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String predsStr = ""; 300324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver predsStr = "&&{"+ 301324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver preds.genExpr(grammar.generator, 302324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar.generator.getTemplates(), null).toString() 303324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver +"}?"; 304324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver label += predsStr; 305324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 306324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 307324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return label; 308324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 309324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 310324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected String getStateLabel(State s) { 311324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( s==null ) { 312324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return "null"; 313324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 314324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String stateLabel = String.valueOf(s.stateNumber); 315324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( s instanceof DFAState ) { 316324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver StringBuffer buf = new StringBuffer(250); 317324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver buf.append('s'); 318324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver buf.append(s.stateNumber); 319324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( Tool.internalOption_ShowNFAConfigsInDFA ) { 320324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( s instanceof DFAState ) { 321324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( ((DFAState)s).abortedDueToRecursionOverflow ) { 322324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver buf.append("\\n"); 323324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver buf.append("abortedDueToRecursionOverflow"); 324324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 325324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 326324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Set alts = ((DFAState)s).getAltSet(); 327324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( alts!=null ) { 328324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver buf.append("\\n"); 329324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // separate alts 330324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver List altList = new ArrayList(); 331324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver altList.addAll(alts); 332324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Collections.sort(altList); 333324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Set configurations = ((DFAState) s).nfaConfigurations; 334324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver for (int altIndex = 0; altIndex < altList.size(); altIndex++) { 335324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Integer altI = (Integer) altList.get(altIndex); 336324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int alt = altI.intValue(); 337324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( altIndex>0 ) { 338324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver buf.append("\\n"); 339324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 340324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver buf.append("alt"); 341324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver buf.append(alt); 342324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver buf.append(':'); 343324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // get a list of configs for just this alt 344324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // it will help us print better later 345324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver List configsInAlt = new ArrayList(); 346324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver for (Iterator it = configurations.iterator(); it.hasNext();) { 347324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver NFAConfiguration c = (NFAConfiguration) it.next(); 348324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( c.alt!=alt ) continue; 349324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver configsInAlt.add(c); 350324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 351324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int n = 0; 352324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver for (int cIndex = 0; cIndex < configsInAlt.size(); cIndex++) { 353324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver NFAConfiguration c = 354324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver (NFAConfiguration)configsInAlt.get(cIndex); 355324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver n++; 356324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver buf.append(c.toString(false)); 357324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( (cIndex+1)<configsInAlt.size() ) { 358324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver buf.append(", "); 359324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 360324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( n%5==0 && (configsInAlt.size()-cIndex)>3 ) { 361324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver buf.append("\\n"); 362324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 363324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 364324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 365324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 366324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 367324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver stateLabel = buf.toString(); 368324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 369324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( (s instanceof NFAState) && ((NFAState)s).isDecisionState() ) { 370324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver stateLabel = stateLabel+",d="+ 371324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ((NFAState)s).getDecisionNumber(); 372324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( ((NFAState)s).endOfBlockStateNumber!=State.INVALID_STATE_NUMBER ) { 373324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver stateLabel += ",eob="+((NFAState)s).endOfBlockStateNumber; 374324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 375324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 376324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else if ( (s instanceof NFAState) && 377324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ((NFAState)s).endOfBlockStateNumber!=State.INVALID_STATE_NUMBER) 378324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 379324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver NFAState n = ((NFAState)s); 380324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver stateLabel = stateLabel+",eob="+n.endOfBlockStateNumber; 381324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 382324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else if ( s instanceof DFAState && ((DFAState)s).isAcceptState() ) { 383324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver stateLabel = stateLabel+ 384324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver "=>"+((DFAState)s).getUniquelyPredictedAlt(); 385324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 386324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return '"'+stateLabel+'"'; 387324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 388324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 389324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public String getArrowheadType() { 390324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return arrowhead; 391324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 392324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 393324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public void setArrowheadType(String arrowhead) { 394324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver this.arrowhead = arrowhead; 395324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 396324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 397324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public String getRankdir() { 398324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return rankdir; 399324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 400324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 401324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public void setRankdir(String rankdir) { 402324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver this.rankdir = rankdir; 403324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 404324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver} 405