Lesen Sie die C-Variablendeklaration aus

41

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

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?

  1. Beginnen Sie mit dem Variablennamen. (name) is ...
  2. Wählen Sie den Modifikator mit der höchsten Priorität.
  3. Lies es:
    • * -> pointer to ...
    • [N] -> array of N ...
    • () -> function returning ...
  4. Wiederholen Sie 2 und 3, bis die Modifikatoren erschöpft sind.
  5. 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 etwas unsigned long longwird nicht getestet.
  • Für die Array - Notation [N], die Zahl Nwird immer eine einzige positive ganze Zahl in der Basis geschrieben sein 10. Dinge wie int a[5+5], int a[SIZE]oder int a[0x0f]nicht getestet werden.
  • Für die Funktionsnotation ()werden, wie oben ausgeführt, überhaupt keine Parameter angegeben.
  • Bei Leerzeichen wird nur das Leerzeichen 0x20verwendet. 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ückgibt
  • f()[] Array, das die Funktion zurückgibt
  • a[]() 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, theSingular- / 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:

  1. Beginnen Sie mit dem Variablennamen. (name) is ...
  2. Wählen Sie den Modifikator mit der höchsten Priorität.
  3. Lies es:
    • * -> pointer to ...
    • [N] -> array of N ...
    • () -> function returning ...
  4. Wiederholen Sie 2 und 3, bis die Modifikatoren erschöpft sind.
  5. 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 Herausforderung. Das Programm mit der geringsten Anzahl von Bytes gewinnt.

Bubbler
quelle
9
Related: cdecl.org
user202729
int arr[3][4];ist an array of 3 arrays of 4 ints(wie du sagst), oder an array of 4 arrays of 3 ints?
Charlie
1
@ Charlie Ersteres ist richtig. sizeof(arr[0]) == sizeof(int[4]), so arrenthält ein Gegenstand von vier ints.
Bubbler
1
Enthält die Eingabe das ;am Ende der Zeile?
Black Owl Kai
2
@KamilDrakari Es ist das letztere. "array of pointer to function" ist im Wesentlichen "array of pointer", was in C.
Bubbler

Antworten:

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)

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

Schwarze Eule Kai
quelle
1
Netter Ansatz, +1 von mir! Sie können Golf spielen , [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_]*.
Kevin Cruijssen
Ich mag diesen Ansatz :) hier ist es in 253 Bytes
Lynn
1
Das ist ein guter Punkt. 261 ist es dann.
Lynn
1
Sie können [0]statt .group()seit Python 3.6 verwenden.
Infmagic2047
1
Und hier ist eine 240-Byte-Version .
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 

Probieren Sie es online! Link enthält Testfälle. Bessere Grammatik . Bearbeiten: 10 21 Bytes durch Portierung der Pip-Lösung von @ DLosc gespeichert. Erläuterung:

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

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

\(\)
 function returning

Verarbeiten Sie alle Funktionen.

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

Verarbeiten Sie alle Arrays.

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

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.

\*
 pointer to

Verarbeiten Sie alle Zeiger.

1` 
 is 

Legen Sie die is.

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

Probieren Sie es online aus.

Erläuterung:

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
quelle
Schlägt im Testfall mit redundanten Klammern fehl.
Bubbler
@Bubbler Ah, diesen neuen Testfall habe ich nicht bemerkt. Zum Glück ist es eine einfache Lösung.
Kevin Cruijssen
6

Bash + cdecl + GNU sed, 180

cdeclist ein ehrwürdiges Unix-Dienstprogramm, das das meiste tut, was hier benötigt wird. Um jedoch die E / A-Anforderungen zu erfüllen, sind einige sedVor- und Nachbearbeitungsschritte erforderlich:

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'
  • Es wurden keine Versuche unternommen, die Grammatik zu korrigieren.

sed Vorverarbeitung:

  • s/^/explain struct /- Fügen Sie am Anfang jeder Zeile "EXPLAIN STRUCT" ein
  • s/struct (int|char double|float|void) /\1 /- structBeim Umgang mit C-Sprachtypen entfernen
  • s/\bfunc/_func/g - "func" wird von cdecl als Schlüsselwort erkannt - unterdrücken Sie dies

sed Nachbearbeitung:

  • s/^declare // - "declare" am Zeilenanfang entfernen
  • s/as/is/ - selbsterklärend
  • s/struct //g - Entfernen Sie alle "struct" -Schlüsselwörter
  • s/([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 wurden

In Aktion:

$ < 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
$ 
Digitales Trauma
quelle
Wäre es ausreichend, s/\bfu/_fu/gdie Bytes der vollständigen funcErsetzung zu tun und zu speichern ?
DLosc
Warten Sie, es ist ein echtes Dienstprogramm? Ich habe immer gedacht, dass es der Name der Website ist
phuclv
@phuclv cdecl ist ein echtes Hilfsprogramm und sehr nützlich zum Überprüfen von C-Deklarationen.
Patricia Shanahan
Schlägt fehl für eine Variable mit dem Namen as(+4 Bytes für Leerzeichen). Ich habe keinen Zugriff auf, cdeclaber ich denke, Sie können mit 64 Bytes sparen sed -r 's/^(\w+)(\W+)/explain struct \1_\2_/'|cdecl|sed -r 's/^declare struct _|_$//;s/ as / is /;s/([0-9]+) of/of \1/g'.
Neil
6

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

Dritter Ansatz!

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

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

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"

Wenn unsere ursprüngliche Eingabe war float *((*p()))[16];, haben wir jetzt float (*((*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.

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
    }

Beispielschritte:

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

Aufräumen

Das einzige, was noch übrig bleibt, ist, den Typ ans Ende zu setzen und "is" hinzuzufügen:

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

Für Definitionen wie int x;dieses führt dieser Ansatz zu einem zusätzlichen Platz, der durch die Herausforderung zugelassen wird.

DLosc
quelle
5

JavaScript (ES6), 316 ... 268 253 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`!`)

Probieren Sie es online!

Kommentiert

Hilfsfunktion

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

Hauptteil

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
quelle
Ich habe mich gefragt, warum Sie [...s.split`()`.join`!`]anstatt nur verwendet haben [...s.replace('()','!')], aber ich habe festgestellt, dass es genau die gleiche
Byteanzahl ist
@ KevinCruijssen Der Hauptgrund ist, dass s.replace('()','!')nur das erste Vorkommen ersetzt würde.
Arnauld
Ah, natürlich. Ich habe vergessen, dass JS replace nicht mit Java identisch ist. In Java werden .replacealle Vorkommen .replaceAllersetzt 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 .replaceAllund .regexReplaceAlloder etwas in dieser Richtung genannt hätte, aber ich denke, für Codegolf ist es kürzer als .replaceund .replaceAll.
Kevin Cruijssen
1
Übrigens habe ich bemerkt, dass Sie die gleiche Technik (mit ~) angewendet haben, kurz nachdem Sie die erste Version meiner eigenen Antwort veröffentlicht haben. Große Köpfe denken wohl gleich. : p
Arnauld
3

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

Probieren Sie es online!

Οurous
quelle
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())))))

Probieren 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 R evalmit überladenen Operatoren.

Kirill L.
quelle
1
Clevere Lösung!
J.Doe
3

Perl 6 , 209 190 171 162 153 Bytes

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

Probieren Sie es online!

Rekursiver Regex-Ansatz. Erzeugt einige zusätzliche Leerzeichen, die auf Kosten von 3 Byte vermieden werden können .

Erläuterung

{     # 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
quelle
2

JavaScript 250 Bytes [249?]

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

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 Puffer ain einen Stapel verschoben s, 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.

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
)

HINWEIS

Wenn ich "Verwenden eines Leerzeichens überall zwischen Token" richtig verstehe:

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

ist technisch gültig und verwendet

249 Bytes

Angenommen, zwischen jedem Token ist ein Leerzeichen.

Nicholas Pipitone
quelle
2
Das hat mich viele, viele Stunden gekostet, obwohl es einfach ausgesehen hat. Ich habe wahrscheinlich 5-10 Bytes / Stunde geschlagen, beginnend mit 350 Zeichen. Ich habe in der Tat kein Leben.
Nicholas Pipitone
2
Ich war ungefähr 325, als ich dachte "Ich habe mit meinem aktuellen Algorithmus die Optimalität erreicht - Rippen", aber dann konnte ich aus irgendeinem Grund immer noch 5-10 / Stunde klopfen, obwohl auf jedes Klopfen "Okay, das ist definitiv das" folgte optimales Ergebnis ". 250 zu treffen war willkürlich, da es das erste war, das die 253 besiegte. Auch wenn ich immer noch sage "Okay, das ist definitiv das optimale Ergebnis", könnte es noch mehr zu optimieren geben.
Nicholas Pipitone
1

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

Probieren Sie es online!

Erläuterung:

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
quelle
0

APL (NARS), Zeichen 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

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:

  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
quelle