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").
- 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
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?
- Commencez par le nom de la variable.
(name) is ...
- Sélectionnez le modificateur avec la priorité la plus élevée.
- Lis le:
* -> pointer to ...
[N] -> array of N ...
() -> function returning ...
- Répétez les étapes 2 et 3 jusqu'à ce que les modificateurs soient épuisés.
- 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 commeunsigned long long
ne sera pas testé. - Pour la notation de tableau
[N]
, le nombreN
sera toujours un entier positif écrit en base 10. Des choses commeint a[5+5]
,int a[SIZE]
ouint 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
0x20
sera 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 retourf()[]
Fonction retournant un tableaua[]()
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:
- Commencez par le nom de la variable.
(name) is ...
- Sélectionnez le modificateur avec la priorité la plus élevée.
- Lis le:
* -> pointer to ...
[N] -> array of N ...
() -> function returning ...
- Répétez les étapes 2 et 3 jusqu'à ce que les modificateurs soient épuisés.
- 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 code-golf . Le programme avec le plus petit nombre d'octets gagne.
int arr[3][4];
estan array of 3 arrays of 4 ints
(comme vous dites), ouan array of 4 arrays of 3 ints
?sizeof(arr[0]) == sizeof(int[4])
, donc un élément dearr
contient quatreint
s.;
à la fin de la ligne?Réponses:
Python 3 ,
331 312 294 261240 octetsEssayez-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.la source
[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_]*
.[0]
au lieu de.group()
depuis Python 3.6.Retina 0.8.2 ,
142138128117 octetsEssayez-le en ligne! Le lien inclut des cas de test. Meilleure grammaire . Édition:
1021 octets enregistrés en portant la solution Pip de @ DLosc. Explication:Déplacez le type à la fin et placez le reste de la déclaration dans
()
s au cas où il contiendrait un extérieur*
.Traiter toutes les fonctions.
Traitez tous les tableaux.
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.
Traiter tous les pointeurs.
Insérer le
is
.la source
Java 11,
469467463450 octetsEssayez-le en ligne.
Explication:
la source
Bash + cdecl + GNU sed, 180
cdecl
est 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, certainssed
pré et post-traitements sont nécessaires:pré-traitement sed:
s/^/explain struct /
- Ajouter "explique la structure" au début de chaque lignes/struct (int|char double|float|void) /\1 /
- Retirerstruct
lorsqu'il s'agit de types de langage Cs/\bfunc/_func/g
- "func" est reconnu comme mot clé par cdecl - supprime cecipost-traitement sed:
s/^declare //
- supprimer "déclarer" au début de la lignes/as/is/
- explicites/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étraitementEn action:
la source
s/\bfu/_fu/g
et de sauvegarder les octets dufunc
remplacement complet ?as
(+4 octets pour les espaces à corriger). Je n'ai pas accès àcdecl
mais je pense que vous pouvez économiser 64 octets en utilisantsed -r 's/^(\w+)(\W+)/explain struct \1_\2_/'|cdecl|sed -r 's/^declare struct _|_$//;s/ as / is /;s/([0-9]+) of/of \1/g'
.Pip
-s
,152150148139137126125 125123 octetsTroisième approche!
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.Si notre entrée d'origine était
float *((*p()))[16];
, nous avons maintenantfloat (*((*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.
Exemple d'étapes:
Nettoyer
La seule chose qui reste à faire est de déplacer le type à la fin et d'ajouter "est":
Pour des définitions similaires
int x;
, cette approche créera un espace supplémentaire, ce que permet le défi.la source
JavaScript (ES6),
316...268253 octetsEssayez-le en ligne!
Commenté
Fonction d'assistance
Partie principale
la source
[...s.split`()`.join`!`]
plutôt que juste[...s.replace('()','!')]
, mais j'ai réalisé que c'était exactement le même nombre d'octets .. :)s.replace('()','!')
cela ne remplacerait que la première occurrence..replace
remplace toutes les occurrences et.replaceAll
toutes 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.replaceAll
et.regexReplaceAll
ou quelque chose dans ce sens, mais je pense que pour codegolf il est plus court.replace
et.replaceAll
.~
) juste après la publication de la première version de ma propre réponse. Les grands esprits se rencontrent, je suppose. : pPropre , 415 octets
Essayez-le en ligne!
la source
R ,
225218 octetsEssayez-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 Reval
avec des opérateurs surchargés.la source
Perl 6 ,
209190171162 162153 octetsEssayez-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
la source
JavaScript 250 octets [249?]
Cela utilise 250 octets:
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 tampona
vers une piles
jusqu'à 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.REMARQUE
Si je comprends bien "Utilisez un espace partout entre les jetons" correctement:
est techniquement valide et utilise
249 octets
En supposant qu'il y ait un espace entre chaque jeton.
la source
Rouge ,
418410 octetsEssayez-le en ligne!
Explication:
la source
APL (NARS), caractères 625, octets 1250
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:
la source