Я пытаюсь преобразовать дерево в дерево с помощью antlr3.4.
Речь идет (для этого вопроса) о логических выражениях, где «И» и «ИЛИ» разрешено связывать с n выражениями. Этап парсера создает что-то вроде этого
(OR
(AND (expr1) (expr2) (expr3)
(OR (AND (expr4))
(AND (expr5))
(AND (expr6))
)
)
)
К сожалению, есть узлы AST для «И» и «ИЛИ», которые связываются только с одним выражением. (Что бесполезно, но эй - вызываются правила andExpr и orExpr)
Я пытался выгнать их (имеется в виду, заменить их их подузлами), но не смог этого сделать в грамматике дерева. (Кстати: использование обхода/модификации дерева в глубину в чистой Java работает, но это не мое намерение)
Я пытался использовать предикаты, но я не могу понять это правильно.
Это грамматика для разбора потока без изменений.
start :
orExpr^ EOF!
;
orExpr :
^(OR r+=andExpr+ ) -> ^(OR $r)
;
andExpr :
^(AND unaryExpr+ )
;
notExpr:
^( NOT unaryExpr)
;
unaryExpr :
.+ // it gets more complicated below this
;
Я попробовал предикат, чтобы поймать случай с одним подузлом, но не смог передать случай n> 1 без изменений.
orExpr @init { int N = 0; }
:
( ^(OR (r+=andExpr {N++;})+ ) {N==1}? -> $r)
;
Любые идеи, как сделать это правильно?
edit: Прилагается грамматика парсера, которая почти такая же...
start
: '('! orExpr^ ')'! EOF! ;
orExpr
: a+=andExpr ( OR_T a+=andExpr )* -> ^(OR $a+ ) // 'AND' and 'OR' are multivalent
;
andExpr
: u+=unaryExpr ( AND_T u+=unaryExpr )* -> ^(AND $u+ )
;
notExpr
: NOT_T unaryExpr -> ^( NOT unaryExpr)
;
unaryExpr
: '('! orExpr ')'! // -> ^( BRACE orExpr), brace not needed in the ast (but needed for propper parsing)
| notExpr
| internal^ // internal is very complex in itself
;