package main import ( "fmt" "os" "errors" ) const STACK_SIZE = 1024 type Operation int const ( HALT Operation = 0 PUSH Operation = 1 POP Operation = 2 DUP Operation = 3 ADD Operation = 4 SUB Operation = 5 MUL Operation = 6 DIV Operation = 7 EQ Operation = 8 JMP Operation = 9 JMPIF Operation = 10 ) type Inst struct { Operation Operation Operand int } type Machine struct { program []Inst stack []int ip int sp int isHalted bool; } func Constructor() *Machine { m := Machine{} m.program = make([]Inst, 0) m.stack = make([]int, STACK_SIZE) m.ip = 0 m.sp = 0 m.isHalted = false return &m } func (m* Machine) Push(i Inst) error { m.program = append(m.program, i) return nil } func (m* Machine) Execute() error { instr := m.program[m.ip] switch op := instr.Operation; op { case HALT: m.isHalted = true case PUSH: if (m.sp >= STACK_SIZE) { return errors.New("Stack Overflow"); } m.stack[m.sp] = instr.Operand m.sp++ m.ip++ case POP: if (m.sp <= 0) { return errors.New("Empty Stack") } m.stack[m.sp] = 0 m.sp-- case DUP: if (m.sp - instr.Operand <= 0) { return errors.New("Stack Underflow") } if (m.sp >= STACK_SIZE) { return errors.New("Stack Overflow"); } if (instr.Operand < 0) { return errors.New("Illegal access") } m.stack[m.sp] = m.stack[m.sp - 1 - instr.Operand] m.sp++ case ADD: if (m.sp < 2) { return errors.New("Stack size is less than required to execute binary operation") } m.stack[m.sp - 2] += m.stack[m.sp - 1]; m.sp-- m.ip++ case SUB: if (m.sp < 2) { return errors.New("Stack size is less than required to execute binary operation") } m.stack[m.sp - 2] -= m.stack[m.sp - 1]; m.sp-- m.ip++ case MUL: if (m.sp < 2) { return errors.New("Stack size is less than required to execute binary operation") } m.stack[m.sp - 2] *= m.stack[m.sp - 1]; m.sp-- m.ip++ case DIV: if (m.sp < 2) { return errors.New("Stack size is less than required to execute binary operation") } if (m.stack[m.sp - 2] == 0 || m.stack[m.sp - 1] == 0) { return errors.New("Divide by zero exception") } m.stack[m.sp - 2] /= m.stack[m.sp - 1]; m.sp-- m.ip++ case EQ: if (m.sp < 2) { return errors.New("Stack size is less than required to execute binary operation") } eq := m.stack[m.sp - 1] == m.stack[m.sp - 2] if (eq) { m.stack[m.sp - 2] = 1 } else { m.stack[m.sp - 2] = 0 } m.sp-- m.ip++ case JMP: if (len(m.program) < instr.Operand || instr.Operand < 0) { return errors.New("Illegal access") } m.ip = instr.Operand case JMPIF: if (m.sp < 1) { return errors.New("Stack Underflow") } if (len(m.program) <= instr.Operand || instr.Operand < 0) { return errors.New("Illegal access") } if (m.stack[m.sp - 1] >= 1) { m.sp-- m.ip = instr.Operand } else { m.ip++ } } return nil } func (m* Machine) Print() { fmt.Println("Stack:"); for i := 0; i < m.sp; i++ { fmt.Println(m.stack[i]) } } func main() { m := Constructor() // m.Push(Inst{Operation: PUSH, Operand: 1}) // m.Push(Inst{Operation: PUSH, Operand: 2}) // m.Push(Inst{Operation: ADD}) // m.Push(Inst{Operation: PUSH, Operand: 2}) // m.Push(Inst{Operation: SUB}) // m.Push(Inst{Operation: PUSH, Operand: 6}) // m.Push(Inst{Operation: MUL}) // m.Push(Inst{Operation: PUSH, Operand: 2}) // m.Push(Inst{Operation: DIV}) // m.Push(Inst{Operation: HALT}) m.Push(Inst{Operation: PUSH, Operand: 1}) m.Push(Inst{Operation: JMPIF, Operand: 3}) m.Push(Inst{Operation: HALT}) m.Push(Inst{Operation: PUSH, Operand: 1}) m.Push(Inst{Operation: PUSH, Operand: 2}) m.Push(Inst{Operation: HALT}) stackCounter := 0 for !m.isHalted && stackCounter < 69 { err := m.Execute() m.Print() if err != nil { fmt.Fprintf(os.Stderr, "[ERR] %s\n", err); os.Exit(1) } stackCounter++ } }