Leia a declaração da variável C

41

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

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?

  1. Comece pelo nome da variável. (name) is ...
  2. Selecione o modificador com a maior precedência.
  3. Leia-o:
    • * -> pointer to ...
    • [N] -> array of N ...
    • () -> function returning ...
  4. Repita 2 e 3 até que os modificadores estejam esgotados.
  5. 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 como unsigned long longnão será testado.
  • Para a marcação de matriz [N], o número Nserá sempre um único número inteiro positivo escrito na base 10. O como int a[5+5], int a[SIZE]ou int 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 0x20será 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ção
  • f()[] Função que retorna a matriz
  • a[]() 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, theformas 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:

  1. Comece pelo nome da variável. (name) is ...
  2. Selecione o modificador com a maior precedência.
  3. Leia-o:
    • * -> pointer to ...
    • [N] -> array of N ...
    • () -> function returning ...
  4. Repita 2 e 3 até que os modificadores estejam esgotados.
  5. 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 . O programa com o menor número de bytes vence.

Bubbler
fonte
9
Relacionados: cdecl.org
user202729
int arr[3][4];é an array of 3 arrays of 4 ints(como você diz) ou an array of 4 arrays of 3 ints?
25418 Charlie
1
@ Charlie O primeiro está correto. sizeof(arr[0]) == sizeof(int[4]), então um item de arrcontém quatro ints.
Bubbler
1
A entrada contém ;o final da linha?
Black Owl Kai
2
@KamilDrakari É o último. "matriz de ponteiro de função" é essencialmente "matriz de ponteiro", que é perfeitamente válida em C.
borbulhador

Respostas:

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)

Experimente 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.

Coruja preta Kai
fonte
1
Boa abordagem, +1 de mim! Você pode jogar golfe [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_]*.
Kevin Cruijssen 25/10
Eu gosto dessa abordagem :) aqui está ele em 253 bytes #
Lynn
1
Este é um bom ponto. 261 é então.
22418 Lynn
1
Você pode usar em [0]vez do .group()Python 3.6.
infmagic2047
1
E aqui está uma versão 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 

Experimente online! O link inclui casos de teste. Melhor gramática . Editar: salvou 10 21 bytes, portando a solução Pip do @ DLosc. Explicação:

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

Mova o tipo para o final e envolva o restante da declaração em ()s, caso ela contenha uma parte externa *.

\(\)
 function returning

Processe qualquer função.

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

Processe qualquer matriz.

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

Mova os ponteiros para o final de seus colchetes e exclua-os, trabalhando repetidamente do conjunto mais externo de colchetes para dentro.

\*
 pointer to

Processe qualquer ponteiro.

1` 
 is 

Insira o is.

Neil
fonte
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;}

Experimente online.

Explicação:

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)
Kevin Cruijssen
fonte
Falha no caso de teste com parênteses redundantes.
Bubbler
@ Bobbler Ah, não percebi esse novo caso de teste. Felizmente, é uma solução fácil.
Kevin Cruijssen 25/10
6

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 -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'
  • Nenhuma tentativa feita para corrigir a gramática.

sed Pré-processamento:

  • s/^/explain struct /- Adicione "struct struct" ao início de cada linha
  • s/struct (int|char double|float|void) /\1 /- Remova structao lidar com tipos de linguagem C
  • s/\bfunc/_func/g - "func" é reconhecido como uma palavra-chave por cdecl - suprime

Pós-processamento:

  • s/^declare // - remova "declare" no início da linha
  • s/as/is/ - auto-explicativo
  • s/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é-processamento

Em ação:

$ < 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
$ 
Trauma Digital
fonte
Seria suficiente fazer s/\bfu/_fu/ge salvar os bytes da funcsubstituição completa ?
DLosc
espera, é uma utilidade real? Eu sempre pensei que era o nome do site #
phuclv 27/10/1918
O @phuclv cdecl é um utilitário real e realmente útil para verificar as declarações em C.
Patricia Shanahan
Falha na variável denominada as(+4 bytes para os espaços a serem corrigidos). Não tenho acesso, cdeclmas acho que você pode salvar 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'.
28418 Neil
6

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

Terceira abordagem!

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

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

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"

Se nossa entrada original foi float *((*p()))[16];, agora temos float (*((*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.

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
    }

Etapas de exemplo:

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

Limpar

A única coisa que resta é mover o tipo para o final e adicionar "é":

{[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 definições como int x;, essa abordagem resultará em um espaço extra, que é permitido pelo desafio.

DLosc
fonte
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`!`)

Experimente online!

Comentado

Função 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 '!'
Arnauld
fonte
Fiquei me perguntando por que você usou [...s.split`()`.join`!`]em vez de apenas [...s.replace('()','!')], mas eu percebi que é exatamente o mesmo byte-count .. :)
Kevin Cruijssen
@KevinCruijssen O principal motivo é que s.replace('()','!')apenas substituiria a primeira ocorrência.
Arnauld 25/10
Ah, claro. A substituição esquecida de JS não é a mesma que a de Java. Em Java .replacesubstitui todas as ocorrências e .replaceAllsubstitui 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 .replaceAlle .regexReplaceAllou algo assim, mas acho que para o codegolf é mais curto como .replacee .replaceAll.
Kevin Cruijssen 25/10
1
BTW, notei que você estava usando a mesma técnica (com ~) logo após postar a primeira versão da minha própria resposta. Grandes mentes pensam da mesma forma, suponho. : p
Arnauld 25/10
3

Limpo , 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)

Experimente online!

Furioso
fonte
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())))))

Experimente 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's evalcom operadores sobrecarregados.

Kirill L.
fonte
1
Solução inteligente!
precisa saber é
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)}

Experimente online!

Abordagem regex recursiva. Produz alguns caracteres de espaço extra que podem ser evitados ao custo de 3 bytes .

Explicação

{     # 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)
 )
}
Nwellnhof
fonte
2

250 bytes de JavaScript [249?]

Isso 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))

Explicação:

Basicamente, é a leitura de um buffer a, que é a entrada tokenizada. Ele move continuamente os tokens do buffer apara uma pilha s, 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.

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

Se eu entender "Use um espaço em qualquer lugar entre os tokens" corretamente:

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

é tecnicamente válido e usa

249 bytes

Supondo que haja um espaço entre cada token.

Nicholas Pipitone
fonte
2
Isso me levou muitas horas, apesar de parecer direto. Eu provavelmente bati 5-10 bytes / hora, começando com 350 caracteres. Eu realmente não tenho vida.
Nicholas Pipitone
2
Eu tinha cerca de 325 anos quando pensei "atingi a otimização com meu algoritmo atual - rip", mas, por algum motivo, ainda era capaz de bater de 5 a 10 / hora, apesar de cada batida ser seguida por "Ok, esse é definitivamente o resultado ideal ". Atingir 250 foi arbitrário, já que foi o primeiro a vencer o atual 253, por isso, embora eu ainda diga "Ok, este é definitivamente o resultado ideal", ainda pode haver mais para otimizar.
Nicholas Pipitone
1

Vermelho , 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]]

Experimente online!

Explicação:

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
]
Galen Ivanov
fonte
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

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:

  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
RosLuP
fonte