Skip to content

Commit

Permalink
Merge pull request #22 from parrt/master
Browse files Browse the repository at this point in the history
added -parse-listener option, interfaces; fixes #18
  • Loading branch information
parrt committed Feb 19, 2012
2 parents 9b49005 + 65bd541 commit 9792b36
Show file tree
Hide file tree
Showing 18 changed files with 247 additions and 168 deletions.
4 changes: 4 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
18 changes: 18 additions & 0 deletions runtime/Java/src/org/antlr/v4/runtime/ParseListener.java
Original file line number Diff line number Diff line change
@@ -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<Symbol> 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<Symbol> {
void visitTerminal(ParserRuleContext<Symbol> ctx, Symbol symbol);

/** Enter all but left-recursive rules */
void enterNonLRRule(ParserRuleContext<Symbol> ctx);

void exitEveryRule(ParserRuleContext<Symbol> ctx);
}
33 changes: 16 additions & 17 deletions runtime/Java/src/org/antlr/v4/runtime/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<Token, ParserATNSimulator<Token>> {
public class TraceListener implements ParseTreeListener<Token> {
public class TraceListener implements ParseListener<Token> {
@Override
public void enterEveryRule(ParserRuleContext<Token> ctx) {
public void enterNonLRRule(ParserRuleContext<Token> ctx) {
System.out.println("enter " + getRuleNames()[ctx.ruleIndex] + ", LT(1)=" + _input.LT(1).getText());
}

Expand Down Expand Up @@ -75,7 +72,7 @@ public void visitTerminal(ParserRuleContext<Token> ctx, Token token) {
* the parse or during tree walks later. Both could be done.
* Not intended for tree parsing but would work.
*/
protected List<ParseTreeListener<Token>> _parseListeners;
protected List<ParseListener<Token>> _parseListeners;

/** Did the recognizer encounter a syntax error? Track how many. */
protected int _syntaxErrors = 0;
Expand Down Expand Up @@ -154,36 +151,36 @@ public boolean getBuildParseTree() {
// return traceATNStates;
// }

public List<ParseTreeListener<Token>> getParseListeners() {
public List<ParseListener<Token>> getParseListeners() {
return _parseListeners;
}

public void addParseListener(ParseTreeListener<Token> listener) {
public void addParseListener(ParseListener<Token> listener) {
if ( listener==null ) return;
if ( _parseListeners==null ) {
_parseListeners = new ArrayList<ParseTreeListener<Token>>();
_parseListeners = new ArrayList<ParseListener<Token>>();
}
this._parseListeners.add(listener);
}

public void removeParseListener(ParseTreeListener<Token> l) {
public void removeParseListener(ParseListener<Token> l) {
if ( l==null ) return;
if ( _parseListeners!=null ) _parseListeners.remove(l);
}

public void removeParseListeners() { if ( _parseListeners!=null ) _parseListeners.clear(); }

public void triggerEnterRuleEvent() {
for (ParseTreeListener<Token> l : _parseListeners) {
l.enterEveryRule(_ctx);
for (ParseListener<Token> l : _parseListeners) {
l.enterNonLRRule(_ctx);
_ctx.enterRule(l);
}
}

public void triggerExitRuleEvent() {
// reverse order walk of listeners
for (int i = _parseListeners.size()-1; i >= 0; i--) {
ParseTreeListener<Token> l = _parseListeners.get(i);
ParseListener<Token> l = _parseListeners.get(i);
_ctx.exitRule(l);
l.exitEveryRule(_ctx);
}
Expand Down Expand Up @@ -293,7 +290,7 @@ public Token consume() {
else _ctx.addChild((Token)o);
}
if ( _parseListeners != null) {
for (ParseTreeListener<Token> l : _parseListeners) l.visitTerminal(_ctx, o);
for (ParseListener<Token> l : _parseListeners) l.visitTerminal(_ctx, o);
}
return o;
}
Expand Down Expand Up @@ -455,6 +452,8 @@ public IntervalSet getExpectedTokensWithinCurrentRule() {
// return atn.nextTokens(s, ctx);
// }

public ParserRuleContext<Token> getRuleContext() { return _ctx; }

/** Return List<String> 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
Expand Down Expand Up @@ -548,7 +547,7 @@ public void setTrace(boolean trace) {
else {
if ( _tracer!=null ) removeParseListener(_tracer);
else _tracer = new TraceListener();
addParseListener( _tracer );
addParseListener(_tracer);
}
}
}
8 changes: 8 additions & 0 deletions runtime/Java/src/org/antlr/v4/runtime/ParserRuleContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,18 @@ public ParserRuleContext(@Nullable ParserRuleContext<Symbol> parent, int stateNu

// Double dispatch methods for listeners and visitors

// parse listener
public void enterRule(ParseListener<Symbol> listener) { }
public void exitRule(ParseListener<Symbol> listener) { }

// parse tree listener
public void enterRule(ParseTreeListener<Symbol> listener) { }
public void exitRule(ParseTreeListener<Symbol> listener) { }

// visitor
public <T> T accept(ParseTreeVisitor<? extends T> visitor) { visitor.visitChildren(this); return null; }


/** Does not set parent link; other add methods do */
public void addChild(TerminalNode<Symbol> t) {
if ( children==null ) children = new ArrayList<ParseTree>();
Expand Down
8 changes: 0 additions & 8 deletions tool/playground/A.g4
Original file line number Diff line number Diff line change
Expand Up @@ -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 ;
3 changes: 3 additions & 0 deletions tool/playground/AVisitor.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import org.antlr.v4.runtime.tree.*;
import org.antlr.v4.runtime.Token;

public interface AVisitor<T> {
T visitMult(AParser.MultContext ctx);
T visitParens(AParser.ParensContext ctx);
Expand Down
12 changes: 11 additions & 1 deletion tool/playground/TestA.java
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,16 @@ public void visitTerminal(ParserRuleContext<Token> 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();
Expand All @@ -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<Token> t = p.s();
System.out.println("tree = "+t.toStringTree(p));

Expand Down
11 changes: 5 additions & 6 deletions tool/playground/TestA2.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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<Token> 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);
}
}
11 changes: 7 additions & 4 deletions tool/playground/TestVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,27 @@ public class TestVisitor {
public static class MyVisitor extends ABaseVisitor<Integer> implements AVisitor<Integer> {
@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());
}
}

Expand Down
42 changes: 35 additions & 7 deletions tool/resources/org/antlr/v4/tool/templates/codegen/Java/Java.stg
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,42 @@ import org.antlr.v4.runtime.Token;

public class <file.grammarName>BaseListener implements <file.grammarName>Listener {
<file.listenerNames:{lname |
@Override public void enter<lname; format="cap">(<file.parserName>.<lname; format="cap">Context ctx) { \}
@Override public void exit<lname; format="cap">(<file.parserName>.<lname; format="cap">Context ctx) { \}}; separator="\n">
public void enter<lname; format="cap">(<file.parserName>.<lname; format="cap">Context ctx) { \}
public void exit<lname; format="cap">(<file.parserName>.<lname; format="cap">Context ctx) { \}}; separator="\n">

@Override public void enterEveryRule(ParserRuleContext\<<InputSymbolType()>\> ctx) { }
@Override public void exitEveryRule(ParserRuleContext\<<InputSymbolType()>\> ctx) { }
@Override public void visitTerminal(ParserRuleContext\<<InputSymbolType()>\> ctx, <InputSymbolType()> symbol) { }
public void enterEveryRule(ParserRuleContext\<<InputSymbolType()>\> ctx) { }
public void exitEveryRule(ParserRuleContext\<<InputSymbolType()>\> ctx) { }
public void visitTerminal(ParserRuleContext\<<InputSymbolType()>\> ctx, <InputSymbolType()> symbol) { }
}
>>

ParseListenerFile(file, header) ::= <<
<header>
import org.antlr.v4.runtime.tree.*;
import org.antlr.v4.runtime.*;

public interface <file.grammarName>ParseListener extends ParseListener\<<InputSymbolType()>\> {
<file.listenerEnterNames:{lname |
void enter<lname; format="cap">(ParseListener\<<InputSymbolType()>\> ctx);}; separator="\n">
<file.listenerExitNames:{lname |
void exit<lname; format="cap">(<file.parserName>.<lname; format="cap">Context ctx);}; separator="\n">
}
>>

BaseParseListenerFile(file, header) ::= <<
<header>

import org.antlr.v4.runtime.*;

public class <file.grammarName>BaseParseListener implements <file.grammarName>ParseListener {
<file.listenerEnterNames:{lname |
public void enter<lname; format="cap">(ParseListener\<<InputSymbolType()>\> ctx) { \}}; separator="\n">
<file.listenerExitNames:{lname |
public void exit<lname; format="cap">(<file.parserName>.<lname; format="cap">Context ctx) { \}}; separator="\n">

public void enterNonLRRule(ParserRuleContext\<<InputSymbolType()>\> ctx) { }
public void exitEveryRule(ParserRuleContext\<<InputSymbolType()>\> ctx) { }
public void visitTerminal(ParserRuleContext\<<InputSymbolType()>\> ctx, <InputSymbolType()> symbol) { }
}
>>

Expand Down Expand Up @@ -587,14 +617,12 @@ public static class <struct.name> extends <currentRule.name; format="cap">Contex
>>

ListenerDispatchMethod(method) ::= <<
@Override
public void <if(method.isEnter)>enter<else>exit<endif>Rule(ParseTreeListener\<<InputSymbolType()>\> listener) {
if ( listener instanceof <parser.grammarName>Listener ) ((<parser.grammarName>Listener)listener).<if(method.isEnter)>enter<else>exit<endif><struct.derivedFromName; format="cap">(this);
}
>>

VisitorDispatchMethod(method) ::= <<
@Override
public \<T> T accept(ParseTreeVisitor\<? extends T> visitor) {
if ( visitor instanceof <parser.grammarName>Visitor ) return ((<parser.grammarName>Visitor\<T>)visitor).visit<struct.derivedFromName; format="cap">(this);
else return null;
Expand Down
24 changes: 8 additions & 16 deletions tool/src/org/antlr/v4/Tool.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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 = {
Expand All @@ -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)"),

Expand Down
Loading

0 comments on commit 9792b36

Please sign in to comment.