为什么 Bison 可以将“错误”项减少为空规则

问题描述

我有以下 yacc 语法:

33 CompSt: "{" DefList StmtList "}"
34       | "{" error ";" DefList StmtList "}"
......
52 DefList: Def DefList
53        | %empty

54 Def: Specifier DecList ";"
55    | Specifier error ";"
56    | Specifier DecList error ";"
57    | Specifier VarDec "[" error ";"
58    | Specifier VarDec "[" INT error ";" 

59 DecList: Dec
60        | Dec "," DecList

61 Dec: VarDec
62    | VarDec "=" Exp

添加了规则34来处理一对大括号开头出现非法项的情况。我认为这个规则是必要的(如果你有其他方法,请告诉我),但有一个shift/reduce警告:

33 CompSt: "{" . DefList StmtList "}"
34       | "{" . error ";" DefList StmtList "}"

 error   shift,and go to state 45
 STRUCT  shift,and go to state 2
 TYPE    shift,and go to state 3

 error   [reduce using rule 53 (DefList)]

我不明白为什么规则 53 可以减少“错误”,我也不知道如何解决这个警告。

非常感谢您的回复

解决方法

在 shift-reduce 冲突中,解析器有两个选项:reduce(特定的产生式),让先行标记在之后处理,或者 转移 前瞻令牌。错误规则也不例外; error 至少在最初被视为任何其他标记。 (特殊处理是 error 移位后的重新同步,但那是在移位之后。)

因此,产生式 53 减少的不是 error。而是 Deflist 之前的空 error。当然,这种减少永远不会发生,因为 bison 解决了 shift-reduce 冲突而有利于 shift 操作,但如果您认为减少空 Deflist 很重要,它会警告您。

虽然这个 shift-reduce 冲突并不重要,但它有点难看,而且根本不明白为什么你觉得需要首先添加错误产生。你真的不需要那么多错误产生,因为错误有效地使解析冒泡。 (除非你试图在每种情况下产生特定的错误消息,我想。)

我会删除错误产生式 55 到 58,将 34 更改为更简单的

| "{" error "}"

并添加

| error ';'

Deflist(生产 52 之后)。