diff options
author | Suleyman Farajli <suleyman@farajli.net> | 2024-12-30 02:47:15 +0400 |
---|---|---|
committer | Suleyman Farajli <suleyman@farajli.net> | 2024-12-30 02:47:15 +0400 |
commit | 450f522047f447e2a8881c52b102786c9d3b4d2d (patch) | |
tree | f5593ad6fd00bb9a594b9ca90d67aef04f9d46dc /src | |
parent | f15e7a927d43954d3cc9b2d549be60fe7af3776f (diff) |
tokenizer and parser added
Diffstat (limited to 'src')
-rw-r--r-- | src/main.go | 264 |
1 files changed, 144 insertions, 120 deletions
diff --git a/src/main.go b/src/main.go index 24b5db1..e7943a0 100644 --- a/src/main.go +++ b/src/main.go @@ -9,78 +9,147 @@ import ( var print = fmt.Println -func readfile(path string) []string { +type Operation struct { + name string + label string + crosslabel string + data string +} + +type Token struct { + str string + line int + offset int +} - var raw []string; - reg := regexp.MustCompile(`\s`) +/* TODO: add error checking */ +func tokenize(path string) []Token { + var tokens []Token; + + reg := regexp.MustCompile(`\n`) dat, err := os.ReadFile(path); if (err != nil) { - panic("failed to read file"); + panic("Failed to read file"); } - tmp := reg.Split(string(dat), -1); - /* TODO: add comments */ + lines := reg.Split(string(dat), -1); + lines = lines[:len(lines) - 1] /* Remove trailing empty line at the end */ + + /* FIXME: offset value apperas to be one value less when using tabs */ + for lineIndex := 0; lineIndex < len(lines); lineIndex++ { + line := lines[lineIndex] + buf := "" + for offset := 0; offset < len(line); offset++ { + char := string(line[offset]) + if char == "#" { + break + } + if char != " " && char != "\t" { + buf += char + if offset != len(line) - 1 { + continue + } + } + if buf == "" { + continue + } + tokenBuf := Token{str: buf, line: lineIndex + 1, offset: offset - len(buf) + 1} + tokens = append(tokens, tokenBuf) + + buf = "" + } + } + return tokens +} - for i := range tmp { - if tmp[i] != "" { - raw = append(raw, tmp[i]); +func parse(tokens[]Token) []Operation { + var ops[] Operation + var iflabels[] int + var iflabel int = 0 + for i := 0; i < len(tokens); i++ { + var op Operation + _, err := strconv.Atoi(tokens[i].str); + if err == nil { + op.name = "number" + op.data = tokens[i].str + /* FIXME: append for ops called at the end */ + ops = append(ops, op) + continue; + } + if tokens[i].str[0] == '"' { + panic("string parsing is not implemented") } - }; - return raw; -} + switch tokens[i].str { + case "+": + op.name = "plus" + case "-": + op.name = "minus" + case "=": + op.name = "equal" + case ">": + op.name = "greater" + case "<": + op.name = "less" + case ".": + op.name = "dump" + case "dup": + op.name = "duplicate" + case "rem": + op.name = "remove" + case "swap": + op.name = "swap" + case "if": + op.name = "if" + op.crosslabel = fmt.Sprintf(".if%d", iflabel) + iflabels = append(iflabels, iflabel) + iflabel++ + case "else": + op.name = "else" + op.crosslabel = fmt.Sprintf(".if%d", iflabel) + op.label = fmt.Sprintf(".if%d",iflabels[len(iflabels) - 1]) + iflabels = iflabels[:len(iflabels) - 1] + iflabels = append(iflabels, iflabel) + iflabel++ + case "fi": + op.name = "fi" + op.label = fmt.Sprintf(".if%d", iflabels[len(iflabels) - 1]) + iflabels = iflabels[:len(iflabels) - 1] -func parseString(raw[] string, i int) (str string, strLen int, endIndex int) { - str = "" - for ;; i++ { - word := raw[i] - strLen += len(word) - str += word - if word[len(word) - 1] == '"' { - break; + case "while": fallthrough + case "do": fallthrough + case "done": + panic("Loops not implemented") + default: + panic("invalid word") } - str += " " - strLen++ + ops = append(ops, op) } - - return str, strLen, i + return ops } -func compile(raw[]string) { - var iflabels[] int - var looplabels[] int - var strings[][2] string - +func compileX86_64(ops[] Operation) { print("section .text") print("global _start") print("_start:") - for i := 0; i < len(raw); i++ { - number, err := strconv.Atoi(raw[i]); - if err == nil { - print(" ;; PUSHING TO STACK") - print(" push", number) - continue; - } - - switch raw[i] { - case "+": - print(" ;; PLUS") + for i := 0; i < len(ops); i++ { + fmt.Printf(" ;; %s\n", ops[i].name) + switch ops[i].name { + case "plus": print(" pop rsi") print(" pop rax") print(" add rax, rsi") print(" push rax") - case "-": - print(" ;; MINUS") + case "minus": print(" pop rsi") print(" pop rax") print(" sub rax, rsi") print(" push rax") - case ">": - print(" ;; GREATER") + case "greater": print(" mov r10, 0") print(" mov r11, 1") print(" pop rsi") @@ -89,8 +158,7 @@ func compile(raw[]string) { print(" cmovg r10, r11") print(" push r10") - case "<": - print(" ;; LESS") + case "less": print(" mov r10, 0") print(" mov r11, 1") print(" pop rsi") @@ -99,8 +167,7 @@ func compile(raw[]string) { print(" cmovl r10, r11") print(" push r10") - case "=": - print(" ;; EQUAL") + case "equal": print(" mov r10, 0") print(" mov r11, 1") print(" pop rsi") @@ -109,90 +176,50 @@ func compile(raw[]string) { print(" cmove r10, r11") print(" push r10") - case ".": - print(" ;; DUMP") + case "dump": print(" pop rdi") print(" call .dump") - case "dup": - print(" ;; DUPLICATE") + case "duplicate": print(" pop r10") print(" push r10") print(" push r10") - case "if": - print(" ;; IF") - print(" pop r10") - print(" cmp r10, 0") - fmt.Printf(" je .if%d\n", i) - iflabels = append(iflabels, i) - - case "else": - print(" ;; ELSE") - fmt.Printf(" jmp .if%d\n", i) - fmt.Printf(".if%d:\n", iflabels[len(iflabels) - 1]) - iflabels = iflabels[:len(iflabels) - 1] - iflabels = append(iflabels, i) - - case "endif": - print(" ;; ENDIF") - fmt.Printf(".if%d:\n", iflabels[len(iflabels) - 1]) - iflabels = iflabels[:len(iflabels) - 1] - - case "while": - print(" ;; WHILE") - fmt.Printf(".loop%d:\n", i); - looplabels = append(looplabels, i) - - case "do": - print(" ;; DO") - print(" pop r10") - print(" cmp r10, 0") - fmt.Printf(" je .endloop%d\n", looplabels[len(looplabels) - 1]) - - case "endloop": - print(" ;; ENDLOOP") - fmt.Printf(" jmp .loop%d\n", looplabels[len(looplabels) - 1]) - fmt.Printf(".endloop%d:\n", looplabels[len(looplabels) - 1]) - looplabels = looplabels[:len(looplabels) - 1] - - case "pushstr": - str, strLen, lastIndex := parseString(raw, i + 1) - - print(" ;; PUSHING STRING LENGTH") - fmt.Printf(" push %d\n", strLen) - print(" ;; PUSHING STRING") - fmt.Printf(" push string_%d\n", i); - tmp := [2]string{str, fmt.Sprintf("string_%d", i)} - strings = append(strings, tmp) - i = lastIndex; case "rem": - print(" ;; REMOVE") print(" pop r10") + case "swap": - print(" ;; SWAP") print(" pop r11") print(" pop r10") print(" push r11") print(" push r10") - /* Functions */ - case "exit": - print(" ;; EXIT") - print(" pop rdi") - print(" mov rax, 60") - print(" syscall") + case "if": + print(" pop r10") + print(" cmp r10, 0") + fmt.Printf(" je %s\n", ops[i].crosslabel) - case "println": - print(" ;; PRINTLN") - print(" pop rsi") - print(" pop rdx") - print(" mov rdi, 1") - print(" mov rax, 1") - print(" syscall") + case "else": + fmt.Printf(" jmp %s\n", ops[i].crosslabel) + fmt.Printf("%s:\n", ops[i].label) + + case "fi": + fmt.Printf("%s:\n", ops[i].label) + + case "while": fallthrough + case "do": fallthrough + case "done": + panic("Unreachable: loops not implemented") + + case "number": + number, err := strconv.Atoi(ops[i].data) + if err != nil { + panic("Unreachable") + } + fmt.Printf(" push %d\n", number) default: - panic("invalid word") + panic("Unreachable") } } @@ -278,10 +305,6 @@ func compile(raw[]string) { print(" ret") print("section .data") - for i := 0; i < len(strings); i++ { - fmt.Printf("%s: db %s, 10\n", strings[i][1], strings[i][0]) - } - print("") } func main() { @@ -292,6 +315,7 @@ func main() { panic("Invaid usage"); } - raw := readfile(argv[argc - 1]) - compile(raw); + tokens := tokenize(argv[argc - 1]) + ops := parse(tokens) + compileX86_64(ops) } |