| Université Paris 6 Licence d'informatique | Module de Programmation Année 2000-2001 |
|---|
<decl> :: = def <nom> = <expr>;;où
<expr> désigne n'importe quelle expression. Un <nom>
est une séquence ininterrompue de lettres de l'alphabet.
Les expressions sont définies par la grammaire suivante au format BNF
(Bachus Naur Form):
<expr> ::= si <expr> alors <expr> sinon <expr>
| soit <nom> = <expr> dans <expr>
| fonction <nom> -> <expr>
| rec <nom> <nom> = <expr>
| <expr> <expr>
| ( <expr> )
| <nom>
| i
| vrai | faux
| <expr> <op> <expr>
<op> ::= + | - | * | / | < | > | <= | >= | != | =
Une expression peut être, une expression conditionnelle
(si), une
déclaration locale (soit), une fonction (fonction), une fonction
récursive (rec),
une application de fonction, une expression entre parenthèses, une
variable (nom), une constante entière (i), un booléen
(vrai et faux) ou une expression arithmétique.
def x = 42;;
def y =
soit z = x * x dans
soit k = z + 1 dans
z + 2;;
def f =
fonction x -> fonction y -> si y = x alors soit x = 2 dans x+y sinon 3;;
def resultat = f 2 3;;
def g = rec fact x = si x = 0 alors 1 sinon x * (fact (x-1));;
let v = g 4
def app = fonction f -> fonction g -> fonction x -> f (g x);;
Les constructions sont essentiellement celles de Caml Light (à un
renommage près des mots clefs pour éviter les ambiguïtés). La
construction de fonctions récursives est cependant un peu différente:
l'expression
rec fact x = si x = 0 alors 1 sinon x * (fact (x-1))définit directement une fonction récursive et est équivalente à l'expression de Caml Light suivante:
let rec fact x = if x = 0 then 1 else x * (fact (x-1)) in fact
type decl = ... and expr = ... and immediat = .. and op = ... and typ = ... and var_type = ... and schema_de_type = ...Ce module vous est donné (voir fichier
syntaxe_abstraite.mli).
exception Erreur;;
value ajout_global : (string * schema_de_type) list -> unit;;
value chercher_env_global : string -> schema_de_type;;
(* peut lever l'exception Not_found *)
Ce module vous est donné.
lexing du manuel de référence de Caml Light
(page 151).value lire_decl_chaine : string -> decl;; value lire_expr_chaine : string -> expr;; value lire_decl : lexing__lexbuf -> decl;;Ce module vous est donné.
value afficher_type : out_channel -> typ -> unit;;
value affiche_type_schema : out_channel -> schema_de_type -> unit;;
value afficher_decl_type : out_channel -> (string * schema_de_type) list
-> unit;;
afficher_type oc typ affiche le type typ dans la sortie
oc (oc est un descripteur de fichier de sortie qui devra
avoir été créé auparavant). afficher_type permet d'afficher un
schéma de type. Enfin, afficher_decl_type permet d'afficher une
liste de déclaration d'identificateurs globaux et leurs schémas de
type associés.value erreur_de_syntaxe : unit -> unit;; value erreur_identificateur : string -> unit;; value erreur_de_type : unit -> unit;;
erreur_de_syntaxe () affiche un message en cas d'erreurs de syntaxe.erreur_identificateur x indique que x n'est pas
déclaré.erreur_de_type () indique qu'une erreur de type est survenue.main_decl : unit -> unit main_string : string -> unitCe module est à écrire.
main_decl lance l'analyse syntaxique et le typage
de la suite des déclarations apparaissant dans un fichier. Les
déclarations sont analysées les unes après les autres. L'analyse
d'un fichier s'arrête dès que l'analyse d'une déclaration échoue. La
fonction main_string a le même comportement mais peut être
appliquée à une chaîne de caractères.
> Caml Light version 0.74
#include "load.ml";;
#lire_decl_chaine "def x = si c alors 1 sinon y + 3;;";;
- : decl =
Ldef
("x",
Lconditionnelle
(Lvar "c", Lconst (Lint 1), Lbinop (Bplus, Lvar "y", Lconst (Lint 3))))
Dans cette première partie, l'objectif est d'implanter un algorithme
permettant de typer les expressions arithmétiques, les variables, les
constantes, les conditionnelles ainsi que les déclarations locales.typer
permettant de typer une expression. Elle sera basée sur les règles de
typage que vous avez vu en cours.Makefile qui vous est donné.e1 op e2.si c alors e1 sinon e2 est bien typée si c est un booléen
et si e1 et e2 sont de même type.
typer sera:
typer : (string * schema_de_type) list -> expr -> typLa fonction
typer sera telle que: typer Env e rend le
type ty lorsque Env |- e: ty.
typer. Vous définirez ensuite la fonction principale du module
main. Il faudra pour cela ouvrir le fichier en lecture, lancer
l'analyse syntaxique puis le typage et enfin, mettre à jour
l'environnement de type global.
subst_type dans la suite du
texte. Par exemple, les deux types:
(var_type * typ) list associant un type typ à une
variable de type var_type.
exception Unification;;
value reinit_var_de_type : unit -> unit;;
value gen_var_type : unit -> var_type;;
value vars : var_type list -> var_type list -> typ -> var_type list;;
value var_libres : typ -> var_type list;;
value var_libres_env : (string * schema_de_type) list -> var_type list;;
value substituer : (var_type * typ) list -> typ -> typ;;
value unifier : (var_type * typ) list -> typ -> typ -> (var_type * typ) list;;
value generaliser :
(string * schema_de_type) list -> typ * (var_type * typ) list
-> schema_de_type;;
value instancier : schema_de_type -> typ;;
La fonction gen_var_type rend une nouvelle variable de type et
reinit_var_de_type permet d'initialiser cette fonction.substituer subst_type t où subst_type est une
substitution de type (associant des types à des variables de type) et
t, un type, rend un type t' déduit de t en
remplaçant les variables de t figurant dans subst_type
par les types qui leur sont associés.unifier subst_type t1 t2, où subst_type est une
substitution de type, t1 et t2 sont des types, rend une
nouvelle substitution subst_type' telle que
substituer subst_type' t1 = substituer subst_type' t2.
Lorsque les deux types ne sont pas unifiables, l'exception
Unification est levée.
value typer :
(string * schema_de_type) list -> (var_type * typ) list
-> expr -> typ * (var_type * typ) list;;
value typer_decl : decl -> unit;;
typer env_de_type subst_type e rend un couple
(ty, nouv_subst_type) où ty est le type obtenu pour
l'expression e et où nouv_subst_type est une nouvelle
substitution de type (on peut en effet supposer que le typage de
e a fait apparaître de nouvelles contraintes de type). Cette
nouvelle substitution enrichie la substitution subst_type avec
de nouvelles contraintes. La fonction typer prend en paramètre un
environnement de type env_de_type (associant des schémas de type
aux variables du
programme) et subst_type. typer_decl s'occupe du typage des déclarations: cette fonction
type une déclaration, modifie l'environnement global et affiche le
type obtenu.
env_type est:
var_libres_env est définie dans le
module unification.
f e est bien typée et de type t2
si le type de f peut s'unifier avec un type t1 ® t2 et
si le type de e peut s'unifier avec t1.
~pouzet/tp3.
Vous y trouverez un fichier LISEZMOI qui décrit les différents
fichiers ainsi qu'un Makefile donnant l'architecture générale
du logiciel. Ce fichier est à modifier suivant vos besoin. Enfin, le
fichier exemples.mml vous donne quelques exemples de programmes du
langage et le résultat rendu par le typage.typer qui prend en entrée un
fichier fichier.mml et qui affiche sur la sortie standard le
résultat du typage.
Ce document a été traduit de LATEX par HEVEA.