Antlr4 - соответствует правилу, только если предыдущее правило соответствует - PullRequest
0 голосов
/ 12 июля 2019

У меня парсер выложен аналогично (хотя и не совсем так) этому:

compilationUnit: statement* EOF;
methodBody:      statement*;
ifBlock:         IF '(' expression ')' '{' statement* '}' ;
statement:       methodBody | ifBlock | returnStatement | ... ;

Этот парсер работает нормально, и я могу его использовать.Однако у него есть недостаток, который returnStatement будет анализировать, даже если он не находится в теле метода.В идеале я мог бы настроить его так, чтобы returnStatement совпадало с правилом statement только в том случае, если один из его родителей в дальнейшем был methodBody.Есть ли способ сделать это?

Ответы [ 2 ]

0 голосов
/ 12 июля 2019

Вы пытаетесь решить эту проблему не на том уровне. Он не должен обрабатываться на уровне грамматики, но на следующем семантическом этапе (который используется для поиска логических / семантических ошибок, а не синтаксических ошибок, с которыми имеет дело ваш синтаксический анализатор). Вы можете увидеть тот же подход в грамматике C . Правило statement ссылается на правило jumpStatement, которое в свою очередь соответствует (среди прочего) оператору возврата.

Обработка таких семантических ошибок также позволяет улучшить сообщения об ошибках. Вместо «no viable alt» вы можете вывести ошибку, которая гласит «возврат разрешен только в теле функции» или аналогичный. Для этого проверьте сгенерированное дерево синтаксического анализа, найдите операторы return и проверьте родительский контекст (ы) этого поддерева, чтобы узнать, является ли оно действительным или нет.

0 голосов
/ 12 июля 2019

Вы должны отличать операторы, которые появляются внутри methodBody от тех, которые появляются вне этой области.В идеале у вас будет два разных производства.Как то так:

compilationUnit: member* EOF;
member:          method | class | ... ;
method:          methodName  '(' parameters ')' '{' methodBody '}' ;
methodBody:      statement*;
statement:       methodBody | ifBlock | returnStatement | ... ;
ifBlock:         IF '(' expression ')' '{' statement* '}' ;
...