Это упрощенная версия моей грамматики в формате BNFC:
-- programs -------------------------------------
entrypoints Program ;
Prog. Program ::= [ Def ] ;
terminator Def "" ;
-- definitions ----------------------------------
DVar. Def ::= VarDecl ;
DFun. Def ::= FunDef;
-- functions definitions ------------------------
DFunAll. FunDef ::= FunType Id "(" [ Arg ] ")" FunBody;
DFunBody. FunBody ::= "{" RetStmt "}" ;
-- function statements --------------------------
StmtRetVoid. RetStmt ::= "return" ";" ;
-- variable declarations ------------------------
DVarSimple. VarDecl ::= Type Id ";" ;
DVarList. VarDecl ::= Type Id "," [Id] ";" ;
-- arguments ------------------------------------
ArgDecl. Arg ::= Type Id ;
separator Arg "," ;
-- types -----------------------------------------
TInt. Type ::= "int" ;
TFunRetT. FunType ::= Type ;
TFunRetV. FunType ::= "void" ;
-- identifiers ------------------------------------
position token Id (letter (letter | digit | '_')*) ;
separator Id "," ;
Для этой грамматики happy
генерирует 1 неиспользуемое правило и 1 предупреждение о сдвиге / уменьшении конфликта. Проблема, с которой я здесь сталкиваюсь, заключается в том, что я не могу правильно проанализировать функцию, возвращающую тип. Пахнет очень просто, но я застрял.
Если быть более точным, я получаю ошибку синтаксического анализа для int foo(int x) {return;}
, в то время как void foo(int x) {return;}
успешно анализирует. Таким образом, кажется, что эти три правила не работают вместе, как предполагалось:
DFunAll. FunDef ::= FunType Id "(" [ Arg ] ")" FunBody;
TInt. Type ::= "int" ;
TFunRetT. FunType ::= Type ;
Если я изменю правило FunDef
на FunDef ::= Type Id "(" [ Arg ] ")" FunBody;
, разбор пройдет гладко, но я хочу, чтобы Type
и FunType
различались, чтобы void
не было обычным Type
.