250 lines
4.5 KiB
Go
250 lines
4.5 KiB
Go
package dasmlbl
|
|
|
|
import (
|
|
"strings"
|
|
"strconv"
|
|
"fmt"
|
|
)
|
|
|
|
type Parser struct {
|
|
config *Config
|
|
items chan LexItem
|
|
}
|
|
|
|
func NewParser(items chan LexItem) *Parser {
|
|
return &Parser{
|
|
config: &Config{},
|
|
items: items,
|
|
}
|
|
}
|
|
|
|
func (p *Parser) next() LexItem {
|
|
select {
|
|
case itm := <- p.items:
|
|
//fmt.Println(itm)
|
|
return itm
|
|
}
|
|
return LexItem{lex_EOF, "EOF"}
|
|
}
|
|
|
|
func (p *Parser) Run() (*Config, error) {
|
|
for {
|
|
itm := p.next()
|
|
//fmt.Println("<", itm)
|
|
if itm.typ == lex_EOF {
|
|
break
|
|
}
|
|
|
|
if itm.typ == lex_Pound {
|
|
itm = p.next()
|
|
continue
|
|
}
|
|
|
|
if itm.typ != lex_Ident {
|
|
continue
|
|
//return nil, fmt.Errorf("expected ident, got %s", itm)
|
|
}
|
|
|
|
//if strings.ToLower(itm.val) != "label" {
|
|
// continue
|
|
//}
|
|
|
|
var err error
|
|
switch strings.ToLower(itm.val) {
|
|
case "label":
|
|
err = p.parseLabel()
|
|
case "range":
|
|
err = p.parseRange()
|
|
}
|
|
|
|
if err != nil {
|
|
return p.config, err
|
|
}
|
|
}
|
|
return p.config, nil
|
|
}
|
|
|
|
func (p *Parser) parseRange() error {
|
|
itm := p.next()
|
|
if itm.typ != lex_OpenBracket {
|
|
return fmt.Errorf("missing open bracket")
|
|
}
|
|
|
|
rng := Range{}
|
|
for {
|
|
itm = p.next()
|
|
if itm.typ == lex_CloseBracket {
|
|
break
|
|
}
|
|
|
|
if itm.typ != lex_Ident {
|
|
return fmt.Errorf("missing ident")
|
|
}
|
|
|
|
switch strings.ToLower(itm.val) {
|
|
case "name", "comment":
|
|
typ := itm.val
|
|
itm = p.next()
|
|
if itm.typ != lex_String {
|
|
return fmt.Errorf("%s requires string: %s", typ, itm)
|
|
//return fmt.Errorf("name requires string")
|
|
}
|
|
|
|
switch typ {
|
|
case "name":
|
|
rng.Name = itm.val
|
|
case "comment":
|
|
rng.Comment = itm.val
|
|
case "type":
|
|
rng.Type = itm.val
|
|
case "addrmode":
|
|
rng.AddrMode = itm.val
|
|
}
|
|
|
|
case "type", "addrmode":
|
|
itm = p.next()
|
|
if itm.typ != lex_Ident {
|
|
return fmt.Errorf("%s requires ident: %s", itm.val, itm)
|
|
}
|
|
rng.Type = itm.val
|
|
|
|
case "start", "end", "unit":
|
|
typ := itm.val
|
|
itm = p.next()
|
|
if itm.typ != lex_Number {
|
|
return fmt.Errorf("%s: %s", strings.ToLower(typ+" requires number"), itm)
|
|
}
|
|
|
|
str := itm.val
|
|
if strings.HasPrefix(str, "$") {
|
|
str = "0x"+strings.TrimPrefix(str, "$")
|
|
} else if strings.HasPrefix(str, "%") {
|
|
str = "0b"+strings.TrimPrefix(str, "%")
|
|
}
|
|
|
|
val, err := strconv.ParseInt(str, 0, 32)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
switch typ {
|
|
case "start":
|
|
rng.Start = int(val)
|
|
case "end":
|
|
rng.End = int(val)
|
|
case "unit":
|
|
rng.Unit = int(val)
|
|
}
|
|
}
|
|
|
|
itm = p.next()
|
|
if itm.typ != lex_Semicolon {
|
|
return fmt.Errorf("[parseRange] missing semicolon")
|
|
}
|
|
}
|
|
|
|
p.config.Ranges = append(p.config.Ranges, rng)
|
|
return nil
|
|
}
|
|
|
|
func (p *Parser) parseLabel() error {
|
|
itm := p.next()
|
|
if itm.typ != lex_OpenBracket {
|
|
return fmt.Errorf("missing open bracket")
|
|
}
|
|
|
|
lbl := Label{}
|
|
for {
|
|
itm = p.next()
|
|
if itm.typ == lex_CloseBracket {
|
|
break
|
|
}
|
|
|
|
if itm.typ != lex_Ident {
|
|
return fmt.Errorf("missing ident")
|
|
}
|
|
|
|
//fmt.Println("]", itm)
|
|
|
|
switch strings.ToLower(itm.val) {
|
|
case "name":
|
|
itm = p.next()
|
|
if itm.typ != lex_String {
|
|
return fmt.Errorf("name requires string: %s", itm)
|
|
}
|
|
lbl.Name = itm.val
|
|
|
|
case "addr", "size", "paramsize":
|
|
typ := strings.ToLower(itm.val)
|
|
itm = p.next()
|
|
if itm.typ != lex_Number {
|
|
return fmt.Errorf("%s: %s", strings.ToLower(typ+" requires number"), itm)
|
|
}
|
|
|
|
str := itm.val
|
|
if strings.HasPrefix(str, "$") {
|
|
str = "0x"+strings.TrimPrefix(str, "$")
|
|
} else if strings.HasPrefix(str, "%") {
|
|
str = "0b"+strings.TrimPrefix(str, "%")
|
|
}
|
|
|
|
val, err := strconv.ParseInt(str, 0, 32)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
switch typ {
|
|
case "addr":
|
|
lbl.Address = int(val)
|
|
case "size":
|
|
lbl.Size = int(val)
|
|
case "paramsize":
|
|
lbl.ParamSize = int(val)
|
|
}
|
|
|
|
case "comment":
|
|
itm = p.next()
|
|
if itm.typ != lex_String {
|
|
return fmt.Errorf("comment requires string")
|
|
}
|
|
|
|
lbl.Comment = itm.val
|
|
}
|
|
|
|
itm = p.next()
|
|
if itm.typ != lex_Semicolon {
|
|
return fmt.Errorf("[parseLabel] missing semicolon; %#v", lbl)
|
|
}
|
|
}
|
|
|
|
p.config.Labels = append(p.config.Labels, lbl)
|
|
return nil
|
|
}
|
|
|
|
//func (p *Parser) parseIdent(itm LexItem) error {
|
|
// switch strings.ToLower(itm.val) {
|
|
// case "global":
|
|
// select {
|
|
// case itm = <- p.items:
|
|
// if itm.typ != lex_OpenBracket {
|
|
// return fmt.Errorf("expected { after global, got %q", itm)
|
|
// }
|
|
// return p.parseGlobal()
|
|
// default:
|
|
// return fmt.Errorf("early EOF")
|
|
// }
|
|
// }
|
|
//
|
|
// return nil
|
|
//}
|
|
|
|
//func (p *Parser) parseGlobal() error {
|
|
// for {
|
|
// select {
|
|
// case itm := <- p.items:
|
|
// default:
|
|
// return fmt.Errorf("early EOF")
|
|
// }
|
|
// }
|
|
//}
|