0

这是我的 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;解析顺利,但我想保留TypeFunType区分,以免成为void常规的Type.

4

1 回答 1

1

我想保持TypeFunType区分,以免像常规一样有 void Type

但是您要求解析器在它有足够的信息做出决定之前决定int是 aType还是 a 。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。

于 2019-04-12T02:42:40.913 回答