• 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.tool;
29 
30 import org.antlr.analysis.DFA;
31 import org.antlr.analysis.NFAState;
32 import org.antlr.grammar.v3.ANTLRParser;
33 import org.antlr.misc.IntSet;
34 import org.antlr.misc.Interval;
35 import org.antlr.runtime.CommonToken;
36 import org.antlr.runtime.Token;
37 import org.antlr.runtime.TokenSource;
38 import org.antlr.runtime.tree.CommonTree;
39 import org.antlr.runtime.tree.Tree;
40 import org.antlr.runtime.tree.TreeAdaptor;
41 import org.stringtemplate.v4.ST;
42 import org.omg.PortableInterceptor.ORBInitInfoPackage.DuplicateName;
43 
44 import java.util.*;
45 
46 /** Grammars are first converted to ASTs using this class and then are
47  *  converted to NFAs via a tree walker.
48  *
49  *  The reader may notice that I have made a very non-OO decision in this
50  *  class to track variables for many different kinds of nodes.  It wastes
51  *  space for nodes that don't need the values and OO principles cry out
52  *  for a new class type for each kind of node in my tree.  I am doing this
53  *  on purpose for a variety of reasons.  I don't like using the type
54  *  system for different node types; it yields too many damn class files
55  *  which I hate.  Perhaps if I put them all in one file.  Most importantly
56  *  though I hate all the type casting that would have to go on.  I would
57  *  have all sorts of extra work to do.  Ick.  Anyway, I'm doing all this
58  *  on purpose, not out of ignorance. ;)
59  */
60 public class GrammarAST extends CommonTree {
61 	static int count = 0;
62 
63 	public int ID = ++count;
64 
65 	private String textOverride;
66 
67     public String enclosingRuleName;
68 
69     /** If this is a decision node, what is the lookahead DFA? */
70     public DFA lookaheadDFA = null;
71 
72     /** What NFA start state was built from this node? */
73     public NFAState NFAStartState = null;
74 
75 	/** This is used for TREE_BEGIN nodes to point into
76 	 *  the NFA.  TREE_BEGINs point at left edge of DOWN for LOOK computation
77      *  purposes (Nullable tree child list needs special code gen when matching).
78 	 */
79 	public NFAState NFATreeDownState = null;
80 
81 	/** Rule ref nodes, token refs, set, and NOT set refs need to track their
82 	 *  location in the generated NFA so that local FOLLOW sets can be
83 	 *  computed during code gen for automatic error recovery.
84 	 */
85 	public NFAState followingNFAState = null;
86 
87 	/** If this is a SET node, what are the elements? */
88     protected IntSet setValue = null;
89 
90     /** If this is a BLOCK node, track options here */
91     protected Map<String,Object> blockOptions;
92 
93 	/** If this is a BLOCK node for a rewrite rule, track referenced
94 	 *  elements here.  Don't track elements in nested subrules.
95 	 */
96 	public Set<GrammarAST> rewriteRefsShallow;
97 
98 	/*	If REWRITE node, track EVERY element and label ref to right of ->
99 	 *  for this rewrite rule.  There could be multiple of these per
100 	 *  rule:
101 	 *
102 	 *     a : ( ... -> ... | ... -> ... ) -> ... ;
103 	 *
104 	 *  We may need a list of all refs to do definitions for whole rewrite
105 	 *  later.
106 	 *
107 	 *  If BLOCK then tracks every element at that level and below.
108 	 */
109 	public Set<GrammarAST> rewriteRefsDeep;
110 
111 	public Map<String,Object> terminalOptions;
112 
113 	/** if this is an ACTION node, this is the outermost enclosing
114 	 *  alt num in rule.  For actions, define.g sets these (used to
115 	 *  be codegen.g).  We need these set so we can examine actions
116 	 *  early, before code gen, for refs to rule predefined properties
117 	 *  and rule labels.  For most part define.g sets outerAltNum, but
118 	 *  codegen.g does the ones for %foo(a={$ID.text}) type refs as
119 	 *  the {$ID...} is not seen as an action until code gen pulls apart.
120 	 */
121 	public int outerAltNum;
122 
123 	/** if this is a TOKEN_REF or RULE_REF node, this is the code ST
124 	 *  generated for this node.  We need to update it later to add
125 	 *  a label if someone does $tokenref or $ruleref in an action.
126 	 */
127 	public ST code;
128 
129     /**
130      *
131      * @return
132      */
getBlockOptions()133     public Map<String, Object> getBlockOptions() {
134         return blockOptions;
135     }
136 
137     /**
138      *
139      * @param blockOptions
140      */
setBlockOptions(Map<String, Object> blockOptions)141     public void setBlockOptions(Map<String, Object> blockOptions) {
142         this.blockOptions = blockOptions;
143     }
144 
GrammarAST()145 	public GrammarAST() {;}
146 
GrammarAST(int t, String txt)147 	public GrammarAST(int t, String txt) {
148 		initialize(t,txt);
149 	}
150 
GrammarAST(Token token)151 	public GrammarAST(Token token) {
152 		initialize(token);
153 	}
154 
initialize(int i, String s)155 	public void initialize(int i, String s) {
156         token = new CommonToken(i,s);
157 		token.setTokenIndex(-1);
158     }
159 
initialize(Tree ast)160     public void initialize(Tree ast) {
161 		GrammarAST t = ((GrammarAST)ast);
162 		this.startIndex = t.startIndex;
163 		this.stopIndex = t.stopIndex;
164 		this.token = t.token;
165 		this.enclosingRuleName = t.enclosingRuleName;
166 		this.setValue = t.setValue;
167 		this.blockOptions = t.blockOptions;
168 		this.outerAltNum = t.outerAltNum;
169 	}
170 
initialize(Token token)171     public void initialize(Token token) {
172         this.token = token;
173 		if ( token!=null ) {
174 			startIndex = token.getTokenIndex();
175 			stopIndex = startIndex;
176 		}
177     }
178 
getLookaheadDFA()179     public DFA getLookaheadDFA() {
180         return lookaheadDFA;
181     }
182 
setLookaheadDFA(DFA lookaheadDFA)183     public void setLookaheadDFA(DFA lookaheadDFA) {
184         this.lookaheadDFA = lookaheadDFA;
185     }
186 
getNFAStartState()187     public NFAState getNFAStartState() {
188         return NFAStartState;
189     }
190 
setNFAStartState(NFAState nfaStartState)191     public void setNFAStartState(NFAState nfaStartState) {
192 		this.NFAStartState = nfaStartState;
193 	}
194 
195 	/** Save the option key/value pair and process it; return the key
196 	 *  or null if invalid option.
197 	 */
setBlockOption(Grammar grammar, String key, Object value)198 	public String setBlockOption(Grammar grammar, String key, Object value) {
199 		if ( blockOptions == null ) {
200 			blockOptions = new HashMap();
201 		}
202 		return setOption(blockOptions, Grammar.legalBlockOptions, grammar, key, value);
203 	}
204 
setTerminalOption(Grammar grammar, String key, Object value)205 	public String setTerminalOption(Grammar grammar, String key, Object value) {
206 		if ( terminalOptions == null ) {
207 			terminalOptions = new HashMap<String,Object>();
208 		}
209 		return setOption(terminalOptions, Grammar.legalTokenOptions, grammar, key, value);
210 	}
211 
setOption(Map options, Set legalOptions, Grammar grammar, String key, Object value)212 	public String setOption(Map options, Set legalOptions, Grammar grammar, String key, Object value) {
213 		if ( !legalOptions.contains(key) ) {
214 			ErrorManager.grammarError(ErrorManager.MSG_ILLEGAL_OPTION,
215 									  grammar,
216 									  token,
217 									  key);
218 			return null;
219 		}
220 		if ( value instanceof String ) {
221 			String vs = (String)value;
222 			if ( vs.charAt(0)=='"' ) {
223 				value = vs.substring(1,vs.length()-1); // strip quotes
224             }
225         }
226 		if ( key.equals("k") ) {
227 			grammar.numberOfManualLookaheadOptions++;
228 		}
229         if ( key.equals("backtrack") && value.toString().equals("true") ) {
230             grammar.composite.getRootGrammar().atLeastOneBacktrackOption = true;
231         }
232         options.put(key, value);
233 		return key;
234     }
235 
getBlockOption(String key)236     public Object getBlockOption(String key) {
237 		Object value = null;
238 		if ( blockOptions != null ) {
239 			value = blockOptions.get(key);
240 		}
241 		return value;
242 	}
243 
setOptions(Grammar grammar, Map options)244     public void setOptions(Grammar grammar, Map options) {
245 		if ( options==null ) {
246 			this.blockOptions = null;
247 			return;
248 		}
249 		String[] keys = (String[])options.keySet().toArray(new String[options.size()]);
250 		for (String optionName : keys) {
251 			String stored= setBlockOption(grammar, optionName, options.get(optionName));
252 			if ( stored==null ) {
253 				options.remove(optionName);
254 			}
255 		}
256     }
257 
258     @Override
getText()259     public String getText() {
260 		if ( textOverride!=null ) return textOverride;
261         if ( token!=null ) {
262             return token.getText();
263         }
264         return "";
265     }
266 
setType(int type)267 	public void setType(int type) {
268 		token.setType(type);
269 	}
270 
setText(String text)271 	public void setText(String text) {
272 		textOverride = text; // don't alt tokens as others might see
273 	}
274 
275     @Override
getType()276     public int getType() {
277         if ( token!=null ) {
278             return token.getType();
279         }
280         return -1;
281     }
282 
283     @Override
getLine()284     public int getLine() {
285 		int line=0;
286         if ( token!=null ) {
287             line = token.getLine();
288         }
289 		if ( line==0 ) {
290 			Tree child = getChild(0);
291 			if ( child!=null ) {
292 				line = child.getLine();
293 			}
294 		}
295         return line;
296     }
297 
298     @Override
getCharPositionInLine()299     public int getCharPositionInLine(){
300 		int col=0;
301         if ( token!=null ) {
302             col = token.getCharPositionInLine();
303         }
304 		if ( col==0 ) {
305 			Tree child = getChild(0);
306 			if ( child!=null ) {
307 				col = child.getCharPositionInLine();
308 			}
309 		}
310         return col;
311     }
312 
setLine(int line)313     public void setLine(int line) {
314         token.setLine(line);
315     }
316 
setCharPositionInLine(int value)317     public void setCharPositionInLine(int value){
318         token.setCharPositionInLine(value);
319     }
320 
getSetValue()321  	public IntSet getSetValue() {
322         return setValue;
323     }
324 
setSetValue(IntSet setValue)325     public void setSetValue(IntSet setValue) {
326         this.setValue = setValue;
327     }
328 
getLastChild()329     public GrammarAST getLastChild() {
330         if (getChildCount() == 0)
331             return null;
332         return (GrammarAST)getChild(getChildCount() - 1);
333     }
334 
getNextSibling()335     public GrammarAST getNextSibling() {
336         return (GrammarAST)getParent().getChild(getChildIndex() + 1);
337     }
338 
getLastSibling()339     public GrammarAST getLastSibling() {
340         Tree parent = getParent();
341         if ( parent==null ) {
342             return null;
343         }
344         return (GrammarAST)parent.getChild(parent.getChildCount() - 1);
345     }
346 
347 
getChildrenAsArray()348     public GrammarAST[] getChildrenAsArray() {
349         return (GrammarAST[])getChildren().toArray(new GrammarAST[getChildCount()]);
350     }
351 
352     private static final GrammarAST DescendantDownNode = new GrammarAST(Token.DOWN, "DOWN");
353     private static final GrammarAST DescendantUpNode = new GrammarAST(Token.UP, "UP");
354 
descendants(Tree root)355     public static List<Tree> descendants(Tree root){
356         return descendants(root, false);
357     }
358 
descendants(Tree root, boolean insertDownUpNodes)359     public static List<Tree> descendants(Tree root, boolean insertDownUpNodes){
360         List<Tree> result = new ArrayList<Tree>();
361         int count = root.getChildCount();
362 
363         if (insertDownUpNodes){
364             result.add(root);
365             result.add(DescendantDownNode);
366 
367             for (int i = 0 ; i < count ; i++){
368                 Tree child = root.getChild(i);
369                 for (Tree subchild : descendants(child, true))
370                     result.add(subchild);
371             }
372 
373             result.add(DescendantUpNode);
374         }else{
375             result.add(root);
376             for (int i = 0 ; i < count ; i++){
377                 Tree child = root.getChild(i);
378                 for (Tree subchild : descendants(child, false))
379                     result.add(subchild);
380             }
381         }
382 
383         return result;
384     }
385 
findFirstType(int ttype)386 	public GrammarAST findFirstType(int ttype) {
387 		// check this node (the root) first
388 		if ( this.getType()==ttype ) {
389 			return this;
390 		}
391 		// else check children
392 		List<Tree> descendants = descendants(this);
393 		for (Tree child : descendants) {
394 			if ( child.getType()==ttype ) {
395 				return (GrammarAST)child;
396 			}
397 		}
398 		return null;
399 	}
400 
findAllType(int ttype)401 	public List<GrammarAST> findAllType(int ttype) {
402 		List<GrammarAST> nodes = new ArrayList<GrammarAST>();
403 		_findAllType(ttype, nodes);
404 		return nodes;
405 	}
406 
_findAllType(int ttype, List<GrammarAST> nodes)407 	public void _findAllType(int ttype, List<GrammarAST> nodes) {
408 		// check this node (the root) first
409 		if ( this.getType()==ttype ) nodes.add(this);
410 		// check children
411 		for (int i = 0; i < getChildCount(); i++){
412 			GrammarAST child = (GrammarAST)getChild(i);
413 			child._findAllType(ttype, nodes);
414 		}
415 	}
416 
417     /** Make nodes unique based upon Token so we can add them to a Set; if
418 	 *  not a GrammarAST, check type.
419 	 */
420 	@Override
equals(Object ast)421 	public boolean equals(Object ast) {
422 		if ( this == ast ) {
423 			return true;
424 		}
425 		if ( !(ast instanceof GrammarAST) ) {
426 			return this.getType() == ((Tree)ast).getType();
427 		}
428 		GrammarAST t = (GrammarAST)ast;
429 		return token.getLine() == t.getLine() &&
430 			   token.getCharPositionInLine() == t.getCharPositionInLine();
431 	}
432 
433     /** Make nodes unique based upon Token so we can add them to a Set; if
434 	 *  not a GrammarAST, check type.
435 	 */
436     @Override
hashCode()437     public int hashCode(){
438         if (token == null)
439             return 0;
440 
441         return token.hashCode();
442     }
443 
444 	/** See if tree has exact token types and structure; no text */
hasSameTreeStructure(Tree other)445 	public boolean hasSameTreeStructure(Tree other) {
446 		// check roots first.
447 		if (this.getType() != other.getType()) return false;
448 		// if roots match, do full list match test on children.
449 		Iterator<Tree> thisDescendants = descendants(this, true).iterator();
450 		Iterator<Tree> otherDescendants = descendants(other, true).iterator();
451 		while (thisDescendants.hasNext()) {
452 			if (!otherDescendants.hasNext())
453 				return false;
454 			if (thisDescendants.next().getType() != otherDescendants.next().getType())
455 				return false;
456 		}
457 		return !otherDescendants.hasNext();
458 	}
459 
dup(Tree t)460 	public static GrammarAST dup(Tree t) {
461 		if ( t==null ) {
462 			return null;
463 		}
464 		GrammarAST dup_t = new GrammarAST();
465 		dup_t.initialize(t);
466 		return dup_t;
467 	}
468 
469     @Override
dupNode()470     public Tree dupNode(){
471         return dup(this);
472     }
473 
474 	/**Duplicate a tree, assuming this is a root node of a tree--
475 	 * duplicate that node and what's below; ignore siblings of root node.
476 	 */
dupTreeNoActions(GrammarAST t, GrammarAST parent)477 	public static GrammarAST dupTreeNoActions(GrammarAST t, GrammarAST parent) {
478 		if ( t==null ) {
479 			return null;
480 		}
481 		GrammarAST result = (GrammarAST)t.dupNode();
482 		for (GrammarAST subchild : getChildrenForDupTree(t)) {
483 			result.addChild(dupTreeNoActions(subchild, result));
484 		}
485 		return result;
486 	}
487 
getChildrenForDupTree(GrammarAST t)488 	private static List<GrammarAST> getChildrenForDupTree(GrammarAST t) {
489 		List<GrammarAST> result = new ArrayList<GrammarAST>();
490 		for (int i = 0; i < t.getChildCount(); i++){
491 			GrammarAST child = (GrammarAST)t.getChild(i);
492 			int ttype = child.getType();
493 			if (ttype == ANTLRParser.REWRITES || ttype == ANTLRParser.REWRITE || ttype==ANTLRParser.ACTION) {
494 				continue;
495 			}
496 
497 			if (ttype == ANTLRParser.BANG || ttype == ANTLRParser.ROOT) {
498 				for (GrammarAST subchild : getChildrenForDupTree(child))
499 					result.add(subchild);
500 			} else {
501 				result.add(child);
502 			}
503 		}
504 		if ( result.size()==1 && result.get(0).getType()==ANTLRParser.EOA &&
505 			 t.getType()==ANTLRParser.ALT )
506 		{
507 			// can't have an empty alt, insert epsilon
508 			result.add(0, new GrammarAST(ANTLRParser.EPSILON, "epsilon"));
509 		}
510 
511 		return result;
512 	}
513 
dupTree(GrammarAST t)514 	public static GrammarAST dupTree(GrammarAST t) {
515 		if ( t==null ) {
516 			return null;
517 		}
518 		GrammarAST root = dup(t);		// make copy of root
519 		// copy all children of root.
520 		for (int i= 0; i < t.getChildCount(); i++) {
521 			GrammarAST child = (GrammarAST)t.getChild(i);
522 			root.addChild(dupTree(child));
523 		}
524 		return root;
525 	}
526 
setTreeEnclosingRuleNameDeeply(String rname)527 	public void setTreeEnclosingRuleNameDeeply(String rname) {
528 		enclosingRuleName = rname;
529 		if (getChildCount() == 0) return;
530 		for (Object child : getChildren()) {
531 			if (!(child instanceof GrammarAST)) {
532 				continue;
533 			}
534 			GrammarAST grammarAST = (GrammarAST)child;
535 			grammarAST.setTreeEnclosingRuleNameDeeply(rname);
536 		}
537 	}
538 
toStringList()539 	String toStringList() {
540 		return "";
541 	}
542 
543 	/** Track start/stop token for subtree root created for a rule.
544 	 *  Only works with Tree nodes.  For rules that match nothing,
545 	 *  seems like this will yield start=i and stop=i-1 in a nil node.
546 	 *  Might be useful info so I'll not force to be i..i.
547 	 */
setTokenBoundaries(Token startToken, Token stopToken)548 	public void setTokenBoundaries(Token startToken, Token stopToken) {
549 		if ( startToken!=null ) startIndex = startToken.getTokenIndex();
550 		if ( stopToken!=null ) stopIndex = stopToken.getTokenIndex();
551 	}
552 
getBlockALT(int i)553 	public GrammarAST getBlockALT(int i) {
554 		if ( this.getType()!=ANTLRParser.BLOCK ) return null;
555 		int alts = 0;
556 		for (int j =0 ; j < getChildCount(); j++) {
557 			if (getChild(j).getType() == ANTLRParser.ALT) {
558 				alts++;
559 			}
560 			if (alts == i) {
561 				return (GrammarAST)getChild(j);
562 			}
563 		}
564 		return null;
565 	}
566 }
567