繁体   English   中英

如何在JavaCC中实现JavaScript自动分号插入?

[英]How to implement JavaScript automatic semicolon insertion in JavaCC?

我正在完成JavaCC的 ECMAScript 5.1 / JavaScript 语法 我已经按照规范完成了所有标记和制作。

现在,我面临着一个大问题,我不知道该如何解决。

JavaScript具有自动分号插入的这一出色功能:

JavaScript自动分号(ASI)的规则是什么?

引用规范 ,规则是:

分号插入有三个基本规则:

  1. 当从左到右解析程序时,遇到任何语法产生都不允许的令牌(称为冒犯令牌)时,如果以下一项或多项操作,则在冒犯令牌之前会自动插入分号条件为真:

    • 至少有一个LineTerminator将有问题的令牌与前一个令牌分开。
    • 令人讨厌的令牌是}
  2. 当从左向右解析程序时,遇到令牌输入流的末尾,并且解析器无法将输入令牌流作为单个完整的ECMAScript程序进行解析,则分号将自动插入到末尾。输入流。

  3. 当从左向右解析程序时,遇到某种语法的某种生产所允许的令牌,但是该生产是受限制的生产,并且该令牌将成为紧随注解之后的终端或非终端的第一个令牌在受限产品中[no LineTerminator here] (因此,此类令牌称为受限令牌),并且受限令牌与至少一个LineTerminator与前一个令牌分开,然后在受限令牌之前自动插入分号。

但是,上述规则还有一个额外的优先条件:如果分号随后将被解析为空语句,或者如果该分号成为for语句的标头中的两个分号之一,则永远不会自动插入分号。 12.6.3 )。

如何用JavaCC来实现呢?

到目前为止,我发现的答案JAVACODE是Dojo工具箱中的这种语法工具箱具有专门用于该任务的JAVACODE部分,称为insertSemiColon 但是我看不到在任何地方都可以调用此方法(无论是在语法上还是在整个jslinker代码中)。

如何用JavaCC解决这个问题?

另请参阅以下问题:

javascript语法和semocolon自动插入

(那里没有答案。)

评论中的一个问题:

说分号只需要在语法上允许分号的地方插入是正确的吗?

我认为说分号仅在语法上需要分号的地方插入是正确的。

这里的相关部分是第7.9节:

7.9自动分号插入

某些ECMAScript语句(空语句,变量语句,表达式语句,do-while语句,continue语句,break语句,return语句和throw语句)必须以分号终止。 这样的分号可能总是显式地出现在源文本中。 但是,为方便起见,在某些情况下可以从源文本中省略此类分号。 通过说在这些情况下将分号自动插入到源代码令牌流中来描述这些情况。

让我们以return语句为例:

ReturnStatement :
    return ;
    return [no LineTerminator here] Expression ;

因此(从我的理解)从语法上说 ,分号是必需的 ,而不仅仅是被允许的 (如您的问题)。

分号插入的3条规则可以在ECMAScript 5.1标准的7.9.1节中找到

我认为标准中的规则1和2可以通过语义先行处理。

void PossiblyInsertedSemicolon() 
{}
{
    LOOKAHEAD( {semicolonNeedsInserting()} ) {}
|
    ";"
}

那么什么时候需要插入分号呢? 当其中之一为真时

  • 当下一个标记不是分号并且在另一行上时( getToken(1).kind != SEMICOLON && getToken(0).endLine < getToken(1).beginLine
  • 当下一个标记是右括号时。
  • 当下一个令牌是EOF时

所以我们需要

boolean semicolonNeedsInserting() {
    return (`getToken(1).kind != SEMICOLON && getToken(0).endLine < getToken(1).beginLine`) 
    || getToken(1).kind == RBRACE
    || getToken(1).kind == EOF ;
}

这照顾了标准的规则1和2。

对于我对这个问题的回答中提到的规则3(限制生产),您可以执行以下操作

void returnStatement()
{}
{
    "return"
    [   // Parse an expression unless either the next token is a ";", "}" or EOF, or the next token is on another line.
        LOOKAHEAD( {   getToken(1).kind != SEMICOLON
                    && getToken(1).kind != RBRACE
                    && getToken(1).kind != EOF
                    && getToken(0).endLine == getToken(1).beginLine} )
        Expression()
    ]
    PossiblyInsertedSemicolon() 
}

暂无
暂无

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

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