aboutsummaryrefslogtreecommitdiff
path: root/main.go
blob: b4fa941155257db0ba50ac0310d894f273f6cf9a (plain)
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)
	}
}