C++解析歧义:构造函数与带括号的声明符
C++ parsing ambiguity: Constructor vs. parenthesized declarator
我正试图编写一个yacc(menhir(语法,用于解析C++的一个非常精简的子集(没有模板,只允许使用没有函数体的头…(,但我已经遇到了歧义。
typedef int B;
class A {
A(); // (*)
B(c)(); // (**)
};
Case*是一个构造函数,Case**是一个带括号的声明符。解析器是如何区分的?我可以想象可以告诉的一些方法,但我想知道一个兼容的c++解析器是如何做到的。我也知道,我可能无法用yacc解析c++的一个实用子集,但我只想更好地了解发生了什么。最后,也许我会切换到解析器组合子或其他什么。此外,我应该注意,我对链接clang没有任何兴趣,因为我打算添加一些自定义语法。
解析C++是一项令人沮丧的工作,因为C++本质上不是上下文无关的。您需要知道标识符是指模板、类型还是其他什么,C++中的名称解析也不是一项简单的任务。例如,您可能必须实例化一个模板,才能知道模板化类的成员是变量还是类型名。(程序只需要对依赖类型中的名称使用typename
。(
因此,如果不考虑包含的头文件,您当然不能期望解析翻译单元。(无论如何,你不能这样做,因为头文件可以定义一个宏,它的扩展会以意想不到的方式改变语法。所以你需要一个预处理器。(
当我写下这个答案时,我的眼睛跳过了OP注意到的括号;yacc";他们的意思是";menhir";。很抱歉不幸的是,据我所知,menhir并没有生成GLR解析器。但我认为这种方法仍然有效,而且足够有用,所以我将把它留在原地。也许有一个OCaml GLR(或GLL(解析器生成器,或者C/C++生成的代码仍然可以使用
说了这么多,一切都没有失去。您可以使用bison生成GLR解析器,然后尝试编写自定义的消歧函数。如果消歧函数需要知道一个名称是否是typedef,它可以尝试在符号表中查找它。与经典的";lexer hack";方法,GLR消歧发生在解析器中,所以它不需要构建笨拙的反向通道。
这可能是一个迭代过程,因为您不需要弄清楚如何解决在您试图编译的特定代码中不存在的歧义。最终,你可能会想处理所有这些问题,但根据需要进行这些问题可能会被证明是一种更令人满意的体验。
通常,在C++中识别构造函数(和析构函数(需要特别识别包含类的名称,与任何其他标识符不同。
这可以通过lexer中返回不同令牌的上下文查找来完成。{
内部。。。构成A类主体的}
,lexer可以识别A
令牌并为其返回不同的令牌类型(不同于它将为B
返回的TYPENAME令牌(
- .cpp和.h文件中的模板专用化声明
- 未在作用域中声明unordered_map
- C++避免重复声明的语法是什么
- 如何确保C++函数在定义之前声明(如override关键字)
- 错误:未在此范围内声明'reverse'
- 构造对象的歧义
- 奇怪的(对我来说)返回声明 - 在谷歌上找不到任何关于它的信息
- 为什么在定义函数之前先声明它
- 使用声明解决歧义
- C++中成员名称查找和访问声明中的歧义
- 了解函数错误的歧义新声明
- 在size_t的声明中解决歧义
- 强制将最令人烦恼的解析的歧义消除为函数声明
- C++11参数子句中声明符和抽象声明符之间的歧义
- 当我在类中声明一个固定长度的向量时,我能避免歧义吗?
- GCC声明友元函数是重载的,有歧义调用,clang编译
- 使用声明和歧义声明的上下文
- c++0x:解决函数定义后接空声明和简单声明之间的歧义
- 由于模板函数声明中存在歧义而导致错误
- 错误:对旧声明“double-round(double)”存在歧义