package creature type Machine struct { Program []int stack []int block []int counter int pointer int } // Execute starts execution at the address specified by offset. The machine will // run until a HALT instruction is encountered, or the end of program memory is // reached. func (machine *Machine) Execute (offset int) { machine.counter = offset for { switch machine.instruction() { case 0x0: // PUSH // push the next word in program memory onto the stack machine.counter ++ machine.Push(machine.instruction()) case 0x1: // POP // pop the top word off of the stack, and discard it machine.Pop() case 0x2: // LOAD // push the word at an address onto the stack machine.Push(machine.Peek(machine.Pop())) case 0x3: // STOR // store a word at an address machine.Poke(machine.Pop(), machine.Pop()) case 0x4: // ADD // adds the last two words on the stack machine.Push(machine.Pop() + machine.Pop()) case 0x5: // SUB // subtracts the second to last word on the stack from // the last word on the stack machine.Push(machine.Pop() - machine.Pop()) case 0x6: // MUL // multiplies the last two words on the stack machine.Push(machine.Pop() * machine.Pop()) case 0x7: // DIV // divides the last word on the stack by the second to // last word on the stack machine.Push(machine.Pop() / machine.Pop()) case 0x8: // EQ // checks if the last two words on the stack are equal equal := 0 if machine.Pop() == machine.Pop() { equal = 1 } machine.Push(equal) case 0x9: // GT // checks if the last word on the stack is greater than // the second to last word on the stack greater := 0 if machine.Pop() > machine.Pop() { greater = 1 } machine.Push(greater) case 0xa: // LT // checks if the last word on the stack is less than the // second to last word on the stack less := 0 if machine.Pop() > machine.Pop() { less = 1 } machine.Push(less) case 0xb: // NEQ // checks if the last two words on the stack are not // equal notEqual := 0 if machine.Pop() != machine.Pop() { notEqual = 1 } machine.Push(notEqual) case 0xc: // MOD // performs a modulo operation of the second to last // word on the stack to the last word on the stack machine.Push(machine.Pop() % machine.Pop()) case 0xd: // HALT // stops execution return case 0xe: // JMP // jump to the address specified by the last word on the // stack if the second to last word on the stack is // nonzero jumpTo := machine.Pop() if machine.Pop() != 0 { machine.counter = jumpTo - 1 } case 0xf: } machine.counter ++ } } // Instruction returns the current instruction in program memory. func (machine *Machine) instruction () (instruction int) { instruction = machine.Program[machine.counter] return } // reallocateStack changes the size of the stack to something reasonable. This // should be called then the stack pointer is really small compared to the // actual stack size, or the stack pointer is bigger than the stack. func (machine *Machine) reallocateStack () { reallocatedStack := make([]int, machine.pointer * 3 / 2) copy(reallocatedStack, machine.stack) machine.stack = reallocatedStack } // Push pushes a word onto the stack, increasing the stack pointer and // reallocating the stack if necessary. func (machine *Machine) Push (word int) { machine.pointer ++ if len(machine.stack) <= machine.pointer { machine.reallocateStack() } } // Pop pops the last word off of the stack, and returns it, decreasing the stack // pointer and reallocating the stack if necessary. func (machine *Machine) Pop () (word int) { word = machine.stack[machine.pointer] machine.pointer -- if machine.pointer < len(machine.stack) / 3 { machine.reallocateStack() } return } // Peek returns the word at address in the block func (machine *Machine) Peek (address int) (word int) { if address < len(machine.block) { word = machine.block[address] } return } // Poke sets the value at address in the block to word func (machine *Machine) Poke (address int, word int) { if address >= len(machine.block) { reallocatedBlock := make([]int, address * 3 / 2) copy(reallocatedBlock, machine.block) machine.block = reallocatedBlock } } // Milk milks the stack machine func (machine *Machine) Milk () {}