INTERCAL (C-INTERCAL), 15 códigos, 313 + 2 = 315 bytes
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
Experimente online!
Todo espaço em branco aqui é irrelevante. (O programa original continha guias, mas eu as converti em espaços para que se alinhassem corretamente no SE; é convencional usar uma largura de guia 8 para INTERCAL. Testei uma versão do programa com todas as guias, espaços , e novas linhas excluídas, e funciona bem.)
Compile com -abm
(penalidade de 2 bytes, porque -b
é necessário para o compilador ser determinístico).
Como de costume para INTERCAL, isso requer entrada numérica no formato, por exemplo, ONE TWO THREE
para 123
.
Explicação
Quando um programa C-INTERCAL erra, o status de saída é o código de erro módulo 256. Como resultado, podemos ter como objetivo escrever um programa capaz de produzir o maior número possível de erros de tempo de execução. Este programa omite apenas dois erros de tempo de execução que não indicam problemas internos do compilador: ICL200I, porque sua reprodução requer o uso de bibliotecas externas que são compatíveis apenas com um programa de thread único (e os programas multithread têm mais erros disponíveis); e ICL533I, porque 533 tem o mesmo valor de módulo 256 que 277 e o programa é capaz de produzir ICL277I.
O programa sempre começa da mesma maneira. Primeiro, inserimos ( WRITE IN
) um valor para a variável .1
. Então, usamos uma CREATE
declaração computada para criar nova sintaxe (aqui, A
); mas, como é calculado, a definição da sintaxe varia com base no valor de .1
. Finalmente, na maioria dos casos, executamos nossa nova A
instrução, que foi definida para produzir um erro; a tabela de definições possíveis que temos contém uma definição para cada possível erro de tempo de execução (além das exceções listadas acima).
Primeiro, existem duas exceções a esse esquema geral. (0)
não é um número de linha válido; portanto, se o usuário inserir ZERO
, passamos da segunda linha (numerada (8)
) para a quarta linha por meio de uma COME FROM
instrução computada . Isso então cai em um erro de sintaxe DO X
, que produz um erro ICL000I
. (No INTERCAL, os erros de sintaxe ocorrem no tempo de execução, devido à tendência de os comandos serem desabilitados, a sintaxe ser redefinida sob você, etc.). A COME FROM
instrução também tem um efeito colateral, mesmo que nada real COME FROM
aconteça, criando uma sobrecarga de operando de .1
para #1
sempre que uma linha com um número de linha for executada; isso é usado posteriormente ao produzir a saída 21. (Efeitos colaterais globais aleatórios são bastante idiomáticos em INTERCAL.)
A outra exceção é com entrada ONE TWO NINE
. Como não há número de linha (129)
no programa, obtemos um erro para um número de linha ausente ICL129I
. Portanto, não precisei escrever nenhum código para cobrir esse caso.
Aqui estão os outros erros e o que os causa:
- 123 é um
NEXT
estouro de pilha ( DO (123) NEXT
). A NEXT
instrução precisa de outros modificadores ( FORGET
ou RESUME
) para determinar retroativamente que tipo de instrução de controle era. Não ter o erro ICL123I dessas causas, uma vez que existem 80 instruções `NEXT não resolvidas.
- 222 é um estouro de estoque (
DO STASH .2
em um COME FROM
loop). Os stashes são limitados apenas pela memória disponível, mas isso acabará eventualmente, causando o erro ICL222I.
- 240 é dimensões de uma matriz para o tamanho zero. É exatamente isso que
DO ,1 <- #0
significa e causa o erro ICL240I.
- 241 é causado pela atribuição fora dos limites de uma matriz. Nesse caso,
,1
não foi alocado ( ,
é usado para variáveis do tipo matriz em INTERCAL), portanto, a indexação causa o erro ICL241I.
- 19 atribui 65536 (
#256 $ #0
) a uma variável de 16 bits .2
. Não se encaixa, causando o erro ICL275I.
- 21 atribui
#2
a .1
. Isso pode parecer uma atribuição bastante simples, mas sobrecarregamos .1
para significar #1
mais cedo, e tentar alterar o valor de 1 sem -v
opção na linha de comandos causa o erro ICL277I.
- 148 tentativas de retornar à entrada superior da pilha do ponto de escolha (
GO BACK
), que não existe neste momento no programa (não executamos nenhum comando para manipular a pilha do ponto de escolha, portanto ela ainda está vazia). Isso causa o erro ICL404I.
- 180 tentativas de
RETRIEVE .2
partir de um stash inexistente (porque não escondemos nada nesse ramo do programa), causando o erro ICL436I.
- 50 solicita input (
WRITE IN
) para sempre em um COME FROM
loop. Eventualmente, acabaremos lendo EOF passado, causando o erro ICL562I.
- 109 executa a instrução
DO RESUME #0
, que não tem sentido e está especificamente documentada como causando um erro (ICL621I).
- 120 executa a declaração
DO RESUME #9
. Ainda não executamos tantas NEXT
instruções e, portanto, obtemos o erro ICL120I. (Curiosamente, esse erro específico é definido na documentação INTERCAL como sair do programa normalmente e depois causar o erro, em vez de sair do programa com um erro. Porém, não acredito que esses dois casos sejam notavelmente diferentes.)
- 223 é basicamente um emaranhado complexo de primitivas multithreading que apontam para a linha 223, causando um loop infinito que explode memória. Eventualmente, há exaustão de memória no subsistema multithreading, levando ao erro ICL991I.
- 121 é realmente uma declaração válida (é um comentário), mas aparece no final do programa. Como tal, a execução cai no final do programa imediatamente após a execução, causando o erro ICL633I.
Verificação
Alguns dos erros envolvem a execução intencional da memória do programa, por isso sugiro definir limites de memória bastante pequenos. Aqui está o comando shell que eu usei para testar o programa (com novas linhas adicionadas para facilitar a leitura; exclua-as se você executá-lo):
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
E aqui está a saída (com os números de linha e as mensagens "POR FAVOR CORRETA SOURCE" excluídas para economizar espaço), que adicionei parcialmente para demonstrar o funcionamento do programa, mas principalmente para mostrar as mensagens de erro tolas da 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