Compilatore Programma sorgente Compilatore Programma ‘oggetto’ Statistiche Informazioni debugger Listing Messaggi errore Cross reference.

Slides:



Advertisements
Presentazioni simili
Linguaggio C e C++.
Advertisements

I Linguaggi di programmazione
Estendere i linguaggi: i tipi di dato astratti
Evoluzione dei linguaggi di programmazione
PROGRAMMARE IN PASCAL (le basi)
I linguaggi di programmazione
Analizzatori Lessicali con JLex
Sintassi (prima parte)
Traduttore diretto dalla sintassi (seconda parte)
LR Parser Giuseppe Morelli. La maggior parte dei parser Bottom-Up è costituita dai cosiddetti parser LR(k) dove: L indica il verso dellanalisi della stringa.
Parser Bottom UP Giuseppe Morelli. Parser Bottom UP Un parser Bottom Up lavora costruendo il corrispondente albero di parsing per una data stringa di.
Viable Prefixes, conflitti e formato delle tabelle per il parsing LR
Tabelle LALR Costruzione delle tabelle LALR Metodo LALR Introduciamo lultimo metodo di costruzione di tabelle per il parsing LR Nome: lookahead-LR abbreviato.
Costruzione delle tabelle di parsing LR canoniche
Costruzione di tabelle di Parsing SLR
Traduzione guidata dalla sintassi
Type Checking (1° parte)
Generazione di Codice Intermedio
Algoritmi e Programmazione
Generalità Linguaggio e Macchina Astratta
Anno accademico Il preprocessore del linguaggio C.
Fondamenti di Informatica I a.a Il linguaggio C Il preprocessore La sostituzione di macro Le compilazioni condizionali Linclusione di file C.
RB-alberi (Red-Black trees)
Strutture dati elementari
TRADUZIONE DEL PROGRAMMA Una volta che un programma sia stato scritto in C, esso non può essere eseguito senza unulteriore traduzione. Ciò perché qualsiasi.
Informatica di base A.A. 2003/2004 Algoritmi e programmi
Università degli Studi di Bergamo Facoltà di Lingue e Letterature Straniere Facoltà di Lettere e Filosofia A.A Informatica generale 1 Appunti.
Algoritmi e strutture Dati - Lezione 7
Corso di Informatica (Programmazione)
Algoritmi e Strutture Dati Alberi Binari di Ricerca.
Algoritmi e Strutture Dati
Programmazione Un programma descrive al computer, in estremo dettaglio, la sequenza di passi necessari a svolgere un particolare compito L’attività di.
Introduzione alla programmazione lll
DAL PROBLEMA ALL'ALGORITMO Problemi e Programmi Paolo Amico
1 Implementazione di Linguaggi 2 Implementazione di Linguaggi 2 Federico Bernardi Type checking 2° parte Type checking 2° parte - Equivalenza di type expressions.
1 Generazione codice Daniela Briola Lorena Bellino.
Procedure e funzioni nei linguaggi di alto livello Lab Programmazione - turno /2006.
Unità Didattica 2 I Linguaggi di Programmazione
mosaic manipola oggetti primitivi (ruota e unisci) regole:
memoria gestita staticamente:
Strutture di controllo in C -- Flow Chart --
INSIEMI NUMERABILI L’analisi matematica introduce il concetto di insieme numerabile come insieme i cui elementi possono essere “contati” ossia che possiede.
LINGUAGGI DI PROGRAMMAZIONE
Linguaggi e Modelli Computazionali LS - Prof E.Denti
Lezione 1 Linguaggi di programmazione – Algoritmi –Istruzioni
Lo sviluppo del software e i linguaggi di programmazione
Attività progettuale in Linguaggi e Modelli Computazionali M
Linguaggi per COMUNICARE
Linguaggi e modelli computazionali LS Manni Tiziano
- prof. V. Riboldi - SOTTOPROGRAMMI IN TPASCAL METODO TOP DOWN.
Lezione 3 Struttura lessicale del linguaggio
Introduzione a Javascript
Alberi Alberi radicati : alberi liberi in cui un vertice è stato scelto come radice. Alberi liberi : grafi non orientati connessi e senza cicli. Alberi.
Allievi Elettrici - AA Le funzioni ricorsive in C
1 Tipi di Dato §descrittori, tipi, controllo e inferenza dei tipi §specifica (semantica) e implementazione di tipi di dato l implementazioni “sequenziali”
Tecnologie Informatiche ed Elettroniche per le Produzioni Animali
Algoritmi e Strutture Dati Strutture Dati Elementari.
Paola Disisto, Erika Griffini, Yris Noriega.  Insieme ordinato di operazioni non ambigue ed effettivamente computabili che, quando eseguito, produce.
13 ottobre Decisioni F. Bombi 13 ottobre 2002.
Nucleo di Java: Struttura e Semantica Espressioni Assegnamento Controllo di sequenza Dichiarazioni.
Trading EToro Un linguaggio per descrivere e gestire operazioni di borsa Progetto di Linguaggi e Modelli Computazionali LS Prof. Enrico Denti Mancini Laura.
Grammatiche Grammatiche libere da contesto Grammatiche regolari
1 Macchine astratte, linguaggi, interpretazione, compilazione.
Algoritmi e Programmazione (in C) Stefano Cagnoni e Monica Mordonini
Informatica e Informatica di Base
Linguaggi e Grammatiche Alfabeto : insieme non vuoto di elementi detti simboli A = { a, b, c } Stringa : sequenza di simboli di un alfabeto ab abc abcab.
Parsing ricorsivo discendente Il parsing ricorsivo discendente (recursive descent parsing) è un metodo di tipo top-down che può essere facilmente codificato.
Unità di apprendimento 6
ALGORITMI, LINGUAGGI E PROGRAMMI Facoltà di Lingue e Letterature Straniere Corso di laurea in Relazioni Pubbliche.
Transcript della presentazione:

Compilatore Programma sorgente Compilatore Programma ‘oggetto’ Statistiche Informazioni debugger Listing Messaggi errore Cross reference

Source lang.  Compilatore  Target lang. Obiettivo : emettere velocemente codice per una macchina target, corretto ed efficiente Velocemente  veloce generazione di codice veloce (retargetting) Corretto  preservare la semantica del linguaggio sorgente Efficiente  in esecuzione

Soluzione : dividire il compilatore in due blocchi principali source program Front End Back End Analisi Sintesi target program Rappresentazione intermedia Isolare le dipendenze dal linguaggio sorgente nel Front End (analisi lessicale, sintattica e semantica) Isolare nel Back End le dipendenze dalla macchina target (generazione ed ottomizzazione del codice)

Analizzatore Lessicale Analizzatore Sintattico Preparazione alla Generazione del codice Generatore di codice TABELLETABELLE Analisi Sintesi L’Analisi Semantica è dispersa in tutte le fasi

Problema degli M x N traduttori CPascalFortranBasic i Z8000 Cobol CPascalFortranBasicCobol i Z8000 Linguaggio intermedio m = 5 n = 3 5 * 3 = 15 traduttori m + n = = 8 traduttori

Esempio di traduzione IA = B + C * DELTA + DELTA * C si riconoscono le diverse unità del testo si classificano le diverse unità del testo si crea la tabella dei simboli si trasforma il linguaggio sorgente in un linguaggio di tokens (id,P 1 ) = (id,P 2 ) + (id,P 3 ) * (id,P 4 ) + (id,P 4 ) * (id,P 3 ) B IA C DELTA P 2 P 1 P 3 P 4 Tabella dei simboli

(id,P 1 ) = (id,P 2 ) + (id,P 3 ) * (id,P 4 ) + (id,P 4 ) * (id,P 3 ) ALBERO SINTATTICO

Albero derivante dalla grammatica:  id =  + | - |  * | / |  id | cost | ( ) Anche per l’analisi semantica e per la traduzione si utilizza l’albero sintattico

Lessico Insieme delle parole chiave del linguaggio, degli identificatori, delle costanti e dei commenti IF  ‘I’ ‘F’ i simboli lessicali  IF, DO, WHILE, …  DO  ‘D’ ‘O’ appaiono come terminali  [ | ] * lettera cifra lettera Commento   stringa_senza_graffa_chiusa  Stringa_senza_graffa_chiusa  (  - ‘  ’) *

Analisi lessicale  Produzioni Regole di produzione Codici Costante  ( 0 | 1 | ….|9 ) [0 | 1 | ….|9 ] * 2 Identif.  ( A | B | …| Z) [ 0 | 1 | …| 9 | A | B|…Z]* 1 Espon.  ‘*’ ‘*’ 6 Più  ‘+’ 3 Per  ‘*’ 7

Analisi lessicale  Automa a stati finiti q0q0 q1q1 q2q2 q3q3 q4q4 þ 0,1,..9 þ A, B,..Z 0,1,…9 A,B,…Z + - = þ * * þ

Grafi sintattici * / cost var )( Espr  ( | + | - ) term (( + | - ) term ) * Fatt  cost | var | (espr) espr Term  fatt (( * | / ) fatt ) * fatt term

ANALISI SINTATTICA Grammatiche ambigue (dannose perchè non è chiaro il significato della frase) Metodi per togliere l’ambiguità:  Cambio della grammatica  Aggiunta di regole per disambiguare

Esempio  if then else  if then if E1 then S1 else if E2 then S2 else S3 if then else E1 S1 if then else E2 S2 S3

Esempio di ambiguità If E1 then if E2 then S1 else S2 (ambigua perchè ci sono 2 possibili alberi sintattici) 1) if then else E1 S2 if then E2 S1

Esempio di ambiguità 2) If then E1 if then else E1 S1 S2

Esempio di soluzione: “closest match” (si lega l’else all’if-then annidato più vicino) if E1 then if E2 then S1 else S2 if then E1 if else E2 S1 S2

1. E - - > E + T 2. E - - > T 3. T - - > T * F 4. T - - > F 5. F - - > (E) 6. F - - > id id + id * id E E + T T T * F F F id id id

Derivazione sinistra E - - > E + T - - > T + T - - > F + T - - > id + T - - > id + T * F - - > E E E E E E + T E + T E + T E + T E + T T T T T T * F F F F id id

> id + F * F - - > id + id * F - - > id + id * id E E E E + T E + T E + T T T * F T T * F T T * F F F F F id F id id id id id id Derivazione sinistra

ANALISI SINTATTICA verifica se X appartiene a L(G) TOP DOWN Il parser inizia l’analisi dal nodo radice corrispondente allo “start symbol” e ricorsivamente discende sui sottoalberi tracciando l’intero albero sintattico BOTTOM UP Il parser parte dai nodi foglia (terminali) e si costruiscono i sottoalberi dal basso verso l’alto fine ad arrivare all’intero albero sintattico

ANALISI SINTATTICA DETERMINISTICA Ad ogni passo dell’analisi esiste sempre una sola scelta possibile NON DETERMINISTICA E’ possibile arrivare a situazioni in cui più scelte sono possibili. Si procede per tentativi ed in caso di insuccesso occorre tornare sui propri passi e tentare strade alternative

BACKTRACKING Ritornare al punto in cui è stata compiuta l’ultima scelta che aveva alternative valide possibili, disfare tutte le azioni compiute fino a quel punto (cancellare l’albero tracciato fino a quel punto) e continuare scegliendo una delle rimanenti alternative. Nei casi pratici ciò è usualmente non accettabile perchè associate all’analisi sintattica ci sono altre azioni “semantiche” (aggiornamento delle tabelle dei simboli ecc.) ed è troppo costoso farle più di una volta. Si fanno perciò solo analisi deterministiche.

Metodo ricorsivo discendente Ad ogni non terminale è associato un sottoprogramma eventualmente ricorsivo. S - - > c A d ; A - - > a b; A - - > a Procedure A(); begin if scan() = ‘a’ then begin if scan() = ‘b’ then return (true) end; else return(false); end; Procedure S(); begin if scan() = ‘c’ then begin if A() then if scan() = ‘d’ then return(true); end; return(false); end;

Analisi ricorsivo discendente Impedita dalla ricorsione a sinistra: A - - > A α E - - > E + T E - - > T T - - > T * F T - - > F F - - > (E) F - - > id Procedure E(); begin if E() then …… Va in loop

Trasformazione della grammatica E - - > E + T E - - > T E’ = = > E’ - - > + T E’ E - - > T E’ - - > ε T - - > T * F T - - > F T’ = = > T’ - - > * F T’ T - - > F T’ - - > ε F - - > (E) = = > F - - > id

Programma di analisi procedure E(); begin T(); EPRIME(); end; Procedure EPRIME(); begin if scan() = ‘+’ then begin T(); EPRIME(), end; procedure T(); begin F(); TPRIME(); end; Procedure TPRIME(); begin if scan() = ‘*’ then begin F(); TPRIME(); end;

Programma di analisi Procedure F(); begin if scan() = id then return (‘OK’) else if scan() = ‘(‘ then begin E(); if scan() = ‘)’ then ERROR(); end; else ERROR(); end;

Altri impedimenti Prefissi comuni nelle parti destre di diverse produzioni per lo stesso non terminale - - > if then else - - > if then - - > else - - > ε

Regola generale per la fattorizzazione sinistra A - - > α β A - - > α A’ diventano A’ - - > β A - - > α γ A’ - - > γ Analisi ricorsivo discendente: Facile scrittura delle procedure dell’analizzatore sintattico Possibile solo se il linguaggio implementativo permette la ricorsione ed essa è realizzata in modo efficiente

Analisi TOP -DOWN Top Down deterministico si dice PREDITTIVO se e solo se: per ogni non terminale si può prevedere la corretta riduzione. Il Parser, per decidere come procedere, usa il non terminale corrente ed il prossimo token (LOOK AHEAD = prospezione) Se la prospezione ha lunghezza pari ad 1, l’analisi si dice LL(1) (Look ahead, Left to right) Il Pascal è LL(1).

Analisi BOTTOM UP Analisi ascendente a spostamento e riduzione : LR(k) Partendo dalla stringa da analizzare, si procede da sinistra a destra e quando si trova una sottostringa corrispondente ad una parte destra di una produzione si fa una riduzione. S > S # a c b # S - - > a S b S S # S - - > c S 0

Analisi BOTTOM UP Si usano le stesse regole della grammatica ( produzioni) ma in senso riduttivo, cioè da destra a sinistra. Si chiama parte riducibile (HANDLE) la porzione di una stringa, composta da terminali e non terminali, che è parte destra di una regola di produzione e può essere ridotta al non terminale della parte sinistra della regola stessa.

Esempio di analisi BOTTOM UP S - - > a A B e A - - > A b c | b B - - > d 1.a b b c d e(A - - > b) 2. a A b c d e(A - - > A b c) 3. a A d e(B - - > d) 4. a A B e(S - - > a A B e) 5. S Nel passaggio 2-3 si poteva scegliere la regola A - - > b ma …. la frase a A b c d e non è riducibile perchè da S non e’ possibile derivare a A A c d e, cioè S -/ - > a A A c d e PROBLEMA CHIAVE E’ LA DETERMINAZIONE DELLA PARTE RIDUCIBILE (HANDLE)

ANALISI ASCENDENTE LR(k) A SPOSTAMENTO E RIDUZIONE repeat leggi simbolo dal buffer di input sposta simbolo al top dello stack while top dello stack <> handle aggiungi simbolo allo stack endwhile riduci stringa al top dello stack elimina simboli ridotti dallo stack aggiungi al top dello stack il simbolo ridotto until top dello stack = simbolo distintivo or buffer di input = vuoto if top dello stack = simbolo distintivo and buffer di input = vuoto then exit(‘successo’) else exit (‘errore’) endif

Esempio (1) E - - > E + T(2)E - - > T (3)T - - > T * F (4)T - - > F (5)F - - > (E) (6)F - - > id id + id * id stack input azione # id + id * id # sposta 2.# id + id * id # riduce con (6) 3.# F + id * id # riduce con (4) 4.# T + id * id # riduce con (2) 5.# E + id * id # sposta 6.# E + id * id # sposta 7.# E + id * id # riduce con (6) 8.# E + F * id # riduce con (4) 9.# E + T * id # sposta 10.# E + T * id # sposta 11.# E + T * id # riduce con (6) 12.# E + T * F # riduce con (3) 13.# E + T # riduce con (1) 14.# E # accetta

ANALISI SINTATTICA GUIDATA DA TABELLE LR: Analizzatore sintattico governato da tabella che, in funzione del prossimo simbolo in input e del contenuto al top dello stack, esegue una mossa di spostamento o di riduzione. Una grammatica è detta LR se la tabella non ha elementi che indicano contemporaneamente spostamenti e riduzioni. Esistono strumenti che verificano automaticamente se la grammatica è LR e ne costruiscono la tabella dell’analizzatore sintattico ascendente. Es. LEX, YACC in UNIX

Schema di un parser LR guidato da tabella a 1 …. ………a n ………... a k # input S m.. output. S 0 # tabella stack azione goto LR parser

AZIONEGOTO STATOid+*()#ETF 0S 5S S 6accept 2r2S 7r2 3r4 4S 5S r6 6S 5S 493 7S 5S 410 8S 6S 11 9r1S 7r r3 r5 r3 r5 r3 r5

STACKINPUT (1)0id* + # (2)0id5* + # (3)0F3*id+ # (4)0T2*id+ # (5)0T2*7id+ # (6)0T“*7id5+ # (7)0T2*7F10+id# (8)0T2+id# (9)0E1+id# (10)0E1+6id# (11)0E1+6id5# (12)0E1+6F3# (13)0E1+6T9# (14)0E1#

Algoritmo di base per parser LR(1) token = next_token() Loop s = top_stack if action[s,token] = “shift s i ” then push token push s i token = next_token() else if action[s,token] =“reduce A - - >β” then pop 2* length(β ) symbols s = top stack push A push result of goto[s,A] else if action[s,token] =“accept” then return else error endloop

TRATTAMENTO DEGLI ERRORI -rilevamento dell’errore e diagnosi -rimedio all’errore -ripresa dell’analisi -Criteri di merito: -segnalare l’errore al più presto possibile -saltare meno testo possibile prima di riprendere l’analisi Gli analizzatori LL(1) e LR(1) rilevano un errore quandoil token corrente non può essere parte di un programma corretto (grammatica); Trattamento: -Fermarsi al primo errore -Fare error recovery, cioè superare l’errore e riprendere l’analisi

Rimedio agli errori Diverse tecniche: Cancellazione (metodo del “panico”) –Salta i simboli fino a che è possibile la ripresa dell’analisi; ricerca di un simbolo sicuro in grado di far sincronizzare il parser. E’ la forma più semplice di error recovery Sostituzione –Cerca di sostituire un simbolo con un altro (ipoteticamente più probabile); continua con il simbolo successivo a quello errato Inserimento –Cerca di inserire simboli che possono permettere la continuazione dell’analisi

ANALISI SEMANTICA Verifica che ogni elemento del programma (operatori ed operandi) sia usato nel contesto in cui può apparire in base alla specifiche del linguaggio (restrizioni rispetto alla grammatica libera dal contesto) Controlli di tipo statico (alla compilazione :compile time): Controllo sulla congruenza tra operandi di tipo diverso Controllo sul flusso del programma (errata uscita o entrata in strutture di controllo) Controllo di unicità ( ridefinizione delle variabili, labels di “case ripetute, ecc.) Le strutture di lavoro per l’analisi semantica sono: La tavola dei simboli L’albero sintattico generato dall’analizzatore sintattico

Esempio di analisi semantica x := y dichiarata? visibile? variabile? variabile? funzione? costante? tipo? tipo? # parametri? tipo? assegnabile? tipo? compatibile? in range? valore?

Gestione dello “scope” var a : real; var b : integer; a:= a + b; var a: integer, a:= a + b;

Visibilità delle variabili (struttura delle tabelle dei simboli) a ( real)indirizzo b (integer)indirizzo a (integer)indirizzo

CODICI (LINGUAGGI) INTERMEDI 1)Alberi sintattici a:= b + c > := a + b c 2)Statements a 3 indirizzi a := b op c Quadruple oparg1arg2ris +bct1 :=t1a

CODICI (LINGUAGGI) INTERMEDI 3)Statements a 2 indirizzi triple 4)Notazione polacca prefissa := a + b c postfissa a b c + := oparg1arg2 +bc(0) :=a(0)(1)

Quadruple A := - B * ( C + D) T1 := - B T2 := C + D T3 := T1 * T2 A := T3 OPARG1ARG2RIS (0)MinusB-T1 (1)+CDT2 (2)*T1T2T3 (3):=T3-A

Triple A := - B * ( C + D) A[I] := B A := B[I] OPARG1ARG2 (0)minusB- (1)+CD (2)*(0)(1) (3):=(2)A OPARG1ARG2 (0)[]AI (1):=B(0) OPARG!ARG2 (0)[]BI (1):=(0)A

Notazione polacca postfissa (eseguibile o interpretabile direttamente) L’operatore segue gli operandi x + y ----->x y + x + y * z----->x y z * + (a + b) * (x + y)----->a b + x y + *

Interpretazione di una forma polacca postfissa Var γ : pila di valori (interi) cursimb : elemento dell’espressione val : valore (intero) Begin repeat leggi pross. elemento in cursimb if cursimb = operando then push(γ, cursimb) else pop operandi di cursimb ed applicalo ad essi cursimb = val:=cursimb(op1,…., opn); push (γ, val) endif until fine espressione scrivi (top (γ)) End

Valutazione della espressione (3 + 2) * (7 – 3) > * pilainput * * 5 4 * 20

Linguaggio intermedio per istruzioni di controllo if a < b then a:=1 else b:= 1; ge abl1 assign1-a ramo then jpl2-- defl1-- ramo else assign1-b defl2--

Produzione codice intermedio: diretta da sintassi produzioniazione di traduzione S - - > id := ES.ptr = mknode(ASSIGN, BINARY, mknode(NAME, id), E.ptr) E - - > E1 + E2E.ptr = mknode(ADD, E1.ptr, E2.ptr) E - - > E1 * E2E.ptr = mknode(MUL, E1.ptr, E2.ptr) E - - > - E1E.ptr = mknode(MINUS, E1.ptr) E - - > (E1)E.ptr = E1.ptr E - - > idE.ptr = mknode(NAME, id)

Esempio: semplice calcolatrice produzioniazioni semantiche S - - > Eprint(E_val) E - - > T + - EE_val = T_val +- E_val E - - > TE_val = T_val T - - > F */ TT_val = F_val */T_val T - - > FT_val = F_val F - - > (E)F_val = E_val F - - > numF_val = num.value

Generazione del codice INPUT al generatore di codice: formato intermedio – albero sintattico –istruzioni a 3 indirizzi –notazione polacca OUTPUT del generatore di codice: 1.linguaggio macchina assoluto 2.linguaggio macchina rilocabile 3.linguaggio assembler sorgente 2. Maggiore flessibilità: compilazione separata + link a librerie 3. Maggiore semplicità: allocazione della memoria, risoluzione dei salti, gestione del formato rilocabile lasciata all’assemblatore

Tecniche di generazione del codice 1. Macro Espansione 2. “Ad hoc” 3. Pattern matching 2. Famiglia di algoritmi ritagliati sul tipo di architettura target: prive di presupposti formali e/o di possibilità di automatizzazione

Macro espansione Assumendo come input delle quadruple e come output assembler per un processore dotato di registri. ADD ($1, $2, $3) isMOV$1, R0 ADD$2, R0 MOVR0, $3ASSIGN($1, nil, $3) endisMOV$1, R0 MUL ($1, $2, $3)MOVR0, $3 isMOV$1, R0end MUL$2, R0 MOVR0, $3) end

Esempio di macro espansione Istruzione sorgente:a:= b + c * d Produce le seguenti quadruple e codice assembler: MOVc, R0 *cdt1MULd, R0 +bt1t2MOVR0, t1 :=t2-aMOVb, R0 ADDt1, R0 MOVR0, t2 MOVt2, R0 MOVR0, a

Pattern matching si usano patterns srutturati ad albero che descrivono istruzioni e forme intermedie ad albero; si selezionano le istruzioni scomponendo l’input in singoli patterns; si procede top-down con tecnica simile all’analisi sintattica. L’algoritmo è simile all’analisi guidata da sintassi: ogni volta che si riconosce un pattern lo si riscrive (come se fosse una regola sintattica) e come azione corrispondente si emette codice.

Esempio di pattern matching A := B + C * D := A + * B C D Libreria di patterns mem < - - :=[mov reg, mem] mem reg reg < - - +[add mem, reg] mem reg reg < - - *[mov mem1, reg mem1 mem2 mul mem2, reg] Seleziona il pattern 1 Chiede match sul figlio destro Seleziona pattern 2 Chiede match sul figlio destro Seleziona pattern 3 Emissione codice 3 Riscrittira del’albero Emissione codice 2 Riscrittura dell’albero Emissione codice