diff --git a/runtime/Java/src/org/antlr/v4/runtime/tree/BaseAST.java b/runtime/Java/src/org/antlr/v4/runtime/tree/BaseAST.java index babebb4d3..b81cdff97 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/tree/BaseAST.java +++ b/runtime/Java/src/org/antlr/v4/runtime/tree/BaseAST.java @@ -29,7 +29,8 @@ package org.antlr.v4.runtime.tree; -import java.util.*; +import java.util.ArrayList; +import java.util.List; /** A generic AST implementation with no payload. You must subclass to * actually have any user data. ANTLR v3 uses a list of children approach @@ -186,12 +187,13 @@ public abstract class BaseAST implements AST { return false; } - /** Insert child t at child position i (0..n-1) by shifting children + /** Insert child t at child position i (0..n) by shifting children i+1..n-1 to the right one position. Set parent / indexes properly but does NOT collapse nil-rooted t's that come in here like addChild. + Set position i==n to add to end. */ public void insertChild(int i, BaseAST t) { - if (i < 0 || i >= getChildCount()) { + if (i < 0 || i > getChildCount()) { throw new IndexOutOfBoundsException(i+" out or range"); } diff --git a/tool/src/org/antlr/v4/automata/TreeParserATNFactory.java b/tool/src/org/antlr/v4/automata/TreeParserATNFactory.java index 02a835601..8b6273f3e 100644 --- a/tool/src/org/antlr/v4/automata/TreeParserATNFactory.java +++ b/tool/src/org/antlr/v4/automata/TreeParserATNFactory.java @@ -29,12 +29,16 @@ package org.antlr.v4.automata; -import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.RuleContext; +import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.atn.*; import org.antlr.v4.runtime.misc.IntervalSet; -import org.antlr.v4.tool.*; +import org.antlr.v4.tool.Grammar; +import org.antlr.v4.tool.GrammarAST; +import org.antlr.v4.tool.TreePatternAST; -import java.util.*; +import java.util.ArrayList; +import java.util.List; /** Build ATNs for tree grammars */ public class TreeParserATNFactory extends ParserATNFactory { @@ -60,9 +64,8 @@ public class TreeParserATNFactory extends ParserATNFactory { if ( look.member(Token.UP) ) { // nullable child list if we can see the UP as the next token. - // convert r DN kids UP to r (DN kids UP)?; leave AST + // convert r DN kids UP to r (DN kids UP)?; leave AST alone-- // that drives code gen. This just affects analysis - root.isNullable = true; epsilon(downStates.get(i), upTargetStates.get(i)); } } @@ -75,15 +78,17 @@ public class TreeParserATNFactory extends ParserATNFactory { * Elems are [root, DOWN_TOKEN, x, y, UP_TOKEN] */ public Handle tree(GrammarAST node, List els) { - Handle h = elemList(els); + TreePatternAST root = (TreePatternAST) node; - treePatternRootNodes.add((TreePatternAST)node); + Handle h = elemList(els); + treePatternRootNodes.add(root); // find DOWN node then first child for (Handle elh : els) { Transition trans = elh.left.transition(0); if ( !trans.isEpsilon() && trans.label().member(Token.DOWN) ) { ATNState downState = elh.left; downStates.add(downState); + root.downState = downState; firstChildStates.add(downState.transition(0).target); break; } @@ -93,6 +98,7 @@ public class TreeParserATNFactory extends ParserATNFactory { Transition trans = elh.left.transition(0); if ( trans instanceof AtomTransition && trans.label().member(Token.UP) ) { ATNState upTargetState = elh.right; + root.upState = elh.left; upTargetStates.add(upTargetState); break; } diff --git a/tool/src/org/antlr/v4/codegen/model/MatchTree.java b/tool/src/org/antlr/v4/codegen/model/MatchTree.java index 742e262a4..5d4119385 100644 --- a/tool/src/org/antlr/v4/codegen/model/MatchTree.java +++ b/tool/src/org/antlr/v4/codegen/model/MatchTree.java @@ -31,8 +31,13 @@ package org.antlr.v4.codegen.model; import org.antlr.v4.codegen.OutputModelFactory; import org.antlr.v4.misc.Utils; +import org.antlr.v4.runtime.RuleContext; import org.antlr.v4.runtime.Token; -import org.antlr.v4.tool.*; +import org.antlr.v4.runtime.atn.ATNState; +import org.antlr.v4.runtime.atn.LL1Analyzer; +import org.antlr.v4.runtime.misc.IntervalSet; +import org.antlr.v4.tool.GrammarAST; +import org.antlr.v4.tool.TreePatternAST; import java.util.List; @@ -49,7 +54,7 @@ public class MatchTree extends RuleElement { public MatchTree(OutputModelFactory factory, GrammarAST ast, List elems) { super(factory, ast); TreePatternAST rootNode = (TreePatternAST)ast; - this.isNullable = rootNode.isNullable; + this.isNullable = isNullable(rootNode); List afterRoot = elems.subList(1, elems.size()); int downIndex = Utils.indexOf(afterRoot, new Utils.Filter() { @@ -72,4 +77,12 @@ public class MatchTree extends RuleElement { this.kids = elems.subList(downIndex+1, upIndex); } + boolean isNullable(TreePatternAST rootNode) { + ATNState firstChildState = rootNode.downState.transition(0).target; + LL1Analyzer analyzer = new LL1Analyzer(firstChildState.atn); + IntervalSet look = analyzer.LOOK(firstChildState, RuleContext.EMPTY); + System.out.println(rootNode.toStringTree()+"==nullable? "+look.member(Token.UP)); + return look.member(Token.UP); + } + } diff --git a/tool/src/org/antlr/v4/parse/ANTLRParser.g b/tool/src/org/antlr/v4/parse/ANTLRParser.g index e9efd827a..7fd01989b 100644 --- a/tool/src/org/antlr/v4/parse/ANTLRParser.g +++ b/tool/src/org/antlr/v4/parse/ANTLRParser.g @@ -665,7 +665,8 @@ treeSpec i--; p = (GrammarAST)$tree.getChild(i); } - $tree.insertChild(i+1, up); // ADD UP + if ( i+1 >= $tree.getChildCount() ) $tree.addChild(up); + else $tree.insertChild(i+1, up); // ADD UP } : begin=TREE_BEGIN // Only a subset of elements are allowed to be a root node. However diff --git a/tool/src/org/antlr/v4/tool/TreePatternAST.java b/tool/src/org/antlr/v4/tool/TreePatternAST.java index 54cbdf98c..9a7e3fd28 100644 --- a/tool/src/org/antlr/v4/tool/TreePatternAST.java +++ b/tool/src/org/antlr/v4/tool/TreePatternAST.java @@ -30,9 +30,12 @@ package org.antlr.v4.tool; import org.antlr.runtime.Token; +import org.antlr.v4.runtime.atn.ATNState; public class TreePatternAST extends GrammarAST { - public boolean isNullable; + /** Record ATN DN, UP nodes so we can find easily later */ + public ATNState downState; + public ATNState upState; public TreePatternAST(Token t) { super(t);