28

When looking through C's BNF grammar, I thought it was weird that the production rule for a declaration looked like this (according to https://cs.wmich.edu/~gupta/teaching/cs4850/sumII06/The%20syntax%20of%20C%20in%20Backus-Naur%20form.htm):

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

Why use an * quantifier (meaning zero or more occurrences) for the init-declarator? This allows statements such as int; or void; to be syntactically valid, even though they're semantically invalid. Couldn't they have just used a + quantifier (one or more occurrences) instead of * in the production rule?

I tried compiling a simple program to see what the compiler outputs and all it does is issue a warning.

Input:

int main(void) {
    int;
}

Output:

test.c: In function ‘main’:
test.c:2:5: warning: useless type name in empty declaration
     int;
     ^~~
S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
rafaelfp
  • 383
  • 2
  • 6
  • 2
    The difference is that the BNF only defines the syntax. Quite many things are syntactically allowed but still invalid (or absurd) C. Nice find though! – ljrk Apr 04 '20 at 10:21
  • 7
    Ah, and please use `int` as a return type for `main` and don't use `()` as a parameters types list in functions but `(void)` instead. – ljrk Apr 04 '20 at 10:22
  • 1
    _Conceptually_, there's nothing really wrong with this except that it sounds a bit funny: it's basically asking the computer "I would like zero int variables, please, names: [emptyset].". You can ask someone for zero apples, after all (though it will likely elicit a bit more interesting reaction than asking for one, but it's not an inherently nonsensical statement). Hence why should it be ungrammatical in C? There is nothing wrong with this kind of grammar. – The_Sympathizer Apr 05 '20 at 03:42
  • Very often things work a lot nicer when we include the vacuous (or perhaps, vacuum?) case, anyways. – The_Sympathizer Apr 05 '20 at 03:43
  • Sometimes it is not a human who writes a program, but another program. Such a program might sometimes want to print "int " followed by a comma-separated list o fth evarnames we need, followed by ";" and be happy not to need to check if said list is empty first. – Hagen von Eitzen Apr 05 '20 at 06:21
  • In some cases after going thru the pre-processor with some macros compiling away to nothing you might wind up with just a bare `int;` on the line perhaps. – Sez Apr 07 '20 at 06:06

2 Answers2

29

declaration-specifier includes type-specifier, which includes enum-specifier. A construct like

enum stuff {x, y};

is a valid declaration with no init-declarator.

Constructs like int; are ruled out by 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.

I would guess that there are backward compatibility reasons behind your compiler only issuing a warning.

user2357112
  • 260,549
  • 28
  • 431
  • 505
14

A declaration without an init declarator:

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

is harmless for declaration specifier lists that aren't a single enum/struct/union specifier and it usefully matches those that are.

In any case, the presented grammar will also erroneously match declarations like int struct foo x; or double _Bool y; (it allows multiple specifiers in order to match things like long long int), but all these can be detected later, in a semantic check.

The BNF grammar itself won't weed out all illegal constructs.

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142