forked from jasder/antlr
Got the visitor thing cleaned up enough for a small example
[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 9059]
This commit is contained in:
parent
da7e7c8813
commit
2d234ee28c
|
@ -29,10 +29,11 @@
|
||||||
|
|
||||||
package org.antlr.v4.runtime.tree;
|
package org.antlr.v4.runtime.tree;
|
||||||
|
|
||||||
import org.antlr.v4.runtime.*;
|
import org.antlr.v4.runtime.ParserRuleContext;
|
||||||
|
import org.antlr.v4.runtime.Token;
|
||||||
|
|
||||||
public interface ParseTreeListener {
|
public interface ParseTreeListener {
|
||||||
void visitToken(Token token);
|
void visitToken(Token token);
|
||||||
void discoverRule(ParserRuleContext ctx);
|
void enterEveryRule(ParserRuleContext ctx);
|
||||||
void finishRule(ParserRuleContext ctx);
|
void exitEveryRule(ParserRuleContext ctx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,55 +57,13 @@ public class ParseTreeVisitor {
|
||||||
*/
|
*/
|
||||||
protected void enterRule(ParseTreeListener listener, ParseTree.RuleNode r) {
|
protected void enterRule(ParseTreeListener listener, ParseTree.RuleNode r) {
|
||||||
ParserRuleContext ctx = (ParserRuleContext)r.getRuleContext();
|
ParserRuleContext ctx = (ParserRuleContext)r.getRuleContext();
|
||||||
listener.discoverRule((ParserRuleContext)r.getRuleContext());
|
listener.enterEveryRule((ParserRuleContext) r.getRuleContext());
|
||||||
ctx.enterRule(listener);
|
ctx.enterRule(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void exitRule(ParseTreeListener listener, ParseTree.RuleNode r) {
|
protected void exitRule(ParseTreeListener listener, ParseTree.RuleNode r) {
|
||||||
ParserRuleContext ctx = (ParserRuleContext)r.getRuleContext();
|
ParserRuleContext ctx = (ParserRuleContext)r.getRuleContext();
|
||||||
ctx.exitRule(listener);
|
ctx.exitRule(listener);
|
||||||
listener.finishRule(ctx);
|
listener.exitEveryRule(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
public static void main(String[] args) {
|
|
||||||
TListener listener = new TListener() {
|
|
||||||
public void discover_s(s_ctx ctx) {
|
|
||||||
}
|
|
||||||
public void finish_s(s_ctx ctx) {
|
|
||||||
}
|
|
||||||
public void discover_ifstat(ParserRuleContext ctx) {
|
|
||||||
}
|
|
||||||
public void finish_ifstat(ParserRuleContext ctx) {
|
|
||||||
}
|
|
||||||
public void visitToken(Token token) {
|
|
||||||
}
|
|
||||||
public void discoverRule(ParserRuleContext ctx) {
|
|
||||||
}
|
|
||||||
public void finishRule(ParserRuleContext ctx) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ParserRuleContext ctx = new ParserRuleContext();
|
|
||||||
ParseTreeVisitor visitor = new ParseTreeVisitor();
|
|
||||||
visitor.visit(listener, ctx);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
interface TListener extends ParseTreeListener {
|
|
||||||
void discover_s(s_ctx ctx);
|
|
||||||
void finish_s(s_ctx ctx);
|
|
||||||
void discover_ifstat(ParserRuleContext ctx); // no labels
|
|
||||||
void finish_ifstat(ParserRuleContext ctx); // no labels
|
|
||||||
}
|
|
||||||
|
|
||||||
class s_ctx extends ParserRuleContext {
|
|
||||||
public ParserRuleContext i;
|
|
||||||
public s_ctx(RuleContext parent, int state) {
|
|
||||||
super(parent, state);
|
|
||||||
}
|
|
||||||
public void discover(TListener listener) { listener.discover_s(this); }
|
|
||||||
public void finish(TListener listener) { listener.discover_s(this); }
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import org.antlr.v4.runtime.ANTLRFileStream;
|
import org.antlr.v4.runtime.ANTLRFileStream;
|
||||||
import org.antlr.v4.runtime.CommonTokenStream;
|
import org.antlr.v4.runtime.CommonTokenStream;
|
||||||
|
import org.antlr.v4.runtime.ParserRuleContext;
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
|
||||||
|
|
||||||
public class TestT {
|
public class TestT {
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
|
@ -11,7 +13,18 @@ public class TestT {
|
||||||
// }
|
// }
|
||||||
TParser p = new TParser(tokens);
|
TParser p = new TParser(tokens);
|
||||||
p.setBuildParseTrees(true);
|
p.setBuildParseTrees(true);
|
||||||
TParser.sContext ret = p.s();
|
TParser.sContext tree = p.s();
|
||||||
System.out.println(ret.toStringTree(p));
|
System.out.println(tree.toStringTree(p));
|
||||||
|
|
||||||
|
ParseTreeVisitor visitor = new ParseTreeVisitor();
|
||||||
|
TListener listener = new BlankTListener() {
|
||||||
|
public void enterEveryRule(ParserRuleContext ctx) {
|
||||||
|
System.out.println("enter rule "+TParser.ruleNames[ctx.ruleIndex]);
|
||||||
|
}
|
||||||
|
public void exitRule(TParser.sContext ctx) { // specific to rule s
|
||||||
|
System.out.println("exit rule s");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
visitor.visit(listener, tree);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,15 +35,36 @@ import java.util.ArrayList;
|
||||||
<parser>
|
<parser>
|
||||||
>>
|
>>
|
||||||
|
|
||||||
ListenerFile(listener) ::= <<
|
ListenerFile(listener, header) ::= <<
|
||||||
|
<header>
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTreeListener;
|
||||||
|
|
||||||
@SuppressWarnings({"all", "warnings", "unchecked", "unused"})
|
@SuppressWarnings({"all", "warnings", "unchecked", "unused"})
|
||||||
public interface <listener.grammarName>Listener {
|
public interface <listener.grammarName>Listener extends ParseTreeListener {
|
||||||
<listener.rules:{r |
|
<listener.rules:{r |
|
||||||
void enterRule(<listener.parserName>.<r.name>Context ctx);
|
void enterRule(<listener.parserName>.<r.name>Context ctx);
|
||||||
void exitRule(<listener.parserName>.<r.name>Context ctx);}; separator="\n">
|
void exitRule(<listener.parserName>.<r.name>Context ctx);}; separator="\n">
|
||||||
}
|
}
|
||||||
>>
|
>>
|
||||||
|
|
||||||
|
BlankListenerFile(listener, header) ::= <<
|
||||||
|
<header>
|
||||||
|
|
||||||
|
import org.antlr.v4.runtime.ParserRuleContext;
|
||||||
|
import org.antlr.v4.runtime.Token;
|
||||||
|
|
||||||
|
@SuppressWarnings({"all", "warnings", "unchecked", "unused"})
|
||||||
|
public class Blank<listener.grammarName>Listener implements <listener.grammarName>Listener {
|
||||||
|
<listener.rules:{r |
|
||||||
|
public void enterRule(<listener.parserName>.<r.name>Context ctx) { \}
|
||||||
|
public void exitRule(<listener.parserName>.<r.name>Context ctx) { \}}; separator="\n">
|
||||||
|
|
||||||
|
public void enterEveryRule(ParserRuleContext ctx) { }
|
||||||
|
public void exitEveryRule(ParserRuleContext ctx) { }
|
||||||
|
public void visitToken(Token token) { }
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
Parser(parser, scopes, funcs, atn, sempredFuncs) ::= <<
|
Parser(parser, scopes, funcs, atn, sempredFuncs) ::= <<
|
||||||
@SuppressWarnings({"all", "warnings", "unchecked", "unused"})
|
@SuppressWarnings({"all", "warnings", "unchecked", "unused"})
|
||||||
public class <parser.name> extends Parser {
|
public class <parser.name> extends Parser {
|
||||||
|
@ -429,8 +450,8 @@ public static class <s.name> extends ParserRuleContext {
|
||||||
super(parent, state);
|
super(parent, state);
|
||||||
<s.ctorAttrs:{a | this.<a.name> = <a.name>;}; separator="\n">
|
<s.ctorAttrs:{a | this.<a.name> = <a.name>;}; separator="\n">
|
||||||
}
|
}
|
||||||
public void enterRule(<parser.grammarName>Listener listener) { listener.enterRule(this); }
|
public void enterRule(ParseTreeListener listener) { ((<parser.grammarName>Listener)listener).enterRule(this); }
|
||||||
public void exitRule(<parser.grammarName>Listener listener) { listener.exitRule(this); }
|
public void exitRule(ParseTreeListener listener) { ((<parser.grammarName>Listener)listener).exitRule(this); }
|
||||||
}
|
}
|
||||||
>>
|
>>
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ public class CodeGenPipeline {
|
||||||
else {
|
else {
|
||||||
gen.writeRecognizer(gen.generateParser());
|
gen.writeRecognizer(gen.generateParser());
|
||||||
gen.writeListener(gen.generateListener());
|
gen.writeListener(gen.generateListener());
|
||||||
|
gen.writeBlankListener(gen.generateBlankListener());
|
||||||
gen.writeHeaderFile();
|
gen.writeHeaderFile();
|
||||||
}
|
}
|
||||||
gen.writeVocabFile();
|
gen.writeVocabFile();
|
||||||
|
|
|
@ -52,8 +52,6 @@ public class CodeGenerator {
|
||||||
"<tokens.keys:{t | <t>=<tokens.(t)>\n}>" +
|
"<tokens.keys:{t | <t>=<tokens.(t)>\n}>" +
|
||||||
"<literals.keys:{t | <t>=<literals.(t)>\n}>";
|
"<literals.keys:{t | <t>=<literals.(t)>\n}>";
|
||||||
|
|
||||||
public OutputModelObject outputModel;
|
|
||||||
|
|
||||||
public Grammar g;
|
public Grammar g;
|
||||||
public Tool tool;
|
public Tool tool;
|
||||||
public Target target;
|
public Target target;
|
||||||
|
@ -118,9 +116,6 @@ public class CodeGenerator {
|
||||||
// OutputModelFactory factory;
|
// OutputModelFactory factory;
|
||||||
// if ( g.isLexer() ) factory = new LexerFactory(this);
|
// if ( g.isLexer() ) factory = new LexerFactory(this);
|
||||||
// else factory = new ParserFactory(this);
|
// else factory = new ParserFactory(this);
|
||||||
//
|
|
||||||
// // TODO: let someone add their own factory?
|
|
||||||
//
|
|
||||||
// // CREATE OUTPUT MODEL FROM GRAMMAR OBJ AND AST WITHIN RULES
|
// // CREATE OUTPUT MODEL FROM GRAMMAR OBJ AND AST WITHIN RULES
|
||||||
// OutputModelController controller = new OutputModelController(factory);
|
// OutputModelController controller = new OutputModelController(factory);
|
||||||
// if ( g.hasASTOption() ) {
|
// if ( g.hasASTOption() ) {
|
||||||
|
@ -140,7 +135,7 @@ public class CodeGenerator {
|
||||||
OutputModelController controller = new OutputModelController(factory);
|
OutputModelController controller = new OutputModelController(factory);
|
||||||
factory.setController(controller);
|
factory.setController(controller);
|
||||||
|
|
||||||
outputModel = controller.buildLexerOutputModel();
|
OutputModelObject outputModel = controller.buildLexerOutputModel();
|
||||||
|
|
||||||
OutputModelWalker walker = new OutputModelWalker(tool, templates);
|
OutputModelWalker walker = new OutputModelWalker(tool, templates);
|
||||||
ST st = walker.walk(outputModel);
|
ST st = walker.walk(outputModel);
|
||||||
|
@ -156,8 +151,6 @@ public class CodeGenerator {
|
||||||
public ST generateParser() {
|
public ST generateParser() {
|
||||||
OutputModelFactory factory = new ParserFactory(this);
|
OutputModelFactory factory = new ParserFactory(this);
|
||||||
|
|
||||||
// TODO: let someone add their own factory?
|
|
||||||
|
|
||||||
// CREATE OUTPUT MODEL FROM GRAMMAR OBJ AND AST WITHIN RULES
|
// CREATE OUTPUT MODEL FROM GRAMMAR OBJ AND AST WITHIN RULES
|
||||||
OutputModelController controller = new OutputModelController(factory);
|
OutputModelController controller = new OutputModelController(factory);
|
||||||
if ( g.hasASTOption() ) {
|
if ( g.hasASTOption() ) {
|
||||||
|
@ -165,7 +158,7 @@ public class CodeGenerator {
|
||||||
}
|
}
|
||||||
factory.setController(controller);
|
factory.setController(controller);
|
||||||
|
|
||||||
outputModel = controller.buildParserOutputModel();
|
OutputModelObject outputModel = controller.buildParserOutputModel();
|
||||||
|
|
||||||
OutputModelWalker walker = new OutputModelWalker(tool, templates);
|
OutputModelWalker walker = new OutputModelWalker(tool, templates);
|
||||||
ST st = walker.walk(outputModel);
|
ST st = walker.walk(outputModel);
|
||||||
|
@ -181,25 +174,26 @@ public class CodeGenerator {
|
||||||
public ST generateListener() {
|
public ST generateListener() {
|
||||||
OutputModelFactory factory = new ParserFactory(this);
|
OutputModelFactory factory = new ParserFactory(this);
|
||||||
|
|
||||||
// TODO: let someone add their own factory?
|
|
||||||
|
|
||||||
// CREATE OUTPUT MODEL FROM GRAMMAR OBJ AND AST WITHIN RULES
|
|
||||||
OutputModelController controller = new OutputModelController(factory);
|
OutputModelController controller = new OutputModelController(factory);
|
||||||
if ( g.hasASTOption() ) {
|
|
||||||
controller.addExtension( new ParserASTExtension(factory) );
|
|
||||||
}
|
|
||||||
factory.setController(controller);
|
factory.setController(controller);
|
||||||
|
|
||||||
outputModel = controller.buildListenerOutputModel();
|
OutputModelObject listenerModel = controller.buildListenerOutputModel();
|
||||||
|
|
||||||
OutputModelWalker walker = new OutputModelWalker(tool, templates);
|
OutputModelWalker walker = new OutputModelWalker(tool, templates);
|
||||||
ST st = walker.walk(outputModel);
|
ST st = walker.walk(listenerModel);
|
||||||
|
return st;
|
||||||
|
}
|
||||||
|
|
||||||
if ( tool.launch_ST_inspector ) {
|
public ST generateBlankListener() {
|
||||||
st.inspect();
|
OutputModelFactory factory = new ParserFactory(this);
|
||||||
//if ( templates.isDefined("headerFile") ) headerFileST.inspect();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
OutputModelController controller = new OutputModelController(factory);
|
||||||
|
factory.setController(controller);
|
||||||
|
|
||||||
|
OutputModelObject blankModel = controller.buildBlankListenerOutputModel();
|
||||||
|
|
||||||
|
OutputModelWalker walker = new OutputModelWalker(tool, templates);
|
||||||
|
ST st = walker.walk(blankModel);
|
||||||
return st;
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,7 +234,11 @@ public class CodeGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeListener(ST outputFileST) {
|
public void writeListener(ST outputFileST) {
|
||||||
target.genFile(g,outputFileST,getListenerFileName());
|
target.genFile(g,outputFileST, getListenerFileName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeBlankListener(ST outputFileST) {
|
||||||
|
target.genFile(g,outputFileST, getBlankListenerFileName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeHeaderFile() {
|
public void writeHeaderFile() {
|
||||||
|
@ -322,6 +320,15 @@ public class CodeGenerator {
|
||||||
return listenerName+extST.render();
|
return listenerName+extST.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A given grammar T, return a blank listener implementation
|
||||||
|
* such as BlankTListener.java, if we're using the Java target.
|
||||||
|
*/
|
||||||
|
public String getBlankListenerFileName() {
|
||||||
|
ST extST = templates.getInstanceOf("codeFileExtension");
|
||||||
|
String listenerName = "Blank" + g.name + "Listener";
|
||||||
|
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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -110,6 +110,11 @@ public class OutputModelController {
|
||||||
return new ListenerFile(delegate, gen.getListenerFileName());
|
return new ListenerFile(delegate, gen.getListenerFileName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OutputModelObject buildBlankListenerOutputModel() {
|
||||||
|
CodeGenerator gen = delegate.getGenerator();
|
||||||
|
return new BlankListenerFile(delegate, gen.getBlankListenerFileName());
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package org.antlr.v4.codegen.model;
|
||||||
|
|
||||||
|
import org.antlr.v4.codegen.OutputModelFactory;
|
||||||
|
|
||||||
|
public class BlankListenerFile extends ListenerFile {
|
||||||
|
public BlankListenerFile(OutputModelFactory factory, String fileName) {
|
||||||
|
super(factory, fileName);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package org.antlr.v4.codegen.model;
|
package org.antlr.v4.codegen.model;
|
||||||
|
|
||||||
import org.antlr.v4.codegen.OutputModelFactory;
|
import org.antlr.v4.codegen.OutputModelFactory;
|
||||||
|
import org.antlr.v4.tool.ActionAST;
|
||||||
import org.antlr.v4.tool.Grammar;
|
import org.antlr.v4.tool.Grammar;
|
||||||
import org.antlr.v4.tool.Rule;
|
import org.antlr.v4.tool.Rule;
|
||||||
|
|
||||||
|
@ -15,6 +16,8 @@ public class ListenerFile extends OutputModelObject {
|
||||||
public String parserName;
|
public String parserName;
|
||||||
public Collection<Rule> rules;
|
public Collection<Rule> rules;
|
||||||
|
|
||||||
|
@ModelElement public Action header;
|
||||||
|
|
||||||
public ListenerFile(OutputModelFactory factory, String fileName) {
|
public ListenerFile(OutputModelFactory factory, String fileName) {
|
||||||
super(factory);
|
super(factory);
|
||||||
this.fileName = fileName;
|
this.fileName = fileName;
|
||||||
|
@ -22,5 +25,7 @@ public class ListenerFile extends OutputModelObject {
|
||||||
parserName = g.getRecognizerName();
|
parserName = g.getRecognizerName();
|
||||||
grammarName = g.name;
|
grammarName = g.name;
|
||||||
rules = g.rules.values();
|
rules = g.rules.values();
|
||||||
|
ActionAST ast = g.namedActions.get("header");
|
||||||
|
if ( ast!=null ) header = new Action(factory, ast);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue