Analyse Lexicale

Rappels sur les langages rationnels

expressions rationnelles (regular expressions)
: epsilon, +, *, .
automates finis non deterministes
: (Q,I,T,F)
automates finis deterministes
:
(Q,I,T,F) avec F fonctionnelle et I singleton
determinisation
: construction de l'ensemble puissance
minimalisation
: construction de Moore
propriétés
: lemme de l'étoile, complémentation, intersection, union

Exemple OcamlLex Voici un exemple de fichier de définition OcamlLex:

{
exception Eof;;
let count = ref 0;;
}
let alphanum = [^ ' ' '\t' '\n']
let mot = alphanum alphanum*

rule token = parse mot {count := !count + 1;} | _ {} | eof {raise Eof} { let _ = try let lexbuf = Lexing.from_channel stdin in while true do token lexbuf; done with Eof -> print_int !count; print_newline(); exit 0 }

Extensions pour analyseurs lexicaux

Un analyseur lexical doit séparer un flot de caractères en une série de tokens'' (unit&#233;s lexicales), chacune d&#233;finie par une expression r&#233;guli&#232;re.<BR> <P> Cela est l&#233;g&#232;rement diff&#233;rent du probl&#232;me de la reconnaissance d'un langage rationnel: <UL><LI> on recherche le plus long prefixe de l'entr&#233;e qui corresponde &#224; une des d&#233;finitions d'unit&#233;s lexicales, on n'&#233;choue pas s'il reste qque chose apr&#232;s, et on doit pouvoir returner &#224; la fois ce prefixe et identifier quelle d&#233;finition a &#233;t&#233; trouv&#233;e, donc...<BR><LI> on augmente l'automate fini avec une information suppl&#233;mentaire sur les &#233;tats finaux (la r&#232;gle qui corresponde &#224; l'&#233;tat, et en cas de ambiguit&#233;, on choisit la pr&#233;mi&#232;re en ordre de d&#233;finition).<BR><LI> on mantient deux variables suppl&#233;mentaires: <TT>dernierEtatFinal</TT> et <TT>positionEntreeAuDernierEtatFinal</TT>, qu'il faut mantenir &#224; jour.<BR><LI> on retourne <TT>dernierEtatFinal</TT> quand l'automate se trouve bloqu&#233;. </UL> <P> Utilisation de OcamlLex <P> Un fichier source pour OcamlLex a extension <TT>.mll</TT> et a cette structure: <PRE>{ prologue } let ident = regexp ... rule etatinitial = parse regexp { action } | ... | regexp { action } and etatinitial = parse ... and ... { epilogue }</PRE> <P> Les commentaires sont d&#233;limit&#233;s par <code>(*</code> et <code>*)</code> comme en OCaml.<BR> Prologue et epilogue sont des sections optionnelles qui contiennent du code Ocaml arbitraire (typiquement, prologue d&#233;finit des fonctions n&#233;c&#233;ssaires dans les actions, alors que &#233;pilogue est plus souvent utilis', comme dans l'exemple pr&#233;c&#233;dent, pour r&#233;aliser un programmestand-alone'').

Utilisation de OcamlLex: expressions rationnelles

' char ' le caractère dénoté par char .

_ un caractère quelconque.

eof la fin du flot de caractères.

" string " une chaîne de caractères.

[ ens-char ] filtre tout caractère dans l'ensemble ens-char, qui peut être

une constante 'c', un intervalle 'c1' - 'c2'

ou l'union de deux ensembles (ex: 'a' - 'z' 'A' - 'Z')

[ ^ ens-char ] tout caractère qui n'est pas dans ens-char

exp * étoile de Kleene

exp + 1 ou plus occurrences de exp

exp ? 1 ou 0 occurrences de exp

exp1 | exp2 une occurrence de exp1 ou une de exp2

exp1 exp2 une occurrence de exp1, puis une de exp2

( exp ) la même chose que exp

ident l'expression abregée de nom ident (voir plus bas)


Précédences: * et + precèdent ?, qui precède la concatenation, et enfin |

Utilisation de OcamlLex: abbréviations

Il est possible de donner un nom à des expressions rationnelle qui apparaissent souvent, en écrivant:

let ident = regexp

entre le prologue et les régles.

Bien entendu, ces definitions ne peuvent être récursives.

Utilisation de OcamlLex: états initiaux

Dans rule token = parse, token est un identificateur Ocaml valide (qui commence par une minuscule), et définit un état initial de l'automate, que l'on peut invoquer sur un flot de caractères. Par exemple:

let lexbuf = Lexing.from_channel stdin in
token lexbuf;

Construit un flot à partir de l'entrée standard et appelle l'automate sur le flot avec l'état initial token''.<BR> <P> La possibilit&#233; d'avoir plusieurs &#233;tats initiaux est fort pratique pourchanger de mode'', ce qui permet de traiter par exemple de façon simple les commentaires imbriqués.

Commentaires Imbriqués

{ exception Eof;;
   let level = ref 0;; }
let ouvrecomm = "/*"
let fermecomm = "*/"

rule token = parse ouvrecomm {level:=1; comment lexbuf;} | _ {print_string(Lexing.lexeme lexbuf);} | eof {raise Eof} and comment = parse fermecomm {level := !level -1; if !level=0 then token lexbuf else comment lexbuf; } | ouvrecomm {level := !level + 1; comment lexbuf;} | _ {comment lexbuf; (* glob comments *)} | eof { raise Eof;}

{let _ = try let lexbuf = Lexing.from_channel stdin in while true do token lexbuf; done with Eof -> exit 0 }

Compilation

  1. écrire un fichier lexer.mll avec les définitions OcamlLex
  2. appeler OcamlLex: ocamllex lexer.mll
  3. cela produit le fichier lexer.ml
  4. compiler lexer.ml:
    • s'il est un programme standalone: ocamlc -o lexer lexer.ml
      et ensuite on peut l'exécuter en tapant ./lexer
    • s'il est un module: ocamlc -c lexer.ml

Exemples

Regardez ici

About this document ...

This document was generated using the LaTeX2HTML translator Version 96.1 (Feb 5, 1996) Copyright © 1993, 1994, 1995, 1996, Nikos Drakos, Computer Based Learning Unit, University of Leeds.

The command line arguments were:
latex2html -ascii_mode -split 0 Slides01.tex.

The translation was initiated by Roberto Di Cosmo on Mon Oct 25 16:27:25 MET 1999


Roberto Di Cosmo
Mon Oct 25 16:27:25 MET 1999