4

我正在编写一个 JavaScript 预处理器,它会在必要的地方自动插入分号。不要问为什么。

现在我知道解决这个问题的一般方法是编写一个 JavaScript 解析器,并根据规范中的规则在必要时添加分号。但是我不想这样做,原因如下:

  1. 我不想写一个成熟的解析器。
  2. 我想保留评论和空白。

我已经(正确地)使用简单的扫描仪实现了自动分号插入的第二条和第三条规则。

然而,第一条规则被证明是实施起来更具挑战性。所以我有三个问题:

  1. 是否可以使用带有前瞻和后视的简单扫描仪来实现第一条规则?
  2. 如果可能,那么有人已经做到了吗?
  3. 如果不是那么我应该如何解决这个问题?

为了完整起见,这里是三个规则:

  • 当从左到右解析程序时,遇到任何语法生成都不允许的标记(称为违规标记)时,如果出现以下一项或多项,则在违规标记之前自动插入分号条件为真:

    1. 违规标记与前一个标记至少有一个LineTerminator分开。

    2. 有问题的令牌是}

  • 当程序从左到右解析时,遇到输入令牌流的结尾,并且解析器无法将输入令牌流解析为单个完整的 ECMAScript Program,则在末尾自动插入分号输入流。

  • 当程序从左到右解析时,遇到某个语法产生式允许的记号,但产生式是受限制的产生式,并且该记号将是紧跟注释之后的终端或非终端的第一个记号"[no LineTerminator here]" 在受限产生式中(因此这样的记号被称为受限记号),并且受限记号与前一个记号至少有一个LineTerminator分隔,然后在受限记号前自动插入分号.

但是,前面的规则还有一个额外的覆盖条件:如果分号随后将被解析为空语句,或者如果该分号将成为for语句标题中的两个分号之一(部分12.6.3 )。

4

1 回答 1

4

仅使用扫描仪(标记器)无法实现您想要的。这是因为要回答“我们这里需要分号吗?” 您需要回答“下一个标记是违规标记吗?” 要回答这个问题,您需要一个 JavaScript 语法,因为违规标记被定义为该语法在此位置不允许的东西。

我在创建所有标记的列表方面取得了一些成功,然后在第二步中处理了该列表(所以我会有一些上下文)。使用这种方法,您可以通过编写如下代码来修复某些地方:

  • 向后迭代标记(从最后一个开始,朝向文件的开头)
  • 如果当前令牌是IF, FOR, WHILE,VAR等:
    • 跳过标记前的空格和注释
    • 如果当前令牌不是;,则插入一个

这种方法有效,因为错误不是随机的。人们总是犯同样的错误。大多数时候,人们会忘记;行尾之后,而在关键字之前寻找缺失;是找到它们的好方法。

但这种方法只会让你走这么远。如果您必须可靠地找到所有丢失的分号,则必须编写一个 JavaScript 解析器(或重用现有的解析器)。

于 2013-02-25T14:22:16.340 回答