我目前正在使用JavaCC实现JavaScript / ECMAScript 5.1解析器。我最近learned关于LOOKAHEAD
这里很方便,因为语法不完全是LL(1)。
我在ECMAScript语法中看到的一件事是“负向前瞻检查”,如下面的ExpressionStatement
制作:
ExpressionStatement :
[lookahead ∉ {{, function}] Expression ;
所以我可能需要LOOKAHEAD(!("{" | "function"))
这样的东西,但它在这种语法中不起作用。
我的问题是,如何在JavaCC中实现这个“否定LOOKAHEAD
”
在阅读LOOKAHEAD MiniTutorial后,我认为getToken(1).kind != FUNCTION
这样的表达式可能就是我所需要的,但我对此并不十分肯定。
答案 0 :(得分:1)
对于您提供的示例,我更倾向于使用语法向前看,这在某种意义上必然是"肯定"。
由于没有选择,ExpressionStatement的制作不是解决问题的地方。
void ExpressionStatement() : {} { Expression() ";" }
如果在表达式语句和块之间或者在表达式语句和函数声明(或两者)之间进行选择,就会出现问题。
E.g。在声明中你会找到
void Statement() :{} {
...
|
Block()
|
ExpressionStatement()
| ...
}
发出警告,因为两个选项都可以以" {"开头。你有两个选择。一个是忽略警告。只要Block首先出现,第一个选择将被采用并且一切都会很好。第二种选择是使用先行规范来抑制警告。像这样:
void Statement() :{} {
...
|
LOOKAHEAD("{") Block()
|
ExpressionStatement()
| ...
}
从某种意义上说,语法前瞻正面 - "如果X"采取这种替代方案。
如果你真的想要消极的 - 即。"如果不是X"则采取这种替代方案 - 展望未来它必须是语义的。
对于Statement,你可以写
void Statement() :{} {
...
|
LOOKAHEAD({!(getToken(1)==LBRACE)}) ExpressionStatement()
|
Block()
}
我确保这些是最后两个选项,否则你需要在阻止ExpressionStatement()的标记集中包含更多标记,例如:如果下一个标记是"如果"则不应该选择它。或者"而#34;或者" for"等等。
总的来说,你最好尽可能使用语法先行。它通常更直接,更难搞乱。
答案 1 :(得分:1)