Completed part 3, need clone
[TinyThreePassCompiler/.git] / compiler.go
index 4ad5e55090da421ad08fc1a97dd652d970657464..75d4d8f115d58d14cadc1e5e18a61bb0c1fe0448 100644 (file)
@@ -29,76 +29,211 @@ type AST struct {
 func main() {
        //a := &AST{Op: imm, N: 5
        //b := &AST{Op: plus, A: a, B: &AST{Op: arg, N: 0}}
-       input := "[ a b ] a*a + b*b"
-       //value := []rune(input)
+       input := "[ a b ] ((a*b) + (5*5))-3"
+       //input := "[ a b ] (a*a) + (5*5)"
 
        variables, program := extractVariables(input)
 
        fmt.Println(variables, program)
-       var Tree AST
-       firstPass(program, &Tree)
-       //si es una letra y el stack esta sin setear pon en el A del stack un AST arg
-       //si es una operacion setea la op en el stack
-       //si es un abrir parentesis apunta al lado que este disponible del AST
-       //si es una letra y ya esta seteada la op mete un AST arg a la otra letra
-       //si es un cerrar parentesis coge para el pai.
+       Tree := AST{}
+       firstPass(variables, program, &Tree)
+       fmt.Println(Tree)
+       secondPass(&Tree)
+       slices.Sort(variables)
+       thirdPass(&Tree, variables)
+       printer(&Tree)
 
-       //los numeros se portan justo como las letras.
+}
 
+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(")")
+
+       }
 }
 
+// firstPass Is a function that makes the first pass of the compiler,
+// it converts the variable and program into an AST
 func firstPass(variables, program []rune, node *AST) {
+       pass := node
        switch program[0] {
        case '-':
                node.Op = min
-               firstPass(variables, program[1:], node)
        case '+':
                node.Op = plus
-               firstPass(variables, program[1:], node)
        case '*':
                node.Op = mul
-               firstPass(variables, program[1:], node)
        case '/':
                node.Op = div
-               firstPass(variables, program[1:], node)
        case '(':
-               if node.Left != nil {
-                       firstPass(variables, program[1:], node.Left)
+               if node.Left == nil {
+                       node.Left = &AST{}
+                       node.Left.Parent = node
+                       pass = node.Left
                } else {
-                       firstPass(variables, program[1:], node.Right)
+                       node.Right = &AST{}
+                       node.Right.Parent = node
+                       pass = node.Right
                }
        case ')':
-               return
+               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}
-                               firstPass(variables, program[1:], node)
                                //a := &AST{Op: imm, N: 5
                        } else {
                                node.Right = &AST{Op: imm, Value: int(program[0]) - 48}
-                               firstPass(variables, program[1:], node)
                        }
                } else if slices.Contains(variables, program[0]) {
-                       var zeroOp op
-                       if node.Op == zeroOp {
-                               node.Left = &AST{Op: imm, Value: int(program[0]) - 48}
-                               firstPass(variables, program[1:], node)
+                       //var zeroOp op
+                       if node.Op != plus && node.Op != min && node.Op != mul && node.Op != div {
+                               node.Left = &AST{Op: arg, Value: int(program[0])}
                                //a := &AST{Op: imm, N: 5
                        } else {
-                               node.Right = &AST{Op: imm, Value: int(program[0]) - 48}
-                               firstPass(variables, program[1:], node)
+                               node.Right = &AST{Op: arg, Value: int(program[0])}
                        }
 
                }
 
+       }
+       if len(program) > 1 {
+               firstPass(variables, program[1:], pass)
+
        }
        return
 
 }
 
+// secondPass takes an AST and reduces the operations that only include imm
+// values so the program results in a more compact one with precalculated imms
+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)
+       }
+}
+
+func thirdPass(node *AST, variables []rune) {
+       /////////////////////////////////////////THINKING SPACE/////////////////////
+       //
+       //   If I am a imm I just load to R0
+       //   If I am an arg I just load to R0
+       //
+       //
+       //   If I am an operator then I put my answer to my father  on R0
+       //   If my left child is a imm or arg just call it and then SW
+       //   If my right child is a imm or arg just call it then SW then operate
+       //   If my left is an operand then call it(not sure about this one)
+       //   If my right is an operand PU then call it then SW then PO then SW
+       //   If i am an operand at the end always just operate AD MU DI SU
+       //
+       ////////////////////////////////////////////////////////////////////////////
+       switch node.Op {
+       case arg:
+               number, found := slices.BinarySearch(variables, rune(node.Value))
+               if found {
+                       fmt.Printf("AR %d\n", number)
+               }
+
+       case imm:
+               fmt.Printf("IM %d\n", node.Value)
+       default:
+               switch node.Left.Op {
+               case arg:
+                       number, valid := slices.BinarySearch(variables, rune(node.Left.Value))
+                       if valid {
+                               fmt.Printf("AR %d\n", number)
+                       }
+               case imm:
+                       fmt.Printf("IM %d\n", node.Left.Value)
+               default:
+                       thirdPass(node.Left, variables)
+               }
+
+               switch node.Right.Op {
+               case arg:
+                       fmt.Println("SW")
+                       number, valid := slices.BinarySearch(variables, rune(node.Right.Value))
+                       if valid {
+                               fmt.Printf("AR %d\n", number)
+                       }
+                       fmt.Println("SW")
+               case imm:
+                       fmt.Println("SW")
+                       fmt.Printf("IM %d\n", node.Right.Value)
+                       fmt.Println("SW")
+               default:
+                       fmt.Println("PU")
+                       thirdPass(node.Right, variables)
+                       fmt.Println("SW")
+                       fmt.Println("PO")
+               }
+
+               //need to think about which kind of child nodes make me want to PU & PO
+               switch node.Op {
+               case mul:
+                       fmt.Println("MU")
+               case div:
+                       fmt.Println("DI")
+               case min:
+                       fmt.Println("SU")
+               case plus:
+                       fmt.Println("AD")
+
+               }
+
+       }
+
+}
+
 // 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