Add basic compiling mechanism
This commit is contained in:
parent
f647a754a7
commit
f26d7704a8
2
Makefile
2
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
|
||||
|
|
|
@ -0,0 +1,326 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#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;
|
||||
}
|
||||
}
|
|
@ -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
|
503
compiler.c
503
compiler.c
|
@ -1,254 +1,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#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) {
|
||||
|
|
13
compiler.h
13
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);
|
||||
|
|
18
main.c
18
main.c
|
@ -2,26 +2,10 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#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[]) {
|
||||
|
|
21
parser.c
21
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);
|
||||
|
||||
|
|
23
parser.h
23
parser.h
|
@ -2,10 +2,16 @@
|
|||
#define PARSER_H
|
||||
#include <stdbool.h>
|
||||
#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;
|
||||
|
||||
|
|
443
printer.c
443
printer.c
|
@ -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, "<identifier> %s </identifier>\r\n", ls->content);
|
||||
if(ls->next != NULL) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<symbol> , </symbol>\r\n");
|
||||
printstringlist(output, depth, ls->next);
|
||||
}
|
||||
}
|
||||
|
||||
void printvardec(VARDEC* vd, FILE* output, int depth) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<%s> %s </%s>\r\n", tmptokentypes[vd->typeclass], vd->type, tmptokentypes[vd->typeclass]);
|
||||
|
||||
printstringlist(output, depth, vd->names);
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "<symbol> ; </symbol>\r\n");
|
||||
}
|
||||
|
||||
void printvardecs(VARDEC* vd, FILE* output, int depth) {
|
||||
VARDEC* current = vd;
|
||||
while(current != NULL) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<varDec>\r\n");
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<keyword> var </keyword>\r\n");
|
||||
printvardec(current, output, depth+1);
|
||||
current = current->next;
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "</varDec>\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
void printclassvardec(CLASSVARDEC* vd, FILE* output, int depth) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<keyword> %s </keyword>\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, "<classVarDec>\r\n");
|
||||
|
||||
printclassvardec(current, output, depth+1);
|
||||
current = current->next;
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "</classVarDec>\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
void printparameter(PARAMETER* p, FILE* output, int depth) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<keyword> %s </keyword>\r\n", p->type);
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "<identifier> %s </identifier>\r\n", p->name);
|
||||
|
||||
if(p->next != NULL) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<symbol> , </symbol>\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
void printparameters(PARAMETER* p, FILE* output, int depth) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<parameterList>\r\n");
|
||||
|
||||
PARAMETER* current = p;
|
||||
while(current != NULL) {
|
||||
printparameter(current, output, depth+1);
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "</parameterList>\r\n");
|
||||
}
|
||||
|
||||
void printexpressionlist(EXPRESSIONLIST* list, FILE* output, int depth) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<expressionList>\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, "<symbol> , </symbol>\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "</expressionList>\r\n");
|
||||
}
|
||||
|
||||
void printsubroutcall(SUBROUTCALL* c, FILE* output, int depth) {
|
||||
if(c->parentname != NULL) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<identifier> %s </identifier>\r\n", c->parentname);
|
||||
printident(output, depth);
|
||||
fprintf(output, "<symbol> . </symbol>\r\n");
|
||||
}
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "<identifier> %s </identifier>\r\n", c->name);
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "<symbol> ( </symbol>\r\n");
|
||||
|
||||
printexpressionlist(c->parameters, output, depth);
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "<symbol> ) </symbol>\r\n");
|
||||
}
|
||||
|
||||
void printterm(TERM* e, FILE* output, int depth) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<term>\r\n");
|
||||
|
||||
if(e->type == varname) {
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<identifier> %s </identifier>\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, "<stringConstant> %s </stringConstant>\r\n", e->string);
|
||||
} else if(e->type == keywordconstant) {
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<keyword> %s </keyword>\r\n", e->string);
|
||||
} else if(e->type == intconstant) {
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<integerConstant> %i </integerConstant>\r\n", e->integer);
|
||||
} else if(e->type == arrayitem) {
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<identifier> %s </identifier>\r\n", e->string);
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<symbol> [ </symbol>\r\n");
|
||||
|
||||
printexpression(e->arrayexp, output, depth+1);
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<symbol> ] </symbol>\r\n");
|
||||
} else if(e->type == innerexpression) {
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<symbol> ( </symbol>\r\n");
|
||||
|
||||
printexpression(e->expression, output, depth+1);
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<symbol> ) </symbol>\r\n");
|
||||
} else {
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<symbol> ~ </symbol>\r\n");
|
||||
|
||||
printterm(e->expression, output, depth+1);
|
||||
}
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "</term>\r\n");
|
||||
|
||||
if(e->next != NULL) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<symbol> %c </symbol>\r\n", e->op);
|
||||
}
|
||||
}
|
||||
|
||||
void printexpression(TERM* e, FILE* output, int depth) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<expression>\r\n");
|
||||
|
||||
TERM* current = e;
|
||||
while(current != NULL) {
|
||||
printterm(current, output, depth+1);
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "</expression>\r\n");
|
||||
}
|
||||
|
||||
void printcond(CONDSTATEMENT* st, FILE* output, int depth) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<symbol> ( </symbol>\r\n");
|
||||
|
||||
printexpression(st->expression, output, depth);
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "<symbol> ) </symbol>\r\n");
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "<symbol> { </symbol>\r\n");
|
||||
|
||||
printstatements(st->statements, output, depth);
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "<symbol> } </symbol>\r\n");
|
||||
}
|
||||
|
||||
void printif(IFSTATEMENT* st, FILE* output, int depth) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<ifStatement>\r\n");
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<keyword> if </keyword>\r\n");
|
||||
|
||||
printcond(st->base, output, depth+1);
|
||||
|
||||
if(st->elsestatements != NULL) {
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<keyword> else </keyword>\r\n");
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<symbol> { </symbol>\r\n");
|
||||
|
||||
printstatements(st->elsestatements, output, depth+1);
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<symbol> } </symbol>\r\n");
|
||||
}
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "</ifStatement>\r\n");
|
||||
}
|
||||
|
||||
void printwhile(CONDSTATEMENT* st, FILE* output, int depth) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<whileStatement>\r\n");
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<keyword> while </keyword>\r\n");
|
||||
|
||||
printcond(st, output, depth+1);
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "</whileStatement>\r\n");
|
||||
}
|
||||
|
||||
void printlet(LETSTATEMENT* st, FILE* output, int depth) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<letStatement>\r\n");
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<keyword> let </keyword>\r\n");
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<identifier> %s </identifier>\r\n", st->varname);
|
||||
|
||||
if(st->arrayind != NULL) {
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<symbol> [ </symbol>\r\n");
|
||||
|
||||
printexpression(st->arrayind, output, depth+1);
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<symbol> ] </symbol>\r\n");
|
||||
}
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<symbol> = </symbol>\r\n");
|
||||
|
||||
printexpression(st->expression, output, depth+1);
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<symbol> ; </symbol>\r\n");
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "</letStatement>\r\n");
|
||||
}
|
||||
|
||||
void printdo(SUBROUTCALL* st, FILE* output, int depth) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<doStatement>\r\n");
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<keyword> do </keyword>\r\n");
|
||||
|
||||
printsubroutcall(st, output, depth+1);
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<symbol> ; </symbol>\r\n");
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "</doStatement>\r\n");
|
||||
}
|
||||
|
||||
void printreturn(TERM* st, FILE* output, int depth) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<returnStatement>\r\n");
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<keyword> return </keyword>\r\n");
|
||||
|
||||
if(st != NULL)
|
||||
printexpression(st, output, depth+1);
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<symbol> ; </symbol>\r\n");
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "</returnStatement>\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, "<statements>\r\n");
|
||||
|
||||
STATEMENT* current = st;
|
||||
while(current != NULL) {
|
||||
printstatement(current, output, depth+1);
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "</statements>\r\n");
|
||||
}
|
||||
|
||||
void printsubroutbody(SUBROUTBODY* bd, FILE* output, int depth) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<subroutineBody>\r\n");
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<symbol> { </symbol>\r\n");
|
||||
|
||||
printvardecs(bd->vardecs, output, depth+1);
|
||||
|
||||
printstatements(bd->statements, output, depth+1);
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<symbol> } </symbol>\r\n");
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "</subroutineBody>\r\n");
|
||||
}
|
||||
|
||||
void printsubroutdec(SUBDEC* sd, FILE* output, int depth) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<keyword> %s </keyword>\r\n", tmpsubroutclasses[sd->subroutclass]);
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "<%s> %s </%s>\r\n", tmptokentypes[sd->typeclass], sd->type, tmptokentypes[sd->typeclass]);
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "<identifier> %s </identifier>\r\n", sd->name);
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "<symbol> ( </symbol>\r\n");
|
||||
|
||||
printparameters(sd->parameters, output, depth);
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "<symbol> ) </symbol>\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, "<subroutineDec>\r\n");
|
||||
|
||||
printsubroutdec(current, output, depth+1);
|
||||
current = current->next;
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "</subroutineDec>\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
void printclass(CLASS* c, FILE* output, int depth) {
|
||||
printident(output, depth);
|
||||
fprintf(output, "<class>\r\n");
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<keyword> class </keyword>\r\n");
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<identifier> %s </identifier>\r\n", c->name);
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<symbol> { </symbol>\r\n");
|
||||
|
||||
printclassvardecs(c->vardecs, output, depth+1);
|
||||
|
||||
printsubroutdecs(c->subdecs, output, depth+1);
|
||||
|
||||
printident(output, depth+1);
|
||||
fprintf(output, "<symbol> } </symbol>\r\n");
|
||||
|
||||
printident(output, depth);
|
||||
fprintf(output, "</class>\r\n");
|
||||
}
|
||||
|
||||
void printparser(FILE* output, PARSER* p) {
|
||||
printclass(p->output, output, 0);
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
#ifndef PRINTER_H
|
||||
#define PRINTER_H
|
||||
#include "parser.h"
|
||||
|
||||
void printparser(FILE* output, PARSER* p);
|
||||
|
||||
#endif
|
24
util.c
24
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);
|
||||
}
|
||||
|
|
28
util.h
28
util.h
|
@ -1,26 +1,20 @@
|
|||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* 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
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
#include <stdlib.h>
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
#ifndef VM_LINES_H
|
||||
#define VM_LINES_H
|
||||
#include <stdio.h>
|
||||
|
||||
/* 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
|
Loading…
Reference in New Issue