Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 Langages formels Projet de cours Idées en vrac à organiser : Minimisation d’un automate Algo de reconnaissance : automate à pile. Exos : mots du Grand Dyck ; palindromes ; etc…union de tel et tel ; intersection pas toujours algébrique. Grammaires régulières pour les expressions rationnelles déjà vues. Passer du dessin d'un automate à sa spécification abstraite et vice versa. M.M. Département Informatique Décembre 2000 1 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 Plan 1. 2. 3. 4. 5. Langages Systèmes de réécriture Langages rationnels Langages reconnaissables Langages algébriques Introduction La notion de langage formel est à distinguer (entre autres) de celle de langage de programmation, même s’il existe des liens entre un langage formel et un langage de programmation : les mots d’un langage formel seront étudiés indépendamment de toute sémantique. On se préoccupe seulement de questions syntaxiques. On peut rattacher la théorie d’abord aux travaux du mathématicien américain Stephen Cole Kleene dont les préoccupations étaient avant tout orientées vers les fondements des mathématiques (à rapprocher de Gödel, Turing, Church) ; à l’occasion de certains de ses travaux, il est amené au milieu des années 50 (1956) à définir une classse de langages formels, les langages dits réguliers ou langages de Kleene, ou encore langages rationnels. Quelques années plus tard, le linguiste américain Noam Chomsky (qui avait fait aussi des études de mathématiques et de philosophie), s’interroge sur les mécanismes qui permettent la production du langage (quelques règles apprises en très peu d’années nb. infini de phrases syntaxiquement correctes) et sa reconnaissance (un enfant se rend très vite compte si une phrase qu’il entend est ou non une phrase de sa langue, i.e. syntaxiquement correcte) ; à partir de ces réflexions, il travaille sur la (très vieille) notion de grammaire, apportant des définitions nouvelles, très précises, qui lui permettent de proposer des théorèmes et une classification : parmi les grammaires, les grammaires algébriques. Mais si la théorie provient de divers horizons, son succès vient de sa grande fécondité dans plusieurs domaines essentiels de l’informatique, au premier rang desquels la compilation. M.M. Département Informatique Décembre 2000 2 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 1. Langages 1.1. Définitions et notations Définition 1 : on appelle alphabet un ensemble fini non vide. Les éléments d’un alphabet sont appelés lettres. Remarque : la notion d’ensemble donne un contenu précis (définition, propriétés, opérations possibles, etc…) aux notions communes d’alphabet et de lettre. Mais le fait de nommer alphabet un ensemble fini quelconque ne le munit évidemment d’aucune structure particulière, et ne le distingue en rien du même ensemble que l’on n’aurait pas ainsi baptisé. Exemples : X1 = { 2, 4, 8, 16, 24, 48} X2 = {a, b, c, d, e, f} X3 = {‘0‘, ‘1‘,‘2‘,‘3‘} Sont des alphabets. Définition 2 : soit n un entier naturel ; un mot f de longueur n sur un alphabet X est une application de {1, 2, … n} dans X. La longueur n du mot f se note |f|. Exemples : f = (16, 16, 4, 2) et g = (4, 8, 48, 2, 4, 24) sont des mots sur X1. On a |f| = 4 et |g| = 6 De même u = (a,a,a,d,a,f,a,d,a) est un mot sur X2. L’application de dans X est appelée le mot vide ; ce mot, de longueur nulle, est noté ou 1X. Notation : lorsqu’il n’y a pas d’ambiguïté, on note un mot f sous la forme f(1) f(2) f(3) … f(n) plutôt que (f(1), f(2), … f(n)) Exemples : abba est un mot sur X2. Mais 248 n’est pas un mot sur X1 : (2, 4, 8) ? (2, 48) ? (24, 8) ? M.M. Département Informatique Décembre 2000 3 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 Par ailleurs, la notation d’un mot par juxtaposition des lettres conduit à ne pas distinguer le mot f de longueur 1 et la lettre f(1) : sauf en de rares cas, il est inutile d’alourdir les explications en distinguant systématiquement le mot a de la lettre a ! Notation : le nombre d’occurrences de la lettre x dans le mot f se note |f|x. Cette notion est suffisamment claire ; notons cependant que formellement, le nombre d’occurrences de x dans f est le cardinal de l’image réciproque de {x} : Card f-1 {x} Notation : l’ensemble de tous les mots sur un alphabet X est noté X*. Remarque : cet ensemble est infini. Exercice : montrer que X* est dénombrable. Réponse : on peut le faire en s’inspirant de la méthode de Gödel pour les listes : X est fini, on peut donc numéroter ses éléments ; par exemple X = {a, b, c} n(a) = 1, n(b) = 2, n(c)=3 Ensuite, un mot f sur X étant donné, on considère les |f| premiers nombres premiers, que l’on note p(1) (=2) , p(2), etc… On forme alors le nombre (f) = f p(i) n(f(i)) i1 Exemple : f = acbaacb (f) = 21x32x53x71x111x133x172 = 110002142250 Par l’unicité de la décomposition en facteurs premiers, (f) = (f’) f = f’ et est injective ; les mots de X* ne sont pas plus nombreux que les entiers naturels. Cqfd. Exercice : quel mot de X* a pour numéro 415800 415800 = 23x33x52x71x111 M.M. Département Informatique Décembre 2000 4 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 donc c c b a a Même question avec numéro 30 ? c’est a a a Et numéro 15 ? aucun : 3 x 5 et il n’y a pas eu 2. Définition 3 : On définit sur X* une loi de composition interne notée . ou <vide>, appelée produit de concaténation : X* x X* X* (f, g) fg, avec fg (i) = f(i) i {1, 2, … |f|} fg (i) = g(i-|f|) i {|f|+1, … |f|+|g|} Exemple : Avec l’alphabet X2 ci-dessus prenons u = ac, v = dc u v = acdc Propriétés du produit de concaténation : Il est clair que cette loi est associative : u (v w) = (u v) w D’autre part elle admet le mot vide pour élément neutre : x X*, x = x = x Ces propriétés sont très intuitives : il suffit de considérer des suites de lettres. Mais il est possible de les vérifier de façon plus formelle à partir des définitions : ce peut être un excellent exercice… Remarque très importante : les deux propriétés ci-dessus font de l’ensemble X* muni du produit de concaténation un monoïde. On désigne souvent X* par l’expression « le monoïde libre ». Dans cette expression, l’adjectif libre signifie que les éléments de X ne sont liés entre eux par aucune relation. On remarque enfin que le produit de concaténation n’est pas en général commutatif. u = ac, v = dc u. v = acdc v. u = dcac M.M. Département Informatique Décembre 2000 5 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 Remarques : (1) on dit souvent plus simplement concaténation, parfois même produit lorsqu’aucune confusion n’est à craindre. Les remarques suivantes sont à rapprocher du caractère multiplicatif de cette loi. (2) on note souvent exponentiellement une séquence d’occurrences consécutives d’une même lettre : a3b2a4 plutôt que aaabbaaaa (clairement a0 = = b 0 etc …) Enfin, on parle de facteur : les mots u, v et w sont facteurs du mot f = uvw . Exercice : donnez tous les facteurs du mot aababa Réponse : , a, b, aa, ab, ba, aab, aba, bab, aaba, abab, baba, aabab, ababa, aababa. Définition 4 : pour tout mot f sur un alphabet X, on appelle image ~ miroir de f le mot noté f et tel que : i {1,2 … |f|}, f (i) = f(|f|i+1) ~ Exemple si f = aaabba alors f = abbaaa ~ Définition 5 : Un langage (formel) est une partie de X* Exemples : X = {a, b} L1 X* = { f X* / |f|a = |f|b} L2 = {ubu / u X*} mots symétriques autour d’un b L3 = L4 = {} Exercice : donner des exemples de mots de chacun de ces langages. M.M. Département Informatique Décembre 2000 6 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 1.2. Opérations sur les langages On retrouve très naturellement les opérations ensemblistes classiques (justifiées par la définition d’un langage comme un ensemble de mots, plus précisément une partie de X*) : , , C L1 L2 (noté L1 \ L2 ou L1 - L2). Le complémentaire de L par rapport à X* est noté L On a aussi L1 L2 : concaténation de deux langages, opération induite par la concaténation des mots : L1 L2 = {f X* / (u,v) L1 x L2 /f = uv} De la même façon, ~L = {~f/ f L} Une opération très importante est appelée l’étoile d’une partie : Définition 6 : A toute partie A d’un langage L on associe A* = {} A AA AAA… A n Soit encore n0 Remarque : en identifiant les éléments de X et les mots de longueur 1 sur X, l’ensemble des mots sur X est bien X*. Enfin, on note A+ l’étoile propre d’une partie A : A+ = A.A* = A*.A Exercice : soit X = {a, b}, L1, L2, L3 comme ci-dessus. Expliciter L1.L2, L1.L3, L4.L1, L1*, L2*, L3*, L4*, L1 L2, L1 L3, L1 L4, L1 L2, etc… On remarque ici ~L1 = L1, ~L2 = L2, ~L3 = L3, ~L4 = L4. Est-ce toujours le cas ? Non ! L = {anbn / n N} alors ~L = { bn an / n N} L ~L = {} On étudiera en TD certaines propriétés des opérations sur les langages. M.M. Département Informatique Décembre 2000 7 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 2. Systèmes de réécriture. Avant d’aller plus loin, il peut être intéressant de faire quelques 2.1. Rappels et compléments sur les relations : Notation : Soit R une relation sur un ensemble E Pour tout couple (x,y) de E², et pour tout entier k > 0, on note x Rk y x R o R k-1 y et x R 0 y x = y Autrement dit x Rk y signifie x R o R o R . . (k fois). . o R y Définition 7.a : Soit R une relation sur un ensemble E. On appelle clôture transitive de R et on note R + la relation définie sur E par (x,y) E², x R + y k N* / x R k y DIAPO 32 Propriété : Pour toute relation R, R + est la relation transitive dont le graphe est le plus petit incluant celui de R. 1) G R G R+ 2) T transitive sur E, G R G T G R + G T Cette propriété découle directement de la construction : on se contente de « rajouter » au graphe de R les couples qui manquaient pour assurer la transitivité. Exemple : A = { 1, 2, 3} GR = {(1,1), (1,2),(2,1), (2,2), (2,3)} GR+ = {(1,1),(1,2) (1, 3), (2,1), (2,2), (2,3)} M.M. Département Informatique Décembre 2000 8 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 Définition 7.b : si R est une relation sur un ensemble E, on appelle clôture transitive et réflexive R la relation notée R* et définie comme suit : (x,y) E², x R*y x R+ y x = y On a donc G R* = G R+ A 2.2. Définition d’un système de réécriture Définition 7.c : on appelle système semi-thuéien une partie finie de X* x X*. Définition 7 : à tout système semi-thuéien T on associe une relation de réécriture sur X*, notée ; pour tous mots f, g de X*, on dit que T le mot f se réécrit en le mot g selon T et on note f g ssi u, v, x, y T X* tq. f = u x v g = u y v (x, y) T Langage engendré (définition 7bis) : à toute partie A de X*, à tout système T (sur X*) on associe le langage L(A, T) = {f X* / a A tq a *T f} Autrement dit, le langage L(A,T) est l’ensemble des mots f en lesquels se réécrivent les éléments de A selon*T, fermeture réflexive et transitive de la relation de réécriture associée au système T T Exemple : X = {a, b}, A = {ab, ba} T = {(ab, aabb), (ba, bba)} L(A,T) = {anbn /n>0} {bna/ n>0} Exercice : X = {a, b, c}, A = {abc}, T = {(ab, ba), (ac, ca), (bc, cb)} Les mots suivants sont-ils éléments de L(A,T) ? si oui, expliciter *T, c’est à dire écrire les différentes étapes de la réécriture (en utilisant seulement . T cba, bac, cbabac Comme on peut intuitivement le deviner, un système de réécriture est un moyen très pratique pour « produire » des mots, en revanche, il M.M. Département Informatique Décembre 2000 9 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 n’est pas très facile à utiliser pour valider l’appartenance d’un mot à un langage. Plus précisément, soit X un alphabet, A une partie de X*, T une relation de réécriture sur X*, et u un mot de X*, on appelle problème du mot la question de savoir si u L(A,T). Nous admettrons le résultat suivant (très technique) : Proposition 1 : le problème du mot est indécidable. Ceci signifie exactement qu’il ne peut exister d’algorithme (se terminant toujours en un temps fini) permettant de résoudre le problème du mot. Attention, il ne s’agit pas d’une absence historique (« on n’a pas encore trouvé d’algorithme… ») mais d’une impossibilité théorique (liée à l’indécidabilité du problème de l’arrêt d’un algorithme, lui-même prouvé par Alan Turing selon une méthode qui imite l’argument diagonal de Cantor). Ceci est très « fâcheux » : pour simplifier la question, comment le compilateur g++ va-t-il pouvoir décider si le programme que vous lui soumettez est un mot du langage formel que constitue l’ensemble des programmes C++ ? « Heureusement », si le problème du mot est indécidable en général, il existe des systèmes possédant des propriétés particulières qui permettent de décider. Ce sont évidemment ces cas particuliers qui vont retenir maintenant notre attention. 3. Langages rationnels Définition 8.a : l’expression d’un langage L sur X selon une décomposition finie d’unions, produits et étoiles de parties finies de X* s’appelle une expression rationnelle de L. Définition 8 : un langage L sur X est dit rationnel ssi il possède une expression rationnelle. Remarque 1 : il résulte des définitions qu’un langage rationnel est un langage formé à partir des lettres de X (en fait mots de longueur 1) au moyen d’un nombre fini d’applications des opérations d’union, produit, et étoile. Remarque 2 : on dit aussi expression régulière, d’où langage régulier (on verra plus loin un prolongement) et parfois langage de Kleene. M.M. Département Informatique Décembre 2000 10 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 Exemple : X = {a, b} L = {a}* {b}* {abab,a} est une expression rationnelle de L qui est donc un langage rationnel. On simplifie l’écriture en identifiant un langage composé d’un seul mot et ce mot lui-même ; de plus, on note + pour l’union : L = a* + b*(abab+a) Exercice : donnez tous les mots de L de longueur < 7 Autre exemple : X = {0, 1} L = 0 + 1.X* Exercices : 1. Expliciter L (écriture binaire des entiers naturels). 2. Montrer que l’ensemble des identificateurs du langage C forme un langage rationnel ; rappel : un identificateur C commence par un caractère alphabétique, suivi d’une séquence éventuellement vide de caractères alphanumériques ; les lettres majuscules et minuscules sont distinguées ; _ est considéré comme alphabétique. Réponse : X = {A .. Z} {a .. z} {0 .. 9} {_} IdentC = (X – {0..9})+ . X* Ou encore (plus joli) : L = {A, B, .. Z, a, b, .. z} C = {0, 1, ..9} IdentC = (L + _).(L + C + _ )* IdentC est rationnel puisqu’il s’exprime selon etc… On note Rat(X*) l’ensemble des parties rationnelles de X*. Remarque : il résulte des définitions que tout langage fini est rationnel. On va se servir d’une nouvelle notion : Définition : soit E un ensemble muni d’une loi de composition interne © . On dit qu’une partie A de E est fermée par © ssi (x, y) A² , x © y A. M.M. Département Informatique Décembre 2000 11 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 Exemples : N R est fermé par addition, produit, pas par division ni soustraction. Autrement dit, © est une l.c.i. dans A. Propriétés de Rat(X*) : La famille des langages rationnels est fermée par , produit et * : ceci résulte des définitions. Définition 9 : on dit qu’un mot u X* possède un facteur itérant dans L X* si u = f g h, avec |g| > 0 (g n’est pas le mot vide), et fg*h L. Ce facteur itérant est noté (f, g, h). Lemme 1(dit lemme de l’étoile, en anglais pumping lemma) : Si un langage L sur un alphabet X est rationnel, alors il existe un entier naturel non nul N tel que tout mot de L de longueur au moins égale à N possède un facteur itérant dans L. u L, |u| N f,g,h X*, |g| > 0 u = fgh fg*h L Preuve : si L est fini, il ne peut admettre de facteur itérant. En revanche, il contient des mots de longueur maximale M. Ainsi N = M+1 et le lemme est vérifié puisque l’antécédent de l’implication est toujours faux. si L est infini, il s’exprime en une décomposition finie d’unions, produits et étoiles de parties finies de X*. Notons L1, L2, … Ln ces parties. Il est clair que L1.L2. … .Ln est une partie finie dont les mots les plus longs ont pour longueur M1 + M2 …+ Mn. De même Li + Lj ( Li Lj) est une partie finie dont les mots les plus longs ont pour longueur max{Mi, Mj}. En revanche, Li* est clairement une partie infinie. On ne perd donc rien en généralité à considérer une expression simplifiée de tout langage rationnel non fini L = La.Lb*.Lc Si un mot u de L a une longueur supérieure à Ma + Mc, c’est qu’il comporte au-moins un facteur qui est un mot de Lb ; on a donc u = abc, |b| > 0 puisque |u| > Ma+Mc, et ab*c L par définition de L. Exercice : montrer que L = {anbn/ n N} n’est pas rationnel. Il suffit d’utiliser la contraposée du lemme de l’étoile : aucun mot de L n’admet de facteur itérant dans L. M.M. Département Informatique Décembre 2000 12 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 On raisonne par l’absurde Montrer que le langage suivant est rationnel : Lk = {anbm/n,m N n m (mod k)} Réponse : Lk = (ak)*(bk)* + (ak)*a(bk)*b + (ak)*a2 (bk)*b2…+ (ak)*ak1 k (b )*bk-1 NB : attention, le lemme de l'étoile ici ne sert à rien ( mais pas ) 4. Langages reconnaissables. 4.1. Automate fini définition 10 : un automate fini A est la donnée < X, E, I, F, > où : X est un alphabet appelé ici alphabet d’entrée. E est un ensemble fini dont les éléments sont appelés les états de A I E est l’ensemble des états initiaux F E est l’ensemble des états d’acceptation (ou états terminaux) E x (X ) x E est l’ensemble des transitions de l’automate. On représente souvent un automate par un graphe valué (au sens où chaque arc est étiqueté par une valeur, ici une lettre de X ou ) : < (X ), E, > où E représente l’ensemble des sommets du graphe, (X ) celui des étiquettes et l’ensemble des arcs. On représentera par exemple (ei, a, ej) par le schéma suivant : a ei ej Un symbolisme de type flèche entrante (resp. sortante) suffira à distinguer les états initiaux (resp. terminaux) e0 M.M. Département Informatique Décembre 2000 ef 13 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 Exemple 1 : a b 0 1 a On parlera d’automate fini non déterministe (AFN) parce que 1) la lecture d’une même lettre peut conduire d’un état donné à plusieurs états différents (« au choix »). Plus précisément, on peut avoir (e,x,e’) (e,x,e’’) e’ e’’ 2) il peut exister une transition d’un état e vers un état e’ sans qu’aucune lettre ait été lue : on parle d’- transition. 3) il peut exister plusieurs états initiaux Sur l’exemple ci-dessus, (0,a,0) et (0, a, 1) sont des éléments de . Voici un autre exemple d’automate non déterministe : Exemple 2 : a e2 b b e0 e1 b e3 a c e4 Définition 10bis : un mot u X* est reconnu (on dit aussi accepté) par l’automate A ssi il existe une suite de |u| éléments de de la forme : (ei0,u1,ei1),(ei1,u2,ei2), … (ei|u|-1, u|u|, ei|u|), avec ei0 I et ei|u| F et u=u1u2..u|u|…. Intuitivement, on peut passer dans le graphe d’un sommet initial à un sommet terminal en « lisant » le mots sur les arcs traversés. L’automate ci-dessus (exemple 1) reconnaît les mots : M.M. Département Informatique Décembre 2000 14 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 abbb, aaabb, aaaaaa, a Donnez-en d’autres. Définition 10ter : l’ensemble des mots reconnus par l’automate fini A s’appelle le langage reconnu par A et se note généralement L(A). Sur l’exemple : mots commençant par un nombre non nul de a éventuellement suivis par des b. {f {a,b}*/ m N*, n N / f = ambn} Donnez une expression rationnelle L’ensemble des langages reconnus par AFN est noté ND(X*) Théorème 1 (Kleene[1]) : Rat(X*) = ND(X*) On admettra ce résultat dont la preuve est un peu technique ; on peut cependant remarquer : a a ab a b a+b a b a a* de même (ab)* a b Définition 11 : un automate fini <X,E,I,F,> est déterministe si : I est un singleton. est le graphe d’une relation fonctionnelle de E x X vers E Remarque : dans ce cas, il est courant de spécifier l’automate par <X,E, e0, F, > (au lieu de {e0}) M.M. Département Informatique Décembre 2000 15 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 L’ensemble des langages reconnus est noté Rec(X*) ; ils sont appelés langages reconnaissables. Exemple a a 0 1 b b 2 Langage reconnu ? Le même que pour l’exemple précédent. Méthode générale pour passer d’un automate à une expression rationnelle : on résout un système d’équations L0 = aL1 L1 = aL1 + bL2 + L2 = bL2 + Pour résoudre ce système, on va utiliser la propriété suivante dite lemme d’Arden : Pour tous A, B, C P(X*), l’équation A = BA + C admet pour solution A = B*.C Preuve : de la définition de l’étoile, il découle que B*C = B*B.C + C = B.B*.C + C. Donc, si on substitue B*C à A, l’équation devient une proposition vraie. Donc ici L2 = b* (lemme) L1 = a*b* (substitution + lemme) L0 = a.a*b* = a+b* Théorème 2 (Kleene[2]) : ND(X*) = Rec(X*) Preuve : l’inclusion Rec(X*) ND (X*) résulte des définitions. M.M. Département Informatique Décembre 2000 16 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 L’inclusion réciproque est prouvée par l’existence d’un algorithme de déterminisation qui à tout AFN fait correspondre un AFD reconnaissant le même langage. L’algorithme consiste à reprendre l’AFN A’, à supprimer les -transitions pour obtenir A", et à remplacer l’ensemble E" des états par P(E") ; l’ensemble I" des états initiaux de A" devient alors l’unique état initial I de A ; enfin, on remplace " par : Q E", (Q, x) = {e" E" / e Q /. (e,x,e") "} La suppression des -transitions se fait ainsi : pour chaque état e : calculer son -fermeture, i.e. l'ensemble des états que l'on peut atteindre à partir de lui en ne suivant que des -transitions. On a e -fermeture(e). (e,x,e") " r -fermeture(e) / (r, x, e") ' Enfin un état e appartient à F" ssi son -fermeture contient un élément de F'. A faire en TD : déterminiser un AFN. On voit sur les diapos 1) AFD reconnaissant le même langage que précédemment ; 2) AFN suppression des -transitions Exercice : Montrer que les langages suivants parties de {a,b}* sont rationnels : Lp = {f /|f|a 0 (mod 2)} Lpi = {f / |f|a 0 |f|b 1 (mod 2)} Lkp = {f / k N / |f|a = kp} p donné Lk = {f / |f|a |f|b (mod k)} Il suffit de montrer qu’ils sont reconnaissables (Kleene) et donc d’exhiber pour chacun des langages un automate fini qui le reconnaisse (on pourrait ensuite calculer l'expression rationnelle à partir de l'automate) : Lp : b a b 0 1 a M.M. Département Informatique Décembre 2000 17 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 Lpi a p,p i,p a b b b b a p,i i,i a etc… Corollaire (Kleene) : la famille RAT(X*) est fermée par et différence. La preuve repose sur la construction d’automates finis reconnaissant L1L2 et L1 – L2 (L1, L2 RAT(X*) donc à REC(X*)). L’intersection est facile à construire si l’on considère des automates non déterministes. Pour L1-L2 c’est l’automate construit à partir de A(L1), A(L2), et donc A(X*-L2), enfin A(L1 (X*-L2)) Définition 12 : un automate fini déterministe <X,E, e0, F, > est dit complet si est le graphe d’une application. En pratique on parle souvent de la fonction de transition de l’automate. Il est très facile et très commode de compléter un AFD A non complet : il suffit de rajouter un état e qui n’est pas un état d’acceptation, et pour tout état ei, s’il existe une lettre x telle que pour tout état ej (ei, x, ej) , on rajoute une transition (ei,x,e). En particulier, x X, ( e, x) = e Un état e pour lequel , ( e, x) = e pour tout x (comme e ) est appelé un état puits. On peut le voir comme l’état correspondant à une situation d’erreur. Exemple : M.M. Département Informatique Décembre 2000 18 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 b a a a b b Le théorème suivant permet de prouver qu’un langage est reconnaissable, ou de vérifier qu’il ne l’est pas (utile lorsque le lemme de l’étoile ne permet pas de conclure) : Définitions 13 : (a) soit L X*, w X*, w-1L = {v X*/ wv L} (un langage, appelé résiduel de L par rapport à w) (b) R(L) = {w-1L : w X*} (un ensemble de langages) Théorème 3 (Nérode – Myhill) L Rec(X*) R(L) est fini Preuve : L = L(A), A déterministe complet. Donc, w X*, il existe un unique état e(w) tq e0 wA e(w) Et w-1L = {v / e(w) vA e’, e’ F} e’ acceptation Donc Card(R(L)) |A| (nb. états de A) Soit R(L) = {L0, L1, … Ln} Comme L = -1L, L R(L), L0=L On construit A = < X, {e0, e1…en}, , {e0}, F} avec F = {ei / Li, i {0,1, … n}} (ei, x) = ej tq Lj = x-1 Li On vérifie par induction sur |w| que e0 wA ei w-1L = Li Donc L = L(A) M.M. Département Informatique Décembre 2000 19 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 Langages rationnels et algorithmes de reconnaissance et de traitement Les langages rationnels se prêtent donc à une reconnaissance « automatique », d’où leur intérêt en informatique. Cet intérêt se manisfeste particulièrement dans le cas des automates déterministes, qui se traduisent directement par des algorithmes : M.M. Département Informatique Décembre 2000 20 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 Algorithme de reconnaissance simulant un automate : On indique ici seulement le principe fonction reconnu(f : chaîne de caractères) : booléen var TableTransitions : tableau[N][M] d’états e : état début e e0 tant que il reste des lettres à lire faire début lire (lettre) e TableTransitions[e][lettre] fin retourner (e est un état d’acceptation) fin Exercice : préciser les structures de données et écrire une fonction C++ implémentant cet algorithme dans le cas où l’alphabet est {a, b} et langage Lp = {f /|f|a 0 (mod 2)} Par exemple : // automate reconnaissant le langage formé // sur {a,b} par les mots ayant un nombre pair de a #include <iostream.h> #include <string> typedef int etat ; const int NB_ETATS = 2; const int NB_LETTRES = 2; // les états : const etat e0 = 0; const etat e1 = 1; // la fonction de transition : const etat delta[NB_ETATS][NB_LETTRES] = {{e1,e0}, {e0,e1}}; bool correct(string f){ etat e=e0; int i=0; // pour parcourir le mot char lettre; // pour lire les lettres de f while((lettre = f[i])!='\0'){ M.M. Département Informatique Décembre 2000 21 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 if(lettre != 'a' && lettre != 'b')return false; e=delta[e][lettre-'a']; i++; } return (e==e0); } int main(int argc, char** argv){ if(correct(argv[1])) cout << "OK\n"; else cout << "NON\n"; return 0; } Mais dans le cas non déterministe, deux possibilités : 1. Déterminisation de l’automate (ce qui est une opération automatisable !) 2. méthode des essais / erreurs, (algorithme appelé backtracking ou encore rétro-parcours) Automates finis avec sortie : On peut donner plusieurs définitions. En voici une assez simple : Définition 14 : un automate fini avec sortie A est un triplet <A’, S, > où A’ est l’automate fini (que pour simplifier on considèrera déterministe) <X,E,e0,F,>, S un alphabet dit alphabet de sortie, et une application de E x X dans S*. Remarques : XS est quelconque (pas nécessairement vide, etc…). On peut voir comme un traducteur : si je suis dans l’état e, et que je lis la lettre x, alors je produis la sortie s (i.e. (e,x)=s) et je passe dans l’état e’(i.e. (e,x)=e’). Exemples : A partir d’un mot de {a, b}*, on veut produire un mot de (a + ba)*, ce qui modélise la suppression des blancs multiples dans un texte (a représente un signe typographique quelconque, et b un blanc) : M.M. Département Informatique Décembre 2000 22 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 b/ a/a b/b 0 1 a/a Codage / décodage Définition 15 : soient X, Y des alphabets ; un homomorphisme injectif de X* dans Y* est appelé un codage. L’injectivité garantit que deux mots distincts de X* ne seront pas codés identiquement dans Y* Le problème du décodage consiste à trouver h-1({w}), w Y*. Remarque : puisque h est injective, h-1 est fonctionnelle, et h-1({w}) est soit l’ensemble vide, soit un singleton. Définition 16 : un langage L X* est dit préfixe ssi f L, u,v X*, f = uv u L Exemple sur X = {a,b} L1 = {a, aab, ab, abba} n’est pas préfixe L2 = {a, bba, bab, baab} est préfixe. Nous admettrons le résultat suivant, fort intéressant : Proposition 2 : soit h : X* Y* un homomorphisme de monoïdes tel que {h(u) / |u| = 1} est un langage préfixe, alors h est injectif et h -1 est définissable par un automate avec sortie. Exemple : h: a b c d M.M. Département Informatique Décembre 2000 01 0011 1 0001 23 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 1/b 1/ 0/ 1/c 0/ 0/ 1/a 1/d Application : compression de fichier Un fichier est une suite de mots binaires, par exemples d’octets (huit chiffres binaires). On peut classer les octets selon leur fréquence et coder les plus fréquents par les mots les plus courts : le plus fréquent = 1, ensuite 01, etc… Exemple : « ceci est un exemple » est codé en ASCII par 19 octets. Fréquence : e (5), spc (3), c (2), le reste : 1 Donc par exemple :) e 1 ; spc 01 ; c : 001 ; i : 0001 ; s : 00001 ; t : 000001 ; u : 0000001 ; n : 00000001 ; x : 000000001 ; m : 0000000001 ; p :00000000001 ; l : 00000000000 La phrase devient : 001 1 001 0001 01 1 00001 000001 01 0000001 00000001 01 1 000000001 1 0000000001 00000000001 0000000000 1 On vérifie aisément qu’elle est décodable sans ambiguïté, et elle occupe un peu moins de 11 octets (au lieu de 19). Conclusion sur les langages réguliers Plusieurs utilisations évidentes en informatique : Comme on vient de le voir, compression des textes (gzip, winzip, etc…) La commande Unix grep recherche dans un fichier les occurrences de chaînes définies par expression rationnelle. Par exemple grep a.*e.*i.*o.*u.* toto affiche toutes les lignes du fichier toto contenant les voyelles M.M. Département Informatique Décembre 2000 24 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 dans l’ordre croissant au milieu de n’importe quels autres caractères (pour cette commande le point signifie n’importe quel caractère, la concaténation est notée par juxtaposition sans espace, l’étoile est l’étoile, et bien d’autres aspects encore…) Plus couramment, une commande comme rm accepte des arguments de type f*a*.o (pour f.X*.a.X*.o) ce qui signifie suppression des fichiers dont le nom commence par f, comporte un a, et se termine par la chaîne .o ; la syntaxe est ici légèrement différente (moins puissante en fait mais adaptée au but !) que pour grep. Enfin, il faut évoquer la phase d’analyse lexicale dans la compilation, i.e. les identificateurs, les opérateurs, etc… sont ils bien formés ? Par ex. 3ab25 = 6 est refusé par g++, de même a #=5. Nous reviendrons sur cette question ultérieurement. Mais un morceau de programme C++ comme as_long_as (x = w ; or + if = 2) ; Complètement incohérent ne peut pas être détecté au niveau lexical. Les « mots » vocabulaire C++ (parenthèses, +, = , identificateurs), mais la structure de l’énoncé, la « grammaire » n’est pas respectée. D’où l’intérêt d’un outil plus puissant que les automates et les langages de Kleene. Langages algébriques Une grammaire algébrique permet de définir un langage. On utilise notamment les grammaires algébriques pour définir la syntaxe d’un langage de programmation. Définition 17 : une grammaire algébrique est la donnée de < X, V, P, S > où : X est un alphabet dit terminal V (comme variables) est un alphabet dit non terminal, tel que XV= P, appelé ensemble des productions, est une partie finie de Vx(XV)*, c’est-à-dire un système semi-thueien. S est une lettre distinguée de V, appelée axiome. M.M. Département Informatique Décembre 2000 25 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 Notation : Les non terminaux sont généralement notés en minuscules et les NT en majuscules. (A, m) P sera noté A m De même si (A,m), (A,n), (A,tB) sont des règles de la grammaire considérée, on notera A m + n + tB Enfin, on néglige souvent de préciser l’axiome (on ne le fait éventuellement qu’après coup), notamment lorque V est un singleton. Exemple : G1 = < X1, V1, P1, A> X1 = {a,b}, V1 = {A}, P1 = {A aAb + } Définition 17bis : soit G = < X, V, P, A> une grammaire algébrique. On appelle langage engendré par G l’ensemble L(G) = {f X* / A *P f} Par exemple, il est facile de deviner que L(G1) (ci-dessus) = {anbn /n 0} Remarque : les grammaires algébriques sont aussi appelées non contextuelles (context free) : w1 A w2 * w1 w’ w2 ; la production ne modifie pas le contexte. Définition 17ter : un langage est algébrique ssi il existe une grammaire algébrique qui l’engendre. Ainsi {anbn /n 0} est algébrique. On note ALG(X*) la famille des langages algébriques. Définition 18 : pour tous u, v (X V)*, on appelle dérivation de u en v toute suite (u0, u1, …uk) tq u0=u, uk=v et i<k, ui ui+1 Une telle dérivation est notée u0 u1 u2 … uk . L’entier k s’appelle l’ordre (ou la longueur) de la dérivation, et on note u k v Exemple : X = {a, b}, V = {A}, P = {A aAbA + } Dérivation n° 1 : M.M. Département Informatique Décembre 2000 26 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 A aAbA aAbaAbA aaAbAbaAbA aabAbaAbA aabbaAbA aabbaAb aabbab Dérivation n°2 : A aAbA aaAbAbA aaAbbA aabbA aabbaAbA aabbabA aabbab On voit que deux dérivations distinctes peuvent engendrer le même mot. Mais on définit sur les dérivations une relation d’équivalence, et il existe un moyen simple de vérifier que deux dérivations sont équivalentes ; pour cela, il faut introduire la notion d’arbre : Définition 19.1 : si R est une relation sur un ensemble E, et si x, y sont des éléments de E, on appelle R-chemin de x à y une suite x = x0,x1,x2 ... xn-1,xn = y telle que (x,x1),(x1,x2) ... (xn-2,xn-1),(xn-1, y) sont éléments de GR Définition 19.2 : un arbre A sur un ensemble E est une relation sur E possédant les propriétés suivantes : (a) il existe un élément r de E tel que pour tout xr il existe un et un seul A-chemin de r à x (b) (r,r) n’est pas élément de A+ R est appelé racine de l’arbre ; on montre facilement que r est unique, et que A est acyclique (i.e. A+ est antiréflexive). De même x E, (x,r) GA. et aussi x, y, z éléments de E, x A z y A z x = y. On appelle feuille de l’arbre A un élément x E tq y E/ yAx z E, xAz Enfin, il est souvent utile de considérer des arbres ordonnés. Définition 19.3 : on dit qu’un arbre est ordonné ssi x E, l’ensemble {y E / xAy} est un ensemble totalement ordonné. M.M. Département Informatique Décembre 2000 27 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 L’utilité de cette notion est telle que souvent on dira par abus de langage arbre à la place de arbre ordonné. Cette utilité se comprend intuitivement lorsqu’on représente graphiquement un arbre ; si l’arbre n’est pas ordonné, alors a a = b c c b Ce qui peut être gênant, par exemple si on remplace a par l’opérateur de division, et que b et c représentent des réels ! Définition 19.4 : dans le cas d’un arbre ordonné, le mot formé par la suite des feuilles parcourue de gauche à droite s’appelle frontière de l’arbre. Revenons aux dérivations ; à chaque dérivation, on peut associer un arbre (ordonné) de dérivation A a A A b a b A A A a b A On s’aperçoit que D1 et D2 donnent le même arbre. La seule différence est en fait l’ordre dans lequel on a appliqué les règles. On ferait apparaître cette différence sur les arbres en numérotant les nœuds dans l’ordre de leur création. Mais la différence ne se répercute pas sur le mot engendré, qui se lit en parcourant les feuilles de gauche à droite. Lorsque deux dérivations produisent le même arbre, on dit qu’elles sont équivalentes. Il peut cependant se faire qu’un même mot soit engendré par deux dérivations non équivalentes au sens ci-dessus : M.M. Département Informatique Décembre 2000 28 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 Exemple : Dans l’exemple suivant, le ou (union) est noté | car + fait partie des symboles terminaux. Cette notation est courante de toute façon. E E + E | E x E | ( E ) | - E | id Cette grammaire engendre les expressions arithmétiques, avec id représentant un identificateur, qui peut lui-même être reconnu par un automate fini. Par exemple : E *id x (id+id) Ou encore E *id x id+id Considérons des dérivations pour cette dernière expression : D1 : E E x E id x E id x E + E id x id + E id x id + id D2 : E E + E E + id E x E + id id x E + id id x id + id Construisons les arbres A1 et A2 correspondant : A1 A2 E E E x E id E + id E E E id id x + E E id Ces deux arbres ont même frontière, mais ils sont différents ; les deux dérivations ne sont donc pas équivalentes. Ici par exemple, A1 pourraît s’interpréter comme id x (id + id), et A2 id x id + id. Plus formellement : Définition 19 : une grammaire algébrique G = < X,V,P,A> est dite ambiguë s’il existe un mot f de (X V)* qui est la frontière de deux arbres de dérivation distincts et de même racine. Remarque : c’est la grammaire qui est ambiguë, non en général le langage engendré. Définition 19.bis : un langage algébrique est dit ambigu si toute grammaire qui l’engendre est ambiguë. M.M. Département Informatique Décembre 2000 29 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 La preuve du fait qu’un langage est ambigu est très technique (il faut prouver que toutes les grammaires le sont…). Voici néanmoins un exemple de langage algébrique ambigu : La = {anbnc*/ n > 0} {a*bpcp / p>0} Au contraire, le langage des expressions arithmétiques n’est pas ambigu. Exercice : trouver une grammaire non ambiguë qui engendre les expressions arithmétiques. Réponse : EE+T|T TTxF|F F (E) | id Le résultat suivant est très important : il est utile lorsque l’on veut prouver que telle grammaire engendre tel langage : Lemme 3 : Soit une grammaire algébrique G = < X, V, P, A> ; n u1,u2, v (XV)*, n N, u1u2 v ssi : n1 n2 n1,n2 N, v1,v2 (XV)* tq n1+n2=n u1 v1 u2 v2 La preuve se fait par récurrence sur n : i. Si n = 0 , c’est trivial La preuve du pas récurrent utilise le pas n = 1 qu’il faut donc prouver : ii. Par définition de , M V, u’, u’’ (X V)* tq u1u2 = u’Mu’’, v = u’mu’’ et (M,m) P. Il faut alors distinguer deux cas : 1. |u’| |u1| : alors t (X V)* tq u’ = u1t u2 = tMu’’. On pose alors v1 = u1 et v2 = tmu’’ et le lemme est vérifié puisqu’on a bien u1 0 v1 et u2 (= tMu’’) 1 v2 (= tmu’’) 2. |u’| < |u1|, de la même façon u1 = u’Mt et u’’=tu2 iii. Supposons donc le lemme vérifié pour n < k u1u2 k v u1u2 k-1 w v M.M. Département Informatique Décembre 2000 30 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 Donc (HR) w = w1w2 et u1 k1 w1, u2 k2 w2 et k1+k2 = k-1 D’après l’étape ii, w1w2 v donc w1 e1 v1 et w2 e2 v2, avec v1v2 = v et e1+e2 = 1. Par conséquent u1 k1+e1 v1 et u2 k2+e2 v2 et k1+e1+k2+e2 = k QED Application : prouver que la grammaire ci-dessus (X = {a, b}, V = {A}, P = {A aAbA + }) engendre les mots de parenthèses, autrement dit que L(G) = P = {f {a,b}* tq |f|a = |f|b u, v X*, uv = f |u|a |u|b} i.e. toujours ouvrir les parenthèses avant de les fermer. Remarque utile : un mot P ssi soit il est vide, soit il est de la forme afbg, avec f, g P (les parenthèses ne peuvent pas se « croiser »). 1. P L(G) récurrence sur la longueur des mots longueur nulle P et L(G) HR : |f| < n et f P f L(G) Soit g P, |g| = n alors g = a u b v ; u et v P et de longueur < n donc u, vL(G). Donc A *u et A *v. Il existe donc une dérivation AaAbA*aubA*aubv = g, ainsi g L(G). Il reste à montrer que L(G) P, ce qui se fait par récurrence sur la longueur des dérivations. Ordre 1 : A f f = et P HR : A k f f P Soit A k+1 f, alors A u k f et u = aAbA k f. Le lemme ci-dessus nous permet alors d’écrire : f = af1bf2 avec A k1 f1 et Ak2 f2 et k1+k2=k Par hypothèse de récurrence, f1 et f2 P, et donc af1bf2 = f P La proposition suivante est très utile pour construire une grammaire à partir de grammaires plus simples : Proposition 3 : ALG(X*) est fermée par , . et * Preuve : M.M. Département Informatique Décembre 2000 31 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 : si L1 et L2 ALG(X*) alors L1=L(G1) et L2=L(G2). Notons G1= < X, V1,P1, A1>, G2 = <X,V2,P2,A2> On peut supposer sans perte de généralité V1 V2 = . Si ce n’est pas le cas, on renomme les éléments de V2 par exemple. Posons V = V1V2{A} , avec A V1V2 P = P1P2{(A,A1), (A,A2)} G = <X,V,P,A> Il est clair que L(G) = L1L2 Remarque : si L1 et L2 ne sont pas disjoints, G est ambiguë . (produit) : même construction, sauf P = P1P2({A, A1.A2)} * : ici, on part de G = <X, V, P, A > engendrant L ; on contruit G’ engendrant L* de la façon suivante : V’ = V {A’} ; P’ = P { (A’, AA’), (A’, )} En effet, par définition de *, L* ; or L(G’). Si w L* (w ), alors w = w1w2 … wn avec wi L, et donc on a la dérivation suivante : A’ AA’ * w1A’ w1AA’ * w1w2A’ … w1w2 … wn-1A’ w1w2 … wn-1AA’* w1w2…w n-1wnA’ w1w2 … wn-1 wn Donc L* L(G’) Réciproquement, si A’ se dérive directement en un mot de L(G’), alors ce mot est ; sinon, A’ se réécrit AA’ et A se dérive en un mot de L puisque c’est l’axiome de G. Par induction sur la longueur de la dérivation, il vient donc que L(G’) L* Grammaires régulières : Définition 20 : une grammaire algébrique G = < X, V, P,A> est dite régulière ssi pour tout élément (U, m) de P on a m (XV X ) Exercice : quelles sont les grammaires régulières, X = {a,b} G1 : A aAb + G2 : A aB ; B baBb + G3 : A aA + bB + ; B bB + a Seule G3. M.M. Département Informatique Décembre 2000 32 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 Proposition 4 : Si G est une grammaire régulière, alors L(G) est rationnel. Preuve : il suffit d’identifier chaque non terminal à un état d’un automate ; chaque règle, de la forme U1 xU2 peut s’interpréter comme un élément de : (U1, x, U2). Grammaire en forme de Backus-Naur (BNF) Le mot forme ne doit pas ici faire illusion : il s’agit uniquement d’une notation ; commode et surtout très usuelle, cette notation permet de spécifier une grammaire ; reprenons l’exemple de la grammaire E,T,F, soit G = <X,V,P,A>, P = {(E,E+T),(E,T),(T,T*F),(T,F),(F,(E)), (F,id)} On la décrira en notation BNF : <expression> ::= <expression> + <expression> | <terme> <terme> ::= <terme> * <facteur> | <facteur> <facteur> ::= ( <expression> ) | <identificateur> le symbole ::= signifie « se dérive directement en » le symbole | (ou) permet de regrouper les règles issues d’un même non terminal. Les non terminaux sont notés entre chevrons ; ils sont souvent désignés par des symboles assez explicites (expression, ou expr plutôt que E). Les terminaux sont notés tels quels. Compléments sur l’analyse lexicale : On rappelle qu’en informatique la compilation est la traduction d’un texte (dit texte source) en un autre texte (dit texte objet). Cette opération, en particulier dans le cas des langages de programmation, permet de passer d’un programme écrit en langage symbolique proche de l’homme (C++, Pascal, etc…) à un programme équivalent mais « proche » de la machine (et donc exécutable après l’édition des liens). La compilation peut donc se décompose très schématiquement M.M. Département Informatique Décembre 2000 33 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 en deux grandes étapes, l’analyse du code source, et la production de code objet ; l’analyse, elle, comporte, toujours très schématiquement, deux phases qui sont, dans l’ordre chronologique : analyse lexicale, analyse syntaxique. L’analyse lexicale consiste à découper le texte en lexèmes, et pour chaque lexème reconnu à produire une unité lexicale (ou token). Par exemple soit le morceau de programme C++ suivant : moyenne = somme / nbElements ; l’analyse lexicale permet de découper ce texte en 6 lexèmes : moyenne / = / somme / / / nbElements / ; et de produire la chaîne lexicale (suite de tokens) suivante (ou quelque chose d’équivalent) : id affect id oparithm id terminstr L’analyse syntaxique pourra alors reconnaître dans cette chaîne une instruction valide. L’analyse lexicale telle que l’on vient de la décrire peut être réalisée par un automate avec sortie : chaque fois qu’un lexème est reconnu, le token correspondant est produit : NB : en plus, l’analyse lexicale s’efforce de ne pas perdre la trace des symboles ! (ils sont recopiés dans la table des symboles qui sera utilisée ultérieurement). En effet, de même qu’on peut associer des sorties à un automate, on peut plus généralement lui associer des actions (une sortie étant une action de la forme écrire(x)) Mais comme nous l’avons vu, le fait de lui ajouter des sorties ne transforme pas essentiellement un automate et le besoin apparaît d’un outil plus puissant pour mener à bien la phase suivante : l’analyse syntaxique repose sur la notion de grammaire algébrique, et de même qu’à une expression rationnelle on peut associer un automate fini (théorème de Kleene), de même à toute grammaire algébrique on va associer un automate à pile. Automate à pile Introduction. Rappelons-nous qu’un automate sait reconnaître a*b*, mais pas anbn. On dit familièrement qu’un automate ne sait pas compter : il lui manque une mémoire, c’est ce que va lui fournir une pile qu’on va lui associer. M.M. Département Informatique Décembre 2000 34 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 La notion de pile est familière aux informaticiens ; on peut utiliser le cadre de la théorie des langages pour fournir une définition précise de ce qu’est une pile : Définition : soit un mot p sur un alphabet Y ; on dit que p est une pile si on autorise sur ce mot les seules manipulations suivantes : pilevide : Y* {vrai, faux} p pilevide(p) = (p = En particulier, on ne dispose pas de |p| valeursommet: Y+ Y p valeursommet(p) = p(1) p(1) est appelé le sommet de pile. On interdit de faire référence à p(i) i 1 empiler : Y x Y* Y* (y,p) empiler(y, p) = y.p La concaténation est donc limitée à un mot d’une lettre concaténé à gauche de p. Remarque : cette limitation n’est qu’apparente ; en effet soit Y = {y,z} et soit p Y* ; alors empiler(y, empiler(z, empiler (z, p))) = yzzp = up, u=yzz. dépiler: Y+ Y* p dépiler(p) = p’ / |p’| = |p|-1 p’(i) = p(i+1) dépilement : p(1), le sommet de pile, est supprimé. 1 i < |p| Informellement, une pile est la donnée d’un alphabet, et de règles de construction des mots sur cet alphabet. Il existe plusieurs façons de définir un automate à pile. De façon intuitive, un automate (comme ceux que nous avons déjà rencontrés) lit une lettre, et selon son état e et la lettre lue, il passe dans un état e’ ; comme son nom l’indique un automate à pile est un automate mais qui peut « décider » son état suivant en consultant, en plus ou à la place de M.M. Département Informatique Décembre 2000 35 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 la lettre lue, le sommet de pile ; de même, en plus de la transition d’état, il peut effectuer des manipulations de sa pile. Définition 21 : on appelle automate à pile la donnée < X, Y, E,e0, F, > où : X est un alphabet, dit alphabet d’entrée Y est un alphabet dit alphabet de pile E,e0, F sont l’ensemble des états, l’état initial, et l’ensemble des états terminaux est une partie finie de X {} x E x Y { x E x Y* appelée ensemble des règles de l’automate à pile Remarque : les règles de l’automate à pile intègrent les primitives de manipulation de la pile (applications pilevide , valeursommet, empiler, dépiler ). Ainsi, soit (x, e, y, e’, h) ; y est le symbole de sommet de pile, ou le mot vide si la pile est vide, h est le mot éventuellement vide qui va remplacer y en sommet de pile. Définition 21bis : une configuration de l’automate à pile est un élément de X* x E x Y* : un mot restant à lire, l’état courant, la pile. Pour compléter la définition d’un automate à pile, il faut préciser une configuration initiale, et une ou plusieurs configurations d’acceptation. On simplifiera en disant qu’initialement la pile est vide (configuration initiale = (f,e0, )), et l’acceptation se fait par pile vide et état d’acceptation (configuration d’acceptation = (, ef,), où ef F). Il existe d’autres possibilités, et on démontre qu’elles sont équivalentes à celle-ci (très technique). Un automate à pile va nous permettre de reconnaître les langages algébriques : anbn : tant qu’on lit des a, les empiler ; tant qu’on lit des b, dépiler ; le mot est reconnu si on a une pile vide à la fin (pas avant !). plus précisément : X = {a, b} ; Y = {a} ; E = { e0 , e1, e }, F = {e1}. ={ (a, e0, ,e0, a), // config init = (f, e0, ) (a, e0, a ,e0, aa) , // empilement des a M.M. Département Informatique Décembre 2000 36 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 (b, e0, a, e1, ) , // premier b, on change d’état, on veut dépiler tous les a (b, e1, a, e1, ), // on dépile les a // config accept = (, e1, } Exercice : faire tourner l’automate sur aaabbb, puis sur aba. Nous allons préciser un peu ce qui se passe : Définition 21ter : on dit qu’il existe une transition entre c = (xf, e, yp) et c’=(f, e’, hp) ssi (x, e, y, e’, h) . Remarque : x peut être le mot vide. On parle alors d’-transition. Définition 21quater : un mot f X* est reconnu par l’automate à pile A ssi il existe une suite de transitions c1 c’1, c2 c’2 ….cm c’m telle que i, (0<i<m), c’i = ci+1 c1 = (f, e0, ) et c’m = (, ef, ) (ef F) On parlera de même de langage reconnu pour l’ensemble des mots reconnus. Enfin, on admettra la proposition suivante : Proposition 5 : un langage est algébrique ssi il est reconnu par un automate à pile. Prenons un nouvel exemple : X = Y = {a,b} ; E = {e0, e1}, F = { e1 } Configuration initiale (f, e0, ) Acceptation (, e1, ) Pour faciliter les explications, on numérote les règles (éléments de ) ={ // première phase : on empile tout ce qui se présente (a, e0, , e0, a) (1) (b, e0, , e0, b) (2) (a, e0, a, e0, aa) (3) (a, e0, b, e0, ab) (4) (b, e0, a, e0, ba) (5) M.M. Département Informatique Décembre 2000 37 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 (b, e0, b, e0, bb) (6) // on change de politique : (, e0, a, e1, a) (7) (, e0, b, e1, b) (8) (, e0, , e1, ) (9) (a, e0 , a, e1 ,a) (10) (b, e0 , b, e1 ,b) (11) // phase 2 : on tente de reconnaître ~u, on dépile si le sommet = la lettre lue (a, e1, a, e1, ) (12) (b, e1, b, e1, ) (13) } Faisons tourner l’automate sur le mot ab : (ab, e0, ) (1) (b, e0, a) (4) (e0, ba) : échec il serait fastidieux (mais possible : nombre fini de règles et de lettres) de vérifier que l’on ne peut réussir prenons maintenant le mot abaaba On vérifie qu’en appliquant successivement les règles 1, 5, 4, 7, 12, 13, 12 l’automate reconnaît le mot proposé. Essayer avec le mot aba Néanmoins, on aura remarqué une difficulté : comment prévoir le bon moment pour passer dans l’état e1 ? réponse : au hasard ! Cet automate n’est pas déterministe. Sa mise en œuvre effective (algorithme) suppose le backtracking. On essaie jusqu’à trouver un calcul valide ou avoir épuisé sans succès toutes les possibilités. M.M. Département Informatique Décembre 2000 38 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 Schéma de l'algorithme de backtracking : fonction reconnaître(f : mot, e : état, p : pile) : booléen var accepté : booléen ; début Si f = p = e F // on a lu le mot, la pile est vide, l'état est d'acceptation Alors accepté vrai Sinon début accepté faux Tant Que ((il existe une règle non essayée) et (accepté = faux)) // on suppose f = xf', p = yp', et règle = (x, e, y, e', h) faire accepté reconnaître(f', e', hp') retourner accepté fin Or ici on n’a hélas pas la possibilité de déterminiser tout automate à pile, comme c’était le cas pour les automates. En fait, il existe des langages algébriques non déterministes (les palindromes, ou anbp / 0 n p<2n ou encore { anbn} { anb2n.}). On s’intéressera de préférence aux langages déterministes, c’est à dire ceux qui peuvent être reconnus par automate à pile déterministe : Définition 22 : un automate à pile est dit déterministe ssi quelle que soit la configuration, une règle au plus est applicable. Exemple : on a vu anbn. Prenons les mots de parenthèses : tant qu’on n’a pas fini de lire le mot, quand on lit un a on l’empile, un b on dépile ; la pile doit être vide à la fin (pas avant). Plus précisément : X = {a, b} ; Y = {b} ; E = {e0} Conf. Init = (f, e0 , ) , accept = (, e0 , ) = { (a, e0 , , e0 , a), (a, e0 , a, e0 , aa), (b, e0 , a , e0 , )} Enfin, de même que les langages rationnels débouchent sur l'analyse lexicale, de même les langages algébriques autorisent la mise en œuvre de techniques puissantes (algorithmes) d'analyse syntaxique. On évoquera l'analyse descendante LL et l'analyse ascendante LR. On se contentera cependant d'un aperçu schématique, car ces notions peuvent facilement conduire à des considérations fort techniques. M.M. Département Informatique Décembre 2000 39 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 Grammaires LL(1) LL signifie Left to right scanning Leftmost derivation. Le 1 signifie 1 seul symbole d'entrée. Les grammaires LL(1) autorisent une analyse descendante (en quelque sorte on part de la racine et on construit l'arbre de dérivation) en par la seule connaissance d'un seul symbole d'entrée, et du non terminal à dériver. Exemple de grammaire LL(1): (1) E T E' (2) E' + T E' | (3) T F T' (4) T' * F T' | (5) F ( E ) | id Soit l'expression (id + id) * id ; au départ, on cherche à dériver E. Pile Mot Dérivation E id*id+id TE' id*id+id E TE' FT'E' id*id+id T FT' idT'E' id*id+id F id T'E' *id+id *FT'E' *id+id T' *FT' FT'E' id+id idT'E' id+id F id T'E' +id E' +id T' +TE' +id E' +TE' TE' id FT'E' id T FT' idT'E' id F id T'E' E' T' E' On voit que c'est toujours le non terminal le plus à gauche qui est dérivé, de même la chaîne est parcourue de gauche à droite. M.M. Département Informatique Décembre 2000 40 I.U.T. Bordeaux I Cours de mathématiques 1° année : Théorie des langages version du 16/04/17 Grammaires LR Left to right scanning Rightmost derivation. Ces grammaires permettent une analyse ascendante : on part des feuilles pour construire l'arbre de dérivation en dérivant à chaque fois le non terminal le plus à droite. Très utilisé par les constructeurs automatiques d'analyseurs syntaxiques (Yacc , yet another compiler of compilers). Mais assez technique à mettre en œuvre. M.M. Département Informatique Décembre 2000 41 I.U.T. Bordeaux I