Antlr4 говорит, что мое правило взаимно рекурсивно само по себе

Я работаю над заданием, где мы делаем компилятор для простого языка, и мы используем ANTLR4 для Java. После того, как моя грамматика наконец заработала, мне пришлось добавить некоторый код Java в парсер языка, чтобы построить AST. Вот тут я запутался. Предполагается, что Antlr выдает ошибку, если правила взаимно леворекурсивны, и, насколько я понимаю, это происходит, когда одно правило ссылается на другое правило, а второе правило ссылается на первое правило. Чего я не понимаю, так это почему antlr говорит мне, что мое правило взаимно рекурсивно само по себе? Вот сообщение об ошибке, которое я продолжаю получать: error(119): PrevParser.g4::: The following sets of rules are mutually left-recursive [expr]. Я посмотрел вокруг, и кажется, что ни у кого нет этой проблемы. Я нашел кого-то, кто сказал, что взаимно леворекурсивные правила имеют общее то, что их первый токен — это другое правило, поэтому я попытался поставить обычный токен . прямо перед токеном правила, и теперь он волшебным образом компилируется. Почему это происходит, когда правило ссылается только на себя? Вот кусок кода, который вызывает проблему:

expr returns [AstExpr ast] 
     : (VOID_CONST {$ast = new AstAtomExpr(loc($VOID_CONST), AstAtomExpr.Type.VOID, $VOID_CONST.text);}) 
     | (INT_CONST {$ast = new AstAtomExpr(loc($INT_CONST), AstAtomExpr.Type.INT, $INT_CONST.text);}) 
     | (CHAR_CONST {$ast = new AstAtomExpr(loc($CHAR_CONST), AstAtomExpr.Type.CHAR, $CHAR_CONST.text);}) 
     | (POINT_CONST {$ast = new AstAtomExpr(loc($POINT_CONST), AstAtomExpr.Type.POINTER, $POINT_CONST.text);}) 
     | (STRING_CONST {$ast = new AstAtomExpr(loc($STRING_CONST), AstAtomExpr.Type.STRING, $STRING_CONST.text);}) 
     | (BOOL_CONST {$ast = new AstAtomExpr(loc($BOOL_CONST), AstAtomExpr.Type.BOOL, $BOOL_CONST.text);}) 
     | (IDENTIFIER {$ast = new AstNameExpr(loc($IDENTIFIER), $IDENTIFIER.text);}) 
     | ( e1=expr O_OKLEPAJ e2=expr O_ZAKLEPAJ {$ast = new AstArrExpr(loc($e1.ast, $O_ZAKLEPAJ), $e1.ast, $e2.ast);} ) 
;

Ошибка появляется в последней строке, где выражение правила ссылается на себя как e1=expr. Если я изменю правило, чтобы оно выглядело так: ( DOT e1=expr O_OKLEPAJ e2=expr O_ZAKLEPAJ {$ast = new AstArrExpr(loc($e1.ast, $O_ZAKLEPAJ), $e1.ast, $e2.ast);} ) все компилируется нормально. Кто-нибудь знает, как я могу решить эту проблему? Любая помощь приветствуется.

Учебная записка [Medium] Leetcode#22 Generate Parentheses
Учебная записка [Medium] Leetcode#22 Generate Parentheses
На этот раз мы собираемся решить еще одну классическую проблему, связанную с парными скобками, так называемую генерацию скобок.
1
0
24
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Раньше я видел это в stackoverflow (но больше не могу найти). Похоже, это ошибка, вызванная скобками перед леворекурсивным expr. Просто удалите скобки (которые в любом случае избыточны).

Так что нет:

expr returns [AstExpr ast] 
 : ...
 | ( e1=expr O_OKLEPAJ e2=expr O_ZAKLEPAJ {$ast = new AstArrExpr(loc($e1.ast, $O_ZAKLEPAJ), $e1.ast, $e2.ast);} )
 ;

но вместо этого:

expr returns [AstExpr ast] 
 : ...
 | e1=expr O_OKLEPAJ e2=expr O_ZAKLEPAJ {$ast = new AstArrExpr(loc($e1.ast, $O_ZAKLEPAJ), $e1.ast, $e2.ast);}
 ;

О да, это, казалось, сработало, скобки были там, потому что я, не зная об этой ошибке, имел несколько правил ниже бита кода, который я разместил в паре скобок (двоичные операции), и я получаю эту ошибку и думаю, что я мог перепутать приоритеты Я помещаю каждое правило в пару em. Спасибо

simsam 17.03.2022 14:29

Однако у меня есть дополнительный вопрос: если что-то до правила вызывает эту ошибку, как я могу инициализировать вектор для правила, в котором хранится список аргументов?

simsam 17.03.2022 14:35

«если наличие чего-либо перед правилом вызывает эту ошибку», нет, это не что-то: ее вызвала скобка. «Как я могу инициализировать вектор для правила, в котором хранится список аргументов?» Я не знаю, что ты имеешь в виду. Вместо того, чтобы пытаться объяснить в этих небольших полях для комментариев, я бы посоветовал вам попробовать, а когда вы застряли, просто опубликуйте новый вопрос здесь, на SO. Удачи!

Bart Kiers 17.03.2022 14:39

Я попробую, еще раз спасибо.

simsam 17.03.2022 14:45

Добро пожаловать @simsam

Bart Kiers 17.03.2022 15:01

Другие вопросы по теме