NewLang รจ un nuovo linguaggio di programmazione molto basilare, creato con il solo scopo di comprendere la teoria, messa poi in pratica dietro lo sviluppo di un compilatore. Sono stati usati vari generatori per l'analisi lessicale e semantica. Il progetto รจ stato commissionato dal professore dell'Universitร degli Studi di Salerno Gennaro Costagliola e sviluppato dalle studentesse Esposito Mariarosaria e Perillo Francesca.
---------------------------------------------------
๐ฉ๐พโ๐ป Esposito Mariarosaria
๐ง m.esposito281@studenti.unisa.it
๐ฉ๐พโ๐ป Perillo Francesca
๐ง f.perillo11@studenti.unisa.it
---------------------------------------------------
๐ง๐พโ๐ซ Gennaro Costagliola
---------------------------------------------------
๐
A.A. 2022/2023
---------------------------------------------------
-----------------------------------------------
๐ข NOTA BENE.
-----------------------------------------------
TUTTO CIO' CHE CONCERNE GESTIONE DELLO
SCOPING, INFERENZA DI TIPO E TYPE
CHECKING VIENE RIPORTATO NELL'APPOSITA
DOCUMENTAZIONE RICHIESTA PER IL PROGETTO.
------------------------------------------------
๐๐ผ Clicca qui ๐๐ผ per accedere facilmente alla documentazione in formato pdf!
Di seguito viene riportata una breve panoramica della struttura del progetto.
๐ img
๐ข vengono storicizzate le immagini, utili per il readme.md
๐ src
๐ main
๐ generated
๐ข vengono salvati tutti i file generati da altri file!
๐ java
๐ข classi main, se ne discute nel capitolo Main classes
๐ visitor
๐ utility
๐ข classi utili ai visitors, come la tabella di compatibilitร e cosรฌ via
๐ CGenerator.java
๐ VisitorGenerateTreeXML.java
๐ VisitorSementic.java
๐ nodi
๐ข classi che rappresentano i nodi dell'albero
๐ test
๐ข nostre classi di test, discusse nei capitoli che seguono
๐ srcjflexcup
๐ GeneratoreLessicale.flex
๐ต GeneratoreSintattico.cup
๐ tests
๐ข classi di test fornite dal docente
All'interno della documentazione correlata al progetto verranno approfonditi alcuni aspetti della
struttura del progetto, specificando il contenuto della cartella ๐ utility/.. per una completa comprensione
della gestione dello scoping e dell'implementazione delle regole di tipo.
La grammatica originale รจ stata modificata eliminando ogni traccia di epsilon condition. Le produzioni che hanno portato alla modifica sono evidenziate di seguito:
*****************************************************************************
**************** Produzioni con epsilon prima della modifica ****************
*****************************************************************************
Program ::= DeclList MainFunDecl DeclList
DeclList ::= VarDecl DeclList | FunDecl DeclList | /* empty */
MainFunDecl ::= MAIN FunDecl
ParamDeclList ::= /*empty */
| NonEmptyParamDeclList
VarDeclList -> /* empty */
| VardDecl VarDeclList
Stat ::= IfStat
| ForStat
| ReadStat SEMI
| WriteStat SEMI
| AssignStat SEMI
| WhileStat
| FunCall SEMI
| RETURN Expr SEMI
| RETURN SEMI
| /* empty */
Else ::= /* empty */
| ELSE Body
L'intera grammatica dopo la modifica, risulta essere cosรฌ formata.
Program ::= DeclList MainFunDecl DeclList
| MainFunDecl DeclList
| DeclList MainFunDecl
| MainFunDecl
DeclList ::= VarDecl DeclList
| VarDEcl
| FunDecl DeclList
| FunDecl
MainFunDecl ::= MAIN FunDecl
VarDecl ::= Type IdInitList SEMI
| VAR IdInitObblList SEMI
Type ::= INTEGER
| BOOL
| REAL
| STRING
| CHAR
IdInitList ::= ID
| IdInitList COMMA ID
| ID ASSIGN Expr
| IdInitList COMMA ID ASSIGN Expr
IdInitObblList ::= ID ASSIGN Const
| IdInitObblList COMMA ID ASSIGN Const
Const ::= INTEGER_CONST
| REAL_CONST
| TRUE
| FALSE
| STRING_CONST
| CHAR_CONST
;
FunDecl ::= DEF ID LPAR ParamDeclList RPAR COLON TypeOrVoid Body
| DEF ID LPAR RPAR COLON TypeOrVoid Body
Body ::= LBRAC VarDeclList StatList RBRAC
| LBRAC StatList RBRAC
| LBRAC VarDeclList RBRAC
| LBRAC RBRAC
ParamDeclList ::= NonEmptyParamDeclList
NonEmptyParamDeclList ::= ParDecl
| NonEmptyParamDeclList PIPE ParDecl
ParDecl ::= Type IdList
| OUT Type IdList
TypeOrVoid ::= Type
| VOID
VarDeclList ::= VarDecl
| VarDecl VarDeclList
StatList ::= Stat
| Stat StatList
Stat ::= IfStat
| ForStat
| ReadStat
| WriteStat
| AssignStat
| WhileStat
| FunCall
| RETURN Expr SEMI
| RETURN SEMI
;
IfStat ::= IF Expr THEN Body Else
| IF Expr THEN Body
;
Else ::= ELSE Body
WhileStat ::= WHILE Expr LOOP Body
ForStat ::= FOR ID ASSIGN INTEGER_CONST TO INTEGER_CONST LOOP Body
ReadStat ::= IdList READ STRING_CONST
IdList ::= ID
| IdList COMMA ID
WriteStat ::= LPAR ExprList RPAR WRITE
| LPAR ExprList RPAR WRITELN
AssignStat ::= IdList ASSIGN ExprList
FunCall ::= ID LPAR ExprList RPAR
| ID LPAR RPAR
ExprList ::= Expr
| Expr COMMA ExprList
Expr ::= TRUE
| FALSE
| INTEGER_CONST
| REAL_CONST
| STRING_CONST
| CHAR_CONST
| ID
| FunCall
| Expr PLUS Expr
| Expr MINUS Expr
| Expr TIMES Expr
| Expr DIV Expr
| Expr AND Expr
| Expr POW Expr
| Expr STR_CONCAT Expr
| Expr OR Expr
| Expr GT Expr
| Expr GE Expr
| Expr LT Expr
| Expr LE Expr
| Expr EQ Expr
| Expr NE Expr
| MINUS Expr
| NOT Expr
| LPAR Expr RPAR
Occorre notare che nonostante la rimozione delle epsilon condition, la grammatica risulta essere equivalente alla precedente.
Di seguito vengono riportati i diagrammi per la specifica degli alberi sintattici, presenti anche nella quarta esercitazione.
๐๐ผ Clicca qui ๐๐ผ per accedere facilmente al formato pdf!
Per quanto concerne la gestione dello scope sono state utilizzate varie classi java, presenti al path:
๐ src
๐ main
๐ visitor
๐ utility
๐ Element
๐ ElementMethod
๐ ElementVar
๐ SymbolTable
๐ TypeEnvironment
๐ ...
La tabella dei simboli รจ gestita dalla classe SymbolTable.java e vede lโutilizzo di un
HashMap<String, Element>. La classe Element viene estesa da due altre classi: ElementMethod.java e
ElementVar.java a seconda se l'elemento da aggiungere sia rispettivamente un metodo o una variabile.
La tabella dei simboli รจ una entry del TypeEnvironment, gestito dall'omonima classe TypeEnvironment.java,
che fa uso di un da uno Stack di SymbolTable. Questa classe contiene metodi per la gestione dello scope
(si riporta alla documentazione associata per una visione piรน approfondita dei metodi
utilizzati per la gestione dello scope).
Occorre notare che NewLang permette l'utilizzo di una variabile e di una funzione anche prima della loro dichiarazione. Per permettere ciรฒ sono state rispettivamente utilizzate due diverse strutture dati:
- una
HashMap<String,String>, nel caso di una variabile. La chiave รจ il nome della variabile stessa; mentre il valore รจ il suo Tipo. - un
ArrayList<String>, nel caso di una funzione. La stringa rappresenta il nome della funzione.
Nel momento in cui una variabile viene utilizzata viene fatto un primo check facendo la .lookup(), se non รจ stata ancora dichiarata
allora viene aggiunta all'HashMap<String, String> e viene rimossa solo nel momento in cui viene effettivamente dichiarata.
Per verificare che tutte le variabili utilizzate siano effettivamente state anche dichiarate, un ultimo controllo viene effettuato
alla fine dell'esecuzione. Se l'HashMap<String,String> allora vuol dire che tutte le variabili sono state dichiarate; altrimenti
l'esecuzione terminerร con un errore.
Per quanto invece riguarda le funzioni, la gestione รจ simile.
In totale nel progetto sono presenti tre classi main nel path main/java/..:
๐ main
๐ java
๐โถ NewLang2C
๐โถ TesterLexer
๐โถ TesterParser
๐TesterLexerper ottenere l'output dell'analisi lessicale;๐TesterParserper ottenere l'output dell'analisi sintattica e semantica.๐NewLang2Cper ottenere gli output dei vari casi di test presenti al pathtest_files/..
In questa esercitazione viene eseguita la classe ๐โถTesterParser.
๐พ โถ Per eseguire il programma di prova di NewLang occorre lanciare la configurazione programma
Per testare il codice C generato dalla classe main ๐NewLang2C รจ stato utilizzato il seguente compilatore online.
In questo capitolo verranno illustrati prima i nostri casi di test che abbiamo utilizzato per il testing di questa esercitazione; poi i casi di test che ci sono stati forniti dal docente per la Continuous Integration.
In questo paragrafo vengono riportati e spiegati i casi di test utilizzati nel corso della seguente esercitazione prima di ricevere i test forniti dal docente. E' possibile visionare tali casi di test al path:
๐ src
๐ test
๐ testFAIL
๐ declFail
๐ ...
๐ Test_[n]
๐ ...
๐ methodFail
๐ ...
๐ methodT[n]
๐ ...
๐ Programma.txt
Nella cartella ๐ declFail/.. sono riportati nello specifico i seguenti casi di errore:
๐ Test_01. Si sta tentando di fare l'assegnazione fra due tipi differenti (string e integer);๐ Test_02. Tipo atteso e tipo effettivo di una data variabile non corrispondono;๐ Test_03. Si sta tentando di utilizzare un identificatore specifico senza che questo sia mai stato dichiarato;
Nella cartella ๐ methodFail/.. sono riportati nello specifico i seguenti casi di errore:
๐ methodT2. La funzione esecuzione() viene chiamata con un numero diverso di parametri;๐ methodT3. So sta tentando di dichiarare due funzioni identiche.๐ methodT4. Si tenta di usare una funzione senza che la dichiarazione della funzione stessa esista.
Il file ../๐ Programma.txt contiene tutto ciรฒ che รจ stato richiesto dal docente, ovvero
("2. Addizione") -->!;
("3. Sottrazione") -->!;
("4. Moltiplicazione usando la somma") -->!;
("5. Divisione intera fra due numeri positivi") -->!;
("6. Elevamento a potenza") -->!;
("7. Successione di Fibonacci") -->!;
Per vedere l'esecuzione di ogni file di test, sono presenti delle configurazioni che seguono il nome degli stessi files di test.
In questo paragrafo vengono riportati i bug riscontrati durante l'esecuzione dei test forniteci dal docente e
il mondo in cui questi sono stati risolti. I file sono situati nella cartella ๐ tests/...
๐ tests
๐ invalid_xxx
๐ invalid_xxx.txt
๐ valid[n]
๐ valid[n].txt
๐ valid[n]_in.txt
๐ valid[n]_out.txt
I file con prefisso invalid_ rientrano tutti in situazioni di errore che riprendono il nome del file stesso (xxx nell'esempio riportato sopra).
Oltre ciรฒ, tali file contengono informazioni aggiuntive, ad esempio, come evince della pipeline, per il test
๐ invalid_missingfunction l'errore corrisponde al nome del file (Missing Function), ma oltre ciรฒ viene riportata una informazione
aggiuntiva circa il nome della funzione che non esiste.
Test name: tests/invalid_missingfunction
mvn --batch-mode -q exec:java -Dexec.args=tests/invalid_missingfunction/invalid_missingfunction.txt
java.lang.Error: Missing Function.
VisitorSemantic - La funzione - potenza() - non esiste.
at main.visitor.VisitorSemantic.visit(VisitorSemantic.java:79)
at nodi.ProgramOp.accept(ProgramOp.java:81)
at main.java.NewLang2C.main(NewLang2C.java:31)
at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:254)
at java.base/java.lang.Thread.run(Thread.java:833)
Oltre ciรฒ, ๐ invalid_toomanyparm, ๐ invalid_wrongparameternumber
e ๐ invalid_wrongparaumber forniscono un Error diverso dal nome del file stesso in quanto per
tutti questi l'errore risulta essere "Wrong Param Number". Ancora, ๐ invalid_wrongoutuse
fornisce un Error diverso da "Wrong out use". Di seguito ne viene riportato un esempio:
------------------------
๐ invalid_wrongoutuse
------------------------
Test name: tests/invalid_wrongoutuse
mvn --batch-mode -q exec:java -Dexec.args=tests/invalid_wrongoutuse/invalid_wrongoutuse.txt
java.lang.Exception: VisitorSemantic - TypeChecking_ERROR.
Errore di compatibilita' fra i tipi in
- tipo 1: string
- operazione: PLUS
- tipo 2: integer
------------------------
๐ invalid_toomanyparm
------------------------
Test name: tests/invalid_toomanyparm
mvn --batch-mode -q exec:java -Dexec.args=tests/invalid_toomanyparm/invalid_toomanyparm.txt
java.lang.Error: Wrong param number.
VisitorSemantic. La funzione potenza() viene chiamata con un numero diverso di parametri:
- numero di parametri attesi: 3
- numero di parametri con cui viene chiamata: 2
-------------------------------
๐ invalid_wrongparameternumber
-------------------------------
Test name: tests/invalid_wrongparameternumber
mvn --batch-mode -q exec:java -Dexec.args=tests/invalid_wrongparameternumber/invalid_wrongparameternumber.txt
java.lang.Error: Wrong param number.
VisitorSemantic. La funzione potenza() viene chiamata con un numero diverso di parametri:
- numero di parametri attesi: 2
- numero di parametri con cui viene chiamata: 1
-------------------------
๐ invalid_wrongparaumber
-------------------------
Test name: tests/invalid_wrongparamnumber
mvn --batch-mode -q exec:java -Dexec.args=tests/invalid_wrongparamnumber/invalid_wrongparamnumber.txt
java.lang.Error: Wrong param number.
VisitorSemantic. La funzione succ_fibonacci() viene chiamata con un numero diverso di parametri:
- numero di parametri attesi: 0
- numero di parametri con cui viene chiamata: 1
I files con prefisso valid devono fornire un codice C che, compilato ed eseguito con gli input
presenti nei files ๐ valid[numero]_in.txt, devono fornire in output il contenuto dei files
๐ valid[numero]_out.txt. Di seguito vengono riportate tutte le modifiche necessarie al file di permettere la corretta
compilazione del codice in C.
Testando questo file ci siamo rese conto della mancanza di una regola di compatibilitร tra i tipi string.
Quest'ultima รจ stata inserita nella classe
๐ src
๐ main
๐ visitor
๐ utility
๐ CompatibilityTables.txt
che gestisce la tabella di compatibilitร . I due metodi principali per la gestione della tabella di compatibilitร sono i seguenti
/**
* Metodo che implementa la tabella di compatibilitร per opType1:
* operatori unari.
* T |- e:t1 optype1(op1,t1) = t
* -----------------------------------
* T |- op1 e : t
* @param operazione
* @param tipoOperando
* @return
*/
public TypeOperation optype1(OpType operazione, String tipoOperando)
{...}/**
* Metodo che implementa la tabella di compatibilitร per opType2:
* operatori binari.
* T |- e1:t1 T |- e2:t2 optype2(op2,t1,t2) = t
* ------------------------------------------------------
* T |- e1 op2 e2 : t
* @param operazione tipo di operazione che si deve svolgere
* @param tipoOperando1 tipo del primo operando
* @param tipoOperando2 tipo del secondo operando
* @return tipo risultante
*/
public TypeOperation optype2(OpType operazione, String tipoOperando1, String tipoOperando2)
{...}dove optype1(...) e optype2(...) rappresentano rispettivamente le tabelle di compatibilitร riportate
all'interno della documentazione correlata al suddetto progetto.
Inoltre, per quanto concerne gli identificatori, il pattern รจ stato modificato nel modo che segue
โ from: identifier = [A-Za-z][A-Za-z0-9]*
โ to: identifier = [A-Za-z][\_A-Za-z0-9]*
in modo da consentire che un id potesse contenere il carattere speciale _ (trattino basso)
In questo caso di test la funzione main viene richiamata, cosa non gestita prima di lanciare questo test, motivo per cui
la classe ๐ CGenerator.java ha subito una modifica. Considerando il caso specifico del secondo file di test valido
start:
def stampa(string messaggio): void {
integer a;
integer i;
for x << 4 to 1 loop {
("") -->! ;
}
(messaggio) -->! ;
}
il codice C avrร la dichiarazione di una funzione void stampa(string messaggio) {...} e un main
contenente nel proprio body la dichiarazione di una stringa messaggio (paraertro passato alla funzione stampa).
Sono state inserite le regole di compatibilitร per permettere la concatenazione anche quando il primo argomento รจ una stringa e il secondo รจ un intero o un real.
--------------------------------------------------
๐ข NOTA BENE.
--------------------------------------------------
LA NOSTRA IMPLEMENTAZIONE NON PREVEDE LA
CONCATENAZIONE CON I VALORI DI RITORNO DELLE
FUNZIONI. PER EFFETTUARE TALE CONCATENAZIONE,
E' NECESSARIO SALVARE IL VALORE DI RITORNO
DELLA FUNZIONE IN UNA VARIABILE.
---------------------------------------------------
Esempio.
โ๏ธ
stampa("la somma fra a e b รจ: " & somma(a,b));
โ๏ธ
float c << somma(a,b);
stampa("la somma fra a e b รจ: " & c);
In questo caso, il problema era dovuto ad un errore lessicale dato dal non riconoscimento di alcuni caratteri speciali all'interno della sezione dedicata ai commenti. Per tale motivo, nell'analizzatore lessicale la gestione dei commenti รจ stata modificata permettendo a questi ultimi di contenere la maggior parte dei caratteri speciali consentiti.
โ from: /* comments */
CommentMoreLine = "|*"({identifier}|{integer}|{whitespace}|"'")*"|"
CommentLine = "||"({identifier}|{integer}|{whitespaceNoLN}|"'")*{ln}
โ to: accented = ร |รจ|รฉ|รฌ|รฒ|รน
special = _|-|\!|\"|ยฃ|%|&|\/|\(|\)|=|\?|\^|,|\.|;|:|ยฐ|#|@|รง|\{|\}|\[|\]|\*|\+|ยง|<|>|\/|\\
/* comments */
CommentMoreLine = "|*"({identifier}|{integer}|{whitespace}|"'"|{accented}|{special})*"|"
CommentLine = "||"({identifier}|{integer}|{whitespaceNoLN}|"'"|{accented}|{special})*{ln}
Per la generazione del codice C vengono utilizzati delle variabili temporanee utili al fine della corretta generazione del codice.
Pertanto, tali variabili NON possono essere utilizzate nella scrittura del codice NewLang, tali variabili sono le seguenti:
MAXDIMutilizzata per settare la dimensione dei buffer di caratteri;concat_[n]ebuffer_bis_[n], con n>0, utilizzata per la gestione della concatenazione;v_tmp_[n], con n>0, utilizzata per la gestione di variabili temporanee utili come variabili di appoggio.
