aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAstatin <[email protected]>2025-01-07 16:20:52 +0900
committerAstatin <[email protected]>2025-01-07 16:20:52 +0900
commitb5b9637ff2d222841632b8644b94835ec1c93359 (patch)
treee7239875fd331effe67e62c62569c0cff5b8c1d0
parente4c337519fb9842de5eb12e5975f50efa02784d0 (diff)
Add label offset + allow to use labels with .DB macro + relative labels
-rw-r--r--instructions.go17
-rw-r--r--macros.go40
-rw-r--r--main.go24
-rw-r--r--parameters.go33
4 files changed, 96 insertions, 18 deletions
diff --git a/instructions.go b/instructions.go
index 59daa3a..ddcb833 100644
--- a/instructions.go
+++ b/instructions.go
@@ -8,10 +8,11 @@ import (
type ParamType func(labels *Labels, defs *Definitions, param string) (uint16, error)
type InstructionParams struct {
- Types []ParamType
- Assembler func(currentAddress uint16, args []uint16) ([]uint8, error)
- Wildcard bool
- MacroForbidden bool
+ Types []ParamType
+ Assembler func(currentAddress uint16, args []uint16) ([]uint8, error)
+ Wildcard bool
+ MacroForbidden bool
+ LabelsBeforeOnly bool
}
type InstructionSet map[string][]InstructionParams
@@ -503,6 +504,7 @@ func (set InstructionSet) Parse(
labels *Labels,
defs *Definitions,
isMacro bool,
+ isFirstPass bool,
currentAddress uint16,
line string,
) ([]byte, error) {
@@ -534,7 +536,12 @@ instruction_param_loop:
paramType = instrParam.Types[i]
}
- parsed, err := paramType(labels, defs, params[i])
+ accessibleLabels := labels
+
+ if isFirstPass && !instrParam.LabelsBeforeOnly {
+ accessibleLabels = nil
+ }
+ parsed, err := paramType(accessibleLabels, defs, params[i])
if err != nil {
continue instruction_param_loop
}
diff --git a/macros.go b/macros.go
index 8e8d4c1..5daf3c9 100644
--- a/macros.go
+++ b/macros.go
@@ -30,7 +30,16 @@ func NewInstructionSetMacros() InstructionSet {
Assembler: func(currentAddress uint16, args []uint16) ([]byte, error) {
return make([]byte, args[0]-currentAddress), nil
},
- MacroForbidden: true,
+ MacroForbidden: true,
+ LabelsBeforeOnly: true,
+ },
+ {
+ Types: []ParamType{Raw16MacroRelativeLabel},
+ Assembler: func(currentAddress uint16, args []uint16) ([]byte, error) {
+ return make([]byte, args[0]-currentAddress), nil
+ },
+ MacroForbidden: false,
+ LabelsBeforeOnly: true,
},
}
@@ -46,6 +55,18 @@ func NewInstructionSetMacros() InstructionSet {
},
Wildcard: true,
},
+ {
+ Types: []ParamType{Raw16},
+ Assembler: func(currentAddress uint16, args []uint16) ([]byte, error) {
+ result := make([]byte, len(args)*2)
+ for i := range args {
+ result[i*2] = uint8(args[i] >> 8)
+ result[i*2+1] = uint8(args[i] & 0xff)
+ }
+ return result, nil
+ },
+ Wildcard: true,
+ },
}
return result
@@ -63,8 +84,8 @@ func MacroParse(
lines []string,
result *[]byte,
state *ProgramState,
- line_nb *int, // line_nb
- is_first_pass bool,
+ lineNb *int,
+ isFirstPass bool,
offset uint,
) error {
words := strings.Split(line, " ")
@@ -79,6 +100,7 @@ func MacroParse(
&state.Labels,
&state.Defs,
state.IsMacro,
+ isFirstPass,
uint16(uint(len(*result))+offset),
line,
)
@@ -102,7 +124,7 @@ func MacroParse(
}
fileStartOffset := uint(len(*result)) + offset
- if is_first_pass {
+ if isFirstPass {
included, err := firstPass(filePath, input, fileStartOffset, state)
if err != nil {
return err
@@ -145,14 +167,14 @@ func MacroParse(
return fmt.Errorf(".MACRODEF should have one argument, followed by the definition")
}
definedMacroName := strings.ToUpper(words[1])
- (*line_nb) += 1
+ (*lineNb) += 1
macroContent := []byte{}
- for *line_nb < len(lines) && strings.TrimSpace(strings.Split(lines[*line_nb], ";")[0]) != ".END" {
- macroContent = append(macroContent, (lines[*line_nb] + "\n")...)
- (*line_nb) += 1
+ for *lineNb < len(lines) && strings.TrimSpace(strings.Split(lines[*lineNb], ";")[0]) != ".END" {
+ macroContent = append(macroContent, (lines[*lineNb] + "\n")...)
+ (*lineNb) += 1
}
- if is_first_pass {
+ if isFirstPass {
if _, ok := MacroInstructions[definedMacroName]; ok {
return fmt.Errorf("Macro %s is already defined", definedMacroName)
}
diff --git a/main.go b/main.go
index cf087f3..dd6ce6c 100644
--- a/main.go
+++ b/main.go
@@ -43,6 +43,7 @@ func firstPass(
line_nb := 0
result := []byte{}
+ lastAbsoluteLabel := ""
for line_nb < len(lines) {
line := lines[line_nb]
line_parts := strings.Split(line, ";")
@@ -62,6 +63,25 @@ func firstPass(
label,
)
}
+
+ if strings.HasPrefix(label, ".") {
+ if lastAbsoluteLabel == "" {
+ return nil, fmt.Errorf(
+ "Relative label \"%s\" found without a parent",
+ label,
+ )
+ }
+
+ label = lastAbsoluteLabel + label
+ } else {
+ labelParts := strings.Split(label, ".")
+ if len(labelParts) < 1 {
+ return nil, fmt.Errorf("Unknown issue while retrieving label absolute part ! (label: \"%s\")", label)
+ }
+
+ lastAbsoluteLabel = labelParts[0]
+ }
+
if _, ok := state.Labels[label]; ok {
return nil, fmt.Errorf(
"File %s, line %d:\nLabel %s is already defined",
@@ -98,7 +118,7 @@ func firstPass(
)
}
} else {
- next_instruction, err := Instructions.Parse(nil, &state.Defs, state.IsMacro, 0, line)
+ next_instruction, err := Instructions.Parse(&state.Labels, &state.Defs, state.IsMacro, true, 0, line)
if err != nil {
return nil, fmt.Errorf(
"File %s, line %d (1st pass):\n%w",
@@ -151,7 +171,7 @@ func secondPass(
)
}
} else {
- next_instruction, err := Instructions.Parse(&state.Labels, &state.Defs, state.IsMacro, uint16(uint(len(result))+offset), line)
+ next_instruction, err := Instructions.Parse(&state.Labels, &state.Defs, state.IsMacro, false, uint16(uint(len(result))+offset), line)
if err != nil {
return nil, fmt.Errorf(
"File %s, line %d (2nd pass): %w",
diff --git a/parameters.go b/parameters.go
index 4c787f3..ddb4532 100644
--- a/parameters.go
+++ b/parameters.go
@@ -121,11 +121,30 @@ func Raw16(labels *Labels, defs *Definitions, param string) (uint16, error) {
}
if strings.HasPrefix(param, "=") {
+ var offset uint16 = 0
+ labelWithoutOffset := param
+
+ if strings.Contains(param, "+") {
+ labelParts := strings.Split(param, "+")
+ if len(labelParts) != 2 {
+ return 0, fmt.Errorf(
+ "Labels with offset should have exactly 1 offset (in \"%s\")",
+ param,
+ )
+ }
+ labelWithoutOffset = labelParts[0]
+ o, err := strconv.ParseUint(labelParts[1], 0, 16)
+ if err != nil {
+ return 0, fmt.Errorf("Error while parsing label offset: %w", err)
+ }
+ offset = uint16(o)
+ }
+
if labels == nil {
return 0, nil
}
- label := strings.ToUpper(strings.TrimPrefix(param, "="))
+ label := strings.ToUpper(strings.TrimPrefix(labelWithoutOffset, "="))
labelValue, ok := (*labels)[label]
if !ok {
return 0, fmt.Errorf("Label \"%s\" not found", label)
@@ -136,7 +155,7 @@ func Raw16(labels *Labels, defs *Definitions, param string) (uint16, error) {
panic("Switchable ROM banks are not implemented yet")
}
- return uint16(labelValue), nil
+ return uint16(labelValue) + offset, nil
}
res, err := strconv.ParseUint(param, 0, 16)
@@ -144,6 +163,16 @@ func Raw16(labels *Labels, defs *Definitions, param string) (uint16, error) {
return uint16(res), err
}
+func Raw16MacroRelativeLabel(labels *Labels, defs *Definitions, param string) (uint16, error) {
+ if !strings.HasPrefix(param, "=$") {
+ return 0, fmt.Errorf(
+ "label \"%s\" is external to the macro",
+ param,
+ )
+ }
+ return Raw16(labels, defs, param)
+}
+
func Reg16Indirect(_ *Labels, _ *Definitions, param string) (uint16, error) {
switch param {
case "(BC)":