练习15A、15B和15C不分先后学习顺序。
在这一课中,你将完成一个长而复杂的问题,我们已经把它分解成了几个部分,所以可以分部完成。本课还将介绍str.split()
,它是一个有用的分割字符串的方法:删除所有的空格,然后返还一个字符串中所有单词的序列,并且原始字符串不会被修改。
你可以调用split() 并加上特殊的参数来做更复杂的分割,但目前我们不需要这么做。如果感兴趣的话,可以查看一下Python文档. |
现在我们需要完成第一步。旧的编程语言 BASIC 因其带有编号的代码行和goto
语句而出名。对于这个练习,你将创建一个带有下面这些功能的BASIC简单版。具体来说,程序的输入将由下面格式中的几行组成
«label» goto «target»
«label»
和«target»
都是正整数。label(标签)就像是这一行的名字或者地址;所有的标签都是唯一的。target(目标)会告诉你需要移动到的下一行代码的标签是什么。程序的最后一行是«label» END
,表明一旦运行到这一行,程序就应该停止。下面是一个BASIC程序的示例:
5 GOTO 30 10 GOTO 20 20 GOTO 10 30 GOTO 40 40 END当这个BASIC程序运行时,我们在第一行(标签5)处开始。标签5这行代码的目标是30,所以下一步我们前往标签为30的这一行。然后30这一行告诉我们去标签为40的代码行。最后这行代码告诉我们程序结束。所以,程序就终止了。
另一方面,一个BASIC程序也可以循环。这里是一个例子:
10 GOTO 21 21 GOTO 37 37 GOTO 21 40 END该程序在第10行开始,但它会永远在21和37行之间循环。
你的任务 是要编写一个Python程序, 它可以读入一个BASIC程序作为输入。如果程序终止,你的程序应该打印success
。如果程序进入一个无限循环,程序应该打印infinite loop
。假设每个目标都有有效的标签,所有的标签都是独一无二的。所以不必检查。
有几种不同的方法可以做到这一点。但在这一课中,我们选择一个简单的方法,并把它分解成3个子任务(课程15C中有一个比较大的问题,你需要自己设计子任务)。
子任务1: 读取程序
想要读取BASIC程序,我们需要不停地调用input()
。但是,当我们达到最后一行BASIC代码(带有END
的那一行)的时候,我们要停止调用input()
来避免EOFError
。
子任务2: Go to it!
一旦读取了这个程序,我们就需要能够在程序中跳跃到另一行。要做到这一点,你需要完成以下子程序。
子任务3: 智能模拟
在前两个练习中,我们完成了输入程序和搜寻任务。这将有助于主程序的编写并使
其更加简练。然而,仍然有一个主要的问题要解决:如何才能真正解决最初的问题?最简单的方法是模拟BASIC程序的运行:
- 让
prog
作为BASIC程序 (一个字符串列表) - 开始名为
location
的计数变量;因为我们是从程序的第一行开始,所以设定初始值为0 - 正确时,
- 如果
prog[location]
是结束行,返还"success"并终止。 - 让
T
作为在prog[location]
中指出的目标字符串 - 让
findLine(prog, T)
作为location
的新值
- 如果
但是还有一个主要问题没有解决:无法检测无限循环,如果BASIC程序有一个无限循环,那么Python程序也将永远循环。而我们想要的是:在这种情况下,该程序打印“无限循环”。我们把这个问题留给你解决,但是会给你一个提示。
整合
要测试你的代码,复制并粘贴你以前的答案到下面的模板中。
如果你使用的编程语言再稍微复杂一点,那么你是不可能写出一个关于这个语言的终止检查程序的。这是计算机科学中最早的一个重要定理,这个定理在19世纪30年代被艾伦-图灵证明,现在人们将这个结果称为"这个停机问题是不可判定的。" |