Arbitrary checkpoint

Apparently a gofmt happened in the meantime.
This commit is contained in:
Přemysl Eric Janouch 2016-10-19 20:20:43 +02:00
parent 04639942af
commit 17279e3e6e
Signed by: p
GPG Key ID: B715679E3A361BE6
2 changed files with 84 additions and 56 deletions

View File

@ -1,12 +1,12 @@
package main package main
import ( import (
"errors"
"io"
"fmt"
"bufio" "bufio"
"strings" "errors"
"fmt"
"io"
"strconv" "strconv"
"strings"
) )
const ( const (
@ -28,12 +28,10 @@ type token struct {
} }
type tokenizer struct { type tokenizer struct {
line int // Current line location location // Current position
column int // Current column
value []byte // Current token string value []byte // Current token string
reader *bufio.Reader // Reader reader *bufio.Reader // Reader
tokens chan<- token // Token channel tokens chan<- token // Output token channel
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -47,7 +45,9 @@ func isNumber(c byte) bool {
} }
func isWordHead(c byte) bool { func isWordHead(c byte) bool {
if c >= 'a' && c <= 'z' { c -= 32 } if c >= 'a' && c <= 'z' {
c -= 32
}
return c >= 'a' && c <= 'z' || c == '_' return c >= 'a' && c <= 'z' || c == '_'
} }
@ -57,12 +57,13 @@ func isWordTail(c byte) bool {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
func (t *tokenizer) send(kind int) { func (t *tokenizer) send(start location, kind int) {
// FIXME: track the beginning of the token t.tokens <- token{start, string(t.value), kind}
t.tokens <- token{location{t.line, t.column}, string(t.value), kind}
t.value = []byte{} t.value = []byte{}
} }
// XXX: the handling could probably be simplified by extending the "byte"
// to also include a special value for io.EOF and other errors
func (t *tokenizer) peek() (byte, error) { func (t *tokenizer) peek() (byte, error) {
buf, err := t.reader.Peek(1) buf, err := t.reader.Peek(1)
return buf[0], err return buf[0], err
@ -70,13 +71,15 @@ func (t *tokenizer) peek() (byte, error) {
func (t *tokenizer) eat() (byte, error) { func (t *tokenizer) eat() (byte, error) {
c, err := t.reader.ReadByte() c, err := t.reader.ReadByte()
if err != nil { return 0, err } if err != nil {
return 0, err
}
if c == '\n' { if c == '\n' {
t.line++ t.location.line++
t.column = 0 t.location.column = 0
} else { } else {
t.column++ t.location.column++
} }
return c, nil return c, nil
} }
@ -87,63 +90,88 @@ func (t *tokenizer) step() error {
t.value = []byte{} t.value = []byte{}
c, err := t.peek() c, err := t.peek()
if err == io.EOF { return nil } if err == io.EOF {
if err != nil { return err } return nil
}
if err != nil {
return err
}
start := t.location
switch { switch {
case isSpace(c): case isSpace(c):
t.eat() c, err = t.eat()
case c == '\n': case c == '\n':
c, err = t.eat() c, err = t.eat()
t.value = append(t.value, c) t.value = append(t.value, c)
t.send(NEWLINE) t.send(start, NEWLINE)
case isNumber(c): case isNumber(c):
c, err = t.eat() c, err = t.eat()
t.value = append(t.value, c) t.value = append(t.value, c)
for { for {
c, err = t.peek() c, err = t.peek()
if err == io.EOF { break } if err == io.EOF {
if err != nil { return err } break
}
if err != nil {
return err
}
if !isNumber(c) { break } if !isNumber(c) {
break
}
c, _ = t.eat() c, err = t.eat()
t.value = append(t.value, c) t.value = append(t.value, c)
} }
t.send(NUMBER) t.send(start, NUMBER)
case isWordHead(c): case isWordHead(c):
c, err = t.eat() c, err = t.eat()
t.value = append(t.value, c) t.value = append(t.value, c)
for { for {
c, err = t.peek() c, err = t.peek()
if err == io.EOF { break } if err == io.EOF {
if err != nil { return err } break
}
if err != nil {
return err
}
if !isWordTail(c) { break } if !isWordTail(c) {
break
}
c, _ = t.eat() c, err = t.eat()
t.value = append(t.value, c) t.value = append(t.value, c)
} }
t.send(WORD) t.send(start, WORD)
case c == '/': case c == '/':
c, err = t.eat() c, err = t.eat()
t.value = append(t.value, c) t.value = append(t.value, c)
c, err = t.peek() c, err = t.peek()
if err != nil { return err } if err != nil {
return err
}
if c != '/' { if c != '/' {
return errors.New("unrecognized input") return errors.New("unrecognized input")
} }
for { for {
c, err = t.peek() c, err = t.peek()
if err == io.EOF { break } if err == io.EOF {
if err != nil { return err } break
}
if err != nil {
return err
}
if c == '\n' { break } if c == '\n' {
break
}
t.eat() t.eat()
} }
default: default:
@ -154,8 +182,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{
line: 1, location: location{line: 1, column: 0},
column: 0,
tokens: tokens, tokens: tokens,
reader: bufio.NewReader(r), reader: bufio.NewReader(r),
} }
@ -165,9 +192,8 @@ func tokenize(r io.Reader, tokens chan<- token) {
break break
} }
if err != nil { if err != nil {
t.tokens <- token{location{t.line, t.column}, t.tokens <- token{t.location, fmt.Sprintf("line %d, column %d: %s",
fmt.Sprintf("line %d, column %d: %s", t.location.line, t.location.column, err.Error()), ERROR}
t.line, t.column, err.Error()), ERROR}
break break
} }
} }
@ -221,7 +247,9 @@ type assembler struct {
func (a *assembler) step() (bool, error) { func (a *assembler) step() (bool, error) {
token, ok := <-a.tokens token, ok := <-a.tokens
if !ok { return false, nil } if !ok {
return false, nil
}
// TODO: add token location information to returned errors // TODO: add token location information to returned errors
@ -297,7 +325,7 @@ func Assemble(r io.Reader) (code []int16, err error) {
} }
} }
for _, x := range(a.output) { for _, x := range a.output {
n := x.id * 100 n := x.id * 100
if len(x.target) != 0 { if len(x.target) != 0 {
if resolved, ok := a.labels[x.target]; !ok { if resolved, ok := a.labels[x.target]; !ok {

View File

@ -1,8 +1,8 @@
package main package main
import ( import (
"os"
"fmt" "fmt"
"os"
) )
func main() { func main() {