ANTLR 4树注入/重写操作符

时间:2013-01-28 15:50:45

标签: antlr antlr3 antlr4

在ANTLR 3中,您可以执行以下操作:

    andExpression
  :  (andnotExpression        -> andnotExpression)
     (AND? a=andnotExpression -> ^(AndNode $andExpression $a))* 
  ;

知道如何在新版本中执行此操作吗?

2 个答案:

答案 0 :(得分:29)

如Sam(280Z28)所述,ANTLR 4没有重写操作符。

生成解析器时,ANTLR 4会创建一些侦听器类,您可以使用它们来侦听所有解析器规则的“enter”和“exit”事件。

此外,ANTLR 4支持“直接左递归规则”,因此您的表达式规则可以在单个规则中定义,如下所示:

grammar Expr;

parse
 : expression EOF
 ;

expression
 : '(' expression ')'
 | IDENTIFIER
 | NOT expression
 | expression AND? expression
 | expression OR expression
 ;

LPAREN     : '(';
RPAREN     : ')';
NOT        : 'NOT';
AND        : 'AND';
OR         : 'OR';
IDENTIFIER : [a-zA-Z_] [a-zA-Z_0-9]*;
SPACE      : [ \t\r\n]+ -> skip;

解析输入"a b OR NOT c AND d"时,将创建以下解析树:

enter image description here

(使用ANTLRWorks2创建的图片,谢谢Sam!非常令人印象深刻的IDE,我喜欢它!)

生成解析器和监听器类:

java -cp antlr-4.0-complete.jar org.antlr.v4.Tool Expr.g4

生成以下类,它将帮助您“走”树:

public class ExprBaseListener implements ExprListener {

    @Override public void enterExpression(ExprParser.ExpressionContext ctx) { }
    @Override public void exitExpression(ExprParser.ExpressionContext ctx) { }

    @Override public void enterParse(ExprParser.ParseContext ctx) { }
    @Override public void exitParse(ExprParser.ParseContext ctx) { }

    @Override public void enterEveryRule(ParserRuleContext<Token> ctx) { }
    @Override public void exitEveryRule(ParserRuleContext<Token> ctx) { }
    @Override public void visitTerminal(TerminalNode<Token> node) { }
    @Override public void visitErrorNode(ErrorNode<Token> node) { }
}

现在,您需要检查ExprParser.ExpressionContext以查看expression中哪些替代方案匹配,这就是“树标签”派上用场的地方。更改expression规则如下:

expression
 : '(' expression ')'           # EXPR
 | IDENTIFIER                   # ID_EXPR
 | 'NOT' expression             # NOT_EXPR
 | expression 'AND'? expression # AND_EXPR
 | expression 'OR' expression   # OR_EXPR
 ;

并重新生成解析器和侦听器,您将看到ExprBaseListener现在看起来像这样:

public class ExprBaseListener implements ExprListener {
    @Override public void enterAND_EXPR(ExprParser.AND_EXPRContext ctx) { }
    @Override public void exitAND_EXPR(ExprParser.AND_EXPRContext ctx) { }

    @Override public void enterOR_EXPR(ExprParser.OR_EXPRContext ctx) { }
    @Override public void exitOR_EXPR(ExprParser.OR_EXPRContext ctx) { }

    @Override public void enterEXPR(ExprParser.EXPRContext ctx) { }
    @Override public void exitEXPR(ExprParser.EXPRContext ctx) { }

    @Override public void enterNOT_EXPR(ExprParser.NOT_EXPRContext ctx) { }
    @Override public void exitNOT_EXPR(ExprParser.NOT_EXPRContext ctx) { }

    @Override public void enterID_EXPR(ExprParser.ID_EXPRContext ctx) { }
    @Override public void exitID_EXPR(ExprParser.ID_EXPRContext ctx) { }

    @Override public void enterParse(ExprParser.ParseContext ctx) { }
    @Override public void exitParse(ExprParser.ParseContext ctx) { }

    @Override public void enterEveryRule(ParserRuleContext ctx) { }
    @Override public void exitEveryRule(ParserRuleContext ctx) { }
    @Override public void visitTerminal(TerminalNode node) { }
    @Override public void visitErrorNode(ErrorNode node) { }
}

即,expression中的每个标签都会创建一个单独的进入和退出方法。

现在,假设您只对AND表达式的输入事件感兴趣。您可以创建一个自定义类来扩展此ExprBaseListener并覆盖enterAND_EXPR

public class ExprWalker extends ExprBaseListener {

    @Override 
    public void enterAND_EXPR(ExprParser.AND_EXPRContext ctx) { 
        java.util.List<ExprParser.ExpressionContext> e = ctx.expression();
        System.out.println("AND -> " + e.get(0).getText() + ", " + e.get(1).getText());
    }
}

要测试这一切,请创建一个小型驱动程序类:

import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.*;

public class Main {

    public static void main(String[] args) throws Exception {

        String input = "a b OR NOT c AND d";
        ExprLexer lexer = new ExprLexer(new ANTLRInputStream(input));
        ExprParser parser = new ExprParser(new CommonTokenStream(lexer));
        ParseTree tree = parser.parse();
        ParseTreeWalker walker = new ParseTreeWalker();
        walker.walk(new ExprWalker(), tree);
    }
}

并运行它:

java -cp antlr-4.0-complete.jar org.antlr.v4.Tool Expr.g4
javac -cp antlr-4.0-complete.jar *.java
java -cp .:antlr-4.0-complete.jar Main

之后您将看到以下内容被打印到您的控制台:

AND -> a, bORNOTcANDd
AND -> NOTc, d

答案 1 :(得分:5)

ANTLR 4没有重写运算符或output=AST选项,如ANTLR 3. ANTLR 4解析器生成的树是解析树,其形状由语法规则隐式定义。