Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • youssef.sellami/e-language-compiler
1 result
Show changes
Commits on Source (2)
tokens SYM_EOF SYM_IDENTIFIER<string> SYM_INTEGER<int> SYM_PLUS SYM_MINUS SYM_ASTERISK SYM_DIV SYM_MOD
tokens SYM_LPARENTHESIS SYM_RPARENTHESIS SYM_LBRACE SYM_RBRACE
tokens SYM_ASSIGN SYM_SEMICOLON SYM_RETURN SYM_IF SYM_WHILE SYM_ELSE SYM_COMMA SYM_PRINT
tokens SYM_ASSIGN SYM_SEMICOLON SYM_RETURN SYM_IF SYM_WHILE SYM_ELSE SYM_COMMA
tokens SYM_EQUALITY SYM_NOTEQ SYM_LT SYM_LEQ SYM_GT SYM_GEQ
tokens SYM_INT SYM_CHAR SYM_VOID SYM_CHARACTER<char>
non-terminals S INSTR<tree> INSTRS<tree list> LINSTRS ELSE EXPR FACTOR
non-terminals LPARAMS REST_PARAMS
non-terminals IDENTIFIER INTEGER
......@@ -12,6 +13,7 @@ non-terminals CMP_EXPRS CMP_EXPR
non-terminals EQ_EXPRS EQ_EXPR
non-terminals AFTER_IDENTIFIER_INSTR AFTER_IDENTIFIER_FACTOR LARGS REST_ARGS
non-terminals TYPE AFTER_IDENTIFIER_DEC CHARACTER
axiom S
{
......@@ -40,11 +42,15 @@ rules
S -> FUNDEFS SYM_EOF { Node(Tlistglobdef, $1) }
FUNDEFS -> FUNDEF FUNDEFS { $1::$2 }
FUNDEFS -> { [] }
FUNDEF -> IDENTIFIER SYM_LPARENTHESIS LPARAMS SYM_RPARENTHESIS INSTR { Node(Tfundef, [Node(Tfunname, [$1]); Node(Tfunargs, $3); Node(Tfunbody, [$5])]) }
FUNDEF -> TYPE IDENTIFIER SYM_LPARENTHESIS LPARAMS SYM_RPARENTHESIS INSTR { Node(Tfundef, [Node(Tfuntype, [$1]); Node(Tfunname, [$2]); Node(Tfunargs, $4); Node(Tfunbody, [$6])]) }
LPARAMS -> IDENTIFIER REST_PARAMS { Node(Targ, [$1])::$2 }
TYPE -> SYM_INT { TypeLeaf Tint }
TYPE -> SYM_CHAR { TypeLeaf Tchar }
TYPE -> SYM_VOID { TypeLeaf Tvoid }
LPARAMS -> TYPE IDENTIFIER REST_PARAMS { Node(Targ, [$1; $2])::$3 }
LPARAMS -> { [] }
REST_PARAMS -> SYM_COMMA IDENTIFIER REST_PARAMS { Node(Targ, [$2])::$3 }
REST_PARAMS -> SYM_COMMA TYPE IDENTIFIER REST_PARAMS { Node(Targ, [$2; $3])::$4 }
REST_PARAMS -> { [] }
LARGS -> EXPR REST_ARGS { $1::$2 }
......@@ -60,18 +66,26 @@ INSTRS -> { [] }
INSTR -> SYM_IF SYM_LPARENTHESIS EXPR SYM_RPARENTHESIS SYM_LBRACE LINSTRS SYM_RBRACE ELSE { Node(Tif, [$3; $6; $8]) }
INSTR -> SYM_WHILE SYM_LPARENTHESIS EXPR SYM_RPARENTHESIS INSTR { Node(Twhile, [$3; $5]) }
INSTR -> SYM_RETURN EXPR SYM_SEMICOLON { Node(Treturn, [$2]) }
INSTR -> SYM_PRINT SYM_LPARENTHESIS EXPR SYM_RPARENTHESIS SYM_SEMICOLON { Node(Tprint, [$3]) }
INSTR -> IDENTIFIER AFTER_IDENTIFIER_INSTR SYM_SEMICOLON {
match $2 with
| Assign exp -> Node(Tassign, [$1; exp])
| Funcall args -> Node(Tcall, [$1; Node(Targs, args)])
| _ -> $1
}
INSTR -> TYPE IDENTIFIER AFTER_IDENTIFIER_DEC SYM_SEMICOLON {
match $3 with
| Assign exp -> Node(Tblock, [Node(Tdeclare, [$1; $2]); Node(Tassign, [$2; exp])])
| Nothing -> Node(Tdeclare, [$1; $2])
| _ -> $1
}
INSTR -> SYM_LBRACE LINSTRS SYM_RBRACE { $2 }
AFTER_IDENTIFIER_INSTR -> SYM_ASSIGN EXPR { Assign $2 }
AFTER_IDENTIFIER_INSTR -> SYM_LPARENTHESIS LARGS SYM_RPARENTHESIS { Funcall $2 }
AFTER_IDENTIFIER_DEC -> SYM_ASSIGN EXPR { Assign $2 }
AFTER_IDENTIFIER_DEC -> { Nothing }
ELSE -> SYM_ELSE SYM_LBRACE LINSTRS SYM_RBRACE { $3 }
ELSE -> { NullLeaf }
......@@ -110,9 +124,11 @@ FACTOR -> IDENTIFIER AFTER_IDENTIFIER_FACTOR {
| _ -> $1
}
FACTOR -> SYM_LPARENTHESIS EXPR SYM_RPARENTHESIS { $2 }
FACTOR -> CHARACTER { $1 }
IDENTIFIER -> SYM_IDENTIFIER {StringLeaf $1}
INTEGER -> SYM_INTEGER {IntLeaf $1}
CHARACTER -> SYM_CHARACTER {CharLeaf $1}
AFTER_IDENTIFIER_FACTOR -> { Nothing }
AFTER_IDENTIFIER_FACTOR -> SYM_LPARENTHESIS LARGS SYM_RPARENTHESIS { Funcall $2 }
open Batteries
open Prog
(* Les AST sont des arbres, du type [tree], étiquetés par des [tag].
......@@ -22,14 +23,14 @@ open Batteries
*)
type tag = Tassign | Tif | Twhile | Tblock | Treturn | Tprint
| Tint
type tag = Tassign | Tif | Twhile | Tblock | Treturn | Tdeclare
| Tint | Tchar | Tvoid
| Tadd | Tmul | Tdiv | Tmod | Txor | Tsub
| Tclt | Tcgt | Tcle | Tcge | Tceq | Tne
| Tneg
| Tlistglobdef
| Tfundef | Tfunname | Tfunargs | Tfunbody | Tcall
| Tassignvar
| Tfundef | Tfuntype | Tfunname | Tfunargs | Tfunbody | Tcall
| Tassignvar (*never used*)
| Targ | Targs
type tree = | Node of tag * tree list
......@@ -37,7 +38,7 @@ type tree = | Node of tag * tree list
| IntLeaf of int
| NullLeaf
| CharLeaf of char
| TypeLeaf of typ
let string_of_stringleaf = function
| StringLeaf s -> s
| _ -> failwith "string_of_stringleaf called on non-stringleaf nodes."
......@@ -51,7 +52,6 @@ let string_of_tag = function
| Twhile -> "Twhile"
| Tblock -> "Tblock"
| Treturn -> "Treturn"
| Tprint -> "Tprint"
| Tint -> "Tint"
| Tadd -> "Tadd"
| Tmul -> "Tmul"
......@@ -75,6 +75,10 @@ let string_of_tag = function
| Targ -> "Targ"
| Tcall -> "Tcall"
| Targs -> "Targs"
| Tdeclare -> "Tdeclare"
| Tfuntype -> "Tfuntype"
| Tchar -> "Tchar"
| Tvoid -> "Tvoid"
(* Écrit un fichier .dot qui correspond à un AST *)
let rec draw_ast a next =
......@@ -101,7 +105,8 @@ let rec draw_ast a next =
(next, next+1, [ Format.sprintf "n%d [label=\"null\"]\n" next])
| CharLeaf i ->
(next, next+1, [ Format.sprintf "n%d [label=\"%c\"]\n" next i])
| TypeLeaf t ->
(next, next+1, [ Format.sprintf "n%d [label=\"%s\"]\n" next (string_of_typ t)])
let draw_ast_tree oc ast =
let (_, _, s) = draw_ast ast 1 in
let s = String.concat "" s in
......@@ -116,3 +121,4 @@ let rec string_of_ast a =
| IntLeaf i -> Format.sprintf "%d" i
| CharLeaf i -> Format.sprintf "%c" i
| NullLeaf -> "null"
| TypeLeaf t -> string_of_typ t
\ No newline at end of file
......@@ -13,7 +13,6 @@ type expr =
type cfg_node =
| Cassign of string * expr * int
| Creturn of expr
| Cprint of expr * int
| Ccmp of expr * int * int
| Cnop of int
| Ccall of string * expr list * int
......@@ -32,7 +31,6 @@ type cprog = cfg_fun prog
let succs cfg n =
match Hashtbl.find_option cfg n with
| None -> Set.empty
| Some (Cprint (_, s))
| Some (Cassign (_, _, s)) -> Set.singleton s
| Some (Creturn _) -> Set.empty
| Some (Ccmp (_, s1, s2)) -> Set.of_list [s1;s2]
......@@ -45,7 +43,6 @@ let preds cfgfunbody n =
Hashtbl.fold (fun m m' acc ->
match m' with
| Cassign (_, _, s)
| Cprint (_, s)
| Cnop s
| Ccall (_, _, s) -> if s = n then Set.add m acc else acc
| Creturn _ -> acc
......@@ -71,7 +68,6 @@ let size_instr (i: cfg_node) : int =
match (i : cfg_node) with
| Cassign (_, e, _) -> 1 + size_expr e
| Creturn e -> 1 + (size_expr e)
| Cprint (e, _) -> 1 + (size_expr e)
| Ccmp (e, _, _) -> 1 + size_expr e
| Cnop _ -> 1
| Ccall (_, args, _) -> 1 + List.fold_left (fun acc arg -> acc + size_expr arg) 0 args
......
......@@ -28,6 +28,7 @@ let rec cfg_expr_of_eexpr (e: Elang.expr) : expr res =
| Elang.Ecall (f, args) ->
list_map_res cfg_expr_of_eexpr args >>= fun es ->
OK (Ecall (f, es))
| Elang.Echar c -> OK (Eint (Char.code c))
(* [cfg_node_of_einstr next cfg succ i] builds the CFG node(s) that correspond
to the E instruction [i].
......@@ -69,15 +70,11 @@ let rec cfg_node_of_einstr (next: int) (cfg : (int, cfg_node) Hashtbl.t)
| Elang.Ireturn e ->
cfg_expr_of_eexpr e >>= fun e ->
Hashtbl.replace cfg next (Creturn e); OK (next, next + 1)
| Elang.Iprint e ->
cfg_expr_of_eexpr e >>= fun e ->
Hashtbl.replace cfg next (Cprint (e,succ));
OK (next, next + 1)
| Elang.Icall (f, args) ->
list_map_res cfg_expr_of_eexpr args >>= fun es ->
Hashtbl.replace cfg next (Ccall (f, es, succ));
OK (next, next + 1)
| Elang.Ideclare (_, s) -> cfg_node_of_einstr next cfg succ (Elang.Iassign (s, Eint 0))
(* Some nodes may be unreachable after the CFG is entirely generated. The
[reachable_nodes n cfg] constructs the set of node identifiers that are
......@@ -89,7 +86,6 @@ let rec reachable_nodes n (cfg: (int,cfg_node) Hashtbl.t) =
match Hashtbl.find_option cfg n with
| None -> reach
| Some (Cnop succ)
| Some (Cprint (_, succ))
| Some (Cassign (_, _, succ)) -> reachable_aux succ reach
| Some (Creturn _) -> reach
| Some (Ccmp (_, s1, s2)) ->
......@@ -105,7 +101,7 @@ let cfg_fun_of_efun { funargs; funbody } =
(* remove unreachable nodes *)
let r = reachable_nodes node cfg in
Hashtbl.filteri_inplace (fun k _ -> Set.mem k r) cfg;
OK { cfgfunargs = funargs;
OK { cfgfunargs = List.map (fun (s, t) -> s) funargs;
cfgfunbody = cfg;
cfgentry = node;
}
......
......@@ -32,7 +32,6 @@ let live_cfg_node (node: cfg_node) (live_after: string Set.t) =
match node with
| Cassign (s, e, i) -> vars_in_expr e
| Creturn e -> vars_in_expr e
| Cprint (e, i) -> vars_in_expr e
| Ccmp (e, i1, i2) -> vars_in_expr e
| Cnop (i) -> Set.empty
| Ccall (f, args, i) -> vars_in_expr (Ecall (f, args))
......
......@@ -64,7 +64,6 @@ let replace_succs nop_succs (n: cfg_node) =
(* TODO *)
match n with
| Cassign (s, e, i) -> Cassign (s, e, replace_succ nop_succs i)
| Cprint (e, i) -> Cprint (e, replace_succ nop_succs i)
| Ccmp (e, i1, i2) -> Ccmp (e, replace_succ nop_succs i1, replace_succ nop_succs i2)
| Cnop i -> Cnop (replace_succ nop_succs i)
| Creturn e -> Creturn e
......
......@@ -17,7 +17,6 @@ let dump_list_cfgexpr l =
let dump_arrows oc fname n (node: cfg_node) =
match node with
| Cassign (_, _, succ)
| Cprint (_, succ)
| Cnop succ
| Ccall (_, _, succ) ->
Format.fprintf oc "n_%s_%d -> n_%s_%d\n" fname n fname succ
......@@ -30,7 +29,6 @@ let dump_arrows oc fname n (node: cfg_node) =
let dump_cfg_node oc (node: cfg_node) =
match node with
| Cassign (v, e, _) -> Format.fprintf oc "%s = %s" v (dump_cfgexpr e)
| Cprint (e, _) -> Format.fprintf oc "print %s" (dump_cfgexpr e)
| Creturn e -> Format.fprintf oc "return %s" (dump_cfgexpr e)
| Ccmp (e, _, _) -> Format.fprintf oc "%s" (dump_cfgexpr e)
| Cnop _ -> Format.fprintf oc "nop"
......
......@@ -34,12 +34,18 @@ let rec eval_cfgexpr oc st cp (e: expr) : (int * int state) res =
| Error msg -> Error msg
| OK (i, st'') -> OK ((l@[i]), st'')
) (OK([], st)) args >>= fun (int_args, st') ->
find_function cp f >>= fun found_f ->
match eval_cfgfun oc st' cp f found_f int_args with
| Error msg -> Error msg
| OK (None, st'') -> Error (Format.sprintf "CFG: Function %s doesn't have a return value.\n" f)
| OK (Some ret, st'') -> OK (ret, st'')
match find_function cp f with
| OK found_f ->
(match eval_cfgfun oc st' cp f found_f int_args with
| Error msg -> Error msg
| OK (None, st'') -> Error (Format.sprintf "CFG: Function %s doesn't have a return value.\n" f)
| OK (Some ret, st'') -> OK (ret, st''))
| Error msg ->
(match do_builtin oc st.mem f int_args with
| Error msg -> Error msg
| OK None -> Error (Format.sprintf "CFG: Function %s doesn't have a return value.\n" f)
| OK (Some ret) -> OK (ret, st'))
and eval_cfginstr oc st cp ht (n: int): (int * int state) res =
match Hashtbl.find_option ht n with
| None -> Error (Printf.sprintf "Invalid node identifier\n")
......@@ -57,10 +63,6 @@ and eval_cfginstr oc st cp ht (n: int): (int * int state) res =
| Creturn(e) ->
eval_cfgexpr oc st cp e >>= fun (e, st') ->
OK (e, st')
| Cprint(e, succ) ->
eval_cfgexpr oc st cp e >>= fun (e, st') ->
Format.fprintf oc "%d\n" e;
eval_cfginstr oc st' cp ht succ
| Ccall (f, args, succ) ->
List.fold_left (
fun (acc : (int list * int state) res) (arg : expr) ->
......@@ -72,9 +74,16 @@ and eval_cfginstr oc st cp ht (n: int): (int * int state) res =
| OK (i, st'') -> OK ((l@[i]), st'')
) (OK([], st)) args
>>= fun (int_args, st') ->
find_function cp f >>= fun found_f ->
eval_cfgfun oc st' cp f found_f int_args >>= fun (ret, st'') ->
eval_cfginstr oc st'' cp ht succ
match find_function cp f with
| OK found_f ->
(match eval_cfgfun oc st' cp f found_f int_args with
| Error msg -> Error msg
| OK (_, st'') -> eval_cfginstr oc st'' cp ht succ)
| Error msg ->
(match do_builtin oc st'.mem f int_args with
| OK _ -> eval_cfginstr oc st' cp ht succ
| Error msg -> Error msg )
and eval_cfgfun oc st cp cfgfunname { cfgfunargs;
cfgfunbody;
......
......@@ -70,11 +70,10 @@ let list_regexp : (regexp * (string -> token option)) list =
(keyword_regexp "int", fun _ -> Some (SYM_INT));
(* begin TODO *)
(keyword_regexp "void", fun _ -> Some (SYM_VOID));
(keyword_regexp "void", fun _ -> Some (SYM_CHAR));
(keyword_regexp "char", fun _ -> Some (SYM_CHAR));
(keyword_regexp "if", fun _ -> Some (SYM_IF));
(keyword_regexp "else", fun _ -> Some (SYM_ELSE));
(keyword_regexp "return", fun _ -> Some (SYM_RETURN));
(keyword_regexp "print", fun _ -> Some (SYM_PRINT));
(keyword_regexp "struct", fun _ -> Some (SYM_STRUCT));
(char_regexp '.', fun _ -> Some (SYM_POINT));
(char_regexp '+', fun _ -> Some (SYM_PLUS));
......
......@@ -10,6 +10,7 @@ type expr =
| Eint of int
| Evar of string
| Ecall of string * expr list
| Echar of char
type instr =
| Iassign of string * expr
......@@ -17,12 +18,14 @@ type instr =
| Iwhile of expr * instr
| Iblock of instr list
| Ireturn of expr
| Iprint of expr
| Icall of string * expr list
| Ideclare of typ * string
type efun = {
funargs: ( string ) list;
funargs: ( string * typ ) list;
funbody: instr;
funvartyp : (string, typ) Hashtbl.t;
funrettype : typ
}
type eprog = efun prog
......@@ -39,85 +39,118 @@ let binop_of_tag =
| Tne -> Ecne
| _ -> assert false
let remove_local_vars typ_var local_typ_var =
Hashtbl.filteri (fun s t -> Hashtbl.mem typ_var s) local_typ_var
let rec type_expr (typ_var : (string,typ) Hashtbl.t) (typ_fun : (string, typ list * typ) Hashtbl.t) (e: expr) : typ res =
match e with
| Ebinop (b, e1, e2) ->
type_expr typ_var typ_fun e1 >>= fun t1 ->
type_expr typ_var typ_fun e2 >>= fun t2 ->
if t1 != Tvoid && t2 != Tvoid
then OK Tint
else Error "E: Binop is not defined on void type."
| Eunop (u, e) ->
type_expr typ_var typ_fun e >>= fun t ->
if t != Tvoid
then OK Tint
else Error "E: Unop is not defined on void type."
| Eint i -> OK Tint
| Echar c -> OK Tchar
| Evar s ->
(match Hashtbl.find_option typ_var s with
| Some t when t != Tvoid -> OK t
| _ -> Error (Format.sprintf "E: Expression %s type is not defined." s))
| Ecall (f, _) ->
match Hashtbl.find_option typ_fun f with
| Some (_, t) when t != Tvoid -> OK t
| _ -> Error "E: Function return type is not defined."
let are_compatible (t1 : typ) (t2 : typ) : bool =
match t1, t2 with
| Tint, Tint
| Tchar, Tchar
| Tint, Tchar
| Tchar, Tint -> true
| _ -> false
(* [make_eexpr_of_ast a] builds an expression corresponding to a tree [a]. If
the tree is not well-formed, fails with an [Error] message. *)
let rec make_eexpr_of_ast (a: tree) : expr res =
let rec make_eexpr_of_ast (typ_var : (string,typ) Hashtbl.t) (typ_fun : (string, typ list * typ) Hashtbl.t) (a: tree) : expr res =
let res =
match a with
(* TODO *)
| IntLeaf i -> OK (Eint i)
| StringLeaf s -> OK (Evar s)
| CharLeaf c -> OK (Echar c)
| Node(t, [e1; e2]) when tag_is_binop t ->
(let res1 = make_eexpr_of_ast e1
in let res2 = make_eexpr_of_ast e2
in match res1, res2 with
| Error msg, _ -> Error msg
| _, Error msg -> Error msg
| OK expr1, OK expr2 -> OK (Ebinop (binop_of_tag t, expr1, expr2)))
(make_eexpr_of_ast typ_var typ_fun e1 >>= fun expr1 ->
make_eexpr_of_ast typ_var typ_fun e2 >>= fun expr2 ->
OK (Ebinop (binop_of_tag t, expr1, expr2)))
| Node(Tneg, [e]) ->
(let res = make_eexpr_of_ast e
in match res with
| Error msg -> Error msg
| OK expr -> OK (Eunop (Eneg, expr)))
make_eexpr_of_ast typ_var typ_fun e >>= fun expr ->
OK (Eunop (Eneg, expr))
| Node(Tcall, [StringLeaf f; Node(Targs, args)]) ->
(let res = list_map_res make_eexpr_of_ast args
in match res with
| Error msg -> Error msg
| OK exprs -> OK (Ecall (f, exprs)))
list_map_res (make_eexpr_of_ast typ_var typ_fun) args >>= fun exprs ->
OK (Ecall (f, exprs))
| _ ->
Error (Printf.sprintf "Unacceptable ast in make_eexpr_of_ast %s"
(string_of_ast a))
in
match res with
OK o -> res
OK o -> type_expr typ_var typ_fun o >>= fun t -> res
| Error msg -> Error (Format.sprintf "In make_eexpr_of_ast %s:\n%s"
(string_of_ast a) msg)
let rec make_einstr_of_ast (a: tree) : instr res =
let rec make_einstr_of_ast (typ_var : (string,typ) Hashtbl.t) (typ_fun : (string, typ list * typ) Hashtbl.t) (a: tree) : instr res =
let res =
match a with
(* TODO *)
| Node(Tassign, [StringLeaf s; e]) ->
(let res_of_e = make_eexpr_of_ast e
in match res_of_e with
| OK exp -> OK (Iassign (s, exp))
| Error msg -> Error msg)
make_eexpr_of_ast typ_var typ_fun e >>= fun expr ->
type_expr typ_var typ_fun expr >>= fun te ->
type_expr typ_var typ_fun (Evar s) >>= fun ts ->
if are_compatible te ts
then OK (Iassign (s, expr))
else Error (Format.sprintf "E: Types %s and %s are not compatible." (string_of_typ ts) (string_of_typ te))
| Node(Tif, [e; i1; i2]) ->
(let res_of_e = make_eexpr_of_ast e
in let res_of_i1 = make_einstr_of_ast i1
in let res_of_i2 = make_einstr_of_ast i2
in match res_of_e, res_of_i1, res_of_i2 with
| Error msg, _, _ -> Error msg
| _, Error msg, _ -> Error msg
| _, _, Error msg -> Error msg
| OK exp, OK inst1, OK inst2 -> OK (Iif (exp, inst1, inst2)))
make_eexpr_of_ast typ_var typ_fun e >>= fun expr ->
type_expr typ_var typ_fun expr >>= fun te ->
make_einstr_of_ast typ_var typ_fun i1 >>= fun instr1 ->
make_einstr_of_ast typ_var typ_fun i2 >>= fun instr2 ->
OK (Iif (expr, instr1, instr2))
| Node(Twhile, [e; i]) ->
(let res_of_e = make_eexpr_of_ast e
in let res_of_i = make_einstr_of_ast i
in match res_of_e, res_of_i with
| Error msg, _ -> Error msg
| _, Error msg -> Error msg
| OK exp, OK inst-> OK (Iwhile (exp, inst)))
| Node(Tblock, i_list) ->
(let res_of_i_list = list_map_res make_einstr_of_ast i_list
in match res_of_i_list with
| Error msg -> Error msg
| OK instr_list -> OK (Iblock instr_list))
make_eexpr_of_ast typ_var typ_fun e >>= fun expr ->
type_expr typ_var typ_fun expr >>= fun te ->
make_einstr_of_ast typ_var typ_fun i >>= fun instr ->
OK (Iwhile (expr, instr))
| Node(Tblock, i_list) ->
list_map_res (make_einstr_of_ast typ_var typ_fun) i_list >>= fun instr_list ->
OK (Iblock instr_list)
| Node(Treturn, [e]) ->
(let res_of_e = make_eexpr_of_ast e
in match res_of_e with
| OK exp -> OK (Ireturn exp)
| Error msg -> Error msg)
| Node(Tprint, [e]) ->
(let res_of_e = make_eexpr_of_ast e
in match res_of_e with
| OK exp -> OK (Iprint exp)
| Error msg -> Error msg)
make_eexpr_of_ast typ_var typ_fun e >>= fun expr ->
type_expr typ_var typ_fun expr >>= fun te ->
OK (Ireturn expr)
| Node(Tcall, [StringLeaf f; Node(Targs, args)]) ->
(let res = list_map_res make_eexpr_of_ast args
in match res with
| Error msg -> Error msg
| OK exprs -> OK (Icall (f, exprs)))
list_map_res (make_eexpr_of_ast typ_var typ_fun) args >>= fun exprs ->
list_map_res (type_expr typ_var typ_fun) exprs >>= fun types ->
(match Hashtbl.find_option typ_fun f with
| None -> Error (Format.sprintf "E: Unknown argument types of function %s." f)
| Some (arg_types, ret_type) ->
if types = arg_types
then OK (Icall (f, exprs))
else Error (Format.sprintf "E: Unvalid argument types in function %s calling." f))
| Node (Tdeclare, [TypeLeaf t; StringLeaf s]) ->
if t != Tvoid
then
if Hashtbl.mem typ_var s
then
Error (Format.sprintf "E: Variable %s already declared." s)
else
(Hashtbl.add typ_var s t;
OK (Ideclare (t ,s)))
else
Error (Format.sprintf "E: Can not declare void variable.")
| NullLeaf -> OK (Iblock [])
| _ -> Error (Printf.sprintf "Unacceptable ast in make_einstr_of_ast %s"
(string_of_ast a))
......@@ -127,20 +160,22 @@ let rec make_einstr_of_ast (a: tree) : instr res =
| Error msg -> Error (Format.sprintf "In make_einstr_of_ast %s:\n%s"
(string_of_ast a) msg)
let make_ident (a: tree) : string res =
let make_ident (a: tree) : (string * typ) res =
match a with
| Node (Targ, [s]) ->
OK (string_of_stringleaf s)
| Node (Targ, [TypeLeaf t; StringLeaf s]) -> OK (s, t)
| a -> Error (Printf.sprintf "make_ident: unexpected AST: %s"
(string_of_ast a))
let make_fundef_of_ast (a: tree) : (string * efun) res =
let make_fundef_of_ast (typ_fun : (string, typ list * typ) Hashtbl.t) (a: tree) : (string * efun) res =
match a with
| Node (Tfundef, [Node(Tfunname, [StringLeaf fname]); Node (Tfunargs, fargs); Node(Tfunbody, [fbody])]) ->
| Node (Tfundef, [Node(Tfuntype, [TypeLeaf t]); Node(Tfunname, [StringLeaf fname]); Node (Tfunargs, fargs); Node(Tfunbody, [fbody])]) ->
list_map_res make_ident fargs >>= fun fargs ->
(* TODO *)
make_einstr_of_ast fbody >>= fun fbody ->
OK (fname, {funargs = fargs; funbody = fbody})
(* TODO *)
let typ_var = Hashtbl.of_list fargs
in let arg_types = List.map (fun (arg, typ) -> typ) fargs
in Hashtbl.add typ_fun fname (arg_types, t);
make_einstr_of_ast typ_var typ_fun fbody >>= fun fbody ->
OK (fname, {funargs = fargs; funbody = fbody; funvartyp = typ_var; funrettype = t})
| _ ->
Error (Printf.sprintf "make_fundef_of_ast: Expected a Tfundef, got %s."
(string_of_ast a))
......@@ -148,7 +183,11 @@ let make_fundef_of_ast (a: tree) : (string * efun) res =
let make_eprog_of_ast (a: tree) : eprog res =
match a with
| Node (Tlistglobdef, l) ->
list_map_res (fun a -> make_fundef_of_ast a >>= fun (fname, efun) -> OK (fname, Gfun efun)) l
let fun_typ = Hashtbl.create (List.length l) in
Hashtbl.replace fun_typ "print" ([Tint], Tvoid);
Hashtbl.replace fun_typ "print_int" ([Tint], Tvoid);
Hashtbl.replace fun_typ "print_char" ([Tchar], Tvoid);
list_map_res (fun a -> make_fundef_of_ast fun_typ a >>= fun (fname, efun) -> OK (fname, Gfun efun)) l
| _ ->
Error (Printf.sprintf "make_fundef_of_ast: Expected a Tlistglobdef, got %s."
(string_of_ast a))
......
......@@ -27,7 +27,7 @@ let rec dump_eexpr = function
| Eint i -> Printf.sprintf "%d" i
| Evar s -> Printf.sprintf "%s" s
| Ecall (f, args) -> Printf.sprintf "%s(%s)" f (String.concat ", " (List.map dump_eexpr args))
| Echar c -> Printf.sprintf "%c" c
let indent_size = 2
let spaces n =
range (indent_size*n) |> List.map (fun _ -> ' ') |> String.of_list
......@@ -56,13 +56,12 @@ let rec dump_einstr_rec indent oc i =
| Ireturn(e) ->
print_spaces oc indent;
Format.fprintf oc "return %s;\n" (dump_eexpr e)
| Iprint(e) ->
print_spaces oc indent;
Format.fprintf oc "print %s;\n" (dump_eexpr e)
| Icall(f, args) ->
print_spaces oc indent;
Format.fprintf oc "%s(%s);\n" f (String.concat ", " (List.map dump_eexpr args))
| Ideclare(t, s) ->
print_spaces oc indent;
Format.fprintf oc "%s %s;\n" (string_of_typ t) s
let dump_einstr oc i = dump_einstr_rec 0 oc i
......@@ -70,7 +69,7 @@ let dump_einstr oc i = dump_einstr_rec 0 oc i
let dump_efun oc funname {funargs; funbody} =
Format.fprintf oc "%s(%s) {\n%a\n}\n"
funname
(String.concat "," funargs)
(String.concat "," (List.map (fun (s, t) -> Printf.sprintf "%s %s" (string_of_typ t) s) funargs))
dump_einstr funbody
let dump_eprog oc = dump_prog dump_efun oc
......
......@@ -2,6 +2,11 @@ open Elang
open Batteries
open Prog
open Utils
open Builtins
let remove_local_vars st local_st =
let filtered_env = Hashtbl.filteri (fun k v -> if Hashtbl.mem st.env k then (Printf.printf "Not removing %s\n" k; true) else (Printf.printf "removing %s\n" k; false) ) local_st.env
in {local_st with env = filtered_env}
let binop_bool_to_int f x y = if f x y then 1 else 0
......@@ -38,42 +43,33 @@ let rec eval_eexpr oc st (ep: eprog) (e : expr) : (int * int state) res =
| Some i -> OK (i, st)
| None -> Error "Variable is not defined")
| Ebinop (b, ex, ey) ->
(let res_x = eval_eexpr oc st ep ex
in match res_x with
| Error msg -> Error msg
| OK (x, st') ->
let res_y = eval_eexpr oc st' ep ey
in match res_y with
| Error msg -> Error msg
| OK (y, st'') -> OK (eval_binop b x y, st''))
eval_eexpr oc st ep ex >>= fun (x, st') ->
eval_eexpr oc st' ep ey >>= fun (y, st'') ->
OK (eval_binop b x y, st'')
| Eunop (u, ex) ->
(let res_x = eval_eexpr oc st ep ex
in match res_x with
| Error msg -> Error msg
| OK (x, st') -> OK (eval_unop u x, st'))
eval_eexpr oc st ep ex >>= fun (x, st') ->
OK (eval_unop u x, st')
| Ecall (f, args) ->
let (res : (int list * int state) res) = List.fold_left (
fun (acc : (int list * int state) res) (arg : expr) ->
match acc with
| Error msg -> Error msg
| OK (l, st') ->
match eval_eexpr oc st' ep arg with
| Error msg -> Error msg
| OK (i, st'') -> OK ((l@[i]), st'')
) (OK([], st)) args
in match res with
| Error msg -> Error msg
| OK (int_args, st') ->
(List.fold_left
(fun acc arg ->
acc >>= fun (l, st') ->
eval_eexpr oc st' ep arg >>= fun (i, st'') ->
OK ((l@[i]), st''))
(OK([], st)) args >>= fun(int_args, st') ->
match find_function ep f with
| Error msg -> Error msg
| OK found_f ->
match eval_efun oc st' ep found_f f int_args with
(match eval_efun oc st' ep found_f f int_args with
| Error msg -> Error msg
| OK (None, st'') -> Error (Format.sprintf "E: Function %s doesn't have a return value.\n" f)
| OK (Some ret, st'') -> OK (ret, st'')
| OK (Some ret, st'') -> OK (ret, st''))
| Error msg ->
(match do_builtin oc st'.mem f int_args with
| Error msg -> Error msg
| OK None -> Error (Format.sprintf "E: Function %s doesn't have a return value.\n" f)
| OK (Some ret) -> OK (ret, st')))
| Echar c -> OK (Char.code c, st)
(* [eval_einstr oc st ins] évalue l'instrution [ins] en partant de l'état [st].
(* [eval_einstr oc st ins] évalue l'instruction [ins] en partant de l'état [st].
Le paramètre [oc] est un "output channel", dans lequel la fonction "print"
écrit sa sortie, au moyen de l'instruction [Format.fprintf].
......@@ -88,31 +84,33 @@ let rec eval_eexpr oc st (ep: eprog) (e : expr) : (int * int state) res =
and eval_einstr oc (st: int state) (ep: eprog) (ins: instr) :
(int option * int state) res =
match ins with
| Iassign (s, e) ->
(match eval_eexpr oc st ep e with
| Error msg -> Error msg
| OK (v, st') ->
let replace st s v =
| Iassign (s, e) ->
if Hashtbl.mem st.env s
then
(let replace st s v =
let new_env = Hashtbl.copy st.env
in Hashtbl.replace new_env s v;
{st with env = new_env}
in OK (None, replace st' s v))
{st with env = new_env}
in match eval_eexpr oc st ep e with
| Error msg -> Error msg
| OK (v, st') -> OK (None, replace st' s v))
else
Error (Format.sprintf "E: Variable %s was not declared." s)
| Iif (e, i1, i2) ->
(match eval_eexpr oc st ep e with
| Error msg -> Error msg
| OK (v, st') -> if v = 0 then eval_einstr oc st' ep i2 else eval_einstr oc st' ep i1)
(eval_eexpr oc st ep e >>= fun (v, st') ->
if v != 0
then eval_einstr oc st' ep i1 >>= fun (r_opt, st'') ->
OK (r_opt, remove_local_vars st' st'')
else eval_einstr oc st' ep i2 >>= fun (r_opt, st'') ->
OK (r_opt, remove_local_vars st' st''))
| Iwhile (e, i) ->
(match eval_eexpr oc st ep e with
| Error msg -> Error msg
| OK (v, st') ->
if v = 1
then (let res_i = eval_einstr oc st' ep i
in match res_i with
| Error msg -> Error msg
| OK (r_opt, next_st) -> match r_opt with
| None -> eval_einstr oc next_st ep (Iwhile (e, i))
| Some r -> OK (r_opt, next_st))
else OK(None, st'))
(eval_eexpr oc st ep e >>= fun (v, st') ->
if v != 0
then eval_einstr oc st' ep i >>= fun (r_opt, next_st) ->
match r_opt with
| None -> eval_einstr oc (remove_local_vars st' next_st) ep (Iwhile (e, i))
| Some r -> OK (r_opt, remove_local_vars st' next_st)
else OK (None, st'))
| Iblock i_list ->
(match i_list with
| [] -> OK (None, st)
......@@ -122,34 +120,26 @@ and eval_einstr oc (st: int state) (ep: eprog) (ins: instr) :
| OK (Some r, next_st) -> OK (Some r, next_st)
| OK (None, next_st) -> eval_einstr oc next_st ep (Iblock rest))
| Ireturn e ->
(match eval_eexpr oc st ep e with
| Error msg -> Error msg
| OK (v, st') -> OK(Some v, st'))
| Iprint e ->
(match eval_eexpr oc st ep e with
| Error msg -> Error msg
| OK (v, st') ->
Format.fprintf oc "%d\n" v;
OK(None, st'))
eval_eexpr oc st ep e >>= fun (v, st') ->
OK(Some v, st')
| Icall (f, args) ->
let (res : (int list * int state) res) = List.fold_left (
fun (acc : (int list * int state) res) (arg : expr) ->
match acc with
| Error msg -> Error msg
| OK (l, st') ->
match eval_eexpr oc st' ep arg with
| Error msg -> Error msg
| OK (i, st'') -> OK ((l@[i]), st'')
) (OK([], st)) args
in match res with
| Error msg -> Error msg
| OK (int_args, st') ->
(List.fold_left
(fun acc arg ->
acc >>= fun (l, st') ->
eval_eexpr oc st' ep arg >>= fun (i, st'') ->
OK ((l@[i]), st''))
(OK([], st)) args >>= fun(int_args, st') ->
match find_function ep f with
| Error msg -> Error msg
| OK found_f ->
match eval_efun oc st' ep found_f f int_args with
| Error msg -> Error msg
| OK (_, st'') -> OK (None, st'')
(eval_efun oc st' ep found_f f int_args >>= fun (_, st'') ->
OK (None, st''))
| Error msg ->
(do_builtin oc st'.mem f int_args >>= fun _ ->
OK (None, st')))
| Ideclare (_, s) ->
let new_env = Hashtbl.copy st.env
in Hashtbl.add new_env s 0;
OK (None, {st with env = new_env})
(* [eval_efun oc st f fname vargs] évalue la fonction [f] (dont le nom est
[fname]) en partant de l'état [st], avec les arguments [vargs].
......@@ -166,7 +156,7 @@ and eval_efun oc (st: int state) ep ({ funargs; funbody}: efun)
seulement ses arguments), puis on restore l'environnement de l'appelant. *)
let env_save = Hashtbl.copy st.env in
let env = Hashtbl.create 17 in
match List.iter2 (fun a v -> Hashtbl.replace env a v) funargs vargs with
match List.iter2 (fun (a, t) v -> Hashtbl.replace env a v) funargs vargs with
| () ->
eval_einstr oc { st with env } ep funbody >>= fun (v, st') ->
OK (v, { st' with env = env_save })
......
......@@ -30,7 +30,6 @@ rule token = parse
| "void" { SYM_VOID }
| "char" { SYM_CHAR }
| "int" { SYM_INT }
| "print" { SYM_PRINT }
| "struct" { SYM_STRUCT }
| "if" { SYM_IF }
| "else" { SYM_ELSE }
......
......@@ -8,7 +8,6 @@ open Rtl
let gen_live (i: rtl_instr) =
match i with
| Rbinop (b, rd, rs1, rs2) -> Set.of_list [rs1; rs2]
| Rprint rs
| Runop (_, _, rs) -> Set.singleton rs
| Rconst (_, _) -> Set.empty
| Rbranch (_, rs1, rs2, _) -> Set.of_list [rs1; rs2]
......@@ -26,7 +25,6 @@ let kill_live (i: rtl_instr) =
| Rmov (rd,_)
| Rcall (Some rd, _, _) -> Set.singleton rd
| Rbranch (_, _, _, _)
| Rprint _
| Rret _
| Rjmp _
| Rlabel _
......
......@@ -47,13 +47,6 @@ let rec exec_linear_instr oc lp fname f st (i: rtl_instr) =
OK (None, st)
| _ -> Error (Printf.sprintf "Mov on undefined register (%s)" (print_reg rs))
end
| Rprint r ->
begin match Hashtbl.find_option st.regs r with
| Some s ->
Format.fprintf oc "%d\n" s;
OK (None, st)
| _ -> Error (Printf.sprintf "Print on undefined register (%s)" (print_reg r))
end
| Rret r ->
begin match Hashtbl.find_option st.regs r with
| Some s -> OK (Some s, st)
......@@ -71,12 +64,20 @@ let rec exec_linear_instr oc lp fname f st (i: rtl_instr) =
| Some v -> Some (vs@[v])))
(Some []) args
in match vs_opt with
| Some params -> find_function lp g >>= fun found_g ->
(match rd_opt, exec_linear_fun oc lp st g found_g params with
| _, Error msg -> Error msg
| Some rd, OK (Some ret, st') -> exec_linear_instr oc lp fname f st' (Rconst (rd, ret))
| Some rd, OK (None, st') -> Error (Printf.sprintf "Function %s doesn't have a return value" g)
| None, OK (_, st') -> OK(None, st'))
| Some params ->
(match find_function lp g with
| OK found_g ->
(match rd_opt, exec_linear_fun oc lp st g found_g params with
| _, Error msg -> Error msg
| Some rd, OK (Some ret, st') -> exec_linear_instr oc lp fname f st' (Rconst (rd, ret))
| Some rd, OK (None, st') -> Error (Printf.sprintf "Function %s doesn't have a return value" g)
| None, OK (_, st') -> OK(None, st'))
| Error msg ->
(match rd_opt, do_builtin oc st.mem g params with
| _, Error msg -> Error msg
| Some rd, OK None -> Error (Format.sprintf "RTL: Function %s doesn't have a return value.\n" g)
| Some rd, OK (Some ret) -> exec_linear_instr oc lp fname f st (Rconst (rd, ret))
| None, OK _ -> OK(None, st)))
| _ -> Error (Printf.sprintf "Function %s applied on undefined register" g)
end
......
......@@ -217,7 +217,6 @@ let written_rtl_regs_instr (i: rtl_instr) =
| Rconst (rd, _)
| Rmov (rd, _)
| Rcall (Some rd, _, _)-> Set.singleton rd
| Rprint _
| Rret _
| Rlabel _
| Rbranch (_, _, _, _)
......@@ -228,7 +227,6 @@ let read_rtl_regs_instr (i: rtl_instr) =
match i with
| Rbinop (_, _, rs1, rs2)
| Rbranch (_, rs1, rs2, _) -> Set.of_list [rs1; rs2]
| Rprint rs
| Runop (_, _, rs)
| Rmov (_, rs)
| Rret rs -> Set.singleton rs
......@@ -302,24 +300,6 @@ let ltl_instrs_of_linear_instr fname live_out allocation
load_loc reg_tmp1 allocation rs >>= fun (ls, rs) ->
store_loc reg_tmp1 allocation rd >>= fun (ld, rd) ->
OK (ls @ LMov(rd, rs) :: ld)
| Rprint r ->
let (save_a_regs, arg_saved, ofs) =
save_caller_save
(range 32)
(- (numspilled+1)) in
let parameter_passing =
match Hashtbl.find_option allocation r with
| None -> Error (Format.sprintf "Could not find allocation for register %d\n" r)
| Some (Reg rs) -> OK [LMov(reg_a0, rs)]
| Some (Stk o) -> OK [LLoad(reg_a0, reg_fp, (Archi.wordsize ()) * o, (archi_mas ()))]
in
parameter_passing >>= fun parameter_passing ->
OK (LComment "Saving a0-a7,t0-t6" :: save_a_regs @
LAddi(reg_sp, reg_s0, (Archi.wordsize ()) * (ofs + 1)) ::
parameter_passing @
LCall "print" ::
LComment "Restoring a0-a7,t0-t6" :: restore_caller_save arg_saved)
| Rret r ->
load_loc reg_tmp1 allocation r >>= fun (l,r) ->
OK (l @ [LMov (reg_ret, r) ; LJmp epilogue_label])
......
......@@ -53,7 +53,6 @@ let to_yacc_token = function
| SYM_LBRACKET -> Yaccparser.SYM_LBRACKET
| SYM_RBRACKET -> Yaccparser.SYM_RBRACKET
| SYM_ALLOC -> Yaccparser.SYM_ALLOC
| SYM_PRINT -> Yaccparser.SYM_PRINT
| SYM_EXTERN -> Yaccparser.SYM_EXTERN
| SYM_INCLUDE(s) -> Yaccparser.SYM_INCLUDE s
| SYM_AMPERSAND -> Yaccparser.SYM_AMPERSAND
......
......@@ -6,6 +6,17 @@ type mem_access_size =
| MAS4
| MAS8
type typ =
| Tint
| Tchar
| Tvoid
let string_of_typ t =
match t with
| Tint -> "int"
| Tchar -> "char"
| Tvoid -> "void"
let string_of_mem_access_size mas =
match mas with
| MAS1 -> "{1}"
......
......@@ -14,7 +14,6 @@ type rtl_instr = Rbinop of binop * reg * reg * reg
| Rmov of reg * reg
| Rret of reg
| Rlabel of int
| Rprint of reg
| Rcall of reg option * string * reg list
type rtl_fun = { rtlfunargs: reg list;
......@@ -29,7 +28,6 @@ let written_rtl_regs_instr (i: rtl_instr) =
| Runop (_, rd, _)
| Rconst (rd, _)
| Rmov (rd, _) -> Set.singleton rd
| Rprint _
| Rret _
| Rlabel _
| Rbranch (_, _, _, _)
......