-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathscanner.go
143 lines (114 loc) · 2.36 KB
/
scanner.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package mm
import (
"bufio"
"bytes"
"io"
)
type Scanner struct {
r *bufio.Reader
}
func NewScanner(r io.Reader) *Scanner {
return &Scanner{r: bufio.NewReader(r)}
}
// Scan() returns token and corresponding string literal.
func (s *Scanner) Scan() (ItemType, string) {
// Reads the next rune.
ch := s.read()
switch {
case isWhitespace(ch):
return s.scanWhitespace()
case isNewLine(ch):
s.unread()
return s.scanNewLine()
case isStar(ch):
s.unread()
return s.scanStar()
case isHex(ch):
s.unread()
return s.scanHex()
case ch == eof:
return EOF, string(eof)
}
s.unread()
return s.scanStringLiteral()
}
func (s *Scanner) scanWhitespace() (ItemType, string) {
// Create a buffer and read the current ch into it.
var buf bytes.Buffer
// Read every subsequent WS ch into the buffer.
// Non WS ch will cause the loop to exit.
for {
if ch := s.read(); !isWhitespace(ch) {
s.unread()
break
} else {
buf.WriteRune(ch)
}
}
return WS, " "
}
func (s *Scanner) scanNewLine() (ItemType, string) {
var buf bytes.Buffer
for {
if ch := s.read(); !isNewLine(ch) {
s.unread()
break
} else {
buf.WriteRune(ch)
}
}
return NEWLINE, ""
}
func (s *Scanner) scanHex() (ItemType, string) {
var buf bytes.Buffer
buf.WriteRune(s.read())
for {
if ch := s.read(); !isHex(ch) {
s.unread()
break
} else {
buf.WriteRune(ch)
}
}
return HEX, buf.String()
}
func (s *Scanner) scanStar() (ItemType, string) {
var buf bytes.Buffer
buf.WriteRune(s.read())
ch := s.read()
if !isStar(ch) {
s.unread()
return SINGLESTAR, buf.String()
}
buf.WriteRune(ch)
return DOUBLESTAR, buf.String()
}
func (s *Scanner) scanStringLiteral() (ItemType, string) {
var buf bytes.Buffer
buf.WriteRune(s.read())
for {
if ch := s.read(); !isStringLiteral(ch) {
s.unread()
break
} else {
buf.WriteRune(ch)
}
}
return STRINGLIT, buf.String()
}
func (s *Scanner) read() rune {
ch, _, err := s.r.ReadRune()
if err != nil {
return eof
}
return ch
}
func (s *Scanner) unread() { _ = s.r.UnreadRune() }
func isWhitespace(ch rune) bool { return ch == ' ' || ch == '\t' }
func isNewLine(ch rune) bool { return ch == '\n' }
func isHex(ch rune) bool { return ch == '#' }
func isStar(ch rune) bool { return ch == '*' }
func isStringLiteral(ch rune) bool {
return (ch != '\t' && ch != '\n' && ch != '#' && ch != '*')
}
var eof = rune(0)