Sei sulla pagina 1di 12

MODULO 04 ELEMENTI DI TEORIA DEI LINGUAGGI FORMALI Un linguaggio di programmazione uno strumento per esprimere algoritmi in una forma

a adatta allo loro esecuzione da parte di un elaboratore. La formulazione di un algoritmo in un linguaggio di programmazione detta programma. Il processo di esecuzione di un programma col quale si ottengono i risultati calcolati dall algoritmo codificato dal programma, fatto in generale da due passi: compilazione ovvero una trasformazione del testo del programma (codice sorgente) operata da un altro programma detto compilatore , in una forma equivalente ma eseguibile dalla macchina (codice oggetto o codice macchina). esecuzione nella quale il codice oggetto viene eseguito dallelaboratore. Questa caratteristica tipica dei linguaggi di programmazione nati per esprimere algoritmi in una forma indipendente dalla macchina ma espressiva per lutente. La descrizione di un linguaggio di programmazione distingue aspetti sintattici, semantici e pragmatici. I primi riguardano la forma che le frasi del linguaggio possono assumere, i secondi il significato di ogni frase e gli ultimi sono legati alla utilizzazione pratica del linguaggio. IL LINGUAGGIO Alcune definizioni preliminari Alfabeto un insieme finito e non vuoto di elementi detti simboli ALR = { I, V, X, L, D, C, M } APCP = {begin, end, while, repeat, for, } alfabeto lettere romane alfabeto parole chiave del Pascal

Stringa ( o parola, o frase) su un alfabeto A la concatenazione di un numero finito di simboli di A. La stringa vuota fatta da 0 simboli e si indica di norma con o con . III, IVX, CCC sono parole su ALR Lunghezza o cardinalit di una stringa il numero di simboli concatenati per formare e si indica con | | | XVII | = 4 | |=0

La concatenazione di due stringhe e si indica giustapponendole ; la stringa vuota unit sinistra e destra rispetto alla concatenazione = = non commutativa ma associativa () = () Dato un alfabeto A, la stellatura di A, scritta A*, si pu definire per induzione usando come costruttore la concatenazione (cl. base) A* (cl. induttiva) se A* e aA, a A* ad es. se A = { a, b} , A* = {, a, b, aa, bb, ba, bb, aaa, aab, }, oppure definendo le potenze cartesiane n-esime di A come segue A0 = { } A1 = A A2 = A x A . . . An +1 = A x An e poi unendole A* = U iN Ai = A0 u A1 u u x An u. La stellatura di un alfabeto A qualunque contiene dunque tutte le frasi su A di lunghezza finita. Se indichiamo con loperazione di concatenazione su A* con le propriet gi indicate, lalgebra (A* , , ) un monoide su A u { } detto linguaggio universale su A. Per definizione un linguaggio L su A un sottinsieme di A* : L A* .

Tra due linguaggi, in quanto insiemi, si possono applicare le operazioni di unione e intersezione. Se L1 e L2 sono due linguaggi su uno stesso alfabeto A, allora L1 L2 = { L1 oppure L2 } lunione L1 L2 = { L1 e L2 } lintersezione. Oltre a queste abbiamo la concatenazione denotata ancora con e definita come segue: sia ( A* ) linsieme delle parti di A* , allora : ( A* ) x ( A* ) ( A* ) tale che dati due linguaggi L1 e L2 su A L1 L2 = { I L1, L2 } con le seguenti propriet: L { } = { } L L{} ={} L={} L1 ( L2 L3 ) = ( L1 L2 ) L3 identit zero associativit L1 , L2 ( A* ),

e literazione denotata con , che dato un linguaggio L produce il linguaggio L cosi definito L = U nN Ln L ( A* ),

con Ln definito per induzione L =


n

L0={ } Ln-1 L

, n=0 , n>0

Il simbolo si chiama stella di Kleene. Un linguaggio su un alfabeto A pu essere descritto in modo insiemistico , ad es. se A = { a,b } la scrittura Lbs = {an bn I n N} definisce linsieme delle stringhe formate da due sottostringhe e di uguale lunghezza n>=0 e tale che i simboli di siano tutti uguali ad a e quelli di tutti uguali a b; questo linguaggio chiamato bisomatico [ Manca, op. cit.],

mentre Lbp ={an bm I n,m N} descrive il linguaggio bipartito [ Manca, op. cit.] le cui frasi sono fatte di due sottostringhe e con i simboli di tutti uguali ad a e quelli di tutti uguali a b. Questo linguaggio pu essere ottenuto tramite iterazione e concatenazione Lbp ={a} {b} Il problema centrale della teoria dei linguaggi formali consiste nel fornire metodi rigorosi per definirli. Un modo naturale per descrivere un linguaggio quello di definire la forma delle sue frasi; ci avviene fornendo una descrizione sintattica all interno di un pi ampio contesto generativo ( poich consente di generare un linguaggio) detto grammatica . Una grammatica pu pensarsi come un algoritmo in grado di produrre frasi caratterizzate da descrizioni sintattiche e pu essere espressa anche come automa generatore. Oltre agli algoritmi di generazione ci sono quelli di riconoscimento che possono essere implementati anche sotto forma di automi riconoscitori. Sugli automi torneremo pi avanti, ora ci occupiamo di definire che cosa sia una grammatica partendo da un esempio completo. Vogliamo costruire un linguaggio che chiamiamo LN10, le cui frasi rappresentano numeri in base 10 dotati di parte intera e/o di parte frazionaria. Quelle che seguono 179, .394, 15.38 sono frasi di questo linguaggio e lalfabeto A sul quale sono costruite A = {0, 1,2, ,9, . } Ma LN10 per quanto visto un sottoinsieme di A* , LN10 A* , anzi dato che la parola vuota ha qui nessun interesse, detto A+ = A* - { } linsieme di tutte le stringhe di lunghezza finita privo della stringa vuota, sar LN10 A+ Tuttavia questa propriet che non d alcuna informazione che consenta di distinguere le frasi che appartengono a LN10 da altre definite sullo stesso alfabeto: occorre fornire un criterio per distinguere sequenze qualsiasi di A+ da quelle buone appartenenti a LN10 .

Tale criterio consiste nel definire la forma delle frasi corrette di LN10 e si presenta come un insieme di regole o produzioni che definiscono la sintassi delle frasi del linguaggio: 1. Nd Sd I . Sd I Sd . Sd 2. Sd Cd I Sd Cd 3. Cd 0 I 1 I 2 II 9 Ciascuna regola ha una struttura del tipo parte_ sinistra parte_ destra e si noti che in questo esempio la parte sinistra di ciascuna delle regole date fatta di un solo simbolo. La un simbolo ausiliario che si pu leggere in pi modi equivalenti la parte sx . produce la parte dx. pu essere riscritta come la parte dx. ha la forma indicata nella parte dx. . . . la barra verticale un altro simbolo ausiliario che significa oppure. Pertanto la regola 1. stabilisce che un qualsiasi numero di LN10 che indichiamo con Nd ha una forma del tipo Sd cio una Sequenza di digit, oppure (I) un punto . seguito da una Sd, oppure (I) una Sd seguita da un punto seguita da una Sd La 2. prescrive che una Sd sia formata da una singola Cifra decimale, Cd, oppure da una Sd seguita da una Cd ( questa una regola ricorsiva ) Infine la 3. prescrive che una cifra decimale Cd pu essere una delle cifre dell alfabeto A. Le tre regole descrivono esaurientemente tutte le possibili forme delle frasi di LN10 . I simboli Nd, Sd e Cd si dicono categorie sintattiche o variabili, appartengono al linguaggio col quale descriviamo LN10 , detto metalinguaggio, e in questo senso sono dei mtasimboli da tenere distinti ( qui attraverso l uso del grassetto) da quelli, appartenenti allalfabeto, che usiamo per formare le frasi di LN10 e che sono invece simboli terminali.

Usiamo la scrittura => per indicare che generata direttamente da sostituendo una categoria sintattica presente in con una delle sue possibili riscritture come prescritto dalle regole del linguaggio. Ad es. la sequenza Sd => Sd Cd => Sd 5 => Sd Cd 5 => Cd Cd 5 => 3 Cd 5 => 3 0 5 esprime il processo di generazione o derivazione della frase 305 di LN10, ottenuta con una catena di generazioni dirette. Una derivazione di 18.32 da Nd data da Nd => Sd . Cd => Sd Cd . Sd => Sd Cd . Sd Cd => Cd Cd . Sd Cd => =>Cd Cd . Cd Cd => 1 Cd . Cd Cd => 18. Cd Cd =>18. 3 Cd => 18.32 Fissando le idee su quanto detto, individuiamo un insieme finito di norma indicato con V di simboli nonterminali (variabili, cat. sint.) un insieme finito T di simboli terminali un elemento S di V, detto simbolo iniziale (start symbol) o assioma un insieme P sottoinsieme di V x (V T) detto insieme delle produzioni

Riferendoci allesempio presentato abbiamo V = {Nd, Sd, Cd} T = {0, 1,,9, .} S = Nd P = {(Nd, Sd), (Nd, .Sd), (Nd, Sd .Sd), (Sd, Cd), (Sd, Sd Cd), (Cd, 0), ,(Cd, 9)} ( si noti che scriviamo v w1Iw2I Iwn se (v ,w1 ), (v,w2), , (v, wn) sono tutte le produzioni in P con v in V come primo elemento). Le frasi di LN10 sono esattamente quelle stringhe che possono essere derivate da Nd ( simbolo iniziale ) applicando le produzioni e contenenti solo i simboli terminali appartenenti allalfabeto. Ci giustifica la seguente Definizione 1. Una grammatica G, libera dal contesto (in inglese, context free), una quadrupla G = (V, T, S, P) con V, T, S e P come specificato sopra.

Data una grammatica G = (V, T, S, P) libera dal contesto, la relazione binaria di derivazione diretta => definita su (V T) e come abbiamo detto, => si legge come genera (o deriva) direttamente ; questa relazione pu essere definita specificando che => esattamente nel caso in cui sia ottenuta da sostituendo una singola variabile ( categoria sintattica ) in secondo quanto prescritto da una produzione in P, cio nel caso in cui esistono le stringhe e in (V T) , la stringa v in V e la produzione (v, w ) in P tale che = v , = w . Date due relazioni qualsiasi R: A B e S: B C, la relazione composta S R:A C S R = {(a,c)esiste un b in B con aRb e bSc } A X C Se una relazione R ha dominio e codominio uguali, R: A A, le potenze di R sono definite induttivamente come : R0 = idA = {(a,a) a A} R1 = R R2 = R R R3 = R2 R . . . Rn+1 = Rn R identit

La chiusura transitiva di R viene indicata con R+ e definita come R+ = U n>0 Rn invece la chiusura riflessiva transitiva di R indicata con R* , R* = U n0 Rn Ad esempio se R: N N una relazione dai naturali ai naturali nella quale mRn sse m=n+1, allora R+ la relazione >, maggiore, mentre R* la relazione , maggiore o uguale. La relazione binaria =>* su ( V T) la chiusura riflessiva e transitiva di =>, scriviamo w =>* w che significa w deriva w nel caso in cui w = w oppure se esiste una sequenza w1, w2, , wn (n >= 2) di stringhe in (V T) , tale che w = w1 ; w j => w j+1 per 1 j < n ; w n= w

Definizione 2. Il linguaggio L(G) generato da una grammatica G linsieme delle stringhe di caratteri terminali che possono essere derivate da S L(G) = {w | w T , S =>* w }. Un insieme LLC T un linguaggio libero dal contesto se LLC un L(G) generato da una grammatica acontestuale G. Come secondo es. di grammatica libera dal contesto sia G2 ( V, T, S, P) con: V = {S} T = {a, b} S = aSb | ab si pu notare che le sole derivazioni possibili sono del tipo S => ab S => aSb => aabb S => aSb => aaSbb => aaabbb etc. Usando la notazione an come abbreviazione di una stringa di n occorrenze di a , il linguaggio generato da G2 L(G2 ) = { an bn| n 1} che abbiamo gi visto: il linguaggio bisomatico. Esercizi 1. Definire la grammatica che genera il linguaggio delle frasi palindrome su {a, b}. 2. Definire la grammatica le cui frasi sono numeri naturali divisibili per 5 3. Data la grammatica G nella quale: V = {S, A, B, C, D}, T = {a, b}, S il simbolo distinto e P contiene le seguenti produzioni: S CD Ab bA C aCAI bCB Ba aB AD aD Bb bB BD bD C Aa aA D derivare qualche frase e descrivere il linguaggio generato da G. 4. Descrivete la grammatica le cui frasi sono espressioni aritmetiche esprimibili con i simboli a, +, *, ( e ). Nota La semplice osservazione della forma delle derivazioni di una grammatica non consente affatto di stabilire quale sia il linguaggio generato, occorre produrre una dimostrazione (spesso induttiva). Un testo fondamentale per queste problematiche quello di Hopcrooft e Ullman citato in bibliografia.

La classificazione di N. Chomsky Lanalisi fatta sulla forma delle produzioni di una grammatica ha portato alla seguente classificazione dovuta a Chomsky. Grammatiche di tipo 0 La struttura delle produzioni non soggetta ad alcun vincolo; i linguaggi generati da esse si dicono di tipo 0 e indicati con L0 Grammatiche di tipo 1 ( contestuali ) Un modo di caratterizzarle imponendo che ciascuna produzione abbia questa caratteristica |||| i linguaggi generati si diranno, analogamente, di tipo 1 e indicati con L1 Grammatiche di tipo 2 ( context-free , acontestuali, libere dal contesto ) Ogni produzione del tipo A con A V e ( V T)+ La parte sinistra costituita da un solo simbolo terminale. Si prestano a descrivere linguaggi di programmazione, i linguaggi che generano si chiamano liberi dal contesto e sono denotati con L2 Grammatiche di tipo 3 ( regolari ) Ciascuna produzione del tipo A aB oppure A a con A, B V e aT regolari si dicono i linguaggi generati da esse, denotati con L3. Cenni di semantica denotazionale Un linguaggio di programmazione serve per esprimere i processi di calcolo che devono essere svolti da un elaboratore. Se vogliamo assegnare una semantica a un linguaggio allora dobbiamo trovare il modo di specificare senza ambiguit quale sia il significato di un qualsiasi programma scritto in quel linguaggio. Due modi fondamentali sono 1. spiegare come si comporta una macchina pi o meno reale che esegua il programma stesso; 2. costruire un modello che, indipendentemente da qualsiasi macchina, fornisca per ogni programma un oggetto matematico che ne definisca il significato. 9

Il primo modo di procedere, detto operazionale, implica la definizione di una macchina in grado di eseguire il linguaggio e dare la semantica di uno specifico programma consiste nel mostrare il comportamento della macchina durante lesecuzione di quel programma: esattamente questo che abbiamo fatto nel caso delle istruzioni della macchina a registri e (informalmente) nel caso delle istruzioni di sequenza, selezione e iterazione avendo supposto che la macchina che le esegue sia un normale personal. La seconda alternativa, detta denotazionale, consiste invece nel definire una funzione di interpretazione semantica che associ a ogni programma un elemento di un insieme di oggetti matematici che diremo oggetti semantici scelti come significato o denotazione di quel programma. Attraverso un esempio molto semplice vediamo lapproccio denotazionale. Cominciamo definendo un linguaggio per rappresentare i numeri naturali servendoci dei caratteri z e u; la grammatica che genera tale linguaggio G(V, T, S, P) con V={ Num, Cif } T={ z, u } S= Num P={Num ::=Cif I Num Cif ; Cif ::= z I u } categorie sintattiche simboli terminali assioma, simbolo iniziale insieme delle produzioni

(notate che nelle produzioni ho usato il simbolo ::= , invece che la freccia , per separare la parte sinistra dalla destra e che non indicato in grassetto le categorie sintattiche: questa notazione molto vicina alla BNF). Il linguaggio generato da G coincide con {z, u} e ogni parola ha una precisa struttura. Per dare una semantica denotazionale a questo linguaggio occorre innanzitutto scegliere linsieme delle denotazioni che intendiamo usare. La scelta obbligata: visto che intendiamo rappresentare numeri naturali, scegliamo linsieme N dei naturali, appunto, sul quale assumiamo definite le operazioni di somma e prodotto e li rappresentiamo nella consueta rappresentazione decimale. Restano da definire le funzioni di interpretazione semantica che ci permetteranno di passare da un programma sintatticamente corretto al suo significato. C un modo standard per definire tali funzioni, detto definizione guidata dalla sintassi, che consiste nel definire: 1. una funzione di interpretazione semantica per ogni categoria sintattica presente nella grammatica; 2. ciascuna funzione di interpretazione per casi, uno per ogni produzione della grammatica che abbia la categoria sintattica in questione come membro sinistro.

10

Per il nostro esempio le due funzioni da definire sono allora: N : Num N C : Cif N corrispondenti alle due categorie sintattiche. La prima associa ogni parola del linguaggio generato dalle produzioni con membro sinistro Num al suo significato: chiamiamo ancora Num tale linguaggio. La seconda associa ogni parola del linguaggio Cif al suo significato. Per definire C dobbiamo considerare due casi, ovvero Cu=1 Cz=0 da interpretare come segue: per ogni elemento c di Cif , C c = 1 se c= u cio se derivabile con la seconda produzione per Cif, C c = 0 se c= z. In definitiva il significato della parola u il naturale 1, mentre quello della z , denota, il naturale 0. Le definizioni corrispondenti ai vari casi vengono chiamate clausole delle definizioni semantiche; in ciascuna clausola delle funzioni di interpretazione, le componenti sintattiche sono racchiuse in una coppia omologa di per distinguerle dalle componenti semantiche: pi precisamente gli elementi dei domini sintattici che compaiono nelle definizioni sono sempre racchiusi come indicato. Se la definizione di C immediata, quella di N pi complicata poich Num definito ricorsivamente ( una produzione ricorsiva se la categoria sintattica nel lato sinistro presente anche in quello destro). Usando n come generico elemento di Num e c come generico elemento di Cif abbiamo la seguente definizione N c = C c N nc = 2 N n + C c da interpretare come: il significato di una parola n appartenente a Num dato dalla prima clausola che rimanda alla funzione C se n derivabile con la prima produzione per Num, altrimenti se n derivabile con la seconda allora ha una struttura formata da due parti, n e c rispettivamente, come espresso dalla seconda clausola. Calcoliamo il significato del programma uzu: osservando che uzu formata dalla u pi a destra che appartiene alla categoria Cif e dalla parte uz appartenente alla categoria Num, avremo N uzu = 2 N uz + C u = 2 ( 2 N u + C z ) + C u = = 2 ( 2 C u + C z ) + C u = = 2 ( 2x 1 + 0 ) + 1 = 5

11

Num

Num

Cif

Albero sintattico (parziale) della parola uzu. Esercizi 1. verificare denotazionalmente che uuz e zzuuz hanno lo stesso significato 2. calcolare il significato di uuzu Questo modulo si chiude qui. Nel prossimo indagheremo il rapporto tra i linguaggi e gli automi riconoscitori deterministici a stati finiti con qualche cenno a questioni di calcolabilit e decidibilit.

12

Potrebbero piacerti anche