ANTLR 3では、次のことを実行できます。
andExpression
: (andnotExpression -> andnotExpression)
(AND? a=andnotExpression -> ^(AndNode $andExpression $a))*
;
新しいバージョンでそれを行う方法はありますか?
Sam(280Z28)が述べたように、ANTLR4には書き換え演算子がありません。
パーサーを生成するとき、ANTLR 4は、すべてのパーサールールの「enter」および「exit」イベントをリッスンするために使用できるいくつかのリスナークラスを作成します。
また、ANTLR 4は「直接左再帰ルール」をサポートしているため、以下に示すように、式ルールを1つのルールで定義できます。
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"
と、次の解析ツリーが作成されます。
(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
つまり、個別のEnterメソッドとExitメソッドのラベルごとに作成されます。
ここで、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メイン
その後、コンソールに次のように印刷されます。
AND-> a、bORNOTcANDd AND-> NOTc、d
ANTLR 4には、書き換え演算子やANTLR 3のようなオプションはありませんoutput=AST
。ANTLR4パーサーによって生成されるツリーは解析ツリーであり、その形状は文法規則によって暗黙的に定義されます。