From ce8a04b4395cf84ccbb15d283f3247b22d7a0b39 Mon Sep 17 00:00:00 2001 From: HiveBeats Date: Tue, 23 Jan 2024 16:52:08 +0700 Subject: [PATCH] Introduce calls --- elm.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/elm.go b/elm.go index 23fbf34..0b42250 100644 --- a/elm.go +++ b/elm.go @@ -26,6 +26,8 @@ const ( EQ Operation = 8 JMP Operation = 9 JMPIF Operation = 10 + CALL Operation = 11 + RET Operation = 12 ) type Inst struct { @@ -33,9 +35,31 @@ type Inst struct { Operand int32 } +type Frame struct { + Locals map[int]int32 + ReturnAddress int +} + +func CreateFrame(returnAddress int32) *Frame { + f := Frame{} + f.Locals = make(map[int]int32) + f.ReturnAddress = int(returnAddress) + + return &f +} + +func (f *Frame) StoreVariable(address int, value int32) { + f.Locals[address] = value +} + +func (f *Frame) GetVariable(address int) int32 { + return f.Locals[address] +} + type Machine struct { program []Inst stack []int32 + stackFrame []*Frame ip int32 sp int32 isHalted bool; @@ -45,6 +69,8 @@ func Constructor() *Machine { m := Machine{} m.program = make([]Inst, 0) m.stack = make([]int32, STACK_SIZE) + m.stackFrame = make([]*Frame, 0) + m.stackFrame = append(m.stackFrame, CreateFrame(0)) m.ip = 0 m.sp = 0 m.isHalted = false @@ -165,6 +191,21 @@ func (m* Machine) Execute() error { } else { m.ip++ } + case CALL: + if (int32(len(m.program) - 1) < instr.Operand || instr.Operand < 0) { + return errors.New("Illegal access") + } + + m.stackFrame = append(m.stackFrame, CreateFrame(m.ip + 1)) + m.ip = instr.Operand + case RET: + if len(m.stackFrame) < 2 { + return errors.New("Stackframe underflow") + } + + currentFrame := m.stackFrame[len(m.stackFrame) - 1] + m.stackFrame = m.stackFrame[:len(m.stackFrame) - 1] + m.ip = int32(currentFrame.ReturnAddress) } return nil } @@ -269,6 +310,14 @@ func (m* Machine) InterpretProgramFromFile(filename string) error { m.Push(Inst{Operation: JMP, Operand: int32(op)}) } else if (strings.HasPrefix(line, "EQ")) { m.Push(Inst{Operation: EQ}) + } else if (strings.HasPrefix(line, "CALL")) { + op, err := strconv.Atoi(strings.Fields(line)[1]) + if err != nil { + return err + } + m.Push(Inst{Operation: CALL, Operand: int32(op)}) + } else if (strings.HasPrefix(line, "RET")) { + m.Push(Inst{Operation: RET}) } }