Luppolo è un linguaggio di programmazione in grado di manipolare espressioni algebriche creato come progetto durante il corso Magistrale di Linguaggi e Traduttori dell'Università degli Studi di Milano. La traccia completa dello stesso può essere trovata al seguente link.
- STRUTTURA DEL PROGETTO
- DIPENDENZE
- GUIDA ALL'UTILIZZO
- RAPPRESENTAZIONE
- FUNZIONI LIBRERIA
- LUPPOLO TEST
Tutti i file sorgente possono essere trovati all'interno della cartella src
.
Essi sono suddivisi rispettivamente in ast
, che contiene la definizione degli alberi sintattici astratti, grammar
, che contiene la grammatica de
8000
l linguaggio, interpreter
, che contiene l'interprete del linguaggio e utils
, che contiene una serie di classi di utilità.
Oltre a src
è anche presente la cartella test
, che contiene i test del progetto.
L'ast rappresenta l'albero astratto del linguaggio, ovvero una semplificazione dell'albero sintattico originale generato dal parser in fase di parsing del codice.
La generazione dell'AST avviene attraverso la classe AstGenerator che utilizzando un visitor, visita l'albero sintattico generato dal parser e produce per ogni nodo le corrispettive astrazioni che possono essere trovate all'interno della directory elements.
Le espressioni sono le unità fondamentali del linguaggio, e sono rappresentate all'interno della cartella expression.
Sono utilizzate per la rappresentazione di espressioni algebriche e possono essere suddivise in nodes, che rappresentano gli operatori di somma, prodotto e potenza, e leaf, che sono i numeri razionali e i simboli.
Contiene la definizione della grammatica del linguaggio Luppolo.
E' presente inoltre la classe AntlrGrammarCompiler che permette di compilare la grammatica in modo automatico. Vedi sezione compilazione automatica per ulteriori informazioni.
In LuppoloGrammar è presente invece la definizione di tutti gli elementi utili per interagire con la grammatica.
Contiente l'interprete del linguaggio, che permette di eseguire il codice scritto in Luppolo.
L'interprete è un interprete iterativo che permette di interpretare funzioni e per ognuna di esse possiede una memoria delle variabili, uno stack delle istruzioni e uno stack dei valori computati.
Contiente alcuni elementi utilizzati durante lo sviluppo del progetto, come la classe LuppoloLogger che permette di loggare messaggi in maniera strutturata, e le classi GenericTreeNode, che rappresenta un generico nodo con i relativi figli per strutturare una gerarchia di nodi, e GraphTreeNode, che permette la rappresentazione grafica di un nodo.
La classe Converter permette di convertire qualsiasi espressione della grammatica in un'opportuna espressione dell'AST (utile per passare i parametri nell'interpretezione delle funzioni).
Infine la classe ExprToPdf permette la generazione di un file pdf contenente tutte le rappresentazioni di una espressione algebrica data la stessa e di poter inoltre generare la rappresentazione grafica PDF di un qualsiasi GenericTreeNode
.
-
PYTHON 3.10.11
Il progetto è stato sviluppato utilizzando Python 3.10.11. Se non si possiede Python è possibile scaricarlo dal sito ufficiale. -
ANTLR4 (V4.13.2)
Il progetto utilizza ANTLR4 per la generazione del Lexer e del Parser. Per installare ANTLR4 è possibile seguire la guida ufficiale disponibile al seguente link.
Si consiglia di impostare%ANTLR4_JAR%
come variabile d'ambiente contenente il path del jar di antlr4, altrimenti è necessario specificare il path del jar di antlr4 in fase di compilazione della grammatica. Vedi sezione guida all'utilizzo per ulteriori informazioni. -
TEX DISTRIBUTION (Opzionale)
Se si vuole sfruttare la generazione del PDF contenente il risultato del programma, è necessario avere una distribuzione di TEX installata che permetta il comandopdflatex
.
Durante lo sviluppo è stato utilizzato MikTex.
Luppolo mette a disposizione 3 funzionalità principali:
ATTENZIONE: Prima di iniziare ad utilizzare LUPPOLO è necessario compilare la grammatica, che non viene fornita precompilata.
La compilazione della grammatica può essere effettuata o manualmente o automaticamente. La sua compilazione permette la generazione all'interno della cartella bin del Lexer
, del Parser
, del Listener
e del Visitor
, sui quali è basato il resto del funzionamento del progetto.
Per la compilazione automatica viene messa a disposizione la classe AntlrGrammarCompiler, che permette di compilare la grammatica in modo automatico.
Per avviare la compilazione basta eseguire il metodo compileGrammar()
della classe AntlrGrammarCompiler
. Vedere la documentazione del metodo per ulteriori informazioni sui parametri.
E' possibile inoltre compilare la grammatima direttamente da linea di comando eseguendo il comando:
python -m src.main compile
Per approfondimenti vedere la guida aggiungendo --help
alla fine del comando.
Per la compilazione manuale è necessario utilizzare il jar di antlr4 attraverso il comando:
java -jar [YOUR ANTLR_JAR] -Dlanguage=Python3 -visitor -o ../bin/ src/grammar/syntax/luppolo.g
oppure:
cd src
antlr4 -Dlanguage=Python3 -visitor -o ../bin/ src/grammar/syntax/luppolo.g
ATTENZIONE: L'esecuzione dell'interprete è subordinata alla compilazione della grammatica.
Il file sorgente che deve essere interpretato deve avere l'estensione .lp
e deve essere passato come primo argomento quando viene eseguito l'interprete.
Oltre al file sorgente è possibile specificare (se necessario) i parametri in formato stringa che verranno passati alla funzione principale del programma. Questi possono essere semplici valori numerici così come valori più complessi tipo espressioni algebriche, funzioni definite nello stesso sorgente o funzioni di libreria. Essi verranno infatti interpretati nel momento dell'esecuzione dell'interprete.
Di default il comando produce un file pdf contenente l'espressione risultante dall'interpretazione del programma e questa viene fornita sotto forma di albero, in formato LaTeX e in formato testuale. Vedi la sezione Rappresentazione per ulteriori informazioni.
Per eseguire l'interprete è possibile utilizzare il comando run
come segue:
python3 -m src.main run ./path/to/sorgente/sorgente.lp [param1] [param2] ...
Il comando mette a disposizioni una serie di opzioni che permettono ad esempio di specificare la funzione principale, di scegliere il formato del file pdf generato, di scegliere il tipo di output da dare in console, di specificare il livello di logging e altro.
Per tutte le opzioni disponibili è possibile aggiungere --help
alla fine del comando per avere ulteriori informazioni.
Per eseguire i test è possibile utilizzare il comando test
come segue:
python -m src.main test
Il comando mette a disposizioni una serie di opzioni che possono essere consultate aggiungendo --help
alla fine del comando.
All'interno di Luppolo è stata data la possibilità di rappresentare sia le espressioni algebriche che i nodi dell'AST in molteplici formati.
FORMATO TESTUALE
ALBERI GRAFICI
generati come PDFFORMATO LATEX
(solo per le espressioni algebriche)
Il formato testuale è la rappresentazione più semplice e consiste in una stringa che rappresenta la struttura dell'albero dell'AST o dell'espressione.
Essa può essere ottenuta utilizzando il metodo Trees.toStringTree(par)
di antlr4, e come parametro può essere passato sia l'AST che una espressione.
Un esempio di rappresentazione testuale dell'AST
è il seguente:
(P (F (BLK (A 2) (IFEL (EQ A 2) (BLK (A (POW x 2))) (BLK (A 0))) (RET A))))
Un esempio di rappresentazione testuale di un'espressione
è il seguente:
(S (M 3 x) (P x 1/2) (P x 3))
Questo tipo di formato permette di ottenere una semplice rappresentazione grafica dell'albero dell'AST o dell'espressione.
Per ottenere un albero grafico è possibile utilizzare la classe GraphTreeNode
che permette di generare un albero grafico a partire dall'AST o da una espressione.
Un esempio di albero grafico dell'AST
è il seguente:
Un esempio di albero grafico di un'espressione
è il seguente:
Il formato LaTeX permette di ottenere una rappresentazione in formato LaTeX dell'espressione algebrica.
Per ottenere una rappresentazione in formato LaTeX è possibile utilizzare il metodo getLatexRapresentation()
fornito da tutti gli elementi che rappresentano un'espressione algebrica.
Un esempio di rappresentazione LaTeX di un'espressione
è il seguente:
'3\\cdot x+\\sqrt{x}+x^{3}'
In formato LaTeX:
In Luppolo sono state sviluppate 5 funzioni di libreria che possono essere utilizzate all'interno del codice sorgente.
Le funzioni di libreria sono le seguenti:
Expand
: Espande un'espressione algebricaSubstitute
: Sostituisce tutte le sottoespressioni di un'espressione algebrica con un'altra espressione algebricaEval
: Valuta un'espressione algebrica sostituendo il simbolo nell'espressione con il valore datoSimpleDerive
: Calcola la derivata di un'espressione algebrica rispetto ad una variabileDerivePolynomial
: Calcola la derivata di un polinomio univariato dopo averlo espanso
In questo progetto sono stati forniti dei test di base che permettono di verificare il corretto funzionamento del linguaggio.
I test non devono essere intesi come esaustivi e non seguono nessun tipo di specifica formale quale unit test o integration test o analoghi, ma sono stati creati per verificare il corretto funzionamento del linguaggio durante lo sviluppo.
Sono state create molteplici cartelle con dentro i corrispettivi test (spiegati di seguito) e sono stati divisi in due categorie: valid
e erroneous
.
I test valid
sono test che dovrebbero essere accettati dal linguaggio, mentre i test erroneous
sono test che dovrebbero essere rifiutati.
NOTA: Alcuni test sono subordinati alla correttezza di altri costrutti sintattici, altrimenti sarebbero rifiutati a prescindere dalla grammatica.
Es: In grammar Id è subordinato alla correttezza di function(vedi emptyFunc), poichè il funzionamento è stato testato nella dichiarazione di funzione.
Per l'esecuzione dei test è possibile utilizzare il comando test
come spiegato nella sezione Esecuzione dei test.
All'interno della folder grammar sono presenti alcune batterie di test per la grammatica del linguaggio.
Sono stati testati tutti i costrutti sintattici del linguaggio e per ognuno di essi sono stati sono stati creati dei test che permettono di provare le varie configurazioni che
5579
devono essere rispettate.
All'interno di interpreter sono presenti dei test che permettono di verificare il corretto funzionamento dell'interprete.
All'interno di ast sono presenti dei test che permettono di verificare il corretto funzionamento della generazione dell'AST. Questi non sono divisi tra valid
e erroneous
poichè non è possibile generare un AST da un codice errato.
Questi test richiedono di essere eseguiti a mano e verificare dunque che l'AST prodotto rispecchi quanto atteso.