C++ 标准要求实现在解析阶段之前执行词法分析以生成标记流。根据词法分析规则,两个连续>
的字符(不跟在后面=
)总是会被解释为一个>>
记号。C++ 标准提供的语法是根据这些标记定义的。
在某些上下文中(例如>
在模板 ID 中期望 a 时)实现应解释>>
为 2>
的要求并未在语法中指定。相反,该规则被指定为一种特殊情况:
14.2 模板特化的名称 [temp.names] ###
在名称查找 (3.4) 发现名称是模板名称或operator-function-id或literal-operator-id引用一组重载函数后,其中任何成员都是函数模板,如果后面跟着a <
,<
始终将其作为模板参数列表的分隔符,而从不作为小于运算符。解析模板参数列表时,将第一个非嵌套>
的作为结束分隔符而不是大于运算符。类似地,第一个非嵌套>>
的被视为两个连续但不同的>
标记,其中第一个被视为模板参数列表的结尾并完成
模板 ID。[注意:此替换规则产生的第二个>
标记可能会终止封闭的
模板ID构造,或者它可能是不同构造的一部分(例如演员表)。-结束注释]
请注意前面的规则,在某些情况下,<
应将其解释为<
template -argument-list 中的。这是另一个需要上下文以消除解析歧义的构造示例。
C++ 语法包含许多这样的歧义,在解析过程中如果没有上下文信息就无法解决这些歧义。其中最著名的被称为Most Vexing Parse,其中标识符可以根据上下文解释为类型名称。
在 C++ 中跟踪上述上下文需要实现与解析阶段并行执行一些语义分析。这通常以在给定上下文中识别特定语法结构时调用的语义动作的形式实现。然后,这些语义动作构建了一个表示上下文并允许有效查询的数据结构。这通常被称为符号表,但 C++ 所需的结构几乎是整个AST。
这些上下文敏感的语义动作也可以用来解决歧义。例如,在识别namespace-body上下文中的标识符时,语义操作将检查该名称是否先前被定义为模板。然后将其结果反馈给解析器。这可以通过用结果标记标识符标记来完成,或者用匹配不同语法规则的特殊标记替换它。
可以使用相同的技术将 a 标记为模板参数列表<
的开头,或将 a标记为结尾。用两个进行上下文敏感替换的规则本质上是相同的问题,并且可以使用相同的方法解决。>
>>
>