20xx年,没书读的 Bardisk 考了本教资当起了小学老师。
今天他要给同学们关于科普图灵机的常识,为形象生动起见,他搬来了一个「图灵机教具」。
实际的图灵机的行为很难被同学们直观理解,因此这一个教具并不是一个严格意义上的图灵机,而只是一个与之相似的模型。
具体来说,该模型具备两条可以滚动、且嵌在纸带筒里的纸带(注意不是纸环,不能无限滚动下去,也不会循环)。每个纸带筒上有一个固定不动的指针,指向纸带筒的中间位置(以及目前停留在纸带筒中间位置的那段纸带)。因此,随着纸带的滚动,指针指向的纸带位置也会不断改变。同时,每条纸带被分成 512 个长度一样的格子,而在初始状态时,纸带筒上的指针指向纸带最左侧的一格。
不过,这两条纸带上的内容并不一样——其中一条纸带叫做「program」,即程序纸带。另一条纸带叫做「data」,即数据纸带。程序纸带的每一格上都画着一个符号,而数据纸带的每一格上都写着两位的十六进制数。起初,程序纸带由用户写好,而数据纸带上全部都是 0。
模型还有一个可供写入的纸板,和一个纸板输出口,以及一个模式转换开关,对应「数字模式」和「字符模式」,初始时模型在数字模式。
接下来,为了描述简便,我们将当前数据纸带筒指针指向的数字称为「当前数字」,并将当前程序纸带筒指针指向的符号称为「当前符号」,将目前模式转换开关状态对应的模式称为「当前模式」。
当模型开始运行时,模型会首先检查当前符号,根据其类型进行操作:
+:模型会计算出当前数字 的结果,然后将这个数覆写到纸带的对应位置上。
-:模型会计算出当前数字 的结果,然后将这个数覆写到纸带的对应位置上。
<:模型会将数据纸带顺时针(指针相对纸带向左移动)转动一格。
>:模型会将数据纸带逆时针(指针相对纸带向右移动)转动一格。
[:模型会检查当前数字。如果当前数字非零,那么什么也不做;否则,模型会一直逆时针滚动程序纸带,直到碰到程序纸带上与这个 [ 相匹配的 ] 才停止(注意此处的匹配指的是滚动到此处时,指针遇见的 [ 和 ] 一样多)。
]:模型会检查当前数字。如果当前数字为零,那么什么也不做;否则,模型会一直顺时针滚动程序纸带,直到碰到程序纸带上与这个 ] 相匹配的 [ 才停止(注意此处的匹配指的是滚动到此处时,指针遇见的 [ 和 ] 一样多)。
.:如果当前模式是字符模式,那么模型会根据 ASCII 码表把当前数字编码为 ASCII 字符后写到一个纸板上,并从纸板出口排出;如果当前模式是数字模式,模型会把当前数字直接写在纸板上排出。
,:如果当前模式是字符模式,那么模型会首先通知用户在输入纸板处写下一个字符,此后模型将写下的字符按 ASCII 解码为数字覆写到当前数字对应的纸带位置上;如果当前模式是数字模式,那么模型会通知用户写下一个两位的十六进制数字,然后将它覆写到当前数字对应的纸带位置上。
#:模型会拨动模式转换开关,改变当前的模式。
!:终止运行并复位。
在按照当前符号做完上述操作以后,模型会逆时针滚动一次程序纸带,使得指针相对纸带向右移动一格。
当然,模型在运行时会由于程序纸带没有被妥善编写而出现错误,在出现错误以后,模型会直接通知用户发生了错误和发生的错误类型,随后停止运行并复位纸带。可能的错误类型有:
DATA_OUT_OF_BOUND:数据纸带无法继续滚动(在指针抵达边界的情况下向边界方向继续移动)。
PROGRAM_OUT_OF_BOUND:程序纸带无法继续滚动(在指针抵达边界的情况下向边界方向继续移动)。
INVALID_USER_INPUT:根据当前模式,用户的输入是非法的。
UNEXPECTED_END_OF_INPUT:请求输入,但用户不再给出输入。
NOT_PRINTABLE:在字符模式下,输出解码得到的字符不是一个 ASCII 可打印字符(\n 除外)。
Bardisk 不擅长编程,尤其是面对这种神秘的「编程语言」,更是无所适从,因此他首先希望你编写一个解释器,能够在给定程序纸带内容时,模拟模型的运行并给出模型在停机或报错前的输出。