Dispensa Universitaria
Quest'opera è stata rilasciata sotto la licenza Creative Commons Attribuzione - Non
Commerciale - Condividi allo stesso modo. Per leggere una copia della licenza visita il sito web
http://creativecommons.org/licenses/publicdomain/ o spedisci una lettera a Creative
Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
Linguaggio
Un linguaggio si basa sul concetto di alfabeto che è un insieme composto da
simboli:
={a 1, a 2, a 3, a 4. ... a n }
Per mezzo del prodotto di giustappozione sono generati casi speciali all'interno di una
stessa parola.
● Prefisso di y è quella stringa x tale che y=xz
● Suffisso di y è quella stringa x tale che y=zx
● Fattore di y e quella stringa x tale che y=zxw
In conclusione:
● L * è un linguaggio ottenuto moltiplicando tra loro in tutti i modi possibili tutte le
parole del linguaggio L unitamente alla parola vuota ottenendo in questo modo un
insieme infinito.
● L + è lo stesso di L * escludendo la parola vuota.
Formalmente:
Un linguaggio L in cui ogni parola di L + è decomponibile in un unico modo come
prodotto di parole di L è detto codice.
● Ogni linguaggio prefisso è anche un codice. Viceversa non vale che ogni codice è
anche prefisso. Questo semplicemente perchè non avendo alcuna parola composta
da altre parole, il modo per decomporla è unico.
● Ogni linguaggio con parole di lunghezza uguale è sempre un codice prefisso. Questo
perchè ogni parola ha una sua composizione specifica diversa una dall'altra
assicurata dal fatto che ogni parola ha sempre lunghezza n .
Rappresentazioni
I linguaggi L possono essere descritti e quindi rappresentati in due modi.
Come abbiamo detto non tutti i linguaggi ammettono un riconoscitore. Questi linguaggi
vengono chiamati ricorsivamente numerabili. Sono classificati ricorsivamente
numerabili i linguaggi che restituiscono 1 se w ∈ L e vanno in loop se w∉ L .
● I linguaggi ricorsivi sono un sottoinsieme dei linguaggi ricorsivamente numerabili.
Questo perchè dato un riconoscitore per un linguaggio ricorsivo è facile, una volta
ricevuto l'output relativo al caso w∉ L , costruire una procedura che entra in loop.
● Il contrario non può essere, perchè è impossibile capire quando un algoritmo è
entrato in loop.
Generatore
Il secondo modo per descrivere un linguaggio è il sistema generativo. Questo sistema
si basa sul concetto di calcolo logico. Un calcolo logico non riconosce se w∈ L , ma ne
ricerca la dimostrazione! Quindi un calcolo logico V x , d riceve in input un parola
x , una dimostrazione d e ritorna in output 1 se w∈ L e 0 se w∉ L . Ossia in altre
parole restituisce 1 se la dimostrazione d permette di affermare che la frase/parola
x è vera.
function L (x)
{
n=1
while (V(x,d)=0)
n = (n+1)
return (1)
}
Se noi ad esempio forziamo l'uscita dal ciclo while ad un certo numero n (questo per
rispettare il fatto di lavorare su linguaggi non ricorsivamente numerabili e quindi che
non ammettono un loop) avremo un calcolo logico completo perchè effettivamente
w ∈ L , ma incompleto in quanto non abbiamo avuto abbastanza tempo da trovare una
dimostrazione tale che V x , d =1 .
Grammatiche
Un sistema generativo sono le grammatiche. Una grammatica è una quadrupla
〈 ,Q , P , S 〉
● e Q sono due alfabeti rispettivamente di simboli terminali e di metasimboli.
● P è l'insieme di regole di produzione
● S è un simbolo chiamato assioma
Innanzi tutto a differenza dei simboli, i metasimboli o simboli NON terminali sono
espressioni atte alla generazione del linguaggio e non sono parole appartenenti al
linguaggio.
Le regole di produzione sono essenziali per la creazione di un linguaggio in quanto
dettano come è possibile articolare un insieme di simboli e metasimboli al fine di
ottere un linguaggio più completo e complesso.
In generale le regole si produzione sono dichiarate nel seguente modo:
con e due parole di simboli e/o metasimboli tali che
∈ ∪Q ∗e ∈ ∪Q ∗.
Infine l'assioma non è altro che il simbolo o il metasimbolo di partenza.
La rappresentazione
⇒G
indica poi la possibilità di derivare un simbolo da un simbolo secondo la
grammatica G in un sol passaggio. Mentre
⇒G∗
indica che si può derivare da con un numero finito di derivazioni.
Proprio grazie alla derivazione possiamo notare come le grammatiche siano calcoli
logici in cui la dimostrazione d è la derivazione stessa.
Per ipotesi un linguaggio L è generato da una grammatica solamente se L è
ricorsivamente numerabile, ma allora L è generabile da una grammatica solamente
se per L esiste un calcolo logico corretto e completo.
Un linguaggio LG generato da una grammatica di tipo G è l'insieme delle parole
sull'alfabeto derivabili dall'assioma S , ossia:
LG ={w∣w ∈∗e S ⇒G∗w }
Con grammatiche equivalenti si intende il caso in cui date due grammatiche G1 e
G2 :
LG1= LG2
Classificazione
Le regole di produzione sono usate per la classificazione delle grammatiche. A seconda
del tipo di regola esiste un tipo di grammatica.
Riprendendo alcune definizioni fatte precedentemente sui linguaggi si può dire che:
● R0 sono tutti i linguaggi ricorsivamente numerabili.
● R1 sono tutti i linguaggi contenstuali.
● R2 sono tutti i linguaggi acontenstuali.
● R3 sono tutti i linguaggi regolari.
Altri esempi di equivalenza sono dati dalla possibilità di generare un linguaggio di tipo
3 da una grammatica di tipo 3 contenente però solamente regole A B e A .
Ciò si ottiene introducendo un nuovo metasimbolo M e una nuova regola M e
sostituendo la regola A con A M . Quindi:
● Se L è di tipo 3 allora è generato da una grammatica di tipo 3 con regole del tipo
A B e A .
Il contrario, ossia generare una grammatica equivalente con regole solamente del tipo
A B e A non è sempre detto perchè in generale date queste regole allora
∉ L . Però:
● Se L è di tipo 3 con ∈ L , allora L=L ' ∪{} dove L ' è generato da una
grammatica di tipo 3 con regole del tipo A B e A .
Automi a stati
Un automa a stati A è un sistema
A=〈 ,Q , , q0 , F 〉
dove:
● Q è un insieme di stati
● è un alfabeto finito
● è la funzione di transizione
● q0 è lo stato iniziale
● F è l'insime degli stati finali
Se l'insieme Q è finito l'automa prende il nome di automa a stati finiti.
Un esperimento su questo sistema avviene in due fasi:
1. Viene dato come input un messaggio composta da una parola w∈ *.
2. Si osserva il valore di ouput se questo è 1 allora la parola w è accettata altrimenti
scartata.
Un sistema simile è conoscibile solamente per mezzo di esperimenti, ossia il
comportamento del sistema è descritto dalle parole accettate. Questo sistema è
quindi un riconoscitore di linguaggio.
Più nel particolare un sistema di questo tipo è composta da un numero finito di stati:
1. Ad ogni istante il sistema si trova su uno stato specifico q∈Q . Per modificare il
suo stato si deve mettere in ingresso un nuovo messaggio in modo tale da poter
associare il sistema ad un nuovo stato, ossia ad uno stato futuro o prossimo. La
legge che descrive questa procedura prende il nome di funzione di transizione
: x Q Q . Per esempio se il sistema è nello stato q ed arriva un messaggio
la sua funzione sarà q , .
2. Inizialmente il sistema si trova sempre in uno stato iniziale q0 ∈Q .
3. L'output del sistema è invece rappresentato dalla funzione di uscita : Q {0,1} e
se il sistema finisce in uno stato q allora q . Il sistema inoltre può uscire
solamente da uno stato finale. La totalità di questo stati forma l'insieme degli stati
finali F ={q∣q=1} .
Il linguaggio L A riconosciuto dall'automa A
L A= { w∣w∈∗e ∗q0 , w }={w∣w∈∗e ∗q0 , w=1}
Un automa a stati può essere rappresentato graficamente con un diagramma per
mezzo di cerchi (che rappresentano gli stati) e archi (che rappresentano le possibili
transizioni tra stato e stato). Lo stato iniziale è rappresentato con una freccia in
ingresso, mentre quello finale con un cerchio concentrico.
Esempio: A=〈 S ,Q , , q1 , F 〉
● S = {a.b}
● Q = {q1,q2}
● F = {q2}
● : {a , b}x {q1 , q2} {q1 , q2} descritto dalla tabella:
d a b
q1 q1 q2
q2 q2 q1
a a
b
q1 q2
b
a a
b
q1 q2
b
q3
avendo l'automa:
A=〈Q , , , q0 , F 〉
si costruisce la grammatica G :
G=〈 S , Q , P , q0 〉
in modo tale che:
● L'insieme dei metasimboli coincide con gli stati dell'automa
● L'assioma è lo stato iniziale
● qk qj è una regola di produzione se qj=qk , w
● qk è una regola di produzione se qk ∈ F
Esempio:
q0 a q1 a q2
a
● q0 aq1
● q1 aq2
● q2 aq1
● q2
Al contrario possiamo dire che data una grammatica di tipo 3 è possibile costruire un
automa a stati finiti.
Esempio:
Abbiamo questa grammatica:
● q0→aq0
● q0→aq1
● q1→bq0
● q0→e
a
b q1
q1
q0 a
L'associazione tra stati è dettata dalle regole di produzione della grammatica. Per
esempio si ha q0→aq0 e q0→aq1. Queste due regole vengono tradotte nel nuovo
automa deterministico con la regola q0→aq0q1 ossia dallo stato q0 di P(K) si passa a
quello q0q1.
riconoscono rispettivamente ∅ , , .
Per il punto 2 supponiamo che A , B siano riconosciuti da automi a stati finiti. Di
conseguenza sono rispettivamente generati, come abbiamo visto, da una grammatica
di tipo 3 del tipo
G ' =〈 S , Q ' , P ' , S ' 〉 e G ' ' =〈 S , Q ' ' , P ' ' , S ' ' 〉
Supponiamo inoltre che le regole di produzione siano del tipo
● qk qj
● qk
e che Q ' , Q ' ' siano insiemi disgiunti. Quindi:
● A∪B è verificato perchè generato dalla grammatica G1=〈 S , Q1 , P1 , S1〉 in cui
Q1=Q ' ∪Q ' ' con un nuovo metasimbolo S2 , P1=P ' ∪P ' ' con S1 S ' e
S1 S ' ' come regole nuove aggiuntive.
● A∗B è verificato perchè generato dalla grammatica G2=〈 S , Q2 , P2 , S ' 〉 in cui
Q2=Q '∗Q ' ' con un nuovo metasimbolo S2 , P1=P '∗P ' ' esclusa la regola
q ' con la nuova regola q ' S ' in aggiunta.
● A * è verificato perchè generato dalla grammatica G3=〈 S , Q ' , P3 , S ' 〉 in cui
P3=P ' con l'aggiunta della regola q ' S ' .
Alberi di derivazione
L'albero di derivazione ha le seguenti proprietà:
● Le foglie sono simboli terminali
● I nodi sono metasimboli
● La radice è l'assioma
● Se un nodo è etichettato B e i figli, in ordine, B1 , B2 , B3 ... Bn allora B1... Bn
è una regola di produzione
● Leggendo le foglie in ordine prefisso, la sequenza di etichette forma una parola w
Esempio:
Data la grammatica: G=〈{ , ,, x , y }, {E }, {E E E / x / y }, E 〉
e una parola x y x ha la seguente derivazione:
E ⇒ g E E ⇒ g E E E ⇒ g xE E ⇒ g x y E ⇒ g x y x
e il corrispondede albero di derivazione:
Per ogni linguaggio acontestuale L esiste una costante H tale che ogni parola z ∈ L
con lunghezza ∣z∣H può essere decomposta nella forma z=uvwxy tale che:
1. ∣vx∣1 ossia almeno una parola tra v e x è differente da
2. ∣vwx∣H
3. per ogni k 0 vale che u v k w x k y ∈ L
Supponiamo di avere una grammatica G in forma normale di Chomsky che genera un
linguaggio L .
h è il numero di metasimoli in G . Abbiamo poi una parola z ∈ L tale che ∣z∣H
con H =2h1 .
Come abbiamo visto, c'è per z un albero di derivazione con H foglie e altezza
log 2 H .
Prendiamo adesso in considerazione il cammino C più lungo e discendente dalla
radice ad una foglia. C sarà per forza di cose h1=log 2 H .
Dal momento che G ha h metasimboli, in C sarà per forza presente una ripetizione
di un metasimbolo qualsiasi A !
Chiamiamo w la parola composta dalle foglie del sottoalbero del secondo
metasimbolo A e vwx la parola composta dalle foglie del primo metasimbolo A .
Abbiamo così ottenuto z=uvwxy con u , y opportune parole.
Risulta inoltre che:
1. ∣vx∣1 altrimenti le radici sei sottoalberi etichettati A coninciderebbero.
2. ∣vwx∣H in quanto il sottoalbero con radice nel primo metasimbolo A ha altezza
al più h1 e di conseguenza possiede al più H =2h1 foglie.
3. per ogni k 0 vale che u v k w x k y ∈ L . Dal momento che:
S ⇒ g∗uAy , A⇒ g∗vAx , A⇒ g∗w
allora:
S ⇒ g∗uAy ⇒ g∗uvAxy ⇒ g∗uv 2 Ax 2 y ⇒ g∗u v k A x k y ⇒ g∗u v k w x k y
Automi a pila
I linguaggi acontestuali non possono essere riconosciuti da automi a stati finiti dal
momento che non possiedono una memoria. Un linguaggio acontestuale:
L={a n b n∣n≥1}
non può essere riconosciuto da un automa a stati finiti in quanto non gli è possibile
contare il numero di a per confrontarlo al numero di b .
E' necessario quindi una memoria teoricamente infinita... la memoria a pila o stack.
Per mezzo di una memoria a pila è possibile memorizzare una qualsiasi parola su un
alfabeto K e implementare le seguenti operazioni:
● Controllare se una parola è vuota: ISEMPY z =0,1 .
● Leggere il primo simbolo: TOP z .
● Cancellare il primo simbolo: POP z .
● Aggiungere un simbolo in testa: PUSH a , z .
Per capire il funzionamento dell'automa a pila prendiamo un linguaggio L
acontestuale generato da una grammatica in forma normale di Greibach e applicando
una derivazione più a sinistra.
Applicando una regola X1 aW ad una parola x1x2x3X1X2X3 otteniamo
x1x2x3aWX2X3 . Notare che per effettuare una simile operazione basta:
1. POP X1
2. PUSH W
Per applicare una regola qualunque A aV serve però prima il riconoscimento del
metasimbolo. Questa operazione è effettuata tramite TOP . Infatti
TOP X1X2X3= X1 . Adesso si controlla se X1= A e si applica o meno la regola.
Una parola è riconosciuta da un automa a pila se la sua memoria stack alla fine del
riconoscimento risulta essere vuota!