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