7 "golang.org/x/exp/slices"
30 //TODO(josuer08): Change this for a argv reader and all of the printing can
31 // be moved to writing to a file or just use standalone with redirection not
32 //quite sure about it.
33 input := "[ a b ] ((a*b) + (5*5))-3"
35 variables, program := extractVariables(input)
36 //fmt.Println(variables, program)
38 firstPass(variables, program, &Tree)
41 slices.Sort(variables)
42 thirdPass(&Tree, variables)
47 // printer si a function that prints in Reverse Pollish Notation the AST
48 func printer(tree *AST) {
53 fmt.Printf("%c", tree.Value)
75 // firstPass Is a function that makes the first pass of the compiler,
76 // it converts the variable and program into an AST
77 func firstPass(variables, program []rune, node *AST) {
91 node.Left.Parent = node
95 node.Right.Parent = node
102 if program[0] > 47 && program[0] < 58 {
104 if node.Op == zeroOp {
105 node.Left = &AST{Op: imm, Value: int(program[0]) - 48}
107 node.Right = &AST{Op: imm, Value: int(program[0]) - 48}
109 } else if slices.Contains(variables, program[0]) {
110 if node.Op != plus && node.Op != min && node.Op != mul && node.Op != div {
111 node.Left = &AST{Op: arg, Value: int(program[0])}
113 node.Right = &AST{Op: arg, Value: int(program[0])}
117 if len(program) > 1 {
118 firstPass(variables, program[1:], pass)
122 // secondPass takes an AST and reduces the operations that only include imm
123 // values so the program results in a more compact one with precalculated imms
124 func secondPass(node *AST) {
131 if node.Right.Op == imm && node.Left.Op == imm {
134 node.Value = node.Left.Value - node.Right.Value
136 node.Value = node.Left.Value + node.Right.Value
138 node.Value = node.Left.Value * node.Right.Value
140 node.Value = node.Left.Value / node.Right.Value
147 if node.Left.Op != arg && node.Left.Op != imm {
148 secondPass(node.Left)
150 if node.Right.Op != arg && node.Right.Op != imm {
151 secondPass(node.Right)
155 func thirdPass(node *AST, variables []rune) {
158 number, found := slices.BinarySearch(variables, rune(node.Value))
160 fmt.Printf("AR %d\n", number)
163 fmt.Printf("IM %d\n", node.Value)
165 switch node.Left.Op {
167 number, valid := slices.BinarySearch(variables, rune(node.Left.Value))
169 fmt.Printf("AR %d\n", number)
172 fmt.Printf("IM %d\n", node.Left.Value)
174 thirdPass(node.Left, variables)
176 switch node.Right.Op {
179 number, valid := slices.BinarySearch(variables, rune(node.Right.Value))
181 fmt.Printf("AR %d\n", number)
186 fmt.Printf("IM %d\n", node.Right.Value)
190 thirdPass(node.Right, variables)
210 // extractVariables receives the original program string and converts it in
211 // two rune slices, the first containing the variables and a second containing
212 // the trimmed program
213 func extractVariables(input string) ([]rune, []rune) {
214 variables := strings.Split(input, "]")
215 // Cleaning out the variables that are gettting extracted
216 variables[0] = strings.Split(variables[0], "[")[1]
217 variables[0] = strings.Trim(variables[0], " ")
218 cleanVariables := []rune(variables[0])
219 var resultVariables []rune
220 for _, v := range cleanVariables {
222 resultVariables = append(resultVariables, v)
225 //Cleaning out the program that is getting extracted
226 variables[1] = strings.Trim(variables[1], " ")
227 cleanProgram := []rune(variables[1])
228 var resultProgram []rune
229 for _, v := range cleanProgram {
231 resultProgram = append(resultProgram, v)
234 return resultVariables, resultProgram