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 }