这是我的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
。
答案 0 :(得分:0)
我想区分
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。