(***** Langage Mini-C ****) (** Analyse lexicale **) (* les tokens *) type tok_t = PtV | Plus | Prt | DPt (* ; + print : *) | Eq | ParG | ParD (* = ( ) *) | Ident of string (* identifiant *) | Num of int (* nombre *) let tok_of_string s = (* transforme une chaîne de caractère matchée par la Regexp en token *) if s = ";" then PtV else if s = "+" then Plus else if s = "print" then Prt else if s = ":" then DPt else if s = "=" then Eq else if s = "(" then ParG else if s = ")" then ParD else if 'a' <= s.[0] && s.[0] <= 'z' then Ident s else Num (int_of_string s) ;; let analyse_lexicale (texte:string) : tok_t list = let re = Str.regexp "[a-z]+\\|0\\|[1-9][0-9]*\\|[ \\(\\):;=+\n]" in let rec tokenize texte i = if i = String.length texte then [] else let j = Str.search_forward re texte i in let str = Str.matched_string texte in (* Printf.printf "matched-%s-\n" str; *) if str = " " || str = "\n" then tokenize texte (j + String.length str) else (tok_of_string str) :: tokenize texte (j + String.length str) in tokenize texte 0 ;; assert (analyse_lexicale "x := 3; print(x)" = [Ident "x"; DPt; Eq; Num 3; PtV; Prt; ParG; Ident "x"; ParD]);; assert (analyse_lexicale "a b+33 c ==" = [Ident "a"; Ident "b"; Plus; Num 33; Ident "c"; Eq; Eq]);; assert (analyse_lexicale "(aaa(:print:" = [ParG; Ident "aaa"; ParG; DPt; Prt; DPt]);; (** Analyse syntaxique **) (* arbre de syntaxe abstraite *) type progr_t = Uniq of instr_t | Seq of instr_t * progr_t and instr_t = Affiche of expr_t | Affect of string * expr_t and expr_t = Val of string | Add of expr_t * expr_t | Entier of int let rec parse_progr l = let instr, ll = parse_instr l in (* on parse une instruction *) match ll with (* en fonction du flux restant ...*) | [PtV] -> Uniq instr, [] (* c'était la dernière instruction *) | PtV :: lll -> let prog, llll = parse_progr lll in Seq (instr, prog), llll | _ -> failwith "Erreur1" and parse_instr l = match l with | Prt :: ParG :: ll -> (* c'est un print ( ... *) begin let expr, lll = parse_expr ll in (* on parse une expr *) (* il reste à lire une ) *) match lll with | ParD :: llll -> Affiche expr, llll | _ -> failwith "Erreur2" end | Ident v :: DPt :: Eq :: ll -> (* c'est une affectation *) let expr, lll = parse_expr ll in (* on parse une expr *) Affect (v, expr), lll | _ -> failwith "Erreur3" and parse_expr l = (* on parse un identifiant ou un entier *) let e1, ll = match l with | Ident v :: ll -> Val v, ll | Num n :: ll -> Entier n, ll | _ -> failwith "Erreur4" in match ll with (* si la suite commence par +, on parse à nouveau une expression*) | Plus :: lll -> let e2, llll = parse_expr lll in Add (e1, e2), llll (* sinon on a fini de parser l'expression *) | _ -> e1, ll ;; let analyse_syntaxique tok_list = (* on parse le programme à partir de la liste de tokens *) let prog, l = parse_progr tok_list in (* on vérifie que tous les tokens ont éété consommés *) if l = [] then prog else failwith "Erreur6" ;; (** Evaluation de l'arbre de syntaxe abstraite **) (* Environnement d'évaluation *) let new_env () = Hashtbl.create 10;; let get_val env nom = Hashtbl.find env nom;; let set_val env nom v = Hashtbl.add env nom v;; (* Fonctions d'évaluation, récursive sur la structure de l'arbre, en utilisant l'environnement *) let rec evalue_progr progr env = match progr with | Uniq instr -> evalue_instr instr env | Seq (instr, prg) -> evalue_instr instr env; evalue_progr prg env and evalue_instr instr env = match instr with | Affiche e -> let v = evalue_expr e env in Printf.printf "%d\n" v | Affect(nom, e) -> let v = evalue_expr e env in set_val env nom v and evalue_expr expr env = match expr with | Entier n -> n | Val nom -> get_val env nom | Add (e1, e2) -> let v1 = evalue_expr e1 env in let v2 = evalue_expr e2 env in v1 + v2 ;; (** Fonction de lecture, tokenisation, parsing, puis évaluation **) let interprete filename = (* lecture du code source fichier *) let ch = open_in filename in let texte = ref "" in begin try while true do let ligne = input_line ch in texte := !texte ^ ligne ^ "\n" done with End_of_file -> () end; close_in ch; (* print_endline !texte; *) (* analyse lexicale *) let tok_list = analyse_lexicale !texte in (* analyse syntaxique *) let arbre = analyse_syntaxique tok_list in (* evaluation *) evalue_progr arbre (new_env ()) ;; interprete Sys.argv.(1);;