Ваше правило:
expression
: term ('|' term)*
-> ^( OR_EXPR term term* )
;
всегда заставляет правило перезаписи создавать дерево с корнем типа OR_EXPR
.Вы можете создать «правила перезаписи», например:
expression
: (term -> REWRITE_RULE_X) ('|' term -> ^(REWRITE_RULE_Y))*
;
. И чтобы устранить неоднозначность в вашей грамматике, проще всего включить глобальный возврат, который можно выполнить в разделе options { ... }
вашей грамматики.
Быстрая демонстрация:
grammar CocoR;
options {
output=AST;
backtrack=true;
}
tokens {
RULE;
GROUP;
SEQUENCE;
OPTIONAL;
OR;
ATOMS;
}
parse
: rule EOF -> rule
;
rule
: ID '=' expr* '.' -> ^(RULE ID expr*)
;
expr
: (a=atoms -> $a) ('|' b=atoms -> ^(OR $expr $b))*
;
atoms
: atom+ -> ^(ATOMS atom+)
;
atom
: ID
| '(' expr ')' -> ^(GROUP expr)
| '{' expr '}' -> ^(SEQUENCE expr)
| '[' expr ']' -> ^(OPTIONAL expr)
;
ID
: ('a'..'z' | 'A'..'Z') ('a'..'z' | 'A'..'Z' | '0'..'9')*
;
Space
: (' ' | '\t' | '\r' | '\n') {skip();}
;
со входом:
CS = { ExternAliasDirective }
{ UsingDirective }
EOF .
производит AST:
ивход:
foo = a | b ({c} | d [e f]) .
производит:
Класс для проверки этого:
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 =
"CS = { ExternAliasDirective } \n" +
"{ UsingDirective } \n" +
"EOF . ";
*/
String source = "foo = a | b ({c} | d [e f]) .";
ANTLRStringStream in = new ANTLRStringStream(source);
CocoRLexer lexer = new CocoRLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
CocoRParser parser = new CocoRParser(tokens);
CocoRParser.parse_return returnValue = parser.parse();
CommonTree tree = (CommonTree)returnValue.getTree();
DOTTreeGenerator gen = new DOTTreeGenerator();
StringTemplate st = gen.toDOT(tree);
System.out.println(st);
}
}
и с выходом этого классапроизводит, я использовал следующий сайт для создания AST-изображений: http://graph.gafol.net/
HTH
EDIT
Для учета epsilon (пустая строка) в вашемOR
выражений, вы можете попробовать что-то (быстро протестированное!), Например:
expr
: (a=atoms -> $a) ( ( '|' b=atoms -> ^(OR $expr $b)
| '|' -> ^(OR $expr NOTHING)
)
)*
;
, которое анализирует источник:
foo = a | b | .
в следующее AST: