如何在JavaCC中实现负面LOOKAHEAD检查令牌?

时间:2014-11-13 12:45:08

标签: javascript parsing grammar ecmascript-5 javacc

我目前正在使用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这样的表达式可能就是我所需要的,但我对此并不十分肯定。

2 个答案:

答案 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)

我碰到了这个问题,正在寻找其他东西,是的,我知道这个问题是六年前提出的。

JavaCC的最高级版本是JavaCC21.,而JavaCC21确实允许否定句法超前。

在JavaCC21中,您将编写LOOKAHEAD(~<LBRACE>)来指定仅在下一个标记是 not LBRACE时才输入后面的扩展名。 ~字符使超前扩展无效,如果需要,您可以使用它与单个令牌相比抵消更复杂的扩展。例如:

LOOKAHEAD(〜( | ))

JavaCC21实际上还有许多其他功能,这些功能在旧版JavaCC项目中不存在。这是一个大问题:修复了长期存在的嵌套嵌套先行无法正常工作的错误。参见here.