/
lex.go
124 lines (103 loc) · 1.94 KB
/
lex.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
package main
import "strings"
const (
DIGITS string = "0123456789"
OPERATORS string = "^*/+-"
EOF rune = -1
)
type LexemeType int
type LexFn func(*Lexer) LexFn
const (
ErrLexeme LexemeType = iota
NumberLexeme
OperatorLexeme
LeftParenLexeme
RightParenLexeme
)
type Lexeme struct {
lexeme_type LexemeType
value string
}
func (l *Lexeme) String() string {
return l.value
}
type Lexer struct {
input []rune
window struct {
start int
end int
}
stream chan Lexeme
}
func (l *Lexer) Peek() rune {
if l.window.end >= len(l.input) {
return EOF
}
return l.input[l.window.end]
}
func (l *Lexer) Expand() {
l.window.end += 1
}
func (l *Lexer) Skip() {
l.Expand()
l.Discard()
}
func (l *Lexer) Discard() {
l.window.start = l.window.end
}
func (l *Lexer) Current() []rune {
return l.input[l.window.start:l.window.end]
}
func (l *Lexer) Emit(lexeme_type LexemeType) {
chunk := l.Current()
l.stream <- Lexeme{lexeme_type, string(chunk)}
l.Discard()
}
func lexStart(l *Lexer) (next_fn LexFn) {
for {
r := l.Peek()
if r == EOF {
return nil
} else if r == ' ' {
l.Skip()
} else if strings.IndexRune(DIGITS, r) >= 0 {
return lexNumber
} else if strings.IndexRune(OPERATORS, r) >= 0 {
l.Expand()
l.Emit(OperatorLexeme)
} else if r == '(' {
l.Expand()
l.Emit(LeftParenLexeme)
} else if r == ')' {
l.Expand()
l.Emit(RightParenLexeme)
} else {
l.Expand()
l.Emit(ErrLexeme)
}
}
return nil
}
func lexNumber(l *Lexer) LexFn {
for {
r := l.Peek()
if strings.IndexRune(DIGITS, r) >= 0{
l.Expand()
} else {
l.Emit(NumberLexeme)
break
}
}
return lexStart
}
func (l *Lexer) Run() {
for state := lexStart; state != nil; {
state = state(l)
}
close(l.stream)
}
func Lex(input string) *Lexer {
l := &Lexer {input: []rune(input), stream: make(chan Lexeme)}
go l.Run()
return l
}