Warum erlaubt die BNF-Grammatik von C Deklarationen mit einer leeren Folge von Init-Deklaratoren?

28

Beim Durchsehen der BNF-Grammatik von C fand ich es seltsam, dass die Produktionsregel für eine Deklaration so aussah (laut https://cs.wmich.edu/~gupta/teaching/cs4850/sumII06/The%20syntax%20of%) 20C% 20in% 20Backus-Naur% 20form.htm ):

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

Warum einen *Quantifizierer (dh null oder mehr Vorkommen) für die verwenden init-declarator? Dadurch können Anweisungen wie int;oder void;syntaktisch gültig sein, obwohl sie semantisch ungültig sind. Könnten sie nicht einfach einen +Quantifizierer (ein oder mehrere Vorkommen) anstelle *der Produktionsregel verwendet haben?

Ich habe versucht, ein einfaches Programm zu kompilieren, um zu sehen, was der Compiler ausgibt, und alles, was er tut, ist eine Warnung auszugeben.

Eingang:

int main(void) {
    int;
}

Ausgabe:

test.c: In function main’:
test.c:2:5: warning: useless type name in empty declaration
     int;
     ^~~
rafaelfp
quelle
2
Der Unterschied besteht darin, dass der BNF nur die Syntax definiert. Sehr viele Dinge sind syntaktisch erlaubt, aber immer noch ungültig (oder absurd) C. Netter Fund!
Larkey
7
Ah, und bitte intals Rückgabetyp für mainund nicht ()als Parametertypenliste in Funktionen verwenden, sondern (void)stattdessen.
Larkey
1
Konzeptionell ist daran nichts wirklich auszusetzen, außer dass es ein bisschen komisch klingt: Es fragt den Computer im Grunde: "Ich möchte null int-Variablen, bitte, Namen: [Emptyset]." Sie können schließlich jemanden um null Äpfel bitten (obwohl dies wahrscheinlich eine etwas interessantere Reaktion hervorruft als die Frage nach einem, aber es ist keine inhärent unsinnige Aussage). Warum sollte es in C ungrammatisch sein? An dieser Art von Grammatik ist nichts auszusetzen.
The_Sympathizer
Sehr oft funktionieren die Dinge viel besser, wenn wir sowieso den leeren (oder vielleicht Vakuum?) Fall einbeziehen.
The_Sympathizer
Manchmal ist es nicht ein Mensch, der ein Programm schreibt, sondern ein anderes Programm. Ein solches Programm möchte manchmal "int" drucken, gefolgt von einer durch Kommas getrennten Liste der benötigten Namen, gefolgt von ";" und seien Sie froh, nicht zuerst prüfen zu müssen, ob diese Liste leer ist.
Hagen von Eitzen

Antworten:

29

declaration-specifierbeinhaltet type-specifier, was beinhaltet enum-specifier. Ein Konstrukt wie

enum stuff {x, y};

ist eine gültige declarationmit nr init-declarator.

Konstrukte wie int;werden durch Einschränkungen jenseits der Grammatik ausgeschlossen :

Eine andere Deklaration als eine static_assert-Deklaration muss mindestens einen Deklarator (außer den Parametern einer Funktion oder den Mitgliedern einer Struktur oder Union), einem Tag oder den Mitgliedern einer Aufzählung deklarieren.

Ich würde vermuten, dass es Abwärtskompatibilitätsgründe dafür gibt, dass Ihr Compiler nur eine Warnung ausgibt.

user2357112 unterstützt Monica
quelle
14

Eine Deklaration ohne Init-Deklarator:

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

ist harmlos für Deklarationsspezifiziererlisten, die kein einzelner enum/ struct/ unionSpezifizierer sind, und es stimmt sinnvollerweise mit denen überein, die es sind.

In jedem Fall stimmt die dargestellte Grammatik auch fälschlicherweise mit Deklarationen wie int struct foo x;oder überein double _Bool y;(sie ermöglicht mehrere Spezifizierer, um mit Dingen wie übereinzustimmen long long int), aber all diese können später in einer semantischen Prüfung erkannt werden.

Die BNF-Grammatik selbst wird nicht alle illegalen Konstrukte aussortieren.

PSkocik
quelle