diff --git a/.gitignore b/.gitignore index 6175f16..5c8db72 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -/elm \ No newline at end of file +/elm +*.bin +*.lil \ No newline at end of file diff --git a/elm.go b/elm.go index 5283ca8..bd9af45 100644 --- a/elm.go +++ b/elm.go @@ -1,14 +1,18 @@ package main import ( + "bufio" + "strings" "fmt" "os" "errors" + "encoding/binary" + "strconv" ) const STACK_SIZE = 1024 -type Operation int +type Operation int32 const ( HALT Operation = 0 @@ -26,21 +30,21 @@ const ( type Inst struct { Operation Operation - Operand int + Operand int32 } type Machine struct { program []Inst - stack []int - ip int - sp int + stack []int32 + ip int32 + sp int32 isHalted bool; } func Constructor() *Machine { m := Machine{} m.program = make([]Inst, 0) - m.stack = make([]int, STACK_SIZE) + m.stack = make([]int32, STACK_SIZE) m.ip = 0 m.sp = 0 m.isHalted = false @@ -139,7 +143,7 @@ func (m* Machine) Execute() error { m.sp-- m.ip++ case JMP: - if (len(m.program) < instr.Operand || instr.Operand < 0) { + if (int32(len(m.program)) < instr.Operand || instr.Operand < 0) { return errors.New("Illegal access") } @@ -149,7 +153,7 @@ func (m* Machine) Execute() error { return errors.New("Stack Underflow") } - if (len(m.program) <= instr.Operand || instr.Operand < 0) { + if (int32(len(m.program)) <= instr.Operand || instr.Operand < 0) { return errors.New("Illegal access") } @@ -165,11 +169,104 @@ func (m* Machine) Execute() error { func (m* Machine) Print() { fmt.Println("Stack:"); - for i := 0; i < m.sp; i++ { + for i := 0; int32(i) < m.sp; i++ { fmt.Println(m.stack[i]) } } +func (m* Machine) DumpProgramBinary(filename string) error { + f, err := os.Create(filename) + if err != nil { + return errors.New("Couldn't open file") + } + defer f.Close() + + err = binary.Write(f, binary.LittleEndian, m.program) + if err != nil { + return err + //return errors.New("Couldn't write to file") + } + + return nil +} + +func (m* Machine) LoadProgramFromBinary(filename string) error { + f, err := os.Open(filename) + if err != nil { + return errors.New("Couldn't open file") + } + defer f.Close() + + program := make([]Inst, STACK_SIZE) + err = binary.Read(f, binary.LittleEndian, &program) + if err != nil { + return err + } + + m.program = program + return nil +} + +func (m* Machine) InterpretProgramFromFile(filename string) error { + f, err := os.Open(filename) + if err != nil { + return errors.New("Couldn't open file") + } + defer f.Close() + + scanner := bufio.NewScanner(f) + + for scanner.Scan() { + line := scanner.Text() + + if (strings.HasPrefix(line, "HALT")){ + m.Push(Inst{Operation: HALT}) + } else if (strings.HasPrefix(line, "PUSH")) { + op, err := strconv.Atoi(strings.Fields(line)[1]) + if err != nil { + return err + } + m.Push(Inst{Operation: PUSH, Operand: int32(op)}) + } else if (strings.HasPrefix(line, "POP")) { + m.Push(Inst{Operation: POP}) + } else if (strings.HasPrefix(line, "DUP")) { + op, err := strconv.Atoi(strings.Fields(line)[1]) + if err != nil { + return err + } + m.Push(Inst{Operation: DUP, Operand: int32(op)}) + } else if (strings.HasPrefix(line, "ADD")) { + m.Push(Inst{Operation: ADD}) + } else if (strings.HasPrefix(line, "SUB")) { + m.Push(Inst{Operation: SUB}) + } else if (strings.HasPrefix(line, "DIV")) { + m.Push(Inst{Operation: DIV}) + } else if (strings.HasPrefix(line, "MUL")) { + m.Push(Inst{Operation: MUL}) + } else if (strings.HasPrefix(line, "JMPIF")) { + op, err := strconv.Atoi(strings.Fields(line)[1]) + if err != nil { + return err + } + m.Push(Inst{Operation: JMPIF, Operand: int32(op)}) + } else if (strings.HasPrefix(line, "JMP")) { + op, err := strconv.Atoi(strings.Fields(line)[1]) + if err != nil { + return err + } + m.Push(Inst{Operation: JMP, Operand: int32(op)}) + } else if (strings.HasPrefix(line, "EQ")) { + m.Push(Inst{Operation: EQ}) + } + } + + if err := scanner.Err(); err != nil { + return err + } + + return nil +} + func main() { m := Constructor() @@ -184,16 +281,21 @@ func main() { // 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}) - + // 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}) + err := m.InterpretProgramFromFile("program.lil") + if err != nil { + fmt.Fprintf(os.Stderr, "[ERR] %s\n", err); + os.Exit(1) + } + stackCounter := 0 - for !m.isHalted && stackCounter < 69 { - err := m.Execute() + for !m.isHalted { + err = m.Execute() m.Print() if err != nil { fmt.Fprintf(os.Stderr, "[ERR] %s\n", err); @@ -201,6 +303,6 @@ func main() { } stackCounter++ - } + m.Print() }