Почему грамматика BNF в C допускает объявления с пустой последовательностью init-деклараторов?

28

Просматривая грамматику BNF в C, я подумал, что странно, что производственное правило для объявления выглядит следующим образом (согласно https://cs.wmich.edu/~gupta/teaching/cs4850/sumII06/The%20syntax%20of% 20C% 20in% 20Backus-Naur% 20form.htm ):

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

Зачем использовать *квантификатор (имеется в виду ноль или более вхождений) для init-declarator? Это позволяет синтаксически допустимым операторам типа int;или void;быть, даже если они семантически недействительны. Разве они не могли просто использовать +квантификатор (одно или несколько вхождений) вместо *правила производства?

Я попытался скомпилировать простую программу, чтобы увидеть, что выводит компилятор, и все, что он делает, это выдает предупреждение.

Входные данные:

int main(void) {
    int;
}

Вывод:

test.c: In function main’:
test.c:2:5: warning: useless type name in empty declaration
     int;
     ^~~
rafaelfp
источник
2
Разница в том, что BNF определяет только синтаксис. Многие вещи синтаксически разрешены, но все еще недействительны (или абсурдны).
Ларки
7
Ах, и, пожалуйста, используйте intв качестве типа возврата для mainи не используйте ()в качестве списка типов параметров в функциях, но (void)вместо этого.
Ларки
1
С концептуальной точки зрения в этом нет ничего плохого, за исключением того, что это звучит немного забавно: в основном он спрашивает компьютер: «Я бы хотел, чтобы ноль int-переменных, пожалуйста, names: [emptyset]». В конце концов, вы можете попросить кого-нибудь о нулевых яблоках (хотя это, скорее всего, вызовет более интересную реакцию, чем запрос одного, но это не бессмысленное по своей сути утверждение). Следовательно, почему это должно быть неграмотно в C? В такой грамматике нет ничего плохого.
The_Sympathizer
Очень часто все работает намного лучше, когда мы включаем пустые (или, возможно, вакуумные) дела, в любом случае.
The_Sympathizer
Иногда не человек пишет программу, а другая программа. Такая программа может иногда захотеть вывести «int», за которым следует разделенный запятыми список нужных нам названий, а затем «;» и будьте счастливы, что вам не нужно проверять, является ли указанный список пустым.
Хаген фон Айцен

Ответы:

29

declaration-specifierвключает в себя type-specifier, который включает в себя enum-specifier. Конструкция как

enum stuff {x, y};

является действительным declarationс нет init-declarator.

Такие конструкции, как int;исключаются из грамматических ограничений :

Объявление, отличное от объявления static_assert, должно объявлять, по крайней мере, декларатора (кроме параметров функции или членов структуры или объединения), тега или членов перечисления.

Я предполагаю, что за компилятором есть причины обратной совместимости, выдающие только предупреждение.

user2357112 поддерживает Monica
источник
14

Объявление без инициатора объявления:

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

безвреден для списков спецификаторов объявлений, которые не являются одиночными enum/ struct/ unionспецификаторами, и полезны для тех, которые являются.

В любом случае, представленная грамматика также будет ошибочно соответствовать объявлениям, подобным int struct foo x;или double _Bool y;(она позволяет использовать несколько спецификаторов для соответствия вещам вроде long long int), но все это может быть обнаружено позже, в семантической проверке.

Сама грамматика BNF не отсеет все незаконные конструкции.

PSkocik
источник