-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparser.go
More file actions
106 lines (93 loc) · 2.25 KB
/
Copy pathparser.go
File metadata and controls
106 lines (93 loc) · 2.25 KB
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
package main
import (
"errors"
"fmt"
)
// FIXME I don't like how syntax errors are handled and displayed
type parser struct {
currentToken *token
lexer *lexer
// Names of token types, for descriptive error/debug messages
ttNames map[int]string
}
func (p *parser) Parse() (n node, e error) {
var parseError error
defer func() {
if r := recover(); r != nil {
fmt.Println("Parse error")
parseError = errors.New(fmt.Sprintf("Syntax error:", r))
}
}()
return p.Expr(), parseError
}
// Expr evaluates expression
// expr : term ((PLUS | MINUS) term)*
// Panics if try to divide by 0
// Returns result of calculation
func (p *parser) Expr() node {
if (p.currentToken == nil) {
t := p.lexer.GetNextToken()
p.currentToken = &t
}
left := p.Term()
for p.currentToken.tType == PLUS || p.currentToken.tType == MINUS {
prevToken := p.currentToken
if p.currentToken.tType == PLUS {
p.Eat(PLUS)
} else if p.currentToken.tType == MINUS {
p.Eat(MINUS)
}
right := p.Term()
left = binOp{left, *prevToken, right}
}
return left
}
// Term
// term : factor ((MUL | DIV) factor)*
func (p *parser) Term() node {
left := p.Factor()
for p.currentToken.tType == MUL || p.currentToken.tType == DIV {
prevToken := p.currentToken
if p.currentToken.tType == MUL {
p.Eat(MUL)
} else if p.currentToken.tType == DIV {
p.Eat(DIV)
}
right := p.Factor()
left = binOp{left, *prevToken, right}
}
return left
}
// Factor
// factor : INTEGER | LPAREN expr RPAREN
func (p *parser) Factor() node {
t := p.currentToken
if t.tType == INTEGER {
p.Eat(INTEGER)
return num{*t}
} else if t.tType == LPAREN {
p.Eat(LPAREN)
node := p.Expr()
p.Eat(RPAREN)
return node
}
panic(fmt.Sprintf(
"Token '%s' (type %s) found at position %d when factor (INTEGER or LPAREN) expected",
t.value,
p.ttNames[t.tType],
p.lexer.pos-1))
}
// Eat moves to new current token
// Panics if token type occurs to be different than expected
func (p *parser) Eat(tokenType int) {
if p.currentToken.tType != tokenType {
panic(fmt.Sprintf(
"Token of type %s ('%s') found at position %d when %s expected",
p.ttNames[p.currentToken.tType],
p.currentToken.value,
p.lexer.pos,
p.ttNames[tokenType]))
}
t := p.lexer.GetNextToken()
p.currentToken = &t
}