为什么在C语言BNF中,`int test {}`是一个函数定义

6

我对著名的C语言BNF范式很感兴趣,并学习了一段时间,让我困惑的是有些语法看起来不正确,但根据BNF规则却被认为是正确的。

例如,int test {}是什么意思?我认为这在C语言中是错误的语法,但事实上,BNF将其视为函数定义:

int -> type_const -> type_spec -> decl_specs
test-> id -> direct_declarator -> declarator
'{' '}' -> compound_stat
decl_specs declarator compound_stat -> function_definition

我用bison试了一下,它认为输入的int test {}是正确的形式,但是我在C编译器上尝试了一下,它无法编译。

所以有以下问题:

  1. int test {} 是一个正确的语法吗?
  2. 如果是正确的语法,那么它意味着什么,为什么编译器不能识别它?
  3. 如果它是一种错误的语法,我可以说BNF不够严格吗?这是不是意味着现代C编译器不遵循这个BNF?
2个回答

3
语法对于描述一个有效的C程序是必要但不足够的。为此,您还需要标准中的限制条件。一个更简单的例子是0 ++,它遵循C表达式的语法,但肯定不是一个有效的程序片段... C11 6.9.1p2
函数定义中声明的标识符(即函数的名称)应该有一个函数类型,由函数定义的声明部分指定。[162] 注释162解释了约束的意图,即typedef不能使用。
typedef int F(void);
F f { /* ... */ }

即使这样的 typedef 可以用于函数 声明,但它仍然无效。
F f;

将声明该函数

int f(void);

但是这种限制的存在也证明了BNF语法本身在这种情况下是不足够的。因此,您正确地指出该语法将把这样的片段视为函数定义。

我能理解这个BNF中,int test {}是语法上正确但语义上错误的吗? - user2269707
如果你要为所有语义上有效的句子编写BNF,那么考虑到英语语言,它会比语法的BNF复杂得多... - Antti Haapala -- Слава Україні
你说得对,我猜test->id->direct_declarator->identifier路径看来行不通了。除非有另一种奇特的定义函数的方式。 - Blaze
1
但是你可以说“雪羊吃。”这在语法和语义上都是完全正确的! - Antti Haapala -- Слава Україні
1
@antti:但在这种情况下,约束确实是语法上的。虽然可以用BNF写出来,但他们选择不这样做,因为结果会使语法更难读懂。 Ecmascript使用的标记非终端形式(仅仅是BNF的语法糖)使得编写(和阅读)这种约束变得更加容易。 - rici
显示剩余6条评论

1
BNF表达式是一种精确描述语言语法的方式,即从原始输入开始,准确地得到解析树所需做的操作。
对于每种语言,您可以定义无限多个描述该语言的语法。描述相同语言的这些语法的属性可以有很大差异。
如果您学习C语言的语法,请注意它不是上下文自由的,而是上下文相关的,这意味着选择规则还是其他规则的决定取决于该点周围的输入。
阅读lexer hack了解如何正确解释C语法的Backus Naur形式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接