diff --git a/runtime/Java/src/org/antlr/v4/runtime/ParserRuleContext.java b/runtime/Java/src/org/antlr/v4/runtime/ParserRuleContext.java index 70dac3a32..c3bdc8634 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/ParserRuleContext.java +++ b/runtime/Java/src/org/antlr/v4/runtime/ParserRuleContext.java @@ -28,16 +28,11 @@ */ package org.antlr.v4.runtime; -import org.antlr.v4.runtime.atn.ATN; -import org.antlr.v4.runtime.atn.ATNState; -import org.antlr.v4.runtime.misc.NotNull; -import org.antlr.v4.runtime.misc.Nullable; -import org.antlr.v4.runtime.tree.ParseTree; -import org.antlr.v4.runtime.tree.ParseTreeListener; +import org.antlr.v4.runtime.atn.*; +import org.antlr.v4.runtime.misc.*; +import org.antlr.v4.runtime.tree.*; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.*; /** A rule invocation record for parsing and tree parsing. * @@ -131,10 +126,11 @@ public class ParserRuleContext extends RuleContext { this(parent, parent!=null ? parent.s : -1 /* invoking state */, stateNumber); } - // Double dispatch methods + // Double dispatch methods for listeners and visitors public void enterRule(ParseTreeListener listener) { } public void exitRule(ParseTreeListener listener) { } + public T accept(ParseTreeVisitor visitor) { visitor.visitChildren(this); return null; } /** Does not set parent link; other add methods do */ public void addChild(TerminalNode t) { diff --git a/runtime/Java/src/org/antlr/v4/runtime/tree/ParseTreeVisitor.java b/runtime/Java/src/org/antlr/v4/runtime/tree/ParseTreeVisitor.java new file mode 100644 index 000000000..5dd260312 --- /dev/null +++ b/runtime/Java/src/org/antlr/v4/runtime/tree/ParseTreeVisitor.java @@ -0,0 +1,26 @@ +package org.antlr.v4.runtime.tree; + +import org.antlr.v4.runtime.ParserRuleContext; + +/** T is return type of visit methods. Use T=Void for no return type. */ +public class ParseTreeVisitor { + public T visit(ParserRuleContext ctx) { + return ctx.accept(this); + } + + /** Visit all rule, nonleaf children. Not useful if you are using T as + * non-Void. This returns nothing, losing all computations from below. + * But handy if you are just walking the tree with a visitor and only + * care about some nodes. The ParserRuleContext.accept() method + * walks all children by default; i.e., calls this method. + */ + public void visitChildren(ParserRuleContext ctx) { + for (ParseTree c : ctx.children) { + if ( c instanceof ParseTree.RuleNode) { + ParseTree.RuleNode r = (ParseTree.RuleNode)c; + ParserRuleContext rctx = (ParserRuleContext)r.getRuleContext(); + visit(rctx); + } + } + } +} diff --git a/tool/playground/AVisitor.java b/tool/playground/AVisitor.java new file mode 100644 index 000000000..5730fa2d6 --- /dev/null +++ b/tool/playground/AVisitor.java @@ -0,0 +1,10 @@ +import org.antlr.v4.runtime.tree.*; +import org.antlr.v4.runtime.Token; + +public interface AVisitor { + T visit(AParser.MultContext ctx); + T visit(AParser.ParensContext ctx); + T visit(AParser.sContext ctx); + T visit(AParser.AddContext ctx); + T visit(AParser.IntContext ctx); +} \ No newline at end of file diff --git a/tool/playground/TestE.java b/tool/playground/TestE.java index 02791e0c7..476cbb29f 100644 --- a/tool/playground/TestE.java +++ b/tool/playground/TestE.java @@ -3,7 +3,7 @@ import org.antlr.v4.runtime.*; public class TestE { public static void main(String[] args) throws Exception { CharStream input = new ANTLRFileStream(args[0]); - E lex = new E(input); + ELexer lex = new ELexer(input); CommonTokenStream tokens = new CommonTokenStream(lex); tokens.fill(); for (Object t : tokens.getTokens()) System.out.println(t); diff --git a/tool/playground/TestVisitor.java b/tool/playground/TestVisitor.java new file mode 100644 index 000000000..6d7e240cb --- /dev/null +++ b/tool/playground/TestVisitor.java @@ -0,0 +1,76 @@ +/* + [The "BSD license"] + Copyright (c) 2011 Terence Parr + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.tree.ParseTreeVisitor; + +public class TestVisitor { + public static class MyVisitor extends ABaseVisitor implements AVisitor { + @Override + public Integer visit(AParser.AddContext ctx) { + return ctx.e(0).accept(this) + ctx.e(1).accept(this); + } + + @Override + public Integer visit(AParser.IntContext ctx) { + return Integer.valueOf(ctx.INT().getText()); + } + + @Override + public Integer visit(AParser.MultContext ctx) { +// return ctx.e(0).accept(this) * ctx.e(1).accept(this); + return visit(ctx.e(0)) * visit(ctx.e(1)); + } + + @Override + public Integer visit(AParser.ParensContext ctx) { + return ctx.e().accept(this); + } + + @Override + public Integer visit(AParser.sContext ctx) { + return visit(ctx.e()); + //return ctx.e().accept(this); + } + } + + public static void main(String[] args) throws Exception { + ALexer lexer = new ALexer(new ANTLRFileStream(args[0])); + CommonTokenStream tokens = new CommonTokenStream(lexer); + AParser p = new AParser(tokens); + p.setBuildParseTree(true); + ParserRuleContext t = p.s(); + System.out.println("tree = "+t.toStringTree(p)); + + MyVisitor visitor = new MyVisitor(); + Integer result = visitor.visit(t); +// Integer result = t.accept(visitor); + System.out.println("result from tree walk = " + result); + } +} diff --git a/tool/resources/org/antlr/v4/tool/templates/codegen/Java/Java.stg b/tool/resources/org/antlr/v4/tool/templates/codegen/Java/Java.stg index 5c0d27bba..6fd56d759 100644 --- a/tool/resources/org/antlr/v4/tool/templates/codegen/Java/Java.stg +++ b/tool/resources/org/antlr/v4/tool/templates/codegen/Java/Java.stg @@ -56,6 +56,28 @@ public class BaseListener implements Listene } >> +VisitorFile(file, header) ::= << +
+import org.antlr.v4.runtime.tree.*; +import org.antlr.v4.runtime.Token; + +public interface Visitor\ { + .Context ctx);}; separator="\n"> +} +>> + +BaseVisitorFile(file, header) ::= << +
+import org.antlr.v4.runtime.tree.*; +import org.antlr.v4.runtime.Token; + +public class BaseVisitor\ extends ParseTreeVisitor\ implements Visitor\ { + .Context ctx) { visitChildren(ctx); return null; \}}; separator="\n"> +} +>> + Parser(parser, funcs, atn, sempredFuncs, superclass) ::= << >> @@ -533,7 +555,7 @@ ListLabelName(label) ::= "