Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
vuoi
o PayPal
tutte le volte che vuoi
Macchine Astratte - capitolo 1
Sia un programma per il linguaggio L un insieme finito di istruzioni di L.
Una macchina astratta ML per il linguaggio L è un insieme finito di algoritmi e strutture dati in grado di eseguire e salvare un programma per L.
Interprete compiendo gli algoritmi, la memoria le strutture dati.
Un ML per essere eseguibile (programmabile) richiede di avere implementato un algoritmo simulatore del linguaggio L o sempre al di sopra di un altro linguaggio specifico in grado di eseguire le istruzioni di L.
Nel caso sia presente almeno un ML ci saranno meno rappresentazioni, ogni istruzione di L diventa una sub routine di L0.
Compilazione vs Interpretazione
Dato il problema di realizzare una macchina astratta ML per un linguaggio L disponendo di un'altra macchina astratta ML0 per il linguaggio L0, è possibile effettuare la scelta di:
- Compilazione: traduzione di ogni istruzione del programma in istruzioni di L0 ed esecuzione del tradotto su ML0.
- Interpretazione: esecuzione di un programma interprete IL0 scritto in L0 che legge le istruzioni contenute nel testo istruzioni di L, senza generare codice L esplicito.
- Compilazione: è presente CL0, scritto in un linguaggio qualsiasi (non il suo input), converte esplicitamente un programma.
- Interpretazione: riguarda un programma interprete specifico per il linguaggio destinazione L e per la macchina destinazione che prende il programma per L e il suo input e lo legge passo passo.
Vantaggi: Il vantaggio della compilazione riguarda la efficienza e le prestazioni, ogni tipo del sorgente rilette una volta sola durante la codifica, nella interpretazione ogni riga può essere rileccata più volte, in compilazione consente controlli statici, quindi maggiore rapidità del computer.
Il vantaggio della interpretazione è maggiore flessibilità e maggior facilità di implementazione, consente inoltre debugging sul codice originale.
Caso intermedio: A volte il sorgente può essere pre-processato, mediante compilazione semplificata con conversione bitecode, il risultato viene interpretato questo viene simile al Java Bytecode per JCVM che lo interpreta, per le architetture ma in questo caso rimane semplice pre-processing pre-processing.
La differenza fra compilazione e pre-processing riguarda la semantica: il pre-processing fa solo sostituzioni nel codice, la compilazione fa molti controlli assicurando correttezza.
Supposto anche Aggita che il compilatore nel file compilato non inserisca soltanto istruzioni per il linguaggio della macchina astratta d'astrazione ma anche istruzioni virtuali, chiamate System call. Il linker poi traduce queste chiamate tramite le librerie e ottiene il codice effettivo per il linguaggio dist.
Compilatore traduce codice assembly, che è codice per una macchina astratta e non può esser estratto. Questo facilita debugging e consente di avere solo l'assembly.
Per Just-in-time si intende ritardare la compilazione fino all'istante precedente alla esecuzione.
P-code
Il P-Code è un codice intermedio generato per semplificare il compito di creare un compilatore per il linguaggio pascal da una specifica architettura.
Si crea un compilatore che crea codice P-Code dal sorgente tramite la compilazione. Poi si crea, per la specifica architettura, un interprete P-Code. Può fare interprete e fu facile di un intero compilatore e creare il P-code e più semplice del linguaggio sorgente.
I dati di Pascal forniscono un compilatore Pascal-> P-Code scritto in P-code e, poi, interpreto il compilatore con input il programma Pascal da compilare e ottengo così il mio programma in P-Code che poi interpreto col mio interprete.
Tuttavia in questo modo ottengo una interpretazione e non una compilazione del mio programma. Per ovviare:
scrivo in Pascal un compilatore Pascal-> HW che poi do in input al compilatore Pascal -> P-code
interpetre: pcode(Cpascal-hw) = Cpascal-hw
interpreto: (Cpascal) = Cpcode
= mantiene la semantica
- = l'output del compilatore è il linguaggio in cui è scritto l'output
semantica denotazionale: approccio matematico formale programma e il suo comportamento sono funzioni dipendenti dallo stato interno.
semantica operazionale: regole per la valutazione di ogni tipo di programma.
riassunto
- input
- token stream
- parse tree
- albero astratto/codice intermedio
- codice assembler
- scanner
- parser
- analisi semantica
- generazione codice oggetto
tabella dei simboli
YACC
Cos'è: generatore di parser, il suo output è un programma C che implementa il parser.
Definizioni: regole: sono le regole della grammatica CF:
Y: nonterm
regole
nonterm: c1 | c2 | ck diventa:
funt aux nonterm:
- c1 { azione 1; }
- c2 { azione 2; }
- ck { azione k; }
Definizioni: precedenza fra operatori, le definizioni più in alto hanno minore priorità, minore precedenza. Si determina se gli operatori associano a dx o a sx.
Osservazioni: grammatiche LALR (o LR) non possono essere ambigue ma yacc le accetta e usa l'ordine di definizione delle regole per risolvere la ambiguità.
Le regole contengono azioni quindi comandi da eseguire ogni volta che una regola viene scelta.
● Più Liste : invece che inserire tutti i blocchi liberi nella stessa lista, si mantengono tante liste, una per potenza di 2, che contene il blocchi di tale dimensione o body system. Inizialmente i blocchi liberi sono nella lista più grande dei blocchi più piccoli e quando un insieme di blocco viene assegnato, questi vengono tolti dalla lista e i blocchi meno grandi vengono spezzati della dimensione richiesta. Ad es: nel caso 256, verrà presa che contiene lo spazio relativo alla dimensione in 600. L'opposto di tale dimensione non è nella lista relativa allora il blocco della lista di dimezzare viene spezzato in 1 e con la metà dei suoi blocchi. Un blocco simile è unirsene - B nella lista superiore. Un blocco ha 1 e 1 e solo tempore nel caso essere unito?
Regole di scope: statico
problema: come implementare le regole di scope statico e dinamico, come ponte recuperare le variabili non locale corrette
Non posso usare l'ordine dato dai link dinamici, mi serve informazione aggiuntiva sul frame in cui la funzione è definita (su blocco).
int X=10 A(C) { X=X+3; B(C); } int X=5 C() { X = X+2; A(C) {/* */} C();/* */ } B() { } struttura statica del programma
Struttura dinamica del programma
A ← LS A ← LD C ← LS LS LD LD Xcatena statica: per ogni RDA è necessario indicare, oltre al puntatore di catena dinamica che determina l'ordine di esecuzione dei blocchi, anche un puntatore alla funzione statica del punto T in cui è stato definito nell codice del programma. Nell’esempio statica esempio A. Seguendo tale puntatore è possibile ottenere le variabili non locali secondo le regole di scope statico.
determinare il pentatore : quando una procedura (o un blocco) viene chiamata come elemento di catena chiamiamo la procedura: ARS