Sei sulla pagina 1di 87

POLITECNICO DI BARI

Facolt di Ingegneria Corso di Laurea Magistrale in INGEGNERIA INFORMATICA (D.M.270)

Tema danno in: LINGUAGGI FORMALI E COMPILATORI

D2C++ COMPILER

Docente: Prof. Giacomo Piscitelli Studenti: Donato Barone Marco Suma

_________________________________________________________________________________________ ANNO ACCADEMICO 2011/2012

Data_inizio_progetto: 12/11/2011 Data_fine_progetto: 04/03/2012

D2C++ Compiler Linguaggi Formali e Compilatori


Sommario Donato Barone - Marco Suma

SOMMARIO
1. INTRODUZIONE ................................................................................................................... 5 1.1 STRUMENTI UTILIZZATI ............................................................................................ 6 FLEX ......................................................................................................................... 6 BISON ....................................................................................................................... 8

1.1.1 1.1.2 1.2 1.3 2.

CENNI TEORICI ........................................................................................................... 10 SCHEMA DI FUNZIONAMENTO ............................................................................... 12

ANALIZZATORE LESSICALE .......................................................................................... 13 2.1 2.2 IMPLEMENTAZIONE .................................................................................................. 13 ERRORI LESSICALI ..................................................................................................... 17

3.

ANALIZZATORE SINTATTICO ........................................................................................ 18 3.1 3.2 IMPLEMENTAZIONE .................................................................................................. 18 ERRORI SINTATTICI................................................................................................... 25

4.

ANALIZZATORE SEMANTICO E GENERAZIONE DEL CODICE INTERMEDIO ..... 28 4.1 4.2 4.3 GESTIONE DEGLI ERRORI SEMANTICI ................................................................. 28 PARSER-STACK OPTIMIZATION ............................................................................. 31 GENERAZIONE DEL CODICE INTERMEDIO ......................................................... 33

5.

SYMBOL TABLE ................................................................................................................ 36 5.1 5.2 5.3 INTRODUZIONE .......................................................................................................... 36 TIPI DI DATO................................................................................................................ 39 ADD&FIND NELLA SYMBOL TABLE ..................................................................... 43

HT_VARIABLES IMPLEMENTATION ............................................................................ 44 HT_SCOPE IMPLEMENTATION ...................................................................................... 45 HT_CLASS IMPLEMENTATION ...................................................................................... 46 HT_ATTRIBUTE IMPLEMENTATION............................................................................. 47
3

D2C++ Compiler Linguaggi Formali e Compilatori


Sommario Donato Barone - Marco Suma HT_METHOD IMPLEMENTATION .................................................................................. 48 HT_OBJECT IMPLEMENTATION .................................................................................... 49 6. TEST CASES ........................................................................................................................ 50 6.1 6.2 6.3 6.4 6.5 6.6 6.7 7. 8. TEST CASE: Hello World .......................................................................................... 50 TEST CASE: Selection Sort ........................................................................................... 52 TEST CASE: Polimorfismo ........................................................................................... 58 TEST CASE: Parser Stack Optimization ....................................................................... 63 TEST CASE: Programmazione Orientata agli oggetti(1) .............................................. 66 TEST CASE: Programmazione Orientata agli oggetti(2) .............................................. 69 TEST CASE: Programmazione orientata agli oggetti (3) .............................................. 72

GRAPHICAL USER INTERFACE ...................................................................................... 75 CONCLUSIONI .................................................................................................................... 86 8.1. 8.2. 8.3. PERCH IL LINGUAGGIO D? .................................................................................... 86 PERCH IL C++? .......................................................................................................... 86 QUALI SONO I PRINCIPI DI REALIZZAZIONE DEL TEMA DANNO?............... 86

BIBLIOGRAFIA ........................................................................................................................... 87

D2C++ Compiler Linguaggi Formali e Compilatori


Introduzione Donato Barone - Marco Suma

1. INTRODUZIONE
Il D-Language [1] un linguaggio moderno. Esso mira a un obiettivo ambizioso: unire le potenzialit dei linguaggi C++ e Java. La sua caratteristica quella di essere un linguaggio con una sintassi C-Like ed una tipizzazione statica. Poich mette a disposizione notevoli funzionalit, esso un linguaggio molto complesso e richiede una certa esperienza da parte del programmatore per poter sfruttare a pieno le potenzialit del linguaggio. Nonostante la tipizzazione statica, il D-Language consente anche lutilizzo di aspetti dinamici, evitando talvolta alcune ridondanze nello specificare i tipi. Tra le caratteristiche principali di questo linguaggio, citiamo il garbage collector, il function overloading, lObject Oriented Programming, Class and Function Templates e molto altro. Nel nostro caso, vista la complessit di certi argomenti che richiederebbero troppo tempo qualora venissero trattati (ma non necessariamente eccessive problematiche risolutive), ci siamo soffermati solo sui costrutti fondamentali del linguaggi di programmazione di alto livello, sui tipi di dati pi comunemente utilizzati e su aspetti base della programmazione orientata agli oggetti; proprio relativamente a questultimo aspetto si spiega la scelta di un linguaggio intermedio di alto livello, come il C++. Di seguito portiamo un piccolo esempio di codice scritto in linguaggio D:

Fig. 1.1 Esempio di codice scritto in linguaggio D.

D2C++ Compiler Linguaggi Formali e Compilatori


Introduzione Donato Barone - Marco Suma

1.1 STRUMENTI UTILIZZATI


Per poter realizzare il nostro traduttore si scartata a priori lipotesi di generare un analizzatore lessicale e un analizzatore sintattico hand coded, poich questo avrebbe richiesto un tempo eccessivo e avrebbe portato ad ottenere dei componenti di qualit ed efficienza sicuramente inferiore rispetto a quelli ottenuti tramite lutilizzo di tool di generazione automatica. I due tool scelti sono Flex e Bison, approfonditi nelle prossime sottosezioni. Il sistema operativo utilizzato per la realizzazione e lo sviluppo di tutto il progetto Ubuntu, versione 10.04 e 11.04. Le versioni utilizzate sono due poich non si ritenuto necessario effettuare lupgrade della 10.04, dato che ai fini della realizzazione del progetto ci non comportava alcuna differenza.

1.1.1 FLEX
Flex [2] [3] si propone come un nuovo tool open source per la generazione automatica di analizzatori lessicali. stato scritto originariamente in C da Vern Paxson nel 1987. Flex sotto molti aspetti simile al generatore di scanner Lex, realizzato da M.E.Lesk e E.Schmidt degli AT&T. Bell Laboratories, che oltre ad avere lo svantaggio di essere un software proprietario, produce delle performance peggiori rispetto a Flex. Per tutti questi motivi si ritenuto opportuno optare per il primo applicativo e non per il secondo. Tale scelta stata anche facilitata dalla possibilit di poter utilizzare Flex in maniera identica a Lex, andandone in questo modo a peggiorare le performance, utilizzando durante la compilazione da terminale il flag l. Il purpose di Flex quello di generare uno scanner, il quale non nientaltro che un programma in grado di riconoscere allinterno di un testo. Per poter effettuare tale generazione Flex necessit di un file dotato del seguente pattern lessicali skeleton: Macro %{ #include Costant definition Scanner Macro }% Basic Definition Pattern Definition Support Procedure %% Token Definitions and Action %% Support Procedure C User Code

D2C++ Compiler Linguaggi Formali e Compilatori


Introduzione Donato Barone - Marco Suma Nella prima sezione: Macro vengono normalmente inserite le classiche operazioni assegnate ad un preprocessore: dichiarazioni di variabili globali, include dei vari file necessari, dichiarazioni di funzioni che vengono poi definite nella sezione di Support Procedure e etc. In Basic Definition vengono scritte le definizioni delle espressioni regolari utilizzando la seguente forma: Name Definition

In cui il Name rappresenta il nome con cui successivamente si potr fare riferimento al pattern presente in Definition. Ogni Name dovr, in maniera simile al C, iniziare con una lettera o un _ seguito da zero o pi lettere, cifre, _ e -. Tutto ci che viene trovato dal primo spazio non bianco successivo al Name fino alla End Of Line viene considerato come Definition. Example: _Letter [a-zA-Z]*

Lesempio su proposto rappresenta unespressione regolare in grado di riconoscere tutte le lettere maiuscole o minuscole ripetute nel testo zero o pi volte. In Pattern Definition possibile specificare quelle che sono le azioni da eseguire ogni qual volta viene individuata unespressione regolare. Il modello per effettuare tali definizioni il seguente: Pattern Action

In Pattern pu essere specificato un nuovo pattern oppure pu direttamente essere richiamata unespressione regolare definita nella sezione Basic Definition attraverso il suo Name. In Action possono essere definite le operazioni che devono essere effettuate al riconoscimento di un determinato Pattern; nel caso di interazione con un analizzatore sintattico tali operazioni consistono, nella maggior parte dei casi, nel ritorno del token associato a quello specifico pattern. Se viene riscontrato pi di un possibile match con i pattern definiti, viene assunto quello che considera il maggior numero di caratteri. Se il numero di caratteri dovesse essere identico, allora tale lessema viene associato allespressione definita prima allinterno di Flex. Nellultima sezione del file che viene passato a Flex vengono poste le definizioni di tutte le funzioni eventualmente dichiarate nella prima sezione e se lanalizzatore lessicale dovesse essere utilizzato senza lausilio di una parser, si potr scrivere un main che ci permetta di eseguirlo.

D2C++ Compiler Linguaggi Formali e Compilatori


Introduzione Donato Barone - Marco Suma Tutto ci che viene scritto in questa sezione viene ricopiato senza eccezioni allinterno del file .c rappresentante lo scanner. Per poter effettuare la compilazione con Flex , del file appena descritto, bisogna digitare da terminale il comando flex nomeFile.l con leventuale presenza di flag. Tale compilazione ci permetter di riscontrare gli errori presenti allinterno del file .l e successivamente verr creato un file che di default denominato lex.yy.c che definisce al suo interno la procedura yylex() , la quale avr come scopo quello di effettuare lanalisi lessicale basandosi sui pattern definiti nella sezione apposita.

Fig 1.2 Modello a blocchi del funzionamento di Flex.

Limmagine in Fig 1.2 mostra efficacemente ci che viene effettuato da Flex, il quale si comporta essenzialmente come un compilatore, prendendo in ingresso un file con estensione .l e restituendo in uscita un file di default chiamato lex.yy.c, contenente limplementazione dello scanner nel linguaggio C; in particolare il contentuto di questo file viene esplicato da una funzione denominata yylex() che corrisponde esattamente a quello che si aspetta Bison, che descriviamo nella sezione successiva.

1.1.2 BISON
Per poter realizzare lanalizzatore sintattico, cuore del nostro front-end/traduttore, si optato anche in questo caso per lutilizzo di un tool open source di generazione automatica: Bison. Tale scelta stata fatta per due motivi: 1) La realizzazione di una parser LR hand coded un task molto complesso e la generazione di uno che sia efficiente e perfettamente funzionante potrebbe richiedere anche anni uomo; 2) Bison un tool di generazione automatica che prendendo un file di input simile a quello visto per Flex ci permette di realizzare un parser di tipo LR che sia efficiente e che ci permetta di analizzare linput in un tempo linearmente proporzionale alla sua lunghezza.

D2C++ Compiler Linguaggi Formali e Compilatori


Introduzione Donato Barone - Marco Suma Bison [4], come Flex, vede la sua controparte proprietaria e meno efficiente in YACC (Yet Another Compiler of Compilers). Come per lanalizzatore lessicale, anche in questo caso sono stati gli stessi i motivi che hanno reso molto semplice la scelta fra questi due applicativi. Anche Bison non nientaltro che un compilatore che permette, prelevando un file .y in input, di ottenere in uscita un file .c; pi precisamente, Bison sfrutta e converte una annotated context free grammar, passata in ingresso in un formato che vedremo di seguito, in un deterministic LR utilizzando le parsing table LALR(1). La prima versione di Bison stata scritta da Robert Corbett e Richard Stallman. Similmente a Flex, anche Bison, utilizza un file di input con una particolare struttura per generare automaticamente il parser in linguaggio C. successivamente compilato da Bison la seguente: Prologo %{ La struttura del file .y che viene

Prologue }% Bison Declaration Regole e strutture sintattiche %% Grammar Rules Epilogo e Sezione Routine Ausiliarie %% Epilogue Nella sezione Prologo vengono usualmente inserite tutte le dichiarazioni di variabili globali, dichiarazioni di funzioni e le include dei file le cui funzionalit verranno utilizzate durante lanalisi sintattica. In Bison Declaration vengono definiti tutti i token e perci i simboli terminali che Bison stesso utilizzer allinterno della grammatica. Questo potr essere fatto tramite lausilio della parola chiave token nel seguente modo: %token NomeToken

Il NomeToken sar quello utilizzato allinterno dellanalizzatore lessicale nel momento in cui verr effettuata la return NomeToken associata al riconoscimento di un lessema. In questa sezione potranno essere utilizzate anche altre funzionalit di Bison, tra cui definire lassociativit degli operandi, definire una union che permetta di associare un determinato tipo ad un token e di evidenziare, tramite la keyword %expect, il numero di shift-reduce che la grammatica produce. Nella sezione Regole e Strutture Sintattiche verr inserita la grammatica context free utilizzando la seguente notazione:
9

D2C++ Compiler Linguaggi Formali e Compilatori


Introduzione Donato Barone - Marco Suma NonTerminal: Terminal-NonTerminal |Terminal-NonTerminal | ;

In cui NonTerminal indica un simbolo non terminale che a sua volta produce simboli terminali e/o non terminali(TerminalNonTerminal). In pi ad ogni produzione potr essere associata unazione semantica tramite la quale riusciamo ad utilizzare un SDT (Syntax Directed Translation Scheme). Possiamo inoltre associare ad ogni produzione dei frammenti di codice scritti in C, racchiusi tra parentesi graffe. Lultima sezione del file .y, Epilogo, contiene la definizione di tutte le procedure dichiarate nel prologo. Tale sezione verr ricopiata per intero nel file generato da Bison parser.tab.c. Permettere lintegrazione tra Flex e Bison molto semplice; baster effettuare una banale include specificando lheader del file .c prodotto da Bison allinterno della sezione Macro di Flex. Questo file .h contiene delle coppie NomeToken NumProgressivoAssociato che vengono utilizzate dallanalizzatore lessicale per capire quale valore deve essere restituito alla funzione yyparse(). Per poter compilare il file sorgente utilizzato per la definizione del parser con Bison, si utilizza analogamente a Flex il seguente comando da terminale: bison NomeFile.y con la possibilit di aggiungere eventuali flag.

1.2 CENNI TEORICI


La teoria dei linguaggi formali e la costruzione di un compilatore sono argomenti di elevata complessit. Come abbiamo gi detto, lutilizzo di strumenti automatici pu essere di aiuto nelle varie fasi di implementazione di un compilatore, ma comunque permane la vastit degli argomenti da conoscere per non incappare in errori concettuali. per questo che riteniamo opportuno richiamare brevemente il percorso teorico che abbiamo seguito nel corso del nostro lavoro per una maggiore chiarezza, in virt del fatto che, sulla base di una solida conoscenza, un valido programmatore pu considerare notevoli vie nella realizzazione di un compilatore, ma alla fine dovr sceglierne soltanto una.

10

D2C++ Compiler Linguaggi Formali e Compilatori


Introduzione Donato Barone - Marco Suma Per lanalizzatore lessicale e lanalizzatore sintattico abbiamo gi discusso quando abbiamo introdotto rispettivamente Flex e Bison. Per quanto riguarda le azioni semantiche, avendo utilizzato un approccio bottom-up con un LR Parser per lanalisi sintattica, ci siamo serviti di una classe S-Attributed mediante un metodo di attraversamento post-order; in altre parole lazione semantica viene effettuata dopo aver attraversato lultima volta il non terminale/terminale interessato. In sostanza, la nostra SDT (Syntax Directed Translation) Scheme ha previsto nella maggior parte dei casi azioni postfisse (alla fine della produzione), e in altri casi azioni inside-production che per sfruttavano solo attributi gi presenti. Per il calcolo delle espressioni aritmetiche abbiamo utilizzato la tecnica del Parser-Stack Implementation of Postfix STDs [5] utilizzando un codice gi esistente per la gestione dello stack [6]. La tecnica utilizzata molto efficiente e rappresenta un ottimizzazione per la generazione del codice intermedio, perch garantisce il calcolo semantico di qualsiasi espressione aritmetica comunque complessa riconosciuta dallanalizzatore sintattico, ma risulta applicabile solo se tutti i valori delle variabili sono presenti, quindi non sono acquisiti da input, non sono passati come parametri o non appartengono a una iterazione (vedi figura 1.3); tuttavia approfondiremo il discorso nel Capitolo 4. { } = 5; = 10; = ; = ( + )/2 { } { } = 5; = 10; = 50; = 375; { } { } ( = 0; < 10; + +){ [] = ; }{ } { } ( = 0; < 10; + +){ [] = ; }{ } { } ( , ){ = + ; } { } ( , ){ = + ; }

Figura 1.3 3 esempi che mostrano il principio del Parser-Stack Implementation of Postfix SDTs, evidenziando in verde il caso in cui applicabile lottimizzazione, in rosso il caso contrario.

Per la generazione del codice intermedio, abbiamo scelto un linguaggio di alto livello, il C++, perch ci ha consentito di gestire le classi dal punto di vista degli errori e di poterle riportare comodamente nel linguaggio intermedio in caso di esito positivo; quindi, data la stretta
11

CODICE SORGENTE CODICE INTERMEDIO

D2C++ Compiler Linguaggi Formali e Compilatori


Introduzione Donato Barone - Marco Suma somiglianza tra il D e il C++, la regola stata quasi sempre quella di aggiungere un operazione di traduzione inside-production tranne che per alcuni casi come: Scrittura dellheader del file .cpp; Traduzione delle operazioni di input e output; Applicazione del Parser-stack Implementation of Postfix SDTs.

Ulteriori approfondimenti vengono specificati nel capitolo 5, dove introdurremo anche il concetto di Marker Non-Terminal che abbiamo utilizzato.

1.3 SCHEMA DI FUNZIONAMENTO


In definitiva, possiamo schematizzare il lavoro interamente realizzato con il seguente schema:

Fig. 1.4. Diagramma dei componenti e di deployment del progetto realizzato.

12

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Lessicale Donato Barone - Marco Suma

2. ANALIZZATORE LESSICALE
Lanalizzatore lessicale il primo componente fondamentale di un compilatore; esso ha il compito di individuare i lessemi allinterno del file di input, di riconoscerli mediante dei pattern costruiti dal programmatore, e di restituire al parser i relativi token.

2.1 IMPLEMENTAZIONE
Come gi detto nel capitolo precedente, per costruire lanalizzatore lessicale ci siamo serviti di Flex; di seguito mostriamo il codice relativo:

13

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Lessicale Donato Barone - Marco Suma

In questa prima sezione abbiamo descritto tutte le Basic_Definitions che ci sono servite nel progetto; oltre alle varie keyword, quelle di maggiore importanza sono _ID,

_BLOCKCOMMENT, _LINECOMMENT, _INTEGERLITERAL e _FLOATLITERAL.

14

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Lessicale Donato Barone - Marco Suma

15

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Lessicale Donato Barone - Marco Suma

In questa sezione espletiamo le azioni corrispondenti ai vari token individuati; sostanzialmente, a parte i commenti per i quali non necessaria alcuna operazione se non quella di NON restituire nulla al parser, nella maggior parte dei casi la procedura prevede di: Richiamare una funzione countToken che incrementa il numero di token individuati; Valorizzare la variabile yylval con il contenuto del token presente in yytext; Restituire il token mediantre il comando return;

La variabile rows serve a tenere conto del numero di righe; viene incrementata allinterno dei commenti e ogni volta che si trova un token _EOL.

In questultima sezione defininiamo solo la funzione countToken() che semplicemente incrementa il numero di token. Tale funzione definita allinterno dellanalizzatore lessicale, non
16

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Lessicale Donato Barone - Marco Suma viene mai utilizzata dal parser e perci al momento praticamente inutile, ma nulla vieta che in un futuro possa essere adoperata per dare informazioni pi dettagliate su dove lerrore sito.

2.2 ERRORI LESSICALI


importante sottolineare che un errore lessicale molto comune, quello relativo alla definizione errata del nome di un identificatore. Sappiamo, infatti, che un identificatore pu essere costituito da lettere maiuscole/minuscole, da numeri e dal simbolo _, purch il primo simbolo non sia un numero. Per questo motivo, il token _WRONGID ci consente di gestire questeventualit, generando un opportuno errore.

17

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Sintattico Donato Barone - Marco Suma

3. ANALIZZATORE SINTATTICO
La CFG (Context-Free Grammar) implementata riguarda un sottoinsieme del linguaggio D; non stato possibile, soprattutto in termini di tempo, elaborare lintero linguaggio. Per la generazione delle produzioni, abbiamo consultato [7] e [8] con laccortezza di inserire opportune modifiche per evitare la presenza di conflitti di tipo reduce-reduce 1 assolutamente da evitare per il nostro tipo di parser. Ricordiamo inoltre che, trattandosi di un LR parser, abbiamo preferito ricorsioni sinistre (left-recursion) che introducono vantaggi in termini di memoria utilizzata 2.

3.1 IMPLEMENTAZIONE

Ricordiamo che un conflitto reduce-reduce un conflitto secondo cui il parser pu risolvere una stessa stringa mediante due riduzioni diverse; di default viene scelta la prima regola incontrata dal parser. Un conflitto shit-reduce un conflitto secondo cui il parser pu contemporaneamente shiftare o ridurre; di default viene privilegiata loperazione di shift. 2 Le ricorsioni sinistre vanno assolutatmente evitate se si tratta di un LL parser, perch potrebbero introdurre ricorsioni infinite. In Bison, tali ricorsioni, producono delle ottimizzazioni nella gestione della memoria.
18

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Sintattico Donato Barone - Marco Suma

19

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Sintattico Donato Barone - Marco Suma

20

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Sintattico Donato Barone - Marco Suma

21

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Sintattico Donato Barone - Marco Suma

22

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Sintattico Donato Barone - Marco Suma

23

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Sintattico Donato Barone - Marco Suma

24

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Sintattico Donato Barone - Marco Suma

Le immagini mostrano solo le regole sintattiche; nel codice ovviamente queste sono mischiate alle regole semantiche e di generazione del codice intermedio. Per motivi di ordine e di comprensione, non le abbiamo mostrate contemporaneamente. Come si pu vedere, nella grammatica abbiamo fatto ricorso alluso dei MarkerNonTerminal per poter attuare azioni intermedie (tipicamente legate a operazioni di traduzione) laddove questo avrebbe portato a dei conflitti non risolvibili diversamente. Lultima sezione, a partire da ClassDeclaration, dedicata alla parte relativa alla dichiarazione e definizione delle classi. Questa sezione sicuramente rappresenta la novit del nostro tema danno, avendo gestito anche lereditariet singola, loverloading e loverriding; tuttavia, questi argomenti riguarderanno il capitolo successivo.

3.2 ERRORI SINTATTICI


Possiamo iniziare questo paragrafo dicendo che per errori sintattici intendiamo quegli errori che si evidenziano nel momento in cui il parser non in grado di individuare una regola che effettui un matching valido con la stringa di input. Come gi spiegato nel paragrafo 3.1, per la gestione

25

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Sintattico Donato Barone - Marco Suma di errori sintattici abbiamo utilizzato le due tecniche principali, ossia panic mode e error production. Mostriamo adesso i casi principali in cui gestiamo e risolviamo questi errori; chiaramente non possibile, per questioni di lunghezza, mostrare tutti i casi.

In questo primo caso viene riportato lerrore sintattico generato nel ramo dello SwitchStatement che pu essere dovuto alla mancanza di ( e/o ) e/o errori nel blocco Expression. La modalit : panic mode.

Sempre attraverso la modalit panic mode viene gestito un eventuale errore allinterno del blocco Expression del ForStatement.

Sia attraverso la modalit panic mode ed error production allinterno del Do-While-Statement vengono gestiti errori sintattici pi dettagliati rispetto a quelli precedenti. In particolare viene individuato il caso in cui manchino separatamente (, ) e ;.

26

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Sintattico Donato Barone - Marco Suma

BlockStatement rappresenta il blocco di codice di definizione di una funzione, che per la nostra grammatica deve essere necessariamente racchiuso tra le parentesi graffe; quindi, sia attraverso la modalit error production che panic mode, vengono individuati e gestiti separatamente i casi in cui manchi { e }.

Nel blocco di dichiarazione un errore tipico quello di dimenticare il simbolo ;. Per questo, mediante la tecnica panic mode, gestiamo questo tipo di errore. Pi genericamente, con questo tipo di produzione riusciamo anche a gestire altri tipi di errori sintattici.

27

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Semantico Donato Barone - Marco Suma

4. ANALIZZATORE SEMANTICO E GENERAZIONE DEL CODICE INTERMEDIO


4.1 GESTIONE DEGLI ERRORI SEMANTICI
Nei capitoli precedenti abbiamo mostrato com stata effettuata la gestione degli errori lessicali e sintattici. Per i primi, non sono state previste grandi eccezioni dato che un errore in tale fase non viene quasi mai riconosciuto se non durante lanalisi sintattica (Es.: scrivere fi al posto di if); per la seconda tipologia di errori sono state previste le classiche eccezioni: ( o ) mancante, mancanza del ;, errori allinterno di unespressione, etc. La fase di analisi semantica, invece, stata trattata in modo molto pi minuzioso e pignolo. Lobiettivo da raggiungere stato: cercare di emulare al meglio il comportamento del compilatore del DLanguage dal punto di vista semantico. Gli errori gestiti allinterno del nostro front-end sono stati i seguenti: 1. Eliminare la possibilit che allinterno di uno stesso scope (vedi concetto di scope nel capitolo 5) ci sia la ridefinizione di una variabile, anche se di tipo diverso; 2. Lutente non pu accedere ad una posizione di memoria non prevista, nel nostro caso laccesso ad una posizione del vettore che supera la sua dimensione; 3. Viene effettuato un casting implicito, segnalando tale operazione con un warning (tale feature non prevista dal compilatore del DLanguage); 4. Eliminare la possibilit di ridefinire oggetti allinterno di uno stesso scope; 5. Individuare oggetti con classi di appartenenza non definite nel sorgente; 6. Prima di notificare un errore, relativo alla non dichiarazione di una variabile allinterno dello scope, viene controllato che tale variabile non sia stata definita a livello globale; 7. Viene verificato che le funzioni richiamate allinterno di altre funzioni siano state gi definite, in questo caso non stato previsto alcun meccanismo che permetta di utilizzare funzioni dichiarate dopo allinterno del sorgente; 8. Viene verificato che i parametri passati alla funzione corrispondano alla firma della stessa;

28

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Semantico Donato Barone - Marco Suma Quanto appena elencato riguarda la parte di base del modulo di analisi semantica. Degno di nota il sistema di gestione delle classi, del meccanismo di ereditariet, delloverloading e delloverriding, implementato allinterno del nostro front-end. Loverloading stato implementato sfruttando quella che la firma della funzione, ossia il numero e il tipo di parametri che lo costituiscono. La entry immagazzinata allinterno della symbol table apposita viene indicizzata in base al nome e al tipo di parametri. In questo modo solo due funzioni che presentano stesso nome e stessa firma verranno individuate come duplicati e perci verr segnalato lerrore, altrimenti il tutto risulter funzionante. Oltre a gestire la fase di creazione ci si spinti oltre, permettendo allutente di richiamare le funzioni su cui stato effettuato overloading; anche in questo caso in base al tipo di variabili o valori numerici che vengono passati, il front-end riuscir a comprendere a quale funzione ci si sta riferendo. Tale tecnica fondamentale nella programmazione ad oggetti, pu essere applicata anche per i metodi presenti allinterno di una classe. Il nostro traduttore anche in grado di gestire le classi, viene perci previsto un controllo semantico a livello di classe per verificare che non ci siano assegnazioni agli attributi a meno che questi non siano statici; viene tenuto traccia del tipo di protezione su ogni attributo(public, private), vengono effettuati controlli in fase di creazione di un metodo e viene, anche in questo caso, immagazzinata linformazione sulla protezione. Questo vuol dire che funzioni e metodi dichiarati private non saranno accessibili allesterno della classe stessa. In aggiunta a tutto ci, viene prevista anche la possibilit di applicare una delle caratteristiche cardine della programmazione object oriented: lereditariet. Per semplificare il problema, data la sua grande complessit, viene data al programmatore la possibilit di poter ereditare una sola classe; tuttavia viene gestito il meccanismo transitivo dellereridariet. Ovviamente viene previsto un controllo sulleffettiva presenza della classe padre. Inoltre viene permesso anche di specificare con che tipo di protezione si vuole ereditare se public o private. Nel caso in cui la classe venga ereditata con protection=public allora da un oggetto della classe figlia sar possibile accedere agli attributi e ai metodi pubblici della classe padre; se invece protection=private non sar possibile accedere a nessun attributo o propriet della classe padre. Allinterno della classe specializzata o figlia sar possibile come previsto dal meccanismo di ereditariet usufruire di qualsiasi attributo o metodo public definito nella classe generalizzata. Se tali condizioni non venissero rispettate, saranno mostrati dei messaggi che mostreranno lerrore semantico.

29

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Semantico Donato Barone - Marco Suma Infine un altro concetto di fondamentale importanza del polimorfismo, implementato nel nostro traduttore, loverriding. Viene quindi data la possibilit al programmatore di poter ridefinire metodi della classe padre allinterno della classe figlia. Come gi accennato, verr consentita anche la creazione di oggetti sia allinterno delle classi (relazioni di aggregazione) e sia allesterno delle classi. Lulteriore semplificazione adottata che gli oggetti siano statici; detto ci possibile utilizzare tutti i metodi e le funzioni associate alloggetto creato. Nelle immagini seguenti mostriamo frammenti di codice inerenti allindividuazione degli errori semantici:

Fig. 4.1 Semantic Error: no identifier for class

In Fig. 4.1 nella produzione utilizzata per definire un ereditariet, lazione semantica prevede di ricercare lesistenza della classe padre; in caso contrario verr generato un errore semantico.

Fig. 4.2 Semantic Error: undeclared

In Fig. 4.2 viene mostrata la funzione che viene richiamata ogni volta che si verifica un errore semantico del tipo undeclared, ossia quando un dato viene utilizzato ma non stato dichiarato.

30

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Semantico Donato Barone - Marco Suma

Fig. 4.3 Semantic Error: Redefinition of.

In Fig. 4.3 viene mostrata la funzione che viene richiamata ogni volta che si verifica un errore semantico del tipo redefinition of, ossia quando viene dichiarato un dato utilizzando due o piu volte lo stesso nome allinterno dello stesso scope.

Fig. 4.4 Semantic Error: member not static.

In Fig. 4.4 viene mostrata la funzione che viene richiamata ogni volta che si verifica un errore semantico del tipo not a static member, ossia quando si prova ad assegnare un valore allinterno della definizione di una classe che non sia stata dichiarata come static.

Fig. 4.5 funzione yyerror(char *) gestita da Bison.

4.2 PARSER-STACK OPTIMIZATION


Le operazioni del Parser-Stack Implementation of Postfix SDTs si svolgono nella sezione AssignExpression (vedi capitolo 3). Lidea nasce dalla necessit di gestire espressioni aritmetiche comunque complesse valutandole in anticipo rispetto alla fase di esecuzione, qualora si abbiano a disposizione tutti i valori delle variabili coinvolte. Il funzionamento si basa sullutilizzo di uno stack: in realt questidea nasce senza una conoscenza teorica del problema;
31

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Semantico Donato Barone - Marco Suma in un secondo momento abbiamo scoperto dellesistenza di una tecnica simile a quella implementata da noi, denominata Parser-Stack Implementation of Postfix SDTs.
Op1 Op2 Op2 Op1 X4 X3 X2 X1

op

Result

Result X4 X3 X2 X1

Fig. 4.6 Rappresentazione grafica del nostro Parser-Stack Optimization.

Come ci chiaramente noto, per le operazioni +,/,-,* e % abbiamo bisogno di due operandi, che a loro volta possono essere risultato di altre operazioni. Quindi, per ogni operazione di questo tipo, vengono effettuate due pop() per prelevare gli ultimi due valori, viene svolta loperazione e viene effettuata la push() del risultato 3. Supponiamo di gestire unoperazione di questo tipo: = ((/ ) ) 4 --- il risultato 2 = 15, = 3, = 2, = 4;

Osserviamo cosa succede con lo stack:

1) La prima operazione effettuata push(a) che inserisce il valore 15 nello stack; 2) Successivamente si passa a push(b); 3) A questo punto il parser ha riconsociuto la regola MulExpression _SLASH UnaryExpression e mediante un azione postfix effettua due pop, prelevando a e b, calcola la divisione e inserisce il risultato nello stack mediante push(a/b); 4) La prossima operazione sar pop(c); 5) Il parser riconosce la regola MulExpression _TIMES UnaryExpression, preleva i due valori dallo stack e vi inserisce il risultato; 6) Dopodich viene riconosciuto d e quindi pop(d);

N.B. :Avendo esplicitamente definito lassociativit e la precedenza degli operandi, avendo scritto una grammatica apposita al nostro tipo di parser LR, abbiamo sempre la certezza che i due valori utili si trovino in cima allo stack.
32

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Semantico Donato Barone - Marco Suma 7) Il parser riconosce la regola AddExpression _MINUS MulExpression e quindi, in seguito alle due pop, viene inserito il risultato mediante una push. 8) Il processo viene ripetuto anche per il valore 4 come nei punti 6 e 7; 9) Infine, in seguito alla regola di assegnazione, viene effettuata una push corrispondente al risultato della operazione e viene inserito il valore nella entry della symbol table associata ad e. Il discorso molto simile anche per gli operatori unari (++ e --); in quel caso si effettua una sola operazione di pop() e una operazione di push(). Nel capitolo 6 viene mostrato un esempio completo inerente a questo argomento.

4.3 GENERAZIONE DEL CODICE INTERMEDIO


Lultimo step che viene effettuato dal nostro semplice front-end per il DLanguage la generazione del codice intermedio in C++. Tale scelta stata effettuata a causa della grande analogia presente tra i due linguaggi (la maggior parte dei costrutti sono pressoch identici) e per poter gestire la creazione di classi e lutilizzo di oggetti statici. Il codice intermedio viene generato allinterno di un file denominato intermediateCode.cpp presente allinterno della cartella in cui memorizzato il front-end. Per questa prima versione dellapplicativo non si ritenuto necessario diversificare e generare tale file allinterno della cartella in cui il sorgente da tradurre presente, daltronde effettuare tale modifica non richiederebbe sforzi eccessivi. Questo vuol dire che se si vuole salvare il codice intermedio, per eseguirlo successivamente, bisogner farlo manualmente prima di effettuare una nuova traduzione.

Fig. 4.7 Esempio di tecnica di traduzione. In evidenza, la regola di casting esplicito presente nel linguaggio D.

Per poter effettuare la traduzione si utilizza una SDT (Syntax Directed Translation Scheme), ossia dei frammenti di codice, nel nostro caso scritti in C, che vengono associati alle varie
33

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Semantico Donato Barone - Marco Suma produzioni mediante postfix-actions e middle-actions. Per la maggior parte dei costrutti, data la grande similitudine dei due linguaggi, al riconoscimento di ogni simbolo terminale si effettuata una scrittura dello stesso attraverso una fprintf allinterno del file intermediateCode.cpp. Poche sono state le eccezioni; un caso di particolare rilevanza quello relativo alla dichiarazione di un vettore. In D gli elementi con cui si vuole inizializzare il vettore vengono racchiusi tra parentesi quadre, mentre in C++ questo viene fatto tra parentesi graffe, perci sono state utilizzate una middle-action e una postfix-action associate a tale produzione per poter effettuare la conversione. Lesempio riportato nellimmagine sottostante:

Fig. 4.8 esempio di traduzione nel codice intermedio.

Inoltre nel caso in cui, allinterno del file sorgente che si vuole compilare, il programmatore faccia uso dello standard output o dello standard input e quindi di operazioni di I/O classiche, dovr necessariamente importare delle librerie std.stdio per loutput e std.c.stdio per linput. Il front-end in caso di presenza di operazioni di I/O e di assenza dellimport di tali libreria restituir un messaggio di errore allutente (vedi paragrafo relativo agli errori semantici). Le due funzioni implementate sono la writefln per loutput e la scanf per linput. Le due hanno una sintassi molto simile alla printf e alla scanf del C, per tale motivo essendo il C++ retrocompatibile sono state adoperate tali funzioni per implementare a livello di codice intermedio le operazioni di I/O. In fase di generazione dell intermediateCode.cpp viene richiamata una funzione che, utilizzando un approccio di tipo blindly, va ad effettuare una include delle librerie necessarie per le operazioni di interazione con lo stdin e lo stdout in C++. Tale funzione mostrata di seguito:

Fig.4.9 codice di generazione dellheader del file .cpp

Ultimo punto degno di nota e forse anche il pi complesso relativo alla generazione del codice intermedio il sistema di ottimizzazione realizzato ed implementato nel front-end. Durante la generazione del codice intermedio, a fronte di un assegnazione, anzich ricopiare eventuali espressioni aritmetiche allinterno del file intermediateCode.cpp, viene scritto solo il risultato
34

D2C++ Compiler Linguaggi Formali e Compilatori


Analizzatore Semantico Donato Barone - Marco Suma dellespressione; questo porta ad un ottimizzazione, se pur piccola, in termini di tempo di esecuzione e di sforzo computazionale da parte del back-end. Tale risoluzione viene fatta sempre se lespressione del tutto numerica, se invece questa presenta al suo interno delle variabili, allora bisogner considerare una serie di scenari differenti che potrebbero portare allinibizione di tale metodo e perci alla copiatura in toto dellespressione non risolta: 1. Se il valore di una variabile viene settato tramite lo standard input, allora lottimizzazione verr inibita dallacquisizione del valore in poi, dato che non avrebbe senso calcolare in fase di compilazione il risultato di unespressione dipendente da una variabile il cui valore viene settato dallutente a run-time. 2. Se una variabile viene utilizzata allinterno di uno dei seguenti costrutti: for, if , switch, while- do, do-while e successivamente viene adoperata per il calcolo di unaltra variabile lottimizzazione sar inibita. 3. Allinterno di una classe tale ottimizzazione sar sempre inibita, dato che le propriet verranno avvalorate solo alla creazione di una istanza. Lottimizzazione, come possiamo vedere, presenta effettivamente molti scenari di inibizione, ci non toglie che possa rivelarsi molto utile in sorgenti in cui vengono effettuate un elevato numero di computazioni sotto forma di espressioni aritmetiche. (Vedi Paragrafo 6.4)

35

D2C++ Compiler Linguaggi Formali e Compilatori


Symbol Table Donato Barone - Marco Suma

5. SYMBOL TABLE
5.1 INTRODUZIONE
Lo scopo principale della Symbol Table quello di tenere traccia di tutte le informazioni ricavate dai moduli separati e di poterle riutilizzare quando necessarie, sia nei moduli del front-end; che nei moduli del back-end. Per questo necessario progettare la Symbol Table nel miglior modo possibile, cosi che, ad esempio, il valore di una costante prelevato durante le azioni sintattiche possa essere immediatamente disponibile in fase di scrittura del codice intermedio. Nel nostro caso abbiamo deciso di strutturare le symbol table come hash table ad indirizzamento diretto, utilizzandone una implementazione gi esistente denominata Uthash [9] scritta da Troy Hanson e gi precedentemente utilizzata da altri colleghi in [10] e [11]. In particolare, abbiamo utilizzato 6 diverse symbol table: una per la gestione delle variabili (globali e di ciascuna funzione), una per le funzioni dichiarate (main, etc) una per la definizione delle classi, una per gli attributi , una per i metodi di ciascuna classe e un'altra per la dichiarazione degli oggetti. Per ciascuna symbol table abbiamo definito una chiave primaria composta che identificasse univocamente la specifica entry. Tale stratagemma stato utilizzato per risolvere il problema legato allo scope di validit delle variabili. Invece di generare un'unica symbol table per variabili, attributi, classi, oggetti, metodi e funzioni o di generarne una associata ad ogni scope, si preferito utilizzare le sei su citate indicizzandone laccesso con una chiave composta, la cui morfologia cambia a seconda della symbol table considerata. Le seguente immagini mostrano la struttura di tutte le symbol table utilizzate:

36

D2C++ Compiler Linguaggi Formali e Compilatori


Symbol Table Donato Barone - Marco Suma

Fig. 5.1. Symbol Table per le variabili.

Fig. 5.2. Symbol Table per le funzioni.

Fig. 5.3. Symbol Table per gli attributi.

37

D2C++ Compiler Linguaggi Formali e Compilatori


Symbol Table Donato Barone - Marco Suma

Fig. 5.4. Symbol Table per i metodi.

Fig. 5.5. Symbol Table per le classi.

La particolarit di HT_Class che essa una doppia symbol table, ossia indicizzata sia secondo il nome della classe che secondo lo scope univoco associato a ciascuna classe. Questa doppia indicizzazione stata necessaria nel momento in cui dovevamo ricercare un elemento nella symbol table e avevamo a disposizione solo una delle due chiavi.

Fig. 5.6. Symbol Table per gli oggetti.

Va fatto un chiarimento sul concetto di scope e quindi anche su HT_scope. Per scope intendiamo definire una localit spaziale associata alla dichiarazione delle funzioni, in modo che le variabili dichiarate possano identificarsi allinterno di una zona del codice; evidente che
38

D2C++ Compiler Linguaggi Formali e Compilatori


Symbol Table Donato Barone - Marco Suma questo metodo ci permette di gestire le variabili globali (che avranno scope 0) distinguendole da quelle dichiarate ad esempio allinterno del main o di qualsiasi altra funzione. Il discorso molto simile per le classi; ciascuna classe ha un suo class_scope; per ogni classe viene definito un subClassScope che serve a definire la localit spaziale delle variabili e dei metodi allinterno delle classi.

5.2 TIPI DI DATO


I tipi di variabili gestiti sono: char, byte, bool,, ubyte, int, uint, float, double, long, ulong, void codificati secondo lordine predetto tramite un numero intero. Per utilizzare il campo value abbiamo definito un nuovo tipo di dato typeval strutturato come segue: ; ; ; ; ; ; ; ;

Tale struttura si rivelata molto utile per poter tenere traccia del valore associato ad ogni variabile utilizzata allinterno del sorgente analizzato Il compilatore D non permette il casting implicito durante una assegnazione e questo porta alla generazione di un errore ogni qual volta si ha unespressione del tipo: a=b+c; in cui a un tipo di dato int e b e c sono float. Il traduttore da noi realizzato invece aggira il problema operando un casting implicito(logicamente anche esplicito), generando cos al posto di un errore un warning che avvisa il programmatore della possibile perdita di dati a cui va incontro. Ovviamente se si cercasse di assegnare un char ad un intero, loperazione verrebbe comunque eseguita, ma il risultato non avrebbe alcun senso. Per permettere il funzionamento del tutto, sono state sfruttate due strutture di tipo typeVal: initVal e getVal . La prima stata usata per tener traccia del valore da assegnare al campo value di una variabile memorizzata allinterno della symbol table (il valore se non specificato settato

39

D2C++ Compiler Linguaggi Formali e Compilatori


Symbol Table Donato Barone - Marco Suma a 0 di default); la seconda, invece, stata utilizzata per prelevare il campo il medesimo campo associato alla generica variabile. Tale soluzione per portava ad un side effect: la presenza di un enorme quantit di if-else_if. Questo generava due sostanziali svantaggi: 1. Incrementava la scarsa leggibilit delle azioni semantiche associate alle produzioni 2. Appesantiva il carico computazionale con un numero ancora pi elevato di confronti Per tutti questi motivi si optato per una soluzione pi elegante: per ogni tipo di dato stata definita una diversa funzione di inizializzazione initializeTipo, che come mostrato nelle immagini sottostanti opera su quel particolare tipo di dato, ed una diversa funzione per il reperimento del dato stesso getTipo. Successivamente sono stati creati dei vettori statici di puntatori a funzioni: initType e getType che ci hanno permesso di effettuare un accesso diretto e puntuale alle procedure senza dover utilizzare cascate di if-elseif.

40

D2C++ Compiler Linguaggi Formali e Compilatori


Symbol Table Donato Barone - Marco Suma

41

D2C++ Compiler Linguaggi Formali e Compilatori


Symbol Table Donato Barone - Marco Suma

Fig. 5.7. Funzioni associate ai vara tipi di dato.

42

D2C++ Compiler Linguaggi Formali e Compilatori


Symbol Table Donato Barone - Marco Suma

5.3 ADD&FIND NELLA SYMBOL TABLE


Per ogni Symbol Table abbiamo definito una funzione per aggiungere e una per ricercare un elemento. La ricerca di un elemento utile in due circostanze separate: 1) Prima di aggiungere un elemento alla symbol table necessario accertarsi che non esista gi una entry con la stessa chiave primaria. Facciamo un esempio: se vogliamo dichiarare una variabile denominata a allinterno del main, dobbiamo accertarci che non esista un altra variabile con lo stesso nome allinterno dello stesso scope, altrimenti dovremo generare un errore semantico; daltro canto se tale variabile esiste in un altro scope allora non viene generato alcun tipo di errore; 2) Ogni volta che una variabile, una funzione o un qualsiasi altro elemento viene utilizzato in un generico Non_Declaration_Non_Empty_Statement necessario controllare che sia presente nella Symbol Table e prelevare il suo contenuto; in caso contrario dovremo generare un errore semantico. OK

Request

Add entry

Fig. 5.8. Procedura per aggiungere un elemento nella Symbol Table.

Find if_exist

Already Esist

Request

Find if_exist

Yes

No

Fig. 5.9. Procedura per ricercare un elemento nella Symbol Table.


43

D2C++ Compiler Linguaggi Formali e Compilatori


Symbol Table Donato Barone - Marco Suma Di seguito, proponiamo i segmenti di codice relativi alle varie procedure:

HT_VARIABLES IMPLEMENTATION

44

D2C++ Compiler Linguaggi Formali e Compilatori


Symbol Table Donato Barone - Marco Suma

HT_SCOPE IMPLEMENTATION

45

D2C++ Compiler Linguaggi Formali e Compilatori


Symbol Table Donato Barone - Marco Suma

HT_CLASS IMPLEMENTATION

46

D2C++ Compiler Linguaggi Formali e Compilatori


Symbol Table Donato Barone - Marco Suma

HT_ATTRIBUTE IMPLEMENTATION

47

D2C++ Compiler Linguaggi Formali e Compilatori


Symbol Table Donato Barone - Marco Suma

HT_METHOD IMPLEMENTATION

48

D2C++ Compiler Linguaggi Formali e Compilatori


Symbol Table Donato Barone - Marco Suma

HT_OBJECT IMPLEMENTATION

49

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma

6. TEST CASES
In questa sezione verranno proposti tutti i casi di test e quindi tutti i principali errori che il nostro front-end per il DLanguage in grado di rilevare e comunicare allutente. Nel caso in cui lutente generi errori non contemplati dalla grammatica, verr generato un messaggio di errore di questo tipo: Fatal Error: this error isnt managed from the grammar specificando la riga in cui tale errore stato generato. Tutti i sorgenti relativi ai casi di test sono presenti alla directory /Test_Case e tramite lapplicativo realizzato potranno essere facilmente caricati ed eseguiti. Nelle successive immagini, relative ai vari test case, si possono notare del piccole differenze in termini di look dellinterfaccia, ci dovuto come spiegato nel capitolo 1.1 allutilizzo di due versioni differenti di Ubuntu.

6.1 TEST CASE: Hello World


Come previsto allinterno di una qualsiasi guida o manuale associato ad un linguaggio, il primo esempio proposto sempre il classico Hello World!, che ci accingiamo a riportare come primo test. Di seguito possiamo vedere il codice presente allinterno del sorgente

test_case_hello_world.d.

Dopo aver caricato il file e cliccato sul bottone con etichetta Translate il risultato ottenuto il seguente:

50

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma

Il codice intermedio generato per tale esempio il seguente:

Verificato che il sorgente fosse corretto e venisse compilato senza problemi, si passati a testare il front-end sottoponendo lo stesso esempio corredato di errori:

Loutput risultante da tale traduzione stato soddisfacente; ovviamente il compilatore ci ha restituito un errore insensato, ma il parsing comunque non stato interrotto.

Nel secondo caso di test stata eliminata la import che permette di utilizzare la funzione writefln e loutput della compilazione viene riportato di seguito:

51

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma

6.2 TEST CASE: Selection Sort


In questo secondo caso di test ci si spinti molto pi in l rispetto al banale Hello World; si passati alla verifica della correttezza di un algoritmo molto utilizzato soprattutto in strutture come i vettori: lalgoritmo di ordinamento Selection Sort. Per incrementare la complessit del caso di test sono state aggiunte dichiarazioni multiple, strutture iterative (ciclo for) e lacquisizione dei dati direttamente dallo stdin.

52

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma

E il risultato di tale compilazione stato ovviamente privo di errori.

Lintermediate code generato viene riportato in questimmagine:

53

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma

proprio in questo primo esempio un po pi complesso che si cercato di testare lefficacia del nostro traduttore. Gli errori introdotti in questo prima verifica sono stati: 1. Mancata inclusione delle librerie per gestire le routine di I/O; 2. Mancata dichiarazione della variabile i utilizzata praticamente in tutto il sorgente;

54

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma

Loutput derivante dalla traduzione stato in grado di individuare la mancata dichiarazione della i ogni qual volta questa veniva utilizzata e in pi stata segnalata la mancata import associata alle funzioni di I/O nel momento in cui queste venivano adoperate. Il numero totale di errori riscontrati stato pari a 22, poich in maniera corretta lutilizzo di i allinterno di ogni for stato considerato tre volte. Proprio come succede spesso nei compilatori, correggendo il codice consultando anche solo il primo errore, nella compilazione seguente spariscono anche gli altri errori.

55

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma

La compilazione stata ripetuta considerando nuovi errori: 1. Eliminazione della parentesi graffa di chiusura del for a riga 16; 2. Eliminazione del return dal main; Nel DLanguage il main deve avere sempre come tipo di ritorno int. Il sorgente proposto il seguente:

56

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma

Gli errori sono stati riconosciuti correttamente, lunica pecca che per viene riscontrata anche nei compilatori pi famosi e affermati la posizione associata ai due errori; questo ovvio poich in questo caso il parser associa lultima parentesi graffa } al for e quindi segnaler lerrore solo per la mancanza della parentesi associata alla funzione main. Discorso analogo pu essere

57

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma ripetuto per il return il cui errore non potr essere rilevato finch non si scansionata tutta la funzione main.

6.3 TEST CASE: Polimorfismo


Con questo caso di test abbiamo cercato di mettere sotto stress il compilatore da noi realizzato e in base a quanto visto i risultati sono stati pi che soddisfacenti. Tale caso di test prevedeva diverse insidie: Lelevata lunghezza, quasi ottanta righe di codice; La realizzazione di tre classi; Ereditariet e polimorfismo; Lutilizzo di oggetti statici; Acquisizione dallo stdin e stampa dei valori sullo stdout;

Mandando in pasto al nostro front-end il seguente codice abbiamo ottenuto un Successfully Translated. Il risultato della compilazione mostrato subito dopo il codice sorgente.

58

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma

59

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma

Il codice intermedio stato correttamente generato dal nostro compilatore e il risultato viene mostrato di seguito:

60

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma Dopo aver verificato che il riconoscimento era stato effettuato con successo si passati allinserimento dei seguenti errori allinterno del sorgente: 1. Gli attributi della classe padre sono stati definiti come privati; 2. Alla funzione SetAltezzaRettangolo() della classe Rettangolo sono stati passati parametri differenti rispetto a quelli attesi; 3. Alla riga 51 stato rettango al posto di rettangolo; Non viene riportato di seguito il codice data leccessiva lunghezza del sorgente. Tali esempi sono comunque consultabili allinterno della cartella allegata Test_Case e tranquillamente eseguibili utilizzano linterfaccia grafica realizzata. Gli errori restituiti sono stati i seguenti:

Come possiamo notare dallimmagine sovrastante tutti gli errori prima citati sono stati individuati correttamente, sia per numero di riga che per tipo di errore; daltro canto sono presenti errori aggiuntivi che individuano uno StackOverflow, tale errore si verifica a causa dellottimizzazione del codice intermedio (vedi Paragrafo 5.2). Poich per eseguire tale
61

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma operazione si sfrutta uno stack e poich la presenza di attributi privati genera un errore che manda in tilt tale sistema utilizzato allinterno delle funzioni per il calcolo del perimetro e dellarea, il sistema genera questi errori aggiuntivi. Effettuando una comparazione con i reali compilatori possibile vedere delle analogie, anche i pi rinomati e consolidati compiler a fronte di particolari errori generano altri errori apparentemente scorrelati. Nellanalisi ci si spinti ancora oltre andando in questo caso a considerare i seguenti errori: A causa di un mispelling la variabile latoQuad (riga 72) stata dichiarata come latoad; Nella definizione delloggetto di classe Rettangolo il nome della classe stato digitato in minuscolo; stata commentata la riga 60 in cui presente la dichiarazione delloggetto di classe Quadrato; Loutput della compilazione riuscito in maniera corretta ad individuare tutti gli errori:

62

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma

6.4 TEST CASE: Parser Stack Optimization


In questo esempio, mettiamo in evidenza le caratteristiche di questo processo di ottimizzazione. Il codice del programma e lesito del programma sono: Nel codice possiamo notare due funzioni somma overlodate e diverse espressioni matematiche, delle quali alcune possono essere direttamente calcolate, altre risultano essere parametrizzate e pertanto non possibile calcolarle. Di seguito mostriamo il codice intermedio risultante e lesito della compilazione:

Come possiamo vedere, nel codice intermedio (destra) le variabili c (in somma()), a, ris, ris1, tot (prima operazione), ris2 sono state direttamente calcolate, mentre c (in somma(a,b)), j, tot (seconda operazione) dipendono da variabili il cui valore cambia, per questo non possono essere calcolate. Lesito della compilazione nella figura sottostante:

63

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma

Ora allinterno dello stesso codice, effettuiamo una variazione: come facile notare, la variabile a viene utilizzata allinterno del main, ma non stata dichiarata. Ecco il risultato della compilazione:

Il compilatore correttamente evidenzia la mancanza della dichiarazione di a ogni qual volta che questa viene utilizzata.

64

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma Mostriamo adesso ulteriori tipi di errori che il nostro compilatore riesce a individuare. Scriviamo il seguente codice:

65

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma

6.5 TEST CASE: Programmazione Orientata agli oggetti(1)


In questo esempio effettuiamo alcune operazioni con le classi. Ecco il codice: In questo esempio definiamo una classe

Automobile, con tre attributi privati (di default se non dichiarati) e tre metodi pubblici. Allinterno del main richiamiamo i tre metodi. Di seguito mostriamo il codice intermedio generato e il risultato della compilazione:

66

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma

In questo caso mostriamo anche il risultato della compilazione del codice intermedio, il quale stampa correttamente a video la frase sto cambiando marcia. Adesso modifichiamo leggermente il codice,

dichiarando come private anche i metodi accelera() e frena(). Il risultato della compilazione il seguente:

Come previsto, il compilatore ci avverte che i due metodi sono privati, e quindi non sono accessibili.

67

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma Effettuiamo un'altra modifica (codice sottostante); in questo caso proviamo ad assegnare un valore a un attributo della classe in modalit static, ma la classe non static! Per cui il risultato della compilazione sar il seguente:

Un ultima modifica per questo esempio la seguente: Nel codice mostrato, proviamo a richiamare la funzione frena(), passando un parametro; ma frena() non prevede alcun parametro; per cui il risultato della compilazione sar il seguente:

68

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma

6.6 TEST CASE: Programmazione Orientata agli oggetti(2)


In questo esempio mostriamo il funzionamento della relazione di aggregazione di tipo has a. Nella classe Automobile

dichiariamo un oggetto di classe Motore; concettualmente, infatti, un automobile ha un motore; sfruttiamo, della quindi, allinterno gli

classe

automobile,

attributi della classe motore. Il risultato della compilazione e il relativo codice intermedio vengono mostrati nelle figure sottostanti:

69

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma

Anche in questo caso, effettuiamo delle modifiche al codice per mostrare gli errori riconosciuti dal nostro compilatore: Nel codice rappresentato, lattributo vel_max della classe Motore privato, e quindi non pu essere utilizzato allinterno da nessuno, classe se non

della

Motore

stessa. In pi, definiamo un oggetto di una classe che non esiste. Nella pagina seguente possiamo osservare il risultato della compilazione

70

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma

Un altro esempio di errori riconosciuti il seguente: In questo codice invece, viene sbagliata la modalit di accesso alla variabile vel_max; infatti vel_max non direttamente un attributo della classe Automobile e quindi bisogna accedervi

attraverso la classe Motore; in pi, allinterno del main viene dichiarata una variabile b, ma manca il ;.

71

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma

6.7 TEST CASE: Programmazione orientata agli oggetti (3)


Lultimo esempio mostrato in questa relazione rappresentato dal seguente codice, in cui ancora una volta mostriamo il caso dellereditariet:

72

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma Introduciamo due varianti al codice, generando degli errori che il compilatore in grado di riconoscere:

In questo caso, oltre ad un accesso negato ad un attributo privato, mancano le due parentesi { e } del main().Lerrore generato di questo tipo: Syntax error: something wrong during Declaration. Maybe does ; miss?. Abbiamo scelto questo caso perch ovviamente anche il nostro compilatore pu sbagliare nel riconoscere un errore in alcune circostanze particolari. In questi casi, infatti, gli errori appropriati avrebbero dovuto riguardare esplicitamente la mancanza di { e }. Purtroppo, la mancanza contemporanea delle due parentesi crea un problema di precisione di questo tipo. Il prossimo caso il seguente:

73

D2C++ Compiler Linguaggi Formali e Compilatori


Test cases Donato Barone - Marco Suma

In questo ultimo esempio, ancora una volta dimostriamo il funzionamento delle protezioni delle variabili e metodi (sia allinterno della classe che eredita, che allesterno) e la chiamata di un metodo che non esiste secondo quel passaggio di parametri. Nel capito seguente presenteremo linterfaccia grafica realizzata.

74

D2C++ Compiler Linguaggi Formali e Compilatori


Graphical User Interface Donato Barone - Marco Suma

7. GRAPHICAL USER INTERFACE


Linterfaccia grafica dellapplicativo realizzato potrebbe risultare, ad un utente che non sia uno dei due realizzatori , non molto userfriendly. Tutto ci dovuto alla mancanza (per questioni di tempo) di un manuale che spieghi in dettaglio tutte le operazioni che possibile effettuare e quali sono gli strumenti a disposizione. Per sopperire a tale mancanza si ritenuto opportuno dedicare questa sezione a tale scopo. Innanzitutto linterfaccia grafica stata realizzata mediante il supporto delle librerie Qt [12], uno strumento potentissimo in grado di realizzare interfacce grafiche accattivanti e molto, molto altro. In aggiunta, ci siamo serviti dellIDE associato Qt Creator [13]. Prima di approfondire le principali operazioni effettuabili e quindi gli strumenti a disposizione, verranno proposte una serie di screenshot illustrative, che permetteranno al lettore di associare unazione al suo punto di chiamata. La prima screenshot mostra linterfaccia grafica dellapplicativo nella sua totalit. Da tale immagine si possono notare la casella di testo per poter caricare il file sorgente evidenziata dallintestazione Source e al momento in cui stata acquisita la screenshot priva di focus, la casella di testo in cui verr visualizzato il codice intermedio dopo la traduzione avvenuta con successo Intermediate.

75

D2C++ Compiler Linguaggi Formali e Compilatori


Graphical User Interface Donato Barone - Marco Suma

Fig. 7.1 Schermata principale dellapplicativo

Nellimmagine sottostante viene mostrato la barra di menu, altres detta MenuBar, presente in alto a sinistra che permette in questordine di creare un nuovo file (New), di aprire un proprio file sorgente (Open), di salvare le modifiche apportate sul file(Save), di salvare il file con nome(Save As), di eseguire il programma(Run) e di aprire un terminale(Open Terminal).

Fig. 7.2 visualizzazione della MenuBar

La screenshot successiva mostra i due menu a tendina a cui possibile accedere e dai quali possibile innescare le stesse azioni descritte sopra.

Fig. 7.3 visualizzazione dei men a tendina.

76

D2C++ Compiler Linguaggi Formali e Compilatori


Graphical User Interface Donato Barone - Marco Suma Degna di nota lulteriore finestra che viene creata nel momento in cui si vuole eseguire un programma. La nuova window si presenta nel seguente modo:

Fig. 7.4 Visualizzazione della schermata di esecuzione del codice intermedio.

I vari messaggi derrore che vengono individuati dai due casi duso: procedura derrore esecuzione e procedura derrore traduzione sono rappresentati nelle immagini sottostanti.

Fig. 7.5 alcuni esempi di visualizzazione di errori in fase di esecuzione dellapplicativo

Per meglio inquadrare le operazioni che lutente potr innescare stato utilizzato uno strumento fondamentale dello standard UML 2.0: il diagramma dei casi duso. Nellimmagine sottostante possiamo vedere il diagramma dei casi duso, che come si pu evincere dal titolo, mette in evidenza tutte le operazioni che un utilizzatore dellinterfaccia( rappresentato nellimmagine dallattore Utente) pu effettivamente eseguire.

77

D2C++ Compiler Linguaggi Formali e Compilatori


Graphical User Interface Donato Barone - Marco Suma

Fig. 7.6 Rappresentazione del diagramma dei casi duso Window Interaction

Fondamentalmente linterfaccia stata modellata in modo tale da ricordare un classico IDE (Integrated Development Environment) , per permettere allutente , in maniera intuitiva e senza aver letto alcun manuale sullapplicativo, di eseguire tutti i task previsti. Come in un qualsiasi IDE stata data la possibilit di caricare, creare e salvare file sorgenti; nel nostro caso i file sorgenti avranno estensione .d. Inoltre se la traduzione e quindi lanalisi del sorgente vanno a buon fine, lutente potr compilare e mandare in esecuzione il file contenente la rappresentazione intermedia, il tutto per due ragioni: 1) 2) Verificare che effettivamente il sorgente sia privo di errori; Mandare in esecuzione il programma per poterne visionare il risultato logico;

In aggiunta alle suddette funzionalit lutente/programmatore potr, in caso di necessit, aprire con la semplice pressione di un bottone un nuovo terminale per poter eseguire le operazioni pi disparate. Nelle pagine seguenti verranno riportati i casi duso presenti nellimmagine in forma testuale per riuscire cos ad avere uno scenario ancora pi completo delle operazioni consentite.

78

D2C++ Compiler Linguaggi Formali e Compilatori


Graphical User Interface Donato Barone - Marco Suma Come gi accennato lutente potr, come in un classico IDE, creare un nuovo sorgente direttamente allinterno dellapplicativo. Il che porter alla perdita di eventuali modifiche non salvate sul file precedentemente aperto, dato che non sono stati previsti controlli per evitare tale possibilit. Nuovo Sorgente(New) Descrizione Pre-Condizioni Post-Condizioni Evento Innescante Attore Primario Include il caso duso Estende il caso duso Esteso dal caso duso Specializza il caso duso Generalizza il caso duso Viene data la possibilit come in un qualsiasi IDE di poter scrivere direttamente il proprio sorgente .e successivamente di compilarlo ed eseguirlo Nessuna Dopo il salvataggio il file potr essere analizzato dal punto di vista lessicale, sintattico e semantico Cliccare sulla sottovoce New del menu oppure tramite la pressione del bottone presente nella menu bar in alto a sinistra dellinterfaccia Utente Nessuno Nessuno Nessuno Nessuno Nessuno
Fig. 7.7 Descrizione testuale del caso duso New.

Lutente/programmatore potr decidere di caricare il file direttamente da un qualsiasi supporto di memorizzazione di massa. Prima dellapertura lutente dovr scegliere il percorso del file da caricare tramite una comunissima finestra di dialogo per la scelta del path Aprire un sorgente(Open) Descrizione Viene data la possibilit in maniera analoga ad un comune IDE di poter caricare un file sorgente che potr successivamente essere modificato e analizzato Il file sorgente da aprire deve avere estensione .d Il file, se non soggetto a modifiche, potr essere analizzato dal punto di vista lessicale, sintattico e semantico e se lanalisi avviene con successo anche eseguito Cliccare sulla sottovoce Open del menu oppure tramite la pressione del bottone presente nella menu bar in alto a sinistra dellinterfaccia Utente Nessuno

Pre-Condizioni Post-Condizioni

Evento Innescante

Attore Primario Include il caso duso

79

D2C++ Compiler Linguaggi Formali e Compilatori


Graphical User Interface Donato Barone - Marco Suma Estende il caso duso Esteso dal caso duso Specializza il caso duso Generalizza il caso duso Nessuno Nessuno Nessuno Nessuno

Fig. 7.8 Descrizione testuale del caso duso Open.

Viene permesso anche il salvataggio del file che stato soggetto a modifiche. Nel caso in cui la prima volta che viene effettuato il salvataggio per un nuovo programma realizzato dallutente, verr data allo stesso la possibilit di scegliere la directory di salvataggio e il nome del file. Se invece non ci troviamo in tale situazione allora il file sar salvato sulla directory precedentemente fornita. Salvare un sorgente(Save) Descrizione Dopo aver effettuato modifiche allinterno del file sorgente caricato o dopo aver realizzato un nuovo file sorgente direttamente da interfaccia, sar possibile salvare tali modifiche Il file sorgente dovr essere salvato con estensione .d Il file, se non soggetto a modifiche, potr essere analizzato dal punto di vista lessicale, sintattico e semantico e se lanalisi avviene con successo anche eseguito Cliccare sulla sottovoce Save del menu oppure tramite la pressione del bottone presente nella menu bar in alto a sinistra dellinterfaccia Utente Salva File Nessuno Finestra di Salvataggio Nessuno Nessuno

Pre-Condizioni Post-Condizioni

Evento Innescante

Attore Primario Include il caso duso Estende il caso duso Esteso dal caso duso Specializza il caso duso Generalizza il caso duso

Fig. 7.9 Descrizione testuale del caso duso Save.

Il programmatore tramite una finestra di supporto potr prelevare informazioni di carattere generale sui realizzatori e sullapplicativo. Verranno fornite anche le e-mail dei realizzatori per eventuali domande. Informazioni(Info) Descrizione Lutente per poter ricevere una risposta ad un qualunque quesito potr accedere alla sezione dedicata alle informazioni e prelevare le e-mail o informazioni aggiuntive sui creatori Nessuna
80

Pre-Condizioni

D2C++ Compiler Linguaggi Formali e Compilatori


Graphical User Interface Donato Barone - Marco Suma Post-Condizioni Evento Innescante Attore Primario Include il caso duso Estende il caso duso Esteso dal caso duso Specializza il caso duso Generalizza il caso duso Nessuna Cliccare sulla sottovoce Info del menu Utente Nessuno Nessuno Nessuno Nessuno Nessuno

Fig. 7.10 Descrizione testuale del caso duso Save.

La chiusura dellapplicativo potr essere ottenuta con la pressione della classica x sullangolo della finestra oppure tramite la sottovoce presente allinterno del men a tendina. Uscire(Exit) Descrizione Pre-Condizioni Post-Condizioni Dopo aver terminato tutte le operazioni lutente potr uscire dallapplicativo Il file sorgente dovr essere salvato con estensione .d Il file, se non soggetto a modifiche, potr essere analizzato dal punto di vista lessicale, sintattico e semantico e se lanalisi avviene con successo anche eseguito Tale operazione sar perpetuata tramite la pressione della classica x presente sullangolo sinistro dellinterfaccia oppure utilizzando la sottovoce Exit del men Utente Nessuno Nessuno Nessuno Nessuno Nessuno

Evento Innescante

Attore Primario Include il caso duso Estende il caso duso Esteso dal caso duso Specializza il caso duso Generalizza il caso duso

Fig. 7.11 Descrizione testuale del caso duso Exit.

Per poter raggiungere la piena analogia con i classici IDE, viene permesso allutente, dopo aver tradotto con successo il proprio programma di mandarlo in esecuzione. Dato che il linguaggio utilizzato per la rappresentazione intermedia del nostro compilatore il C++, viene effettuata una ulteriore compilazione con il g++. Questo pu essere utile per riscontrare la presenza di errori non individuati dal nostro traduttore e in questo caso lesecuzione verr bloccata; se invece anche tale compilazione va a buon fine allora il programma realizzato verr eseguito allinterno di una finestra di supporto.

81

D2C++ Compiler Linguaggi Formali e Compilatori


Graphical User Interface Donato Barone - Marco Suma Esecuzione del sorgente(Run) Descrizione Dopo aver analizzato e tradotto il sorgente lutente come ulteriore verifica della correttezza del processo potr eseguire il programma direttamente allinterno dellinterfaccia Il file sorgente deve essere stato analizzato con successo Nessuna Cliccare sulla sottovoce Run del menu oppure tramite la pressione del bottone presente nella menu bar in alto a sinistra dellinterfaccia Utente Nessuno Nessuno Procedura derrore esecuzione Nessuno Nessuno

Pre-Condizioni Post-Condizioni Evento Innescante

Attore Primario Include il caso duso Estende il caso duso Esteso dal caso duso Specializza il caso duso Generalizza il caso duso

Fig. 7.12 Descrizione testuale del caso duso Run.

La funzionalit di base dellapplicativo e su cui si fonda tutto il progetto proprio la seguente, cio la possibilit di effettuare la traduzione del codice sorgente posto in ingresso dal D al C++, se durante la compilazione non vengono riscontrati errori. Traduzione del codice sorgente(Translate) Descrizione Pre-Condizioni Post-Condizioni Evento Innescante Attore Primario Include il caso duso Estende il caso duso Esteso dal caso duso Specializza il caso duso Generalizza il caso duso Il file sorgente caricato viene analizzato e tradotto Il file sorgente se modificato deve essere stato salvato Nella sezione dedicata al file intermedio apparir il risultato della traduzione Cliccare sulla sottovoce Translate del menu oppure tramite la pressione del bottone con etichetta Translate Utente Nessuno Nessuno Procedura derrore traduzione Nessuno Nessuno

Fig. 7.13 Descrizione testuale del caso duso Translate.

Giusto per aggiungere unulteriore funzionalit allapplicativo viene data la possibilit, tramite la pressione di un semplice pulsante, di poter aprire un terminale grazie al quale i programmatori

82

D2C++ Compiler Linguaggi Formali e Compilatori


Graphical User Interface Donato Barone - Marco Suma pi esperti e conoscitori della shell bash potranno addentrarsi per poter eseguire le operazioni di compilazione nellold-fashion-way. Aprire la Shell Bash (Terminal) Descrizione Per gli utenti pi esperti viene data la possibilit di aprire direttamente da interfaccia un terminale per poter effettuare qualsiasi tipo di operazione, tra cui leventuale compilazione del sorgente sfruttando un compilatore registrato Nessuna La CWD di default quella della cartella in cui risiede lapplicativo Tramite la pressione del bottone presente nella menu bar in alto a sinistra dellinterfaccia Utente Nessuno Nessuno Nessuno Nessuno Nessuno

Pre-Condizioni Post-Condizioni Evento Innescante Attore Primario Include il caso duso Estende il caso duso Esteso dal caso duso Specializza il caso duso Generalizza il caso duso

Fig. 7.14 Descrizione testuale del caso duso Terminal.

Questo caso duso viene richiamato nel momento in cui c la necessit di avere una finestra per la selezione della directory di salvataggio e normalmente viene attivato nel momento in cui si sta salvando per la prima volta un nuovo sorgente oppure se si sfruttata la classica funzione Save as. Finestra di Salvataggio (Save File Dialog) Descrizione Nel caso in cui lutente abbia creato un nuovo file, prima di effettuare il salvataggio, viene richiesta tramite interfaccia la directory in cui questo dovr avvenire Sia stato creato un nuovo file Il percorso in cui il file verr salvato verr settato in base al percorso che lutente ha scelto Viene richiamato nel momento in cui il path non settato Utente Nessuno Save Nessuno Nessuno Nessuno
83

Pre-Condizioni Post-Condizioni Evento Innescante Attore Primario Include il caso duso Estende il caso duso Esteso dal caso duso Specializza il caso duso Generalizza il caso duso

D2C++ Compiler Linguaggi Formali e Compilatori


Graphical User Interface Donato Barone - Marco Suma
Fig. 7.15 Descrizione testuale del caso duso Save File Dialog.

Permette di salvare il file in formato testuale nel path memorizzato con estensione .d. Salva File (Save File) Descrizione Pre-Condizioni Post-Condizioni Evento Innescante Attore Primario Include il caso duso Estende il caso duso Esteso dal caso duso Specializza il caso duso Generalizza il caso duso Viene salvato il contenuto della casella di testo presente allinterno del file specificato dal path Il path deve essere settato Il file se non presente viene creato Cliccare sulla sottovoce Save del menu oppure tramite la pressione del bottone Save Utente Nessuno Save Nessuno Nessuno Nessuno

Fig. 7.16 Descrizione testuale del caso duso Save File.

Permette di effettuare il classico Salva con nome presente allinterno di qualsiasi editor di testo. Salvare con nome(Save As) Descrizione Pre-Condizioni Post-Condizioni Evento Innescante Attore Primario Include il caso duso Estende il caso duso Esteso dal caso duso Specializza il caso duso Generalizza il caso duso Se si vuole salvare un sorgente caricato in unaltra directory lo si pu fare scegliendo sempre il percorso da interfaccia Sia stato caricato un file Il file viene creato nella directory specificata Cliccare sulla sottovoce Save As del menu oppure tramite la pressione del bottone Utente Finestra di Salvataggio, Salva File Nessuno Nessuno Nessuno Nessuno

Fig. 7.17 Descrizione testuale del caso duso Save File.

Se si dovesse cercare di effettuare lesecuzione di un file che non stato ancora caricato, lapplicativo mostrer una finestra di errore, segnalando allutente che prima di svolgere tale operazione dovr provvedere a fornire il percorso in cui il file sito.

84

D2C++ Compiler Linguaggi Formali e Compilatori


Graphical User Interface Donato Barone - Marco Suma Procedura derrore esecuzione (Execution Error) Descrizione Pre-Condizioni Post-Condizioni Evento Innescante Attore Primario Include il caso duso Estende il caso duso Esteso dal caso duso Specializza il caso duso Generalizza il caso duso Viene generata una finestra di errore per comunicare la tipologia dellerrore allutente durante lesecuzione Lutente voglia eseguire il risultato dellelaborazione Viene mostrata una finestra di errore Non sia stato caricato alcun file Utente Nessuno Esecuzione del sorgente Nessuno Nessuno Nessuno

Fig. 7.17 Descrizione testuale del caso duso Execution Error.

Procedura derrore traduzione(Translation Error) Descrizione Pre-Condizioni Post-Condizioni Evento Innescante Attore Primario Include il caso duso Estende il caso duso Esteso dal caso duso Specializza il caso duso Generalizza il caso duso Viene generata una finestra di errore per comunicare la tipologia dellerrore allutente durante la traduzione Lutente voglia tradurre il codice sorgente Viene mostrata una finestra di errore Non sia stato caricato alcun file Utente Nessuno Traduzione del codice sorgente Nessuno Nessuno Nessuno

Fig. 7.18 Descrizione testuale del caso duso Translation Error.

Infine, una piccola finestra di informazioni:

85

D2C++ Compiler Linguaggi Formali e Compilatori


Conclusioni Donato Barone - Marco Suma

8. CONCLUSIONI
Poniamoci alcune domande e forniamo delle risposte.

8.1. PERCH IL LINGUAGGIO D?


Non conoscevamo questo linguaggio. Per questo motivo abbiamo colto anche loccasione per conoscerne alcuni aspetti e incrementare il nostro bagaglio di conoscenza.

8.2. PERCH IL C++?


Abbiamo voluto concentrare lattenzione sul punto fondamentale di un front-end di un compilatore: la gestione degli errori. Se un traduttore non dovesse preoccuparsi di gestire gli errori dellutente, sarebbe un software relativamente facile da trattare. La scelta del C++ ci ha permesso innanzitutto di facilitare la fase di traduzione, ma soprattutto di poter gestire in maniera approfondita le classi e di poter avere un risultato concreto alla fine del nostro front-end.

8.3. QUALI SONO I PRINCIPI DI REALIZZAZIONE DEL TEMA DANNO?


Durante la realizzazione di questo tema danno, abbiamo tenuto conto di tre aspetti fondamentali, in ordine di importanza: 1) la qualit del lavoro: abbiamo ritenuto fosse importante mettere esplicitamente in pratica e dimostrare di aver appreso i concetti teorici della materia; 2) il tempo: abbiamo iniziato a lavorare per il progetto durante il corso perch rispettare i tempi di un esame un requisito per noi fondamentale nella misura in cui i tempi di consegna di un progetto in ambito lavorativo sono rigidi e incidono sui costi di sviluppo; per questo anche nel nostro piccolo abbiamo cercato di rientrare nei tempi previsti; 3) la quantit: linearmente dipendente da 1) e 2), ossia finch abbiamo ritenuto soddisfacente la qualit e finch c stato tempo, abbiamo incrementato la quantit degli aspetti da sviluppare;

86

D2C++ Compiler Linguaggi Formali e Compilatori


Bibliografia Donato Barone - Marco Suma

BIBLIOGRAFIA
[1] [2] [3] [4] [5] http://www.d-programming-language.org http://flex.sourceforge.net http://www.gnu.org/software/flex/manual/html_node/flex_toc.html http://www.gnu.org/software/bison/manual/index.html Compilers: Prinicples, Techiques, &Tools Alfred V.Aho, Monica S.Lam, Ravi Sethi,

Jeffrey D.Ullman pag 325 paragrafo 5.4.2 [6] [7] [8] [9] [10] Robert I. Pitts rip@cs.bu.edu : Stack - Array Implementation http://dlang.org/module.html http://seatd.mainia.de/grammar.html#Expression Uthash http://uthash.sourceforge.net/index.html - an hash tablle for C structures A2C An ADA-like parser/scanner and C translator - Ruggiero Campese, A.A.

2010/2011 [11] PHP2C Un traduttore da PHP a C - Bavaro Gianvito, Capurso Domenico, Donvito

Marcello, A.A. 2010/2011 [12] [13] http://qt.nokia.com/products/ http://qt.nokia.com/products/developer-tools/

87