简体   繁体   English

如何在 JavaCC 中对令牌实施负面的 LOOKAHEAD 检查?

[英]How to implement a negative LOOKAHEAD check for a token in JavaCC?

I currently implementing a JavaScript/ ECMAScript 5.1 parser with JavaCC.我目前正在使用 JavaCC 实现一个 JavaScript/ ECMAScript 5.1解析器。 I recently learned about LOOKAHEAD s which are handy here as the grammar is not fully LL(1).我最近了解到LOOKAHEAD在这里很方便,因为语法不完全是 LL(1)。

One of the things I see in the ECMAScript grammar is "negative lookahead check", like in the following ExpressionStatement production:我在 ECMAScript 语法中看到的一件事是“负前瞻检查”,就像在下面的ExpressionStatement产品中一样:

ExpressionStatement :
    [lookahead ∉ {{, function}] Expression ;

So I'll probably need something like LOOKAHEAD(!("{" | "function")) but it does not work in this syntax.所以我可能需要类似LOOKAHEAD(!("{" | "function"))但它在这种语法中不起作用。

My question is, how could I implement this "negative LOOKAHEAD " it in JavaCC?我的问题是,我怎么能在 JavaCC 中实现这个“负面的LOOKAHEAD ”呢?

After reading the LOOKAHEAD MiniTutorial I think that an expression like getToken(1).kind != FUNCTION may be what I need, but I am not quite sure about it.阅读LOOKAHEAD MiniTutorial 后,我认为像getToken(1).kind != FUNCTION这样的表达式可能是我需要的,但我不太确定。

For the example you provide, I would prefer to use syntactic look ahead, which is in a sense necessarily "positive".对于您提供的示例,我更喜欢使用句法前瞻,这在某种意义上必然是“积极的”。

The production for ExpressionStatement is not the place to tackle the problem as there is no choice. ExpressionStatement 的生成不是解决问题的地方,因为别无选择。

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

The problem will arise where there is a choice between an expression statement and a block or between an expression statement and a function declaration (or both).如果在表达式语句和块之间或在表达式语句和函数声明(或两者)之间进行选择,就会出现问题。

Eg in Statement you will find例如在 Statement 你会发现

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

gives a warning because both choices can start with a "{".给出警告,因为这两个选项都可以以“{”开头。 You have two options.你有两个选择。 One is to ignore the warning.一种是忽略警告。 The first choice will be taken and all will be well, as long as Block comes first.只要 Block 是第一位的,就会采取第一个选择,一切都会好起来的。 The second choice is to suppress the warning with a lookahead specification.第二种选择是使用先行规范来抑制警告。 like this:像这样:

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

Syntactic look ahead is, in a sense positive -- "take this alternative if X".从某种意义上说,语法展望是积极的——“如果 X 则采用这种替代方案”。

If you really want a negative --ie, "take this alternative if not X"-- look ahead it has to be semantic.如果你真的想要一个否定——即,“如果不是 X,就采用这个替代方案”——向前看,它必须是语义的。

In the case of Statement you could write在 Statement 的情况下,您可以编写

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

I made sure that these are the last two alternatives since otherwise you'd need to include more tokens in the set of tokens that block ExpressionStatement(), eg it should not be chosen if the next token is an "if" or a "while" or a "for", etc.我确保这些是最后两个替代方案,否则您需要在阻止 ExpressionStatement() 的标记集中包含更多标记,例如,如果下一个标记是“if”或“while”,则不应选择它" 或 "for" 等。

On the whole, you are better off using syntactic lookahead when you can.总的来说,最好尽可能使用句法先行。 It is usually more straight forward and harder to mess up.它通常更直接,更难搞砸。

I came across this question looking for something else, and yes, I am aware that the question was posed nearly 6 years ago.我在寻找其他问题时遇到了这个问题,是的,我知道这个问题是在近 6 年前提出的。

The most advanced version of JavaCC is JavaCC21. JavaCC 的最高级版本是JavaCC21。 and JavaCC21 does allow negative syntactic lookahead.并且 JavaCC21 确实允许负句法前瞻。

In JavaCC21 you would write LOOKAHEAD(~<LBRACE>) to specify that you only enter the expansion that follows if the next token is not an LBRACE, for example.例如,在 JavaCC21 中,您将编写LOOKAHEAD(~<LBRACE>)以指定仅在下一个标记不是LBRACE 时才输入LOOKAHEAD(~<LBRACE>)的扩展。 The ~ character negates the lookahead expansion and you can use it to negate more complex expansions than a single token, if you want to. ~字符否定前瞻扩展,如果需要,您可以使用它来否定比单个标记更复杂的扩展。 For example:例如:

LOOKAHEAD (~(<LBRACE>|<LPAREN>))前瞻 (~(<LBRACE>|<LPAREN>))

There are actually quite a few other features that JavaCC21 that are not present in the legacy JavaCC project.实际上,JavaCC21 中还有很多其他功能在遗留 JavaCC 项目中不存在。 Here is a biggie: the longstanding bug in which nested syntactic lookahead does not work correctly has been fixed.这是一个大问题:嵌套句法前瞻无法正常工作的长期错误已得到修复。 Seehere.看到这里。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM