Hintergrund
Die Variablendeklarationsanweisung in C besteht aus drei Teilen: dem Namen der Variablen, ihrem Basistyp und den Typmodifikatoren .
Es gibt drei Arten von Typmodifikatoren:
- Zeiger
*
(Präfix) - Array
[N]
(Postfix) - Funktion
()
(Postfix)- Sie können eine Liste von Funktionsargumenten in den Parens angeben. Um diese Herausforderung zu bewältigen, ignorieren wir sie und verwenden einfach
()
(was technisch bedeutet, dass die Funktion alle Arten von Argumenten annehmen kann).
- Sie können eine Liste von Funktionsargumenten in den Parens angeben. Um diese Herausforderung zu bewältigen, ignorieren wir sie und verwenden einfach
Und ein Weg, um die Notationen auszulesen, ist wie folgt:
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
Der Haken ist, dass wir all diese Elemente mischen können, um einen komplizierteren Typ zu bilden, beispielsweise ein Array von Arrays oder ein Array von Funktionszeigern oder einen Zeiger auf ein Array von Zeigern :
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
Wie habe ich diese komplizierten Aussagen gelesen?
- Beginnen Sie mit dem Variablennamen.
(name) is ...
- Wählen Sie den Modifikator mit der höchsten Priorität.
- Lies es:
* -> pointer to ...
[N] -> array of N ...
() -> function returning ...
- Wiederholen Sie 2 und 3, bis die Modifikatoren erschöpft sind.
- Lesen Sie abschließend den Basistyp.
... (base type).
In C haben Postfix-Operatoren Vorrang vor Präfix-Operatoren, und Typmodifikatoren sind keine Ausnahme. Also, []
und dann erst ()
binden *
. Alles innerhalb eines Paares von Parens (...)
(nicht zu verwechseln mit dem Funktionsoperator) wird zuerst über alles außerhalb gebunden.
Illustriertes Beispiel:
int (*fptrs[10])();
fptrs fptrs is ...
[10] array of 10 ... // [] takes precedence over *
(* ) pointer to ...
() function returning ...
int int
Aufgabe
Geben Sie bei einer in C geschriebenen Zeile der Variablendeklarationsanweisung den englischen Ausdruck aus, der die Zeile beschreibt, und verwenden Sie dabei die oben gezeigte Methode.
Eingang
Die Eingabe ist eine einzelne C-Anweisung, die einen einzelnen Basistyp, einen einzelnen Variablennamen, null oder mehr Typmodifizierer und das abschließende Semikolon enthält. Sie müssen alle oben beschriebenen Syntaxelemente implementieren, plus:
- Sowohl der Basistyp als auch der Variablenname stimmen mit dem regulären Ausdruck überein
[A-Za-z_][A-Za-z0-9_]*
. - Theoretisch sollte Ihr Programm eine unbegrenzte Anzahl von Typmodifikatoren unterstützen.
Sie können andere C-Syntaxelemente auf folgende Weise vereinfachen (eine vollständige Implementierung ist ebenfalls willkommen):
- Der Basistyp ist immer ein einziges Wort, zum Beispiel
int
,float
,uint32_t
,myStruct
. So etwasunsigned long long
wird nicht getestet. - Für die Array - Notation
[N]
, die ZahlN
wird immer eine einzige positive ganze Zahl in der Basis geschrieben sein 10. Dinge wieint a[5+5]
,int a[SIZE]
oderint a[0x0f]
nicht getestet werden. - Für die Funktionsnotation
()
werden, wie oben ausgeführt, überhaupt keine Parameter angegeben. - Bei Leerzeichen wird nur das Leerzeichen
0x20
verwendet. Sie können Ihr Programm auf die Verwendung von Leerzeichen beschränken, z- Verwenden Sie nach dem Basistyp nur ein Leerzeichen
- Verwenden Sie überall zwischen Token ein Leerzeichen
- Sie können jedoch nicht zwei oder mehr aufeinanderfolgende Leerzeichen verwenden, um mehr Informationen zu übermitteln, als ein Tokentrennzeichen zu sein.
Laut C-Syntax sind die folgenden drei Kombinationen ungültig und werden daher nicht getestet:
f()()
Funktion, die Funktion zurückgibtf()[]
Array, das die Funktion zurückgibta[]()
Array von N Funktionen
C-Entwickler verwenden stattdessen diese äquivalenten Formulare (und alle diese werden in den Testfällen behandelt):
(*f())()
Funktion, die den Zeiger auf die Funktion zurückgibt*f()
Funktion, die den Zeiger auf das erste Element des Arrays zurückgibt(*a[])()
Array von N Zeigern, die funktionieren sollen
Ausgabe
Die Ausgabe ist ein einzelner englischer Satz. Sie müssen die englische Grammatik nicht respektieren (können dies aber tun), z. B. die Verwendung von a, an, the
Singular- / Pluralformen und den Endpunkt (Punkt). Jedes Wort sollte durch ein oder mehrere Leerzeichen (Leerzeichen, Tabulator, Zeilenvorschub) getrennt sein, damit das Ergebnis für den Menschen lesbar ist.
Hier ist wieder der Konvertierungsprozess:
- Beginnen Sie mit dem Variablennamen.
(name) is ...
- Wählen Sie den Modifikator mit der höchsten Priorität.
- Lies es:
* -> pointer to ...
[N] -> array of N ...
() -> function returning ...
- Wiederholen Sie 2 und 3, bis die Modifikatoren erschöpft sind.
- Lesen Sie abschließend den Basistyp.
... (base type).
Testfälle
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 */
Scoring & Winning-Kriterium
Dies ist eine Code-Golf- Herausforderung. Das Programm mit der geringsten Anzahl von Bytes gewinnt.
int arr[3][4];
istan array of 3 arrays of 4 ints
(wie du sagst), oderan array of 4 arrays of 3 ints
?sizeof(arr[0]) == sizeof(int[4])
, soarr
enthält ein Gegenstand von vierint
s.;
am Ende der Zeile?Antworten:
Python 3 ,
331 312 294 261240 BytesProbieren Sie es online!
-19 Bytes durch Umschalten auf Python 2 und Einfügen der Klassendefinition in ein
exec
-18 Bytes durch Ändern der Regex von
[a-zA-Z_][a-zA-Z0-9_]*
nach\\w+
, dank Kevin Cruijssen-33 Bytes durch Arbeiten mit Klassen-Definitionsmagie und Verwendung von str, dank Lynn, die zurück zu Python 3 wechselt
-21 Bytes durch Zusammenführen mehrerer regulärer Ausdrücke dank infmagic2047
Erfordert, dass nur ein Leerzeichen in der Eingabe enthalten ist (zwischen dem Typ und dem Ausdruck).
Ich denke, das ist eine ziemlich einzigartige Herangehensweise an das Problem. Dies
(**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5])
beruht hauptsächlich auf der Tatsache, dass Python selbst Zeichenfolgen wie und die richtige Reihenfolge von Funktionsaufrufen, Array-Indizes und Zeigern auswerten kann - und dass der Benutzer diese überladen kann.quelle
[a-zA-Z_][A-Za-z0-9_]*
um[a-zA-Z_]\\w*
ein paar Bytes zu speichern. EDIT: Eigentlich, denke ich Sie nur verwenden können ,\\w+
statt[a-zA-Z_][A-Za-z0-9_]*
.[0]
statt.group()
seit Python 3.6 verwenden.Retina 0.8.2 ,
142138128117 BytesProbieren Sie es online! Link enthält Testfälle. Bessere Grammatik . Bearbeiten:
1021 Bytes durch Portierung der Pip-Lösung von @ DLosc gespeichert. Erläuterung:Verschieben Sie den Typ an das Ende und schließen Sie den Rest der Deklaration in
()
s ein, falls er ein Äußeres enthält*
.Verarbeiten Sie alle Funktionen.
Verarbeiten Sie alle Arrays.
Bewegen Sie alle Zeiger an das Ende ihrer Klammern und löschen Sie die Klammern, indem Sie wiederholt von der äußersten Klammergruppe nach innen arbeiten.
Verarbeiten Sie alle Zeiger.
Legen Sie die
is
.quelle
Java 11,
469467463450 BytesProbieren Sie es online aus.
Erläuterung:
quelle
Bash + cdecl + GNU sed, 180
cdecl
ist ein ehrwürdiges Unix-Dienstprogramm, das das meiste tut, was hier benötigt wird. Um jedoch die E / A-Anforderungen zu erfüllen, sind einigesed
Vor- und Nachbearbeitungsschritte erforderlich:sed Vorverarbeitung:
s/^/explain struct /
- Fügen Sie am Anfang jeder Zeile "EXPLAIN STRUCT" eins/struct (int|char double|float|void) /\1 /
-struct
Beim Umgang mit C-Sprachtypen entfernens/\bfunc/_func/g
- "func" wird von cdecl als Schlüsselwort erkannt - unterdrücken Sie diessed Nachbearbeitung:
s/^declare //
- "declare" am Zeilenanfang entfernens/as/is/
- selbsterklärends/struct //g
- Entfernen Sie alle "struct" -Schlüsselwörters/([0-9]+) of/of \1/g
- korrekte Reihenfolge von "von"s/\b_func/func/g
- Setzen Sie alle "_func" zurück, die in der Vorverarbeitung ersetzt wurdenIn Aktion:
quelle
s/\bfu/_fu/g
die Bytes der vollständigenfunc
Ersetzung zu tun und zu speichern ?as
(+4 Bytes für Leerzeichen). Ich habe keinen Zugriff auf,cdecl
aber ich denke, Sie können mit 64 Bytes sparensed -r 's/^(\w+)(\W+)/explain struct \1_\2_/'|cdecl|sed -r 's/^declare struct _|_$//;s/ as / is /;s/([0-9]+) of/of \1/g'
.Pip
-s
,152150148139137126125123 BytesDritter Ansatz!
Übernimmt die Deklaration als Befehlszeileneingabe. Probieren Sie es online!
Erläuterung
Der Code besteht aus drei Teilen: Ersteinrichtung und Handhabung von Funktionen und Arrays; eine Schleife, die Klammern und Zeiger behandelt; und eine endgültige Umlagerung.
Setup, Funktionen & Arrays
Wir möchten, dass die gesamte Deklaration in Klammern steht (dies hilft später bei der Schleife), also wechseln wir
type ...;
zutype (...)
. Beachten Sie dann, dass bei den Beschreibungen der Funktionen und Arrays keine Neuordnung vorgenommen wird, sodass wir alle diese Ersetzungen zuerst durchführen können, ohne die endgültige Ausgabe zu beeinträchtigen.Wenn unsere ursprüngliche Eingabe war
float *((*p()))[16];
, haben wir jetztfloat (*((*p function returning)) array of 16)
.Klammern und Zeiger
Wir führen eine Schleife durch, die das äußerste Klammerpaar und alle Sternchen ersetzt, die sich unmittelbar innerhalb des Eröffnungsparens befinden.
Beispielschritte:
Aufräumen
Das einzige, was noch übrig bleibt, ist, den Typ ans Ende zu setzen und "is" hinzuzufügen:
Für Definitionen wie
int x;
dieses führt dieser Ansatz zu einem zusätzlichen Platz, der durch die Herausforderung zugelassen wird.quelle
JavaScript (ES6),
316...268253 BytesProbieren Sie es online!
Kommentiert
Hilfsfunktion
Hauptteil
quelle
[...s.split`()`.join`!`]
anstatt nur verwendet haben[...s.replace('()','!')]
, aber ich habe festgestellt, dass es genau die gleiches.replace('()','!')
nur das erste Vorkommen ersetzt würde..replace
alle Vorkommen.replaceAll
ersetzt und alle Vorkommen mit aktiviertem Regex ersetzt. Dachte immer, dass die Benennung für diese beiden Methoden in Java ziemlich schlecht war, wie ich sie.replaceAll
und.regexReplaceAll
oder etwas in dieser Richtung genannt hätte, aber ich denke, für Codegolf ist es kürzer als.replace
und.replaceAll
.~
) angewendet haben, kurz nachdem Sie die erste Version meiner eigenen Antwort veröffentlicht haben. Große Köpfe denken wohl gleich. : pSauber , 415 Bytes
Probieren Sie es online!
quelle
R ,
225218 BytesProbieren Sie es online!
Vollständiges Programm, eingebunden in eine Funktion von TIO zum bequemen Testen aller Testfälle auf einmal.
Zuerst verwenden wir Regex, um die Eingabe des Formulars
type ...name...;
in zu konvertieren..."name is"..."type"
. Die Funktionsnotation()
wird dann mit einem Verkettungsoperator mit hoher Priorität in Text konvertiert. Leider müssen wir auch ersetzen*
mit+
da erstere nicht akzeptabel als unärer Operator ist. Den Rest erledigen Reval
mit überladenen Operatoren.quelle
Perl 6 ,
209190171162153 BytesProbieren Sie es online!
Rekursiver Regex-Ansatz. Erzeugt einige zusätzliche Leerzeichen, die auf Kosten von 3 Byte vermieden werden können .
Erläuterung
quelle
JavaScript 250 Bytes [249?]
Dies verwendet 250 Bytes:
Erläuterung:
Grundsätzlich wird aus einem Puffer gelesen
a
, bei dem es sich um die tokenisierte Eingabe handelt. Es werden fortlaufend Token aus dem Puffera
in einen Stapel verschobens
, bis der Auswertungsmodus ausgelöst wird. Bewertungsmodus wird Postfix Operationen verbraucht ersten()
,[]
aus dem Puffer, und dann wird es die Präfixoperator verbrauchen*
aus dem Stapel. Der Auswertungsmodus wird ausgelöst, wenn sich der Zustand befindet, in dem sich ein Wort befinden würde (entweder wird der Typname gefunden und verbraucht oder eine Endung)
wird gefunden und entfernt). Der Auswertungsmodus wird deaktiviert, wenn keine Präfix- / Postfix-Operatoren mehr gefunden werden.HINWEIS
Wenn ich "Verwenden eines Leerzeichens überall zwischen Token" richtig verstehe:
ist technisch gültig und verwendet
249 Bytes
Angenommen, zwischen jedem Token ist ein Leerzeichen.
quelle
Rot ,
418.410BytesProbieren Sie es online!
Erläuterung:
quelle
APL (NARS), Zeichen 625, Bytes 1250
Dies ist nur eine Übersetzung von C-Sprache zu APL aus dem Code des Buches: "Linguaggio C" von Brian W. Kerninghan und Dennis M. Ritchie, Kapitel 5.12. Ich weiß nicht, wie ich das alles reduzieren soll, weil ich diesen Code nicht zu 100% verstanden habe und weil ich nicht zu viel über APL weiß ... Die Funktion für die Übung ist f; Ich denke, es sind nur 150 geschachtelte Parentesen '(' ')' für Fehler erlaubt, die eine Zeichenkette mit einem negativen Wert in dieser oder der Zeichenkettenbeschreibung zurückgeben, wenn alles in Ordnung ist. Es scheint, dass dies nicht besser ist als die andere Version, auch wenn weniger Zeichen, weil der andere die Fehler besser sieht. Einige test:
quelle