INTERCAL (C-INTERCAL), 15 kodów, 313 + 2 = 315 bajtów
PLEASE WRITE IN .1
(8) PLEASE CREATE .1 A
PLEASE A
PLEASE COME FROM #2$!1/#1'
DO X
(123) DO (123) NEXT
DO COME FROM (222)
(222) DO STASH .2
(240) DO ,1 <- #0
(241) DO ,1 SUB #0 <- #1
(19) DO .2 <- #256 $ #0
(21) DO .1 <- #2
(148) DO GO BACK
(180) DO RETRIEVE .2
DO COME FROM (50)
(50) DO WRITE IN .2
(109) DO RESUME #0
(120) DO RESUME #9
MAYBE COME FROM (223)
(223) DO COME FROM (223)
(121) PLEASE NOT X
Wypróbuj online!
Cała biała spacja tutaj nie ma znaczenia. (Oryginalny program zawierał tabulatory, ale przekonwertowałem je na spacje, aby poprawnie wyrównały się w SE; w INTERCAL zwykle używa się tabulacji o szerokości 8. Testowałem wersję programu ze wszystkimi tabulatorami, spacjami , i nowe wiersze zostały jednak usunięte i działa dobrze).
Kompiluj z -abm
(kara 2 bajty, ponieważ -b
jest wymagana, aby kompilator był deterministyczny).
Jak zwykle w przypadku INTERCAL, wymaga to wprowadzania danych liczbowych w formacie, np . ONE TWO THREE
Dla 123
.
Wyjaśnienie
W przypadku błędu programu C-INTERCAL stanem wyjścia jest kod błędu modulo 256. W rezultacie możemy dążyć do napisania programu, który jest w stanie wygenerować jak najwięcej błędów w czasie wykonywania. Ten program pomija tylko dwa błędy środowiska wykonawczego, które nie wskazują na wewnętrzne problemy z kompilatorem: ICL200I, ponieważ jego odtworzenie wymaga użycia bibliotek zewnętrznych, które są kompatybilne tylko z programem jednowątkowym (a programy wielowątkowe mają więcej dostępnych błędów); i ICL533I, ponieważ 533 ma taką samą wartość modulo 256 jak 277, a program jest w stanie wygenerować ICL277I.
Program zawsze zaczyna się w ten sam sposób. Najpierw wprowadzamy ( WRITE IN
) wartość zmiennej .1
. Następnie używamy CREATE
instrukcji obliczeniowej do utworzenia nowej składni (tutaj, A
); ale ponieważ jest obliczona, definicja składni różni się w zależności od wartości .1
. Wreszcie, w większości przypadków uruchamiamy naszą nową A
instrukcję, która została zdefiniowana w celu generowania błędu; tabela możliwych definicji zawiera definicję każdego możliwego błędu środowiska wykonawczego (oprócz wyjątków wymienionych powyżej).
Po pierwsze, istnieją dwa wyjątki od tego ogólnego schematu. (0)
nie jest poprawnym numerem wiersza, więc jeśli użytkownik wprowadzi dane ZERO
, przeskakujemy z drugiego wiersza (numerowanego (8)
) do czwartego wiersza za pomocą COME FROM
instrukcji obliczeniowej . To następnie przechodzi w błąd składniowy DO X
, który powoduje błąd ICL000I
. (W INTERCAL błędy w składni zdarzają się w czasie wykonywania, ze względu na tendencję do wyłączania poleceń, zmiany składni pod tobą itp.). COME FROM
Stwierdzenie ma również efekt uboczny, nawet jeśli nie rzeczywiste COME FROM
dzieje, tworząc przeciążenie operandu od .1
celu #1
, gdy linia z numerem linii jest wykonywana; jest to wykorzystywane później przy tworzeniu wyniku 21. (Losowe globalne skutki uboczne są dość idiomatyczne w INTERCAL).
Innym wyjątkiem jest wejście ONE TWO NINE
. W programie nie ma numeru linii (129)
, więc otrzymujemy błąd dotyczący brakującego numeru linii, czyli ICL129I
. Nie musiałem więc pisać żadnego kodu, by w ogóle opisać tę sprawę.
Oto inne błędy i ich przyczyny:
- 123 jest
NEXT
przepełnieniem stosu ( DO (123) NEXT
). NEXT
Oświadczenie potrzebuje innych modyfikatorów ( FORGET
lub RESUME
), aby z mocą wsteczną ustalenia, jakiego rodzaju instrukcji sterującej było. Brak tych przyczyn powoduje błąd ICL123I, gdy pojawi się 80 nierozwiązanych instrukcji `NEXT.
- 222 jest przepełnieniem skrytki (
DO STASH .2
w COME FROM
pętli). Skrytki są ograniczone tylko dostępną pamięcią, ale ostatecznie się skończy, powodując błąd ICL222I.
- 240 to wymiary tablicy do rozmiaru zero. Dokładnie to
DO ,1 <- #0
oznacza i powoduje błąd ICL240I.
- 241 jest spowodowane przez przypisywanie poza granicami tablicy. W tym przypadku
,1
nie został przydzielony ( ,
służy do zmiennych typu tablicowego w INTERCAL), więc indeksowanie powoduje błąd ICL241I.
- 19 przypisuje 65536 (
#256 $ #0
) zmiennej 16-bitowej .2
. Nie pasuje, powodując błąd ICL275I.
- 21 przypisuje
#2
do .1
. Może to wyglądać na dość proste przypisanie, ale przeciążaliśmy .1
to, co #1
wcześniej, i próba zmiany wartości 1 bez -v
opcji w wierszu poleceń powoduje błąd ICL277I.
- 148 próbuje wrócić do górnego wpisu stosu wyboru punktów (
GO BACK
), który nie istnieje w tym momencie w programie (nie uruchomiliśmy żadnych poleceń w celu manipulowania stosem wyboru punktów, więc nadal jest pusty). To powoduje błąd ICL404I.
- 180 prób
RETRIEVE .2
z nieistniejącej skrytki (ponieważ nie ukryliśmy niczego w tej gałęzi programu), powodując błąd ICL436I.
- 50 żądań input (
WRITE IN
) na zawsze w COME FROM
pętli. W końcu skończymy czytać poza EOF, powodując błąd ICL562I.
- 109 uruchamia instrukcję
DO RESUME #0
, która jest pozbawiona znaczenia i szczegółowo udokumentowana jako powodująca błąd (ICL621I).
- 120 uruchamia instrukcję
DO RESUME #9
. Nie uruchomiliśmy jeszcze tak wielu NEXT
instrukcji, dlatego otrzymujemy błąd ICL120I. (Intrygujące jest to, że ten konkretny błąd jest zdefiniowany w dokumentacji INTERCAL jako normalne wyjście z programu, a następnie spowodowanie błędu, zamiast wyjścia z programu z błędem. Nie sądzę jednak, aby te dwa przypadki były zauważalnie różne.)
- 223 jest w zasadzie złożoną plątaniną prymitywów wielowątkowych, które wszystkie wskazują z powrotem na linię 223, powodując nieskończoną pętlę, która wysadza pamięć. Ostatecznie wyczerpuje się pamięć w podsystemie wielowątkowym, co prowadzi do błędu ICL991I.
- 121 jest w rzeczywistości prawidłową instrukcją (jest to komentarz), ale pojawia się na końcu programu. W związku z tym wykonanie spada z końca programu natychmiast po jego uruchomieniu, powodując błąd ICL633I.
Weryfikacja
Niektóre błędy obejmują celowe uruchamianie programu z pamięci, dlatego sugeruję ustawienie dość małych limitów pamięci. Oto polecenie powłoki, którego użyłem do przetestowania programu (z nowymi wierszami dodanymi dla czytelności; usuń je, jeśli sam go uruchomisz):
for x in "ZERO" "ONE NINE" "TWO ONE" "FIVE ZERO" "ONE ZERO NINE"
"ONE TWO ZERO" "ONE TWO ONE" "ONE TWO THREE" "ONE TWO NINE"
"ONE FOUR EIGHT" "ONE EIGHT ZERO" "TWO TWO TWO"
"TWO TWO THREE" "TWO FOUR ZERO" "TWO FOUR ONE";
do echo;
echo $x;
echo $x | (ulimit -Sd 40000; ulimit -Sv 40000; ulimit -Ss 40000;
./errors; echo $?);
done
A oto wynik (z numerami wierszy i komunikatami „PROSZĘ PRAWIDŁOWE ŹRÓDŁO” usunięty, aby zaoszczędzić miejsce), który dodałem częściowo, aby zademonstrować działanie programu, ale głównie, aby pokazać głupie komunikaty o błędach INTERCAL:
ZERO
ICL000I PLEASEWRITEIN.1(8)PLEASECREATE.1APLEASEAPLEASECOMEFROM#2$!1/#1'DOX(123)DO(123)NEXTDOCOMEFROM(222)(222)DOSTASH.2(240)DO,1<-#0(241)DO,1SUB#0<-#1(19)DO.2<-#256$#0(21)DO.1<-#2(148)DOGOBACK(180)DORETRIEVE.2DOCOMEFROM(50)(50)DOWRITEIN.2(109)DORESUME#0(120)DORESUME#9MAYBECOMEFROM(223)(223)DOCOMEFROM(223)(121)PLEASENOTX
0
ONE NINE
ICL275I DON'T BYTE OFF MORE THAN YOU CAN CHEW
19
TWO ONE
ICL277I YOU CAN ONLY DISTORT THE LAWS OF MATHEMATICS SO FAR
21
FIVE ZERO
ICL562I I DO NOT COMPUTE
50
ONE ZERO NINE
ICL621I ERROR TYPE 621 ENCOUNTERED
109
ONE TWO ZERO
ICL632I THE NEXT STACK RUPTURES. ALL DIE. OH, THE EMBARRASSMENT!
120
ONE TWO ONE
ICL633I PROGRAM FELL OFF THE EDGE
121
ONE TWO THREE
ICL123I PROGRAM HAS DISAPPEARED INTO THE BLACK LAGOON
123
ONE TWO NINE
ICL129I PROGRAM HAS GOTTEN LOST
129
ONE FOUR EIGHT
ICL404I I'M ALL OUT OF CHOICES!
148
ONE EIGHT ZERO
ICL436I THROW STICK BEFORE RETRIEVING!
180
TWO TWO TWO
ICL222I BUMMER, DUDE!
222
TWO TWO THREE
ICL991I YOU HAVE TOO MUCH ROPE TO HANG YOURSELF
223
TWO FOUR ZERO
ICL240I ERROR HANDLER PRINTED SNIDE REMARK
240
TWO FOUR ONE
ICL241I VARIABLES MAY NOT BE STORED IN WEST HYPERSPACE
241