在 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 解析器那样处理它还是以不同的方式处理它?还有哪些其他方法可以解析这种情况和类似情况?
例如,我认为可以将方法体的解析推迟到整个结构体都解析完之后,但这真的可行和实用吗?
答案显然取决于编译器,但 Eli Bendersky 的文章 How Clang handles the type / variable name ambiguity of C/C++ 解释了 Clang 是如何做到的。我将简单地记下文章中的一些要点:
Clang 不需要词法分析器:信息从词法分析器到解析器的单向传输
Clang 通过使用符号 table
知道标识符何时是类型
C++ 要求声明在整个 class 中可见,即使在出现在它之前的代码中也是如此
Clang 通过对声明进行完整的 parsing/semantic 分析来解决这个问题,但将定义留到以后;换句话说,它被词法化但在所有声明的类型可用后被解析
虽然肯定可以使用GLR技术来解析C++(参见Ira Baxter的一些回答),但我相信gcc和clang等常用编译器中常用的方法恰恰是推迟函数体的解析直到 class 定义完成。 (由于 C++ 源代码在解析之前通过预处理器,解析器在标记流上工作,这是必须保存以便重新解析函数体的内容。我认为重新解析源代码是不可行的。 )
很容易知道函数定义何时完成,因为大括号 ({}
) 必须平衡,即使不知道尖括号是如何嵌套的。
C++ 并不是唯一一种在处理声明之前延迟解析有用的语言。例如,一种允许用户定义具有不同优先级的新运算符的语言将要求在已知运算符的名称和优先级后(重新)解析所有表达式。更病态的例子是COBOL,其中OR
在a = b OR c
中的优先级取决于c
是否为整数(a
是否等于b
之一或 c
) 或布尔值(a
等于 b
或 c
为真)。以这种方式设计语言是否是一个好主意是另一个问题。
读完
struct foo
{
void method() { a<b>c; }
// a b c may be declared here
};
他们是像 GLR 解析器那样处理它还是以不同的方式处理它?还有哪些其他方法可以解析这种情况和类似情况?
例如,我认为可以将方法体的解析推迟到整个结构体都解析完之后,但这真的可行和实用吗?
答案显然取决于编译器,但 Eli Bendersky 的文章 How Clang handles the type / variable name ambiguity of C/C++ 解释了 Clang 是如何做到的。我将简单地记下文章中的一些要点:
Clang 不需要词法分析器:信息从词法分析器到解析器的单向传输
Clang 通过使用符号 table
知道标识符何时是类型
C++ 要求声明在整个 class 中可见,即使在出现在它之前的代码中也是如此
Clang 通过对声明进行完整的 parsing/semantic 分析来解决这个问题,但将定义留到以后;换句话说,它被词法化但在所有声明的类型可用后被解析
虽然肯定可以使用GLR技术来解析C++(参见Ira Baxter的一些回答),但我相信gcc和clang等常用编译器中常用的方法恰恰是推迟函数体的解析直到 class 定义完成。 (由于 C++ 源代码在解析之前通过预处理器,解析器在标记流上工作,这是必须保存以便重新解析函数体的内容。我认为重新解析源代码是不可行的。 )
很容易知道函数定义何时完成,因为大括号 ({}
) 必须平衡,即使不知道尖括号是如何嵌套的。
C++ 并不是唯一一种在处理声明之前延迟解析有用的语言。例如,一种允许用户定义具有不同优先级的新运算符的语言将要求在已知运算符的名称和优先级后(重新)解析所有表达式。更病态的例子是COBOL,其中OR
在a = b OR c
中的优先级取决于c
是否为整数(a
是否等于b
之一或 c
) 或布尔值(a
等于 b
或 c
为真)。以这种方式设计语言是否是一个好主意是另一个问题。