diff --git a/compiler/compiler b/compiler/compiler new file mode 100755 index 0000000..a896792 Binary files /dev/null and b/compiler/compiler differ diff --git a/compiler/compiler.go b/compiler/compiler.go new file mode 100644 index 0000000..f6d8fc2 --- /dev/null +++ b/compiler/compiler.go @@ -0,0 +1,190 @@ +package main + +import ( + "unicode" + "bytes" + "bufio" + "strings" + "strconv" + "os" + "fmt" + "errors" + . "e1lama/elm" +) + + +var InstructionTable map[string]Operation = map[string]Operation{ + "HALT": 0, + "PUSH": 1, + "POP" : 2, + "DUP" : 3, + "ADD" : 4, + "SUB" : 5, + "MUL" : 6, + "DIV" : 7, + "EQ" : 8, + "JMP" : 9, + "JMPIF" : 10, + "CALL" : 11, + "RET" : 12, + "STORE" : 13, + "GET" : 14, +} + + +type PreprocessorResult struct { + LabelMap map[string]int + Listing *bytes.Buffer +} + +func PreprocessAssembly(f *os.File) (*PreprocessorResult, error) { + labelMap := make(map[string]int) + lineCount := 0 + + buf := bytes.Buffer{} + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := scanner.Text() + + if (strings.HasSuffix(line, ":")) { + labelMap[strings.Split(line, ":")[0]] = lineCount + } else { + _, ok := InstructionTable[strings.Fields(line)[0]] + if (ok) { + lineCount++ + fmt.Fprintln(&buf, line) + } else { + return nil, errors.New("Unknown instruction: " + line) + } + } + + } + + return &PreprocessorResult{ LabelMap: labelMap, Listing: &buf }, nil +} + +func parseProgramFromFile(m* Machine, filename string) error { + f, err := os.Open(filename) + if err != nil { + return errors.New("Couldn't open file") + } + defer f.Close() + + preprocessed, err := PreprocessAssembly(f) + if err != nil { + return err + } + fmt.Println(preprocessed.LabelMap) + scanner := bufio.NewScanner(preprocessed.Listing) + + for scanner.Scan() { + line := scanner.Text() + if (strings.HasPrefix(line, "//")) { + continue; + } else 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 := parseLabelledOperand(line, preprocessed) + if err != nil { + return err + } + m.Push(Inst{Operation: JMPIF, Operand: int32(op)}) + } else if (strings.HasPrefix(line, "JMP")) { + op, err := parseLabelledOperand(line, preprocessed) + if err != nil { + return err + } + 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 := parseLabelledOperand(line, preprocessed) + if err != nil { + return err + } + m.Push(Inst{Operation: CALL, Operand: int32(op)}) + } else if (strings.HasPrefix(line, "RET")) { + m.Push(Inst{Operation: RET}) + } else if (strings.HasPrefix(line, "STORE")) { + op, err := strconv.Atoi(strings.Fields(line)[1]) + if err != nil { + return err + } + m.Push(Inst{Operation: STORE, Operand: int32(op)}) + } else if (strings.HasPrefix(line, "GET")) { + op, err := strconv.Atoi(strings.Fields(line)[1]) + if err != nil { + return err + } + m.Push(Inst{Operation: GET, Operand: int32(op)}) + } else { + return errors.New("Unknown instruction: " + line) + } + } + + if err := scanner.Err(); err != nil { + return err + } + + return nil +} + +func Any[T any](ts []T, pred func(T) bool) bool { + for _, t := range ts { + if pred(t) { + return true + } + } + return false +} + +func parseLabelledOperand(line string, preprocessed *PreprocessorResult) (int, error) { + op := 0; + dest := strings.Fields(line)[1] + containsLetter := Any([]rune(dest), unicode.IsLetter) + if (containsLetter) { + op = preprocessed.LabelMap[dest] + } else { + op, err := strconv.Atoi(dest) + if err != nil { + return op, err + } + } + + return op, nil +} + +func main() { + m := Constructor() + + err := parseProgramFromFile(m, "../program.lil") + if err != nil { + fmt.Fprintf(os.Stderr, "[ERR] %s\n", err); + os.Exit(1) + } + + m.Run() +} diff --git a/compiler/go.mod b/compiler/go.mod new file mode 100644 index 0000000..466381e --- /dev/null +++ b/compiler/go.mod @@ -0,0 +1,7 @@ +module e1lama/compiler + +go 1.20 + +replace e1lama/elm => ../core + +require e1lama/elm v0.0.0-00010101000000-000000000000 \ No newline at end of file diff --git a/compiler/go.sum b/compiler/go.sum new file mode 100644 index 0000000..1fdbe10 --- /dev/null +++ b/compiler/go.sum @@ -0,0 +1,4 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/elm.go b/core/elm.go similarity index 72% rename from elm.go rename to core/elm.go index 90b8f1c..a83b79c 100644 --- a/elm.go +++ b/core/elm.go @@ -1,13 +1,14 @@ -package main - +package elm import ( - "bufio" - "strings" + // "unicode" + // "bytes" + // "bufio" + // "strings" "fmt" - "os" + //"os" "errors" - "encoding/binary" - "strconv" + // "encoding/binary" + // "strconv" ) const STACK_SIZE = 1024 @@ -251,6 +252,7 @@ func (m* Machine) Print() { } } +/* func (m* Machine) DumpProgramBinary(filename string) error { f, err := os.Create(filename) if err != nil { @@ -283,89 +285,28 @@ func (m* Machine) LoadProgramFromBinary(filename string) error { 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}) - } 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}) - } - } - - if err := scanner.Err(); err != nil { - return err - } - - return nil -} - +*/ +/* func main() { m := Constructor() - - err := m.InterpretProgramFromFile("program.lil") - if err != nil { - fmt.Fprintf(os.Stderr, "[ERR] %s\n", err); - os.Exit(1) - } + // err := m.InterpretProgramFromFile("program.lil") + // if err != nil { + // fmt.Fprintf(os.Stderr, "[ERR] %s\n", err); + // os.Exit(1) + // } stackCounter := 0 + jumpCounter := 0 for !m.isHalted && stackCounter < 100 { + + if (m.program[m.ip].Operation == JMPIF) { + jumpCounter++ + fmt.Printf("Jump Counter: %d \n", jumpCounter) + } + err = m.Execute() - m.Print() + //m.Print() if err != nil { fmt.Fprintf(os.Stderr, "[ERR] %s\n", err); os.Exit(1) @@ -375,3 +316,4 @@ func main() { } m.Print() } +*/ \ No newline at end of file diff --git a/elm_test.go b/core/elm_test.go similarity index 99% rename from elm_test.go rename to core/elm_test.go index 9be45d8..95903d0 100644 --- a/elm_test.go +++ b/core/elm_test.go @@ -1,4 +1,4 @@ -package main +package elm import ( "testing" diff --git a/go.mod b/core/go.mod similarity index 100% rename from go.mod rename to core/go.mod diff --git a/go.sum b/core/go.sum similarity index 100% rename from go.sum rename to core/go.sum