This commit is contained in:
Laureηt 2023-06-21 19:58:18 +02:00
commit 7f6e51dfea
Signed by: Laurent
SSH key fingerprint: SHA256:kZEpW8cMJ54PDeCvOhzreNr4FSh6R13CMGH/POoO8DI
70 changed files with 3710 additions and 0 deletions

55
BE/ascendant/Lexer.mll Executable file
View file

@ -0,0 +1,55 @@
{
(* Partie recopiée dans le fichier CaML généré. *)
(* Ouverture de modules exploités dans les actions *)
(* Déclarations de types, de constantes, de fonctions, d'exceptions exploités dans les actions *)
open Parser
exception LexicalError
}
(* Déclaration d'expressions régulières exploitées par la suite *)
let chiffre = ['0' - '9']
let entier = ['1' - '9']
let minuscule = ['a' - 'z']
let majuscule = ['A' - 'Z']
let alphabet = minuscule | majuscule
let alphanum = alphabet | chiffre | '_'
let commentaire =
(* Commentaire fin de ligne *)
"#" [^'\n']*
rule lexer = parse
| ['\n' '\t' ' ']+ { (lexer lexbuf) }
| commentaire { (lexer lexbuf) }
| "model" { UL_MODEL }
| "system" { UL_SYSTEM }
| "block" { UL_BLOCK }
| "flow" { UL_FLOW }
| "from" { UL_FROM }
| "to" { UL_TO }
| "in" { UL_IN }
| "out" { UL_OUT }
| "int" { UL_INT }
| "float" { UL_FLOAT }
| "boolean" { UL_BOOLEAN }
| "{" { UL_ACCOUV }
| "}" { UL_ACCFER }
| "(" { UL_PAROUV }
| ")" { UL_PARFER }
| "[" { UL_CROOUV }
| "]" { UL_CROFER }
| ";" { UL_PTV }
| "," { UL_VIRG }
| ":" { UL_PT2 }
| "." { UL_PT }
| eof { UL_FIN }
| majuscule alphabet* as texte { (UL_IDENT texte) }
| minuscule alphabet* as texte { (UL_PORT texte) }
| entier chiffre* as texte { (UL_ENTIER (int_of_string texte)) }
| _ as texte { (print_string "Erreur lexicale : ");(print_char texte);(print_newline ()); raise LexicalError }
{
}

52
BE/ascendant/MainSystem.ml Executable file
View file

@ -0,0 +1,52 @@
open Parser
(* Fonction d'affichage des unités lexicales et des données qu'elles contiennent *)
let printToken t =
(print_endline
(match t with
| UL_MODEL -> "model"
| UL_SYSTEM -> "system"
| UL_BLOCK -> "block"
| UL_FLOW -> "flow"
| UL_FROM -> "from"
| UL_TO -> "to"
| UL_IN -> "in"
| UL_OUT -> "out"
| UL_INT -> "int"
| UL_FLOAT -> "float"
| UL_BOOLEAN -> "boolean"
| UL_ACCOUV -> "{"
| UL_ACCFER -> "}"
| UL_PAROUV -> "("
| UL_PARFER -> ")"
| UL_CROOUV -> "["
| UL_CROFER -> "]"
| UL_PTV -> ";"
| UL_VIRG -> ","
| UL_PT2 -> ":"
| UL_PT -> "."
| UL_IDENT texte -> texte
| UL_PORT texte -> texte
| UL_ENTIER texte -> (string_of_int texte)
| UL_FIN -> "EOF"
));;
(* Analyse lexicale du fichier passé en paramètre de la ligne de commande *)
if (Array.length Sys.argv > 1)
then
let lexbuf = (Lexing.from_channel (open_in Sys.argv.(1))) in
let token = ref (Lexer.lexer lexbuf) in
while ((!token) != UL_FIN) do
(printToken (!token));
(token := (Lexer.lexer lexbuf))
done
else
(print_endline "MainJSON fichier");;
(* Analyse lexicale, syntaxique et sémantique du fichier passé en paramètre de la ligne de commande *)
if (Array.length Sys.argv > 1)
then
let lexbuf = (Lexing.from_channel (open_in Sys.argv.(1))) in
(Parser.modele Lexer.lexer lexbuf)
else
(print_endline "MainJSON fichier");;

88
BE/ascendant/Parser.mly Executable file
View file

@ -0,0 +1,88 @@
%{
(* Partie recopiee dans le fichier CaML genere. *)
(* Ouverture de modules exploites dans les actions *)
(* Declarations de types, de constantes, de fonctions, d'exceptions exploites dans les actions *)
%}
/* Declaration des unites lexicales et de leur type si une valeur particuliere leur est associee */
%token UL_MODEL
%token UL_ACCOUV UL_ACCFER
%token UL_SYSTEM
%token UL_BLOCK
%token UL_FLOW UL_FROM UL_TO
%token UL_IN UL_OUT
%token UL_INT UL_FLOAT UL_BOOLEAN
%token UL_PAROUV UL_PARFER
%token UL_CROOUV UL_CROFER
%token UL_PTV UL_VIRG UL_PT2 UL_PT
/* Defini le type des donnees associees a l'unite lexicale */
%token <string> UL_IDENT
%token <string> UL_PORT
%token <int> UL_ENTIER
/* Unite lexicale particuliere qui represente la fin du fichier */
%token UL_FIN
/* Type renvoye pour le nom terminal document */
%type <unit> modele
/* Le non terminal document est l'axiome */
%start modele
%% /* Regles de productions */
modele : UL_MODEL UL_IDENT UL_ACCOUV loop_element UL_ACCFER UL_FIN { (print_endline "modele : UL_MODEL IDENT { loop_element } UL_FIN ") }
element : bloc { (print_endline "element : bloc") }
| systeme { (print_endline "element : systeme") }
| flot { (print_endline "element : flot") }
loop_element : /* Lambda */ { (print_endline "loop_element : /* Lambda */") }
| element loop_element { (print_endline "loop_element : element loop_element") }
bloc : UL_BLOCK UL_IDENT parametres UL_PTV { (print_endline "bloc : UL_BLOCK UL_IDENT parametres UL_PTV") }
systeme : UL_SYSTEM UL_IDENT parametres UL_ACCOUV loop_element UL_ACCFER { (print_endline "systeme : UL_SYSTEM UL_IDENT parametres UL_ACCOUV loop_element UL_ACCFER") }
parametres : UL_PAROUV port loop_port UL_PARFER { (print_endline "parametres : UL_PAROUV port loop_port UL_PARFER") }
loop_port : /* Lambda */ { (print_endline "loop_port : /* Lambda */") }
| UL_VIRG port loop_port { (print_endline "loop_port : UL_VIRG port loop_port") }
port : UL_PORT UL_PT2 in_or_out type_ { (print_endline "port : UL_PORT UL_PT2 in_or_out type_") }
in_or_out : UL_IN { (print_endline "in_or_out : UL_IN") }
| UL_OUT { (print_endline "in_or_out : UL_OUT") }
type_ : select_type option_entiers { (print_endline "type_ : select_type option_entiers") }
select_type : UL_INT { (print_endline "select_type : UL_INT") }
| UL_FLOAT { (print_endline "select_type : UL_FLOAT") }
| UL_BOOLEAN { (print_endline "select_type : UL_BOOLEAN") }
option_entiers : /* Lambda */ { (print_endline "option_entiers : /* Lambda */") }
| UL_CROOUV UL_ENTIER loop_entier UL_CROFER { (print_endline "option_entiers : UL_CROOUV UL_ENTIER loop_entier UL_CROFER") }
loop_entier : /* Lambda */ { (print_endline "loop_entier : /* Lambda */") }
| UL_VIRG UL_ENTIER loop_entier { (print_endline "loop_entier : UL_VIRG UL_ENTIER loop_entier") }
flot : UL_FLOW UL_PORT UL_FROM option_ident UL_PORT UL_TO option_loop_ident_port UL_PTV { (print_endline "flot : UL_FLOW UL_PORT UL_FROM option_ident UL_PORT UL_TO option_loop_ident_port UL_PTV") }
option_ident : /* Lambda */ { (print_endline "option_ident : /* Lambda */") }
| UL_IDENT UL_PT { (print_endline "option_ident : UL_IDENT UL_PT") }
ident_port : option_ident UL_PORT { (print_endline "ident_port : option_ident UL_PORT") }
loop_ident_port : /* Lambda */ { (print_endline "loop_ident_port : /* Lambda */") }
| UL_VIRG ident_port loop_ident_port { (print_endline "loop_ident_port : UL_IDENT UL_PT") }
option_loop_ident_port : /* Lambda */ { (print_endline "option_loop_ident_port : /* Lambda */") }
| ident_port loop_ident_port { (print_endline "option_loop_ident_port : ident_port loop_ident_port") }
%%

7
BE/ascendant/dune Executable file
View file

@ -0,0 +1,7 @@
(ocamllex Lexer)
(menhir
(modules Parser))
(executable
(name MainSystem))

2
BE/ascendant/dune-project Executable file
View file

@ -0,0 +1,2 @@
(lang dune 2.9)
(using menhir 2.1)

25
BE/descendant/MainSystem.ml Executable file
View file

@ -0,0 +1,25 @@
open Tokens
open Scanner
open Parser
(* main : unit -> unit *)
(* Analyse le contenu d'un fichier passé en paramètre ou l'entrée standard si aucun fichier n'est donné *)
(* Affiche OK si l'analyse syntaxique c'est bien passée et KO sinon *)
let main () =
let cin =
if Array.length Sys.argv > 1 then
open_in Sys.argv.(1)
else
stdin
in
let lexbuf = Lexing.from_channel cin in
let tokens = (scanner lexbuf) in
(print_endline ("Résultat de l'analyse lexicale :" ^ (string_of_stream tokens)));
(print_endline "Analyse syntaxique par descente récursive, règles appliquées :");
(match (parseR tokens)
with
| Success [UL_FIN] -> print_endline "Succés"
| _ -> print_endline "Echec")
;;
main();;

303
BE/descendant/Parser.ml Executable file
View file

@ -0,0 +1,303 @@
open Tokens
(* Type du résultat d'une analyse syntaxique *)
type parseResult =
| Success of inputStream
| Failure
;;
(* accept : token -> inputStream -> parseResult *)
(* Vérifie que le premier token du flux d'entrée est bien le token attendu *)
(* et avance dans l'analyse si c'est le cas *)
let accept expected stream =
match (peekAtFirstToken stream) with
| token when (token = expected) ->
(Success (advanceInStream stream))
| _ -> Failure
;;
(* acceptIdent : inputStream -> parseResult *)
(* Vérifie que le premier token du flux d'entrée est bien un identifiant *)
(* et avance dans l'analyse si c'est le cas *)
let acceptIdent stream =
match (peekAtFirstToken stream) with
| (UL_IDENT _) -> (Success (advanceInStream stream))
| _ -> Failure
;;
(* acceptPort : inputStream -> parseResult *)
(* Vérifie que le premier token du flux d'entrée est bien un port *)
(* et avance dans l'analyse si c'est le cas *)
let acceptPort stream =
match (peekAtFirstToken stream) with
| (UL_PORT _) -> (Success (advanceInStream stream))
| _ -> Failure
;;
(* acceptEntier : inputStream -> parseResult *)
(* Vérifie que le premier token du flux d'entrée est bien un entier *)
(* et avance dans l'analyse si c'est le cas *)
let acceptEntier stream =
match (peekAtFirstToken stream) with
| (UL_ENTIER _) -> (Success (advanceInStream stream))
| _ -> Failure
;;
(* Définition de la monade qui est composée de : *)
(* - le type de donnée monadique : parseResult *)
(* - la fonction : inject qui construit ce type à partir d'une liste de terminaux *)
(* - la fonction : bind (opérateur >>=) qui combine les fonctions d'analyse. *)
(* inject inputStream -> parseResult *)
(* Construit le type de la monade à partir d'une liste de terminaux *)
let inject s = Success s;;
(* bind : 'a m -> ('a -> 'b m) -> 'b m *)
(* bind (opérateur >>=) qui combine les fonctions d'analyse. *)
(* ici on utilise une version spécialisée de bind :
'b -> inputStream
'a -> inputStream
m -> parseResult
*)
(* >>= : parseResult -> (inputStream -> parseResult) -> parseResult *)
let (>>=) result f =
match result with
| Success next -> f next
| Failure -> Failure
;;
(* parseR : inputStream -> parseResult *)
(* Analyse du non terminal Programme *)
let rec parseR stream =
(print_string "R");
(match (peekAtFirstToken stream) with
(* 1. R -> model Ident { SE } *)
| UL_MODEL ->
inject stream >>=
accept UL_MODEL >>=
acceptIdent >>=
accept UL_ACCOUV >>=
parseSE >>=
accept UL_ACCFER
(* Failure *)
| _ -> Failure)
(* parseSE : inputStream -> parseResult *)
and parseSE stream =
(print_endline "SE");
(match (peekAtFirstToken stream) with
(* 2. SE -> Λ *)
| UL_ACCFER ->
inject stream
(* 3. SE -> E SE *)
| ( UL_BLOCK | UL_SYSTEM | UL_FLOW ) ->
inject stream >>=
parseE >>=
parseSE
(* Failure *)
| _ -> Failure)
(* parseE : inputStream -> parseResult *)
and parseE stream =
(print_endline "E");
(match (peekAtFirstToken stream) with
(* 4. E -> block Ident P ; *)
| UL_BLOCK ->
inject stream >>=
accept UL_BLOCK >>=
acceptIdent >>=
parseP >>=
accept UL_PTV
(* 5. E -> system Ident P { SE } *)
| UL_SYSTEM ->
inject stream >>=
accept UL_SYSTEM >>=
acceptIdent >>=
parseP >>=
accept UL_ACCOUV >>=
parseSE >>=
accept UL_ACCFER
(* 6. E -> flow ident from NQ to LN ; *)
| UL_FLOW ->
inject stream >>=
accept UL_FLOW >>=
acceptPort >>=
accept UL_FROM >>=
parseNQ >>=
accept UL_TO >>=
parseLN >>=
accept UL_PTV
(* Failure *)
| _ -> Failure)
(* parseNQ : inputStream -> parseResult *)
and parseNQ stream =
(print_endline "NQ");
(match (peekAtFirstToken stream) with
(* 7. NQ -> ident *)
| (UL_PORT _) ->
inject stream >>=
acceptPort
(* 8. NQ -> Ident . ident *)
| (UL_IDENT _) ->
inject stream >>=
acceptIdent >>=
accept UL_PT >>=
acceptPort
(* Failure *)
| _ -> Failure)
(* parseLN : inputStream -> parseResult *)
and parseLN stream =
(print_endline "LN");
(match (peekAtFirstToken stream) with
(* 9. LN -> Λ *)
| UL_PTV ->
inject stream
(* 10. LN -> NQ SN *)
| ( (UL_IDENT _) | (UL_PORT _) ) ->
inject stream >>=
parseNQ >>=
parseSN
(* Failure *)
| _ -> Failure)
(* parseSN : inputStream -> parseResult *)
and parseSN stream =
(print_endline "SN");
(match (peekAtFirstToken stream) with
(* 11. SN -> Λ *)
| UL_PTV ->
inject stream
(* 12. LN -> , NQ SN *)
| UL_VIRG ->
inject stream >>=
accept UL_VIRG >>=
parseNQ >>=
parseSN
(* Failure *)
| _ -> Failure)
(* parseP : inputStream -> parseResult *)
and parseP stream =
(print_endline "P");
(match (peekAtFirstToken stream) with
(* 13. P -> ( LP ) *)
| UL_PAROUV ->
inject stream >>=
accept UL_PAROUV >>=
parseLP >>=
accept UL_PARFER
(* Failure *)
| _ -> Failure)
(* parseLP : inputStream -> parseResult *)
and parseLP stream =
(print_endline "LP");
(match (peekAtFirstToken stream) with
(* 14. LP -> DP SP *)
| (UL_PORT _) ->
inject stream >>=
parseDP >>=
parseSP
(* Failure *)
| _ -> Failure)
(* parseSP : inputStream -> parseResult *)
and parseSP stream =
(print_endline "SP");
(match (peekAtFirstToken stream) with
(* 15. SP -> Λ *)
| UL_PARFER ->
inject stream
(* 16. LN -> , DP SP *)
| UL_VIRG ->
inject stream >>=
accept UL_VIRG >>=
parseDP >>=
parseSP
(* Failure *)
| _ -> Failure)
(* parseDP : inputStream -> parseResult *)
and parseDP stream =
(print_endline "DP");
(match (peekAtFirstToken stream) with
(* 17. LP -> ident : M T OT *)
| (UL_PORT _) ->
inject stream >>=
acceptPort >>=
accept UL_PT2 >>=
parseM >>=
parseT >>=
parseOT
(* Failure *)
| _ -> Failure)
(* parseM : inputStream -> parseResult *)
and parseM stream =
(print_endline "M");
(match (peekAtFirstToken stream) with
(* 18. M -> in *)
| UL_IN ->
inject stream >>=
accept UL_IN
(* 19. M -> out *)
| UL_OUT ->
inject stream >>=
accept UL_OUT
(* Failure *)
| _ -> Failure)
(* parseT : inputStream -> parseResult *)
and parseT stream =
(print_endline "T");
(match (peekAtFirstToken stream) with
(* 20. T -> int *)
| UL_INT ->
inject stream >>=
accept UL_INT
(* 21. M -> float *)
| UL_FLOAT ->
inject stream >>=
accept UL_FLOAT
(* 22. M -> boolean *)
| UL_BOOLEAN ->
inject stream >>=
accept UL_BOOLEAN
(* Failure *)
| _ -> Failure)
(* parseOT : inputStream -> parseResult *)
and parseOT stream =
(print_endline "OT");
(match (peekAtFirstToken stream) with
(* 23. OT -> Λ *)
| ( UL_VIRG | UL_PARFER ) ->
inject stream
(* 24. OT -> [ entier SV ] *)
| UL_CROOUV ->
inject stream >>=
accept UL_CROOUV >>=
acceptEntier >>=
parseSV >>=
accept UL_CROFER
(* Failure *)
| _ -> Failure)
(* parseSV : inputStream -> parseResult *)
and parseSV stream =
(print_endline "SV");
(match (peekAtFirstToken stream) with
(* 25. OT -> Λ *)
| UL_CROFER ->
inject stream
(* 26. OT -> , entier SV *)
| UL_VIRG ->
inject stream >>=
accept UL_VIRG >>=
acceptEntier >>=
parseSV
(* Failure *)
| _ -> Failure)

55
BE/descendant/Scanner.mll Executable file
View file

@ -0,0 +1,55 @@
{
(* Partie recopiée dans le fichier CaML généré. *)
(* Ouverture de modules exploités dans les actions *)
(* Déclarations de types, de constantes, de fonctions, d'exceptions exploités dans les actions *)
open Tokens
exception Printf
}
(* Déclaration d'expressions régulières exploitées par la suite *)
let chiffre = ['0' - '9']
let entier = ['1' - '9']
let minuscule = ['a' - 'z']
let majuscule = ['A' - 'Z']
let alphabet = minuscule | majuscule
let alphanum = alphabet | chiffre | '_'
let commentaire =
(* Commentaire fin de ligne *)
"#" [^'\n']*
rule scanner = parse
| ['\n' '\t' ' ']+ { (scanner lexbuf) }
| commentaire { (scanner lexbuf) }
| "model" { UL_MODEL::(scanner lexbuf) }
| "system" { UL_SYSTEM::(scanner lexbuf) }
| "block" { UL_BLOCK::(scanner lexbuf) }
| "flow" { UL_FLOW::(scanner lexbuf) }
| "from" { UL_FROM::(scanner lexbuf) }
| "to" { UL_TO::(scanner lexbuf) }
| "in" { UL_IN::(scanner lexbuf) }
| "out" { UL_OUT::(scanner lexbuf) }
| "int" { UL_INT::(scanner lexbuf) }
| "float" { UL_FLOAT::(scanner lexbuf) }
| "boolean" { UL_BOOLEAN::(scanner lexbuf) }
| "{" { UL_ACCOUV::(scanner lexbuf) }
| "}" { UL_ACCFER::(scanner lexbuf) }
| "(" { UL_PAROUV::(scanner lexbuf) }
| ")" { UL_PARFER::(scanner lexbuf) }
| "[" { UL_CROOUV::(scanner lexbuf) }
| "]" { UL_CROFER::(scanner lexbuf) }
| ";" { UL_PTV::(scanner lexbuf) }
| "," { UL_VIRG::(scanner lexbuf) }
| ":" { UL_PT2::(scanner lexbuf) }
| "." { UL_PT::(scanner lexbuf) }
| majuscule alphabet* as texte { (UL_IDENT texte)::(scanner lexbuf) }
| minuscule alphabet* as texte { (UL_PORT texte)::(scanner lexbuf) }
| entier chiffre* as texte { (UL_ENTIER (int_of_string texte))::(scanner lexbuf) }
| eof { [UL_FIN] }
| _ as texte { (print_string "Erreur lexicale : ");(print_char texte);(print_newline ()); (UL_ERREUR::(scanner lexbuf)) }
{
}

88
BE/descendant/Tokens.ml Executable file
View file

@ -0,0 +1,88 @@
open List
type token =
| UL_MODEL
| UL_SYSTEM
| UL_BLOCK
| UL_FLOW
| UL_FROM
| UL_TO
| UL_IN
| UL_OUT
| UL_INT
| UL_FLOAT
| UL_BOOLEAN
| UL_ACCOUV
| UL_ACCFER
| UL_PAROUV
| UL_PARFER
| UL_CROOUV
| UL_CROFER
| UL_PTV
| UL_VIRG
| UL_PT2
| UL_PT
| UL_IDENT of string
| UL_PORT of string
| UL_ENTIER of int
| UL_FIN
| UL_ERREUR;;
type inputStream = token list;;
(* string_of_token : token -> string *)
(* Converti un token en une chaîne de caractère*)
let string_of_token token =
match token with
| UL_MODEL -> "model"
| UL_SYSTEM -> "system"
| UL_BLOCK -> "block"
| UL_FLOW -> "flow"
| UL_FROM -> "from"
| UL_TO -> "to"
| UL_IN -> "in"
| UL_OUT -> "out"
| UL_INT -> "int"
| UL_FLOAT -> "float"
| UL_BOOLEAN -> "boolean"
| UL_ACCOUV -> "{"
| UL_ACCFER -> "}"
| UL_PAROUV -> "("
| UL_PARFER -> ")"
| UL_CROOUV -> "["
| UL_CROFER -> "]"
| UL_PTV -> ";"
| UL_VIRG -> ","
| UL_PT2 -> ":"
| UL_PT -> "."
| UL_IDENT texte -> texte
| UL_PORT texte -> texte
| UL_ENTIER texte -> (string_of_int texte)
| UL_FIN -> "EOF"
| UL_ERREUR -> "Erreur Lexicale";;
(* string_of_stream : inputStream -> string *)
(* Converti un inputStream (liste de token) en une chaîne de caractère *)
let string_of_stream stream =
List.fold_right (fun t tq -> (string_of_token t) ^ " " ^ tq ) stream "";;
(* peekAtFirstToken : inputStream -> token *)
(* Renvoie le premier élément d'un inputStream *)
(* Erreur : si l'inputStream est vide *)
let peekAtFirstToken stream =
match stream with
(* Normalement, ne doit jamais se produire sauf si la grammaire essaie de lire *)
(* après la fin de l'inputStream. *)
| [] -> failwith "Impossible d'acceder au premier element d'un inputStream vide"
|t::_ -> t;;
(* advanceInStream : inputStream -> inputStream *)
(* Consomme le premier élément d'un inputStream *)
(* Erreur : si l'inputStream est vide *)
let advanceInStream stream =
match stream with
(* Normalement, ne doit jamais se produire sauf si la grammaire essaie de lire *)
(* après la fin de l'inputStream. *)
| [] -> failwith "Impossible de consommer le premier element d'un inputStream vide"
| _::q -> q;;

4
BE/descendant/dune Executable file
View file

@ -0,0 +1,4 @@
(ocamllex Scanner)
(executables
(names MainSystem))

1
BE/descendant/dune-project Executable file
View file

@ -0,0 +1 @@
(lang dune 2.9)

11
BE/tests/sujet.sdl Executable file
View file

@ -0,0 +1,11 @@
model S {
flow f from Ba.ra to HS.pa, HS.pb;
block Ba(pa : in float, pb : in float, ra : out float [ 2 ] );
system HS(pa : in float [ 2 ], ra : out float, pb : in float [ 2 ] , rb : out float [ 2 ] ) {
block Bb(ra : out float, pa : in float);
flow fa from pa to Bb.pa;
flow fb from pb to rb;
}
flow fb from HS.ra to Ba.pa, Ba.pb;
flow fc from HS.rb to;
}

View file

@ -0,0 +1,43 @@
{
(* Partie recopiée dans le fichier CaML généré. *)
(* Ouverture de modules exploités dans les actions *)
(* Déclarations de types, de constantes, de fonctions, d'exceptions exploités dans les actions *)
open Parser
exception LexicalError
}
(* Déclaration d'expressions régulières exploitées par la suite *)
let chiffre = ['0' - '9']
let minuscule = ['a' - 'z']
let majuscule = ['A' - 'Z']
let alphabet = minuscule | majuscule
let alphanum = alphabet | chiffre | '_'
let commentaire =
(* Commentaire fin de ligne *)
"#" [^'\n']*
rule lexer = parse
| ['\n' '\t' ' ']+ { (lexer lexbuf) }
| commentaire { (lexer lexbuf) }
| "{" { UL_ACCOUV }
| "}" { UL_ACCFER }
| "." { UL_PT }
| "machine" { UL_MACHINE }
| "to" { UL_TO }
| "on" { UL_ON }
| "event" { UL_EVENT }
| "from" { UL_FROM }
| "region" { UL_REGION }
| "ends" { UL_ENDS }
| "starts" { UL_STARTS }
| "state" { UL_STATE }
| eof { UL_FIN }
| alphabet+ as texte { (UL_IDENT texte) }
| _ as texte { (print_string "Erreur lexicale : ");(print_char texte);(print_newline ()); raise LexicalError }
{
}

View file

@ -0,0 +1,41 @@
open Parser
(* Fonction d'affichage des unités lexicales et des données qu'elles contiennent *)
let printToken t =
(print_endline
(match t with
| UL_IDENT (texte) -> texte
| UL_ACCOUV -> "{"
| UL_ACCFER -> "}"
| UL_PT -> "."
| UL_MACHINE -> "machine"
| UL_TO -> "to"
| UL_ON -> "on"
| UL_EVENT -> "event"
| UL_FROM -> "from"
| UL_REGION -> "region"
| UL_ENDS -> "ends"
| UL_STARTS -> "starts"
| UL_STATE -> "state"
| UL_FIN -> "EOF"
));;
(* Analyse lexicale du fichier passé en paramètre de la ligne de commande *)
if (Array.length Sys.argv > 1)
then
let lexbuf = (Lexing.from_channel (open_in Sys.argv.(1))) in
let token = ref (Lexer.lexer lexbuf) in
while ((!token) != UL_FIN) do
(printToken (!token));
(token := (Lexer.lexer lexbuf))
done
else
(print_endline "MainJSON fichier");;
(* Analyse lexicale, syntaxique et sémantique du fichier passé en paramètre de la ligne de commande *)
if (Array.length Sys.argv > 1)
then
let lexbuf = (Lexing.from_channel (open_in Sys.argv.(1))) in
(Parser.machine Lexer.lexer lexbuf)
else
(print_endline "MainJSON fichier");;

View file

@ -0,0 +1,71 @@
%{
(* Partie recopiee dans le fichier CaML genere. *)
(* Ouverture de modules exploites dans les actions *)
(* Declarations de types, de constantes, de fonctions, d'exceptions exploites dans les actions *)
%}
/* Declaration des unites lexicales et de leur type si une valeur particuliere leur est associee */
%token UL_MACHINE
%token UL_ACCOUV UL_ACCFER
%token UL_FROM UL_TO UL_ON
%token UL_STARTS UL_ENDS
%token UL_REGION
%token UL_STATE
%token UL_EVENT
%token UL_PT
/* Defini le type des donnees associees a l'unite lexicale */
%token <string> UL_IDENT
/* Unite lexicale particuliere qui represente la fin du fichier */
%token UL_FIN
/* Type renvoye pour le nom terminal document */
%type <unit> machine
/* Le non terminal document est l'axiome */
%start machine
%% /* Regles de productions */
machine : UL_MACHINE UL_IDENT UL_ACCOUV loop_composant UL_ACCFER UL_FIN { (print_endline "machine : MACHINE IDENT ACCOUV loop_composant ACCFER FIN") }
composant : UL_EVENT UL_IDENT { (print_endline "composant : EVENT IDENT") }
| transition { (print_endline "composant : transition") }
| region { (print_endline "composant : region") }
transition : UL_FROM nom_qualifie UL_TO nom_qualifie UL_ON UL_IDENT { (print_endline "transition : FROM nom_qualifie TO nom_qualifie ON IDENT") }
nom_qualifie : UL_IDENT loop_nom_qualfie { (print_endline "nom_qualifie : IDENT loop_nom_qualifie") }
etat : UL_STATE UL_IDENT option_starts option_ends option_regions { (print_endline "etat : STATE IDENT option_starts option_ends option_regions") }
region : UL_REGION UL_IDENT UL_ACCOUV etat loop_etat UL_ACCFER { (print_endline "region : REGION IDENT ACCOUV etat loop_etat ACCFER") }
loop_composant : /* Lambda, mot vide */ { (print_endline "loop_composant : /* Lambda, mot vide */") }
| composant loop_composant { (print_endline "loop_composant : composant loop_composant") }
loop_nom_qualfie : /* Lambda, mot vide */ { (print_endline "loop_nom_qualifie : /* Lambda, mot vide */") }
| UL_PT UL_IDENT loop_nom_qualfie { (print_endline "loop_nom_qualifie : PT IDENT loop_nom_qualifie") }
loop_etat : /* Lambda, mot vide */ { (print_endline "loop_etat : /* Lambda, mot vide */") }
| etat loop_etat { (print_endline "loop_etat : etat loop_etat") }
loop_region : /* Lambda, mot vide */ { (print_endline "loop_region : /* Lambda, mot vide */") }
| region loop_region { (print_endline "loop_region : region loop_region") }
option_starts : /* Lambda, mot vide */ { (print_endline "option_starts : /* Lambda, mot vide */") }
| UL_STARTS { (print_endline "option_starts : STARTS") }
option_ends : /* Lambda, mot vide */ { (print_endline "option_ends : /* Lambda, mot vide */") }
| UL_ENDS { (print_endline "option_ends : ENDS") }
option_regions : /* Lambda, mot vide */ { (print_endline "option_regions : /* Lambda, mot vide */") }
| UL_ACCOUV region loop_region UL_ACCFER { (print_endline "option_regions : ACCOUV region loop_region ACCFER") }
%%

7
BE_2020_2021/ascendant/dune Executable file
View file

@ -0,0 +1,7 @@
(ocamllex Lexer)
(menhir
(modules Parser))
(executable
(name MainMachine))

View file

@ -0,0 +1,2 @@
(lang dune 2.9)
(using menhir 2.1)

View file

@ -0,0 +1,25 @@
open Tokens
open Scanner
open Parser
(* main : unit -> unit *)
(* Analyse le contenu d'un fichier passé en paramètre ou l'entrée standard si aucun fichier n'est donné *)
(* Affiche OK si l'analyse syntaxique c'est bien passée et KO sinon *)
let main () =
let cin =
if Array.length Sys.argv > 1 then
open_in Sys.argv.(1)
else
stdin
in
let lexbuf = Lexing.from_channel cin in
let tokens = (scanner lexbuf) in
(print_endline ("Résultat de l'analyse lexicale : " ^ (string_of_stream tokens)));
(print_endline "Analyse syntaxique par descente récursive, règles appliquées :");
(match (parseM tokens)
with
| Success [UL_FIN] -> print_endline "Succés"
| _ -> print_endline "Echec")
;;
main();;

239
BE_2020_2021/descendant/Parser.ml Executable file
View file

@ -0,0 +1,239 @@
open Tokens
(* Type du résultat d'une analyse syntaxique *)
type parseResult =
| Success of inputStream
| Failure
;;
(* accept : token -> inputStream -> parseResult *)
(* Vérifie que le premier token du flux d'entrée est bien le token attendu *)
(* et avance dans l'analyse si c'est le cas *)
let accept expected stream =
match (peekAtFirstToken stream) with
| token when (token = expected) -> (Success (advanceInStream stream))
| _ -> Failure
;;
(* acceptIdent : inputStream -> parseResult *)
(* Vérifie que le premier token du flux d'entrée est bien un identifiant *)
(* et avance dans l'analyse si c'est le cas *)
let acceptIdent stream =
match (peekAtFirstToken stream) with
| (UL_IDENT _) -> (Success (advanceInStream stream))
| _ -> Failure
;;
(* Définition de la monade qui est composée de : *)
(* - le type de donnée monadique : parseResult *)
(* - la fonction : inject qui construit ce type à partir d'une liste de terminaux *)
(* - la fonction : bind (opérateur >>=) qui combine les fonctions d'analyse. *)
(* inject inputStream -> parseResult *)
(* Construit le type de la monade à partir d'une liste de terminaux *)
let inject s = Success s;;
(* bind : 'a m -> ('a -> 'b m) -> 'b m *)
(* bind (opérateur >>=) qui combine les fonctions d'analyse. *)
(* ici on utilise une version spécialisée de bind :
'b -> inputStream
'a -> inputStream
m -> parseResult
*)
(* >>= : parseResult -> (inputStream -> parseResult) -> parseResult *)
let (>>=) result f =
match result with
| Success next -> f next
| Failure -> Failure
;;
(****** Règles LL1 ******)
(* parseM : inputStream -> parseResult *)
let rec parseM stream =
(print_endline "M");
(match (peekAtFirstToken stream) with
(* 1. M -> machine ident { SC } *)
| UL_MACHINE ->
inject stream >>=
accept UL_MACHINE >>=
acceptIdent >>=
accept UL_ACCOUV >>=
parseSC >>=
accept UL_ACCFER
(* Failure *)
| _ -> Failure)
(* parseSC : inputStream -> parseResult *)
and parseSC stream =
(print_endline "SC");
(match (peekAtFirstToken stream) with
(* 2. SC -> Λ *)
| UL_ACCFER ->
inject stream
(* 3. SC -> C SC *)
| ( UL_EVENT | UL_FROM | UL_REGION ) ->
inject stream >>=
parseC >>=
parseSC
(* Failure *)
| _ -> Failure)
(* parseC : inputStream -> parseResult *)
and parseC stream =
(print_endline "C");
(match (peekAtFirstToken stream) with
(* 4. C -> event ident *)
| UL_EVENT ->
inject stream >>=
accept UL_EVENT >>=
acceptIdent
(* 5. C -> from NQ to NQ on ident *)
| UL_FROM ->
inject stream >>=
accept UL_FROM >>=
parseNQ >>=
accept UL_TO >>=
parseNQ >>=
accept UL_ON >>=
acceptIdent
(* 9. C -> R *)
| UL_REGION ->
inject stream >>=
parseR
(* Failure *)
| _ -> Failure)
(* parseNQ : inputStream -> parseResult *)
and parseNQ stream =
(print_endline "NQ");
(match (peekAtFirstToken stream) with
(* 6. NQ -> ident SQ *)
| (UL_IDENT _) ->
inject stream >>=
acceptIdent >>=
parseSQ
(* Failure *)
| _ -> Failure)
(* parseSQ : inputStream -> parseResult *)
and parseSQ stream =
(print_endline "SQ");
(match (peekAtFirstToken stream) with
(* 7. SQ -> Λ *)
| ( UL_TO | UL_ON ) ->
inject stream
(* 8. SQ -> . ident SQ *)
| UL_PT ->
inject stream >>=
accept UL_PT >>=
acceptIdent >>=
parseSQ
(* Failure *)
| _ -> Failure)
(* parseR : inputStream -> parseResult *)
and parseR stream =
(print_endline "R");
(match (peekAtFirstToken stream) with
(* 10. R -> region ident { E SE } *)
| UL_REGION ->
inject stream >>=
accept UL_REGION >>=
acceptIdent >>=
accept UL_ACCOUV >>=
parseE >>=
parseSE >>=
accept UL_ACCFER
(* Failure *)
| _ -> Failure)
(* parseSE : inputStream -> parseResult *)
and parseSE stream =
(print_endline "SE");
(match (peekAtFirstToken stream) with
(* 11. SE -> Λ *)
| UL_ACCFER ->
inject stream
(* 12. SE -> E SE *)
| UL_STATE ->
inject stream >>=
parseE >>=
parseSE
(* Failure *)
| _ -> Failure)
(* parseE : inputStream -> parseResult *)
and parseE stream =
(print_endline "E");
(match (peekAtFirstToken stream) with
(* 13. E -> state ident ES EE EC *)
| UL_STATE ->
inject stream >>=
accept UL_STATE >>=
acceptIdent >>=
parseES >>=
parseEE >>=
parseEC
(* Failure *)
| _ -> Failure)
(* parseES : inputStream -> parseResult *)
and parseES stream =
(print_endline "ES");
(match (peekAtFirstToken stream) with
(* 14. ES -> Λ *)
| ( UL_ENDS | UL_ACCOUV | UL_ACCFER | UL_STATE ) ->
inject stream
(* 15. ES -> starts *)
| UL_STARTS ->
inject stream >>=
accept UL_STARTS
(* Failure *)
| _ -> Failure)
(* parseEE : inputStream -> parseResult *)
and parseEE stream =
(print_endline "EE");
(match (peekAtFirstToken stream) with
(* 16. EE -> Λ *)
| ( UL_ACCOUV | UL_ACCFER | UL_STATE ) ->
inject stream
(* 17. EE -> ends *)
| UL_ENDS ->
inject stream >>=
accept UL_ENDS
(* Failure *)
| _ -> Failure)
(* parseEC : inputStream -> parseResult *)
and parseEC stream =
(print_endline "EC");
(match (peekAtFirstToken stream) with
(* 18. EC -> Λ *)
| ( UL_ACCFER | UL_STATE ) ->
inject stream
(* 19. EC -> { R SR } *)
| UL_ACCOUV ->
inject stream >>=
accept UL_ACCOUV >>=
parseR >>=
parseSR >>=
accept UL_ACCFER
(* Failure *)
| _ -> Failure)
(* parseSR : inputStream -> parseResult *)
and parseSR stream =
(print_endline "SR");
(match (peekAtFirstToken stream) with
(* 20. SR -> Λ *)
| UL_ACCFER ->
inject stream
(* 21. SR -> R SR *)
| UL_REGION ->
inject stream >>=
parseR >>=
parseSR
(* Failure *)
| _ -> Failure)

View file

@ -0,0 +1,43 @@
{
(* Partie recopiée dans le fichier CaML généré. *)
(* Ouverture de modules exploités dans les actions *)
(* Déclarations de types, de constantes, de fonctions, d'exceptions exploités dans les actions *)
open Tokens
exception Printf
}
(* Déclaration d'expressions régulières exploitées par la suite *)
let chiffre = ['0' - '9']
let minuscule = ['a' - 'z']
let majuscule = ['A' - 'Z']
let alphabet = minuscule | majuscule
let alphanum = alphabet | chiffre | '_'
let commentaire =
(* Commentaire fin de ligne *)
"#" [^'\n']*
rule scanner = parse
| ['\n' '\t' ' ']+ { (scanner lexbuf) }
| commentaire { (scanner lexbuf) }
| "machine" { UL_MACHINE::(scanner lexbuf) }
| "." { UL_PT::(scanner lexbuf) }
| "{" { UL_ACCOUV::(scanner lexbuf) }
| "}" { UL_ACCFER::(scanner lexbuf) }
| "to" { UL_TO::(scanner lexbuf) }
| "on" { UL_ON::(scanner lexbuf) }
| "event" { UL_EVENT::(scanner lexbuf) }
| "from" { UL_FROM::(scanner lexbuf) }
| "region" { UL_REGION::(scanner lexbuf) }
| "ends" { UL_ENDS::(scanner lexbuf) }
| "starts" { UL_STARTS::(scanner lexbuf) }
| "state" { UL_STATE::(scanner lexbuf) }
| eof { [UL_FIN] }
| alphabet+ as texte { (UL_IDENT texte)::(scanner lexbuf) }
| _ as texte { (print_string "Erreur lexicale : ");(print_char texte);(print_newline ()); (UL_ERREUR::(scanner lexbuf)) }
{
}

View file

@ -0,0 +1,68 @@
open List
type token =
| UL_ACCOUV
| UL_ACCFER
| UL_PT
| UL_MACHINE
| UL_TO
| UL_ON
| UL_EVENT
| UL_FROM
| UL_REGION
| UL_ENDS
| UL_STARTS
| UL_STATE
| UL_FIN
| UL_IDENT of string
| UL_ERREUR
;;
type inputStream = token list;;
(* string_of_token : token -> string *)
(* Converti un token en une chaîne de caractère*)
let string_of_token token =
match token with
| UL_MACHINE -> "machine"
| UL_ACCOUV -> "{"
| UL_ACCFER -> "}"
| UL_PT -> "."
| UL_TO -> "to"
| UL_ON -> "on"
| UL_EVENT -> "event"
| UL_FROM -> "from"
| UL_REGION -> "region"
| UL_ENDS -> "ends"
| UL_STARTS -> "starts"
| UL_STATE -> "state"
| UL_FIN -> "EOF"
| UL_ERREUR -> "Erreur Lexicale"
| UL_IDENT (texte) -> texte
;;
(* string_of_stream : inputStream -> string *)
(* Converti un inputStream (liste de token) en une chaîne de caractère *)
let string_of_stream stream =
List.fold_right (fun t tq -> (string_of_token t) ^ " " ^ tq ) stream "";;
(* peekAtFirstToken : inputStream -> token *)
(* Renvoie le premier élément d'un inputStream *)
(* Erreur : si l'inputStream est vide *)
let peekAtFirstToken stream =
match stream with
(* Normalement, ne doit jamais se produire sauf si la grammaire essaie de lire *)
(* après la fin de l'inputStream. *)
| [] -> failwith "Impossible d'acceder au premier element d'un inputStream vide"
|t::_ -> t;;
(* advanceInStream : inputStream -> inputStream *)
(* Consomme le premier élément d'un inputStream *)
(* Erreur : si l'inputStream est vide *)
let advanceInStream stream =
match stream with
(* Normalement, ne doit jamais se produire sauf si la grammaire essaie de lire *)
(* après la fin de l'inputStream. *)
| [] -> failwith "Impossible de consommer le premier element d'un inputStream vide"
| _::q -> q;;

4
BE_2020_2021/descendant/dune Executable file
View file

@ -0,0 +1,4 @@
(ocamllex Scanner)
(executables
(names MainMachine))

View file

@ -0,0 +1 @@
(lang dune 2.9)

10
BE_2020_2021/tests/sujet.sml Executable file
View file

@ -0,0 +1,10 @@
machine lamp {
event switchOn
event switchOff
region bulb {
state Off starts ends
state On
}
from bulb.Off to buld.On on switchOn
from buld.On to buld.Off on SwitchOff
}

View file

@ -0,0 +1 @@
machine Test {

View file

@ -0,0 +1,2 @@
machine Test {
}

View file

@ -0,0 +1,55 @@
{
(* Partie recopiée dans le fichier CaML généré. *)
(* Ouverture de modules exploités dans les actions *)
(* Déclarations de types, de constantes, de fonctions, d'exceptions exploités dans les actions *)
open Parser
exception LexicalError
}
(* Déclaration d'expressions régulières exploitées par la suite *)
let chiffre = ['0' - '9']
let entier = ['1' - '9']
let minuscule = ['a' - 'z']
let majuscule = ['A' - 'Z']
let alphabet = minuscule | majuscule
let alphanum = alphabet | chiffre | '_'
let commentaire =
(* Commentaire fin de ligne *)
"#" [^'\n']*
rule lexer = parse
| ['\n' '\t' ' ']+ { (lexer lexbuf) }
| commentaire { (lexer lexbuf) }
| "model" { UL_MODEL }
| "system" { UL_SYSTEM }
| "block" { UL_BLOCK }
| "flow" { UL_FLOW }
| "from" { UL_FROM }
| "to" { UL_TO }
| "in" { UL_IN }
| "out" { UL_OUT }
| "int" { UL_INT }
| "float" { UL_FLOAT }
| "boolean" { UL_BOOLEAN }
| "{" { UL_ACCOUV }
| "}" { UL_ACCFER }
| "(" { UL_PAROUV }
| ")" { UL_PARFER }
| "[" { UL_CROOUV }
| "]" { UL_CROFER }
| ";" { UL_PTV }
| "," { UL_VIRG }
| ":" { UL_PT2 }
| "." { UL_PT }
| eof { UL_FIN }
| majuscule alphabet* as texte { (UL_IDENT texte) }
| minuscule alphabet* as texte { (UL_PORT texte) }
| entier chiffre* as texte { (UL_ENTIER (int_of_string texte)) }
| _ as texte { (print_string "Erreur lexicale : ");(print_char texte);(print_newline ()); raise LexicalError }
{
}

View file

@ -0,0 +1,52 @@
open Parser
(* Fonction d'affichage des unités lexicales et des données qu'elles contiennent *)
let printToken t =
(print_endline
(match t with
| UL_MODEL -> "model"
| UL_SYSTEM -> "system"
| UL_BLOCK -> "block"
| UL_FLOW -> "flow"
| UL_FROM -> "from"
| UL_TO -> "to"
| UL_IN -> "in"
| UL_OUT -> "out"
| UL_INT -> "int"
| UL_FLOAT -> "float"
| UL_BOOLEAN -> "boolean"
| UL_ACCOUV -> "{"
| UL_ACCFER -> "}"
| UL_PAROUV -> "("
| UL_PARFER -> ")"
| UL_CROOUV -> "["
| UL_CROFER -> "]"
| UL_PTV -> ";"
| UL_VIRG -> ","
| UL_PT2 -> ":"
| UL_PT -> "."
| UL_IDENT texte -> texte
| UL_PORT texte -> texte
| UL_ENTIER texte -> (string_of_int texte)
| UL_FIN -> "EOF"
));;
(* Analyse lexicale du fichier passé en paramètre de la ligne de commande *)
if (Array.length Sys.argv > 1)
then
let lexbuf = (Lexing.from_channel (open_in Sys.argv.(1))) in
let token = ref (Lexer.lexer lexbuf) in
while ((!token) != UL_FIN) do
(printToken (!token));
(token := (Lexer.lexer lexbuf))
done
else
(print_endline "MainJSON fichier");;
(* Analyse lexicale, syntaxique et sémantique du fichier passé en paramètre de la ligne de commande *)
if (Array.length Sys.argv > 1)
then
let lexbuf = (Lexing.from_channel (open_in Sys.argv.(1))) in
(Parser.modele Lexer.lexer lexbuf)
else
(print_endline "MainJSON fichier");;

View file

@ -0,0 +1,88 @@
%{
(* Partie recopiee dans le fichier CaML genere. *)
(* Ouverture de modules exploites dans les actions *)
(* Declarations de types, de constantes, de fonctions, d'exceptions exploites dans les actions *)
%}
/* Declaration des unites lexicales et de leur type si une valeur particuliere leur est associee */
%token UL_MODEL
%token UL_ACCOUV UL_ACCFER
%token UL_SYSTEM
%token UL_BLOCK
%token UL_FLOW UL_FROM UL_TO
%token UL_IN UL_OUT
%token UL_INT UL_FLOAT UL_BOOLEAN
%token UL_PAROUV UL_PARFER
%token UL_CROOUV UL_CROFER
%token UL_PTV UL_VIRG UL_PT2 UL_PT
/* Defini le type des donnees associees a l'unite lexicale */
%token <string> UL_IDENT
%token <string> UL_PORT
%token <int> UL_ENTIER
/* Unite lexicale particuliere qui represente la fin du fichier */
%token UL_FIN
/* Type renvoye pour le nom terminal document */
%type <unit> modele
/* Le non terminal document est l'axiome */
%start modele
%% /* Regles de productions */
modele : UL_MODEL UL_IDENT UL_ACCOUV loop_element UL_ACCFER UL_FIN { (print_endline "modele : UL_MODEL IDENT { loop_element } UL_FIN ") }
element : bloc { (print_endline "element : bloc") }
| systeme { (print_endline "element : systeme") }
| flot { (print_endline "element : flot") }
loop_element : /* Lambda */ { (print_endline "loop_element : /* Lambda */") }
| element loop_element { (print_endline "loop_element : element loop_element") }
bloc : UL_BLOCK UL_IDENT parametres UL_PTV { (print_endline "bloc : UL_BLOCK UL_IDENT parametres UL_PTV") }
systeme : UL_SYSTEM UL_IDENT parametres UL_ACCOUV loop_element UL_ACCFER { (print_endline "systeme : UL_SYSTEM UL_IDENT parametres UL_ACCOUV loop_element UL_ACCFER") }
parametres : UL_PAROUV port loop_port UL_PARFER { (print_endline "parametres : UL_PAROUV port loop_port UL_PARFER") }
loop_port : /* Lambda */ { (print_endline "loop_port : /* Lambda */") }
| UL_VIRG port loop_port { (print_endline "loop_port : UL_VIRG port loop_port") }
port : UL_PORT UL_PT2 in_or_out type_ { (print_endline "port : UL_PORT UL_PT2 in_or_out type_") }
in_or_out : UL_IN { (print_endline "in_or_out : UL_IN") }
| UL_OUT { (print_endline "in_or_out : UL_OUT") }
type_ : select_type option_entiers { (print_endline "type_ : select_type option_entiers") }
select_type : UL_INT { (print_endline "select_type : UL_INT") }
| UL_FLOAT { (print_endline "select_type : UL_FLOAT") }
| UL_BOOLEAN { (print_endline "select_type : UL_BOOLEAN") }
option_entiers : /* Lambda */ { (print_endline "option_entiers : /* Lambda */") }
| UL_CROOUV UL_ENTIER loop_entier UL_CROFER { (print_endline "option_entiers : UL_CROOUV UL_ENTIER loop_entier UL_CROFER") }
loop_entier : /* Lambda */ { (print_endline "loop_entier : /* Lambda */") }
| UL_VIRG UL_ENTIER loop_entier { (print_endline "loop_entier : UL_VIRG UL_ENTIER loop_entier") }
flot : UL_FLOW UL_PORT UL_FROM option_ident UL_PORT UL_TO option_loop_ident_port UL_PTV { (print_endline "flot : UL_FLOW UL_PORT UL_FROM option_ident UL_PORT UL_TO option_loop_ident_port UL_PTV") }
option_ident : /* Lambda */ { (print_endline "option_ident : /* Lambda */") }
| UL_IDENT UL_PT { (print_endline "option_ident : UL_IDENT UL_PT") }
ident_port : option_ident UL_PORT { (print_endline "ident_port : option_ident UL_PORT") }
loop_ident_port : /* Lambda */ { (print_endline "loop_ident_port : /* Lambda */") }
| UL_VIRG ident_port loop_ident_port { (print_endline "loop_ident_port : UL_IDENT UL_PT") }
option_loop_ident_port : /* Lambda */ { (print_endline "option_loop_ident_port : /* Lambda */") }
| ident_port loop_ident_port { (print_endline "option_loop_ident_port : ident_port loop_ident_port") }
%%

View file

@ -0,0 +1,7 @@
(ocamllex Lexer)
(menhir
(modules Parser))
(executable
(name MainSystem))

View file

@ -0,0 +1,2 @@
(lang dune 2.9)
(using menhir 2.1)

View file

@ -0,0 +1,25 @@
open Tokens
open Scanner
open Parser
(* main : unit -> unit *)
(* Analyse le contenu d'un fichier passé en paramètre ou l'entrée standard si aucun fichier n'est donné *)
(* Affiche OK si l'analyse syntaxique c'est bien passée et KO sinon *)
let main () =
let cin =
if Array.length Sys.argv > 1 then
open_in Sys.argv.(1)
else
stdin
in
let lexbuf = Lexing.from_channel cin in
let tokens = (scanner lexbuf) in
(print_endline ("Résultat de l'analyse lexicale :" ^ (string_of_stream tokens)));
(print_endline "Analyse syntaxique par descente récursive, règles appliquées :");
(match (parseR tokens)
with
| Success [UL_FIN] -> print_endline "Succés"
| _ -> print_endline "Echec")
;;
main();;

View file

@ -0,0 +1,303 @@
open Tokens
(* Type du résultat d'une analyse syntaxique *)
type parseResult =
| Success of inputStream
| Failure
;;
(* accept : token -> inputStream -> parseResult *)
(* Vérifie que le premier token du flux d'entrée est bien le token attendu *)
(* et avance dans l'analyse si c'est le cas *)
let accept expected stream =
match (peekAtFirstToken stream) with
| token when (token = expected) ->
(Success (advanceInStream stream))
| _ -> Failure
;;
(* acceptIdent : inputStream -> parseResult *)
(* Vérifie que le premier token du flux d'entrée est bien un identifiant *)
(* et avance dans l'analyse si c'est le cas *)
let acceptIdent stream =
match (peekAtFirstToken stream) with
| (UL_IDENT _) -> (Success (advanceInStream stream))
| _ -> Failure
;;
(* acceptPort : inputStream -> parseResult *)
(* Vérifie que le premier token du flux d'entrée est bien un port *)
(* et avance dans l'analyse si c'est le cas *)
let acceptPort stream =
match (peekAtFirstToken stream) with
| (UL_PORT _) -> (Success (advanceInStream stream))
| _ -> Failure
;;
(* acceptEntier : inputStream -> parseResult *)
(* Vérifie que le premier token du flux d'entrée est bien un entier *)
(* et avance dans l'analyse si c'est le cas *)
let acceptEntier stream =
match (peekAtFirstToken stream) with
| (UL_ENTIER _) -> (Success (advanceInStream stream))
| _ -> Failure
;;
(* Définition de la monade qui est composée de : *)
(* - le type de donnée monadique : parseResult *)
(* - la fonction : inject qui construit ce type à partir d'une liste de terminaux *)
(* - la fonction : bind (opérateur >>=) qui combine les fonctions d'analyse. *)
(* inject inputStream -> parseResult *)
(* Construit le type de la monade à partir d'une liste de terminaux *)
let inject s = Success s;;
(* bind : 'a m -> ('a -> 'b m) -> 'b m *)
(* bind (opérateur >>=) qui combine les fonctions d'analyse. *)
(* ici on utilise une version spécialisée de bind :
'b -> inputStream
'a -> inputStream
m -> parseResult
*)
(* >>= : parseResult -> (inputStream -> parseResult) -> parseResult *)
let (>>=) result f =
match result with
| Success next -> f next
| Failure -> Failure
;;
(* parseR : inputStream -> parseResult *)
(* Analyse du non terminal Programme *)
let rec parseR stream =
(print_string "R");
(match (peekAtFirstToken stream) with
(* 1. R -> model Ident { SE } *)
| UL_MODEL ->
inject stream >>=
accept UL_MODEL >>=
acceptIdent >>=
accept UL_ACCOUV >>=
parseSE >>=
accept UL_ACCFER
(* Failure *)
| _ -> Failure)
(* parseSE : inputStream -> parseResult *)
and parseSE stream =
(print_endline "SE");
(match (peekAtFirstToken stream) with
(* 2. SE -> Λ *)
| UL_ACCFER ->
inject stream
(* 3. SE -> E SE *)
| ( UL_BLOCK | UL_SYSTEM | UL_FLOW ) ->
inject stream >>=
parseE >>=
parseSE
(* Failure *)
| _ -> Failure)
(* parseE : inputStream -> parseResult *)
and parseE stream =
(print_endline "E");
(match (peekAtFirstToken stream) with
(* 4. E -> block Ident P ; *)
| UL_BLOCK ->
inject stream >>=
accept UL_BLOCK >>=
acceptIdent >>=
parseP >>=
accept UL_PTV
(* 5. E -> system Ident P { SE } *)
| UL_SYSTEM ->
inject stream >>=
accept UL_SYSTEM >>=
acceptIdent >>=
parseP >>=
accept UL_ACCOUV >>=
parseSE >>=
accept UL_ACCFER
(* 6. E -> flow ident from NQ to LN ; *)
| UL_FLOW ->
inject stream >>=
accept UL_FLOW >>=
acceptPort >>=
accept UL_FROM >>=
parseNQ >>=
accept UL_TO >>=
parseLN >>=
accept UL_PTV
(* Failure *)
| _ -> Failure)
(* parseNQ : inputStream -> parseResult *)
and parseNQ stream =
(print_endline "NQ");
(match (peekAtFirstToken stream) with
(* 7. NQ -> ident *)
| (UL_PORT _) ->
inject stream >>=
acceptPort
(* 8. NQ -> Ident . ident *)
| (UL_IDENT _) ->
inject stream >>=
acceptIdent >>=
accept UL_PT >>=
acceptPort
(* Failure *)
| _ -> Failure)
(* parseLN : inputStream -> parseResult *)
and parseLN stream =
(print_endline "LN");
(match (peekAtFirstToken stream) with
(* 9. LN -> Λ *)
| UL_PTV ->
inject stream
(* 10. LN -> NQ SN *)
| ( (UL_IDENT _) | (UL_PORT _) ) ->
inject stream >>=
parseNQ >>=
parseSN
(* Failure *)
| _ -> Failure)
(* parseSN : inputStream -> parseResult *)
and parseSN stream =
(print_endline "SN");
(match (peekAtFirstToken stream) with
(* 11. SN -> Λ *)
| UL_PTV ->
inject stream
(* 12. LN -> , NQ SN *)
| UL_VIRG ->
inject stream >>=
accept UL_VIRG >>=
parseNQ >>=
parseSN
(* Failure *)
| _ -> Failure)
(* parseP : inputStream -> parseResult *)
and parseP stream =
(print_endline "P");
(match (peekAtFirstToken stream) with
(* 13. P -> ( LP ) *)
| UL_PAROUV ->
inject stream >>=
accept UL_PAROUV >>=
parseLP >>=
accept UL_PARFER
(* Failure *)
| _ -> Failure)
(* parseLP : inputStream -> parseResult *)
and parseLP stream =
(print_endline "LP");
(match (peekAtFirstToken stream) with
(* 14. LP -> DP SP *)
| (UL_PORT _) ->
inject stream >>=
parseDP >>=
parseSP
(* Failure *)
| _ -> Failure)
(* parseSP : inputStream -> parseResult *)
and parseSP stream =
(print_endline "SP");
(match (peekAtFirstToken stream) with
(* 15. SP -> Λ *)
| UL_PARFER ->
inject stream
(* 16. LN -> , DP SP *)
| UL_VIRG ->
inject stream >>=
accept UL_VIRG >>=
parseDP >>=
parseSP
(* Failure *)
| _ -> Failure)
(* parseDP : inputStream -> parseResult *)
and parseDP stream =
(print_endline "DP");
(match (peekAtFirstToken stream) with
(* 17. LP -> ident : M T OT *)
| (UL_PORT _) ->
inject stream >>=
acceptPort >>=
accept UL_PT2 >>=
parseM >>=
parseT >>=
parseOT
(* Failure *)
| _ -> Failure)
(* parseM : inputStream -> parseResult *)
and parseM stream =
(print_endline "M");
(match (peekAtFirstToken stream) with
(* 18. M -> in *)
| UL_IN ->
inject stream >>=
accept UL_IN
(* 19. M -> out *)
| UL_OUT ->
inject stream >>=
accept UL_OUT
(* Failure *)
| _ -> Failure)
(* parseT : inputStream -> parseResult *)
and parseT stream =
(print_endline "T");
(match (peekAtFirstToken stream) with
(* 20. T -> int *)
| UL_INT ->
inject stream >>=
accept UL_INT
(* 21. M -> float *)
| UL_FLOAT ->
inject stream >>=
accept UL_FLOAT
(* 22. M -> boolean *)
| UL_BOOLEAN ->
inject stream >>=
accept UL_BOOLEAN
(* Failure *)
| _ -> Failure)
(* parseOT : inputStream -> parseResult *)
and parseOT stream =
(print_endline "OT");
(match (peekAtFirstToken stream) with
(* 23. OT -> Λ *)
| ( UL_VIRG | UL_PARFER ) ->
inject stream
(* 24. OT -> [ entier SV ] *)
| UL_CROOUV ->
inject stream >>=
accept UL_CROOUV >>=
acceptEntier >>=
parseSV >>=
accept UL_CROFER
(* Failure *)
| _ -> Failure)
(* parseSV : inputStream -> parseResult *)
and parseSV stream =
(print_endline "SV");
(match (peekAtFirstToken stream) with
(* 25. OT -> Λ *)
| UL_CROFER ->
inject stream
(* 26. OT -> , entier SV *)
| UL_VIRG ->
inject stream >>=
accept UL_VIRG >>=
acceptEntier >>=
parseSV
(* Failure *)
| _ -> Failure)

View file

@ -0,0 +1,55 @@
{
(* Partie recopiée dans le fichier CaML généré. *)
(* Ouverture de modules exploités dans les actions *)
(* Déclarations de types, de constantes, de fonctions, d'exceptions exploités dans les actions *)
open Tokens
exception Printf
}
(* Déclaration d'expressions régulières exploitées par la suite *)
let chiffre = ['0' - '9']
let entier = ['1' - '9']
let minuscule = ['a' - 'z']
let majuscule = ['A' - 'Z']
let alphabet = minuscule | majuscule
let alphanum = alphabet | chiffre | '_'
let commentaire =
(* Commentaire fin de ligne *)
"#" [^'\n']*
rule scanner = parse
| ['\n' '\t' ' ']+ { (scanner lexbuf) }
| commentaire { (scanner lexbuf) }
| "model" { UL_MODEL::(scanner lexbuf) }
| "system" { UL_SYSTEM::(scanner lexbuf) }
| "block" { UL_BLOCK::(scanner lexbuf) }
| "flow" { UL_FLOW::(scanner lexbuf) }
| "from" { UL_FROM::(scanner lexbuf) }
| "to" { UL_TO::(scanner lexbuf) }
| "in" { UL_IN::(scanner lexbuf) }
| "out" { UL_OUT::(scanner lexbuf) }
| "int" { UL_INT::(scanner lexbuf) }
| "float" { UL_FLOAT::(scanner lexbuf) }
| "boolean" { UL_BOOLEAN::(scanner lexbuf) }
| "{" { UL_ACCOUV::(scanner lexbuf) }
| "}" { UL_ACCFER::(scanner lexbuf) }
| "(" { UL_PAROUV::(scanner lexbuf) }
| ")" { UL_PARFER::(scanner lexbuf) }
| "[" { UL_CROOUV::(scanner lexbuf) }
| "]" { UL_CROFER::(scanner lexbuf) }
| ";" { UL_PTV::(scanner lexbuf) }
| "," { UL_VIRG::(scanner lexbuf) }
| ":" { UL_PT2::(scanner lexbuf) }
| "." { UL_PT::(scanner lexbuf) }
| majuscule alphabet* as texte { (UL_IDENT texte)::(scanner lexbuf) }
| minuscule alphabet* as texte { (UL_PORT texte)::(scanner lexbuf) }
| entier chiffre* as texte { (UL_ENTIER (int_of_string texte))::(scanner lexbuf) }
| eof { [UL_FIN] }
| _ as texte { (print_string "Erreur lexicale : ");(print_char texte);(print_newline ()); (UL_ERREUR::(scanner lexbuf)) }
{
}

View file

@ -0,0 +1,88 @@
open List
type token =
| UL_MODEL
| UL_SYSTEM
| UL_BLOCK
| UL_FLOW
| UL_FROM
| UL_TO
| UL_IN
| UL_OUT
| UL_INT
| UL_FLOAT
| UL_BOOLEAN
| UL_ACCOUV
| UL_ACCFER
| UL_PAROUV
| UL_PARFER
| UL_CROOUV
| UL_CROFER
| UL_PTV
| UL_VIRG
| UL_PT2
| UL_PT
| UL_IDENT of string
| UL_PORT of string
| UL_ENTIER of int
| UL_FIN
| UL_ERREUR;;
type inputStream = token list;;
(* string_of_token : token -> string *)
(* Converti un token en une chaîne de caractère*)
let string_of_token token =
match token with
| UL_MODEL -> "model"
| UL_SYSTEM -> "system"
| UL_BLOCK -> "block"
| UL_FLOW -> "flow"
| UL_FROM -> "from"
| UL_TO -> "to"
| UL_IN -> "in"
| UL_OUT -> "out"
| UL_INT -> "int"
| UL_FLOAT -> "float"
| UL_BOOLEAN -> "boolean"
| UL_ACCOUV -> "{"
| UL_ACCFER -> "}"
| UL_PAROUV -> "("
| UL_PARFER -> ")"
| UL_CROOUV -> "["
| UL_CROFER -> "]"
| UL_PTV -> ";"
| UL_VIRG -> ","
| UL_PT2 -> ":"
| UL_PT -> "."
| UL_IDENT texte -> texte
| UL_PORT texte -> texte
| UL_ENTIER texte -> (string_of_int texte)
| UL_FIN -> "EOF"
| UL_ERREUR -> "Erreur Lexicale";;
(* string_of_stream : inputStream -> string *)
(* Converti un inputStream (liste de token) en une chaîne de caractère *)
let string_of_stream stream =
List.fold_right (fun t tq -> (string_of_token t) ^ " " ^ tq ) stream "";;
(* peekAtFirstToken : inputStream -> token *)
(* Renvoie le premier élément d'un inputStream *)
(* Erreur : si l'inputStream est vide *)
let peekAtFirstToken stream =
match stream with
(* Normalement, ne doit jamais se produire sauf si la grammaire essaie de lire *)
(* après la fin de l'inputStream. *)
| [] -> failwith "Impossible d'acceder au premier element d'un inputStream vide"
|t::_ -> t;;
(* advanceInStream : inputStream -> inputStream *)
(* Consomme le premier élément d'un inputStream *)
(* Erreur : si l'inputStream est vide *)
let advanceInStream stream =
match stream with
(* Normalement, ne doit jamais se produire sauf si la grammaire essaie de lire *)
(* après la fin de l'inputStream. *)
| [] -> failwith "Impossible de consommer le premier element d'un inputStream vide"
| _::q -> q;;

View file

@ -0,0 +1,4 @@
(ocamllex Scanner)
(executables
(names MainSystem))

View file

@ -0,0 +1 @@
(lang dune 2.9)

View file

@ -0,0 +1,11 @@
model S {
flow f from Ba.ra to HS.pa, HS.pb;
block Ba(pa : in float, pb : in float, ra : out float [ 2 ] );
system HS(pa : in float [ 2 ], ra : out float, pb : in float [ 2 ] , rb : out float [ 2 ] ) {
block Bb(ra : out float, pa : in float);
flow fa from pa to Bb.pa;
flow fb from pb to rb;
}
flow fb from HS.ra to Ba.pa, Ba.pb;
flow fc from HS.rb to;
}

5
TP1/dune Executable file
View file

@ -0,0 +1,5 @@
(ocamllex lexerJava)
(executable
(modes byte exe)
(name mainJava))

3
TP1/dune-project Executable file
View file

@ -0,0 +1,3 @@
(lang dune 2.0)
(formatting disabled)

95
TP1/lexerJava.mll Executable file
View file

@ -0,0 +1,95 @@
{
open TokenJava
(* open String *)
(* open Str *)
exception LexicalError
}
(* Macro-definitions *)
let minuscule = ['a'-'z']
let javaLetter = minuscule | '_'
let majuscule = ['A'-'Z']
let chiffre = ['0'-'9']
let hexa = chiffre | ['a'-'f'] | ['A'-'F']
let octa = ['0'-'7']
let alphabet = minuscule | majuscule
let alphanum = alphabet | chiffre | '_'
let commentaireBloc = "/*" [^'*']* ('*' [^'/'] [^'*']*)* "*/"
let commentaireLigne = "//" [^'\n']* '\n'
(* Analyseur lexical : expression reguliere { action CaML } *)
rule lexer = parse
(* Espace, tabulation, passage a ligne, etc : consommes par l'analyse lexicale *)
| ['\n' '\t' ' ']+ { lexer lexbuf }
(* Commentaires consommés par l'analyse lexicale *)
| commentaireBloc { lexer lexbuf }
| commentaireLigne { lexer lexbuf }
(* Structures de blocs *)
| "(" { PAROUV }
| ")" { PARFER }
| "[" { CROOUV }
| "]" { CROFER }
| "{" { ACCOUV }
| "}" { ACCFER }
(* Separateurs *)
| "," { VIRG }
| ";" { PTVIRG }
(* Operateurs booleens *)
| "||" { OPOU }
| "&&" { OPET }
| "!" { OPNON }
(* Operateurs comparaisons *)
| "==" { OPEG }
| "!=" { OPNONEG }
| "<=" { OPSUPEG }
| "<" { OPSUP }
| ">=" { OPINFEG }
| ">" { OPINF }
(* Operateurs arithmetiques *)
| "+" { OPPLUS }
| "-" { OPMOINS }
| "*" { OPMULT }
| "/" { OPDIV }
| "%" { OPMOD }
| "." { OPPT }
| "=" { ASSIGN }
| "new" { NOUVEAU }
(* Mots cles : types *)
| "bool" { BOOL }
| "char" { CHAR }
| "float" { FLOAT }
| "int" { INT }
| "String" { STRING }
| "void" { VOID }
(* Mots cles : instructions *)
| "while" { TANTQUE }
| "if" { SI }
| "else" { SINON }
| "return" { RETOUR }
(* Mots cles : constantes *)
| "true" { (BOOLEEN true) }
| "false" { (BOOLEEN false) }
| "null" { VIDE }
(* Nombres entiers : *)
| ( '0' | (['1' - '9'](chiffre | '_')*) ) as texte { (ENTIER (int_of_string texte)) }
| ( '0'('b'|'B') (chiffre | '_')* ) as texte { (BINAIRE (int_of_string texte)) }
| ( '0'('x'|'X') (hexa | '_')* ) as texte { (HEXA (int_of_string texte)) }
| ( '0'* (octa | '_')* ) as texte { (OCTA (int_of_string ("0o" ^ texte))) }
(* Nombres flottants : *)
| ['+''-']? ( chiffre+ | chiffre+ '.' chiffre+ | '.' chiffre+ | chiffre+ '.' ) (['e''E'] ['+''-']? chiffre+ )? as texte { (FLOTTANT (float_of_string texte)) }
(* Caracteres : *)
| "'" _ "'" as texte { CARACTERE texte.[1] }
| "'" '\\' _* "'" as texte { print_endline texte; CARACTERE (char_of_int (int_of_string (String.sub texte 2 ((String.length texte) - 3)))) }
(* Chaines de caracteres : A COMPLETER *)
| '"' _* '"' as texte { CHAINE texte }
(* Identificateurs *)
| majuscule alphanum* as texte { TYPEIDENT texte }
| javaLetter alphanum* as texte { IDENT texte }
| eof { FIN }
| _ { raise LexicalError }
{
}

12
TP1/mainJava.ml Executable file
View file

@ -0,0 +1,12 @@
open TokenJava;;
if (Array.length Sys.argv > 1)
then
let lexbuf = (Lexing.from_channel (open_in Sys.argv.(1))) in
let token = ref (LexerJava.lexer lexbuf) in
while ((!token) != FIN) do
(printToken (!token));
(token := (LexerJava.lexer lexbuf))
done
else
(print_endline "mainJava.exe fichier")

View file

@ -0,0 +1,49 @@
/* Cet exemple respecte la syntaxe (grammaire) de microjava, avec des
* commentaires, des cha<EFBFBD>nes complexes, des r<EFBFBD>els bizarres...
* Les constructions qui ne sont pas trait
* Ce programme est s<EFBFBD>mantiquement faux (typage en particulier)
*/
/* class Point {
private int x;
private int y;
private String toto;
// rien {
public int get_x () */
{ return x; }
// public void set_x (int _x)
{ x = _x; }
// private void essai_string ()
{
toto = "machin avec des espaces et des \" quotes
et multiligne avec echappement \n meme a la fin \\"; foo(); "et une autre chaine";
x = 3.14 + .14 + 3. + 14e-1 + .3e1;
y = 'a' + '\33' + 0x2A;
}
}
/* ghjd /* ****/
/* class PointColore extends Point {
public int c;
public int get_c () */
{ return c*2; }
/* } */
/*****
class PointColore extends Point **g
// dfgkhdk *f ** */
/* public class Exemple {
public static void main (String[] argv) */
{
int x;
bool b;
b = true;
if (b) {
x = 2*x + 3;
}
}
// }

32
TP1/tests/exemple-simple.java Executable file
View file

@ -0,0 +1,32 @@
// Note: ce fichier ne respecte pas la *grammaire* de micro-java
// Il ne fait qu'enumerer les tokens de la grammaire.
// mot clefs
// class extends private public static main
// types
int void float bool char String
// structures de controle
if else while return
// instructions
new null
// operateurs
< > >= <= == !=
+ - / * % && || ! = .
// parentheses
( [ { } ] )
// separateurs
, ;
// constantes
true false 0 245 1_234_567 0b1101 0B1_0100_1100 077 01_345 0xFF 0X1_FF00_1234 'a' '(' '?' '\'' '\\' 567.34 +1e-5 -.12 1.5e-4 2.
"bonjour"
// noms
x toto Point

View file

@ -0,0 +1,3 @@
, /* test */ int while // ceci est un autre test
" te \" st "
123

2
TP1/tests/exemple.java Executable file
View file

@ -0,0 +1,2 @@
453 while 45, 4, 8
int 4 int while , 8

11
TP1/tests/test.java Executable file
View file

@ -0,0 +1,11 @@
// commentaire ligne
/*
commentaire
bloc
*/
a = 4
/*aaa*/
index + 000123
{
bonjour = 3
}

121
TP1/tokenJava.ml Executable file
View file

@ -0,0 +1,121 @@
open Char
(* Type déclarent les différentes unités lexicales possibles *)
type token =
(* Identificateurs *)
| IDENT of string
| TYPEIDENT of string
(* Mots cles : types *)
| INT
| FLOAT
| BOOL
| CHAR
| VOID
| STRING
(* Structure de blocs *)
| ACCOUV
| ACCFER
| PAROUV
| PARFER
| CROOUV
| CROFER
(* Separateurs *)
| PTVIRG
| VIRG
(* Mots cles : Instructions *)
| SI
| SINON
| TANTQUE
| RETOUR
(* Valeurs *)
| ENTIER of int
| BINAIRE of int
| HEXA of int
| OCTA of int
| FLOTTANT of float
| BOOLEEN of bool
| CARACTERE of char
| CHAINE of string
| VIDE
(* Operateurs *)
| NOUVEAU
| ASSIGN
| OPPT
(* Comparaison *)
| OPNONEG
| OPEG
| OPSUPEG
| OPINFEG
| OPSUP
| OPINF
(* Booleen *)
| OPOU
| OPET
| OPNON
(* Arithmetique *)
| OPPLUS
| OPMOINS
| OPMULT
| OPDIV
| OPMOD
(* Fin de texte *)
| FIN ;;
let printToken t =
(print_endline
(match t with
(* Structure de blocs *)
| PAROUV -> "bloc : ("
| PARFER -> "bloc : )"
| CROOUV -> "bloc : ["
| CROFER -> "bloc : ]"
| ACCOUV -> "bloc : {"
| ACCFER -> "bloc : }"
(* Separateurs *)
| VIRG -> "separateur : ,"
| PTVIRG -> "separateur : ;"
(* Operateurs *)
| OPEG -> "operateur : =="
| OPNONEG -> "operateur : !="
| OPINFEG -> "operateur : >="
| OPINF -> "operateur : >"
| OPSUPEG -> "operateur : <="
| OPSUP -> "operateur : <"
| OPET -> "operateur : &&"
| OPOU -> "operateur : ||"
| OPNON -> "operateur : !"
| OPPLUS -> "operateur : +"
| OPMOINS -> "operateur : -"
| OPMULT -> "operateur : *"
| OPDIV -> "operateur : /"
| OPMOD -> "operateur : %"
| ASSIGN -> "operateur : ="
| OPPT -> "operateur : ."
| NOUVEAU -> "operateur : new"
(* Mots cles : Instructions *)
| TANTQUE -> "mot-cle : while"
| SI -> "mot-cle : if"
| SINON -> "mot-cle : else"
| RETOUR -> "mot-cle : return"
(* Mots cles : Types *)
| BOOL -> "type : boolean"
| CHAR -> "type : char"
| FLOAT -> "type : float"
| INT -> "type : int"
| STRING -> "type : String"
| VOID -> "type : void"
(* Valeurs *)
| BOOLEEN b -> "booleen : " ^ (if b then "true" else "false")
| CARACTERE c -> "caractere : '" ^ (escaped c) ^ "'"
| CHAINE s -> "chaine : " ^ s
| ENTIER n -> "entier : " ^ string_of_int n
| HEXA n -> "hexa : " ^ string_of_int n
| OCTA n -> "octa : " ^ string_of_int n
| BINAIRE n -> "binaire : " ^ string_of_int n
| FLOTTANT f -> "flottant : " ^ string_of_float f
| VIDE -> "null"
(* Identificateurs *)
| IDENT n -> "identificateur : " ^ n
| TYPEIDENT t -> "identificateur de type : " ^ t
| _ -> "TBC"));;

65
TP1/tokenJava.mli Executable file
View file

@ -0,0 +1,65 @@
(* Type déclarent les différentes unités lexicales possibles *)
type token =
(* Identificateurs *)
| IDENT of string
| TYPEIDENT of string
(* Mots cles : types *)
| INT
| FLOAT
| BOOL
| CHAR
| VOID
| STRING
(* Structure de blocs *)
| ACCOUV
| ACCFER
| PAROUV
| PARFER
| CROOUV
| CROFER
(* Separateurs *)
| PTVIRG
| VIRG
(* Mots cles : Instructions *)
| SI
| SINON
| TANTQUE
| RETOUR
(* Valeurs *)
| ENTIER of int
| BINAIRE of int
| HEXA of int
| OCTA of int
| FLOTTANT of float
| BOOLEEN of bool
| CARACTERE of char
| CHAINE of string
| VIDE
(* Operateurs *)
| NOUVEAU
| ASSIGN
| OPPT
(* Comparaison *)
| OPNONEG
| OPEG
| OPSUPEG
| OPINFEG
| OPSUP
| OPINF
(* Booleen *)
| OPOU
| OPET
| OPNON
(* Arithmetique *)
| OPPLUS
| OPMOINS
| OPMULT
| OPDIV
| OPMOD
(* Fin de texte *)
| FIN ;;
(* Fonction d'affichage d'une unité lexicale *)
val printToken : token -> unit;;

7
TP2/dune Executable file
View file

@ -0,0 +1,7 @@
(ocamllex lexerJava)
(menhir
(modules parserJava))
(executable
(name mainJava))

5
TP2/dune-project Executable file
View file

@ -0,0 +1,5 @@
(lang dune 2.0)
(using menhir 2.0)
(formatting disabled)

82
TP2/lexerJava.mll Executable file
View file

@ -0,0 +1,82 @@
{
(* Partie recopiée dans le fichier CaML généré. *)
(* Ouverture de modules exploités dans les actions *)
(* Déclarations de types, de constantes, de fonctions, d'exceptions exploités dans les actions *)
open ParserJava
exception LexicalError
}
(* Déclaration d'expressions régulières exploitées par la suite *)
let chiffre = ['0' - '9']
let binaire = ('0' | '1')
let octal = ['0' - '7']
let hexadecimal = chiffre | ['A' - 'F']
let minuscule = ['a' - 'z']
let majuscule = ['A' - 'Z']
let alpha = minuscule | majuscule
let alphanum = alpha | chiffre | '_'
let commentaire =
(* Commentaire bloc *)
("/*" [^ '*']* '*'* ([^ '*' '/'] [^ '*']* '*'*)* '/')
(* Commentaire fin de ligne *)
| "//" [^'\n']*
rule main = parse
| ['\n' '\t' ' ']+ { main lexbuf }
| commentaire { (main lexbuf) }
| "import" { IMPORT }
| "int" { INT }
| "float" { FLOAT }
| "boolean" { BOOL }
| "char" { CHAR }
| "void" { VOID }
| "String" { STRING }
| "{" { ACCOUV }
| "}" { ACCFER }
| "," { VIRG }
| ";" { PTVIRG }
| "(" { PAROUV }
| ")" { PARFER }
| "[" { CROOUV }
| "]" { CROFER }
| "if" { SI }
| "else" { SINON }
| "while" { TANTQUE }
| "return" { RETOUR }
| "=" { ASSIGN }
| "<" { OPINF }
| ">" { OPSUP }
| "<=" { OPINFEG }
| ">=" { OPSUPEG }
| "==" { OPEG }
| "!=" { OPNONEG }
| "+" { OPPLUS }
| "-" { OPMOINS }
| "||" { OPOU }
| "*" { OPMULT }
| "%" { OPMOD }
| "/" { OPDIV }
| "&&" { OPET }
| "!" { OPNON }
| "." { OPPT }
| chiffre+ as texte { (ENTIER (int_of_string texte)) }
| "0x" hexadecimal+ as texte { (ENTIER (int_of_string texte)) }
| "0o" octal+ as texte { (ENTIER (int_of_string texte)) }
| "0b" binaire+ as texte { (ENTIER (int_of_string texte)) }
| chiffre+"."chiffre+ as texte { (FLOTTANT (float_of_string texte))}
| ("true" | "false") as texte { (BOOLEEN (bool_of_string texte)) }
| '\'' _ '\'' as texte { (CARACTERE texte.[1]) }
| '\"' ([^ '\"' '\\'] | ('\\' _))* '\"' as texte { (CHAINE texte) }
| "null" { VIDE }
| "new" { NOUVEAU }
| ('_' | minuscule) alphanum* as texte { (IDENT texte) }
| majuscule alphanum* as texte { (TYPEIDENT texte) }
| eof { FIN }
| _ as texte { (print_string "Erreur lexicale : ");(print_char texte);(print_newline ()); VIDE }
{
}

71
TP2/mainJava.ml Executable file
View file

@ -0,0 +1,71 @@
open ParserJava
(* Fonction d'affichage des unités lexicales et des données qu'elles contiennent *)
let printToken t =
(print_endline
(match t with
| IMPORT -> "import"
| IDENT (texte) -> texte
| TYPEIDENT (texte) -> texte
| INT -> "int"
| FLOAT -> "float"
| BOOL -> "bool"
| CHAR -> "char"
| VOID -> "void"
| STRING -> "String"
| ACCOUV -> "{"
| ACCFER -> "}"
| PTVIRG -> ";"
| VIRG -> ","
| PAROUV -> "("
| PARFER -> ")"
| CROOUV -> "["
| CROFER -> "]"
| SI -> "if"
| SINON -> "else"
| TANTQUE -> "while"
| RETOUR -> "return"
| ENTIER (texte) -> (string_of_int texte)
| FLOTTANT (texte) -> (string_of_float texte)
| BOOLEEN (texte) -> (string_of_bool texte)
| CARACTERE (texte) -> (String.make 1 texte)
| CHAINE (texte) -> texte
| VIDE -> "null"
| NOUVEAU -> "new"
| FIN -> "EOF"
| ASSIGN -> "="
| OPINF -> "<"
| OPSUP -> ">"
| OPINFEG -> "<="
| OPSUPEG -> ">="
| OPEG -> "=="
| OPNONEG -> "!="
| OPPLUS -> "+"
| OPMOINS -> "-"
| OPOU -> "||"
| OPMULT -> "*"
| OPMOD -> "%"
| OPDIV -> "/"
| OPET -> "&&"
| OPNON -> "!"
| OPPT -> "."));;
(* Analyse lexicale du fichier passé en paramètre de la ligne de commande *)
if (Array.length Sys.argv > 1)
then
let lexbuf = (Lexing.from_channel (open_in Sys.argv.(1))) in
let token = ref (LexerJava.main lexbuf) in
while ((!token) != FIN) do
(printToken (!token));
(token := (LexerJava.main lexbuf))
done
else
(print_endline "MainMuJava fichier");;
(* Analyse lexicale, syntaxique et sémantique du fichier passé en paramètre de la ligne de commande *)
if (Array.length Sys.argv > 1)
then
let lexbuf = (Lexing.from_channel (open_in Sys.argv.(1))) in
(ParserJava.fichier LexerJava.main lexbuf)
else
(print_endline "MainJava fichier");;

165
TP2/parserJava.mly Executable file
View file

@ -0,0 +1,165 @@
%{
(* Partie recopiee dans le fichier CaML genere. *)
(* Ouverture de modules exploites dans les actions *)
(* Declarations de types, de constantes, de fonctions, d'exceptions exploites dans les actions *)
(* let nbrVariables = ref 0;; *)
let nbrFonctions = ref 0;;
%}
/* Declaration des unites lexicales et de leur type si une valeur particuliere leur est associee */
%token IMPORT
%token <string> IDENT TYPEIDENT
%token INT FLOAT BOOL CHAR VOID STRING
%token ACCOUV ACCFER PAROUV PARFER CROOUV CROFER
%token PTVIRG VIRG
%token SI SINON TANTQUE RETOUR
/* Defini le type des donnees associees a l'unite lexicale */
%token <int> ENTIER
%token <float> FLOTTANT
%token <bool> BOOLEEN
%token <char> CARACTERE
%token <string> CHAINE
%token VIDE
%token NOUVEAU
%token ASSIGN
%token OPINF OPSUP OPINFEG OPSUPEG OPEG OPNONEG
%token OPPLUS OPMOINS OPOU
%token OPMULT OPMOD OPDIV OPET
%token OPNON
%token OPPT
/* Unite lexicale particuliere qui represente la fin du fichier */
%token FIN
/* Declarations des regles d'associative et de priorite pour les operateurs */
/* La priorite est croissante de haut en bas */
/* Associatif a droite */
%right ASSIGN /* Priorite la plus faible */
/* Non associatif */
%nonassoc OPINF OPSUP OPINFEG OPSUPEG OPEG OPNONEG
/* Associatif a gauche */
%left OPPLUS OPMOINS OPOU
%left OPMULT OPMOD OPDIV OPET
%right OPNON
%left OPPT PAROUV CROOUV /* Priorite la plus forte */
/* Type renvoye pour le nom terminal fichier */
%type <unit> fichier
%type <int> variables
/* Le non terminal fichier est l'axiome */
%start fichier
%% /* Regles de productions */
fichier : programme FIN { (print_endline "fichier : programme FIN");(print_string "Nombre de fonctions : ");(print_int !nbrFonctions);(print_newline()) }
programme : /* Lambda, mot vide */ { (nbrFonctions := 0); (print_endline "programme : /* Lambda, mot vide */") }
| fonction programme { (nbrFonctions := !nbrFonctions + 1);(print_endline "programme : fonction programme") }
typeStruct : typeBase declTab { (print_endline "typeStruct : typeBase declTab") }
typeBase : INT { (print_endline "typeBase : INT") }
| FLOAT { (print_endline "typeBase : FLOAT") }
| BOOL { (print_endline "typeBase : BOOL") }
| CHAR { (print_endline "typeBase : CHAR") }
| STRING { (print_endline "typeBase : STRING") }
| TYPEIDENT { (print_endline "typeBase : TYPEIDENT") }
declTab : /* Lambda, mot vide */ { (print_endline "declTab : /* Lambda, mot vide */") }
| CROOUV CROFER { (print_endline "declTab : CROOUV CROFER") }
fonction : entete bloc { (print_endline "fonction : entete bloc") }
entete : typeStruct IDENT PAROUV parsFormels PARFER { (print_endline "entete : typeStruct IDENT PAROUV parsFormels PARFER") }
| VOID IDENT PAROUV parsFormels PARFER { (print_endline "entete : VOID IDENT PAROUV parsFormels PARFER") }
parsFormels : /* Lambda, mot vide */ { (print_endline "parsFormels : /* Lambda, mot vide */") }
| typeStruct IDENT suiteParsFormels { (print_endline "parsFormels : typeStruct IDENT suiteParsFormels") }
suiteParsFormels : /* Lambda, mot vide */ { (print_endline "suiteParsFormels : /* Lambda, mot vide */") }
| VIRG typeStruct IDENT suiteParsFormels { (print_endline "suiteParsFormels : VIRG typeStruct IDENT suiteParsFormels") }
bloc : ACCOUV /* $1 */ variables /* $2 */ instructions /* $3 */ ACCFER /* $4 */
{
(print_endline "bloc : ACCOUV variables instructions ACCFER");
(print_string "Nombre de variables = ");
(print_int $2);
(print_newline ());
(print_string "Nombre d'instructions = ");
(print_int $3);
(print_newline ())
}
variables : /* Lambda, mot vide */ {(print_endline "variables : /* Lambda, mot vide */");0}
| variable /* $1 */ variables /* $2 */ {(print_endline "variables : variable variables");($2 + 1)}
variable : typeStruct IDENT PTVIRG { (print_endline "variable : typeStruct IDENT PTVIRG") }
instructions : /* Lambda, mot vide */ { (print_endline "instructions : /* Lambda, mot vide */");0}
| instruction /* $1 */ instructions /* $2 */ { (print_endline "instructions : instruction instructions");($2 + 1) }
/* A FAIRE : Completer pour ajouter les autres formes d'instructions */
instruction : expression PTVIRG { (print_endline "instruction : expression PTVIRG") }
| TANTQUE PAROUV expression PARFER bloc { (print_endline "instruction : TANTQUE PAROUV expression PARFER bloc") }
| RETOUR expression PTVIRG { (print_endline "instruction : RETURN expression PTVIRG") }
| SI PAROUV expression PARFER bloc else_option {(print_endline "instruction : SI PAROUV expression PARFER bloc else_option")}
expression : unaires sub_expression_1 {(print_endline "expression : unaires sub_expressions_1")}
| expression binaire expression {(print_endline "expression : expression binaire expression")}
else_option : /* Lambda, mot vide */ {(print_endline "else_option : /* Lambda, mot vide */")}
| SINON bloc {(print_endline "else_option : SINON bloc")}
sub_expression_1 : ENTIER {(print_endline "expression : ENTIER")}
| FLOTTANT {(print_endline "expression : FLOTTANT")}
| BOOLEEN {(print_endline "expression : BOOLEEN")}
| CARACTERE {(print_endline "expression : CARACTERE")}
| VIDE {(print_endline "expression : VIDE")}
| NOUVEAU IDENT sub_expression_2 {(print_endline "expression : NOUVEAU IDENT")}
| IDENT suffixes {(print_endline "expression : IDENT suffixes")}
| PAROUV expression PARFER suffixes {(print_endline "expression : PAROUV expression PARFER suffixes")}
| OPPLUS expression %prec OPNON {}
sub_expression_2 : PAROUV PARFER {(print_endline "sub_expression_2 : ( )" )}
| CROOUV expression CROFER {(print_endline "sub_expression_2 : [ expression ]" )}
binaire : ASSIGN {(print_endline "binaire : =")}
| OPINF {(print_endline "binaire : <")}
| OPSUP {(print_endline "binaire : >")}
| OPINFEG {(print_endline "binaire : <=")}
| OPSUPEG {(print_endline "binaire : >=")}
| OPEG {(print_endline "binaire : ==")}
| OPNONEG {(print_endline "binaire : !=")}
| OPPLUS {(print_endline "binaire : +")}
| OPMOINS {(print_endline "binaire : -")}
| OPOU {(print_endline "binaire : ||")}
| OPMULT {(print_endline "binaire : *")}
| OPMOD {(print_endline "binaire : %")}
| OPDIV {(print_endline "binaire : /")}
| OPET {(print_endline "binaire : &&")}
| OPPT {(print_endline "binaire : .")}
unaires : /* Lambda, mot vide */ {(print_endline "unaires : /* Lambda, mot vide */")}
| unaire unaires {(print_endline "unaires : unaire unaires")}
unaire : PAROUV typeStruct PARFER {(print_endline "unaire : ( typeStruct )")}
| OPPLUS {(print_endline "unaire : +")}
| OPMOINS {(print_endline "unaire : -")}
| OPNON {(print_endline "unaire : !")}
suffixes : /* Lambda, mot vide */ {(print_endline "suffixe : /* Lambda, mot vide */")}
| suffixe suffixes {(print_endline "suffixes : suffixe suffixes")}
suffixe : CROOUV expression CROFER {(print_endline "suffixe : CROOUV expression CROFER")}
| PAROUV sub_suffixe PARFER {(print_endline "suffixe : PAROUV sub_suffixe PARFER")}
sub_suffixe : /* Lambda, mot vide */ {(print_endline "sub_suffixe : /* Lambda, mot vide */")}
| expression {(print_endline "sub_suffixe : expression")}
| sub_suffixe VIRG sub_suffixe {(print_endline "expression : sub_suffixe binaire sub_suffixe")}
%%

View file

@ -0,0 +1,49 @@
/* Cet exemple respecte la syntaxe (grammaire) de microjava, avec des
* commentaires, des chaînes complexes, des réels bizarres...
* Les constructions qui ne sont pas trait
* Ce programme est sémantiquement faux (typage en particulier)
*/
/* class Point {
private int x;
private int y;
private String toto;
// rien {
public int get_x () */
{ return x; }
// public void set_x (int _x)
{ x = _x; }
// private void essai_string ()
{
toto = "machin avec des espaces et des \" quotes
et multiligne avec echappement \n meme a la fin \\"; foo(); "et une autre chaine";
x = 3.14 + .14 + 3. + 14e-1 + .3e1;
y = 'a' + '\13' + 0x2A;
}
}
/* ghjd /* ****/
/* class PointColore extends Point {
public int c;
public int get_c () */
{ return c*2; }
/* } */
/*****
class PointColore extends Point **g
// dfgkhdk *f ** */
/* public class Exemple {
public static void main (String[] argv) */
{
int x;
bool b;
b = true;
if (b) {
x = 2*x + 3;
}
}
// }

32
TP2/tests/exemple-simple.java Executable file
View file

@ -0,0 +1,32 @@
// Note: ce fichier ne respecte pas la *grammaire* de micro-java
// Il ne fait qu'enumerer les tokens de la grammaire.
// mot clefs
// class extends private public static main
// types
int void float bool char String
// structures de controle
if else while return
// instructions
new null
// operateurs
< > >= <= == !=
+ - / * % && || ! = .
// parentheses
( [ { } ] )
// separateurs
, ;
// constantes
true false 0 245 1_234_567 0b1101 0B1_0100_1100 077 01_345 0xFF 0X1_FF00_1234 'a' 567.34 1e-5 .12
"bonjour"
// noms
x toto Point

View file

@ -0,0 +1,3 @@
, /* test */ int while // ceci est un autre test
" te \" st "
123

2
TP2/tests/exemple.java Executable file
View file

@ -0,0 +1,2 @@
453 while 45, 4, 8
int 4 int while , 8

3
TP2/tests/test.java Executable file
View file

@ -0,0 +1,3 @@
//
index + 000123

30
TP2/tests/test00.java Executable file
View file

@ -0,0 +1,30 @@
void f() {
int i;
int j;
return 1.0 = 2 + 3 - 4 * 5 / 6 % 7 || 8 && 9 == 10 != 11 < 12 > 13 <= 14 >= 15;
-3.14;
null;
new bonjour();
new entiers[10];
test(a, b, c, d);
tableau[13];
while (1) {
2;
}
if (10 == 3) {
int k;
}
else {
while (1) {
2;
}
}
}
void deuxieme() {
int k;
}

145
TP3/A_FAIRE.txt Executable file
View file

@ -0,0 +1,145 @@
TP Outils Mathématiques Informatique : Analyse Syntaxique par Descente Récursive
================================================================================
Le but de ce TP est d'apprendre à écrire un analyseur syntaxique
descendant récursif et à le tester.
Nous allons dans une première étape traiter le cas de la grammaire manipulée
en TD, puis nous étendrons celle-ci :
A/ La syntaxe du langage est un sous ensemble des expressions en CaML :
E est l'axiome.
E -> ER = E
E -> ER
ER -> ER + T
ER -> ER - T
ER -> T
T -> T * F
T -> T / F
T -> F
F -> - F
F -> ( E )
F -> ident
F -> true
F -> false
F -> number
Voici une grammaire LL(1) possible (vous pouvez aussi partir de celle proposée
en TD pour les expressions de bloc) :
E -> ER EX - ( ident true false number
EX -> = ER EX =
EX -> ) $
ER -> T TX - ( ident true false number
TX -> + T TX +
TX -> - T TX -
TX -> = ) $
T -> F FX - ( ident true false number
FX -> * F FX *
FX -> / F FX /
FX -> + - = ) $
F -> - F -
F -> ( E ) (
F -> ident ident
F -> true true
F -> false false
F -> number number
1) Écrire quelques programmes de test respectant la syntaxe de miniml.
2) L'analyseur lexical étant fourni (généré par camllex à partir du
fichier Scanner.mll), écrire un analyseur descendant récursif pour
miniml dans le fichier Syntax.ml, suivant le principe étudié en TD.
La compilation est effectuée par la commande : dune build Main.exe
3) Tester cet analyseur syntaxique.
================================================================
B/ Simplification de l'analyseur par notation monadique
L'analyseur développé dans l'exercice précédent est relativement complexe à
cause de la gestion des succès/échec et de la transmission de la liste des
terminaux en cours d'analyse.
Il est possible de simplifier la programmation en utilisant une notation
monadique pour factoriser ce traitement répétitif.
Celle-ci est composée de trois parties :
- le type de donnée monadique : parseResult
- la fonction : inject qui construit ce type à partir d'une liste de terminaux
- la fonction : bind (opérateur >>=) qui combine les fonctions d'analyse.
1) Étudier le fichier SyntaxMonad.ml qui implante le même analyseur
que l'exercice A/ en utilisant cette notation.
La compilation est effectuée par la commande : dune build MainMonad.exe
================================================================
C/ La syntaxe du langage étendue sera celle d'un mini CaML.
E0 est l'axiome.
Nous avons mis en évidence les nouvelles règles et les règles modifiées.
* E0 -> function ident -> E0
* E0 -> let ident = E0 in E0
* E0 -> letrec ident = E0 in E0
* E0 -> if E0 then E0 else E0
* E0 -> E
E -> ER = E
E -> ER
ER -> ER + T
ER -> ER - T
ER -> T
T -> T * F
T -> T / F
T -> F
F -> - F
* F -> ( E0 )
* F -> ( E0 ) (E0)
F -> ident
* F -> ident (E0)
F -> true
F -> false
F -> number
1) Écrire quelques programmes de test respectant la syntaxe de miniml.
2) Cette grammaire n'est pas LL(1), factoriser celle-ci et éliminer la
récursivité à gauche.
LL(1)
E0 -> function ident -> E0
E0 -> let ident = E0 in E0
E0 -> letrec ident = E0 in E0
E0 -> if E0 then E0 else E0
E0 -> E
E -> ER = E
E -> ER
ER -> T EY
EY -> + T EY
EY -> - T EY
EY ->
T -> F TY
TY -> * F TY
TY -> / F TY
TY ->
F -> - F
F -> ( E0 )
F -> ( E0 ) (E0)
F -> ident
F -> ident (E0)
F -> true
F -> false
F -> number
3) L'analyseur lexical étant fourni (généré par camllex à partir du
fichier Scanner.mll), écrire un analyseur descendant récursif pour
miniML en exploitant la technique monadique présentée dans
l'exercice précédent, vous modifierez pour cela le fichier
SyntaxMonad.ml.
4) Tester cet analyseur syntaxique.

88
TP3/Lex.ml Executable file
View file

@ -0,0 +1,88 @@
(* open List *)
type token =
| EOSToken
| FunctionToken
| BodyToken
| IfToken
| ThenToken
| ElseToken
| LetToken
| InToken
| TrueToken
| FalseToken
| RecToken
| IdentToken of string
| NumberToken of int
| EqualToken
| DifferentToken
| LesserToken
| GreaterToken
| LesserEqualToken
| GreaterEqualToken
| PlusToken
| MinusToken
| TimesToken
| DivideToken
| LeftParenthesisToken
| RightParenthesisToken
;;
type inputStream = token list;;
(* string_of_token : token -> string *)
(* Converti un token en une chaîne de caractère*)
let string_of_token token =
match token with
| EOSToken -> "$"
| FunctionToken -> "function"
| BodyToken -> "->"
| IfToken -> "if"
| ThenToken -> "then"
| ElseToken -> "else"
| LetToken -> "let"
| InToken -> "in"
| TrueToken -> "true"
| FalseToken -> "false"
| RecToken -> "letrec"
| NumberToken xxx -> string_of_int xxx
| IdentToken name -> name
| EqualToken -> "="
| DifferentToken -> "!="
| LesserToken -> "<"
| GreaterToken -> ">"
| LesserEqualToken -> "<="
| GreaterEqualToken -> ">="
| PlusToken -> "+"
| MinusToken -> "-"
| TimesToken -> "*"
| DivideToken -> "/"
| LeftParenthesisToken -> "("
| RightParenthesisToken -> ")"
;;
(* string_of_stream : inputStream -> string *)
(* Converti un inputStream (liste de token) en une chaîne de caractère *)
let string_of_stream stream =
List.fold_right (fun t tq -> (string_of_token t) ^ " " ^ tq ) stream "";;
(* peekAtFirstToken : inputStream -> token *)
(* Renvoie le premier élément d'un inputStream *)
(* Erreur : si l'inputStream est vide *)
let peekAtFirstToken stream =
match stream with
(* Normalement, ne doit jamais se produire sauf si la grammaire essaie de lire *)
(* après la fin de l'inputStream. *)
| [] -> failwith "Impossible d'acceder au premier element d'un inputStream vide"
|t::_ -> t;;
(* advanceInStream : inputStream -> inputStream *)
(* Consomme le premier élément d'un inputStream *)
(* Erreur : si l'inputStream est vide *)
let advanceInStream stream =
match stream with
(* Normalement, ne doit jamais se produire sauf si la grammaire essaie de lire *)
(* après la fin de l'inputStream. *)
| [] -> failwith "Impossible de consommer le premier element d'un inputStream vide"
| _::q -> q;;

22
TP3/Main.ml Executable file
View file

@ -0,0 +1,22 @@
open Lex
open Scanner
open Syntax
(* main : unit -> unit *)
(* Analyse le contenu d'un fichier passé en paramètre ou l'entrée standard si aucun fichier n'est donné *)
(* Affiche OK si l'analyse syntaxique c'est bien passée et KO sinon *)
let main () =
let cin =
if Array.length Sys.argv > 1 then
open_in Sys.argv.(1)
else
stdin
in
let lexbuf = Lexing.from_channel cin in
match (parseE (scanner lexbuf))
with
| Success [EOSToken] -> print_endline "Ok"
| _ -> print_endline "Ko"
;;
main();;

22
TP3/MainMonad.ml Executable file
View file

@ -0,0 +1,22 @@
open Lex
open Scanner
open SyntaxMonad
(* main : unit -> unit *)
(* Analyse le contenu d'un fichier passé en paramètre ou l'entrée standard si aucun fichier n'est donné *)
(* Affiche OK si l'analyse syntaxique c'est bien passée et KO sinon *)
let main () =
let cin =
if Array.length Sys.argv > 1 then
open_in Sys.argv.(1)
else
stdin
in
let lexbuf = Lexing.from_channel cin in
match (parseE (scanner lexbuf))
with
| Success [EOSToken] -> print_endline "Ok"
| _ -> print_endline "Ko"
;;
main();;

118
TP3/Scanner.mll Executable file
View file

@ -0,0 +1,118 @@
{
open Lex
open Printf
}
let digit = ['0'-'9']
let id = ['a'-'z'] ['a'-'z' '0'-'9']*
rule scanner = parse
| [' ' '\t' '\n' '\r'] { (scanner lexbuf) } (* eat up whitespace *)
| '('
{
LeftParenthesisToken :: (scanner lexbuf)
}
| ')'
{
RightParenthesisToken :: (scanner lexbuf)
}
| '='
{
EqualToken :: (scanner lexbuf)
}
| "!="
{
DifferentToken :: (scanner lexbuf)
}
| '='
{
EqualToken :: (scanner lexbuf)
}
| '<'
{
LesserToken :: (scanner lexbuf)
}
| '>'
{
GreaterToken :: (scanner lexbuf)
}
| "<="
{
LesserEqualToken :: (scanner lexbuf)
}
| ">="
{
GreaterEqualToken :: (scanner lexbuf)
}
| '+'
{
PlusToken :: (scanner lexbuf)
}
| '-'
{
MinusToken :: (scanner lexbuf)
}
| '*'
{
TimesToken :: (scanner lexbuf)
}
| '/'
{
DivideToken :: (scanner lexbuf)
}
| "->"
{
BodyToken :: (scanner lexbuf)
}
| "function"
{
FunctionToken :: (scanner lexbuf)
}
| "if"
{
IfToken :: (scanner lexbuf)
}
| "then"
{
ThenToken :: (scanner lexbuf)
}
| "else"
{
ElseToken :: (scanner lexbuf)
}
| "let"
{
LetToken :: (scanner lexbuf)
}
| "in"
{
InToken :: (scanner lexbuf)
}
| "letrec"
{
RecToken :: (scanner lexbuf)
}
| "true"
{
TrueToken :: (scanner lexbuf)
}
| "false"
{
FalseToken :: (scanner lexbuf)
}
| digit+ as inum
{
(NumberToken (int_of_string inum)) :: (scanner lexbuf)
}
| id as text
{
(IdentToken ("\"" ^ text ^"\"")) :: (scanner lexbuf)
}
| _ as c
{ printf "Unrecognized character: %c\n" c;
(scanner lexbuf)
}
| eof {[ EOSToken ] }
{
}

209
TP3/Syntax.ml Executable file
View file

@ -0,0 +1,209 @@
open Lex
type parseResult =
| Success of inputStream
| Failure
;;
(*
E -> ER = E
E -> ER
ER -> ER + T
ER -> ER - T
ER -> T
T -> T * F
T -> T / F
T -> F
F -> - F
F -> ( E )
F -> ident
F -> true
F -> false
F -> number
*)
(*
LL(1) Règle de production / Symboles directeurs
#1 - E -> function ident fleche E { function }
#2 - E -> if E then E else E { if }
#5 - E -> ER EX | { -, number, ident, true, false, ( }
#6 - EX -> = ER EX | { = }
#7 - EX -> | { $, ), then, else }
#8 - ER -> T TX | { -, number, ident, true, false, ( }
#9 - TX -> + T TX | { + }
#10 - TX -> - T TX | { - }
#11 - TX -> | { $, =, ), then, else }
#12 - T -> F FX | { -, number, ident, true, false, ( }
#13 - FX -> * F FX | { * }
#14 - FX -> / F FX | { / }
#15 - FX -> | { $, +, -, =, ), then, else }
#16 - F -> - F | { - }
#17 - F -> number | { number }
#20 - F -> ident | { ident }
#21 - F -> true | { true }
#22 - F -> false | { false }
#23 - F -> ( E ) | { ( }
*)
(* accept : token -> inputStream -> parseResult *)
(* Vérifie que le premier token du flux d'entrée est bien le token attendu *)
(* et avance dans l'analyse si c'est le cas *)
let accept expected stream =
match (peekAtFirstToken stream) with
| token when (token = expected) ->
(print_endline (string_of_token token));
(Success (advanceInStream stream))
| _ -> Failure
;;
(* acceptIdent : inputStream -> parseResult *)
(* Vérifie que le premier token du flux d'entrée est bien un identifiant *)
(* et avance dans l'analyse si c'est le cas *)
let acceptIdent stream =
match (peekAtFirstToken stream) with
| (IdentToken nom) ->
(print_endline nom);
(Success (advanceInStream stream))
| _ -> Failure
;;
(* acceptNumber : inputStream -> parseResult *)
(* Vérifie que le premier token du flux d'entrée est bien un nombre *)
(* et avance dans l'analyse si c'est le cas *)
let acceptNumber stream =
match (peekAtFirstToken stream) with
| (NumberToken _) -> (Success (advanceInStream stream))
| _ -> Failure
;;
(* parseE : inputStream -> parseResult *)
(* Analyse du non terminal E *)
let rec parseE stream =
(*
(print_endline (string_of_stream stream));
*)
(print_endline "E");
(match (peekAtFirstToken stream) with
(* regle #5 - E -> ER EX | { -, number, ident, true, false, ( } *)
(* Symboles directeurs *)
| (IdentToken _) | (NumberToken _) | TrueToken | FalseToken |
MinusToken | LeftParenthesisToken ->
(* Regle *)
(* Analyse ER *)
(match (parseER stream) with
| (Success next) ->
(* En cas de succes, analyse EX *)
parseEX next
| _ -> Failure)
| _ -> Failure)
(* parseEX : inputStream -> parseResult *)
(* Analyse du non terminal EX *)
and parseEX stream =
(print_endline "EX");
(match (peekAtFirstToken stream) with
(* regle #6 - EX -> = ER EX | { = } *)
| EqualToken -> (match (accept EqualToken stream) with
| Success next -> (match (parseER next) with
| Success next2 -> (parseEX next2)
| _ -> Failure)
| _ -> Failure)
(* regle #7 - EX -> | { $, ) } *)
| EOSToken | RightParenthesisToken | ThenToken | ElseToken -> (Success stream)
| _ -> Failure)
(* parseER : inputStream -> parseResult *)
(* Analyse du non terminal ER *)
and parseER stream =
(print_endline "ER");
(match (peekAtFirstToken stream) with
(* regle #8 - ER -> T TX | { -, number, ident, true, false, ( } *)
| (IdentToken _) | (NumberToken _) | TrueToken | FalseToken | MinusToken | LeftParenthesisToken ->
(match (parseT stream) with
| Success next -> (parseTX next)
| _ -> Failure)
| _ -> Failure)
(* parseTX : inputStream -> parseResult *)
(* Analyse du non terminal TX *)
and parseTX stream =
(print_endline "TX");
(match (peekAtFirstToken stream) with
(* regle #9 - TX -> + T TX | { + } *)
| PlusToken -> (match (accept PlusToken stream) with
| Success next -> (
match (parseT next) with
| Success next -> (parseTX next)
| _ -> Failure)
| _ -> Failure)
(* regle #10 - TX -> - T TX | { - } *)
| MinusToken -> (match (accept MinusToken stream) with
| Success next -> (
match (parseT next) with
| Success next -> (parseTX next)
| _ -> Failure)
| _ -> Failure)
(* regle #11 - TX -> | { $, =, ) } *)
| EOSToken | EqualToken | RightParenthesisToken -> Success stream
| _ -> Failure)
(* parseT : inputStream -> parseResult *)
(* Analyse du non terminal T *)
and parseT stream =
(print_endline "T");
(match (peekAtFirstToken stream) with
(* regle #12 - T -> F FX | { -, number, ident, true, false, ( } *)
| (IdentToken _) | (NumberToken _) | TrueToken | FalseToken |
MinusToken | LeftParenthesisToken -> (match (parseF stream) with
| Success next -> (parseFX next)
| _ -> Failure)
| _ -> Failure)
(* parseFX : inputStream -> parseResult *)
(* Analyse du non terminal FX *)
and parseFX stream =
(print_endline "FX");
(match (peekAtFirstToken stream) with
(* regle #13 - FX -> * F FX | { * } *)
| TimesToken -> (match (accept TimesToken stream) with
| Success next -> (
match (parseF next) with
| Success next -> (parseFX next)
| _ -> Failure)
| _ -> Failure)
(* regle #14 - FX -> / F FX | { / } *)
| DivideToken -> (match (accept DivideToken stream) with
| Success next -> (
match (parseF next) with
| Success next -> (parseFX next)
| _ -> Failure)
| _ -> Failure)
(* regle #15 - FX -> | { $, +, -, =, ) } *)
| EOSToken | PlusToken | MinusToken | EqualToken | RightParenthesisToken -> (Success stream)
| _ -> Failure)
(* parseF : inputStream -> parseResult *)
(* Analyse du non terminal F *)
and parseF stream =
(print_endline "F");
(match (peekAtFirstToken stream) with
(* regle #16 - F -> - F | { - } *)
| MinusToken -> (match (accept MinusToken stream) with
| Success next -> (parseF next)
| _ -> Failure)
(* regle #17 - F -> number | { number } *)
| NumberToken _ -> (acceptNumber stream)
(* regle #20 - F -> ident | { ident } *)
| IdentToken _ -> (acceptIdent stream)
(* regle #21 - F -> true | { true } *)
| TrueToken -> (accept TrueToken stream)
(* regle #22 - F -> false | { false } *)
| FalseToken -> (accept FalseToken stream)
(* regle #23 - F -> ( E ) | { ( } *)
| LeftParenthesisToken -> (match (accept LeftParenthesisToken stream) with
| Success next -> (match (parseE next) with
| Success next2 -> (accept RightParenthesisToken next2)
| _ -> Failure)
| _ -> Failure)
| _ -> Failure)
;;

288
TP3/SyntaxMonad.ml Executable file
View file

@ -0,0 +1,288 @@
open Lex
type parseResult =
| Success of inputStream
| Failure
;;
(*
LL(1)
#01 - E0 -> function ident -> E0
#02 - E0 -> let ident = E0 in E0
#03 - E0 -> letrec ident = E0 in E0
#04 - E0 -> if E0 then E0 else E0
#05 - E0 -> F TY EY EX
#06 - EX -> = F TY EY EX
#07 - EX ->
#08 - EY -> + F TY EY
#09 - EY -> - F TY EY
#10 - EY ->
#11 - TY -> * F TY
#12 - TY -> / F TY
#13 - TY ->
#14 - F -> - F
#15 - F -> ( E0 ) FX
#16 - F -> ident FX
#17 - F -> true
#18 - F -> false
#19 - F -> number
#20 - FX -> ( E0 )
#21 - FX ->
*)
(* accept : token -> inputStream -> parseResult *)
(* Vérifie que le premier token du flux d'entrée est bien le token attendu *)
(* et avance dans l'analyse si c'est le cas *)
let accept expected stream =
match (peekAtFirstToken stream) with
| token when (token = expected) ->
(print_endline (string_of_token token)); (Success (advanceInStream stream))
| _ -> Failure
;;
(* acceptIdent : inputStream -> parseResult *)
(* Vérifie que le premier token du flux d'entrée est bien un identifiant *)
(* et avance dans l'analyse si c'est le cas *)
let acceptIdent stream =
match (peekAtFirstToken stream) with
| (IdentToken _) -> (Success (advanceInStream stream))
| _ -> Failure
;;
(* acceptNumber : inputStream -> parseResult *)
(* Vérifie que le premier token du flux d'entrée est bien un nombre *)
(* et avance dans l'analyse si c'est le cas *)
let acceptNumber stream =
match (peekAtFirstToken stream) with
| (NumberToken _) -> (Success (advanceInStream stream))
| _ -> Failure
;;
(* Définition de la monade qui est composée de : *)
(* - le type de donnée monadique : parseResult *)
(* - la fonction : inject qui construit ce type à partir d'une liste de terminaux *)
(* - la fonction : bind (opérateur >>=) qui combine les fonctions d'analyse. *)
(* inject inputStream -> parseResult *)
(* Construit le type de la monade à partir d'une liste de terminaux *)
let inject s = Success s;;
(* bind : 'a m -> ('a -> 'b m) -> 'b m *)
(* bind (opérateur >>=) qui combine les fonctions d'analyse. *)
(* ici on utilise une version spécialisée de bind :
'b -> inputStream
'a -> inputStream
m -> parseResult
*)
(* >>= : parseResult -> (inputStream -> parseResult) -> parseResult *)
let (>>=) result f =
match result with
| Success next -> f next
| Failure -> Failure
;;
(* parseE0 : inputStream -> parseResult *)
(* Analyse du non terminal E0 *)
let rec parseE0 stream =
(*
(print_endline (string_of_stream stream));
*)
(print_endline "E0");
(match (peekAtFirstToken stream) with
(* regle #1 *)
| FunctionToken ->
inject stream >>=
accept FunctionToken >>=
acceptIdent >>=
accept BodyToken >>=
parseE0
(* regle #2 *)
| LetToken ->
inject stream >>=
accept LetToken >>=
acceptIdent >>=
accept EqualToken >>=
parseE0 >>=
accept InToken >>=
parseE0
(* regle #3 *)
| RecToken ->
inject stream >>=
accept RecToken >>=
acceptIdent >>=
accept EqualToken >>=
parseE0 >>=
accept InToken >>=
parseE0
(* regle #4 if E then E else E *)
| IfToken ->
inject stream >>=
accept IfToken >>=
parseE0 >>=
accept ThenToken >>=
parseE0 >>=
accept ElseToken >>=
parseE0
(* regle #5 *)
| ((IdentToken _) | (NumberToken _) | TrueToken | FalseToken | MinusToken | LeftParenthesisToken ) ->
inject stream >>=
parseF >>=
parseTY >>=
parseEY >>=
parseEX
| _ -> Failure)
(* parseEX : inputStream -> parseResult *)
(* Analyse du non terminal EX *)
and parseE stream =
(print_endline "EX");
(match (peekAtFirstToken stream) with
(* regle #6 *)
| EqualToken ->
inject stream >>=
accept EqualToken >>=
parseF >>=
parseTY >>=
parseEY >>=
parseEX
(* regle #7 *)
| (RightParenthesisToken | ElseToken | ThenToken | InToken) ->
inject stream
| EOSToken ->
inject stream
| _ -> Failure)
(* parseER : inputStream -> parseResult *)
(* Analyse du non terminal ER *)
and parseER stream =
(print_endline "ER");
(match (peekAtFirstToken stream) with
(* regle #8 *)
| ((IdentToken _) | (NumberToken _) | TrueToken | FalseToken | MinusToken | LeftParenthesisToken) ->
inject stream >>=
parseT >>=
parseTX
| _ -> Failure)
(* parseTX : inputStream -> parseResult *)
(* Analyse du non terminal TX *)
and parseTX stream =
(print_endline "TX");
(match (peekAtFirstToken stream) with
(* regle 9 *)
| PlusToken ->
inject stream >>=
accept PlusToken >>=
parseT >>=
parseTX
(* regle 10 *)
| MinusToken ->
inject stream >>=
accept MinusToken >>=
parseT >>=
parseTX
(* regle 11 *)
| (RightParenthesisToken | EqualToken | ElseToken | ThenToken | InToken) -> inject stream
| EOSToken -> inject stream
| _ -> Failure)
(* parseT : inputStream -> parseResult *)
(* Analyse du non terminal T *)
and parseT stream =
(print_endline "T");
(match (peekAtFirstToken stream) with
(* regle 12 *)
| ((IdentToken _) | (NumberToken _) | TrueToken | FalseToken | MinusToken | LeftParenthesisToken) ->
inject stream >>=
parseF >>=
parseFX
| _ -> Failure)
(* parseFX : inputStream -> parseResult *)
(* Analyse du non terminal FX *)
and parseFX stream =
(print_endline "FX");
(match (peekAtFirstToken stream) with
(* regle 13 *)
| TimesToken ->
inject stream >>=
accept TimesToken >>=
parseF >>=
parseFX
(* regle 14 *)
| DivideToken ->
inject stream >>=
accept DivideToken >>=
parseF >>=
parseFX
(* regle 15 *)
| (RightParenthesisToken | EqualToken | PlusToken | MinusToken | ElseToken | ThenToken | InToken) ->
inject stream
| EOSToken -> inject stream
| _ -> Failure)
(* parseF : inputStream -> parseResult *)
(* Analyse du non terminal F *)
and parseF stream =
(print_endline "F");
(match (peekAtFirstToken stream) with
(* regle 16 *)
| MinusToken ->
inject stream >>=
accept MinusToken >>=
parseF
(* regle 17 *)
| (NumberToken _) ->
inject stream >>=
acceptNumber
(* regle 20 *)
| ((IdentToken _) | LeftParenthesisToken) ->
inject stream >>=
parseFF >>=
parseARG
(* regle 21 *)
| TrueToken ->
inject stream >>=
accept TrueToken
(* regle 22 *)
| FalseToken ->
inject stream >>=
accept FalseToken
| _ -> Failure)
(* parseFF : inputStream -> parseResult *)
(* Analyse du non terminal FF *)
and parseFF stream =
(print_endline "FF");
(match (peekAtFirstToken stream) with
(* regle 23 ( E ) *)
| LeftParenthesisToken ->
inject stream >>=
accept LeftParenthesisToken >>=
parseE >>=
accept RightParenthesisToken
(* regle 24 *)
| IdentToken _ ->
inject stream >>=
acceptIdent
| _ -> Failure)
(* parseARG : inputStream -> parseResult *)
(* Analyse du non terminal ARG *)
and parseARG stream =
(print_endline "ARG");
(match (peekAtFirstToken stream) with
(* regle 25 - ARG -> ( E ) *)
| LeftParenthesisToken ->
inject stream >>=
accept LeftParenthesisToken >>=
parseE >>=
accept RightParenthesisToken
(* regle 26 - ARG -> *)
| (RightParenthesisToken | EqualToken | PlusToken | MinusToken | ElseToken | ThenToken | InToken | TimesToken | DivideToken ) ->
inject stream
| EOSToken ->
inject stream
| _ -> Failure)
;;

4
TP3/dune Executable file
View file

@ -0,0 +1,4 @@
(ocamllex Scanner)
(executables
(names Main MainMonad))

1
TP3/dune-project Executable file
View file

@ -0,0 +1 @@
(lang dune 1.11)

27
TP3/tests/test.ml Executable file
View file

@ -0,0 +1,27 @@
(*
LL(1)
#01 - E0 -> function ident -> E0
#02 - E0 -> let ident = E0 in E0
#03 - E0 -> letrec ident = E0 in E0
#04 - E0 -> if E0 then E0 else E0
#05 - E0 -> F TY EY EX
#06 - EX -> = F TY EY EX
#07 - EX ->
#08 - EY -> + F TY EY
#09 - EY -> - F TY EY
#10 - EY ->
#11 - TY -> * F TY
#12 - TY -> / F TY
#13 - TY ->
#14 - F -> - F
#15 - F -> ( E0 ) FX
#16 - F -> ident FI
#17 - F -> true
#18 - F -> false
#19 - F -> number
#20 - FX -> ( E0 )
#21 - FX ->
#22 - FI -> ( EO )
#23 - FI ->
*)