[script] Better auto label support
Labels are now their own object instead of just a string. This allows for a bit more control with them. Labels can also now have comments. Additionally, add the ability to load user-defined labels from a file. The format of this file is subject to change, but for now it is just a simple text file. Each line of the file is a label definition. Each line has three fields, separated by spaces. The first field is the address, second is the label name, and the rest of the line is a comment. If a label name is just a dollar sign ($) it will not have a name. This is used when adding comments without a bespoke label.
This commit is contained in:
parent
29e48f3cac
commit
4b9f04874b
|
@ -5,8 +5,11 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
"strconv"
|
||||
"bufio"
|
||||
"slices"
|
||||
|
||||
"github.com/alexflint/go-arg"
|
||||
|
||||
"git.zorchenhimer.com/Zorchenhimer/go-studybox/script"
|
||||
)
|
||||
|
||||
|
@ -14,6 +17,8 @@ type Arguments struct {
|
|||
Input string `arg:"positional,required"`
|
||||
Output string `arg:"positional"`
|
||||
StartAddr string `arg:"--start" default:"0x6000" help:"base address for the start of the script"`
|
||||
LabelFile string `arg:"--labels" help:"file containing address/label pairs"`
|
||||
|
||||
start int
|
||||
}
|
||||
|
||||
|
@ -38,6 +43,18 @@ func run(args *Arguments) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if args.LabelFile != "" {
|
||||
labels, err := parseLabelFile(args.LabelFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, label := range labels {
|
||||
//fmt.Printf("%#v\n", label)
|
||||
scr.Labels[label.Address] = label
|
||||
}
|
||||
}
|
||||
|
||||
outfile := os.Stdout
|
||||
if args.Output != "" {
|
||||
outfile, err = os.Create(args.Output)
|
||||
|
@ -64,6 +81,62 @@ func run(args *Arguments) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func parseLabelFile(filename string) ([]*script.Label, error) {
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
labels := []*script.Label{}
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
|
||||
line = strings.ReplaceAll(line, "\t", " ")
|
||||
parts := strings.Split(line, " ")
|
||||
|
||||
parts = slices.DeleteFunc(parts, func(str string) bool {
|
||||
return str == ""
|
||||
})
|
||||
|
||||
if len(parts) < 2 {
|
||||
fmt.Println("Ignoring", line)
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(parts[0], "$") {
|
||||
parts[0] = "0x"+parts[0][1:]
|
||||
}
|
||||
|
||||
addr, err := strconv.ParseInt(parts[0], 0, 32)
|
||||
if err != nil {
|
||||
fmt.Printf("Address parse error for %q: %s\n", line, err)
|
||||
continue
|
||||
}
|
||||
|
||||
lbl := &script.Label{
|
||||
Name: parts[1],
|
||||
Address: int(addr),
|
||||
}
|
||||
|
||||
if lbl.Name == "$" {
|
||||
lbl.Name = ""
|
||||
}
|
||||
|
||||
if len(parts) > 2 {
|
||||
lbl.Comment = strings.Join(parts[2:], " ")
|
||||
}
|
||||
|
||||
labels = append(labels, lbl)
|
||||
}
|
||||
|
||||
return labels, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
args := &Arguments{}
|
||||
arg.MustParse(args)
|
||||
|
|
|
@ -5,6 +5,42 @@ import (
|
|||
"os"
|
||||
)
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
func ParseFile(filename string, startAddr int) (*Script, error) {
|
||||
rawfile, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
|
@ -24,7 +60,7 @@ func Parse(rawinput []byte, startAddr int) (*Script, error) {
|
|||
Warnings: []string{},
|
||||
StackAddress: (int(rawinput[1])<<8) | int(rawinput[0]),
|
||||
StartAddress: startAddr,
|
||||
Labels: make(map[int]string), // map[location]name
|
||||
Labels: make(map[int]*Label), // map[location]name
|
||||
}
|
||||
tokenMap := make(map[int]*Token)
|
||||
|
||||
|
@ -112,7 +148,7 @@ func Parse(rawinput []byte, startAddr int) (*Script, error) {
|
|||
if tok.Offset == addr {
|
||||
tok.IsTarget = true
|
||||
found = true
|
||||
script.Labels[addr] = fmt.Sprintf("L%04X", addr)
|
||||
script.Labels[addr] = AutoLabel(addr) //fmt.Sprintf("L%04X", addr)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -133,7 +169,7 @@ func Parse(rawinput []byte, startAddr int) (*Script, error) {
|
|||
if tok.Offset == addr {
|
||||
tok.IsTarget = true
|
||||
found = true
|
||||
script.Labels[addr] = fmt.Sprintf("L%04X", addr)
|
||||
script.Labels[addr] = AutoLabel(addr) //fmt.Sprintf("L%04X", addr)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -152,7 +188,7 @@ func Parse(rawinput []byte, startAddr int) (*Script, error) {
|
|||
addr := t.Inline[0].Int()
|
||||
if tok, ok := tokenMap[addr]; ok {
|
||||
tok.IsVariable = true
|
||||
script.Labels[addr] = fmt.Sprintf("Var_%04X", addr)
|
||||
script.Labels[addr] = AutoLabelVar(addr) //fmt.Sprintf("Var_%04X", addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,5 +10,6 @@ type Script struct {
|
|||
StartAddress int
|
||||
StackAddress int
|
||||
|
||||
Labels map[int]string
|
||||
//Labels map[int]string
|
||||
Labels map[int]*Label
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ type Token struct {
|
|||
Instruction *Instruction
|
||||
}
|
||||
|
||||
func (t Token) String(labels map[int]string) string {
|
||||
func (t Token) String(labels map[int]*Label) string {
|
||||
suffix := ""
|
||||
switch t.Raw {
|
||||
case 0x86:
|
||||
|
@ -25,10 +25,18 @@ func (t Token) String(labels map[int]string) string {
|
|||
prefix := ""
|
||||
if t.IsTarget || t.IsVariable {
|
||||
if lbl, ok := labels[t.Offset]; ok {
|
||||
prefix = "\n"+lbl+":\n"
|
||||
comment := ""
|
||||
if lbl.Comment != "" {
|
||||
comment = "; "+lbl.Comment+"\n"
|
||||
}
|
||||
prefix = "\n"+comment+lbl.Name+":\n"
|
||||
} else {
|
||||
prefix = fmt.Sprintf("\nL%04X:\n", t.Offset)
|
||||
}
|
||||
} else {
|
||||
if lbl, ok := labels[t.Offset]; ok && lbl.Comment != "" {
|
||||
suffix = " ; "+lbl.Comment+suffix
|
||||
}
|
||||
}
|
||||
|
||||
if t.Raw < 0x80 {
|
||||
|
@ -56,7 +64,7 @@ func (t Token) String(labels map[int]string) string {
|
|||
argstr := []string{}
|
||||
for _, a := range t.Inline {
|
||||
if lbl, ok := labels[a.Int()]; ok {
|
||||
argstr = append(argstr, lbl)
|
||||
argstr = append(argstr, lbl.Name)
|
||||
} else {
|
||||
argstr = append(argstr, a.HexString())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue