




Studia grazie alle numerose risorse presenti su Docsity
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Prepara i tuoi esami
Studia grazie alle numerose risorse presenti su Docsity
Prepara i tuoi esami con i documenti condivisi da studenti come te su Docsity
Trova i documenti specifici per gli esami della tua università
Preparati con lezioni e prove svolte basate sui programmi universitari!
Rispondi a reali domande d’esame e scopri la tua preparazione
Riassumi i tuoi documenti, fagli domande, convertili in quiz e mappe concettuali
Studia con prove svolte, tesine e consigli utili
Togliti ogni dubbio leggendo le risposte alle domande fatte da altri studenti come te
Esplora i documenti più scaricati per gli argomenti di studio più popolari
Ottieni i punti per scaricare
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Appunti Compilatori e linguaggi di programmazione
Tipologia: Appunti
1 / 8
Questa pagina non è visibile nell’anteprima
Non perderti parti importanti!





A: Una grammatica che produce più di un albero di parsing per una data frase è detta ambigua, in altri termini una grammatica è ambigua se ammette più di una derivazione destra o più di una derivazione sinistra per una stessa frase. Una sentenza o frase di una grammatica è una forma sentenziale che non contiene alcun non terminale (formata solo da terminali). Esempio: G: E à E + E | E * E | id Frase: id + id * id E ⇒ E + E ⇒ id + E ⇒ id + E * E ⇒ id + id * E ⇒ id + id * id E ⇒ E * E ⇒ E + E * E ⇒ id + E * E ⇒ id + id * E ⇒ id + id * id
sostituzione di tale occorrenza di β con A produce la forma sentenziale destra precedente in una derivazione destra di γ. Il processo di handle pruning consiste nell’ottenere una derivazione destra al rovescio a partire dalla stringa w costituita da soli terminali, riconoscendo l’handle ad ogni passo e sostituendo il corpo della produzione associata con la testa di tale produzione.
A: Una grammatica è LL(1) quando, date due produzioni distinte A àα|β:
Analisi Lessicale La prima fase di compilazione e detta analisi lessicale o scanning. L'analizzatore lessicale legge il programma in ingresso come un flusso di caratteri che raggruppa in sequenze complete e dotate di significato dette lessemi. Analisi Sintattica La seconda fase della compilazione e l'analisi sintattica o parsing. L' analizzatore sintattico, detto parser, utilizza il primo elemento dei token prodotti dall'analizzatore lessicale per produrre una rappresentazione intermedia ad albero che indica la struttura grammaticale della sequenza dei token. Una tipica rappresentazione intermedia è l' albero sintattico o syntax tree in cui un nodo interno rappresenta un'operazione mentre i figli di tale nodo rappresentano gli argomenti dell'operazione. Analisi Semantica L' analizzatore semantico utilizza l'albero sintattico e le informazioni nella tabella dei simboli per verificare la consistenza del programma sorgente rispetto alla definizione del linguaggio. Inoltre raccoglie ulteriori informazioni di tipo e le memorizza nell'albero sintattico oppure nella tabella dei simboli per poterle poi usare nella fase successiva di generazione del codice intermedio. Una parte importante dell'analisi semantica e il controllo sui tipi o type checking che ha lo scopo di verificare che ogni operatore abbia operandi di tipo adeguato. Generazione del codice intermedio Dopo tali fasi molti compilatori generano esplicitamente una rappresentazione intermedia di basso livello (simile al codice macchina) che può essere vista come un programma per una macchina virtuale. Una rappresentazione intermedia dovrebbe avere due importanti proprietà: deve essere semplice da generare e semplice da tradurre nel linguaggio della macchina destinazione. Considereremo una forma di rappresentazione intermedia, nota come codice a tre indirizzi o three-address code, che consiste in una sequenza di istruzioni a tre operandi simili a quelle di un generico linguaggio assembly. Ogni operando può essere considerato un registro. Ottimizzazione del codice La fase di ottimizzazione del codice indipendente dalla macchina di destinazione cerca di migliorare il codice intermedio in modo da consentire un migliore risultato nella generazione del codice destinazione. Generatore codice macchina Il generatore di codice prende come ingresso la rappresentazione intermedia e la traduce nel programma destinazione. Se il linguaggio destinazione e un codice macchina, in primo luogo vengono selezionati registri e/o locazioni di memoria per ognuna delle variabili utilizzate dal programma. Quindi, le istruzioni del linguaggio intermedio vengono tradotte in opportune sequenze di istruzioni macchina che realizzano le operazioni desiderate. Tabella dei simboli La tabella dei simboli è appunto una struttura dati che contiene, per ogni nome di variabile, un record i cui campi indicano i vari attributi del nome. Una tale struttura dati deve essere organizzata in modo tale da rendere efficiente sia l'accesso e la modifica delle informazioni sia la ricerca di uno specifico nome. Fasi del compilatore (oltre lo schema) La fase di analisi di un compilatore suddivide un programma sorgente in elementi costitutivi di base e produce una rappresentazione interna detta codice intermedio. La fase di sintesi, quindi, traduce la rappresentazione intermedia nel programma destinazione.
Definizioni regolari Per semplificare la notazione, introduciamo alcuni nomi simbolici per indicare specifiche espressioni regolari in modo da poter usare poi tali nomi come se fossero simboli nella descrizione di espressioni più complesse. Eliminazione della ricorsione sinistra Una grammatica e detta ricorsiva a sinistra se ha un non-terminale A per cui esiste una derivazione A=>Aa della stringa a. I parser top-down non possono gestire grammatiche con ricorsione sinistra, per cui si rende necessaria un metodo di trasformazione mirato a eliminare tale ricorsione. Fattorizzazione sinistra La fattorizzazione sinistra e una trasformazione utile per ottenere una grammatica più adatta per il parsing predittivo (top- down). Grammatiche LL(1) E sempre possibile costruire un parser predittivo (cioè un parser a discesa ricorsiva senza backtracking) a partire da una grammatica della classe LL(l). La prima "L" indica che la sequenza d'ingresso viene analizzata da sinistra (left, appunto) verso destra, la seconda "L'' specifica che si costruisce una derivazione sinistra (leftmost derivation) e infine l' "1" fra parentesi indica che le decisioni durante il parsing vengono prese analizzando un solo simbolo di lookahead. Parsing bottom-up Il parsing bottom-up procede alla costruzione di un albero di parsing per una data stringa d'ingresso cominciando dalle foglie (bottom) e procedendo verso l'alto (up) fino alla radice. Front-end & back-end La parte di analisi ha lo scopo di suddividere il programma sorgente in elementi di base e di imporre loro una struttura grammaticale. Quindi, basandosi su tale struttura, costruisce una rappresentazione intermedia del programma sorgente. Se l'analisi individua nel programma sorgente dei costrutti sintatticamente scorretti o semanticamente non significativi deve fornire messaggi informativi in modo che l'utente possa provvedere a correggere gli errori. La parte di analisi raccoglie inoltre informazioni sul programma sorgente e le memorizza in una struttura dati detta tabella dei simboli o symbol table che viene poi passata alla successiva parte di sintesi insieme alla rappresentazione intermedia. La parte di sintesi, a partire dalle informazioni nella tabella dei simboli e dalla rappresentazione intermedia, costruisce il programma destinazione. La parte di analisi e anche detta front-end del compilatore, mentre la parte di sintesi è detta back end. GRADI DI LIBERTÀ