Compare commits
3 Commits
045f204a6b
...
bfc7beb382
Author | SHA1 | Date |
---|---|---|
|
bfc7beb382 | |
|
11cfad1e1a | |
|
d8cc126c04 |
|
@ -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,17 +52,31 @@ 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
|
||||||
if err != nil {
|
cdlname := file[:len(file)-4]+".cdl.json"
|
||||||
if scr != nil {
|
if slices.Contains(w.CDLs, cdlname) {
|
||||||
for _, token := range scr.Tokens {
|
fmt.Println("", cdlname)
|
||||||
fmt.Println(token.String(scr.Labels))
|
cdl, err = script.CdlFromJsonFile(cdlname)
|
||||||
}
|
if err != nil {
|
||||||
|
fmt.Println(" CDL read error:", err)
|
||||||
|
cdl = nil
|
||||||
}
|
}
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stats.Add(scr.Stats())
|
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())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
outfile, err := os.Create(args.Output)
|
outfile, err := os.Create(args.Output)
|
||||||
|
|
|
@ -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,9 @@ 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"`
|
||||||
|
CDLOutput string `arg:"--cdl-output"`
|
||||||
|
Smart bool `arg:"--smart"`
|
||||||
|
|
||||||
start int
|
start int
|
||||||
}
|
}
|
||||||
|
@ -39,19 +43,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 {
|
||||||
|
//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 err != nil {
|
||||||
return err
|
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 +89,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 +98,12 @@ 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 _, token := range scr.Tokens {
|
for _, token := range scr.Tokens {
|
||||||
fmt.Fprintln(outfile, token.String(scr.Labels))
|
fmt.Fprintln(outfile, token.String(scr.Labels))
|
||||||
}
|
}
|
||||||
|
@ -86,13 +115,28 @@ 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if scr.CDL != nil {
|
||||||
|
cdlout := args.CDL
|
||||||
|
if args.CDLOutput != "" {
|
||||||
|
cdlout = args.CDLOutput
|
||||||
|
}
|
||||||
|
|
||||||
|
if cdlout == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = scr.CDL.WriteToFile(cdlout)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error writing CDL file: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,245 @@
|
||||||
|
package script
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
"fmt"
|
||||||
|
"slices"
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
//cdlOpCode cdlBit = 0x04
|
||||||
|
)
|
||||||
|
|
||||||
|
func (cdl *CodeDataLog) WriteToFile(filename string) error {
|
||||||
|
file, err := os.Create(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, werr := cdl.WriteTo(file)
|
||||||
|
err = file.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return werr
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRanges(list []int) []CdlRange {
|
||||||
|
//fmt.Printf("getRanges(%v)\n", list)
|
||||||
|
data := []CdlRange{}
|
||||||
|
|
||||||
|
start := -1
|
||||||
|
//end := -1
|
||||||
|
prev := -1
|
||||||
|
for _, addr := range list {
|
||||||
|
if start == -1 {
|
||||||
|
start = addr
|
||||||
|
}
|
||||||
|
|
||||||
|
if prev != -1 && prev != addr-1 {
|
||||||
|
data = append(data, CdlRange{
|
||||||
|
Start: fmt.Sprintf("0x%X", start),
|
||||||
|
End: fmt.Sprintf("0x%X", prev),
|
||||||
|
})
|
||||||
|
|
||||||
|
//fmt.Printf("start: 0x%X end: 0x%X\n", start, prev)
|
||||||
|
|
||||||
|
start = addr
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = addr
|
||||||
|
}
|
||||||
|
|
||||||
|
if start != -1 && prev != -1 {
|
||||||
|
data = append(data, CdlRange{
|
||||||
|
Start: fmt.Sprintf("0x%X", start),
|
||||||
|
End: fmt.Sprintf("0x%X", prev),
|
||||||
|
})
|
||||||
|
|
||||||
|
//fmt.Println("start:", start, "end:", prev)
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cdl *CodeDataLog) WriteTo(w io.Writer) (int64, error) {
|
||||||
|
clean := &CodeDataLog{
|
||||||
|
Code: []CdlRange{},
|
||||||
|
Data: []CdlRange{},
|
||||||
|
}
|
||||||
|
|
||||||
|
keys := []int{}
|
||||||
|
for k, _ := range cdl.cache {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
slices.Sort(keys)
|
||||||
|
|
||||||
|
code := []int{}
|
||||||
|
data := []int{}
|
||||||
|
|
||||||
|
for _, k := range keys {
|
||||||
|
b := cdl.cache[k]
|
||||||
|
if b & cdlCode == cdlCode {
|
||||||
|
code = append(code, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
if b & cdlData == cdlData {
|
||||||
|
data = append(data, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clean.Code = getRanges(code)
|
||||||
|
clean.Data = getRanges(data)
|
||||||
|
|
||||||
|
raw, err := json.MarshalIndent(clean, "", "\t")
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err := w.Write(raw)
|
||||||
|
return int64(n), err
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
409
script/parser.go
409
script/parser.go
|
@ -3,185 +3,300 @@ 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{
|
||||||
Tokens: []*Token{},
|
|
||||||
Warnings: []string{},
|
script: &Script{
|
||||||
StackAddress: (int(rawinput[1])<<8) | int(rawinput[0]),
|
Tokens: []*Token{},
|
||||||
StartAddress: startAddr,
|
Warnings: []string{},
|
||||||
Labels: make(map[int]*Label), // map[location]name
|
StackAddress: (int(rawinput[1])<<8) | int(rawinput[0]),
|
||||||
|
StartAddress: startAddr,
|
||||||
|
Labels: make(map[int]*Label), // map[location]name
|
||||||
|
|
||||||
|
CDL: cdl,
|
||||||
|
},
|
||||||
|
|
||||||
|
rawinput: rawinput,
|
||||||
|
startAddr: startAddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.script.CDL == nil {
|
||||||
|
p.script.CDL = &CodeDataLog{}
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenMap := make(map[int]*Token)
|
||||||
|
|
||||||
|
// starting point is the third byte in the script.
|
||||||
|
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{
|
||||||
|
Offset: startAddr+p.current,
|
||||||
|
Raw: raw,
|
||||||
|
Inline: []InlineVal{},
|
||||||
|
}
|
||||||
|
p.script.Tokens = append(p.script.Tokens, token)
|
||||||
|
tokenMap[token.Offset] = token
|
||||||
|
|
||||||
|
//fmt.Printf("{$%04X} %s\n", token.Offset, token.String(map[int]*Label{}))
|
||||||
|
|
||||||
|
p.script.CDL.setCode(p.current)
|
||||||
|
if raw < 0x80 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err := p.parseToken(token, raw)
|
||||||
|
if err != nil {
|
||||||
|
return p.script, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//fmt.Println(token.String(map[int]*Label{}))
|
||||||
|
|
||||||
|
switch raw {
|
||||||
|
case 0x86, 0xAC, 0xFF, 0x81, 0x9B, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xFD: // return, long_return, break_engine & halts
|
||||||
|
//fmt.Printf("[$%04X] %s\n",
|
||||||
|
// token.Offset, token.Instruction.Name)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
branches = branches[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.script, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Parse(rawinput []byte, startAddr int, cdl *CodeDataLog) (*Script, error) {
|
||||||
|
if len(rawinput) < 3 {
|
||||||
|
return nil, fmt.Errorf("not enough bytes for script")
|
||||||
|
}
|
||||||
|
|
||||||
|
p := &Parser{
|
||||||
|
script: &Script{
|
||||||
|
Tokens: []*Token{},
|
||||||
|
Warnings: []string{},
|
||||||
|
StackAddress: (int(rawinput[1])<<8) | int(rawinput[0]),
|
||||||
|
StartAddress: startAddr,
|
||||||
|
Labels: make(map[int]*Label), // map[location]name
|
||||||
|
CDL: cdl,
|
||||||
|
},
|
||||||
|
rawinput: rawinput,
|
||||||
|
startAddr: startAddr,
|
||||||
}
|
}
|
||||||
tokenMap := make(map[int]*Token)
|
tokenMap := make(map[int]*Token)
|
||||||
|
|
||||||
for i := 2; i < len(rawinput); i++ {
|
if p.script.CDL == nil {
|
||||||
raw := rawinput[i]
|
p.script.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{
|
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
|
||||||
|
|
||||||
if raw < 0x80 {
|
if raw < 0x80 || p.script.CDL.IsData(p.current+startAddr) { // || p.current >= earliestVar {
|
||||||
|
if p.script.CDL.IsData(p.current+startAddr) {
|
||||||
|
token.IsData = true
|
||||||
|
//fmt.Print(".")
|
||||||
|
//fmt.Printf("%#v\n", token)
|
||||||
|
}
|
||||||
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{}
|
|
||||||
switch op.OpCount {
|
|
||||||
case -1: // null terminated
|
|
||||||
for ; i < len(rawinput); i++ {
|
|
||||||
val := ByteVal(rawinput[i])
|
|
||||||
args = append(args, val)
|
|
||||||
if rawinput[i] == 0x00 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case -2: // count then count words
|
|
||||||
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]}))
|
|
||||||
i+=2
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 +304,83 @@ 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++ {
|
||||||
|
p.script.CDL.setCode(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])
|
||||||
|
p.script.CDL.setCode(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.script.CDL.setCode(p.current)
|
||||||
|
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.script.CDL.setCode(p.current+1)
|
||||||
|
p.script.CDL.setCode(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++
|
||||||
|
p.script.CDL.setCode(p.current)
|
||||||
|
args = append(args, ByteVal(p.rawinput[p.current]))
|
||||||
|
}
|
||||||
|
|
||||||
|
token.Inline = args
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package script
|
package script
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Script struct {
|
type Script struct {
|
||||||
|
@ -12,15 +11,7 @@ type Script struct {
|
||||||
StackAddress int
|
StackAddress int
|
||||||
|
|
||||||
Labels map[int]*Label
|
Labels map[int]*Label
|
||||||
}
|
CDL *CodeDataLog
|
||||||
|
|
||||||
type InstrStat struct {
|
|
||||||
Instr *Instruction
|
|
||||||
Count int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (is InstrStat) String() string {
|
|
||||||
return fmt.Sprintf("0x%02X %3d %s", is.Instr.Opcode, is.Count, is.Instr.String())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Script) Stats() Stats {
|
func (s *Script) Stats() Stats {
|
||||||
|
|
|
@ -9,6 +9,15 @@ import (
|
||||||
|
|
||||||
type Stats map[byte]*InstrStat
|
type Stats map[byte]*InstrStat
|
||||||
|
|
||||||
|
type InstrStat struct {
|
||||||
|
Instr *Instruction
|
||||||
|
Count int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (is InstrStat) String() string {
|
||||||
|
return fmt.Sprintf("0x%02X %6d %s", is.Instr.Opcode, is.Count, is.Instr.String())
|
||||||
|
}
|
||||||
|
|
||||||
func (this Stats) Add(that Stats) {
|
func (this Stats) Add(that Stats) {
|
||||||
for _, st := range that {
|
for _, st := range that {
|
||||||
op := st.Instr.Opcode
|
op := st.Instr.Opcode
|
||||||
|
@ -40,7 +49,23 @@ func (s Stats) WriteTo(w io.Writer) (int64, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err := fmt.Fprintln(w, "\nUnknown uses:", unknownUses)
|
n, err := fmt.Fprintln(w, "\nUnused OpCodes:")
|
||||||
|
count += int64(n)
|
||||||
|
if err != nil {
|
||||||
|
return count, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := byte(0x80); i <= 0xFF && i >= 0x80; i++ {
|
||||||
|
if _, ok := s[i]; !ok {
|
||||||
|
n, err = fmt.Fprintf(w, "0x%02X %s\n", i, InstrMap[i].Name)
|
||||||
|
count += int64(n)
|
||||||
|
if err != nil {
|
||||||
|
return count, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err = fmt.Fprintln(w, "\nUnknown uses:", unknownUses)
|
||||||
count += int64(n)
|
count += int64(n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return count, err
|
return count, err
|
||||||
|
|
|
@ -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"
|
|
||||||
} else {
|
|
||||||
prefix = fmt.Sprintf("\nL%04X:\n", t.Offset)
|
|
||||||
}
|
}
|
||||||
} else {
|
name := ""
|
||||||
if lbl, ok := labels[t.Offset]; ok && lbl.Comment != "" {
|
if lbl.Name != "" {
|
||||||
suffix = " ; "+lbl.Comment+suffix
|
name = lbl.Name+":\n"
|
||||||
}
|
}
|
||||||
|
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,
|
||||||
|
|
Loading…
Reference in New Issue