commit 101555a3d3d2e8f9c3bbce08d3cb1f5faf14c311 Author: Mysaa Date: Sat Jan 22 22:18:16 2022 +0100 Premier commit avec ce qui a été fait pendant la séance. diff --git a/Rendu0/.gitignore b/Rendu0/.gitignore new file mode 100644 index 0000000..d83b120 --- /dev/null +++ b/Rendu0/.gitignore @@ -0,0 +1,3 @@ +_build/ +fouine +main.native diff --git a/Rendu0/Makefile b/Rendu0/Makefile new file mode 100644 index 0000000..933ffc5 --- /dev/null +++ b/Rendu0/Makefile @@ -0,0 +1,11 @@ +all: + ocamlbuild -yaccflag -v -lib unix main.native #on dit de fabriquer main.native + ln -f -s main.native fouine + chmod +x fouine + +byte: + ocamlbuild -yaccflag -v main.byte + +clean: + ocamlbuild -clean + rm -f fouine diff --git a/Rendu0/README.txt b/Rendu0/README.txt new file mode 100644 index 0000000..aeb34db --- /dev/null +++ b/Rendu0/README.txt @@ -0,0 +1,21 @@ +Ce répertoire contient un sequelette de départ à partir duquel vous +pouvez programmer votre fouine. + +Pour compiler, faites +make +qui aura pour effet de créer l'exécutable appelé fouine. +Faites ensuite +./fouine +pour lancer l'exécutable et saisir une expression au clavier. +./fouine tests/basic.ml pour lancer fouine sur le fichier basic.ml + + +main.ml : fichier principal +expr.ml : définition des expressions et de l'évaluation +affichage.ml : fonctions d'affichage +lexer.mll : lexèmes, analyse lexicale +parser.mly : règles de grammaire, analyse syntaxique +tests/ : sous-répertoire de tests +Makefile : pour la compilation, à ne pas modifier a priori + + diff --git a/Rendu0/affichage.ml b/Rendu0/affichage.ml new file mode 100644 index 0000000..76b2dd8 --- /dev/null +++ b/Rendu0/affichage.ml @@ -0,0 +1,42 @@ +open Expr + +let affiche_val v = match v with + | VInt k -> print_int k + | VBool b -> print_string (if b then "Vrai" else "Faux") + + +(* fonction d'affichage *) +let rec affiche_expr e = + let aff_aux s a b = + begin + print_string s; + affiche_expr a; + print_string ", "; + affiche_expr b; + print_string ")" + end + in + match e with + | Const k -> print_int k + | BConst b -> affiche_val (VBool b) + | Add(e1,e2) -> aff_aux "Add(" e1 e2 + | Mul(e1,e2) -> aff_aux "Mul(" e1 e2 + | Min(e1,e2) -> aff_aux "Min(" e1 e2 + | Eq(e1,e2) -> aff_aux "Eq(" e1 e2 + | Gt(e1,e2) -> aff_aux "Gt(" e1 e2 + | Lt(e1,e2) -> aff_aux "Lt(" e1 e2 + | Gte(e1,e2) -> aff_aux "Gte(" e1 e2 + | Lte(e1,e2) -> aff_aux "Lte(" e1 e2 + | Band(e1,e2) -> aff_aux "BooleanAnd(" e1 e2 + | Bor(e1,e2) -> aff_aux "BooleanOr(" e1 e2 + | ITE(ec,e1,e2) -> + begin print_string "IF("; + affiche_expr ec; + print_string ", "; + affiche_expr e1; + print_string ", "; + affiche_expr e2; + print_string ")" + end + | PrInt(e1) -> print_string "PrInt(";affiche_expr e1;print_string ")" + diff --git a/Rendu0/expr.ml b/Rendu0/expr.ml new file mode 100644 index 0000000..5b01902 --- /dev/null +++ b/Rendu0/expr.ml @@ -0,0 +1,60 @@ +(* définition des différents types : tout est à reprendre et étendre *) +type expr = + Const of int + | BConst of bool + | Add of expr*expr + | Mul of expr*expr + | Min of expr*expr + | Eq of expr*expr + | Gt of expr*expr + | Lt of expr*expr + | Gte of expr*expr + | Lte of expr*expr + | Band of expr*expr + | Bor of expr*expr + | ITE of expr*expr*expr + | PrInt of expr + +type valeur = VInt of int | VBool of bool + +type env = unit + +let empty_env = () + +exception InvalidTypeException + + +let rec intIntOp op e1 e2 env = match (eval e1 env, eval e2 env) with + | VInt k1,VInt k2 -> VInt(op k1 k2) + | _ -> raise InvalidTypeException +and intBoolOp op e1 e2 env = match (eval e1 env, eval e2 env) with + | VInt k1,VInt k2 -> VBool(op k1 k2) + | _ -> raise InvalidTypeException +(* sémantique opérationnelle à grands pas *) +and eval e env = match e with + | Const(k) -> VInt k + | BConst(b) -> VBool b + | Add(e1,e2) -> intIntOp ( + ) e1 e2 env + | Mul(e1,e2) -> intIntOp ( * ) e1 e2 env + | Min(e1,e2) -> intIntOp ( - ) e1 e2 env + | Gt(e1,e2) -> intBoolOp ( > ) e1 e2 env + | Lt(e1,e2) -> intBoolOp ( < ) e1 e2 env + | Gte(e1,e2) -> intBoolOp ( >= ) e1 e2 env + | Lte(e1,e2) -> intBoolOp ( <= ) e1 e2 env + | Eq(e1,e2) -> (match (eval e1 env, eval e2 env) with + | VInt k1,VInt k2 -> VBool (k1=k2) + | VBool k1,VBool k2 -> VBool (k1=k2) + | _ -> raise InvalidTypeException) + | Band(e1,e2) -> (match (eval e1 env, eval e2 env) with + | VBool b1,VBool b2 -> VBool (b1 && b2) + | _ -> raise InvalidTypeException) + | Bor(e1,e2) -> (match (eval e1 env, eval e2 env) with + | VBool b1,VBool b2 -> VBool (b1 || b2) + | _ -> raise InvalidTypeException) + | ITE(ec,e1,e2) -> (match (eval ec env) with + | VBool bc -> eval (if bc then e1 else e2) env + | _ -> raise InvalidTypeException) + | PrInt e1 -> (match (eval e1 env) with + | VInt k -> VInt k + | _ -> raise InvalidTypeException) + diff --git a/Rendu0/lexer.mll b/Rendu0/lexer.mll new file mode 100644 index 0000000..f56f063 --- /dev/null +++ b/Rendu0/lexer.mll @@ -0,0 +1,32 @@ +{ + open Parser +exception Eof +} + +rule token = parse (* la "fonction" aussi s'appelle token .. *) + | [' ' '\t'] { token lexbuf } (* on saute les blancs et les tabulations *) + (* token: appel récursif *) + (* lexbuf: argument implicite + associé au tampon où sont + lus les caractères *) + | '\n' { EOL } + | '+' { PLUS } + | '*' { TIMES } + | '-' { MINUS } + | '(' { LPAREN } + | ')' { RPAREN } + | ['0'-'9']+ as s { INT (int_of_string s) } + | "true" { TRUE } + | "false" { FALSE } + | '>' { GT } + | '<' { LT } + | ">=" { GTE } + | ">=" { LTE } + | '=' { EQ } + | "&&" { BAND } + | "||" { BOR } + | "if" { IF } + | "then" { THEN } + | "else" { ELSE } + | "prInt" { PRINT } + | eof { raise Eof } (* fin du fichier *) diff --git a/Rendu0/main.ml b/Rendu0/main.ml new file mode 100644 index 0000000..844ab98 --- /dev/null +++ b/Rendu0/main.ml @@ -0,0 +1,67 @@ +open Expr +open Affichage + + +(* "incantations" qu'il n'est pas nécessaire de comprendre dans un premier + temps : on récupère l'entrée, dans un fichier ou sur le clavier *) +let nom_fichier = ref "" + +let recupere_entree () = + Arg.parse [] (fun s -> nom_fichier := s) ""; + try + let where_from = match !nom_fichier with + | "" -> stdin + | s -> open_in s in + let lexbuf = Lexing.from_channel where_from in + let parse () = Parser.main Lexer.token lexbuf in + parse () + with e -> (Printf.printf "problème de saisie\n"; raise e) + +(* mettre à true et recompiler si l'on veut voir l'exécution pas à pas de l'automate *) +let trace = ref false +let _ = Stdlib.Parsing.set_trace !trace + + + + +let rec affiche_printexpr e env = begin + match e with + | Add(e1,e2) -> affiche_printexpr e1 env;affiche_printexpr e2 env + | Mul(e1,e2) -> affiche_printexpr e1 env;affiche_printexpr e2 env + | Min(e1,e2) -> affiche_printexpr e1 env;affiche_printexpr e2 env + | Eq(e1,e2) -> affiche_printexpr e1 env;affiche_printexpr e2 env + | Gt(e1,e2) -> affiche_printexpr e1 env;affiche_printexpr e2 env + | Lt(e1,e2) -> affiche_printexpr e1 env;affiche_printexpr e2 env + | Gte(e1,e2) -> affiche_printexpr e1 env;affiche_printexpr e2 env + | Lte(e1,e2) -> affiche_printexpr e1 env;affiche_printexpr e2 env + | Band(e1,e2) -> affiche_printexpr e1 env;affiche_printexpr e2 env + | Bor(e1,e2) -> affiche_printexpr e1 env;affiche_printexpr e2 env + | ITE(ec,e1,e2) -> affiche_printexpr ec env;affiche_printexpr e1 env;affiche_printexpr e2 env + | _ -> () + end; + begin + match e with + | PrInt e -> (match (eval e env) with + | VInt(k) -> print_int k;print_newline () + | _ -> raise InvalidTypeException) + | _ -> () + end +(* le traitement d'une expression en entrée *) +let execute e = + begin + affiche_printexpr e Expr.empty_env; + print_newline(); + let v = Expr.eval e Expr.empty_env in + affiche_val v; + print_newline() + end + +(* la boucle principale *) +let calc () = + try + let saisie = recupere_entree () in + execute saisie; flush stdout + with e -> raise e + + +let _ = calc() diff --git a/Rendu0/parser.mly b/Rendu0/parser.mly new file mode 100644 index 0000000..38243c6 --- /dev/null +++ b/Rendu0/parser.mly @@ -0,0 +1,64 @@ +%{ +(* --- préambule: ici du code Caml --- *) + +open Expr (* rappel: dans expr.ml: + type expr = Const of int | Add of expr*expr | Mull of expr*expr *) + +%} +/* description des lexèmes, ceux-ci sont décrits (par vous) dans lexer.mll */ + +%token INT /* le lexème INT a un attribut entier */ +%token TRUE FALSE +%token IF THEN ELSE +%token PRINT +%token BAND BOR +%token EQ GT LT GTE LTE +%token PLUS TIMES MINUS +%token LPAREN RPAREN +%token EOL /* retour à la ligne */ + +%nonassoc IF THEN ELSE +%left BAND BOR +%left EQ +%nonassoc GT LT GTE LTE +%left PLUS MINUS /* associativité gauche: a+b+c, c'est (a+b)+c */ +%left TIMES /* associativité gauche: a*b*c, c'est (a*b)*c */ +%nonassoc PRINT +%nonassoc UMINUS /* un "faux token", correspondant au "-" unaire */ + /* cf. son usage plus bas : il sert à "marquer" une règle pour lui donner la précédence maximale */ + + +%start main /* "start" signale le point d'entrée: */ + /* c'est ici main, qui est défini plus bas */ +%type main /* on _doit_ donner le type associé au point d'entrée */ + +%% + /* --- début des règles de grammaire --- */ + /* à droite, les valeurs associées */ + + +main: /* <- le point d'entrée (cf. + haut, "start") */ +expression EOL { $1 } /* on veut reconnaître une expression */ + ; + + + expression: /* règles de grammaire pour les expressions */ + | INT { Const $1 } + | TRUE { BConst true } + | FALSE { BConst false } + | LPAREN expression RPAREN { $2 } /* on récupère le deuxième élément */ + | expression PLUS expression { Add($1,$3) } + | expression TIMES expression { Mul($1,$3) } + | expression MINUS expression { Min($1,$3) } + | expression EQ expression { Eq($1,$3) } + | expression GT expression { Gt($1,$3) } + | expression LT expression { Lt($1,$3) } + | expression GTE expression { Gte($1,$3) } + | expression LTE expression { Lte($1,$3) } + | expression BAND expression { Band($1,$3) } + | expression BOR expression { Bor($1,$3) } + | PRINT expression { PrInt($2) } + | IF expression THEN expression ELSE expression { ITE($2,$4,$6)} + | MINUS expression %prec UMINUS { Min(Const 0, $2) } +; + diff --git a/Rendu0/tests/arith0.ml b/Rendu0/tests/arith0.ml new file mode 100644 index 0000000..22494a2 --- /dev/null +++ b/Rendu0/tests/arith0.ml @@ -0,0 +1 @@ +1+2+3+4*5*(6+7-8) diff --git a/Rendu0/tests/basic.ml b/Rendu0/tests/basic.ml new file mode 100644 index 0000000..26b4409 --- /dev/null +++ b/Rendu0/tests/basic.ml @@ -0,0 +1 @@ +3+2*4 diff --git a/Rendu0/tests/booleans.ml b/Rendu0/tests/booleans.ml new file mode 100644 index 0000000..484ab13 --- /dev/null +++ b/Rendu0/tests/booleans.ml @@ -0,0 +1 @@ +if (5+6=11) then (if 5-9=9 && 3+3=6 then 42 else 5+98) else 4*2