【问题标题】:How are (complex) declarations parsed in terms of precedence and associativity?如何根据优先级和关联性来解析(复杂的)声明?
【发布时间】:2014-09-01 08:06:30
【问题描述】:

符号,如&* 等,用于表达式声明,这是两个不同的概念。

表达式中,符号是运算符,我们有一个明确定义的优先级和关联性表。当一个表达式比较复杂的时候,我们可以用这张表来分解分析。 例如

    (a + b) * ++c

问题: 在声明中,这些符号不是运算符,因此我们不能应用运算符的优先级和关联性表声明中的符号是否有优先级和关联性表? 或者换句话说,当声明变得复杂时(试试这个int*& (*&f(int*))),是否有系统的方法来分解和分析它?

一个密切相关的后续问题: 某本书(入门)通过typedef 的示例教我们如何阅读复杂的声明:

typedef int (*tp_alias)[10]; //defines tp_alias as an pointer to an array of 10 int

书上讲授的方法:使用别名作为阅读的起点tp_alias是新的类型名。向左看,它有一个*,所以它是一个指针。然后看括号外:向右,[10] 表示它是一个大小为 10 的数组;在左边,int 表示数组的元素是 int。
后续问题: 我们如何阅读其他类型的别名声明,例如using?既然别名不在位了?例如using tp_alias = int (*)[10]?
也许可以从() 中读取,但如果有多个()s 怎么办?(我没见过,但有可能。)

【问题讨论】:

标签: c++


【解决方案1】:

表达式没有优先级表!

运算符的优先级是从语法中推断出来的。例如,考虑 logical-and-expressionlogical-or-expression 的定义:

logical-and-expression:
    inclusive-or-expression
    logical-and-expression && inclusive-or-expression

logical-or-expression:
    logical-and-expression
    logical-or-expression || logical-and-expression

现在考虑表达式a || b && c。它必须被解析为 logical-or-expression (其中左侧是 logical-or-expression a 而右侧是 logical-or-expression -and-expression b && c)。它不能被解析为 logical-and-expression,因为如果是,那么左侧 a || b 将必须是一个 logical-and-expression em> 也是,它不是。

另一方面,在(a || b) && c 中,您不能将其解析为逻辑或表达式,因为这样您将有(a 作为左侧,而b) && c作为右边,也不是一个有效的表达式。您可以将其解析为逻辑和表达式,因为(a || b)a || b 不同,它是一个有效的逻辑和表达式 .

编译器解析代码并构建语法树。如果根节点是一个逻辑或表达式,那么逻辑或运算最后完成。如果根节点是一个逻辑与表达式,那么逻辑与运算最后完成。以此类推。

好的,这是个坏消息。现在是好消息。

即使表达式中的运算符没有优先表,大多数时候你可以假装有(当然它可以被括号覆盖);这就是你在心理上解析表达式的方式。因此,事实证明,声明符也是如此。没有优先表,但你可以像有优先表一样在脑海中解析它们。

事实上,C 的设计者足够聪明,可以让声明使用与表达式相同的“优先规则”。这是“声明遵循用法”规则。例如,在表达式中

(*a)[10]

我们有一个包含间接表达式的数组索引表达式,反之亦然。同理,在

int (*a)[10];

我们拥有的是一个包含指针声明符的数组声明符,而不是反之亦然。 (因此,结果是指向数组的指针。)因此,如果您记得 [](数组索引)和 ()(函数调用)的优先级高于 *(间接),您可以应用相同的也为了理解声明。 (引用是一种特殊情况;很容易记住,引用在声明中与指针具有相同的“优先级”。)

【讨论】:

  • 非常详细的解释。但我很难相信运营商没有优先权。我刚刚检查了 cppreference(见下面的链接)和 C++ Primer(第 5 版,第 166 页)。两者都说运算符具有明确定义的优先级。 [链接:en.cppreference.com/w/cpp/language/operator_precedence]
  • 你的意思是没有子表达式的求值顺序?例如f()+g()+h(); 没有指定首先评估哪个函数?我同意这一点。
  • @user3424826 该表不在标准中。在标准中没有优先级;只是规则哪些类型的表达式可以包含哪些其他类型的表达式。它的确有所作为。考虑表达式w ? x , y : z。如果编译器基于“优先级”进行解析,则表达式将不正确,因为它将被解析为(w ? x) , (y : z)
  • @user3424826 但是您可以根据标准中的语法规则推断优先级。这就是人们构建这些表格的方式。
  • 好的,我尝试搜索 C++ 标准,但没有找到表。但仍有两点需要说明: 1. 是否有迹象表明这些符号在声明中与在表达式中具有相同的优先级? (非常感谢标准中的引用。) 2. 类型别名中是否可以有超过 1 个括号?例如像using tp_alias = int (*)(*)(我知道这是非法的)这样的(合法的),可能会混淆解析器?
【解决方案2】:

你使用螺旋法则。

一个很好的解释是here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-20
    • 1970-01-01
    • 2012-01-02
    • 1970-01-01
    • 1970-01-01
    • 2021-07-20
    • 2021-12-27
    • 1970-01-01
    相关资源
    最近更新 更多