java ANTLR 4 和 AST 访客
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14667781/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ANTLR 4 and AST visitors
提问by GlinesMome
I'm trying to use ASTs with ANTLR4, with this files:
我正在尝试将 AST 与 ANTLR4 一起使用,并使用以下文件:
Builder.java
生成器.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.
我发现使用 ANTLR4 很难理解访客。
I have tree goals:
我有树目标:
- Get collect INTs of MEASUREs and ACTIONs (in two different sets)
- Replace some OPs (for example != by <>)
- Get the condexpr (the top item) string with OPs remplaced (se my previous point)
- 获取 MEASURE 和 ACTION 的收集 INT(在两个不同的集合中)
- 替换一些 OP(例如 != by <>)
- 获取替换了 OP 的 condexpr(顶部项目)字符串(参见我之前的观点)
采纳答案by Tux the Ravin Penguin
A tree label you could use, to set the context of the parse and then walks the leaves of the observed graph with a visitor class and trigger methods in order to create actions from the expressions in the language source code. Thus, at the initial visitation, the listener does not process the actual visitor pattern. The actual visitor pattern and the processing through visitation is done by the methods of the expressionbase listener class extension.
您可以使用树标签来设置解析的上下文,然后使用访问者类和触发器方法遍历观察到的图的叶子,以便从语言源代码中的表达式创建操作。因此,在初始访问时,侦听器不会处理实际的访问者模式。实际的访问者模式和通过访问进行的处理是由 expressionbase 侦听器类扩展的方法完成的。
The listener identifies the expression:
侦听器识别表达式:
@Override public void enterListener(ExprParser.EXPR_CONTEXTContext ctx) {
//some code to view the compilation process
}
The expression rule gets a name label:
表达式规则获取名称标签:
'EXPR_CONTEXT' expression # EXPR_CONTEXT //the tree label
The expression walker is implemented:
表达式 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
}
The main file then walks with the walker:
然后主文件与 walker 一起走:
ParseTree tree = parser.parse(); //parse the tree
intermezzo: before applying the walker visitation pattern one may imagine tree segment optimisation- or processing patterns. The parsed tree could be handled here as a seperate induction of the source code tree. This approach enables more complicated code- and tree processing patterns.
插曲:在应用步行者访问模式之前,人们可以想象树段优化或处理模式。解析后的树可以在这里作为源代码树的单独归纳处理。这种方法支持更复杂的代码和树处理模式。
ParseTreeWalker walker = new ParseTreeWalker(); //get the walker
walker.walk(new ExprWalker(), tree); //start visiting
回答by Sam Harwell
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:
首先,请阅读您调用的方法的文档。该Parser.addParseListener
文档包括以下注释:
THIS IS ONLY FOR ADVANCED USERS. Please give your ParseTreeListener to a ParseTreeWalker instead of giving it to the parser!!!!
这仅适用于高级用户。请将您的 ParseTreeListener 提供给 ParseTreeWalker,而不是将其提供给解析器!!!!
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.
实行toString()
了ParserRuleContext
类简单地打印规则调用栈的情况下被创建的时间。当侦听器输入规则时打印一次,退出时打印一次。对于actionexpr
, cond
, 并condexpr
再次打印它,导致每个上下文总共有 4 个相同的输出行。
Now some notes on your goals:
现在就你的目标做一些说明:
- Inside of
enterCond
andexitCond
, theMEASURE
text is available by callingctx.MEASURE().getText()
. - Inside of
enterActionexpr
andexitActionexpr
, theACTION
text is available by callingctx.ACTION().getText()
. - You can change the
COND
token by creating a newTerminalNodeImpl
andCommonToken
for the updated token, and assigning it to the correct index in the fieldCondContext.children
using either a visitor or a listener.
- 在
enterCond
and内部exitCond
,MEASURE
文本可通过调用获得ctx.MEASURE().getText()
。 - 在
enterActionexpr
and内部exitActionexpr
,ACTION
文本可通过调用获得ctx.ACTION().getText()
。 - 您可以更改
COND
通过创建一个新的令牌TerminalNodeImpl
,并CommonToken
在更新的令牌,并在现场将其分配给正确的索引CondContext.children
使用一个访问者或监听。