JavaScript 是上下文无关语言吗?

Is JavaScript a Context Free Language?

how browsers work 上的这篇文章解释了 CSS 如何是上下文无关的,而 HTML 不是 。但是 JavaScript 呢,JavaScript 是上下文无关的吗?

我正在学习 CFG 和形式证明,但离理解如何解决这个问题还有很长的路要走。有谁知道 JavaScript 是否是上下文无关的?

没有一种编程语言是(完全)上下文无关的(我想说包括 CSS)。即使上下文无关文法 (CFG) 可用于 define/generate compilers/parsers 语言。

一个简单的事实(例如)变量需要在使用之前首先定义,或者涉及标识符的声明应该是独一无二,使语言“上下文敏感”。

一种(编程)语言的语法应该描述(并生成)字符串,这些字符串只是该语言中的有效程序(在句法上,但在语义上)。然而,CFG 可以描述和生成不是有效程序的字符串(给定语言语义和规范)。描述有效程序的条件(例如:1. class 需要在使用 new class() 之前定义,2. ids 必须匹配等)需要 context-sensitivity

没有 CFG(具有任何有限数量的产生式)可以正确地表示只有这种语言的有效字符串{ anbncn : n >= 1 }, where n should be the same for a, b, c (it should match). Note one can indeed define a CFG for (a superset of) this language, but it will accept also non-valid strings along with valid ones (and then by other means filter them out), this is not what a grammar specification for a language is supposed to do. It should accept only the valid strings and reject the non-valid. In an analogy with statistics,可以说语法规范一种语言应该 eliminate/minimise Type-I(拒绝有效字符串)和 Type-II(接受无效字符串)错误,不只是其中之一。

让我在 JavaScript 的上下文中举一个简单的例子(因为变量似乎对 JavaScript 没有问题)。

在JavaScript(在strict mode)中,重复的命名函数声明无效。所以这是无效的:

function duplicateFunc(){}
function duplicateFunc(){} // duplicate named function declaration

所以程序不正确,但CFG无法处理这种情况。

甚至开启严格模式本身也是上下文相关的 严格模式规则的一个子集可以通过在案例中拆分 CFG 并根据 (删除严格模式示例)

进行相应解析来处理

[更新]

我将尝试给出几个 JavaScript 非上下文无关代码的示例,这些代码 不需要 "strict mode"(对 suggestions/corrections).

reserved words/keywords的使用是对语法的扩展(或限制)。这是一个无关的功能,因此以下示例应算作非 CF 行为的示例。

var var; // identifier using reserved name
var function; // identifier using reserved name
obj.var; // reserved name used as (explicit) property
obj["var"]; // this is fine!!
Object++; // built-in type used as numeric variable

[/更新]

所以上下文在程序的正确解析中起着重要作用。俗话说“上下文就是一切”!

然而,这种 上下文敏感度 可以(希望)通过对上下文无关语法的轻微扩展(例如 Attribute Grammars, Affix Grammars, TAG Grammars 等)来处理,这仍然可以进行有效的解析(意味着在多项式时间内)。

[更新]

"我会说包括 CSS"

详细说明一下这个说法。 CSS1 将是 CF,但由于 CSS 规范添加了更多功能,包括 variable 支持(例如 css-counters),它使 CSS 代码上下文-上述意义上的敏感(例如变量需要在使用前定义)。所以下面的 css 代码将被浏览器解析(并被忽略,因为它无效)但它不能用 CFG

来描述
body { }
h3::before {
  counter-increment: section;               /* no counter section has been defined, not valid css code */
  content: "Section" counter(section) ": "; /* Display the counter */
}

[/更新]

我很确定 JS 不是 上下文无关的 — 给定任意代码人工制品,在不知道其上下文的情况下不一定能确定其确切含义。

第一个想到的例子是{}——这代表一个空的对象字面量还是一个空的语句块?没有上下文是不可能决定的,但是因为该语言允许从以 '}' 结尾的语句中省略分号(就像大多数具有类似 C 语法的语言一样)它也可能是不可决定的 with语境!考虑 {x: {}} ——这可能是一个对象字面量,其 "x" 字段包含一个空对象,或者是一个带有标签子语句的语句块(其中标签是 'x' 和子-语句是 {})。也许语言规范有一些规则可以在这种情况下选择正确的解释,但无论如何,仅通过这些示例来判断,语言似乎并不是上下文无关的。

JavaScript的'automatic semicolon insertion'特征当然不能帮助区分表达式和语句。

还有一个要考虑的问题:function x() {} — 这有什么作用?如果它是一条语句,它会声明一个新的提升变量 'x' 并将此函数作为其值。如果它是一个表达式,它只是计算一个函数,该函数的上值 'x' 绑定到同一函数(用于自引用)。

不,JavaScript 不是上下文无关语言。

非常接近一,ECMAScript 5 规范确实做到了use a context-free grammar1 to describe the language's syntax (you can find all productions in Annex A)。

当然,它确实对纯上下文无关语法产生式做了一些扩展,并描述了解析器的额外行为。一个特别的事情是 lookahead 的使用,它仍然是一种上下文无关的语言,但如果它不能用于某些规则,会使语法复杂化很多。不允许某些东西出现在严格模式代码中是类似的——它可以通过调整语法来完成(有更多的产品),但是通过离开 BNF 更容易表达规则。

但是,也有一些2 规则确实使语言不是上下文无关的。您会在 description of early errors 中找到一个概述,它可以使程序代码无效。对象字面量不能包含重复的 属性 名称,函数参数列表不能包含重复的标识符,这两个规则不能使用(有限的)上下文无关语法来表达。
我的直觉告诉我 the automatic semicolon insertion 属于同一个盒子,但我认为它的规则太复杂了,甚至无法在这里尝试证明。

1:实际上它使用两个语法,一个 lexical and a syntactical 一个,其中第一个消除除法表达式和正则表达式之间的歧义,并产生作为第二个语法输入的标记.
2:与其他编程语言相比,实际上相当少