Как исключить оператор запятой из выражения в Grammar-Kit?
Я пишу плагин языка IntelliJ для языка, производного от C, который включает оператор запятой. Я использую Grammar-Kit для генерации парсера. Там, где в формальной грамматике много вложенных выражений, я переписал их с помощью разбора выражений на основе приоритетов Grammar-Kit, поэтому мой вывод выражений выглядит следующим образом:
expression ::= comma_expression
| assignment_expression
| conditional_expression
| eor_expression
| xor_expression
| and_expression
| equality_expression
| relation_expression
| add_expression
| mul_expression
| prefix_expression
| postfix_group
| primary_expression
comma_expression ::= expression ',' expression {pin=2}
// etc.
Само по себе это прекрасно работает, но в грамматике есть места, где мне нужно разобрать выражение, которое не может быть выражением запятой. Функциональные вызовы являются одним из примеров этого:
function_call_expression ::= identifier '(' ('void'|<<comma_list expression>>)? ')'
private meta comma_list ::= <<p>> (',' <<p>>)*
Аргумент функции не может быть выражением запятой, потому что это будет неоднозначно с запятой, разделяющей следующий аргумент. (В имеющейся у меня грамматике она всегда анализируется как одно выражение запятой.) Формальная грамматика решает эту проблему, указывая, что каждый аргумент функции должен быть выражением присваивания, поскольку их выражение присваивания включает в себя все выражения с более узким приоритетом. Это не работает для грамматики, основанной на приоритете Grammar-Kit, потому что выражение присваивания действительно должно включать присваивание.
То же самое относится и к инициализаторам, где разрешение выражения с запятой может привести к неоднозначному анализу в случаях, подобных int x=1, y;
,
Как мне справиться с этой ситуацией? Я хотел бы продолжать использовать анализ на основе приоритетов, чтобы сохранить мелкое дерево PSI, но также избегать переписывания дерева PSI вручную для вызовов функций, чтобы превратить CommaExpression
в список аргументов.