Cosa è un linguaggio?
Transcript
Cosa è un linguaggio?
Teoria dei linguaggi
Cosa è un linguaggio?
Alfabeto = insieme di simboli (caratteri ascii)
Stringa
insieme finito di simboli di un alfabeto
ε e la stringa vuota (talvolta denotata da λ)
|s| rappresenta la lunghezza di una stringa.
Linguaggio un insieme di stringhe
∅, l’insieme vuoto è un linguaggio
{ε} è il linguaggio contenente la sola stringa vuota
L’insieme di tutti I possibile ptogrammi C è un
linguaggio
L’insieme di tutti I possibili identificatori in un linguaggio
è un linguaggio
1
Terminologia
Dato un alfabeto
T = {a, b}
su di esso si possono definire infiniti linguaggi
L1 = {a, aa, ab, aab}
L2 = {a,b}
L3 = linguaggio contenente lo stesso numero
di a e di b
Definizioni
Cardinalità di un linguaggio = numero di
stringhe appartenenti al linguaggio
Frase = stringa appartenente al linguaggio
Linguaggio infinito = linguaggio con
cardinalità infinita
Linguaggio finito = linguaggio con
cardinalità finita
Linguaggio vuoto Φ = linguaggio con
cardinalità 0
stringa vuota = ε oppure λ
2
Operazioni su stringhe
Concatenamento
x=a
y = bc
x ·y = abc
sε =s
εs=s
Sottostringhe
x = bc
Riflessione
x = ab
y = ba
Potenza m-esima
sn = s s s .. s ( n times)
s0 = ε
x=a
x4 = aaaa
y = ab
y3 = ababab
Operazioni su i linguaggi
Concatenamento
L1 = {a, b}
L2 = {c, d}
L = L1 ·L2 =
= {xy | x ∈ L1, y ∈ L2} =
= {ac, ad, bc, bd}
Unione
L1 = {a, b}
L2 = {c, d}
L = L1 ∪ L2=
= {x ∈ L1 ∪ L2} =
= {a, b, c, d}
Potenza m-esima
Lm = Lm-1 ·L
L0 = Φ
Esempio
L = {a, b}
L3 = L2 ·L
= {aa, ab, ba, bb} ·{a, b} =
= {aaa, aba, baa, bba, aab,
abb,
bab, bbb}
3
Linguaggio universale
Definiamo linguaggio universale (monoide libero)
su un alfabeto T l’insieme di tutte le stringhe di tale
alfabeto
Il linguaggio universale si può definire come limite
dell’elevamento a potenza
L* = stella di Kleene =
∪n=0Ln = L0 ∪ L1 ∪ L2 ∪….
∝
Positive Closure
L+ = ∪n=1Ln = L1 ∪ L2 ∪….
Esempi di Linguaggi
L1 = {a,b,c,d}
L2 = {1,2}
L1L2 = {a1,a2,b1,b2,c1,c2,d1,d2}
L1 ∪ L2 = {a,b,c,d,1,2}
L13 = tutte le stringhe di lunghezza 3 (con a,b,c,d}
L1* = tutte le stringhe con a,b,c,d e la stringa vuota
L1+ = non include la stringa vuota
4
Grammatiche
Per descrivere un linguaggio sia esso un linguaggio
naturale o un linguaggio di programmazione è
necessario definire un insieme di regole a cui deve
sottostare ogni frase del linguaggio per essere corretta.
Tali regole devono specificare tutte o solo le stringhe
appartenenti al linguaggio
Per fare ciò è necessario quindi introdurre:
una grammatica: cioè una specifica formale di tutte le
strutture di frase (o frasi) consentite
un algoritmo di riconoscimento: cioè un metodo per
analizzare le frasi e determinare la loro struttura
Grammatiche generative
Una Grammatica generativa può essere
pensata come un insieme di regole che
generano tutte e sole le frasi del linguaggio
Noam Chomsky ha definito quattro classi di
“complessità” per le grammatiche generative
Chomsky Hierarchy.
5
The Chomsky Hierarchy
Tipo 0 - Grammatiche generali - Macchina di Turing
Tipo1 - Grammatiche Dipendenti dal Contesto
Tipo 2 - Grammatiche non contestuali - Automi a Pila
Tipo 3 - Grammatiche regolari - Automi a stati finiti
Tipo 0
Tipo 1
Tipo 2
Tipo 3
Grammatiche generative
Una grammatica generativa G è espressa come una quadrupla
G=(V, Σ, P, S),
dove:
V è l’insieme dei non terminali o variabile (nel seguito
utilizzeremo le lettere maiscule)
Σ è l’insieme finito di terminali (utilizzaremo le lettere minuscole)
P è l’insieme finito delle produzioni o regole nella forma
α→β
S è un simbolo speciale appartenente all’insieme dei non
terminali V chiamato assioma
Normalmente V ∩ Σ = ∅.
Ogni simbolo della grammatica è un elemento di V ∪ Σ.
6
Grammatiche regolare (tipo 3)
Una grammatica regolare (RG) è denotata da G = (V, Σ,
P,S), dove V è l’ insieme dei non terminali, Σ è l’insieme
dei terminali, S è un non-terminale chiamato assioma, P
è un insieme finito di produzioni, con ogni produzione
nella forma
A →β,
con: A ∈ V e β ∈ (V ∪ Σ)*.
∀ produzione in una grammatica regolare regolare le produzioni
possono consistere in produzioni come le seguenti
A → aB, B → b (grammatiche lineari destre)
oppure
B → Ab, A → a (grammatiche lineari sinistre)
Generalmenre, le lettere greche minuscole denotano
stringhe in (V ∪ Σ)*.
Esempio di grammatica
V = {S}
Σ = {a, b}
P = {S → ε (stringa vuota)
S → abS
S = {S}
Stringhe appartenenti al linguaggio:
S → abS → ab
S → abS → ababS → abab
7
Nelle grammatiche di tipo 3, il solo non
terminale nella parte destra (RHS) della
produzione sempre si trova alla fine della
regola (o alternativamente all’inizio)
Le grammatiche di tipo 3 sono molto
restrittive (non si possono utilizzare per la
sintassi dei linguaggi di programmazione) ma
i loro riconoscitori sono molto efficenti.
Cosa è un linguaggio regolare?
Sono tutti e soli i linguaggi che si possono
generare con grammatiche generative di tipo
3
Un linguaggio che può essere espresso
mediante le operazioni di concatenamento,
unione e stella di Kleene applicate un numero
finito di volte a linguaggi unitari e al
linguaggio vuoto
Ogni linguaggio finito è regolare
8
Automi a stati finiti
Un riconoscitore per un linguaggio è un programma
che prende iuna stringa x e risponde “si” se x è una
frase del linguaggio, “no” altrimenti.
Chiameremo Automa a stati finiti il riconoscitore per il
linguaggi regolari
Un automa a stati finiti può essere deterministico
(DFA o DFSA) o non deterministico (NFA o NFSA)
Sia DFA che NFA riconoscono I linguaggi regolari
deterministico – piu’ veloce, ma talvonta poco
compatto
non-deterministico – piu’ lento, ma piu compatto
Per la costruzione degli analizzatori lessicali si
utilizzano automi deterministici.
Finite state automata (FSA)
Un FSA ha:
un insieme finito di stati
un insieme di transizioni (o mosse) da uno
stato ad un altro stato etichettato da caratteri
di Σ
uno stato speciale chiamato stato iniziale S0
un insieme di stati finali o di accettazione
(stringa valida)
9
Gli automi a stati finiti sono rappresentati
graficamente da un digramma di transizioni.
Iniziamo dallo stato iniziale
Il carattere di input a genera una transizione dallo
stato corrente ad uno altro stato se esiste una
mossa dallo stato corrente etichettata con il
carattere di input
Se non esiste una mossa etichetata con il
carattere di unput la stringa è valida se lo stato è
di accettazione (stato finale)
Esempio
(a b (c)+ )+.
Non-Deterministic Finite
Automaton (NFA)
Un automa a stati finiti non-deterministico (NFA) è un modelllo
matematico che consiste di:
S – un insieme di stati
Σ - un insieme di simboli di input (alfabeto)
mosse – una funzione che data una coppia stato-simbolo
restituisce uno stato, cioè
Mossa : S x Σ → S
s0 - uno stato iniziale, s0 ∈ S
F – un insieme di stati finali F ⊆ S
In un NFA sono consentite
ε-mosse. In altre parole, esistono transizioni che non consumano
simboli
due mosse che da uno stato per effetto dello stesso simbolo
portano a due stati diversi
Un NFA accetta una stringa x, se e solo se esiste un cammino
dallo stato iniziale ad uno stato finale tale ogni arco sia etichettato
coni simboli in x
10
Costruzione del riconoscitore di
un FSA
lettera = a .. z, A..Z
cifra = 0..9
Del è un qualsiasi carattere diverso da a..z e
0..9
lettera | cifra
0
lettera | _ 1
2
Del
a..z
0..9
-
del
FINALI
0
1
Error
1
Error
NO
1
1
1
Error
2
NO
2
Error Error Error Error
SI
11
NFA (Esempio)
0 rappresenta lo stato iniziale s0
{2} è l’insieme degli stati finali F
Σ = {a,b}
S = {0,1,2}
a
La funzione di transizione e descritta
a
b
dalla tabella
0
1
2
start
a
b
b
0 {0,1} {0}
Grafo di transizione di un NFA
1
_
{2}
2
_
_
Il linguaggio riconosciuto da questo NFA è
(a | b) * a b
Esempio: commenti C++
12
Espressioni regolari
Una espressione regolare puo essere:
ε (la stringa vuota) e denota il linguaggio {ε}
∀ simbolo terminale a, a è una espressione regolare
se R è una espressione regolare R* è una espressione regolare (R*
è chiamate stella di kleene o chiusura di R). Per esempio: (ab)*
genera: ε, ab, abab, etc.
se R è una espressione regolare R+ è una espressione regolare. Per
esempio: (ab)+ genera: ab, abab, etc.
se R e S sono espressioni regolari, R ∪ S (oppure R|S) è una
espressione regolare che si comporta come R o S
se R e S sono espressioni regolari, R · S (oppure RS) è una
espressione regolare che descrive la concatenazione di R seguito
da S
[a-z] è una abbreviazione per denotes a|b|c|..|z
Espressioni regolare
Espressioni regolai sopra un alfabeto Σ
Espressione reg.
Linguaggio
ε
{ε}
a∈ Σ
{a}
L(r1) ∪ L(r2)
(r1) | (r2)
(r1) (r2)
L(r1) L(r2)
(L(r))*
(r)*
(r)
L(r)
(r)+ = (r)(r)*
(r)? = (r) | ε
13
Esempi
(c|d|e)(a|b)
rappresenta il linguaggio
L = {ca, cb, da, db, ea, eb}
(a|b)*c(a|b)*
rappresenta l’insieme di stringhe con zero o
piu “a” seguite da “c”, seguite da zero o piu “b”
(a b (c)+
)+
14
Espressioni regolari
Le parentesi possono essere omesse nelle
espressioni regolare utilizzando le regole di
precedenza
*
concatenation
|
ab*|c
means
highest
next
lowest
(a(b)*)|(c)
Esempi
Σ = {0,1}
0|1 => {0,1}
(0|1)(0|1) => {00,01,10,11}
0* => {ε ,0,00,000,0000,....}
(0|1)* => tutte le stringhe con 0 e 1, compresa la stringa
vuota
Definizioni Regolari
LA scrittura di espressioni regolari per alcuni linguaggi può
essere complessa perche le espressioni regolari che lo
descrivono possono essere complesse, In questo caso si usano
le definizioni regolari”.
Noi possiamo attribuire dei nomi come simboli per la definizione
di altre espressioni regolari.
Una definizione regolare è una sequenza di definizioni nella
forma:
d1 → r 1
d2 → r 2
.
dn → r n
dove di è un nome
e
ri è una espressione regolare sui simboli
Σ∪{d1,d2,...,di-1}
15
Definizioni regolari
Esempio: Identificatori in C
lettera → A | B | ... | Z | a | b | ... | z
cifra → 0 | 1 | ... | 9
identificatore → lettera (lettera | cifra ) *
SE noi scriviamo direttamente l’espressione regolare
avremo
(A|...|Z|a|...|z) ( (A|...|Z|a|...|z) | (0|...|9) ) *
Esempio: Numeri interi senza segno
cifra → 0 | 1 | ... | 9
cifra → cifra +
opt-fraction → ( . cifra ) ?
opt-exponent → ( E (+|-)? cifra ) ?
unsigned-num → cifra opt-fraction opt-exponent
Proprieta’ algebriche
Assioma
Descrizione
r |s = s|r
| e’ commutativo
r |(s|t) = r |(s|t)
| è associativo
(rs)t = r (st)
La concatenazione è
associativa
La concatenazione gode della
prorprietà distributiva su |
ε è l’elemento neutro per la
concatenazione
r (s|t) = rs|rt
(s|t)r = sr |tr
εr = r
rε = r
r* = ( r |ε)*
r** = r*
* è idenpotente
16
Grammatiche regolari - Automi a
stati finiti (FSA)
Esiste una corrispondenza biunivoca tra
grammatiche regolari ed FSA
Esempio
Espressione regolare : a*·b·c*
Grammatica regolare:
V = {S, A, C}
T = {a, b, c}
P={
S→A
A → aA
A → bC
C → cC
C → ε}
S = {S}
a
c
P0
b
P1
17
Esempio
V = {S}
T = {a, b}
P = {S → ε
S → abS
S = {S}
a
P0
P1
b
Esempio
Grammatica per il linguaggio dei numeri interi
V = {S,D}
0,1,2,3,…9
T = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
P = {S → D
P0
P1
0,1,2,3…9
S →DS
D →0|1|2|3|4|5|6|7|8|9}
S = {S}
Grammatica per il linguaggio dei numeri interi (non sono accettati numeri
come 04)
V = {S,D}
1,2,3,…9
T = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
P = {S → D
P0
P1
S →0
0,1,2,3…9
S →DS
D →1|2|3|4|5|6|7|8|9}
P2
0
S = {S}
18
Esempio
Esempio
V = {S}
T = {a, b}
P = {S → ε
S → abS
S = {S}
Il seguente FSA riconosce a*b*
a
non anbn
b
P0
b
P1
La ricorsione è necessaria per modellare anbn (Cioè non
è un FSA
Le grammatiche regolari sono troppo
restrittive per i linguaggi di programmazione e
pertanto non sono sufficienti per la
costruzione dei compilatori
Per esempio, le grammatiche regolari non
possono generare il linguaggio anbn con n ≥
1 (Nota che tale linguaggio corrisponde al
Begin e End dei linguaggi di a
programmazione)
Esistono altri tipi di grammatiche generative
che possono generare tale linguaggio.
19
Espressioni regolari - Grammatica
regolare
Esiste una corrispondenza biunivoca tra
linguaggio regolare ed espressione regolare
Esempio
Espressione regolare : a*·b·c*
Regular Grammar:
V = {S, A, C}
T = {a, b, c}
P={
S→A
A → aA
A → bC
C → cC
C → ε}
S = {S}
Grammatiche regolari - Automi a
stati finiti (FSA)
FSA(Q, T, δ, q0, F)
Dove Q = insieme degli stati
T insieme di simboli terminali
δ insieme delle transizioni,
q0 = stato iniziali,
F = insieme stati finali
G(V, T, P, S)
Algoritmo di costruzione
V=Q
S = q0
∀ q ∈ Q, ∀ a ∈ T se ∃ una transizione etichettata con a da q a r ∈ Q
allora esiste in P la produzione q → a r
∀ q ∈ F, ∃ una produzione q → ε
20
Esempio
Q = {A, B, C}
a
T = {a, b, c, d}
F = {B, C}
A
q0 = A
A = δ(A,a), B = δ(A,b), C = δ(B,c),
C = δ(C,d), A = δ(C,b)
d
c
b
B
C
b
V = {A, B, C}
T = {a, b, c, d}
B → ε, C → ε
A → a A, A → a B, B → c C, C → d C, C → b A
S=A
Esempio
Linea di commento che inizia
con “//” a termina con “eol”
V = {S, A, C}
T = {/, c, e}
P={
S → // A
A→ cA
A → e}
E = // c* e
P2
P1
c
e
e = eol
c = qualsiasi carattere
P0
P1
21
Conversione di una espressione
regolare in un Automa a stati finiti
La conversione di una espressione regolare
in un NFA produce un NFA tale che ogni
stato ho solo uno o due successori ed ha un
unico stato finale
Un espressione regolare può essere
convertito in un NFA automaticamente
utilizzando le regole di Thomson’s.
Queste regole sono semplici e sistematiche
Non è detto che sia uil metodo più efficente per
effettuare la conversione
Garantisceh che il risultante NFA abbia uno stato
iniziale e uno stato finale.
Forme base
Per ε, si costruisce il seguente NFA
start
ε
i
f
Per a in T, si costruisce il seguente NFA
start
i
a
f
22
Recursive Rules
Detti N(s) e N(t) gli NFA for s and t.
NFA N(s|t):
N(s)
ε
ε
start
i
f
ε
ε
N(t)
Recursive Rules
NFA N(st):
start
i
N(s)
N(t)
f
23
Recursive Rules
NFA N(s*)
ε
start
ε
i
ε
N(s)
f
ε
NFA N((s)) = N(s)
Thomson’s Construction (Example
- (a|b) * a )
a:
b:
a
a
ε
(a | b)
b
ε
ε
ε
b
ε
(a|b)
*
ε
ε
a
ε
ε
ε
b
ε
ε
(a|b)
*a
ε
ε
ε
a
ε
ε
ε
b
a
ε
ε
24
Chiusura
La ε chiusura di uno stato è l’insieme degli stati che
include:
Lo stato stesso,
Gli stati che possono essere raggiunti dallo stato
attraverso una serie di ε mosse
Per calcolare la ε -chiusura di un insieme s:
Aggiungere s alla ε -chiusura
Se t appartiene alla ε-chiusura(s) e esiste una ε
mossa da t a u, aggiungere u alla chiusura e
continuare fino a quando possibile
Funzione chiusura
void close(NFASet S) {
while (x in S and x →λy and y notin S) {
S = S U {y}
}
}
25
Costruzione di un DSA da un NFA
Eliminazione delle epsilon mosse
N (Q, T, δ, q0, F)
automa con epsilon mosse
N’ (Q, T, δ’, q0, F’) automa senza epsilon mosse
con F’ = F ∪ q0 se ε-chiusura(q0) contiene uno stato di F
F’ = F altrimenti
per ogni a in T esiste δ’(q,a) se esiste δ(q,a) oppure esiste
uno stato p tale che
δ(p,a), p= δ(q, ε)
Costruzione di un DSA da un NFA
Eliminazione delle transizioni non deterministiche
N (Q, T, δ, q0, F)
automa non deterministico
senza epsilon mosse
M (Q’, T, δ’, q’0, F’) automa deterministico
dove
Q’ = 2Q
F’ = {p ∈ Q’ | p contiene uno stato appartenente a F}
q’0 = [q0 ]
∀ p ∈ Q’ e ∀ a ∈ T
δ’(p,a) = {s | s ∈ δ(q,a) ∩ F ≠ ∅}
26
Esempio
a
ε
a
2
1
5
a
a
b
3
4
b
Esempio
a
a
a
2
1
a
5
a
a
b
3
b
4
27
Esempio
a
a
a
2
1
a
5
a
a
b
3
4
b
Esempio
[2,3,4]
a
a
[2]
[1]
[5]
a
b
a
[4,5]
b
[2,4]
a
b
28
Uno stato S è finale (o accettante) nel DS se contiene uno stato
finale in NFA
Lo stato iniziale e ε-closure({s0}
Conversione di un NFA in un DFA
Inserire ε-closure({s0}) come stato non marcato in DS
while (c’è uno stato non marcato S1 in DS) do {
marcare S1
per ogni simbolo di ingresso a do {
S2 Í ε-closure(move(S1,a))
if (S2 ∉ DS)
aggiungere S2 in DS come stato non marcato
transfunc[S1,a] Í S2
}
}
DFA MakeDeterministic(NFA N) {
DFA D; NFASet T
D.StartState = { N.StartState }
close(D.StartState)
D.States = { D.StartState }
while (è possibile aggiungere stati/transizioni){
∀ S in D.States and c in Σ
T = {y in N.States : x→c y per qualche x in S}
close(T);
if (T notin D.States) {
D.States = D.States U {T}
D.Trans = D.Trans U {S →c T}
}}
D.AcceptingStates = { S in D.States : uno stato di
accettazione di N in S}
}
29
Esempio di conversione di un NFA
in un DFA
2
ε
0
ε
a
3
ε
1
6
ε
ε
7
a
8
ε
4
b
5
ε
Esempio di conversione di un NFA
in un DFA
S0 = ε-closure({0}) = {0,1,2,4,7} S0 in DS come stato non marcato
⇓ marcare S0
ε-closure(move(S0,a)) = ε-closure({3,8}) = {1,2,3,4,6,7,8} = S1
ε-closure(move(S0,b)) = ε-closure({5}) = {1,2,4,5,6,7} = S2
transfunc[S0,b] Í S2
transfunc[S0,a] Í S1
⇓ marcare S1
ε-closure(move(S1,a)) = ε-closure({3,8}) = {1,2,3,4,6,7,8} = S1
ε-closure(move(S1,b)) = ε-closure({5}) = {1,2,4,5,6,7} = S2
transfunc[S1,a] Í S1
transfunc[S1,b] Í S2
⇓ marcare S2
ε-closure(move(S2,a)) = ε-closure({3,8}) = {1,2,3,4,6,7,8} = S1
ε-closure(move(S2,b)) = ε-closure({5}) = {1,2,4,5,6,7} = S2
transfunc[S2,a] Í S1
transfunc[S2,b] Í S2
S1 in DS
S2 in DS
30
Esempio di conversione di un NFA
in un DFA
S0 è lo stato iniziale dato che 0 membro di S0={0,1,2,4,7}
S1 è lo stato di accettazione (stato finale) del DFA dato che 8 appartiene a S1 = {1,2,3,4,6,7,8}
a
S1
a
S0
a
b
b
S2
b
Esempio
31
Conversione di una Espressione
Regolare direttamente in un DFAs
E’ possibile convertire direttamente una espressione
1.
2.
3.
4.
regolare in un DFA (senza creare prima un NFA).
Concatenare l’espressione con un simbolo speciale #.
r Î (r)#
“espressione regolare aumentata”
Creare un albero sintattico della “espressione regolare
aumentata”
In tale albero sintattico tutti gli elementi del vocabolario
(più # e ε) sono delle foglie dell’albero
Numerare con “position number” tutti gli elementi del
vocabolario (più # e ε)
Regular Expression Î DFA
(cont.)
(a|b) * a Î (a|b) * a #
•
•
|
a
1
b
2
Albero sintattico di (a|b) * a #
#
4
a
3
*
“espressione regolare aumentata”
• Ogni simbolo e numerato (positions)
• Ogni simbolo è una foglia
• inner nodes sono operatori
32
followpos
Definiamo la funzione followpos
followpos(i) -- è l’insime di posizioni che seguono una
posizione I nella stringa generata dall’espressione regolare
aumentata
Esempio,
( a | b) * a #
1 2
3 4
followpos(1) = {1,2,3}
followpos(2) = {1,2,3}
followpos(3) = {4}
followpos(4) = {}
firstpos, lastpos, nullable
Per valutare followpos, noi abbiamo bisogno
di tre funzioni che sono definite per I nodi
dell’albero
firstpos(n) -- l’insieme di posizioni del first
simbolo della stringa generata dalla subexpression di radice n.
lastpos(n) -- l’insieme di posizioni del last
simbolo della stringa generata dalla subexpression di radice n. nullable(n) -- true
se la stringa vuota appartine alla subexpression di radice n, false altrimenti
33
Come valutare firstpos, lastpos,
nullable
n
nullable(
n)
firstpos(n)
lastpos(n)
foglia ε
true
Φ
Φ
Foglia i
false
{i}
{i}
c2
nullable(c1)
or
nullable(c2)
firstpos(c1) ∪
firstpos(c2)
lastpos(c1) ∪
lastpos(c2)
c2
nullable(c1)
and
nullable(c2)
if (nullable(c1))
firstpos(c1)∪firstpos(c
2)
else firstpos(c1)
if (nullable(c2))
lastpos(c1) ∪
lastpos(c2)
else lastpos(c2)
firstpos(c1)
lastpos(c1)
|
c1
•
c1
*
c
true
Come valutare followpos
Due regole per calcolare la funzione followpos:
1. Se n un concatenation-node (•)con figlio sinistro c1 e
figlio destro c2, e i ∈ lastpos(c1), allora firstpos(c2)
⊆ followpos(i).
2. Se n è un star-node (*), e i ∈ lastpos(n), allora
firstpos(n) ⊆ followpos(i).
Se firstpos e lastpos sono stati calcolati per ogni
nodo, followpos può essere calcolato con una visita
depth-first dell’albero sintattico.
34
Example -- ( a | b) * a #
green – firstpos
blue – lastpos
{1,2,3} • {4}
{1,2,3}• {3} {4}# {4}
4
{1,2}*{1,2}{3}a{3}
3
{1,2} {1,2}
|
{1} a {1} {2}b {2}
2
1
followpos(1) = {1,2,3}
followpos(2) = {1,2,3}
followpos(3) = {4}
followpos(4) = {}
• Dopo aver calcolato followpos possiamo creare il DFA
per l’espressione regolare.
Algoritmo (RE Î DFA)
Creare l’albero sintattico di (r) #
Calcolare le funzioni followpos, firstpos, lastpos, nullable
Porre firstpos(root) in S (S è l’insieme degli stati del DFA) come stato non
marcato.
while (∃ s ∈ S non marcato) {
s
for each simbolo a {
s’ Í followpos(s1) ∪ ... ∪ followpos(sn)
let s1,...,sn posizioni in s e simboli per quelle posizioni sono a
move(s,a) Í s’
if (s’ non e vuoto e non in S
put s’ into S come stato non marcato.
the start state of DFA is firstpos(root)
the accepting states of DFA are all states containing the position of #
35
Esempio -- ( a | b) * a #
followpos(1)={1,2,3}
followpos(3)={4}
followpos(2)={1,2,3}
followpos(4)={}
S1=firstpos(root)={1,2,3}
⇓ marcare S1
a: followpos(1) ∪ followpos(3)={1,2,3,4}=S2
b: followpos(2)={1,2,3}=S1
⇓ marcare S2
a: followpos(1) ∪ followpos(3)={1,2,3,4}=S2
b: followpos(2)={1,2,3}=S1
move(S1,a)=S2
move(S1,b)=S1
move(S2,a)=S2
move(S2,b)=S1
b
S1
start state: S1
accepting states: {S2}
a
a
S2
b
Example -- ( a | ε) b c* #
followpos(1)={2}
followpos(2)={3,4}
followpos(3)={3,4}
followpos(4)={}
S1=firstpos(root)={1,2}
⇓ marcare S1
a: followpos(1)={2}=S2
move(S1,a)=S2
b: followpos(2)={3,4}=S3
move(S1,b)=S3
⇓ marcare S2
b: followpos(2)={3,4}=S3
⇓ marcare S3
c: followpos(3)={3,4}=S3
S2
move(S2,b)=S3
a
b
S1
move(S3,c)=S3
b
S3
c
start state: S1
accepting states: {S3}
36
Minimizzare il numero di stati per
un DFA
Dividere gli stati in due insiemi:
G1 : insiemi di stati finali
G2 : insieme di stati non finali states
Per ogni nuovo gruppo G
Partizionare G in sottogruppo take che gli stati s1 e s2 sono
nello stesso gruppo iff
per tutti I simboli di input a, gli stati s1 e s2 hanno transizioni a
stati nello stesso gruppo.
Lo stato iniziale del DFA minimizzato è il gruppo
contenente lo stato inziale del DFA originale.
GLi stati finiale del DFA minimizzato sono I gruppi
contenente gli stati finiali del DFA originale.
Esempio si minimizzazione
a
1
G1 = {2}
G2 = {1,3}
2
a
b
b
a
G2 cannot be partitioned because
3
move(1,a)=2
move(3,a)=2
b
move(1,b)=3
move(2,b)=3
So, the minimized DFA (with minimum states)
b
{1,3}
a
a
{2}
b
37
Minimizing DFA – Esempio
a
a
1
2
a
Groups:
4
b
a
b
3
{1,2,3}
{1,2}
b
{4}
{3}
no more partitioning
b
So, the minimized DFA
a
b
1->2
2->2
3->4
1->3
2->3
3->3
b
a
{3}
b
a
{1,2}
a
b
{4}
Esempi di espressioni regolari
1. letter(letter|digit)*
2. digits = digit digit*
opt_frac = . digits | ε
opt_exp = (E(+|-| ε) digits | ε
num = digits opt_frac opt_exp
38