这是我的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个shift/reduce冲突警告。这里我面临的问题是,我不能正确地解析返回类型的函数。闻起来很简单,但我被卡住了。
更确切地说,当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。
发布于 2019-04-12 02:42:40
我想保持
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。
https://stackoverflow.com/questions/55630385
复制相似问题