1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
package main
import (
"fmt"
"io"
"os"
"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]\n")
os.Exit(1)
}
input_file_name := os.Args[1]
output_file_name := os.Args[2]
input_file, err := os.Open(input_file_name)
if err != nil {
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\n", err.Error())
os.Exit(1)
}
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\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\n", err.Error())
os.Exit(1)
}
}
|