diff --git a/CHANGES.txt b/CHANGES.txt index 82936d6771..7b178f7eb4 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -2,6 +2,10 @@ ANTLR v4 Honey Badger early access Feb 17, 2012 +* added -parse-listener option and differentiated between parse and parse + tree listener interfaces now. Only parse tree listener stuff generated + by default. + * names changed. visit() -> visitX(). enter/exit() -> enter/exitX() * capitalizing automatically now. rule s -> SContext not sContext * no enter/exit method in generic rule context object if rule has alt labels, nor in interfaces. diff --git a/runtime/Java/src/org/antlr/v4/runtime/ParseListener.java b/runtime/Java/src/org/antlr/v4/runtime/ParseListener.java new file mode 100644 index 0000000000..6821bdbe2d --- /dev/null +++ b/runtime/Java/src/org/antlr/v4/runtime/ParseListener.java @@ -0,0 +1,18 @@ +package org.antlr.v4.runtime; + +/** We must distinguish between listeners triggered during the parse + * from listeners triggered during a subsequent tree walk. During + * the parse, the ctx object arg for enter methods don't have any labels set. + * We can only access the general ParserRuleContext ctx. + * Also, we can only call exit methods for left-recursive rules. Let's + * make the interface clear these semantics up. If you need the ctx, + * use Parser.getRuleContext(). + */ +public interface ParseListener { + void visitTerminal(ParserRuleContext ctx, Symbol symbol); + + /** Enter all but left-recursive rules */ + void enterNonLRRule(ParserRuleContext ctx); + + void exitEveryRule(ParserRuleContext ctx); +} diff --git a/runtime/Java/src/org/antlr/v4/runtime/Parser.java b/runtime/Java/src/org/antlr/v4/runtime/Parser.java index 16fb7e20a8..14f5bcf7da 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/Parser.java +++ b/runtime/Java/src/org/antlr/v4/runtime/Parser.java @@ -30,18 +30,15 @@ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT import org.antlr.v4.runtime.atn.*; import org.antlr.v4.runtime.dfa.DFA; -import org.antlr.v4.runtime.misc.IntervalSet; -import org.antlr.v4.runtime.misc.Nullable; -import org.antlr.v4.runtime.tree.ParseTreeListener; +import org.antlr.v4.runtime.misc.*; -import java.util.ArrayList; -import java.util.List; +import java.util.*; /** This is all the parsing support code essentially; most of it is error recovery stuff. */ public abstract class Parser extends Recognizer> { - public class TraceListener implements ParseTreeListener { + public class TraceListener implements ParseListener { @Override - public void enterEveryRule(ParserRuleContext ctx) { + public void enterNonLRRule(ParserRuleContext ctx) { System.out.println("enter " + getRuleNames()[ctx.ruleIndex] + ", LT(1)=" + _input.LT(1).getText()); } @@ -75,7 +72,7 @@ public void visitTerminal(ParserRuleContext ctx, Token token) { * the parse or during tree walks later. Both could be done. * Not intended for tree parsing but would work. */ - protected List> _parseListeners; + protected List> _parseListeners; /** Did the recognizer encounter a syntax error? Track how many. */ protected int _syntaxErrors = 0; @@ -154,19 +151,19 @@ public boolean getBuildParseTree() { // return traceATNStates; // } - public List> getParseListeners() { + public List> getParseListeners() { return _parseListeners; } - public void addParseListener(ParseTreeListener listener) { + public void addParseListener(ParseListener listener) { if ( listener==null ) return; if ( _parseListeners==null ) { - _parseListeners = new ArrayList>(); + _parseListeners = new ArrayList>(); } this._parseListeners.add(listener); } - public void removeParseListener(ParseTreeListener l) { + public void removeParseListener(ParseListener l) { if ( l==null ) return; if ( _parseListeners!=null ) _parseListeners.remove(l); } @@ -174,8 +171,8 @@ public void removeParseListener(ParseTreeListener l) { public void removeParseListeners() { if ( _parseListeners!=null ) _parseListeners.clear(); } public void triggerEnterRuleEvent() { - for (ParseTreeListener l : _parseListeners) { - l.enterEveryRule(_ctx); + for (ParseListener l : _parseListeners) { + l.enterNonLRRule(_ctx); _ctx.enterRule(l); } } @@ -183,7 +180,7 @@ public void triggerEnterRuleEvent() { public void triggerExitRuleEvent() { // reverse order walk of listeners for (int i = _parseListeners.size()-1; i >= 0; i--) { - ParseTreeListener l = _parseListeners.get(i); + ParseListener l = _parseListeners.get(i); _ctx.exitRule(l); l.exitEveryRule(_ctx); } @@ -293,7 +290,7 @@ public Token consume() { else _ctx.addChild((Token)o); } if ( _parseListeners != null) { - for (ParseTreeListener l : _parseListeners) l.visitTerminal(_ctx, o); + for (ParseListener l : _parseListeners) l.visitTerminal(_ctx, o); } return o; } @@ -455,6 +452,8 @@ public IntervalSet getExpectedTokensWithinCurrentRule() { // return atn.nextTokens(s, ctx); // } + public ParserRuleContext getRuleContext() { return _ctx; } + /** Return List of the rule names in your parser instance * leading up to a call to the current rule. You could override if * you want more details such as the file/line info of where @@ -548,7 +547,7 @@ public void setTrace(boolean trace) { else { if ( _tracer!=null ) removeParseListener(_tracer); else _tracer = new TraceListener(); - addParseListener( _tracer ); + addParseListener(_tracer); } } } diff --git a/runtime/Java/src/org/antlr/v4/runtime/ParserRuleContext.java b/runtime/Java/src/org/antlr/v4/runtime/ParserRuleContext.java index c3bdc86348..b5df150445 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/ParserRuleContext.java +++ b/runtime/Java/src/org/antlr/v4/runtime/ParserRuleContext.java @@ -128,10 +128,18 @@ public ParserRuleContext(@Nullable ParserRuleContext parent, int stateNu // Double dispatch methods for listeners and visitors + // parse listener + public void enterRule(ParseListener listener) { } + public void exitRule(ParseListener listener) { } + + // parse tree listener public void enterRule(ParseTreeListener listener) { } public void exitRule(ParseTreeListener listener) { } + + // visitor public T accept(ParseTreeVisitor visitor) { visitor.visitChildren(this); return null; } + /** Does not set parent link; other add methods do */ public void addChild(TerminalNode t) { if ( children==null ) children = new ArrayList(); diff --git a/tool/playground/A.g4 b/tool/playground/A.g4 index c62a6be7c9..0683b06588 100644 --- a/tool/playground/A.g4 +++ b/tool/playground/A.g4 @@ -5,16 +5,8 @@ s : e ; e : e '*' e -> Mult | e '+' e -> Add | INT -> primary - | ID -> primary | '(' e ')' -> Parens ; -/* -primary : EEE; - -add : A ; -*/ - -ID : [a-z]+ ; INT : [0-9]+ ; WS : [ \t\n]+ -> skip ; diff --git a/tool/playground/AVisitor.java b/tool/playground/AVisitor.java index 42686165fa..dd70dbfcd0 100644 --- a/tool/playground/AVisitor.java +++ b/tool/playground/AVisitor.java @@ -1,3 +1,6 @@ +import org.antlr.v4.runtime.tree.*; +import org.antlr.v4.runtime.Token; + public interface AVisitor { T visitMult(AParser.MultContext ctx); T visitParens(AParser.ParensContext ctx); diff --git a/tool/playground/TestA.java b/tool/playground/TestA.java index 8798d31bf4..da3d96087c 100644 --- a/tool/playground/TestA.java +++ b/tool/playground/TestA.java @@ -145,6 +145,16 @@ public void visitTerminal(ParserRuleContext ctx, Token symbol) { printMethodName(ctx); } + @Override + public void enterPrimary(AParser.PrimaryContext ctx) { + printMethodName(ctx); + } + + @Override + public void exitPrimary(AParser.PrimaryContext ctx) { + printMethodName(ctx); + } + public void printMethodName(ParserRuleContext ctx) { Throwable t = new Throwable(); StackTraceElement[] stack = t.getStackTrace(); @@ -161,7 +171,7 @@ public static void main(String[] args) throws Exception { CommonTokenStream tokens = new CommonTokenStream(lexer); AParser p = new AParser(tokens); p.setBuildParseTree(true); - p.addParseListener(new Tracer()); +// p.addParseListener(new Tracer()); ParserRuleContext t = p.s(); System.out.println("tree = "+t.toStringTree(p)); diff --git a/tool/playground/TestA2.java b/tool/playground/TestA2.java index 0c36d13478..4c4f20ca75 100644 --- a/tool/playground/TestA2.java +++ b/tool/playground/TestA2.java @@ -43,25 +43,25 @@ public static class Do extends A2BaseListener { A2Parser p; public Do(A2Parser p) { this.p = p; } @Override - public void exit(A2Parser.AddContext ctx) { + public void exitAdd(A2Parser.AddContext ctx) { ctx.v = ctx.e(0).v + ctx.e(1).v; System.out.println("Add: " + ctx.v); } @Override - public void exit(A2Parser.IntContext ctx) { + public void exitInt(A2Parser.IntContext ctx) { ctx.v = Integer.valueOf(ctx.INT().getText()); System.out.println("Int: "+ctx.v); } @Override - public void exit(A2Parser.MultContext ctx) { + public void exitMult(A2Parser.MultContext ctx) { ctx.v = ctx.e(0).v * ctx.e(1).v; System.out.println("Mult: " + ctx.v); } @Override - public void exit(A2Parser.ParensContext ctx) { + public void exitParens(A2Parser.ParensContext ctx) { ctx.v = ctx.e().v; System.out.println("Parens: "+ctx.v); } @@ -71,14 +71,13 @@ public static void main(String[] args) throws Exception { CommonTokenStream tokens = new CommonTokenStream(lexer); A2Parser p = new A2Parser(tokens); p.setBuildParseTree(true); - p.addParseListener(new Do(p)); ParserRuleContext t = p.s(); System.out.println("tree = "+t.toStringTree(p)); ParseTreeWalker walker = new ParseTreeWalker(); Do doer = new Do(p); walker.walk(doer, t); - A2Parser.eContext ectx = (A2Parser.eContext)t.getChild(0); + A2Parser.EContext ectx = (A2Parser.EContext)t.getChild(0); System.out.println("result from tree walk = "+ ectx.v); } } diff --git a/tool/playground/TestVisitor.java b/tool/playground/TestVisitor.java index 4fd8f71f3d..e417cb2af5 100644 --- a/tool/playground/TestVisitor.java +++ b/tool/playground/TestVisitor.java @@ -33,24 +33,27 @@ public class TestVisitor { public static class MyVisitor extends ABaseVisitor implements AVisitor { @Override public Integer visitAdd(AParser.AddContext ctx) { - return ctx.e(0).accept(this) + ctx.e(1).accept(this); + return visit(ctx.e(0)) + visit(ctx.e(1)); } @Override public Integer visitMult(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 visitParens(AParser.ParensContext ctx) { - return ctx.e().accept(this); + return visit(ctx.e()); } @Override public Integer visitS(AParser.SContext ctx) { return visit(ctx.e()); - //return ctx.e().accept(this); + } + + @Override + public Integer visitPrimary(AParser.PrimaryContext ctx) { + return Integer.valueOf(ctx.INT().getText()); } } 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 8896567ec0..7f7efaff65 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 @@ -47,12 +47,42 @@ import org.antlr.v4.runtime.Token; public class BaseListener implements Listener { (.Context ctx) { \} -@Override public void exit(.Context ctx) { \}}; separator="\n"> +public void enter(.Context ctx) { \} +public void exit(.Context ctx) { \}}; separator="\n"> - @Override public void enterEveryRule(ParserRuleContext\<\> ctx) { } - @Override public void exitEveryRule(ParserRuleContext\<\> ctx) { } - @Override public void visitTerminal(ParserRuleContext\<\> ctx, symbol) { } + public void enterEveryRule(ParserRuleContext\<\> ctx) { } + public void exitEveryRule(ParserRuleContext\<\> ctx) { } + public void visitTerminal(ParserRuleContext\<\> ctx, symbol) { } +} +>> + +ParseListenerFile(file, header) ::= << +
+import org.antlr.v4.runtime.tree.*; +import org.antlr.v4.runtime.*; + +public interface ParseListener extends ParseListener\<\> { + (ParseListener\<\> ctx);}; separator="\n"> + (.Context ctx);}; separator="\n"> +} +>> + +BaseParseListenerFile(file, header) ::= << +
+ +import org.antlr.v4.runtime.*; + +public class BaseParseListener implements ParseListener { + (ParseListener\<\> ctx) { \}}; separator="\n"> + (.Context ctx) { \}}; separator="\n"> + + public void enterNonLRRule(ParserRuleContext\<\> ctx) { } + public void exitEveryRule(ParserRuleContext\<\> ctx) { } + public void visitTerminal(ParserRuleContext\<\> ctx, symbol) { } } >> @@ -587,14 +617,12 @@ public static class extends Contex >> ListenerDispatchMethod(method) ::= << -@Override public void enterexitRule(ParseTreeListener\<\> listener) { if ( listener instanceof Listener ) ((Listener)listener).enterexit(this); } >> VisitorDispatchMethod(method) ::= << -@Override public \ T accept(ParseTreeVisitor\ visitor) { if ( visitor instanceof Visitor ) return ((Visitor\)visitor).visit(this); else return null; diff --git a/tool/src/org/antlr/v4/Tool.java b/tool/src/org/antlr/v4/Tool.java index 34172f8f3e..14b336fade 100644 --- a/tool/src/org/antlr/v4/Tool.java +++ b/tool/src/org/antlr/v4/Tool.java @@ -31,29 +31,18 @@ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT import org.antlr.runtime.*; import org.antlr.v4.analysis.AnalysisPipeline; -import org.antlr.v4.automata.ATNFactory; -import org.antlr.v4.automata.LexerATNFactory; -import org.antlr.v4.automata.ParserATNFactory; +import org.antlr.v4.automata.*; import org.antlr.v4.codegen.CodeGenPipeline; -import org.antlr.v4.parse.ANTLRLexer; -import org.antlr.v4.parse.ANTLRParser; -import org.antlr.v4.parse.GrammarASTAdaptor; -import org.antlr.v4.parse.ToolANTLRParser; -import org.antlr.v4.runtime.misc.LogManager; -import org.antlr.v4.runtime.misc.Nullable; +import org.antlr.v4.parse.*; +import org.antlr.v4.runtime.misc.*; import org.antlr.v4.semantics.SemanticPipeline; import org.antlr.v4.tool.*; -import org.antlr.v4.tool.ast.GrammarAST; -import org.antlr.v4.tool.ast.GrammarASTErrorNode; -import org.antlr.v4.tool.ast.GrammarRootAST; +import org.antlr.v4.tool.ast.*; import org.stringtemplate.v4.STGroup; import java.io.*; import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.List; +import java.util.*; public class Tool { public String VERSION = "4.0-"+new Date(); @@ -96,6 +85,7 @@ public Option(String fieldName, String name, OptionArgType argType, String descr public boolean verbose_dfa = false; public boolean no_auto_element_labels = false; public boolean gen_listener = true; + public boolean gen_parse_listener = false; public boolean gen_visitor = false; public static Option[] optionDefs = { @@ -110,6 +100,8 @@ public Option(String fieldName, String name, OptionArgType argType, String descr new Option("msgFormat", "-message-format", OptionArgType.STRING, "specify output style for messages"), new Option("gen_listener", "-listener", "generate parse tree listener (default)"), new Option("gen_listener", "-no-listener", "don't generate parse tree listener"), + new Option("gen_parse_listener", "-parse-listener", "generate parse listener"), + new Option("gen_parse_listener", "-no-parse-listener", "don't generate parse listener (default)"), new Option("gen_visitor", "-visitor", "generate parse tree visitor"), new Option("gen_visitor", "-no-visitor", "don't generate parse tree visitor (default)"), diff --git a/tool/src/org/antlr/v4/codegen/CodeGenPipeline.java b/tool/src/org/antlr/v4/codegen/CodeGenPipeline.java index 6b2286738f..51165399ae 100644 --- a/tool/src/org/antlr/v4/codegen/CodeGenPipeline.java +++ b/tool/src/org/antlr/v4/codegen/CodeGenPipeline.java @@ -30,6 +30,7 @@ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT package org.antlr.v4.codegen; import org.antlr.v4.tool.Grammar; +import org.stringtemplate.v4.ST; public class CodeGenPipeline { Grammar g; @@ -42,14 +43,22 @@ public void process() { CodeGenerator gen = new CodeGenerator(g); if ( g.isLexer() ) { - gen.writeRecognizer(gen.generateLexer()); + ST lexer = gen.generateLexer(); + if ( g.tool.launch_ST_inspector ) lexer.inspect(); + gen.writeRecognizer(lexer); } else { - gen.writeRecognizer(gen.generateParser()); + ST parser = gen.generateParser(); + if ( g.tool.launch_ST_inspector ) parser.inspect(); + gen.writeRecognizer(parser); if ( g.tool.gen_listener ) { gen.writeListener(gen.generateListener()); gen.writeBaseListener(gen.generateBaseListener()); } + if ( g.tool.gen_parse_listener ) { + gen.writeParseListener(gen.generateParseListener()); + gen.writeBaseParseListener(gen.generateBaseParseListener()); + } if ( g.tool.gen_visitor ) { gen.writeVisitor(gen.generateVisitor()); gen.writeBaseVisitor(gen.generateBaseVisitor()); diff --git a/tool/src/org/antlr/v4/codegen/CodeGenerator.java b/tool/src/org/antlr/v4/codegen/CodeGenerator.java index 418f7c8340..71c1454e60 100644 --- a/tool/src/org/antlr/v4/codegen/CodeGenerator.java +++ b/tool/src/org/antlr/v4/codegen/CodeGenerator.java @@ -114,100 +114,35 @@ public void loadTemplates(String language) { } // CREATE TEMPLATES BY WALKING MODEL - public ST generateLexer() { - OutputModelFactory factory = new LexerFactory(this); - // CREATE OUTPUT MODEL FROM GRAMMAR OBJ AND AST WITHIN RULES - OutputModelController controller = new OutputModelController(factory); - factory.setController(controller); - - OutputModelObject outputModel = controller.buildLexerOutputModel(); - - OutputModelWalker walker = new OutputModelWalker(tool, templates); - ST st = walker.walk(outputModel); - - if ( tool.launch_ST_inspector ) { - st.inspect(); - //if ( templates.isDefined("headerFile") ) headerFileST.inspect(); - } - -// String x = ATNSerializer.getDecoded(g, g.atn); -// System.out.println(x); - - return st; - } - - public ST generateParser() { + public ST generateModelST(String factoryMethod) { OutputModelFactory factory = new ParserFactory(this); // CREATE OUTPUT MODEL FROM GRAMMAR OBJ AND AST WITHIN RULES OutputModelController controller = new OutputModelController(factory); factory.setController(controller); - OutputModelObject outputModel = controller.buildParserOutputModel(); - - OutputModelWalker walker = new OutputModelWalker(tool, templates); - ST st = walker.walk(outputModel); - - if ( tool.launch_ST_inspector ) { - st.inspect(); - //if ( templates.isDefined("headerFile") ) headerFileST.inspect(); + OutputModelObject outputModel = null; + try { + Method m = OutputModelController.class.getDeclaredMethod(factoryMethod); + outputModel = (OutputModelObject)m.invoke(controller); + } + catch (Exception e) { + tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, "can't exec factory method", e); } - - return st; - } - - public ST generateListener() { - OutputModelFactory factory = new ParserFactory(this); - - OutputModelController controller = new OutputModelController(factory); - factory.setController(controller); - - OutputModelObject listenerModel = controller.buildListenerOutputModel(); - - OutputModelWalker walker = new OutputModelWalker(tool, templates); - ST st = walker.walk(listenerModel); - return st; - } - - public ST generateVisitor() { - OutputModelFactory factory = new ParserFactory(this); - - OutputModelController controller = new OutputModelController(factory); - factory.setController(controller); - - OutputModelObject visitorModel = controller.buildVisitorOutputModel(); - - OutputModelWalker walker = new OutputModelWalker(tool, templates); - ST st = walker.walk(visitorModel); - return st; - } - - public ST generateBaseListener() { - OutputModelFactory factory = new ParserFactory(this); - - OutputModelController controller = new OutputModelController(factory); - factory.setController(controller); - - OutputModelObject baseModel = controller.buildBaseListenerOutputModel(); OutputModelWalker walker = new OutputModelWalker(tool, templates); - ST st = walker.walk(baseModel); - return st; + return walker.walk(outputModel); } - 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; - } + public ST generateLexer() { return generateModelST("buildLexerOutputModel"); } + public ST generateParser() { return generateModelST("buildParserOutputModel"); } + public ST generateListener() { return generateModelST("buildListenerOutputModel"); } + public ST generateBaseListener() { return generateModelST("buildBaseListenerOutputModel"); } + public ST generateParseListener() { return generateModelST("buildParseListenerOutputModel"); } + public ST generateBaseParseListener() { return generateModelST("buildBaseParseListenerOutputModel"); } + public ST generateVisitor() { return generateModelST("buildVisitorOutputModel"); } + public ST generateBaseVisitor() { return generateModelST("buildBaseVisitorOutputModel"); } /** Generate a token vocab file with all the token names/types. For example: * ID=7 @@ -253,6 +188,14 @@ public void writeBaseListener(ST outputFileST) { target.genFile(g,outputFileST, getBaseListenerFileName()); } + public void writeParseListener(ST outputFileST) { + target.genFile(g,outputFileST, getParseListenerFileName()); + } + + public void writeBaseParseListener(ST outputFileST) { + target.genFile(g,outputFileST, getBaseParseListenerFileName()); + } + public void writeVisitor(ST outputFileST) { target.genFile(g,outputFileST, getVisitorFileName()); } @@ -360,6 +303,20 @@ public String getBaseListenerFileName() { return listenerName+extST.render(); } + public String getParseListenerFileName() { + assert g.name != null; + ST extST = templates.getInstanceOf("codeFileExtension"); + String listenerName = g.name + "ParseListener"; + return listenerName+extST.render(); + } + + public String getBaseParseListenerFileName() { + assert g.name != null; + ST extST = templates.getInstanceOf("codeFileExtension"); + String listenerName = g.name + "BaseParseListener"; + return listenerName+extST.render(); + } + /** A given grammar T, return a blank listener implementation * such as TBaseListener.java, if we're using the Java target. */ diff --git a/tool/src/org/antlr/v4/codegen/OutputModelController.java b/tool/src/org/antlr/v4/codegen/OutputModelController.java index b8894b2b94..c3c61e2a44 100644 --- a/tool/src/org/antlr/v4/codegen/OutputModelController.java +++ b/tool/src/org/antlr/v4/codegen/OutputModelController.java @@ -114,6 +114,16 @@ public OutputModelObject buildBaseListenerOutputModel() { return new BaseListenerFile(delegate, gen.getBaseListenerFileName()); } + public OutputModelObject buildParseListenerOutputModel() { + CodeGenerator gen = delegate.getGenerator(); + return new ParseListenerFile(delegate, gen.getParseListenerFileName()); + } + + public OutputModelObject buildBaseParseListenerOutputModel() { + CodeGenerator gen = delegate.getGenerator(); + return new BaseParseListenerFile(delegate, gen.getBaseParseListenerFileName()); + } + public OutputModelObject buildVisitorOutputModel() { CodeGenerator gen = delegate.getGenerator(); return new VisitorFile(delegate, gen.getVisitorFileName()); diff --git a/tool/src/org/antlr/v4/codegen/model/BaseParseListenerFile.java b/tool/src/org/antlr/v4/codegen/model/BaseParseListenerFile.java new file mode 100644 index 0000000000..c653250bc4 --- /dev/null +++ b/tool/src/org/antlr/v4/codegen/model/BaseParseListenerFile.java @@ -0,0 +1,9 @@ +package org.antlr.v4.codegen.model; + +import org.antlr.v4.codegen.OutputModelFactory; + +public class BaseParseListenerFile extends ParseListenerFile { + public BaseParseListenerFile(OutputModelFactory factory, String fileName) { + super(factory, fileName); + } +} diff --git a/tool/src/org/antlr/v4/codegen/model/ParseListenerFile.java b/tool/src/org/antlr/v4/codegen/model/ParseListenerFile.java new file mode 100644 index 0000000000..268751f6ba --- /dev/null +++ b/tool/src/org/antlr/v4/codegen/model/ParseListenerFile.java @@ -0,0 +1,46 @@ +package org.antlr.v4.codegen.model; + +import org.antlr.v4.codegen.OutputModelFactory; +import org.antlr.v4.misc.Triple; +import org.antlr.v4.tool.*; +import org.antlr.v4.tool.ast.*; + +import java.util.*; + +public class ParseListenerFile extends OutputFile { + public String grammarName; + public String parserName; + public Set listenerEnterNames = new HashSet(); + public Set listenerExitNames = new HashSet(); + + @ModelElement public Action header; + + public ParseListenerFile(OutputModelFactory factory, String fileName) { + super(factory, fileName); + Grammar g = factory.getGrammar(); + parserName = g.getRecognizerName(); + grammarName = g.name; + for (Rule r : g.rules.values()) { + List> labels = r.getAltLabels(); + // EXIT RULES + if ( labels!=null ) { + // add exit rules for alt labels + for (Triple pair : labels) { + listenerExitNames.add(pair.c); + if ( !(r instanceof LeftRecursiveRule) ) { + listenerEnterNames.add(pair.c); + } + } + } + else { + // add exit rule if no labels + listenerExitNames.add(r.name); + if ( !(r instanceof LeftRecursiveRule) ) { + listenerEnterNames.add(r.name); + } + } + } + ActionAST ast = g.namedActions.get("header"); + if ( ast!=null ) header = new Action(factory, ast); + } +} diff --git a/tool/src/org/antlr/v4/codegen/model/decl/AltLabelStructDecl.java b/tool/src/org/antlr/v4/codegen/model/decl/AltLabelStructDecl.java index 75308aeb4d..35bc77dcb4 100644 --- a/tool/src/org/antlr/v4/codegen/model/decl/AltLabelStructDecl.java +++ b/tool/src/org/antlr/v4/codegen/model/decl/AltLabelStructDecl.java @@ -30,9 +30,11 @@ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT package org.antlr.v4.codegen.model.decl; import org.antlr.v4.codegen.OutputModelFactory; -import org.antlr.v4.codegen.model.VisitorDispatchMethod; +import org.antlr.v4.codegen.model.*; import org.antlr.v4.tool.Rule; +import java.util.ArrayList; + /** A StructDecl to handle a -> label on alt */ public class AltLabelStructDecl extends StructDecl { public int altNum; @@ -42,13 +44,15 @@ public AltLabelStructDecl(OutputModelFactory factory, Rule r, super(factory, r); this.altNum = altNum; this.name = // override name set in super to the label ctx - factory.getGenerator().target.getAltLabelContextStructName(label); + factory.getGenerator().target.getAltLabelContextStructName(label); derivedFromName = label; } @Override public void addDispatchMethods(Rule r) { - super.addDispatchMethods(r); + dispatchMethods = new ArrayList(); + dispatchMethods.add(new ListenerDispatchMethod(factory, true)); + dispatchMethods.add(new ListenerDispatchMethod(factory, false)); if ( factory.getGrammar().tool.gen_visitor ) { dispatchMethods.add(new VisitorDispatchMethod(factory)); } diff --git a/tool/test/org/antlr/v4/test/TestPerformance.java b/tool/test/org/antlr/v4/test/TestPerformance.java index c6c7afc863..a8c9d34763 100644 --- a/tool/test/org/antlr/v4/test/TestPerformance.java +++ b/tool/test/org/antlr/v4/test/TestPerformance.java @@ -29,30 +29,17 @@ package org.antlr.v4.test; import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.atn.*; +import org.antlr.v4.runtime.dfa.*; 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.tree.ParseTreeWalker; -import org.junit.Assert; -import org.junit.Test; +import org.antlr.v4.runtime.tree.*; +import org.junit.*; import java.io.*; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; -import org.antlr.v4.runtime.atn.ATNConfig; -import org.antlr.v4.runtime.atn.ParserATNSimulator; -import org.antlr.v4.runtime.dfa.DFA; -import org.antlr.v4.runtime.dfa.DFAState; +import java.lang.reflect.*; +import java.net.*; +import java.util.*; +import java.util.logging.*; public class TestPerformance extends BaseTest { /** Parse all java files under this package within the JDK_SOURCE_ROOT. */ @@ -461,7 +448,8 @@ public void parseFile(CharStream input) { sharedParser = parserCtor.newInstance(tokens); sharedParser.setBuildParseTree(BUILD_PARSE_TREES); if (!BUILD_PARSE_TREES && BLANK_LISTENER) { - sharedParser.addParseListener(sharedListener); + // TJP commented out for now; changed interface +// sharedParser.addParseListener(sharedListener); } if (BAIL_ON_ERROR) { sharedParser.setErrorHandler(new BailErrorStrategy());