feat(go): show where in main.sym that errors appear

This commit is contained in:
phaneron 2024-07-25 17:13:56 -04:00
parent cf049a801f
commit adb68c759c

View file

@ -1,139 +1,141 @@
package symfile package symfile
import ( import (
"bufio" "bufio"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"slices" "slices"
"strconv" "strconv"
"strings" "strings"
) )
const min_columns = 3 const min_columns = 3
type loader struct { type loader struct {
input *bufio.Reader input *bufio.Reader
table Table table Table
line_number int line_number int
} }
func (l *loader) read_line() (line string, err error) { func (l *loader) read_line() (line string, err error) {
l.line_number++ l.line_number++
line, err = l.input.ReadString('\n') line, err = l.input.ReadString('\n')
if err != nil { if err != nil {
return return
} }
line = strings.TrimRight(line, "\r\n") line = strings.TrimRight(line, "\r\n")
return return
} }
func (l *loader) parse_line(line string) (err error) { func (l *loader) parse_line(line string) (err error) {
// trim extraneous whitespace // trim extraneous whitespace
line = strings.Trim(line, " \t") line = strings.Trim(line, " \t")
// split into columns // split into columns
columns := strings.Split(line, " ") columns := strings.Split(line, " ")
// validate // validate
if len(columns) < min_columns { if len(columns) < min_columns {
// this line is discarded but not in error // this line is discarded but not in error
return return
} }
var ( var (
start_address uint64 start_address uint64
comment_text string comment_text string
) )
// get name of symbol // get name of symbol
name_column := columns[0] name_column := columns[0]
if name_column == "" { if name_column == "" {
return fmt.Errorf("symfile: (*loader).parse_line: line %d: entry has invalid name '%s", l.line_number, name_column) return fmt.Errorf("symfile: (*loader).parse_line: line %d: entry has invalid name '%s", l.line_number, name_column)
} }
start_address, err = strconv.ParseUint(columns[1], 16, 64) start_address, err = strconv.ParseUint(columns[1], 16, 64)
if err != nil { if err != nil {
return return
} }
kind_column := columns[2] kind_column := columns[2]
if len(kind_column) != 1 { if len(kind_column) != 1 {
return fmt.Errorf("symfile: (*loader).parse_line: line %d: entry has invalid kind", l.line_number) return fmt.Errorf("symfile: (*loader).parse_line: line %d: entry has invalid kind", l.line_number)
} }
kind := EntryKind(kind_column[0]) kind := EntryKind(kind_column[0])
if !slices.Contains(valid_kinds, kind) { if !slices.Contains(valid_kinds, kind) {
return fmt.Errorf("symfile: (*loader).parse_line: line %d: entry has invalid kind", l.line_number) return fmt.Errorf("symfile: (*loader).parse_line: line %d: entry has invalid kind", l.line_number)
} }
// find index of comment column // find index of comment column
index_of_comment := slices.Index(columns, ";") index_of_comment := slices.Index(columns, ";")
var num_semantic_columns int var num_semantic_columns int
if index_of_comment != -1 { if index_of_comment != -1 {
num_semantic_columns = index_of_comment num_semantic_columns = index_of_comment
comment_text_columns := columns[index_of_comment+1:] comment_text_columns := columns[index_of_comment+1:]
comment_text = strings.Join(comment_text_columns, " ") comment_text = strings.Join(comment_text_columns, " ")
} else { } else {
num_semantic_columns = len(columns) num_semantic_columns = len(columns)
} }
// Start to build entry // Start to build entry
var entry Entry var entry Entry
entry.Name = name_column entry.Name = name_column
entry.StartAddress = start_address entry.StartAddress = start_address
entry.Kind = kind entry.Kind = kind
entry.Comment = comment_text entry.Comment = comment_text
// build attributes // build attributes
if num_semantic_columns > 3 { if num_semantic_columns > 3 {
for _, column := range columns[3:] { for _, column := range columns[3:] {
key, value, found := strings.Cut(column, "=") key, value, found := strings.Cut(column, "=")
if found { if found {
switch key { switch key {
case "end": case "end":
entry.EndAddress, err = strconv.ParseUint(value, 16, 64) entry.EndAddress, err = strconv.ParseUint(value, 16, 64)
if err != nil { if err != nil {
return return
} }
default: default:
return fmt.Errorf("symfile: (*loader).parse_line: line %d: unknown attribute '%s'", l.line_number, key) return fmt.Errorf("symfile: (*loader).parse_line: line %d: unknown attribute '%s'", l.line_number, key)
} }
} }
} }
} }
err = l.table.Insert(&entry) err = l.table.Insert(&entry)
return return
} }
func load(text io.Reader, table Table) (err error) { func load(text io.Reader, table Table) (err error) {
l := new(loader) l := new(loader)
l.input = bufio.NewReader(text) l.input = bufio.NewReader(text)
l.table = table l.table = table
var ( var (
line string line string
) )
for { for {
line, err = l.read_line() line, err = l.read_line()
if err != nil { if err != nil {
if errors.Is(err, io.EOF) { if errors.Is(err, io.EOF) {
err = nil err = nil
break break
} else { } else {
return err = fmt.Errorf("symfile: error reading at line %d: %w", l.line_number, err)
} return
} }
}
if err = l.parse_line(line); err != nil {
return if err = l.parse_line(line); err != nil {
} err = fmt.Errorf("symfile: error parsing at line %d: %w", l.line_number, err)
} return
}
return }
}
return
}