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:
parrt 2011-09-08 13:45:05 -08:00
parent da7e7c8813
commit 2d234ee28c
9 changed files with 96 additions and 76 deletions

View File

@ -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);
} }

View File

@ -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); }
}
*/

View File

@ -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);
} }
} }

View File

@ -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); }
} }
>> >>

View File

@ -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();

View File

@ -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.
*/ */

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);
} }
} }