From a18db587efc2ef981938a899bdcaa0e1510d5ca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=A0s?= Date: Mon, 20 Mar 2023 10:38:10 +0100 Subject: [PATCH 01/12] Add Authors in README.md --- README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index bb2bf86..3d5f79e 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,18 @@ > Compilateur du langage Postscript en Ocaml -## Author +## Authors + +👤 **Laurian DUFRECHOU** + +* Github: [@Laurian-Dufrechou](https://github.com/Laurian-Dufrechou) + +👤 **Gaël BRUGUES** + +* Github: [@Gagl08](https://github.com/Gagl08) 👤 **Lucas VABRE** * Github: [@LucasVbr](https://github.com/LucasVbr) * LinkedIn: [@lucasvbr](https://linkedin.com/in/lucasvbr) -## Show your support - -Give a ⭐️ if this project helped you! From 6d9246c4207ada2cd97e54fdcfb4521972f2161d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=A0s?= Date: Mon, 3 Apr 2023 10:19:54 +0200 Subject: [PATCH 02/12] Debut de typage --- src/Makefile | 10 ++-- src/typing.ml | 123 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 108 insertions(+), 25 deletions(-) diff --git a/src/Makefile b/src/Makefile index 5c4c317..97ef93f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,5 +1,5 @@ -# Import lib + compile + clean folder -all: lib comp clean +# Import lib + compile +all: lib comp # Compilation of Ocaml files # Attention: order of object files important @@ -51,10 +51,14 @@ parser.cmo: parser.ml parser.cmi lang.cmo .PHONY: clean -### Import files from /lib +### Import files from /lib (temporarly) lib: cp ../lib/* ./ ## Remove compiled modules and lib clean: rm -f lexer.ml parser.ml *.mli *.cmi *.cmo + +## Run tests +tests: + ./comp ./../tests/rectangles.c ./../tests/out/rectangles.ps \ No newline at end of file diff --git a/src/typing.ml b/src/typing.ml index a47fb87..992cec0 100644 --- a/src/typing.ml +++ b/src/typing.ml @@ -8,31 +8,110 @@ type environment = { funbind: fundecl list } -let find_var (var: vname) (env: environment) = - let rec aux local_vars = - match local_vars with - | [] -> failwith "Variable inconnue" - | tete::reste -> - let (name, _) = tete in - if name = var - then tete - else aux reste - in aux (env.localvars) +(* Recherche dans l'environement *) +type 'a option = None| Some of 'a;; + +let lookup_env (name: vname) (env: environment) = + let rec aux = function + | [] -> None + | (k, v)::reste -> + if k = name then Some(v) + else aux(reste) + in aux(env.localvars) ;; -(* let rec tp_expr (expression: expr) (env: environment) = +(* Ajoute dans l'environement *) +let rec add_env (key, valeur) env = + let paire = (key, valeur) + in {localvars: paire::(env.localvars); funbind: (env.funbind)} +;; + +(* Enlève de l'environement *) +let rec remove_env key env = + let aux (liste) = + match liste with + | [] -> [] + | (k, v)::reste when k = key -> remove_assoc key reste + | a::reste -> a::(remove_assoc key reste) + in { + localvars: (aux(env.localvars)); + funbind: (env.funbind) + } +;; + +(* Typage d'une expression *) +let rec tp_expr (env: environment) (expression: expr) = match expression with - | Const(const) -> - match const with - | BoolV(_) -> BoolT - | FloatV(_) -> FloatT - | IntV(_) -> IntT - | LitV(_) -> LitT - | StringV(_) -> StringT - | VarE(var) -> tp_expr (find_var var env) env - | BinOp(op, expr1, expr2) -> - | CondE(expr1, expr2, expr3) -> - | CallE(functionName, exprList) -> *) + | Const(const) -> ( + match const with + | BoolV _ -> BoolT + | FloatV _ -> FloatT + | IntV _ -> IntT + | LitV _ -> LitT + | StringV _ -> StringT + ) + | VarE(var) -> ( + let var_value = (lookup_env var env) in + match var_value with + | Some(value) -> value + | None -> raise (Failure "Unknown var") + ) + | BinOp(op, expr1, expr2) -> + let tp_expr1 = tp_expr env expr1 + and tp_expr2 = tp_expr env expr2 in + if tp_expr1 = tp_expr2 + then match op with + | BArith(barith) -> ( + match barith with + | BAadd -> IntT + | BAsub -> IntT + | BAmul -> IntT + | BAdiv -> IntT + | BAmod -> IntT + | BAfadd -> FloatT + | BAfsub -> FloatT + | BAfmul -> FloatT + | BAfdiv -> FloatT + ) + | BBool(_) -> BoolT + | BCompar(_) -> BoolT + else raise (Failure "Invalid type of Binary operation") + | CondE(expr1, expr2, expr3) -> + let tp_expr1 = tp_expr env expr1 + and tp_expr2 = tp_expr env expr2 + and tp_expr3 = tp_expr env expr3 + in if tp_expr1 = BoolT && tp_expr2 = tp_expr3 + then tp_expr2 + else raise (Failure "Invalid type of Conditionnal Expression") + | CallE(name, list_expr) -> VoidT (* TODO *) +;; + + +let rec tp_cmd (env: environment) (cmd: com) = + match cmd with + | Skip -> VoidT + | Exit -> VoidT + | Assign(name, expr) -> VoidT (* TODO ajouter dans env *) + | Seq(cmd1, cmd2) -> + let tp_cmd1 = (tp_cmd env cmd1) + and tp_cmd2 = (tp_cmd env cmd2) + in if tp_cmd1 = Void + then tp_cmd2 + else raise (Failure "Invalid type Sequence") + | CondC(expr1, cmd1, cmd2) -> + let tp_expr1 = tp_expr env expr1 + and tp_cmd1 = tp_cmd env cmd1 + and tp_cmd2 = tp_cmd env cmd2 + in + if tp_expr1 = BoolT && tp_cmd1 = tp_cmd2 + then tp_cmd1 + else raise (Failure "Invalid type of Conditionnal Command") + | Loop(cmd1) -> + let _ = (tp_cmd env cmd1) + in VoidT + | CallC(name, list_expr) -> VoidT (* TODO Faire l'appel *) + | Return(expr) -> (tp_expr env expr) + ;; let tp_prog (Prog (fundecls, fundefns)) = true \ No newline at end of file From 820bd83f66413aed10c3c65b3c815b13c3ede14d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=A0s?= Date: Thu, 6 Apr 2023 18:46:58 +0200 Subject: [PATCH 03/12] fix(typing): complete and test `tp_expr` --- src/typing.ml | 177 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 137 insertions(+), 40 deletions(-) diff --git a/src/typing.ml b/src/typing.ml index 992cec0..2802071 100644 --- a/src/typing.ml +++ b/src/typing.ml @@ -1,17 +1,17 @@ (* Typechecking of source programs *) -open Lang +open Lang;; (* Environments *) type environment = { localvars: (vname * tp) list; funbind: fundecl list -} +};; (* Recherche dans l'environement *) type 'a option = None| Some of 'a;; -let lookup_env (name: vname) (env: environment) = +let findEnv_var (name: vname) (env: environment) = let rec aux = function | [] -> None | (k, v)::reste -> @@ -19,27 +19,32 @@ let lookup_env (name: vname) (env: environment) = else aux(reste) in aux(env.localvars) ;; +(* val findEnv_var : + Lang.vname -> environment + -> Lang.tp option = +*) -(* Ajoute dans l'environement *) -let rec add_env (key, valeur) env = - let paire = (key, valeur) - in {localvars: paire::(env.localvars); funbind: (env.funbind)} +let findEnv_fun (name: fname) (env: environment) = + let rec aux = function + | [] -> None + | Fundecl(tp, fname, vars)::reste -> + let f = (tp, fname, vars) in + if fname = name then Some(f) + else aux(reste) + in aux(env.funbind) ;; +(* val findEnv_fun : + Lang.fname -> environment + -> (Lang.tp * Lang.fname * Lang.vardecl list) option = +*) -(* Enlève de l'environement *) -let rec remove_env key env = - let aux (liste) = - match liste with - | [] -> [] - | (k, v)::reste when k = key -> remove_assoc key reste - | a::reste -> a::(remove_assoc key reste) - in { - localvars: (aux(env.localvars)); - funbind: (env.funbind) - } +let tp_vardecl (vdecl: vardecl) = + let Vardecl(vdecl_tp, _) = vdecl + in vdecl_tp ;; +(* val tp_vardecl : Lang.vardecl -> Lang.tp = *) -(* Typage d'une expression *) +(* ----- Typage d'une expression ----- *) let rec tp_expr (env: environment) (expression: expr) = match expression with | Const(const) -> ( @@ -51,7 +56,7 @@ let rec tp_expr (env: environment) (expression: expr) = | StringV _ -> StringT ) | VarE(var) -> ( - let var_value = (lookup_env var env) in + let var_value = (findEnv_var var env) in match var_value with | Some(value) -> value | None -> raise (Failure "Unknown var") @@ -60,21 +65,26 @@ let rec tp_expr (env: environment) (expression: expr) = let tp_expr1 = tp_expr env expr1 and tp_expr2 = tp_expr env expr2 in if tp_expr1 = tp_expr2 - then match op with - | BArith(barith) -> ( - match barith with - | BAadd -> IntT - | BAsub -> IntT - | BAmul -> IntT - | BAdiv -> IntT - | BAmod -> IntT - | BAfadd -> FloatT - | BAfsub -> FloatT - | BAfmul -> FloatT - | BAfdiv -> FloatT + then ( + match op with + | BArith(barith) -> ( + match barith with + | BAadd -> IntT + | BAsub -> IntT + | BAmul -> IntT + | BAdiv -> IntT + | BAmod -> IntT + | BAfadd -> FloatT + | BAfsub -> FloatT + | BAfmul -> FloatT + | BAfdiv -> FloatT + ) + | BBool(_) -> + if tp_expr1 = BoolT && tp_expr2 = BoolT + then BoolT + else raise (Failure "Invalid Boolean operation") + | BCompar(_) -> BoolT ) - | BBool(_) -> BoolT - | BCompar(_) -> BoolT else raise (Failure "Invalid type of Binary operation") | CondE(expr1, expr2, expr3) -> let tp_expr1 = tp_expr env expr1 @@ -83,10 +93,95 @@ let rec tp_expr (env: environment) (expression: expr) = in if tp_expr1 = BoolT && tp_expr2 = tp_expr3 then tp_expr2 else raise (Failure "Invalid type of Conditionnal Expression") - | CallE(name, list_expr) -> VoidT (* TODO *) + | CallE(name, list_expr) -> + match (findEnv_fun name env) with + | Some(func) -> ( + let (func_tp, func_name, func_list_vardecl) = func in + if (List.map (tp_expr env) list_expr) = (List.map tp_vardecl func_list_vardecl) + then func_tp + else raise (Failure "Invalid arguments") + ) + | None -> raise (Failure "Unknown function in the environment") ;; - +(* val tp_expr : + environment -> Lang.expr + -> Lang.tp = +*) +(* - tp_expr: TESTS - *) +let test_tp_expr_const = + let function_to_test = tp_expr { + localvars=[ + ("i", IntT); + ("f", FloatT); + ("b", BoolT); + ("l", LitT); + ("s", StringT); + ]; + funbind=[ + Fundecl(BoolT, "fun1", [Vardecl(IntT, "a"); Vardecl(FloatT, "b")]) + ] + } + and input_values = [ + Const(BoolV(true)); + Const(FloatV(10.98)); + Const(IntV(10)); + Const(LitV("l")); + Const(StringV("Hello")); + + VarE("b"); + VarE("f"); + VarE("i"); + VarE("l"); + VarE("s"); + + BinOp(BArith(BAadd), Const(IntV(5)), VarE("i")); + BinOp(BArith(BAsub), Const(IntV(5)), VarE("i")); + BinOp(BArith(BAmul), Const(IntV(5)), VarE("i")); + BinOp(BArith(BAdiv), Const(IntV(5)), VarE("i")); + BinOp(BArith(BAmod), Const(IntV(5)), VarE("i")); + + BinOp(BArith(BAfadd), Const(FloatV(5.)), VarE("f")); + BinOp(BArith(BAfsub), Const(FloatV(5.)), VarE("f")); + BinOp(BArith(BAfmul), Const(FloatV(5.)), VarE("f")); + BinOp(BArith(BAfdiv), Const(FloatV(5.)), VarE("f")); + + BinOp(BCompar(BCeq), VarE("i"), VarE("i")); + BinOp(BCompar(BCge), VarE("i"), VarE("i")); + BinOp(BCompar(BCgt), VarE("i"), VarE("i")); + BinOp(BCompar(BCle), VarE("i"), VarE("i")); + BinOp(BCompar(BClt), VarE("i"), VarE("i")); + BinOp(BCompar(BCne), VarE("i"), VarE("i")); + + BinOp(BBool(BBand), VarE("b"), VarE("b")); + BinOp(BBool(BBor), VarE("b"), VarE("b")); + + (* (4 >= 5) ? 7 : 8 -> IntT *) + CondE( + BinOp(BCompar(BCge), Const(IntV(4)), Const(IntV(5))), + Const(IntV(7)), + Const(IntV(8)) + ); + + CallE("fun1", [VarE("i"); VarE("f")]); + (* CallE("fun2", [VarE("i"); VarE("f")]); *) + (* CallE("fun1", [VarE("b"); VarE("f")]); *) + ] and expected_result = [ + BoolT; FloatT; IntT; LitT; StringT; + BoolT; FloatT; IntT; LitT; StringT; + IntT; IntT; IntT; IntT; IntT; + FloatT; FloatT; FloatT; FloatT; + BoolT; BoolT; BoolT; BoolT; BoolT; BoolT; + BoolT; BoolT; + + IntT; + BoolT; + ] in + try ((List.map function_to_test input_values) = expected_result) with + _ -> false +;; + +(* ----- Typage d'une commande ----- *) let rec tp_cmd (env: environment) (cmd: com) = match cmd with | Skip -> VoidT @@ -95,7 +190,7 @@ let rec tp_cmd (env: environment) (cmd: com) = | Seq(cmd1, cmd2) -> let tp_cmd1 = (tp_cmd env cmd1) and tp_cmd2 = (tp_cmd env cmd2) - in if tp_cmd1 = Void + in if tp_cmd1 = VoidT then tp_cmd2 else raise (Failure "Invalid type Sequence") | CondC(expr1, cmd1, cmd2) -> @@ -107,11 +202,13 @@ let rec tp_cmd (env: environment) (cmd: com) = then tp_cmd1 else raise (Failure "Invalid type of Conditionnal Command") | Loop(cmd1) -> - let _ = (tp_cmd env cmd1) - in VoidT + let _ = (tp_cmd env cmd1) in VoidT | CallC(name, list_expr) -> VoidT (* TODO Faire l'appel *) | Return(expr) -> (tp_expr env expr) ;; -let tp_prog (Prog (fundecls, fundefns)) = true \ No newline at end of file +(* let tp_fundefn fundefns = ;; *) +(* let tp_stmt fundecls = ;; *) + +let tp_prog (Prog (fundecls, fundefns)) = true;; (* try (tp_fundefn fundefns) && (tp_stmt fundecls) with _ -> false *) \ No newline at end of file From 244e2b4b6df669389fe9fe9669530be59e9f63da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=A0s?= Date: Thu, 6 Apr 2023 19:17:08 +0200 Subject: [PATCH 04/12] fix: edit name of test function of expressions --- src/typing.ml | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/typing.ml b/src/typing.ml index 2802071..bd4e3a7 100644 --- a/src/typing.ml +++ b/src/typing.ml @@ -109,7 +109,7 @@ let rec tp_expr (env: environment) (expression: expr) = *) (* - tp_expr: TESTS - *) -let test_tp_expr_const = +let test_tp_expr = let function_to_test = tp_expr { localvars=[ ("i", IntT); @@ -186,7 +186,7 @@ let rec tp_cmd (env: environment) (cmd: com) = match cmd with | Skip -> VoidT | Exit -> VoidT - | Assign(name, expr) -> VoidT (* TODO ajouter dans env *) + | Assign(name, expr) -> VoidT | Seq(cmd1, cmd2) -> let tp_cmd1 = (tp_cmd env cmd1) and tp_cmd2 = (tp_cmd env cmd2) @@ -205,7 +205,26 @@ let rec tp_cmd (env: environment) (cmd: com) = let _ = (tp_cmd env cmd1) in VoidT | CallC(name, list_expr) -> VoidT (* TODO Faire l'appel *) | Return(expr) -> (tp_expr env expr) - +;; + +(* - tp_cmd: TESTS - *) +let test_tp_cmd = + let function_to_test = tp_cmd { + localvars=[ + ("i", IntT); + ("f", FloatT); + ("b", BoolT); + ("l", LitT); + ("s", StringT); + ]; + funbind=[ + Fundecl(BoolT, "fun1", [Vardecl(IntT, "a"); Vardecl(FloatT, "b")]) + ] + } + and input_values = [] + and expected_result = [] in + try ((List.map function_to_test input_values) = expected_result) with + _ -> false ;; (* let tp_fundefn fundefns = ;; *) From 5985f75d7b9f595bdd7626bf4f24fc3b6ed0bc3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=A0s?= Date: Thu, 6 Apr 2023 21:30:49 +0200 Subject: [PATCH 05/12] feat(typing): Function and tests of commands --- src/typing.ml | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/src/typing.ml b/src/typing.ml index bd4e3a7..d5abb87 100644 --- a/src/typing.ml +++ b/src/typing.ml @@ -177,8 +177,7 @@ let test_tp_expr = IntT; BoolT; ] in - try ((List.map function_to_test input_values) = expected_result) with - _ -> false + (List.map function_to_test input_values) = expected_result ;; (* ----- Typage d'une commande ----- *) @@ -203,9 +202,13 @@ let rec tp_cmd (env: environment) (cmd: com) = else raise (Failure "Invalid type of Conditionnal Command") | Loop(cmd1) -> let _ = (tp_cmd env cmd1) in VoidT - | CallC(name, list_expr) -> VoidT (* TODO Faire l'appel *) + | CallC(name, list_expr) -> tp_expr env (CallE(name, list_expr)) (* TODO => Question: Il faut renvoyer le type ??? *) | Return(expr) -> (tp_expr env expr) ;; +(* val tp_cmd : + environment -> Lang.com + -> Lang.tp = +*) (* - tp_cmd: TESTS - *) let test_tp_cmd = @@ -213,18 +216,38 @@ let test_tp_cmd = localvars=[ ("i", IntT); ("f", FloatT); - ("b", BoolT); - ("l", LitT); - ("s", StringT); ]; funbind=[ Fundecl(BoolT, "fun1", [Vardecl(IntT, "a"); Vardecl(FloatT, "b")]) ] } - and input_values = [] - and expected_result = [] in - try ((List.map function_to_test input_values) = expected_result) with - _ -> false + and input_values = [ + Skip; + Exit; + Assign("test", Const(IntV(5))); + Seq(Skip, Exit); + Seq(Skip, Return(Const(FloatV(5.)))); + + CondC( + BinOp(BCompar(BCge), Const(IntV(4)), Const(IntV(5))), + Skip, Skip + ); + Loop(Exit); + + CallC("fun1", [VarE("i"); VarE("f")]); + Return(Const(IntV(5))); + ] + and expected_result = [ + VoidT; + VoidT; + VoidT; + VoidT; FloatT; + VoidT; + VoidT; + BoolT; + IntT; + ] in + (List.map function_to_test input_values) = expected_result ;; (* let tp_fundefn fundefns = ;; *) From add79589f0c567a2203402135015381dc7faad1d Mon Sep 17 00:00:00 2001 From: Laurian-Dufrechou Date: Thu, 6 Apr 2023 22:59:20 +0200 Subject: [PATCH 06/12] feat(Parser and Lexer): Added Parser.mly and Lexer.mll --- src/parser_laurian/Tests/progsimple.c | 12 ++ src/parser_laurian/lang.ml | 64 ++++++++ src/parser_laurian/lexer.mll | 94 ++++++++++++ src/parser_laurian/parser.mly | 203 ++++++++++++++++++++++++++ 4 files changed, 373 insertions(+) create mode 100644 src/parser_laurian/Tests/progsimple.c create mode 100644 src/parser_laurian/lang.ml create mode 100644 src/parser_laurian/lexer.mll create mode 100644 src/parser_laurian/parser.mly diff --git a/src/parser_laurian/Tests/progsimple.c b/src/parser_laurian/Tests/progsimple.c new file mode 100644 index 0000000..edf793e --- /dev/null +++ b/src/parser_laurian/Tests/progsimple.c @@ -0,0 +1,12 @@ +void main (string y, int x) { + x = 15; + while (x < 20) { + x = x + 1; + y = "hello"; + if (x == 17) { + y = "world"; + } + /* */ + } + return x; +} diff --git a/src/parser_laurian/lang.ml b/src/parser_laurian/lang.ml new file mode 100644 index 0000000..c3791aa --- /dev/null +++ b/src/parser_laurian/lang.ml @@ -0,0 +1,64 @@ +(* Definition of source language data structures *) + +(* variable names *) +type vname = string + +(* function names *) +type fname = string + +(* binary arithmetic operators *) +type barith = BAadd | BAsub | BAmul | BAdiv | BAmod (* integer *) + | BAfadd | BAfsub | BAfmul | BAfdiv (* float *) + +(* binary boolean operators: and, or *) +type bbool = BBand | BBor + +(* binary comparison operators: =, >=, >, <=, <, != *) +type bcompar = BCeq | BCge | BCgt | BCle | BClt | BCne + +(* binary operators, combining all of the above *) +type binop = + BArith of barith +| BBool of bbool +| BCompar of bcompar + +type value = + BoolV of bool +| FloatV of float +| IntV of int +| LitV of string +| StringV of string + +(* Expresssions *) +type expr = + Const of value (* constant *) + | VarE of vname (* variable *) + | BinOp of binop * expr * expr (* binary operation *) + | CondE of expr * expr * expr (* conditional expr *) + | CallE of fname * (expr list) (* call expression *) + +(* Commands *) +type com = + Skip (* no operation *) + | Exit (* exit from loop *) + | Assign of vname * expr (* assign expression to var *) + | Seq of com * com (* sequence of statements *) + | CondC of expr * com * com (* conditional com *) + | Loop of com (* loop until exit *) + | CallC of fname * (expr list) (* call statement *) + | Return of expr (* return from call *) + +(* Types *) +type tp = BoolT | FloatT | IntT | LitT | StringT | VoidT + +(* variable / parameter declaration *) +type vardecl = Vardecl of tp * vname + +(* function declaration: return type; parameter declarations *) +type fundecl = Fundecl of tp * fname * (vardecl list) + +(* function definition: function declaration; function body *) +type fundefn = Fundefn of fundecl * com + +type prog = Prog of (fundecl list) * (fundefn list) + diff --git a/src/parser_laurian/lexer.mll b/src/parser_laurian/lexer.mll new file mode 100644 index 0000000..a1bf9f4 --- /dev/null +++ b/src/parser_laurian/lexer.mll @@ -0,0 +1,94 @@ +{ + open Lexing + open Parser + open Lang + exception Lexerror + + let pos lexbuf = (lexeme_start lexbuf, lexeme_end lexbuf) + + let advance_line_pos pos = + { pos with pos_lnum = pos.pos_lnum + 1; pos_bol = pos.pos_cnum; } + + let advance_line lexbuf = + lexbuf.lex_curr_p <- advance_line_pos lexbuf.lex_curr_p + +} + +let includeline = '#' [^ '\n']* '\n' +let num = ['1'-'9']['0'-'9']* +let num_virgule = ['1'-'9']['0'-'9']*'.'(['1'-'9']['0'-'9']*)? +let alph = ['a'-'z''A'-'Z'] +let literal = '/'alph(alph|'-')* +let str = '\"'alph(alph|'-'|'_'|num)*'\"' +let blancs = [' ''\t']+ +let comment = '/' '*' (blancs|alph|num|num_virgule|'>'|'<')* '*' '/' + +rule token = parse + blancs + { token lexbuf } (* white space: recursive call of lexer *) +|'\n' + {advance_line lexbuf; token lexbuf } (* white space: recursive call of lexer *) +| includeline + { advance_line lexbuf; token lexbuf } (* C include directives --> ignore *) +| comment + { token lexbuf } (* comment --> ignore *) + + +| "int" {TP(IntT)} +| "bool" {TP(BoolT)} +| "string" {TP(StringT)} +| "float" {TP(FloatT)} +| "void" {TP(VoidT)} +| "lit" {TP(LitT)} (* Potentiellement list *) + +| '(' { LPAREN } +| ')' { RPAREN } +| '{' { LBRACE } +| '}' { RBRACE } +| "==" { BCEQ } +| '=' { EQ } +| '+' { PLUS } +| '-' { MINUS } +| '*' { TIMES } +| '/' { DIV } +| '%' { MOD } +| '/' { DIV } +| "<=" { BCLE } +| ">=" { BCGE } +| ">" { BCGT } +| "<" { BCLT } +| "!=" { BCNE } +| "and" {BLAND} +| "or" {BLOR} +| "," {COMMA} +| ";" {SEMICOLON} +| ":" {COLON} +| "?" {QMARK} + + +| "return" {RETURN} + +| "if" {IF} +| "else" {ELSE} +| "while" {WHILE} +| "for" {FOR} + +| "true" {BCONSTANT(true)} +| "false" {BCONSTANT(false)} +| num_virgule as s {FLOATCONSTANT(float_of_string s)} +| num as s {INTCONSTANT(int_of_string s)} +| literal as l { LITCONSTANT l } +| str as s { STRINGCONSTANT s } + + +| eof {EOF} + +| alph alph* as i {IDENTIFIER i} + +| _ {Printf.printf "ERROR: unrecogized symbol '%s'\n" (Lexing.lexeme lexbuf); + raise Lexerror } + +and + ruleTail acc = parse +| eof { acc } +| _* as str { ruleTail (acc ^ str) lexbuf } diff --git a/src/parser_laurian/parser.mly b/src/parser_laurian/parser.mly new file mode 100644 index 0000000..fc1b2a9 --- /dev/null +++ b/src/parser_laurian/parser.mly @@ -0,0 +1,203 @@ +%{ +open Lang +%} + +%token IDENTIFIER +%token LITCONSTANT +%token STRINGCONSTANT +%token TP +%token BCONSTANT +%token INTCONSTANT +%token FLOATCONSTANT +%token PLUS MINUS TIMES DIV MOD FPLUS FMINUS FTIMES FDIV +%token LPAREN RPAREN LBRACE RBRACE +%token EQ COMMA SEMICOLON COLON QMARK +%token IF ELSE WHILE FOR RETURN BCEQ BCGE BCGT BCLE BCLT BCNE BLAND BLOR +%token EOF + +%left BLOR +%left BLAND +%left BCEQ BCNE +%left BCGE BCGT BCLE BCLT +%left PLUS MINUS FPLUS FMINUS +%left TIMES DIV FDIV FTIMES MOD +%left LPAREN RPAREN LBRACE RBRACE + +%right IF ELSE +%right WHILE FOR +%right RETURN + +%start start +%type start + +%% + +start: fundefn { Prog ([], [$1]) } + ; + +fundefn: /* Compound-statement dans la doc --> 6.8.2 */ + /* d'apres la doc, on peut lui mettre --> LBRACE RBRACE {Skip} */ + |fundecl LBRACE block_item_list_opt RBRACE { Fundefn($1, $3) } + // |fundecl LBRACE statement RBRACE { Fundefn($1, $3) } + +; + +fundecl: TP IDENTIFIER LPAREN vardecl_comma_list_opt RPAREN + { Fundecl($1, $2, $4) } +; + +vardecl_comma_list_opt: + |TP IDENTIFIER COMMA vardecl_comma_list_opt {[Vardecl($1, $2)] @ $4} /* dans celle là c'est récursif*/ + |TP IDENTIFIER {[Vardecl($1, $2)]} + |/* empty */{ [] } +; + + +constant: + |LITCONSTANT{LitV($1) } + |STRINGCONSTANT {StringV($1) } + |BCONSTANT {BoolV($1) } + |INTCONSTANT {IntV($1) } + |FLOATCONSTANT {FloatV($1) } +; + +/*expression_opt: + |{Skip} + |expression {$1} +; +*/ + +expression: /* A.2.1 ---> 6.5.1 */ + |constant {Const($1)} + |IDENTIFIER {VarE($1)} + |LPAREN expression RPAREN {$2} + |multiplicative_expression {$1} + |additive_expression {$1} + |relational_expression {$1} + |equality_expression {$1} + |logical_and_expression {$1} + |conditional_expression {$1} +; + +/*les calculs*/ +multiplicative_expression: /* 6.5.5 */ + |expression TIMES expression {BinOp(BArith(BAmul), $1, $3)} + |expression FTIMES expression {BinOp(BArith(BAfmul), $1, $3)} + |expression DIV expression {BinOp(BArith(BAdiv), $1, $3)} + |expression FDIV expression {BinOp(BArith(BAfdiv), $1, $3)} + |expression MOD expression {BinOp(BArith(BAmod), $1, $3)} +; + +additive_expression: /* 6.5.6 */ + |expression PLUS expression {BinOp(BArith(BAadd), $1, $3)} + |expression MINUS expression {BinOp(BArith(BAsub), $1, $3)} + |expression FPLUS expression {BinOp(BArith(BAfadd), $1, $3)} + |expression FMINUS expression {BinOp(BArith(BAfsub), $1, $3)} +; + +/*les comparaisons*/ +relational_expression: /* 6.5.8 */ + |expression BCLE expression {BinOp(BCompar(BCle), $1, $3)} + |expression BCGE expression {BinOp(BCompar(BCge), $1, $3)} + |expression BCGT expression {BinOp(BCompar(BCgt), $1, $3)} + |expression BCLT expression {BinOp(BCompar(BClt), $1, $3)} +; +equality_expression: /* 6.5.9 */ + |expression BCEQ expression {BinOp(BCompar(BCeq), $1, $3)} + |expression BCNE expression {BinOp(BCompar(BCne), $1, $3)} +; + +/*les operateurs booleens */ +logical_and_expression: + |expression BLAND expression {BinOp(BBool(BBand), $1, $3)} /* 6.5.13 */ + |expression BLOR expression {BinOp(BBool(BBor), $1, $3)} /* 6.5.14 */ +; + + +conditional_expression: /* 6.5.16 */ + |expression QMARK expression COLON expression {CondE($1, $3, $5)} +; + + +/*///////////// FIN DES EXPRESSIONS ///////////////////*/ + +/*///////////// DEBUT DES STATEMENTS //////////////////*/ + +statement: /* A.2.3 ----> 6.8 */ + |LBRACE block_item_list_opt RBRACE {$2} /* peut etre fundefn plutot vu que c'est le vrai compound_statement*/ + |select_statement {$1} /*if et else*/ + |iteration_statement {$1} /*while et for*/ + |jump_statement SEMICOLON {$1} /*return et break*/ + |assignation SEMICOLON {$1} + // Faut faire l'appel à des foncttions avec CondC( fname * (expr_list ) ) +; + +block_item_list_opt: /* 6.8.2 */ + |statement {$1} + |block_item_list_opt statement {Seq($1,$2)} /* pas sur du tout */ + | {Skip} +; + + + +block_item: /* 6.8.2 */ + /* declaration de variable / function (A.2.2 dans la doc) */ + |statement {$1} +; + + +select_statement: /* 6.8.4 */ + |IF LPAREN expression RPAREN statement {CondC ($3, $5, Skip) } + |IF LPAREN expression RPAREN statement ELSE statement {CondC ($3, $5, $7) } +; + +iteration_statement: /* 6.8.5 */ + |WHILE LPAREN expression RPAREN statement {Loop (Seq (CondC ( $3, Skip, Exit), $5))} + /*|FOR LPAREN expression_opt SEMICOLON expression_opt SEMICOLON expression_opt RPAREN statement {Loop (Seq (CondC ( $5, Skip, Exit), $9))} */ /*Absolument pas sur*/ +; + +jump_statement: /* 6.8.6 */ + |RETURN expression {Return($2)} +; + +assignation: /* 6.5.17 */ /* dans la doc ça fait parti des expressions mais pg */ + |IDENTIFIER EQ expression {Assign($1, $3)} +; + + + +/* + Dans ce qu'il y a marqué dans lang.ml, il manque + + expr : CallE of fname * (expr list) ( call expression ) + + et + + com : CallC of fname * (expr list) ( call statement ) +*/ + + + +/* + Demander au prof : + + + ---Comment on différencie "==" et "=" + + ---Type LitT (peut etre list ?) + + --- Je vois pas comment déclarer une variable (utiliser Vardecl qui demande un tp * vname) + qui renvoie un type vardecl avec Assign qui demande vname * expr ( et qui renvoie un com) + + pour pouvoir prendre en compte "int x = 15;" par exemple + + + ---Comment ça marche pour appeler une fonction ou expressionn CallE et CallC ? + + + ---|block_item_list_opt {$1} // peut etre fundefn plutot vu que c'est le vrai compound_statement + + : d'apres la doc, fundefn c'est le compound_statement, mais il a pas le optionnel + + associativité des opérateurs ? (dans le pdf TP2 : introduction à YACC, partie 4 --> développons la grammaire ---> tirer 2) +*/ From d005ec0e22d440981e5826714d3ae371d1842d07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=A0s?= Date: Thu, 6 Apr 2023 23:49:05 +0200 Subject: [PATCH 07/12] feat(typing): function definition --- src/typing.ml | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/src/typing.ml b/src/typing.ml index d5abb87..7bad263 100644 --- a/src/typing.ml +++ b/src/typing.ml @@ -38,6 +38,28 @@ let findEnv_fun (name: fname) (env: environment) = -> (Lang.tp * Lang.fname * Lang.vardecl list) option = *) +(* Ajout dans l'environnement *) +let addEnv_var (var_decl: vardecl) (env: environment) = + let Vardecl(var_decl_tp, var_decl_name) = var_decl + in { + localvars=(var_decl_name, var_decl_tp)::(env.localvars); + funbind=env.funbind +};; +(* val addEnv_var : + Lang.vardecl -> environment + -> environment = +*) + +let addEnv_fun (fun_decl: fundecl) (env: environment) = { + localvars=(env.localvars); + funbind=(fun_decl::(env.funbind)) +};; +(* val addEnv_fun : + Lang.fundecl -> environment + -> environment = +*) + +(* Typage d'une declaration de variable *) let tp_vardecl (vdecl: vardecl) = let Vardecl(vdecl_tp, _) = vdecl in vdecl_tp @@ -250,7 +272,58 @@ let test_tp_cmd = (List.map function_to_test input_values) = expected_result ;; -(* let tp_fundefn fundefns = ;; *) +(* ----- Typage d'une définition de fonction ----- *) +let rec count_same_var_name (name: string) (var_decl_list: vardecl list) = + match var_decl_list with + | [] -> 0 + | Vardecl(var_tp, var_name)::reste -> + (count_same_var_name name reste) + + if name = var_name then 1 else 0 +;; +(* val count_same_var_decl : string -> Lang.vardecl list -> int = *) + +let rec valid_vardecl_list (var_decl_list: vardecl list) = + match var_decl_list with + | [] -> true + | Vardecl(var_tp, var_name)::reste -> + if (count_same_var_name var_name reste) = 0 + then valid_vardecl_list reste + else false +;; +(* val valid_vardecl_list : Lang.vardecl list -> bool = *) + +let tp_fundefn (env: environment) (fun_def: fundefn) = + let Fundefn(fun_decl, cmd) = fun_def in + let Fundecl(fun_decl_tp,_,var_decl_list) = fun_decl in + let env1 = (addEnv_fun fun_decl env) in (* Besoin d'effacer dans l'env si recurence ? *) + let _ = tp_cmd env1 cmd + in if valid_vardecl_list var_decl_list && (tp_cmd env1 cmd) = fun_decl_tp + then fun_decl_tp + else raise (Failure "Invalid function definition") +;; +(* val tp_fundefn : + environment -> Lang.fundefn + -> Lang.tp = +*) + +(* - tp_fundefn: TESTS - *) +let test_tp_fundefn = + let function_to_test = tp_fundefn { + localvars=[]; + funbind=[] + } + and input_values = [ + Fundefn( + Fundecl(BoolT, "fun1", [Vardecl(IntT, "a"); Vardecl(FloatT, "b")]), + Return(BinOp(BCompar(BCeq), Const(IntV(4)), Const(IntV(5)))) + ) + ] + and expected_result = [ + BoolT + ] in + (List.map function_to_test input_values) = expected_result +;; + (* let tp_stmt fundecls = ;; *) let tp_prog (Prog (fundecls, fundefns)) = true;; (* try (tp_fundefn fundefns) && (tp_stmt fundecls) with _ -> false *) \ No newline at end of file From 78fd8371cbf22a19921557b128ccc476a0f61a0b Mon Sep 17 00:00:00 2001 From: Laurian-Dufrechou Date: Thu, 6 Apr 2023 23:53:48 +0200 Subject: [PATCH 08/12] docs(Makefile, interf, use): Makefile, interf, use --- src/parser_laurian/Makefile | 46 ++++++++++++++++++++++++++++++++++++ src/parser_laurian/interf.ml | 33 ++++++++++++++++++++++++++ src/parser_laurian/use.ml | 16 +++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 src/parser_laurian/Makefile create mode 100644 src/parser_laurian/interf.ml create mode 100644 src/parser_laurian/use.ml diff --git a/src/parser_laurian/Makefile b/src/parser_laurian/Makefile new file mode 100644 index 0000000..b55f18e --- /dev/null +++ b/src/parser_laurian/Makefile @@ -0,0 +1,46 @@ +all: lang.cmo parser.cmo lexer.cmo interf.cmo + +# Compilation of .ml files +lang.cmo: lang.ml + ocamlc -c $< + +# typing.cmo: typing.ml lang.cmo +# ocamlc -c $< + +# instrs.cmo: instrs.ml lang.cmo +# ocamlc -c $< + +# gen.cmo: gen.ml lang.cmo instrs.cmo typing.cmo +# ocamlc -c $< + +#interf.cmo: interf.ml lexer.cmo parser.cmo gen.cmo typing.cmo +interf.cmo: interf.ml lexer.cmo parser.cmo + ocamlc -c $< + +# comp.cmo: comp.ml gen.cmo typing.cmo parser.cmo interf.cmo +# ocamlc -c $< + +# ocaml lexer and parser + +lexer.ml: lexer.mll lang.cmo + ocamllex $< + +parser.ml parser.mli: parser.mly lang.cmo + ocamlyacc $< + +lexer.cmo: lexer.ml parser.cmo + ocamlc -c $< +parser.cmo: parser.ml parser.cmi lang.cmo + ocamlc -c $< + + +#### Generic rules + +%.cmi: %.mli + ocamlc -c $< + + +.PHONY: clean + +clean: + rm -f lexer.ml parser.ml *.mli *.cmi *.cmo diff --git a/src/parser_laurian/interf.ml b/src/parser_laurian/interf.ml new file mode 100644 index 0000000..17ca594 --- /dev/null +++ b/src/parser_laurian/interf.ml @@ -0,0 +1,33 @@ +(* Interface with parser *) + +exception ParseLexError of exn * (string * int * int * string * string) + +let parse_file infile = + let lexbuf = Lexing.from_channel (open_in infile) in + try + Parser.start Lexer.token lexbuf + with exn -> + begin + let curr = lexbuf.Lexing.lex_curr_p in + let line = curr.Lexing.pos_lnum in + let cnum = curr.Lexing.pos_cnum - curr.Lexing.pos_bol in + let tok = Lexing.lexeme lexbuf in + let tail = Lexer.ruleTail "" lexbuf in + raise (ParseLexError (exn,(infile, line,cnum,tok,tail))) + end +;; + +let print_parse_error (filename, line,cnum,tok,tail) = + print_string ("Parsing error in file: " ^ filename ^ + " on line: " ^ (string_of_int line) ^ + " column: " ^ (string_of_int cnum) ^ + " token: " ^ tok ^ + "\nrest: " ^ tail ^ "\n") +;; + +let parse infile = + try parse_file infile + with ParseLexError (e, r) -> + print_parse_error r; + failwith "Stopped execution." +;; diff --git a/src/parser_laurian/use.ml b/src/parser_laurian/use.ml new file mode 100644 index 0000000..63e5293 --- /dev/null +++ b/src/parser_laurian/use.ml @@ -0,0 +1,16 @@ + +#load "lang.cmo";; +#load "parser.cmo" ;; +#load "lexer.cmo" ;; +#load "interf.cmo";; + +open Interf;; +open Lang;; + +(* For using the parser: + +- Evaluate this file (use.ml) +- parse "Tests/progsimple.c" ;; + +*) + From 27c1366c116c888c77e4c8a35dbd7fde0d517168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=A0s?= Date: Fri, 7 Apr 2023 14:38:53 +0200 Subject: [PATCH 09/12] fix(typing): Typage de programme et creation de son environnement --- src/typing.ml | 140 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 113 insertions(+), 27 deletions(-) diff --git a/src/typing.ml b/src/typing.ml index 7bad263..f32633d 100644 --- a/src/typing.ml +++ b/src/typing.ml @@ -8,6 +8,28 @@ type environment = { funbind: fundecl list };; +(* Fonction sur les listes de declarations de variables *) +let rec count_same_var_name (name: string) (var_decl_list: vardecl list) = + match var_decl_list with + | [] -> 0 + | Vardecl(var_tp, var_name)::reste -> + (count_same_var_name name reste) + + if name = var_name then 1 else 0 +;; +(* val count_same_var_decl : string -> Lang.vardecl list -> int = *) + +let rec valid_vardecl_list (var_decl_list: vardecl list) = + match var_decl_list with + | [] -> true + | Vardecl(var_tp, var_name)::reste -> + if (count_same_var_name var_name reste) = 0 + then valid_vardecl_list reste + else false +;; +(* val valid_vardecl_list : Lang.vardecl list -> bool = *) + + + (* Recherche dans l'environement *) type 'a option = None| Some of 'a;; @@ -38,6 +60,8 @@ let findEnv_fun (name: fname) (env: environment) = -> (Lang.tp * Lang.fname * Lang.vardecl list) option = *) + + (* Ajout dans l'environnement *) let addEnv_var (var_decl: vardecl) (env: environment) = let Vardecl(var_decl_tp, var_decl_name) = var_decl @@ -59,6 +83,35 @@ let addEnv_fun (fun_decl: fundecl) (env: environment) = { -> environment = *) + + +(* Ajout dans l'environnement (récursif) *) +let rec build_env_fun (env: environment) (fun_decl_list: fundecl list) = + match fun_decl_list with + | [] -> env + | fun_decl::reste -> + let Fundecl(fun_decl_tp,_,var_decl_list) = fun_decl + in if valid_vardecl_list var_decl_list + then addEnv_fun fun_decl env + else raise (Failure "There is var declaration with the same name as arguments") +;; +(* val build_env_fun : + environment -> Lang.fundecl list + -> environment = +*) + +let rec build_env_var (env: environment) (var_decl_list: vardecl list) = + match var_decl_list with + | [] -> env + | var_decl::reste -> build_env_var (addEnv_var var_decl env) reste +;; +(* val build_env_var : + environment -> Lang.vardecl list + -> environment = +*) + + + (* Typage d'une declaration de variable *) let tp_vardecl (vdecl: vardecl) = let Vardecl(vdecl_tp, _) = vdecl @@ -66,6 +119,8 @@ let tp_vardecl (vdecl: vardecl) = ;; (* val tp_vardecl : Lang.vardecl -> Lang.tp = *) + + (* ----- Typage d'une expression ----- *) let rec tp_expr (env: environment) (expression: expr) = match expression with @@ -202,6 +257,8 @@ let test_tp_expr = (List.map function_to_test input_values) = expected_result ;; + + (* ----- Typage d'une commande ----- *) let rec tp_cmd (env: environment) (cmd: com) = match cmd with @@ -224,7 +281,7 @@ let rec tp_cmd (env: environment) (cmd: com) = else raise (Failure "Invalid type of Conditionnal Command") | Loop(cmd1) -> let _ = (tp_cmd env cmd1) in VoidT - | CallC(name, list_expr) -> tp_expr env (CallE(name, list_expr)) (* TODO => Question: Il faut renvoyer le type ??? *) + | CallC(name, list_expr) -> tp_expr env (CallE(name, list_expr)) | Return(expr) -> (tp_expr env expr) ;; (* val tp_cmd : @@ -272,34 +329,17 @@ let test_tp_cmd = (List.map function_to_test input_values) = expected_result ;; + + (* ----- Typage d'une définition de fonction ----- *) -let rec count_same_var_name (name: string) (var_decl_list: vardecl list) = - match var_decl_list with - | [] -> 0 - | Vardecl(var_tp, var_name)::reste -> - (count_same_var_name name reste) - + if name = var_name then 1 else 0 -;; -(* val count_same_var_decl : string -> Lang.vardecl list -> int = *) - -let rec valid_vardecl_list (var_decl_list: vardecl list) = - match var_decl_list with - | [] -> true - | Vardecl(var_tp, var_name)::reste -> - if (count_same_var_name var_name reste) = 0 - then valid_vardecl_list reste - else false -;; -(* val valid_vardecl_list : Lang.vardecl list -> bool = *) - let tp_fundefn (env: environment) (fun_def: fundefn) = let Fundefn(fun_decl, cmd) = fun_def in let Fundecl(fun_decl_tp,_,var_decl_list) = fun_decl in - let env1 = (addEnv_fun fun_decl env) in (* Besoin d'effacer dans l'env si recurence ? *) + let env1 = build_env_var env var_decl_list in let _ = tp_cmd env1 cmd in if valid_vardecl_list var_decl_list && (tp_cmd env1 cmd) = fun_decl_tp then fun_decl_tp - else raise (Failure "Invalid function definition") + else raise (Failure "Type return is not the same as the type of the function") ;; (* val tp_fundefn : environment -> Lang.fundefn @@ -310,20 +350,66 @@ let tp_fundefn (env: environment) (fun_def: fundefn) = let test_tp_fundefn = let function_to_test = tp_fundefn { localvars=[]; - funbind=[] + funbind=[ + Fundecl(BoolT, "fun1", [Vardecl(IntT, "x"); Vardecl(FloatT, "y")]); + Fundecl(IntT, "fun2", [Vardecl(IntT, "x"); Vardecl(FloatT, "y")]); + ] } and input_values = [ Fundefn( Fundecl(BoolT, "fun1", [Vardecl(IntT, "a"); Vardecl(FloatT, "b")]), Return(BinOp(BCompar(BCeq), Const(IntV(4)), Const(IntV(5)))) - ) + ); + Fundefn( + Fundecl(IntT, "fun2", [Vardecl(IntT, "a"); Vardecl(FloatT, "b")]), + Return(VarE("a")) + ); ] and expected_result = [ - BoolT + BoolT; + IntT; ] in (List.map function_to_test input_values) = expected_result ;; -(* let tp_stmt fundecls = ;; *) -let tp_prog (Prog (fundecls, fundefns)) = true;; (* try (tp_fundefn fundefns) && (tp_stmt fundecls) with _ -> false *) \ No newline at end of file + +(* ----- Typage d'un programme ----- *) +let tp_prog (Prog (fundecls, fundefns)) = + let env = build_env_fun {localvars=[];funbind=[]} fundecls in + try ( + let _ = List.map (tp_fundefn env) fundefns + in true + ) with _ -> false +;; +(* val tp_prog : + Lang.prog + -> bool = +*) + +(* - tp_prog: TESTS - *) +let test_tp_prog = + let function_to_test = tp_prog + and input_values = [ + Prog( + [ + Fundecl(BoolT, "fun1", [Vardecl(IntT, "x"); Vardecl(FloatT, "y")]); + Fundecl(IntT, "fun2", [Vardecl(IntT, "x"); Vardecl(FloatT, "y")]); + ], + [ + Fundefn( + Fundecl(BoolT, "fun1", [Vardecl(IntT, "a"); Vardecl(FloatT, "b")]), + Return(BinOp(BCompar(BCeq), Const(IntV(4)), Const(IntV(5)))) + ); + Fundefn( + Fundecl(IntT, "fun2", [Vardecl(IntT, "a"); Vardecl(FloatT, "b")]), + Return(VarE("a")) + ); + ] + ); + ] + and expected_result = [ + true; + ] in + (List.map function_to_test input_values) = expected_result +;; \ No newline at end of file From e691dc72f8b32f0da72cad0e0a8071073d24f603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=A0s?= Date: Fri, 7 Apr 2023 17:35:09 +0200 Subject: [PATCH 10/12] feat(parser/lexer): Complete parser/lexer --- src/parser_laurian/.gitignore | 1 + src/parser_laurian/Makefile | 2 +- src/parser_laurian/Tests/progsimple.c | 14 ++++- src/parser_laurian/lexer.mll | 14 ++--- src/parser_laurian/parser.mly | 87 +++++++++++++-------------- 5 files changed, 62 insertions(+), 56 deletions(-) create mode 100644 src/parser_laurian/.gitignore diff --git a/src/parser_laurian/.gitignore b/src/parser_laurian/.gitignore new file mode 100644 index 0000000..0f274e7 --- /dev/null +++ b/src/parser_laurian/.gitignore @@ -0,0 +1 @@ +*.output \ No newline at end of file diff --git a/src/parser_laurian/Makefile b/src/parser_laurian/Makefile index b55f18e..0ec793e 100644 --- a/src/parser_laurian/Makefile +++ b/src/parser_laurian/Makefile @@ -26,7 +26,7 @@ lexer.ml: lexer.mll lang.cmo ocamllex $< parser.ml parser.mli: parser.mly lang.cmo - ocamlyacc $< + ocamlyacc -v $< lexer.cmo: lexer.ml parser.cmo ocamlc -c $< diff --git a/src/parser_laurian/Tests/progsimple.c b/src/parser_laurian/Tests/progsimple.c index edf793e..af4358d 100644 --- a/src/parser_laurian/Tests/progsimple.c +++ b/src/parser_laurian/Tests/progsimple.c @@ -1,12 +1,20 @@ -void main (string y, int x) { +void yes( int yes){ + yes = 5; + return yes; +} + +void main (string y, int x, int yooo) { x = 15; while (x < 20) { - x = x + 1; + x = x + 1 -16; y = "hello"; if (x == 17) { y = "world"; } - /* */ } + + yooo = yes(5); + return x; } + diff --git a/src/parser_laurian/lexer.mll b/src/parser_laurian/lexer.mll index a1bf9f4..deb988b 100644 --- a/src/parser_laurian/lexer.mll +++ b/src/parser_laurian/lexer.mll @@ -39,7 +39,7 @@ rule token = parse | "string" {TP(StringT)} | "float" {TP(FloatT)} | "void" {TP(VoidT)} -| "lit" {TP(LitT)} (* Potentiellement list *) +| "lit" {TP(LitT)} (* faut demander *) | '(' { LPAREN } | ')' { RPAREN } @@ -73,16 +73,16 @@ rule token = parse | "while" {WHILE} | "for" {FOR} -| "true" {BCONSTANT(true)} -| "false" {BCONSTANT(false)} -| num_virgule as s {FLOATCONSTANT(float_of_string s)} -| num as s {INTCONSTANT(int_of_string s)} -| literal as l { LITCONSTANT l } -| str as s { STRINGCONSTANT s } +| "True" {BCONSTANT(true)} +| "False" {BCONSTANT(false)} | eof {EOF} +| num_virgule as s {FLOATCONSTANT(float_of_string s)} +| num as s {INTCONSTANT(int_of_string s)} +| literal as l { LITCONSTANT l } +| str as s { STRINGCONSTANT s } | alph alph* as i {IDENTIFIER i} | _ {Printf.printf "ERROR: unrecogized symbol '%s'\n" (Lexing.lexeme lexbuf); diff --git a/src/parser_laurian/parser.mly b/src/parser_laurian/parser.mly index fc1b2a9..ad03eed 100644 --- a/src/parser_laurian/parser.mly +++ b/src/parser_laurian/parser.mly @@ -15,26 +15,33 @@ open Lang %token IF ELSE WHILE FOR RETURN BCEQ BCGE BCGT BCLE BCLT BCNE BLAND BLOR %token EOF +%left QMARK COLON %left BLOR %left BLAND %left BCEQ BCNE %left BCGE BCGT BCLE BCLT %left PLUS MINUS FPLUS FMINUS %left TIMES DIV FDIV FTIMES MOD -%left LPAREN RPAREN LBRACE RBRACE + %right IF ELSE -%right WHILE FOR -%right RETURN +%left RPAREN +%right LPAREN +%left SEMICOLON %start start %type start %% -start: fundefn { Prog ([], [$1]) } +start: list_fundefn { Prog ([], $1) } ; +list_fundefn: + | {[]} + | fundefn list_fundefn {$1 :: $2} +; + fundefn: /* Compound-statement dans la doc --> 6.8.2 */ /* d'apres la doc, on peut lui mettre --> LBRACE RBRACE {Skip} */ |fundecl LBRACE block_item_list_opt RBRACE { Fundefn($1, $3) } @@ -61,46 +68,44 @@ constant: |FLOATCONSTANT {FloatV($1) } ; -/*expression_opt: - |{Skip} - |expression {$1} -; -*/ expression: /* A.2.1 ---> 6.5.1 */ - |constant {Const($1)} |IDENTIFIER {VarE($1)} + |constant {Const($1)} |LPAREN expression RPAREN {$2} |multiplicative_expression {$1} |additive_expression {$1} |relational_expression {$1} |equality_expression {$1} |logical_and_expression {$1} + |logical_or_expression {$1} |conditional_expression {$1} + |IDENTIFIER LPAREN expr_list RPAREN {CallE($1,$3)} ; + /*les calculs*/ multiplicative_expression: /* 6.5.5 */ - |expression TIMES expression {BinOp(BArith(BAmul), $1, $3)} |expression FTIMES expression {BinOp(BArith(BAfmul), $1, $3)} - |expression DIV expression {BinOp(BArith(BAdiv), $1, $3)} + |expression TIMES expression {BinOp(BArith(BAmul), $1, $3)} |expression FDIV expression {BinOp(BArith(BAfdiv), $1, $3)} + |expression DIV expression {BinOp(BArith(BAdiv), $1, $3)} |expression MOD expression {BinOp(BArith(BAmod), $1, $3)} ; additive_expression: /* 6.5.6 */ - |expression PLUS expression {BinOp(BArith(BAadd), $1, $3)} - |expression MINUS expression {BinOp(BArith(BAsub), $1, $3)} |expression FPLUS expression {BinOp(BArith(BAfadd), $1, $3)} |expression FMINUS expression {BinOp(BArith(BAfsub), $1, $3)} + |expression PLUS expression {BinOp(BArith(BAadd), $1, $3)} + |expression MINUS expression {BinOp(BArith(BAsub), $1, $3)} ; /*les comparaisons*/ relational_expression: /* 6.5.8 */ + |expression BCLT expression {BinOp(BCompar(BClt), $1, $3)} + |expression BCGT expression {BinOp(BCompar(BCgt), $1, $3)} |expression BCLE expression {BinOp(BCompar(BCle), $1, $3)} |expression BCGE expression {BinOp(BCompar(BCge), $1, $3)} - |expression BCGT expression {BinOp(BCompar(BCgt), $1, $3)} - |expression BCLT expression {BinOp(BCompar(BClt), $1, $3)} ; equality_expression: /* 6.5.9 */ |expression BCEQ expression {BinOp(BCompar(BCeq), $1, $3)} @@ -110,6 +115,9 @@ equality_expression: /* 6.5.9 */ /*les operateurs booleens */ logical_and_expression: |expression BLAND expression {BinOp(BBool(BBand), $1, $3)} /* 6.5.13 */ +; + +logical_or_expression: |expression BLOR expression {BinOp(BBool(BBor), $1, $3)} /* 6.5.14 */ ; @@ -124,28 +132,32 @@ conditional_expression: /* 6.5.16 */ /*///////////// DEBUT DES STATEMENTS //////////////////*/ statement: /* A.2.3 ----> 6.8 */ - |LBRACE block_item_list_opt RBRACE {$2} /* peut etre fundefn plutot vu que c'est le vrai compound_statement*/ + |compound_statement {$1} /* peut etre fundefn plutot vu que c'est le vrai compound_statement*/ + // |expression_statement {$1} |select_statement {$1} /*if et else*/ |iteration_statement {$1} /*while et for*/ |jump_statement SEMICOLON {$1} /*return et break*/ |assignation SEMICOLON {$1} + |IDENTIFIER LPAREN expr_list RPAREN {CallC($1,$3)} + // Faut faire l'appel à des foncttions avec CondC( fname * (expr_list ) ) ; +expr_list: + | { [] } + | expression expr_list{[$1] @ $2} +; + +compound_statement: /* 6.8.2 */ + |LBRACE block_item_list_opt RBRACE {$2} +; + + block_item_list_opt: /* 6.8.2 */ - |statement {$1} - |block_item_list_opt statement {Seq($1,$2)} /* pas sur du tout */ - | {Skip} + |statement block_item_list_opt {Seq($1,$2)} /* pas sur du tout */ + |{Skip} ; - - -block_item: /* 6.8.2 */ - /* declaration de variable / function (A.2.2 dans la doc) */ - |statement {$1} -; - - select_statement: /* 6.8.4 */ |IF LPAREN expression RPAREN statement {CondC ($3, $5, Skip) } |IF LPAREN expression RPAREN statement ELSE statement {CondC ($3, $5, $7) } @@ -153,7 +165,7 @@ select_statement: /* 6.8.4 */ iteration_statement: /* 6.8.5 */ |WHILE LPAREN expression RPAREN statement {Loop (Seq (CondC ( $3, Skip, Exit), $5))} - /*|FOR LPAREN expression_opt SEMICOLON expression_opt SEMICOLON expression_opt RPAREN statement {Loop (Seq (CondC ( $5, Skip, Exit), $9))} */ /*Absolument pas sur*/ + |FOR LPAREN expression SEMICOLON expression SEMICOLON expression RPAREN statement {Loop (Seq (CondC ( $5, Skip, Exit), $9))} /*Absolument pas sur*/ ; jump_statement: /* 6.8.6 */ @@ -182,22 +194,7 @@ assignation: /* 6.5.17 */ /* dans la doc ça fait parti des expressions mais pg Demander au prof : - ---Comment on différencie "==" et "=" - - ---Type LitT (peut etre list ?) - - --- Je vois pas comment déclarer une variable (utiliser Vardecl qui demande un tp * vname) - qui renvoie un type vardecl avec Assign qui demande vname * expr ( et qui renvoie un com) - - pour pouvoir prendre en compte "int x = 15;" par exemple - - ---Comment ça marche pour appeler une fonction ou expressionn CallE et CallC ? - - ---|block_item_list_opt {$1} // peut etre fundefn plutot vu que c'est le vrai compound_statement - - : d'apres la doc, fundefn c'est le compound_statement, mais il a pas le optionnel - - associativité des opérateurs ? (dans le pdf TP2 : introduction à YACC, partie 4 --> développons la grammaire ---> tirer 2) + associativité des opérateurs ? (dans le pdf TP2 : introduction à YACC, partie 4 --> développons la grammaire ---> tirer 2) */ From 41cc5c6189bfe7dad680d6416d04c57e3759ec49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=A0s?= Date: Fri, 7 Apr 2023 17:37:51 +0200 Subject: [PATCH 11/12] Merge Parser and typing --- .gitignore | 1 + src/Makefile | 16 ++--- src/{parser_laurian => }/lexer.mll | 0 src/{parser_laurian => }/parser.mly | 0 src/parser_laurian/.gitignore | 1 - src/parser_laurian/Makefile | 46 ------------- src/parser_laurian/interf.ml | 33 ---------- src/parser_laurian/lang.ml | 64 ------------------- src/parser_laurian/use.ml | 16 ----- .../Tests => tests}/progsimple.c | 0 10 files changed, 9 insertions(+), 168 deletions(-) rename src/{parser_laurian => }/lexer.mll (100%) rename src/{parser_laurian => }/parser.mly (100%) delete mode 100644 src/parser_laurian/.gitignore delete mode 100644 src/parser_laurian/Makefile delete mode 100644 src/parser_laurian/interf.ml delete mode 100644 src/parser_laurian/lang.ml delete mode 100644 src/parser_laurian/use.ml rename {src/parser_laurian/Tests => tests}/progsimple.c (100%) diff --git a/.gitignore b/.gitignore index b0a833a..a1de90b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ src/parser.ml *.mli src/**/*.cmi comp +*/**/*.output # Tests out tests/out/ diff --git a/src/Makefile b/src/Makefile index 97ef93f..43621e7 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,5 +1,5 @@ -# Import lib + compile -all: lib comp +# Compile +all: comp # Compilation of Ocaml files # Attention: order of object files important @@ -30,12 +30,12 @@ comp.cmo: comp.ml gen.cmo typing.cmo parser.cmo interf.cmo # ocaml lexer and parser # Comment in for your own lexer -# lexer.ml: lexer.mll lang.cmo -# ocamllex $< +lexer.ml: lexer.mll lang.cmo + ocamllex $< # Comment in for your own parser -# parser.ml parser.mli: parser.mly lang.cmo -# ocamlyacc $< +parser.ml parser.mli: parser.mly lang.cmo + ocamlyacc $< lexer.cmo: lexer.ml parser.cmo ocamlc -c $< @@ -52,8 +52,8 @@ parser.cmo: parser.ml parser.cmi lang.cmo .PHONY: clean ### Import files from /lib (temporarly) -lib: - cp ../lib/* ./ +# lib: +# cp ../lib/* ./ ## Remove compiled modules and lib clean: diff --git a/src/parser_laurian/lexer.mll b/src/lexer.mll similarity index 100% rename from src/parser_laurian/lexer.mll rename to src/lexer.mll diff --git a/src/parser_laurian/parser.mly b/src/parser.mly similarity index 100% rename from src/parser_laurian/parser.mly rename to src/parser.mly diff --git a/src/parser_laurian/.gitignore b/src/parser_laurian/.gitignore deleted file mode 100644 index 0f274e7..0000000 --- a/src/parser_laurian/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.output \ No newline at end of file diff --git a/src/parser_laurian/Makefile b/src/parser_laurian/Makefile deleted file mode 100644 index 0ec793e..0000000 --- a/src/parser_laurian/Makefile +++ /dev/null @@ -1,46 +0,0 @@ -all: lang.cmo parser.cmo lexer.cmo interf.cmo - -# Compilation of .ml files -lang.cmo: lang.ml - ocamlc -c $< - -# typing.cmo: typing.ml lang.cmo -# ocamlc -c $< - -# instrs.cmo: instrs.ml lang.cmo -# ocamlc -c $< - -# gen.cmo: gen.ml lang.cmo instrs.cmo typing.cmo -# ocamlc -c $< - -#interf.cmo: interf.ml lexer.cmo parser.cmo gen.cmo typing.cmo -interf.cmo: interf.ml lexer.cmo parser.cmo - ocamlc -c $< - -# comp.cmo: comp.ml gen.cmo typing.cmo parser.cmo interf.cmo -# ocamlc -c $< - -# ocaml lexer and parser - -lexer.ml: lexer.mll lang.cmo - ocamllex $< - -parser.ml parser.mli: parser.mly lang.cmo - ocamlyacc -v $< - -lexer.cmo: lexer.ml parser.cmo - ocamlc -c $< -parser.cmo: parser.ml parser.cmi lang.cmo - ocamlc -c $< - - -#### Generic rules - -%.cmi: %.mli - ocamlc -c $< - - -.PHONY: clean - -clean: - rm -f lexer.ml parser.ml *.mli *.cmi *.cmo diff --git a/src/parser_laurian/interf.ml b/src/parser_laurian/interf.ml deleted file mode 100644 index 17ca594..0000000 --- a/src/parser_laurian/interf.ml +++ /dev/null @@ -1,33 +0,0 @@ -(* Interface with parser *) - -exception ParseLexError of exn * (string * int * int * string * string) - -let parse_file infile = - let lexbuf = Lexing.from_channel (open_in infile) in - try - Parser.start Lexer.token lexbuf - with exn -> - begin - let curr = lexbuf.Lexing.lex_curr_p in - let line = curr.Lexing.pos_lnum in - let cnum = curr.Lexing.pos_cnum - curr.Lexing.pos_bol in - let tok = Lexing.lexeme lexbuf in - let tail = Lexer.ruleTail "" lexbuf in - raise (ParseLexError (exn,(infile, line,cnum,tok,tail))) - end -;; - -let print_parse_error (filename, line,cnum,tok,tail) = - print_string ("Parsing error in file: " ^ filename ^ - " on line: " ^ (string_of_int line) ^ - " column: " ^ (string_of_int cnum) ^ - " token: " ^ tok ^ - "\nrest: " ^ tail ^ "\n") -;; - -let parse infile = - try parse_file infile - with ParseLexError (e, r) -> - print_parse_error r; - failwith "Stopped execution." -;; diff --git a/src/parser_laurian/lang.ml b/src/parser_laurian/lang.ml deleted file mode 100644 index c3791aa..0000000 --- a/src/parser_laurian/lang.ml +++ /dev/null @@ -1,64 +0,0 @@ -(* Definition of source language data structures *) - -(* variable names *) -type vname = string - -(* function names *) -type fname = string - -(* binary arithmetic operators *) -type barith = BAadd | BAsub | BAmul | BAdiv | BAmod (* integer *) - | BAfadd | BAfsub | BAfmul | BAfdiv (* float *) - -(* binary boolean operators: and, or *) -type bbool = BBand | BBor - -(* binary comparison operators: =, >=, >, <=, <, != *) -type bcompar = BCeq | BCge | BCgt | BCle | BClt | BCne - -(* binary operators, combining all of the above *) -type binop = - BArith of barith -| BBool of bbool -| BCompar of bcompar - -type value = - BoolV of bool -| FloatV of float -| IntV of int -| LitV of string -| StringV of string - -(* Expresssions *) -type expr = - Const of value (* constant *) - | VarE of vname (* variable *) - | BinOp of binop * expr * expr (* binary operation *) - | CondE of expr * expr * expr (* conditional expr *) - | CallE of fname * (expr list) (* call expression *) - -(* Commands *) -type com = - Skip (* no operation *) - | Exit (* exit from loop *) - | Assign of vname * expr (* assign expression to var *) - | Seq of com * com (* sequence of statements *) - | CondC of expr * com * com (* conditional com *) - | Loop of com (* loop until exit *) - | CallC of fname * (expr list) (* call statement *) - | Return of expr (* return from call *) - -(* Types *) -type tp = BoolT | FloatT | IntT | LitT | StringT | VoidT - -(* variable / parameter declaration *) -type vardecl = Vardecl of tp * vname - -(* function declaration: return type; parameter declarations *) -type fundecl = Fundecl of tp * fname * (vardecl list) - -(* function definition: function declaration; function body *) -type fundefn = Fundefn of fundecl * com - -type prog = Prog of (fundecl list) * (fundefn list) - diff --git a/src/parser_laurian/use.ml b/src/parser_laurian/use.ml deleted file mode 100644 index 63e5293..0000000 --- a/src/parser_laurian/use.ml +++ /dev/null @@ -1,16 +0,0 @@ - -#load "lang.cmo";; -#load "parser.cmo" ;; -#load "lexer.cmo" ;; -#load "interf.cmo";; - -open Interf;; -open Lang;; - -(* For using the parser: - -- Evaluate this file (use.ml) -- parse "Tests/progsimple.c" ;; - -*) - diff --git a/src/parser_laurian/Tests/progsimple.c b/tests/progsimple.c similarity index 100% rename from src/parser_laurian/Tests/progsimple.c rename to tests/progsimple.c From 1ffec0ca0aae597ae852ed914c86e3bd73381194 Mon Sep 17 00:00:00 2001 From: Laurian-Dufrechou Date: Fri, 7 Apr 2023 18:02:09 +0200 Subject: [PATCH 12/12] fix test path --- src/use.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/use.ml b/src/use.ml index 16880ca..76cf849 100644 --- a/src/use.ml +++ b/src/use.ml @@ -13,12 +13,12 @@ open Instrs;; (* For using the parser: - Evaluate this file (use.ml) -- parse "Tests/rectangles.c" ;; +- parse "../Tests/progsimple.c" ;; * For code generation: - Evaluate this file (use.ml) -- run_test "Tests/rectangles.c" "Tests/rectangles.ps";; +- run_test "../Tests/rectangles.c" "../Tests/rectangles.ps";; *)