使用python编写虚拟机解释器

来源:互联网 发布:c语言的主函数类型 编辑:程序博客网 时间:2024/05/29 08:04

本文参考自:http://www.ituring.com.cn/article/199660

#!/usr/bin/python3# encoding: utf-8from io import StringIOfrom collections import dequeimport tokenizeimport sysclass Stack(deque):    push = deque.append    def top(self):        return self[-1]class Machine:    def __init__(self, code):        self.data_stack = Stack()        self.return_addr_stack = Stack()        self.instruction_pointer = 0        self.code = code    def pop(self):        return self.data_stack.pop()    def push(self, value):        self.data_stack.push(value)    def top(self):        return self.data_stack.top()    def run(self):        while self.instruction_pointer < len(self.code):            opcode = self.code[self.instruction_pointer]            self.instruction_pointer += 1            self.dispatch(opcode)    def dispatch(self, op):        dispatch_map = {            "%": self.mod,            "*": self.mul,            "+": self.plus,            "-": self.minus,            "/": self.div,            "==": self.eq,            "cast_int": self.cast_int,            "cast_str": self.cast_str,            "drop": self.drop,            "dup": self.dup,            "if": self.if_stmt,            "jmp": self.jmp,            "over": self.over,            "print": self.print,            "println": self.println,            "read": self.read,            "dump": self.dump,            "stack": self.stack,            "swap": self.swap,        }        if op in dispatch_map:            dispatch_map[op]()        elif isinstance(op, int):            self.push(op)        elif isinstance(op, str) and op[0] == op[-1] == '"':            self.push(op[1:-1])        else:            raise RuntimeError("Unknown opcode: '%s'" % op)    def mod(self):        self.push(self.pop() % self.pop())    def mul(self):        self.push(self.pop() * self.pop())    def plus(self):        self.push(self.pop() + self.pop())    def minus(self):        self.push(self.pop() - self.pop())    def div(self):        self.push(self.pop() / self.pop())    def eq(self):        self.push(self.top() == self.top())    def cast_int(self):        self.push(int(self.pop()))    def cast_str(self):        self.push(str(self.pop()))    def drop(self):        self.pop()    def dup(self):        self.push(self.top())    def if_stmt(self):        false_clause = self.pop()        true_clause = self.pop()        test = self.pop()        self.push(true_clause if test else false_clause)    def jmp(self):        addr = self.pop()        if (isinstance(addr, int) and 0 <= addr < len(self.code)):            self.instruction_pointer = addr        else:            raise RuntimeError("JMP address must be a valid integer.")    def over(self):        b = self.pop()        a = self.pop()        self.push(a)        self.push(b)        self.push(a)    def print(self):        sys.stdout.write(str(self.pop()))        sys.stdout.flush()    def println(self):        sys.stdout.write("%s\n" % self.pop())        sys.stdout.flush()    def dump(self):        pass    def read(self):        self.push(input())    def stack(self):        pass    def swap(self):        a = self.pop()        b = self.pop()        self.push(a)        self.push(b)def parse(text):    tokens = tokenize.generate_tokens(StringIO(text).readline)    for toknum, tokval, _, _, _ in tokens:        if toknum == tokenize.NUMBER:            yield int(tokval)        elif toknum in [tokenize.OP, tokenize.STRING, tokenize.NAME]:            yield tokval        elif toknum == tokenize.ENDMARKER:            break        else:            raise RuntimeError("Unknown token %s: '%s'" %                               (tokenize.tok_name[toknum], tokval))def constant_fold(code):    """Constant-folds simple mathematical expressions like 2 3 + to 5."""    while True:        # Find two consecutive numbers and an arithmetic operator        for i, (a, b, op) in enumerate(zip(code, code[1:], code[2:])):            if isinstance(a, int) and isinstance(b, int) \                and op in {"+", "-", "*", "/"}:                m = Machine((a, b, op))                m.run()                code[i:i+3] = [m.top()]                print("Constant-folded %s%s%s to %s" % (a, op, b, m.top()))                break        else:            break    return codedef repl():    print('Hit CTRL-D or type "exit" to quit.')    while True:        try:            source = input("> ")            code = list(parse(source))            code = constant_fold(code)            Machine(code).run()        except (RuntimeError, IndexError) as e:            print("IndexError: %s" % e)        except KeyboardInterrupt:            print("\nKeyBoardInterrupt")if __name__ == "__main__":    # Machine([    #     '"Enter a number: "', "print", "read", "cast_int",    #     '"Enter another number: "', "print", "read", "cast_int",    #     "over", "over",    #     '"Their sum is: "', "print", "+", "println",    #     '"Their product is: "', "print", "*", "println"    # ]).run()    # Machine([    #     '"Enter a number: "', "print", "read", "cast_int",    #     '"The number "', "print", "dup", "print", '" is "', "print",    #     2, "%", "==", '"even."', '"odd."', "if", "println",    #     0, "jmp"  # loop forever!    # ]).run()    repl()

程序运行结果:
这里写图片描述