 
 
 
 Exercices
 Suppression de commentaires
Les commentaires en Objective CAML sont hiérarchiques. On peut ainsi
commenter des parties de texte, y compris celles contenant déjà des
commentaires. Un commentaire commence par les caractères (* et
se termine par *). Voici un exemple :
(* début du commentaire
      sur plusieurs 
         lignes *)
 let succ x = (* fonction successeur *)
   x + 1;;
(* niveau 1  texte commenté 
  let old_succ y = (* niveau 2 fonction successeur niveau 2 *)
    y +1;;
    niveau 1 *)
  succ 2;;
Le but de cet exercice est de créer un nouveau texte sans tous les
commentaires. Le choix de l'outil d'analyse lexicale est libre.
- 
 Écrire un analyseur lexical  
qui puisse
reconnaître les commentaires d'Objective CAML. Ceux-ci commencent par un
(*et se terminent par un*). Attention les commentaires
sont bien balancés, c'est-à-dire que le nombre d'ouvertures est égal
au nombre de fermetures.
(** fichier comment1.mll **)
 
 {
   let ignore_lex lb = ignore (Lexing.lexeme lb) 
   let traite_normal = ignore_lex
   let traite_comment = ignore_lex 
   exception Commentaires_mal_balances
 }
 
 rule normal = parse 
     "(*"    { ignore_lex lexbuf ; commentaire lexbuf ; normal lexbuf }
   | "*)"    { raise Commentaires_mal_balances }
   | _       { traite_normal lexbuf ; normal lexbuf }
   | eof     { () }
 
 and commentaire = parse 
     "(*"    { ignore_lex lexbuf ; commentaire lexbuf ; commentaire lexbuf }
   | "*)"    { ignore_lex lexbuf  }
   | _       { traite_comment lexbuf ; commentaire lexbuf }
   | eof     { raise Commentaires_mal_balances }
 
 
 
 
 
-  Écrire un programme  
qui prend un fichier, le lit, retire les
commentaires de son texte puis crée un nouveau fichier résultat. 
 
(** fichier comment2.mll **)
 {
   let ignore_lex lb = ignore (Lexing.lexeme lb) 
   let sortie = ref stdout 
   let init_sortie f = sortie := f 
   let traite_normal lb = output_string !sortie (Lexing.lexeme lb)
   let traite_comment = ignore_lex 
   exception Commentaires_mal_balances
 }
 
 rule normal = parse 
     "(*"    { ignore_lex lexbuf ; commentaire lexbuf ; normal lexbuf }
   | "*)"    { raise Commentaires_mal_balances }
   | _       { traite_normal lexbuf ; normal lexbuf }
   | eof     { () }
 
 and commentaire = parse 
     "(*"    { ignore_lex lexbuf ; commentaire lexbuf ; commentaire lexbuf }
   | "*)"    { ignore_lex lexbuf  }
   | _       { traite_comment lexbuf ; commentaire lexbuf }
   | eof     { raise Commentaires_mal_balances }
 
 
 {
 
 let decommente src dest = 
   let file_in = open_in src in
   let lb = Lexing.from_channel file_in in
   let file_out = open_out dest in 
     init_sortie file_out ;
     normal lb ;
     close_in file_in ;
     close_out file_out ;;
 
 let usage () = 
   print_string "comment2 filein fileout";
   print_newline() ;;
 
   
 let main () = 
   if Array.length (Sys.argv) <> 3 then usage () 
   else decommente Sys.argv.(1) Sys.argv.(2) ;;
 
 main ();;
   }
 
 
 
 
 
 
 
 
 
 
 
 
 
-  En Objective CAML les chaînes de caractères peuvent contenir
n'importe quel caractères, y compris les suites (*ou*). Par exemple la chaîne de caractères"un te(*xte quelco*)nque"ne doit pas être considéré comme un commentaire. 
Modifier  
l'analyseur lexical pour
prendre en compte les chaînes de caractères.
(** fichier comment3.mll **)
 {
   let ignore_lex lb = ignore (Lexing.lexeme lb) 
   let sortie = ref stdout 
   let init_sortie f = sortie := f 
   let traite_normal lb = output_string !sortie (Lexing.lexeme lb)
   let traite_comment = ignore_lex 
   exception Commentaires_mal_balances
 }
 
 rule normal = parse 
     "(*"    { ignore_lex lexbuf ; commentaire lexbuf ; normal lexbuf }
   | "*)"    { raise Commentaires_mal_balances }
   | '"'     { traite_normal lexbuf ; chaine lexbuf ; normal lexbuf }
   | _       { traite_normal lexbuf ; normal lexbuf }
   | eof     { () }
 
 and commentaire = parse 
     "(*"    { ignore_lex lexbuf ; commentaire lexbuf ; commentaire lexbuf }
   | "*)"    { ignore_lex lexbuf  }
   | _       { traite_comment lexbuf ; commentaire lexbuf }
   | eof     { raise Commentaires_mal_balances }
 
 and  chaine = parse 
     '"'     { traite_normal lexbuf ; () }
   | "\\\""    { traite_normal lexbuf ; chaine lexbuf }
   | _       { traite_normal lexbuf ; chaine lexbuf }
 
 
 
 
 
 
 
-  Utiliser ce nouvel analyseur pour enlever les commentaires d'un
programme  
Objective CAML.
 
(** fichier comment4.mll **)
 {
   let ignore_lex lb = ignore (Lexing.lexeme lb) 
   let sortie = ref stdout 
   let init_sortie f = sortie := f 
   let traite_normal lb = output_string !sortie (Lexing.lexeme lb)
   let traite_comment = ignore_lex 
   exception Commentaires_mal_balances
 }
 
 rule normal = parse 
     "(*"    { ignore_lex lexbuf ; commentaire lexbuf ; normal lexbuf }
   | "*)"    { raise Commentaires_mal_balances }
   | '"'     { traite_normal lexbuf ; chaine lexbuf ; normal lexbuf }
   | _       { traite_normal lexbuf ; normal lexbuf }
   | eof     { () }
 
 and commentaire = parse 
     "(*"    { ignore_lex lexbuf ; commentaire lexbuf ; commentaire lexbuf }
   | "*)"    { ignore_lex lexbuf  }
   | _       { traite_comment lexbuf ; commentaire lexbuf }
   | eof     { raise Commentaires_mal_balances }
 
 and  chaine = parse 
     '"'     { traite_normal lexbuf ; () }
   | "\\\""    { traite_normal lexbuf ; chaine lexbuf }
   | _       { traite_normal lexbuf ; chaine lexbuf }
 
 
 {
 
 let decommente src dest = 
   let file_in = open_in src in
   let lb = Lexing.from_channel file_in in
   let file_out = open_out dest in 
     init_sortie file_out ;
     normal lb ;
     close_in file_in ;
     close_out file_out ;;
 
 let usage () = 
   print_string "comment2 filein fileout";
   print_newline() ;;
 
   
 let main () = 
   if Array.length (Sys.argv) <> 3 then usage () 
   else decommente Sys.argv.(1) Sys.argv.(2) ;;
 
 main ();;
   }
 
 
 
 Évaluateur
On utilise ocamlyacc pour réaliser un évaluateur
d'expressions. L'idée est d'associer directement l'évaluation des
expressions aux règles de grammaire.
On choisit un langage d'expressions arithmétiques préfixées (et
complètement parenthésées) avec des opérateurs d'arité
variable. Par exemple, l'expression (ADD e1 e2 .. en) est
équivalente à e1 + e2 + .. + en. Les opérateurs
d'addition et de multiplication sont associatifs à droite et ceux de
soustraction et de division associatifs à gauche. 
-  Définir dans un fichier 
opn_parser.mly  
l'analyse syntaxique et les
règles d'évaluation d'une expression.
 
 %{
   let rec app_right f xs =
    match xs with
      [x] -> x
    | x::xs -> f x (app_right f xs) 
    | _ -> failwith"missing argument" ;;
   let rec app_left f xs =
    match xs with
      [x] -> x
    | x1::x2::xs -> app_left f ((f x1 x2)::xs)
    | _ -> failwith"missing argument" ;; 
   
   let t = Hashtbl.create 3 ;;
   
   (
     Hashtbl.add t "ADD" (app_right (+.));
     Hashtbl.add t "SUB" (app_left (-.));
     Hashtbl.add t "MUL" (app_right ( *.));
     Hashtbl.add t "DIV" (app_left (/.))
   ) ;;
 
   let apply o vs =
     try 
       (Hashtbl.find t o) vs
     with 
       Not_found -> (Printf.eprintf"Unknown operator %s\n" o; exit(1)) ;;
 %}
 
 %token Lpar Rpar
 %token <float> Num
 %token <string> Atom
 
 %start term
 %type <float> term
 %type <float list> terms
 
 %%
 term :
   Num                { $1 }
 | Lpar Atom terms Rpar        
                 { (apply $2 $3) }
 ;
 terms :
   term                { [$1] }
 | term terms        { $1::$2 }
 ;
 %%
 
 
 
 
-  Définir dans un fichier opn_lexer.mll 
l'analyse lexicale des expressions.
 
 {
   open Opn_parser 
 }
 
 rule lexer = parse
   [' ' '\n']                { lexer lexbuf }
 | '('                        { Lpar }
 | ')'                        { Rpar }
 | '-'?['0'-'9']*'.'?['0'-'9']*        
                         { Num (float_of_string (Lexing.lexeme lexbuf)) }
 | ['A'-'z']+                { Atom (Lexing.lexeme lexbuf) }
 
 
 
 
-  Écrire un petit programme  
principal opn 
qui lit une ligne sur l'entrée standard et affiche le résultat de
l'évaluation. 
 
 open Opn_lexer ;;
 open Opn_parser ;;
 
 Printf.printf"? "; flush stdout;
 let buf = Lexing.from_string (input_line stdin) in
   Printf.printf "= %f\n" (Opn_parser.term Opn_lexer.lexer buf) ;; 
 
 
 
 
