Проблема синтаксического анализа для простых правил производства BNFC - PullRequest
0 голосов
/ 11 апреля 2019

Это упрощенная версия моей грамматики в формате 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.

1 Ответ

0 голосов
/ 12 апреля 2019

Я хочу, чтобы Type и FunType различались, чтобы не иметь пустоты как обычные Type.

Но вы просите синтаксический анализатор решить, является ли int Type или FunType, прежде чем у него будет достаточно информации для принятия решения. Так как он не может сказать, применять ли производство FunType ::= Type, он вместо этого выбирает смещение Id (потому что разрешение по умолчанию для конфликта смещения / уменьшения - смещение). Это делает невозможным использование продукции FunType ::= Type, которая вызывает предупреждение о неиспользованном правиле.

Единственное простое решение - полностью отказаться от FunType ценой некоторого дублирования:

DFunAllT.        FunDef ::= Type Id "(" [ Arg ] ")" FunBody;
DFunAllV.        FunDef ::= "void" Id "(" [ Arg ] ")" FunBody;

Если дублирование вас беспокоит, вы можете оставить множитель:

DFunTI.   FunTypeId ::= Type Id;
DFunVI.   FunTypeId ::= "void" Id;
DFunAll.  FunDef ::= FunTypeId "(" [ Arg ] ")" FunBody;

Первый, вероятно, лучше подходит для вашего AST.

...