void f(int x) {} f(42);
这里还有一个int参数的函数:
void g(int(x)) {} g(42);
现在让我们将x定义为一个类型:
typedef int x; void h(int(x)) {} h(42); // warning: passing argument 1 of ‘h’ makes pointer from integer without a cast
(这是我用gcc 4.8.2观察的行为)
解析器作者如何处理这种情况?
看来经典的流水线Lexer – >解析器 – >语义检查器 – > …在这里不工作
解决方法
void h(int(int)) {}
该参数被解释为一个未命名的函数指针,它接受一个int并返回一个int.当您尝试传递42时,编译器会抱怨您正在尝试从一个整数形成一个函数指针.
我想你所要求的是编译器如何处理(未命名)函数指针类型及其可能含糊的解析.您的问题与C中的the most vexing parse有关.
在那里,他们决定,每当函数指针类型和另一种解析方式之间存在歧义时,它将被解释为函数指针.他们做到这一点,因为当你不想让它成为一个函数指针时,有其他的方法可以消除歧义(例如 – 用括号括起来,使用{}初始化语法等).
了解解析器作者如何处理此解析的细节,以下是C11:http://quut.com/c/ANSI-C-grammar-l-2011.html的词法分析器和语法在您的示例中,在typedef之前,x在之后将是一个IDENTIFIER令牌,它将是一个TYPEDEF_NAME令牌,因为分析仪正在通过符号表通知x现在是一种类型.在这种特殊情况下,解析是明确的.在这种情况下,您通过符号表发出的“流水线反馈”发生在这种情况下,在汇编进行时,词汇分析器会被上级影响其输出的上级信息通知上下文.
编辑:These three articles,由OP发现,描述了这个问题,以及它如何被一些C解析器/编译器非常好地解决.基本上,几乎可以指定仅接受/产生合法C语法的上下文无关语法(CFG).通过引入范围查找表,允许词法分析器适当地区分标识符和typedef名称,那么只能接受/产生合法C的CFG [和更重要的是LALR(1)解析器(例如,yacc生成)]可以指定语法.
这是一个比OP更可怕的例子:
typedef int x; int main() { x x = 5; return x; } /* crazily enough this is legal C Syntax and a well formed C program */