INTERCAL (C-INTERCAL), 15 codici, 313 + 2 = 315 byte
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
Provalo online!
Tutto lo spazio qui è irrilevante. (Il programma originale conteneva schede, ma le ho convertite in spazi in modo che si allineassero correttamente su SE; è convenzionale usare una larghezza di scheda di 8 per INTERCAL. Ho testato una versione del programma con tutte le schede, gli spazi e le nuove righe cancellate, tuttavia, e funziona bene.)
Compilare con -abm
(penalità di 2 byte, perché -b
è necessario che il compilatore sia deterministico).
Come al solito per INTERCAL, questo richiede un input numerico nel formato, ad es . ONE TWO THREE
Per 123
.
Spiegazione
Quando un programma C-INTERCAL si guasta, lo stato di uscita è il codice di errore modulo 256. Di conseguenza, possiamo mirare a scrivere un programma in grado di produrre il maggior numero possibile di errori di runtime. Questo programma omette solo due errori di runtime che non indicano problemi del compilatore interno: ICL200I, perché la riproduzione richiede l'uso di librerie esterne che sono compatibili solo con un programma a thread singolo (e i programmi multithread hanno più errori disponibili); e ICL533I, perché 533 ha lo stesso valore modulo 256 di 277 e il programma è in grado di produrre ICL277I.
Il programma si avvia sempre allo stesso modo. Innanzitutto, inseriamo ( WRITE IN
) un valore per la variabile .1
. Quindi, usiamo CREATE
un'istruzione calcolata per creare una nuova sintassi (qui, A
); ma poiché è calcolato, la definizione della sintassi varia in base al valore di .1
. Infine, nella maggior parte dei casi eseguiamo la nostra nuova A
dichiarazione, che è stata definita per produrre un errore; la tabella delle possibili definizioni che abbiamo contiene una definizione per ogni possibile errore di runtime (tranne le eccezioni sopra elencate).
Innanzitutto, ci sono due eccezioni a questo schema generale. (0)
non è un numero di riga valido, quindi se l'utente inserisce ZERO
, passiamo dalla seconda riga (numerata (8)
) alla quarta riga mediante COME FROM
un'istruzione calcolata . Questo quindi si traduce in un errore di sintassi DO X
, che produce errori ICL000I
. (In INTERCAL, errori di sintassi si verificano in fase di esecuzione, a causa della tendenza dei comandi a essere disabilitati, alla sintassi da ridefinire sotto di te, ecc.). L' COME FROM
affermazione ha anche un effetto collaterale, anche se non effettivo COME FROM
accade, creando un sovraccarico operando da .1
a #1
quando viene eseguita una linea con un numero di riga; questo viene usato in seguito durante la produzione dell'uscita 21. (Gli effetti collaterali globali casuali sono abbastanza idiomatici in INTERCAL.)
L'altra eccezione è con l'input ONE TWO NINE
. Non esiste un numero di riga (129)
nel programma, quindi viene visualizzato un errore per un numero di riga mancante, ovvero ICL129I
. Quindi non ho dovuto scrivere alcun codice per coprire quel caso.
Ecco gli altri errori e cosa li causa:
- 123 è uno
NEXT
stack overflow ( DO (123) NEXT
). L' NEXT
istruzione necessita di altri modificatori ( FORGET
o RESUME
) per determinare retroattivamente quale tipo di istruzione di controllo fosse. Non avendo queste cause si verifica l'errore ICL123I una volta che ci sono 80 istruzioni NEXT non risolte.
- 222 è un overflow stash (
DO STASH .2
in un COME FROM
ciclo). Gli stash sono limitati solo dalla memoria disponibile, ma alla fine si esauriranno, causando l'errore ICL222I.
- 240 è dimensioni un array per dimensione zero. Questo è esattamente ciò che
DO ,1 <- #0
significa e causa l'errore ICL240I.
- 241 è causato dall'assegnazione al di fuori dei limiti di un array. In questo caso,
,1
non è stato allocato ( ,
viene utilizzato per le variabili di tipo array in INTERCAL), quindi l'indicizzazione causa l'errore ICL241I.
- 19 assegna 65536 (
#256 $ #0
) a una variabile a 16 bit .2
. Non si adatta, causando errore ICL275I.
- 21 assegna
#2
a .1
. Potrebbe sembrare un compito abbastanza semplice, ma abbiamo sovraccarico .1
di significato in #1
precedenza e il tentativo di modificare il valore di 1 senza alcuna -v
opzione sulla riga di comando provoca l'errore ICL277I.
- 148 tentativi di tornare alla voce principale dello stack choicepoint (
GO BACK
), che non esiste a questo punto nel programma (non abbiamo eseguito alcun comando per manipolare lo stack choicepoint, quindi è ancora vuoto). Ciò causa l'errore ICL404I.
- 180 tentativi di eseguire
RETRIEVE .2
uno stash inesistente (perché non abbiamo nascosto nulla in questo ramo del programma), causando l'errore ICL436I.
- 50 richieste input (
WRITE IN
) per sempre in un COME FROM
ciclo. Alla fine finiremo per leggere EOF passato, causando l'errore ICL562I.
- 109 esegue l'istruzione
DO RESUME #0
, che è insignificante e specificamente documentata come causa di un errore (ICL621I).
- 120 esegue la dichiarazione
DO RESUME #9
. Non abbiamo ancora eseguito così tante NEXT
dichiarazioni e quindi otteniamo l'errore ICL120I. (Curiosamente, questo particolare errore è definito nella documentazione INTERCAL come uscire normalmente dal programma e quindi causare l'errore, piuttosto che uscire dal programma con un errore. Non credo che questi due casi siano notevolmente diversi, però.)
- 223 è fondamentalmente un groviglio complesso di primitive multithreading che puntano tutte alla linea 223, causando un loop infinito che fa esplodere la memoria. Alla fine, c'è un esaurimento della memoria nel sottosistema multithreading, che porta all'errore ICL991I.
- 121 è in realtà una dichiarazione valida (è un commento), ma appare alla fine del programma. Pertanto, l'esecuzione cade alla fine del programma immediatamente dopo l'esecuzione, causando l'errore ICL633I.
Verifica
Alcuni errori implicano l'esecuzione intenzionale della memoria del programma, quindi suggerisco di impostare limiti di memoria abbastanza piccoli. Ecco il comando shell che ho usato per testare il programma (con le nuove righe aggiunte per la leggibilità; eliminale se lo esegui da solo):
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
Ed ecco l'output (con i numeri di riga e i messaggi "PLEASE CORRECT SOURCE" cancellati per risparmiare spazio), che ho aggiunto in parte per dimostrare il funzionamento del programma ma soprattutto per mostrare i messaggi di errore stupidi di 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