c65gm/internal/optimizer/scanner.go

97 lines
1.8 KiB
Go

package optimizer
import (
"strconv"
"strings"
)
// parseHexOrDec parses an ACME-style number: $ff or 255
func parseHexOrDec(s string) int {
if strings.HasPrefix(s, "$") {
v, _ := strconv.ParseInt(s[1:], 16, 16)
return int(v)
}
// Strip trailing characters after the number (e.g., ",y" in "5,y")
if idx := strings.IndexAny(s, ",)"); idx >= 0 {
s = s[:idx]
}
v, _ := strconv.ParseInt(s, 10, 16)
return int(v)
}
type asmLine struct {
text string
isLabel bool
isCode bool
isComment bool
optMarker bool
opcode string
operand string
}
func parseLines(lines []string) []asmLine {
var result []asmLine
for _, l := range lines {
al := asmLine{text: l}
if l == "" {
result = append(result, al)
continue
}
if strings.HasPrefix(l, "; @@OPT:") {
al.optMarker = true
al.isComment = true
result = append(result, al)
continue
}
if strings.HasPrefix(l, ";") {
al.isComment = true
result = append(result, al)
continue
}
if l[0] == '\t' {
al.isCode = true
parts := strings.Fields(l)
if len(parts) > 0 {
al.opcode = strings.ToLower(parts[0])
}
if len(parts) > 1 {
al.operand = parts[1]
}
} else {
al.isLabel = true
}
result = append(result, al)
}
return result
}
// stripOptMarkers removes @@OPT comment lines from the output
func stripOptMarkers(lines []asmLine) []asmLine {
var result []asmLine
for _, l := range lines {
if l.optMarker {
continue
}
result = append(result, l)
}
return result
}
func linesToString(lines []asmLine) []string {
var result []string
for _, l := range lines {
result = append(result, l.text)
}
return result
}
// skipJmpMarker returns true if the line is an @@OPT comment (to be skipped in pass logic)
func skipJmpMarker(line asmLine) bool {
return line.optMarker
}