Organize compiler
This commit is contained in:
parent
26de7337da
commit
b9f016f82a
|
@ -4,7 +4,7 @@
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
|
|
||||||
/* compiler-expressions
|
/* compiler-expressions
|
||||||
* Subroutines for dealing and compiling expressions and singular terms. */
|
* Functions for dealing and compiling expressions and singular terms. */
|
||||||
|
|
||||||
// Dealing with singular terms
|
// Dealing with singular terms
|
||||||
LINEBLOCK* compilesubroutcall(SCOPE* s, SUBROUTCALL* call);
|
LINEBLOCK* compilesubroutcall(SCOPE* s, SUBROUTCALL* call);
|
||||||
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "compiler-expressions.h"
|
||||||
|
#include "compiler-statements.h"
|
||||||
|
#include "compiler-util.h"
|
||||||
|
|
||||||
|
/* BEGIN FORWARD DECLARATIONS */
|
||||||
|
|
||||||
|
// Miscelaneous
|
||||||
|
LINE* popthat();
|
||||||
|
LINE* pushtemp();
|
||||||
|
char* mkcondlabel(char* name, int count);
|
||||||
|
|
||||||
|
// Handling individual statements
|
||||||
|
LINEBLOCK* compileret(SCOPE* s, TERM* e);
|
||||||
|
LINEBLOCK* compileif(COMPILER* c, SCOPE* s, IFSTATEMENT* st);
|
||||||
|
LINEBLOCK* compilewhile(COMPILER* c, SCOPE* s, CONDSTATEMENT* w);
|
||||||
|
LINEBLOCK* compilelet(SCOPE* s, LETSTATEMENT* l);
|
||||||
|
LINEBLOCK* compilestatement(COMPILER* c, SCOPE* s, STATEMENT* st);
|
||||||
|
|
||||||
|
/* END FORWARD DECLARATIONS */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Miscelaneous
|
||||||
|
LINE* popthat() {
|
||||||
|
char* popthat[] = { "pop", "that", "0" };
|
||||||
|
return mkln(popthat);
|
||||||
|
}
|
||||||
|
|
||||||
|
LINE* pushtemp() {
|
||||||
|
char* pushtemp[] = { "push", "temp", "0" };
|
||||||
|
return mkln(pushtemp);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* mkcondlabel(char* name, int count) {
|
||||||
|
int sz = (strlen(name) + countplaces(count) + 1) * sizeof(char);
|
||||||
|
char* result = (char*)malloc(sz);
|
||||||
|
sprintf(result, "%s%i", name, count);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handling individual statements
|
||||||
|
LINEBLOCK* compileret(SCOPE* s, TERM* e) {
|
||||||
|
LINE* ret = onetoken("return");
|
||||||
|
LINEBLOCK* blk = mklnblk(ret);
|
||||||
|
|
||||||
|
// void subroutdecs return 0
|
||||||
|
if(e == NULL) {
|
||||||
|
char* tokens[] = { "push", "constant", "0" };
|
||||||
|
appendlnbefore(blk, mkln(tokens));
|
||||||
|
} else
|
||||||
|
blk = mergelnblks(compileexpression(s, e), blk);
|
||||||
|
|
||||||
|
return blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
LINEBLOCK* compileif(COMPILER* c, SCOPE* s, IFSTATEMENT* st) {
|
||||||
|
LINEBLOCK* blk = compileexpression(s, st->base->expression);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&(c->ifmutex));
|
||||||
|
static int ifcount = 0;
|
||||||
|
int mycount = ifcount;
|
||||||
|
ifcount++;
|
||||||
|
pthread_mutex_unlock(&(c->ifmutex));
|
||||||
|
|
||||||
|
char* truelabel = mkcondlabel("IF_TRUE", mycount);
|
||||||
|
char* ifgoto[] = { "if-goto", truelabel };
|
||||||
|
appendln(blk, mkln(ifgoto));
|
||||||
|
|
||||||
|
char* falselabel = mkcondlabel("IF_FALSE", mycount);
|
||||||
|
char* gotofalse[] = { "goto", falselabel };
|
||||||
|
appendln(blk, mkln(gotofalse));
|
||||||
|
|
||||||
|
char* truelabelln[] = { "label", truelabel };
|
||||||
|
appendln(blk, mkln(truelabelln));
|
||||||
|
|
||||||
|
blk = mergelnblks(blk, compilestatements(c, s, st->base->statements));
|
||||||
|
|
||||||
|
char* endlabel;
|
||||||
|
bool haselse = st->elsestatements != NULL;
|
||||||
|
if(haselse) {
|
||||||
|
endlabel = mkcondlabel("IF_END", mycount);
|
||||||
|
char* endgoto[] = { "goto", endlabel };
|
||||||
|
appendln(blk, mkln(endgoto));
|
||||||
|
}
|
||||||
|
|
||||||
|
char* falselabelln[] = { "label", falselabel};
|
||||||
|
appendln(blk, mkln(falselabelln));
|
||||||
|
|
||||||
|
if(haselse) {
|
||||||
|
blk = mergelnblks(blk, compilestatements(c, s, st->elsestatements));
|
||||||
|
char* endlabelln[] = { "label", endlabel };
|
||||||
|
appendln(blk, mkln(endlabelln));
|
||||||
|
}
|
||||||
|
|
||||||
|
return blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
LINEBLOCK* compilewhile(COMPILER* c, SCOPE* s, CONDSTATEMENT* w) {
|
||||||
|
LINEBLOCK* blk = compileexpression(s, w->expression);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&(c->whilemutex));
|
||||||
|
static int whilecount = 0;
|
||||||
|
int mycount = whilecount;
|
||||||
|
whilecount++;
|
||||||
|
pthread_mutex_unlock(&(c->whilemutex));
|
||||||
|
|
||||||
|
char* explabel = mkcondlabel("WHILE_EXP", mycount);
|
||||||
|
char* explabelln[] = { "label", explabel };
|
||||||
|
appendlnbefore(blk, mkln(explabelln));
|
||||||
|
|
||||||
|
appendln(blk, onetoken("not"));
|
||||||
|
|
||||||
|
char* endlabel = mkcondlabel("WHILE_END", mycount);
|
||||||
|
char* ifgoto[] = { "if-goto", endlabel };
|
||||||
|
appendln(blk, mkln(ifgoto));
|
||||||
|
|
||||||
|
blk = mergelnblks(blk, compilestatements(c, s, w->statements));
|
||||||
|
|
||||||
|
char* gotoln[] = { "goto", explabel };
|
||||||
|
appendln(blk, mkln(gotoln));
|
||||||
|
|
||||||
|
char* endlabelln[] = { "label", endlabel };
|
||||||
|
appendln(blk, mkln(endlabelln));
|
||||||
|
|
||||||
|
return blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
LINEBLOCK* compilelet(SCOPE* s, LETSTATEMENT* l) {
|
||||||
|
LINEBLOCK* blk = compileexpression(s, l->expression);
|
||||||
|
|
||||||
|
if(l->arrayind != NULL) {
|
||||||
|
appendlnbefore(blk, onetoken("add"));
|
||||||
|
appendlnbefore(blk, pushvar(s, l->varname));
|
||||||
|
blk = mergelnblks(compileexpression(s, l->arrayind), blk);
|
||||||
|
|
||||||
|
appendln(blk, poptemp());
|
||||||
|
appendln(blk, popthatadd());
|
||||||
|
appendln(blk, pushtemp());
|
||||||
|
appendln(blk, popthat());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
appendln(blk, popvar(s, l->varname));
|
||||||
|
return blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
LINEBLOCK* compilestatement(COMPILER* c, SCOPE* s, STATEMENT* st) {
|
||||||
|
s->currdebug = st->debug;
|
||||||
|
if(st->type == dostatement) return compilesubroutcall(s, st->dostatement);
|
||||||
|
if(st->type == returnstatement) return compileret(s, st->retstatement);
|
||||||
|
if(st->type == ifstatement) return compileif(c, s, st->ifstatement);
|
||||||
|
if(st->type == whilestatement) return compilewhile(c, s, st->whilestatement);
|
||||||
|
if(st->type == letstatement) return compilelet(s, st->letstatement);
|
||||||
|
eprintf("UNSUPPORTED type %i\n", st->type);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
LINEBLOCK* compilestatements(COMPILER* c, SCOPE* s, STATEMENT* sts) {
|
||||||
|
LINEBLOCK* head = NULL;
|
||||||
|
while(sts != NULL) {
|
||||||
|
head = mergelnblks(head, compilestatement(c, s, sts));
|
||||||
|
sts = sts->next;
|
||||||
|
}
|
||||||
|
return head;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef COMPILER_STATEMENTS_H
|
||||||
|
#define COMPILER_STATEMENTS_H
|
||||||
|
#include "compiler.h"
|
||||||
|
|
||||||
|
/* compiler-statements
|
||||||
|
* Single function for compiling statements */
|
||||||
|
|
||||||
|
LINEBLOCK* compilestatements(COMPILER* c, SCOPE* s, STATEMENT* sts);
|
||||||
|
#endif
|
|
@ -0,0 +1,130 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "compiler-statements.h"
|
||||||
|
#include "compiler-structure.h"
|
||||||
|
#include "compiler-util.h"
|
||||||
|
|
||||||
|
/* BEGIN FORWARD DECLARATIONS */
|
||||||
|
|
||||||
|
// Miscelaneous
|
||||||
|
int countlocalvars(VARDEC* decs);
|
||||||
|
int countstrs(STRINGLIST* ls);
|
||||||
|
int getobjsize(CLASS* c);
|
||||||
|
LINE* mksubdeclabel(CLASS* c, SUBROUTDEC* sd);
|
||||||
|
|
||||||
|
// Compiling methods
|
||||||
|
LINEBLOCK* compilefunbody(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTBODY* b);
|
||||||
|
LINEBLOCK* compilefundec(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* f);
|
||||||
|
LINEBLOCK* compileconstructor(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* con);
|
||||||
|
LINEBLOCK* compilemethod(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* m);
|
||||||
|
|
||||||
|
/* END FORWARD DECLARATIONS */
|
||||||
|
|
||||||
|
|
||||||
|
// Miscelaneous
|
||||||
|
int countlocalvars(VARDEC* decs) {
|
||||||
|
int i = 0;
|
||||||
|
while(decs != NULL) {
|
||||||
|
STRINGLIST* curr = decs->names;
|
||||||
|
while(curr != NULL) {
|
||||||
|
i++;
|
||||||
|
curr = curr->next;
|
||||||
|
}
|
||||||
|
decs = decs->next;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int countstrs(STRINGLIST* ls) {
|
||||||
|
int count = 0;
|
||||||
|
while(ls != NULL) {
|
||||||
|
count++;
|
||||||
|
ls = ls->next;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getobjsize(CLASS* c) {
|
||||||
|
CLASSVARDEC* curr = c->vardecs;
|
||||||
|
int count = 0;
|
||||||
|
while(curr != NULL) {
|
||||||
|
if(curr->type == field)
|
||||||
|
count += countstrs(curr->base->names);
|
||||||
|
curr = curr->next;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
LINE* mksubdeclabel(CLASS* c, SUBROUTDEC* sd) {
|
||||||
|
char* labelstrs[] = { "function", dotlabel(c->name, sd->name), itoa(countlocalvars(sd->body->vardecs)) };
|
||||||
|
LINE* label = mkln(labelstrs);
|
||||||
|
free(labelstrs[1]);
|
||||||
|
free(labelstrs[2]);
|
||||||
|
label->next = NULL;
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compiling methods
|
||||||
|
LINEBLOCK* compilefunbody(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTBODY* b) {
|
||||||
|
SCOPE* myscope = mkscope(s);
|
||||||
|
myscope->currclass = cl;
|
||||||
|
if(b->vardecs != NULL)
|
||||||
|
addlocalvars(s, b->vardecs);
|
||||||
|
LINEBLOCK* head = compilestatements(c, myscope, b->statements);
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
|
||||||
|
LINEBLOCK* compilefundec(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* f) {
|
||||||
|
LINE* label = mksubdeclabel(cl, f);
|
||||||
|
|
||||||
|
if(f->body->statements != NULL) {
|
||||||
|
LINEBLOCK* body = compilefunbody(c, s, cl, f->body);
|
||||||
|
appendlnbefore(body, label);
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return mklnblk(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
LINEBLOCK* compileconstructor(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* con) {
|
||||||
|
LINE* label = mksubdeclabel(cl, con);
|
||||||
|
LINEBLOCK* blk = mklnblk(label);
|
||||||
|
|
||||||
|
char* size[] = { "push", "constant", itoa(getobjsize(cl)) };
|
||||||
|
char* memalloc[] = { "call", "Memory.alloc", "1" };
|
||||||
|
char* poppointer[] = { "pop", "pointer", "0" };
|
||||||
|
appendln(blk, mkln(size));
|
||||||
|
appendln(blk, mkln(memalloc));
|
||||||
|
appendln(blk, mkln(poppointer));
|
||||||
|
free(size[2]);
|
||||||
|
|
||||||
|
if(con->body != NULL)
|
||||||
|
return mergelnblks(blk, compilefunbody(c, s, cl, con->body));
|
||||||
|
else
|
||||||
|
return blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
LINEBLOCK* compilemethod(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* m) {
|
||||||
|
LINE* label = mksubdeclabel(cl, m);
|
||||||
|
LINEBLOCK* blk = mklnblk(label);
|
||||||
|
|
||||||
|
char* pusharg0[] = { "push", "argument", "0" };
|
||||||
|
char* poppointer[] = { "pop", "pointer", "0" };
|
||||||
|
appendln(blk, mkln(pusharg0));
|
||||||
|
appendln(blk, mkln(poppointer));
|
||||||
|
|
||||||
|
if(m->body != NULL)
|
||||||
|
return mergelnblks(blk, compilefunbody(c, s, cl, m->body));
|
||||||
|
else
|
||||||
|
return blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
LINEBLOCK* compilesubroutdec(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* sd) {
|
||||||
|
SCOPE* myscope = mkscope(s);
|
||||||
|
if(sd->parameters != NULL)
|
||||||
|
addparameters(myscope, sd->subroutclass == method, sd->parameters);
|
||||||
|
if(sd->subroutclass == function)
|
||||||
|
return compilefundec(c, myscope, cl, sd);
|
||||||
|
if(sd->subroutclass == constructor)
|
||||||
|
return compileconstructor(c, myscope, cl, sd);
|
||||||
|
return compilemethod(c, myscope, cl, sd);
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef COMPILER_STRUCTURE_H
|
||||||
|
#define COMPILER_STRUCTURE_H
|
||||||
|
#include "compiler.h"
|
||||||
|
|
||||||
|
/* compiler-structure
|
||||||
|
* Module for dealing with and compiling general program structure. */
|
||||||
|
|
||||||
|
LINEBLOCK* compilesubroutdec(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* sd);
|
||||||
|
#endif
|
|
@ -4,6 +4,9 @@
|
||||||
#include "compiler-scopes.h"
|
#include "compiler-scopes.h"
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
|
|
||||||
|
/* compiler-util
|
||||||
|
* Random utilities for the compiler. */
|
||||||
|
|
||||||
#define mkln(id) mksimpleln(id, strcount(id))
|
#define mkln(id) mksimpleln(id, strcount(id))
|
||||||
|
|
||||||
LINE* onetoken(char* str);
|
LINE* onetoken(char* str);
|
||||||
|
|
|
@ -1,280 +1,9 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include "compiler-structure.h"
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
#include "compiler-util.h"
|
|
||||||
#include "compiler-expressions.h"
|
|
||||||
|
|
||||||
LINEBLOCK* compilestatements(COMPILER* c, SCOPE* s, STATEMENT* sts);
|
|
||||||
LINEBLOCK* compileexpression(SCOPE* s, TERM* e);
|
|
||||||
|
|
||||||
int countparameters(PARAMETER* params) {
|
|
||||||
int i = 0;
|
|
||||||
while(params != NULL) {
|
|
||||||
i++;
|
|
||||||
params = params->next;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
int countlocalvars(VARDEC* decs) {
|
|
||||||
int i = 0;
|
|
||||||
while(decs != NULL) {
|
|
||||||
STRINGLIST* curr = decs->names;
|
|
||||||
while(curr != NULL) {
|
|
||||||
i++;
|
|
||||||
curr = curr->next;
|
|
||||||
}
|
|
||||||
decs = decs->next;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* mkcondlabel(char* name, int count) {
|
|
||||||
int sz = (strlen(name) + countplaces(count) + 1) * sizeof(char);
|
|
||||||
char* result = (char*)malloc(sz);
|
|
||||||
sprintf(result, "%s%i", name, count);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
LINE* pushthatadd() {
|
|
||||||
char* pushthatadd[] = { "push", "pointer", "1" };
|
|
||||||
return mkln(pushthatadd);
|
|
||||||
}
|
|
||||||
|
|
||||||
LINE* popthat() {
|
|
||||||
char* popthat[] = { "pop", "that", "0" };
|
|
||||||
return mkln(popthat);
|
|
||||||
}
|
|
||||||
|
|
||||||
LINE* pushtemp() {
|
|
||||||
char* pushtemp[] = { "push", "temp", "0" };
|
|
||||||
return mkln(pushtemp);
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* compileret(SCOPE* s, TERM* e) {
|
|
||||||
LINE* ret = onetoken("return");
|
|
||||||
LINEBLOCK* blk = mklnblk(ret);
|
|
||||||
|
|
||||||
// void subroutdecs return 0
|
|
||||||
if(e == NULL) {
|
|
||||||
char* tokens[] = { "push", "constant", "0" };
|
|
||||||
appendlnbefore(blk, mkln(tokens));
|
|
||||||
} else
|
|
||||||
blk = mergelnblks(compileexpression(s, e), blk);
|
|
||||||
|
|
||||||
return blk;
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* compileif(COMPILER* c, SCOPE* s, IFSTATEMENT* st) {
|
|
||||||
LINEBLOCK* blk = compileexpression(s, st->base->expression);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&(c->ifmutex));
|
|
||||||
static int ifcount = 0;
|
|
||||||
int mycount = ifcount;
|
|
||||||
ifcount++;
|
|
||||||
pthread_mutex_unlock(&(c->ifmutex));
|
|
||||||
|
|
||||||
char* truelabel = mkcondlabel("IF_TRUE", mycount);
|
|
||||||
char* ifgoto[] = { "if-goto", truelabel };
|
|
||||||
appendln(blk, mkln(ifgoto));
|
|
||||||
|
|
||||||
char* falselabel = mkcondlabel("IF_FALSE", mycount);
|
|
||||||
char* gotofalse[] = { "goto", falselabel };
|
|
||||||
appendln(blk, mkln(gotofalse));
|
|
||||||
|
|
||||||
char* truelabelln[] = { "label", truelabel };
|
|
||||||
appendln(blk, mkln(truelabelln));
|
|
||||||
|
|
||||||
blk = mergelnblks(blk, compilestatements(c, s, st->base->statements));
|
|
||||||
|
|
||||||
char* endlabel;
|
|
||||||
bool haselse = st->elsestatements != NULL;
|
|
||||||
if(haselse) {
|
|
||||||
endlabel = mkcondlabel("IF_END", mycount);
|
|
||||||
char* endgoto[] = { "goto", endlabel };
|
|
||||||
appendln(blk, mkln(endgoto));
|
|
||||||
}
|
|
||||||
|
|
||||||
char* falselabelln[] = { "label", falselabel};
|
|
||||||
appendln(blk, mkln(falselabelln));
|
|
||||||
|
|
||||||
if(haselse) {
|
|
||||||
blk = mergelnblks(blk, compilestatements(c, s, st->elsestatements));
|
|
||||||
char* endlabelln[] = { "label", endlabel };
|
|
||||||
appendln(blk, mkln(endlabelln));
|
|
||||||
}
|
|
||||||
|
|
||||||
return blk;
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* compilewhile(COMPILER* c, SCOPE* s, CONDSTATEMENT* w) {
|
|
||||||
LINEBLOCK* blk = compileexpression(s, w->expression);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&(c->whilemutex));
|
|
||||||
static int whilecount = 0;
|
|
||||||
int mycount = whilecount;
|
|
||||||
whilecount++;
|
|
||||||
pthread_mutex_unlock(&(c->whilemutex));
|
|
||||||
|
|
||||||
char* explabel = mkcondlabel("WHILE_EXP", mycount);
|
|
||||||
char* explabelln[] = { "label", explabel };
|
|
||||||
appendlnbefore(blk, mkln(explabelln));
|
|
||||||
|
|
||||||
appendln(blk, onetoken("not"));
|
|
||||||
|
|
||||||
char* endlabel = mkcondlabel("WHILE_END", mycount);
|
|
||||||
char* ifgoto[] = { "if-goto", endlabel };
|
|
||||||
appendln(blk, mkln(ifgoto));
|
|
||||||
|
|
||||||
blk = mergelnblks(blk, compilestatements(c, s, w->statements));
|
|
||||||
|
|
||||||
char* gotoln[] = { "goto", explabel };
|
|
||||||
appendln(blk, mkln(gotoln));
|
|
||||||
|
|
||||||
char* endlabelln[] = { "label", endlabel };
|
|
||||||
appendln(blk, mkln(endlabelln));
|
|
||||||
|
|
||||||
return blk;
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* compilelet(SCOPE* s, LETSTATEMENT* l) {
|
|
||||||
LINEBLOCK* blk = compileexpression(s, l->expression);
|
|
||||||
|
|
||||||
if(l->arrayind != NULL) {
|
|
||||||
appendlnbefore(blk, onetoken("add"));
|
|
||||||
appendlnbefore(blk, pushvar(s, l->varname));
|
|
||||||
blk = mergelnblks(compileexpression(s, l->arrayind), blk);
|
|
||||||
|
|
||||||
appendln(blk, poptemp());
|
|
||||||
appendln(blk, popthatadd());
|
|
||||||
appendln(blk, pushtemp());
|
|
||||||
appendln(blk, popthat());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
appendln(blk, popvar(s, l->varname));
|
|
||||||
return blk;
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* compilestatement(COMPILER* c, SCOPE* s, STATEMENT* st) {
|
|
||||||
s->currdebug = st->debug;
|
|
||||||
if(st->type == dostatement) return compilesubroutcall(s, st->dostatement);
|
|
||||||
if(st->type == returnstatement) return compileret(s, st->retstatement);
|
|
||||||
if(st->type == ifstatement) return compileif(c, s, st->ifstatement);
|
|
||||||
if(st->type == whilestatement) return compilewhile(c, s, st->whilestatement);
|
|
||||||
if(st->type == letstatement) return compilelet(s, st->letstatement);
|
|
||||||
eprintf("UNSUPPORTED type %i\n", st->type);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* compilestatements(COMPILER* c, SCOPE* s, STATEMENT* sts) {
|
|
||||||
LINEBLOCK* head = NULL;
|
|
||||||
while(sts != NULL) {
|
|
||||||
head = mergelnblks(head, compilestatement(c, s, sts));
|
|
||||||
sts = sts->next;
|
|
||||||
}
|
|
||||||
return head;
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* compilefunbody(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTBODY* b) {
|
|
||||||
SCOPE* myscope = mkscope(s);
|
|
||||||
myscope->currclass = cl;
|
|
||||||
if(b->vardecs != NULL)
|
|
||||||
addlocalvars(s, b->vardecs);
|
|
||||||
LINEBLOCK* head = compilestatements(c, myscope, b->statements);
|
|
||||||
return head;
|
|
||||||
}
|
|
||||||
|
|
||||||
LINE* mksubdeclabel(CLASS* c, SUBROUTDEC* sd) {
|
|
||||||
char* labelstrs[] = { "function", dotlabel(c->name, sd->name), itoa(countlocalvars(sd->body->vardecs)) };
|
|
||||||
LINE* label = mkln(labelstrs);
|
|
||||||
free(labelstrs[1]);
|
|
||||||
free(labelstrs[2]);
|
|
||||||
label->next = NULL;
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* compilefundec(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* f) {
|
|
||||||
LINE* label = mksubdeclabel(cl, f);
|
|
||||||
|
|
||||||
if(f->body->statements != NULL) {
|
|
||||||
LINEBLOCK* body = compilefunbody(c, s, cl, f->body);
|
|
||||||
appendlnbefore(body, label);
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return mklnblk(label);
|
|
||||||
}
|
|
||||||
|
|
||||||
int countstrs(STRINGLIST* ls) {
|
|
||||||
int count = 0;
|
|
||||||
while(ls != NULL) {
|
|
||||||
count++;
|
|
||||||
ls = ls->next;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getobjsize(CLASS* c) {
|
|
||||||
CLASSVARDEC* curr = c->vardecs;
|
|
||||||
int count = 0;
|
|
||||||
while(curr != NULL) {
|
|
||||||
if(curr->type == field)
|
|
||||||
count += countstrs(curr->base->names);
|
|
||||||
curr = curr->next;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* compileconstructor(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* con) {
|
|
||||||
LINE* label = mksubdeclabel(cl, con);
|
|
||||||
LINEBLOCK* blk = mklnblk(label);
|
|
||||||
|
|
||||||
char* size[] = { "push", "constant", itoa(getobjsize(cl)) };
|
|
||||||
char* memalloc[] = { "call", "Memory.alloc", "1" };
|
|
||||||
char* poppointer[] = { "pop", "pointer", "0" };
|
|
||||||
appendln(blk, mkln(size));
|
|
||||||
appendln(blk, mkln(memalloc));
|
|
||||||
appendln(blk, mkln(poppointer));
|
|
||||||
free(size[2]);
|
|
||||||
|
|
||||||
if(con->body != NULL)
|
|
||||||
return mergelnblks(blk, compilefunbody(c, s, cl, con->body));
|
|
||||||
else
|
|
||||||
return blk;
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* compilemethod(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* m) {
|
|
||||||
LINE* label = mksubdeclabel(cl, m);
|
|
||||||
LINEBLOCK* blk = mklnblk(label);
|
|
||||||
|
|
||||||
char* pusharg0[] = { "push", "argument", "0" };
|
|
||||||
char* poppointer[] = { "pop", "pointer", "0" };
|
|
||||||
appendln(blk, mkln(pusharg0));
|
|
||||||
appendln(blk, mkln(poppointer));
|
|
||||||
|
|
||||||
if(m->body != NULL)
|
|
||||||
return mergelnblks(blk, compilefunbody(c, s, cl, m->body));
|
|
||||||
else
|
|
||||||
return blk;
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* compilesubroutdec(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* sd) {
|
|
||||||
// 'this' and arguments are pushed by caller
|
|
||||||
// Must have a 'return' at the end
|
|
||||||
// Label names must have class name too (see mapping)
|
|
||||||
|
|
||||||
// types: method, function, constructor
|
|
||||||
// must switch all of these
|
|
||||||
SCOPE* myscope = mkscope(s);
|
|
||||||
if(sd->parameters != NULL)
|
|
||||||
addparameters(myscope, sd->subroutclass == method, sd->parameters);
|
|
||||||
if(sd->subroutclass == function)
|
|
||||||
return compilefundec(c, myscope, cl, sd);
|
|
||||||
if(sd->subroutclass == constructor)
|
|
||||||
return compileconstructor(c, myscope, cl, sd);
|
|
||||||
return compilemethod(c, myscope, cl, sd);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* This should be part of compiler-structure, but since it is used by other modules,
|
||||||
|
* it will stay here for convenience */
|
||||||
LINEBLOCK* compileclass(COMPILER* c, CLASS* class) {
|
LINEBLOCK* compileclass(COMPILER* c, CLASS* class) {
|
||||||
SCOPE* topscope = mkscope(c->globalscope);
|
SCOPE* topscope = mkscope(c->globalscope);
|
||||||
if(class->vardecs != NULL)
|
if(class->vardecs != NULL)
|
||||||
|
|
|
@ -5,8 +5,11 @@
|
||||||
#include "vm-lines.h"
|
#include "vm-lines.h"
|
||||||
#include "compiler-scopes.h"
|
#include "compiler-scopes.h"
|
||||||
|
|
||||||
struct scope;
|
/* compiler
|
||||||
|
* This is the file that should be included in other modules
|
||||||
|
* that want to compile a class/program. */
|
||||||
|
|
||||||
|
struct scope;
|
||||||
typedef struct compiler {
|
typedef struct compiler {
|
||||||
pthread_mutex_t ifmutex;
|
pthread_mutex_t ifmutex;
|
||||||
pthread_mutex_t whilemutex;
|
pthread_mutex_t whilemutex;
|
||||||
|
|
Loading…
Reference in New Issue