-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathast.go
130 lines (106 loc) · 2.35 KB
/
ast.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
package main
import (
"fmt"
"log"
"strconv"
)
type Node interface {
Pos() Position
String() string
}
type Expression interface {
Node
}
type BinaryExpression struct {
Left Expression
Op Token
Right Expression
Position Position
}
func (be *BinaryExpression) Pos() Position {
return be.Position
}
func (be *BinaryExpression) String() string {
return fmt.Sprintf("(%s %s %s)", be.Left.String(), tokens[be.Op], be.Right.String())
}
type IntegerLiteral struct {
Value int
Position Position
}
func (il *IntegerLiteral) Pos() Position {
return il.Position
}
func (il *IntegerLiteral) String() string {
return strconv.Itoa(il.Value)
}
func parseExpression(l *Lexer) Expression {
return parseAddSubExpr(l)
}
func parseAddSubExpr(l *Lexer) Expression {
left := parseMulDivExpr(l)
for {
tok, _ := l.Lex()
if tok != ADD && tok != SUB {
l.backup()
return left
}
right := parseMulDivExpr(l)
left = &BinaryExpression{Left: left, Op: tok, Right: right, Position: left.Pos()}
}
}
func parseMulDivExpr(l *Lexer) Expression {
left := parsePrimaryExpr(l)
for {
tok, _ := l.Lex()
if tok != MUL && tok != DIV && tok != MOD {
l.backup() // return prev line and column
return left
}
right := parsePrimaryExpr(l)
left = &BinaryExpression{Left: left, Op: tok, Right: right, Position: left.Pos()}
}
}
func parsePrimaryExpr(l *Lexer) Expression {
tok, lit := l.Lex()
if tok == INT {
value, _ := strconv.Atoi(lit)
return &IntegerLiteral{Value: value, Position: Position{line: l.pos.line, column: l.pos.column}}
}
log.Fatalf("Unexpected token: %s", tokens[tok])
return nil // unreachable
}
func evaluateExpression(expr Expression) (int, error) {
switch e := expr.(type) {
case *BinaryExpression:
left, err := evaluateExpression(e.Left)
if err != nil {
return 0, err
}
right, err := evaluateExpression(e.Right)
if err != nil {
return 0, err
}
switch e.Op {
case ADD:
return left + right, nil
case SUB:
return left - right, nil
case MUL:
return left * right, nil
case DIV:
if right == 0 {
return 0, fmt.Errorf("division by zero")
}
return left / right, nil
case MOD:
res := left % right
return res, nil
default:
return 0, fmt.Errorf("unknown operator")
}
case *IntegerLiteral:
return e.Value, nil
default:
return 0, fmt.Errorf("unknown expression type")
}
}