This commit is contained in:
Terence Parr 2012-02-16 13:36:07 -08:00
parent 4a374dab60
commit 646b22b9ec
10 changed files with 79 additions and 21 deletions

View File

@ -8,7 +8,12 @@ public class ParseTreeVisitor<T> {
return ctx.accept(this); return ctx.accept(this);
} }
/** Visit all rule, nonleaf children */ /** 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 <Symbol> void visitChildren(ParserRuleContext<Symbol> ctx) { public <Symbol> void visitChildren(ParserRuleContext<Symbol> ctx) {
for (ParseTree c : ctx.children) { for (ParseTree c : ctx.children) {
if ( c instanceof ParseTree.RuleNode) { if ( c instanceof ParseTree.RuleNode) {

View File

@ -1,11 +1,10 @@
import org.antlr.v4.runtime.tree.*;
import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
public class ABaseVisitor<T> extends ParseTreeVisitor<T> implements AVisitor<T> { public class ABaseVisitor<T> extends ParseTreeVisitor<T> implements AVisitor<T> {
public T visit(AParser.MultContext ctx) { return null; } public T visit(AParser.MultContext ctx) { visitChildren(ctx); return null; }
public T visit(AParser.ParensContext ctx) { return null; } public T visit(AParser.ParensContext ctx) { visitChildren(ctx); return null; }
public T visit(AParser.eContext ctx) { return null; } public T visit(AParser.sContext ctx) { visitChildren(ctx); return null; }
public T visit(AParser.sContext ctx) { return null; } public T visit(AParser.AddContext ctx) { visitChildren(ctx); return null; }
public T visit(AParser.AddContext ctx) { return null; } public T visit(AParser.IntContext ctx) { visitChildren(ctx); return null; }
public T visit(AParser.IntContext ctx) { return null; } }
}

View File

@ -1,3 +1,6 @@
import org.antlr.v4.runtime.tree.*;
import org.antlr.v4.runtime.Token;
public interface AVisitor<T> { public interface AVisitor<T> {
T visit(AParser.MultContext ctx); T visit(AParser.MultContext ctx);
T visit(AParser.ParensContext ctx); T visit(AParser.ParensContext ctx);

View File

@ -31,7 +31,7 @@ import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.ParseTreeVisitor; import org.antlr.v4.runtime.tree.ParseTreeVisitor;
public class TestVisitor { public class TestVisitor {
public static class MyVisitor extends ParseTreeVisitor<Integer> implements AVisitor<Integer> { public static class MyVisitor extends ABaseVisitor<Integer> implements AVisitor<Integer> {
@Override @Override
public Integer visit(AParser.AddContext ctx) { public Integer visit(AParser.AddContext ctx) {
return ctx.e(0).accept(this) + ctx.e(1).accept(this); return ctx.e(0).accept(this) + ctx.e(1).accept(this);

View File

@ -67,6 +67,16 @@ T visit(<file.parserName>.<lname>Context ctx);}; separator="\n">
} }
>> >>
BaseVisitorFile(file, header) ::= <<
<header>
import org.antlr.v4.runtime.tree.*;
import org.antlr.v4.runtime.Token;
public class <file.grammarName>BaseVisitor\<T> extends ParseTreeVisitor\<T> implements <file.grammarName>Visitor\<T> {
<file.visitorNames:{lname |
public T visit(<file.parserName>.<lname>Context ctx) { visitChildren(ctx); return null; \}}; separator="\n">
}
>>
Parser(parser, funcs, atn, sempredFuncs, superclass) ::= << Parser(parser, funcs, atn, sempredFuncs, superclass) ::= <<
<Parser_(ctor="parser_ctor", ...)> <Parser_(ctor="parser_ctor", ...)>

View File

@ -48,8 +48,9 @@ public class CodeGenPipeline {
gen.writeRecognizer(gen.generateParser()); gen.writeRecognizer(gen.generateParser());
if ( g.tool.gen_listener) { if ( g.tool.gen_listener) {
gen.writeListener(gen.generateListener()); gen.writeListener(gen.generateListener());
gen.writeBaseListener(gen.generateBaseListener());
gen.writeVisitor(gen.generateVisitor()); gen.writeVisitor(gen.generateVisitor());
gen.writeBlankListener(gen.generateBlankListener()); gen.writeBaseVisitor(gen.generateBaseVisitor());
} }
gen.writeHeaderFile(); gen.writeHeaderFile();
} }

View File

@ -182,16 +182,29 @@ public class CodeGenerator {
return st; return st;
} }
public ST generateBlankListener() { public ST generateBaseListener() {
OutputModelFactory factory = new ParserFactory(this); OutputModelFactory factory = new ParserFactory(this);
OutputModelController controller = new OutputModelController(factory); OutputModelController controller = new OutputModelController(factory);
factory.setController(controller); factory.setController(controller);
OutputModelObject blankModel = controller.buildBlankListenerOutputModel(); OutputModelObject baseModel = controller.buildBaseListenerOutputModel();
OutputModelWalker walker = new OutputModelWalker(tool, templates); OutputModelWalker walker = new OutputModelWalker(tool, templates);
ST st = walker.walk(blankModel); ST st = walker.walk(baseModel);
return st;
}
public ST generateBaseVisitor() {
OutputModelFactory factory = new ParserFactory(this);
OutputModelController controller = new OutputModelController(factory);
factory.setController(controller);
OutputModelObject baseModel = controller.buildBaseVisitorOutputModel();
OutputModelWalker walker = new OutputModelWalker(tool, templates);
ST st = walker.walk(baseModel);
return st; return st;
} }
@ -235,14 +248,18 @@ public class CodeGenerator {
target.genFile(g,outputFileST, getListenerFileName()); target.genFile(g,outputFileST, getListenerFileName());
} }
public void writeBlankListener(ST outputFileST) { public void writeBaseListener(ST outputFileST) {
target.genFile(g,outputFileST, getBlankListenerFileName()); target.genFile(g,outputFileST, getBaseListenerFileName());
} }
public void writeVisitor(ST outputFileST) { public void writeVisitor(ST outputFileST) {
target.genFile(g,outputFileST, getVisitorFileName()); target.genFile(g,outputFileST, getVisitorFileName());
} }
public void writeBaseVisitor(ST outputFileST) {
target.genFile(g,outputFileST, getBaseVisitorFileName());
}
public void writeHeaderFile() { public void writeHeaderFile() {
String fileName = getHeaderFileName(); String fileName = getHeaderFileName();
if ( fileName==null ) return; if ( fileName==null ) return;
@ -333,15 +350,25 @@ public class CodeGenerator {
} }
/** A given grammar T, return a blank listener implementation /** A given grammar T, return a blank listener implementation
* such as BlankTListener.java, if we're using the Java target. * such as TBaseListener.java, if we're using the Java target.
*/ */
public String getBlankListenerFileName() { public String getBaseListenerFileName() {
assert g.name != null; assert g.name != null;
ST extST = templates.getInstanceOf("codeFileExtension"); ST extST = templates.getInstanceOf("codeFileExtension");
String listenerName = g.name + "BaseListener"; String listenerName = g.name + "BaseListener";
return listenerName+extST.render(); return listenerName+extST.render();
} }
/** A given grammar T, return a blank listener implementation
* such as TBaseListener.java, if we're using the Java target.
*/
public String getBaseVisitorFileName() {
assert g.name != null;
ST extST = templates.getInstanceOf("codeFileExtension");
String listenerName = g.name + "BaseVisitor";
return listenerName+extST.render();
}
/** What is the name of the vocab file generated for this grammar? /** What is the name of the vocab file generated for this grammar?
* Returns null if no .tokens file should be generated. * Returns null if no .tokens file should be generated.
*/ */

View File

@ -108,9 +108,9 @@ public class OutputModelController {
return new ListenerFile(delegate, gen.getListenerFileName()); return new ListenerFile(delegate, gen.getListenerFileName());
} }
public OutputModelObject buildBlankListenerOutputModel() { public OutputModelObject buildBaseListenerOutputModel() {
CodeGenerator gen = delegate.getGenerator(); CodeGenerator gen = delegate.getGenerator();
return new BaseListenerFile(delegate, gen.getBlankListenerFileName()); return new BaseListenerFile(delegate, gen.getBaseListenerFileName());
} }
public OutputModelObject buildVisitorOutputModel() { public OutputModelObject buildVisitorOutputModel() {
@ -118,6 +118,11 @@ public class OutputModelController {
return new VisitorFile(delegate, gen.getVisitorFileName()); return new VisitorFile(delegate, gen.getVisitorFileName());
} }
public OutputModelObject buildBaseVisitorOutputModel() {
CodeGenerator gen = delegate.getGenerator();
return new BaseVisitorFile(delegate, gen.getBaseVisitorFileName());
}
public ParserFile parserFile(String fileName) { public ParserFile parserFile(String fileName) {
ParserFile f = delegate.parserFile(fileName); ParserFile f = delegate.parserFile(fileName);
for (CodeGeneratorExtension ext : extensions) f = ext.parserFile(f); for (CodeGeneratorExtension ext : extensions) f = ext.parserFile(f);

View File

@ -0,0 +1,9 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory;
public class BaseVisitorFile extends VisitorFile {
public BaseVisitorFile(OutputModelFactory factory, String fileName) {
super(factory, fileName);
}
}

View File

@ -14,7 +14,6 @@ public class ListenerFile extends OutputFile {
public String grammarName; public String grammarName;
public String parserName; public String parserName;
public Set<String> listenerNames = new HashSet<String>(); public Set<String> listenerNames = new HashSet<String>();
// public List<String> ruleNames = new ArrayList<String>();
@ModelElement public Action header; @ModelElement public Action header;