Lire la déclaration de la variable C

42

Contexte

L'instruction de déclaration de variable en C se compose de trois parties: le nom de la variable, son type de base et le modificateur de type .

Il existe trois types de modificateurs de type:

  • Pointeur *(préfixe)
  • Tableau [N] (postfixe)
  • Fonction ()(postfixe)
    • Vous pouvez spécifier une liste d'arguments de fonction à l'intérieur des parenthèses, mais dans l'intérêt de ce défi, ignorons-le et utilisons-le simplement ()(ce qui signifie techniquement que "la fonction peut prendre n'importe quel type d'argument").

Et une façon de lire les notations est la suivante:

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

Le problème, c'est que nous pouvons combiner tous ces éléments pour former un type plus complexe, tel qu'un tableau de tableaux ou un tableau de pointeurs de fonction ou un pointeur sur un tableau de pointeurs :

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

Comment ai-je lu ces déclarations compliquées?

  1. Commencez par le nom de la variable. (name) is ...
  2. Sélectionnez le modificateur avec la priorité la plus élevée.
  3. Lis le:
    • * -> pointer to ...
    • [N] -> array of N ...
    • () -> function returning ...
  4. Répétez les étapes 2 et 3 jusqu'à ce que les modificateurs soient épuisés.
  5. Enfin, lisez le type de base. ... (base type).

En C, les opérateurs postfixés ont priorité sur les opérateurs préfixés et les modificateurs de type ne font pas exception. Par conséquent, []et ()lier en premier, alors *. Quelque chose dans une paire de parens(...) (à ne pas confondre avec l'opérateur de la fonction) est d'abord lié à tout ce qui se trouve à l'extérieur.

Exemple illustré:

int (*fptrs[10])();
      fptrs           fptrs is ...
           [10]       array of 10 ... // [] takes precedence over *
    (*         )      pointer to ...
                ()    function returning ...
int                   int

Tâche

Avec une ligne d'instruction de déclaration de variable écrite en C, indiquez l'expression anglaise décrivant la ligne, à l'aide de la méthode présentée ci-dessus.

Contribution

L'entrée est une instruction C unique comprenant un seul type de base, un nom de variable unique, zéro modificateur de type ou plus, ainsi que le point-virgule de fin. Vous devez implémenter tous les éléments de syntaxe décrits ci-dessus, plus:

  • Le type de base et le nom de la variable correspondent à l'expression régulière [A-Za-z_][A-Za-z0-9_]* .
  • Théoriquement, votre programme devrait supporter un nombre illimité de modificateurs de type.

Vous pouvez simplifier les autres éléments de la syntaxe C des manières suivantes (une implémentation complète est également la bienvenue):

  • Le type de base est toujours un seul mot, par exemple int, float, uint32_t, myStruct. Quelque chose comme unsigned long longne sera pas testé.
  • Pour la notation de tableau [N], le nombre Nsera toujours un entier positif écrit en base 10. Des choses comme int a[5+5], int a[SIZE]ou int a[0x0f]ne seront pas testées.
  • Pour la notation de fonction (), aucun paramètre ne sera spécifié, comme indiqué ci-dessus.
  • Pour les espaces, seul le caractère d'espace 0x20sera utilisé. Vous pouvez limiter votre programme à une utilisation spécifique des espaces, par exemple
    • Utilisez un seul espace après le type de base
    • Utilisez un espace partout entre les jetons
  • Cependant, vous ne pouvez pas utiliser deux espaces consécutifs ou plus pour transmettre plus d'informations qu'un séparateur de jetons.

Selon la syntaxe C, les trois combinaisons suivantes ne sont pas valides et ne seront donc pas testées:

  • f()() Fonction de retour
  • f()[] Fonction retournant un tableau
  • a[]() Tableau de N fonctions

Les développeurs C utilisent ces formulaires équivalents à la place (et tous sont couverts dans les cas de test):

  • (*f())()Fonction retournant le pointeur à la fonction
  • *f()Fonction renvoyant le pointeur sur le premier élément du tableau
  • (*a[])()Tableau de N pointeurs pour fonctionner

Sortie

La sortie est une phrase anglaise unique. Vous n’avez pas besoin (mais vous pouvez si vous le souhaitez) de respecter la grammaire anglaise, par exemple l’utilisation dea, an, the formes singulières / plurielles et le point de fin (point). Chaque mot doit être séparé par un ou plusieurs espaces (espaces, tabulations, nouvelles lignes) pour que le résultat soit lisible par l'homme.

Encore une fois, voici le processus de conversion:

  1. Commencez par le nom de la variable. (name) is ...
  2. Sélectionnez le modificateur avec la priorité la plus élevée.
  3. Lis le:
    • * -> pointer to ...
    • [N] -> array of N ...
    • () -> function returning ...
  4. Répétez les étapes 2 et 3 jusqu'à ce que les modificateurs soient épuisés.
  5. Enfin, lisez le type de base. ... (base type).

Cas de test

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ère de notation et de gain

Ceci est un défi de . Le programme avec le plus petit nombre d'octets gagne.

Barboteur
la source
9
Connexes: cdecl.org
user202729
int arr[3][4];est an array of 3 arrays of 4 ints(comme vous dites), ou an array of 4 arrays of 3 ints?
Charlie
1
@Charlie Le premier est correct. sizeof(arr[0]) == sizeof(int[4]), donc un élément de arrcontient quatre ints.
Bubbler
1
Est-ce que l'entrée contient le ;à la fin de la ligne?
Black Owl Kai
2
@ KamilDrakari C'est le dernier. "tableau de pointeur vers fonction" est essentiellement "tableau de pointeur", ce qui est parfaitement valable en C.
Bubbler

Réponses:

17

Python 3 , 331 312 294 261 240 octets

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)

Essayez-le en ligne!

-19 octets en passant à Python 2 et en mettant la définition de la classe dans un exec

-18 octets en changeant la regex de [a-zA-Z_][a-zA-Z0-9_]*à \\w+, grâce à Kevin Cruijssen

-33 octets en utilisant une magie de définition de classe et en utilisant str, grâce à Lynn, pour revenir au python 3

-21 octets en fusionnant plusieurs regex, grâce à infmagic2047

Requiert qu’un seul espace soit contenu dans l’entrée (entre le type et l’expression).

Je pense que c'est une approche assez unique du problème. Cela utilise principalement le fait que Python lui-même peut évaluer des chaînes telles que (**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5])et obtient la séquence correcte d'appels de fonction, d'index de tableaux et de pointeurs - et que l'utilisateur peut les surcharger.

Black Owl Kai
la source
1
Belle approche, +1 de moi! Vous pouvez jouer [a-zA-Z_][A-Za-z0-9_]*au golf pour [a-zA-Z_]\\w*économiser quelques octets. EDIT: En fait, je pense que vous pouvez simplement utiliser à la \\w+place de [a-zA-Z_][A-Za-z0-9_]*.
Kevin Cruijssen
J'aime cette approche :) la voici en 253 octets
Lynn
1
C'est un bon point. 261 c'est alors.
Lynn
1
Vous pouvez utiliser [0]au lieu de .group()depuis Python 3.6.
infmagic2047
1
Et voici une version de 240 octets .
infmagic2047
13

Retina 0.8.2 , 142 138 128 117 octets

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

Essayez-le en ligne! Le lien inclut des cas de test. Meilleure grammaire . Édition: 10 21 octets enregistrés en portant la solution Pip de @ DLosc. Explication:

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

Déplacez le type à la fin et placez le reste de la déclaration dans ()s au cas où il contiendrait un extérieur *.

\(\)
 function returning

Traiter toutes les fonctions.

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

Traitez tous les tableaux.

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

Déplacez les pointeurs à la fin de leurs crochets et supprimez les crochets en travaillant de manière répétée à partir du jeu de crochets le plus externe.

\*
 pointer to

Traiter tous les pointeurs.

1` 
 is 

Insérer le is.

Neil
la source
7

Java 11, 469 467 463 450 octets

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

Essayez-le en ligne.

Explication:

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
la source
Échec du scénario de test avec des parenthèses redondantes.
Bubbler
@Bubbler Ah, je n'ai pas remarqué ce nouveau cas de test. Heureusement, c'est une solution facile.
Kevin Cruijssen
6

Bash + cdecl + GNU sed, 180

cdeclest un utilitaire Unix vénérable qui fait la plupart de ce qui est requis ici, mais pour faire correspondre les exigences d’E / S, certains sedpré et post-traitements sont nécessaires:

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'
  • Aucune tentative n'a été faite pour corriger la grammaire.

pré-traitement sed:

  • s/^/explain struct / - Ajouter "explique la structure" au début de chaque ligne
  • s/struct (int|char double|float|void) /\1 / - Retirer struct lorsqu'il s'agit de types de langage C
  • s/\bfunc/_func/g - "func" est reconnu comme mot clé par cdecl - supprime ceci

post-traitement sed:

  • s/^declare // - supprimer "déclarer" au début de la ligne
  • s/as/is/ - explicite
  • s/struct //g - supprimer tous les mots-clés "struct"
  • s/([0-9]+) of/of \1/g - commande correcte de "de"
  • s/\b_func/func/g - annuler tout "_func" qui a été remplacé dans le prétraitement

En action:

$ < 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 numérique
la source
Serait-il suffisant de faire s/\bfu/_fu/get de sauvegarder les octets du funcremplacement complet ?
DLosc
attendez c'est un vrai utilitaire? J'ai toujours pensé que c'était le nom du site
phuclv
@phuclv cdecl est un véritable utilitaire, et vraiment utile pour vérifier les déclarations en C.
Patricia Shanahan
Echoue pour une variable nommée as(+4 octets pour les espaces à corriger). Je n'ai pas accès à cdeclmais je pense que vous pouvez économiser 64 octets en utilisant 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 125 123 octets

Troisième approche!

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

Prend la déclaration en tant qu'entrée de ligne de commande. Essayez-le en ligne!

Explication

Le code est composé de trois parties: configuration initiale et gestion des fonctions et des tableaux; une boucle qui gère les parenthèses et les pointeurs; et un réarrangement final.

Configuration, fonctions et tableaux

Nous voulons que toute la déclaration soit mise entre parenthèses (cela aidera plus tard avec la boucle), alors nous passons type ...;à type (...). Ensuite, observez qu’aucune réorganisation n’est effectuée avec les descriptions de fonctions et de tableaux, afin que nous puissions effectuer tous ces remplacements d’abord sans affecter la sortie finale.

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 notre entrée d'origine était float *((*p()))[16];, nous avons maintenant float (*((*p function returning)) array of 16).

Parenthèses et pointeurs

Nous exécutons une boucle en remplaçant la paire de parenthèses extérieure et tous les astérisques se trouvant immédiatement à l'intérieur du paren d'ouverture.

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
    }

Exemple d'étapes:

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

Nettoyer

La seule chose qui reste à faire est de déplacer le type à la fin et d'ajouter "est":

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

Pour des définitions similaires int x;, cette approche créera un espace supplémentaire, ce que permet le défi.

DLosc
la source
5

JavaScript (ES6), 316 ... 268 253 octets

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

Essayez-le en ligne!

Commenté

Fonction d'assistance

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

Partie principale

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
la source
Je me demandais pourquoi vous utilisiez [...s.split`()`.join`!`]plutôt que juste [...s.replace('()','!')], mais j'ai réalisé que c'était exactement le même nombre d'octets .. :)
Kevin Cruijssen
@KevinCruijssen La raison principale est que s.replace('()','!')cela ne remplacerait que la première occurrence.
Arnauld
Ah bien sur. Le remplacement oublié de JS n'est pas identique à celui de Java. En Java, .replaceremplace toutes les occurrences et .replaceAlltoutes les occurrences lorsque regex est activé. Toujours pensé que la nomination était assez mauvais pour ces deux méthodes en Java, comme je les ai appelés .replaceAllet .regexReplaceAllou quelque chose dans ce sens, mais je pense que pour codegolf il est plus court .replaceet .replaceAll.
Kevin Cruijssen
1
D'ailleurs, j'ai remarqué que vous utilisiez la même technique (avec ~) juste après la publication de la première version de ma propre réponse. Les grands esprits se rencontrent, je suppose. : p
Arnauld
3

Propre , 415 octets

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)

Essayez-le en ligne!

Οurous
la source
3

R , 225 218 octets

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

Essayez-le en ligne!

Programme complet, intégré à une fonction sur TIO pour un test pratique de tous les tests en même temps.

Premièrement, nous utilisons Regex pour convertir l’entrée du formulaire type ...name...;en ..."name is"..."type". La notation de fonction ()est ensuite convertie en texte avec un opérateur de concaténation de haute priorité. Malheureusement, nous devons également le remplacer *par +l'ancien, ce qui n'est pas acceptable en tant qu'opérateur unaire. Le reste est fait par R evalavec des opérateurs surchargés.

Kirill L.
la source
1
Solution intelligente!
J.Doe
3

Perl 6 , 209 190 171 162 162 153 octets

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

Essayez-le en ligne!

Approche regex récursive. Produit des caractères d'espace supplémentaires qui peuvent être évités au prix de 3 octets .

Explication

{     # 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
la source
2

JavaScript 250 octets [249?]

Cela utilise 250 octets:

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

Explication:

Fondamentalement, il lit dans un tampon a, qui est l'entrée à jeton. Il déplace en permanence les jetons de la mémoire tampon avers une pile sjusqu'à ce que le mode d'évaluation soit déclenché. Le mode évaluation utilisera d’abord les opérations postfixes (), à []partir de la mémoire tampon, puis l’opérateur préfixe *de la pile. Le mode d'évaluation est déclenché lorsque l'état correspond à l'endroit où se trouverait un mot (le nom de type est trouvé et utilisé, ou une fin )est trouvée et supprimée). Le mode d'évaluation est désactivé lorsqu'il ne reste plus aucun opérateur préfixe / postfixe.

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
)

REMARQUE

Si je comprends bien "Utilisez un espace partout entre les jetons" correctement:

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

est techniquement valide et utilise

249 octets

En supposant qu'il y ait un espace entre chaque jeton.

Nicholas Pipitone
la source
2
Cela m'a pris de nombreuses heures, même si cela semblait simple. J'ai probablement frappé 5-10 octets / heure, en commençant par 350 caractères. Je n'ai en effet pas de vie.
Nicholas Pipitone
2
J'étais vers 325 quand je me suis dit "je vis l'optimalité avec mon algorithme actuel - rip", mais pour une raison quelconque, je pouvais quand même frapper à 5-10 / heure, malgré chaque frappe suivie de "OK, c'est définitivement le résultat optimal ". Frapper 250 était arbitraire, car c’était le premier à battre les 253 en titre, alors même si je dis toujours "OK, c’est définitivement le résultat optimal", il pourrait encore y avoir plus à optimiser.
Nicholas Pipitone
1

Rouge , 418 410 octets

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

Essayez-le en ligne!

Explication:

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
la source
0

APL (NARS), caractères 625, octets 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

ceci est juste une traduction du langage C à APL à partir du code du livre: "Linguaggio C" de Brian W. Kerninghan et Dennis M. Ritchie chapitre 5.12. Je ne sais pas comment réduire tout ça parce que je n'avais pas compris à 100% ce code, et parce que je ne sais pas trop sur APL ... La fonction pour l'exercice c'est f; Je pense que 150 parententes imbriquées '(' '') ne sont autorisées que pour retourner une chaîne avec une valeur négative ou la description de la chaîne si tout va bien. Il semble que ce n’est pas meilleur que l’autre version, même s’il contient moins de caractères car l’autre voit mieux les erreurs. Quelques tests:

  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
la source