A simple Python virtual machine implementation

We realize this simple virtual machines, and computer cpu somewhat similar. Nothing more than an instruction fetch, instruction execute the operation or the like.

Common virtual machine is usually divided into two categories, one is the stack virtual machine, the other is register virtual machine. For example CPython, Jvm is stack-based virtual machine, but is lua-based virtual machine registers.

We achieve this "toy" virtual machine, it is a stack-based virtual machine.

There are three important attributes virtual machine instruction code to be executed on behalf of the list, stack for storing temporary variables, and addr represents the address of the current instruction.

Efficient Programming Python

class Machine:
    def __init__(self, code):
        self.code = code
        self.stack = list()
        self.addr = 0

Principle is very simple, we have to get instructions and data from the instruction list through continuous access to the current instruction address, if it is a number or string, then pushed onto the stack; if it is an instruction on the implementation of the corresponding function.

For a few less characters, we add a few methods to Machine class:

def push(self, value):
    self.stack.append(value)
 
def pop(self):
    return self.stack.pop()
 
@property
def top(self):
    return self.stack[-1]

We dispatch method to determine the current segment list acquired from the instruction is an instruction or data:

def dispatch(self, opcode):
    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,
        "exit":     self.exit,
        "if":       self.if_stmt,
        "jmp":      self.jmp,
        "over":     self.over,
        "print":    self.print,
        "println":  self.println,
        "read":     self.read,
        "stack":    self.dump_stack,
        "swap":     self.swap,
        }
    if opcode in dispatch_map:
        dispatch_map[opcode]()
    elif isinstance(opcode, int):
        self.push(opcode)
    elif isinstance(opcode, str)\
        and opcode[0] == opcode[-1] == '"':
        self.push(opcode[1:-1])

dispatch_map on corresponding method we implemented in the Machine class.

For example, jmp plus method and the method:

def plus(self):
    v2 = self.pop()
    v1 = self.pop()
    self.push(v1 + v2)
 
 
def jmp(self):
    addr = self.pop()
    if 0 <= addr < len(self.code):
        self.addr = addr
    else:
        raise RuntimeError("addr must be integer")

The remaining method is very simple, you can directly view the source code.

Well, added a run in the function, we can interpret the code. As long as the current address is less than the length of the instruction, to constantly fetch, execute the instructions.

def run(self):
    while self.addr < len(self.code):
        opcode = self.code[self.addr]
        self.addr += 1
        self.dispatch(opcode)

We created the Machine class and perform run function, note the string to use quotes.

>>> from vm import Machine
>>> Machine([521, 1314,"+", 6, "*","println"]).run()
11010

We can also add an interactive interface to the virtual machine:

def repl(prompt="VM>> "):
    welcome()
    while True:
        try:
            text = read(prompt)
            code = list(tokenize(text))
            code = constants_fold(code)
            Machine(code).run()
        except (RuntimeError, IndexError):
            stdout.write("1表达式不合法\n")
        except KeyboardInterrupt:
            stdout.write("请使用exit退出程序\n")

After reading the user input character string, a character string processing:

def parse_word(word):
    try:
        return int(word)
    except ValueError:
        try:
            return float(word)
        except ValueError:
            return word
 
def tokenize(text):
    for word in text.split():
        yield parse_word(word)
Released eight original articles · won praise 5 · Views 3397

Guess you like

Origin blog.csdn.net/G1011/article/details/102908919