diff --git a/Makefile b/Makefile index e0228a5..eca13d0 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -FILES = tokenizer.c main.c parser.c printer.c compiler.c util.c +FILES = *.c INCLUDES = -I. CFLAGS = -std=c99 -g OUTFILE = compiler diff --git a/compiler-scopes.c b/compiler-scopes.c new file mode 100644 index 0000000..ff0fc07 --- /dev/null +++ b/compiler-scopes.c @@ -0,0 +1,326 @@ +#include +#include +#include +#include "compiler-scopes.h" + +// INTERNAL FUNCTIONS +// Information gathering +bool existstr(STRINGLIST* strs, char* str); +bool existclass(CLASS* c, char* name); +DEBUGINFO* getdebuginfo(OBJ* obj); + +// Error messages +void doubledeclaration(char* name, DEBUGINFO* debug, OBJ* other); +void ensurenoduplicate(SCOPE* s, char* name, DEBUGINFO* debug); + +// Scope handling +void popscope(SCOPE** s); // may be removed + +// Single type getters +VARDEC* getvardec(SCOPE* s, char* name); +CLASSVARDEC* getclassvardec(SCOPE* s, char* name); + +// Generic getters +OBJ* getbynamelist(SCOPE* s, STRINGLIST* names, char** retname); + +// Scope adding +void addclassvardec(SCOPE* s, CLASSVARDEC* v); +void addvardec(SCOPE* s, VARDEC* v); +void addsubdec(SCOPE* s, SUBDEC* sd); +void addclass(SCOPE* s, CLASS* c); + +// DEFINITIONS +// Information gathering +bool existstr(STRINGLIST* strs, char* str) { + while(strs != NULL) { + if(!strcmp(strs->content, str)) + return true; + strs = strs->next; + } + return false; +} + +bool existclass(CLASS* c, char* name) { + while(c != NULL) { + if(!strcmp(c->name, name)) + return true; + c = c->next; + } + return false; +} + +// OBJ handling + +DEBUGINFO* getdebugclassvardec(OBJ* obj) { + return obj->classvardec->base->debug; +} + +DEBUGINFO* getdebugvardec(OBJ* obj) { + return obj->vardec->debug; +} + +DEBUGINFO* getdebugsubdec(OBJ* obj) { + return obj->subdec->debug; +} + +DEBUGINFO* getdebugclass(OBJ* obj) { + return obj->class->debug; +} + +VARDEC* tovardec(OBJ* obj) { + if (obj->type == classvardec) + return obj->classvardec->base; + else if (obj->type == vardec) + return obj->vardec; + return NULL; +} + +// Error messages + +void doubledeclaration(char* name, DEBUGINFO* debug, OBJ* other) { + DEBUGINFO* debugother = other->getdebug(other); + fprintf(stderr, "Double declaration of '%s' at '%s', line %i; previously defined at '%s', line %i\n", + name, debug->file, debug->definedat, debugother->file, debugother->definedat); + exit(1); +} + +void notdeclared(char* name, DEBUGINFO* debug) { + fprintf(stderr, "'%s' not declared; file '%s', line %i\n", name, debug->file, debug->definedat); + exit(1); +} + +void invalidparent(SUBROUTCALL* call) { + fprintf(stderr, "Invalid subroutine parent '%s'; file '%s', line %i\n", call->parentname, call->debug->file, call->debug->definedat); + exit(1); +} + +void ensurenoduplicate(SCOPE* s, char* name, DEBUGINFO* debug) { + OBJ* other = getbyname(s, name); + if(other != NULL) + doubledeclaration(name, debug, other); +} + +void ensurenoduplicates(SCOPE* s, STRINGLIST* names, DEBUGINFO* debug) { + char* othername; + OBJ* other = getbynamelist(s, names, &othername); + if(other != NULL) + doubledeclaration(othername, debug, other); +} + +// Scope handling + +SCOPE* mkscope(SCOPE* prev) { + SCOPE* s = (SCOPE*)malloc(sizeof(SCOPE)); + s->subroutines = NULL; + s->classvardecs = NULL; + s->vardecs = NULL; + s->classes = NULL; + s->previous = prev; + return s; +} + +void popscope(SCOPE** s) { // might be useless + SCOPE* prev = (*s)->previous; + free(*s); + (*s) = prev; +} + +// Single type getters +VARDEC* getvardec(SCOPE* s, char* name) { + VARDEC* curr = s->vardecs; + while(curr != NULL) { + if(existstr(curr->names, name)) + return curr; + curr = curr->next; + } + if(s->previous != NULL) + return getvardec(s->previous, name); + return NULL; +} + +CLASSVARDEC* getclassvardec(SCOPE* s, char* name) { + CLASSVARDEC* curr = s->classvardecs; + while(curr != NULL) { + if(existstr(curr->base->names, name)) + return curr; + curr = curr->next; + } + if(s->previous != NULL) + return getclassvardec(s->previous, name); + return NULL; +} + +SUBDEC* getsubdec(SCOPE* s, char* name) { + SUBDEC* curr = s->subroutines; + while(curr != NULL) { + if(!strcmp(curr->name, name)) + return curr; + curr = curr->next; + } + if(s->previous != NULL) + return getsubdec(s->previous, name); + return NULL; +} + +CLASS* getclass(SCOPE* s, char* name) { + CLASS* curr = s->classes; + while(curr != NULL) { + if(!strcmp(curr->name, name)) + return curr; + curr = curr->next; + } + if(s->previous != NULL) + return getclass(s->previous, name); + return NULL; +} + +SUBDEC* getsubdecfromclass(CLASS* c, char* name) { + SUBDEC* curr = c->subdecs; + while(curr != NULL) { + if(!strcmp(curr->name, name)) + return curr; + curr = curr->next; + } + return NULL; +} + +SUBDEC* getsubdecfromvar(SCOPE* s, OBJ* var, SUBROUTCALL* call) { + VARDEC* vd = tovardec(var); + if(vd == NULL || vd->primitive) + invalidparent(call); + CLASS* c = getclass(s, vd->type); + return getsubdecfromclass(c, call->name); +} + +SUBDEC* getsubdecfromparent(SCOPE* s, SUBROUTCALL* call) { + SUBDEC* sd; + + OBJ* parent = getbyname(s, call->parentname); + if(parent == NULL) + notdeclared(call->parentname, call->debug); + + if(parent->type == class) + sd = getsubdecfromclass(parent->class, call->name); + else + sd = getsubdecfromvar(s, parent, call); + return sd; +} + +SUBDEC* getsubdecfromcall(SCOPE* s, SUBROUTCALL* call) { + SUBDEC* sd; + if(call->parentname != NULL) + sd = getsubdecfromparent(s, call); + else + sd = getsubdec(s, call->name); + if(sd == NULL) + notdeclared(call->name, call->debug); + return sd; +} + +// Generic getters +OBJ* getbyname(SCOPE* s, char* name) { + OBJ* o = (OBJ*)malloc(sizeof(OBJ)); + + CLASSVARDEC* cvd = getclassvardec(s, name); + if(cvd != NULL) { + o->classvardec = cvd; + o->type = classvardec; + o->getdebug = getdebugvardec; + return o; + } + + VARDEC* vd = getvardec(s, name); + if(vd != NULL) { + o->vardec = vd; + o->type = vardec; + o->getdebug = getdebugsubdec; + return o; + } + + SUBDEC* sd = getsubdec(s, name); + if(sd != NULL) { + o->subdec = sd; + o->type = subdec; + o->getdebug = getdebugclassvardec; + return o; + } + + CLASS* c = getclass(s, name); + if(c != NULL) { + o->class = c; + o->type = class; + o->getdebug = getdebugclass; + return o; + } + + free(o); + return NULL; +} + +OBJ* getbynamelist(SCOPE* s, STRINGLIST* names, char** retname) { + while(names != NULL) { + OBJ* o = getbyname(s, names->content); + if(o != NULL) { + *retname = names->content; + return o; + } + names = names->next; + } + if(s->previous != NULL) + return getbynamelist(s->previous, names, retname); + return NULL; +} + +// Scope adding +void addclassvardec(SCOPE* s, CLASSVARDEC* v) { + ensurenoduplicates(s, v->base->names, v->base->debug); + v->next = s->classvardecs; + s->classvardecs = v; +} + +void addvardec(SCOPE* s, VARDEC* v) { + ensurenoduplicates(s, v->names, v->debug); + v->next = s->vardecs; + s->vardecs = v; +} + +void addsubdec(SCOPE* s, SUBDEC* sd) { + ensurenoduplicate(s, sd->name, sd->debug); + sd->next = s->subroutines; + s->subroutines = sd; +} + +void addclass(SCOPE* s, CLASS* c) { + ensurenoduplicate(s, c->name, c->debug); + c->next = s->classes; + s->classes = c; +} + +// Group adding +void addclassvardecs(SCOPE* s, CLASSVARDEC* vs) { + while(vs != NULL) { + addclassvardec(s, vs); + vs = vs->next; + } +} + +void addvardecs(SCOPE* s, VARDEC* vs) { + while(vs != NULL) { + addvardec(s, vs); + vs = vs->next; + } +} + +void addsubdecs(SCOPE* s, SUBDEC* ss) { + while(ss != NULL) { + addsubdec(s, ss); + ss = ss->next; + } +} + +void addclasses(SCOPE* s, CLASS* c) { + while(c != NULL) { + addclass(s, c); + c = c->next; + } +} diff --git a/compiler-scopes.h b/compiler-scopes.h new file mode 100644 index 0000000..e8c7f28 --- /dev/null +++ b/compiler-scopes.h @@ -0,0 +1,51 @@ +#ifndef COMPILER_SCOPES_H +#define COMPILER_SCOPES_H +#include "parser.h" + +/* compiler-scopes + * Tools for dealing with scopes. + * + * They can be used to create, expand and stack scopes, as well as to enforce + * certain semantic rules. */ + +// Data types +typedef struct scope { + SUBDEC* subroutines; + CLASSVARDEC* classvardecs; + VARDEC* vardecs; + CLASS* classes; + struct scope* previous; +} SCOPE; + +typedef enum { + subdec, classvardec, vardec, class +} OBJTYPE; + +typedef struct object { + OBJTYPE type; + union { + SUBDEC* subdec; + CLASSVARDEC* classvardec; + VARDEC* vardec; + CLASS* class; + }; + DEBUGINFO* (*getdebug)(struct object*); +} OBJ; + +// Group adding +void addclassvardecs(SCOPE* s, CLASSVARDEC* vs); +void addvardecs(SCOPE* s, VARDEC* vs); +void addsubdecs(SCOPE* s, SUBDEC* ss); +void addclasses(SCOPE* s, CLASS* c); + +// Scope handling +SCOPE* mkscope(SCOPE* prev); + +// Single type getters +SUBDEC* getsubdec(SCOPE* s, char* name); +SUBDEC* getsubdecfromcall(SCOPE* s, SUBROUTCALL* call); +CLASS* getclass(SCOPE* s, char* name); + +// Generic getters +OBJ* getbyname(SCOPE* s, char* name); +#endif diff --git a/compiler.c b/compiler.c index 6739752..72b6d3e 100644 --- a/compiler.c +++ b/compiler.c @@ -1,254 +1,7 @@ #include -#include -#include #include #include "compiler.h" -typedef enum { - subdec, classvardec, vardec, cl -} OBJTYPE; - -void addtoken(LINE* l, char* token) { - l->tokens[l->tokenscount] = token; - l->tokenscount++; -} - -bool existclass(CLASS* c, char* name) { - CLASS* current = c; - while(current != NULL) { - if(!strcmp(current->name, name)) - return true; - current = current->next; - } - return false; -} - -void doubledeclarationmsg(char* name, char* f1, int l1, char* f2, int l2) { - fprintf(stderr, "Double declaration of '%s' at '%s', line %i; previously defined at '%s', line %i\n", name, f1, l1, f2, l2); - exit(1); -} - -void xtractinfo(void* obj, OBJTYPE type, char** file, int* line) { - if(type == classvardec) { - *file = ((CLASSVARDEC*)obj)->base->file; - *line = ((CLASSVARDEC*)obj)->base->definedat; - } - else if(type == vardec) { - *file = ((VARDEC*)obj)->file; - *line = ((VARDEC*)obj)->definedat; - } - else if(type == subdec) { - *file = ((SUBDEC*)obj)->file; - *line = ((SUBDEC*)obj)->definedat; - } - else if(type == cl) { - *file = ((CLASS*)obj)->file; - *line = ((CLASS*)obj)->definedat; - } -} - -void doubledeclaration(char* name, void* o1, OBJTYPE t1, void* o2, OBJTYPE t2) { - char* f1; - char* f2; - int l1, l2; - xtractinfo(o1, t1, &f1, &l1); - xtractinfo(o2, t2, &f2, &l2); - doubledeclarationmsg(name, f1, l1, f2, l2); -} - -SCOPE* mkscope(SCOPE* prev) { - SCOPE* s = (SCOPE*)malloc(sizeof(SCOPE)); - s->subroutines = NULL; - s->classvardecs = NULL; - s->vardecs = NULL; - s->classes = NULL; - s->previous = prev; - return s; -} - -void popscope(SCOPE** s) { - SCOPE* prev = (*s)->previous; - free(*s); - (*s) = prev; -} - -bool existstr(STRINGLIST* strs, char* str) { - STRINGLIST* current = strs; - while(current != NULL) { - if(!strcmp(current->content, str)) - return true; - current = current->next; - } - return false; -} - -VARDEC* getvardec(SCOPE* s, char* name) { - VARDEC* current = s->vardecs; - while(current != NULL) { - if(existstr(current->names, name)) - return current; - current = current->next; - } - if(s->previous != NULL) - return getvardec(s->previous, name); - return NULL; -} - -CLASSVARDEC* getclassvardec(SCOPE* s, char* name) { - CLASSVARDEC* current = s->classvardecs; - while(current != NULL) { - if(existstr(current->base->names, name)) - return current; - current = current->next; - } - if(s->previous != NULL) - return getclassvardec(s->previous, name); - return NULL; -} - -SUBDEC* getsubdec(SCOPE* s, char* name) { - SUBDEC* current = s->subroutines; - while(current != NULL) { - if(!strcmp(current->name, name)) - return current; - current = current->next; - } - if(s->previous != NULL) - return getsubdec(s->previous, name); - return NULL; -} - -SUBDEC* getsubdecfromclass(CLASS* c, char* name) { - SUBDEC* current = c->subdecs; - while(current != NULL) { - if(!strcmp(current->name, name)) - return current; - current = current->next; - } - return NULL; -} - -CLASS* getclass(SCOPE* s, char* name) { - CLASS* current = s->classes; - while(current != NULL) { - if(!strcmp(current->name, name)) - return current; - current = current->next; - } - if(s->previous != NULL) - return getclass(s->previous, name); - return NULL; -} - -void* getbyname(SCOPE* s, OBJTYPE* t, char* name) { - SUBDEC* sd = getsubdec(s, name); - if(sd != NULL) { - *t = subdec; - return sd; - } - CLASSVARDEC* cvd = getclassvardec(s, name); - if(cvd != NULL) { - *t = classvardec; - return cvd; - } - VARDEC* vd = getvardec(s, name); - if(vd != NULL) { - *t = vardec; - return vd; - } - CLASS* c = getclass(s, name); - if(c != NULL) { - *t = cl; - return c; - } - return NULL; -} - -void* getbynamelist(SCOPE* s, STRINGLIST* names, OBJTYPE* t, char** name) { - STRINGLIST* current = names; - while(current != NULL) { - void* obj = getbyname(s, t, current->content); - if(obj != NULL) { - *name = current->content; - return obj; - } - current = current->next; - } - if(s->previous != NULL) - return getbynamelist(s->previous, names, t, name); - return NULL; -} - -void addclassvardec(SCOPE* s, CLASSVARDEC* v) { - OBJTYPE type; - char* name; - void* tmp = getbynamelist(s, v->base->names, &type, &name); - if(tmp != NULL) - doubledeclaration(name, v, classvardec, tmp, type); - v->next = s->classvardecs; - s->classvardecs = v; -} - -void addvardec(SCOPE* s, VARDEC* v) { - OBJTYPE type; - char* name; - void* tmp = getbynamelist(s, v->names, &type, &name); - if(tmp != NULL) - doubledeclaration(name, v, vardec, tmp, type); - v->next = s->vardecs; - s->vardecs = v; -} - -void addsubdec(SCOPE* s, SUBDEC* sd) { - OBJTYPE type; - void* tmp = getbyname(s, &type, sd->name); - if(tmp != NULL) - doubledeclaration(sd->name, sd, subdec, tmp, type); - sd->next = s->subroutines; - s->subroutines = sd; -} - -void addclass(SCOPE* s, CLASS* c) { - OBJTYPE type; - void* tmp = getbyname(s, &type, c->name); - if(tmp != NULL) - doubledeclaration(c->name, c, cl, tmp, type); - c->next = s->classes; - s->classes = c; -} - -void addclassvardecs(SCOPE* s, CLASSVARDEC* vs) { - CLASSVARDEC* current = vs; - while(current != NULL) { - addclassvardec(s, current); - current = current->next; - } -} - -void addvardecs(SCOPE* s, VARDEC* vs) { - VARDEC* current = vs; - while(current != NULL) { - addvardec(s, current); - current = current->next; - } -} - -void addsubdecs(SCOPE* s, SUBDEC* ss) { - SUBDEC* current = ss; - while(current != NULL) { - addsubdec(s, current); - current = current->next; - } -} - -void addclasses(SCOPE* s, CLASS* c) { - CLASS* current = c; - while(current != NULL) { - addclass(s, current); - current = current->next; - } -} - int countparameters(EXPRESSIONLIST* params) { int i = 0; while(params != NULL) { @@ -270,7 +23,7 @@ int countlocalvars(VARDEC* decs) { char* dotlabel(char* n1, char* n2) { int sz = (strlen(n1) + strlen(n2) + 2) * sizeof(char); char* result = (char*)malloc(sz); - snprintf(result, sz, "%s.%s", n1, n2); + sprintf(result, "%s.%s", n1, n2); return result; } @@ -278,44 +31,17 @@ char* subdecname(CLASS* c, SUBDEC* sd) { return dotlabel(c->name, sd->name); } -SUBDEC* getsubdecfromparent(SCOPE* s, SUBROUTCALL* call) { - SUBDEC* sd; - OBJTYPE type; - void* parent = getbyname(s, &type, call->parentname); - if(type == cl) - sd = getsubdecfromclass((CLASS*)parent, call->name); - else { - VARDEC* vd; - if (type == classvardec) - vd = ((CLASSVARDEC*)parent)->base; - else if (type == vardec) - vd = (VARDEC*)parent; - else { - fprintf(stderr, "Unexpected subroutine identifier; file '%s', line %i\n", call->file, call->definedat); - exit(1); - } - if(vd->primitive) { - fprintf(stderr, "Primitive type doesn't have methods; file '%s', line %i\n", call->file, call->definedat); - exit(1); - } - sd = getsubdecfromparent(s, call); - } - return sd; -} - LINE* onetoken(char* str) { LINE* ln = mkline(1); addtoken(ln, ezheapstr(str)); + ln->next = NULL; return ln; } -LINE* mksimpleln(char** tokens) { - int count = sizeof(tokens) / sizeof(char*); - +LINE* mksimpleln(char** tokens, int count) { LINE* ln = mkline(count); for(int i = 0; i < count; i++) addtoken(ln, ezheapstr(tokens[i])); - return ln; } @@ -336,115 +62,122 @@ LINE* mathopln(char op) { return onetoken("and"); if(op == '/') { char* tokens[] = { "call", "Math.divide", "2" }; - return mksimpleln(tokens); + return mksimpleln(tokens, sizeof(tokens) / sizeof(char*)); } if(op == '*') { char* tokens[] = { "call", "Math.multiply", "2" }; - return mksimpleln(tokens); + return mksimpleln(tokens, sizeof(tokens) / sizeof(char*)); } } -LINE* compileexpression(SCOPE* s, TERM* e, LINE** tail) { - LINE* nexts = NULL; - LINE* nextstail; - LINE* r; - - if(e->next != NULL) { - nexts = compileexpression(s, e->next, &nextstail); - LINE* op = mathopln(e->op); - nextstail->next = op; - nextstail = op; - op->next = NULL; - } +LINEBLOCK* compileexpression(SCOPE* s, TERM* e) { + LINEBLOCK* myblk; + LINEBLOCK* next = NULL; if(e->type == intconstant) { - r = mkline(3); - addtoken(r, ezheapstr("push")); - addtoken(r, ezheapstr("constant")); - addtoken(r, itoa(e->integer)); + LINE* ln = mkline(3); + addtoken(ln, ezheapstr("push")); + addtoken(ln, ezheapstr("constant")); + addtoken(ln, itoa(e->integer)); + ln->next = NULL; + myblk = mklnblk(ln); } else if(e->type == unaryopterm) { - r = mkline(1); - addtoken(r, ezheapstr("neg")); + myblk = compileexpression(s, e->expression); + LINE* neg = onetoken("neg"); + appendln(myblk, neg); } else if(e->type == innerexpression) { - r = compileexpression(s, e->expression, tail); // might be wrong tail + myblk = compileexpression(s, e->expression); } else { - fprintf(stderr, "Unsuported SHIT %i\n", e->type); + fprintf(stderr, "Unsupported term yet %i\n", e->type); exit(1); } - if(nexts != NULL) { - r->next = nexts; - (*tail) = nextstail; + if(e->next != NULL) { + next = compileexpression(s, e->next); + LINE* op = mathopln(e->op); + appendln(next, op); + op->next = NULL; + myblk = mergelnblks(myblk, next); } - else { - (*tail) = r; - r->next = NULL; - } - return r; + + return myblk; } -LINE* compileparameters(SCOPE* s, EXPRESSIONLIST* ps, LINE** tail) { - LINE* head; - LINE* mytail; - if(ps != NULL) - head = compileexpression(s, ps->expression, &mytail); - LINE* currln = head; - EXPRESSIONLIST* current = ps->next; - while(current != NULL) { - LINE* newln = compileexpression(s, current->expression, &mytail); - current = current->next; - currln->next = newln; - currln = newln; +LINEBLOCK* compileparameters(SCOPE* s, EXPRESSIONLIST* params) { + LINEBLOCK* head = NULL; + while(params != NULL) { + head = mergelnblks(head, compileexpression(s, params->expression)); + params = params->next; } - (*tail) = mytail; return head; } -LINE* compilesubroutcall(SCOPE* s, CLASS* c, SUBROUTCALL* call) { - /* FOR NOW THERE IS NO OS SO THIS WILL CAUSE PROBLEMS - SUBDEC* sd; +LINEBLOCK* compilecallln(CLASS* c, SUBROUTCALL* call) { + LINE* ln = mkline(3); + + addtoken(ln, ezheapstr("call")); + if(call->parentname != NULL) - sd = getsubdecfromparent(s, call); + addtoken(ln, dotlabel(call->parentname, call->name)); else - sd = getsubdec(s, call->name); - if(sd == NULL) { - fprintf(stderr, "Method '%s' does not exist; file '%', line %i\n", call->name, call->file, call->definedat); - exit(1); - } - */ + addtoken(ln, dotlabel(c->name, call->name)); - // At the moment can only call functions - LINE* tail; - LINE* head = compileparameters(s, call->parameters, &tail); + addtoken(ln, itoa(countparameters(call->parameters))); - LINE* callvm = mkline(3); - addtoken(callvm, ezheapstr("call")); - if(call->parentname != NULL) - addtoken(callvm, dotlabel(call->parentname, call->name)); - else - addtoken(callvm, dotlabel(c->name, call->name)); - - addtoken(callvm, itoa(countparameters(call->parameters))); - - tail->next = callvm; - tail = callvm; - - return head; + return mklnblk(ln); } -LINE* compileret(SCOPE* s, TERM* e) { - // missing expression handling +// temporary ignore list for OS functions +char* ignoresubdecs[] = { + "printInt", "void" +}; +int ignorecount = sizeof(ignoresubdecs) / sizeof(char*); + +LINEBLOCK* compilesubroutcall(SCOPE* s, CLASS* c, SUBROUTCALL* call) { + LINEBLOCK* block = compilecallln(c, call); + + if(call->parameters != NULL) + block = mergelnblks(compileparameters(s, call->parameters), block); + + // void functions always return 0 + // therefore must be thrown away + + // gambiarra + char* type = NULL; + for(int i = 0; i < ignorecount; i += 2) { + if(!strcmp(call->name, ignoresubdecs[i])) { + type = ignoresubdecs[i+1]; + break; + } + } + if(type == NULL) + type = getsubdecfromcall(s, call)->type; + if(!strcmp(type, "void")) { + char* tokens[] = { "pop", "temp", "0" }; + appendln(block, mksimpleln(tokens, sizeof(tokens) / sizeof(char*))); + } + + return block; +} + +LINEBLOCK* compileret(SCOPE* s, TERM* e) { + LINE* ret = onetoken("return"); + LINEBLOCK* block = mklnblk(ret); + + // void subdecs return 0 if(e == NULL) { - LINE* r = mkline(1); - addtoken(r, ezheapstr("return")); - return r; - } + char* tokens[] = { "push", "constant", "0" }; + appendlnbefore(block, mksimpleln(tokens, sizeof(tokens) / sizeof(char*))); + } else + block = mergelnblks(compileexpression(s, e), block); + + return block; } -LINE* compilestatement(SCOPE* s, CLASS* c, STATEMENT* st) { +LINEBLOCK* compilestatement(SCOPE* s, CLASS* c, STATEMENT* st) { if(st->type == dostatement) return compilesubroutcall(s, c, st->dost); else if(st->type == returnstatement) @@ -455,40 +188,38 @@ LINE* compilestatement(SCOPE* s, CLASS* c, STATEMENT* st) { } } -LINE* compilestatements(SCOPE* s, CLASS* c, STATEMENT* sts) { - LINE* head; - LINE* curr; - if(sts != NULL) { - head = compilestatement(s, c, sts); - curr = head; +LINEBLOCK* compilestatements(SCOPE* s, CLASS* c, STATEMENT* sts) { + LINEBLOCK* head = NULL; + while(sts != NULL) { + head = mergelnblks(head, compilestatement(s, c, sts)); sts = sts->next; - while(sts != NULL) { - LINE* ln = compilestatement(s, c, sts); - curr->next = ln; - curr = ln; - sts = sts->next; - } } return head; } -LINE* compilefunbody(SCOPE* s, CLASS* c, SUBROUTBODY* b) { +LINEBLOCK* compilefunbody(SCOPE* s, CLASS* c, SUBROUTBODY* b) { // missing scope and vardecs handling - LINE* head = compilestatements(s, c, b->statements); + LINEBLOCK* head = compilestatements(s, c, b->statements); return head; } -LINE* compilefundec(SCOPE* s, CLASS* c, SUBDEC* f) { - LINE* head = mkline(3); - addtoken(head, ezheapstr("function")); - addtoken(head, subdecname(c, f)); - addtoken(head, itoa(countlocalvars(f->body->vardecs))); +LINEBLOCK* compilefundec(SCOPE* s, CLASS* c, SUBDEC* f) { + LINE* label = mkline(3); + addtoken(label, ezheapstr("function")); + addtoken(label, subdecname(c, f)); + addtoken(label, itoa(countlocalvars(f->body->vardecs))); + label->next = NULL; - head->next = compilefunbody(s, c, f->body); - return head; + if(f->body->statements != NULL) { + LINEBLOCK* body = compilefunbody(s, c, f->body); + appendlnbefore(body, label); + return body; + } + else + return mklnblk(label); } -LINE* compilesubdec(SCOPE* s, CLASS* c, SUBDEC* sd) { +LINEBLOCK* compilesubdec(SCOPE* s, CLASS* c, SUBDEC* sd) { // 'this' and arguments are pushed by caller // Must have a 'return' at the end // Label names must have class name too (see mapping) @@ -499,24 +230,28 @@ LINE* compilesubdec(SCOPE* s, CLASS* c, SUBDEC* sd) { return compilefundec(s, c, sd); } -void compileclass(COMPILER* c, CLASS* class) { +LINEBLOCK* compileclass(COMPILER* c, CLASS* class) { SCOPE* topscope = mkscope(c->globalscope); addclassvardecs(topscope, class->vardecs); addsubdecs(topscope, class->subdecs); - SUBDEC* current = class->subdecs; - while(current != NULL) { - compilesubdec(topscope, class, current); - current = current->next; + LINEBLOCK* output = NULL; + SUBDEC* curr = class->subdecs; + while(curr != NULL) { + output = mergelnblks(output, compilesubdec(topscope, class, curr)); + curr = curr->next; } + return output; } void compile(COMPILER* c) { - CLASS* current = c->globalscope->classes; - while(current != NULL) { - compileclass(c, current); - current = current->next; + LINEBLOCK* output = NULL; + CLASS* curr = c->globalscope->classes; + while(curr != NULL) { + output = mergelnblks(output, compileclass(c, curr)); + curr = curr->next; } + c->output = output; } COMPILER* mkcompiler(CLASS* classes) { diff --git a/compiler.h b/compiler.h index a999b60..6acef81 100644 --- a/compiler.h +++ b/compiler.h @@ -2,19 +2,12 @@ #define COMPILER_H #include "util.h" #include "parser.h" - -typedef struct scope { - SUBDEC* subroutines; - CLASSVARDEC* classvardecs; - VARDEC* vardecs; - CLASS* classes; - struct scope* previous; -} SCOPE; +#include "vm-lines.h" +#include "compiler-scopes.h" typedef struct { SCOPE* globalscope; - LINE* output; - LINE* lastln; + LINEBLOCK* output; } COMPILER; COMPILER* mkcompiler(CLASS* classes); diff --git a/main.c b/main.c index 5fd73af..09c2c7d 100644 --- a/main.c +++ b/main.c @@ -2,26 +2,10 @@ #include #include #include -#include "tokenizer.h" -#include "printer.h" -#include "parser.h" #include "compiler.h" -void println(LINE* ln) { - for(int i = 0; i < ln->tokenscount; i++) { - printf("%s", ln->tokens[i]); - if(i != ln->tokenscount-1) - printf(" "); - } - printf("\n"); -} - void printcompiler(COMPILER* c) { - LINE* current = c->output; - while(current != NULL) { - println(current); - current = current->next; - } + printlns(c->output->head, stdout); } int main(int argc, char* argv[]) { diff --git a/parser.c b/parser.c index 932cd6d..6fa026d 100644 --- a/parser.c +++ b/parser.c @@ -39,6 +39,13 @@ const char* tokentypes[] = { "keyword", "identifier", "symbol", "integerConstant", "stringConstant" }; +DEBUGINFO* getdebug(PARSER* p) { + DEBUGINFO* d = (DEBUGINFO*)malloc(sizeof(DEBUGINFO)); + d->file = p->file; + d->definedat = p->current->truen; + return d; +} + void next(PARSER* p) { p->current = p->current->next; } @@ -203,9 +210,7 @@ SUBROUTCALL* parsesubroutcall(PARSER* p) { restorecp(p); return NULL; } - - call->definedat = p->current->truen; - call->file = p->file; + call->debug = getdebug(p); call->name = p->current->token; next(p); @@ -377,8 +382,8 @@ void parsevardeccommon(PARSER* p, VARDEC* v) { STRINGLIST* currstr = (STRINGLIST*)malloc(sizeof(STRINGLIST)); v->names = currstr; - v->file = p->file; - v->definedat = p->current->truen; + v->debug = getdebug(p); + v->names->content = parseidentifier(p); while(!strcmp(p->current->token, ",")) { @@ -496,8 +501,7 @@ SUBDEC* parsesubroutdec(PARSER* p) { subdec->type = parsetype(p, &dummy); } - subdec->file = p->file; - subdec->definedat = p->current->truen; + subdec->debug = getdebug(p); subdec->name = parseidentifier(p); @@ -530,8 +534,7 @@ CLASS* parseclass(PARSER* p) { CLASS* class = (CLASS*)malloc(sizeof(CLASS)); - class->definedat = p->current->truen; - class->file = p->file; + class->debug = getdebug(p); class->name = parseidentifier(p); diff --git a/parser.h b/parser.h index 8a10a5a..59d6594 100644 --- a/parser.h +++ b/parser.h @@ -2,10 +2,16 @@ #define PARSER_H #include #include "tokenizer.h" +#include "util.h" struct statement; struct explist; +typedef struct { + char* file; + int definedat; +} DEBUGINFO; + typedef enum { ifstatement, whilestatement, letstatement, dostatement, returnstatement } STATEMENTTYPE; @@ -17,9 +23,8 @@ typedef enum { typedef struct { char* parentname; char* name; - char* file; - int definedat; struct explist* parameters; + DEBUGINFO* debug; } SUBROUTCALL; typedef struct term { @@ -72,19 +77,13 @@ typedef enum { stat, field } VARCLASS; -typedef struct stringlist { - char* content; - struct stringlist* next; -} STRINGLIST; - typedef struct vardec { - char* file; - int definedat; char* type; bool primitive; TOKENTYPE typeclass; STRINGLIST* names; struct vardec* next; + DEBUGINFO* debug; } VARDEC; typedef struct classvardec { @@ -109,14 +108,13 @@ typedef struct SUBROUTBODY { } SUBROUTBODY; typedef struct subdec { - char* file; - int definedat; SUBROUTCLASS subroutclass; char* type; TOKENTYPE typeclass; char* name; PARAMETER* parameters; SUBROUTBODY* body; + DEBUGINFO* debug; struct subdec* next; } SUBDEC; @@ -124,8 +122,7 @@ typedef struct cl { char* name; CLASSVARDEC* vardecs; SUBDEC* subdecs; - char* file; - int definedat; + DEBUGINFO* debug; struct cl* next; } CLASS; diff --git a/printer.c b/printer.c deleted file mode 100644 index 8fc81e3..0000000 --- a/printer.c +++ /dev/null @@ -1,443 +0,0 @@ -#include "printer.h" -void printexpression(TERM* e, FILE* output, int depth); -void printstatements(STATEMENT* st, FILE* output, int depth); - -const char* tmpvarclasses[] = { - "static", "field" -}; -const int tmpvarclassessize = sizeof(tmpvarclasses) / sizeof(char*); - -const char* tmpsubroutclasses[] = { - "constructor", "function", "method" -}; -const int tmpsubroutclassessize = sizeof(tmpsubroutclasses) / sizeof(char*); - -const char* tmptokentypes[] = { - "keyword", "identifier" -}; - -void printident(FILE* output, int depth) { - for(int i = 0; i < depth; i++) - fprintf(output, " "); -} - -void printstringlist(FILE* output, int depth, STRINGLIST* ls) { - printident(output, depth); - fprintf(output, " %s \r\n", ls->content); - if(ls->next != NULL) { - printident(output, depth); - fprintf(output, " , \r\n"); - printstringlist(output, depth, ls->next); - } -} - -void printvardec(VARDEC* vd, FILE* output, int depth) { - printident(output, depth); - fprintf(output, "<%s> %s \r\n", tmptokentypes[vd->typeclass], vd->type, tmptokentypes[vd->typeclass]); - - printstringlist(output, depth, vd->names); - - printident(output, depth); - fprintf(output, " ; \r\n"); -} - -void printvardecs(VARDEC* vd, FILE* output, int depth) { - VARDEC* current = vd; - while(current != NULL) { - printident(output, depth); - fprintf(output, "\r\n"); - - printident(output, depth+1); - fprintf(output, " var \r\n"); - printvardec(current, output, depth+1); - current = current->next; - - printident(output, depth); - fprintf(output, "\r\n"); - } -} - -void printclassvardec(CLASSVARDEC* vd, FILE* output, int depth) { - printident(output, depth); - fprintf(output, " %s \r\n", tmpvarclasses[vd->varclass]); - - printvardec(vd->base, output, depth); -} - -void printclassvardecs(CLASSVARDEC* vd, FILE* output, int depth) { - CLASSVARDEC* current = vd; - while(current != NULL) { - printident(output, depth); - fprintf(output, "\r\n"); - - printclassvardec(current, output, depth+1); - current = current->next; - - printident(output, depth); - fprintf(output, "\r\n"); - } -} - -void printparameter(PARAMETER* p, FILE* output, int depth) { - printident(output, depth); - fprintf(output, " %s \r\n", p->type); - - printident(output, depth); - fprintf(output, " %s \r\n", p->name); - - if(p->next != NULL) { - printident(output, depth); - fprintf(output, " , \r\n"); - } -} - -void printparameters(PARAMETER* p, FILE* output, int depth) { - printident(output, depth); - fprintf(output, "\r\n"); - - PARAMETER* current = p; - while(current != NULL) { - printparameter(current, output, depth+1); - current = current->next; - } - - printident(output, depth); - fprintf(output, "\r\n"); -} - -void printexpressionlist(EXPRESSIONLIST* list, FILE* output, int depth) { - printident(output, depth); - fprintf(output, "\r\n"); - - if(list != NULL) { - EXPRESSIONLIST* current = list; - while(current != NULL) { - printexpression(current->expression, output, depth+1); - current = current->next; - if(current != NULL) { - printident(output, depth+1); - fprintf(output, " , \r\n"); - } - } - } - - printident(output, depth); - fprintf(output, "\r\n"); -} - -void printsubroutcall(SUBROUTCALL* c, FILE* output, int depth) { - if(c->parentname != NULL) { - printident(output, depth); - fprintf(output, " %s \r\n", c->parentname); - printident(output, depth); - fprintf(output, " . \r\n"); - } - - printident(output, depth); - fprintf(output, " %s \r\n", c->name); - - printident(output, depth); - fprintf(output, " ( \r\n"); - - printexpressionlist(c->parameters, output, depth); - - printident(output, depth); - fprintf(output, " ) \r\n"); -} - -void printterm(TERM* e, FILE* output, int depth) { - printident(output, depth); - fprintf(output, "\r\n"); - - if(e->type == varname) { - printident(output, depth+1); - fprintf(output, " %s \r\n", e->string); - } else if(e->type == subroutcall) { - printsubroutcall(e->call, output, depth+1); - } else if(e->type == stringconstant) { - printident(output, depth+1); - fprintf(output, " %s \r\n", e->string); - } else if(e->type == keywordconstant) { - printident(output, depth+1); - fprintf(output, " %s \r\n", e->string); - } else if(e->type == intconstant) { - printident(output, depth+1); - fprintf(output, " %i \r\n", e->integer); - } else if(e->type == arrayitem) { - printident(output, depth+1); - fprintf(output, " %s \r\n", e->string); - - printident(output, depth+1); - fprintf(output, " [ \r\n"); - - printexpression(e->arrayexp, output, depth+1); - - printident(output, depth+1); - fprintf(output, " ] \r\n"); - } else if(e->type == innerexpression) { - printident(output, depth+1); - fprintf(output, " ( \r\n"); - - printexpression(e->expression, output, depth+1); - - printident(output, depth+1); - fprintf(output, " ) \r\n"); - } else { - printident(output, depth+1); - fprintf(output, " ~ \r\n"); - - printterm(e->expression, output, depth+1); - } - - printident(output, depth); - fprintf(output, "\r\n"); - - if(e->next != NULL) { - printident(output, depth); - fprintf(output, " %c \r\n", e->op); - } -} - -void printexpression(TERM* e, FILE* output, int depth) { - printident(output, depth); - fprintf(output, "\r\n"); - - TERM* current = e; - while(current != NULL) { - printterm(current, output, depth+1); - current = current->next; - } - - printident(output, depth); - fprintf(output, "\r\n"); -} - -void printcond(CONDSTATEMENT* st, FILE* output, int depth) { - printident(output, depth); - fprintf(output, " ( \r\n"); - - printexpression(st->expression, output, depth); - - printident(output, depth); - fprintf(output, " ) \r\n"); - - printident(output, depth); - fprintf(output, " { \r\n"); - - printstatements(st->statements, output, depth); - - printident(output, depth); - fprintf(output, " } \r\n"); -} - -void printif(IFSTATEMENT* st, FILE* output, int depth) { - printident(output, depth); - fprintf(output, "\r\n"); - - printident(output, depth+1); - fprintf(output, " if \r\n"); - - printcond(st->base, output, depth+1); - - if(st->elsestatements != NULL) { - printident(output, depth+1); - fprintf(output, " else \r\n"); - - printident(output, depth+1); - fprintf(output, " { \r\n"); - - printstatements(st->elsestatements, output, depth+1); - - printident(output, depth+1); - fprintf(output, " } \r\n"); - } - - printident(output, depth); - fprintf(output, "\r\n"); -} - -void printwhile(CONDSTATEMENT* st, FILE* output, int depth) { - printident(output, depth); - fprintf(output, "\r\n"); - - printident(output, depth+1); - fprintf(output, " while \r\n"); - - printcond(st, output, depth+1); - - printident(output, depth); - fprintf(output, "\r\n"); -} - -void printlet(LETSTATEMENT* st, FILE* output, int depth) { - printident(output, depth); - fprintf(output, "\r\n"); - - printident(output, depth+1); - fprintf(output, " let \r\n"); - - printident(output, depth+1); - fprintf(output, " %s \r\n", st->varname); - - if(st->arrayind != NULL) { - printident(output, depth+1); - fprintf(output, " [ \r\n"); - - printexpression(st->arrayind, output, depth+1); - - printident(output, depth+1); - fprintf(output, " ] \r\n"); - } - - printident(output, depth+1); - fprintf(output, " = \r\n"); - - printexpression(st->expression, output, depth+1); - - printident(output, depth+1); - fprintf(output, " ; \r\n"); - - printident(output, depth); - fprintf(output, "\r\n"); -} - -void printdo(SUBROUTCALL* st, FILE* output, int depth) { - printident(output, depth); - fprintf(output, "\r\n"); - - printident(output, depth+1); - fprintf(output, " do \r\n"); - - printsubroutcall(st, output, depth+1); - - printident(output, depth+1); - fprintf(output, " ; \r\n"); - - printident(output, depth); - fprintf(output, "\r\n"); -} - -void printreturn(TERM* st, FILE* output, int depth) { - printident(output, depth); - fprintf(output, "\r\n"); - - printident(output, depth+1); - fprintf(output, " return \r\n"); - - if(st != NULL) - printexpression(st, output, depth+1); - - printident(output, depth+1); - fprintf(output, " ; \r\n"); - - printident(output, depth); - fprintf(output, "\r\n"); -} - -void printstatement(STATEMENT* st, FILE* output, int depth) { - if(st->type == ifstatement) - printif(st->ifst, output, depth); - else if(st->type == letstatement) - printlet(st->letst, output, depth); - else if(st->type == whilestatement) - printwhile(st->whilest, output, depth); - else if(st->type == dostatement) - printdo(st->dost, output, depth); - else - printreturn(st->retst, output, depth); -} - -void printstatements(STATEMENT* st, FILE* output, int depth) { - printident(output, depth); - fprintf(output, "\r\n"); - - STATEMENT* current = st; - while(current != NULL) { - printstatement(current, output, depth+1); - current = current->next; - } - - printident(output, depth); - fprintf(output, "\r\n"); -} - -void printsubroutbody(SUBROUTBODY* bd, FILE* output, int depth) { - printident(output, depth); - fprintf(output, "\r\n"); - - printident(output, depth+1); - fprintf(output, " { \r\n"); - - printvardecs(bd->vardecs, output, depth+1); - - printstatements(bd->statements, output, depth+1); - - printident(output, depth+1); - fprintf(output, " } \r\n"); - - printident(output, depth); - fprintf(output, "\r\n"); -} - -void printsubroutdec(SUBDEC* sd, FILE* output, int depth) { - printident(output, depth); - fprintf(output, " %s \r\n", tmpsubroutclasses[sd->subroutclass]); - - printident(output, depth); - fprintf(output, "<%s> %s \r\n", tmptokentypes[sd->typeclass], sd->type, tmptokentypes[sd->typeclass]); - - printident(output, depth); - fprintf(output, " %s \r\n", sd->name); - - printident(output, depth); - fprintf(output, " ( \r\n"); - - printparameters(sd->parameters, output, depth); - - printident(output, depth); - fprintf(output, " ) \r\n"); - - printsubroutbody(sd->body, output, depth); -} - -void printsubroutdecs(SUBDEC* sd, FILE* output, int depth) { - SUBDEC* current = sd; - while(current != NULL) { - printident(output, depth); - fprintf(output, "\r\n"); - - printsubroutdec(current, output, depth+1); - current = current->next; - - printident(output, depth); - fprintf(output, "\r\n"); - } -} - -void printclass(CLASS* c, FILE* output, int depth) { - printident(output, depth); - fprintf(output, "\r\n"); - - printident(output, depth+1); - fprintf(output, " class \r\n"); - - printident(output, depth+1); - fprintf(output, " %s \r\n", c->name); - - printident(output, depth+1); - fprintf(output, " { \r\n"); - - printclassvardecs(c->vardecs, output, depth+1); - - printsubroutdecs(c->subdecs, output, depth+1); - - printident(output, depth+1); - fprintf(output, " } \r\n"); - - printident(output, depth); - fprintf(output, "\r\n"); -} - -void printparser(FILE* output, PARSER* p) { - printclass(p->output, output, 0); -} diff --git a/printer.h b/printer.h deleted file mode 100644 index 45107b1..0000000 --- a/printer.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef PRINTER_H -#define PRINTER_H -#include "parser.h" - -void printparser(FILE* output, PARSER* p); - -#endif diff --git a/util.c b/util.c index 26fc95f..30f53fa 100644 --- a/util.c +++ b/util.c @@ -34,24 +34,16 @@ char* itoa(int i) { return a; } -void printlns(LINELIST* lns, FILE* stream) { - LINELIST* curln = lns; - while(curln != NULL) { - fprintf(stream, "%s\n", curln->content); - curln = curln->next; +void printstrlist(STRINGLIST* strlist, FILE* stream) { + while(strlist != NULL) { + fprintf(stream, "%s\n", strlist->content); + strlist = strlist->next; } } -void freelns(LINELIST* lns) { - LINELIST* next = lns->next; - free(lns); +void freestrlist(STRINGLIST* strlist) { + STRINGLIST* next = strlist->next; + free(strlist); if(next != NULL) - freelns(next); -} - -LINE* mkline(int count) { - LINE* l = (LINE*)malloc(sizeof(LINE)); - l->tokenscount = 0; - l->tokens = (char**)malloc(sizeof(char*)*count); - return l; + freestrlist(next); } diff --git a/util.h b/util.h index d38d7f2..d606c3c 100644 --- a/util.h +++ b/util.h @@ -1,26 +1,20 @@ #ifndef UTIL_H #define UTIL_H - #include +/* util + * Random utilities. */ + +typedef struct stringlist { + char* content; + struct stringlist* next; +} STRINGLIST; + char* heapstr(char* str, int len); char* ezheapstr(char* str); int countplaces(int n); - -typedef struct line { - char** tokens; - int tokenscount; - struct line* next; -} LINE; - -typedef struct lnls { - char* content; - int truen; - struct lnls* next; -} LINELIST; - -void printlns(LINELIST* lns, FILE* stream); -void freelns(LINELIST* lns); -LINE* mkline(int count); char* itoa(int i); + +void printstrlist(STRINGLIST* strlist, FILE* stream); +void freestrlist(STRINGLIST* strlist); #endif diff --git a/vm-lines.c b/vm-lines.c new file mode 100644 index 0000000..6a0bf9f --- /dev/null +++ b/vm-lines.c @@ -0,0 +1,69 @@ +#include +#include "vm-lines.h" + +LINE* mkline(int size) { + LINE* ln = (LINE*)malloc(sizeof(LINE)); + ln->tokens = (char**)malloc(sizeof(char*)*size); + ln->count = 0; + return ln; +} + +void addtoken(LINE* ln, char* token) { + ln->tokens[ln->count] = token; + ln->count++; +} + +void println(LINE* ln, FILE* stream) { + for(int i = 0; i < ln->count; i++) { + fprintf(stream, "%s", ln->tokens[i]); + if(i + 1 < ln->count) + fprintf(stream, " "); + } + fprintf(stream, "\n"); +} + +void printlns(LINE* lns, FILE* stream) { + while(lns != NULL) { + println(lns, stream); + lns = lns->next; + } +} + +void freeln(LINE* ln) { + for(int i = 0; i < ln->count; i++) + free(ln->tokens[i]); + free(ln); +} + +void freelns(LINE* lns) { + LINE* next = lns->next; + freeln(lns); + if(next != NULL) + freelns(next); +} + +LINEBLOCK* mklnblk(LINE* start) { + LINEBLOCK* blk = (LINEBLOCK*)malloc(sizeof(LINEBLOCK)); + blk->head = start; + blk->tail = start; + return blk; +} + +LINEBLOCK* mergelnblks(LINEBLOCK* head, LINEBLOCK* tail) { + if(head == NULL) + return tail; + head->tail->next = tail->head; + head->tail = tail->tail; + free(tail); + return head; +} + +void appendln(LINEBLOCK* lnblk, LINE* ln) { + lnblk->tail->next = ln; + lnblk->tail = ln; +} + +void appendlnbefore(LINEBLOCK* lnblk, LINE* ln) { + ln->next = lnblk->head; + lnblk->head = ln; +} diff --git a/vm-lines.h b/vm-lines.h new file mode 100644 index 0000000..186d414 --- /dev/null +++ b/vm-lines.h @@ -0,0 +1,38 @@ +#ifndef VM_LINES_H +#define VM_LINES_H +#include + +/* vm-lines + * Unified standard for the compiler's output and vm-translator's input. + * It is also used by vm-parser when reading .vm files. */ + +// Data types +typedef struct line { + char** tokens; + int count; + struct line* next; +} LINE; + +typedef struct { + LINE* head; + LINE* tail; +} LINEBLOCK; + +// Line manipulation +LINE* mkline(int size); +void addtoken(LINE* ln, char* token); + +// Line printing +void println(LINE* ln, FILE* stream); +void printlns(LINE* lns, FILE* stream); + +// Line freeing +void freeln(LINE* ln); +void freelns(LINE* lns); + +// Line block manipulation +LINEBLOCK* mklnblk(LINE* start); +LINEBLOCK* mergelnblks(LINEBLOCK* head, LINEBLOCK* tail); +void appendln(LINEBLOCK* lnblk, LINE* ln); +void appendlnbefore(LINEBLOCK* lnblk, LINE* ln); +#endif