Итак, я использую X-Text и играю с синтаксическими предикатами.
Классический пример — проблема оборванного else, где дано решение — жадно проанализировать оператор else, т. е. не завершать внутреннее выражение, например так:
IfStatement:
'if' condition=Expression 'then' then=Expression
(=>'else' else=Expression)?;
У меня есть грамматика процессов, где два могут быть объединены для создания одного большого процесса с бинарным оператором, например,
process 1 + process 2
предоставляет выбор между процессом 1 и процессом 2.
Кроме того, процессы могут вызывать другие процессы:
process 1 -> process 2
означает выполнение процесса 1, затем выполнение процесса 2.
В моей грамматике следующее:
process 1 -> process 2 + process 3
следует интерпретировать как
(process 1 -> process 2) + process 3
Однако, рассматривая это как оборванную проблему else, решение, которое все дают, дает мне неправильное решение. Как же тогда в X-Text я могу сказать: «Если это имеет смысл, и программа все еще выполняет синтаксический анализ, выпрыгнуть из внутреннего оператора при первой же возможности»
Вот фрагмент моей грамматики для ясности:
PProc:
PProcAtomic ({Binary.left = current} '+' right=Proc)?
;
PProcAtomic returns PProc:
dotted=Dotted (fields+=Field)* type="->" proc=Proc
| bool=Bool type="&" proc=Proc
| type="(" proc=Proc ")"
| type="||" (gens+=Gen)+ "@" "[" rset=Set "]" proc=Proc
| type="|~|" (gens+=Gen)+ "@" proc=Proc
| type="[]" (gens+=Gen)+ "@" proc=Proc
| type="|||" (gens+=Gen)+ "@" proc=Proc
| type=";" (gens+=Gen)+ "@" proc=Proc
| type="[|" rset=PSet "|]" (gens+=Gen)+ "@" proc=Proc
| type="|[" rset=PSet "]|" (gens+=Gen)+ "@" proc=Proc
| type="<->" (gens+=Gen)+ "@" "[" (exprs+=Expr)+ "]" proc=Proc
| type="STOP"
| type="SKIP"
| type="CHAOS" "(" rset=PSet ")"
;
Proc:
PProc
| "namedprocess"
;
Очевидно, что если я поставлю «=>» на «+», то он будет потреблять это жадно, что приведет к неправильному AST. Как заставить его «смотреть вперед» для символа «+», а затем разделить оператор на два, если он увидит это?