-
Notifications
You must be signed in to change notification settings - Fork 1
/
vm.py
138 lines (121 loc) · 5.74 KB
/
vm.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# Subleq Improved Virtual Machine
# Copyright (C) 2022 McChuck
# original Copyright (C) 2013 Chris Lloyd
# Released under GNU General Public License
# See LICENSE for more details.
# https://github.com/cjrl
# This Subleq Virtual Machine was based on the pseudocode from the OSIC Wikipedia article:
# http://en.wikipedia.org/wiki/One_instruction_set_computer
try:
from getch import getch, getche # Linux
except ImportError:
from msvcrt import getch, getche # Windows
class VM:
@staticmethod
def execute(mem):
pointer = int(mem[0]) # Instruction Pointer initialized to the first number in the file! MANDATORY!
running = True
maxmem = len(mem)-1
return_stack = []
data_stack = []
if pointer <= 0 or pointer > (maxmem - 2):
print("/nInstruction pointer out of bounds at program init./n")
running = False
raise IndexError
def deref(where):
index = int(where)
if out_of_bounds(index):
print(" at instruction location: ", where, flush=True)
raise IndexError
if index < 0:
index = mem[abs(index)]
if index < 0:
print("Dereferenced location", index, "from", where, "is negative.")
raise IndexError
return index
def out_of_bounds(where):
if abs(where) > maxmem:
print("\nReference out of bounds:", where, end="")
return True
else:
return False
while running:
try:
a = mem[pointer]
b = mem[pointer+1]
c = mem[pointer+2]
ap = deref(a)
bp = deref(b)
cp = deref(c)
a_val = mem[ap]
b_val = mem[bp]
c_val = mem[cp]
next_ip = pointer + 3
# print(pointer, "A", a, ap, a_val, "B", b, bp, b_val, "C", c, cp, c_val, flush=True)
if a != 0 and b != 0 and c != 0: # SUBLEQ A B C
mem[cp] = b_val - a_val
elif a != 0 and b == 0 and c == 0: # PUSH A 0 0
data_stack.append(a_val)
elif a == 0 and b == 0 and c != 0: # POP 0 0 C
if len(data_stack) > 0:
mem[cp] = data_stack.pop(-1)
else:
print("Cannot pop from an empty stack @", pointer, flush=True)
print("A", a, ap, a_val, "B", b, bp, b_val, "C", c, cp)
running = False
elif a == 0 and b != 0 and c == 0: # RET? 0 B 0
if b_val <= 0:
if len(return_stack) > 0:
next_ip = return_stack[-1]
return_stack.pop(-1)
else:
print("Attempted to return from an empty stack @", pointer, flush=True)
print("A", a, ap, a_val, "B", b, bp, b_val, "C", c, cp)
running = False
elif a != 0 and b == 0 and c != 0: # GOTO? A 0 C
if a_val <= 0:
if cp <= 0:
print("\nInvalid address:", cp, " Halted @:", pointer, "\n")
running = False
else:
next_ip = cp
elif a == 0 and b != 0 and c != 0: # CALL? 0 B C
if b_val <= 0:
if cp <= 0:
print("\nInvalid address:", cp, " Halted @:", pointer, "\n")
running = False
else:
next_ip = cp
return_stack.append(pointer+3)
elif a != 0 and b != 0 and c == 0: # I/O A B 0 where A is the target and B is the format
if b > 0: # Print
if b == 1: # character
if a_val >= 0:
print(chr(a_val), end="", flush=True)
else:
print("\nInvalid character:", a_val, " @ memory:", ap, " @ instrtuction:", pointer)
running = False
raise ValueError
else: # number
print(a_val, end="", flush=True)
else: # Input character
if b == -1: # echo
mem[ap] = ord(getche())
else: # no echo
mem[ap] = ord(getch())
else: # HALT 0 0 0
print("\n\n\nProgram successfully halted @", pointer, "\n", flush=True)
running = False
pointer = next_ip
mem[0] = pointer
if pointer <= 0 or pointer > (maxmem - 2):
running = False
raise IndexError
except IndexError:
print("Memory out of bounds error at instruction", pointer)
print("A", a, ap, a_val, "B", b, bp, b_val, "C", c, cp, c_val)
running = False
except ValueError:
print("Value error at instruction", pointer)
print("A", a, ap, a_val, "B", b, bp, b_val, "C", c, cp, c_val)
running = False