From 87b5d59fc6fefd7d68cabe55f5c121394fe003ea Mon Sep 17 00:00:00 2001 From: AlexZhu2 <52172864+AlexZhu2@users.noreply.github.com> Date: Fri, 16 May 2025 17:20:59 -0400 Subject: [PATCH] pow ** working --- lib/ast.ml | 2 +- lib/irgen.ml | 134 +++++++++++++++++++++++++-------------- lib/parser.mly | 4 +- lib/scanner.mll | 2 +- lib/semant.ml | 2 +- lib/utils/prints.ml | 4 +- test/scanner/test_exp.ml | 28 ++++---- 7 files changed, 108 insertions(+), 68 deletions(-) diff --git a/lib/ast.ml b/lib/ast.ml index 180cabc..04fee2e 100644 --- a/lib/ast.ml +++ b/lib/ast.ml @@ -4,7 +4,7 @@ type op = | Mult | Div | Mod - | Exp + | Pow | Preincr | Postincr | Predecr diff --git a/lib/irgen.ml b/lib/irgen.ml index d02f06d..036cf4c 100644 --- a/lib/irgen.ml +++ b/lib/irgen.ml @@ -220,65 +220,105 @@ let rec build_expr expr (vars : variable StringMap.t) var_types the_module build let se1 = build_expr e1 vars var_types the_module builder in let se2 = build_expr e2 vars var_types the_module builder in let lval = - match typ with - | RInt -> - (match op with - | A.Add -> L.build_add - | A.Sub -> L.build_sub - | A.Mult -> L.build_mul - | A.Div -> L.build_sdiv - | A.Mod -> L.build_srem - | A.Equal -> L.build_icmp L.Icmp.Eq - | A.Neq -> L.build_icmp L.Icmp.Ne - | A.Less -> L.build_icmp L.Icmp.Slt - | A.Leq -> L.build_icmp L.Icmp.Sle - | A.Greater -> L.build_icmp L.Icmp.Sgt - | A.Geq -> L.build_icmp L.Icmp.Sge - | _ -> - failwith - (Printf.sprintf - "Integer binary operator %s not yet implemented" - (Utils.string_of_op op))) - | RFloat -> - (match op with - | A.Add -> L.build_fadd - | A.Sub -> L.build_fsub - | A.Mult -> L.build_fmul - | A.Div -> L.build_fdiv - | A.Mod -> L.build_frem - | A.Equal -> L.build_fcmp L.Fcmp.Oeq - | A.Neq -> L.build_fcmp L.Fcmp.One - | A.Less -> L.build_fcmp L.Fcmp.Olt - | A.Leq -> L.build_fcmp L.Fcmp.Ole - | A.Greater -> L.build_fcmp L.Fcmp.Ogt - | A.Geq -> L.build_fcmp L.Fcmp.Oge - | _ -> - failwith - (Printf.sprintf - "Float binary operator %s not yet implemented" - (Utils.string_of_op op))) - | RBool -> + match typ, op with + | RInt, A.Pow -> + (* se1 = base, se2 = exponent *) + let parent_func = L.block_parent (L.insertion_block builder) in + + let result = L.build_alloca l_int "pow_result" builder in + ignore (L.build_store (L.const_int l_int 1) result builder); + + let i = L.build_alloca l_int "pow_i" builder in + ignore (L.build_store (L.const_int l_int 0) i builder); + + let loop_bb = L.append_block context "pow_loop" parent_func in + let after_bb = L.append_block context "pow_after" parent_func in + + ignore (L.build_br loop_bb builder); + + (* Loop condition *) + L.position_at_end loop_bb builder; + let i_val = L.build_load i "i_val" builder in + let cond = L.build_icmp L.Icmp.Slt i_val se2 "pow_cond" builder in + let body_bb = L.append_block context "pow_body" parent_func in + ignore (L.build_cond_br cond body_bb after_bb builder); + + (* Loop body: result *= base; i++ *) + L.position_at_end body_bb builder; + let res_val = L.build_load result "res_val" builder in + let new_res = L.build_mul res_val se1 "new_res" builder in + ignore (L.build_store new_res result builder); + let i_next = L.build_add i_val (L.const_int l_int 1) "i_next" builder in + ignore (L.build_store i_next i builder); + ignore (L.build_br loop_bb builder); + + (* After loop *) + L.position_at_end after_bb builder; + L.build_load result "pow_result" builder + | RInt, _ -> + let op_fn = + match op with + | A.Add -> L.build_add se1 se2 "tmp_int" builder + | A.Sub -> L.build_sub se1 se2 "tmp_int" builder + | A.Mult -> L.build_mul se1 se2 "tmp_int" builder + | A.Div -> L.build_sdiv se1 se2 "tmp_int" builder + | A.Mod -> L.build_srem se1 se2 "tmp_int" builder + | A.Equal -> L.build_icmp L.Icmp.Eq se1 se2 "tmp_bool" builder + | A.Neq -> L.build_icmp L.Icmp.Ne se1 se2 "tmp_bool" builder + | A.Less -> L.build_icmp L.Icmp.Slt se1 se2 "tmp_bool" builder + | A.Leq -> L.build_icmp L.Icmp.Sle se1 se2 "tmp_bool" builder + | A.Greater -> L.build_icmp L.Icmp.Sgt se1 se2 "tmp_bool" builder + | A.Geq -> L.build_icmp L.Icmp.Sge se1 se2 "tmp_bool" builder + | _ -> + failwith + (Printf.sprintf + "Integer binary operator %s not yet implemented" + (Utils.string_of_op op)) + in + op_fn + | RFloat, _ -> + let op_fn = + match op with + | A.Add -> L.build_fadd se1 se2 "tmp_float" builder + | A.Sub -> L.build_fsub se1 se2 "tmp_float" builder + | A.Mult -> L.build_fmul se1 se2 "tmp_float" builder + | A.Div -> L.build_fdiv se1 se2 "tmp_float" builder + | A.Mod -> L.build_frem se1 se2 "tmp_float" builder + | A.Equal -> L.build_fcmp L.Fcmp.Oeq se1 se2 "tmp_bool" builder + | A.Neq -> L.build_fcmp L.Fcmp.One se1 se2 "tmp_bool" builder + | A.Less -> L.build_fcmp L.Fcmp.Olt se1 se2 "tmp_bool" builder + | A.Leq -> L.build_fcmp L.Fcmp.Ole se1 se2 "tmp_bool" builder + | A.Greater -> L.build_fcmp L.Fcmp.Ogt se1 se2 "tmp_bool" builder + | A.Geq -> L.build_fcmp L.Fcmp.Oge se1 se2 "tmp_bool" builder + | _ -> + failwith + (Printf.sprintf + "Float binary operator %s not yet implemented" + (Utils.string_of_op op)) + in + op_fn + | RBool, _ -> (match op with - | A.And -> L.build_and - | A.Or -> L.build_or - | A.Equal -> L.build_icmp L.Icmp.Eq - | A.Neq -> L.build_icmp L.Icmp.Ne + | A.And -> L.build_and se1 se2 "tmp_bool" builder + | A.Or -> L.build_or se1 se2 "tmp_bool" builder + | A.Equal -> L.build_icmp L.Icmp.Eq se1 se2 "tmp_bool" builder + | A.Neq -> L.build_icmp L.Icmp.Ne se1 se2 "tmp_bool" builder | _ -> failwith (Printf.sprintf "Boolean binary operator %s not yet implemented" (Utils.string_of_op op))) - | REnumType _ -> + | REnumType _, _ -> (match op with - | A.Equal -> L.build_icmp L.Icmp.Eq - | A.Neq -> L.build_icmp L.Icmp.Ne + | A.Equal -> L.build_icmp L.Icmp.Eq se1 se2 "tmp_enum" builder + | A.Neq -> L.build_icmp L.Icmp.Ne se1 se2 "tmp_enum" builder | _ -> failwith (Printf.sprintf "Internal Compiler Error: Operator %s on EnumType %s reached IRgen." (Utils.string_of_op op) (Utils.string_of_resolved_type typ))) - | RString -> failwith "GOT A STRING\n" + | RString, _ -> failwith "GOT A STRING\n" | _ -> failwith (Printf.sprintf @@ -286,7 +326,7 @@ let rec build_expr expr (vars : variable StringMap.t) var_types the_module build (Utils.string_of_op op) (Utils.string_of_resolved_type typ)) in - lval se1 se2 ("tmp_" ^ Utils.string_of_resolved_type typ) builder + lval | SUDTInstance (typename, fields) -> let struct_type = Hashtbl.find udt_structs typename in let field_indices = Hashtbl.find udt_field_indices typename in diff --git a/lib/parser.mly b/lib/parser.mly index 1ed532a..3c4ec4c 100644 --- a/lib/parser.mly +++ b/lib/parser.mly @@ -4,7 +4,7 @@ open Ast %} %token SEMI COLON DCOLON DOT COMMA LPAREN RPAREN LBRACE RBRACE LBRACKET RBRACKET -%token PLUS MINUS DIVIDE MODULO TIMES INCR DECR EXPONENT +%token PLUS MINUS DIVIDE MODULO TIMES INCR DECR POW %token EQUAL WALRUS PLUS_ASSIGN MINUS_ASSIGN MULT_ASSIGN DIV_ASSIGN %token BEQ NEQ LT LEQ GT GEQ AND OR NOT @@ -86,7 +86,7 @@ expr: | expr TIMES expr { Binop($1, Mult, $3) } | expr DIVIDE expr { Binop($1, Div, $3) } | expr MODULO expr { Binop($1, Mod, $3) } - | expr EXPONENT expr { Binop($1, Exp, $3) } + | expr POW expr { Binop($1, Pow, $3) } | expr OR expr { Binop($1, Or, $3) } | expr AND expr { Binop($1, And, $3) } | expr BEQ expr { Binop($1, Equal, $3) } diff --git a/lib/scanner.mll b/lib/scanner.mll index 1f57c5b..661d3c8 100644 --- a/lib/scanner.mll +++ b/lib/scanner.mll @@ -38,7 +38,7 @@ rule tokenize = parse | '+' { PLUS } | '-' { MINUS } | '*' { TIMES } - | "**" { EXPONENT } + | "**" { POW } | '/' { DIVIDE } | '%' { MODULO } | '=' { EQUAL } diff --git a/lib/semant.ml b/lib/semant.ml index 30ef5b6..9accc50 100644 --- a/lib/semant.ml +++ b/lib/semant.ml @@ -150,7 +150,7 @@ and format_binop_error expr t1 t2 = and get_binop_return_type expr t1 binop t2 = match binop with - | Add | Sub | Mult | Div | Mod | Exp -> + | Add | Sub | Mult | Div | Mod | Pow -> (match t1, t2 with | RInt, RInt -> RInt | RFloat, RFloat -> RFloat diff --git a/lib/utils/prints.ml b/lib/utils/prints.ml index 7a36801..c82a23e 100644 --- a/lib/utils/prints.ml +++ b/lib/utils/prints.ml @@ -7,7 +7,7 @@ let string_of_token = function | MINUS -> "MINUS" | TIMES -> "TIMES" | DIVIDE -> "DIVIDE" - | EXPONENT -> "EXPONENT" + | POW -> "POW" | MODULO -> "MODULO" | AND -> "AND" (* Logical operators *) | OR -> "OR" @@ -116,7 +116,7 @@ let string_of_op = function | Sub -> "-" | Mult -> "*" | Div -> "/" - | Exp -> "**" + | Pow -> "**" | Mod -> "%" | Preincr -> "++" | Predecr -> "--" diff --git a/test/scanner/test_exp.ml b/test/scanner/test_exp.ml index a515df4..5d18d00 100644 --- a/test/scanner/test_exp.ml +++ b/test/scanner/test_exp.ml @@ -19,7 +19,7 @@ let tests = let actual = string_of_tokens (to_list lexbuf) in let expected = "LET ID(a1) WALRUS LITERAL(2) SEMI LET ID(b1) WALRUS LITERAL(3) SEMI LET \ - ID(result1) WALRUS ID(a1) EXPONENT ID(b1) SEMI" + ID(result1) WALRUS ID(a1) POW ID(b1) SEMI" in assert_equal expected actual ~printer:(fun s -> "\"" ^ s ^ "\"")) ; ("test2" @@ -30,7 +30,7 @@ let tests = let actual = string_of_tokens (to_list lexbuf) in let expected = "LET ID(a2) WALRUS FLIT(2.500000) SEMI LET ID(b2) WALRUS LITERAL(2) SEMI LET \ - ID(result2) WALRUS ID(a2) EXPONENT ID(b2) SEMI" + ID(result2) WALRUS ID(a2) POW ID(b2) SEMI" in assert_equal expected actual ~printer:(fun s -> "\"" ^ s ^ "\"")) ; ("test3" @@ -41,7 +41,7 @@ let tests = let actual = string_of_tokens (to_list lexbuf) in let expected = "LET ID(a3) WALRUS LITERAL(2) SEMI LET ID(b3) WALRUS FLIT(3.500000) SEMI LET \ - ID(result3) WALRUS ID(a3) EXPONENT ID(b3) SEMI" + ID(result3) WALRUS ID(a3) POW ID(b3) SEMI" in assert_equal expected actual ~printer:(fun s -> "\"" ^ s ^ "\"")) ; ("test4" @@ -53,7 +53,7 @@ let tests = let actual = string_of_tokens (to_list lexbuf) in let expected = "LET ID(a4) WALRUS LITERAL(2) SEMI LET ID(b4) WALRUS SLIT(3) SEMI LET \ - ID(result4) WALRUS ID(a4) EXPONENT ID(b4) SEMI" + ID(result4) WALRUS ID(a4) POW ID(b4) SEMI" in assert_equal expected actual ~printer:(fun s -> "\"" ^ s ^ "\"")) ; ("test5" @@ -64,7 +64,7 @@ let tests = let actual = string_of_tokens (to_list lexbuf) in let expected = "LET ID(a5) WALRUS LITERAL(2) SEMI LET ID(b5) WALRUS BLIT(true) SEMI LET \ - ID(result5) WALRUS ID(a5) EXPONENT ID(b5) SEMI" + ID(result5) WALRUS ID(a5) POW ID(b5) SEMI" in assert_equal expected actual ~printer:(fun s -> "\"" ^ s ^ "\"")) ; ("test6" @@ -76,7 +76,7 @@ let tests = let actual = string_of_tokens (to_list lexbuf) in let expected = "LET ID(a6) WALRUS LPAREN LITERAL(1) COMMA LITERAL(2) RPAREN SEMI LET ID(b6) \ - WALRUS LITERAL(2) SEMI LET ID(result6) WALRUS ID(a6) EXPONENT ID(b6) SEMI" + WALRUS LITERAL(2) SEMI LET ID(result6) WALRUS ID(a6) POW ID(b6) SEMI" in assert_equal expected actual ~printer:(fun s -> "\"" ^ s ^ "\"")) ; ("test7" @@ -89,7 +89,7 @@ let tests = let expected = "LET ID(a7) WALRUS LBRACKET LITERAL(1) COMMA LITERAL(2) COMMA LITERAL(3) \ RBRACKET SEMI LET ID(b7) WALRUS LITERAL(3) SEMI LET ID(result7) WALRUS \ - ID(a7) EXPONENT ID(b7) SEMI" + ID(a7) POW ID(b7) SEMI" in assert_equal expected actual ~printer:(fun s -> "\"" ^ s ^ "\"")) ; ("test8" @@ -102,7 +102,7 @@ let tests = let expected = "LET ID(a8) WALRUS LBRACE LITERAL(1) COMMA LITERAL(2) COMMA LITERAL(3) \ RBRACE SEMI LET ID(b8) WALRUS LITERAL(2) SEMI LET ID(result8) WALRUS ID(a8) \ - EXPONENT ID(b8) SEMI" + POW ID(b8) SEMI" in assert_equal expected actual ~printer:(fun s -> "\"" ^ s ^ "\"")) ; ("test9" @@ -113,7 +113,7 @@ let tests = let actual = string_of_tokens (to_list lexbuf) in let expected = "LET ID(a9) WALRUS LITERAL(0) SEMI LET ID(b9) WALRUS LITERAL(5) SEMI LET \ - ID(result9) WALRUS ID(a9) EXPONENT ID(b9) SEMI" + ID(result9) WALRUS ID(a9) POW ID(b9) SEMI" in assert_equal expected actual ~printer:(fun s -> "\"" ^ s ^ "\"")) ; ("test10" @@ -125,7 +125,7 @@ let tests = let actual = string_of_tokens (to_list lexbuf) in let expected = "LET ID(a10) WALRUS LITERAL(4) SEMI LET ID(b10) WALRUS LITERAL(-2) SEMI LET \ - ID(result10) WALRUS ID(a10) EXPONENT ID(b10) SEMI" + ID(result10) WALRUS ID(a10) POW ID(b10) SEMI" in assert_equal expected actual ~printer:(fun s -> "\"" ^ s ^ "\"")) ; ("test11" @@ -137,7 +137,7 @@ let tests = let actual = string_of_tokens (to_list lexbuf) in let expected = "LET ID(a11) WALRUS FLIT(5.000000) SEMI LET ID(b11) WALRUS LITERAL(-3) SEMI \ - LET ID(result11) WALRUS ID(a11) EXPONENT ID(b11) SEMI" + LET ID(result11) WALRUS ID(a11) POW ID(b11) SEMI" in assert_equal expected actual ~printer:(fun s -> "\"" ^ s ^ "\"")) ; ("test12" @@ -149,7 +149,7 @@ let tests = let actual = string_of_tokens (to_list lexbuf) in let expected = "LET ID(a12) WALRUS LITERAL(1) SEMI LET ID(b12) WALRUS LITERAL(1000) SEMI \ - LET ID(result12) WALRUS ID(a12) EXPONENT ID(b12) SEMI" + LET ID(result12) WALRUS ID(a12) POW ID(b12) SEMI" in assert_equal expected actual ~printer:(fun s -> "\"" ^ s ^ "\"")) ; ("test13" @@ -161,7 +161,7 @@ let tests = let actual = string_of_tokens (to_list lexbuf) in let expected = "LET ID(a13) WALRUS LITERAL(-2) SEMI LET ID(b13) WALRUS LITERAL(3) SEMI LET \ - ID(result13) WALRUS ID(a13) EXPONENT ID(b13) SEMI" + ID(result13) WALRUS ID(a13) POW ID(b13) SEMI" in assert_equal expected actual ~printer:(fun s -> "\"" ^ s ^ "\"")) ; ("test14" @@ -173,7 +173,7 @@ let tests = let actual = string_of_tokens (to_list lexbuf) in let expected = "LET ID(a14) WALRUS FLIT(-2.500000) SEMI LET ID(b14) WALRUS LITERAL(2) SEMI \ - LET ID(result14) WALRUS ID(a14) EXPONENT ID(b14) SEMI" + LET ID(result14) WALRUS ID(a14) POW ID(b14) SEMI" in assert_equal expected actual ~printer:(fun s -> "\"" ^ s ^ "\"")) ]