Grammatiche: equivalenze, forme normali e trasformazioni

Da testwiki.
Vai alla navigazione Vai alla ricerca

Template:Risorsa

Introduciamo in questa lezione altri concetti delle grammatiche che ci aiutano a definire i linguaggi formali.

Equivalenza di due grammatiche

Dividiamo l'equivalenza di due grammatiche in due tipi: equivalenza forte (detta anche equivalenza strutturale) e equivalenza debole.

Due grammatiche G e G sono debolmente equivalenti se generano lo stesso linguaggio L(G)=L(G).

Si noti che con questa definizione le due grammatiche possono generare una stessa stringa attraverso due differenti alberi di derivazione. L'albero di derivazione utilizzato si dice assegnato a una stringa.

Due grammatiche G e G sono fortemente o strutturalmente equivalenti se sono debolmente equivalenti e gli alberi di derivazione condensati sono uguali.

Quindi alla luce delle definizioni, se una grammatica è fortemente equivalente è anche debolmente equivalente, ma non viceversa. Stabilire se due grammatiche sono debolmente equivalenti è un problema indecidibile, viceversa stabilire se due grammatiche sono fortemente equivalenti è un problema decidibile.

Esempio

Vedi la pagina degli esercizi.

Grammatiche in forma normale

Le forme normali sono regole che permettono di modificare una grammatica senza però variarne il linguaggio generato. Queste forme sono molto usate in teoria per semplificare dimostrazioni di teoremi. Tuttavia nella pratica non sono molto usate, perché introducono una forma prolissa e poco leggibile. L'importanza di queste forme sarà più chiara nelle prossime lezioni.

Nella prossima sezione vedremo come avvengono le trasformazioni, qui ci limitiamo a elencare le forme normali:

  • grammatica senza termini annullabili: una grammatica che non presenta in nessuna regola (ad eccezione dell'assioma) un termine annullabile, ovvero non presenta ϵ nella sua definizione.
  • grammatica non ricorsiva a sinistra: come dice il nome, è una grammatica che non presenta regole ricorsive a sinistra; le regole ricorsive si presenteranno tutte nella forma a destra A  ϕ A | ...
  • grammatica in forma di Chmosky o binaria: le regole della grammatica si presentano solo in due forme:
    • omogenea binaria: A  BC,   B,CV
    • terminale con singleton a destra: A  aΣ
  • grammatica in forma real-time: ogni regola inizia con un terminale, cioè ogni regola è nella forma A  a α con aΣ,   α{ΣV}*
  • grammatica in forma di Greibach: ogni regola inizia con un terminale seguito da uno o più non terminali, cioè ogni regola è nella forma A  a α con aΣ,   αV*

Attraverso la forma di Chmosky, nell'albero di sintassi un nodo può avere come figli (di primo grado) solo due non terminali o un terminale.

Trasformazioni di grammatiche

Definiamo inizialmente alcune operazioni che poi utilizzeremo per portare le grammatiche in forma normale.

Espansione di un non terminale

Come dice il titolo, un'operazione molto semplice consiste nel sostituire ovvero espandere un nonterminale:

A  αBγ
B  β1 | β2 | β3 | ...

Diventa:

A  αβ1γ | αβ2γ | αβ3γ | ...
B  β1 | β2 | β3 | ...

Eliminazione dell'assioma nella parte destra

Senza perdere di generalità è possibili eliminare tutti gli assiomi che compaiono nella parte destra di ogni regola semplicemente introducendo un nonterminale:

S0  S

e poi sostituirlo a tutte le occorrenze dell'assioma.

Costruzione della forma normale senza nonterminali annullabili

L'algoritmo per riportare una grammatica in forma normale senza nonterminali annullabili è rappresentato dai seguenti 4 passi:

  • Calcolare l'insieme null che rappresenta un sottoinsieme di V (non terminabili), con la proprietà di essere annullabili;
  • Per ogni regola rP aggiungere un'alternativa ottenuta eliminando nella parte destra tutti i nonterminali annullabili;
  • Rimuovere tutte le regole vuote nella forma Aϵ ad eccezione dell'assioma;
  • Pulire la grammatica e rimuovere qualsiasi circolarità.

Esempio: Grammatica di partenza:

SSAB | AC
AaA |ε
BbB |ε
CcCc | c

Grammatica in forma normale:

SSAB | AC | SA | SB | C
AaA | a
BbB | b
CcCc | c

Copia ed eliminazione di regole

Definiamo un insieme Copy(A)V come l'insieme dei non terminali in cui il non terminale A può essere copiato, eventualmente transitivamente:

Copy(A):={BV |  a derivation A*B}

La computazione di questo insieme può essere eseguita come:

ACopy(A)
CCopy(A) if (BCopy(A))(BC P)

Forma normale di Chomsky

Si procede come segue:

  • Se la stringa vuota appartiene al linguaggio si aggiunge Sε all'insieme delle regole;
  • Per ogni regola del tipo A0A1A2A3...An:
    • si aggiunga una regola del tipo A0<A1><A2A3...An> (dove i termini tra parentesi angolari sono nonterminali temporanei)
    • si aggiunga un'altra regola <A2A3...An>A2A3...An
    • infine se A1Σ si aggiunge <A1>A1

Conversione delle ricorsioni

Questa operazione porta la ricorsione da sinistra a destra, per portare la grammatica nella relativa forma normale. Questa forma normale tornerà utile nel design dei parser top-down.

Spieghiamo con un esempio esplicativo:

Grammatica di partenza:

A  Aβ1 | Aβ2 | ...Aβh
A  γ1 | γ2 | ...γk

Si introduce un nuovo non terminale A:

A  γ1 | γ2 | ...γk|γ1A | γ2A | ...γkA
A  β1A | β2A | ...βhA|β1 | β2 | ...βk

Non è sempre possibile riportare le grammatiche in questa forma normale.