Por que a gramática BNF de C permite declarações com uma sequência vazia de init-declarators?


28

Ao examinar a gramática BNF de C, achei estranho que a regra de produção de uma declaração tivesse essa aparência (de acordo com https://cs.wmich.edu/~gupta/teaching/cs4850/sumII06/The%20syntax%20of% 20C% 20in% 20Backus-Naur% 20form.htm ):

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

Por que usar um *quantificador (significando zero ou mais ocorrências) para o init-declarator? Isso permite que instruções como int;ou void;sejam sintaticamente válidas, mesmo que sejam semanticamente inválidas. Eles não poderiam ter usado apenas um +quantificador (uma ou mais ocorrências) em vez de *na regra de produção?

Tentei compilar um programa simples para ver o que o compilador gera e tudo o que ele faz é emitir um aviso.

Entrada:

int main(void) {
    int;
}

Resultado:

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

2
A diferença é que o BNF define apenas a sintaxe. Muitas coisas são sintaticamente permitidas, mas ainda são inválidas (ou absurdas).
larkey 04/04

7
Ah, e por favor use intcomo um tipo de retorno para maine não use ()como uma lista de tipos de parâmetros em funções, mas (void)sim.
larkey 4/04

11
Conceitualmente , não há nada realmente errado nisso, exceto que isso soa um pouco engraçado: é basicamente perguntar ao computador "Gostaria de zero variáveis ​​int, por favor, nomes: [emptyset].". Afinal, você pode pedir zero maçã a alguém (embora isso provavelmente provoque uma reação um pouco mais interessante do que pedir uma, mas não é uma afirmação inerentemente sem sentido). Portanto, por que deveria ser não gramatical em C? Não há nada de errado com esse tipo de gramática.
The_Sympathizer

Muitas vezes, as coisas funcionam muito melhor quando incluímos o caso vazio (ou talvez o vácuo?).
The_Sympathizer

Às vezes, não é um humano que escreve um programa, mas outro programa. Às vezes, esse programa pode imprimir "int", seguido de uma lista separada por vírgulas dos nomes de usuário de que precisamos, seguida por ";" e fique feliz por não precisar verificar se a lista está vazia primeiro.
Hagen von Eitzen

Respostas:


29

declaration-specifierinclui type-specifier, o que inclui enum-specifier. Uma construção como

enum stuff {x, y};

é um válido declarationsem init-declarator.

Construções como int;são descartadas por restrições além da gramática :

Uma declaração que não seja uma declaração static_assert deve declarar pelo menos um declarador (que não seja os parâmetros de uma função ou os membros de uma estrutura ou união), uma tag ou os membros de uma enumeração.

Eu acho que existem razões de compatibilidade com versões anteriores por trás do seu compilador apenas emitir um aviso.


14

Uma declaração sem um declarador init:

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

é inofensivo para as listas de especificadores de declaração que não são um único especificador enum/ struct/ unione combina de maneira útil com as que são.

De qualquer forma, a gramática apresentada também corresponderá erroneamente a declarações como int struct foo x;or double _Bool y;(permite vários especificadores para corresponder a coisas como long long int), mas todos esses podem ser detectados posteriormente, em uma verificação semântica.

A própria gramática da BNF não eliminará todas as construções ilegais.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.