Pourquoi la grammaire BNF de C autorise-t-elle les déclarations avec une séquence vide de déclarateurs init?

28

En parcourant la grammaire BNF de C, j'ai trouvé étrange que la règle de production d'une déclaration ressemble à ceci (selon https://cs.wmich.edu/~gupta/teaching/cs4850/sumII06/The%20syntax%20of% 20C% 20in% 20Backus-Naur% 20form.htm ):

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

Pourquoi utiliser un *quantificateur (signifiant zéro ou plusieurs occurrences) pour le init-declarator? Cela permet aux instructions telles que int;ou void;d'être syntaxiquement valides, même si elles sont sémantiquement invalides. Ne pouvaient-ils pas simplement utiliser un +quantificateur (une ou plusieurs occurrences) au lieu de *dans la règle de production?

J'ai essayé de compiler un programme simple pour voir ce que le compilateur produit et il ne fait qu'émettre un avertissement.

Contribution:

int main(void) {
    int;
}

Production:

test.c: In function main’:
test.c:2:5: warning: useless type name in empty declaration
     int;
     ^~~
rafaelfp
la source
2
La différence est que le BNF ne définit que la syntaxe. Beaucoup de choses sont autorisées syntaxiquement mais toujours invalides (ou absurdes) C. Belle trouvaille cependant!
Larkey
7
Ah, et veuillez utiliser intcomme type de retour pour mainet ne pas utiliser ()comme liste de types de paramètres dans les fonctions mais à la (void)place.
larkey
1
Sur le plan conceptuel , il n'y a rien de mal à cela, sauf que cela semble un peu drôle: il s'agit essentiellement de demander à l'ordinateur "Je voudrais zéro variable int, s'il vous plaît, noms: [emptyset].". Vous pouvez demander à quelqu'un zéro pomme, après tout (bien que cela suscitera probablement une réaction un peu plus intéressante que d'en demander une, mais ce n'est pas une déclaration intrinsèquement absurde). Par conséquent, pourquoi devrait-il être non grammatical en C? Il n'y a rien de mal à ce genre de grammaire.
The_Sympathizer
Très souvent, les choses fonctionnent beaucoup mieux lorsque nous incluons le cas vide (ou peut-être, vide?), De toute façon.
The_Sympathizer
Parfois, ce n'est pas un humain qui écrit un programme, mais un autre programme. Un tel programme peut parfois vouloir imprimer "int" suivi d'une liste séparée par des virgules des cinq noms dont nous avons besoin, suivis de ";" et soyez heureux de ne pas avoir à vérifier si cette liste est vide en premier.
Hagen von Eitzen

Réponses:

29

declaration-specifiercomprend type-specifier, qui comprend enum-specifier. Une construction comme

enum stuff {x, y};

est valide declarationsans init-declarator.

Des constructions comme celles-ci int;sont exclues par des contraintes au-delà de la grammaire :

Une déclaration autre qu'une déclaration static_assert doit déclarer au moins un déclarant (autre que les paramètres d'une fonction ou les membres d'une structure ou d'union), une balise ou les membres d'une énumération.

Je suppose qu'il existe des raisons de compatibilité descendante derrière votre compilateur émettant uniquement un avertissement.

user2357112 prend en charge Monica
la source
14

Une déclaration sans déclarateur init:

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

est inoffensif pour les listes de spécificateurs de déclaration qui ne sont pas un seul spécificateur enum/ struct/ unionet il correspond utilement à ceux qui le sont.

Dans tous les cas, la grammaire présentée correspondra également à tort aux déclarations comme int struct foo x;ou double _Bool y;(elle autorise plusieurs spécificateurs afin de faire correspondre des choses comme long long int), mais tout cela peut être détecté plus tard, dans un contrôle sémantique.

La grammaire BNF elle-même n'éliminera pas toutes les constructions illégales.

PSkocik
la source