Coding/Python 삽질기2023. 3. 17. 01:08

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부에서 계속 됩니다.

Posted by chobocho