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