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.
|
INCLUDES = -I.
|
||||||
CFLAGS = -std=c99 -g
|
CFLAGS = -std=c99 -g
|
||||||
OUTFILE = compiler
|
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 <stdlib.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "compiler.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 countparameters(EXPRESSIONLIST* params) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while(params != NULL) {
|
while(params != NULL) {
|
||||||
|
@ -270,7 +23,7 @@ int countlocalvars(VARDEC* decs) {
|
||||||
char* dotlabel(char* n1, char* n2) {
|
char* dotlabel(char* n1, char* n2) {
|
||||||
int sz = (strlen(n1) + strlen(n2) + 2) * sizeof(char);
|
int sz = (strlen(n1) + strlen(n2) + 2) * sizeof(char);
|
||||||
char* result = (char*)malloc(sz);
|
char* result = (char*)malloc(sz);
|
||||||
snprintf(result, sz, "%s.%s", n1, n2);
|
sprintf(result, "%s.%s", n1, n2);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,44 +31,17 @@ char* subdecname(CLASS* c, SUBDEC* sd) {
|
||||||
return dotlabel(c->name, sd->name);
|
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* onetoken(char* str) {
|
||||||
LINE* ln = mkline(1);
|
LINE* ln = mkline(1);
|
||||||
addtoken(ln, ezheapstr(str));
|
addtoken(ln, ezheapstr(str));
|
||||||
|
ln->next = NULL;
|
||||||
return ln;
|
return ln;
|
||||||
}
|
}
|
||||||
|
|
||||||
LINE* mksimpleln(char** tokens) {
|
LINE* mksimpleln(char** tokens, int count) {
|
||||||
int count = sizeof(tokens) / sizeof(char*);
|
|
||||||
|
|
||||||
LINE* ln = mkline(count);
|
LINE* ln = mkline(count);
|
||||||
for(int i = 0; i < count; i++)
|
for(int i = 0; i < count; i++)
|
||||||
addtoken(ln, ezheapstr(tokens[i]));
|
addtoken(ln, ezheapstr(tokens[i]));
|
||||||
|
|
||||||
return ln;
|
return ln;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,115 +62,122 @@ LINE* mathopln(char op) {
|
||||||
return onetoken("and");
|
return onetoken("and");
|
||||||
if(op == '/') {
|
if(op == '/') {
|
||||||
char* tokens[] = { "call", "Math.divide", "2" };
|
char* tokens[] = { "call", "Math.divide", "2" };
|
||||||
return mksimpleln(tokens);
|
return mksimpleln(tokens, sizeof(tokens) / sizeof(char*));
|
||||||
}
|
}
|
||||||
if(op == '*') {
|
if(op == '*') {
|
||||||
char* tokens[] = { "call", "Math.multiply", "2" };
|
char* tokens[] = { "call", "Math.multiply", "2" };
|
||||||
return mksimpleln(tokens);
|
return mksimpleln(tokens, sizeof(tokens) / sizeof(char*));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LINE* compileexpression(SCOPE* s, TERM* e, LINE** tail) {
|
LINEBLOCK* compileexpression(SCOPE* s, TERM* e) {
|
||||||
LINE* nexts = NULL;
|
LINEBLOCK* myblk;
|
||||||
LINE* nextstail;
|
LINEBLOCK* next = NULL;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(e->type == intconstant) {
|
if(e->type == intconstant) {
|
||||||
r = mkline(3);
|
LINE* ln = mkline(3);
|
||||||
addtoken(r, ezheapstr("push"));
|
addtoken(ln, ezheapstr("push"));
|
||||||
addtoken(r, ezheapstr("constant"));
|
addtoken(ln, ezheapstr("constant"));
|
||||||
addtoken(r, itoa(e->integer));
|
addtoken(ln, itoa(e->integer));
|
||||||
|
ln->next = NULL;
|
||||||
|
myblk = mklnblk(ln);
|
||||||
}
|
}
|
||||||
else if(e->type == unaryopterm) {
|
else if(e->type == unaryopterm) {
|
||||||
r = mkline(1);
|
myblk = compileexpression(s, e->expression);
|
||||||
addtoken(r, ezheapstr("neg"));
|
LINE* neg = onetoken("neg");
|
||||||
|
appendln(myblk, neg);
|
||||||
}
|
}
|
||||||
else if(e->type == innerexpression) {
|
else if(e->type == innerexpression) {
|
||||||
r = compileexpression(s, e->expression, tail); // might be wrong tail
|
myblk = compileexpression(s, e->expression);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, "Unsuported SHIT %i\n", e->type);
|
fprintf(stderr, "Unsupported term yet %i\n", e->type);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(nexts != NULL) {
|
if(e->next != NULL) {
|
||||||
r->next = nexts;
|
next = compileexpression(s, e->next);
|
||||||
(*tail) = nextstail;
|
LINE* op = mathopln(e->op);
|
||||||
|
appendln(next, op);
|
||||||
|
op->next = NULL;
|
||||||
|
myblk = mergelnblks(myblk, next);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
(*tail) = r;
|
return myblk;
|
||||||
r->next = NULL;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LINE* compileparameters(SCOPE* s, EXPRESSIONLIST* ps, LINE** tail) {
|
LINEBLOCK* compileparameters(SCOPE* s, EXPRESSIONLIST* params) {
|
||||||
LINE* head;
|
LINEBLOCK* head = NULL;
|
||||||
LINE* mytail;
|
while(params != NULL) {
|
||||||
if(ps != NULL)
|
head = mergelnblks(head, compileexpression(s, params->expression));
|
||||||
head = compileexpression(s, ps->expression, &mytail);
|
params = params->next;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
(*tail) = mytail;
|
|
||||||
return head;
|
return head;
|
||||||
}
|
}
|
||||||
|
|
||||||
LINE* compilesubroutcall(SCOPE* s, CLASS* c, SUBROUTCALL* call) {
|
LINEBLOCK* compilecallln(CLASS* c, SUBROUTCALL* call) {
|
||||||
/* FOR NOW THERE IS NO OS SO THIS WILL CAUSE PROBLEMS
|
LINE* ln = mkline(3);
|
||||||
SUBDEC* sd;
|
|
||||||
|
addtoken(ln, ezheapstr("call"));
|
||||||
|
|
||||||
if(call->parentname != NULL)
|
if(call->parentname != NULL)
|
||||||
sd = getsubdecfromparent(s, call);
|
addtoken(ln, dotlabel(call->parentname, call->name));
|
||||||
else
|
else
|
||||||
sd = getsubdec(s, call->name);
|
addtoken(ln, dotlabel(c->name, call->name));
|
||||||
if(sd == NULL) {
|
|
||||||
fprintf(stderr, "Method '%s' does not exist; file '%', line %i\n", call->name, call->file, call->definedat);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// At the moment can only call functions
|
addtoken(ln, itoa(countparameters(call->parameters)));
|
||||||
LINE* tail;
|
|
||||||
LINE* head = compileparameters(s, call->parameters, &tail);
|
|
||||||
|
|
||||||
LINE* callvm = mkline(3);
|
return mklnblk(ln);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LINE* compileret(SCOPE* s, TERM* e) {
|
// temporary ignore list for OS functions
|
||||||
// missing expression handling
|
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) {
|
if(e == NULL) {
|
||||||
LINE* r = mkline(1);
|
char* tokens[] = { "push", "constant", "0" };
|
||||||
addtoken(r, ezheapstr("return"));
|
appendlnbefore(block, mksimpleln(tokens, sizeof(tokens) / sizeof(char*)));
|
||||||
return r;
|
} 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)
|
if(st->type == dostatement)
|
||||||
return compilesubroutcall(s, c, st->dost);
|
return compilesubroutcall(s, c, st->dost);
|
||||||
else if(st->type == returnstatement)
|
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) {
|
LINEBLOCK* compilestatements(SCOPE* s, CLASS* c, STATEMENT* sts) {
|
||||||
LINE* head;
|
LINEBLOCK* head = NULL;
|
||||||
LINE* curr;
|
while(sts != NULL) {
|
||||||
if(sts != NULL) {
|
head = mergelnblks(head, compilestatement(s, c, sts));
|
||||||
head = compilestatement(s, c, sts);
|
|
||||||
curr = head;
|
|
||||||
sts = sts->next;
|
sts = sts->next;
|
||||||
while(sts != NULL) {
|
|
||||||
LINE* ln = compilestatement(s, c, sts);
|
|
||||||
curr->next = ln;
|
|
||||||
curr = ln;
|
|
||||||
sts = sts->next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return head;
|
return head;
|
||||||
}
|
}
|
||||||
|
|
||||||
LINE* compilefunbody(SCOPE* s, CLASS* c, SUBROUTBODY* b) {
|
LINEBLOCK* compilefunbody(SCOPE* s, CLASS* c, SUBROUTBODY* b) {
|
||||||
// missing scope and vardecs handling
|
// missing scope and vardecs handling
|
||||||
LINE* head = compilestatements(s, c, b->statements);
|
LINEBLOCK* head = compilestatements(s, c, b->statements);
|
||||||
return head;
|
return head;
|
||||||
}
|
}
|
||||||
|
|
||||||
LINE* compilefundec(SCOPE* s, CLASS* c, SUBDEC* f) {
|
LINEBLOCK* compilefundec(SCOPE* s, CLASS* c, SUBDEC* f) {
|
||||||
LINE* head = mkline(3);
|
LINE* label = mkline(3);
|
||||||
addtoken(head, ezheapstr("function"));
|
addtoken(label, ezheapstr("function"));
|
||||||
addtoken(head, subdecname(c, f));
|
addtoken(label, subdecname(c, f));
|
||||||
addtoken(head, itoa(countlocalvars(f->body->vardecs)));
|
addtoken(label, itoa(countlocalvars(f->body->vardecs)));
|
||||||
|
label->next = NULL;
|
||||||
|
|
||||||
head->next = compilefunbody(s, c, f->body);
|
if(f->body->statements != NULL) {
|
||||||
return head;
|
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
|
// 'this' and arguments are pushed by caller
|
||||||
// Must have a 'return' at the end
|
// Must have a 'return' at the end
|
||||||
// Label names must have class name too (see mapping)
|
// 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);
|
return compilefundec(s, c, sd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void compileclass(COMPILER* c, CLASS* class) {
|
LINEBLOCK* compileclass(COMPILER* c, CLASS* class) {
|
||||||
SCOPE* topscope = mkscope(c->globalscope);
|
SCOPE* topscope = mkscope(c->globalscope);
|
||||||
addclassvardecs(topscope, class->vardecs);
|
addclassvardecs(topscope, class->vardecs);
|
||||||
addsubdecs(topscope, class->subdecs);
|
addsubdecs(topscope, class->subdecs);
|
||||||
|
|
||||||
SUBDEC* current = class->subdecs;
|
LINEBLOCK* output = NULL;
|
||||||
while(current != NULL) {
|
SUBDEC* curr = class->subdecs;
|
||||||
compilesubdec(topscope, class, current);
|
while(curr != NULL) {
|
||||||
current = current->next;
|
output = mergelnblks(output, compilesubdec(topscope, class, curr));
|
||||||
|
curr = curr->next;
|
||||||
}
|
}
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
void compile(COMPILER* c) {
|
void compile(COMPILER* c) {
|
||||||
CLASS* current = c->globalscope->classes;
|
LINEBLOCK* output = NULL;
|
||||||
while(current != NULL) {
|
CLASS* curr = c->globalscope->classes;
|
||||||
compileclass(c, current);
|
while(curr != NULL) {
|
||||||
current = current->next;
|
output = mergelnblks(output, compileclass(c, curr));
|
||||||
|
curr = curr->next;
|
||||||
}
|
}
|
||||||
|
c->output = output;
|
||||||
}
|
}
|
||||||
|
|
||||||
COMPILER* mkcompiler(CLASS* classes) {
|
COMPILER* mkcompiler(CLASS* classes) {
|
||||||
|
|
13
compiler.h
13
compiler.h
|
@ -2,19 +2,12 @@
|
||||||
#define COMPILER_H
|
#define COMPILER_H
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "vm-lines.h"
|
||||||
typedef struct scope {
|
#include "compiler-scopes.h"
|
||||||
SUBDEC* subroutines;
|
|
||||||
CLASSVARDEC* classvardecs;
|
|
||||||
VARDEC* vardecs;
|
|
||||||
CLASS* classes;
|
|
||||||
struct scope* previous;
|
|
||||||
} SCOPE;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
SCOPE* globalscope;
|
SCOPE* globalscope;
|
||||||
LINE* output;
|
LINEBLOCK* output;
|
||||||
LINE* lastln;
|
|
||||||
} COMPILER;
|
} COMPILER;
|
||||||
|
|
||||||
COMPILER* mkcompiler(CLASS* classes);
|
COMPILER* mkcompiler(CLASS* classes);
|
||||||
|
|
18
main.c
18
main.c
|
@ -2,26 +2,10 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "tokenizer.h"
|
|
||||||
#include "printer.h"
|
|
||||||
#include "parser.h"
|
|
||||||
#include "compiler.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) {
|
void printcompiler(COMPILER* c) {
|
||||||
LINE* current = c->output;
|
printlns(c->output->head, stdout);
|
||||||
while(current != NULL) {
|
|
||||||
println(current);
|
|
||||||
current = current->next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
|
|
21
parser.c
21
parser.c
|
@ -39,6 +39,13 @@ const char* tokentypes[] = {
|
||||||
"keyword", "identifier", "symbol", "integerConstant", "stringConstant"
|
"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) {
|
void next(PARSER* p) {
|
||||||
p->current = p->current->next;
|
p->current = p->current->next;
|
||||||
}
|
}
|
||||||
|
@ -203,9 +210,7 @@ SUBROUTCALL* parsesubroutcall(PARSER* p) {
|
||||||
restorecp(p);
|
restorecp(p);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
call->debug = getdebug(p);
|
||||||
call->definedat = p->current->truen;
|
|
||||||
call->file = p->file;
|
|
||||||
|
|
||||||
call->name = p->current->token;
|
call->name = p->current->token;
|
||||||
next(p);
|
next(p);
|
||||||
|
@ -377,8 +382,8 @@ void parsevardeccommon(PARSER* p, VARDEC* v) {
|
||||||
STRINGLIST* currstr = (STRINGLIST*)malloc(sizeof(STRINGLIST));
|
STRINGLIST* currstr = (STRINGLIST*)malloc(sizeof(STRINGLIST));
|
||||||
v->names = currstr;
|
v->names = currstr;
|
||||||
|
|
||||||
v->file = p->file;
|
v->debug = getdebug(p);
|
||||||
v->definedat = p->current->truen;
|
|
||||||
v->names->content = parseidentifier(p);
|
v->names->content = parseidentifier(p);
|
||||||
|
|
||||||
while(!strcmp(p->current->token, ",")) {
|
while(!strcmp(p->current->token, ",")) {
|
||||||
|
@ -496,8 +501,7 @@ SUBDEC* parsesubroutdec(PARSER* p) {
|
||||||
subdec->type = parsetype(p, &dummy);
|
subdec->type = parsetype(p, &dummy);
|
||||||
}
|
}
|
||||||
|
|
||||||
subdec->file = p->file;
|
subdec->debug = getdebug(p);
|
||||||
subdec->definedat = p->current->truen;
|
|
||||||
|
|
||||||
subdec->name = parseidentifier(p);
|
subdec->name = parseidentifier(p);
|
||||||
|
|
||||||
|
@ -530,8 +534,7 @@ CLASS* parseclass(PARSER* p) {
|
||||||
|
|
||||||
CLASS* class = (CLASS*)malloc(sizeof(CLASS));
|
CLASS* class = (CLASS*)malloc(sizeof(CLASS));
|
||||||
|
|
||||||
class->definedat = p->current->truen;
|
class->debug = getdebug(p);
|
||||||
class->file = p->file;
|
|
||||||
|
|
||||||
class->name = parseidentifier(p);
|
class->name = parseidentifier(p);
|
||||||
|
|
||||||
|
|
23
parser.h
23
parser.h
|
@ -2,10 +2,16 @@
|
||||||
#define PARSER_H
|
#define PARSER_H
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "tokenizer.h"
|
#include "tokenizer.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
struct statement;
|
struct statement;
|
||||||
struct explist;
|
struct explist;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* file;
|
||||||
|
int definedat;
|
||||||
|
} DEBUGINFO;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ifstatement, whilestatement, letstatement, dostatement, returnstatement
|
ifstatement, whilestatement, letstatement, dostatement, returnstatement
|
||||||
} STATEMENTTYPE;
|
} STATEMENTTYPE;
|
||||||
|
@ -17,9 +23,8 @@ typedef enum {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char* parentname;
|
char* parentname;
|
||||||
char* name;
|
char* name;
|
||||||
char* file;
|
|
||||||
int definedat;
|
|
||||||
struct explist* parameters;
|
struct explist* parameters;
|
||||||
|
DEBUGINFO* debug;
|
||||||
} SUBROUTCALL;
|
} SUBROUTCALL;
|
||||||
|
|
||||||
typedef struct term {
|
typedef struct term {
|
||||||
|
@ -72,19 +77,13 @@ typedef enum {
|
||||||
stat, field
|
stat, field
|
||||||
} VARCLASS;
|
} VARCLASS;
|
||||||
|
|
||||||
typedef struct stringlist {
|
|
||||||
char* content;
|
|
||||||
struct stringlist* next;
|
|
||||||
} STRINGLIST;
|
|
||||||
|
|
||||||
typedef struct vardec {
|
typedef struct vardec {
|
||||||
char* file;
|
|
||||||
int definedat;
|
|
||||||
char* type;
|
char* type;
|
||||||
bool primitive;
|
bool primitive;
|
||||||
TOKENTYPE typeclass;
|
TOKENTYPE typeclass;
|
||||||
STRINGLIST* names;
|
STRINGLIST* names;
|
||||||
struct vardec* next;
|
struct vardec* next;
|
||||||
|
DEBUGINFO* debug;
|
||||||
} VARDEC;
|
} VARDEC;
|
||||||
|
|
||||||
typedef struct classvardec {
|
typedef struct classvardec {
|
||||||
|
@ -109,14 +108,13 @@ typedef struct SUBROUTBODY {
|
||||||
} SUBROUTBODY;
|
} SUBROUTBODY;
|
||||||
|
|
||||||
typedef struct subdec {
|
typedef struct subdec {
|
||||||
char* file;
|
|
||||||
int definedat;
|
|
||||||
SUBROUTCLASS subroutclass;
|
SUBROUTCLASS subroutclass;
|
||||||
char* type;
|
char* type;
|
||||||
TOKENTYPE typeclass;
|
TOKENTYPE typeclass;
|
||||||
char* name;
|
char* name;
|
||||||
PARAMETER* parameters;
|
PARAMETER* parameters;
|
||||||
SUBROUTBODY* body;
|
SUBROUTBODY* body;
|
||||||
|
DEBUGINFO* debug;
|
||||||
struct subdec* next;
|
struct subdec* next;
|
||||||
} SUBDEC;
|
} SUBDEC;
|
||||||
|
|
||||||
|
@ -124,8 +122,7 @@ typedef struct cl {
|
||||||
char* name;
|
char* name;
|
||||||
CLASSVARDEC* vardecs;
|
CLASSVARDEC* vardecs;
|
||||||
SUBDEC* subdecs;
|
SUBDEC* subdecs;
|
||||||
char* file;
|
DEBUGINFO* debug;
|
||||||
int definedat;
|
|
||||||
struct cl* next;
|
struct cl* next;
|
||||||
} CLASS;
|
} 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;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
void printlns(LINELIST* lns, FILE* stream) {
|
void printstrlist(STRINGLIST* strlist, FILE* stream) {
|
||||||
LINELIST* curln = lns;
|
while(strlist != NULL) {
|
||||||
while(curln != NULL) {
|
fprintf(stream, "%s\n", strlist->content);
|
||||||
fprintf(stream, "%s\n", curln->content);
|
strlist = strlist->next;
|
||||||
curln = curln->next;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void freelns(LINELIST* lns) {
|
void freestrlist(STRINGLIST* strlist) {
|
||||||
LINELIST* next = lns->next;
|
STRINGLIST* next = strlist->next;
|
||||||
free(lns);
|
free(strlist);
|
||||||
if(next != NULL)
|
if(next != NULL)
|
||||||
freelns(next);
|
freestrlist(next);
|
||||||
}
|
|
||||||
|
|
||||||
LINE* mkline(int count) {
|
|
||||||
LINE* l = (LINE*)malloc(sizeof(LINE));
|
|
||||||
l->tokenscount = 0;
|
|
||||||
l->tokens = (char**)malloc(sizeof(char*)*count);
|
|
||||||
return l;
|
|
||||||
}
|
}
|
||||||
|
|
28
util.h
28
util.h
|
@ -1,26 +1,20 @@
|
||||||
#ifndef UTIL_H
|
#ifndef UTIL_H
|
||||||
#define UTIL_H
|
#define UTIL_H
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* util
|
||||||
|
* Random utilities. */
|
||||||
|
|
||||||
|
typedef struct stringlist {
|
||||||
|
char* content;
|
||||||
|
struct stringlist* next;
|
||||||
|
} STRINGLIST;
|
||||||
|
|
||||||
char* heapstr(char* str, int len);
|
char* heapstr(char* str, int len);
|
||||||
char* ezheapstr(char* str);
|
char* ezheapstr(char* str);
|
||||||
int countplaces(int n);
|
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);
|
char* itoa(int i);
|
||||||
|
|
||||||
|
void printstrlist(STRINGLIST* strlist, FILE* stream);
|
||||||
|
void freestrlist(STRINGLIST* strlist);
|
||||||
#endif
|
#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