Arbitrary checkpoint
Apparently a gofmt happened in the meantime.
This commit is contained in:
parent
04639942af
commit
17279e3e6e
110
assembler.go
110
assembler.go
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue