fundo
A declaração de declaração de variável em C consiste em três partes: o nome da variável, seu tipo base e o (s) modificador (es) de tipo .
Existem três tipos de modificadores de tipo:
- Ponteiro
*
(prefixo) - Matriz
[N]
(postfix) - Função
()
(postfix)- Você pode especificar uma lista de argumentos da função dentro dos parênteses, mas, para o bem desse desafio, vamos ignorá-lo e usar apenas
()
(o que tecnicamente significa "a função pode aceitar qualquer tipo de argumento").
- Você pode especificar uma lista de argumentos da função dentro dos parênteses, mas, para o bem desse desafio, vamos ignorá-lo e usar apenas
E uma maneira de ler as notações é a seguinte:
int i; // i is an int
float *f; // f is a pointer to a float
my_struct_t s[10]; // s is an array of 10 my_struct_t
int func(); // func is a function returning an int
O problema é que podemos misturar tudo isso para formar um tipo mais complicado, como matriz de matrizes ou matriz de ponteiros de função ou ponteiro para matriz de ponteiros :
int arr[3][4];
// arr is an array of 3 arrays of 4 ints
int (*fptrs[10])();
// fptrs is an array of 10 pointers to functions returning an int
float *(*p)[16];
// p is a pointer to an array of 16 pointers to float
Como eu li essas declarações complicadas?
- Comece pelo nome da variável.
(name) is ...
- Selecione o modificador com a maior precedência.
- Leia-o:
* -> pointer to ...
[N] -> array of N ...
() -> function returning ...
- Repita 2 e 3 até que os modificadores estejam esgotados.
- Por fim, leia o tipo de base.
... (base type).
Em C, os operadores de Postfix têm precedência sobre os operadores de prefixo e os modificadores de tipo não são exceção. Portanto, []
e ()
ligue primeiro, então *
. Qualquer coisa dentro de um par de parênteses (...)
(que não deve ser confundida com o operador de função) se liga primeiro a qualquer coisa externa.
Exemplo ilustrado:
int (*fptrs[10])();
fptrs fptrs is ...
[10] array of 10 ... // [] takes precedence over *
(* ) pointer to ...
() function returning ...
int int
Tarefa
Dada uma linha de declaração de declaração de variável escrita em C, produza a expressão em inglês que descreve a linha, usando o método mostrado acima.
Entrada
A entrada é uma única instrução C que inclui um único tipo base, um único nome de variável, zero ou mais modificadores de tipo e o ponto e vírgula final. Você precisa implementar todos os elementos de sintaxe abordados acima, além de:
- O tipo de base e o nome da variável correspondem à expressão regular
[A-Za-z_][A-Za-z0-9_]*
. - Teoricamente, seu programa deve suportar um número ilimitado de modificadores de tipo.
Você pode simplificar outros elementos da sintaxe C das seguintes maneiras (a implementação completa também é bem-vinda):
- O tipo de base é sempre uma única palavra, por exemplo
int
,float
,uint32_t
,myStruct
. Algo comounsigned long long
não será testado. - Para a marcação de matriz
[N]
, o númeroN
será sempre um único número inteiro positivo escrito na base 10. O comoint a[5+5]
,int a[SIZE]
ouint a[0x0f]
não irá ser testada. - Para a notação de função
()
, nenhum parâmetro será especificado, como indicado acima. - Para espaços em branco, apenas o caractere de espaço
0x20
será usado. Você pode restringir seu programa ao uso específico de espaços em branco, por exemplo- Use apenas um espaço após o tipo base
- Use um espaço em qualquer lugar entre os tokens
- No entanto, você não pode usar dois ou mais espaços consecutivos para transmitir mais informações do que ser um separador de token.
De acordo com a sintaxe C, as três combinações a seguir são inválidas e, portanto, não serão testadas:
f()()
Função retornando funçãof()[]
Função que retorna a matriza[]()
Matriz de N funções
Os desenvolvedores de C usam esses formulários equivalentes (e todos são abordados nos casos de teste):
(*f())()
Função retornando ponteiro para função*f()
Função retornando o ponteiro para o primeiro elemento da matriz(*a[])()
Matriz de N ponteiros para funcionar
Saída
A saída é uma única sentença em inglês. Você não precisa (mas pode, se desejar) respeitar a gramática inglesa, por exemplo, o uso de a, an, the
formas singular / plural e o ponto final (ponto final). Cada palavra deve ser separada por um ou mais espaços em branco (espaço, tabulação, nova linha) para que o resultado seja legível por humanos.
Novamente, aqui está o processo de conversão:
- Comece pelo nome da variável.
(name) is ...
- Selecione o modificador com a maior precedência.
- Leia-o:
* -> pointer to ...
[N] -> array of N ...
() -> function returning ...
- Repita 2 e 3 até que os modificadores estejam esgotados.
- Por fim, leia o tipo de base.
... (base type).
Casos de teste
int i; // i is int
float *f; // f is pointer to float
my_struct_t s[10]; // s is array of 10 my_struct_t
int func(); // func is function returning int
int arr[3][4]; // arr is array of 3 array of 4 int
int (*fptrs[10])(); // fptrs is array of 10 pointer to function returning int
float *(*p)[16]; // p is pointer to array of 16 pointer to float
_RANdom_TYPE_123 (**(*_WTH_is_TH15)())[1234][567];
/* _WTH_is_TH15 is pointer to function returning pointer to pointer to array of
1234 array of 567 _RANdom_TYPE_123 */
uint32_t **(*(**(*(***p)[2])())[123])[4][5];
/* p is pointer to pointer to pointer to array of 2 pointer to function returning
pointer to pointer to array of 123 pointer to array of 4 array of 5 pointer to
pointer to uint32_t */
uint32_t (**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5]);
// Same as above, just more redundant parens
some_type (*(*(*(*(*curried_func())())())())())();
/* curried_func is function returning pointer to function returning pointer to
function returning pointer to function returning pointer to
function returning pointer to function returning some_type */
Critério de pontuação e vitória
Este é um desafio do código-golfe . O programa com o menor número de bytes vence.
int arr[3][4];
é an array of 3 arrays of 4 ints
(como você diz) ou an array of 4 arrays of 3 ints
?
sizeof(arr[0]) == sizeof(int[4])
, então um item de arr
contém quatro int
s.
;
o final da linha?