我目前正在实现 JavaScript/ECMAScript 5.1使用 JavaCC 的解析器。我最近learned关于 LOOKAHEAD
在这里很方便,因为语法不完全是 LL(1)。
我在 ECMAScript 语法中看到的一件事是“负向先行检查”,如下所示 ExpressionStatement
生产:
ExpressionStatement :
[lookahead ∉ {{, function}] Expression ;
所以我可能需要类似 LOOKAHEAD(!("{"| "function"))
的东西,但它在这种语法中不起作用。
我的问题是,我如何在 JavaCC 中实现这个“负 LOOKAHEAD
”?
阅读 LOOKAHEAD MiniTutorial 后我认为像 getToken(1).kind != FUNCTION
这样的表达式可能就是我需要的,但我不太确定。
最佳答案
对于您提供的示例,我更愿意使用句法前瞻,这在某种意义上必然是“积极的”。
ExpressionStatement 的产生式不是解决问题的地方,因为别无选择。
void ExpressionStatement() : {} { Expression() ";" }
当在表达式语句和 block 之间或表达式语句和函数声明(或两者)之间进行选择时,就会出现问题。
例如在声明中你会发现
void Statement() :{} {
...
|
Block()
|
ExpressionStatement()
| ...
}
给出警告,因为两个选择都可以以“{”开头。你有两个选择。一是忽略警告。只要 Block 优先,就会采取第一个选择,一切都会好起来的。第二种选择是使用前瞻规范来抑制警告。像这样:
void Statement() :{} {
...
|
LOOKAHEAD("{") Block()
|
ExpressionStatement()
| ...
}
从某种意义上来说,句法前瞻是积极的——“如果 X 就采用这个替代方案”。
如果你真的想要一个否定——即“如果不是X,就采用这个替代方案”——向前看,它必须是语义的。
在声明的情况下,你可以写
void Statement() :{} {
...
|
LOOKAHEAD({!(getToken(1)==LBRACE)}) ExpressionStatement()
|
Block()
}
我确保这是最后两个替代方案,否则您需要在阻止 ExpressionStatement() 的标记集中包含更多标记,例如如果下一个标记是“if”、“while”或“for”等,则不应选择它。
总的来说,如果可以的话,最好使用语法前瞻。它通常更直接,更难搞乱。
关于javascript - 如何在 JavaCC 中实现对 token 的负 LOOKAHEAD 检查?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26909200/