Better error messages

This commit is contained in:
Přemysl Eric Janouch 2016-10-20 01:47:07 +02:00
parent b247f025d5
commit 17e7453fff
Signed by: p
GPG Key ID: B715679E3A361BE6
2 changed files with 27 additions and 31 deletions

View File

@ -125,7 +125,7 @@ func (t *tokenizer) eat() (byte, error) {
if c == '\n' { if c == '\n' {
t.location.line++ t.location.line++
t.location.column = 0 t.location.column = 1
} else { } else {
t.location.column++ t.location.column++
} }
@ -210,7 +210,7 @@ func (t *tokenizer) step() error {
func tokenize(r io.Reader, tokens chan<- token) { func tokenize(r io.Reader, tokens chan<- token) {
t := tokenizer{ t := tokenizer{
location: location{line: 1, column: 0}, location: location{line: 1, column: 1},
tokens: tokens, tokens: tokens,
reader: bufio.NewReader(r), reader: bufio.NewReader(r),
} }
@ -218,8 +218,7 @@ func tokenize(r io.Reader, tokens chan<- token) {
if err := t.step(); err == io.EOF { if err := t.step(); err == io.EOF {
break break
} else if err != nil { } else if err != nil {
t.tokens <- token{t.location, fmt.Sprintf("line %d, column %d: %s", t.tokens <- token{t.location, err.Error(), 0, ERROR}
t.location.line, t.location.column, err.Error()), 0, ERROR}
break break
} }
} }
@ -246,19 +245,23 @@ func (a *assembler) step() (bool, error) {
return false, nil return false, nil
} }
// TODO: add token location information to returned errors mkerr := func(format string, a ...interface{}) error {
prefix := fmt.Sprintf("line %d, column %d: ",
token.location.line, token.location.column)
return errors.New(prefix + fmt.Sprintf(format, a...))
}
switch token.kind { switch token.kind {
case WORD: case WORD:
if _, dup := a.labels[token.value]; dup { if _, dup := a.labels[token.value]; dup {
return false, fmt.Errorf("Duplicate label: %s", token.value) return false, mkerr("duplicate label: %s", token.value)
} }
a.labels[token.value] = len(a.output) a.labels[token.value] = len(a.output)
if token, ok = <-a.tokens; !ok { if token, ok = <-a.tokens; !ok {
return false, errors.New("Unexpected end of file") return false, mkerr("unexpected end of file")
} }
if token.kind != INSTRUCTION { if token.kind != INSTRUCTION {
return false, errors.New("Expected instruction name after label") return false, mkerr("expected instruction name after label")
} }
fallthrough fallthrough
case INSTRUCTION: case INSTRUCTION:
@ -288,17 +291,17 @@ func (a *assembler) step() (bool, error) {
case !ok: case !ok:
case token.kind == NEWLINE: case token.kind == NEWLINE:
case token.kind == ERROR: case token.kind == ERROR:
return false, errors.New(token.value) return false, mkerr("%s", token.value)
default: default:
return false, errors.New("Expected end of line") return false, mkerr("expected end of line")
} }
} }
case NEWLINE: case NEWLINE:
// Ignore empty lines // Ignore empty lines
case NUMBER: case NUMBER:
return false, errors.New("Unexpected number") return false, mkerr("unexpected number")
case ERROR: case ERROR:
return false, errors.New(token.value) return false, mkerr("%s", token.value)
} }
return true, nil return true, nil
} }
@ -318,7 +321,7 @@ func Assemble(r io.Reader) (code []int16, err error) {
code = make([]int16, 100) code = make([]int16, 100)
for i, x := range a.output { for i, x := range a.output {
if i >= len(code) { if i >= len(code) {
return nil, errors.New("Program too long") return nil, errors.New("program too long")
} }
n := x.id n := x.id
switch { switch {
@ -327,7 +330,7 @@ func Assemble(r io.Reader) (code []int16, err error) {
case len(x.target) != 0: case len(x.target) != 0:
// Resolve targets to code locations // Resolve targets to code locations
if resolved, ok := a.labels[x.target]; !ok { if resolved, ok := a.labels[x.target]; !ok {
return nil, errors.New("Unknown label") return nil, errors.New("unknown label")
} else { } else {
n += resolved n += resolved
} }

27
main.go
View File

@ -7,22 +7,15 @@ import (
func main() { func main() {
if len(os.Args) != 2 { if len(os.Args) != 2 {
fmt.Printf("usage: %s file", os.Args[0]) fmt.Printf("usage: %s file\n", os.Args[0])
os.Exit(1) } else if file, err := os.Open(os.Args[1]); err != nil {
} fmt.Printf("Cannot open file: %s\n", err)
file, err := os.Open(os.Args[1]) } else if code, err := Assemble(file); err != nil {
if err != nil { fmt.Printf("Assembly failed: %s\n", err)
fmt.Printf("Cannot open file: %s", err) } else if err = Run(code); err != nil {
os.Exit(1) fmt.Printf("Runtime error: %s\n", err)
} } else {
code, err := Assemble(file) os.Exit(0)
if err != nil {
fmt.Printf("Assembly failed: %s", err)
os.Exit(1)
}
err = Run(code)
if err != nil {
fmt.Printf("Runtime error: %s", err)
os.Exit(1)
} }
os.Exit(1)
} }