我目前使用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这样的表达式,但是我不太确定。

最佳答案

对于您提供的示例,我希望使用句法向前看,从某种意义上说,这一定是“积极的”。

ExpressionStatement的产生不是解决问题的地方,因为别无选择。

void ExpressionStatement() : {} { Expression() ";" }


如果在表达式语句和块之间或者在表达式语句和函数声明(或两者)之间进行选择,就会出现问题。

例如。在声明中,您会发现

void Statement() :{} {
    ...
|
    Block()
|
    ExpressionStatement()
|   ...
}


发出警告,因为两个选择都可以以“ {”开头。您有两个选择。一种是忽略警告。只要Block排名第一,就将是第一选择,并且一切都会好起来。第二种选择是使用超前规范抑制警告。像这样:

void Statement() :{} {
    ...
|
    LOOKAHEAD("{") Block()
|
    ExpressionStatement()
|   ...
}


从某种意义上说,语法向前看是积极的-“如果X则采用此替代方法”。

如果您确实想要否定的符号,即“如果不是X,请采用其他替代方法”,请注意它必须是语义的。

在声明的情况下,您可以写

void Statement() :{} {
    ...
|
    LOOKAHEAD({!(getToken(1)==LBRACE)}) ExpressionStatement()
|
    Block()
}


我确保这是最后两种选择,因为否则您需要在阻止ExpressionStatement()的一组令牌中包括更多令牌,例如如果下一个标记是“ if”,“ while”或“ for”等,则不应选择该标记。

总体而言,最好在可能的情况下使用语法超前。通常更直接,更难弄乱。

07-24 17:31