在ANTLR 3,你可以只做到以下几点:
andExpression
: (andnotExpression -> andnotExpression)
(AND? a=andnotExpression -> ^(AndNode $andExpression $a))*
;
任何想法如何做到这一点,在新的版本?
在ANTLR 3,你可以只做到以下几点:
andExpression
: (andnotExpression -> andnotExpression)
(AND? a=andnotExpression -> ^(AndNode $andExpression $a))*
;
任何想法如何做到这一点,在新的版本?
正如萨姆(280Z28)提到,ANTLR 4不必重写运营商。
当生成解析器,ANTLR 4创建可用于侦听“进入”和“退出”的所有语法规则事件的一些监听器类。
此外,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;
当解析输入"ab OR NOT c AND d"
,下面的分析树将被创建:
(图片使用创建ANTLRWorks2 ,谢谢山姆!令人印象深刻的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
ANTLR 4不具有重写操作员或output=AST
选项等ANTLR 3. ANTLR产生树4个解析器解析树,其形状被隐含由语法规则定义的。