¿Por qué la gramática BNF de C permite declaraciones con una secuencia vacía de declaradores de inicio?

28

Al mirar la gramática BNF de C, pensé que era extraño que la regla de producción para una declaración se viera así (de acuerdo con https://cs.wmich.edu/~gupta/teaching/cs4850/sumII06/The%20syntax%20of% 20C% 20in% 20Backus-Naur% 20form.htm ):

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

¿Por qué usar un *cuantificador (que significa cero o más ocurrencias) para el init-declarator? Esto permite que declaraciones como int;o void;sean sintácticamente válidas, aunque sean semánticamente inválidas. ¿No podrían haber usado un +cuantificador (una o más ocurrencias) en lugar de *en la regla de producción?

Intenté compilar un programa simple para ver qué genera el compilador y todo lo que hace es emitir una advertencia.

Entrada:

int main(void) {
    int;
}

Salida:

test.c: In function main’:
test.c:2:5: warning: useless type name in empty declaration
     int;
     ^~~
rafaelfp
fuente
2
La diferencia es que el BNF solo define la sintaxis. Muchas cosas están sintácticamente permitidas pero siguen siendo inválidas (o absurdas) C. ¡Buen descubrimiento!
larkey
77
Ah, y utilícelo intcomo un tipo de retorno para mainy no utilice ()como una lista de tipos de parámetros en funciones, sino en su (void)lugar.
larkey
1
Conceptualmente , no hay nada realmente malo en esto, excepto que suena un poco extraño: básicamente le está preguntando a la computadora "Me gustaría cero variables int, por favor, nombres: [conjunto vacío]". Puede pedirle a alguien cero manzanas, después de todo (aunque probablemente provocará una reacción un poco más interesante que pedir una, pero no es una declaración inherentemente sin sentido). Por lo tanto, ¿por qué debería ser no gramatical en C? No hay nada malo con este tipo de gramática.
The_Sympathizer
Muy a menudo las cosas funcionan mucho mejor cuando incluimos el caso de vacío (¿o quizás vacío?), De todos modos.
The_Sympathizer
A veces no es un humano quien escribe un programa, sino otro programa. Tal programa a veces puede querer imprimir "int" seguido de una lista separada por comas de los evarnames que necesitamos, seguida de ";" y no dude en comprobar si dicha lista está vacía primero.
Hagen von Eitzen

Respuestas:

29

declaration-specifierincluye type-specifier, que incluye enum-specifier. Una construcción como

enum stuff {x, y};

es válido declarationcon no init-declarator.

Las construcciones como int;se descartan por restricciones más allá de la gramática :

Una declaración que no sea una declaración static_assert declarará al menos un declarador (que no sean los parámetros de una función o los miembros de una estructura o unión), una etiqueta o los miembros de una enumeración.

Supongo que hay razones de compatibilidad con versiones anteriores detrás de su compilador que solo emite una advertencia.

user2357112 es compatible con Monica
fuente
14

Una declaración sin un declarador init:

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

es inofensivo para las listas de especificadores de declaración que no son un solo enum/ struct/ unionespecificador y coincide útilmente con las que sí lo son.

En cualquier caso, la gramática presentada también coincidirá erróneamente con declaraciones como int struct foo x;o double _Bool y;(permite múltiples especificadores para hacer coincidir cosas como long long int), pero todo esto se puede detectar más tarde, en una comprobación semántica.

La gramática BNF en sí misma no eliminará todas las construcciones ilegales.

PSkocik
fuente