C++的解析器在可以区分比较和模板实例化之前会做什么?
What does a parser for C++ do until it can differentiate between comparisons and template instantiations?
读完这个问题后,我想知道当主要的C++编译器像这样解析代码时会发生什么(关于 AST(:
struct foo
{
void method() { a<b>c; }
// a b c may be declared here
};
他们是像 GLR 解析器那样处理它还是以不同的方式处理它?还有什么其他方法可以解析这种情况和类似的情况?
例如,我认为可以推迟解析方法的主体,直到解析整个结构,但这真的可能和实用吗?
虽然当然可以使用GLR技术来解析C++(参见Ira Baxter的一些答案(,但我相信gcc和clang等常用编译器中常用的方法恰恰是将函数体的解析推迟到类定义完成。(由于C++源代码在解析之前会通过预处理器,因此解析器处理令牌流,这是为了重新解析函数体而必须保存的内容。我不认为重新解析源代码是可行的。
当函数定义完成时很容易知道,因为大括号({}
(必须平衡,即使不知道尖括号如何嵌套。
C++ 并不是在处理声明之前延迟解析的唯一有用语言。例如,允许用户定义具有不同优先级的新运算符的语言将要求在知道运算符的名称和优先级后(重新(解析所有表达式。一个更病态的例子是COBOL,其中OR
在a = b OR c
中的优先级取决于c
是整数(a
等于b
或c
之一(还是布尔值(a
等于b
或c
为真(。以这种方式设计语言是否是一个好主意是另一个问题。
答案显然取决于编译器,但 Eli Bendersky 的文章 Clang如何处理 C/C++ 的类型/变量名称歧义解释了 Clang 是如何做到的。我将简单地指出文章中的一些关键点:
Clang不需要词法分析器黑客:信息从词法分析器到解析器的单一方向
Clang 通过使用符号表知道标识符何时为类型
C++要求声明在整个类中可见,即使在它前面出现的代码中也是如此
Clang通过对声明进行完整的解析/语义分析来解决这个问题,但将定义留待以后使用;换句话说,它是词法化的,但在所有声明的类型都可用后进行解析。
- C++的解析器在可以区分比较和模板实例化之前会做什么?
- 什么是当前实例化?
- 函数模板实例化、替换和重载解析的顺序是什么?
- 从 c++ 中的实例化进程获取输出的可靠方法是什么?
- 在不使用默认构造函数的情况下声明 POD 结构时,会实例化什么?
- 使用大括号实例化 - 它是什么,为什么在这里使用它?
- 创建实例化所有其他类和子系统的类的目的是什么
- 显式实例化失败的原因是什么
- 我做了什么?需要在模板化类的方法中实例化派生类
- 当我创建一个int指针并实例化一个数组时,数组在内存中发生了什么
- 在显式实例化向量时<someType>,someType 默认构造函数的用途是什么?
- 在C++中实例化带大括号与不带大括号的变量有什么区别?
- 两者之间的最佳方法是什么:实例化对象或使用指针
- c++:什么是显式实例化
- C++:在堆栈中实例化类的正确方法是什么
- 在这个失败的C++类实例化中,我忽略了什么明显的事情
- 静态成员与静态常量成员实例化 - 有什么区别?
- C++模板实例化,它到底是什么意思
- 当用字符串文字实例化时,模板T和参数到底是什么?
- 定义和实例化的区别是什么?