Fondo
La declaración de declaración de variables en C consta de tres partes: el nombre de la variable, su tipo base y los modificadores de tipo .
Hay tres tipos de modificadores de tipo:
- Puntero
*
(prefijo) - Matriz
[N]
(postfix) - Función
()
(postfix)- Puede especificar una lista de argumentos de función dentro de los elementos parentales, pero en aras de este desafío, ignorémoslo y solo usemos
()
(lo que técnicamente significa "la función puede tomar cualquier tipo de argumento").
- Puede especificar una lista de argumentos de función dentro de los elementos parentales, pero en aras de este desafío, ignorémoslo y solo usemos
Y una forma de leer las anotaciones es la siguiente:
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
El problema es que podemos mezclar todo esto para formar un tipo más complicado, como una matriz de matrices o una matriz de punteros de función o un puntero a una matriz de punteros :
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
¿Cómo leí estas complicadas declaraciones?
- Comience desde el nombre de la variable.
(name) is ...
- Seleccione el modificador con la mayor precedencia.
- Léelo:
* -> pointer to ...
[N] -> array of N ...
() -> function returning ...
- Repita 2 y 3 hasta que los modificadores estén agotados.
- Finalmente, lea el tipo base.
... (base type).
En C, los operadores de postfix tienen prioridad sobre los operadores de prefijo, y los modificadores de tipo no son una excepción. Por lo tanto, []
y ()
atar primero, luego *
. Cualquier cosa dentro de un par de parens (...)
(que no debe confundirse con el operador de función) se une primero sobre cualquier cosa fuera.
Ejemplo ilustrado:
int (*fptrs[10])();
fptrs fptrs is ...
[10] array of 10 ... // [] takes precedence over *
(* ) pointer to ...
() function returning ...
int int
Tarea
Dada una línea de declaración de declaración de variables escrita en C, genera la expresión en inglés que describe la línea, utilizando el método que se muestra arriba.
Entrada
La entrada es una declaración C única que incluye un tipo base único, un nombre de variable único, cero o más modificadores de tipo y el punto y coma final. Tiene que implementar todos los elementos de sintaxis cubiertos anteriormente, además de:
- Tanto el tipo base como el nombre de la variable coinciden con la expresión regular
[A-Za-z_][A-Za-z0-9_]*
. - Teóricamente, su programa debería admitir un número ilimitado de modificadores de tipo.
Puede simplificar otros elementos de sintaxis de C de las siguientes maneras (la implementación completa también es bienvenida):
- El tipo de base es siempre una única palabra, por ejemplo
int
,float
,uint32_t
,myStruct
. Algo asíunsigned long long
no será probado. - Para la notación de matriz
[N]
, el númeroN
será siempre un solo número entero positivo escrito en base 10. cosas comoint a[5+5]
,int a[SIZE]
oint a[0x0f]
no se ensayó. - Para la notación de función
()
, no se especificarán parámetros, como se señaló anteriormente. - Para espacios en blanco, solo se
0x20
usará el carácter de espacio . Puede restringir su programa al uso específico de espacios en blanco, p. Ej.- Use solo un espacio después del tipo base
- Usa un espacio en todas partes entre fichas
- Sin embargo, no puede usar dos o más espacios consecutivos para transmitir más información que ser un separador de tokens.
Según la sintaxis de C, las siguientes tres combinaciones no son válidas y, por lo tanto, no se probarán:
f()()
Función función de retornof()[]
Función que devuelve la matriza[]()
Matriz de funciones N
Los desarrolladores de C utilizan estos formularios equivalentes (y todos estos están cubiertos en los casos de prueba):
(*f())()
Función que devuelve el puntero a la función*f()
Función que devuelve el puntero al primer elemento de la matriz(*a[])()
Matriz de N punteros para funcionar
Salida
El resultado es una sola oración en inglés. No es necesario (pero puede hacerlo si lo desea) respetar la gramática inglesa, por ejemplo, el uso de a, an, the
formas singulares / plurales y el punto final (punto). Cada palabra debe estar separada por uno o más espacios en blanco (espacio, tabulación, nueva línea) para que el resultado sea legible para los humanos.
Nuevamente, aquí está el proceso de conversión:
- Comience desde el nombre de la variable.
(name) is ...
- Seleccione el modificador con la mayor precedencia.
- Léelo:
* -> pointer to ...
[N] -> array of N ...
() -> function returning ...
- Repita 2 y 3 hasta que los modificadores estén agotados.
- Finalmente, lea el tipo base.
... (base type).
Casos de prueba
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 */
Criterio de puntuación y ganador
Este es un desafío de código de golf . El programa con el menor número de bytes gana.
int arr[3][4];
esan array of 3 arrays of 4 ints
(como dices) oan array of 4 arrays of 3 ints
?sizeof(arr[0]) == sizeof(int[4])
, por lo que un elemento dearr
contiene cuatroint
s.;
al final de la línea?Respuestas:
Python 3 ,
331 312 294 261240 bytesPruébalo en línea!
-19 bytes cambiando a python 2 y poniendo la definición de clase en un
exec
-18 bytes cambiando la expresión regular de
[a-zA-Z_][a-zA-Z0-9_]*
a\\w+
, gracias a Kevin Cruijssen-33 bytes trabajando un poco de magia de definición de clase y utilizando str, gracias a Lynn, volviendo a python 3
-21 bytes fusionando múltiples expresiones regulares, gracias a infmagic2047
Requiere que solo haya un espacio en la entrada (entre el tipo y la expresión).
Creo que este es un enfoque bastante único para el problema. Esto utiliza principalmente el hecho de que Python mismo puede evaluar cadenas como
(**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5])
y obtiene la secuencia correcta de llamadas a funciones, índices de matriz y punteros, y que el usuario puede sobrecargarlos.fuente
[a-zA-Z_][A-Za-z0-9_]*
para[a-zA-Z_]\\w*
ahorrar unos pocos bytes. EDITAR: En realidad, creo que puedes usar en\\w+
lugar de[a-zA-Z_][A-Za-z0-9_]*
.[0]
lugar de.group()
desde Python 3.6.Retina 0.8.2 ,
142138128117 bytesPruébalo en línea! El enlace incluye casos de prueba. Mejor gramática . Editar: ahorró
1021 bytes al portar la solución Pip de @ DLosc. Explicación:Mueva el tipo al final y envuelva el resto de la declaración en
()
s en caso de que contenga un exterior*
.Procesar cualquier función.
Procesar cualquier matriz.
Mueva los punteros al final de sus corchetes y elimine los corchetes, trabajando repetidamente desde el conjunto de corchetes más externo hacia adentro.
Procesar cualquier puntero.
Insertar el
is
.fuente
Java 11,
469467463450 bytesPruébalo en línea.
Explicación:
fuente
Bash + cdecl + GNU sed, 180
cdecl
es una venerable utilidad de Unix que hace la mayor parte de lo que se requiere aquí, pero para cumplir con los requisitos de E / S, se requiere algosed
de procesamiento previo y posterior:Preprocesamiento de sed:
s/^/explain struct /
- Agregue "explicar estructura" al comienzo de cada líneas/struct (int|char double|float|void) /\1 /
- Eliminarstruct
cuando se trata con tipos de lenguaje Cs/\bfunc/_func/g
- "func" es reconocido como una palabra clave por cdecl - suprima estoPostprocesamiento de sed:
s/^declare //
- eliminar "declarar" al inicio de la líneas/as/is/
- Autoexplicativos/struct //g
- eliminar todas las palabras clave "struct"s/([0-9]+) of/of \1/g
- ordenación correcta de "de"s/\b_func/func/g
- revierte cualquier "_func" que fue reemplazado en el preprocesamientoEn acción:
fuente
s/\bfu/_fu/g
y guardar los bytes delfunc
reemplazo completo ?as
(+4 bytes para espacios para arreglar). No tengo accesocdecl
pero creo que puedes guardar 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 bytesTercer enfoque!
Toma la declaración como una entrada de línea de comandos. Pruébalo en línea!
Explicación
El código consta de tres partes: configuración inicial y manejo de funciones y matrices; un bucle que maneja paréntesis y punteros; y un reordenamiento final.
Configuración, funciones y matrices
Queremos que toda la declaración esté entre paréntesis (esto ayuda con el ciclo más adelante), por lo que cambiamos
type ...;
atype (...)
. Luego, observe que no se realiza un reordenamiento con las descripciones de funciones y matrices, por lo que podemos realizar todos esos reemplazos primero sin afectar la salida final.Si nuestra entrada original fue
float *((*p()))[16];
, ahora tenemosfloat (*((*p function returning)) array of 16)
.Paréntesis y punteros
Ejecutamos un bucle que reemplaza el par de paréntesis más externo y cualquier asterisco que esté inmediatamente dentro del paréntesis de apertura.
Pasos de ejemplo:
Limpiar
Lo único que queda es mover el tipo al final y agregar "es":
Para definiciones como
int x;
, este enfoque dará como resultado un espacio adicional, que está permitido por el desafío.fuente
JavaScript (ES6),
316...268253bytesPruébalo en línea!
Comentado
Función auxiliar
Parte principal
fuente
[...s.split`()`.join`!`]
lugar de solo[...s.replace('()','!')]
, pero me di cuenta de que es exactamente el mismo número de bytes ... :)s.replace('()','!')
solo reemplazaría la primera aparición..replace
reemplaza todas las ocurrencias, y.replaceAll
reemplaza todas las ocurrencias con expresiones regulares habilitadas. Siempre pensé que nombrar era bastante malo para estos dos métodos en Java, como los habría llamado.replaceAll
y.regexReplaceAll
algo así, pero supongo que para codegolf es más corto como.replace
y.replaceAll
.~
) justo después de publicar la primera versión de mi propia respuesta. Grandes mentes piensan igual, supongo. : pLimpio , 415 bytes
Pruébalo en línea!
fuente
R ,
225218 bytesPruébalo en línea!
Programa completo, envuelto en una función en TIO para una prueba conveniente de todos los casos de prueba a la vez.
Primero, usamos Regex para convertir la entrada del formulario
type ...name...;
a..."name is"..."type"
. La notación de función()
se convierte luego en texto con un operador de concatenación de alta prioridad. Por desgracia, también hay que reemplazar*
con+
que el primero no es aceptable como un operador unario. El resto lo hacen R'seval
con operadores sobrecargados.fuente
Perl 6 ,
209190171162153 bytesPruébalo en línea!
Enfoque de expresiones regulares recursivas. Produce algunos caracteres de espacio extra que se pueden evitar a costa de 3 bytes .
Explicación
fuente
JavaScript 250 Bytes [249?]
Esto usa 250 Bytes:
Explicación:
Básicamente, está leyendo desde un búfer
a
, que es la entrada tokenizada. Mueve continuamente los tokens desde el búfera
a una pilas
, hasta que se activa el modo de evaluación. El modo de evaluación consumirá primero las operaciones de postfix()
,[]
desde el búfer, y luego consumirá el operador de prefijo*
de la pila. El modo de evaluación se activa cuando el estado es donde estaría una palabra (o se encuentra y se consume el nombre de tipo, o)
se encuentra y elimina un final ). El modo de evaluación se desactiva cuando no se encuentran más operadores de prefijo / postfix.NOTA
Si entiendo "Usar un espacio en todas partes entre tokens" correctamente:
es técnicamente válido y usa
249 bytes
Asumiendo que hay un espacio entre cada ficha.
fuente
Rojo ,
418410 bytesPruébalo en línea!
Explicación:
fuente
APL (NARS), caracteres 625, bytes 1250
esta es solo una traducción del lenguaje C al APL del código del libro: "Linguaggio C" de Brian W. Kerninghan y Dennis M. Ritchie, capítulo 5.12. No sé cómo reducir todo eso porque no había entendido al 100% ese código, y porque no sé demasiado sobre APL ... La función para el ejercicio es f; Creo que solo se permiten 150 parentesis anidadas '(' ')' por error, devuelve una cadena con un valor negativo en eso o la descripción de la cadena si todo está bien. Parece que esto no es mejor que la otra versión, incluso si hay menos caracteres porque el otro ve mejor los errores. Alguna prueba:
fuente