feat: separate compiler executable

This commit is contained in:
2024-01-25 00:14:40 +07:00
parent ab0efa2c0c
commit 8cd8859c85
8 changed files with 227 additions and 84 deletions

BIN
compiler/compiler Executable file

Binary file not shown.

190
compiler/compiler.go Normal file
View File

@@ -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()
}

7
compiler/go.mod Normal file
View File

@@ -0,0 +1,7 @@
module e1lama/compiler
go 1.20
replace e1lama/elm => ../core
require e1lama/elm v0.0.0-00010101000000-000000000000

4
compiler/go.sum Normal file
View File

@@ -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=

View File

@@ -1,13 +1,14 @@
package main package elm
import ( import (
"bufio" // "unicode"
"strings" // "bytes"
// "bufio"
// "strings"
"fmt" "fmt"
"os" //"os"
"errors" "errors"
"encoding/binary" // "encoding/binary"
"strconv" // "strconv"
) )
const STACK_SIZE = 1024 const STACK_SIZE = 1024
@@ -251,6 +252,7 @@ func (m* Machine) Print() {
} }
} }
/*
func (m* Machine) DumpProgramBinary(filename string) error { func (m* Machine) DumpProgramBinary(filename string) error {
f, err := os.Create(filename) f, err := os.Create(filename)
if err != nil { if err != nil {
@@ -283,89 +285,28 @@ func (m* Machine) LoadProgramFromBinary(filename string) error {
m.program = program m.program = program
return nil 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() { func main() {
m := Constructor() m := Constructor()
err := m.InterpretProgramFromFile("program.lil") // err := m.InterpretProgramFromFile("program.lil")
if err != nil { // if err != nil {
fmt.Fprintf(os.Stderr, "[ERR] %s\n", err); // fmt.Fprintf(os.Stderr, "[ERR] %s\n", err);
os.Exit(1) // os.Exit(1)
} // }
stackCounter := 0 stackCounter := 0
jumpCounter := 0
for !m.isHalted && stackCounter < 100 { for !m.isHalted && stackCounter < 100 {
if (m.program[m.ip].Operation == JMPIF) {
jumpCounter++
fmt.Printf("Jump Counter: %d \n", jumpCounter)
}
err = m.Execute() err = m.Execute()
m.Print() //m.Print()
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "[ERR] %s\n", err); fmt.Fprintf(os.Stderr, "[ERR] %s\n", err);
os.Exit(1) os.Exit(1)
@@ -375,3 +316,4 @@ func main() {
} }
m.Print() m.Print()
} }
*/

View File

@@ -1,4 +1,4 @@
package main package elm
import ( import (
"testing" "testing"

View File

View File