2015-10-19 15 views
1

语法,在紧要关头,如下:JavaCC的”预读(AllSymbols())AllSymbols()没有选择,唯一要分析正确

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

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

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

正如你所看到的,无限的前瞻会在一般在僖生产是必需的,因为解析器需要区分等情况:

((Phi_sub && Phi_sub) || Phi_sub) VS ((Psi_sub && Psi_sub) || Psi_sub)

即前缀(的任意量。

我认为,制作像上面一样的向前看是可行的,但事实并非如此。例如,即使Xi没有扩展到Phi,Phi也被选中,但是对于Psi也是如此。通过调用程序调用Phi,可以很容易地在某个流S上检查这个流,在解析后,在Xi内部决定选择Phi,并且即将调用Phi。在这种情况下,调试器显示了对Psi的适当扩展,同时允许解析器只是调用Phi,因为它会导致解析异常。

测试它的另一种方法是交换PHI和PSI:

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

这将使解析器正确地解析特定S,所以它似乎只是内兮第一分支选择,无论是有效的或不。

我想我得到了一些基本的假设错误,但不知道它是什么。如果上面的工作一般,如果没有其他因素,就像内部忽视的前瞻?

回答

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 

您有谎言在问题未示出的东西的问题。


顺便说一句,在每个备选方案的前面放一个lookahead规范是一个坏主意。

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 + ".") ; 
    } 
} 
+0

谢谢你,所以现在我知道,这个问题很可能是被忽略的内部预测。我将(i)尝试将Phi和Psi加入到单个生产中,然后在语义上检查Phi是Phi还是Psi是Psi,或者(ii)在另一个解析器生成器中重写该语法。 – arataj

+0

语法预测规范在语法预测期间被忽略。请参阅FAQ中的讨论。这是我从来没有理解的理由。如果你发布一个完整的最小失败例子作为一个新问题,有人可能会弄清楚。 –