From 17279e3e6e8613547e05366a14d9c30035e8a111 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C5=99emysl=20Janouch?=
Date: Wed, 19 Oct 2016 20:20:43 +0200
Subject: [PATCH] Arbitrary checkpoint
Apparently a gofmt happened in the meantime.
---
assembler.go | 138 +++++++++++++++++++++++++++++++--------------------
main.go | 2 +-
2 files changed, 84 insertions(+), 56 deletions(-)
diff --git a/assembler.go b/assembler.go
index 21bebba..d800500 100644
--- a/assembler.go
+++ b/assembler.go
@@ -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 {
diff --git a/main.go b/main.go
index c277d00..a891931 100644
--- a/main.go
+++ b/main.go
@@ -1,8 +1,8 @@
package main
import (
- "os"
"fmt"
+ "os"
)
func main() {