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,39 +1,37 @@
package main
import (
"errors"
"io"
"fmt"
"bufio"
"strings"
"errors"
"fmt"
"io"
"strconv"
"strings"
)
const (
WORD = iota // [A-Za-z_-]+
NUMBER // [0-9]+
NEWLINE // \n
ERROR // Error
WORD = iota // [A-Za-z_-]+
NUMBER // [0-9]+
NEWLINE // \n
ERROR // Error
)
type location struct {
line int
line int
column int
}
type token struct {
location location // Position of the token
value string // Text content of the token
kind int // Kind of the token
location location // Position of the token
value string // Text content of the token
kind int // Kind of the token
}
type tokenizer struct {
line int // Current line
column int // Current column
value []byte // Current token string
reader *bufio.Reader // Reader
tokens chan<- token // Token channel
location location // Current position
value []byte // Current token string
reader *bufio.Reader // Reader
tokens chan<- token // Output token channel
}
// -----------------------------------------------------------------------------
@ -47,7 +45,9 @@ func isNumber(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 == '_'
}
@ -57,12 +57,13 @@ func isWordTail(c byte) bool {
// -----------------------------------------------------------------------------
func (t *tokenizer) send(kind int) {
// FIXME: track the beginning of the token
t.tokens <- token{location{t.line, t.column}, string(t.value), kind}
func (t *tokenizer) send(start location, kind int) {
t.tokens <- token{start, string(t.value), kind}
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) {
buf, err := t.reader.Peek(1)
return buf[0], err
@ -70,13 +71,15 @@ func (t *tokenizer) peek() (byte, error) {
func (t *tokenizer) eat() (byte, error) {
c, err := t.reader.ReadByte()
if err != nil { return 0, err }
if err != nil {
return 0, err
}
if c == '\n' {
t.line++
t.column = 0
t.location.line++
t.location.column = 0
} else {
t.column++
t.location.column++
}
return c, nil
}
@ -87,63 +90,88 @@ func (t *tokenizer) step() error {
t.value = []byte{}
c, err := t.peek()
if err == io.EOF { return nil }
if err != nil { return err }
if err == io.EOF {
return nil
}
if err != nil {
return err
}
start := t.location
switch {
case isSpace(c):
t.eat()
c, err = t.eat()
case c == '\n':
c, err = t.eat()
t.value = append(t.value, c)
t.send(NEWLINE)
t.send(start, NEWLINE)
case isNumber(c):
c, err = t.eat()
t.value = append(t.value, c)
for {
c, err = t.peek()
if err == io.EOF { break }
if err != nil { return err }
if err == io.EOF {
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.send(NUMBER)
t.send(start, NUMBER)
case isWordHead(c):
c, err = t.eat()
t.value = append(t.value, c)
for {
c, err = t.peek()
if err == io.EOF { break }
if err != nil { return err }
if err == io.EOF {
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.send(WORD)
t.send(start, WORD)
case c == '/':
c, err = t.eat()
t.value = append(t.value, c)
c, err = t.peek()
if err != nil { return err }
if err != nil {
return err
}
if c != '/' {
return errors.New("unrecognized input")
}
for {
c, err = t.peek()
if err == io.EOF { break }
if err != nil { return err }
if err == io.EOF {
break
}
if err != nil {
return err
}
if c == '\n' { break }
if c == '\n' {
break
}
t.eat()
}
default:
@ -154,10 +182,9 @@ func (t *tokenizer) step() error {
func tokenize(r io.Reader, tokens chan<- token) {
t := tokenizer{
line: 1,
column: 0,
tokens: tokens,
reader: bufio.NewReader(r),
location: location{line: 1, column: 0},
tokens: tokens,
reader: bufio.NewReader(r),
}
for {
err := t.step()
@ -165,9 +192,8 @@ func tokenize(r io.Reader, tokens chan<- token) {
break
}
if err != nil {
t.tokens <- token{location{t.line, t.column},
fmt.Sprintf("line %d, column %d: %s",
t.line, t.column, err.Error()), ERROR}
t.tokens <- token{t.location, fmt.Sprintf("line %d, column %d: %s",
t.location.line, t.location.column, err.Error()), ERROR}
break
}
}
@ -190,7 +216,7 @@ const (
IDATA
)
var instructions = map[string]int {
var instructions = map[string]int{
"HLT": IHALT,
"COB": IHALT,
"ADD": IADD,
@ -206,7 +232,7 @@ var instructions = map[string]int {
}
type instruction struct {
id int
id int
target string
number int
}
@ -221,7 +247,9 @@ type assembler struct {
func (a *assembler) step() (bool, error) {
token, ok := <-a.tokens
if !ok { return false, nil }
if !ok {
return false, nil
}
// 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
if len(x.target) != 0 {
if resolved, ok := a.labels[x.target]; !ok {

View File

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