javacc' LOOKAHEAD( AllSymbols() ) AllSymbols() 未被选择,唯一被正确解析

javacc' LOOKAHEAD( AllSymbols() ) AllSymbols() not chosen, sole to be parsed correctly

紧要关头,语法如下:

Phi ::= Phi_sub ( ("&&" | "||") Phi_sub )*
Phi_sub ::= "(" Phi ")" | ...

Psi ::= Psi_sub ( ("&&" | "||") Psi_sub )*
Psi_sub ::= "(" Psi ")" | ...

Xi ::= LOOKAHEAD( Phi ) Phi | LOOKAHEAD( Psi ) Psi

如您所见,Xi 产生式通常需要无限前瞻,因为解析器需要区分以下情况:

((Phi_sub && Phi_sub) || Phi_sub) 对比 ((Psi_sub && Psi_sub) || Psi_sub)

即任意数量的前缀 (.

我认为,像上面那样进行前瞻会起作用,但事实并非如此。例如,选择 Phi,即使 Xi 没有扩展到 Phi,而是扩展到 Psi。这可以很容易地在某个流 S 上检查,方法是在解析后立即用调试器调用 Phi,在 Xi 中决定选择 Phi,并且即将调用 Phi。在这种情况下,调试器显示对 Psi 的适当扩展,同时允许解析器仅按需要调用 Phi 会导致解析异常。

另一种测试方法是交换 Phi 和 Psi:

Xi ::= LOOKAHEAD( Psi ) Psi | LOOKAHEAD( Phi ) Phi

这将使解析器正确解析特定的 S,因此似乎只是选择了 Xi 中的第一个分支,无论它是否有效。

我想我的一些基本假设是错误的,但不知道它会是什么。如果没有其他因素,如被忽略的内部前瞻,上述一般情况下应该工作吗?

你的假设没有错。你正在尝试做的事情应该有效。它应该出于您认为它应该起作用的原因起作用。


这是一个用 JavaCC 编写的完整示例。

void Start() : {} { Xi() <EOF> }

void Xi() : {} {
    LOOKAHEAD( Phi() ) Phi() { System.out.println( "Phi" ) ; }
|   LOOKAHEAD( Psi() ) Psi() { System.out.println( "Psi" ) ; }
}

void Phi() : {} { Phi_sub() ( ("&&" | "||") Phi_sub() )*}

void Phi_sub() : {} { "(" Phi() ")" | "Phi_sub" }

void Psi() : {} { Psi_sub() ( ("&&" | "||") Psi_sub() )* }

void Psi_sub() : {} { "(" Psi() ")" | "Psi_sub" }

下面是一些示例输出:

Input is : <<Phi_sub>>
Phi
Input is : <<Psi_sub>>
Psi
Input is : <<((Phi_sub && Phi_sub) || Phi_sub)>>
Phi
Input is : <<((Psi_sub && Psi_sub) || Psi_sub)>>
Psi

您遇到的问题在于问题中未显示的内容。


顺便说一下,在每个备选方案之前都加上前瞻规范是个坏主意。

void X() : {} { LOOKAHEAD(Y()) Y() | LOOKAHEAD(Z()) Z() }

大致相当于

void X() : {} { LOOKAHEAD(Y()) Y() | LOOKAHEAD(Z()) Z() | fail with a stupid error message }

比如这里还有一个运行上面的语法

Input is : <<((Psi_sub && Psi_sub) || Phi_sub)>>
NOK.
Encountered "" at line 1, column 1.
Was expecting one of:

所有前瞻失败后,解析器将留下一组空的期望!

如果将 Xi 更改为

void Xi() : {} {
    LOOKAHEAD( Phi() ) Phi() { System.out.println( "Phi" ) ; }
|   Psi() { System.out.println( "Psi" ) ; }
}

您会收到稍微好一点的错误消息

Input is : <<((Psi_sub && Psi_sub) || Phi_sub)>>
NOK.
Encountered " "Phi_sub" "Phi_sub "" at line 1, column 26.
Was expecting one of:
    "(" ...
    "Psi_sub" ...

您还可以自定义错误消息

void Xi() : {} {
    LOOKAHEAD( Phi() ) Phi() { System.out.println( "Phi" ) ; }
|   LOOKAHEAD( Psi() ) Psi() { System.out.println( "Psi" ) ; }
|   { throw new ParseException( "Expected either a Phi or a Psi at line "
                               + getToken(1).beginLine
                               + ", column " + getToken(1).beginColumn + "." ) ; 
    }
}