为什么 C 的 BNF 语法允许使用空序列的初始化声明符进行声明?

Why does C's BNF grammar allow declarations with an empty sequence of init-declarators?

在查看 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;
     ^~~

declaration-specifier 包括 type-specifier,其中包括 enum-specifier。像

这样的结构
enum stuff {x, y};

是有效的 declaration,没有 init-declarator

int;这样的构造被constraints beyond the grammar排除了:

A declaration other than a static_assert declaration shall declare at least a declarator (other than the parameters of a function or the members of a structure or union), a tag, or the members of an enumeration.

我猜你的编译器只发出警告是有向后兼容性的原因。

没有 init 声明符的声明:

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

对于不是单个 enum/struct/union 说明符的声明说明符列表是无害的,并且它可以有效地匹配那些

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

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