aboutsummaryrefslogtreecommitdiff
path: root/main.go
diff options
context:
space:
mode:
authorAstatin <[email protected]>2024-09-24 15:01:58 +0900
committerAstatin <astatin@redacted>2024-09-24 15:01:58 +0900
commit748e8ba9e9afd67695ca62f3b691970f943071a6 (patch)
tree0bc707517ca95fe02e046a11616b18fbd685aa1f /main.go
parent1680bc5146b25d3631e6b7bfee3946ef59d906fd (diff)
Add labels in go assembler
Diffstat (limited to 'main.go')
-rw-r--r--main.go104
1 files changed, 88 insertions, 16 deletions
diff --git a/main.go b/main.go
index 101e8d7..b4fa941 100644
--- a/main.go
+++ b/main.go
@@ -7,9 +7,88 @@ import (
"strings"
)
+type ProgramState struct {
+ Labels map[string]uint
+ Defs map[string]any
+}
+
+func parseFile(input_file_name string, input []byte) ([]byte, error) {
+ lines := strings.Split(string(input), "\n")
+
+ state := ProgramState{
+ Labels: make(map[string]uint),
+ Defs: make(map[string]any),
+ }
+
+ label_line_number := uint(0)
+ for line_nb, line := range lines {
+ is_label_defined := strings.Contains(line, ":")
+
+ if is_label_defined {
+ parts := strings.Split(line, ":")
+ for _, label := range parts[:len(parts)-1] {
+ label = strings.ToUpper(label)
+ if _, ok := state.Labels[label]; ok {
+ fmt.Fprintf(
+ os.Stderr,
+ "File %s, line %d:\nLabel %s is already defined",
+ input_file_name,
+ line_nb,
+ label,
+ )
+ os.Exit(1)
+ }
+ state.Labels[label] = label_line_number
+ }
+
+ line = parts[len(parts)-1]
+ }
+
+ line = strings.TrimSpace(line)
+
+ next_instruction, err := Instructions.Parse(nil, line)
+ if err != nil {
+ return nil, fmt.Errorf(
+ "File %s, line %d (1st pass):\n%w",
+ input_file_name,
+ line_nb,
+ err,
+ )
+ }
+
+ // TODO: Handle the case of program bigger than MBC (or maybe do it directly in the parameters)
+ label_line_number += uint(len(next_instruction))
+ }
+
+ result := []byte{}
+ for line_nb, line := range lines {
+ is_label_defined := strings.Contains(line, ":")
+
+ if is_label_defined {
+ parts := strings.Split(line, ":")
+
+ line = parts[len(parts)-1]
+ }
+
+ next_instruction, err := Instructions.Parse(&state, line)
+ if err != nil {
+ return nil, fmt.Errorf(
+ "File %s, line %d (2nd pass): %w",
+ input_file_name,
+ line_nb,
+ err,
+ )
+ }
+
+ result = append(result, next_instruction...)
+ }
+
+ return result, nil
+}
+
func main() {
if len(os.Args) != 3 {
- fmt.Fprintf(os.Stderr, "Usage: gbasm [input_file] [output_file]")
+ fmt.Fprintf(os.Stderr, "Usage: gbasm [input_file] [output_file]\n")
os.Exit(1)
}
@@ -18,38 +97,31 @@ func main() {
input_file, err := os.Open(input_file_name)
if err != nil {
- fmt.Fprintf(os.Stderr, "Error while opening input file: %s", err.Error())
+ fmt.Fprintf(os.Stderr, "Error while opening input file: %s\n", err.Error())
os.Exit(1)
}
input, err := io.ReadAll(input_file)
if err != nil {
- fmt.Fprintf(os.Stderr, "Error while reading input file: %s", err.Error())
+ fmt.Fprintf(os.Stderr, "Error while reading input file: %s\n", err.Error())
os.Exit(1)
}
- lines := strings.Split(string(input), "\n")
-
- result := []byte{}
- for _, line := range lines {
- next_instruction, err := Instructions.Parse(line)
- if err != nil {
- fmt.Fprintf(os.Stderr, "%s", err.Error())
- os.Exit(1)
- }
-
- result = append(result, next_instruction...)
+ result, err := parseFile(input_file_name, input)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
+ os.Exit(1)
}
output_file, err := os.Create(output_file_name)
if err != nil {
- fmt.Fprintf(os.Stderr, "Error while opening output file: %s", err.Error())
+ fmt.Fprintf(os.Stderr, "Error while opening output file: %s\n", err.Error())
os.Exit(1)
}
_, err = output_file.Write(result)
if err != nil {
- fmt.Fprintf(os.Stderr, "Error while writing to output file: %s", err.Error())
+ fmt.Fprintf(os.Stderr, "Error while writing to output file: %s\n", err.Error())
os.Exit(1)
}
}