I'm trying to use ASTs with ANTLR4, with this files:
Builder.java
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.TokenStream;
public class Builder
{
public static void main(String[] args)
{
CharStream input = new ANTLRInputStream("ON M1==2 && M3 == 5 && (M2 > 1 || M5 <= 5.0) "
+ "DO P5:42 P4:10");
ExprLexer lexer = new ExprLexer(input);
TokenStream tokens = new CommonTokenStream(lexer);
ExprParser parser = new ExprParser(tokens);
parser.addParseListener(new ExprTestListener());
ExprParser.ExpressionContext uu = parser.expression();
}
}
ExprTestListener:
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.antlr.v4.runtime.tree.ErrorNode;
public class ExprTestListener extends ExprBaseListener {
@Override public void enterExpression(ExprParser.ExpressionContext ctx)
{
System.out.println(ctx);
}
@Override public void exitExpression(ExprParser.ExpressionContext ctx)
{
System.out.println(ctx);
}
@Override public void enterActionexpr(ExprParser.ActionexprContext ctx)
{
System.out.println(ctx);
}
@Override public void exitActionexpr(ExprParser.ActionexprContext ctx)
{
System.out.println(ctx);
}
@Override public void enterCondexpr(ExprParser.CondexprContext ctx)
{
System.out.println(ctx);
}
@Override public void exitCondexpr(ExprParser.CondexprContext ctx)
{
System.out.println(ctx);
}
@Override public void enterCond(ExprParser.CondContext ctx)
{
System.out.println(ctx);
}
@Override public void exitCond(ExprParser.CondContext ctx)
{
System.out.println(ctx);
}
@Override public void enterEveryRule(ParserRuleContext ctx)
{
System.out.println(ctx);
}
@Override public void exitEveryRule(ParserRuleContext ctx)
{
System.out.println(ctx);
}
@Override public void visitTerminal(TerminalNode node)
{
}
@Override public void visitErrorNode(ErrorNode node)
{
}
}
Expr.g:
grammar Expr;
options
{
// antlr will generate java lexer and parser
language = Java;
}
WS : [ \t\r\n]+ -> skip ;
OP : '&&' | '||';
COMP : '==' | '<' | '>' | '<=' | '>=' | '!=';
fragment INT : [0-9]+;
REAL : INT '.' INT | INT;
ACTION : 'P' INT ':' INT;
MEASURE : 'M' INT;
// ***************** parser rules:
cond : MEASURE COMP REAL;
condexpr : '(' condexpr ')' | cond OP condexpr | cond;
actionexpr : ACTION actionexpr | ACTION;
expression : 'ON' condexpr 'DO' actionexpr;
I have this output:
[]
[]
[29]
[29]
[16 29]
[16 29]
[16 29]
[16 29]
[18 29]
[18 29]
[16 18 29]
[16 18 29]
[16 18 29]
[16 18 29]
[18 18 29]
[18 18 29]
[13 18 18 29]
[13 18 18 29]
[16 13 18 18 29]
[16 13 18 18 29]
[16 13 18 18 29]
[16 13 18 18 29]
[18 13 18 18 29]
[18 13 18 18 29]
[20 18 13 18 18 29]
[20 18 13 18 18 29]
[20 18 13 18 18 29]
[20 18 13 18 18 29]
[18 13 18 18 29]
[18 13 18 18 29]
[13 18 18 29]
[13 18 18 29]
[18 18 29]
[18 18 29]
[18 29]
[18 29]
[29]
[29]
[31]
[31]
[24 31]
[24 31]
[24 31]
[24 31]
[31]
[31]
[]
[]
I find it hard to understand visitors with ANTLR4.
I have tree goals:
ANTLR Visitors The difference between listener and visitor mechanisms is listener methods are called by the ANTLR-provided walker object, whereas visitor methods must walk their children with explicit visit calls. Forgetting to invoke visit() on a node's children means those subtrees don't get visited.
I have created a small Java project that allows you to test your ANTLR grammar instantly by compiling the lexer and parser generated by ANTLR in-memory. You can just parse a string by passing it to the parser, and it will automatically generate an AST from it which can then be used in your application.
ANTLR helps you build intermediate form trees, or abstract syntax trees (ASTs), by providing grammar annotations that indicate what tokens are to be treated as subtree roots, which are to be leaves, and which are to be ignored with respect to tree construction.
ANTLR (ANother Tool for Language Recognition) is a tool for processing structured text. It does this by giving us access to language processing primitives like lexers, grammars, and parsers as well as the runtime to process text against them. It's often used to build tools and frameworks.
First I'll explain what you have observed above:
First and foremost, please read the documentation for the methods you call. The Parser.addParseListener
documentation includes the following note:
THIS IS ONLY FOR ADVANCED USERS. Please give your ParseTreeListener to a ParseTreeWalker instead of giving it to the parser!!!!
The implementation of toString()
for the ParserRuleContext
class simply prints the rule invocation stack at the time the context was created. You are printing this once when the listener enters a rule, and once when it exits. For actionexpr
, cond
, and condexpr
you print it again, resulting in a total of 4 identical output lines for each of those contexts.
Now some notes on your goals:
enterCond
and exitCond
, the MEASURE
text is available by calling ctx.MEASURE().getText()
.enterActionexpr
and exitActionexpr
, the ACTION
text is available by calling ctx.ACTION().getText()
.COND
token by creating a new TerminalNodeImpl
and CommonToken
for the updated token, and assigning it to the correct index in the field CondContext.children
using either a visitor or a listener.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With