避免使用不改变前瞻的通用前缀

Avoid common prefixes without change lookahead

我正在使用 JavaCC 制定识别语言的规范。我遇到的问题是 JavaCC 给了我一个警告,因为 public 是 Member() 声明的公共前缀。 Member() 可以有 Attributes() and/or Method() 但必须至少有一个 Method,顺序无关紧要。

JavaCC 给我的警告是:

第 66 行第 23 列的 (...)+ 构造中的选择冲突。 嵌套在构造内的扩展和构造后的扩展具有共同的前缀,其中之一是:"public"。考虑对嵌套扩展使用 2 或更多的前瞻。

第66行是Member()唯一的一行。我还需要这样做而不改变前瞻值

代码如下:

void Member() : {}
    {
        (Attribute())* (Method())+ (Attribute() | Method())*
    }

void Attribute() : {}
    {
        "private" Type() <Id> [":=" Expr()]";"
    }

void Method() : {}
    {
        MethodHead() MethodBody()
    }

void MethodHead() : {}
    {
        ("public")? (<Id> | Type() | "void") <Id> "(" Parameter() ")"
    }

谢谢。

问题是这个正则表达式

 (Method())+ (Attribute() | Method())*

是模棱两可的。让我们用 M 缩写方法,用 A 缩写属性。如果输入是 MAM,则没有问题。 (Method())+ 匹配第一个 M,(Attribute() | Method())* 匹配剩余的 AM。但是如果输入是MMA,分界线应该在哪里呢? (Method())+ 匹配 M,(Attribute() | Method())* 匹配 MA,或者 (Method())+ 匹配 MM,(Attribute() | Method())* 匹配 A。这两种解析都是可能的。 JavaCC 不知道你想要哪个解析,所以它会抱怨。

你能做什么:

  • 没有。忽略警告。默认行为是 (Method())+ 将识别尽可能多的方法,并且只有第一个属性之后的方法才会被 (Attribute() | Method())*.
  • 识别
  • 使用前瞻抑制警告。你说你不想添加前瞻性,但为了完整起见,我会提到你可以将 (Method())+ 更改为 (LOOKAHEAD(1) Method())+。这不会改变解析器的行为,但会抑制警告。
  • 重写语法。

违规行可以改写为

(Attribute())* Method() (Attribute() | Method())*

(Attribute())* (Method())+ [Attribute() (Attribute() | Method())*]