1부에 이어서, 2부를 시작 합니다.
4. ChatGPT님이 주신 코드를 디버깅 해서 돌아가게 만듭니다.
class StackMachine:
def __init__(self):
self.stack = []
self.program = []
self.labels = {}
self.ip = 0
self.ax = 0
self.bx = 0
self.cx = 0
self.dx = 0
def load_program(self, program):
self.program = program
for i, line in enumerate(program):
if line.endswith(':'):
self.labels[line[:-1]] = i
def run(self):
count = 20000
while self.ip < len(self.program) and count > 0:
count -= 1
cmd = self.program[self.ip].split()
op = cmd[0].upper()
if op == 'PUSH':
self.stack.append(int(cmd[1]))
elif op == 'POP':
self.stack.pop()
elif op == 'ADD':
self.stack.append(self.stack.pop() + self.stack.pop())
elif op == 'SUB':
b, a = self.stack.pop(), self.stack.pop()
self.stack.append(a - b)
elif op == 'MUL':
self.stack.append(self.stack.pop() * self.stack.pop())
elif op == 'DIV':
b, a = self.stack.pop(), self.stack.pop()
self.stack.append(a // b)
elif op == 'MOD':
b, a = self.stack.pop(), self.stack.pop()
self.stack.append(a % b)
elif op == 'DUP':
self.stack.append(self.stack[-1])
elif op == 'SWAP':
self.stack[-1], self.stack[-2] = self.stack[-2], self.stack[-1]
elif op == 'JMP':
self.ip = self.labels[cmd[1]]
continue
elif op == 'JG':
if self.stack.pop() == 1:
self.ip = self.labels[cmd[1]]
continue
elif op == 'JZ':
if self.stack.pop() == 0:
self.ip = self.labels[cmd[1]]
continue
elif op == 'JNZ':
if self.stack.pop() != 0:
self.ip = self.labels[cmd[1]]
continue
elif op == 'CMP':
b, a = self.stack.pop(), self.stack.pop()
self.stack.append((a > b) - (a < b))
elif op == 'NOP':
pass
elif op == 'HALT':
break
self.ip += 1
아래와 같이 올바른 결과가 나오는 것을 확인 합니다.
C:\Users\chobo\AppData\Local\Programs\Python\Python38\python.exe C:\github\simple_vm\simple_vm\main.py
Result: 3628800
5. 코드를 약간 리팩토링 합니다.
6. 수정한 코드를 ChatGPT님에게 드리고 주석을 영어로 바꿔달라고 합니다.
주석은 Step1의 명령어 정리하기로 생성된 걸 그대로 붙였습니다.
class StackMachine:
"""
PUSH <value>: Push a value onto the stack. e.g., PUSH 10
POP: Remove and return the top value from the stack.
ADD: Remove the top two values from the stack, calculate their sum, and push the result onto the stack.
SUB: Remove the top two values from the stack, calculate their difference, and push the result onto the stack.
MUL: Remove the top two values from the stack, calculate their product, and push the result onto the stack.
DIV: Remove the top two values from the stack, calculate their division, and push the result onto the stack.
MOD: Remove the top two values from the stack, calculate their remainder, and push the result onto the stack.
DUP: Copy the top value from the stack and push it onto the stack.
SWAP: Swap the top two values on the stack.
JMP <label>: Move program execution to the given label. e.g., JMP LOOP
JZ <label>: If the top value on the stack is 0, move program execution to the given label.
JNZ <label>: If the top value on the stack is not 0, move program execution to the given label.
CMP: Compare the top two values on the stack and push the result onto the stack.
(-1: First value is smaller, 0: Both values are equal, 1: First value is larger)
CALL <label>: Save the current position and move program execution to the given label.
RET: Return to the previously saved position and continue program execution.
NOP: Perform no operation. This command is ignored in the program.
HALT: Stop program execution.
"""
def __init__(self):
self.stack = []
self.program = []
self.labels = {}
self.register = {'AX': 0, 'BX': 0, 'CX': 0, 'DX': 0}
self.ip = 0
def load_program(self, program):
self.program = program
for i, line in enumerate(program):
if line.endswith(':'):
self.labels[line[:-1]] = i
def run(self):
count = 20000
while self.ip < len(self.program) and count > 0:
count -= 1
cmd = self.program[self.ip].split()
op = cmd[0].upper()
if op == 'PUSH':
if type(cmd[1]) == int:
self.stack.append(int(cmd[1]))
else:
self.stack.append(int(self.register[cmd[1]]))
elif op == 'POP':
self.stack.pop()
elif op == 'MOV':
if cmd[1] == 'AX':
self.ax = self.stack[-1]
elif cmd[1] == 'BX':
self.bx = self.stack[-1]
elif cmd[1] == 'CX':
self.cx = self.stack[-1]
elif cmd[1] == 'DX':
self.dx = self.stack[-1]
elif op == 'ADD':
self.stack.append(self.stack.pop() + self.stack.pop())
elif op == 'SUB':
b, a = self.stack.pop(), self.stack.pop()
self.stack.append(a - b)
elif op == 'MUL':
self.stack.append(self.stack.pop() * self.stack.pop())
elif op == 'DIV':
b, a = self.stack.pop(), self.stack.pop()
self.stack.append(a // b)
elif op == 'MOD':
b, a = self.stack.pop(), self.stack.pop()
self.stack.append(a % b)
elif op == 'DUP':
self.stack.append(self.stack[-1])
elif op == 'SWAP':
self.stack[-1], self.stack[-2] = self.stack[-2], self.stack[-1]
elif op == 'JMP':
self.ip = self.labels[cmd[1]]
continue
elif op == 'JG':
if self.stack.pop() == 1:
self.ip = self.labels[cmd[1]]
continue
elif op == 'JL':
if self.stack.pop() == -1:
self.ip = self.labels[cmd[1]]
continue
elif op == 'JZ':
if self.stack.pop() == 0:
self.ip = self.labels[cmd[1]]
continue
elif op == 'JNZ':
if self.stack.pop() != 0:
self.ip = self.labels[cmd[1]]
continue
elif op == 'CMP':
b, a = self.stack.pop(), self.stack.pop()
self.stack.append((a > b) - (a < b))
elif op == 'NOP':
pass
elif op == 'HALT':
break
self.ip += 1
# print(f"{self.stack} / {self.ax}")
7. 주석과 코드가 안 맞습니다. 주석을 코드 베이스로 업데이트 해달라고 요청합니다.
class StackMachine:
"""
PUSH <value>: Push a value onto the stack. e.g., PUSH 10
POP: Remove and return the top value from the stack.
ADD: Remove the top two values from the stack, calculate their sum, and push the result onto the stack.
SUB: Remove the top two values from the stack, calculate their difference, and push the result onto the stack.
MUL: Remove the top two values from the stack, calculate their product, and push the result onto the stack.
DIV: Remove the top two values from the stack, calculate their division, and push the result onto the stack.
MOD: Remove the top two values from the stack, calculate their remainder, and push the result onto the stack.
DUP: Copy the top value from the stack and push it onto the stack.
SWAP: Swap the top two values on the stack.
JMP <label>: Move program execution to the given label. e.g., JMP LOOP
JG <label>: If the top value on the stack is greater than 0, move program execution to the given label.
JL <label>: If the top value on the stack is less than 0, move program execution to the given label.
JZ <label>: If the top value on the stack is 0, move program execution to the given label.
JNZ <label>: If the top value on the stack is not 0, move program execution to the given label.
CMP: Compare the top two values on the stack and push the result onto the stack.
(-1: First value is smaller, 0: Both values are equal, 1: First value is larger)
MOV <register>: Move the top value from the stack to the specified register (AX, BX, CX, or DX).
NOP: Perform no operation. This command is ignored in the program.
HALT: Stop program execution.
"""
def __init__(self):
self.stack = []
self.program = []
self.labels = {}
self.register = {'AX': 0, 'BX': 0, 'CX': 0, 'DX': 0}
self.ip = 0
def load_program(self, program):
self.program = program
for i, line in enumerate(program):
if line.endswith(':'):
self.labels[line[:-1]] = i
def run(self):
count = 20000
while self.ip < len(self.program) and count > 0:
count -= 1
cmd = self.program[self.ip].split()
op = cmd[0].upper()
if op == 'PUSH':
if 'X' in cmd[1]:
self.stack.append(int(self.register[cmd[1]]))
else:
self.stack.append(int(cmd[1]))
elif op == 'POP':
self.stack.pop()
elif op == 'MOV':
self.register[cmd[1]] = self.stack[-1]
elif op == 'ADD':
self.stack.append(self.stack.pop() + self.stack.pop())
elif op == 'SUB':
b, a = self.stack.pop(), self.stack.pop()
self.stack.append(a - b)
elif op == 'MUL':
self.stack.append(self.stack.pop() * self.stack.pop())
elif op == 'DIV':
b, a = self.stack.pop(), self.stack.pop()
self.stack.append(a // b)
elif op == 'MOD':
b, a = self.stack.pop(), self.stack.pop()
self.stack.append(a % b)
elif op == 'DUP':
self.stack.append(self.stack[-1])
elif op == 'SWAP':
self.stack[-1], self.stack[-2] = self.stack[-2], self.stack[-1]
elif op == 'JMP':
self.ip = self.labels[cmd[1]]
continue
elif op == 'JG':
if self.stack.pop() == 1:
self.ip = self.labels[cmd[1]]
continue
elif op == 'JL':
if self.stack.pop() == -1:
self.ip = self.labels[cmd[1]]
continue
elif op == 'JZ':
if self.stack.pop() == 0:
self.ip = self.labels[cmd[1]]
continue
elif op == 'JNZ':
if self.stack.pop() != 0:
self.ip = self.labels[cmd[1]]
continue
elif op == 'CMP':
b, a = self.stack.pop(), self.stack.pop()
self.stack.append((a > b) - (a < b))
elif op == 'NOP':
pass
elif op == 'HALT':
break
self.ip += 1
# print(f"{self.stack} / {self.ax}")
3부에서 계속 됩니다.
'Coding > Python 삽질기' 카테고리의 다른 글
[ChatGPT에게 묻다] python으로 Simple Stack VM 만들기 (3) (0) | 2023.03.17 |
---|---|
[ChatGPT에게 묻다] python으로 Simple Stack VM 만들기 (1) (0) | 2023.03.17 |
[ChatGPT에게 묻다] python api 작명법 (0) | 2023.03.14 |