import sys class Program: def __init__(self): # static data self.programdata = [] self.labels = {} # dynamic data self.stack = [] self.heap = {} self.programcounter = 0 self.pcstack = [] def __str__(self): return "" % (len(self.programdata), len(self.labels), self.programcounter, len(self.stack), len(self.pcstack), len(self.heap)) def __repr__(self): 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) class Opcodes: # the numbers themselves are meaningless - they just have to be unique # Axx - stack ops Push = 0 # AA num - push num to stack Dup = 1 # ACA - push copy of TOS (top of stack) Swap = 2 # ACB - swap TOS and TOS-1 Discard = 3 # ACC - pop and discard TOS Ref = 4 # ABA num - push copy of TOS-num Slide = 5 # ABC num - pop and discard TOS-1 through TOS-num - keep TOS # - equiv to "ACB ACC" num times # BAxx - math ops Plus = 6 # BAAA - push TOS-1 + TOS Minus = 7 # BAAB - push TOS-1 - TOS Times = 8 # BAAC - push TOS-1 * TOS Divide = 9 # BABA - push TOS-1 / TOS (floored) Modulo = 10 # BABB - push TOS-1 % TOS # BBx - heap ops Store = 11 # BBA - write TOS to address TOS-1 Retrieve = 12 # BBB - read from address TOS # Cxx - flow ops Label = 13 # CAA label - mark a label Call = 14 # CAB label - call a subroutine Jump = 15 # CAC label - jump to a label JumpZero = 16 # CBA label - jump if TOS is zero JumpNeg = 17 # CBB label - jump if TOS is <0 Return = 18 # CBC - return from subroutine Trace = 24 # CCB - print core dump End = 19 # CCC - stop executing program # BCxx - I/O ops OutputChar = 20 # BCAA - output char from TOS OutputNum = 21 # BCAB - output int from TOS InputChar = 22 # BCBA - input char to address at TOS InputNum = 23 # BCBB - input int to address at TOS class Instruction: opcode = -1 def __init__(self, codeloc): self.codeloc = codeloc def __call__(self, program): raise "Hmm, calling a non-opcode? Strange tastes..." class Push(Instruction): opcode = Opcodes.Push def __init__(self, codeloc, value): self.codeloc = codeloc self.value = value def __call__(self, program): program.stack.append(self.value) def __str__(self): return "" % self.value __repr__ = __str__ class Dup(Instruction): opcode = Opcodes.Dup def __init__(self, codeloc): self.codeloc = codeloc def __call__(self, program): try: program.stack.append(program.stack[-1]) except IndexError: print "Error: Dup in empty stack at byte 0x%X (line %d char %d)" % self.codeloc program.programcounter = None def __str__(self): return "" __repr__ = __str__ class Swap(Instruction): opcode = Opcodes.Swap def __init__(self, codeloc): self.codeloc = codeloc def __call__(self, program): try: program.stack[-1],program.stack[-2] = program.stack[-2],program.stack[-1] except IndexError: if len(program.stack) == 0: print "Error: Swap in stack with only one element at byte 0x%X (line %d char %d)" % self.codeloc else: print "Error: Swap in empty stack at byte 0x%X (line %d char %d)" % self.codeloc program.programcounter = None def __str__(self): return "" __repr__ = __str__ class Discard(Instruction): opcode = Opcodes.Discard def __init__(self, codeloc): self.codeloc = codeloc def __call__(self, program): try: program.stack.pop() except IndexError: print "Error: Discard from empty stack at byte 0x%X (line %d char %d)" % self.codeloc program.programcounter = None def __str__(self): return "" __repr__ = __str__ class Ref(Instruction): opcode = Opcodes.Ref def __init__(self, codeloc, location): self.codeloc = codeloc self.location = -location - 1 def __call__(self, program): try: program.stack.append(program.stack[self.location]) except IndexError: print "Error: Ref value larger than stack size at byte 0x%X (line %d char %d)" % self.codeloc program.programcounter = None def __str__(self): return "" % -self.location __repr__ = __str__ class Slide(Instruction): opcode = Opcodes.Slide def __init__(self, codeloc, quantity): self.codeloc = codeloc self.quantity = -quantity - 1 def __call__(self, program): try: program.stack = program.stack[0:self.quantity] + [program.stack[-1]] except IndexError: if len(program.stack) == 0: print "Error: Slide from empty stack at byte 0x%X (line %d char %d)" % self.codeloc else: print "Error: Slide value larger than stack size at byte 0x%X (line %d char %d)" % self.codeloc program.programcounter = None def __str__(self): return "" % (-self.quantity + 1) __repr__ = __str__ class Plus(Instruction): opcode = Opcodes.Plus def __init__(self, codeloc): self.codeloc = codeloc def __call__(self, program): try: y = program.stack.pop() x = program.stack.pop() program.stack.append(x + y) except IndexError: if len(program.stack) == 0: print "Error: Plus with empty stack at byte 0x%X (line %d char %d)" % self.codeloc else: print "Error: Plus with only one stack entry at byte 0x%X (line %d char %d)" % self.codeloc program.programcounter = None def __str__(self): return "" __repr__ = __str__ class Minus(Instruction): opcode = Opcodes.Minus def __init__(self, codeloc): self.codeloc = codeloc def __call__(self, program): try: y = program.stack.pop() x = program.stack.pop() program.stack.append(x - y) except IndexError: if len(program.stack) == 0: print "Error: Minus with empty stack at byte 0x%X (line %d char %d)" % self.codeloc else: print "Error: Minus with only one stack entry at byte 0x%X (line %d char %d)" % self.codeloc program.programcounter = None def __str__(self): return "" __repr__ = __str__ class Times(Instruction): opcode = Opcodes.Times def __init__(self, codeloc): self.codeloc = codeloc def __call__(self, program): try: y = program.stack.pop() x = program.stack.pop() program.stack.append(x * y) except IndexError: if len(program.stack) == 0: print "Error: Times with empty stack at byte 0x%X (line %d char %d)" % self.codeloc else: print "Error: Times with only one stack entry at byte 0x%X (line %d char %d)" % self.codeloc program.programcounter = None def __str__(self): return "" __repr__ = __str__ class Divide(Instruction): opcode = Opcodes.Divide def __init__(self, codeloc): self.codeloc = codeloc def __call__(self, program): try: y = program.stack.pop() x = program.stack.pop() program.stack.append(x / y) except IndexError: if len(program.stack) == 0: print "Error: Divide with empty stack at byte 0x%X (line %d char %d)" % self.codeloc else: print "Error: Divide with only one stack entry at byte 0x%X (line %d char %d)" % self.codeloc program.programcounter = None def __str__(self): return "" __repr__ = __str__ class Modulo(Instruction): opcode = Opcodes.Modulo def __init__(self, codeloc): self.codeloc = codeloc def __call__(self, program): try: y = program.stack.pop() x = program.stack.pop() program.stack.append(x % y) except IndexError: if len(program.stack) == 0: print "Error: Modulo with empty stack at byte 0x%X (line %d char %d)" % self.codeloc else: print "Error: Modulo with only one stack entry at byte 0x%X (line %d char %d)" % self.codeloc program.programcounter = None def __str__(self): return "" __repr__ = __str__ class Store(Instruction): opcode = Opcodes.Store def __init__(self, codeloc): self.codeloc = codeloc def __call__(self, program): try: val = program.stack.pop() addr = program.stack.pop() program.heap[addr] = val except IndexError: if len(program.stack) == 0: print "Error: Store with empty stack at byte 0x%X (line %d char %d)" % self.codeloc else: print "Error: Store with only one stack entry at byte 0x%X (line %d char %d)" % self.codeloc program.programcounter = None def __str__(self): return "" __repr__ = __str__ class Retrieve(Instruction): opcode = Opcodes.Retrieve def __init__(self, codeloc): self.codeloc = codeloc def __call__(self, program): try: addr = program.stack.pop() program.stack.append(program.heap[addr]) except IndexError: print "Error: Retrieve with empty stack at byte 0x%X (line %d char %d)" % self.codeloc program.programcounter = None except KeyError: print "Error: Retrieve from an address not stored to yet at byte 0x%X (line %d char %d)" % self.codeloc program.programcounter = None def __str__(self): return "" __repr__ = __str__ class Label(Instruction): opcode = Opcodes.Label def __init__(self, codeloc, label): self.codeloc = codeloc self.label = label def __call__(self, program): pass # a label is a no-op def __str__(self): return "