2

我有类似的语法

%(var)

%var

和 (var)

我的规则是这样的

optExpr:
    | '%''('CommaLoop')'
    | '%' CommaLoop

CommaLoop:
    val | CommaLoop',' val

Expr:
    MoreRules
    | '(' val ')'

问题是它似乎无法判断 ) 是否属于%(CommaLoop)% (val)但它抱怨 ) 而不是 (。到底是什么?它不应该抱怨(吗?我应该如何修复错误?我认为制作%(令牌是一个很好的解决方案,但我想$(在执行此操作之前确定为什么不是错误。

4

2 回答 2

3

这是由于 LR 解析的工作方式。LR 解析实际上是自下而上的,根据语法规则的 RHS 将标记组合在一起,并用 LHS 替换它们。当解析器“移动”时,它会在堆栈上放置一个标记,但实际上还没有匹配规则。相反,它通过当前状态跟踪部分匹配的规则。当它到达与规则结束相对应的状态时,它可以减少,将 RHS 的符号从堆栈中弹出并推回表示 LHS 的单个符号。因此,如果存在冲突,它们不会出现,直到解析器到达某个规则的末尾并且无法决定是否减少(或减少什么)。

在您的示例中,看到% ( val,这就是堆栈上的内容(顶部在此处的右侧)。当前瞻为)时,它无法决定是否应该通过规则弹出 val 并减少CommaLoop: val,或者如果它应该移动)以便它可以弹出 3 个东西并使用规则Expr: '(' val ')'减少

我在这里假设你有一些额外的规则,比如CommaLoop: Expr,否则你的语法实际上不匹配任何东西,bison/yacc 会抱怨未使用的非终端。

于 2009-12-07T22:50:00.433 回答
0

现在,您的解释和语法似乎不匹配。在您的解释中,您将所有三个短语都显示为具有“var”,但您的语法显示以“%”开头的短语允许逗号分隔的列表,而没有的则只允许一个“val”。

目前,我假设这三个都应该允许逗号分隔的列表。在这种情况下,我会像这样考虑语法:

optExpr: '%' aList

aList: CommaLoop
    | parenList

parenList: '(' CommaLoop ')'

CommaLoop: 
    | val 
    | CommaLoop ',' val

Expr: MoreRules
    | parenList

我已经改变了 optExpr 和 Expr ,所以它们都不能匹配一个空序列——我猜你可能不打算这样开始。我已经充实了这一点,可以通过 byacc 运行它;它不会产生任何警告或错误。

于 2009-12-02T05:56:46.493 回答