| 1 | import sys |
|---|
| 2 | |
|---|
| 3 | class Program: |
|---|
| 4 | def __init__(self): |
|---|
| 5 | # static data |
|---|
| 6 | self.programdata = [] |
|---|
| 7 | self.labels = {} |
|---|
| 8 | # dynamic data |
|---|
| 9 | self.stack = [] |
|---|
| 10 | self.heap = {} |
|---|
| 11 | self.programcounter = 0 |
|---|
| 12 | self.pcstack = [] |
|---|
| 13 | def __str__(self): |
|---|
| 14 | return "<Program, %d opcodes (incl %d labels) - at %d, %d stack length, %d call depth, %d heap size>" % (len(self.programdata), len(self.labels), self.programcounter, len(self.stack), len(self.pcstack), len(self.heap)) |
|---|
| 15 | def __repr__(self): |
|---|
| 16 | return "%s\nProgram Data: %s\nLabels: %s\nData Stack: %s\nHeap: %s\nProgram counter: %d\nPC Stack: %s" % (str(self),self.programdata,self.labels,self.stack,self.heap,self.programcounter,self.pcstack) |
|---|
| 17 | |
|---|
| 18 | class Opcodes: # the numbers themselves are meaningless - they just have to be unique |
|---|
| 19 | # Axx - stack ops |
|---|
| 20 | Push = 0 # AA num - push num to stack |
|---|
| 21 | Dup = 1 # ACA - push copy of TOS (top of stack) |
|---|
| 22 | Swap = 2 # ACB - swap TOS and TOS-1 |
|---|
| 23 | Discard = 3 # ACC - pop and discard TOS |
|---|
| 24 | Ref = 4 # ABA num - push copy of TOS-num |
|---|
| 25 | Slide = 5 # ABC num - pop and discard TOS-1 through TOS-num - keep TOS |
|---|
| 26 | # - equiv to "ACB ACC" num times |
|---|
| 27 | |
|---|
| 28 | # BAxx - math ops |
|---|
| 29 | Plus = 6 # BAAA - push TOS-1 + TOS |
|---|
| 30 | Minus = 7 # BAAB - push TOS-1 - TOS |
|---|
| 31 | Times = 8 # BAAC - push TOS-1 * TOS |
|---|
| 32 | Divide = 9 # BABA - push TOS-1 / TOS (floored) |
|---|
| 33 | Modulo = 10 # BABB - push TOS-1 % TOS |
|---|
| 34 | |
|---|
| 35 | # BBx - heap ops |
|---|
| 36 | Store = 11 # BBA - write TOS to address TOS-1 |
|---|
| 37 | Retrieve = 12 # BBB - read from address TOS |
|---|
| 38 | |
|---|
| 39 | # Cxx - flow ops |
|---|
| 40 | Label = 13 # CAA label - mark a label |
|---|
| 41 | Call = 14 # CAB label - call a subroutine |
|---|
| 42 | Jump = 15 # CAC label - jump to a label |
|---|
| 43 | JumpZero = 16 # CBA label - jump if TOS is zero |
|---|
| 44 | JumpNeg = 17 # CBB label - jump if TOS is <0 |
|---|
| 45 | Return = 18 # CBC - return from subroutine |
|---|
| 46 | Trace = 24 # CCB - print core dump |
|---|
| 47 | End = 19 # CCC - stop executing program |
|---|
| 48 | |
|---|
| 49 | # BCxx - I/O ops |
|---|
| 50 | OutputChar = 20 # BCAA - output char from TOS |
|---|
| 51 | OutputNum = 21 # BCAB - output int from TOS |
|---|
| 52 | InputChar = 22 # BCBA - input char to address at TOS |
|---|
| 53 | InputNum = 23 # BCBB - input int to address at TOS |
|---|
| 54 | |
|---|
| 55 | class Instruction: |
|---|
| 56 | opcode = -1 |
|---|
| 57 | def __init__(self, codeloc): |
|---|
| 58 | self.codeloc = codeloc |
|---|
| 59 | def __call__(self, program): |
|---|
| 60 | raise "Hmm, calling a non-opcode? Strange tastes..." |
|---|
| 61 | |
|---|
| 62 | class Push(Instruction): |
|---|
| 63 | opcode = Opcodes.Push |
|---|
| 64 | def __init__(self, codeloc, value): |
|---|
| 65 | self.codeloc = codeloc |
|---|
| 66 | self.value = value |
|---|
| 67 | def __call__(self, program): |
|---|
| 68 | program.stack.append(self.value) |
|---|
| 69 | def __str__(self): |
|---|
| 70 | return "<Push %d>" % self.value |
|---|
| 71 | __repr__ = __str__ |
|---|
| 72 | class Dup(Instruction): |
|---|
| 73 | opcode = Opcodes.Dup |
|---|
| 74 | def __init__(self, codeloc): |
|---|
| 75 | self.codeloc = codeloc |
|---|
| 76 | def __call__(self, program): |
|---|
| 77 | try: |
|---|
| 78 | program.stack.append(program.stack[-1]) |
|---|
| 79 | except IndexError: |
|---|
| 80 | print "Error: Dup in empty stack at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 81 | program.programcounter = None |
|---|
| 82 | def __str__(self): |
|---|
| 83 | return "<Dup>" |
|---|
| 84 | __repr__ = __str__ |
|---|
| 85 | class Swap(Instruction): |
|---|
| 86 | opcode = Opcodes.Swap |
|---|
| 87 | def __init__(self, codeloc): |
|---|
| 88 | self.codeloc = codeloc |
|---|
| 89 | def __call__(self, program): |
|---|
| 90 | try: |
|---|
| 91 | program.stack[-1],program.stack[-2] = program.stack[-2],program.stack[-1] |
|---|
| 92 | except IndexError: |
|---|
| 93 | if len(program.stack) == 0: |
|---|
| 94 | print "Error: Swap in stack with only one element at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 95 | else: |
|---|
| 96 | print "Error: Swap in empty stack at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 97 | program.programcounter = None |
|---|
| 98 | def __str__(self): |
|---|
| 99 | return "<Swap>" |
|---|
| 100 | __repr__ = __str__ |
|---|
| 101 | class Discard(Instruction): |
|---|
| 102 | opcode = Opcodes.Discard |
|---|
| 103 | def __init__(self, codeloc): |
|---|
| 104 | self.codeloc = codeloc |
|---|
| 105 | def __call__(self, program): |
|---|
| 106 | try: |
|---|
| 107 | program.stack.pop() |
|---|
| 108 | except IndexError: |
|---|
| 109 | print "Error: Discard from empty stack at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 110 | program.programcounter = None |
|---|
| 111 | def __str__(self): |
|---|
| 112 | return "<Discard>" |
|---|
| 113 | __repr__ = __str__ |
|---|
| 114 | class Ref(Instruction): |
|---|
| 115 | opcode = Opcodes.Ref |
|---|
| 116 | def __init__(self, codeloc, location): |
|---|
| 117 | self.codeloc = codeloc |
|---|
| 118 | self.location = -location - 1 |
|---|
| 119 | def __call__(self, program): |
|---|
| 120 | try: |
|---|
| 121 | program.stack.append(program.stack[self.location]) |
|---|
| 122 | except IndexError: |
|---|
| 123 | print "Error: Ref value larger than stack size at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 124 | program.programcounter = None |
|---|
| 125 | def __str__(self): |
|---|
| 126 | return "<Ref %d>" % -self.location |
|---|
| 127 | __repr__ = __str__ |
|---|
| 128 | class Slide(Instruction): |
|---|
| 129 | opcode = Opcodes.Slide |
|---|
| 130 | def __init__(self, codeloc, quantity): |
|---|
| 131 | self.codeloc = codeloc |
|---|
| 132 | self.quantity = -quantity - 1 |
|---|
| 133 | def __call__(self, program): |
|---|
| 134 | try: |
|---|
| 135 | program.stack = program.stack[0:self.quantity] + [program.stack[-1]] |
|---|
| 136 | except IndexError: |
|---|
| 137 | if len(program.stack) == 0: |
|---|
| 138 | print "Error: Slide from empty stack at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 139 | else: |
|---|
| 140 | print "Error: Slide value larger than stack size at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 141 | program.programcounter = None |
|---|
| 142 | def __str__(self): |
|---|
| 143 | return "<Slide %d>" % (-self.quantity + 1) |
|---|
| 144 | __repr__ = __str__ |
|---|
| 145 | |
|---|
| 146 | class Plus(Instruction): |
|---|
| 147 | opcode = Opcodes.Plus |
|---|
| 148 | def __init__(self, codeloc): |
|---|
| 149 | self.codeloc = codeloc |
|---|
| 150 | def __call__(self, program): |
|---|
| 151 | try: |
|---|
| 152 | y = program.stack.pop() |
|---|
| 153 | x = program.stack.pop() |
|---|
| 154 | program.stack.append(x + y) |
|---|
| 155 | except IndexError: |
|---|
| 156 | if len(program.stack) == 0: |
|---|
| 157 | print "Error: Plus with empty stack at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 158 | else: |
|---|
| 159 | print "Error: Plus with only one stack entry at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 160 | program.programcounter = None |
|---|
| 161 | def __str__(self): |
|---|
| 162 | return "<Plus>" |
|---|
| 163 | __repr__ = __str__ |
|---|
| 164 | class Minus(Instruction): |
|---|
| 165 | opcode = Opcodes.Minus |
|---|
| 166 | def __init__(self, codeloc): |
|---|
| 167 | self.codeloc = codeloc |
|---|
| 168 | def __call__(self, program): |
|---|
| 169 | try: |
|---|
| 170 | y = program.stack.pop() |
|---|
| 171 | x = program.stack.pop() |
|---|
| 172 | program.stack.append(x - y) |
|---|
| 173 | except IndexError: |
|---|
| 174 | if len(program.stack) == 0: |
|---|
| 175 | print "Error: Minus with empty stack at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 176 | else: |
|---|
| 177 | print "Error: Minus with only one stack entry at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 178 | program.programcounter = None |
|---|
| 179 | def __str__(self): |
|---|
| 180 | return "<Minus>" |
|---|
| 181 | __repr__ = __str__ |
|---|
| 182 | class Times(Instruction): |
|---|
| 183 | opcode = Opcodes.Times |
|---|
| 184 | def __init__(self, codeloc): |
|---|
| 185 | self.codeloc = codeloc |
|---|
| 186 | def __call__(self, program): |
|---|
| 187 | try: |
|---|
| 188 | y = program.stack.pop() |
|---|
| 189 | x = program.stack.pop() |
|---|
| 190 | program.stack.append(x * y) |
|---|
| 191 | except IndexError: |
|---|
| 192 | if len(program.stack) == 0: |
|---|
| 193 | print "Error: Times with empty stack at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 194 | else: |
|---|
| 195 | print "Error: Times with only one stack entry at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 196 | program.programcounter = None |
|---|
| 197 | def __str__(self): |
|---|
| 198 | return "<Times>" |
|---|
| 199 | __repr__ = __str__ |
|---|
| 200 | class Divide(Instruction): |
|---|
| 201 | opcode = Opcodes.Divide |
|---|
| 202 | def __init__(self, codeloc): |
|---|
| 203 | self.codeloc = codeloc |
|---|
| 204 | def __call__(self, program): |
|---|
| 205 | try: |
|---|
| 206 | y = program.stack.pop() |
|---|
| 207 | x = program.stack.pop() |
|---|
| 208 | program.stack.append(x / y) |
|---|
| 209 | except IndexError: |
|---|
| 210 | if len(program.stack) == 0: |
|---|
| 211 | print "Error: Divide with empty stack at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 212 | else: |
|---|
| 213 | print "Error: Divide with only one stack entry at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 214 | program.programcounter = None |
|---|
| 215 | def __str__(self): |
|---|
| 216 | return "<Divide>" |
|---|
| 217 | __repr__ = __str__ |
|---|
| 218 | class Modulo(Instruction): |
|---|
| 219 | opcode = Opcodes.Modulo |
|---|
| 220 | def __init__(self, codeloc): |
|---|
| 221 | self.codeloc = codeloc |
|---|
| 222 | def __call__(self, program): |
|---|
| 223 | try: |
|---|
| 224 | y = program.stack.pop() |
|---|
| 225 | x = program.stack.pop() |
|---|
| 226 | program.stack.append(x % y) |
|---|
| 227 | except IndexError: |
|---|
| 228 | if len(program.stack) == 0: |
|---|
| 229 | print "Error: Modulo with empty stack at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 230 | else: |
|---|
| 231 | print "Error: Modulo with only one stack entry at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 232 | program.programcounter = None |
|---|
| 233 | def __str__(self): |
|---|
| 234 | return "<Modulo>" |
|---|
| 235 | __repr__ = __str__ |
|---|
| 236 | |
|---|
| 237 | class Store(Instruction): |
|---|
| 238 | opcode = Opcodes.Store |
|---|
| 239 | def __init__(self, codeloc): |
|---|
| 240 | self.codeloc = codeloc |
|---|
| 241 | def __call__(self, program): |
|---|
| 242 | try: |
|---|
| 243 | val = program.stack.pop() |
|---|
| 244 | addr = program.stack.pop() |
|---|
| 245 | program.heap[addr] = val |
|---|
| 246 | except IndexError: |
|---|
| 247 | if len(program.stack) == 0: |
|---|
| 248 | print "Error: Store with empty stack at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 249 | else: |
|---|
| 250 | print "Error: Store with only one stack entry at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 251 | program.programcounter = None |
|---|
| 252 | def __str__(self): |
|---|
| 253 | return "<Store>" |
|---|
| 254 | __repr__ = __str__ |
|---|
| 255 | class Retrieve(Instruction): |
|---|
| 256 | opcode = Opcodes.Retrieve |
|---|
| 257 | def __init__(self, codeloc): |
|---|
| 258 | self.codeloc = codeloc |
|---|
| 259 | def __call__(self, program): |
|---|
| 260 | try: |
|---|
| 261 | addr = program.stack.pop() |
|---|
| 262 | program.stack.append(program.heap[addr]) |
|---|
| 263 | except IndexError: |
|---|
| 264 | print "Error: Retrieve with empty stack at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 265 | program.programcounter = None |
|---|
| 266 | except KeyError: |
|---|
| 267 | print "Error: Retrieve from an address not stored to yet at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 268 | program.programcounter = None |
|---|
| 269 | def __str__(self): |
|---|
| 270 | return "<Retrieve>" |
|---|
| 271 | __repr__ = __str__ |
|---|
| 272 | |
|---|
| 273 | class Label(Instruction): |
|---|
| 274 | opcode = Opcodes.Label |
|---|
| 275 | def __init__(self, codeloc, label): |
|---|
| 276 | self.codeloc = codeloc |
|---|
| 277 | self.label = label |
|---|
| 278 | def __call__(self, program): |
|---|
| 279 | pass # a label is a no-op |
|---|
| 280 | def __str__(self): |
|---|
| 281 | return "<Label %s>" % repr(self.label) |
|---|
| 282 | __repr__ = __str__ |
|---|
| 283 | class Call(Instruction): |
|---|
| 284 | opcode = Opcodes.Call |
|---|
| 285 | def __init__(self, codeloc, label): |
|---|
| 286 | self.codeloc = codeloc |
|---|
| 287 | self.label = label |
|---|
| 288 | def __call__(self, program): |
|---|
| 289 | try: |
|---|
| 290 | program.pcstack.append(program.programcounter) |
|---|
| 291 | program.programcounter = program.labels[self.label] |
|---|
| 292 | except KeyError: |
|---|
| 293 | print "Error: Call to undefined label at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 294 | program.programcounter = None |
|---|
| 295 | def __str__(self): |
|---|
| 296 | return "<Call %s>" % repr(self.label) |
|---|
| 297 | __repr__ = __str__ |
|---|
| 298 | class Jump(Instruction): |
|---|
| 299 | opcode = Opcodes.Jump |
|---|
| 300 | def __init__(self, codeloc, label): |
|---|
| 301 | self.codeloc = codeloc |
|---|
| 302 | self.label = label |
|---|
| 303 | def __call__(self, program): |
|---|
| 304 | try: |
|---|
| 305 | program.programcounter = program.labels[self.label] |
|---|
| 306 | except KeyError: |
|---|
| 307 | print "Error: Jump to undefined label at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 308 | program.programcounter = None |
|---|
| 309 | def __str__(self): |
|---|
| 310 | return "<Jump %s>" % repr(self.label) |
|---|
| 311 | __repr__ = __str__ |
|---|
| 312 | class JumpZero(Instruction): |
|---|
| 313 | opcode = Opcodes.JumpZero |
|---|
| 314 | def __init__(self, codeloc, label): |
|---|
| 315 | self.codeloc = codeloc |
|---|
| 316 | self.label = label |
|---|
| 317 | def __call__(self, program): |
|---|
| 318 | try: |
|---|
| 319 | if program.stack.pop() == 0: |
|---|
| 320 | program.programcounter = program.labels[self.label] |
|---|
| 321 | except KeyError: |
|---|
| 322 | print "Error: JumpZero to undefined label at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 323 | program.programcounter = None |
|---|
| 324 | def __str__(self): |
|---|
| 325 | return "<JumpZero %s>" % repr(self.label) |
|---|
| 326 | __repr__ = __str__ |
|---|
| 327 | class JumpNeg(Instruction): |
|---|
| 328 | opcode = Opcodes.JumpNeg |
|---|
| 329 | def __init__(self, codeloc, label): |
|---|
| 330 | self.codeloc = codeloc |
|---|
| 331 | self.label = label |
|---|
| 332 | def __call__(self, program): |
|---|
| 333 | try: |
|---|
| 334 | if program.stack.pop() < 0: |
|---|
| 335 | program.programcounter = program.labels[self.label] |
|---|
| 336 | except KeyError: |
|---|
| 337 | print "Error: JumpNeg to undefined label at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 338 | program.programcounter = None |
|---|
| 339 | def __str__(self): |
|---|
| 340 | return "<JumpNeg %s>" % repr(self.label) |
|---|
| 341 | __repr__ = __str__ |
|---|
| 342 | class Return(Instruction): |
|---|
| 343 | opcode = Opcodes.Return |
|---|
| 344 | def __init__(self, codeloc): |
|---|
| 345 | self.codeloc = codeloc |
|---|
| 346 | def __call__(self, program): |
|---|
| 347 | try: |
|---|
| 348 | program.programcounter = program.pcstack.pop() |
|---|
| 349 | except IndexError: |
|---|
| 350 | print "Error: Return without Call at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 351 | program.programcounter = None |
|---|
| 352 | def __str__(self): |
|---|
| 353 | return "<Return>" |
|---|
| 354 | __repr__ = __str__ |
|---|
| 355 | class End(Instruction): |
|---|
| 356 | opcode = Opcodes.End |
|---|
| 357 | def __init__(self, codeloc): |
|---|
| 358 | self.codeloc = codeloc |
|---|
| 359 | def __call__(self, program): |
|---|
| 360 | program.programcounter = None |
|---|
| 361 | def __str__(self): |
|---|
| 362 | return "<End>" |
|---|
| 363 | __repr__ = __str__ |
|---|
| 364 | |
|---|
| 365 | class OutputChar(Instruction): |
|---|
| 366 | opcode = Opcodes.OutputChar |
|---|
| 367 | def __init__(self, codeloc): |
|---|
| 368 | self.codeloc = codeloc |
|---|
| 369 | def __call__(self, program): |
|---|
| 370 | try: |
|---|
| 371 | sys.stdout.write(chr(program.stack.pop())) |
|---|
| 372 | except ValueError: |
|---|
| 373 | print "Error: OutputChar value not in range 0-255 at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 374 | program.programcounter = None |
|---|
| 375 | except IndexError: |
|---|
| 376 | print "Error: OutputChar on empty stack at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 377 | program.programcounter = None |
|---|
| 378 | def __str__(self): |
|---|
| 379 | return "<OutputChar>" |
|---|
| 380 | __repr__ = __str__ |
|---|
| 381 | class OutputNum(Instruction): |
|---|
| 382 | opcode = Opcodes.OutputNum |
|---|
| 383 | def __init__(self, codeloc): |
|---|
| 384 | self.codeloc = codeloc |
|---|
| 385 | def __call__(self, program): |
|---|
| 386 | try: |
|---|
| 387 | sys.stdout.write(str(program.stack.pop())) |
|---|
| 388 | except IndexError: |
|---|
| 389 | print "Error: OutputNum on empty stack at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 390 | program.programcounter = None |
|---|
| 391 | def __str__(self): |
|---|
| 392 | return "<OutputNum>" |
|---|
| 393 | __repr__ = __str__ |
|---|
| 394 | class InputChar(Instruction): |
|---|
| 395 | opcode = Opcodes.InputChar |
|---|
| 396 | def __init__(self, codeloc): |
|---|
| 397 | self.codeloc = codeloc |
|---|
| 398 | def __call__(self, program): |
|---|
| 399 | try: |
|---|
| 400 | a = sys.stdin.read(1) |
|---|
| 401 | if (a == ''): |
|---|
| 402 | program.heap[program.stack.pop()] = -1 |
|---|
| 403 | else: |
|---|
| 404 | program.heap[program.stack.pop()] = ord(a) |
|---|
| 405 | except IndexError: |
|---|
| 406 | print "Error: InputChar on empty stack at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 407 | program.programcounter = None |
|---|
| 408 | def __str__(self): |
|---|
| 409 | return "<InputChar>" |
|---|
| 410 | __repr__ = __str__ |
|---|
| 411 | class InputNum(Instruction): |
|---|
| 412 | opcode = Opcodes.InputNum |
|---|
| 413 | def __init__(self, codeloc): |
|---|
| 414 | self.codeloc = codeloc |
|---|
| 415 | def __call__(self, program): |
|---|
| 416 | try: |
|---|
| 417 | program.heap[program.stack.pop()] = int(sys.stdin.readline()) |
|---|
| 418 | except IndexError: |
|---|
| 419 | print "Error: InputNum on empty stack at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 420 | program.programcounter = None |
|---|
| 421 | except ValueError: |
|---|
| 422 | print "Error: Entered value not a number for InputNum at byte 0x%X (line %d char %d)" % self.codeloc |
|---|
| 423 | program.programcounter = None |
|---|
| 424 | def __str__(self): |
|---|
| 425 | return "<InputNum>" |
|---|
| 426 | __repr__ = __str__ |
|---|
| 427 | class Trace(Instruction): |
|---|
| 428 | opcode = Opcodes.Trace |
|---|
| 429 | def __init__(self, codeloc): |
|---|
| 430 | self.codeloc = codeloc |
|---|
| 431 | def __call__(self, program): |
|---|
| 432 | print repr(program) |
|---|
| 433 | def __str__(self): |
|---|
| 434 | return "<Trace>" |
|---|
| 435 | __repr__ = __str__ |
|---|
| 436 | |
|---|
| 437 | def vm(prog): |
|---|
| 438 | while prog.programcounter >= 0: |
|---|
| 439 | a = prog.programdata[prog.programcounter] |
|---|
| 440 | prog.programcounter += 1 |
|---|
| 441 | #sys.stdout.write(str(a)) # uncomment to perform trace |
|---|
| 442 | a(prog) |
|---|