C++解析歧义:构造函数与带括号的声明符

C++ parsing ambiguity: Constructor vs. parenthesized declarator

本文关键字:声明 歧义 构造函数 C++      更新时间:2024-09-22

我正试图编写一个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令牌(