Lea la declaración de la variable C


41

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").

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?

  1. Comience desde el nombre de la variable. (name) is ...
  2. Seleccione el modificador con la mayor precedencia.
  3. Léelo:
    • * -> pointer to ...
    • [N] -> array of N ...
    • () -> function returning ...
  4. Repita 2 y 3 hasta que los modificadores estén agotados.
  5. 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 longno será probado.
  • Para la notación de matriz [N], el número Nserá siempre un solo número entero positivo escrito en base 10. cosas como int a[5+5], int a[SIZE]o int 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 0x20usará 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 retorno
  • f()[] Función que devuelve la matriz
  • a[]() 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, theformas 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:

  1. Comience desde el nombre de la variable. (name) is ...
  2. Seleccione el modificador con la mayor precedencia.
  3. Léelo:
    • * -> pointer to ...
    • [N] -> array of N ...
    • () -> function returning ...
  4. Repita 2 y 3 hasta que los modificadores estén agotados.
  5. 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 . El programa con el menor número de bytes gana.


99
Relacionado: cdecl.org
user202729

int arr[3][4];es an array of 3 arrays of 4 ints(como dices) o an array of 4 arrays of 3 ints?
Charlie

1
@Charlie El primero es correcto. sizeof(arr[0]) == sizeof(int[4]), por lo que un elemento de arrcontiene cuatro ints.
Bubbler

1
¿La entrada contiene el ;al final de la línea?
Black Owl Kai

2
@KamilDrakari Es lo último. "matriz de puntero para funcionar" es esencialmente "matriz de puntero", que es perfectamente válido en C.
Bubbler

Respuestas:


17

Python 3 , 331 312 294 261 240 bytes

from re import*
class V(str):__pos__=lambda s:V(s+'pointer to ');__call__=lambda s:V(s+'function returning ');__getitem__=lambda s,i:V(s+'array of %i '%i)
t,e=input().split()
print(eval(sub('\*','+',sub('(\w+)',r'V("\1 is ")',e[:-1],1)))+t)

Prué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.


1
Buen enfoque, +1 de mi parte! Puede jugar golf [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_]*.
Kevin Cruijssen

Me gusta este enfoque :) aquí está en 253 bytes
Lynn

1
Ese es un buen punto. 261 es entonces.
Lynn

1
Puede usar en [0]lugar de .group()desde Python 3.6.
infmagic2047

1
Y aquí hay una versión de 240 bytes .
infmagic2047

13

Retina 0.8.2 , 142 138 128 117 bytes

(\w+) (.+);
($2) $1
\(\)
 function returning
\[(\d+)?]
 array of$#1$* $1
+`\((\**)(.+)\)
$2$1
\*
 pointer to
1` 
 is 

Pruébalo en línea! El enlace incluye casos de prueba. Mejor gramática . Editar: ahorró 10 21 bytes al portar la solución Pip de @ DLosc. Explicación:

(\w+) (.+);
($2) $1

Mueva el tipo al final y envuelva el resto de la declaración en ()s en caso de que contenga un exterior *.

\(\)
 function returning

Procesar cualquier función.

\[(\d+)?]
 array of$#1$* $1

Procesar cualquier matriz.

+`\((\**)(.+)\)
$2$1

Mueva los punteros al final de sus corchetes y elimine los corchetes, trabajando repetidamente desde el conjunto de corchetes más externo hacia adentro.

\*
 pointer to

Procesar cualquier puntero.

1` 
 is 

Insertar el is.


7

Java 11, 469 467 463 450 bytes

s->{String r="",t,S[];for(s=s.replace("()","~");s.contains("(");s=s.replace(t,"").replace("()",""),r+=t+";")t=s.replaceAll(".*(\\([^()]+\\)).*","$1");S=s.split(" ");t=S[0];r+=r.isEmpty()?S[1]:s;S=r.split(";");r=S[0].replaceAll(".*?(\\w+).*","$1 is ");for(var p:S)r+=p.replaceAll("[A-Za-z_]+\\d+|[^\\[\\d]","").replaceAll("\\[(\\d+)","array of $1 ")+(p.contains("~")?"function returning ":"")+"pointer to ".repeat(p.split("\\*").length-1);return r+t;}

Pruébalo en línea.

Explicación:

s->{               // Method with String as both parameter and return-type
  String r="",     //  Result-String, starting empty
         t,        //  Temp-String, starting uninitialized
         S[];      //  Temp String-array, starting uninitialized
  for(s=s.replace("()","~");
                   //  Replace all "()" in the input `s` with "~"
      s.contains("(");
                   //  Loop as long as the input `s` still contains "("
      ;            //    After every iteration:
       s=s.replace(t,"")
                   //     Remove `t` from `s`
          .replace("()",""),
                   //     And also remove any redundant parenthesis groups
       r+=t+";")   //     Append `t` and a semi-colon to the result-String
    t=s.replaceAll(".*(\\([^()]+\\)).*","$1");
                   //   Set `t` to the inner-most group within parenthesis
  S=s.split(" ");  //  After the loop, split the remainder of `s` on the space
  t=S[0];          //  Set `t` to the first item (the type)
  r+=              //  Append the result-String with:
    r.isEmpty()?   //   If the result-String is empty
                   //   (so there were no parenthesis groups)
     S[1]          //    Set the result-String to the second item
    :              //   Else:
     s;            //    Simple append the remainder of `s`
  S=r.split(";");  //  Then split `r` on semi-colons
  r=S[0].replaceAll(".*?(\\w+).*",
                   //  Extract the variable name from the first item
     "$1 is ");    //  And set `r` to this name appended with " is "
  for(var p:S)     //  Loop over the parts split by semi-colons:
    r+=            //   Append the result-String with:
      p.replaceAll("[A-Za-z_]+\\d+
                   //    First remove the variable name (may contain digits)
         |[^\\[\\d]","")
                   //    And then keep only digits and "["
       .replaceAll("\\[(\\d+)",
                   //    Extract the number after "["
         "array of $1 ")
                   //    And append the result-String with "array of " and this nr
      +(p.contains("~")?
                   //    If the part contains "~"
         "function returning "
                   //     Append the result-String with "function returning "
       :           //    Else:
        "")        //     Leave the result-String the same
      +"pointer to ".repeat(
                   //    And append "pointer to " repeated
         p.split("\\*").length-1);
                   //    the amount of "*" in the part amount of time
  return r         //  Then return the result-String
          +t;}     //  appended with the temp-String (type)

Falla en el caso de prueba con paréntesis redundantes.
Bubbler

@Bubbler Ah, no noté ese nuevo caso de prueba. Afortunadamente es una solución fácil.
Kevin Cruijssen

6

Bash + cdecl + GNU sed, 180

cdecles 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 algo sedde procesamiento previo y posterior:

sed -r 's/^/explain struct /;s/struct (int|char double|float|void) /\1 /;s/\bfunc/_func/g'|cdecl|sed -r 's/^declare //;s/as/is/;s/struct //g;s/([0-9]+) of/of \1/g;s/\b_func/func/g'
  • No se hicieron intentos para corregir la gramática.

Preprocesamiento de sed:

  • s/^/explain struct /- Agregue "explicar estructura" al comienzo de cada línea
  • s/struct (int|char double|float|void) /\1 /- Eliminar structcuando se trata con tipos de lenguaje C
  • s/\bfunc/_func/g - "func" es reconocido como una palabra clave por cdecl - suprima esto

Postprocesamiento de sed:

  • s/^declare // - eliminar "declarar" al inicio de la línea
  • s/as/is/ - Autoexplicativo
  • s/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 preprocesamiento

En acción:

$ < cdecls.txt sed -r 's/^/explain struct /;s/struct (int|char double|float|void) /\1 /;s/\bfunc/_func/g'|cdecl|sed -r 's/^declare //;s/as/is/;s/struct //g;s/([0-9]+) of/of \1/g;s/\b_func/func/g'
i is int
f is pointer to float
s is array of 10 my_struct_t
func is function returning int
arr is array of 3 array of 4 int
fptrs is array of 10 pointer to function returning int
p is pointer to array of 16 pointer to float
_WTH_is_TH15 is pointer to function returning pointer to pointer to array of 1234 array of 567 _RANdom_TYPE_123
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
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
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
$ 

¿Sería suficiente hacer s/\bfu/_fu/gy guardar los bytes del funcreemplazo completo ?
DLosc

espera es una utilidad real? Siempre he pensado que es el nombre del sitio web
phuclv

@phuclv cdecl es una utilidad real y realmente útil para verificar las declaraciones de C.
Patricia Shanahan


Falla para una variable llamada as(+4 bytes para espacios para arreglar). No tengo acceso cdeclpero creo que puedes guardar 64 bytes usando sed -r 's/^(\w+)(\W+)/explain struct \1_\2_/'|cdecl|sed -r 's/^declare struct _|_$//;s/ as / is /;s/([0-9]+) of/of \1/g'.
Neil

6

Pip -s , 152 150 148 139 137 126 125 123 bytes

Tercer enfoque!

YaRs" ("R';')R`\[(\d+)]`` array of \1`R"()"" function returning"L#aYyR`\((\**)(.+)\)`{c." pointer to"X#b}{[b"is"g@>2a]}Vy^s

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 ...;a type (...). 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.

Y                         Yank into y variable...
 a                        The result of a (the cmdline arg)...
  R s                     Replace the space
   " ("                    with " ("
  R ';                    Replace the semicolon
   ')                      with a closing paren
  R `\[(\d+)]`            Replace digits in square brackets
   ` array of \1`          with " array of <digits>"
  R "()"                  Replace function parens
   " function returning"   with " function returning"

Si nuestra entrada original fue float *((*p()))[16];, ahora tenemos float (*((*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.

L#a                   Loop len(a) times (enough to complete all replacements):
 Y                    Yank into y variable...
  y                   The result of y...
   R `\((\**)(.+)\)`  Replace open paren, 0 or more asterisks (group 1), 1 or more
                      characters (group 2), and close paren
    {                  with this callback function (b = group 1, c = group 2):
     c .               The stuff in the middle, concatenated to...
      " pointer to"    that string
       X #b            repeated len(asterisks) times
    }

Pasos de ejemplo:

float (*((*p function returning)) array of 16)
float ((*p function returning)) array of 16 pointer to
float (*p function returning) array of 16 pointer to
float p function returning pointer to array of 16 pointer to

Limpiar

Lo único que queda es mover el tipo al final y agregar "es":

{[b"is"g@>2a]}Vy^s
               y^s  Split y on spaces
{            }V     Use the resulting list as arguments to this function:
 [          ]        Return a list of:
  b                   2nd argument (the variable name)
   "is"               That string
       g@>2           All arguments after the 2nd
           a          1st argument (the type)
                    The resulting list is printed, joining on spaces (-s flag)

Para definiciones como int x;, este enfoque dará como resultado un espacio adicional, que está permitido por el desafío.


5

JavaScript (ES6), 316 ... 268253 bytes

s=>(g=s=>[/\d+(?=])/,/\*/,/!/,/.+ /,/\w+/].some((r,i)=>(S=s.replace(r,s=>(O=[O+`array of ${s} `,O+'pointer to ','function returning '+O,O+s,s+' is '+O][i],'')))!=s)?g(S):'',F=s=>(O='',S=s.replace(/\(([^()]*)\)/,g))!=s?O+F(S):g(s)+O)(s.split`()`.join`!`)

Pruébalo en línea!

Comentado

Función auxiliar

g = s =>                             // s = expression to parse
  [                                  // look for the following patterns in s:
    /\d+(?=])/,                      //   array
    /\*/,                            //   pointer
    /!/,                             //   function
    /.+ /,                           //   type
    /\w+/                            //   variable name
  ].some((r, i) =>                   // for each pattern r at index i:
    ( S = s.replace(                 //   S = new string obtained by removing
      r,                             //       the pattern matching r from s
      s => (                         //     using the first match s and the index i,
        O = [                        //     update the output O:
          O + `array of ${s} `,      //       array
          O + 'pointer to ',         //       pointer
          'function returning ' + O, //       function
          O + s,                     //       type
          s + ' is ' + O             //       variable name
        ][i],                        //
        ''                           //     replace the match with an empty string
    )))                              //   end of replace()
    != s                             //   make some() succeed if S is not equal to s
  ) ?                                // end of some(); if truthy:
    g(S)                             //   do a recursive call with S
  :                                  // else:
    ''                               //   stop recursion and return an empty string

Parte principal

s => (                 // s = input
  g = …,               // define the helper function g (see above)
  F = s => (           // F = recursive function, taking a string s
    O = '',            //   O = iteration output, initialized to an empty string
    S = s.replace(     //   S = new string obtained by removing the next expression from s
      /\(([^()]*)\)/,  //     look for the deepest expression within parentheses
      g                //     and process it with the helper function g
    )                  //   end of replace()
  ) != s ?             // if S is not equal to s:
    O + F(S)           //   append O to the final output and do a recursive call with S
  :                    // else (we didn't find an expression within parentheses):
    g(s) + O           //   process the remaining expression with g and return O
)(s.split`()`.join`!`) // initial call to F with all strings '()' in s replaced with '!'

Me preguntaba por qué lo usaste en [...s.split`()`.join`!`]lugar de solo [...s.replace('()','!')], pero me di cuenta de que es exactamente el mismo número de bytes ... :)
Kevin Cruijssen

@KevinCruijssen La razón principal es que s.replace('()','!')solo reemplazaría la primera aparición.
Arnauld

Ah, por supuesto. Olvidé reemplazar JS no es lo mismo que Java. En Java, .replacereemplaza todas las ocurrencias, y .replaceAllreemplaza 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 .replaceAlly .regexReplaceAllalgo así, pero supongo que para codegolf es más corto como .replacey .replaceAll.
Kevin Cruijssen

1
Por cierto, noté que estaba usando la misma técnica (con ~) justo después de publicar la primera versión de mi propia respuesta. Grandes mentes piensan igual, supongo. : p
Arnauld

3

Limpio , 415 bytes

import StdEnv,Text
$s#(b,[_:d])=span((<>)' ')(init s)
=join" "(?d++[""<+b])
?[]=[]
?['()':s]=["function returning": ?s]
?['*':s]= ?s++["pointer to"]
?['[':s]#(n,[_:t])=span((<>)']')s
=["array of "<+n: ?t]
?s=case@0s of(['(':h],t)= ?(init h)++ ?t;(h,t)|t>[]= ?h++ ?t=[h<+" is"]
~c=app2((++)[c],id)
@n[c:s]=case c of'('= ~c(@(n+1)s);')'|n>1= ~c(@(n-1)s)=([c],s);_|n>0= ~c(@n s)=span(\c=c<>'('&&c<>'[')[c:s]
@_ e=(e,e)

Pruébalo en línea!


3

R , 225 218 bytes

g=gsub
"&"="@"=paste
"["=function(a,b)a&"array of"&b
"+"=function(a)a&"pointer to"
eval(parse(t=g('\\(\\)','@"function returning"',g('(\\w+) (.*?)([A-Za-z_]\\w*)(.*);','\\2"\\3 is"\\4&"\\1"',g('\\*','+',readline())))))

Prué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's evalcon operadores sobrecargados.


1
Solución inteligente!
J.Doe

3

Perl 6 , 209 190 171 162 153 bytes

{~({(.[1]Z'is'),.<e>.&?BLOCK,('array of'X .[2]),('function returning','pointer to'Zxx.[3,0])if $_}(m:g/(\*)*[(\w+)+|\(<e=~~>.][\[(\d+).]*(\(.)*/[1]),$0)}

Prué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

{     # Anonymous block
 ~(   # Convert list to string
   {  # Block converting a regex match to a nested list
     (.[1]            # Array of 0 or 1 variable names
       Z'is'),        # zipped with string "is"
     .<e>.&?BLOCK,    # Recursive call to block with subexpression
     ('array of'      # String "array of"
       X .[2]),       # prepended to each array size
     ('function returning',  # Strings "function returning"
      'pointer to'           # and "pointer to"
      Zxx             # zipped repetition with
      .[3,0])         # number of function and pointer matches
     if $_            # Only if there's an argument
   }
   (             # Call block
     m:g/        # Input matched against regex
      (\*)*      # Sequence of asterisks, stored in [0]
      [          # Either
       (\w+)+    # the variable name, stored as 1-element array in [1]
       |         # or
       \(        # literal (
         <e=~~>  # the same regex matched recursively, stored in <e>
       .         # )
      ]
      [\[(\d+).]*  # Sequence of "[n]" with sizes stored in [2]
      (\(.)*       # Sequence of "()" stored in [3]
     /
     [1]  # Second match
   ),
   $0     # First match (base type)
 )
}

2

JavaScript 250 Bytes [249?]

Esto usa 250 Bytes:

k=>(a=k.match(/\W|\w+/g),s=[v=j=r=""],f=y=>!j&!a[i+1]||(m=a[i],v?(r+=v=m=='['?`array of ${a[i+=3,i-2]} `:m<')'?(i+=2,"function returning "):s[j-1]=='*'?j--&&"pointer to ":""):m==')'?v=j--|i++:m<'+'?s[j++]=a[i++]:r+=a[v=i++]+" is ",f(),r+a[0]),f(i=2))

Explicación:

Básicamente, está leyendo desde un búfer a, que es la entrada tokenizada. Mueve continuamente los tokens desde el búfer aa una pila s, 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.

k=>( // k is input
    a=k.match(/\W|\w+/g), // split by symbol or word
    s=[v=j=r=""], // j=0, v=false, r="", s=[]
    // s is the stack, r is the return string,
    // v is true if we're in evaluation mode (Consume (), [], *)
    // v is false if we're waiting to see a ) or token, which triggers evaluation
    // j is the index of the top of the stack (Stack pointer)
    f=y=>!j&!a[i+1]||( // !j means stack is empty, !a[i+1] means we're at the ;
        m=a[i], // Save a[i] in a variable
        v // Are we evaluating?
        ?(
        r+=v=
            m=='[' // Array
            ?`array of ${a[i+=3,i-2]} ` // Skip three tokens: "[", "10", "]"
                                        // a[i-2] is the "10"
            :m<')' // m == '('
                ?(i+=2,"function returning ") // Skip two tokens: "(", ")"
                :s[j-1]=='*' // Stack has a pointer
                    ?j--&&"pointer to " // Pop the stack
                    :"" // Set v to be false, r+=""
        )
        :m==')'
            ?v=j--|i++ // Pop the '(', skip over the ')', v = Evaluation mode
            :m<'+' // m == '*' || m == '('
                ?s[j++]=a[i++] // push(s, pop(a))
                :r+=a[v=i++]+" is " // Otherwise we have the token
        , f(), r+a[0] // Recurse f(), and return r+a[0]. a[0] is the type.
    ),
    f(i=2) // Set i=2, and call f(), which returns the final value r + type
    // a = ["type", " ", ...], so i=2 give the first real token
    // This soln assumes there is only one space, which is an allowed assumption
)

NOTA

Si entiendo "Usar un espacio en todas partes entre tokens" correctamente:

k=>(a=k.split(" "),s=[v=j=r=""],f=y=>!j&!a[i+1]||(v?(r+=v=a[i]=='['?`array of ${a[i+=3,i-2]} `:a[i]<')'?(i+=2,"function returning "):s[j-1]=='*'?j--&&"pointer to ":""):a[i]==')'?v=j--|i++:a[i]<'+'?s[j++]=a[i++]:r+=a[v=i++]+" is ",f(),r+a[0]),f(i=1))

es técnicamente válido y usa

249 bytes

Asumiendo que hay un espacio entre cada ficha.


2
Esto me llevó muchas horas, a pesar de que parecía sencillo. Probablemente toqué 5-10 bytes / hora, comenzando con 350 caracteres. De hecho, no tengo vida.
Nicholas Pipitone

2
Estaba en torno a 325 cuando pensé "Golpeé la optimización con mi algoritmo actual - rasgadura", pero luego, por alguna razón, todavía podía tocar 5-10 / hora, a pesar de que cada golpe era seguido por "Bien, este es definitivamente el resultado óptimo ". Golpear 250 fue arbitrario, ya que fue el primero en vencer a los 253 reinantes, por lo que aunque sigo diciendo "Está bien, este es definitivamente el resultado óptimo", aún podría haber más para optimizar.
Nicholas Pipitone

1

Rojo , 418 410 bytes

func[s][n: t:""a: charset[#"a"-#"z"#"A"-#"Z"#"0"-#"9""_"]parse s[remove[copy x thru" "(t: x)]to a
change[copy x[any a](n: x)]"#"]b: copy[]until[c: next find s"#"switch c/1[#"("[append
b"function returning"take/part c 2]#"["[parse c[remove[skip copy d to"]"(append b
reduce["array of"d])skip]]]#")"#";"[take c c: back back c while[#"*"= c/1][take c
c: back c append b"pointer to"]take c]]s =""]reduce[n"is"b t]]

Pruébalo en línea!

Explicación:

f: func [ s ] [
    n: t: 0                                         ; n is the name, t is the type
    a: charset [ #"a"-#"z" #"A"-#"Z" #"0"-#"9" "_" ]; characters set for parsing 
    parse s[                                        ; parse the input with the following rules
        remove [ copy x thru " " ](t: x)            ; find the type, save it to t and remove it from the string
        to a                                        ; skip to the next alphanumerical symbol
        change [ copy n [ any a ] (n: x) ] "#"      ; save it to n and replace it with '#'
    ]
    b: copy [ ]                                     ; block for the modifiers 
    until [                                         ; repeat 
       c: next find s "#"                           ; find the place of the name   
       switch c/1 [                                 ; and check what is the next symbol
           #"(" [ append b "function returning"     ; if it's a '('- it's a function - add the modifier       
                  take/part c 2                     ; and drop the "()"
                ]
           #"[" [ parse c [                         ; '[' - an array
                     remove [ skip copy d to "]"    ; save the number
                             (append b reduce [     ; and add the modifier 
                                  "array of" d
                              ] )                   
                             skip ]                 ; and remove it from the string
                     ]
                ]
           #")"                                     ; a closing bracket 
           #";" [ take c                            ; or ';' - drop it
                    c: back back c                  ; go to the left 
                    while [ #"*" = c/1 ]            ; and while there are '*'
                    [
                        take c                      ; drop them
                        c: back c                   ; go to the left
                        append b "pointer to"       ; add the modifier
                    ]
                    take c                          ; drop '(' (or space)
                 ]
       ]
       s = ""                                       ; until the string is exhausted
    ]
    reduce [ n "is" b t ]                     ; display the resul
]

0

APL (NARS), caracteres 625, bytes 1250

CH←⎕D,⎕A,⎕a,'_'⋄tkn←nm←∆←''⋄in←⍬⋄⍙←lmt←lin←0
eb←{∊(1(0 1 0)(0 1)(1 0))[⍺⍺¨⍵]}
tb←{x←({⍵='[':3⋄⍵=']':4⋄⍵∊CH,' ':1⋄2}eb⍵)\⍵⋄(x≠' ')⊂x}

gt
tkn←''⋄→0×⍳⍙>lin⋄tkn←∊⍙⊃in⋄⍙+←1⋄→0×⍳(⍙>lin)∨'('≠↑tkn⋄→0×⍳')'≠↑⍙⊃in⋄tkn←tkn,⍙⊃in⋄⍙+←1

r←dcl;n
   n←0
B: gt⋄→D×⍳'*'≠↑tkn⋄n+←1⋄→B×⍳tkn≢''
D: r←ddcl⋄∆←∆,∊n⍴⊂'pointer to '

r←ddcl;q
   r←¯1⋄→0×⍳0>lmt-←1
   →A×⍳∼'('=↑tkn⋄q←dcl⋄→F×⍳')'=↑tkn⋄→0
A: →B×⍳∼(↑tkn)∊CH⋄nm←tkn⋄→F
B: r←¯2⋄→0
F: gt⋄→G×⍳∼tkn≡'()'⋄∆←∆,'function that return '⋄→F
G: →Z×⍳∼'['=↑tkn⋄∆←∆,'array of ',{''≡p←(¯1↓1↓tkn):''⋄p,' '}⋄→F
Z: r←0

r←f w;q
   nm←∆←''⋄in←tb w⋄⍙←1⋄lin←↑⍴in⋄lmt←150⋄gt⋄→A×⍳∼0>q←dcl⋄r←⍕q⋄→0
A: r←nm,' is a ',∆,1⊃in

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:

  f 'int f()()'
f is a function that return function that return int
  f 'int a[]()'
a is a array of function that return int
  f 'int f()[]'
f is a function that return array of int
  f 'int i;'
i is a int
  f 'float *f;'
f is a pointer to float
  f 'my_struct_t s[10];'
s is a array of 10 my_struct_t
  f 'int func();'
func is a function that return int
  f 'int arr[3][4];'
arr is a array of 3 array of 4 int
  f 'int (*fptrs[10])();'
fptrs is a array of 10 pointer to function that return int
  f 'float *(*p)[16]; '
p is a pointer to array of 16 pointer to float
  f '_RANdom_TYPE_123 (**(*_WTH_is_TH15)())[1234][567];'
_WTH_is_TH15 is a pointer to function that return pointer to pointe
  r to array of 1234 array of 567 _RANdom_TYPE_123
  f 'uint32_t (**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5]);'
p is a pointer to pointer to pointer to array of 2 pointer to funct
  ion that return pointer to pointer to array of 123 pointer to
   array of 4 array of 5 pointer to pointer to uint32_t
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.