From 19ff31e4c92e30e9c58250004c401c52d2df60cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Pottier?= Date: Wed, 13 Dec 2017 14:04:28 +0100 Subject: [PATCH] Publish the project. --- projet/src/.merlin | 9 + projet/src/CPS.ml | 7 + projet/src/CPS.mli | 4 + projet/src/Cook.ml | 54 +++++ projet/src/Cook.mli | 15 ++ projet/src/Defun.ml | 7 + projet/src/Defun.mli | 4 + projet/src/Error.ml | 40 ++++ projet/src/Error.mli | 30 +++ projet/src/Finish.ml | 323 ++++++++++++++++++++++++++ projet/src/Finish.mli | 5 + projet/src/Lambda.ml | 48 ++++ projet/src/Lexer.mll | 97 ++++++++ projet/src/Main.ml | 101 ++++++++ projet/src/Makefile | 28 +++ projet/src/Parser.mly | 155 +++++++++++++ projet/src/RawLambda.ml | 55 +++++ projet/src/Tail.ml | 132 +++++++++++ projet/src/Top.ml | 94 ++++++++ projet/src/_tags | 8 + projet/src/alphalib/Atom.ml | 215 ++++++++++++++++++ projet/src/alphalib/Atom.mli | 71 ++++++ projet/src/kremlin/C.ml | 126 ++++++++++ projet/src/kremlin/Common.ml | 19 ++ projet/src/kremlin/Constant.ml | 66 ++++++ projet/src/kremlin/Options.ml | 7 + projet/src/kremlin/PrintC.ml | 354 +++++++++++++++++++++++++++++ projet/src/kremlin/PrintCommon.ml | 96 ++++++++ projet/src/kremlin/Utils.ml | 73 ++++++ projet/src/prologue.h | 83 +++++++ projet/src/test/.gitignore | 1 + projet/src/test/.merlin | 1 + projet/src/test/Makefile | 21 ++ projet/src/test/_tags | 3 + projet/src/test/auxiliary.ml | 138 +++++++++++ projet/src/test/test.ml | 288 +++++++++++++++++++++++ projet/src/tests/.gitignore | 4 + projet/src/tests/bool.exp | 20 ++ projet/src/tests/bool.lambda | 88 +++++++ projet/src/tests/church.exp | 1 + projet/src/tests/church.lambda | 16 ++ projet/src/tests/hello.exp | 1 + projet/src/tests/hello.lambda | 1 + projet/src/tests/loop/loop.lambda | 10 + projet/src/tests/printprint.exp | 2 + projet/src/tests/printprint.lambda | 2 + projet/sujet.pdf | Bin 0 -> 112447 bytes 47 files changed, 2923 insertions(+) create mode 100644 projet/src/.merlin create mode 100644 projet/src/CPS.ml create mode 100644 projet/src/CPS.mli create mode 100644 projet/src/Cook.ml create mode 100644 projet/src/Cook.mli create mode 100644 projet/src/Defun.ml create mode 100644 projet/src/Defun.mli create mode 100644 projet/src/Error.ml create mode 100644 projet/src/Error.mli create mode 100644 projet/src/Finish.ml create mode 100644 projet/src/Finish.mli create mode 100644 projet/src/Lambda.ml create mode 100644 projet/src/Lexer.mll create mode 100644 projet/src/Main.ml create mode 100644 projet/src/Makefile create mode 100644 projet/src/Parser.mly create mode 100644 projet/src/RawLambda.ml create mode 100644 projet/src/Tail.ml create mode 100644 projet/src/Top.ml create mode 100644 projet/src/_tags create mode 100644 projet/src/alphalib/Atom.ml create mode 100644 projet/src/alphalib/Atom.mli create mode 100644 projet/src/kremlin/C.ml create mode 100644 projet/src/kremlin/Common.ml create mode 100644 projet/src/kremlin/Constant.ml create mode 100644 projet/src/kremlin/Options.ml create mode 100644 projet/src/kremlin/PrintC.ml create mode 100644 projet/src/kremlin/PrintCommon.ml create mode 100644 projet/src/kremlin/Utils.ml create mode 100644 projet/src/prologue.h create mode 100644 projet/src/test/.gitignore create mode 100644 projet/src/test/.merlin create mode 100644 projet/src/test/Makefile create mode 100644 projet/src/test/_tags create mode 100644 projet/src/test/auxiliary.ml create mode 100644 projet/src/test/test.ml create mode 100644 projet/src/tests/.gitignore create mode 100644 projet/src/tests/bool.exp create mode 100644 projet/src/tests/bool.lambda create mode 100755 projet/src/tests/church.exp create mode 100644 projet/src/tests/church.lambda create mode 100755 projet/src/tests/hello.exp create mode 100644 projet/src/tests/hello.lambda create mode 100644 projet/src/tests/loop/loop.lambda create mode 100755 projet/src/tests/printprint.exp create mode 100644 projet/src/tests/printprint.lambda create mode 100644 projet/sujet.pdf diff --git a/projet/src/.merlin b/projet/src/.merlin new file mode 100644 index 0000000..7de32a3 --- /dev/null +++ b/projet/src/.merlin @@ -0,0 +1,9 @@ +S kremlin +S alphalib +B _build +B _build/kremlin +B _build/alphalib +PKG unix +PKG process +PKG pprint +PKG ppx_deriving.std diff --git a/projet/src/CPS.ml b/projet/src/CPS.ml new file mode 100644 index 0000000..9b3d87d --- /dev/null +++ b/projet/src/CPS.ml @@ -0,0 +1,7 @@ +(* The source calculus. *) +module S = Lambda +(* The target calculus. *) +module T = Tail + +let cps_term (t : S.term) : T.term = + assert false diff --git a/projet/src/CPS.mli b/projet/src/CPS.mli new file mode 100644 index 0000000..2497ddd --- /dev/null +++ b/projet/src/CPS.mli @@ -0,0 +1,4 @@ +(* Through a CPS transformation, the surface language [Lambda] is translated + down to the intermediate language [Tail]. *) + +val cps_term: Lambda.term -> Tail.term diff --git a/projet/src/Cook.ml b/projet/src/Cook.ml new file mode 100644 index 0000000..89657ed --- /dev/null +++ b/projet/src/Cook.ml @@ -0,0 +1,54 @@ +open Error + +(* The source calculus. *) +module S = RawLambda +(* The target calculus. *) +module T = Lambda + +(* Environments map strings to atoms. *) +module Env = + Map.Make(String) + +(* [bind env x] creates a fresh atom [a] and extends the environment [env] + with a mapping of [x] to [a]. *) +let bind env x = + let a = Atom.fresh x in + Env.add x a env, a + +let rec cook_term env { S.place; S.value } = + match value with + | S.Var x -> + begin try + T.Var (Env.find x env) + with Not_found -> + error place "Unbound variable: %s" x + end + | S.Lam (x, t) -> + let env, x = bind env x in + T.Lam (T.NoSelf, x, cook_term env t) + | S.App (t1, t2) -> + T.App (cook_term env t1, cook_term env t2) + | S.Lit i -> + T.Lit i + | S.BinOp (t1, op, t2) -> + T.BinOp (cook_term env t1, op, cook_term env t2) + | S.Print t -> + T.Print (cook_term env t) + | S.Let (S.NonRecursive, x, t1, t2) -> + let t1 = cook_term env t1 in + let env, x = bind env x in + let t2 = cook_term env t2 in + T.Let (x, t1, t2) + | S.Let (S.Recursive, f, { S.value = S.Lam (x, t1); _ }, t2) -> + let env, f = bind env f in + let x, t1 = + let env, x = bind env x in + x, cook_term env t1 + in + let t2 = cook_term env t2 in + T.Let (f, T.Lam (T.Self f, x, t1), t2) + | S.Let (S.Recursive, _, { S.place; _ }, _) -> + error place "the right-hand side of 'let rec' must be a lambda-abstraction" + +let cook_term t = + cook_term Env.empty t diff --git a/projet/src/Cook.mli b/projet/src/Cook.mli new file mode 100644 index 0000000..617e408 --- /dev/null +++ b/projet/src/Cook.mli @@ -0,0 +1,15 @@ +(* This module translates [RawLambda] into [Lambda]. *) + +(* This involves ensuring that every name is properly bound (otherwise, an + error is reported) and switching from a representation of names as strings + to a representation of names as atoms. *) + +(* This also involves checking that the right-hand side of every [let] + construct is a function (otherwise, an error is reported) and switching + from a representation where [let] constructs can carry a [rec] annotation + to a representation where functions can carry such an annotation. *) + +(* This also involves dropping places (that is, source code locations), since + they are no longer used after this phase. *) + +val cook_term: RawLambda.term -> Lambda.term diff --git a/projet/src/Defun.ml b/projet/src/Defun.ml new file mode 100644 index 0000000..7264dac --- /dev/null +++ b/projet/src/Defun.ml @@ -0,0 +1,7 @@ +(* The source calculus. *) +module S = Tail +(* The target calculus. *) +module T = Top + +let defun_term (t : S.term) : T.program = + assert false diff --git a/projet/src/Defun.mli b/projet/src/Defun.mli new file mode 100644 index 0000000..0c02815 --- /dev/null +++ b/projet/src/Defun.mli @@ -0,0 +1,4 @@ +(* Through defunctionalization, the intermediate language [Tail] is translated + down to the next intermediate language, [Top]. *) + +val defun_term: Tail.term -> Top.program diff --git a/projet/src/Error.ml b/projet/src/Error.ml new file mode 100644 index 0000000..e4f1d8b --- /dev/null +++ b/projet/src/Error.ml @@ -0,0 +1,40 @@ +open Lexing + +type place = + position * position + +let place lexbuf : place = + lexbuf.lex_start_p, lexbuf.lex_curr_p + +let line p : int = + p.pos_lnum + +let column p : int = + p.pos_cnum - p.pos_bol + +let show place : string = + let startp, endp = place in + Printf.sprintf "File \"%s\", line %d, characters %d-%d" + startp.pos_fname + (line startp) + (column startp) + (endp.pos_cnum - startp.pos_bol) (* intentionally [startp.pos_bol] *) + +let display continuation header place format = + Printf.fprintf stderr "%s:\n" (show place); + Printf.kfprintf + continuation + stderr + (header ^^ format ^^ "\n%!") + +let error place format = + display + (fun _ -> exit 1) + "Error: " + place format + +let set_filename lexbuf filename = + lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_fname = filename } + +let pp_place formatter _place = + Format.fprintf formatter "<>" diff --git a/projet/src/Error.mli b/projet/src/Error.mli new file mode 100644 index 0000000..b8ba5f9 --- /dev/null +++ b/projet/src/Error.mli @@ -0,0 +1,30 @@ +open Lexing + +(* A place is a pair of a start position and an end position. *) + +type place = + position * position + +(* [set_filename lexbuf filename] updates [lexbuf] to record the + fact that the current file name is [filename]. This file name + is later used in error messages. *) + +val set_filename: lexbuf -> string -> unit + +(* [place lexbuf] produces a pair of the current token's start and + end positions. This function is useful when reporting an error + during lexing. *) + +val place: lexbuf -> place + +(* [error place format ...] displays an error message and exits. + The error message is located at [place]. The error message + is composed based on [format] and the extra arguments [...]. *) + +val error: place -> ('a, out_channel, unit, 'b) format4 -> 'a + +(* [pp_place formatter place] prints a place. It is used by + [@@deriving show] for data structures that contain places. + As of now, it prints nothing. *) + +val pp_place: Format.formatter -> place -> unit diff --git a/projet/src/Finish.ml b/projet/src/Finish.ml new file mode 100644 index 0000000..08779b3 --- /dev/null +++ b/projet/src/Finish.ml @@ -0,0 +1,323 @@ +(* The source calculus. *) +module S = Top +(* The target calculus. *) +module T = C + +(* -------------------------------------------------------------------------- *) + +(* [interval i j f] constructs the list [[f i; f (i + 1); ...; f (j - 1)]]. *) + +let rec interval i j (f : int -> 'a) : 'a list = + if i < j then + f i :: interval (i + 1) j f + else + [] + +(* -------------------------------------------------------------------------- *) + +(* [index xs] constructs a list of pairs, where each element of [xs] is paired + with its index. Indices are 0-based. *) + +let index (xs : 'a list) : (int * 'a) list = + let n = List.length xs in + let indices = interval 0 n (fun i -> i) in + List.combine indices xs + +(* -------------------------------------------------------------------------- *) + +(* The number of fields of a block, not counting its tag. *) + +let block_num_fields b = + match b with + | S.Con (_, vs) -> + List.length vs + +(* -------------------------------------------------------------------------- *) + +(* A simple-minded way of ensuring that every atom is printed as a + distinct string is to concatenate the atom's hint and identity, + with an underscore in between. This is guaranteed to rule out + collisions. *) + +let var (x : S.variable) : T.ident = + Printf.sprintf "%s_%d" (Atom.hint x) (Atom.identity x) + +let evar (x : S.variable) : T.expr = + T.Name (var x) + +(* -------------------------------------------------------------------------- *) + +(* Predefined C types and functions. *) + +(* A universal type: every value is translated to a C value of type [univ]. + This is a union type (i.e., an untagged sum) of integers and pointers to + memory blocks. *) + +let univ : T.type_spec = + T.Named "univ" + +(* The type of integers. *) + +let int : T.type_spec = + T.Named "int" + +(* The type [char] appears in the type of [main]. *) + +let char : T.type_spec = + T.Named "char" + +let answer : T.type_spec = + int + (* Our functions never actually return, since they are tail recursive. + We use [int] as their return type, since this is the return type of + [main]. *) + +let exit : T.expr = + T.Name "exit" + +let printf : T.expr = + T.Name "printf" + +(* -------------------------------------------------------------------------- *) + +(* [declare x init] constructs a local variable declaration for a variable [x] + of type [univ]. [x] is optionally initialized according to [init]. *) + +let declare (x : S.variable) (init : T.init option) : T.declaration = + univ, None, [ T.Ident (var x), init ] + +(* -------------------------------------------------------------------------- *) + +(* Macro invocations. *) + +let macro m es : T.expr = + (* We disguise a macro invocation as a procedure call. *) + T.Call (T.Name m, es) + +(* -------------------------------------------------------------------------- *) + +(* Integer literals; conversions between [univ] and [int]. *) + +let iconst i : T.expr = + T.Constant (Constant.Int64, string_of_int i) + +let to_int v : T.expr = + macro "TO_INT" [ v ] + (* This is an unsafe conversion, of course. *) + +let from_int v : T.expr = + macro "FROM_INT" [ v ] + +(* -------------------------------------------------------------------------- *) + +(* The translation of values. *) + +let finish_op = function + | S.OpAdd -> + T.K.Add + | S.OpSub -> + T.K.Sub + | S.OpMul -> + T.K.Mult + | S.OpDiv -> + T.K.Div + +let rec finish_value (v : S.value) : T.expr = + match v with + | S.VVar x -> + evar x + | S.VLit i -> + from_int (iconst i) + | S.VBinOp (v1, op, v2) -> + from_int ( + T.Op2 ( + finish_op op, + to_int (finish_value v1), + to_int (finish_value v2) + ) + ) + +let finish_values vs = + List.map finish_value vs + +(* -------------------------------------------------------------------------- *) + +(* A macro for allocating a memory block. *) + +let alloc b : T.expr = + T.Call (T.Name "ALLOC", [ iconst (block_num_fields b) ]) + +(* -------------------------------------------------------------------------- *) + +(* Macros for reading and initializing the tag of a memory block. *) + +let read_tag (v : S.value) : T.expr = + macro "GET_TAG" [ finish_value v ] + +let set_tag (x : S.variable) (tag : S.tag) : T.stmt = + T.Expr (macro "SET_TAG" [ evar x; iconst tag ]) + +(* -------------------------------------------------------------------------- *) + +(* Macros for reading and setting a field in a memory block. *) + +let read_field (v : S.value) (i : int) : T.expr = + (* [i] is a 0-based field index. *) + macro "GET_FIELD" [ finish_value v; iconst i ] + +let read_field (v : S.value) (i, x) (t : T.stmt list) : T.stmt list = + (* [x] is a variable, which is declared and initialized with + the content of the [i]th field of the block [v]. *) + T.DeclStmt (declare x (Some (T.InitExpr (read_field v i)))) :: + t + +let read_fields (v : S.value) xs (t : T.stmt list) : T.stmt list = + (* [xs] are variables, which are declared and initialized with + the contents of the fields of the block [v]. *) + List.fold_right (read_field v) (index xs) t + +let set_field x i (v : S.value) : T.stmt = + T.Expr (macro "SET_FIELD" [ evar x; iconst i; finish_value v ]) + +(* -------------------------------------------------------------------------- *) + +(* A sequence of instructions for initializing a memory block. *) + +let init_block (x : S.variable) (b : S.block) : T.stmt list = + match b with + | S.Con (tag, vs) -> + T.Comment "Initializing a memory block:" :: + set_tag x tag :: + List.mapi (set_field x) vs + +(* -------------------------------------------------------------------------- *) + +(* Function calls, as expressions and as statements. *) + +let ecall f args : T.expr = + T.Call (f, args) + +let scall f args : T.stmt = + T.Expr (ecall f args) + +(* -------------------------------------------------------------------------- *) + +(* The translation of terms. *) + +let rec finish_term (t : S.term) : C.stmt = + match t with + | S.Exit -> + T.Compound [ + scall exit [ iconst 0 ] + ] + | S.TailCall (f, vs) -> + T.Return (Some (ecall (evar f) (finish_values vs))) + | S.Print (v, t) -> + T.Compound [ + scall printf [ T.Literal "%d\\n"; to_int (finish_value v) ]; + finish_term t + ] + | S.LetVal (x, v1, t2) -> + T.Compound [ + T.DeclStmt (declare x (Some (T.InitExpr (finish_value v1)))); + finish_term t2 + ] + | S.LetBlo (x, b1, t2) -> + T.Compound ( + T.DeclStmt (declare x (Some (T.InitExpr (alloc b1)))) :: + init_block x b1 @ + [ finish_term t2 ] + ) + | S.Swi (v, bs) -> + T.Switch ( + read_tag v, + finish_branches v bs, + default + ) + +and default : T.stmt = + (* This default [switch] branch should never be taken. *) + T.Compound [ + scall printf [ T.Literal "Oops! A nonexistent case has been taken.\\n" ]; + scall exit [ iconst 42 ]; + ] + +and finish_branches v bs = + List.map (finish_branch v) bs + +and finish_branch v (S.Branch (tag, xs, t)) : T.expr * T.stmt = + iconst tag, + T.Compound (read_fields v xs [finish_term t]) + +(* -------------------------------------------------------------------------- *) + +(* Function declarations. *) + +(* We distinguish the function [main], whose type is imposed by the C standard, + and ordinary functions, whose parameters have type [univ]. *) + +(* A parameter of an ordinary function has type [univ]. *) + +let param (x : S.variable) : T.param = + univ, T.Ident (var x) + +(* A declaration of an ordinary function. *) + +let declare_ordinary_function f xs : T.declaration = + answer, None, [ T.Function (None, T.Ident (var f), List.map param xs), None ] + +(* The declaration of the main function. *) + +let declare_main_function : T.declaration = + let params = [ + int, T.Ident "argc"; + char, T.Pointer (T.Pointer (T.Ident "argv")) + ] in + int, None, [ T.Function (None, T.Ident "main", params), None ] + +(* -------------------------------------------------------------------------- *) + +(* A function definition. *) + +type decl_or_fun = + T.declaration_or_function + +let define (decl : T.declaration) (t : S.term) : decl_or_fun = + T.Function ( + [], (* no comments *) + false, (* not inlined *) + decl, + T.Compound [finish_term t] + ) + +let define_ordinary_function (S.Fun (f, xs, t)) : decl_or_fun = + define (declare_ordinary_function f xs) t + +let define_main_function (t : S.term) : decl_or_fun = + define declare_main_function t + +(* -------------------------------------------------------------------------- *) + +(* Because all functions are mutually recursive, their definitions must be + preceded with their prototypes. *) + +let prototype (f : decl_or_fun) : decl_or_fun = + match f with + | T.Function (_, _, declaration, _) -> + T.Decl ([], declaration) + | T.Decl _ -> + assert false + +let prototypes (fs : decl_or_fun list) : decl_or_fun list = + List.map prototype fs @ + fs + +(* -------------------------------------------------------------------------- *) + +(* The translation of a complete program. *) + +let finish_program (S.Prog (decls, main) : S.program) : T.program = + prototypes ( + define_main_function main :: + List.map define_ordinary_function decls + ) diff --git a/projet/src/Finish.mli b/projet/src/Finish.mli new file mode 100644 index 0000000..6785984 --- /dev/null +++ b/projet/src/Finish.mli @@ -0,0 +1,5 @@ +(* This function implements a translation of the intermediate language [Top] + down to [C]. This transformation is mostly a matter of choosing appropriate + C constructs to reflect the concepts of the language [Top]. *) + +val finish_program: Top.program -> C.program diff --git a/projet/src/Lambda.ml b/projet/src/Lambda.ml new file mode 100644 index 0000000..fdb9ecb --- /dev/null +++ b/projet/src/Lambda.ml @@ -0,0 +1,48 @@ +(* This language is the untyped lambda-calculus, extended with recursive + lambda-abstractions, nonrecursive [let] bindings, integer literals and + integer arithmetic operations, and the primitive operation [print]. *) + +(* This language is really the same language as [RawLambda], with the + following internal differences: + + 1. Instead of recursive [let] bindings, the language has recursive + lambda-abstractions. A [let rec] definition whose right-hand side is not + a lambda-abstraction is rejected during the translation of [RawLambda] + to [Lambda]. + + 2. Variables are represented by atoms (instead of strings). A term with an + unbound variable is rejected during the translation of [RawLambda] to + [Lambda]. + + 3. Terms are no longer annotated with places. *) + +(* Variables are atoms. *) + +type variable = + Atom.atom + + (* Every lambda-abstraction is marked recursive or nonrecursive. Whereas a + nonrecursive lambda-abstraction [fun x -> t] binds one variable [x], a + recursive lambda-abstraction [fix f. fun x -> t] binds two variables [f] + and [x]. The variable [f] is a self-reference. *) + +and self = + | Self of variable + | NoSelf + +and binop = RawLambda.binop = + | OpAdd + | OpSub + | OpMul + | OpDiv + +and term = + | Var of variable + | Lam of self * variable * term + | App of term * term + | Lit of int + | BinOp of term * binop * term + | Print of term + | Let of variable * term * term + +[@@deriving show { with_path = false }] diff --git a/projet/src/Lexer.mll b/projet/src/Lexer.mll new file mode 100644 index 0000000..ba016f0 --- /dev/null +++ b/projet/src/Lexer.mll @@ -0,0 +1,97 @@ +{ + +open Lexing +open Error +open Parser +open RawLambda + +} + +(* -------------------------------------------------------------------------- *) + +(* Regular expressions. *) + +let newline = + ('\010' | '\013' | "\013\010") + +let whitespace = + [ ' ' '\t' ] + +let lowercase = + ['a'-'z' '\223'-'\246' '\248'-'\255' '_'] + +let uppercase = + ['A'-'Z' '\192'-'\214' '\216'-'\222'] + +let identchar = + ['A'-'Z' 'a'-'z' '_' '\192'-'\214' '\216'-'\246' '\248'-'\255' '0'-'9'] + +let digit = + ['0'-'9'] + +(* -------------------------------------------------------------------------- *) + +(* The lexer. *) + +rule entry = parse +| "fun" + { FUN } +| "in" + { IN } +| "let" + { LET } +| "print" + { PRINT } +| "rec" + { REC } +| "->" + { ARROW } +| "=" + { EQ } +| "(" + { LPAREN } +| ")" + { RPAREN } +| "+" + { ADDOP OpAdd } +| "-" + { ADDOP OpSub } +| "*" + { MULOP OpMul } +| "/" + { MULOP OpDiv } +| (lowercase identchar *) as x + { IDENT x } +| digit+ as i + { try + INTLITERAL (int_of_string i) + with Failure _ -> + error (place lexbuf) "invalid integer literal." } +| "(*" + { ocamlcomment (place lexbuf) lexbuf; entry lexbuf } +| newline + { new_line lexbuf; entry lexbuf } +| whitespace+ + { entry lexbuf } +| eof + { EOF } +| _ as c + { error (place lexbuf) "unexpected character: '%c'." c } + +(* ------------------------------------------------------------------------ *) + + (* Skip OCaml-style comments. Comments can be nested. This sub-lexer is + parameterized with the place of the opening comment, so if an unterminated + comment is detected, we can show where it was opened. *) + +and ocamlcomment p = parse +| "*)" + { () } +| "(*" + { ocamlcomment (place lexbuf) lexbuf; ocamlcomment p lexbuf } +| newline + { new_line lexbuf; ocamlcomment p lexbuf } +| eof + { error p "unterminated comment." } +| _ + { ocamlcomment p lexbuf } diff --git a/projet/src/Main.ml b/projet/src/Main.ml new file mode 100644 index 0000000..9c8eed4 --- /dev/null +++ b/projet/src/Main.ml @@ -0,0 +1,101 @@ +(* -------------------------------------------------------------------------- *) + +(* Parse the command line. *) + +let debug = + ref false + +let filenames = + ref [] + +let record filename = + filenames := filename :: !filenames + +let options = + Arg.align [ + "--debug", Arg.Set debug, " Enable debugging output"; + ] + +let usage = + Printf.sprintf "Usage: %s " Sys.argv.(0) + +let () = + Arg.parse options record usage + +let debug = + !debug + +let filenames = + List.rev !filenames + +(* -------------------------------------------------------------------------- *) + +(* Printing a syntax tree in an intermediate language (for debugging). *) + +let print_delimiter () = + Printf.eprintf "----------------------------------------"; + Printf.eprintf "----------------------------------------\n" + +let dump (phase : string) (show : 'term -> string) (t : 'term) = + if debug then begin + print_delimiter(); + Printf.eprintf "%s:\n\n%s\n\n%!" phase (show t) + end; + t + +(* -------------------------------------------------------------------------- *) + +(* Reading and parsing a file. *) + +let read filename : RawLambda.term = + try + let contents = Utils.file_get_contents filename in + let lexbuf = Lexing.from_string contents in + Error.set_filename lexbuf filename; + try + Parser.entry Lexer.entry lexbuf + with + | Parser.Error -> + Error.error (Error.place lexbuf) "Syntax error." + with + | Sys_error msg -> + prerr_endline msg; + exit 1 + +(* -------------------------------------------------------------------------- *) + +(* Printing the final C program on the standard output channel. *) + +let output (p : C.program) : unit = + Printf.printf "#include\n"; + Printf.printf "#include\n"; + Printf.printf "#include \"prologue.h\"\n\n"; + let print_program = PrintCommon.print_program PrintC.p_decl_or_function in + let buf = Buffer.create 1024 in + PrintCommon.printf_of_pprint_pretty print_program buf p; + print_endline (Buffer.contents buf) + +(* -------------------------------------------------------------------------- *) + +(* The complete processing pipeline. Beautiful, isn't it? *) + +let process filename = + filename + |> read + |> dump "RawLambda" RawLambda.show_term + |> Cook.cook_term + |> dump "Lambda" Lambda.show_term + |> CPS.cps_term + |> dump "Tail" Tail.show_term + |> Defun.defun_term + |> dump "Top" Top.show_program + |> Finish.finish_program + |> dump "C" C.show_program + |> output + +(* -------------------------------------------------------------------------- *) + +(* The main program. *) + +let () = + List.iter process filenames diff --git a/projet/src/Makefile b/projet/src/Makefile new file mode 100644 index 0000000..73f39e1 --- /dev/null +++ b/projet/src/Makefile @@ -0,0 +1,28 @@ +SHELL := bash +TARGET := Main.native +JOUJOU := joujou +DIRS := kremlin,alphalib +OCAMLBUILD :=\ + ocamlbuild \ + -classic-display \ + -j 4 \ + -use-ocamlfind \ + -use-menhir \ + -menhir "menhir -lg 1 -la 1 --explain" \ + -Is $(DIRS) \ + +.PHONY: all test clean + +all: + @ $(OCAMLBUILD) -quiet $(TARGET) + @ ln -sf $(TARGET) $(JOUJOU) + +test: all + @ make -C test test + +clean: + rm -f *~ + rm -f tests/*.c tests/*.out + $(OCAMLBUILD) -clean + rm -f $(TARGET) $(JOUJOU) + $(MAKE) -C test clean diff --git a/projet/src/Parser.mly b/projet/src/Parser.mly new file mode 100644 index 0000000..4f032b2 --- /dev/null +++ b/projet/src/Parser.mly @@ -0,0 +1,155 @@ +%token IDENT +%token INTLITERAL +%token FUN IN LET PRINT REC +%token ARROW EQ LPAREN RPAREN +%token MULOP ADDOP +%token EOF + +%start entry + +%{ + +open RawLambda + +%} + +%% + +(* -------------------------------------------------------------------------- *) + +(* A toplevel phrase is just a term. *) + +entry: + t = any_term EOF + { t } + +(* -------------------------------------------------------------------------- *) + +(* The syntax of terms is stratified as follows: + + atomic_term -- unambiguously delimited terms + application_term -- n-ary applications of atomic terms + multiplicative_term -- built using multiplication & division + additive_term -- built using addition & subtraction + any_term -- everything + + A [match/with/end] construct is terminated with an [end] keyword, as in Coq, + so it is an atomic term. *) + +atomic_term_: +| LPAREN t = any_term RPAREN + { t.value } +| x = IDENT + { Var x } +| i = INTLITERAL + { Lit i } + +application_term_: +| t = atomic_term_ + { t } +| t1 = placed(application_term_) t2 = placed(atomic_term_) + { App (t1, t2) } +| PRINT t2 = placed(atomic_term_) + { Print t2 } + +%inline multiplicative_term_: + t = left_associative_level(application_term_, MULOP, mkbinop) + { t } + +%inline additive_term_: + t = left_associative_level(multiplicative_term_, ADDOP, mkbinop) + { t } + +any_term_: +| t = additive_term_ + { t } +| FUN x = IDENT ARROW t = any_term + { Lam (x, t) } +| LET mode = recursive x = IDENT EQ t1 = any_term IN t2 = any_term + { Let (mode, x, t1, t2) } + +%inline any_term: + t = placed(any_term_) + { t } + +(* -------------------------------------------------------------------------- *) + +(* An infix-left-associative-operator level in a hierarchy of arithmetic + expressions. *) + +(* [basis] is the next lower level in the hierarchy. + [op] is the category of binary operators. + [action] is a ternary sequencing construct. *) + +left_associative_level(basis, op, action): +| t = basis +| t = action( + left_associative_level(basis, op, action), + op, + basis + ) + { t } + +(* -------------------------------------------------------------------------- *) + +(* A ternary sequence whose semantic action builds a [BinOp] node. *) + +%inline mkbinop(term1, op, term2): + t1 = placed(term1) op = op t2 = placed(term2) + { BinOp (t1, op, t2) } + +(* -------------------------------------------------------------------------- *) + +(* A [let] construct carries an optional [rec] annotation. *) + +recursive: +| REC { Recursive } +| { NonRecursive } + +(* -------------------------------------------------------------------------- *) + +(* A term is annotated with its start and end positions, for use in error + messages. *) + +%inline placed(X): + x = X + { { place = ($startpos, $endpos); value = x } } + +(* -------------------------------------------------------------------------- *) + +(* In a right-flexible list, the last delimiter is optional, i.e., [delim] can + be viewed as a terminator or a separator, as desired. *) + +(* There are several ways of expressing this. One could say it is either a + separated list or a terminated list; this works if one uses right recursive + lists. Or, one could say that it is a separated list followed with an + optional delimiter; this works if one uses a left-recursive list. The + following formulation is direct and seems most natural. It should lead to + the smallest possible automaton. *) + +right_flexible_list(delim, X): +| (* nothing *) + { [] } +| x = X + { [x] } +| x = X delim xs = right_flexible_list(delim, X) + { x :: xs } + +(* In a left-flexible list, the first delimiter is optional, i.e., [delim] can + be viewed as an opening or as a separator, as desired. *) + +(* Again, there are several ways of expressing this, and again, I suppose the + following formulation is simplest. It is the mirror image of the above + definition, so it is naturally left-recursive, this time. *) + +reverse_left_flexible_list(delim, X): +| (* nothing *) + { [] } +| x = X + { [x] } +| xs = reverse_left_flexible_list(delim, X) delim x = X + { x :: xs } + +%inline left_flexible_list(delim, X): + xs = reverse_left_flexible_list(delim, X) + { List.rev xs } diff --git a/projet/src/RawLambda.ml b/projet/src/RawLambda.ml new file mode 100644 index 0000000..51f33e1 --- /dev/null +++ b/projet/src/RawLambda.ml @@ -0,0 +1,55 @@ +(* Variables are strings. *) + +type variable = + string + +(* Every [let] binding is marked recursive or nonrecursive. *) + +and recursive = + | Recursive + | NonRecursive + +(* The four standard integer arithmetic operations are supported. *) + +and binop = + | OpAdd + | OpSub + | OpMul + | OpDiv + +(* This language is the untyped lambda-calculus, extended with possibly + recursive [let] bindings, integer literals (that is, constants), integer + arithmetic operations, and the primitive operation [print], which prints an + integer value and returns it. *) + +and term_ = + | Var of variable + | Lam of variable * term + | App of term * term + | Lit of int + | BinOp of term * binop * term + | Print of term + | Let of recursive * variable * term * term + +(* Every abstract syntax tree node of type [term] is annotated with a place, + that is, a position in the source code. This allows us to produce a good + error message when a problem is detected. *) + +and term = + term_ placed + +(* A value of type ['a placed] can be thought of as a value of type ['a] + decorated with a place. *) + +and 'a placed = { + place: Error.place; + value: 'a + } + +(* The following annotation requests the automatic generation of a [show_] + function for each of the types defined above. For instance, the function + [show_term], of type [term -> string], converts a term to a string. These + functions can be useful during debugging. Running with [--debug] causes + every intermediate abstract syntax tree to be displayed in this way. *) + +[@@deriving show { with_path = false }] diff --git a/projet/src/Tail.ml b/projet/src/Tail.ml new file mode 100644 index 0000000..44b8b6d --- /dev/null +++ b/projet/src/Tail.ml @@ -0,0 +1,132 @@ +(* This intermediate language describes the result of the CPS transformation. + It is a lambda-calculus where the ordering of computations is explicit and + where every function call is a tail call. + + The following syntactic categories are distinguished: + + 1. "Values" include variables, integer literals, and applications of the + primitive integer operations to values. Instead of "values", they could + also be referred to as "pure expressions". They are expressions whose + evaluation terminates and has no side effect, not even memory + allocation. + + 2. "Blocks" include lambda-abstractions. Even though lambda-abstractions + are traditionally considered values, here, they are viewed as + expressions whose evaluation has a side effect, namely, the allocation + of a memory block. + + 3. "Terms" are expressions with side effects. Terms always appear in tail + position: an examination of the syntax of terms shows that a term can be + viewed as a sequence of [LetVal], [LetBlo] and [Print] instructions, + terminated with either [Exit] or [TailCall]. This implies, in + particular, that every call is a tail call. + + In contrast with the surface language, where every lambda-abstraction has + arity 1, in this calculus, lambda-abstractions of arbitrary arity are + supported. A lambda-abstraction [Lam] carries a list of formal arguments + and a function call [TailCall] carries a list of actual arguments. Partial + applications or over-applications are not supported: it is the programmer's + responsibility to ensure that every function call provides exactly as many + arguments as expected by the called function. *) + +type variable = + Atom.atom + +and self = Lambda.self = + | Self of variable + | NoSelf + +and binop = Lambda.binop = + | OpAdd + | OpSub + | OpMul + | OpDiv + +and value = + | VVar of variable + | VLit of int + | VBinOp of value * binop * value + +and block = + | Lam of self * variable list * term + +(* Terms include the following constructs: + + - The primitive operation [Exit] stops the program. + + - The tail call [TailCall (v, vs)] transfers control to the function [v] + with actual arguments [vs]. (The value [v] should be a function and its + arity should be the length of [vs].) + + - The term [Print (v, t)] prints the value [v], then executes the term [t]. + (The value [v] should be a primitive integer value.) + + - The term [LetVal (x, v, t)] binds the variable [x] to the value [v], then + executes the term [t]. + + - The term [LetBlo (x, b, t)] allocates the memory block [b] and binds the + variable [x] to its address, then executes the term [t]. *) + +and term = + | Exit + | TailCall of value * value list + | Print of value * term + | LetVal of variable * value * term + | LetBlo of variable * block * term + +[@@deriving show { with_path = false }] + +(* -------------------------------------------------------------------------- *) + +(* Constructor functions. *) + +let vvar x = + VVar x + +let vvars xs = + List.map vvar xs + +(* -------------------------------------------------------------------------- *) + +(* Computing the free variables of a value, block, or term. *) + +open Atom.Set + +let rec fv_value (v : value) = + match v with + | VVar x -> + singleton x + | VLit _ -> + empty + | VBinOp (v1, _, v2) -> + union (fv_value v1) (fv_value v2) + +and fv_values (vs : value list) = + union_many fv_value vs + +and fv_lambda (xs : variable list) (t : term) = + diff (fv_term t) (of_list xs) + +and fv_block (b : block) = + match b with + | Lam (NoSelf, xs, t) -> + fv_lambda xs t + | Lam (Self f, xs, t) -> + remove f (fv_lambda xs t) + +and fv_term (t : term) = + match t with + | Exit -> + empty + | TailCall (v, vs) -> + fv_values (v :: vs) + | Print (v1, t2) -> + union (fv_value v1) (fv_term t2) + | LetVal (x, v1, t2) -> + union + (fv_value v1) + (remove x (fv_term t2)) + | LetBlo (x, b1, t2) -> + union + (fv_block b1) + (remove x (fv_term t2)) diff --git a/projet/src/Top.ml b/projet/src/Top.ml new file mode 100644 index 0000000..edbb0fb --- /dev/null +++ b/projet/src/Top.ml @@ -0,0 +1,94 @@ +(* This intermediate language describes the result of defunctionalization. + It retains the key features of the previous calculus, [Tail], in that + the ordering of computations is explicit and every function call is a + tail call. Furthermore, lambda-abstractions disappear. A memory block + [Con] now contains an integer tag followed with a number of fields, + which hold values. A [switch] construct appears, which allows testing + the tag of a memory block. A number of (closed, mutually recursive) + functions can be defined at the top level. *) + +type tag = + int + +and variable = + Atom.atom + +and binop = Tail.binop = + | OpAdd + | OpSub + | OpMul + | OpDiv + +and value = Tail.value = + | VVar of variable + | VLit of int + | VBinOp of value * binop * value + +(* A block contains an integer tag, followed with a number of fields. *) + +and block = + | Con of tag * value list + +(* The construct [Swi (v, branches)] reads the integer tag stored in the + memory block at address [v] and performs a case analysis on this tag, + transferring control to the appropriate branch. (The value [v] should be a + pointer to a memory block.) *) + +and term = + | Exit + | TailCall of variable * value list + | Print of value * term + | LetVal of variable * value * term + | LetBlo of variable * block * term + | Swi of value * branch list + +(* A branch [tag xs -> t] is labeled with an integer tag [tag], and is + executed if the memory block carries this tag. The variables [xs] are + then bounds to the fields of the memory block. (The length of the list + [xs] should be the number of fields of the memory block.) *) + +and branch = + | Branch of tag * variable list * term + +(* A toplevel function declaration mentions the function's name, formal + parameters, and body. *) + +and function_declaration = + | Fun of variable * variable list * term + +(* A complete program consits of a set of toplevel function declarations + and a term (the "main program"). The functions are considered mutually + recursive: every function may refer to every function. *) + +and program = + | Prog of function_declaration list * term + +[@@deriving show { with_path = false }] + +(* -------------------------------------------------------------------------- *) + +(* Constructor functions. *) + +let vvar = + Tail.vvar + +let vvars = + Tail.vvars + +(* [let x_1 = v_1 in ... let x_n = v_n in t] *) + +let rec sequential_let (xs : variable list) (vs : value list) (t : term) = + match xs, vs with + | [], [] -> + t + | x :: xs, v :: vs -> + LetVal (x, v, sequential_let xs vs t) + | _ -> + assert false + +(* [let x_1 = v_1 and ... x_n = v_n in t] *) + +let parallel_let (xs : variable list) (vs : value list) (t : term) = + assert (List.length xs = List.length vs); + assert (Atom.Set.disjoint (Atom.Set.of_list xs) (Tail.fv_values vs)); + sequential_let xs vs t diff --git a/projet/src/_tags b/projet/src/_tags new file mode 100644 index 0000000..bf1bddf --- /dev/null +++ b/projet/src/_tags @@ -0,0 +1,8 @@ +true: \ + debug, \ + strict_sequence, \ + warn(A-3-4-30-44-42-45-50), \ + package(unix), \ + package(process), \ + package(pprint), \ + package(ppx_deriving.std) diff --git a/projet/src/alphalib/Atom.ml b/projet/src/alphalib/Atom.ml new file mode 100644 index 0000000..6502410 --- /dev/null +++ b/projet/src/alphalib/Atom.ml @@ -0,0 +1,215 @@ +(* -------------------------------------------------------------------------- *) + +(* We impose maximal sharing on strings so as to reduce the total amount of + space that they occupy. This is done using a weak hash set. *) + +module StringStorage = + Weak.Make(struct + type t = string + let equal (s1 : string) (s2 : string) = (s1 = s2) + let hash = Hashtbl.hash + end) + +let share : string -> string = + StringStorage.merge (StringStorage.create 128) + +(* -------------------------------------------------------------------------- *) + +(* Removing any trailing digits in a string. *) + +let is_digit c = + Char.code '0' <= Char.code c && Char.code c <= Char.code '9' + +let remove_trailing_digits (s : string) : string = + let n = ref (String.length s) in + while !n > 0 && is_digit s.[!n-1] do n := !n-1 done; + (* We assume that there is at least one non-digit character in the string. *) + assert (!n > 0); + String.sub s 0 !n + +(* -------------------------------------------------------------------------- *) + +(* An atom is implemented as a pair of an integer identity and a string that + serves as a printing hint. *) + +(* We maintain the invariant that a hint is nonempty and does not end in a + digit. This allows us to later produce unique identifiers, without risk of + collisions, by concatenating a hint and a unique number. *) + +(* To preserve space, hints are maximally shared. This is not essential for + correctness, though. *) + +type atom = { identity: int; hint: string } + +and t = atom + [@@deriving show { with_path = false }] + +let identity a = + a.identity + +let hint a = + a.hint + +(* -------------------------------------------------------------------------- *) + +(* A global integer counter holds the next available identity. *) + +let counter = + ref 0 + +let allocate () = + let number = !counter in + counter := number + 1; + assert (number >= 0); + number + +(* [fresh hint] produces a fresh atom. *) + +(* The argument [hint] must not be a string of digits. *) + +let fresh hint = + let identity = allocate() + and hint = share (remove_trailing_digits hint) in + { identity; hint } + +(* [copy a] returns a fresh atom modeled after the atom [a]. *) + +let copy a = + fresh a.hint + +(* -------------------------------------------------------------------------- *) + +(* Comparison of atoms. *) + +let equal a b = + a.identity = b.identity + +let compare a b = + (* Identities are always positive numbers (see [allocate] above) + so I believe overflow is impossible here. *) + a.identity - b.identity + +let hash a = + Hashtbl.hash a.identity + +(* -------------------------------------------------------------------------- *) + +(* A scratch buffer for printing. *) + +let scratch = + Buffer.create 1024 + +(* [print_separated_sequence] prints a sequence of elements into the [scratch] + buffer. The sequence is given by the higher-order iterator [iter], applied + to the collection [xs]. The separator is the string [sep]. Each element is + transformed to a string by the function [show]. *) + +let print_separated_sequence show sep iter xs : unit = + let first = ref true in + iter (fun x -> + if !first then begin + Buffer.add_string scratch (show x); + first := false + end + else begin + Buffer.add_string scratch sep; + Buffer.add_string scratch (show x) + end + ) xs + +(* -------------------------------------------------------------------------- *) + +(* Sets and maps. *) + +module Order = struct + type t = atom + let compare = compare +end + +module Set = struct + + include Set.Make(Order) + + (* A disjointness test. *) + + let disjoint xs ys = + is_empty (inter xs ys) + + (* Iterated union. *) + + let union_many (f : 'a -> t) (xs : 'a list) : t = + List.fold_left (fun accu x -> + union accu (f x) + ) empty xs + + (* Disjoint union. *) + + exception NonDisjointUnion of atom + + let disjoint_union xs ys = + match choose (inter xs ys) with + | exception Not_found -> + (* The intersection of [xs] and [ys] is empty. Return their union. *) + union xs ys + | x -> + (* The intersection contains [x]. Raise an exception. *) + raise (NonDisjointUnion x) + + let handle_NonDisjointUnion f x = + try + f x; true + with NonDisjointUnion a -> + Printf.eprintf "NonDisjointUnion: %s\n%!" (show a); + false + + (* Sets of atoms form a monoid under union. *) + + class ['z] union_monoid = object + method zero: 'z = empty + method plus: 'z -> 'z -> 'z = union + end + + (* Sets of atoms form a monoid under disjoint union. *) + + class ['z] disjoint_union_monoid = object + method zero: 'z = empty + method plus: 'z -> 'z -> 'z = disjoint_union + end + + (* These printing functions should be used for debugging purposes only. *) + + let print_to_scratch xs = + Buffer.clear scratch; + Buffer.add_string scratch "{"; + print_separated_sequence show ", " iter xs; + Buffer.add_string scratch "}" + + let show xs = + print_to_scratch xs; + let result = Buffer.contents scratch in + Buffer.reset scratch; + result + + let print oc xs = + print_to_scratch xs; + Buffer.output_buffer oc scratch; + Buffer.reset scratch + +end + +module Map = struct + + include Map.Make(Order) + + (* This is O(nlog n), whereas in principle O(n) is possible. + The abstraction barrier in OCaml's [Set] module hinders us. *) + let domain m = + fold (fun a _ accu -> Set.add a accu) m Set.empty + + let codomain f m = + fold (fun _ v accu -> Set.union (f v) accu) m Set.empty + +end + +type renaming = + atom Map.t diff --git a/projet/src/alphalib/Atom.mli b/projet/src/alphalib/Atom.mli new file mode 100644 index 0000000..6ec6206 --- /dev/null +++ b/projet/src/alphalib/Atom.mli @@ -0,0 +1,71 @@ +(* TEMPORARY document *) + +(* An atom is a pair of a unique integer identity and a (not necessarily + unique) string. *) + +type atom + +and t = atom + [@@deriving show] + +val identity: atom -> int +val hint: atom -> string + +(* Producing fresh atoms. *) + +val fresh: string -> atom +val copy: atom -> atom + +(* Comparison of atoms. *) + +val equal: atom -> atom -> bool +val compare: atom -> atom -> int +val hash: atom -> int + +(* Sets. *) + +module Set : sig + include Set.S with type elt = atom + + val disjoint: t -> t -> bool + + val union_many: ('a -> t) -> 'a list -> t + + (* Disjoint union. *) + + exception NonDisjointUnion of atom + val disjoint_union: t -> t -> t + + val handle_NonDisjointUnion: ('a -> unit) -> 'a -> bool + + (* Sets of atoms form monoids under union and disjoint union. *) + + class ['z] union_monoid : object + constraint 'z = t + method zero: 'z + method plus: 'z -> 'z -> 'z + end + + class ['z] disjoint_union_monoid : object + constraint 'z = t + method zero: 'z + method plus: 'z -> 'z -> 'z + end + + val show: t -> string + val print: out_channel -> t -> unit +end + +(* Maps. *) + +module Map : sig + + include Map.S with type key = atom + + val domain: 'a t -> Set.t + val codomain: ('a -> Set.t) -> 'a t -> Set.t + +end + +type renaming = + atom Map.t diff --git a/projet/src/kremlin/C.ml b/projet/src/kremlin/C.ml new file mode 100644 index 0000000..db29569 --- /dev/null +++ b/projet/src/kremlin/C.ml @@ -0,0 +1,126 @@ + + +module K = Constant +open Common + +(* This pretty-printer based on: http:/ /en.cppreference.com/w/c/language/declarations + * Many cases are omitted from this bare-bones C grammar; hopefully, to be extended. *) +type type_spec = + | Int of Constant.width + | Void + | Named of ident + | Struct of ident option * declaration list option + (** Note: the option allows for zero-sized structs (GCC's C, C++) but as + * of 2017/05/14 we never generate these. *) + | Union of ident option * declaration list + | Enum of ident option * ident list + (** not encoding all the invariants here *) + [@@deriving show { with_path = false }] + +and storage_spec = + | Typedef + | Extern + | Static + +and declarator_and_init = + declarator * init option + +and declarator_and_inits = + declarator_and_init list + +and declarator = + | Ident of ident + | Pointer of declarator + | Array of declarator * expr + | Function of calling_convention option * declarator * params + +and expr = + | Op1 of K.op * expr + | Op2 of K.op * expr * expr + | Index of expr * expr + | Deref of expr + | Address of expr + | Member of expr * expr + | MemberP of expr * expr + | Assign of expr * expr + (** not covering *=, +=, etc. *) + | Call of expr * expr list + | Name of ident + | Cast of type_name * expr + | Literal of string + | Constant of K.t + | Bool of bool + | Sizeof of expr + | SizeofType of type_spec + | CompoundLiteral of type_name * init list + | MemberAccess of expr * ident + | MemberAccessPointer of expr * ident + | InlineComment of string * expr * string + | Type of type_name + (** note: these two not in the C grammar *) + +(** this is a WILD approximation of the notion of "type name" in C _and_ a hack + * because there's the invariant that the ident found at the bottom of the + * [declarator] is irrelevant... *) +and type_name = + type_spec * declarator + +and params = + (* No support for old syntax, e.g. K&R, or [void f(void)]. *) + param list + +and param = + (** Also approximate. *) + type_spec * declarator + +and declaration = + type_spec * storage_spec option * declarator_and_inits + +and ident = + string + +and init = + | InitExpr of expr + | Designated of designator * init + | Initializer of init list + +and designator = + | Dot of ident + | Bracket of int + +(** Note: according to http:/ /en.cppreference.com/w/c/language/statements, + * declarations can only be part of a compound statement... we do not enforce + * this invariant via the type [stmt], but rather check it at runtime (see + * [mk_compound_if]), as the risk of messing things up, naturally. *) +type stmt = + | Compound of stmt list + | DeclStmt of declaration + | Expr of expr + | If of expr * stmt + | IfElse of expr * stmt * stmt + | While of expr * stmt + | For of declaration_or_expr * expr * expr * stmt + | Return of expr option + | Switch of expr * (expr * stmt) list * stmt + (** the last component is the default statement *) + | Break + | Comment of string + (** note: this is not in the C grammar *) + +and program = + declaration_or_function list + +and comment = + string + +and declaration_or_function = + | Decl of comment list * declaration + | Function of comment list * bool * declaration * stmt + (** [stmt] _must_ be a compound statement; boolean is inline *) + +and declaration_or_expr = [ + | `Decl of declaration + | `Expr of expr + | `Skip +] +[@@deriving show { with_path = false }] diff --git a/projet/src/kremlin/Common.ml b/projet/src/kremlin/Common.ml new file mode 100644 index 0000000..77638d7 --- /dev/null +++ b/projet/src/kremlin/Common.ml @@ -0,0 +1,19 @@ +type calling_convention = + | StdCall + | CDecl + | FastCall + [@@deriving show { with_path = false }] + +type lifetime = + | Eternal + | Stack + [@@deriving show { with_path = false }] + +type flag = + | Private + | NoExtract + | CInline + | Substitute + | GcType + | Comment of string + [@@deriving show { with_path = false }] diff --git a/projet/src/kremlin/Constant.ml b/projet/src/kremlin/Constant.ml new file mode 100644 index 0000000..5533d38 --- /dev/null +++ b/projet/src/kremlin/Constant.ml @@ -0,0 +1,66 @@ +(** Machine integers. Don't repeat the same thing everywhere. *) + +type t = width * string + [@@deriving show] + +and width = + | UInt8 | UInt16 | UInt32 | UInt64 | Int8 | Int16 | Int32 | Int64 + | Bool + | CInt (** Checked signed integers. *) + +let bytes_of_width (w: width) = + match w with + | UInt8 -> 1 + | UInt16 -> 2 + | UInt32 -> 4 + | UInt64 -> 8 + | Int8 -> 1 + | Int16 -> 2 + | Int32 -> 4 + | Int64 -> 8 + | CInt -> 4 + | _ -> invalid_arg "bytes_of_width" + +type op = + (* Arithmetic operations *) + | Add | AddW | Sub | SubW | Div | DivW | Mult | MultW | Mod + (* Bitwise operations *) + | BOr | BAnd | BXor | BShiftL | BShiftR | BNot + (* Arithmetic comparisons / boolean comparisons *) + | Eq | Neq | Lt | Lte | Gt | Gte + (* Boolean operations *) + | And | Or | Xor | Not + (* Effectful operations *) + | Assign | PreIncr | PreDecr | PostIncr | PostDecr + (* Misc *) + | Comma + [@@deriving show { with_path = false }] + +let unsigned_of_signed = function + | Int8 -> UInt8 + | Int16 -> UInt16 + | Int32 -> UInt32 + | Int64 -> UInt64 + | CInt | UInt8 | UInt16 | UInt32 | UInt64 | Bool -> raise (Invalid_argument "unsigned_of_signed") + +let is_signed = function + | Int8 | Int16 | Int32 | Int64 | CInt -> true + | UInt8 | UInt16 | UInt32 | UInt64 -> false + | Bool -> raise (Invalid_argument "is_signed") + +let is_unsigned w = not (is_signed w) + +let without_wrap = function + | AddW -> Add + | SubW -> Sub + | MultW -> Mult + | DivW -> Div + | _ -> raise (Invalid_argument "without_wrap") + +let uint8_of_int i = + assert (i < (1 lsl 8) && i >= 0); + UInt8, string_of_int i + +let uint32_of_int i = + assert (i < (1 lsl 32) && i >= 0); + UInt32, string_of_int i diff --git a/projet/src/kremlin/Options.ml b/projet/src/kremlin/Options.ml new file mode 100644 index 0000000..fd6bfbf --- /dev/null +++ b/projet/src/kremlin/Options.ml @@ -0,0 +1,7 @@ +(* By default, the C printer inserts a minimal amount of parentheses. + However, this can trigger GCC and Clang's -Wparentheses warning, + so there is an option to produce more parentheses than strictly + necessary. *) + +let parentheses = + ref false diff --git a/projet/src/kremlin/PrintC.ml b/projet/src/kremlin/PrintC.ml new file mode 100644 index 0000000..34583ee --- /dev/null +++ b/projet/src/kremlin/PrintC.ml @@ -0,0 +1,354 @@ +(** Pretty-printer that conforms with C syntax. Also defines the grammar of + * concrete C syntax, as opposed to our idealistic, well-formed C*. *) + +open PPrint +open PrintCommon +open C + +(* Pretty-printing of actual C syntax *****************************************) + +let p_storage_spec = function + | Typedef -> string "typedef" + | Extern -> string "extern" + | Static -> string "static" + +let rec p_type_spec = function + | Int w -> print_width w ^^ string "_t" + | Void -> string "void" + | Named s -> string s + | Union (name, decls) -> + group (string "union" ^/^ + (match name with Some name -> string name ^^ break1 | None -> empty)) ^^ + braces_with_nesting (separate_map hardline (fun p -> group (p_declaration p ^^ semi)) decls) + | Struct (name, decls) -> + group (string "struct" ^/^ + (match name with Some name -> string name | None -> empty)) ^^ + (match decls with + | Some decls -> + break1 ^^ braces_with_nesting (separate_map hardline (fun p -> group (p_declaration p ^^ semi)) decls) + | None -> + empty) + | Enum (name, tags) -> + group (string "enum" ^/^ + (match name with Some name -> string name ^^ break1 | None -> empty)) ^^ + braces_with_nesting (separate_map (comma ^^ break1) string tags) + + +and p_type_declarator d = + let rec p_noptr = function + | Ident n -> + string n + | Array (d, s) -> + p_noptr d ^^ lbracket ^^ p_expr s ^^ rbracket + | Function (cc, d, params) -> + let cc = match cc with Some cc -> print_cc cc ^^ break1 | None -> empty in + group (cc ^^ p_noptr d ^^ parens_with_nesting (separate_map (comma ^^ break 1) (fun (spec, decl) -> + group (p_type_spec spec ^/^ p_any decl) + ) params)) + | d -> + lparen ^^ p_any d ^^ rparen + and p_any = function + | Pointer d -> + star ^^ p_any d + | d -> + p_noptr d + in + p_any d + +and p_type_name (spec, decl) = + match decl with + | Ident "" -> + p_type_spec spec + | _ -> + p_type_spec spec ^^ space ^^ p_type_declarator decl + +(* http:/ /en.cppreference.com/w/c/language/operator_precedence *) +and prec_of_op2 op = + let open Constant in + match op with + | AddW | SubW | MultW | DivW -> failwith "[prec_of_op]: should've been desugared" + | Add -> 4, 4, 4 + | Sub -> 4, 4, 3 + | Div -> 3, 3, 2 + | Mult -> 3, 3, 3 + | Mod -> 3, 3, 2 + | BOr -> 10, 10, 10 + | BAnd -> + 8, 8, 8 + | BXor | Xor -> 9, 9, 9 + | BShiftL | BShiftR -> + 5, 5, 4 + | Eq | Neq -> 7, 7, 7 + | Lt | Lte | Gt | Gte -> 6, 6, 5 + | And -> 11, 11, 11 + | Or -> 12, 12, 12 + | Assign -> 14, 13, 14 + | Comma -> 15, 15, 14 + | PreIncr | PostIncr | PreDecr | PostDecr | Not | BNot -> raise (Invalid_argument "prec_of_op2") + +and prec_of_op1 op = + let open Constant in + match op with + | PreDecr | PreIncr | Not | BNot -> 2 + | PostDecr | PostIncr -> 1 + | _ -> raise (Invalid_argument "prec_of_op1") + +and is_prefix op = + let open Constant in + match op with + | PreDecr | PreIncr | Not | BNot -> true + | PostDecr | PostIncr -> false + | _ -> raise (Invalid_argument "is_prefix") + +(* The precedence level [curr] is the maximum precedence the current node should + * have. If it doesn't, then it should be parenthesized. Lower numbers bind + * tighter. *) +and paren_if curr mine doc = + if curr < mine then + group (lparen ^^ doc ^^ rparen) + else + doc + +(* [e] is an operand of [op]; is this likely to trigger GCC's -Wparentheses? If + * so, downgrade the current precedence to 0 to force parenthses. *) +and defeat_Wparentheses op e prec = + let open Constant in + if not !Options.parentheses then + prec + else match op, e with + | (BShiftL | BShiftR | BXor | BOr | BAnd), Op2 ((Add | Sub | BOr | BXor), _, _) -> + 0 + | _ -> + prec + +and p_expr' curr = function + | Op1 (op, e1) -> + let mine = prec_of_op1 op in + let e1 = p_expr' mine e1 in + paren_if curr mine (if is_prefix op then print_op op ^^ e1 else e1 ^^ print_op op) + | Op2 (op, e1, e2) -> + let mine, left, right = prec_of_op2 op in + let left = defeat_Wparentheses op e1 left in + let right = defeat_Wparentheses op e2 right in + let e1 = p_expr' left e1 in + let e2 = p_expr' right e2 in + paren_if curr mine (e1 ^/^ print_op op ^^ jump e2) + | Index (e1, e2) -> + let mine, left, right = 1, 1, 15 in + let e1 = p_expr' left e1 in + let e2 = p_expr' right e2 in + paren_if curr mine (e1 ^^ lbracket ^^ e2 ^^ rbracket) + | Assign (e1, e2) -> + let mine, left, right = 14, 13, 14 in + let e1 = p_expr' left e1 in + let e2 = p_expr' right e2 in + paren_if curr mine (group (e1 ^/^ equals) ^^ jump e2) + | Call (e, es) -> + let mine, left, arg = 1, 1, 14 in + let e = p_expr' left e in + let es = nest 2 (separate_map (comma ^^ break 1) (fun e -> group (p_expr' arg e)) es) in + paren_if curr mine (e ^^ lparen ^^ es ^^ rparen) + | Literal s -> + dquote ^^ string s ^^ dquote + | Constant (w, s) -> + string s ^^ if K.is_unsigned w then string "U" else empty + | Name s -> + string s + | Cast (t, e) -> + let mine, right = 2, 2 in + let e = group (p_expr' right e) in + let t = p_type_name t in + paren_if curr mine (lparen ^^ t ^^ rparen ^^ e) + | Type t -> + p_type_name t + | Sizeof e -> + let mine, right = 2, 2 in + let e = p_expr' right e in + paren_if curr mine (string "sizeof" ^^ space ^^ e) + | SizeofType t -> + string "sizeof" ^^ group (lparen ^^ p_type_spec t ^^ rparen) + | Address e -> + let mine, right = 2, 2 in + let e = p_expr' right e in + paren_if curr mine (ampersand ^^ e) + | Deref e -> + let mine, right = 2, 2 in + let e = p_expr' right e in + paren_if curr mine (star ^^ e) + | Member _ | MemberP _ -> + failwith "[p_expr']: not implemented" + | Bool b -> + string (string_of_bool b) + | CompoundLiteral (t, init) -> + (* NOTE: always parenthesize compound literal no matter what, because GCC + * parses an application of a function to a compound literal as an n-ary + * application. *) + parens_with_nesting ( + lparen ^^ p_type_name t ^^ rparen ^^ + braces_with_nesting (separate_map (comma ^^ break1) p_init init) + ) + | MemberAccess (expr, member) -> + p_expr' 1 expr ^^ dot ^^ string member + | MemberAccessPointer (expr, member) -> + p_expr' 1 expr ^^ string "->" ^^ string member + | InlineComment (s, e, s') -> + surround 2 1 (p_comment s) (p_expr' curr e) (p_comment s') + +and p_comment s = + (* TODO: escape *) + string "/* " ^^ nest 2 (flow space (words s)) ^^ string " */" + + +and p_expr e = p_expr' 15 e + +and p_init (i: init) = + match i with + | Designated (designator, i) -> + group (p_designator designator ^^ space ^^ equals ^^ space ^^ p_init i) + | InitExpr e -> + p_expr' 14 e + | Initializer inits -> + let inits = + if List.length inits > 4 then + flow (comma ^^ break1) (List.map p_init inits) + else + separate_map (comma ^^ break1) p_init inits + in + braces_with_nesting inits + +and p_designator = function + | Dot ident -> + dot ^^ string ident + | Bracket i -> + lbracket ^^ int i ^^ rbracket + +and p_decl_and_init (decl, init) = + group (p_type_declarator decl ^^ match init with + | Some init -> + space ^^ equals ^^ jump (p_init init) + | None -> + empty) + +and p_declaration (spec, stor, decl_and_inits) = + let stor = match stor with Some stor -> p_storage_spec stor ^^ space | None -> empty in + stor ^^ group (p_type_spec spec) ^/^ + separate_map (comma ^^ break 1) p_decl_and_init decl_and_inits + +(* This is abusing the definition of a compound statement to ensure it is printed with braces. *) +let nest_if f stmt = + match stmt with + | Compound _ -> + hardline ^^ f stmt + | _ -> + nest 2 (hardline ^^ f stmt) + +(* A note on the classic dangling else problem. Remember that this is how things + * are parsed (note the indentation): + * + * if (foo) + * if (bar) + * ... + * else + * ... + * + * And remember that this needs braces: + * + * if (foo) { + * if (bar) + * ... + * } else + * ... + * + * [protect_solo_if] adds braces to the latter case. However, GCC, unless + * -Wnoparentheses is given, will produce a warning for the former case. + * [protect_ite_if_needed] adds braces to the former case, when the user has + * requested the extra, unnecessary parentheses needed to silence -Wparentheses. + * *) +let protect_solo_if s = + match s with + | If _ -> Compound [ s ] + | _ -> s + +let protect_ite_if_needed s = + match s with + | IfElse _ when !Options.parentheses -> Compound [ s ] + | _ -> s + +let p_or p x = + match x with + | Some x -> p x + | None -> empty + +let rec p_stmt (s: stmt) = + (* [p_stmt] is responsible for appending [semi] and calling [group]! *) + match s with + | Compound stmts -> + lbrace ^^ nest 2 (hardline ^^ separate_map hardline p_stmt stmts) ^^ + hardline ^^ rbrace + | Expr expr -> + group (p_expr expr ^^ semi) + | Comment s -> + group (string "/*" ^/^ separate break1 (words s) ^/^ string "*/") + | For (decl, e2, e3, stmt) -> + let init = match decl with + | `Decl decl -> p_declaration decl + | `Expr expr -> p_expr expr + | `Skip -> empty + in + group (string "for" ^/^ lparen ^^ nest 2 ( + init ^^ semi ^^ break1 ^^ + p_expr e2 ^^ semi ^^ break1 ^^ + p_expr e3 + ) ^^ rparen) ^^ nest_if p_stmt stmt + | If (e, stmt) -> + group (string "if" ^/^ lparen ^^ p_expr e ^^ rparen) ^^ + nest_if p_stmt (protect_ite_if_needed stmt) + | IfElse (e, s1, s2) -> + group (string "if" ^/^ lparen ^^ p_expr e ^^ rparen) ^^ + nest_if p_stmt (protect_solo_if s1) ^^ hardline ^^ + string "else" ^^ + (match s2 with + | If _ | IfElse _ -> + space ^^ p_stmt s2 + | _ -> + nest_if p_stmt s2) + | While (e, s) -> + group (string "while" ^/^ lparen ^^ p_expr e ^^ rparen) ^^ + nest_if p_stmt s + | Return None -> + group (string "return" ^^ semi) + | Return (Some e) -> + group (string "return" ^^ jump (p_expr e ^^ semi)) + | DeclStmt d -> + group (p_declaration d ^^ semi) + | Switch (e, branches, default) -> + group (string "switch" ^/^ lparen ^^ p_expr e ^^ rparen) ^/^ + braces_with_nesting ( + separate_map hardline (fun (e, s) -> + group (string "case" ^/^ p_expr e ^^ colon) ^^ nest 2 ( + hardline ^^ p_stmt s + ) + ) branches ^^ hardline ^^ + string "default:" ^^ nest 2 ( + hardline ^^ p_stmt default + ) + ) + | Break -> + string "break" ^^ semi + +let p_comments cs = + separate_map hardline (fun c -> string ("/*\n" ^ c ^ "\n*/")) cs ^^ + if List.length cs > 0 then hardline else empty + +let p_decl_or_function (df: declaration_or_function) = + match df with + | Decl (comments, d) -> + p_comments comments ^^ + group (p_declaration d ^^ semi) + | Function (comments, inline, d, stmt) -> + p_comments comments ^^ + let inline = if inline then string "inline" ^^ space else empty in + inline ^^ group (p_declaration d) ^/^ p_stmt stmt + +let print_files = + PrintCommon.print_files p_decl_or_function diff --git a/projet/src/kremlin/PrintCommon.ml b/projet/src/kremlin/PrintCommon.ml new file mode 100644 index 0000000..84e2b40 --- /dev/null +++ b/projet/src/kremlin/PrintCommon.ml @@ -0,0 +1,96 @@ +open PPrint +open Constant +open Common + +let break1 = break 1 + +let jump ?(indent=2) body = + jump indent 1 body + +let parens_with_nesting contents = + surround 2 0 lparen contents rparen + +let braces_with_nesting contents = + surround 2 1 lbrace contents rbrace + +let int i = string (string_of_int i) + +let print_width = function + | UInt8 -> string "uint8" + | UInt16 -> string "uint16" + | UInt32 -> string "uint32" + | UInt64 -> string "uint64" + | CInt -> string "krml_checked_int" + | Int8 -> string "int8" + | Int16 -> string "int16" + | Int32 -> string "int32" + | Int64 -> string "int64" + | Bool -> string "bool" + +let print_constant = function + | w, s -> string s ^^ print_width w + +let print_op = function + | Add -> string "+" + | AddW -> string "+w" + | Sub -> string "-" + | SubW -> string "-" + | Div -> string "/" + | DivW -> string "/w" + | Mult -> string "*" + | MultW -> string "*w" + | Mod -> string "%" + | BOr -> string "|" + | BAnd -> string "&" + | BXor -> string "^" + | BNot -> string "~" + | BShiftL -> string "<<" + | BShiftR -> string ">>" + | Eq -> string "==" + | Neq -> string "!=" + | Lt -> string "<" + | Lte -> string "<=" + | Gt -> string ">" + | Gte -> string ">=" + | And -> string "&&" + | Or -> string "||" + | Xor -> string "^" + | Not -> string "!" + | PostIncr | PreIncr -> string "++" + | PostDecr | PreDecr -> string "--" + | Assign -> string "=" + | Comma -> string "," + +let print_cc = function + | CDecl -> string "__cdecl" + | StdCall -> string "__stdcall" + | FastCall -> string "__fastcall" + +let print_lident (idents, ident) = + separate_map dot string (idents @ [ ident ]) + +let print_program p decls = + separate_map (hardline ^^ hardline) p decls + +let print_files print_decl files = + separate_map hardline (fun (f, p) -> + string (String.uppercase f) ^^ colon ^^ jump (print_program print_decl p) + ) files + +let printf_of_pprint f = + fun buf t -> + PPrint.ToBuffer.compact buf (f t) + +let printf_of_pprint_pretty f = + fun buf t -> + PPrint.ToBuffer.pretty 0.95 Utils.twidth buf (f t) + +let pdoc buf d = + PPrint.ToBuffer.compact buf d + +let english_join s = + match List.rev s with + | [] -> empty + | [ x ] -> x + | last :: first -> + group (separate (comma ^^ break1) (List.rev first) ^/^ string "and" ^/^ last) diff --git a/projet/src/kremlin/Utils.ml b/projet/src/kremlin/Utils.ml new file mode 100644 index 0000000..1ac1256 --- /dev/null +++ b/projet/src/kremlin/Utils.ml @@ -0,0 +1,73 @@ +let try_finally f h = let result = + try + f () + with e -> + h (); + raise e + in + h (); + result + +let with_open_in file_path f = + let c = open_in_bin file_path in + try_finally (fun () -> + f c + ) (fun () -> + close_in c + ) + +let with_open_out file_path f = + let c = open_out file_path in + try_finally (fun () -> + f c + ) (fun () -> + close_out c + ) + + +let cp dst src = with_open_out dst (fun oc -> + with_open_in src (fun ic -> + let buf = Bytes.create 2048 in + while + let l = input ic buf 0 2048 in + if l > 0 then begin + output oc buf 0 l; + true + end else + false + do () done + )) + + +let read ic = + let buf = Buffer.create 4096 in + let s = String.create 2048 in + while begin + let l = input ic s 0 (String.length s) in + if l > 0 then begin + Buffer.add_string buf (String.sub s 0 l); + true + end else begin + false + end + end do () done; + Buffer.contents buf + +let file_get_contents f = + with_open_in f read + +(** Sniff the size of the terminal for optimal use of the width. *) +let theight, twidth = + let height, width = ref 0, ref 0 in + match + Scanf.sscanf (List.hd (Process.read_stdout "stty" [|"size"|])) "%d %d" (fun h w -> + height := h; + width := w); + !height, !width + with + | exception _ -> + 24, 80 + | 0, 0 -> + 24, 80 + | h, w -> + h, w diff --git a/projet/src/prologue.h b/projet/src/prologue.h new file mode 100644 index 0000000..239161f --- /dev/null +++ b/projet/src/prologue.h @@ -0,0 +1,83 @@ +/* A forward declaration of [block] -- see below. */ + +struct block; + +/* -------------------------------------------------------------------------- */ + +/* The type [univ] is the universal type of the values that we manipulate. + A value is either an integer or a pointer to a heap-allocated memory + block. A C union is used to represent this disjunction. There is no tag + to distinguish between the two alternatives! The source program had + better be well-typed. */ + +typedef union { + + /* Either this is an integer... */ + int literal; + + /* ... or this is a pointer to a block. */ + struct block* pointer; + +} univ; + +/* -------------------------------------------------------------------------- */ + +/* The struct [block] describes the uniform layout of a heap-allocated + memory block. A block begins with an integer tag and continues with a + sequence of fields of type [univ]. */ + +struct block { + + /* Every memory block begins with an integer tag. */ + int tag; + + /* Then, we have a sequence of fields, whose number depends on the tag. + This idiom is known in C99 as a flexible array member. */ + univ data[]; + +}; + +/* -------------------------------------------------------------------------- */ + +/* Basic operations on memory blocks. */ + +/* The macro [ALLOC(n)] allocates a block of [n] fields, and is used in a + context where an expression of type [univ] is expected. We use a C + "compound literal" containing a "designated initializer" to indicate + that we wish to choose the "pointer" side of the union. We implicitly + assume that the compiler inserts no padding between the "tag" and "data" + parts of a memory block, so [(n + 1) * sizeof(univ)] is enough space to + hold a block of [n] fields. */ + +#define ALLOC(n) \ + (univ) { .pointer = malloc((n + 1) * sizeof(univ)) } + +/* In the following macros, [u] has type [univ], so [u.pointer] has type + [struct block] and is (or should be) the address of a memory block. + [i] is a field number; the numbering of fields is 0-based. */ + +#define GET_TAG(u) \ + (u.pointer->tag) + +#define SET_TAG(u,t) \ + (u.pointer->tag = t) + +#define GET_FIELD(u,i) \ + (u.pointer->data[i]) + +#define SET_FIELD(u,i,v) \ + (u.pointer->data[i]=v) + +/* -------------------------------------------------------------------------- */ + +/* Basic operations on integers. */ + +/* The macro [FROM_INT(i)] converts the integer [i] to the type [univ]. */ + +#define FROM_INT(i) \ + (univ) { .literal = i } + +/* The macro [TO_INT(u)] converts [u] to the type [int]. */ + +#define TO_INT(u) \ + u.literal diff --git a/projet/src/test/.gitignore b/projet/src/test/.gitignore new file mode 100644 index 0000000..55b60e0 --- /dev/null +++ b/projet/src/test/.gitignore @@ -0,0 +1 @@ +test.native diff --git a/projet/src/test/.merlin b/projet/src/test/.merlin new file mode 100644 index 0000000..1a1fd25 --- /dev/null +++ b/projet/src/test/.merlin @@ -0,0 +1 @@ +B _build diff --git a/projet/src/test/Makefile b/projet/src/test/Makefile new file mode 100644 index 0000000..d66fadf --- /dev/null +++ b/projet/src/test/Makefile @@ -0,0 +1,21 @@ +OCAMLBUILD := ocamlbuild -use-ocamlfind -classic-display +TARGET := test.native +TESTS := ../tests + +.PHONY: all test expected clean + +all: + @ $(OCAMLBUILD) $(TARGET) + +test: all + @ $(MAKE) -C .. + @ ./$(TARGET) --verbosity 1 + +expected: all + @ $(MAKE) -C .. + @ ./$(TARGET) --verbosity 1 --create-expected + +clean: + @ rm -f *~ *.native *.byte + @ $(OCAMLBUILD) -clean + @ rm -f $(TESTS)/*.c $(TESTS)/*.exe $(TESTS)/*.out $(TESTS)/*.err $(TESTS)/*~ diff --git a/projet/src/test/_tags b/projet/src/test/_tags new file mode 100644 index 0000000..749aa28 --- /dev/null +++ b/projet/src/test/_tags @@ -0,0 +1,3 @@ +true: \ + warn(A-44), \ + package(unix) diff --git a/projet/src/test/auxiliary.ml b/projet/src/test/auxiliary.ml new file mode 100644 index 0000000..a7bd0c4 --- /dev/null +++ b/projet/src/test/auxiliary.ml @@ -0,0 +1,138 @@ +type filename = string +type command = string + +let has_suffix suffix name = + Filename.check_suffix name suffix + +let fail format = + Printf.kprintf failwith format + +let try_finally f h = + let result = try f() with e -> h(); raise e in + h(); result + +let with_process_code_result command (f : in_channel -> 'a) : int * 'a = + let ic = Unix.open_process_in command in + set_binary_mode_in ic false; + match f ic with + | exception e -> + ignore (Unix.close_process_in ic); raise e + | result -> + match Unix.close_process_in ic with + | Unix.WEXITED code -> + code, result + | Unix.WSIGNALED _ + | Unix.WSTOPPED _ -> + 99 (* arbitrary *), result + +let with_process_result command (f : in_channel -> 'a) : 'a = + let code, result = with_process_code_result command f in + if code = 0 then + result + else + fail "Command %S failed with exit code %d." command code + +let with_open_in filename (f : in_channel -> 'a) : 'a = + let ic = open_in filename in + try_finally + (fun () -> f ic) + (fun () -> close_in_noerr ic) + +let with_open_out filename (f : out_channel -> 'a) : 'a = + let oc = open_out filename in + try_finally + (fun () -> f oc) + (fun () -> close_out_noerr oc) + +let chunk_size = + 16384 + +let exhaust (ic : in_channel) : string = + let buffer = Buffer.create chunk_size in + let chunk = Bytes.create chunk_size in + let rec loop () = + let length = input ic chunk 0 chunk_size in + if length = 0 then + Buffer.contents buffer + else begin + Buffer.add_subbytes buffer chunk 0 length; + loop() + end + in + loop() + +let read_whole_file filename = + with_open_in filename exhaust + +let absolute_directory (path : string) : string = + try + let pwd = Sys.getcwd() in + Sys.chdir path; + let result = Sys.getcwd() in + Sys.chdir pwd; + result + with Sys_error _ -> + Printf.fprintf stderr "Error: the directory %s does not seem to exist.\n" path; + exit 1 + +let get_number_of_cores () = + try match Sys.os_type with + | "Win32" -> + int_of_string (Sys.getenv "NUMBER_OF_PROCESSORS") + | _ -> + with_process_result "getconf _NPROCESSORS_ONLN" (fun ic -> + let ib = Scanf.Scanning.from_channel ic in + Scanf.bscanf ib "%d" (fun n -> n) + ) + with + | Not_found + | Sys_error _ + | Failure _ + | Scanf.Scan_failure _ + | End_of_file + | Unix.Unix_error _ -> + 1 + +let silent command : command = + command ^ " >/dev/null 2>/dev/null" + +(* [groups eq xs] segments the list [xs] into a list of groups, where several + consecutive elements belong in the same group if they are equivalent in the + sense of the function [eq]. *) + +(* The auxiliary function [groups1] deals with the case where we have an open + group [group] of which [x] is a member. The auxiliary function [group0] + deals with the case where we have no open group. [groups] is the list of + closed groups found so far, and [ys] is the list of elements that remain to + be examined. *) + +let rec groups1 eq groups x group ys = + match ys with + | [] -> + group :: groups + | y :: ys -> + if eq x y then + groups1 eq groups x (y :: group) ys + else + groups0 eq (List.rev group :: groups) (y :: ys) + +and groups0 eq groups ys = + match ys with + | [] -> + groups + | y :: ys -> + groups1 eq groups y [y] ys + +let groups eq (xs : 'a list) : 'a list list = + List.rev (groups0 eq [] xs) + +(* [sep ss] separates the nonempty strings in the list [ss] with a space, + and concatenates everything, producing a single string. *) + +let sep (ss : string list) : string = + let ss = List.filter (fun s -> String.length s > 0) ss in + match ss with + | [] -> + "" + | s :: ss -> + List.fold_left (fun s1 s2 -> s1 ^ " " ^ s2) s ss diff --git a/projet/src/test/test.ml b/projet/src/test/test.ml new file mode 100644 index 0000000..fe98195 --- /dev/null +++ b/projet/src/test/test.ml @@ -0,0 +1,288 @@ +open Sys +open Array +open List +open Filename +open Printf +open Auxiliary + +(* -------------------------------------------------------------------------- *) + +(* Settings. *) + +let create_expected = + ref false + +let verbosity = + ref 0 + +let usage = + sprintf "Usage: %s\n" argv.(0) + +let spec = Arg.align [ + "--create-expected", Arg.Set create_expected, + " recreate the expected-output files"; + "--verbosity", Arg.Int ((:=) verbosity), + " set the verbosity level (0-2)"; +] + +let () = + Arg.parse spec (fun _ -> ()) usage + +let create_expected = + !create_expected + +let verbosity = + !verbosity + +(* -------------------------------------------------------------------------- *) + +(* Logging. *) + +(* 0 is minimal verbosity; + 1 shows some progress messages; + 2 is maximal verbosity. *) + +let log level format = + kprintf (fun s -> + if level <= verbosity then + print_string s + ) format + +(* Extend [fail] to display an information message along the way. + The message is immediately emitted by the worker, depending on + the verbosity level, whereas the failure message is sent back + to the master. *) + +let fail id format = + log 1 "[FAIL] %s\n%!" id; + fail format + +(* When issuing an external command, log it along the way. *) + +let command cmd = + log 2 "%s\n%!" cmd; + command cmd + +(* -------------------------------------------------------------------------- *) + +(* Paths. *) + +let root = + absolute_directory ".." + +let src = + root + +let good = + root ^ "/tests" + +let good_slash filename = + good ^ "/" ^ filename + +let joujou = + src ^ "/joujou" + +let gcc = + sprintf "gcc -O2 -I %s" src + +(* -------------------------------------------------------------------------- *) + +(* Test files. *) + +let thisfile = + "this input file" + +let lambda basename = + basename ^ ".lambda" + +(* -------------------------------------------------------------------------- *) + +(* Test inputs and outputs. *) + +(* A test input is a basename, without the .lambda extension. *) + +type input = + | PositiveTest of filename + +type inputs = input list + +let print_input = function + | PositiveTest basename -> + basename + +type outcome = + | OK + | Fail of string (* message *) + +let print_outcome = function + | OK -> + "" + | Fail msg -> + msg + +type output = + input * outcome + +type outputs = output list + +let print_output (input, outcome) = + printf "\n[FAIL] %s\n%s" + (print_input input) + (print_outcome outcome) + +(* -------------------------------------------------------------------------- *) + +(* Auxiliary functions. *) + +let check_expected directory id result expected = + let cmd = sep ["cd"; directory; "&&"; "cp"; "-f"; result; expected] in + let copy() = + if command cmd <> 0 then + fail id "Failed to create %s.\n" expected + in + (* If we are supposed to create the [expected] file, do so. *) + if create_expected then + copy() + (* Otherwise, check that the file [expected] exists. If it does not exist, + create it by renaming [result] to [expected], then fail and invite the + user to review the newly created file. *) + else if not (file_exists (directory ^ "/" ^ expected)) then begin + copy(); + let cmd = sep ["more"; directory ^ "/" ^ expected] in + fail id "The file %s did not exist.\n\ + I have just created it. Please review it.\n %s\n" + expected cmd + end + +(* -------------------------------------------------------------------------- *) + +(* Running a positive test. *) + +(* + Conventions: + The file %.c stores the output of joujou. + The file %.exe is the compiled program produced by gcc. + The file %.out stores the output of the compiled program. + The file %.exp stores the expected output. + The file %.err stores error output (at several stages). + *) + +let process_positive_test (base : string) : unit = + + (* Display an information message. *) + log 2 "Testing %s...\n%!" base; + + (* A suggested command. *) + let more filename = + sep ["more"; good_slash filename] + in + + (* Run joujou. *) + let source = lambda base in + let c = base ^ ".c" in + let errors = base ^ ".err" in + let cmd = sep ( + "cd" :: good :: "&&" :: + joujou :: source :: sprintf ">%s" c :: sprintf "2>%s" errors :: [] + ) in + if command cmd <> 0 then + fail base "joujou fails on this source file.\n\ + To see the source file:\n %s\n\ + To see the error messages:\n %s\n" + (more source) (more errors); + + (* Run the C compiler. *) + let binary = base ^ ".exe" in + let errors = base ^ ".err" in + let cmd = sep ( + "cd" :: good :: "&&" :: + gcc :: c :: "-o" :: binary :: sprintf "2>%s" errors :: [] + ) in + if command cmd <> 0 then + fail base "The C compiler rejects the C file.\n\ + To see the C file:\n %s\n\ + To see the compiler's error messages:\n %s\n" + (more c) (more errors); + + (* Run the compiled program. *) + let out = base ^ ".out" in + let cmd = sep ( + "cd" :: good :: "&&" :: + sprintf "./%s" binary :: sprintf ">%s" out :: "2>&1" :: [] + ) in + if command cmd <> 0 then + fail base "The compiled program fails.\n\ + To see its output:\n %s\n" (more out); + + (* Check that the file [exp] exists. *) + let exp = base ^ ".exp" in + check_expected good base out exp; + + (* Check that the output coincides with what was expected. *) + let cmd = sep ("cd" :: good :: "&&" :: "diff" :: exp :: out :: []) in + if command (silent cmd) <> 0 then + fail base "joujou accepts this input file, but produces incorrect output.\n\ + To see the difference:\n (%s)\n" + cmd; + + (* Succeed. *) + log 1 "[OK] %s\n%!" base + +(* -------------------------------------------------------------------------- *) + +(* Running a test. *) + +let process input : output = + try + begin match input with + | PositiveTest basenames -> + process_positive_test basenames + end; + input, OK + with Failure msg -> + input, Fail msg + +(* -------------------------------------------------------------------------- *) + +(* [run] runs a bunch of tests in sequence. *) + +let run (inputs : inputs) : outputs = + flush stdout; flush stderr; + let outputs = map process inputs in + outputs + +(* -------------------------------------------------------------------------- *) + +(* Main. *) + +(* Menhir can accept several .mly files at once. By convention, if several + files have the same name up to a numeric suffix, then they belong in a + single group and should be fed together to Menhir. *) + +let inputs directory : filename list = + readdir directory + |> to_list + |> filter (has_suffix ".lambda") + |> map chop_extension + |> sort compare + +let positive : inputs = + inputs good + |> map (fun basename -> PositiveTest basename) + +let inputs = + positive + +let outputs : outputs = + printf "Preparing to run %d tests...\n%!" (length inputs); + run inputs + +let successful, failed = + partition (fun (_, o) -> o = OK) outputs + +let () = + printf "%d out of %d tests are successful.\n" + (length successful) (length inputs); + failed |> iter (fun (input, outcome) -> + printf "\n[FAIL] %s\n%s" (print_input input) (print_outcome outcome) + ) diff --git a/projet/src/tests/.gitignore b/projet/src/tests/.gitignore new file mode 100644 index 0000000..9038d29 --- /dev/null +++ b/projet/src/tests/.gitignore @@ -0,0 +1,4 @@ +*.err +*.out +*.exe +*.c diff --git a/projet/src/tests/bool.exp b/projet/src/tests/bool.exp new file mode 100644 index 0000000..829400e --- /dev/null +++ b/projet/src/tests/bool.exp @@ -0,0 +1,20 @@ +1 +0 +1 +0 +0 +24 +120 +8 +13 +5 +0 +1 +7 +1 +1 +2 +6 +24 +120 +42 diff --git a/projet/src/tests/bool.lambda b/projet/src/tests/bool.lambda new file mode 100644 index 0000000..6eaf5da --- /dev/null +++ b/projet/src/tests/bool.lambda @@ -0,0 +1,88 @@ +(* Thunks. *) +let force = fun x -> x 0 in +(* Church Booleans. *) +let false = fun x -> fun y -> y in +let true = fun x -> fun y -> x in +let k = true in +let cond = fun p -> fun x -> fun y -> p x y in +let forcecond = fun p -> fun x -> fun y -> force (p x y) in +let bool2int = fun b -> cond b 1 0 in +let _ = print (bool2int true) in +let _ = print (bool2int false) in +(* Church pairs. *) +let pair = fun x -> fun y -> fun p -> cond p x y in +let fst = fun p -> p true in +let snd = fun p -> p false in +(* Church naturals. *) +let zero = fun f -> fun x -> x in +let one = fun f -> fun x -> f x in +let plus = fun m -> fun n -> fun f -> fun x -> m f (n f x) in +let two = plus one one in +let three = plus one two in +let four = plus two two in +let five = plus four one in +let six = plus four two in +let succ = plus one in +let mult = fun m -> fun n -> fun f -> m (n f) in +let exp = fun m -> fun n -> n m in +let is_zero = fun n -> n (k false) true in +let convert = fun n -> n (fun x -> x + 1) 0 in +let _ = print (bool2int (is_zero zero)) in +let _ = print (bool2int (is_zero one)) in +let _ = print (bool2int (is_zero two)) in +(* Factorial, based on Church naturals. *) +let loop = fun p -> + let n = succ (fst p) in + pair n (mult n (snd p)) +in +let fact = fun n -> + snd (n loop (pair zero one)) +in +let _ = print (convert (fact four)) in +let _ = print (convert (fact five)) in +(* Fibonacci, based on Church naturals. *) +let loop = fun p -> + let fib1 = fst p in + pair (plus fib1 (snd p)) fib1 +in +let fib = fun n -> + snd (n loop (pair one one)) +in +let _ = print (convert (fib five)) in +let _ = print (convert (fib six)) in +(* Predecessor. *) +let loop = fun p -> + let pred = fst p in + pair (succ pred) pred +in +let pred = fun n -> + snd (n loop (pair zero zero)) +in +let _ = print (convert (pred six)) in +(* Comparison, yielding a Church Boolean. *) +let geq = fun m -> fun n -> + m pred n (k false) true +in +let _ = print (bool2int (geq four six)) in +let _ = print (bool2int (geq six one)) in +(* Iteration. *) +let iter = fun f -> fun n -> + n f (f one) +in +(* Ackermann's function. *) +let ack = fun n -> n iter succ n in +let _ = print (convert (ack two)) in +(* A fixpoint. *) +let fix = fun f -> (fun y -> f (fun z -> y y z)) (fun y -> f (fun z -> y y z)) in +(* Another version of fact. *) +let fact = fun n -> + fix (fun fact -> fun n -> forcecond (is_zero n) (fun _ -> one) (fun _ -> mult n (fact (pred n)))) n +in +let _ = print (convert (fact zero)) in +let _ = print (convert (fact one)) in +let _ = print (convert (fact two)) in +let _ = print (convert (fact three)) in +let _ = print (convert (fact four)) in +let _ = print (convert (fact five)) in + +print 42 diff --git a/projet/src/tests/church.exp b/projet/src/tests/church.exp new file mode 100755 index 0000000..d81cc07 --- /dev/null +++ b/projet/src/tests/church.exp @@ -0,0 +1 @@ +42 diff --git a/projet/src/tests/church.lambda b/projet/src/tests/church.lambda new file mode 100644 index 0000000..0cbd2e6 --- /dev/null +++ b/projet/src/tests/church.lambda @@ -0,0 +1,16 @@ +let i = fun x -> x in +let k = fun x -> fun y -> x in +let zero = fun f -> i in +let one = fun f -> fun x -> f x in +let plus = fun m -> fun n -> fun f -> fun x -> m f (n f x) in +let succ = plus one in +let mult = fun m -> fun n -> fun f -> m (n f) in +let exp = fun m -> fun n -> n m in +let two = succ one in +let three = succ two in +let six = mult two three in +let seven = succ six in +let twenty_one = mult three seven in +let forty_two = mult two twenty_one in +let convert = fun n -> n (fun x -> x + 1) 0 in +print (convert forty_two) diff --git a/projet/src/tests/hello.exp b/projet/src/tests/hello.exp new file mode 100755 index 0000000..d81cc07 --- /dev/null +++ b/projet/src/tests/hello.exp @@ -0,0 +1 @@ +42 diff --git a/projet/src/tests/hello.lambda b/projet/src/tests/hello.lambda new file mode 100644 index 0000000..86f387e --- /dev/null +++ b/projet/src/tests/hello.lambda @@ -0,0 +1 @@ +print (21 + 21) diff --git a/projet/src/tests/loop/loop.lambda b/projet/src/tests/loop/loop.lambda new file mode 100644 index 0000000..0629593 --- /dev/null +++ b/projet/src/tests/loop/loop.lambda @@ -0,0 +1,10 @@ +(* This program is supposed to never terminate. + This can actually work if the C compiler is + smart enough to recognize and optimize tail + calls. It works for me with clang but not with + gcc, for some reason. *) +let rec loop = fun x -> + let _ = print x in + loop (x + 1) +in +loop 0 diff --git a/projet/src/tests/printprint.exp b/projet/src/tests/printprint.exp new file mode 100755 index 0000000..daaac9e --- /dev/null +++ b/projet/src/tests/printprint.exp @@ -0,0 +1,2 @@ +42 +42 diff --git a/projet/src/tests/printprint.lambda b/projet/src/tests/printprint.lambda new file mode 100644 index 0000000..f0501dd --- /dev/null +++ b/projet/src/tests/printprint.lambda @@ -0,0 +1,2 @@ +(* Because [print] returns its argument, this program should print 42 twice. *) +print (print 42) diff --git a/projet/sujet.pdf b/projet/sujet.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b7f0a6d1ad0dcab0c9af9792d6320bc21e946fa8 GIT binary patch literal 112447 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 literal 0 HcmV?d00001