X-Git-Url: https://git.josue.xyz/?a=blobdiff_plain;f=compiler.go;h=e928218affb8275dac9a52a98f29b6c603c29b4e;hb=refs%2Fheads%2Fmaster;hp=4ad5e55090da421ad08fc1a97dd652d970657464;hpb=f742d8cf60cd21f626298bf68ca17d4179cf589e;p=TinyThreePassCompiler%2F.git diff --git a/compiler.go b/compiler.go index 4ad5e55..e928218 100644 --- a/compiler.go +++ b/compiler.go @@ -27,75 +27,183 @@ 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) + //TODO(josuer08): Change this for a argv reader and all of the printing can + // be moved to writing to a file or just use standalone with redirection not + //quite sure about it. + input := "[ a b ] ((a*b) + (5*5))-3" variables, program := extractVariables(input) + //fmt.Println(variables, program) + Tree := AST{} + firstPass(variables, program, &Tree) + //fmt.Println(Tree) + secondPass(&Tree) + slices.Sort(variables) + thirdPass(&Tree, variables) + //printer(&Tree) - 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. +} - //los numeros se portan justo como las letras. +// printer si a function that prints in Reverse Pollish Notation the AST +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) - //a := &AST{Op: imm, N: 5 + if node.Op != plus && node.Op != min && node.Op != mul && node.Op != div { + node.Left = &AST{Op: arg, Value: int(program[0])} } 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) + } +} + +// 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) { + 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") + } + switch node.Op { + case mul: + fmt.Println("MU") + case div: + fmt.Println("DI") + case min: + fmt.Println("SU") + case plus: + fmt.Println("AD") } } - return } @@ -114,7 +222,6 @@ func extractVariables(input string) ([]rune, []rune) { resultVariables = append(resultVariables, v) } } - //Cleaning out the program that is getting extracted variables[1] = strings.Trim(variables[1], " ") cleanProgram := []rune(variables[1]) @@ -122,10 +229,7 @@ func extractVariables(input string) ([]rune, []rune) { for _, v := range cleanProgram { if v != ' ' { resultProgram = append(resultProgram, v) - } - } - return resultVariables, resultProgram }