[script] Add CDL; Add "smart" parsing

- Added a CDL implementation.  It is still very incomplete and is not
  really used yet.
- Added "smart" parsing.  This will disassemble the code and follow any
  jumps and calls.  Anything not found by this is currently excluded
  from output.
This commit is contained in:
Zorchenhimer 2025-09-14 16:52:06 -04:00
parent d8cc126c04
commit 11cfad1e1a
Signed by: Zorchenhimer
GPG Key ID: 70A1AB767AAB9C20
6 changed files with 557 additions and 140 deletions

View File

@ -6,6 +6,7 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"io/fs" "io/fs"
"slices"
"github.com/alexflint/go-arg" "github.com/alexflint/go-arg"
@ -19,6 +20,7 @@ type Arguments struct {
type Walker struct { type Walker struct {
Found []string Found []string
CDLs []string
} }
func (w *Walker) WalkFunc(path string, info fs.DirEntry, err error) error { func (w *Walker) WalkFunc(path string, info fs.DirEntry, err error) error {
@ -30,6 +32,10 @@ func (w *Walker) WalkFunc(path string, info fs.DirEntry, err error) error {
w.Found = append(w.Found, path) w.Found = append(w.Found, path)
} }
if strings.HasSuffix(path, "_scriptData.cdl.json") {
w.CDLs = append(w.CDLs, path)
}
return nil return nil
} }
@ -46,18 +52,32 @@ func run(args *Arguments) error {
for _, file := range w.Found { for _, file := range w.Found {
fmt.Println(file) fmt.Println(file)
scr, err := script.ParseFile(file, 0x0000) var cdl *script.CodeDataLog
cdlname := file[:len(file)-4]+".cdl.json"
if slices.Contains(w.CDLs, cdlname) {
fmt.Println("", cdlname)
cdl, err = script.CdlFromJsonFile(cdlname)
if err != nil { if err != nil {
if scr != nil { fmt.Println(" CDL read error:", err)
for _, token := range scr.Tokens { cdl = nil
fmt.Println(token.String(scr.Labels))
} }
} }
return err
}
scr, err := script.SmartParseFile(file, 0x6000, cdl)
if err != nil {
//if scr != nil {
// for _, token := range scr.Tokens {
// fmt.Println(token.String(scr.Labels))
// }
//}
fmt.Println(err)
//return err
}
if scr != nil {
stats.Add(scr.Stats()) stats.Add(scr.Stats())
} }
}
outfile, err := os.Create(args.Output) outfile, err := os.Create(args.Output)
if err != nil { if err != nil {

View File

@ -7,6 +7,7 @@ import (
"strconv" "strconv"
"bufio" "bufio"
"slices" "slices"
"errors"
"github.com/alexflint/go-arg" "github.com/alexflint/go-arg"
@ -19,6 +20,8 @@ type Arguments struct {
StartAddr string `arg:"--start" default:"0x6000" help:"base address for the start of the script"` StartAddr string `arg:"--start" default:"0x6000" help:"base address for the start of the script"`
StatsFile string `arg:"--stats" help:"file to write some statistics to"` StatsFile string `arg:"--stats" help:"file to write some statistics to"`
LabelFile string `arg:"--labels" help:"file containing address/label pairs"` LabelFile string `arg:"--labels" help:"file containing address/label pairs"`
CDL string `arg:"--cdl" help:"CodeDataLog json file"`
Smart bool `arg:"--smart"`
start int start int
} }
@ -39,19 +42,38 @@ func run(args *Arguments) error {
args.start = int(val) args.start = int(val)
scr, err := script.ParseFile(args.Input, args.start) var cdl *script.CodeDataLog
if args.CDL != "" {
//fmt.Println(" CDL:", args.CDL)
cdl, err = script.CdlFromJsonFile(args.CDL)
if err != nil { if err != nil {
return err //return fmt.Errorf("CDL Parse error: %w", err)
cdl = nil
}
}
var scr *script.Script
if args.Smart {
scr, err = script.SmartParseFile(args.Input, args.start, cdl)
} else {
scr, err = script.ParseFile(args.Input, args.start, cdl)
}
if err != nil {
if errors.Is(err, script.ErrEarlyEOF) || errors.Is(err, script.ErrNavigation) {
fmt.Println(err)
} else {
return fmt.Errorf("Script parse error: %w", err)
}
} }
if args.LabelFile != "" { if args.LabelFile != "" {
labels, err := parseLabelFile(args.LabelFile) labels, err := parseLabelFile(args.LabelFile)
if err != nil { if err != nil {
return err return fmt.Errorf("Labels parse error: %w", err)
} }
for _, label := range labels { for _, label := range labels {
//fmt.Printf("%#v\n", label)
scr.Labels[label.Address] = label scr.Labels[label.Address] = label
} }
} }
@ -66,7 +88,7 @@ func run(args *Arguments) error {
} }
for _, w := range scr.Warnings { for _, w := range scr.Warnings {
fmt.Fprintln(os.Stderr, w) //fmt.Fprintln(os.Stderr, w)
if args.Output != "" { if args.Output != "" {
fmt.Fprintln(outfile, "; "+w) fmt.Fprintln(outfile, "; "+w)
} }
@ -75,6 +97,16 @@ func run(args *Arguments) error {
fmt.Fprintf(outfile, "; Start address: $%04X\n", scr.StartAddress) fmt.Fprintf(outfile, "; Start address: $%04X\n", scr.StartAddress)
fmt.Fprintf(outfile, "; Stack address: $%04X\n\n", scr.StackAddress) fmt.Fprintf(outfile, "; Stack address: $%04X\n\n", scr.StackAddress)
slices.SortFunc(scr.Tokens, func(a, b *script.Token) int {
if a.Offset < b.Offset { return -1 }
if a.Offset > b.Offset { return 1 }
return 0
})
//for _, lbl := range scr.Labels {
// fmt.Println(lbl)
//}
for _, token := range scr.Tokens { for _, token := range scr.Tokens {
fmt.Fprintln(outfile, token.String(scr.Labels)) fmt.Fprintln(outfile, token.String(scr.Labels))
} }
@ -86,7 +118,6 @@ func run(args *Arguments) error {
} }
defer statfile.Close() defer statfile.Close()
//err = scr.WriteStats(statfile)
_, err = scr.Stats().WriteTo(statfile) _, err = scr.Stats().WriteTo(statfile)
if err != nil { if err != nil {
return fmt.Errorf("Error writing stats: %w", err) return fmt.Errorf("Error writing stats: %w", err)

151
script/cdl.go Normal file
View File

@ -0,0 +1,151 @@
package script
import (
"io"
"os"
"encoding/json"
"strconv"
"fmt"
)
type CodeDataLog struct {
Code []CdlRange
Data []CdlRange
cache map[int]cdlBit
offset int
}
type CdlRange struct {
// strings cuz json doesn't know wtf hexadecimal is
Start string
End string
}
type cdlBit byte
var (
cdlUnknown cdlBit = 0x00
cdlCode cdlBit = 0x01
cdlData cdlBit = 0x02
)
func (cdl *CodeDataLog) setData(scriptOffset int) {
if cdl.cache == nil {
err := cdl.doCache()
if err != nil {
panic(fmt.Sprintf("CDL data error: %w", err))
}
}
cdl.cache[scriptOffset+cdl.offset] |= cdlData
}
func (cdl *CodeDataLog) setCode(scriptOffset int) {
if cdl.cache == nil {
err := cdl.doCache()
if err != nil {
panic(fmt.Sprintf("CDL data error: %w", err))
}
}
cdl.cache[scriptOffset+cdl.offset] |= cdlCode
}
func (cdl *CodeDataLog) doCache() error {
cdl.cache = make(map[int]cdlBit)
for _, rng := range cdl.Code {
start, err := strconv.ParseInt(rng.Start, 0, 32)
if err != nil {
return fmt.Errorf("Invalid start: %q", rng.Start)
}
end, err := strconv.ParseInt(rng.End, 0, 32)
if err != nil {
return fmt.Errorf("Invalid end: %q", rng.End)
}
for i := int(start); i <= int(end); i++ {
if _, ok := cdl.cache[i]; !ok {
cdl.cache[i] = cdlUnknown
}
cdl.cache[i] |= cdlCode
}
}
for _, rng := range cdl.Data {
start, err := strconv.ParseInt(rng.Start, 0, 32)
if err != nil {
return fmt.Errorf("Invalid start: %q", rng.Start)
}
end, err := strconv.ParseInt(rng.End, 0, 32)
if err != nil {
return fmt.Errorf("Invalid end: %q", rng.End)
}
for i := int(start); i <= int(end); i++ {
if _, ok := cdl.cache[i]; !ok {
cdl.cache[i] = cdlUnknown
}
cdl.cache[i] |= cdlData
}
}
return nil
}
func CdlFromJson(r io.Reader) (*CodeDataLog, error) {
cdl := &CodeDataLog{}
dec := json.NewDecoder(r)
err := dec.Decode(cdl)
if err != nil {
return nil, err
}
return cdl, nil
}
func CdlFromJsonFile(filename string) (*CodeDataLog, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
return CdlFromJson(file)
}
func (cdl *CodeDataLog) IsData(addr int) bool {
if cdl.cache == nil {
err := cdl.doCache()
if err != nil {
panic(fmt.Sprintf("CDL data error: %w", err))
}
}
val, ok := cdl.cache[addr]
if !ok {
return false
}
return val & cdlData == cdlData
}
func (cdl *CodeDataLog) IsCode(addr int) bool {
if cdl.cache == nil {
err := cdl.doCache()
if err != nil {
panic(fmt.Sprintf("CDL data error: %w", err))
}
}
val, ok := cdl.cache[addr]
if !ok {
return false
}
return val & cdlCode == cdlCode
}

42
script/labels.go Normal file
View File

@ -0,0 +1,42 @@
package script
import (
"fmt"
)
type Label struct {
Address int
Name string
Comment string
FarLabel bool
}
func AutoLabel(address int) *Label {
return &Label{
Address: address,
Name: fmt.Sprintf("L%04X", address),
}
}
func AutoLabelVar(address int) *Label {
return &Label{
Address: address,
Name: fmt.Sprintf("Var_%04X", address),
}
}
func AutoLabelFar(address int) *Label {
return &Label{
Address: address,
Name: fmt.Sprintf("F%04X", address),
FarLabel: true,
}
}
func NewLabel(address int, name string) *Label {
return &Label{
Address: address,
Name: name,
}
}

View File

@ -3,185 +3,296 @@ package script
import ( import (
"fmt" "fmt"
"os" "os"
"errors"
) )
type Label struct { var (
Address int ErrEarlyEOF = errors.New("Unexpected EOF when reading OP arguments")
Name string ErrInvalidInstruction = errors.New("Invalid instruction")
Comment string ErrNavigation = errors.New("SmartParse navigation error")
FarLabel bool )
type Parser struct {
rawinput []byte
current int
startAddr int
script *Script
cdl *CodeDataLog
} }
func AutoLabel(address int) *Label { func ParseFile(filename string, startAddr int, cdl *CodeDataLog) (*Script, error) {
return &Label{
Address: address,
Name: fmt.Sprintf("L%04X", address),
}
}
func AutoLabelVar(address int) *Label {
return &Label{
Address: address,
Name: fmt.Sprintf("Var_%04X", address),
}
}
func AutoLabelFar(address int) *Label {
return &Label{
Address: address,
Name: fmt.Sprintf("F%04X", address),
FarLabel: true,
}
}
func NewLabel(address int, name string) *Label {
return &Label{
Address: address,
Name: name,
}
}
func ParseFile(filename string, startAddr int) (*Script, error) {
rawfile, err := os.ReadFile(filename) rawfile, err := os.ReadFile(filename)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to read file: %w", err) return nil, fmt.Errorf("unable to read file: %w", err)
} }
return Parse(rawfile, startAddr) return Parse(rawfile, startAddr, cdl)
} }
func Parse(rawinput []byte, startAddr int) (*Script, error) { func SmartParseFile(filename string, startAddr int, cdl *CodeDataLog) (*Script, error) {
rawfile, err := os.ReadFile(filename)
if err != nil {
return nil, fmt.Errorf("unable to read file: %w", err)
}
return SmartParse(rawfile, startAddr, cdl)
}
func SmartParse(rawinput []byte, startAddr int, cdl *CodeDataLog) (*Script, error) {
if len(rawinput) < 3 { if len(rawinput) < 3 {
return nil, fmt.Errorf("not enough bytes for script") return nil, fmt.Errorf("not enough bytes for script")
} }
script := &Script{ p := &Parser{
// Don't use CDL that was passed in
cdl: &CodeDataLog{},
script: &Script{
Tokens: []*Token{}, Tokens: []*Token{},
Warnings: []string{}, Warnings: []string{},
StackAddress: (int(rawinput[1])<<8) | int(rawinput[0]), StackAddress: (int(rawinput[1])<<8) | int(rawinput[0]),
StartAddress: startAddr, StartAddress: startAddr,
Labels: make(map[int]*Label), // map[location]name Labels: make(map[int]*Label), // map[location]name
},
rawinput: rawinput,
startAddr: startAddr,
} }
tokenMap := make(map[int]*Token) tokenMap := make(map[int]*Token)
for i := 2; i < len(rawinput); i++ { // starting point is the third byte in the script.
raw := rawinput[i] branches := []int{ 2 }
visited := make([]bool, len(p.rawinput))
for len(branches) > 0 {
//fmt.Printf("start @ $%04X\n", branches[0]+startAddr)
INNER:
for p.current = branches[0]; p.current < len(p.rawinput); p.current++ {
//branches = branches[1:]
if p.current < 0 {
return p.script, errors.Join(ErrNavigation,
fmt.Errorf("HOW IS CURRENT NEGATIVE?????"))
}
if visited[p.current] {
//fmt.Printf("found visited at $%04X\n", p.current+startAddr)
break
}
visited[p.current] = true
raw := p.rawinput[p.current]
token := &Token{ token := &Token{
Offset: startAddr+i, Offset: startAddr+p.current,
Raw: raw, Raw: raw,
Inline: []InlineVal{}, Inline: []InlineVal{},
} }
script.Tokens = append(script.Tokens, token) p.script.Tokens = append(p.script.Tokens, token)
tokenMap[token.Offset] = token tokenMap[token.Offset] = token
//fmt.Printf("{$%04X} %s\n", token.Offset, token.String(map[int]*Label{}))
p.cdl.setCode(p.current)
if raw < 0x80 { if raw < 0x80 {
continue continue
} }
op, ok := InstrMap[raw] err := p.parseToken(token, raw)
if !ok { if err != nil {
return nil, fmt.Errorf("OP 0x%02X not in instruction map", raw) return p.script, err
} }
token.Instruction = op
args := []InlineVal{} //fmt.Println(token.String(map[int]*Label{}))
switch op.OpCount {
case -1: // null terminated switch raw {
for ; i < len(rawinput); i++ { case 0x86, 0xAC, 0xFF, 0x81, 0x9B, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xFD: // return, long_return, break_engine & halts
val := ByteVal(rawinput[i]) //fmt.Printf("[$%04X] %s\n",
args = append(args, val) // token.Offset, token.Instruction.Name)
if rawinput[i] == 0x00 { break INNER
case 0x84, 0xBF, 0xC0, 0x85: // jump_abs, jump_not_zero, jump_zero, call_abs
if len(token.Inline) < 1 {
return p.script, errors.Join(ErrNavigation,
fmt.Errorf("jump missing target"))
}
if len(token.Inline) > 1 {
return p.script, errors.Join(ErrNavigation,
fmt.Errorf("jump has too many targets"))
}
val := token.Inline[0].Int()
//fmt.Printf("[$%04X] %s $%04X\n",
// token.Offset, token.Instruction.Name, val)
branches = append(branches, val-startAddr)
p.script.Labels[val] = AutoLabel(val)
if raw == 0x84 { // not jump_abs
break INNER
}
case 0xC1, 0xEE: // jump_switch, call_switch
if len(token.Inline) < 2 {
return p.script, errors.Join(ErrNavigation,
fmt.Errorf("switch missing targets"))
}
count := token.Inline[0].Int()
if len(token.Inline) != count+1 {
return p.script, errors.Join(ErrNavigation,
fmt.Errorf("switch target missmatch (expected %d, got %d)", count, len(token.Inline)-1))
}
for _, val := range token.Inline[1:] {
//fmt.Printf("[$%04X] %s $%04X\n",
// token.Offset, token.Instruction.Name, val.Int())
branches = append(branches, val.Int()-startAddr)
p.script.Labels[val.Int()] = AutoLabel(val.Int())
}
if raw == 0xC1 { // jump_switch
break INNER
}
}
if token.Instruction.OpCount == 2 {
val := token.Inline[0].Int()
if _, ok := p.script.Labels[val]; !ok {
p.script.Labels[val] = AutoLabelVar(val)
}
}
}
if len(branches) == 1 {
break break
} }
branches = branches[1:]
} }
case -2: // count then count words return p.script, nil
i++
l := int(rawinput[i])
args = append(args, ByteVal(l))
i++
for c := 0; c < l; c++ {
if len(rawinput) <= i+1 {
return script, fmt.Errorf("OP early end at offset 0x%X (%d) {%d} %#v", i, i, l, op)
} }
args = append(args, WordVal([2]byte{rawinput[i], rawinput[i+1]})) func Parse(rawinput []byte, startAddr int, cdl *CodeDataLog) (*Script, error) {
i+=2 if len(rawinput) < 3 {
} return nil, fmt.Errorf("not enough bytes for script")
i--
case -3: // count then count words. "default" is no call (skip Code_Pointer to after args)
i++
l := int(rawinput[i])
args = append(args, ByteVal(l))
i++
for c := 0; c < l; c++ {
args = append(args, WordVal([2]byte{rawinput[i], rawinput[i+1]}))
i+=2
}
i--
case 2:
args = append(args, WordVal([2]byte{rawinput[i+1], rawinput[i+2]}))
i+=2
case 1:
i++
args = append(args, ByteVal(rawinput[i]))
} }
token.Inline = args p := &Parser{
cdl: cdl,
script: &Script{
Tokens: []*Token{},
Warnings: []string{},
StackAddress: (int(rawinput[1])<<8) | int(rawinput[0]),
StartAddress: startAddr,
Labels: make(map[int]*Label), // map[location]name
},
rawinput: rawinput,
startAddr: startAddr,
}
tokenMap := make(map[int]*Token)
if p.cdl == nil {
p.cdl = &CodeDataLog{}
}
//earliestVar := len(p.rawinput)-2
//fmt.Printf("var start bounds: $%04X, $%04X\n", startAddr, startAddr+len(p.rawinput))
for p.current = 2; p.current < len(p.rawinput); p.current++ {
//if p.current >= earliestVar {
// fmt.Printf("Earliest Variable found at offset %d ($%04X)\n", p.current, startAddr+p.current)
// break
//}
raw := p.rawinput[p.current]
token := &Token{
Offset: startAddr+p.current,
Raw: raw,
Inline: []InlineVal{},
}
p.script.Tokens = append(p.script.Tokens, token)
tokenMap[token.Offset] = token
if raw < 0x80 || p.cdl.IsData(p.current+startAddr) { // || p.current >= earliestVar {
if p.cdl.IsData(p.current+startAddr) {
token.IsData = true
//fmt.Print(".")
//fmt.Printf("%#v\n", token)
}
continue
}
err := p.parseToken(token, raw)
if err != nil {
return p.script, err
}
} }
// Find and mark labels for a few instructions // Find and mark labels for a few instructions
for _, t := range script.Tokens { for _, t := range p.script.Tokens {
if t.Instruction == nil {
continue
}
switch t.Raw { switch t.Raw {
case 0x84, 0x85, 0xBF, 0xC0: // jmp/call case 0x84, 0x85, 0xBF, 0xC0: // jmp/call
if len(t.Inline) == 0 { if len(t.Inline) == 0 {
return nil, fmt.Errorf("jump/call missing address") //return nil, fmt.Errorf("jump/call missing address ($%04X)", t.Offset)
p.script.Warnings = append(p.script.Warnings,
fmt.Sprintf("jump/call missing addresses ($%04X)", t.Offset))
continue
} }
addr := t.Inline[0].Int() addr := t.Inline[0].Int()
found := false found := false
for _, tok := range script.Tokens { for _, tok := range p.script.Tokens {
if tok.Offset == addr { if tok.Offset == addr {
tok.IsTarget = true tok.IsTarget = true
found = true found = true
script.Labels[addr] = AutoLabel(addr) //fmt.Sprintf("L%04X", addr) p.script.Labels[addr] = AutoLabel(addr) //fmt.Sprintf("L%04X", addr)
break break
} }
} }
if !found { if !found {
script.Warnings = append(script.Warnings, fmt.Sprintf("Warning: no target found for jump/call at offset $%04X; value $%04X", t.Offset, addr)) p.script.Warnings = append(p.script.Warnings, fmt.Sprintf("Warning: no target found for jump/call at offset $%04X; value $%04X", t.Offset, addr))
} }
case 0xC1, 0xEE: // switches case 0xC1, 0xEE: // switches
if len(t.Inline) < 2 { if len(t.Inline) < 2 {
return nil, fmt.Errorf("jump/call switch missing addresses") //return nil, fmt.Errorf("jump/call switch missing addresses")
p.script.Warnings = append(p.script.Warnings,
fmt.Sprintf("jump/call switch missing addresses ($%04X)", t.Offset))
continue
} }
for _, v := range t.Inline[1:] { for _, v := range t.Inline[1:] {
addr := v.Int() addr := v.Int()
found := false found := false
for _, tok := range script.Tokens { for _, tok := range p.script.Tokens {
if tok.Offset == addr { if tok.Offset == addr {
tok.IsTarget = true tok.IsTarget = true
found = true found = true
script.Labels[addr] = AutoLabel(addr) //fmt.Sprintf("L%04X", addr) p.script.Labels[addr] = AutoLabel(addr) //fmt.Sprintf("L%04X", addr)
break break
} }
} }
if !found { if !found {
script.Warnings = append(script.Warnings, fmt.Sprintf("Warning: no target found for jump/call switch at offset $%04X; value: $%04X", t.Offset, addr)) p.script.Warnings = append(p.script.Warnings, fmt.Sprintf("Warning: no target found for jump/call switch at offset $%04X; value: $%04X", t.Offset, addr))
} }
} }
default: default:
// if word arg, see if it's something in this script // if word arg, see if it's something in this script
if t.Instruction == nil { if t.Instruction == nil {
//if t.IsData {
// fmt.Print(",")
//}
continue continue
} }
@ -189,11 +300,76 @@ func Parse(rawinput []byte, startAddr int) (*Script, error) {
addr := t.Inline[0].Int() addr := t.Inline[0].Int()
if tok, ok := tokenMap[addr]; ok { if tok, ok := tokenMap[addr]; ok {
tok.IsVariable = true tok.IsVariable = true
script.Labels[addr] = AutoLabelVar(addr) //fmt.Sprintf("Var_%04X", addr) p.script.Labels[addr] = AutoLabelVar(addr) //fmt.Sprintf("Var_%04X", addr)
} }
} }
} }
} }
return script, nil return p.script, nil
}
func (p *Parser) parseToken(token *Token, raw byte) error {
op, ok := InstrMap[raw]
if !ok {
return errors.Join(ErrInvalidInstruction,
fmt.Errorf("OP 0x%02X not in instruction map", raw))
}
token.Instruction = op
args := []InlineVal{}
switch op.OpCount {
case -1: // null terminated
for ; p.current < len(p.rawinput); p.current++ {
val := ByteVal(p.rawinput[p.current])
args = append(args, val)
if p.rawinput[p.current] == 0x00 {
break
}
}
case -2: // count then count words
// FIXME: wtf makes this different from -3??
p.current++
l := int(p.rawinput[p.current])
args = append(args, ByteVal(l))
p.current++
for c := 0; c < l; c++ {
if len(p.rawinput) <= p.current+1 {
return errors.Join(ErrEarlyEOF,
fmt.Errorf("OP early end at offset 0x%X (%d) {%d} %#v", p.current, p.current, l, op))
}
args = append(args, WordVal([2]byte{p.rawinput[p.current], p.rawinput[p.current+1]}))
p.current+=2
}
p.current--
case -3: // count then count words. "default" is no call (skip Code_Pointer to after args)
p.current++
l := int(p.rawinput[p.current])
args = append(args, ByteVal(l))
p.current++
for c := 0; c < l; c++ {
args = append(args, WordVal([2]byte{p.rawinput[p.current], p.rawinput[p.current+1]}))
p.current+=2
}
p.current--
case 2:
args = append(args, WordVal([2]byte{p.rawinput[p.current+1], p.rawinput[p.current+2]}))
p.current+=2
//fmt.Printf("var at $%04X\n", val.Int())
//if val.Int() > p.startAddr && val.Int() < p.startAddr+len(p.rawinput) && p.earliestVar > val.Int() {
// fmt.Printf("new earliest: $%04X\n", val.Int())
// p.earliestVar = val.Int()
//}
case 1:
p.current++
args = append(args, ByteVal(p.rawinput[p.current]))
}
token.Inline = args
return nil
} }

View File

@ -6,11 +6,12 @@ import (
) )
type Token struct { type Token struct {
Offset int Offset int // in CPU space
Raw byte Raw byte
Inline []InlineVal Inline []InlineVal
IsTarget bool // target of a call/jump? IsTarget bool // target of a call/jump?
IsVariable bool // target of something else IsVariable bool // target of something else
IsData bool // from CDL
Instruction *Instruction Instruction *Instruction
} }
@ -18,28 +19,24 @@ type Token struct {
func (t Token) String(labels map[int]*Label) string { func (t Token) String(labels map[int]*Label) string {
suffix := "" suffix := ""
switch t.Raw { switch t.Raw {
case 0x86: case 0x86: // Newline after return
suffix = "\n" suffix = "\n"
} }
prefix := "" prefix := ""
if t.IsTarget || t.IsVariable {
if lbl, ok := labels[t.Offset]; ok { if lbl, ok := labels[t.Offset]; ok {
comment := "" comment := ""
if lbl.Comment != "" { if lbl.Comment != "" {
comment = "; "+lbl.Comment+"\n" comment = "; "+lbl.Comment+"\n"
} }
prefix = "\n"+comment+lbl.Name+":\n" name := ""
} else { if lbl.Name != "" {
prefix = fmt.Sprintf("\nL%04X:\n", t.Offset) name = lbl.Name+":\n"
}
} else {
if lbl, ok := labels[t.Offset]; ok && lbl.Comment != "" {
suffix = " ; "+lbl.Comment+suffix
} }
prefix = "\n"+comment+name
} }
if t.Raw < 0x80 { if t.Instruction == nil {
return fmt.Sprintf("%s[%04X] %02X %-5s : %d%s", return fmt.Sprintf("%s[%04X] %02X %-5s : %d%s",
prefix, prefix,
t.Offset, t.Offset,