为什么选择二元运算符而不是一元运算符?

Why is a binary operator selected over a unary operator?

对于同时作为一元和二元的运算符,为什么在像 a@b 这样的表达式中选择了二元?

经过大量的思考和搜索,我仍然无法回答为什么 a+b 被解析为二进制表达式而不是 a(+b),这显然是乱码。

我不认为上下文无关语法能够区分这两者,并且试图在 this version of the standard 中找到答案也没有给我任何答案。

解析器是否专门选择二进制版本因为一元版本会是乱码?如果是这样,标准中是否有概述这一点的部分?

上下文无关并不意味着“无状态”。解析器有很多状态来跟踪给定它目前看到的标记可能的语法规则,并预测接下来会出现什么标记。因为没有规则说两个表达式可以直接相邻出现,所以它甚至不会考虑 a+b 可能是并排的表达式 a+b

例如,假设我们正在使用这个基本语法:

expr → expr '+' unary_expr | unary_expr
unary_expr → '+' unary_expr | IDENT

(符号: 给出非终结符可以扩展到的规则,| 表示替代可能性。'+' 是加号标记,IDENT 是任何标识符标记。)

让我们解析 a+b。我们的解析器的起始状态将是:

1. expr → expr '+' unary_expr
         ^
2. expr → unary_expr
         ^
3. unary_expr → '+' unary_expr
               ^
4. unary_expr → IDENT
               ^

开始时它正在考虑一些规则。它不知道它会得到哪个,可能是其中任何一个。请注意,它正在考虑的每个产品还包括一个 光标 ,我在上面用 ^ 插入符号标记了它。那是解析器在规则中的位置。

好的,现在它看到了第一个 IDENT 标记。它将其状态更新为以下内容:

1. expr → expr '+' unary_expr
              ^
2. expr → unary_expr
                    ^
3. unary_expr → IDENT
                     ^

现在它正在考虑三个规则。请注意,光标已向右移动。

如果第一个规则是正确的,那么它刚刚看到一个表达式并且期待下一个 '+'。或者,也许第二条规则是正确的,而 a 只是一个一元表达式。在那种情况下,它不希望有更多的令牌跟随。解析器不知道它会是哪个,所以它正在考虑两者。

你会看到 如果 下一个标记是 '+' 那么它 必须 是二进制加号。为什么?因为第一个规则是唯一一个预期下一个 '+' 标记的规则。

要将 '+' 解释为一元加上解析器必须使此规则处于活动状态,光标位于 '+':

之前
unary_expr → '+' unary_expr 
            ^

你可以看到它没有。


如果上下文无关并不意味着无状态,那么它是什么意思呢?我们从什么“环境”中“解放”出来了?

Context-free 是对语法可以包含哪些规则的限制。相反的是 context-sensitive,其中作品可以根据周围环境而变化。上下文相关语法比上下文无关语法更强大,但它们更难解析——即使对人类来说也是如此!语言理论家很早就发现,上下文无关文法占据了一个甜蜜点,即强大到足以表达而不是极其复杂的推理。

有关详细信息,请参阅: Context-free grammars versus context-sensitive grammars?

A context-free grammar (CFG) is a grammar where (as you noted) each production has the form A → w, where A is a nonterminal and w is a string of terminals and nonterminals. Informally, a CFG is a grammar where any nonterminal can be expanded out to any of its productions at any point. The language of a grammar is the set of strings of terminals that can be derived from the start symbol.

A context-sensitive grammar (CSG) is a grammar where each production has the form wAx → wyx, where w and x are strings of terminals and nonterminals and y is also a string of terminals. In other words, the productions give rules saying "if you see A in a given context, you may replace A by the string y." It's an unfortunate that these grammars are called "context-sensitive grammars" because it means that "context-free" and "context-sensitive" are not opposites, and it means that there are certain classes of grammars that arguably take a lot of contextual information into account but aren't formally considered to be context-sensitive.