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上正确对齐;按惯例,将制表符宽度设置为8用于INTERCAL。我已经测试了该程序的所有制表符,空格的版本,但删除了换行符,效果很好。)
进行编译-abm
(2个字节的代价,因为-b
编译器必须确定性)。
与INTERCAL一样,这通常采用数字输入格式,例如ONE TWO THREE
for 123
。
说明
当C-INTERCAL程序出错时,退出状态为错误代码模256。因此,我们的目标是编写一个能够产生尽可能多的运行时错误的程序。该程序仅忽略了两个运行时错误,这些错误并不表示内部编译器问题:ICL200I,因为对其进行再现需要使用仅与单线程程序兼容的外部库(并且多线程程序具有更多可用错误);和ICL533I,因为533与277具有相同的模256值,并且该程序能够产生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中是相当惯用的。)
另一个例外是input ONE TWO NINE
。(129)
程序中没有行号,因此对于缺少的行号会出现错误ICL129I
。因此,我根本不必编写任何代码来涵盖这种情况。
以下是其他错误以及导致这些错误的原因:
- 123是
NEXT
堆栈溢出(DO (123) NEXT
)。该NEXT
语句需要其他修饰符(FORGET
或RESUME
),以便追溯确定它是哪种控制语句。一旦有80条未解决的`NEXT语句,则没有这些将导致错误ICL123I。
- 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
,并且-v
在命令行上尝试不带任何选项的情况下更改值1 会导致错误ICL277I。
- 148次尝试返回选择点堆栈(
GO BACK
)的顶部条目,该条目在程序中目前不存在(我们没有运行任何命令来操纵选择点堆栈,因此它仍然为空)。这将导致错误ICL404I。
RETRIEVE .2
从不存在的存储中进行180次尝试(因为我们没有在程序的此分支中存储任何内容),导致错误ICL436I。
- 50
WRITE IN
永远COME FROM
循环请求输入()。最终,我们最终将读取超过EOF的值,从而导致错误ICL562I。
- 109运行该语句
DO RESUME #0
,该语句无意义,并且具体记录为导致错误的语句(ICL621I)。
- 120运行语句
DO RESUME #9
。我们尚未运行那么多NEXT
语句,因此我们收到错误ICL120I。(有趣的是,此特殊错误在INTERCAL文档中定义为正常退出程序,然后导致错误,而不是错误退出程序。不过,我认为这两种情况没有明显区别。)
- 223本质上是多线程基元的复杂缠结,它们都指向第223行,从而导致死循环,从而耗尽内存。最终,多线程子系统中的内存耗尽,从而导致错误ICL991I。
- 121实际上是一个有效的语句(它是一个注释),但是它出现在程序的末尾。因此,执行在执行后立即从程序结尾处掉落,从而导致错误ICL633I。
验证
一些错误涉及故意使程序内存不足,因此我建议设置相当小的内存限制。这是我用来测试程序的shell命令(添加了换行符以提高可读性;如果您自己运行它,请将其删除):
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
这是输出(删除了行号和“请更正源”消息以节省空间),我添加了一部分以演示程序的工作,但主要是为了炫耀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