运算符的优先级&同优先级内的结合性&序列点

来源:互联网 发布:linux oracle重建库 编辑:程序博客网 时间:2024/06/05 00:10

运算符的优先级&同优先级内的结合性&序列点

本文以C语言为基础来进行探讨。

参考资料:

运算符的结合性:
https://en.wikipedia.org/wiki/Operator_associativity
c的优先级与结合性:
https://msdn.microsoft.com/en-us/library/2bxt6kc4.aspx
https://msdn.microsoft.com/en-us/library/126fe14k.aspx
http://en.cppreference.com/w/c/language/operator_precedence
http://en.cppreference.com/w/cpp/language/operator_precedence
边效应:
https://msdn.microsoft.com/en-us/library/8a425116.aspx
https://gcc.gnu.org/onlinedocs/gccint/Side-Effects.html
https://gcc.gnu.org/onlinedocs/cpp/Duplication-of-Side-Effects.html
序列点:
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf 的附录C
https://msdn.microsoft.com/en-us/library/azk8zbxd.aspx
http://en.cppreference.com/w/cpp/language/eval_order
https://en.wikipedia.org/wiki/Sequence_point
最大匹配:
c语言n1256.pdf 的6.4 Lexical elements第4段落
https://en.wikipedia.org/wiki/Maximal_munch

优先级Precedence

基础知识略。参考Microsoft的C语言文档。

例子:

  • *p++ : 后缀++的优先级高于*,所以解析成 *(p++) 而不是 (*p)++
  • a & b || c : 位与运算符&的优先级高于||,所以解析成 (a & b) || c
  • a = b || c : 解析成 a = (b || c)
  • 1 || 0 && 0 解析成 1 || (0 && 0) 结果是1
  • q && r || s-- : 解析成 (q && r) || (s––)
  • a.b++ : 解析成 (a.b)++

结合性Associativity

结合性就是指,当同等优先级的操作符一起出现时,怎么将操作数和操作符分组(或说绑定)(以确定运算顺序)。

In programming languages, the associativity (or fixity) of an operator is a property that determines how operators of the same precedence are grouped in the absence of parentheses.

If an operand is both preceded and followed by operators (for example, “^ 4 ^“), and those operators have equal precedence, then the operand may be used as input to two different operations (i.e. the two operations indicated by the two operators). The choice of which operations to apply the operand to, is determined by the “associativity” of the operators.

注意:结合性只有在出现同等优先级操作符的时候才需要考虑(Associativity is only needed when the operators in an expression have the same precedence)。

一般来讲,操作符的结合性有4种:

  • associative (meaning the operations can be grouped arbitrarily)
  • left-associative (meaning the operations are grouped from the left)
  • right-associative (meaning the operations are grouped from the right)
  • non-associative (meaning operations can not be chained, often because the output type is incompatible with the input types)

比如,抽象表达式 a ~ b ~ c 中,~代表某操作符,其结合性如果:

  • left associativity,即从左到右:解析为(a ~ b) ~ c
  • right associativity,即从右到左:解析为a ~ (b ~ c)
  • 其他结合性定义:则其他特殊意义。

代入一个具体的例子,例如 7 − 4 + 2 中,假设+-操作符具有同等优先级,如果:

  • +-都是左结合性: (7 − 4) + 2 = 5
  • +-都是右结合性: 7 − (4 + 2) = 1

下面是一个更详细的例子,来说明结合性
表达式 5^4^3^2 ,这里 ^ 代表幂运算。语法分析器(parser)从左向右扫描读入该表达式。

  • 这里如果幂运算符^右结合性,即从右向左结合顺序,则:

    1. 读入5
    2. 读入^,现在节点是5^
    3. 读入4,现在节点是5^4
    4. 读入^,现在节点是5^(4^
    5. 读入3,现在节点是5^(4^3
    6. 读入^,现在节点是5^(4^(3^
    7. 读入2,现在节点是5^(4^(3^2
    8. 没有token可读,结束,现在节点是5^(4^(3^2))

    接下来,进行求值(depth-first),从树最顶端的^开始走:

    1. 求值程序(evaluator)沿着树,从第一个、经过第二个、到达第三个^表达式
    2. 计算3^2=9,这个结果替换到第二个^的表达式中
    3. 继续在parse tree的向上一层,计算4^9=262144,同样地这个结果替换到第一个^表达式中作为其操作数
    4. 继续向上一层,计算5^262144=...得到结果,最后这棵树就可以销毁了并返回总结果
    5. 结束
  • 这里如果幂运算符^左结合性,则计算式被解析成: ((5^4)^3)^2 ,当然运算结果和上面就不一样了。

序列点Sequence point

边效应Side Effects

最大匹配规则Maximal munch

词法分析器读入能构成有意义标记结构的最多的连续输入(the longest sequence of characters that could constitute a preprocessing token)。

例如:

  • x+++y : 因为从左向右能构成的最大有意义标记是++运算符,所以解析成 (x++)+y ,而不是x+(++y)
  • x+++++y : 同理,被解析成(x++)(++)(+y),所以编译报错。

这里需要注意的是“连续输入”。
例如在x+++y中,三个+字符是连续的,所以被解析成了(x++)+y;但如果是x+ ++y在第一个+符后面跟了空白,那么一般的词法分析器就会把该语句解析成x+(++y)
同理,如果写成x+++ ++y的表达式,就可以编译通过了。


0 0
原创粉丝点击