Module GIM23S04
Théorie des langages et compilation
Redouane Ezzahir
r.ezzahir@uiz.ac.ma
2014/2015
mis-à-jours 2020
TD N° 1 3
TD N° 2 5
TD N° 3 7
TP N° 1 : Expressions régulières 8
TP N° 2 : Automates 13
Correction TD N° 1 19
Correction TD N° 2 22
Correction TD N° 3 28
Correction TP N° 2 : Automates 36
TD N° 1
Exercice 1
Exercice 2
1. Montrer que V n con=ent |V |n éléments (on pourra u=liser la conven=on 00 = 1).
Exercice 3
2. Montrer que toute chaîne sur {a, b}, de longueur supérieure ou égale à 4, admet deux
occurrences consécu=ves d’une même sous-chaîne non vide.
Exercice 4
Remarque Il ne faut pas confondre le langage vide ∅,qui ne con=ent aucun mot, avec le langage
{ε}, qui con=ent le mot vide ε. Le premier est l’élément absorbant et le second est l’élément neutre
de la concaténa=on des langages.
Exercice 5
1. Montrer que les égalités suivantes sont vraies pour tout langage L :
• (L∗)∗ = L∗
• (ε+L)∗=L∗
• L .L = L
2. Montrer que, pour tout langage L, M, N et P, si L⊂M et N⊂P ,alors L∗⊂M∗et L.N ⊂ M.P
(en d’autres termes, l’étoile et la concaténation sont des opérations croissantes.)
3. Montrer que les égalités suivantes sont vraies pour tous langages L et M
— (L .M ) =(L+M)
— (L.M)∗L = L.(M.L)∗
— (L.M+L) .L=L.(M.L+L)*
Montrer que l’égalité suivante nést pas valide : (L + M)∗ = L∗ + M∗
4. Soit V={0,1}. Donner les définitions des langages suivants en seservant des opérations
de concaténation, d’union et de l’étoile :
• (a) L'ensemble des chaînes sur V contenant au moins une occurrence de 0.
Ex. 1 — Démontrez, à l’aide de la définition inductive des langages réguliers, que les deux
langages suivants sont réguliers (l’alphabet considéré est ⌃ = {0, 1}):
1. L’ensemble des mots composés d’un nombre arbitraire de 1, suivis de 01, suivis d’un
nombre arbitraire de 0.
2. L’ensemble des nombres binaires impairs.
Ex. 6 — Donnez une expression régulière (définis sur l’alphabet = {0, 1}) qui accepte chacun
des langages suivants :
1.Toutes les chaînes qui se terminent par 00.
2.Toutes les chaînes dont le 10ème symbole, compté à partir de la fin de la chaîne, est un 1.
3.Ensemble de toutes les chaînes dans lesquelles chaque paire de 0 apparaît devant une paire
de 1.
4.Ensemble de toutes les chaînes ne contenant pas 101.
5.Tous les nombres binaires divisibles par 4
automate 1 automate 2
1
Ex. 8 — Construire un automate reconnaissant l’expression rationnelle (a+b)*aa(a+b)*, le
déterminiser si nécessaire.
Ex. 9 — Determiniser et minimiser l’automate suivant :
Ex. 10 — Donner, pour chacun des langages suivants, un automate qui le reconnaît.
•L1 = { a*bb*}, L2 = { aa*bb*}
•L3 = { mots dans {a,b}* commençant par n b, n > = 0, finissant par un nombre pair de a}
•L4 = { mots dans {a,b}* commençant par ab et finissant par bb}
•L5 = { mots engendres par aa*bb* de longueur impaire}
•L6 = { mots dans {a,b}* n’ayant pas aa comme facteur}
•L7 = { mots dans {a,b}* de longueur paire} L8 = { mots dans {0,1}* dont l’écriture en
base 2 est un multiple de 3}
2
TD N° 3
Université Ibn Zohr Compilation TD N°2 2019/2020
ENSA Agadir R. EZZAHIR
I) Grammaire de réécriture
Soit G = {{a, b, c}, {S, A, B}, S, P} la grammaire définie par les regles suivantes :
S → aAbc A → aABbc A→ a B → bc
Questions :
1. Donner les dérivations gauches des quatre chaines les plus courtes du langage engendré par
la grammaire G.
2. Donner la forme des chaines de ce langage.
3. Démontrer la forme précédente par récurrence sur les chaines générées par A.
Soit l'automate
1. Dire pourquoi A n’est pas déterministe. Donner, sans justification, une expression réguliere
équivalente.
2. Déterminiser A et représenter le graphe de l’automate déterministe D obtenu.
3. Minimiser l’automate D apres l’avoir éventuellement complété. Dessiner l’automate obtenu.
4. Minimiser l’automate suivant
TP N° 1 : Expressions régulières
1. Rappel
Les expressions régulières sont des suites de caractères permettant de faire des sélections. Elles fonctionnent
avec certaines commandes comme grep.
. un caractère quelconque
$ fin de ligne
x* zéro ou plus d’occurrences du caractère x
x+ une ou plus occurrences du caractère x
x? une occurrence unique du caractère x
[...] plage de caractères permis
[^...] plage de caractères interdits
\ {n\} pour définir le nombre de répétition n du caractère placé devant
Exemple déxpression [a-z][a-z] * cherche les lignes contenant au minimum un caractère en minuscule. [a-z]
caractère permis, [a-z]* recherche d’occurrence des lettres permises.
Léxpression ^[0-9]\ {4\}$ a pour signification, du début à la fin du fichier $, recherche les nombres[0-9] de 4
chiffres \ {4\}.
Depuis la version 1.4, Java dispose d’un moteur déxpressions régulières puissant et très complet. Cést un moteur
basé sur un automate fini non déterministe, et il est donc possible pour certaines expressions régulières de
requérir un très long temps de traitement même si le moteur déxpressions régulières de Java est très rapide en
général. De plus, il supporte les quantificateurs avides, paresseux et possessifs et la plupart des autres fonctions
dont nous avons discuté jusqu’à présent.
- Pattern : elle représente un motif défini par une expression régulière ; la documentation de la classe en question
comprend un rappel très utile sur les expressions régulières.
Les classes qui nous concernent sont dans le paquetage java.util.regex. Les deux principales classes sont : -
Matcher : cette classe permet de visiter les différentes occurrences des motifs.
1.2.1 Programmation de base avec les expressions régulières
La classe « java.lang.String » en Java contient déjà un support assez avancé pour les expressions régulières. On
peut ainsi vérifier la concordance d’un motif, séparer une chaîne de caractères en sous-chaînes en utilisant des
motifs et, finalement, utiliser la fonction rechercher/remplacer.
Étant donné une chaîne de caractères en Java, la méthode « matches » permet de vérifier si elle correspond à une
expression régulière. Dans cet exemple, la variable « test » prendra la valeur « vrai ».
On peut aussi séparer une chaîne de caractères en sous-chaînes dans lesquelles les points de segmentation sont
déterminés par une expression régulière. Dans léxemple suivant, la variable « résultat » aura pour valeur ("La
vie est belle", "Jean", "il ne m’aime pas").
String s = "La vie est belle. Jean, il ne m’aime pas."; String[] resultat =
s.split(",|\\.");
Finalement, la fonction rechercher/remplacer avec des expressions régulières fait appel à la méthode «
replaceAll ». Pour remplacer les chiffres par des « X » dans une chaîne de caractères, on procède ainsi :
Notez qu’un objet String, en Java, est immuable : la méthode « replaceAll » ne modifie donc pas l’objet, mais
présente plutôt une version modifiée de l’objet.
Dans notre cas, la réponse est négative parce que notre chaîne nést pas une lettre répétée plusieurs fois. Tester la
présence du motif
Une fois un objet « Matcher » obtenu, on peut tester si le motif se trouve dans la chaîne de caractères avec la
méthode « find ».
if(trouve){
System.out.println("chaine corespond au motif est trouve");
String texte = matcher.group();
System.out.println("Trouvé \""+texte );
}
Dans notre cas, la réponse serait positive parce qu’il y a la lettre « l » répétée dans notre chaîne. La méthode «
find() » a aussi comme effet de trouver la prochaine occurrence du motif dans la chaîne. On peut ensuite aller
chercher la position et la nature du motif avec les méthodes « group », « start » et « end » :
Pour repérer toutes les occurrences, il suffit d’écrire une boucle comme ceci :
while (matcher.find()) {
texte = matcher.group();
debut = matcher.start();
fin = matcher.end();
System.out.println("Trouvé \""+texte+"\"à la position "+debut);
} }
La fonction recherche/remplace
Supposons que l’on veuille remplacer toutes les lettres répétées par le symbole « * ». Ce résultat est aisément
obtenu avec
la méthode « replaceAll » : matcher.replaceAll("*").La seule mise en garde est que si on tente de remplacer un
texte qui contient le symbole du dollar, il faut l’indiquer comme ceci : « \$ ».
Supposons que l’on veuille remplacer toutes les lettres répétées par une seule occurrence de la même lettre, de
sorte que « belle » devienne « bele » ; on peut obtenir ce résultat avec la méthode « replaceAll ». Il faut alors
utiliser les parenthèses de capture et la convention selon laquelle « $1 » fait référence à la première parenthèse
de capture rencontrée et ainsi de suite.
pattern = Pattern.compile("(l)+");
matcher = pattern.matcher("La vie est belle");
résultat = matcher.replaceAll( "$1" );
System.out.println("replaceAll $1 Donne : "+résultat);
Pour tester les limites du traitement des expressions régulières en Java, vous pouvez essayer léxemple suivant :
Pour trouver toutes les lignes dans le fichier toto.txt qui contiennent deux guillemets, il suffit de faire :
Pour traiter un ensemble de fichiers dans le répertoire courant, on peut aussi utiliser l’astérisque :
Finalement, il est toujours possible de rediriger le résultat vers un fichier qu’on pourra ouvrir plus tard avec un
éditeur de texte comme Bloc-notes, comme ceci :
Le but de cet exercice est d'apprendre à manipuler les automates. Les automates sont principalement utilisés
pour l'analyse lexicale, et servent à représenter/implementer les expression régulières. Nous allons écrire deux
classes au cours de ce TD : State et Automaton.
Les états sont codés par la classe State. L'état poubelle est représenté par l'objet null.
Un état contient l'ensemble des états vers lequel mène une epsilon transition.
En plus un état contient la table de transition. Cést une table dont les indices sont des caractères, et les entrées
les états destinations.
Les ensembles d'états sont codés par un arbre AVL.
La classe Automaton réalise un automate fini non-déterministe à epsilon transitions. Elle contient l'ensemble de
ses états, l'état initial et l'ensemble des états finaux.
On va représenter les ensembles d'états par des arbres AVL. La classe TreeSet réalise un ensemble d'objets par
des arbres AVL. Nous auront besoin des méthodes suivantes
QUESTION 1 - STATE
Pour que la classe TreeSet sache comparer les états il faut une méthode compareTo à la classe State. L'appel à
s.compareTo(t) doit retourner un entier <0, l'entier 0 ou un entier >0 suivant que s<t, s=t ou s>t. On va
tout simplement utiliser l'ordre sur les identifiant et donc retourner id-t.id.
Pour que la classe TreeSet sache que State est munie d'une méthode compareTo, il faut déclarer que State
implémente l'interface Comparable<State>.
Écrivez maintenant la classe State qui représente les états. Munissez la des attributs/méthodes suivants : (pensez
à importer java.util.* pour TreeSet)
Pour la méthode epsilon_closure notez qu'on ne peut pas modifier en Java l'ensemble qu'on est en train de
parcourir. Une solution serait alors de produire en une itération intérieure l'ensemble des états à ajouter à set.
Puis l'itération extérieure prendra fin quand cet ensemble sera enfin vide.
Testez en avec cette méthode.
0->1
1->2
2->0
2-x->3
cloture(1) = 0 1 2
QUESTION 2 - AUTOMATON
Ecrivez la classe Automaton avec les attributs, méthodes suivants : (La méthode dump a besoin qu'on importe
java.io.*. )
static Automaton new_WORD(String word) // crée un automate qui reconnait un mot donné et rien d'autre
Ajoutez la méthode d'affichage suivante, qui écrit l'automate dans un fichier dont le
nom sera tmp??.dot où ?? est l'entier qui est passé en paramètre à dump.
/** affiche l'automate comme un graphe en notation DOT
... enfin retourne une chaine qui correspond a l'affichage plutot
*/
public void dump(String word, int i, Set<State> marked) {
try {
PrintWriter out = new PrintWriter(String.format("tmp%02d.dot",i));
String label="";
if (word!=null) {
label=" label=\"";
for (int j=0; j<=word.length(); j++) {
if (j==i)
label+='>';
else
label+=' ';
if (j<word.length())
label+=word.charAt(j);
}
label += "\";\n";
}
// imprimer tout ce qui est spécifique au graphe
out.println("digraph {\n"+
" rankdir=LR;\n"+
label+
" init [shape=point];\n"+
" init->"+initial.id+";\n" );
// imprimer les états
for (State s: states) {
out.print(" "+s.id+" [");
if (accept.contains(s))
out.print("shape=doublecircle");
else
out.print("shape=circle");
if (marked!=null && marked.contains(s))
out.print(",style=filled");
out.println("];");
}
out.println();
// imprimer les epsilon transitions
for (State s: states)
for (State n: s.epsilon)
out.println(" "+s.id+"->"+n.id+";");
out.println();
// imprimer les autres transitions
for (State s: states) {
char c1 = 0;
State n1 = null;
for (char c2=0; c2<=256; c2++) {
State n2 = (c2<256) ? s.transition[c2] : null;
if (n1!=n2) {
if (n1!=null) {
if (c1==0 && c2==256)
label = "\"?\"";
else if (c1==c2-1)
label = "\""+c1+"\"";
else
label = "\""+c1+"-"+(c2-1)+"\"";
out.println(" "+s.id+"->"+n1.id+"[label="+label+"];");
}
c1 = c2;
n1 = n2;
}
}
}
out.println("}");
out.close();
}
catch (FileNotFoundException e) {
throw new Error("fichier tmp??.dot n'a pas pu ^etre crée");
}
}
Testez avec ce code qui produit un fichier tmp00.dot.
Puis dans une commande shell visualisez le résultat avec la commande dot -Tgif -o
tmp00.gif tmp00.dot && xv tmp00.gif
static Automaton new_OR(Automaton a1, Automaton a2) // crée un automate qui reconnait
l'union des languages rec. par a1 et a2
static Automaton new_SEQ(Automaton a1, Automaton a2) // crée un automate qui reconnait
la concaténation des languages
java Automaton
matches : false
matches a : false
matches ab : false
matches ac : false
matches abc : true
matches acb : false
matches adc : true
matches abcd : true
matches abcde : false
matches abcdef : true
matches abcdefe : false
matches abcdefef : true
QUESTION 5 - GÉNÉRER UNE ANIMATION DE L'AUTOMATE
Maintenant à chaque itération appelez dump(word, i, current), où i et l'indice du
caractère traité dans word. Appelez une dernière fois après la boucle dump(word,
word.length(), current). De cette manière votre programme va générer différents
fichiers qui représentent le parcours de l'automate.
#!/bin/bash
for f in tmp??.dot; do
dot -Tgif -o$f.gif $f
done
convert -loop -1 -delay 180 tmp??.dot.gif g.gif rm tmp??.dot.gif tmp??.dot
xv g.gif
• # autre visualiseur:
• # firefox g.gif #
• # sous MacOS
• # open g.gif
vous permet de transformer les fichiers produits par le programme en une image GIF
animée. On léxécute avec bash make_image. Vous devriez avoir le résultat suivant.
(Cést cool, non ?)
Correction TD N° 1
Exercice 1
Montrons maintenant que si ρ∪σ = E ×E, alors ρ implique σ. Ceci est évident : si (x,y) ∈ ρ,
alors par définition (x, y) ∈/ ρ et donc, nécessairement (x, y) ∈ σ, d’où le résultat.
Exercice 2
Soit V un vocabulaire non vide. Nous allons montrer la propriété par induction sur n.
n+1 n
V = {w1…wn+1|∀i wi ∈V} = {wwn+1|w ∈ V , wn+1 ∈ V}
∀n∈N,#(Vn)=(#V)n
Exercice 3
Remarquons tout d’abord que ∀i ∈ {0...n} il existe toujours au moins une sous- chaine/un
préfixe/un suffixe de longueur i. De plus en notant a un élément de V , la chaine w = a . . .
a contient exactement une sous-chaine/un préfixe/un suffixe de longueur i, ∀i. On en
déduit que :
Exercice 4
1. Soit L ∈ P(V∗)
∅.L= {w∈V∗|w=uv,u∈∅,v∈L}=∅ car il n'existe aucun u tel que u ∈∅ De meme, on
montre que L.∅ = ∅
2. Si V = ∅ on a :
Exercice 5
on a
L.{Lk |k ≤ n} = {Lk |k ≤ (n+1)} ⊂ L1 soit P(n+1).
Par principe de récurrence, L∗ ⊂ L1, ce qui achève la démonstration.
3.
— (L∗)∗ = ⋃n≥0(L∗)n d’où en particulier L∗ ⊂ (L∗)∗ (n=1).
Soit w∈(L∗)n Alors w=w1w2…wn tq ∀i wi ∈ L .
Par définition on a
∀wi∃ni, tq w=v(i,1)...v(i,ni) et ∀jvj ∈L.
(∑nn) ∗ Alors w = v(1,1) ...v(1,n1) …v(n,1) v(n, nn) ∈ L (∑ i=1 ni )⊂ L* .
on a trivialement L* ⊂ (L+ε)* .
ou bien w= ε ∈ L0 ⊂ L* .
4. à faire
5. à faire
6. (a) Avec L = ∅ , et M != ∅ l’équation se réécrit ∅ = M (∅ élément absorbant) qui n’as
pas de solution.
(b) Soit L et M deux languages. On pose X0 = L∗M.
1- les dérivations gauches des quatre chaines les plus courtes du langage
engendré par la grammaire G :
1.1. S aAbc aabc a2bc
1.2. S aAbc aaABbcbc aaaBbcbc aaabcbcbc a3(bc)3
1.3. S aAbc aaABbcbc aaaABbcBbcbc aaaaBbcBbcbc aaaabcbcBbcbc
aaaabcbcbcbcbc a4(bc)5
1.4. S aAbc aaABbc aaaABbcBbcbc aaaaABbcBbcBbcbc
aaaaaBbcBbcBbcbc aaaaabcbcBbcBbcbc aaaaabcbcbcbcBbcbc
aaaaabcbcbcbcbcbcbc a5(bc)7
2- la forme des chaines de ce langage : an(bc)2n-3.
3- Démontrer la forme précédente par récurrence sur les chaines générées par
A:
Pour n 2 , la forme est vraie. On suppose que la forme an(bc)2n-3 est vraie pour toute n 2
, et on montre an+1(bc)2(n+1)-3 = an+1(bc)2n-1
S aAbc aa ABbcbc aaaABbcBbcbc aaaaABbcBbcBbcbc
aaaaaABbcBbcBbcBbcbc aaaaaabcbcbcbcbcbcbcbcbc
...
an-1A(Bbc)n-2 bc
an-1 aABbc (Bbc)n-2 bc
an+1(bc)2n-1
II. Automate FN et Expression régulière:
S3 S2 ∅ ∅ S3
S4 ∅ ∅ S0 {S0, S4 }
Déterminisation :
a b
S0 {S1, S2} ∅
{S1, S2} {S0, S4 } { S0 , S3, S4 }
{ S 0 , S4 } {S1, S2} ∅
{ S0 , S3, S4 } {S1, S2} S0
Représentation de l a oma e :
1- Di e po oi A n e pa d e mini e.
Donner, sans justification, une expression régulière équivalente :
- A n e pa déterministe car on a pour un mot w deux transitions possibles
pa i de l état q0.
Par exemple : à partir de q0 pour la transition 1 on peut passer à q1 ou
e e l a 0.
- ER(A) : (0|1)*101(0|1)*.
2- Déterminiser A et représenter le graphe de l a oma e d e mini e D ob en :
Soit le table de transition :
Etat/transition 0 1
q0 q0 { q0 , q1 }
q1 q2
q2 q3
q3 q3 q3
Soi le no ea ablea po d e mini e l a oma e :
0 1
{ q0 } { q0 } { q0 , q1 }
{ q0 , q1 } { q0 , q2 } { q0 , q1 }
{ q0 , q2 } { q0 } { q0 , q1, q3 }
{ q0 , q1, q3 } { q0 , q2 , q3 } { q0 , q1, q3 }
{ q0 , q2, q3 } { q0 , q3 } { q0 , q1, q3 }
{ q0 , q3 } { q0 , q3 } { q0 , q1, q3 }
4- Minimi e l a oma e i an :
1
2 X
3 X X
4 X X X
5 X X X
6 X X X X X
E X X X X X X
1 2 3 4 5 6 E
package regex;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
//**************************************//
//********** teste 1 *******************//
String s = "La vie";
boolean test = s.matches("La.*");
if(test)
System.out.println("l'ER: La.* match (filtre ou correspond)
bien a : "+ s);
//*************************************//
System.out.println();
//********** teste 2 ************************//
s = "La vie est belle. Jean, il ne m’aime pas.";
String[] resultat = s.split(",|\\.");
System.out.println("Le découpage de la chaine : \""+ s +
"\" \nEn utlisant l'ER (,|\\.) comme filtre du
séparateur est :\n"+
Arrays.toString(resultat).replace(',', '\n'));
//********** teste 3 ***********************/
System.out.println();
s = "Mon numéro de carte de crédit est le 4243243243.";
String résultat = s.replaceAll("\\d","X");
System.out.println("Remplacement les chiffres par X dans la chaine :
\n"+s);
System.out.println("Donne : "+résultat);
System.out.println();
//**************************************************************
// Package Regex de java
//*************************************************************
// compiler l’expression régulière pour en faire un objet Java
Pattern pattern = Pattern.compile("(\\w*\\s*)*");
//Appliquer l’expression à une chaîne de caractères
Matcher matcher = pattern.matcher("La vie est belle");
boolean correspond = matcher.matches();
if(correspond)
System.out.println("Regex1: match (filtre ou correspond) bien
a \"La vie est belle\"" );
else
System.out.println("Regex1: ne match (filtre ou correspond)
pas \"La vie est belle\""+
"essayez avec (\\w*\\s*)*");
System.out.println();
//
***************************************************************************//
pattern = Pattern.compile("\\w+");
matcher = pattern.matcher("La vie est belle");
boolean trouve = matcher.find();
if(trouve){
System.out.println("chaine corespond au motif est trouve");
String texte = matcher.group();
System.out.println("Trouvé \""+texte );
}
//
**************************************************************************//
System.out.println();
while (matcher.find()) {
String texte = matcher.group();
int debut = matcher.start();
int fin = matcher.end();
System.out.println("Trouvé \""+texte+"\"à la position "+debut+
" fin="+fin);
}
//
****************************************************************************
/*
* Supposons que l’on veuille remplacer toutes les lettres répétées,
par
* une seule occurrence de la même lettre, de sorte que « belle »
devienne « bele » ;
* on peut obtenir ce résultat avec la méthode « replaceAll ».
* Il faut alors utiliser les parenthèses de capture et la
convention selon
* laquelle « $1 » fait référence à la première parenthèse
* de capture rencontrée et ainsi de suite.
*/
/* notons la parenthèse capturante */
pattern = Pattern.compile("(l)+");
matcher = pattern.matcher("La vie est belle");
// le $1 fait référence à la première lettre
résultat = matcher.replaceAll( "$1" );
System.out.println();
System.out.println("====================adresse IP
==========================");
pattern = Pattern.compile("\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\
\d{1,3}\\b");
matcher = pattern.matcher("192.21.45.36");
correspond = matcher.matches();
if(correspond)
System.out.println("IP 192.21.45.36 ok");
matcher = pattern.matcher("999.999.999.999");
correspond = matcher.matches();
if(correspond) {
System.out.println("Mais l'adrsse non IP : 999.999.999.999 est
aussi filtré");
}
System.out.println();
System.out.println("====================limite de regex
==========================");
//
***************************************************************************//
System.out.println("ctrl + chift + c pour décommeter les lignes
suivantes:");
// pattern = Pattern.compile("^(\\s*foo\\s*)*$"); ;
// String foo = "foo foo foo foo foo"+
// " foo foo foo foo foo foo foo foo foo foo foo"+
// " foo foo foo foo foo foo foo foo foo fo";
// matcher = pattern.matcher(foo);
// correspond = matcher.matches();
// if(correspond) {
// System.out.println("ok");
// }
//
}
}
Solution: 1.1 et 1.3
package regex;
/** *************
* Utilisation:
*
* java Regex monexpression mesfichiers
*
* par exemple:
*
* java Regex '".*"' toto.txt
*
* donne tout texte entre parantheses dans le fichier toto.txt. Le
* traitement se fait ligne par ligne. Pour avoir le texte sans les
* parantheses, faire
*
* java Regex '"(.*)"' toto.txt
*
* Pour avoir plus d'information, vous pouvez utiliser le drapeau "-v"
* comme ceci :
*
* java Regex -v '".*"' toto.txt
*
**/
import java.util.Arrays;
import java.util.regex.*;
import java.io.*;
package automates;
import java.util.HashMap;
import java.util.TreeSet;
int id;
private boolean visited;
public State(){
this.id = nbState++;
this.epsilon =new TreeSet<>();
this.transition = new HashMap<>();
}
package automates;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;
import java.util.Map.Entry;
a.accept.addAll(a1.accept);
a.accept.addAll(a2.accept);
a.states.addAll(a1.states);
a.states.addAll(a2.states);
return a;
}
// cr'ee un automate qui reconnait la concaténation des languages
static Automaton new_SEQ(Automaton a1, Automaton a2) {
Automaton a = new Automaton(a1);
for(State s: a.accept){
s.addTransition(a2.initial);
}
a.states.addAll(a2.states);
a.accept.clear();
a.accept.addAll(a2.accept);
return a;
}
while(!E.isEmpty()){
TreeSet<State> e = E.remove(0);
for(Character c: this.getAlphabet()){
TreeSet<State> tr = transition(e, c);
if(tr.isEmpty()) continue;
State.epsilon_closure(tr);
E.add(tr);
if(map1.containsKey(tr)){
map1.put(tr, new State());
map2.put(map1.get(tr), tr);
a.states.add(map1.get(tr));
}
map1.get(e).addTransition(c, map1.get(tr));
}
for(State s: a.states){
TreeSet<State> sss = new TreeSet<>();
sss.addAll(map2.get(s));
State.epsilon_closure(sss);
for(State ss: sss){
if(this.accept.contains(ss)){
a.accept.add(s);
break;
}
}
}
return a;
}
return this;
}
for(TreeSet<State> k: map.values()) {
if(k.contains(initial)){
map2.put(a.initial, k);
}
else{
map2.put(new State(), k);
}
}
for(State s: map2.keySet()){
TreeSet<State> sv = map2.get(s);
for(State ss: map2.keySet()){
TreeSet<State> ssv = map2.get(s);
for(State e: sv){
for(State ee : ssv ){
for(Character c: e.transition.keySet()){
if(e.transition.get(c).contains(ee)){
s.addTransition(c, ss);
}
}
}
}
}
}
a.states = new TreeSet<>(map2.keySet());
for( State s: a.states){
for(State ss: map2.get(s)){
if(accept.contains(ss))
a.accept.add(s);
}
}
return a;
}
bonjour.dump(null, 8, null);
Automaton a,b,c;
//
// //==========================================================
a = new_OR(new_WORD("JAVA"), new_WORD("KOTLIN"));
b = new_SEQ(new_WORD("Etude"), new_WORD(" A
ENSA"));
c = new_STAR(new_WORD("ENSA"));
//
a.dump(null, 0, null);
b.dump(null, 1, null);
c.dump(null, 2, null);
// //
//
//===========================================================
a = new_SEQ(new_CHAR('a'),
new_OR( new_SEQ(new_WILD(), new_CHAR('c')),
new_SEQ(new_WORD("bcd"),
new_STAR(new_WORD("ef")))));
a.dump(null, 5, null);
for(String s: strings) {
System.out.println("matches " + s + " : " + a.matches(s));
}
out.println();
// imprimer les epsilon transitions
for (State s: states)
for (State n: s.epsilon)
out.println(" "+s.id+"->"+n.id+";");
out.println();
// imprimer les autres transitions
for (State s: states) {
char c1 = 0;
State n1 = null;
if(setn2==null)
setn2=nn ;
for(State n2 : setn2){
if(setn2==nn) n2=null;
if (n1!=n2) {
if (n1!=null) {
if (c1==0 && c2==256)
label = "\"?\"";
else if (c1==c2-1)
label = "\""+c1+"\"";
else
label = "\""+c1+"-"+
(c2-1)+"\"";
out.println(" "+s.id+"-
>"+n1.id+"[label="+label+"];");
}
c1 = c2;
n1 = n2;
}
}
}
}
out.println("}");
out.close();
}
catch (FileNotFoundException e) {
throw new Error("fichier tmp??.dot n'a pas pu ^etre cr'ee");
}
try {
Process p = Runtime.getRuntime().exec("dot -Tgif -o
"+file+".gif "+file+".dot ");
p.waitFor();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
class Pair<E>{
TreeSet<E> p = new TreeSet<>();
Pair(E a, E b){
p.add(a);
p.add(b);
}
@Override
public int hashCode() {
return p.hashCode();
}
@Override
public boolean equals(Object obj) {
return p.equals( ((Pair<E>)obj).p);
}
}
}