(Ask ChatGPT) 파이썬으로 간단한 스택 VM 만들기 (2)

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
결과: 3628800

5. 코드를 약간 리팩토링하십시오.

6. ChatGPT에 수정된 코드를 주고 댓글을 영어로 변경하도록 요청합니다.

주석은 1단계에서 명령을 정리하여 작성한 그대로 첨부합니다.

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