在yacc中建模可选数据的最佳方法是什么?我有以下声明:
StmtBlock : '{' VariableDeclList StmtList '}' { $$ = new StmtBlock($2, $3); }
;
VariableDeclList和StmtList都是可选的(epsilon),所以我将它们建模如下:
VariableDeclList : VariableDeclList VariableDecl { ($$=$1)->Append($2); }
| { $$ = new List<VarDecl*>; }
和
StmtList : StmtList Stmt { ($$=$1)->Append($2); }
| { $$ = new List<Stmt*>; }
;
唯一的问题是我认为这会导致转移/减少冲突。当我尝试编译我的代码时,我的y.ouput文件具有以下内容:
State 74 conflicts: 1 shift/reduce
...
state 74
38 StmtBlock: '{' VariableDeclList . StmtList '}'
39 VariableDeclList: VariableDeclList . VariableDecl
T_Bool shift, and go to state 2
T_Int shift, and go to state 3
T_Double shift, and go to state 4
T_String shift, and go to state 5
T_Identifier shift, and go to state 8
T_Identifier [reduce using rule 18 (Epsilon)]
$default reduce using rule 18 (Epsilon)
VariableDecl go to state 80
Variable go to state 13
Type go to state 34
Epsilon go to state 81
StmtList go to state 82
...
有没有更合适的方法对此进行建模?
答案 0 :(得分:0)
如您所知,如果无法通过第一个令牌区分 Stmt 和 VariableDecl ,这将导致转移/减少冲突 - 在您的示例中为{ {1}}可能也会开始。你可以尝试一些事情:
将两个列表组合成一个 VariableDeclOrStmtList ,它可以包含以任何方式混合的 Stmt 或 VariableDecl 。这比你的更通用,所以你需要进行一次检查,以确保在第一个 Stmt
使用更多的前瞻来确定差异 - 使用bison的GLR模式,或类似btyacc之类的东西,可以推迟判断某些东西是 Stmt 还是 VariableDecl 直到看到足够的决定
在这些结构的开头使用不同的标记,以明确区分它们。这些可以是您的语言中的真实令牌,也可以是词法分析器根据一些额外的上下文插入的合成令牌(这意味着在词法分析器中基本上做更多的前瞻)。
修改强>
对于第一个建议,您将有一条规则:
T_Identifier
其中VarDeclOrStmtList : VarDeclOrStmtList VariableDecl { ($$=$1)->Append($2); }
| VarDeclOrStmtList Stmt { ($$=$1)->Append($2); }
| { $$ = new List<Node *>; }
;
是Node
和VarDecl
的公共基类。然后,在StmtBlock操作中,调用遍历Stmt
的函数,将其拆分为List<Node *>
和List<VarDecl *>
,并在格式不正确时给出错误消息。