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") // } // } //}