de type 3
1. Automate pour les grammaires de type 3
1. Automates pour les grammaires de type 3
1.1 Automates d’états finis déterministes ou non
C’est un Quintuplet A = (VT,E,q0,F,µ)où : VT : vocabulaire terminal de A. E : ensemble des états de A ; E = {q0,q1,...,qn } q0 Î E est dénommé état initial de A. F Ì E : F est l’ensemble des états finaux de A. µ : E x VT ¾®E , une fonction de transition de A. |
Définition
Un automate A, A = (VT,E,q0,F,µ), est dit déterministe, si sa fonction de transition µ est une vraie fonction au sens mathématique. Ce qui revient à dire qu’un couple de E x VT n’a qu’une seule image par µ dans E. |
Intérêt de la notion d’automate :
Comme pour les automates à pile, c'est la fonction de transition qui est l’élément central de l’automate A. Elle doit être définie de manière à permettre d’analyser un mot de VT*, et aussi de décider de l’appartenance ou non d’un mot à un certain langage. Ce langage d’appartenance est appelé le langage reconnu par l’automate.
Exemple : Soit un automate possédant parmi
ses règles, les trois suivantes
( qi , aj ) ¾®qk1
( qi , aj ) ¾®qk2
................
( qi , aj ) ¾®qkn
Il existe trois règles
ayant la même partie gauche ( qi , aj ), ce qui revient à dire
que le couple ( qi , aj ) a trois images distinctes, donc l'automate est non
déterministe.
Par la suite, pour des raisons de simplification pratique, nous considérerons les Automates d’Etats Finis normalisés que nous nommerons AEF, en posant :
F = { qf } un seul
état final
VT = VT È{ # } on ajoute dans VT un symbole terminal de fin
de mot #, le même pour
tous les AEF.
1.2 Algorithme de fonctionnement d’un AEF
Nous construisons notre
AEF comme étant un dispositif physique muni :
L’algorithme de fonctionnement d'un AEF :
L'algorithme est très semblable à celui d'un automate à
pile (en fait on peut considérer qu'il s'agit d'un cas particulier
d'automate à pile dans lequel on n'effectue jamais d'action dans la
pile), on fournit un mot que l’on écrit symbole par symbole de gauche
à droite dans chaque case de l’automate (par exemple avec VT ={a,b} le mot aaaaabbbbb):
- La tête de lecture se déplace par examen des règles de transition de. Le couple (aj, qi) enclenche le processus de recherche d’une transition possible dans la partie gauche de la liste des règles de transitions de µ (il y a recherche de la transition µ : (aj , qi ) ¾® ......).Supposons que la case contienne le symbole aj que la tête soit à l’état qi :
- La transition ( qi , aj ) ¾® qk signifie que l’automate peut passer de l’état qi à l’état qk à condition que le mot d’entrée débute par la chaîne préfixe aj élément de VT* (notons que la chaîne aj peut être réduite par sa définition à un seul élément de VT , ce qui est généralement le cas pratique. Le résultat de la transition fait que le symbole aj est lu et donc reconnu, que la tête d'entrée pointe vers le symbole suivant de la bande d'entrée :
- Le mot est reconnu si l’automate rencontre une règle de transition de la forme ( qi , aj ) ¾® qf ou bien (qi , # ) ¾® qf où qf est un état final. L'automate s’arrête alors.
- Si l’AEF ne trouve pas de règle de transition commençant par ( qj , ai ), c’est à dire que le couple ( qj , ai ) n’a pas d’image par la fonction de transition µ, on dit alors que l’automate bloque : le mot n’est pas reconnu comme appartenant au langage.
1.3 Utilisation d’un AEF en reconnaissance de mots
G1 : VN
= {S,A}
VT = {a,b}
Axiome : S
Règles
1 : S ¾® aS
2 : S ¾®aA
3 : A ¾®bA
4 : A ¾®b
Soit l’automate A1
: ( A1 est non déterministe )
VT = {a,b}
E = {q0,q1,qf
}
µ : ( q0, a
) ¾® q0
µ : ( q0, a
) ¾® q1
µ : ( q1, b
) ¾® q1
µ : ( q1, b
) ¾® qf
Fonctionnement pratique de cet AEF sur le mot a3b2 (aaabb) :
( q1, b ) ¾®4 qf règle 4 Þ l’AEF s’arrête, le mot aaabb est reconnu ! |
Vous remarquerez que dans le cas de cet AEF, il nous a fallu aller " voir " un symbole plus loin, afin de déterminer la bonne règle de transition pour mener jusqu’au bout l’analyse.
On peut montrer que tout AEF non déterministe peut se ramener à un AEF déterministe équivalent. C’est pourquoi nous ne considérerons par la suite que les AEF déterministes (notés AEFD).
Voici à titre d’exemple un AEFD équivalent à l’AEF A1 précédent :
AEFD A2 reconnaissant le langage { anbp / (n ³ 1) et (p ³ 1) }
VT = {a,b,#}
E = {q0,q1,
q2,qf }
µ : ( q0, a
) ¾® q1
µ : ( q2, b
) ¾® q2
µ : ( q1, a
) ¾® q1
µ : ( q2, #
) ¾® qf
µ : ( q1, b
) ¾® q2
Voici la reconnaissance automatique du mot a3b2 par cet automate :
( q0, a ) ¾® q1
( q1, a ) ¾® q1
( q1, a ) ¾® q1
( q1, b ) ¾® q2
( q2, b ) ¾® q2
( q2, # ) ¾® qf
mot reconnu !
1.4 Graphe d’un automate déterministe ou non
C’est un graphe orienté, représentant la suite des transitions de l’automate comme suit :
(qj,ai) ¾® qk est représentée par l’arc
à 2 sommets :
Exemples de graphe des deux
AEF précédents :
graphe
de A1 :
|
graphe
de A2 : |
Que l’AEF soit déterministe ou non, il est toujours possible de lui associer un tel graphe.
Exemple :séparer des chiffres et des lettres
Voici un Automate d’Etats Finis Déterministe qui reconnaît :
- les identificateurs Pascal,
- les constantes chiffrées,
- les mots clefs : END , ELSE
Par la suite, afin de ne pas
surcharger le graphisme, nous noterons :
l’état initial de l’automate,
et
l’état final.
Représentons son graphe :
On peut voir dans le dernier
exemple le schéma général d’un analyseur lexical qui
constitue la première étape d’un compilateur. Il suffit dès
que le symbole a été reconnu donc à partir d’un état
final f1 ou bien f2 de repartir à l’état 0.
1.5 Matrice de transition : dans le cas déterministe
On représente la fonction de transition par une matrice M dont les cellules sont toutes des états de l’AEF (ensemble E), où les colonnes contiennent les éléments de VT (symboles terminaux), les lignes contiennent les états (éléments de E sauf l’état final qf). La règle (qj,ai) ¾® qk est stockée de la façon suivante M(i,j)= qk où :
la ligne j correspond à
l’état qj
la colonne i correspond au symbole
ai
Exemple : la matrice des
transitions de A2 :
|
Utilisation pratique de la matrice des transitions :
Dénommons Mat[i,j] l’état
valide de coordonnées (i,j) dans la matrice des transitions d’un
AEFD. Un schéma d’algorithme de reconnaissance par l’AEFD est très
simple à décrire :
Etat ¬ q0 ; Symlu ¬ premier symbole du mot ; tantque Etat ¹ qf Faire Etat ¬ Mat[Etat,Symlu] ; Symlu ¬ Symbole suivant Fintant ; |
et AEF (Automate d’Etats Finis) |
Il existe une correspondance
bijective entre les K-grammaires (grammaires de type-3) et les AEF. Cette
correspondance est la base sur laquelle nous sytématisons l’implantation
d’un AEFD. En voici une construction pratique .
2.1 Automate associé à une K-grammaire
Soit G une K-grammaire , G =
(VN,VT,S,R)
On cherche l’AEF A, A = (VT’,
E, q0, qf, µ), tel que A reconnaisse G.
Soit la constructionsuivante
de l'AEF A :
1 ) VT’
= VT È {#} 2 ) Chaque élément de VN est un qj de E ( E = VN È {qf} ) 3 ) A toute règle terminale de G de la forme Aj ¾® ak, on associe la règle de transition (qj, ak) ¾® qf 4 ) q0 = S (l’axiome de G) 5 ) A toute règle non terminale de G de la forme Aj ¾® ak Ai, on associe la règle de transition (qj, ak) ¾® qi |
L’automate
A ainsi construit reconnaît le langage engendré par G.
Remarque :
L’automate A1 reconnaissant le langage {anbp /(n³ 1)et(p³ 1) }associé à la grammaire G1 (cf. plus haut) a été construit selon cette méthode. |
Exemple : soit G la K-grammaire suivante
G = (VN,VT,S,R)
VT = { a, b, c, #
}
VN = { S, A, B }
Axiome : S
Règles de G :
1 : S ¾® aS
2 : S ¾® bA
3 : A ¾® bB
4 : B ¾® cB
5 : B ¾® #
Soit Aut l’automate associé
par le procédé bijectif précédent :
Aut = (VT’,
E, q0, qf, µ) VT’ = VT S est associé à : q0 A est associé à : q1 B est associé à : qf 1 : S ¾® aS est associé à :( q0, a ) ¾® q0 2 : S ¾® bA est associé à :( q0, b ) ¾® q1 3 : A ¾® bB est associé à :( q1, b ) ¾® q2 4 : B ¾® cB est associé à :( q2, c ) ¾® q2 5 : B ¾® # est associé à :( q2, # ) ¾® qf |
2.2 Grammaire associée à un Automate
Soit l’AEF A, tel que A = ( VT’,
E , q0 , qf ,µ )
On cherche G une K-grammaire
du langage reconnu par cet automate.
si qj ¹ qf alors
pour (qj, ak)¾® qi on construit : [ r :qj¾® akqi ] dans G |
si qj =
qfalors pour (qj, ak)¾® qf on construit : [ r :qj¾®ak ] dans G |
Exemple :
soit l’automate Aut reconnaissant
le langage {anb2cp / n ³ 0 et p ³ 0}
VT = { a, b, c, #
}
E = {q0,q1,
q2,qf }
transitions
:
(1) ( q0, a ) ¾® q0
[ les an ]
(2) ( q0, b ) ¾® q1
(3) ( q1, b ) ¾® q2
[ le b2 ]
(4) ( q2, c ) ¾® q2
[ les cp ]
(5) ( q2, # ) ¾® qf
La grammaire G de type 3 associée par la méthode précédente est celle que nous avons déjà vue dans l’exemple précédent:
S remplace q0 On pose
: VT = { a, b, c, # }
A remplace q1 On pose
: VN = { S, A, B }
B remplace q2 Axiome
: S
Règles de G :
1 : S ¾® aS remplace ( q0, a ) ¾® q0 |
2 : S ¾® bA remplace ( q0, b ) ¾® q1 |
3 : A ¾® bB remplace ( q1, b ) ¾® q2 |
4 : B ¾® cB remplace ( q2, c ) ¾® q2 |
5 : B ¾® # remplace ( q2, # ) ¾® qf |
Nous proposons deux constructions
différentes de la fonction de transition d’un AEFD soit en utilisant
directement les règles de transition, soit à partir de la
matrice de transition.
3.1 Fonction de transition à partir des règles
Toute règle est de la forme (qj, ak) ¾® qi , donc nous pourrons prendre comme modèle d’implantation de la fonction de transition une méthode function d'une classe que nous nommerons AutomateEF, dont voici ci-dessous une écriture fictive pour une seule règle.. |
function AutomateEF.transition(q:T_etat;car:Vt):T_etat ;
begin if (q= qj)and(car= ak) then q:= qi {la règle (qj, ak) ¾® qi} else .... end ; |
Toutes les autres règles
sont implantées dans la méthode transition de la même
façon.
L’appel de la méthode transition se fera à travers un objet
AEFD de classe AutomateEF :
EtatApres := AEFD.transition(qj, ak) ; {la fonction renvoie l’état qi} |
Exemple : l’automate déterministe
A’2 ( reconnaissant le langage anbp )
( en pascal de base
Pascal.Automates
\aefd_1.pas )
const
imposs =- 1 ;
fin = 20 ;
finmot = '#';
type
T_etat = imposs..fin ;
Vt =char ;
....
AutomateEF = class
q : T_etat ;
mot :string ;
function transition(q : T_etat ; car : Vt) : T_etat ;
end;
Implementation
function AutomateEF.transition(q : T_etat ; car : Vt) : T_etat ;
{par les règles de transition :}
begin
if (q = 0) and (car = 'a' ) then q := 1 {(q0,a) ¾® q1}
else
if (q = 1) and (car = 'a' ) then q := 1 {(q1,a) ¾® q1}
else
if (q = 1) and (car = 'b' ) then q := 2 {(q1,b) ¾® q2}
else
if (q = 2) and (car = 'b' ) then q := 2 {(q2,b) ¾® q2}
else
if (q = 2) and (car = finmot) then q := fin {(q2,#) ¾® qf}
else
q := imposs ; {blocage, le caractère n'est pas dans vt}
transition := q
end;
Appel de la méthode transition dans le programme principal :
{Analyse}
numcar
:= 1 ;
etat := 0 ;
while (etat <>
imposs)
and (etat <>
fin)
do
begin
Symsuiv(numcar,symlu) ;
{fournit dans symlu le symbole suivant}
etat := AEFD.transition(etat,symlu) ;
end;
Comme l’automate est déterministe,
il est possible de procéder différemment en utilisant sa matrice
de transition, ce qui est un bon exemple d’application de la notion de matrice
dans un programme.
3.2 Fonction de transition à partir de la matrice
Méthodologie
UUne autre écriture d’un même AEFD est obtenue (lorsque cela est possible en place mémoire) à partir d’un tableau Delphi (dénoté table) représentant la matrice des transitions de l’automate. Nous utilisons le même modèle d’implantation de la fonction de transition que dans le cas d'une description par règles ( méthode function d'une classe AutomateEF). |
Version réduite initiale du code : morceaux de code
const
imposs =- 1 ;
fin = 20 ;
finmot = '#';
type
T_etat = imposs..fin ;
Vt =char ;
T_transition =array
[T_etat, char
] of
T_etat
;
AutomateEF =
class
q :
T_etat
;
mot :string
;
table : T_transition ; {matrice des transitions}
end;
Il est nécessaire d’initialiser la matrice table avec les valeurs de départ de l’AEFD. Une méthode init_table pourra se charger de ce travail. Dans ce cas, la méthode transition est très simple à écrire, elle se résume à parcourir la matrice des transitions accessible comme champ de la classe :
Version augmentée du code : morceaux de code
const
imposs =- 1 ;
fin = 20 ;
finmot = '#';
type
T_etat = imposs..fin ;
Vt =char ;
T_transition =array
[T_etat, char
] of
T_etat
;
AutomateEF =
class
q :
T_etat
;
mot :string
;
table : T_transition ; {matrice des transitions}
procedure
init_table
;
function transition(q :
T_etat
; car : Vt) : T_etat ;
end;
implementation
procedure AutomateEF.init_table ;
{initialisation de la table des transitions}
var
i : T_etat ;
j : 0..255 ;
k :char ;
begin {init_table}
for
i := imposs to
fin
do
for j := 0 to 255 do
Chargementde(table)
......
end; {init_table}
function AutomateEF.transition(q
: T_etat ; car : Vt) : T_etat ;
{par la table de transition : Dans ce cas, la function
transition
est très simple à écrire. Elle se
résume à parcourir la matrice des
transitions accessible comme champ de la classe
}
begin
q :=
table[q,car]
;
result :=
q ;
end;
L’appel de la méthode
transition se fait comme dans le cas précédent, à travers
un objet AEFD de classe AutomateEF :
EtatApres := AEFD.transition(qj, ak) ; {la fonction renvoi l’état qi }
Exemple : le même automate (reconnaissant le langage anbp )
( en pascal de base Pascal.Automates \aefd_2.pas )
Nous reprenons l’automate du
paragraphe précédent, mais en l’implantant grâce à
sa table de transition.
la méthode transition de l’automate déterministe A2 :
( reconnaissant le langage anbp )
Morceaux de code Delphi :
const
imposs =- 1 ;
fin = 20 ;
finmot = '#';
type
T_etat = imposs..fin ;
Vt =char ;
....
AutomateEF =
class
private
EtatFinal :
T_etat
;
Fmot :string
;
table : T_transition ; {matrice des transitions}
procedure
init_table
;
function transition(q :
T_etat
; car : Vt) : T_etat ;
end;
Implementation
procedure AutomateEF.init_table ;
{initialisation de la table des transitions}
var
i : T_etat ;
j : 0..255 ;
k :char ;
begin {init_table}
for
i := imposs to
fin
do
for j := 0 to 255 do
table[i,chr(j)] :=
imposs
;
{par défaut tout est non reconnu}
table[0, 'a' ] := 1 ;
table[1, 'a' ] := 1 ;
table[1, 'b' ] := 2 ;
table[2, 'b' ] := 2 ;
table[2,finmot] :=
EtatFinal
end; {init_table}
function AutomateEF.transition(q
: T_etat ; car : Vt) : T_etat ;
{par la table de transition :}
begin
q :=
table[q,car]
;
result :=
q ;
end;
Appel de la méthode transition dans le programme principal :
{Analyse}
numcar := 1 ;
etat :=
0
;
while (etat <>
imposs)
and (etat <>
fin)
do
begin
Symsuiv(numcar,symlu) ;
{fournit dans symlu le symbole suivant}
etat := AEFD.transition(etat,symlu) ;
end;
La unit Delphi contient une classe abstraite d'automate et une
classe fille d'AEF Reconnaissant le langage anbp
Unit
UautomEF
;
interface
const
imposs =- 1 ;
fin = 20 ;
finmot = '#';
type
T_etat = imposs..fin ;
Vt =char ;
T_transition =array
[T_etat, char
] of
T_etat
;
AutomateAbstr = class
private
Fmot :string
;
table : T_transition ; {matrice des transitions}
procedure
setMot(s
:string ) ;
function getMot :string
;
function transition(q :
T_etat
; car : Vt) : T_etat ;
procedure Symsuiv (n : integer
; var car : Vt) ;
protected
EtatFinal :
T_etat
;
procedure init_table ;
virtual
; abstract ;
public
property Mot :string read
getmot
write setMot ;
procedure Analyser ;
constructor Create(fin :integer
) ;
end;
AutomateEF =
class (AutomateAbstr)
protected
procedure init_table ; override;
end;
Implementation
{--- AutomateAbstr ---}
constructor AutomateAbstr.Create(fin
:integer ) ;
begin
if fin in
[1..20]
then
EtatFinal :=
fin
else
EtatFinal :=
20
;
Fmot := '#';
init_table ;
end;
function AutomateAbstr.getMot : string
;
begin
result :=
Fmot
;
end;
procedure Symsuiv (n : integer
; var car : Vt) ;
begin
car :=
Fmot[n]
;
end;
procedure AutomateAbstr.setMot(s : string
) ;
var long : integer
;
begin
long := length(s) ;
if long <>
0
then
begin
if s[long] <>
'#' then
Fmot := s + '#';
end
else
Fmot :=
'#';
end;
function AutomateAbstr.transition(q
: T_etat ; car : Vt) : T_etat ;
{par la table de transition :}
begin
q :=
table[q,car]
;
result :=
q ;
end;
procedure AutomateAbstr.Analyser ;
var
etat :
t_etat
;
numcar : integer
;
s : string
;
symlu :
vt
;
begin
numcar := 1 ;
etat := 0 ;
while (etat <>
imposs)
and
(etat <> EtatFinal)
do
begin
Symsuiv (numcar , symlu) ;
numcar :=
numcar
+ 1 ;
{fournit dans symlu le symbole suivant}
etat := self.transition(etat,symlu) ;
end;
if etat =
etatfinal
then
writeln ( 'chaine reconnue !' )
else
writeln ( 'blocage, chaine non reconnue !'
)
end;
{--- AutomateEF ---}
procedure AutomateEF.init_table
;
{initialisation de la table des transitions}
var i : t_etat ;
j : 0..255 ;
k :char ;
begin
for i := imposs to fin do
for j := 0 to 255 do
table[i,chr(j)] :=
imposs
;
{par défaut tout est non reconnu}
table[0, 'a' ] := 1 ;
table[1, 'a' ] := 1 ;
table[1, 'b' ] := 2 ;
table[2, 'b' ] := 2 ;
table[2,finmot] :=
EtatFinal
;
end;
end.
Programme utilisant la classe AutomateEF et reconnaissant le langage
L = { anbp
/ (n < 2) et (p < 2) }
program ProjAutomEF ;
{$APPTYPE CONSOLE}
uses
SysUtils,
UAutomEF in 'UAutomEF.pas';
var AEFD : AutomateEF ;
begin
AEFD := AutomateEF.Create(3) ;
AEFD.Mot := 'aaaaabbbbb';
AEFD.Analyser ;
readln ;
end.
Exécution de ce programme sur l’exemple aaaaabbbbb :
Exécution de ce programme sur l’exemple aaaaabbabb :
Nous remarquons dans ce dernier paragraphe, que nous avons mis en place
un procédé général qui permet de construire méthodiquement
en Delphi une classe d'AEFD, uniquement en changeant le contenu de la méthode
init_table. Nous avons en fait mis au point un générateur
manuel de programme Delphi pour AEFD.
Par la suite, nous utiliserons ce procédé à chaque fois que nous aurons à programmer un AEFD. Nous n’aurons seulement qu’à déclarer une nouvelle classe héritant de AutomateAbstr définie plus haut et implémenter par redéfinition sa méthode init_table :
AutomateEF
=
class ( AutomateAbstr )
protected
procedure init_table ; override;
end;
Implementation
( * ---
AutomateEF
Reconnaissant le langage L =
{ anbp
/ (n < 2) et (p < 2) }
---* )
procedure AutomateEF.init_table
;
{initialisation de la table des transitions}
var i : t_etat ;
j : 0..255 ;
k :char ;
begin
for i := imposs to fin do
for j := 0 to 255 do
table[i,chr(j)] :=
imposs
;
{par défaut tout est non reconnu}
table[0, 'a' ] := 1 ;
table[1, 'a' ] := 1 ;
table[1, 'b' ] := 2 ;
table[2, 'b' ] := 2 ;
table[2,finmot] :=
EtatFinal
;
end;
( en pascal de base Pascal.Automates \aefnd.pas )
Le lecteur trouvera dans ce dossier le programme en pascal non objet "aefnd.pas " l’automate non déterministe A1 (normalisé) vu précédemment dans ce chapitre.
Nous terminons ce chapitre en
détaillant deux exercices de construction de programmes selon la méthode
qui vient d’être décrite. Le lecteur pourra en inventer d’autres
basés sur la même idée.
3.3 Exemple : les identificateurs pascal-like
( en pascal de base Pascal.Automates \Pasidentif.pas )
On donne des diagrammes syntaxiques de construction des identificateurs Pascal :
identificateur :
Construisons un programme Delphi reconnaissant de tels identificateurs, en utilisant le procédé de génération manuelle.
Méthode de travail adoptée
|
Détermination d’une grammaire Gid adéquate
Nous remarquons d’abord qu’il y a une grammaire de type 3 engendrant ces identificateurs :
Soient les ensembles :
Lettre = { a, b,...,
z }. // les 26 lettres de l’alphabet
Chiffre = { 0, 1,...,
9 }. // les 10 chiffres
VT = Chiffre È Lettre È {#}.
VN = { áidentificateurñ,A }
Posons Gid = (VT
, VN , áidentificateurñ ,Règles
) une grammaire où
Axiome : áidentificateurñ
Règles :
áidentificateurñ¾®a |b|...|z A
A¾®a |b|...|z
A
A¾®0 |1|...|9
A
A¾®#
Gid est de type 3
déterministe.
Construction
de l’automate associé à Gid
Afin de réduire le nombre de lignes de texte, nous adoptons les conventions
d’écriture suivantes :
( qk ,Lettre )
¾® qi , représente l’ensemble des
26 règles : ( qk ,a ) ¾® qi ...... ( qk ,z ) ¾® qi |
( qk , Chiffre)
¾® qi , représente l’ensemble des 10
règles : ( qk ,0 ) ¾® qi ...... ( qk ,9 ) ¾® qi |
Etats
associés aux éléments de VN:
áidentificateurñ Û q0
áAñ Û
q1
Etat initial = q0
Etat final = qf
Vocabulaire
terminal de l’automate :
VT’ = VT
È {#} = Chiffre È Lettre È {#}
Règles
de l’automate associé à Gid :
( q0 , Lettre ) ¾® q1// 26 règles
( q1 , Lettre ) ¾® q1// 26 règles
( q1 , Chiffre ) ¾® q1// 10 règles
( q1 ,# ) ¾® qf
Soit un total de 63 règles.
Graphe de l’automate :
Matrice de transitions de l’automate:
Programme Delphi associé à l’automate
Nous héritons de la
classe AutomateAbstr.
Nous n’avons que la méthode init_table à redéfinir.
La partie déclaration est la même que celle que nous avons déjà fournie auparavant au paragraphe " fonction de transition à partir d’une matrice ".
AutomateEF = class
( AutomateAbstr )
protected
procedure init_table ; override;
end;
implementation
procedure AutomateEF.init_table ;
{initialisation de la table des transitions}
var i : t_etat ;
j : 0..255 ;
x :char ;
begin
for i := imposs to fin do
for j := 0 to 255 do
table[i,chr(j)] :=
imposs
;
for x := 'a' to 'z' do
begin
table[0,x] :=
1 ; { (q0,lettre) ¾® q1 }
table[1,x]
:= 1 ;
{ (q1,lettre) ¾® q1 }
end;
for x := '0' to '9' do
table[1,x] :=
1 ; { (q1,chiffre) ¾® q1 }
table[1,finmot]
:=
EtatFinal ; { (q1,#) ¾® qf }
end;
Programme utilisant la classe AutomateEF et reconnaissant le langage
des identificateurs
program ProjAutomEF ;
{$APPTYPE CONSOLE}
uses
SysUtils,
UAutomEF in 'UAutomEF.pas';
var AEFD : AutomateEF ;
begin
AEFD := AutomateEF.Create(3) ;
AEFD.Mot := 'v14bcd73';
AEFD.Analyser ;
readln ;
end.
Exécution de ce programme sur l’exemple prix2 :
Exécution de ce programme sur l’exemple v14bcd73 :
3.4 Exemple : les constantes numériques
( en pascal de base Pascal.Automates \ctdecim.pas )
On donne des diagrammes syntaxiques de construction des constantes décimales positives Pascal-like :
constante :
Construisons un programme Delphi
reconnaissant de telles constantes en utilisant le procédé
de génération manuelle.
Méthode de travail adoptée :(identique à la précédente)
|
Détermination d’une grammaire Gcte adéquate
Nous reconnaissons d’abord qu’il y a une grammaire de type 3 engendrant ces identificateurs :
Soient les ensembles :
EnsChiffre = { 0, 1,..., 9 }.
// les 10 chiffres
VT = EnsChiffre
VN = { áconstanteñ,A,B
}
Posons Gcte = (VT
, VN , á constante ñ ,Règles
) une grammaire où
Axiome : á constante
ñ
Règles :
á constante ñ¾®0 |1|...|9 A
A ¾®0 |1|...|9 A
A ¾®e
A ¾®. B
B ¾®0 |1|...|9 B
B ¾®e
Gcte est de type
3 déterministe.
Construction
de l’automate associé à Gcte
Afin de réduire le
nombre de lignes de texte, nous adoptons les mêmes conventions d’écriture
suivantes que celles de l’exemple précédent:
( qk , Chiffre)
¾® qi , représente l’ensemble des 10
règles : ( qk ,0 ) ¾® qi ...... ( qk ,9 ) ¾® qi |
Etats
associés aux éléments de VN:
á constante ñ Û q0
áAñ Û
q1
áBñ Û
q2
Etat initial = q0
Etat final = qf
Vocabulaire
terminal de l’automate :
VT’ = VT
È {#} = Chiffre È {#}
Règles
de l’automate associé à Gcte :
( q0 , Chiffre) ¾® q1// 10 règles
( q1 , Chiffre ) ¾® q1// 10 règles
( q1 ,# ) ¾® qf
( q1 ,. ) ¾® q2
( q2 , Chiffre ) ¾® q2// 10 règles
( q2 ,# ) ¾® qf
Soit un total de 33 règles.
Graphe de l’automate :
Matrice de transitions de l’automate:
Programme Delphi associé à l’automate
Nous héritons de la classe AutomateAbstr. Comme dans l'exercice précédent , nous n’avons que la méthode init_table à redéfinir.
AutomateEF = class
( AutomateAbstr )
protected
procedure init_table ; override;
end;
implementation
procedure AutomateEF.init_table ;
{initialisation de la table des transitions}
var i : t_etat ;
j : 0..255 ;
x :char ;
begin
for i := imposs to fin do
for j := 0 to 255 do
table[i,chr(j)] :=
imposs
;
for x := '0' to '9' do
begin
table[0,x] :=
1 ; { (q0,chiffre) ¾® q1 }
table[1,x]
:= 1 ;
{ (q1,chiffre)
¾® q1 }
table[2,x]
:= 2 ;
{ (q2,chiffre)
¾® q2 }
end;
table[1, '.' ] := 2 ; { (q1,'.') ¾® q2 }
table[1,finmot]
:= EtatFinal ;
{ (q1,#) ¾® qf }
table[2,finmot]
:= EtatFinal ;
{ (q2,#) ¾® qf }
end;
Programme utilisant la classe AutomateEF et reconnaissant le langage des constantes numériques
program ProjAutomEF ;
{$APPTYPE CONSOLE}
uses
SysUtils,
UAutomEF in 'UAutomEF.pas';
var AEFD : AutomateEF ;
begin
AEFD := AutomateEF.Create(3) ;
AEFD.Mot := 145.78;
AEFD.Analyser ;
readln ;
end.
Exécution de ce programme sur l’exemple prix2 :
Exécution de ce programme sur l’exemple v14bcd73 :
Le lecteur aura pu se convaincre
de la facilité d’utilisation d’un tel générateur manuel.
Il lui est conseillé de réécrire un programme personnel
fondé sur ces idées. Le polymorphisme dynamique de méthode
a montré son utilité dans ces exemples.
Nous appliquons cette connaissance toute neuve à un petit projet de construction d’un interpréteur pour un langage analysable par grammaire de type 3. Nous verrons comment utiliser le graphe d’un automate dans le but de programmer les décisions d’interprétation. Là aussi, le lecteur pourra aisément adapter la méthodologie à d’autres exemples semblables construits sur des K-grammaires.
( en pascal de base Pascal.Automates \PasUautomat.pas )