aboutsummaryrefslogtreecommitdiff
path: root/scanner.go
diff options
context:
space:
mode:
authornirav <nirav@teisuu.com>2021-10-17 10:41:25 +0000
committernirav <nirav@teisuu.com>2021-10-17 10:41:25 +0000
commitaa51be44817e42871218eb2a341ec894ec7a24c5 (patch)
tree794473bd3417deb19e1d8b35101db0f54d2848a0 /scanner.go
downloaddc-aa51be44817e42871218eb2a341ec894ec7a24c5.tar.gz
dc-aa51be44817e42871218eb2a341ec894ec7a24c5.zip
Initial commit
Diffstat (limited to 'scanner.go')
-rw-r--r--scanner.go92
1 files changed, 92 insertions, 0 deletions
diff --git a/scanner.go b/scanner.go
new file mode 100644
index 0000000..a07981d
--- /dev/null
+++ b/scanner.go
@@ -0,0 +1,92 @@
+package main
+
+//go:generate stringer -type=Token
+type Token int
+
+const (
+ INVALID Token = iota
+ EOF
+ NUM
+ ADD
+ SUB
+ MUL
+ DIV
+ EXP
+)
+
+type scanner struct {
+ c byte
+ i int
+ buf []byte
+}
+
+func newScanner(s []byte) *scanner {
+ return &scanner{
+ buf: s,
+ }
+}
+
+func (s *scanner) read() bool {
+ if len(s.buf) <= s.i {
+ return false
+ }
+ s.c = s.buf[s.i]
+ s.i++
+ return true
+}
+
+func (s *scanner) unread() {
+ s.i--
+ s.c = s.buf[s.i]
+}
+
+// Pos returns the index of the next character
+func (s *scanner) Pos() int {
+ return s.i
+}
+
+func (s *scanner) Scan() (t Token, d []byte) {
+read:
+ ok := s.read()
+ if !ok {
+ return EOF, []byte{}
+ }
+ switch s.c {
+ case '+':
+ return ADD, nil
+ case '-':
+ return SUB, nil
+ case '*':
+ return MUL, nil
+ case '/':
+ return DIV, nil
+ case '^':
+ return EXP, nil
+ case ' ', '\n', '\t':
+ goto read
+ default:
+ if (s.c >= '0' && s.c <= '9') {
+ s.unread()
+ return s.scanNumber(false)
+ }
+ if s.c == '-' {
+ return s.scanNumber(true)
+ }
+ }
+ return INVALID, []byte{s.c}
+}
+
+func (s *scanner) scanNumber(neg bool) (t Token, d []byte) {
+ if neg {
+ d = append(d, '-')
+ }
+ for s.read() {
+ if (s.c >= '0' && s.c <= '9') {
+ d = append(d, s.c)
+ } else {
+ s.unread()
+ break
+ }
+ }
+ return NUM, d
+}