ec17a44ee24a6738ed662608bcef72ef0ed40d3d
[TinyThreePassCompiler/.git] / compiler.go
1 package main
2
3 import (
4         "fmt"
5         "strings"
6
7         "golang.org/x/exp/slices"
8 )
9
10 type op int
11
12 const (
13         imm op = iota
14         arg
15         plus
16         min
17         mul
18         div
19 )
20
21 type AST struct {
22         Op     op
23         Left   *AST
24         Right  *AST
25         Value  int
26         Parent *AST
27 }
28
29 func main() {
30         //a := &AST{Op: imm, N: 5
31         //b := &AST{Op: plus, A: a, B: &AST{Op: arg, N: 0}}
32         input := "[ a b ] (a*a) + (5*5)"
33
34         variables, program := extractVariables(input)
35
36         fmt.Println(variables, program)
37         Tree := AST{}
38         firstPass(variables, program, &Tree)
39         fmt.Println(Tree)
40         secondPass(&Tree)
41         printer(&Tree)
42
43 }
44
45 func printer(tree *AST) {
46         switch {
47         case tree.Op == imm:
48                 fmt.Print(tree.Value)
49         case tree.Op == arg:
50                 fmt.Printf("%c", tree.Value)
51         default:
52                 fmt.Print("(")
53                 switch tree.Op {
54                 case min:
55                         fmt.Print("-")
56                 case plus:
57                         fmt.Print("+")
58                 case div:
59                         fmt.Print("/")
60                 case mul:
61                         fmt.Print("*")
62                 }
63                 fmt.Print(",")
64                 printer(tree.Left)
65                 fmt.Print(",")
66                 printer(tree.Right)
67                 fmt.Print(")")
68
69         }
70 }
71
72 func firstPass(variables, program []rune, node *AST) {
73         pass := node
74         switch program[0] {
75         case '-':
76                 node.Op = min
77         case '+':
78                 node.Op = plus
79         case '*':
80                 node.Op = mul
81         case '/':
82                 node.Op = div
83         case '(':
84                 if node.Left == nil {
85                         node.Left = &AST{}
86                         node.Left.Parent = node
87                         pass = node.Left
88                 } else {
89                         node.Right = &AST{}
90                         node.Right.Parent = node
91                         pass = node.Right
92                 }
93         case ')':
94                 pass = node.Parent
95
96         default:
97                 if program[0] > 47 && program[0] < 58 {
98                         var zeroOp op
99                         if node.Op == zeroOp {
100                                 node.Left = &AST{Op: imm, Value: int(program[0]) - 48}
101                                 //a := &AST{Op: imm, N: 5
102                         } else {
103                                 node.Right = &AST{Op: imm, Value: int(program[0]) - 48}
104                         }
105                 } else if slices.Contains(variables, program[0]) {
106                         //var zeroOp op
107                         if node.Op != 2 && node.Op != 3 && node.Op != 4 && node.Op != 5 {
108                                 node.Left = &AST{Op: arg, Value: int(program[0])}
109                                 //a := &AST{Op: imm, N: 5
110                         } else {
111                                 node.Right = &AST{Op: arg, Value: int(program[0])}
112                         }
113
114                 }
115
116         }
117         if len(program) > 1 {
118                 firstPass(variables, program[1:], pass)
119
120         }
121         return
122
123 }
124 func secondPass(node *AST) {
125         if node.Op == arg {
126                 return
127         }
128         if node.Op == imm {
129                 return
130         }
131         if node.Right.Op == imm && node.Left.Op == imm {
132
133                 switch node.Op {
134                 case min:
135                         node.Value = node.Left.Value - node.Right.Value
136                 case plus:
137                         node.Value = node.Left.Value + node.Right.Value
138                 case mul:
139                         node.Value = node.Left.Value * node.Right.Value
140                 case div:
141                         node.Value = node.Left.Value / node.Right.Value
142                 }
143                 node.Op = imm
144                 node.Left = nil
145                 node.Right = nil
146                 return
147         }
148         if node.Left.Op != arg && node.Left.Op != imm {
149                 secondPass(node.Left)
150         }
151         if node.Right.Op != arg && node.Right.Op != imm {
152                 secondPass(node.Right)
153         }
154 }
155
156 // extractVariables receives the original program string and converts it in
157 // two rune slices, the first containing the variables and a second containing
158 // the trimmed program
159 func extractVariables(input string) ([]rune, []rune) {
160         variables := strings.Split(input, "]")
161         // Cleaning out the variables that are gettting extracted
162         variables[0] = strings.Split(variables[0], "[")[1]
163         variables[0] = strings.Trim(variables[0], " ")
164         cleanVariables := []rune(variables[0])
165         var resultVariables []rune
166         for _, v := range cleanVariables {
167                 if v != ' ' {
168                         resultVariables = append(resultVariables, v)
169                 }
170         }
171
172         //Cleaning out the program that is getting extracted
173         variables[1] = strings.Trim(variables[1], " ")
174         cleanProgram := []rune(variables[1])
175         var resultProgram []rune
176         for _, v := range cleanProgram {
177                 if v != ' ' {
178                         resultProgram = append(resultProgram, v)
179
180                 }
181
182         }
183
184         return resultVariables, resultProgram
185 }