Sunteți pe pagina 1din 16

Capitolul 1

Reprezentarea limbajelor

Teoria limbajelor formale se ocupă cu proprietăţile limbajelor abstracte, în care elementele


sunt considerate ca fiind secvenţe arbitrare de simboluri dintr-o mulţime de simboluri numită
alfabetul limbajului. Spre deosebire de limbajul natural, unde elementele sunt constituite din
cuvinte şi propoziţii, iar problemele principale sunt cele de comunicarea între unul sau mai
mulţi comunicatori, limbajele formale şi problemele legate de ele sunt mai apropiate de clasa
limbajelor de programare, precum şi a legăturii lor cu calculatoarele numerice. Din acest
motiv, un aspect important luat în consideraţie în cadrul teoriei limbajelor formale este acela
al posibilităţii rezolvării algoritmice a diferitelor probleme legate de reprezentarea şi
traducerea limbajelor în calculatoarelor numerice.

Există două metode principale pentru definirea limbajelor abstracte:


• generarea unui limbaj, plecând de la o mulţime de generatori;
• recunoaşterea unui limbaj, prin specificarea unui automat de recunoaştere.
Din acest motiv, pentru principalele categorii de limbaje utilizate, se vor studia ambele
metode de specificare.

În acest capitol se vor defini noţiunile principale legate de limbaje, precum şi de cele două
metode de specificare a limbajelor.

1.1 Alfabet, cuvinte şi limbaje


În acest paragraf se specifică elementele de bază ale noţiunii de limbaj.

1.1.1 Alfabet şi cuvinte


Pentru a defini un limbaj ca o mulţime de şiruri de caractere, trebuie definite noţiunile de
alfabet şi cuvânt.

Definiţia 1.1.
(1) Se numeşte alfabet o mulţine finită şi nevidă, notată în mod uzual cu Σ, ale cărei elemente
se numesc simboluri.
(2) Fiind dat un alfabet Σ, o succesiune de simboluri din Σ se numeşte cuvânt peste Σ, sau şir
sau secvenţă.

Două alfabete foarte uzuale sunt alfabetul latin, format din 26 de litere, precum şi alfabetul
binar, format din mulţimea {0, 1}.

Pentru evitarea confuziilor, simbolurile dintr-un alfabet se vor nota cu litere de la începutul
alfabetului latin, iar cuvintele se vor desemna prin litere de la sfârşitul alfabetului.
Pentru simplificarea descrierii noţiunilor legate de limbaje, în continuare se vor utiliza câteva
notaţii:
• Se numeşte cuvânt vid şi se notează cu ε, o secvenţă care nu conţine nici un simbol;
• Se notează cu Σ+ mulţimea tuturor cuvintelor nevide din alfabetul Σ;
• Se notează cu Σ* mulţimea tuturor cuvintelor din alfabetul Σ:
Σ+ = Σ* ∪ {ε}

Una dintre cele mai uzuale operaţii care se pot aplica asupra cuvintelor (care sunt secvenţe de
simboluri) este operaţia de concatenare. Dacă Σ este un alfabet şi Σ* mulţimea cuvintelor
peste Σ, atunci operaţia de concatenare a două cuvinte peste Σ se notează cu caracterul ‘⋅’ şi
este o aplicaţie definită astfel:
⋅ : Σ *×Σ* → Σ*

De exemplu, dacă x şi y sunt două cuvinte peste Σ, concatenarea lor este tot un cuvânt peste Σ,
notat x⋅y. În cazul în care nu există nici un fel de confuzie, operatorul ‘⋅’ se poate omite, aşa
încât notaţia xy reprezintă în mod uzual concatenarea lui x cu y.

Formal, mulţimea cuvintelor peste un alfabet se poate defini inductiv astfel:

Definţia 1.2. Fie Σ un alfabet.


(1) Cuvântul vid ε este un cuvânt peste Σ;
(2) Dacă x este un cuvânt peste Σ şi a∈Σ un simbol, atunci xa este un cuvânt peste Σ;
(3) y este un cuvânt peste Σ dacă şi numai dacă se poate obţine cu ajutorul regulilor (1) şi (2).

Observaţie. În afară de cuvântul vid, se mai utilizează noţiunea de cuvânt unitar. Un cuvânt
unitar este un cuvânt format dintr-un singur simbol. De multe ori, un cuvânt unitar se
specifică prin simbolul conţinut şi nu trebuie să existe confuzie între utilizarea unui caracter
ca un simbol şi ca un cuvânt. De exemplu, dacă x este un cuvânt şi a un simbol, atunci în
notaţia xa, a reprezintă cuvântul unitar format din caracterul a.

O altă noţiune utilizată este cea de lungime a unui cuvânt. Lungimea unui cuvânt x reprezintă
numărul de simboluri ale cuvântului şi se notează cu |x|. Definirea formală a lungimii unui
cuvât se poate realiza de asemenea într-un mod recursiv:

Definiţia 1.3. Fie Σ un alfabet şi x∈Σ* un cuvânt peste Σ. Lungimea cuvântului x se notează
cu |x| şi este definită astfel:
- |x| = 0, dacă x=ε
- |x| = |y|+1, dacă x=ya, unde y∈Σ* şi a∈Σ

Se observă faptul că definiţia anterioară se aplică în mod recursiv unui cuvânt, prin
contorizarea tuturor simbolurilor acestuia, de la dreapta spre stânga. La ultima aplicare a
relaţiei, cuvântul rămas după înlăturarea simbolurilor este cuvântul vid.

În mod asemănător definiţiei anterioare, se poate defini formal operaţia de concatenare:

Definiţia 1.4. Fie Σ un alfabet şi x,y∈Σ* două cuvinte peste Σ. Concatenarea lui x şi y se
notează x⋅y şi este definită astfel:
- x⋅y = x, dacă x=ε
- x⋅y = (x⋅w)⋅a, dacă x=w⋅a, unde w∈Σ * şi a∈Σ
Notaţie. Dacă a∈Σ, atunci cuvântul a⋅a⋅ … ⋅a, obţinut prin concatenarea de n-1 ori a
simbolului a se notează în mod uzual cu an.

Exemplul 1.1. Dacă Σ = {a}, atunci :


Σ* = {ε , a, a2, …, an , …}
Σ+ = {a, a2, …, an , …}

Deoarece operaţia de concatenare este asociativă, iar cuvântul vid este un element neutru
pentru concatenare (xε = εx = x, pentru orice cuvânt x), mulţimea Σ* formează un monoid
împreună cu compunerea. El se numeşte monoidul liber generat de alfabetul Σ. Neluând în
considerare cuvântul vid, operaţia de concatenare determină un semigrup peste Σ.

Definiţia 1.5. Fie Σ un alfabet, ‘⋅’ operaţia de concatenare peste Σ+ şi ε cuvânul vid.
(1) Semigrupul (Σ+, ⋅) se numeşte semigrup liber peste Σ;
(2) Monoidul (Σ *, ⋅, {ε}) se numeşte monoid liber peste Σ.

Observaţie. Elementele mulţimii Σ joacă rol de generatori pentru semigrupul liber Σ+.

Definiţiile următoare introduc alte câteva notaţii uzuale pentru cuvinte: inversul unui cuvânt,
prefixul şi sufixul al unui cuvânt.

Definiţia 1.6. Fie Σ un alfabet şi x∈Σ*. Inversul cuvântului x se notează cu xR şi reprezintă


şirul de simboluri ale lui x scrise în ordine inversă :
- xR = ε, dacă x=ε;
- xR = ayR, dacă x=ya, unde y∈Σ* şi a∈Σ

Definiţia 1.7. Fie Σ un alfabet şi x, y, cuvinte peste Σ. Atunci x este pentru y :


(1) prefix, dacă y = xu, unde u∈Σ*;
(2) prefix propriu, dacă x este prefix pentru y şi y ≠ x;
(3) sufix, dacă y = ux, unde u∈Σ *;
(4) sufix propriu, dacă x este sufix pentru y şi y ≠ x;

1.1.2 Limbaje

Definiţia 1.8. Se numeşte limbaj peste un alfabet Σ o parte a monoidului liber Σ*.

Deci un limbaj peste un alfabet Σ este o submulţime (nu neapărat proprie) a mulţimii Σ*,
înzestrată cu operaţia de concatenare.

Exemple.
1) Mulţimile Φ şi {ε} sunt două limbaje distincte (primul nu are nici un cuvânt, pe când al
doilea conţine doar cuvântul vid).
2) L = {an | n≥0} = {a}* este un limbaj ale cărui cuvinte conţin zero sau mai multe apariţii
consecutive ale simbolului a.
După cum se poate observa, mulţimea Σ* ce conţine toate cuvintele generate peste alfabetul Σ
poate să fie o mulţime infinită, aşa cum este de exemplu mulţimea {a}*. Această mulţine are
însă o proprietate foarte importantă: ea este numărabilă, după cum se observă din teorema
următoare.

Teorema 1.1. Mulţimea cuvintelor monoidului liber Σ * este numărabilă.


Demonstraţie. Fie aplicaţia ϕ: Σ * → N, definită astfel:
ϕ(ε) = 0
ϕ(ai1ai2 … aik) = i1 + i2*n + … + ik*nk-1,
unde:
n = |Σ| este numărul de simboluri din Σ
i1, i2, …, ik ∈ {1, 2, …, n} şi aij∈Σ.
Vom demonstra că ϕ este o funcţie bijectivă, iar pentru că mulţimea numerelor naturale este
numărabilă, va rezulta faptul că şi mulţimea Σ* este numărabilă.
Să demonstrăm întâi faptul că ϕ este injectivă. Fie x = ai1ai2 … aik, y = bj1bj2 … bjr, aşa
încât ϕ(x) = ϕ(y), adică:
(i1-j1) + (i2-j2)*n + … + (ik-jk)*nk-1 + jk+1*nk + … + jr*nr-1 = 0 (am presupus k<n).
Din ecuaţia anterioară rezultă că i1=j1, … ik=jk, jk+1=0, …, jr=0, adică x = y.
Să demonstrăm acum surjectivitatea lui ϕ. Din definiţia lui ϕ rezultă inegalitatea:
1+n+ … +nk-1 ≤ ϕ(x) ≤ n+n2+ … +nk
Notând ϕ(x) cu m, după câteva transformări, rezultă inegalitatea:
(1) logn((n+m*(n-1))/n) ≤ k ≤ logn((1+m*(n-1))/n)
Notând cu A= logn((n+m*(n-1))/n) şi B= logn((1+m*(n-1))/n), avem următoarele relaţii:
B – A = logn((n+m*(n-1))/(1+m*(n-1))) < logn(n) = 1
Rezultă că lungimea intervalului [A, B] este subunitară, iar pentru că k∈[A, B], din relaţia (1)
se poate determina k în mod unic. Mai mult, din ecuaţia:
ϕ(ai1ai2 … aik) = m
simbolurile ai1, ai2, …, aik se pot determina în mod unic prin determinarea indicilor i1, …, ik,
aşa încât funcţia ϕ este surjectivă.
#

Deoarece un limbaj este în esenţă o mulţime de cuvinte, asupra limbajelor se pot aplica
principalele operaţii aferente mulţimilor. În plus, se poate defini şi operaţia de concatenare a
două limbaje.

Definiţia 1.9. Fie L1 şi L2 două limbaje peste Σ.


(1) Reuniunea limbajelor L1 şi L2 este un limbaj definit astfel:
L1∪L2 = {x | x∈L1 sau x∈L2}
(2) Intersecţia limbajelor L1 şi L2 este un limbaj definit astfel:
L1∩L2 = {x | x∈L1 şi x∈L2}
(3) Diferenţa limbajelor L1 şi L2 este un limbaj definit astfel:
L1−L2 = {x | x∈L1 şi x∉L2}
(4) Complementara limbajului L1 este un limbaj definit astfel:
L1 = Σ*−L1 = {x∈Σ | x∉L1}

Definiţia 1.10. Fie L1 şi L2 două limbaje peste Σ. Se numeşte concatenarea sau produsul
limbajelor L1 şi L2 şi se notează L1L2 limbajul definit astfel:
L1L2 = {xy | x∈L1, y∈L2}
Observaţie. Operaţia de concatenare este distributivă faţă de reuniune:
L1(L2∪L3) = L1L2 ∪L1L3
(L1∪L2)L3 = L1L3 ∪L2L3

Se poate defini în cazul limbajelor ca şi în cazul cuvintelor, un limbaj L ridicat la puterea n. O


definiţie recursivă a acestuia este următoarea:
L0 = {ε}
Ln = LLn-1, pentru n≥1

Definiţia 1.11. Închiderea tranzitivă prin produs a unui limbaj L, numită şi închiderea
pozitivă este un limbaj notat L+ şi definit astfel:
L+ = ∪n≥1 (Ln)
Operaţia de închidere tranzitivă şi reflexivă a limbajului L, numită simplu operaţie de
închiderea este un limbaj notat L* şi definit astfel:
L* = ∪n≥0 (Ln)

Din definiţia anterioară rezulă câteva proprietăţi:


- L* = L+ ∪ {ε}
- L+ = LL* = L*L
- LL* = L*L ∪ L+

Cel mai frecvent utilizat mod prin care se pot face aplicaţii între diferite limbaje este cel dat
de noţiunea de homomorfism. Definirea homomorfismului între limbaje este permisă de
următoarea teoremă.

Teorema 1.2. Fiind dat un alfabet Σ şi un semigrup oarecare S, orice aplicaţie ϕ: Σ → S se


extinde în mod unic la un homomorfism de semigrupuri ϕ1: Σ* → S.
Demonstraţie. Fie x∈Σ*. Definim:
ϕ1(x) = ϕ1(ai1ai2 … ain) := ϕ(ai1)ϕ(ai2)…ϕ(ain)
Se observă faptul că aplicaţia construită este un homomorfism de la Σ* la S. În plus se poate
demonstra că aplicaţia construită este unică.
#

Pe baza teoremei anterioare se pot desprinde câteva observaţii importante.

Observaţii.
1) Fiind date două alfabete Σ 1 şi Σ 2 şi un homomorfism ϕ: Σ1 → Σ2*, acesta se poate extinde
unic la un homomorfism:
ϕ1 : Σ 1 * → Σ 2 *
definit astfel:
ϕ1(ε) = ε,
ϕ1(xa) = ϕ(x)ϕ(a), ∀x∈Σ1*, a∈Σ 1
2) Aplicând homomorfismul ϕ la limbaje, pentru un limbaj L, se poate defini un alt limbaj
ϕ(L) astfel: ϕ(L) = {ϕ(w) | w∈L}

Exemplul 1.2. Dacă, pentru un limbaj L, se doreşte înlocuirea oricărui simbol 0 cu simbolul a
în oricare cuvânt, precum şi înlocuirea lui 1 cu secvenţa bb, se poate defini homomorfismul:
ϕ(0) = a, ϕ(1) = bb
Atunci, pentru limbajul:
L = {0n1n | n≥1}
se obţine limbajul următor:
L1 = ϕ(L) = {anb2n | n≥1}

Nu întotdeauna homomorfismele de limbaje sunt aplicaţii bijective. Din acest motiv, de multe
ori este indicat să se determine inversul unui homomorfism, privit ca o relaţie.

Definiţia 1.12. Dacă ϕ: Σ1 → Σ 2* este un homomorfism, atunci relaţia ϕ-1: Σ 2* → ℘(Σ1*) se


numeşte inversul homomorfismului ϕ dacă este definit astfel :
ϕ-1(y) = {x∈Σ1* | ϕ(x)=y}

Deci, dacă y este un cuvânt peste alfabetul Σ 2, atunci ϕ-1(y) reprezintă mulţimea cuvintelor
peste alfabetul Σ1, care sunt aplicate de ϕ în y.

Observaţie. Dacă L este un limbaj peste Σ2, atunci ϕ-1(L) este un limbaj peste Σ1, care constă
din toate cuvintele care sunt aplicate prin ϕ în cuvinte din L:
ϕ-1(L) = ∪y∈L (ϕ-1(y)) = {x∈Σ1* | ϕ(x)∈L}

Exemple.
(1) Fie ϕ un homomorfism aşa încât ϕ(0)=a şi ϕ(1)= ε. Atunci:
ϕ-1(ε) = 1*
ϕ-1(a) = 1*01*, unde 1*01* reprezintă limbajul {1i01j | i, j≥0}
(2) Dacă ϕ este un homomorfism aşa încât ϕ(0)=a şi ϕ(1)=a. Atunci:
ϕ-1(a) = {0, 1}
ϕ-1(a*) = {0, 1}*

1.2 Gramatici şi limbaje generate


Deoarece un limbaj L peste un alfabet Σ este o submulţime L⊆Σ*, rezultă că L poate fi o
mulţime finită sau infinită de cuvinte peste Σ. În primul caz este posibilă definirea completă a
limbajului prin specificarea tuturor cuvintelor din limbaj, pe când în cazul al doilea acest lucru
nu este posibil.

Este important deci ca specificarea unui limbaj să poată fi realizată într-o manieră finită, altfel
decât prin enumerarea cuvintelor limbajului. Există două metode importante utilizate pentru
definirea finită a limbajelor:
• procedee de recunoaştere a cuvintelor unui limbaj L, care pentru fiecare cuvânt x din
mulţimea Σ*, răspund dacă x aparţine sau nu lui L;
• procedee care permit generarea cuvintelor din limbajul L prin specificarea unor reguli
de formare ale acestora.

Prima metodă utilizează aşa numitele automate de recunoaştere ale cuvintelor, pe când
ultima metodă utilizează un sistem de generare al cuvintelor numit gramatică. Gramaticile
permit ca fiecare cuvânt dintr-un limbaj să poată fi generat cu ajutorul unor metode de
generare numite producţii.

O gramatică este un sistem matematic de definire a limbajelor. Ea utilizează două mulţimi


finite şi disjuncte de simboluri, una conţinând simboluri numite simboluri neterminale şi
desemnată în mod uzual prin litera N, cealaltă conţinând simboluri numite simboluri
terminale şi desemnată prin Σ. Mulţimea simbolurilor terminale reprezintă alfabetul peste
care este definit limbajul, iar mulţimea simbolurilor neterminale este utilizată la generarea
cuvintelor din limbaj.

Cea mai importantă parte a gramaticii este o mulţime finită de reguli de formare a cuvintelor
numite producţii, care este demnată în mod uzual prin litera P.

O producţie este practic o pereche de cuvinte, fiind un element din produsul cartezian:
(N∪Σ)*N(N∪Σ)* × (N∪Σ)*
Cu alte cuvinte, prima componentă conţine cel puţin un simbol neterminal, iar a doua
componentă poate fi orice cuvânt peste alfabetul N∪Σ.

O producţie de forma (α, β) înseamnă faptul că şirul α poate fi înlocuit de şirul β în timpul
operaţiei de generare a unui cuvânt din limbaj. De exemplu, să considerăm că perechea (AB,
CDE) este o producţie. Atunci, dacă α este un cuvânt ce poate fi generat de gramatică şi care
conţine AB ca subşir (partea stângă a producţiei), rezultă că gramatica poate de asemenea să
genereze un alt cuvânt, β, care se obţine din α prin înlocuirea şirului AB cu şirul CDE (partea
dreaptă a producţiei).

O altă notaţie uzuală utilizată în cadrul gramaticilor este cea de derivare. Ea este o noţiune
echivalentă pentru cea de generare. Dacă o gramatică poate genera un cuvânt α, atunci se
spune că α poate fi derivat de gramatica respectivă.

Limbajul generat de o gramatică reprezintă o mulţime de cuvinte formate din simboluri


terminale care pot fi derivate plecând de la un cuvânt special ce este format dintr-un singur
simbol neterminal numit simbol de start şi desmnat în mod uzual prin litera S.

Convenţie. O producţie (α, β) se notează în mod uzual sub forma α→β.

Se poate defini acum în mod formal noţiune a de gramatică.

Definiţia 1.13. O gramatică G este un tuplu:


G = (N, Σ, P, S)
unde:
1) N este mulţimea simbolurilor neterminale
2) Σ este mulţimea simbolurilor terminale, disjunctă de N: N∩Σ=Φ
3) S este un simbol distinct, S∈N, numit simbol de start
4) P este o submulţime:
P ⊆ (N∪Σ)*N(N∪Σ)* × (N∪Σ)*
iar un element (α,β)∈P, scris sub forma α→β se numeşte producţie.

Exemplul 1.3. Fie gramatica:


G = ({A, S}, {0, 1}, P, S)
unde mulţimea producţiilor este:
P: S → 0A1
0A → 00A1
A→ε
Se poate observa faptul că o gramatică defineşte un limbaj într-un mod recursiv. Pentru
aceasta se utilizează o noţiune numită formă propoziţională.

Definiţia 1.14. Fie G = (N, Σ, P, S) o gramatică. Mulţimea formelor propoziţionale ale


gramaticii G se defineşte recursiv astfel :
1) S este o formă propoziţională
2) Dacă αβγ este o formă propoziţională şi β→δ este o producţie din P, atunci αδγ este o
formă propoziţională

Deoarece o formă propoziţională este un cuvânt ce poate conţine atât simboluri terminale, cât
şi simboluri neterminale, se poate defini o noţiune numită propoziţie, care este o formă
propoziţională ce nu conţine decât simboluri terminale.

Definiţia 1.15. Fie G o gramatică. O formă propoziţională a gramaticii G care nu conţine


decât simboluri terminale se numeşte propoziţie generată de G.

Se poate defini acum noţiunea de limbaj generat de o gramatică.

Definiţia 1.16. Fie G o gramatică. Mulţimea tuturor propoziţiilor generate de G se notează


L(G) şi reprezintă limbajul generat de gramatica G.

Se vor introduce acum câteva notaţii uzuale referitoare la gramatici şi limbaje generate de
acestea.

Definiţia 1.17. Fie G = (N, Σ, P, S) o gramatică. Se numeşte derivare directă şi se notează


⇒G o relaţie binară pe mulţimea (N∪Σ)* definită astfel:
dacă αβγ este un cuvânt din (N∪Σ)* şi β→δ o producţie din P, atunci αβγ ⇒G αδγ

Atunci când nu există nici o confuzie asupra gramaticii G, litera respectivă poate fi omisă ca
indice în relaţia de derivare, aşa încât relaţia ⇒G poate fi scrisă simplificat ca ⇒.

Pentru a deriva o propoziţie a limbajului, îm mod uzual nu este suficientă o singură derivare,
fiind necesari mai mulţi paşi.

Definiţia 1.18. Fie G = (N, Σ, P, S) o gramatică.


(1) O secvenţă 〈α1, α2, …, αk+1〉 de k+1 cuvinte peste (N∪Σ)* nu neapărat distincte, astfel
încât αi ⇒G αi+1, ∀i=1, 2, …, k se numeşte derivare în k paşi, sau derivare de lungime k
şi se notează ⇒Gk
(2) Închiderea tranzitivă a relaţiei ⇒G se numeşte derivare netrivială în gramatica G şi se
notează ⇒G+ :
α ⇒G+ β dacă şi numai dacă ∃ k≥1 aşa încât α ⇒Gk β
(3) Închiderea tranzitivă şi reflexivă a relaţiei ⇒G se numeşte derivare în gramatica G şi se
notează ⇒G* :
α ⇒G* β dacă şi numai dacă ∃ k≥0 aşa încât α ⇒Gk β

Folosind noţiunile anterioare, se poate redefini forma propoziţională într-o gramatică.

Definiţia 1.19. Fie G = (N, Σ, P, S) o gramatică. O formă propoziţională w în gramatica G


este un cuvânt peste alfabetul (N∪Σ)* pentru care există o derivare S ⇒G* w.
De asemenea, se poate redefini limbajul generat de o gramatică.

Definiţia 1.20. Fie G = (N, Σ, P, S) o gramatică. Limbajul generat de gramatica G este


mulţimea propoziţiilor :
L(G) = {w | w∈Σ *, S ⇒G* w}

Exemplul 1.4. Pentru gramatica din exemplul anterior:


G = ({A, S}, {0, 1}, P, S)
P: S → 0A1
0A → 00A1
A→ε
putem avea următoarele derivări:
S ⇒ 0A1 ⇒ 00A11 ⇒ 0011
Deci, S ⇒3 0011, adică S ⇒+ 0011, S ⇒* 0011 şi deci 0011∈L(G).

Exemplul 1.5. Fie gramatica:


G = ({S}, {a, b}, P, S)
P: S → aSb
S→ε
Se poate demonstra că limbajul generat de G este: L(G) = {aibi | i≥0}.
Demonstraţie. Deoarece L(G) este o mulţime de cuvinte, pentru a demonstra egalitatea celor
două mulţimi, va trebui arătat că {aibi | i≥0} ⊆ L(G) şi L(G) ⊆ {aibi | i≥0}.
Vom demonstra prima incluziune, {aibi | i≥0} ⊆ L(G). Pentru aceasta, va trebui
demonstrat că orice şir w∈{aibi | i≥0} poate fi derivat din simbolul de start S:
∀n≥0, S ⇒* anbn
Dacă n=0, atunci deoarece a0b0 = ε, utilizând a doua producţie, avem:
S ⇒ a0b0 ∈ {aibi | i≥0}
Pentru orice număr n≥1, utilizând de n ori prima producţie, iar apoi producţia a doua, avem
următoarea secvenţă:
S ⇒ aSb ⇒ … ⇒ anSbn ⇒ anεbn = anbn
Pentru a demonstra a doua incluziune, L(G) ⊆ {aibi | i≥0}, trebuie demonstrat că:
∀w∈Σ* aşa încât S ⇒* w, rezultă că w∈{aibi | i≥0}
Vom demonstra aceasta prin inducţie după lungimea derivării.
Pentru n=0, dacă S ⇒0 w, atunci w=ε, adică w=a0b0.
Presupunem acum că ∀k≤n, dacă S ⇒k v, atunci v∈{aibi | i≥0} şi fie o derivare de lungime
n+1: S ⇒n+1 w. Avem relaţiile:
S ⇒ aSb ⇒n avb = w
Din presupunerea inductivă, v∈{aibi | i≥0}, deci ∃j≥1, aşa încât v=ajbj. Atunci:
w = aajbjb = aj+1bj+1∈{aibi | i≥1} ⊆ {aibi | i≥0}
#

În cazul în care în mulţimea producţiilor unei gramatici există mai multe producţii care au în
partea stângă acelaşi cuvânt, există o scriere uzuală simplifictă. De exemplu, pentru
producţiile:
α→β1
α→β2

α→βn
notaţia uzuală simplificată este următoarea:
α→β1 | β2 | … βn
De asemenea, există notaţii uzuale pentru reprezentarea diferitelor simboluri şi cuvinte
generate de gramatici:
• Pentru simbolurile terminale, se utilizează literele mici, de la începutul alfabetului
latin: a, b, c, …
• Pentru simbolurile neterminale, se utilizează literele mari, de la începutul
alfabetului latin: A, B, C, …
• Pentru simbolul de start al gramaticii se utilizează litera S
• Pentru reprezentarea cuvintelor terminale, se utilizează literele mici de la sfârşitul
alfabetului latin: u, v, w, …, z
• Pentru reprezentarea cuvintelor terminale şi neterminale, se utilizează literele mici
ale alfabetului grec: α, β, γ, δ, …

O clasificare a gramaticilor poate fi făcută în funcţie de forma producţiilor sale.

Definiţia 1.21. Fie G = (N, Σ, P, S) o gramatică.


(1) Gramatica G se numeşte liniară la dreapta, dacă fiecare producţie din P are una din
formele :
A → xB
A→x
unde A,B∈N şi x∈Σ* (fiecare producţie are cel mult un simbol neterminal în partea
dreaptă, aflat pe ultima poziţie).
În mod asemănător, se poate defini o gramatică liniară la stânga care are producţiile de
forma următoare (păstrând notaţiile anterioare):
A → Bx
A→x
(2) Gramatica G se numeşte independentă de context, dacă fiecare producţie din P este de
forma : A → α, unde A∈N şi α∈(N∪Σ)*
(3) Gramatica G se numeşte dependentă de context, dacă fiecare producţie din P este de
forma : α → β, unde α,β∈(N∪Σ)* şi |α|≤|β|
(4) Dacă asupra producţiilor gramaticii G nu se face nici o restricţie, atunci G se numeşte
nerestricţionată.

Observaţii.
(1) Se observă din definiţia anterioară faptul că orice gramatică liniară la dreapta este în
acelaşi timp şi o gramatică independentă de context.
(2) Se observă de asemenea faptul că o gramatică dependentă de context nu permite producţii
de forma A → ε, numite şi ε-producţii. Rezultă faptul că o gramatică independentă de
context ce conţine ε-producţii nu este o gramatică dependentă de contex. Această restricţie
a fost impusă pentru a permite limbajului generat de o gramatică dependentă de context să
fie recursiv sau decidabil, dupe poate observa din teorema care urmează.
(3) În cazul gramaticilor independente de context, se observă faptul că indiferent de contextul
apariţiei sale într-o formă propoziţională, simbolul neterminal A se poate înlocui cu şirul
α.
(4) În cazul gramaticilor dependente de context, producţiile acesteia se pot scrie şi sub forma:
αAβ → αγβ, unde γ≠ε
Din această formă, se observă faptul că un simbol neterminal A se poate substitui prin
şirul γ doar în contextul determinat de α şi β.
(5) Gramaticile liniare la dreapta au această denumire deoarece orice simbolul neterminal care
se înlocuieşte într-o formă propoziţională este întotdeauna aflat în extremitatea dreaptă a
formei propoziţionle.

Motivul principal pentru care nu sunt permise ε-producţiile într-o gramatică dependentă de
context este problema decidabilităţii. Aceasta înseamnă că pentru o gramatică dependentă de
context G = (N, Σ, P, S), se poate găsi un algoritm care determină dacă un cuvânt w∈Σ *
aparţine sau nu limbajului L(G).

Problema decidabilităţii se va relua în capitolele următoare, ea se referindu-se la existenţa


unui algoritm care să determine, pentru un limbaj, dacă un anumit cuvânt face parte sau nu
din limbajul respectiv. În acest paragraf se va demonstra acst lucru doar pentru clasa
limbajelor dependente de context (dacă că pentru un cuvânt x∈Σ*, se poate determina dacă el
aparţine sau nu unui limbaj dependent de context).

Teorema 1.3. Orice limbaj dependent de context este decidabil.


Demonstraţie. Să considerăm o gramatică G = (N, Σ, P, S) şi un cuvânt x∈Σ*, pentru care
|x|=n. Vom demonstra prin inducţie după lungimea cuvântului x că se poate decide dacă
x∈L(G) sau x∉L(G).
În cazul n=1 cuvânul x este de forma x=a, unde a∈Σ şi deci dacă S→a∈P, atunci x∈L(G),
altfel x∉L(G).
Să considerăm cazul n>1. Vom construi o secvenţă de mulţimi de cuvinte peste N∪Σ
definită astfel :
Tn0 = {S}
Tnk = Tnk-1 ∪ {α∈(N∪Σ)* | ∃β∈Tnk-1, aşa încât β⇒α şi |α|≤n}, pentru k≥1
Se observă că fiecare mulţime Tnk depinde de mulţimea Tnk-1 şi reprezintă mulţimea tuturor
cuvintelor care se pot obţine plecând de la cuvinte din mulţimea Tnk-1 printr-o derivare directă.
Deoarece Tn0 conţine doar simbolul de start, înseamnă că mulţimea Tnk conţine toate cuvintele
de lungime cel mult n care se pot deriva din S în cel mult k paşi de derivare.
Tot din aceleaşi relaţii se observă că mulţimile (Tnk)k≥0 formează un şir crescător :
Tn0 ⊆ Tn1 ⊆ … ⊆ Tnk ⊆ …
Se observă de aici că dacă există un indice k pentru care Tnk+1 = Tnk, atunci pentru oricare j>k,
este îndeplinită relaţia : Tnj = Tnk.
Vom demonstra acum că şirul mulţimilor (Tnk)k≥0 este mărginit superior. Notăm cu
t=|N∪Σ| numărul simbolurilor din alfabetul N∪Σ şi cu TN mulţimea cuvintelor de lungime cel
mult n. Numărul elementelor din TN este finit şi are valoarea 1+t+t2+ … +tn, fiind deci
majorat de numărul (t+1)n+1.
Rezultă că şirul mulţimilor (Tnk)k≥0 este mărginit superior de mulţimea TN şi deci
există unic un indice j astfel încât Tnj+1 = Tnj. Indicele j fiind determinat, înseamnă că există
un număr finit de mulţimi distincte în şirul (Tnk)k≥0, adică mulţimile Tn0, Tn1, …, Tnj.
În concluzie, dacă există un indice i, 0≤i≤j, pentru care x∈Tni, atunci x∈L(G), iar în
cazul în care ∀i, 0≤i≤j, x∉Tni, atunci x∉L(G).
#

Cele patru tipuri de gramatici formează aşa-numita ierarhie Chomsky. O gramatică liniară la
dreapta se numeşte gramatică de tipul 3 în această ierarhie. O gramatică independentă de
context se numeşte gramatică de tipul 2 în ierarhia Chomsky, o gramatică dependentă de
context se numeşte gramatică de tipul 1, iar o gramatică nerestricţionată se numeşte gramatică
de tipul 0.

Exemplul 1.6.
1) Gramatică de tipul 3:
G = ({S}, {0, 1}, P, S)
P: S → 0S | 1S | ε
Limbajul generat de gramatică este:
L(G) = {0, 1}*
2) Gramatică de tipul 2 - gramatica expresiilor aritmetice ce pot fi construite cu simbolurile
a, +, *, ( şi ) :
G = ({E, T, F}, {a, +, *, (, )}, P, E}
P: E → E+T | T
T → T*F | F
F → (E) | a
3) Gramatică de tipul 3:
G = ({S, B, C}, {a, b, c)}, P, S}
P: S → aSBC | abC
CB → BC
bB → bb
bC → bc
cC → cc
Limbajul generat de granatică este:
L(G) = {anbncn | n≥1}

Corespunzător celor patru tipuri de gramatici, limbajele generate de acestea se denumesc în


mod corespunzător. Notînd cu k∈{0, 1, 2, 3} tipul din ierarhia Chomsky al unei gramatici, un
limbaj de ordin k este un limbaj generat de o gramatică de ordin k. Mulţimea tuturor
limbajelor de ordin k se notează ℒk. Un limbaj de ordinul 0 se numeşte limbaj recursiv
enumerabil, un limbaj de ordinul 1 se numeşte limbaj dependent de contex, un limbaj de
ordinul 2 se numeşte limbaj independent de contex, iar un limbaj de ordinul 3 se numeşte
limbaj liniar la dreapta sau limbaj regulat.

După cum se poate observa din teorema următoare, între mulţimile limbajelor de diferite
ordine există o relaţie de includere, ceea ce justifică denumirea de ierarhie de limbaje. Orice
limbaj limbaj regulat este un limbaj independent de context. La rândul său, orice limbaj
independent de context care nu conţine şirul vid este o submulţime proprie a unui limbaj
dependent de context. De asemenea, un limbaj dependent de context este o submulţime
proprie a unei mulţimi recursive, care la rândul său este o submulţime a unei mulţimi recursiv
enumerabile.

Pentru a elimina asimetria care există între limbajele ℒ1 şi ℒ2, în mod uzual se consideră că
mulţimea limbajelor dependente de context conţine atât limbajele generate de gramaticile
dependente de context, la care se adaugă, pentru fiecare asemenea limbaj L, limbajul L’ ce
conţine în plus cuvântul vid, L’ = L ∪ {ε}.

Teorema 1.4. Între clasele de limbaje din ierarhia Chomsky există relaţiile următoare:
ℒ0 ⊃ ℒ 1 ⊃ ℒ 2 ⊃ ℒ3
1.3 Automate de recunoaştere (de acceptare)
A doua metodă de specificare finită a unui limbaj constă în definirea unui automat de
recunoaştere sau de acceptare a cuvintelor din limbaj.

În esenţă, un automat de recunoaştere este o procedură utilizată pentru definirea unei mulţimi
de cuvinte. El poate fi reprezentat grafic ca în figura 1.1.
Banda de
a0 a1 an
intrare
Cap de citire

Unitate Memorie
de control auxiliară

Figura 1.1

Banda de intrare este considerată formată dintr-o secvenţă liniară de celule, fiecare conţinînd
exact un simbol de intrare dintr-un alfabet finit de intrare. Capul de citire poate citi în fiecare
moment o celulă şi se poate deplasa de la stânga la dreapta, sau poate rămâne staţionar. Un
asemenea automat se numeşte în mod uzual automat cu o singură cale. În mod uzual, banda
de intrare poate fi folosită doar pentru citire, simbolurile de intrare neputând fi modificate în
timpul evoulţie automatului. Memoria automatului poate stoca orice tip de date. Trebuie însă
să existe un alfabet finit al memoriei şi ea să conţină doar simboluri ale acestui alfabet într-o
organizare oarecare, iar conţinutul memoriei să poată fi descris in fiecare moment într-un mod
finit. În mod uzual, numele unui automat de recunoaştere este dat de tipul memoriei
automatului.

Un exemplu de memorie auxiliară este stiva, sau lista “push-down”, care poate fi reprezentată
în mod abstract printr-un şir de simboluri ale memoriei, (z1, z2, …, zn), care aparţin unui
alfabet al memoriei, notat cu Γ, iar z1 este primul element din şir precum şi singurul care
poate fi accesat de către capul de citire. Un automat cu un astfel de tip de memorie este numit
automat push-down şi este foarte utilizat în cazul limbajelor independente de context.

Comportarea memoriei auxiliare pentru o clasă de automate este caracterizată prin două
funcţii: cea de stocare în memorie, precum şi cea de citire din memorie.

Funcţia de citire din memorie este o aplicaţie definită de la mulţimea configuraţiilor posibile
ale memoriei la o mulţime finită de simboluri de informaţie, care pot fi aceleaşi cu alfabetul
memoriei. De exemplu, pentru o memorie de tip listă push-down, funcţia de citire din
memorie poate fi definită prin:
f: Γ* → Γ,
f(z1z2 … zn) = z1

Funcţia de stocare descrie modul în care memoria poate fi modificată, ea fiind o aplicaţie
definită pe produsul cartezian dintre conţinutul memoriei şi o mulţime de şiruri de control ale
acesteia De exemplu, pentru o listă push-down, funcţia de memorare poate înlocui primul
simbol cu un şir finit de alte simboluri din alfabetul memoriei. O asemenea funcţie se poate
reprezenta astfel:
g: Γ* × Γ* → Γ* ,
g(z1 … zn, y1 … yk) = y1 … ykz2 … zn
Se observă faptul că se poate înlocui z1 cu un şir vid, astfel încât următorul simbol ce va putea
fi citit de următoarea operaţie de citire din memorie este z2.

Evoluţia unui automat de recunoaştere se descrie prin intermediul stărilor acestuia. Gestiunea
automatului se realizează prin intermediul unei unităţi de control a stărilor, sau pe scurt
unitatea de control, care poate fi un program ce determină modul de evoluţie al stărilor
automatului.

Astfel, evoluţia unui automat de recunoaştere poate fi reprezentată printr-o mulţime de stări,
împreună cu o aplicaţie care descrie modificarea stărilor, în funcţie de simbolul curent de
intrare şi de informaţia curentă citită din memorie. De asemenea, la trecerea dintr-o stare
curentă în într-o stare următoare, trebuie determinată informaţia care trebuie memorată în
starea următoare.

O altă noţiune uzuală folosită pentru descrierea evoluţiei unui automat este cea de
configuraţie. O configuraţie a automatului este definită de:
• starea curentă a automatului;
• conţinutul benzii de intrare, precum şi a locaţiei curente de citire de pe aceasta;
• conţinutul memoriei.
Trecerea de la configuraţie la alta se realizează prin intermediul unor mişcări. O mişcare este
determintă în mod uzual de simbolul curent de intrare, precum şi de informaţia curentă citită
din memorie, iar acţiunile determinate de ea sunt:
• mutarea capului de citire cu o celulă spre stânga, spre dreapta, sau rămânerea pe
poziţia curentă;
• memorarea unei anumite informaţii în memoria auxiliară;
• schimbarea stării curente de control.

Configuraţia iniţială a unui automat este în mod uzual unică şi specifică starea curentă de
control ca fiind starea iniţială, capul de citire poziţionat pe simbolul cel mai din stânga al
benzii de intrare, iar conţinutul memoriei ca având o structură iniţială. Configuraţia finală nu
este întotdeauna unică, un automat de recunoaştere putând avea o mulţime de configuraţii
finale posibile, determinate de mulţimea stărilor finale de control. Într-o configuraţie finală,
starea curentă de control a automatului este o stare finală, iar capul de citire este poziţionat
după ultimul simbol de pe banda de intrare.

Trecerea dintr-o stare curentă într-o stare următoare nu este întotdeauna unic determinată, iar
din acest motiv este posibil ca plecând dintr-o anumită configuraţie să existe mai multe
mişcări posibile. Un automat de recunoaştere se spune că este:
• determinist, dacă pentru fiecare configuraţie, există cel mult o singură posibilitate de
mişcare spre configuraţia următoare;
• nedeterminist, dacă în fiecare configuraţie există o mulţime de una sau mai multe
mişcări spre o configuraţie următoare.

Pentru definirea formală a unui automat de acceptare se utilizează următoarele notaţii:


• Σ - alfabetul finit al benzii de intrare;
• Γ - alfabetul finit al memoriei;
• Q - mulţimea finită a stărilor unităţii de comandă;
• δ - funcţia de tranziţie, care descrie funcţionarea unităţii de comandă.

Funcţia δ descrie modul de tranziţie între o stare curentă şi o stare următoare a unităţii de
control. În cazul unui automat determinist, starea următoare unei stări curente este unic
determinată, astfel încât funcţia de tranziţie este definită astfel:
δ: Q × Σ × Γ* → Q × Γ*
δ(q1, a, γ1) = (q2, γ2)
unde:
- q1 reprezintă starea curentă a unităţii de control, iar q2 reprezintă satrea următoare;
- a reprezintă simbolul curent de intrare aflat be banda de intrare şi care urmează să fie
citit de capul de citire;
- γ1 reprezintă starea curentă a memoriei automatului, iar γ2 memoria automatului în
starea următoare.

În cazul unui automat nedeterminist, starea următoare a unităţii de control nu este unic
determinată, astfel încât valorile funcţiei δ reprezintă o mulţime de elemente (q2, γ2). În acest
caz, funcţia se poate defini astfel:
δ: Q × (Σ ∪{ε}) × Γ* → ℘(Q × Γ*)
δ(q1, a, γ1) ⊆ {(q2, γ2) | q2∈Q, γ2∈Γ*}

Se pot acum defini mai formal noţiunile de configuraţie şi cea de mişcare între două
configuraţii. Configuraţia unui automat de acceptare este un tuplu de forma:
(q, x, i, γ)
unde:
- q∈Q reprezintă starea curentă a unutăţii de control;
- x∈Σ * reprezintă şirul de pe banda de intrare; în cazul automatelor cu o singură cale, x
reprezintă şirul de pe banda de intrare necitit încă;
- i∈N reprezintă poziţia capului de citire pe banda de intrare a automatului; în cazul
automatelor cu o singură care, i este o informaţie redondantă;
- γ∈Γ* reprezintă conţinutul curent al memoriei.

Relaţia de mişcare între două configuraţii se notează în mod uzual cu simbolul ⊢ şi se poate
defini pe baza funcţiei δ: între două configuraţii (q1, ax, i, γ1) şi (q2, x, j, γ2) se spune că există
o relaţie de mişcare şi se notează (q1, ax, i, γ1) ⊢ (q2, x, j, γ2) dacă:
δ(q1, ax, i, γ1) = (q2, γ2)
j = i + 1, dacă a∈Σ,
j = i, dacă a = ε

Despre un automat se spune că acceptă sau recunoaşte un cuvânt de intrare w, dacă pornind
de la o configuraţie iniţială şi având simbolurile din w pe banda de intrare, acesta realizează o
secvenţă de mişcări care aduce automatul într-o configuraţie finală.

Limbajul acceptat de un automat de recunoaştere este mulţimea cuvintelor de intrare pe care


automatul recunoaşte.
Pentru fiecare clasă de limbajde din ierarhia Chomsky, există o clasă naturală de automate de
acceptare, care definesc aceeaşi clasă de limbaje. Acestea sunt: automatele finite, automatele
push-down, automatele liniar mărginite şi maşinile Turing.

Definiţia exactă a acestor automate va fi specificată în capitolele următoare, dar relaţia lor cu
limbajele din ierarhia Chomsky poate fi descrisă astfel:
• Un limbaj este liniar la dreapta dacă şi numai dacă este definit de un automat finit
determinst;
• Un limbaj este independent de context dacă şi numai dacă este definit de un automat
nedeterminist push-down;
• Un limbaj este dependent de context dacă şi numai dacă este definit de un automat
nedeterminist liniar mărginit;
• Un limbaj este recursiv enumerabil dacă şi numai dacă este definit de o maşină Turing.

S-ar putea să vă placă și