package main
-import "fmt"
+import (
+ "fmt"
+ "strings"
+
+ "golang.org/x/exp/slices"
+)
+
+type op int
+
+const (
+ imm op = iota
+ arg
+ plus
+ min
+ mul
+ div
+)
+
+type AST struct {
+ Op op
+ Left *AST
+ Right *AST
+ Value int
+ Parent *AST
+}
func main() {
- fmt.Println("Hello, world.")
+ //a := &AST{Op: imm, N: 5
+ //b := &AST{Op: plus, A: a, B: &AST{Op: arg, N: 0}}
+ input := "[ a b ] (a*a) + (5*5)"
+
+ variables, program := extractVariables(input)
+
+ fmt.Println(variables, program)
+ Tree := AST{}
+ firstPass(variables, program, &Tree)
+ fmt.Println(Tree)
+ secondPass(&Tree)
+ printer(&Tree)
+
+}
+
+func printer(tree *AST) {
+ switch {
+ case tree.Op == imm:
+ fmt.Print(tree.Value)
+ case tree.Op == arg:
+ fmt.Printf("%c", tree.Value)
+ default:
+ fmt.Print("(")
+ switch tree.Op {
+ case min:
+ fmt.Print("-")
+ case plus:
+ fmt.Print("+")
+ case div:
+ fmt.Print("/")
+ case mul:
+ fmt.Print("*")
+ }
+ fmt.Print(",")
+ printer(tree.Left)
+ fmt.Print(",")
+ printer(tree.Right)
+ fmt.Print(")")
+
+ }
+}
+
+func firstPass(variables, program []rune, node *AST) {
+ pass := node
+ switch program[0] {
+ case '-':
+ node.Op = min
+ case '+':
+ node.Op = plus
+ case '*':
+ node.Op = mul
+ case '/':
+ node.Op = div
+ case '(':
+ if node.Left == nil {
+ node.Left = &AST{}
+ node.Left.Parent = node
+ pass = node.Left
+ } else {
+ node.Right = &AST{}
+ node.Right.Parent = node
+ pass = node.Right
+ }
+ case ')':
+ pass = node.Parent
+
+ default:
+ if program[0] > 47 && program[0] < 58 {
+ var zeroOp op
+ if node.Op == zeroOp {
+ node.Left = &AST{Op: imm, Value: int(program[0]) - 48}
+ //a := &AST{Op: imm, N: 5
+ } else {
+ node.Right = &AST{Op: imm, Value: int(program[0]) - 48}
+ }
+ } else if slices.Contains(variables, program[0]) {
+ //var zeroOp op
+ if node.Op != 2 && node.Op != 3 && node.Op != 4 && node.Op != 5 {
+ node.Left = &AST{Op: arg, Value: int(program[0])}
+ //a := &AST{Op: imm, N: 5
+ } else {
+ node.Right = &AST{Op: arg, Value: int(program[0])}
+ }
+
+ }
+
+ }
+ if len(program) > 1 {
+ firstPass(variables, program[1:], pass)
+
+ }
+ return
+
+}
+func secondPass(node *AST) {
+ if node.Op == arg {
+ return
+ }
+ if node.Op == imm {
+ return
+ }
+ if node.Right.Op == imm && node.Left.Op == imm {
+
+ switch node.Op {
+ case min:
+ node.Value = node.Left.Value - node.Right.Value
+ case plus:
+ node.Value = node.Left.Value + node.Right.Value
+ case mul:
+ node.Value = node.Left.Value * node.Right.Value
+ case div:
+ node.Value = node.Left.Value / node.Right.Value
+ }
+ node.Op = imm
+ node.Left = nil
+ node.Right = nil
+ return
+ }
+ if node.Left.Op != arg && node.Left.Op != imm {
+ secondPass(node.Left)
+ }
+ if node.Right.Op != arg && node.Right.Op != imm {
+ secondPass(node.Right)
+ }
+}
+
+// extractVariables receives the original program string and converts it in
+// two rune slices, the first containing the variables and a second containing
+// the trimmed program
+func extractVariables(input string) ([]rune, []rune) {
+ variables := strings.Split(input, "]")
+ // Cleaning out the variables that are gettting extracted
+ variables[0] = strings.Split(variables[0], "[")[1]
+ variables[0] = strings.Trim(variables[0], " ")
+ cleanVariables := []rune(variables[0])
+ var resultVariables []rune
+ for _, v := range cleanVariables {
+ if v != ' ' {
+ resultVariables = append(resultVariables, v)
+ }
+ }
+
+ //Cleaning out the program that is getting extracted
+ variables[1] = strings.Trim(variables[1], " ")
+ cleanProgram := []rune(variables[1])
+ var resultProgram []rune
+ for _, v := range cleanProgram {
+ if v != ' ' {
+ resultProgram = append(resultProgram, v)
+
+ }
+
+ }
+
+ return resultVariables, resultProgram
}