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() {