• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * [The "BSD license"]
3  *  Copyright (c) 2010 Terence Parr
4  *  All rights reserved.
5  *
6  *  Redistribution and use in source and binary forms, with or without
7  *  modification, are permitted provided that the following conditions
8  *  are met:
9  *  1. Redistributions of source code must retain the above copyright
10  *      notice, this list of conditions and the following disclaimer.
11  *  2. Redistributions in binary form must reproduce the above copyright
12  *      notice, this list of conditions and the following disclaimer in the
13  *      documentation and/or other materials provided with the distribution.
14  *  3. The name of the author may not be used to endorse or promote products
15  *      derived from this software without specific prior written permission.
16  *
17  *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 package org.antlr.analysis;
29 
30 import org.antlr.tool.ErrorManager;
31 import org.antlr.tool.GrammarAST;
32 import org.antlr.tool.Rule;
33 
34 /** A state within an NFA. At most 2 transitions emanate from any NFA state. */
35 public class NFAState extends State {
36 	// I need to distinguish between NFA decision states for (...)* and (...)+
37 	// during NFA interpretation.
38 	public static final int LOOPBACK = 1;
39 	public static final int BLOCK_START = 2;
40 	public static final int OPTIONAL_BLOCK_START = 3;
41 	public static final int BYPASS = 4;
42 	public static final int RIGHT_EDGE_OF_BLOCK = 5;
43 
44 	public static final int MAX_TRANSITIONS = 2;
45 
46 	/** How many transitions; 0, 1, or 2 transitions */
47 	int numTransitions = 0;
48 	public Transition[] transition = new Transition[MAX_TRANSITIONS];
49 
50 	/** For o-A->o type NFA tranitions, record the label that leads to this
51 	 *  state.  Useful for creating rich error messages when we find
52 	 *  insufficiently (with preds) covered states.
53 	 */
54 	public Label incidentEdgeLabel;
55 
56 	/** Which NFA are we in? */
57 	public NFA nfa = null;
58 
59 	/** What's its decision number from 1..n? */
60 	protected int decisionNumber = 0;
61 
62 	/** Subrules (...)* and (...)+ have more than one decision point in
63 	 *  the NFA created for them.  They both have a loop-exit-or-stay-in
64 	 *  decision node (the loop back node).  They both have a normal
65 	 *  alternative block decision node at the left edge.  The (...)* is
66 	 *  worse as it even has a bypass decision (2 alts: stay in or bypass)
67 	 *  node at the extreme left edge.  This is not how they get generated
68 	 *  in code as a while-loop or whatever deals nicely with either.  For
69 	 *  error messages (where I need to print the nondeterministic alts)
70 	 *  and for interpretation, I need to use the single DFA that is created
71 	 *  (for efficiency) but interpret the results differently depending
72 	 *  on which of the 2 or 3 decision states uses the DFA.  For example,
73 	 *  the DFA will always report alt n+1 as the exit branch for n real
74 	 *  alts, so I need to translate that depending on the decision state.
75 	 *
76 	 *  If decisionNumber>0 then this var tells you what kind of decision
77 	 *  state it is.
78 	 */
79 	public int decisionStateType;
80 
81 	/** What rule do we live in? */
82 	public Rule enclosingRule;
83 
84 	/** During debugging and for nondeterminism warnings, it's useful
85 	 *  to know what relationship this node has to the original grammar.
86 	 *  For example, "start of alt 1 of rule a".
87 	 */
88 	protected String description;
89 
90 	/** Associate this NFAState with the corresponding GrammarAST node
91 	 *  from which this node was created.  This is useful not only for
92 	 *  associating the eventual lookahead DFA with the associated
93 	 *  Grammar position, but also for providing users with
94 	 *  nondeterminism warnings.  Mainly used by decision states to
95 	 *  report line:col info.  Could also be used to track line:col
96 	 *  for elements such as token refs.
97 	 */
98 	public GrammarAST associatedASTNode;
99 
100 	/** Is this state the sole target of an EOT transition? */
101 	protected boolean EOTTargetState = false;
102 
103 	/** Jean Bovet needs in the GUI to know which state pairs correspond
104 	 *  to the start/stop of a block.
105 	  */
106 	public int endOfBlockStateNumber = State.INVALID_STATE_NUMBER;
107 
NFAState(NFA nfa)108 	public NFAState(NFA nfa) {
109 		this.nfa = nfa;
110 	}
111 
getNumberOfTransitions()112 	public int getNumberOfTransitions() {
113 		return numTransitions;
114 	}
115 
addTransition(Transition e)116 	public void addTransition(Transition e) {
117 		if ( e==null ) {
118 			throw new IllegalArgumentException("You can't add a null transition");
119 		}
120 		if ( numTransitions>transition.length ) {
121 			throw new IllegalArgumentException("You can only have "+transition.length+" transitions");
122 		}
123 		if ( e!=null ) {
124 			transition[numTransitions] = e;
125 			numTransitions++;
126 			// Set the "back pointer" of the target state so that it
127 			// knows about the label of the incoming edge.
128 			Label label = e.label;
129 			if ( label.isAtom() || label.isSet() ) {
130 				if ( ((NFAState)e.target).incidentEdgeLabel!=null ) {
131 					ErrorManager.internalError("Clobbered incident edge");
132 				}
133 				((NFAState)e.target).incidentEdgeLabel = e.label;
134 			}
135 		}
136 	}
137 
138 	/** Used during optimization to reset a state to have the (single)
139 	 *  transition another state has.
140 	 */
setTransition0(Transition e)141 	public void setTransition0(Transition e) {
142 		if ( e==null ) {
143 			throw new IllegalArgumentException("You can't use a solitary null transition");
144 		}
145 		transition[0] = e;
146 		transition[1] = null;
147 		numTransitions = 1;
148 	}
149 
transition(int i)150 	public Transition transition(int i) {
151 		return transition[i];
152 	}
153 
154 	/** The DFA decision for this NFA decision state always has
155 	 *  an exit path for loops as n+1 for n alts in the loop.
156 	 *  That is really useful for displaying nondeterministic alts
157 	 *  and so on, but for walking the NFA to get a sequence of edge
158 	 *  labels or for actually parsing, we need to get the real alt
159 	 *  number.  The real alt number for exiting a loop is always 1
160 	 *  as transition 0 points at the exit branch (we compute DFAs
161 	 *  always for loops at the loopback state).
162 	 *
163 	 *  For walking/parsing the loopback state:
164 	 * 		1 2 3 display alt (for human consumption)
165 	 * 		2 3 1 walk alt
166 	 *
167 	 *  For walking the block start:
168 	 * 		1 2 3 display alt
169 	 * 		1 2 3
170 	 *
171 	 *  For walking the bypass state of a (...)* loop:
172 	 * 		1 2 3 display alt
173 	 * 		1 1 2 all block alts map to entering loop exit means take bypass
174 	 *
175 	 *  Non loop EBNF do not need to be translated; they are ignored by
176 	 *  this method as decisionStateType==0.
177 	 *
178 	 *  Return same alt if we can't translate.
179 	 */
translateDisplayAltToWalkAlt(int displayAlt)180 	public int translateDisplayAltToWalkAlt(int displayAlt) {
181 		NFAState nfaStart = this;
182 		if ( decisionNumber==0 || decisionStateType==0 ) {
183 			return displayAlt;
184 		}
185 		int walkAlt = 0;
186 		// find the NFA loopback state associated with this DFA
187 		// and count number of alts (all alt numbers are computed
188 		// based upon the loopback's NFA state.
189 		/*
190 		DFA dfa = nfa.grammar.getLookaheadDFA(decisionNumber);
191 		if ( dfa==null ) {
192 			ErrorManager.internalError("can't get DFA for decision "+decisionNumber);
193 		}
194 		*/
195 		int nAlts = nfa.grammar.getNumberOfAltsForDecisionNFA(nfaStart);
196 		switch ( nfaStart.decisionStateType ) {
197 			case LOOPBACK :
198 				walkAlt = displayAlt % nAlts + 1; // rotate right mod 1..3
199 				break;
200 			case BLOCK_START :
201 			case OPTIONAL_BLOCK_START :
202 				walkAlt = displayAlt; // identity transformation
203 				break;
204 			case BYPASS :
205 				if ( displayAlt == nAlts ) {
206 					walkAlt = 2; // bypass
207 				}
208 				else {
209 					walkAlt = 1; // any non exit branch alt predicts entering
210 				}
211 				break;
212 		}
213 		return walkAlt;
214 	}
215 
216 	// Setter/Getters
217 
218 	/** What AST node is associated with this NFAState?  When you
219 	 *  set the AST node, I set the node to point back to this NFA state.
220 	 */
setDecisionASTNode(GrammarAST decisionASTNode)221 	public void setDecisionASTNode(GrammarAST decisionASTNode) {
222 		decisionASTNode.setNFAStartState(this);
223 		this.associatedASTNode = decisionASTNode;
224 	}
225 
getDescription()226 	public String getDescription() {
227 		return description;
228 	}
229 
setDescription(String description)230 	public void setDescription(String description) {
231 		this.description = description;
232 	}
233 
getDecisionNumber()234 	public int getDecisionNumber() {
235 		return decisionNumber;
236 	}
237 
setDecisionNumber(int decisionNumber)238 	public void setDecisionNumber(int decisionNumber) {
239 		this.decisionNumber = decisionNumber;
240 	}
241 
isEOTTargetState()242 	public boolean isEOTTargetState() {
243 		return EOTTargetState;
244 	}
245 
setEOTTargetState(boolean eot)246 	public void setEOTTargetState(boolean eot) {
247 		EOTTargetState = eot;
248 	}
249 
isDecisionState()250 	public boolean isDecisionState() {
251 		return decisionStateType>0;
252 	}
253 
toString()254 	public String toString() {
255 		return String.valueOf(stateNumber);
256 	}
257 
258 }
259 
260