Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow variable assignment and intialization anywhere #8

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions kazm/ast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ type stmt =
| While of expr * stmt
| Break
| EmptyReturn
| Initialize of bind * expr option

type func_decl = {
typ : typ;
fname : string;
formals : bind list;
locals : bind list;
body : stmt list;
}

Expand Down Expand Up @@ -104,7 +104,6 @@ let string_of_fdecl fdecl =
string_of_typ fdecl.typ ^ " " ^
fdecl.fname ^ "(" ^ String.concat ", " (List.map snd fdecl.formals) ^
")\n{\n" ^
String.concat "" (List.map string_of_vdecl fdecl.locals) ^
String.concat "" (List.map string_of_stmt fdecl.body) ^
"}\n"

Expand Down
78 changes: 47 additions & 31 deletions kazm/checker.ml
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ let check (globals, functions) =
typ = Void;
fname = name;
formals = [(ty, "x")];
locals = []; body = [] } map
body = [] } map
in let smap = StringMap.add "next_int" {
typ = Int;
fname = "next_int";
formals = [];
locals = []; body = [] } StringMap.empty
body = [] } StringMap.empty
in List.fold_left add_bind smap [ ("print", String);
("println", String);
("int_print", Int);
Expand Down Expand Up @@ -73,9 +73,9 @@ let check (globals, functions) =
let _ = find_func "main" in (* Ensure "main" is defined *)

let check_function func =
(* Make sure no formals or locals are void or duplicates *)
(* Make sure no formals are void or duplicates *)
check_binds "formal" func.formals;
check_binds "local" func.locals;
(* check_binds "local" func.locals; *)

(* Raise an exception if the given rvalue type cannot be assigned to
the given lvalue type *)
Expand All @@ -85,32 +85,34 @@ let check (globals, functions) =

(* Build local symbol table of variables for this function *)
let symbols = List.fold_left (fun m (ty, name) -> StringMap.add name ty m)
StringMap.empty (globals @ func.formals @ func.locals )
StringMap.empty (globals @ func.formals )
in

(* Return a variable from our local symbol table *)
let type_of_identifier s =
try StringMap.find s symbols
with Not_found -> raise (Failure ("undeclared identifier " ^ s))
let rec type_of_identifier s locals =
try StringMap.find s locals
with Not_found -> try StringMap.find s symbols
with Not_found -> raise (Failure ("undeclared identifier " ^ s))
in

(* Return a semantically-checked expression, i.e., with a type *)
let rec expr = function
let rec expr e locals =
match e with
Literal l -> (Int, SLiteral l)
| Dliteral l -> (Double, SDliteral l)
| BoolLit l -> (Bool, SBoolLit l)
| CharLit c -> (Char, SCharLit c)
| StringLit s -> (String, SStringLit s)
| Noexpr -> (Void, SNoexpr)
| Id s -> (type_of_identifier s, SId s)
| Id s -> (type_of_identifier s locals, SId s)
| Assign(var, e) as ex ->
let lt = type_of_identifier var
and (rt, e') = expr e in
let lt = type_of_identifier var locals
and (rt, e') = expr e locals in
let err = "illegal assignment " ^ string_of_typ lt ^ " = " ^
string_of_typ rt ^ " in " ^ string_of_expr ex
in (check_assign lt rt err, SAssign(var, (rt, e')))
| Unop(op, e) as ex ->
let (t, e') = expr e in
let (t, e') = expr e locals in
let ty = match op with
Neg when t = Int || t = Float -> t
| Not when t = Bool -> Bool
Expand All @@ -119,8 +121,8 @@ let check (globals, functions) =
" in " ^ string_of_expr ex))
in (ty, SUnop(op, (t, e')))
| Binop(e1, op, e2) as e ->
let (t1, e1') = expr e1
and (t2, e2') = expr e2 in
let (t1, e1') = expr e1 locals
and (t2, e2') = expr e2 locals in
(* All binary operators require operands of the same type *)
let same = t1 = t2 in
(* Determine expression type based on operator and operand types *)
Expand All @@ -143,7 +145,7 @@ let check (globals, functions) =
raise (Failure ("expecting " ^ string_of_int param_length ^
" arguments in " ^ string_of_expr call))
else let check_call (ft, _) e =
let (et, e') = expr e in
let (et, e') = expr e locals in
let err = "illegal argument found " ^ string_of_typ et ^
" expected " ^ string_of_typ ft ^ " in " ^ string_of_expr e
in (check_assign ft et err, e')
Expand All @@ -152,22 +154,25 @@ let check (globals, functions) =
in (fd.typ, SCall(fname, args'))
in

let check_bool_expr e =
let (t', e') = expr e
let check_bool_expr e locals =
let (t', e') = expr e locals
and err = "expected Boolean expression in " ^ string_of_expr e
in if t' != Bool then raise (Failure err) else (t', e')
in

(* Return a semantically-checked statement i.e. containing sexprs *)
let rec check_stmt = function
Expr e -> SExpr (expr e)
| If(p, b1, b2) -> SIf(check_bool_expr p, check_stmt b1, check_stmt b2)
let rec check_stmt stmt locals =
match stmt with
Expr e -> SExpr (expr e locals)
| Initialize (bd, None) -> raise (Failure ("Initialize stmts are inside Block."))
| Initialize (bd, Some e) -> raise (Failure ("Initialize stmts are inside Block."))
| If(p, b1, b2) -> SIf(check_bool_expr p locals, check_stmt b1 locals, check_stmt b2 locals)
| For(e1, e2, e3, st) ->
SFor(expr e1, check_bool_expr e2, expr e3, check_stmt st)
| While(p, s) -> SWhile(check_bool_expr p, check_stmt s)
SFor(expr e1 locals, check_bool_expr e2 locals, expr e3 locals, check_stmt st locals)
| While(p, s) -> SWhile(check_bool_expr p locals, check_stmt s locals)
| EmptyReturn -> SEmptyReturn
| Break -> SBreak
| Return e -> let (t, e') = expr e in
| Return e -> let (t, e') = expr e locals in
if t = func.typ then SReturn (t, e')
else raise (
Failure ("return gives " ^ string_of_typ t ^ " expected " ^
Expand All @@ -176,20 +181,31 @@ let check (globals, functions) =
(* A block is correct if each statement is correct and nothing
follows any Return statement. Nested blocks are flattened. *)
| Block sl ->
let rec check_stmt_list = function
[Return _ as s] -> [check_stmt s]
let rec check_stmt_list stmts locals =
match stmts with
[Return _ as s] -> [check_stmt s locals]
| Initialize (bd, None) :: ss ->
let (typ, name) = bd in
if StringMap.mem name locals = true
then raise (Failure ("cannot initialize " ^ name ^ " twice"))
else SInitialize(bd, None) :: check_stmt_list ss (StringMap.add name typ locals)
| Initialize (bd, Some e) :: ss ->
let (typ, name) = bd in
let se = expr e locals in
if StringMap.mem name locals = true
then raise (Failure ("cannot initialize " ^ name ^ " twice"))
else SInitialize(bd, Some se) :: check_stmt_list ss (StringMap.add name typ locals)
| Return _ :: _ -> raise (Failure "nothing may follow a return")
| Block sl :: ss -> check_stmt_list (sl @ ss) (* Flatten blocks *)
| s :: ss -> check_stmt s :: check_stmt_list ss
| Block sl :: ss -> check_stmt_list (sl @ ss) locals (* Flatten blocks *)
| s :: ss -> check_stmt s locals :: check_stmt_list ss locals
| [] -> []
in SBlock(check_stmt_list sl)
in SBlock(check_stmt_list sl locals)

in (* body of check_function *)
{ styp = func.typ;
sfname = func.fname;
sformals = func.formals;
slocals = func.locals;
sbody = match check_stmt (Block func.body) with
sbody = match check_stmt (Block func.body) StringMap.empty with
SBlock(sl) -> sl
| _ -> raise (Failure ("internal error: block didn't become a block?"))
}
Expand Down
30 changes: 20 additions & 10 deletions kazm/codegen.ml
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,13 @@ let gen (bind_list, sfunction_decls) =

let add_var scope name l =
let Scope(p, map) = scope in
let map' = SMap.add name l map in
Scope(p, map')
Scope(p, SMap.add name l map)
in

let initialize_var ctx vtyp name =
let Ctx(builder, scope) = ctx in
let var = L.build_alloca (typ_to_t vtyp) name builder in
Ctx(builder, add_var scope name var)
in

(* Codegen for an expression *)
Expand Down Expand Up @@ -160,7 +165,6 @@ let gen (bind_list, sfunction_decls) =
let typ = func.styp in
let name = func.sfname in
let formals = func.sformals in
let locals = func.slocals in
(* Defines the func *)
let fn = SMap.find name all_funcs in

Expand All @@ -171,7 +175,7 @@ let gen (bind_list, sfunction_decls) =
match stmt with
(* For expressions we just codegen the expression *)
SExpr(e) ->
let (ctx', ex) = codegen_expr ctx e in
let (ctx', _) = codegen_expr ctx e in
ctx'
| SEmptyReturn -> build_default_return typ ctx
| SReturn(expr) ->
Expand Down Expand Up @@ -248,6 +252,16 @@ let gen (bind_list, sfunction_decls) =
Ctx(end_builder, sp)
(* For a block of statements, just fold *)
| SBlock(stmts) -> List.fold_left codegen_stmt ctx stmts
| SInitialize((vtyp, name), None) ->
initialize_var ctx vtyp name
| SInitialize((vtyp, name), Some e) ->
(* Evaluate expression first *)
let (ctx', e') = codegen_expr ctx e in
(* Then initialize the var *)
let Ctx(builder, sp) = initialize_var ctx vtyp name in
(* Finally store *)
ignore (L.build_store e' (find_var sp name) builder);
Ctx(builder, sp)
in

let fn_builder = L.builder_at_end context (L.entry_block fn) in
Expand All @@ -261,12 +275,8 @@ let gen (bind_list, sfunction_decls) =
in
let vars = List.fold_left2 add_param vars formals (Array.to_list (L.params fn)) in
let fn_scope = Scope(None, vars) in
let initialize_var scope (vtyp, name) =
let var = L.build_alloca (typ_to_t vtyp) name fn_builder in
add_var scope name var
in
let fn_scope' = List.fold_left initialize_var fn_scope locals in
let fn_ctx = Ctx(fn_builder, fn_scope') in
(* let fn_scope' = List.fold_left initialize_var fn_scope locals in *)
let fn_ctx = Ctx(fn_builder, fn_scope) in
(* Build all statements *)
let ctx' = codegen_stmt fn_ctx (SBlock body) in
ignore (add_terminator ctx' (build_default_return typ))
Expand Down
18 changes: 7 additions & 11 deletions kazm/parser.mly
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,14 @@ program:

decls:
/* nothing */ { ([], []) }
| decls var_decl { ((fst $1 @ [$2]), snd $1) }
| decls fdecl { (fst $1, (snd $1 @ [$2])) }

fdecl:
typ IDENTIFIER PAREN_L formals_opt PAREN_R BRACE_L var_decls stmts BRACE_R
typ IDENTIFIER PAREN_L formals_opt PAREN_R BRACE_L stmts BRACE_R
{ { typ = $1;
fname = $2;
formals = List.rev $4;
locals = List.rev $7;
body = List.rev $8 } }
body = List.rev $7 } }

formals_opt:
/* nothing */ { [] }
Expand All @@ -74,13 +72,6 @@ typ:
| DOUBLE { Double }
| STRING { String }

var_decls:
{ [] }
| var_decls var_decl { $2 :: $1 }

var_decl:
typ IDENTIFIER SEMI { ($1, $2) }

stmts:
{ [] }
| stmts stmt { $2::$1 }
Expand All @@ -89,6 +80,7 @@ stmt:
expr SEMI { Expr $1 }
| return_stmt SEMI { $1 }
| break_stmt SEMI { $1 }
| var_decl SEMI { $1 }
| if_stmt { $1 }
| while_stmt { $1 }
| for_stmt { $1 }
Expand All @@ -113,6 +105,10 @@ while_stmt:
for_stmt:
FOR PAREN_L expr SEMI expr SEMI expr PAREN_R BRACE_L stmts BRACE_R { For($3, $5, $7, Block(List.rev $10)) }

var_decl:
typ IDENTIFIER { Initialize(($1, $2), None) }
| typ IDENTIFIER ASSIGN expr { Initialize(($1, $2), Some $4) }

expr:
INT_LITERAL { Literal($1) }
| STRING_LITERAL { StringLit($1) }
Expand Down
3 changes: 1 addition & 2 deletions kazm/sast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ type sstmt =
| SWhile of sexpr * sstmt
| SBreak
| SEmptyReturn
| SInitialize of bind * sexpr option

type sfunc_decl = {
styp : typ;
sfname : string;
sformals : bind list;
slocals : bind list;
sbody : sstmt list;
}

Expand Down Expand Up @@ -76,7 +76,6 @@ let string_of_sfdecl fdecl =
string_of_typ fdecl.styp ^ " " ^
fdecl.sfname ^ "(" ^ String.concat ", " (List.map snd fdecl.sformals) ^
")\n{\n" ^
String.concat "" (List.map string_of_vdecl fdecl.slocals) ^
String.concat "" (List.map string_of_sstmt fdecl.sbody) ^
"}\n"

Expand Down