Virtual machine using RPython and PyPy I'm writing a virtual machine in Python using RPython and the PyPy toolchain. The RPython will still work in the ordinary Python 2 interpreter; it's just a bit slow unless it's compiled to C code with PyPy.

Does anyone have any positive or negative feedback about my VM?

The virtual machine has 4 instructions:


EOP - End of Program
EOI - End of Instruction
PUSH - Push item onto stack
PRINT - Print the item at the top of the stack




bcode = []
stack = []
regs = []
sp = 0
bcd = []

'''
Instructions
'''
OP_EOP = 0
OP_EOI = 1
OP_PUSH = 2
OP_PRINT = 3

def load_program(f2o):
    f = open(f2o, "r")
    f2 = f.read()
    f2 = f2.replace("\n"," ")
    bcode = f2.split(" ")
    i = 0
    for item in bcode:
        item = int(item, 16)
        bcd.append(item)
        i += 1
    return bcd

# VM action functions
def do_EOP():
    print "End of Program"

def do_PUSH(ba, b, ip):
    i = 2
    loop = 1
    cb = len(b)

    stack.insert(0, ba)

def do_PRINT(stack):
    stk = stack[0].split(" ")
    for item in stk:
        print unichr(int(item))

def execute_program(b):
    ip = 0
    sp = 0
    loop = 1
    cb = len(b)
    while (loop):
        if ip &lt; cb:
            bc = b[ip]
            if bc == OP_PUSH:
                if bc != OP_EOI:
                    ba = str(b[ip + 1])
                    do_PUSH(ba, b, ip)
            elif bc == OP_PRINT:
                do_PRINT(stack)
            ip += 1
        else:
            loop = 0


def run_program(f):
    b = load_program(f)
    execute_program(b)

def main(argv):
    run_program(argv[1])
    return 0

def target(*args):
    return main, None

if __name__ == '__main__':
    import sys
    main(sys.argv)


Here's a file that includes the bytecode that prints "Hello World!" to the screen:


0002 0048 0001 0003
0002 0065 0001 0003
0002 006C 0001 0003
0002 006C 0001 0003
0002 006F 0001 0003
0002 0020 0001 0003
0002 0057 0001 0003
0002 006F 0001 0003
0002 0072 0001 0003
0002 006C 0001 0003
0002 0064 0001 0003
0002 0021 0001 0003



You can test the VM like this; it's written in Python 2.7:


  python vm.py
bcode = []
stack = []
regs = []
sp = 0
bcd = []


Global variables like this are frowned upon. To be pythonic you should really put them a in a class or something.

'''
Instructions
'''
OP_EOP = 0
OP_EOI = 1
OP_PUSH = 2
OP_PRINT = 3

def load_program(f2o):


f2o? What in the world is that?

    f = open(f2o, "r")
    f2 = f.read()


My recollection of RPython is that it doesn't support this pattern. Are you sure it works in RPython?

    f2 = f2.replace("\n"," ")
    bcode = f2.split(" ")
    i = 0
    for item in bcode:
        item = int(item, 16)
        bcd.append(item)
        i += 1


What are you ding with i? You count it, but don't do anything with the value that you count.

    return bcd

# VM action functions
def do_EOP():
    print "End of Program"

def do_PUSH(ba, b, ip):


ba? b? pick variables names that let me know what they represent.

    i = 2
    loop = 1
    cb = len(b)


None of these last three lines do anything. They set variables local to the function when then gets thrown away.

    stack.insert(0, ba)


For a stack, we usually use the end of the list as the top of stack. That way you can simply append() and pop() the list. Its rather inefficient to insert at the begining.

def do_PRINT(stack):
    stk = stack[0].split(" ")
    for item in stk:
        print unichr(int(item))

def execute_program(b):
    ip = 0
    sp = 0
    loop = 1


Use True and False for true/false.

    cb = len(b)
    while (loop):


You don't need the ( or )

        if ip &lt; cb:
            bc = b[ip]
            if bc == OP_PUSH:
                if bc != OP_EOI:


Are you expecting bc to change between those two lines?

                    ba = str(b[ip + 1])


You read the next piece of bytecode to push it, but you don't skip increment ip to account for it.

                    do_PUSH(ba, b, ip)

            elif bc == OP_PRINT:
                do_PRINT(stack)
            ip += 1
        else:
            loop = 0


def run_program(f):
    b = load_program(f)
    execute_program(b)

def main(argv):
    run_program(argv[1])
    return 0

def target(*args):
    return main, None

if __name__ == '__main__':
    import sys
    main(sys.argv)


The biggest issue with your code is that you have a lot of code that can't possibly do anything useful. Reading me leaves me to wonder if you just haven't cleaned up your code or are confused about the code actually works.