0

根据ECMAScript 规范

在几种情况下,词汇输入元素的识别对使用输入元素的句法语法上下文很敏感。这需要词汇语法的多个目标符号。

两个这样的符号是InputElementDivInputElementRegExp

在 ECMAScript 中, 的含义/取决于它出现的上下文。根据上下文,a/可以是除法运算符、正则表达式文字的开头或注释分隔符。词法分析器无法单独区分除法运算符和正则表达式文字,因此它必须依赖来自解析器的上下文信息。

我想了解为什么这需要在词汇语法中使用多个目标符号。我对语言设计知之甚少,所以我不知道这是由于语法的某种形式要求还是只是惯例。

问题

  • 为什么不像这样使用单个目标符号:
InputElement ::
     [...]
     DivPunctuator
     RegularExpressionLiteral
     [...]

并让解析器告诉词法分析器使用哪个产生式(DivPunctuatorvs RegExLiteral),而不是使用哪个目标符号(InputElementDivvs InputElementRegExp)?

  • 还有哪些其他语言在其词汇语法中使用多个目标符号?

  • 我们如何对 ECMAScript 词法文法进行分类?从 CSG 的正式定义的意义上说,它不是上下文敏感的(即,其产生的 LHS 没有被终端和非终端符号的上下文包围)。

4

2 回答 2

2

在该术语的正式语言定义中,说词汇产生“对消耗输入元素的句法语法上下文敏感”并不会使语法上下文敏感。事实上,在几乎所有重要的语法中都有“对句法语法上下文敏感”的产生式。这是解析的本质:句法上下文有效地提供了一组潜在可扩展的非终结符,并且它们在不同的句法上下文中会有所不同,这意味着,例如,在大多数语言中,不能在需要表达式的地方输入语句(尽管通常情况下,表达式是语句的一种表现形式)。

但是,差异不涉及相同 non-terminal的不同扩展。“无上下文”语言所要求的是,非终结符的可能派生集是相同的集合,无论该非终结符出现在哪里。因此上下文可以提供不同的非终结符选择,但是每个非终结符都可以扩展而不考虑其上下文。这就是语法不受上下文影响的意义。

正如您所注意到的,上下文敏感性通常在语法中由具有左侧模式而不是单个非终结符的语法抽象出来。在最初的定义中,上下文——除了要扩展的非终结符之外的所有东西——都需要原封不动地通过产生式;只能扩展一个非终结符,但可能的扩展取决于上下文,如产生式所示。上面隐含的是,有些语法可以用 BNF 编写,它们甚至不符合上下文敏感的规则(或其他一些等效规则)。所以它不是一个二进制除法,无论是上下文无关的还是上下文敏感的。语法可能两者都不是(并且,由于空上下文仍然是上下文,因此任何上下文无关语法也是上下文敏感的)。底线是,当数学家说话时,他们使用单词的方式有时是出乎意料的。但它总是有一个明确的基本定义。

在形式语言理论中,没有词汇和句法产生;只是制作。如果词汇产生和句法产生都没有上下文,那么整个语法就是没有上下文的。但是,从实际的角度来看,组合语法更难解析,原因有很多,我不打算在这里讨论。事实证明,为一种语言编写语法并对其进行解析会更容易一些,只需区分词法解析器和句法解析器。

在经典模型中,首先进行词法分析,因此解析器看不到单个字符。相反,句法分析是通过“词汇标记”的“字母表”(在非常扩展的意义上)完成的。这非常方便——例如,这意味着词法分析可以简单地删除空格和注释,这极大地简化了句法语法的编写。但它也降低了通用性,正是因为句法解析器不能“指导”词法分析器做任何事情。在语法分析器意识到它的需要之前,词法分析器已经完成了它要做的事情。

如果解析器能够指导词法分析器,它将以与指导自身相同的方式进行。在某些作品中,令牌非终结符将包括InputElementDivand 而在其他作品中InputElementRegExp将是可接受的非终端。正如我所指出的,这不是上下文敏感性——它只是上下文无关语法的正常功能——但它确实需要对程序的组织进行修改,以允许词法分析器考虑解析器的目标. 这通常被(实践者,而不是理论家)称为“词汇反馈”,有时也被称为价值中立性较低的术语;它有时被认为是语言设计中的一个弱点,因为它违反了整齐分离的词法分析器/解析器架构。C++ 是一个非常强烈的例子,确实有人类难以解析的 C++ 程序,这是某种迹象。但是 ECMAScript 并没有真正遇到这个问题。人类通常无需付出任何明显的智力努力就能区分除法运算符和正则表达式分隔符。而且,虽然实现 ECMAScript 解析器所需的词法反馈确实使架构变得不那么整洁,但这也不是一项艰巨的任务。

无论如何,词汇语法中的“目标符号”只是 ECMAScript 参考的作者决定使用的一个短语。那些“目标符号”只是普通的词汇非终结符,就像任何其他产生式一样,所以说有“多个目标符号”和说“解析器指示词法分析器使用不同的产生式”没有区别,我希望解决您提出的问题。

笔记

  1. 两种语境的词汇差异不仅仅在于/具有不同的含义。如果仅此而已,则根本不需要词汇反馈。问题是标记化本身发生了变化。如果一个运算符是可能的,那么/=

    a /=4/gi;
    

    是单个标记(复合赋值运算符),并且gi是单个标识符标记。但是,如果此时可以使用正则表达式文字(但事实并非如此,因为正则表达式文字不能跟随标识符),那么 the/和 the=将是单独的标记,而 and 也是g如此i

  2. 一些程序员更喜欢从一组产品构建的解析器(但不是写这个的人:-));它们通常被称为“无扫描解析器”。在 ECMAScript 的无扫描仪解析器中,不会有词法反馈,因为没有单独的词法分析。

  3. 形式语言理论的理论纯粹性与编写实际编程语言的工作解析器的实际细节之间确实存在差异。理论模型非常有用,如果不了解它们,就很难编写解析器。但是很少有解析器严格遵守模型,这没关系。同样,俗称“正则”的东西表达式”在正式语言意义上根本不是正则表达式;一些“正则表达式”运算符甚至不是上下文无关的(反向引用)。因此假设某些理论结果(“正则表达式”)将是一个巨大的错误表达式可以在线性时间和恒定空间中识别”)实际上适用于“正则表达式”库。我不认为解析理论是唯一表现出这种二分法的计算机科学分支。

于 2021-11-16T04:49:49.400 回答
1

为什么不像这样使用单个目标符号:

InputElement ::
  ...
  DivPunctuator
  RegularExpressionLiteral
  ...

并让解析器告诉词法分析器使用哪个产生式(DivPunctuator vs RegExLiteral),而不是使用哪个目标符号(InputElementDiv vs InputElementRegExp)?

请注意, DivPunctuator 和 RegExLiteral 本身不是产生式,而是非终结符。在这种情况下,它们是您为 InputElement 提议的产品中的右侧(替代方案)。所以我将你的问题改写为:为什么不让句法解析器告诉词法解析器使用这两个替代方案中的哪一个?(或者等效地,要抑制这两者中的哪一个。)

在 ECMAScript 规范中,有一种机制可以实现这一点:语法参数(在5.1.5 节中解释)。

例如,您可以定义参数Div,其中:

  • +Div表示“斜线应被识别为 DivPunctuator”,并且
  • ~Div表示“斜杠应被识别为 RegExLiteral 的开头”。

那么你的生产将变成

InputElement[Div] ::
  ...
  [+Div] DivPunctuator
  [~Div] RegularExpressionLiteral
  ...

但是请注意,句法解析器仍然必须告诉词法解析器使用InputElement[+Div]orInputElement[~Div]作为目标符号,因此您回到规范的当前解决方案,模重命名。

还有哪些其他语言在其词汇语法中使用多个目标符号?

我认为大多数人不会尝试定义派生所有标记(或输入元素)的单个符号,更不用说必须将其划分为 ECMAScript 的 InputElementFoo 之类的变体,因此可能很难在其规范中找到具有类似内容的另一种语言.

相反,简单地为不同类型的标记(例如标识符、数字文字)的语法定义规则,然后从语法产生中引用它们是很常见的。所以这有点像有多个词汇目标符号,但不是(我会说)你所问的意义上的。

我们如何对 ECMAScript 词法文法进行分类?

它基本上是无上下文的,加上一些扩展。

于 2021-11-18T02:41:33.083 回答