为什么关联性是算子的一个基本性质,而不是优先级的性质



在任何编程语言教科书中,我们总是被告知该语言中的每个运算符如何具有左或右关联性。似乎结合性是任何运算符的基本性质,而不管它需要多少个操作数。在我看来,无论我们如何将关联性分配给其他运算符,我们都可以将任何关联性分配到任何运算符。

但为什么会这样呢?也许举个例子更好。假设我想设计一种假设的编程语言。以这种任意方式(所有运算符具有相同的优先级)为这些运算符分配关联性有效吗:

unary operator: 
! right associative 
binary operators:
+ left associative
- right associative
* left associative 
/ right associative

!+-*/我的5个运算符都具有相同的优先级。

如果是的话,像2+2这样的表达式怎么会呢!3+5*6/3-5!3.3-3*2被我假设的解析器加括号了吗?为什么。

编辑:

第一个示例(2+2!3+5*6/3-5!3!3-3*2)不正确。也许忘了一元运算,让我这样说吧,我们能像上面那样为具有相同优先级的运算符分配不同的结合性吗?如果是,如何评估一个例子,比如2+3-4*5/3+2?因为大多数编程语言似乎都将相同的关联性分配给具有相同优先级的运算符。但我们总是谈论运算符关联性,就好像它是单个运算符的属性,而不是优先级的属性。

让我们记住关联性的含义。取任意运算符,比如@。众所周知,它的关联性是消除形式为a @ b @ c的表达式歧义的规则:如果@是左关联的,则解析为(a @ b) @ c;如果它是右关联的,a @ (b @ c)。它也可能是非关联的,在这种情况下a @ b @ c是一个语法错误。

如果我们有两个不同的运算符,比如@#,会怎么样?如果其中一个的优先级高于另一个,那么就没有什么好说的了,也没有什么可为关联性做的工作;优先级负责消除歧义。然而,如果它们的优先级相等,我们需要关联性来帮助我们

  • 如果两个运算符都是关联的,则a @ b # c表示(a @ b) # c
  • 如果两个运算符都是右关联的,则a @ b # c表示a @ (b # c)
  • 如果两个运算符都是非关联的,那么a @ b @ c就是语法错误

在剩下的情况下,运算符对关联性的看法并不一致。哪个操作员的选择优先?你可能会设计出这样的关联性优先规则,但我认为最自然的规则是声明任何这种情况下的语法错误。毕竟,如果两个运算符的优先级相等,为什么其中一个运算符的关联性优先于另一个呢?

根据我刚才给出的自然规则,您的示例表达式是一个语法错误。

现在,我们当然可以将不同的关联性分配给具有相同优先级的运算符。然而,这意味着存在优先级相等的运算符组合(例如您的示例!),这是语法错误。大多数语言设计者似乎更喜欢避免这种情况,并为所有具有同等优先级的运算符分配相同的关联性;这样,所有的组合都是合法的。我认为这只是美学。

你必须以某种方式定义结合性,大多数语言都选择"自然"地分配结合性(和优先级)——以匹配普通数学的规则。

然而,也有明显的例外——APL具有严格的从右到左的关联性,所有运算符都处于相同的优先级。