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) ouan array of 4 arrays of 3 ints
?sizeof(arr[0]) == sizeof(int[4])
, então um item dearr
contém quatroint
s.;
o final da linha?Respostas:
Python 3 ,
331 312 294 261240 bytesExperimente online!
-19 bytes mudando para python 2 e colocando a definição de classe em um
exec
-18 bytes alterando o regex de
[a-zA-Z_][a-zA-Z0-9_]*
para\\w+
, graças a Kevin Cruijssen-33 bytes, trabalhando alguma mágica de definição de classe e utilizando str, graças a Lynn, voltando ao python 3
-21 bytes, mesclando várias regexes, graças a infmagic2047
Requer que apenas um espaço esteja contido na entrada (entre o tipo e a expressão).
Eu acho que essa é uma abordagem bastante única para o problema. Isso usa principalmente o fato de que o próprio Python pode avaliar seqüências de caracteres
(**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5])
e obter a sequência correta de chamadas de função, índices de matriz e ponteiros - e que o usuário pode sobrecarregá-las.fonte
[a-zA-Z_][A-Za-z0-9_]*
para[a-zA-Z_]\\w*
economizar alguns bytes. EDIT: Na verdade, acho que você pode simplesmente usar em\\w+
vez de[a-zA-Z_][A-Za-z0-9_]*
.[0]
vez do.group()
Python 3.6.Retina 0.8.2 ,
142138128117 bytesExperimente online! O link inclui casos de teste. Melhor gramática . Editar: salvou
1021 bytes, portando a solução Pip do @ DLosc. Explicação:Mova o tipo para o final e envolva o restante da declaração em
()
s, caso ela contenha uma parte externa*
.Processe qualquer função.
Processe qualquer matriz.
Mova os ponteiros para o final de seus colchetes e exclua-os, trabalhando repetidamente do conjunto mais externo de colchetes para dentro.
Processe qualquer ponteiro.
Insira o
is
.fonte
Java 11,
469467463450 bytesExperimente online.
Explicação:
fonte
Bash + cdecl + GNU sed, 180
cdecl
é um venerável utilitário Unix que faz a maior parte do necessário aqui, mas, para atender aos requisitos de E / S,sed
é necessário algum pré e pós-processamento:sed Pré-processamento:
s/^/explain struct /
- Adicione "struct struct" ao início de cada linhas/struct (int|char double|float|void) /\1 /
- Removastruct
ao lidar com tipos de linguagem Cs/\bfunc/_func/g
- "func" é reconhecido como uma palavra-chave por cdecl - suprimePós-processamento:
s/^declare //
- remova "declare" no início da linhas/as/is/
- auto-explicativos/struct //g
- remova todas as palavras-chave "struct"s/([0-9]+) of/of \1/g
- ordenação correta de "de"s/\b_func/func/g
- reverta qualquer "_func" que foi substituído no pré-processamentoEm ação:
fonte
s/\bfu/_fu/g
e salvar os bytes dafunc
substituição completa ?as
(+4 bytes para os espaços a serem corrigidos). Não tenho acesso,cdecl
mas acho que você pode salvar 64 bytes usandosed -r 's/^(\w+)(\W+)/explain struct \1_\2_/'|cdecl|sed -r 's/^declare struct _|_$//;s/ as / is /;s/([0-9]+) of/of \1/g'
.Pip
-s
,152150148139137126125123 bytesTerceira abordagem!
Toma a declaração como uma entrada da linha de comandos. Experimente online!
Explicação
O código está dividido em três partes: configuração inicial e manipulação de funções e matrizes; um loop que lida com parênteses e ponteiros; e um rearranjo final.
Configuração, funções e matrizes
Queremos que toda a declaração esteja entre parênteses (isso ajuda com o loop mais tarde), então mudamos
type ...;
paratype (...)
. Em seguida, observe que nenhuma reordenação é feita com as descrições de funções e matrizes, para que possamos executar todas essas substituições primeiro sem afetar a saída final.Se nossa entrada original foi
float *((*p()))[16];
, agora temosfloat (*((*p function returning)) array of 16)
.Parênteses e ponteiros
Executamos um loop substituindo o par mais externo de parênteses e quaisquer asteriscos que estão imediatamente dentro do parêntese de abertura.
Etapas de exemplo:
Limpar
A única coisa que resta é mover o tipo para o final e adicionar "é":
Para definições como
int x;
, essa abordagem resultará em um espaço extra, que é permitido pelo desafio.fonte
JavaScript (ES6),
316...268253bytesExperimente online!
Comentado
Função auxiliar
Parte principal
fonte
[...s.split`()`.join`!`]
em vez de apenas[...s.replace('()','!')]
, mas eu percebi que é exatamente o mesmo byte-count .. :)s.replace('()','!')
apenas substituiria a primeira ocorrência..replace
substitui todas as ocorrências e.replaceAll
substitui todas as ocorrências pelo regex ativado. Sempre pensei que a nomeação era muito ruim para esses dois métodos em Java, como eu os teria chamado.replaceAll
e.regexReplaceAll
ou algo assim, mas acho que para o codegolf é mais curto como.replace
e.replaceAll
.~
) logo após postar a primeira versão da minha própria resposta. Grandes mentes pensam da mesma forma, suponho. : pLimpo , 415 bytes
Experimente online!
fonte
R ,
225218 bytesExperimente online!
Programa completo, agrupado em uma função no TIO para teste conveniente de todos os casos de teste de uma só vez.
Primeiro, usamos Regex para converter a entrada do formulário
type ...name...;
em..."name is"..."type"
. A notação de função()
é então convertida em texto com um operador de concatenação de alta precedência. Infelizmente, também temos de substituir*
com+
que o primeiro não é aceitável como um operador unário. O resto é feito por R'seval
com operadores sobrecarregados.fonte
Perl 6 ,
209190171162153 bytesExperimente online!
Abordagem regex recursiva. Produz alguns caracteres de espaço extra que podem ser evitados ao custo de 3 bytes .
Explicação
fonte
250 bytes de JavaScript [249?]
Isso usa 250 bytes:
Explicação:
Basicamente, é a leitura de um buffer
a
, que é a entrada tokenizada. Ele move continuamente os tokens do buffera
para uma pilhas
, até que o modo de avaliação seja acionado. O modo de avaliação consumirá as operações postfix primeiro()
, a[]
partir do buffer e, em seguida, consumirá o operador de prefixo*
da pilha. O modo de avaliação é acionado quando o estado é o local onde uma palavra estaria (o nome do tipo de letra é encontrado e consumido ou uma finalização)
é encontrada e removida). O modo de avaliação é desativado quando não são encontrados mais operadores de prefixo / postfix.NOTA
Se eu entender "Use um espaço em qualquer lugar entre os tokens" corretamente:
é tecnicamente válido e usa
249 bytes
Supondo que haja um espaço entre cada token.
fonte
Vermelho ,
418410 bytesExperimente online!
Explicação:
fonte
APL (NARS), caracteres 625, bytes 1250
essa é apenas uma tradução da linguagem C para a APL do código do livro: "Linguaggio C", de Brian W. Kerninghan e Dennis M. Ritchie, capítulo 5.12. Não sei como reduzir tudo isso porque não havia entendido 100% desse código e porque não sei muito sobre APL ... A função para exercício é f; Eu acho que só são permitidas 150 parenteses aninhadas '(' ')' para erro retornar um strign com um valor negativo ou descrições de strings se tudo estiver ok. Parece que isso não é melhor do que a outra versão, mesmo que menos caracteres, porque o outro vê os erros melhor. Algum teste:
fonte