This repository has been archived on 2022-12-27. You can view files and clone it, but cannot push or open issues or pull requests.
compilateurMIPS/semantics.ml

138 lines
4.2 KiB
OCaml
Raw Normal View History

2022-12-06 20:39:15 +01:00
open Ast
2022-12-10 17:51:31 +01:00
open Ast.IR1
open Ast.V1
2022-12-06 20:39:15 +01:00
open Baselib
open Errors
2022-12-08 19:55:22 +01:00
let analyze_value = function
2022-12-09 22:20:05 +01:00
| Syntax.Void -> Void, Void_t
2022-12-08 19:55:22 +01:00
| Syntax.Int n -> Int n, Int_t
2022-12-08 21:30:39 +01:00
| Syntax.Bool b -> Bool b, Bool_t
2022-12-11 03:35:52 +01:00
| Syntax.Str s -> Str s, Str_t
2022-12-08 19:55:22 +01:00
;;
2022-12-09 14:45:59 +01:00
let rec analyze_expr env ua t = function
2022-12-08 19:55:22 +01:00
| Syntax.Val v ->
2022-12-09 14:14:33 +01:00
let v2, new_t = analyze_value v.value in
if new_t != t && t != Magic_t then errt t new_t v.pos;
2022-12-09 14:14:33 +01:00
Val v2, new_t
2022-12-08 19:55:22 +01:00
| Syntax.Var v ->
if not (Env.mem v.name env)
then raise (SemanticsError ("Unbound variable \"" ^ v.name ^ "\"", v.pos));
2022-12-08 19:55:22 +01:00
if List.mem v.name ua then warn ("Unassigned variable \"" ^ v.name ^ "\"") v.pos;
2022-12-09 14:14:33 +01:00
let new_t = Env.find v.name env in
if new_t != t then errt t new_t v.pos;
Var v.name, new_t
2022-12-09 14:45:59 +01:00
| Syntax.Call c ->
(match Env.find c.func env with
| Func_t (ret_t, tl) ->
2022-12-10 16:49:51 +01:00
if ret_t != t && t != Magic_t then errt ret_t t c.pos;
2022-12-10 16:11:37 +01:00
if List.length tl != List.length c.args
then
raise
(SemanticsError
( Printf.sprintf
2022-12-11 02:37:07 +01:00
"Function \"%s\" expects %d arguments but %d was given"
c.func
2022-12-10 16:11:37 +01:00
(List.length tl)
(List.length c.args)
, c.pos ));
2022-12-11 02:37:07 +01:00
let args =
List.map2
(fun t e ->
let e2, t2 = analyze_expr env ua t e in
if t2 = t
then e2
else
errt
t
t2
(match e with
| Syntax.Val v -> v.pos
| Syntax.Var v -> v.pos
| Syntax.Call c -> c.pos))
tl
c.args
in
Call (c.func, args), ret_t
| _ -> raise (SemanticsError ("\"" ^ c.func ^ "\" isn't a function", c.pos)))
2022-12-08 19:55:22 +01:00
;;
let rec analyze_instr env ua ret_t = function
2022-12-08 19:55:22 +01:00
| Syntax.Decl d -> Decl d.name, Env.add d.name d.type_t env, [ d.name ] @ ua
| Syntax.Assign a ->
if not (Env.mem a.var env)
then raise (SemanticsError ("Unbound variable \"" ^ a.var ^ "\"", a.pos));
2022-12-08 19:55:22 +01:00
let ae, et = analyze_expr env ua (Env.find a.var env) a.expr in
Assign (a.var, ae), env, List.filter (fun x -> x <> a.var) ua
| Syntax.Do d ->
2022-12-10 16:49:51 +01:00
let ae, _ = analyze_expr env ua Magic_t d.expr in
Do ae, env, []
| Syntax.Cond c ->
let cond, _ = analyze_expr env ua Bool_t c.expr in
let if_b, _ = analyze_block env ua Magic_t c.pos c.if_b in
let else_b, _ = analyze_block env ua Magic_t c.pos c.else_b in
Cond (cond, if_b, else_b), env, []
2022-12-13 17:10:14 +01:00
| Syntax.Loop l ->
let cond, _ = analyze_expr env ua Bool_t l.expr in
let block, _ = analyze_block env ua Magic_t l.pos l.block in
Loop (cond, block), env, []
2022-12-09 14:14:33 +01:00
| Syntax.Return r ->
2022-12-10 16:21:26 +01:00
let ae, _ = analyze_expr env ua ret_t r.expr in
2022-12-09 14:14:33 +01:00
Return ae, env, []
2022-12-06 20:39:15 +01:00
and analyze_block env ua ret_t pos = function
2022-12-10 16:36:41 +01:00
| [] ->
if ret_t != Void_t && ret_t != Magic_t
then warn "Non-void function without return" pos;
2022-12-10 16:36:41 +01:00
[], ua
2022-12-08 19:55:22 +01:00
| instr :: new_block ->
2022-12-10 16:21:26 +01:00
let new_instr, new_env, ua1 = analyze_instr env ua ret_t instr in
2022-12-10 16:28:12 +01:00
(match new_instr with
| Return _ -> [ new_instr ], ua1
| _ ->
2022-12-10 16:36:41 +01:00
let new_block, ua2 = analyze_block new_env ua1 ret_t pos new_block in
2022-12-10 16:28:12 +01:00
new_instr :: new_block, ua2)
2022-12-08 19:55:22 +01:00
;;
let analyze_func env ua = function
2022-12-10 13:49:05 +01:00
| Syntax.Func f ->
2022-12-10 14:57:21 +01:00
let rec add_args env = function
| [] -> env
| h :: t ->
(match h with
| Syntax.Arg a -> add_args (Env.add a.name a.type_t env) t)
in
2022-12-10 16:36:41 +01:00
let block, _ = analyze_block (add_args env f.args) ua f.type_t f.pos f.code in
2022-12-10 14:57:21 +01:00
( Func
( f.func
, List.map
(fun a ->
match a with
| Syntax.Arg a -> a.name)
f.args
, block )
, Env.add
f.func
(Func_t
( f.type_t
, List.map
(fun a ->
match a with
| Syntax.Arg a -> a.type_t)
f.args ))
env )
;;
2022-12-08 19:55:22 +01:00
2022-12-10 15:39:18 +01:00
let rec analyze_prog env ua b default = function
| [] ->
if b
then []
else raise (SemanticsError ("No " ^ default ^ " function", Lexing.dummy_pos))
2022-12-10 14:57:21 +01:00
| fn :: suite ->
let fn, new_env = analyze_func env ua fn in
2022-12-10 15:39:18 +01:00
fn :: analyze_prog new_env ua (if b then b else Env.mem default new_env) default suite
2022-12-08 19:55:22 +01:00
;;
2022-12-10 15:39:18 +01:00
let analyze parsed = analyze_prog _types_ [] false "main" parsed