这一整个作业真是一整个大 e m o emo emo,我就那个第六题零零碎碎写了四天。
其实写完了整个作业才发现,这个作业的前五关有些逻辑是有问题的,具体的要写完六七关才能明白。
先说一下这个 T O Y TOY TOY计算机让各位对整个作业有一个理解:
我们想模拟一个计算机,具体思路是用 P y t h o n Python Python编译一个 t o y toy toy的文件,就是我们写一个程序去执行一个程序。
具体点的话,我们维护两块内存,一块 m e m mem mem,一块 r e g reg reg,我们把要编译的程序从 a d d r e s s address address开始放进 m e m mem mem里,每次把想编译的那一行暂时存进 i R e g iReg iReg, p R e g pReg pReg表示的是现在正在编译的地址是多少。
剩下的就是根据不同的函数单独写就行了。
没啥说的,但是这个题其实有问题,因为 m e m mem mem和 i R e g iReg iReg里面是字符串。
#初始化
def init():
########## Begin ##########
mem = [0] * 1000 #主存,1000个单元
reg = [0] * 10 #通用寄存器,10个
pReg = 0 #程序计数器,1个
iReg = 0 #指令寄存器,1个
########## End ##########
print(mem,reg,pReg,iReg)
这个题就是说一下如何开启文件和读取,同时我们规范了 m e m mem mem里面存放待编译代码的格式,为了后续的 t o y toy toy计算机处理起来方便一点。
#程序加载
def loadProgram(file, mem, address):
########## Begin ##########
txt = open(file, 'r')
s = txt.readlines()
for x in s :
l = len(x)
bg, L = 0, []
while bg <= l - 1 :
mdl = ''
flag = False
while x[bg] != ' ' :
mdl = mdl + x[bg]
bg += 1
if bg == l - 1 :
flag = True
break
while x[bg] == ' ' :
if bg == l - 1 :
flag = True
break
bg += 1
L.append(mdl)
if flag :
break
# L
L.pop(0)
mem[address] = ' '.join(L)
address = address + 1
########## End ##########
print(mem)
这个题的逻辑其实很奇怪,他那个 p R e g pReg pReg其实明明是个全局变量,但是他偏偏要在这个函数里设置一个也叫 p R e g pReg pReg的局部变量,也就是说这个代码里面的 p R e g pReg pReg和全局变量里面的 p R e g pReg pReg不是一个东西。可能有点儿绕,自己理解一下吧。
#取指令:根据程序计数器给出的地址取出主存对应的指令放入指令寄存器
def fetch(mem, pReg):
########## Begin ##########
#print(pReg)
iReg = mem[pReg]
pReg = pReg + 1
########## End ##########
print(iReg)
return pReg, iReg
这个题真是有一个大病,他非要我们输出左右是括号,那我们只好重新定义一下输出好了。
#指令译码:解析指令寄存器中的指令
def decode(iReg):
########## Begin ##########
l = len(iReg)
cnt, i = 0, 0
L = []
while i < l :
while i < l and iReg[i] == ' ' :
i = i + 1
if i == l :
break;
cnt = cnt + 1; mdl = ''
while i < l and iReg[i] != ' ' :
mdl = mdl + iReg[i]
i = i + 1
if cnt > 1 :
bg = 0
while bg < len(mdl) and mdl[bg] == '0' :
bg = bg + 1
mdl = mdl[bg : ]
L.append(mdl)
while cnt < 3 :
L.append('None')
cnt = cnt + 1
ret = '(' + "'" + L[0] + "'" + ',' + ' ' + L[1] + ',' + ' ' + L[2] + ')'
return ret
########## End ##########
这个题比较考验我们的理解,我们需要在跳转操作中,将 i R e g iReg iReg中存好对应的带编译的那一行代码即可。
#执行和写结果
def execute(opcode, op1, op2, reg, mem, pReg):
########## Begin ##########
global iReg
if opcode == 'mov1' :
reg[op1] = eval(mem[op2])
result = reg[op1]
elif opcode == 'mov2' :
mem[op1] = str(reg[op2])
result = mem[op1]
elif opcode == 'mov3' :
reg[op1] = op2
result = reg[op1]
elif opcode == 'add' :
reg[op1] += reg[op2]
result = reg[op1]
elif opcode == 'sub' :
reg[op1] -= reg[op2]
result = reg[op1]
elif opcode == 'mul' :
reg[op1] *= reg[op2]
result = reg[op1]
elif opcode == 'div' :
reg[op1] = reg[op1] // reg[op2]
result = reg[op1]
elif opcode == 'jmp' :
iReg = mem[op1]
# pReg = eval(mem[op1])
return pReg
elif opcode == 'jz' :
if reg[op1] == 0 :
# pReg = eval(mem[op2]
iReg = mem[op2]
result = pReg
elif opcode == 'in' :
reg[op1] = eval(input())
result = reg[op1]
elif opcode == 'out' :
# print(reg[op1])
result = reg[op1]
else :
result = False
########## End ##########
return result
他来了他来了,这个第六关终于来了。
逻辑已经讲清楚了,调代码的过程真是太痛苦了,而且他有些函数里面传的参量也叫 p R e g pReg pReg啥的,很容易让人混淆。
当然,整个代码主要是前五关整合,具体的话还是要一行一行慢慢理解。
而且 e x e c u t e execute execute函数需要我们自己传一个 a d d r addr addr,不然的话我们没有办法实现偏移
#模拟 CPU 执行完整程序代码的全部过程
#初始化主存、通用寄存器、指令寄存器和程序计数器
mem = ['']*1000 #主存
reg = [0]*10 #通用寄存器
pReg = 0 #程序计数器
iReg = '' #指令寄存器
def loadProgram(file, mem, address):
txt = open(file, 'r')
s = txt.readlines()
for x in s :
l = len(x)
bg, L = 0, []
while bg < l :
mdl = ''
while bg < l and x[bg] != ' ' :
mdl = mdl + x[bg]
bg += 1
while bg < l and x[bg] == ' ' :
bg += 1
L.append(mdl)
L.pop(0)
mem[address] = ' '.join(L)
address = address + 1
def fetch(mem, pReg):
iReg = mem[pReg]
return pReg, iReg
def decode(iReg):
l = len(iReg)
cnt, i = 0, 0
L = []
while i < l :
while i < l and iReg[i] == ' ' :
i = i + 1
if i == l :
break
cnt = cnt + 1; mdl = ''
while i < l and iReg[i] != ' ' :
mdl = mdl + iReg[i]
i = i + 1
if cnt > 1 :
bg = 0
while bg < len(mdl) and mdl[bg] == '0' :
bg = bg + 1
mdl = mdl[bg : ]
L.append(mdl)
tmp = cnt
while cnt < 3 :
L.append('None')
cnt = cnt + 1
if tmp == 1 :
return L[0], 0, 0
elif tmp == 2 :
if L[1] == '' or L[1] == '\n':
return L[0], 0, 0
return L[0], eval(L[1]), 0
else :
ret1, ret2 = 0, 0
if L[1] != '' and L[1] != '\n':
ret1 = eval(L[1])
if L[2] != '' and L[2] != '\n':
ret2 = eval(L[2])
return L[0], ret1, ret2
def execute(opcode, op1, op2, reg, mem, addr):
global pReg
flag = False
if opcode == 'mov1' :
reg[op1] = eval(mem[op2])
elif opcode == 'mov2' :
mem[op1] = str(reg[op2])
elif opcode == 'mov3' :
reg[op1] = op2
elif opcode == 'add' :
reg[op1] += reg[op2]
elif opcode == 'sub' :
reg[op1] -= reg[op2]
elif opcode == 'mul' :
reg[op1] *= reg[op2]
elif opcode == 'div' :
reg[op1] = reg[op1] // reg[op2]
elif opcode == 'jmp' :
iReg = mem[op1]
pReg = op1 + addr
flag = True
elif opcode == 'jz' :
if reg[op1] == 0 :
flag = True
iReg = mem[op2]
pReg = op2 + addr
elif opcode == 'in' :
reg[op1] = eval(input())
elif opcode == 'out' :
print(reg[op1])
if flag == False :
pReg = pReg + 1
if opcode != 'halt' and opcode != 'halt\n':
result = True
else :
result = False
return result
def run(file, addr):
global pReg, iReg
pReg = addr
loadProgram(file, mem, addr)
while True :
pReg, iReg = fetch(mem, pReg)
L, op1, op2 = decode(iReg)
mdl = execute(L, op1, op2, reg, mem, addr)
if mdl == False :
break
file = input()
address = int(input())
run(file, address)
这个代码里面的函数我认为才是正常的函数,因为所有的参量都在全局变量里开过了,不需要我们单独去开。
和上一个题没啥区别,代码好看很多。
mem = ['']*1000 #主存
reg = [0]*10 #通用寄存器
pReg = 0 #程序计数器
iReg = '' #指令寄存器
CF = 0
def init():
global mem,reg,pReg,iReg,CF
########## Begin ##########
mem = ['']*1000 #主存
reg = [0]*10 #通用寄存器
pReg = 0 #程序计数器
iReg = '' #指令寄存器
CF = 0
def loadProgram(file, mem, address):
txt = open(file, 'r')
s = txt.readlines()
for x in s :
l = len(x)
bg, L = 0, []
while bg < l :
mdl = ''
while bg < l and x[bg] != ' ' and x[bg] != '\t' :
mdl = mdl + x[bg]
bg += 1
while bg < l and (x[bg] == ' ' or x[bg] == '\t'):
bg += 1
L.append(mdl)
L.pop(0)
mem[address] = ' '.join(L)
address = address + 1
#取指令:根据程序计数器给出的地址取出主存对应的指令放入指令寄存器
def fetch():
global mem, pReg, iReg
iReg = mem[pReg]
return pReg, iReg
#指令译码:解析指令寄存器中的指令,不存在的操作数置为None
def decode():
global iReg
l = len(iReg)
cnt, i = 0, 0
L = []
while i < l :
while i < l and iReg[i] == ' ' :
i = i + 1
if i == l :
break
cnt = cnt + 1; mdl = ''
while i < l and iReg[i] != ' ' :
mdl = mdl + iReg[i]
i = i + 1
if cnt > 1 :
bg = 0
while bg < len(mdl) and mdl[bg] == '0' :
bg = bg + 1
mdl = mdl[bg : ]
L.append(mdl)
tmp = cnt
while cnt < 3 :
L.append('None')
cnt = cnt + 1
if tmp == 1 :
return L[0], 0, 0
elif tmp == 2 :
if L[1] == '' or L[1] == '\n':
return L[0], 0, 0
return L[0], eval(L[1]), 0
else :
ret1, ret2 = 0, 0
if L[1] != '' and L[1] != '\n':
ret1 = eval(L[1])
if L[2] != '' and L[2] != '\n':
ret2 = eval(L[2])
return L[0], ret1, ret2
########## End ##########
#执行和写结果:根据指令解析的操作码执行对应的操作,若为停机指令返回 False,其余指令返回 True
##opcode为操作码,op1为第一个操作数,op2为第二个操作数
def execute(opcode,op1,op2, address):
global reg, pReg, CF, mem
flag = False
if opcode == 'mov1' :
reg[op1] = eval(mem[op2])
elif opcode == 'mov2' :
mem[op1] = str(reg[op2])
elif opcode == 'mov3' :
reg[op1] = op2
elif opcode == 'add' :
reg[op1] += reg[op2]
elif opcode == 'sub' :
reg[op1] -= reg[op2]
elif opcode == 'mul' :
reg[op1] *= reg[op2]
elif opcode == 'div' :
reg[op1] = reg[op1] // reg[op2]
elif opcode == 'jmp' :
iReg = mem[op1]
pReg = op1 + address
flag = True
elif opcode == 'jz' :
if reg[op1] == 0 :
flag = True
iReg = mem[op2]
pReg = op2 + address
elif opcode == 'in' :
reg[op1] = eval(input())
elif opcode == 'out' :
print(reg[op1])
elif opcode == 'add2' :
reg[op1] += op2
elif opcode == 'cmp' :
if reg[op1] <= op2 :
CF = 1
else :
CF = 0
elif opcode == 'ble' :
if CF :
pReg = reg[op1] + address
flag = True
if flag == False :
pReg = pReg + 1
if opcode != 'halt' and opcode != 'halt\n':
result = True
else :
result = False
########## End ##########
return result
#完整过程模拟:程序加载、取指令、指令译码、指令执行和写结果
def run(file, addr):
global pReg, iReg, reg
######## Begin ########
pReg = addr
loadProgram(file, mem, addr)
while True :
pReg, iReg = fetch()
L, op1, op2 = decode()
mdl = execute(L, op1, op2, addr)
if mdl == False :
break
########## End ##########