如何在 Yacc 中强制转换?

How to force shift in Yacc?

我有以下结构作为 yacc 语法的一部分(或者更确切地说是 jison,但两者共享相同的公共基础):

Type
    : IDENT
    | Type "[" "]"
    | Type "*"
    | "func" "(" Types ")" "=>" Type
    ;

Types
    : /* No arguments */
    | Type /* Single argument */
    | Types "," Type /* Multiple arguments */
    ;

这当然是一个简化的例子,但它应该给出总体思路并展示实际问题。我想将 Foo[]Foo*Foo*[] 等结构分别解析为 (Foo)[](Foo)*((Foo)*)[]

然而,Yacc 理所当然地抱怨它在遇到以下结构时不知道该怎么做:

func (A, B) => C[]

可以解析为func (A, B) => (C[])(func (A, B) => C)[]。我当然希望它成为第一个(因为我有一个 ( Type ) 构造用于第二种情况)。有什么办法可以告诉yacc(或jison)遇到这种情况我要shift吗?

给最后一个 Type 产品一个优先级,或者使用 %prec 声明和 pseudo-terminal,或者使用默认值,即 => 的优先级,最后一个终端。然后确保 [ 标记的优先级更高。 (您还必须使 * 的优先级高于 =>,以解决另一个 shift-reduce 冲突。)

还有其他解决方案,但这个是最简单的。

其实bison/yacc/jison/etc。 always prefer shift in a shift-reduce conflict,所以你不需要做任何事情来换班。优先规则将抑制警告,但您也可以使用 expect 声明来做到这一点。