INTERCAL (C-INTERCAL), 15 кодов, 313 + 2 = 315 байт
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
Попробуйте онлайн!
Все пробелы здесь не имеют значения. (Оригинальная программа содержала вкладки, но я преобразовал их в пробелы, чтобы они правильно совмещались в SE; для INTERCAL обычно используется ширина табуляции 8. Я протестировал версию программы со всеми вкладками, пробелами и новые строки удалены, хотя и работает нормально.)
Компилировать с -abm
(2-байтовое наказание, потому -b
что компилятор должен быть детерминированным).
Как обычно для INTERCAL, для этого требуется числовой ввод в формате, например, ONE TWO THREE
для 123
.
объяснение
Когда происходит ошибка программы C-INTERCAL, статусом выхода является код ошибки по модулю 256. В результате мы можем стремиться написать программу, способную выдавать как можно больше ошибок времени выполнения. Эта программа пропускает только две ошибки времени выполнения, которые не указывают на внутренние проблемы компилятора: ICL200I, потому что для его воспроизведения требуется использование внешних библиотек, которые совместимы только с однопоточной программой (а многопоточные программы имеют больше ошибок); и ICL533I, потому что 533 имеет то же значение по модулю 256, что и 277, и программа способна генерировать ICL277I.
Программа всегда запускается одинаково. Сначала мы вводим ( WRITE IN
) значение для переменной .1
. Затем мы используем вычисляемый CREATE
оператор для создания нового синтаксиса (здесь, A
); но поскольку он вычисляется, определение синтаксиса варьируется в зависимости от значения .1
. Наконец, в большинстве случаев мы запускаем наш новый A
оператор, который был определен, чтобы вызвать ошибку; таблица возможных определений, которую мы имеем, содержит определение для каждой возможной ошибки времени выполнения (кроме исключений, перечисленных выше).
Во-первых, есть два исключения из этой общей схемы. (0)
не является допустимым номером строки, поэтому, если пользователь вводит ZERO
, мы переходим со второй строки (пронумерованной (8)
) на четвертую строку с помощью вычисляемого COME FROM
оператора. Затем это приводит к синтаксической ошибке DO X
, которая приводит к ошибке ICL000I
. (В INTERCAL синтаксические ошибки возникают во время выполнения из-за тенденции отключать команды, переопределять синтаксис под вами и т. Д.). COME FROM
Утверждение также имеет побочный эффект, даже если фактическая COME FROM
не происходит, создавая перегрузку операнда из .1
к #1
всякий раз , когда строка с номером строки выполняется; это используется позже при создании вывода 21. (Случайные глобальные побочные эффекты довольно идиоматичны в INTERCAL.)
Другое исключение с вводом ONE TWO NINE
. В программе нет номера строки (129)
, поэтому мы получаем ошибку для отсутствующего номера строки ICL129I
. Поэтому мне не пришлось писать какой-либо код, чтобы покрыть этот случай вообще.
Вот другие ошибки и причины их возникновения:
- 123 -
NEXT
переполнение стека ( DO (123) NEXT
). NEXT
Утверждение нуждается в других модификаторов ( FORGET
или RESUME
) для того , чтобы задним числом определить , какого рода заявление управления было. Отсутствие этих причин приводит к ошибке ICL123I, если имеется 80 неразрешенных операторов `NEXT '.
- 222 - переполнение тайника (
DO STASH .2
в COME FROM
цикле). Тайники ограничены только доступной памятью, но это в конечном счете закончится, вызывая ошибку ICL222I.
- 240 - это размеры массива до нулевого размера. Это именно то, что
DO ,1 <- #0
означает, и это вызывает ошибку ICL240I.
- 241 вызвано присваиванием за пределы массива. В этом случае
,1
он не был выделен ( ,
используется для переменных типа массива в INTERCAL), поэтому его индексация вызывает ошибку ICL241I.
- 19 присваивает 65536 (
#256 $ #0
) 16-битной переменной .2
. Это не подходит, вызывая ошибку ICL275I.
- 21 правопреемников
#2
в .1
. Это может выглядеть как достаточно простое назначение, но мы перегружены, .1
чтобы означать #1
ранее, и попытка изменить значение 1 без -v
параметра в командной строке вызывает ошибку ICL277I.
- 148 пытается вернуться к верхнему элементу стека выбора точек (
GO BACK
), которого нет в данный момент в программе (мы не выполнили никаких команд для управления стеком точек выбора, поэтому он все еще пуст). Это вызывает ошибку ICL404I.
- 180 попыток
RETRIEVE .2
из несуществующего хранилища (потому что мы ничего не хранили там в этой ветке программы), вызывая ошибку ICL436I.
- 50 запросов input (
WRITE IN
) навсегда в COME FROM
цикле. В конечном итоге мы закончим чтение EOF, что приведет к ошибке ICL562I.
- 109 выполняет оператор
DO RESUME #0
, который не имеет смысла и специально задокументирован как вызывающий ошибку (ICL621I).
- 120 запускает заявление
DO RESUME #9
. Мы еще не NEXT
выполнили так много операторов, и поэтому получаем ошибку ICL120I. (Интересно, что эта конкретная ошибка определена в документации INTERCAL как выход из программы в нормальном режиме, а затем вызывает ошибку, а не выход из программы с ошибкой. Однако я не верю, что эти два случая заметно различаются.)
- 223 представляет собой сложный клубок многопоточных примитивов, которые все указывают на строку 223, вызывая бесконечный цикл, который взрывает память. В конце концов, в многопоточной подсистеме происходит исчерпание памяти, что приводит к ошибке ICL991I.
- 121 на самом деле является действительным утверждением (это комментарий), но он появляется в конце программы. Таким образом, выполнение программы прекращается сразу же после ее запуска, вызывая ошибку ICL633I.
верификация
Некоторые из ошибок связаны с преднамеренным запуском программы из памяти, поэтому я предлагаю установить довольно небольшие ограничения памяти. Вот команда оболочки, которую я использовал для тестирования программы (с добавлением новых строк для удобства чтения; удалите их, если вы запустите ее самостоятельно):
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
А вот вывод (с номерами строк и сообщениями «PLEASE CORRECT SOURCE», удаленными для экономии места), которые я добавил частично для демонстрации работы программы, но в основном для демонстрации глупых сообщений об ошибках 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