Compilatore per Espressioni Scopo: Leggere un'espressione aritmetica in notazione infissa (l'espressione puo' contenere anche degli identificatori). Tradurre l'espressione in codice per la macchina virtuale (classe lt2.macchina.Macchina) che valuti l'espressione stessa, dopo avere assegnato agli identificatori dei valori letti da input. File: Compilatore.java ParserEspressioni.java Expr.java Descrittore.java SymbolTable.java Utilizza classi del package lt2.calc Utilizza classi del package lt2.macchina Avvio dell'applicazione: metodo main di Compilatore.java Note relative ai file: ^^^^^^^^^^^^^^^^^^^^^ *** Compilatore.java Questa classe contiene il metodo main che svolge i seguenti compiti: - legge da input una espressione aritmetica in notazione infissa - genera un file di nome "eseguibile", contenente codice per la valutazione dell'espressione, destinato alla macchina virtuale definita nel package lt2.macchina. Tale codice puo' essere eseguito mediante il comando java lt2.macchina.Macchina Per maggiori dettagli sull'uso della macchina virtuale e sul suo set di istruzioni, si faccia riferimento alla relativa documentazione. *** ParserEspressioni.java Esamina un'espressione aritmetica, i cui token vengono forniti tramite un analizzatore lessicale, e costruisce un abstract syntax tree che la rappresenta, con associata una symbol table per gli identificatori. In particolare la classe e' dotata di: - un costruttore che riceve come argomento l'analizzatore lessicale che fornira' i token - un metodo parse() che effettua il parsing e restituisce il riferimento alla radice del parse tree - un metodo getSymbolTable() che restituisce un riferimento alla symbol table (la symbol table, inizialmente vuota, risultera' riempita dopo l'invocazione del metodo parse()). *** Expr.java Definisce la classe astratta Expr, con le sottoclassi concrete per la rappresentazione come abstract syntax tree. La classe fornisce: - un metodo generaCodice(Codice c) che ha il compito di generare il codice corrispondente all'espressione; tale codice viene memorizzato nell'oggetto Codice di cui viene fornito il riferimento tramite il parametro (la classe Codice fa parte del package lt2.macchina) - un metodo toString() che ha il compito di fornire una stringa che rappresenta l'espressione in notazione postfissa. Ciascuna sottoclasse concreta dispone di un costruttore, che dipende dal tipo di espressione rappresentata dalla sottoclasse. In particolare, il costruttore della sottoclasse IdExpr, corrispondente agli identificatori, riceve come argomento il riferimento al descrittore che nella symbol table rappresenta l'identificatore considerato. *** Descrittore.java Descrive un identificatore come terna . Il campo indirizzo e' destinato a contenere l'indirizzo della prima locazione di memoria associata all'identificatore. Il campo lunghezza contiene il numero di locazioni di memoria associate all'identificatore. In questo esempio ogni identificatore ha associata un'unica locazione di memoria; dunque lunghezza vale sempre 1. Se si volessero associare agli identificatori dati di lunghezze differenti (ad esempio volendo gestire gli array) basterebbero semplici modifiche a questa classe. Fornisce due costruttori, uno che riceve solo il nome (e assegna di default 0 a valore), l'altro che riceve il nome e l'indirizzo. Vi sono inoltre i metodi - String getIdentificatore() che restituisce il nome dell'identificatore, - int getIndirizzo(), int getLunghezza() che restituiscono rispettivamente l'indirizzo e la lunghezza. - public int assegnaIndirizzo(int ind) che assegna all'identificatore l'indirizzo specificato e restituisce l'indirizzo immediatamente successivo allo spazio riservato all'identificatore (in questo esempio l'indirizzo successivo sara' sempre ind + 1, se si avesse invece un array di lunghezza 10, tale indirizzo sara' ind + 10). *** SymbolTable.java Rappresenta una tabella di oggetti di tipo Descrittore. Fornisce - un costruttore privo di argomenti che crea la tabella vuota - un metodo Descrittore trova(String s) che ricerca nella tabella un descrittore per l'identificatore fornito tramite l'argomento. Se la ricerca ha successo ne restituisce il riferimento, altrimenti restituisce il riferimento null. - un metodo aggiungi(Descrittore d) per aggiungere un elemento alla tabella - un metodo Descrittore trovaEAggiungi(String s) che ricerca nella tabella un descrittore per l'identificatore fornito tramite l'argomento e, se non lo trova, ne inserisce uno nuovo (ricerca con inserimento). - un metodo iterator() per ottenere un iteratore che permetta di scandire gli elementi presenti nella tabella. Note relative alle implementazioni: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ *** Compilatore.java Il metodo main dopo avere letto l'espressione da input: - crea un analizzatore lessicale per tale espressione - crea un parser che riceve i token dall'analizzatore lessicale Successivamente chiede al parser di produrre l'albero corrispondente all'espressione (invocazione di parse()) e di fornire la symbol table (invocazione di getSymbolTable()) - crea un oggetto Codice, destinato a memorizzare il codice prodotto dalla compilazione - prima di iniziare la generazione del codice, esamina uno alla volta gli elementi presenti nella symbol table (ciclo for-each), assegnando a ogni identificatore un indirizzo di memoria - per ciascuna variabile viene generato codice che, in esecuzione, svolgera' le seguenti operazioni: -- occupa lo spazio di memoria associato all'identificatore -- visualizza il nome dell'identificatore -- legge da input il valore che l'utente intende assegnargli. -- memorizzato tale valore nello spazio riservato all'identificatore - viene poi generato il codice corrispondente all'espressione, invocando il metodo generaCodice dell'oggetto associato al riferimento e (cioe' l'albero che rappresenta l'espressione) - viene generato infine il codice per stampare il risultato (lasciato in cima allo stack della macchina) e per terminare l'esecuzione - viene invocato il metodo fineCodice dell'oggetto Codice, che segnala la fine della generazione del codice. *** ParserEspressioni.java Questo file e' identico a quello della versione precedente (costruzione dell'albero e sua successiva valutazione). *** Expr.java La sottoclasse concreta IdExpr memorizza il riferimento al descrittore, all'interno della symbol table, dell'identificatore considerato. *** SymbolTable.java Questo file e' identico a quello della versione precedente (costruzione dell'albero e sua successiva valutazione), tuttavia la classe Descrittore utilizzata e' differente.