Compilarea unui program presupune minim 4 etape importante:
- verificarea corectitudinii la nivel lexical (la nivelul cuvintelor permise de limbaj)
- verificarea corectitudinii la nivel sintactic (la nivelul propozitiilor permise in limbaj, ex: if cond then expr1 else expr2)
- verificarea corectitudinii la nivel semantic (rezolvarea referintelor catre simboluri de variabile, functii, verificarea compatibilitatii tipurilor folosite)
- generarea de cod intermediar (in acest compilator se genereaza direct cod pentru arhitectura MIPS)
cd src
make build
make compiler
make run INPUT_FILE=<program.cl> OUTPUT_FILE=<result.s>Unde program reprezinta un program cool si result.s va contine un mesaj cu erorile gasite (daca exista) sau codul in limbaj de asamblare generat.
Am folosit limbajul Java.
Pentru analiza lexicala si sintactica a fost folosit ANTLR. Specificatiile pentru Parser si Lexer pot fi gasite in fisierele CoolLexer.g4 si CoolParser.g4.
Pentru analiza semnatica fost construit un AST pornind de la rezultatul primit de la etapa de analiza sintactica. Pe acest AST s-a facut rezolvarea simbolurilor si a tipurilor in scope-urile corespunzatoare din program.
Pentru generarea de cod a fost folosit StringTemplate, care e integrat in ANTLR si permite folosirea unor sabloane parametrizate pentru generarea de text din Java. Sabloanele definite pentru diferitele constructii sunt in fisierul ast/asmgen.stg.
In pachetul cool.ast sunt definite clasele pentru AST si pentru prelucrarile facute pe acesta.
Pentru inceput, dupa ce AST-ul a fost generat si codul a fost corect dpdv lexical si sintactic, incepe analiza semantica.
-
In prima etapa, sunt definite toate tipurile intr-o prima trecere doar la nivelul claselor, apoi in a doua trecere sunt rezolvate referintele la parintii claselor. In a treia trecere la nivelul claselor se verifica ciclurile in mostenire. Daca la acest nivel apar erori, analiza se opreste aici.
-
Daca totul a fost ok in definirea tipurilor, analiza semantica continua cu o trecere peste tot AST-ul pentru analiza definitiilor de metode si atribute din fiecare clasa si din alte constructii care introduc variabile (exemplu: parametrii formali la functii, variabile let, case branch-uri). Tot in aceasta trecere fiecarui simbol ii este atasata si informatia despre scope-ul in care se afla.
-
Dupa aceasta trecere, pentru constructiile care nu au avut erori la definire, se continua analiza de tip. Tipul e rezolvat pentru fiecare simbol in scope-ul cunoscut de la trecerea anterioara, conform cu regulile din manualul limbajului COOL. Pentru rezolvarea
SELF_TYPE, exista un TypeSymbol genericSELF_TYPE, si pentru fiecare clasaCun simbol particularSELF_TYPE_Cstocat in simbolul de tip al clasei. In timpul rezolvarii tipurilor obiectele care au tipulSELF_TYPEsi sunt vizitate primesc tipul cu informatia de clasaSELF_TYPE_C.
Pentru generarea de cod am considerat o functie cgen(expr) care genereaza cod MIPS 1 la 1 pentru fiecare expresie din limbaj: fiecare expresie are un cod generat. De exemplu, daca am o expresie if conditie then expr1 else expr2, codul generat va fi asa: cgen(if) = cgen(cond) + "beqz $a0 then else; then:" + cgen(expr1) + "j endif; else:" + cgen(expr2) + "endif:".
Classroom Object Oriented Language este un limbaj creat in scop didactic, pentru care s-au scris mai multe compilatoare decat programe. COOL este un limbaj de tipul expression-language (functional), orientat obiect. Compilatorul a fost implementat respectand specificatia din manualul de COOL.
Pentru a putea rula codul generat cu un simulator de MIPS (ex: SPIM), e necesar sa fie concatenat dupa continutul fisierului trap.handler.nogc, care contine definitiile in limbaj de asamblare ale metodelor specifice tipurilor predefinite din limbajul COOL.