Swap input output files, allow multiple input, fix string parsing

- Swapped the input filename and output filename on the command line so
  multiple input files could be passed.
- Implemented appending configs when reading multiple input files.  Only
  lables, ranges, and segments are updated.  All other config settings
  are taken from the first input file.
- Fixed string parsing to allow escaping quotes inside a string.
This commit is contained in:
Zorchenhimer 2026-01-10 13:37:05 -05:00
parent 2310b042b0
commit 3406122170
Signed by: Zorchenhimer
GPG Key ID: 70A1AB767AAB9C20
4 changed files with 63 additions and 16 deletions

View File

@ -10,11 +10,11 @@ import (
) )
type Arguments struct { type Arguments struct {
Input string `arg:"positional,required"` Output string `arg:"positional,required"`
Output string `arg:"positional"` Input []string `arg:"positional,required"`
RamStart int `arg:"--ram-start" default:"0x5000"` RamStart int `arg:"--ram-start" default:"0x6000"`
RomStart int `arg:"--rom-start" default:"0xE000"` RomStart int `arg:"--rom-start" default:"0x8000"`
} }
func main() { func main() {
@ -29,20 +29,41 @@ func main() {
} }
func run(args *Arguments) error { func run(args *Arguments) error {
input, err := os.ReadFile(args.Input) var config *dasmlbl.Config
if err != nil { var err error
return err
for _, infile := range args.Input {
input, err := os.ReadFile(infile)
if err != nil {
return err
}
l, ch := dasmlbl.NewLexer(string(input))
go l.Run()
parser := dasmlbl.NewParser(ch)
cfg, err := parser.Run()
if err != nil {
fmt.Printf("[%s] %s\n", infile, err)
}
if config == nil {
config = cfg
} else {
config.Append(cfg)
}
} }
l, ch := dasmlbl.NewLexer(string(input)) if config == nil {
go l.Run() return fmt.Errorf("no configs parsed")
parser := dasmlbl.NewParser(ch)
config, err := parser.Run()
if err != nil {
fmt.Println(err)
} }
//input, err := os.ReadFile(args.Input)
//if err != nil {
// return err
//}
var output *os.File var output *os.File
if args.Output == "" { if args.Output == "" {
output = os.Stdout output = os.Stdout

View File

@ -30,6 +30,12 @@ type Config struct {
Segments []Segment Segments []Segment
} }
func (c *Config) Append(other *Config) {
c.Labels = append(c.Labels, other.Labels...)
c.Ranges = append(c.Ranges, other.Ranges...)
c.Segments = append(c.Segments, other.Segments...)
}
type Label struct { type Label struct {
Name string Name string
Address int Address int

20
lex.go
View File

@ -61,6 +61,19 @@ func (l *Lexer) next() rune {
return r return r
} }
func (l *Lexer) peek() rune {
if l.pos >= len(l.input) {
l.width = 0
return unicode_EOF
}
r, size := utf8.DecodeRuneInString(l.input[l.pos:])
if size == 0 {
panic(fmt.Sprintf("zero width at %d", l.pos))
}
return r
}
func (l *Lexer) backup() { func (l *Lexer) backup() {
l.pos -= l.width l.pos -= l.width
} }
@ -177,6 +190,13 @@ func lexString(l *Lexer) stateFn {
l.items <- LexItem{lex_Error, "EOF before string end"} l.items <- LexItem{lex_Error, "EOF before string end"}
return nil return nil
} }
if r == '\\' && l.peek() == '"' {
r = l.next()
//fmt.Printf("consuming %c\n", r) // consume
continue
}
if r == '"' { if r == '"' {
break break
} }

View File

@ -139,7 +139,7 @@ func (p *Parser) parseRange() error {
itm = p.next() itm = p.next()
if itm.typ != lex_Semicolon { if itm.typ != lex_Semicolon {
return fmt.Errorf("missing semicolon") return fmt.Errorf("[parseRange] missing semicolon")
} }
} }
@ -213,7 +213,7 @@ func (p *Parser) parseLabel() error {
itm = p.next() itm = p.next()
if itm.typ != lex_Semicolon { if itm.typ != lex_Semicolon {
return fmt.Errorf("missing semicolon") return fmt.Errorf("[parseLabel] missing semicolon; %#v", lbl)
} }
} }