TP-automates/TP3/SyntaxMonad.ml
2023-06-21 19:58:18 +02:00

289 lines
7.7 KiB
OCaml
Executable file

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)
;;