なぜCのBNF文法は、空のinit-declaratorのシーケンスでの宣言を許可するのですか?


28

CのBNF文法を調べたとき、宣言のプロダクションルールが次のようになっているのは奇妙だと思いました(https://cs.wmich.edu/~gupta/teaching/cs4850/sumII06/The%20syntax%20of%によると) 20C%20in%20Backus-Naur%20form.htm):

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

なぜ*量指定子(0回以上のオカレンス)を使用するのinit-declaratorですか?これにより、int;またはなどのステートメントvoid;は、意味的に無効であっても、構文的に有効になります。プロダクションルールでは+なく、数量詞(1つ以上のオカレンス)を使用しただけではありません*か?

単純なプログラムをコンパイルして、コンパイラーが何を出力するかを確認しましたが、コンパイラーが行うのは警告を出すことだけです。

入力:

int main(void) {
    int;
}

出力:

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

2
違いは、BNFは構文のみを定義することです。かなり多くのものが構文的に許可されていますが、それでも無効(または不合理)です。
ラーキー

7
ああ、関数のint戻り値の型としてmain使用()し、関数のパラメーター型リストとしては使用しないでください(void)
ラーキー

1
概念的には、少しおかしく聞こえることを除いて、これには本当に何も問題はありません。基本的には、コンピューターに「int変数をゼロにしたいのですが、名前を入力してください:[emptyset]。」です。結局のところ、誰かにリンゴを0個要求することができます(1つを要求するよりも少し興味深い反応を引き起こす可能性がありますが、それは本質的に無意味なステートメントではありません)。したがって、なぜそれがCで文法的ではないのでしょうか?この種の文法には何の問題もありません。
The_Sympathizer

とにかく、バキューム(または、バキューム?)のケースを含めると、非常にうまく機能することがよくあります。
The_Sympathizer

時にはプログラムを書くのは人間ではなく、別のプログラムです。このようなプログラムでは、「int」の後に、必要なevarnameのコンマ区切りのリストが続き、その後に「;」が続く場合があります。そして、最初に上記のリストが空であるかどうかを確認する必要がないことに満足してください。
Hagen von Eitzen

回答:


29

declaration-specifier含むtype-specifier、含むenum-specifier。のような構成

enum stuff {x, y};

はなしdeclarationで有効ですinit-declarator

のような構文は、文法を超えた制約int;によって除外されています

static_assert宣言以外の宣言では、少なくとも宣言子(関数のパラメーター、構造体または共用体のメンバー以外)、タグ、または列挙型のメンバーを宣言する必要があります。

コンパイラが警告のみを発行する背後には、下位互換性の理由があると思います。


14

init宣言子のない宣言:

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

単一のenum/ struct/ union指定子ではない宣言指定子リストの場合は無害であり、一致するものと一致します。

いずれの場合でも、提示された文法は、int struct foo x;またはのような宣言に誤って一致double _Bool y;します(これによりlong long int、などの一致に複数の指定子が許可されます)が、これらはすべて、意味チェックで後で検出できます。

BNF文法自体が、すべての違法な構成要素を取り除くわけではありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.