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”).
- Możesz podać listę argumentów funkcji w parenach, ale ze względu na to wyzwanie zignorujmy je i po prostu użyjmy
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?
- Zacznij od nazwy zmiennej.
(name) is ...
- Wybierz modyfikator o najwyższym priorytecie.
- Przeczytaj to:
* -> pointer to ...
[N] -> array of N ...
() -> function returning ...
- Powtarzaj 2 i 3, aż modyfikatory się wyczerpią.
- 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ś takiegounsigned long long
nie będzie testowane. - Dla notacji tablicy
[N]
, liczbaN
zawsze będzie jedna dodatnia napisany w bazie 10. Co jakint a[5+5]
,int a[SIZE]
alboint 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
0x20
zostanie 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, the
formy 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:
- Zacznij od nazwy zmiennej.
(name) is ...
- Wybierz modyfikator o najwyższym priorytecie.
- Przeczytaj to:
* -> pointer to ...
[N] -> array of N ...
() -> function returning ...
- Powtarzaj 2 i 3, aż modyfikatory się wyczerpią.
- 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 golfa . Program z najmniejszą liczbą bajtów wygrywa.
int arr[3][4];
jestan array of 3 arrays of 4 ints
(jak mówisz), czyan array of 4 arrays of 3 ints
?sizeof(arr[0]) == sizeof(int[4])
, więc elementarr
zawiera czteryint
s.;
koniec na końcu linii?Odpowiedzi:
Python 3 ,
331 312 294 261240 bajtówWypró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ć.źródło
[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_]*
.[0]
zamiast.group()
od Python 3.6.Retina 0.8.2 ,
142138128117 bajtówWypróbuj online! Link zawiera przypadki testowe. Lepsza gramatyka . Edycja: Zapisano
1021 bajtów, przenosząc rozwiązanie Pip @ DLosc. Wyjaśnienie:Przenieś typ na koniec i zawiń resztę deklaracji
()
ws, jeśli zawiera ona zewnętrzną*
.Przetwarzaj dowolne funkcje.
Przetwarzaj dowolne tablice.
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.
Przetwarzaj dowolne wskaźniki.
Włóż
is
.źródło
Java 11,
469467463450 bajtówWypróbuj online.
Wyjaśnienie:
źródło
Bash + cdecl + GNU sed, 180
cdecl
jest czcigodnym narzędziem Uniksa, który wykonuje większość wymaganych tutaj czynności, ale aby spełnić wymagania I / O, wymagane są pewnesed
wstępne i końcowe przetwarzanie:sed Przetwarzanie wstępne:
s/^/explain struct /
- Dodaj „wyjaśnij strukturę” na początku każdej liniis/struct (int|char double|float|void) /\1 /
- Usuń,struct
gdy masz do czynienia z typami języka C.s/\bfunc/_func/g
- „func” jest rozpoznawany jako słowo kluczowe przez cdecl - pomiń tosed Przetwarzanie końcowe:
s/^declare //
- usuń „deklaruj” na początku wierszas/as/is/
- oczywistes/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ępnegoW akcji:
źródło
s/\bfu/_fu/g
i zapisać bajty pełnegofunc
zastąpienia?as
(+4 bajty dla spacji do naprawienia). Nie mam dostępu,cdecl
ale myślę, że możesz zaoszczędzić 64 bajtysed -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
,152150148139137126 126125123 bajtówTrzecie podejście!
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 ...;
wtype (...)
. 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.Jeśli nasz pierwotny wkład był
float *((*p()))[16];
, teraz mamyfloat (*((*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.
Przykładowe kroki:
Sprzątać
Pozostało tylko przenieść typ na koniec i dodać „to”:
W przypadku takich definicji
int x;
, takie podejście spowoduje powstanie dodatkowej przestrzeni, na którą pozwala wyzwanie.źródło
JavaScript (ES6),
316...268253 bajtówWypróbuj online!
Skomentował
Funkcja pomocnika
Główną częścią
źródło
[...s.split`()`.join`!`]
zamiast po prostu[...s.replace('()','!')]
, ale zdałem sobie sprawę, że to dokładnie ta sama liczba bajtów .. :)s.replace('()','!')
że zastąpiłoby to tylko pierwsze wystąpienie..replace
zastępuje wszystkie wystąpienia i.replaceAll
zastę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.replaceAll
i.regexReplaceAll
tak dalej, ale sądzę, że dla codegolf jest krótszy jak.replace
i.replaceAll
.~
) zaraz po opublikowaniu pierwszej wersji mojej własnej odpowiedzi. Sądzę, że wielkie umysły myślą podobnie. : pCzysty , 415 bajtów
Wypróbuj online!
źródło
R ,
225218 bajtówWypró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 Reval
z przeciążonymi operatorami.źródło
Perl 6 ,
209190171162153 bajtówWypróbuj online!
Podejście rekurencyjne. Tworzy dodatkowe znaki spacji, których można uniknąć kosztem 3 bajtów .
Wyjaśnienie
źródło
JavaScript 250 bajtów [249?]
Wykorzystuje to 250 bajtów:
Wyjaśnienie:
Zasadniczo odczytuje z bufora
a
, który jest tokenizowanym wejściem. Ciągle przenosi tokeny z buforaa
do stosus
, 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.UWAGA
Jeśli dobrze rozumiem „Używaj spacji wszędzie między tokenami”:
jest technicznie ważny i wykorzystuje
249 bajtów
Zakładając, że pomiędzy każdym tokenem jest spacja.
źródło
Czerwony ,
418410 bajtówWypróbuj online!
Wyjaśnienie:
źródło
APL (NARS), znaki 625, bajty 1250
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:
źródło