Il seguente documento contiene la specifica del linguaggio MyFun implementato all'interno del progetto.
- Project SDK: 17
- Project Language Level: SDK Default
- Maven: Utilizzato (pom.xml versione MacOS su Gitlab)
GENERAZIONE PARSER,LEXER E JAR: Si consiglia di utilizzare le configurazioni fornite in IntelliJ.
ISTRUZIONI ESECUZIONE: Si consiglia di utilizzare per il lancio del progetto le configurazioni create in IntelliJ (eventualmente modificando i path per aggiungere file esterni), inoltre è stato fornito il test file 8, vuoto per l'eventuale aggiunta di codice di test.
ATTENZIONE: Il file valid2.txt contiene alcuni errori sintattici che sono stati corretti, rispetto alla versione originiale (' all'interno di stringhe, e l'utilzzo della variabile continue, keyword di C).
Indice dei contenuti:
- Analisi Lessicale
- Analisi Sintattica
- Analisi Semantica e Generazione del Codice Intermedio
- Bug Noti e Scelte Progettuali Fatte
Per l'analisi lessicale si è utilizzato JFLEX, per la generazione automatica del LEXER, le specifiche necessarie sono state inserite all'interno del file MyFun.flex.
Sono stati generati i seguenti errori:
- Stringa costante non completata: nel caso in cui il programma in input presenti una stringa costante aperta ma non chiusa (es. "questa è una stringa non chiusa ).
- Commento non chiuso: nel caso in cui il programma in input presenti un commento non chiuso (es. /* questo è un commento non chiuso )
N.B.: in entrambi i casi si raggiunge l'EOF mentre si sta riconoscendo un commento o una stringa. Se si usano gli stati jflex (ad es. COMMENT e STRING), questo si traduce nell'incontrare un EOF mentre si è nel corrispondente stato.
All'interno del linguaggio i commenti iniziano con # oppure con //. Inoltre un blocco di commenti è delimitato da #* e #.
Nel linguaggio sono implementate le seguenti parole chiave:
Identificativo | Valore |
---|---|
MAIN | main |
ID | /[$_A-Za-z][$_a-za-z0-9]*/ |
INTEGER | integer |
STRING | string |
REAL | real |
BOOL | bool |
LPAR | ( |
RPAR | ) |
COLON | : |
FUN | fun |
END | end |
IF | if |
THEN | then |
ELSE | else |
WHILE | while |
LOOP | loop |
READ | % |
WRITE | ? |
WRITELN | ?. |
WRITEB | ?, |
WRITET | ?: |
ASSIGN | := |
PLUS | + |
MINUS | - |
TIMES | * |
DIVINT | div |
DIV | / |
POW | ^ |
STR_CONCAT | & |
EQ | = |
NE | <> or != |
LT | < |
LE | <= |
GT | > |
GE | >= |
AND | and |
OR | or |
NOT | not |
NULL | null |
TRUE | true |
FALSE | false |
INTEGER_CONST | (([1-9][0-9]*)|(0)) |
REAL_CONST | (([1-9][0-9]*)|(0)).(([0-9]*[1-9]+)|(0)) |
STRING_CONST | any string between " or between ' |
SEMI | ; |
COMMA | , |
RETURN | return |
OUTPAR | @ |
VAR | var |
OUT | out |
LOOP | loop |
Per l'analisi lessicale si è utilizzato il CUP, per la generaazione automatica di un PARSER di tipo Top Down, le specifiche necessarie sono state inserite all'interno del file MyFun.cup.
Sono state utilizzate le seguenti regole di precedenza dalla più alta alla più bassa. Eventuali altre ambiguità sono state risolte tramite l'uso dell'associativià sinistra (se non indicata nella tabella):
Operatore | Precendenza |
---|---|
uminus | |
( ) | |
^ | destra |
* / div / divint | |
+ - | |
& | |
= != <> < <= > >= | nessuna |
not | destra |
and | |
or |
N.B.: Sono state codificate in javacup solo quelle necessarie all'eliminazione dei conflitti.
Un programma è composta da:
Program ::= VarDeclList FunList Main
Un Main è composto da:
Main ::= MAIN VarDeclList StatList END MAIN SEMI
Una dichiarazione di una variabile è composta da:
VarDecl ::= Type IdListInit SEMI
| VAR IdListInitObbl SEMI
Una lista di dichiarazioni di variabili può essere vuota oppure composta da:
VarDeclList ::= ε
| VardDecl VarDeclList
Un tipo è defito come segue:
Type ::= INTEGER | BOOL | REAL | STRING
Una lista semplice di ID e composta da una ID oppure da:
IdList ::= ID
| IdList COMMA ID
Una lista di inizializazzioni di ID e composta da un ID oppure da:
IdListInit ::= ID
| IdListInit COMMA ID
| ID ASSIGN Expr
| IdListInit COMMA ID ASSIGN Expr
Una lista di inizializzazioni obbligatorie è definita come:
IdListInitObbl ::= ID ASSIGN Const
| IdListInitObbl COMMA ID ASSIGN Const
Una costante è definita come segue:
Const ::= INTEGER_CONST | REAL_CONST | TRUE | FALSE | STRING_CONST
Una dichiarazione di funzione è composta da:
Fun := FUN ID LPAR ParamDeclList RPAR COLON Type VarDeclList StatList END FUN SEMI
| FUN ID LPAR ParamDeclList RPAR VarDeclList StatList END FUN SEMI
Una lista di funzioni puo essere vuota o composta da:
FunList ::= ε
| Fun FunList
Una chiamata di funzione è composta da:
CallFun ::= ID LPAR ExprList RPAR
| ID LPAR RPAR
Un parametro è composto da:
ParDecl ::= Type ID
| OUT Type ID
Una lista di parametri puo essere vuota o composta da:
ParamDeclList ::= ε
| NonEmptyParamDeclList
Una lista non vuota di paramentri è composta da:
NonEmptyParamDeclList ::= ParDecl
| NonEmptyParamDeclList COMMA ParDecl
Uno statement è definito in uno dei seguenti modi:
Stat ::= IfStat SEMI
| WhileStat SEMI
| ReadStat SEMI
| WriteStat SEMI
| AssignStat SEMI
| CallFun SEMI
| RETURN Expr SEMI
Una lista di statement puo essere vuota o composta da:
StatList ::= ε
| StatList Stat
Uno statement di assegnamento è composto da:
AssignStat ::= ID ASSIGN Expr
Uno statement di lettura è composto da:
ReadStat ::= READ IdList Expr
| READ IdList
Uno statement di scrittura è definito in uno dei seguenti modi:
WriteStat ::= WRITE Expr
| WRITELN Expr
| WRITET Expr
| WRITEB Expr
Uno statement if è composto da:
IfStat ::= IF Expr THEN VarDeclList StatList Else END IF
Lo statement Else è composto da la parola vuota oppure:
Else ::= ε
| ELSE VarDeclList StatList
Lo statement while è composta da:
WhileStat ::= WHILE Expr LOOP VarDeclList StatList END LOOP
Una espressione è composta nel seguente modo:
Expr ::= TRUE
| FALSE
| INTEGER_CONST
| REAL_CONST
| STRING_CONST
| ID
| CallFun
| Expr PLUS Expr
| Expr MINUS Expr
| Expr TIMES Expr
| Expr DIV Expr
| Expr DIVINT 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
Una lista di espressioni è composta da un espressione oppure:
ExprList ::= Expr
| Expr COMMA ExprList
| OUTPAR ID
| OUTPAR ID COMMA ExprList
Per l'analisi sematica è stato utilizzato il patter VISITOR implementato nel file Semantic_Visitor.java: per l'analisi semantica;
Di seguito, le regole di type checking utilizzate all'interno del visitor per l'analisi semantica.
Costanti
ID
Operatori unari
Tabella per optype1(op, t)
op1 | operando | risultato |
---|---|---|
MINUS | integer | integer |
MINUS | real | real |
NOT | bool | bool |
Operatori binari
Tabella per optype2(op,
op1 | operando | operando2 | risultato |
---|---|---|---|
PLUS, MINUS, TIMES, DIV | integer | integer | integer |
PLUS, MINUS, TIMES, DIV | integer | real | real |
PLUS, MINUS, TIMES, DIV | real | integer | real |
PLUS, MINUS, TIMES, DIV | real | real | real |
DIVINT | integer | integer | integer |
DIVINT | real | integer | integer |
STR_CONCAT | string | string | string |
STR_CONCAT | string | integer | string |
STR_CONCAT | string | real | string |
STR_CONCAT | string | bool | string |
AND | bool | bool | bool |
OR | bool | bool | bool |
GT, GE, LT, LE | integer | integer | bool |
GT, GE, LT, LE | integer | real | bool |
GT, GE, LT, LE | real | integer | bool |
GT, GE, LT, LE | real | real | bool |
EQ, NE | integer | integer | bool |
EQ, NE | real | real | bool |
EQ, NE | integer | real | bool |
EQ, NE | real | integer | bool |
EQ, NE | string | string | bool |
EQ, NE | bool | bool | bool |
Lista di istruzioni
Assegnazione
Chiamata a funzione con o senza tipo di ritorno
Istruzione while
Istruzione if then else
Istruzione read
Istruzione write
Istruzione return
## Generazione del Codice Intermedio
Per la generazione del codice è stato utilizza il pattern VISITOR implementato nel file CodeGen_Visitor.java: per la generazione del codice intermedio (C).
-
Sono state introdotte le librerie stdio.h, stdlib.h, stdbool.h e string.h al fine di effettuare le operazioni standard di input/output, effettuare operazioni sulle stringhe (es. strcmp, strcpy) e poter gestire i tipi booleani.
-
Per la gestione della concatenazione delle stringhe e le conversione implicite richieste sono state create quattro funzioni all'interno del codice C:
char *concatInt(char *string, int toConcat)
char *concatReal(char *string, float toConcat)
char *concatBool(char *string, int toConcat)
char *concatString(char *string, char *toConcat)
Nell'implementazione del progetto, con lo scopo di rendere il codice più pulito e mantenibile possibile si è scelto di non supportare alcuni casi estremamente particolari e di difficile riproduzione.
Casi particolari non supportati noti:
- Gestione di concatenazioni di stringha al seguito della dichiarazione di una variabile globale (Sia tramite IdInitNode che IdInitObblNode).