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