为什么C的BNF语法允许使用init-declarator的空序列进行声明?


28

当查看C的BNF语法时,我认为声明的生产规则看起来像这样很奇怪(根据https://cs.wmich.edu/~gupta/teaching/cs4850/sumII06/The%20syntax%20of% 20C%20in%20Backus-Naur%20form.htm):

<declaration> ::=  {<declaration-specifier>}+ {<init-declarator>}* ;

为什么要*为此使用量词(表示零次或多次出现)init-declarator?这允许诸如int;或之类的语句void;在语法上有效,即使它们在语义上无效。他们难道不是在生产规则中使用了+量词(一次或多次)*吗?

我尝试编译一个简单的程序,以查看编译器的输出,它所做的只是发出警告。

输入:

int main(void) {
    int;
}

输出:

test.c: In function main’:
test.c:2:5: warning: useless type name in empty declaration
     int;
     ^~~

2
区别在于BNF仅定义语法。语法上允许很多事情,但仍然无效(或荒谬)C.不错的发现!
larkey

7
啊,请int用作函数的返回类型,main而不要()用作函数中的参数类型列表(void)
larkey

1
从概念上讲,这没有什么真正的错误,只是听起来有点可笑:它基本上是在询问计算机“我想要零个int变量,请给我一个名字:[emptyset]”。毕竟,您可以向某人要零个苹果(尽管它可能会引起比要一个苹果更有趣的反应,但这并不是天生的荒谬说法)。因此,为什么它在C语言中不合语法?这种语法没有错。
The_Sympathizer

无论如何,当我们包含空泡(或真空?)的情况时,通常情况会好得多。
The_Sympathizer

有时编写程序的不是人,而是另一个程序。这样的程序有时可能希望打印“ int”,然后打印我们需要的evarname的逗号分隔列表,然后打印“;”。并且很高兴不需要先检查所述列表是否为空。
哈根·冯·埃岑

Answers:


29

declaration-specifier包括type-specifier,其中包括enum-specifier。像这样的构造

enum stuff {x, y};

是有效的declaration,没有init-declarator

像这样的int;结构被语法以外的约束所排除:

除static_assert声明以外的其他声明应至少声明一个声明符(函数的参数或结构或联合的成员除外),标记或枚举的成员。

我猜您的编译器仅在发出警告之后存在向后兼容性的原因。


14

没有初始化声明符的声明:

<declaration> ::=  {<declaration-specifier>}+ {<init-declarator>}* ;

是无害的是不是一个单一的声明说明清单enum/ struct/ union符,它有效地匹配那些。

无论如何,所提供的语法也会错误地匹配声明,例如int struct foo x;or double _Bool y;(它允许多个说明符来匹配long long int),但是稍后可以在语义检查中检测到所有这些。

BNF语法本身不会清除所有非法构造。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.