我正在尝试将AST与ANTLR4一起使用,包含以下文件:
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;
我有这个输出:
[]
[]
[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]
[]
[]
我发现用ANTLR4很难理解访客。
我有树目标:
答案 0 :(得分:11)
首先,我将解释您在上面观察到的内容:
首先,请阅读您调用的方法的文档。 Parser.addParseListener
文档包含以下注释:
这仅适用于高级用户。请将ParseTreeListener提供给ParseTreeWalker,而不是将其提供给解析器!!!!
toString()
类的ParserRuleContext
的实现只是在创建上下文时打印规则调用堆栈。当收听者输入规则时,以及退出时,您将打印一次。对于actionexpr
,cond
和condexpr
,您再次打印它,导致每个上下文总共有4条相同的输出行。
现在有一些关于你的目标的说明:
enterCond
和exitCond
内,通过拨打MEASURE
可以获得ctx.MEASURE().getText()
文字。enterActionexpr
和exitActionexpr
内,通过拨打ACTION
可以获得ctx.ACTION().getText()
文字。COND
和TerminalNodeImpl
来更改CommonToken
令牌,并使用以下任一标志将其分配到字段CondContext.children
中的正确索引访客或听众。</ li>
答案 1 :(得分:1)
您可以使用的树标签,用于设置解析的上下文,然后使用访问者类和触发器方法遍历观察图的叶子,以便根据语言源代码中的表达式创建操作。因此,在初始访问时,收听者不处理实际的访问者模式。实际的访问者模式和访问处理是通过expressionbase listener类扩展的方法完成的。
侦听器识别表达式:
@Override public void enterListener(ExprParser.EXPR_CONTEXTContext ctx) {
//some code to view the compilation process
}
表达式规则获取名称标签:
'EXPR_CONTEXT' expression # EXPR_CONTEXT //the tree label
表达式walker已实现:
public class ExprWalker extends ExprBaseListener {
@Override
public void enterListener(ExprParser.EXPR_CONTEXTContext ctx) {
java.util.List<ExprParser.ExpressionContext> e = ctx.expression();
System.out.println("EXPRESSION: " //print action
+ e.get(0).getText() + ", " //first element
+ e.get(1).getText() //second element
+ ", " + ... + ", " //number of elements
+ e.get(N).getText()); //last element
}
然后主文件随助行者一起走:
ParseTree tree = parser.parse(); //parse the tree
intermezzo:在应用walker访问模式之前,可以想象树段优化或处理模式。解析的树可以在这里作为源代码树的单独归纳处理。这种方法可以实现更复杂的代码和树处理模式。
ParseTreeWalker walker = new ParseTreeWalker(); //get the walker
walker.walk(new ExprWalker(), tree); //start visiting