Perché la grammatica BNF di C consente dichiarazioni con una sequenza vuota di dichiaratori init?


28

Quando ho esaminato la grammatica BNF di C, ho pensato che fosse strano che la regola di produzione per una dichiarazione fosse simile a questa (secondo https://cs.wmich.edu/~gupta/teaching/cs4850/sumII06/The%20syntax%20of% 20C% 20in% 20Backus-Naur% 20form.htm ):

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

Perché usare un *quantificatore (che significa zero o più occorrenze) per il init-declarator? Ciò consente a dichiarazioni come int;o void;di essere sintatticamente valide, anche se semanticamente non valide. Non avrebbero potuto semplicemente usare un +quantificatore (una o più occorrenze) anziché *nella regola di produzione?

Ho provato a compilare un semplice programma per vedere cosa genera il compilatore e tutto ciò che fa è emettere un avviso.

Ingresso:

int main(void) {
    int;
}

Produzione:

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

2
La differenza è che BNF definisce solo la sintassi. Molte cose sono sintatticamente permesse ma comunque non valide (o assurde) C. Bella scoperta però!
larkey

7
Ah, e si prega di utilizzare intcome tipo di ritorno per maine non utilizzare ()come elenco di tipi di parametri nelle funzioni ma (void)invece.
larkey

1
Concettualmente , non c'è nulla di veramente sbagliato in questo, tranne che suona un po 'divertente: sostanzialmente sta chiedendo al computer "Vorrei zero variabili int, per favore, nomi: [emptyset].". Puoi chiedere a qualcuno zero mele, dopo tutto (anche se probabilmente susciterà una reazione un po 'più interessante rispetto a chiederne una, ma non è un'affermazione intrinsecamente insensata). Quindi perché dovrebbe essere sgrammaticato in C? Non c'è niente di sbagliato in questo tipo di grammatica.
The_Sympathizer

Molto spesso le cose funzionano molto meglio quando includiamo comunque il caso vacuo (o forse vuoto?).
The_Sympathizer il

A volte non è un essere umano che scrive un programma, ma un altro programma. Talvolta un programma del genere potrebbe voler stampare "int" seguito da un elenco separato da virgole dei nomi di cui abbiamo bisogno, seguito da ";" e sii felice di non aver bisogno di controllare se detto elenco è prima vuoto.
Hagen von Eitzen,

Risposte:


29

declaration-specifierinclude type-specifier, che include enum-specifier. Un costrutto simile

enum stuff {x, y};

è valido declarationcon n init-declarator.

I costrutti come int;sono esclusi da vincoli oltre la grammatica :

Una dichiarazione diversa da una dichiarazione static_assert deve dichiarare almeno un dichiaratore (diverso dai parametri di una funzione o dei membri di una struttura o unione), un tag o i membri di un elenco.

Immagino che ci siano ragioni di compatibilità all'indietro dietro il compilatore che emette solo un avviso.


14

Una dichiarazione senza un dichiaratore init:

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

è innocuo per gli elenchi di specificatori di dichiarazioni che non sono un singolo enum/ struct/ unionspecificatore e corrisponde utilmente a quelli che lo sono.

In ogni caso, la grammatica presentata corrisponderà erroneamente anche a dichiarazioni come int struct foo x;o double _Bool y;(consente a più specificatori di abbinare cose come long long int), ma tutti questi possono essere rilevati in seguito, in un controllo semantico.

La stessa grammatica BNF non eliminerà tutti i costrutti illegali.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.