Я работаю над заданием, где мы делаем компилятор для простого языка, и мы используем 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);} )
все компилируется нормально. Кто-нибудь знает, как я могу решить эту проблему? Любая помощь приветствуется.
Раньше я видел это в 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);}
;
Однако у меня есть дополнительный вопрос: если что-то до правила вызывает эту ошибку, как я могу инициализировать вектор для правила, в котором хранится список аргументов?
«если наличие чего-либо перед правилом вызывает эту ошибку», нет, это не что-то: ее вызвала скобка. «Как я могу инициализировать вектор для правила, в котором хранится список аргументов?» Я не знаю, что ты имеешь в виду. Вместо того, чтобы пытаться объяснить в этих небольших полях для комментариев, я бы посоветовал вам попробовать, а когда вы застряли, просто опубликуйте новый вопрос здесь, на SO. Удачи!
Я попробую, еще раз спасибо.
Добро пожаловать @simsam
О да, это, казалось, сработало, скобки были там, потому что я, не зная об этой ошибке, имел несколько правил ниже бита кода, который я разместил в паре скобок (двоичные операции), и я получаю эту ошибку и думаю, что я мог перепутать приоритеты Я помещаю каждое правило в пару em. Спасибо