Чарльз писал:
Как я могу явно сказать ANTLR, что я хочу, чтобы он создал AST слева, таким образом, разъясняя мои намеренияи отключение предупреждения?
Не следует создавать два отдельных правила для assign
и add
.Как ваши правила сейчас, assign
имеет приоритет над add
, который вы не хотите: они должны иметь равный приоритет, глядя на ваш желаемый AST.Итак, вам нужно заключить все операторы +
, -
и =
в одно правило:
program
: expr ';'!
;
expr
: term (('+' | '-' | '=')^ expr)*
;
Но теперь грамматика все еще неоднозначна.Вам нужно «помочь» синтаксическому анализатору выйти за пределы этой двусмысленности, чтобы убедиться, что на самом деле operator expr
впереди при разборе (('+' | '-' | '=') expr)*
.Это можно сделать с помощью синтаксического предиката , который выглядит следующим образом:
(look_ahead_rule(s)_in_here)=> rule(s)_to_actually_parse
(( ... )=>
- это синтаксис предиката)
Небольшая демонстрация:
grammar test;
options {
output=AST;
ASTLabelType=CommonTree;
}
program
: expr ';'!
;
expr
: term ((op expr)=> op^ expr)*
;
op
: '+'
| '-'
| '='
;
term
: ID
| INT
;
ID : (LETTER | '_') (LETTER | DIGIT | '_')* ;
INT : DIGIT+ ;
WS : (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;};
fragment LETTER : ('a'..'z'|'A'..'Z');
fragment DIGIT : '0'..'9';
, которая может быть протестирована с классом:
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;
public class Main {
public static void main(String[] args) throws Exception {
String source = "0 + a = 1 + b = 2 + 3;";
testLexer lexer = new testLexer(new ANTLRStringStream(source));
testParser parser = new testParser(new CommonTokenStream(lexer));
CommonTree tree = (CommonTree)parser.program().getTree();
DOTTreeGenerator gen = new DOTTreeGenerator();
StringTemplate st = gen.toDOT(tree);
System.out.println(st);
}
}
А выход класса Main соответствует следующему AST:
, который создается без любых предупреждений от ANTLR.