Sperimentazione di Traduttori
Universitá di Torino
Dipartimento d’Informatica
Anno accademico 1998-99
Prof. Maria Luisa Sapino
Andrea Caddori
Rosario Marino
Vittorio Cascio
Guida all’Uso
Complimenti per aver scelto l’ultima versione del nostro PCCHAL, Pascal, Cross Compiler for HAL.
Licenza e condizioni d’uso
Il nostro compilatore è bugware! Cioè di libera distribuzione, copia e modifica, ma se ritenete il software interessante e ne vorreste una versione totalmete priva di bug, dovrete pagare!
Installazione
Il pacchetto PCCHAL comprede i seguenti files:
Per compilare il tutto è sufficiente eseguire make, o nell’ordine:
Tutorial
Da linea di comando è sufficiente digitare
pcchal nomefile
per compilare il vostro programma pascal e verificarne la correttezza sintattica.
Se volete vedere il listato del codice intermedio prodotto occore digitare
pcchal –l nomefile
se invece volete eseguire il codice generato occorre invocare l’emulatore HAL9000 col comando
pcchal –r nomefile
l’opzione –h offre un help in linea e la versione del software, mentre con –v si attiva il modo verbose del compilatore che offre informazioni sulla symbol table, generate durante il parsing.
Se si vuol attivare l’opzione di trace di yacc occorre –t, disponibile solo dopo un’opportuna compilazione con di yacc –t.
Per attivare il trace dell’emulatore e visualizzare lo stack del record di attivazione corrente, occorre l’opzione –s.
Il tutto, anziché essere stampato su video puó essere rediretto su un file di output con l’opzione –o
pcchal –o nomefile_di_otput
in modo analogo è possibile stampare gli errori in un file a parte con l’opzione -e
pcchal –e nomefile_di_errori
Guida di riferimento
{
commento delimitato da parentesi graffe }(* commento con parentesi tonde-asterico *)
programma ->
program id (lista_id); dichiarazioni procedure begin lista_istruzioni end.
lista_id -> id | lista_id , iddichiarazioni -> const_decls var_declsvar_decls -> VAR id lista_id_tipata | var_decls ; var_decls
|
lista_id_tipata -> , id lista_id_tipata
| : tipo
tipo -> integer
| real
procedure -> procedure procedura ;
|
procedura -> testa_procedura dichiarazioni procedure begin lista_istruzioni end
testa_procedura -> procedure id argomenti ;
argomenti ->
| ( lista_parametri )
lista_parametri -> id lista_par_typed
| lista_parametri ; lista_parametri
lista_par_typed -> , id lista_par_typed
| : tipo
lista_istruzioni -> istruzione
| lista_istruzioni ; istruzione
istruzione -> id := s_expr
| if espressione then istruzione
| if espressione then istruzione else istruzione
| repeat lista_istruzioni until espressione
| while espressione do istruzione
| for id := s_expr to s_expr do istruzione
| begin lista_istruzioni end
| procedure_call
| read ( id )
| write ( id )
procedure_call -> id
| id ( Elist )
Elist -> Elist , id
| id
espressione -> espressione or espressione
| espressione and espressione
| not espressione
| ( espressione )
| s_expr relop s_expr
| true
| false
const_decls -> const lista_const ; const_decls
|
lista_const -> cds
| lista_const , cds
cds -> id = num
s_expr -> s_expr addop term
| addop s_expr
| term
term -> term mulop factor
| term mod factor
| factor
factor -> num
| ( s_expr )
| id
La traduzione in codice intermedio avviene in un’unica passata con backpatching, facendo uso di una symbol table che funge da stack per le procedure dichiarate ricorsivamente ed implementa cosí le regole di visibilitá del pascal. Parallelamente alla symbol table sono stati mantenuti alcuni stack che conservano le informazioni riguardanti gli offset correnti, la numerazione dei temporanei, il numero dei simboli dichiarati etc, che crescono col crescere del livello d’annidamento delle procedure. Abbiamo cercato di non generare codice intermedio inutile, effettuando ove possibile in fase di compilazione i calcoli tra costanti. Abbiamo inoltre cercato di ridurre l’uso di temporanei, riutilizzando quelli non piú utili. Nel caso di
id : = s_expr
l’attributo place di s_expr conterrá il risultato, tipicamente un temporaneo, per tradurre l’assegnamento, anziché generare una quadrupla IASSIGN o RASSIGN, si modifica quella precedente reindirizzando il risultato sulla variabile.
Per lo sviluppo del parser è stato usato bison, che in mancanza di un token utile ad una riduzione ne segnala l’assenza, yacc invece si limita a segnalare un syntax error rendendo piú difficile individuare l’errore. La gestione degli errori potrebbe dunque sembrare troppo scarna se si usa yacc per generare il parser.
Il codice intermedio e’memorizzato in un vettore di quadruple definito come variabile globale in tipi.h
quadrupla quadvect[MAX_ISTR];
con quadrupla definita come
typedef struct quad
{
istr_opcode opcode;
operandi op1, op2, op3;
} quadrupla;
dove istr_opcode e’un tipo enum che identifica univocamente le istruzioni e operandi è il tipo dei possibili operandi indirizzo o immediato e se immediato intero o reale secondo le seguenti definizioni:
typedef union tipi_numero
{
double reale;
int intero;
} num_type;
typedef struct op_ind
{
int level;
int offset;
} op_indir;
typedef struct op_f
{
num_type imm;
op_indir ind;
} operandi;
Per quanto riguarda il tipo double si assume che abbia la mantissa di ampiezza almeno quanto un intero, per non causare errori nel confronto di variabili di tipo diverso.
Il formato della generica istruzione è:
OPCODE |
OP1 |
OP2 |
OP3 |
Per compatibilitá col nostro emulatore (J !) abbiamo cercato di porre il risultato sempre di seguito ai rispettivi operandi, nella stampa del codice intermedio l’operando destinazione appare in ultima colonna.
IASSIGN |
OP1 |
OP2 |
|
RASSIGN |
OP1 |
OP2 |
Saranno interpretate come OP2:=OP1
IADD |
OP1 |
OP2 |
OP3 |
IGTR |
OP1 |
OP2 |
OP3 |
Saranno interpretate come OP3:=OP1+OP2
If OP1 > OP2 goto OP3
e stampate in un ipotetico programma come :
1 : IASSIGN <#1> <0, 2>
3 : IADD <#10> <0, 1> <0,1>
4 : IGTR <#10> <0, 1> <#2001>
IUMIN |
OP1 |
OP2 |
OP2:=(-OP1)
READ |
OP1 |
||
GOTO |
ADDR |
||
HALT |
Gli operandi immediati, costituiti cioè da una costante disponibile a tempo di compilazione sono distinti, da un level non valido pari a NOLEVEL
Definito come:
#define NOLEVEL –1
e stampati nel listato del codice intermedio come <#costante>.
Molte istruzioni come quelle di salto non controlleranno che il level sia negativo, aspettandosi come operando una costante.
Per ogni dubbio chiarimento o contributo:
caddori.andrea@educ.di.unito.it
marino.rosario@educ.di.unito.it
cascio.vittorio@educ.di.unito.it