的JavaCC' LOOKAHEAD(AllSymbols())未选择AllSymbols(),唯一可以正确解析

时间:2015-10-19 12:46:39

标签: javacc lookahead

语法如下:

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) vs ((Psi_sub && Psi_sub) || Psi_sub)

即。任意数量的前缀(

我认为,如上所述做出前瞻可行,但事实并非如此。例如,选择Phi,即使Xi不扩展到Phi,但对Psi也是如此。这可以通过调用Phi来调用Phi,在解析后决定在Xi内选择Phi,并且即将调用Phi。在这种情况下,调试器显示了对Psi的适当扩展,同时允许解析器只是根据需要调用Phi会导致解析异常。

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

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

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

我想我得到了一些错误的基本假设,但不知道它能是什么。如果上面的工作一般,如果没有其他因素,比如被忽略的内在先行?

1 个答案:

答案 0 :(得分:1)

你的假设没有错。你要做的事情应该是有效的。它应该起作用,因为你认为它应该起作用。

这是一个用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 + "." ) ; 
    }
}