Przeczytaj deklarację zmiennej C.

41

tło

Instrukcja deklaracji zmiennej w C składa się z trzech części: nazwy zmiennej, jej typu podstawowego i modyfikatora (-ów) typu .

Istnieją trzy rodzaje modyfikatorów typów:

  • Wskaźnik *(przedrostek)
  • Array [N](postfix)
  • Funkcja ()(postfiks)
    • Możesz podać listę argumentów funkcji w parenach, ale ze względu na to wyzwanie zignorujmy je i po prostu użyjmy ()(co technicznie oznacza, że ​​„funkcja może przyjmować dowolne argumenty”).

Sposób odczytania notacji jest następujący:

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

Chodzi o to, że możemy mieszać je wszystkie, aby utworzyć bardziej skomplikowany typ, taki jak tablica tablic lub tablica wskaźników funkcji lub wskaźnik do tablicy wskaźników :

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

Jak przeczytałem te skomplikowane wypowiedzi?

  1. Zacznij od nazwy zmiennej. (name) is ...
  2. Wybierz modyfikator o najwyższym priorytecie.
  3. Przeczytaj to:
    • * -> pointer to ...
    • [N] -> array of N ...
    • () -> function returning ...
  4. Powtarzaj 2 i 3, aż modyfikatory się wyczerpią.
  5. Na koniec przeczytaj typ podstawowy. ... (base type).

W języku C operatory Postfiks mają pierwszeństwo przed operatorami Prefiks, a modyfikatory typów nie są wyjątkiem. Dlatego []i ()najpierw wiążę *. Wszystko w parze parenów (...)(nie mylić z operatorem funkcji) wiąże się najpierw nad czymkolwiek na zewnątrz.

Ilustrowany przykład:

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

Zadanie

Biorąc pod uwagę wiersz instrukcji deklaracji zmiennej napisanej w C, wypisz angielskie wyrażenie opisujące linię, używając metody pokazanej powyżej.

Wejście

Dane wejściowe to pojedyncza instrukcja C, która zawiera jeden typ podstawowy, jedną nazwę zmiennej, zero lub więcej modyfikatorów typu i końcowy średnik. Musisz zaimplementować wszystkie elementy składni opisane powyżej, a także:

  • Zarówno typ podstawowy, jak i nazwa zmiennej pasują do wyrażenia regularnego [A-Za-z_][A-Za-z0-9_]*.
  • Teoretycznie twój program powinien obsługiwać nieograniczoną liczbę modyfikatorów typów.

Możesz uprościć inne elementy składni C na następujące sposoby (mile widziane jest również pełne wdrożenie):

  • Typ bazowy jest zawsze jedno słowo, na przykład int, float, uint32_t, myStruct. Coś takiego unsigned long longnie będzie testowane.
  • Dla notacji tablicy [N], liczba Nzawsze będzie jedna dodatnia napisany w bazie 10. Co jak int a[5+5], int a[SIZE]albo int a[0x0f]nie będą testowane.
  • W przypadku notacji funkcji w ()ogóle nie zostaną określone parametry, jak wskazano powyżej.
  • W przypadku białych znaków 0x20zostanie użyty tylko znak spacji . Możesz ograniczyć program do określonego użycia białych znaków, np
    • Użyj tylko jednej spacji za typem podstawowym
    • Użyj odstępu pomiędzy żetonami
  • Nie można jednak użyć dwóch lub więcej następujących po sobie spacji, aby przekazać więcej informacji niż separator tokenów.

Zgodnie ze składnią C następujące trzy kombinacje są nieprawidłowe i dlatego nie będą testowane:

  • f()() Funkcja zwracająca funkcję
  • f()[] Funkcja zwracająca tablicę
  • a[]() Tablica funkcji N.

Programiści C używają zamiast tego tych równoważnych formularzy (wszystkie z nich są omówione w przypadkach testowych):

  • (*f())()Funkcja zwracająca wskaźnik do funkcji
  • *f()Funkcja zwracająca wskaźnik do pierwszego elementu tablicy
  • (*a[])()Tablica N wskaźników do działania

Wydajność

Wynikiem jest pojedyncze zdanie angielskie. Nie musisz (ale możesz, jeśli chcesz) szanować gramatykę angielską, np. Użycie a, an, theformy liczby pojedynczej / mnogiej i kropki (kropki). Każde słowo powinno być oddzielone jedną lub więcej białymi spacjami (spacja, tabulator, nowa linia), aby wynik był czytelny dla człowieka.

Ponownie oto proces konwersji:

  1. Zacznij od nazwy zmiennej. (name) is ...
  2. Wybierz modyfikator o najwyższym priorytecie.
  3. Przeczytaj to:
    • * -> pointer to ...
    • [N] -> array of N ...
    • () -> function returning ...
  4. Powtarzaj 2 i 3, aż modyfikatory się wyczerpią.
  5. Na koniec przeczytaj typ podstawowy. ... (base type).

Przypadki testowe

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

Kryterium punktacji i wygranej

To wyzwanie dla . Program z najmniejszą liczbą bajtów wygrywa.

Bubbler
źródło
9
Powiązane: cdecl.org
user202729
int arr[3][4];jest an array of 3 arrays of 4 ints(jak mówisz), czy an array of 4 arrays of 3 ints?
Charlie,
1
@Charlie Ten pierwszy jest poprawny. sizeof(arr[0]) == sizeof(int[4]), więc element arrzawiera cztery ints.
Bubbler,
1
Czy dane wejściowe zawierają ;koniec na końcu linii?
Black Owl Kai
2
@KamilDrakari To jest to drugie. „wskaźnik na tablicę funkcji” zasadniczo „tablica wskaźnik”, który jest w pełni uzasadniona w C.
płuczki

Odpowiedzi:

17

Python 3 , 331 312 294 261 240 bajtów

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)

Wypróbuj online!

-19 bajtów, przechodząc do Pythona 2 i umieszczając definicję klasy w pliku exec

-18 bajtów poprzez zmianę wyrażenia regularnego z [a-zA-Z_][a-zA-Z0-9_]*na \\w+, dzięki Kevin Cruijssen

-33 bajtów dzięki pracy z magią definicji klasy i wykorzystaniu str, dzięki Lynn, powrót do Pythona 3

-21 bajtów poprzez połączenie wielu wyrażeń regularnych, dzięki infmagic2047

Wymaga, aby na wejściu znajdowała się tylko jedna spacja (między typem a wyrażeniem).

Myślę, że jest to dość unikalne podejście do problemu. Wykorzystuje to głównie fakt, że sam Python może oceniać ciągi takie jak (**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5])i otrzymuje prawidłową sekwencję wywołań funkcji, indeksów tablic i wskaźników - i że użytkownik może je przeciążać.

Czarna sowa Kai
źródło
1
Ładne podejście, +1 ode mnie! Możesz zagrać [a-zA-Z_][A-Za-z0-9_]*w golfa, [a-zA-Z_]\\w*aby zaoszczędzić kilka bajtów. EDYCJA: Właściwie myślę, że możesz po prostu użyć \\w+zamiast [a-zA-Z_][A-Za-z0-9_]*.
Kevin Cruijssen
Podoba mi się to podejście :) tutaj jest w 253 bajtach
Lynn
1
Trafne spostrzeżenie. 261 tak jest.
Lynn
1
Możesz używać [0]zamiast .group()od Python 3.6.
infmagic2047,
1
A tutaj jest wersja 240 bajtów .
infmagic2047,
13

Retina 0.8.2 , 142 138 128 117 bajtów

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

Wypróbuj online! Link zawiera przypadki testowe. Lepsza gramatyka . Edycja: Zapisano 10 21 bajtów, przenosząc rozwiązanie Pip @ DLosc. Wyjaśnienie:

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

Przenieś typ na koniec i zawiń resztę deklaracji ()ws, jeśli zawiera ona zewnętrzną *.

\(\)
 function returning

Przetwarzaj dowolne funkcje.

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

Przetwarzaj dowolne tablice.

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

Przesuń dowolne wskaźniki na koniec ich nawiasów i usuń je, wielokrotnie pracując od najbardziej zewnętrznego zestawu nawiasów do wewnątrz.

\*
 pointer to

Przetwarzaj dowolne wskaźniki.

1` 
 is 

Włóż is.

Neil
źródło
7

Java 11, 469 467 463 450 bajtów

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

Wypróbuj online.

Wyjaśnienie:

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
źródło
Błąd w przypadku testowym ze zbędnymi nawiasami.
Bubbler,
@Bubbler Ah, nie zauważyłem tego nowego przypadku testowego. Na szczęście jest to łatwa naprawa.
Kevin Cruijssen
6

Bash + cdecl + GNU sed, 180

cdecljest czcigodnym narzędziem Uniksa, który wykonuje większość wymaganych tutaj czynności, ale aby spełnić wymagania I / O, wymagane są pewne sedwstępne i końcowe przetwarzanie:

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'
  • Brak prób poprawienia gramatyki.

sed Przetwarzanie wstępne:

  • s/^/explain struct /- Dodaj „wyjaśnij strukturę” na początku każdej linii
  • s/struct (int|char double|float|void) /\1 /- Usuń, structgdy masz do czynienia z typami języka C.
  • s/\bfunc/_func/g - „func” jest rozpoznawany jako słowo kluczowe przez cdecl - pomiń to

sed Przetwarzanie końcowe:

  • s/^declare // - usuń „deklaruj” na początku wiersza
  • s/as/is/ - oczywiste
  • s/struct //g - usuń wszystkie słowa kluczowe „struct”
  • s/([0-9]+) of/of \1/g - prawidłowe uporządkowanie „z”
  • s/\b_func/func/g - cofnij wszelkie „_func”, które zostały zastąpione podczas przetwarzania wstępnego

W akcji:

$ < 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
$ 
Cyfrowa trauma
źródło
Czy wystarczy zrobić s/\bfu/_fu/gi zapisać bajty pełnego funczastąpienia?
DLosc
czekaj, to prawdziwa użyteczność? Zawsze myślałem, że to nazwa strony
phuclv
@phuclv cdecl jest prawdziwym narzędziem i bardzo przydatnym do sprawdzania deklaracji C.
Patricia Shanahan
Błąd dla zmiennej o nazwie as(+4 bajty dla spacji do naprawienia). Nie mam dostępu, cdeclale myślę, że możesz zaoszczędzić 64 bajty 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 126 125 123 bajtów

Trzecie podejście!

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

Pobiera deklarację jako dane wejściowe z wiersza polecenia. Wypróbuj online!

Wyjaśnienie

Kod składa się z trzech części: wstępnej konfiguracji i obsługi funkcji i tablic; pętla, która obsługuje nawiasy i wskaźniki; i ostateczna rearanżacja.

Konfiguracja, funkcje i tablice

Chcemy, aby cała deklaracja była nawiasowana (to pomaga w późniejszej pętli), więc zmieniamy się type ...;w type (...). Następnie zauważ, że nie jest przeprowadzane żadne ponowne porządkowanie z opisami funkcji i tablic, dzięki czemu możemy wykonać wszystkie te zamiany najpierw bez wpływu na końcowy wynik.

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"

Jeśli nasz pierwotny wkład był float *((*p()))[16];, teraz mamy float (*((*p function returning)) array of 16).

Nawiasy i wskaźniki

Uruchamiamy pętlę zastępującą najbardziej zewnętrzną parę nawiasów i wszelkie gwiazdki, które znajdują się bezpośrednio w otwierającym obszarze.

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
    }

Przykładowe kroki:

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

Sprzątać

Pozostało tylko przenieść typ na koniec i dodać „to”:

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

W przypadku takich definicji int x;, takie podejście spowoduje powstanie dodatkowej przestrzeni, na którą pozwala wyzwanie.

DLosc
źródło
5

JavaScript (ES6), 316 ... 268 253 bajtów

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

Wypróbuj online!

Skomentował

Funkcja pomocnika

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

Główną częścią

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
źródło
Zastanawiałem się, dlaczego użyłeś [...s.split`()`.join`!`]zamiast po prostu [...s.replace('()','!')], ale zdałem sobie sprawę, że to dokładnie ta sama liczba bajtów .. :)
Kevin Cruijssen
@KevinCruijssen Głównym powodem jest to, s.replace('()','!')że zastąpiłoby to tylko pierwsze wystąpienie.
Arnauld,
Ach, oczywiście. Zapomniałem, że JS replace nie jest tym samym, co Java. W Javie .replacezastępuje wszystkie wystąpienia i .replaceAllzastępuje wszystkie wystąpienia z włączonym wyrażeniem regularnym. Zawsze myślałem, że nazewnictwo jest dość złe dla tych dwóch metod w Javie, ponieważ nazwałbym je .replaceAlli .regexReplaceAlltak dalej, ale sądzę, że dla codegolf jest krótszy jak .replacei .replaceAll.
Kevin Cruijssen
1
BTW, zauważyłem, że używałeś tej samej techniki (z ~) zaraz po opublikowaniu pierwszej wersji mojej własnej odpowiedzi. Sądzę, że wielkie umysły myślą podobnie. : p
Arnauld,
3

Czysty , 415 bajtów

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)

Wypróbuj online!

Obrzydliwe
źródło
3

R , 225 218 bajtów

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

Wypróbuj online!

Pełny program zawarty w funkcji TIO do wygodnego testowania wszystkich przypadków testowych jednocześnie.

Po pierwsze, możemy użyć wyrażenia regularnego do przekształcenia wejście formie type ...name...;do ..."name is"..."type". Notacja funkcji ()jest następnie konwertowana na tekst za pomocą operatora konkatenacji o wysokim priorytecie. Niestety, mamy też do zastąpienia *z +jak były nie do zaakceptowania jako operator jednoargumentowy. Reszta jest wykonywana przez R evalz przeciążonymi operatorami.

Kirill L.
źródło
1
Sprytne rozwiązanie!
J.Doe
3

Perl 6 , 209 190 171 162 153 bajtów

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

Wypróbuj online!

Podejście rekurencyjne. Tworzy dodatkowe znaki spacji, których można uniknąć kosztem 3 bajtów .

Wyjaśnienie

{     # 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
źródło
2

JavaScript 250 bajtów [249?]

Wykorzystuje to 250 bajtów:

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

Wyjaśnienie:

Zasadniczo odczytuje z bufora a, który jest tokenizowanym wejściem. Ciągle przenosi tokeny z bufora ado stosu s, aż do uruchomienia trybu oceny. Tryb oceny zużywa operacji Postfix, przy pomocy pierwszej (), []z buforu, a następnie będzie zużywać operatora prefiksu *ze stosu. Tryb oceny jest uruchamiany, gdy stanem jest miejsce, w którym byłoby słowo (Albo nazwa typu zostanie znaleziona i zużyta, albo końcówka )zostanie znaleziona i usunięta). Tryb oceny jest wyłączany, gdy nie ma już więcej operatorów prefiksów / postfiksów.

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
)

UWAGA

Jeśli dobrze rozumiem „Używaj spacji wszędzie między tokenami”:

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

jest technicznie ważny i wykorzystuje

249 bajtów

Zakładając, że pomiędzy każdym tokenem jest spacja.

Nicholas Pipitone
źródło
2
Zajęło mi to wiele godzin, choć wyglądało to prosto. Prawdopodobnie zapukałem 5-10 bajtów / godzinę, zaczynając od 350 znaków. Naprawdę nie mam życia.
Nicholas Pipitone
2
Byłem w około 325, gdy pomyślałem „uderzę optymalności z mojego obecnego algorytmu - uderzenie”, ale z jakiegoś powodu byłem jeszcze w stanie wybić 5-10 / h, mimo każdy domina śledzony przez „Ok, to jest zdecydowanie optymalny wynik ”. Trafienie w 250 było arbitralne, ponieważ był pierwszym, który pokonał panującego 253, więc nawet jeśli nadal mówię „OK, to zdecydowanie optymalny wynik”, może być jeszcze więcej do optymalizacji.
Nicholas Pipitone
1

Czerwony , 418 410 bajtów

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

Wypróbuj online!

Wyjaśnienie:

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 Iwanow
źródło
0

APL (NARS), znaki 625, bajty 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

to tylko jedno tłumaczenie z języka C na APL z kodu w książce: „Linguaggio C” autorstwa Briana W. Kerninghana i Dennisa M. Ritchiego, rozdział 5.12. Nie wiem, jak to wszystko zredukować, ponieważ nie zrozumiałem w 100% tego kodu, a ponieważ nie wiem zbyt wiele na temat APL ... Funkcja wykonywania to f; Wydaje mi się, że dozwolone jest tylko 150 zagnieżdżonych nawiasów „(”) dla błędu zwraca jeden ciąg z jedną ujemną wartością w tym lub opis ciągu, jeśli wszystko jest w porządku. Wydaje się, że nie jest to lepsze niż w innej wersji, nawet jeśli mniej znaków, ponieważ druga lepiej widzi błędy. Niektóre testy:

  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
źródło