This page说“前缀运算符通常右关联,而后缀运算符是左关联的”(强调我的)。
是否存在左关联前缀运算符或右关联后缀运算符的实例?如果没有,假设的是什么样的,以及如何解析?
答案 0 :(得分:3)
原则上可能存在。例如,考虑前缀一元加号和减号运算符:假设+
是标识操作,-
否定数值。
它们“通常”是右关联的,这意味着+-1
等同于+(-1)
,结果是减1。
假设它们是左关联的,那么表达式+-1
将等同于(+-)1
。
因此,语言必须赋予子表达式+-
一个含义。语言“通常”不要求它具有意义并且不要给它一个,但是您可以想象一种函数语言,其中将标识运算符应用于否定运算符的结果是具有完全准确的运算符/函数与否定算子相同的效果。然后,对于这个例子,完整表达式的结果将再次为-1。
实际上,如果并置函数/运算符的结果被定义为函数/运算符,其效果与按从右到左的顺序应用两者相同,则始终对于表达式的结果与您关联它们的方式。这只是定义(f g)(x) == f(g(x))
的两种不同方式。但是,如果您的语言将+-
定义为-
以外的其他内容,那么关联的方向就很重要(我怀疑对于习惯于“通常”语言的人来说,这种语言很难阅读...)
另一方面,如果语言不允许并置运算符/函数,则前缀运算符必须是右关联的,以允许表达式+-1
。禁止并置是另一种说法(+-)
没有意义的方式。
答案 1 :(得分:2)
将“左关联”和“右关联”的概念精确化并不是特别容易,因为它们不直接对应于任何明确的语法特征。不过,我会试试。
尽管缺乏数学布局,我试图插入优先关系here的解释,这是我能做的最好的,所以我不再重复了。基本思想是给定一个运算符语法(即,没有生产有两个非终端而没有中间终端的语法),可以定义优先关系⋖
,≐
和{语法符号之间的{1}},然后这种关系可以扩展到终端。
简单地说,如果⋗
和a
是两个终端,b
成立,如果有一些产品,其中a ⋖ b
后跟一个非终端推导(可能不是立即),其中第一个终端是a
。如果存在b
跟随非终端的某个产生,a ⋗ b
成立,该非终端具有最后一个终端为b
的推导。如果a
和a ≐ b
是连续的或由单个非终端分隔,则a
成立。b
成立。使用看起来像算术比较的符号是不幸的,因为通常的算术法则都不适用。 a ≐ a
为真是没有必要的(实际上很少见); a ≐ b
并不意味着b ≐ a
,而a ⋖ b
和a ⋗ b
两者(或两者都不是)都属实。
运算符语法是一个运算符优先级语法iff给定任意两个终端a
和b
,最多只有a ⋖ b
,a ≐ b
和a ⋗ b
一个
如果语法是运算符优先语法,则有可能找到对终端的整数赋值,这使得优先关系或多或少地对应于整数比较。由于a ≐ a
的罕见性,很少有可能进行精确的对应。但是,通常可以找到两个函数f(t)
和g(t)
,如果a ⋖ b
和f(a) < g(b)
为真,则a ⋗ b
为真f(a) > g(b)
}。 (我们不担心only if
,因为a
和b
之间可能不存在任何关系,并且a ≐ b
通常使用不同的机制处理:实际上,它意味着完全不同的东西。)
%left
和%right
(yacc / bison / lemon / ...声明)构造函数f
和g
。他们这样做很简单。如果OP
(运算符)是“左关联”,则表示必须将expr1 OP expr2 OP expr3
解析为<expr1 OP expr2> OP expr3
,在这种情况下OP ⋗ OP
(您可以从推导)。同样,如果ROP
为“右关联”,则必须将expr1 ROP expr2 ROP expr3
解析为expr1 ROP <expr2 ROP expr3>
,在这种情况下ROP ⋖ ROP
。
由于f
和g
是单独的函数,因此很好:左关联运算符将具有f(OP) > g(OP)
,而右关联运算符将具有f(ROP) < g(ROP)
。这可以通过为每个优先级使用两个连续的整数,并且如果运算符是右关联的,依次将它们分配给f
和g
,并g
和{{1反过来,如果它是左关联的。 (此过程将保证f
永远不会等于f(T)
。在通常的表达式语法中,唯一的≐关系在开括号和闭括号类型符号之间,并且这些通常不是模糊的,所以在yacc衍生语法中,没有必要为它们分配优先级值。在Floyd解析器中,它们将被标记为g(T)
。)
现在,前缀和后缀运算符怎么样?前缀运算符始终位于[1]形式的生成中:
≐
non-terminal-1: PREFIX non-terminal-2;
之前没有非终端,所以任何事都不可能是PREFIX
(因为⋗ PREFIX
的定义要求前面有一个非终端{{} 1}})。因此,如果a ⋗ b
完全是关联的,那么它必须是右关联的。同样,后缀运算符对应于:
b
因而PREFIX
,如果它完全是关联的,则必须是左关联的。
运算符在语义上或语法上可以是非关联的(在某种意义上,将运算符应用于同一运算符的应用程序的结果是未定义的或格式错误的)。例如,在C ++中,non-terminal-3: non-terminal-4 POSTFIX;
在语义上是不正确的(除非POSTFIX
以某种方式重新定义++ ++ a
),但它被语法接受(如果operator++()
已被重新定义)。另一方面,a
在语法上不正确。所以operator++()
在语法上是非关联的。
[1]在Floyd语法中,所有非终端都合并为单个非终端类型,通常为new new T
。但是,优先关系的定义并不需要这样,所以我为不同的非终端类型使用了不同的占位符。
答案 2 :(得分:1)
我不记得任何左关联的前缀运算符或右关联的后缀运算符。但我可以想象两者都可以轻易存在。它们并不常见,因为人们如何看待操作员的自然方式是:更靠近身体的方式 - 首先应用。
C#/ C ++语言的简单示例:
~-3
等于2
,但是
-~3
等于4
这是因为那些前缀运算符是右关联的,对于~-3
,它意味着首先 - 运算符应用,然后〜运算符应用于前一个结果。它将导致整个表达式的值等于2
假设您可以想象,如果这些运算符是左关联的,那么首先应用~-3
左侧的运算符~
,然后应用-
之前的运算符4
。它将导致整个表达式的值等于the meaning of "left-associativity" is that +-1 is equivalent to (+-)1
[编辑] 回答 Steve Jessop :
史蒂夫说:@
我不同意这一点,并认为这是完全错误的。为了更好地理解左关联性,请考虑以下示例:
假设我有左关联前缀运算符的假设编程语言:
3
- 将操作数乘以#
7
- 将@#5
添加到操作数
我的语言中的以下构造(5*3)+7 == 22
将等于(5+7)*3 == 36
如果我的语言是正确联想的(与大多数常用语言一样),那么我的语言将{{1}}
如果您有任何疑问,请与我们联系。
答案 3 :(得分:1)
我讨厌拍下我自己提出的一个问题,但是看了另外两个答案后,如果我无意中提出了一个主观问题,并且事实上左边的解释是错误的,那是不对的。关联前缀和右关联后缀只是undefined?
记住即使表达式像表达式一样普遍存在于一些惯例之上,如果有一个公约从未考虑过的边缘情况,那么也许,直到一些标准委员会决定一个定义,最好简单地假装它不存在。
答案 4 :(得分:1)
假设的例子。语言具有前缀运算符 @ 和后缀运算符#,具有相同的优先级。表达式 @x#将等于(@ x)#,如果两个运算符都是左关联的,则 @(x#)如果两个运算符都相同是正确联想的。
答案 5 :(得分:0)
我想说,至少在通常使用的条款中,答案是否定的。
问题非常简单:至少与通常使用的一样,前缀或后缀运算符是一元运算符 - 通过关联性(至少主要)应用于二元运算符。
对于某些任意运算符a @ b @ c
,请考虑一些任意表达式@
。关联性解决了这是否等同于(a @ b) @ c
或a @ (b @ c)
的问题。使用一元运算符(前缀或后缀),首先没有这样的问题。
可能出现的唯一真正问题是,如@ a @
这样的表达式,这是否等同于(@ a) @
或@ (a @)
。但是,不能成为关联性问题。当您再次应用相同的运算符时,关联性仅处理含义 - 但在这种情况下,我们有一个前缀运算符和一个后缀运算符,这意味着它们显然必须是两个不同的运算符,而不是相同的运算符,因此关联性不能适用。