Add compiler-expressions and compiler-util
This commit is contained in:
parent
b7fe5b8f45
commit
26de7337da
2
Makefile
2
Makefile
|
@ -1,7 +1,7 @@
|
||||||
FILES = *.c */*.c
|
FILES = *.c */*.c
|
||||||
LIBRARIES = -lpthread
|
LIBRARIES = -lpthread
|
||||||
INCLUDES = -I. -I./parser/ -I./compiler/ -I./vm/ -I./tokenizer/ -I./misc/
|
INCLUDES = -I. -I./parser/ -I./compiler/ -I./vm/ -I./tokenizer/ -I./misc/
|
||||||
CFLAGS = -std=c99 -g -Wall
|
CFLAGS = -std=c99 -g
|
||||||
OUTFILE = jack-compiler
|
OUTFILE = jack-compiler
|
||||||
|
|
||||||
main: ${FILES}
|
main: ${FILES}
|
||||||
|
|
|
@ -0,0 +1,225 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "compiler-expressions.h"
|
||||||
|
#include "compiler-util.h"
|
||||||
|
|
||||||
|
/* BEGIN FORWARD DECLARATIONS */
|
||||||
|
|
||||||
|
// Miscelaneous
|
||||||
|
LINE* pushconstant(int n);
|
||||||
|
LINE* mathopln(char op);
|
||||||
|
LINE* pushthat();
|
||||||
|
int countexpressions(EXPRESSIONLIST* explist);
|
||||||
|
char* toascii(char c);
|
||||||
|
|
||||||
|
// Dealing with singular terms
|
||||||
|
LINEBLOCK* compilestrconst(char* str);
|
||||||
|
LINEBLOCK* compilekeywordconst(SCOPE* s, TERM* t);
|
||||||
|
LINEBLOCK* compilearrayitem(SCOPE* s, TERM* t);
|
||||||
|
LINEBLOCK* compilecallln(SCOPE* s, SUBROUTDEC* d, SUBROUTCALL* call);
|
||||||
|
LINEBLOCK* pushunaryopterm(SCOPE* s, TERM* t);
|
||||||
|
LINEBLOCK* compileterm(SCOPE* s, TERM* t);
|
||||||
|
|
||||||
|
/* END FORWARD DECLARATIONS */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Miscelaneous
|
||||||
|
LINE* mathopln(char op) {
|
||||||
|
if(op == '+')
|
||||||
|
return onetoken("add");
|
||||||
|
if(op == '-')
|
||||||
|
return onetoken("sub");
|
||||||
|
if(op == '=')
|
||||||
|
return onetoken("eq");
|
||||||
|
if(op == '>')
|
||||||
|
return onetoken("gt");
|
||||||
|
if(op == '<')
|
||||||
|
return onetoken("lt");
|
||||||
|
if(op == '|')
|
||||||
|
return onetoken("or");
|
||||||
|
if(op == '&')
|
||||||
|
return onetoken("and");
|
||||||
|
if(op == '/') {
|
||||||
|
char* tokens[] = { "call", "Math.divide", "2" };
|
||||||
|
return mkln(tokens);
|
||||||
|
}
|
||||||
|
char* tokens[] = { "call", "Math.multiply", "2" };
|
||||||
|
return mkln(tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
LINE* pushconstant(int n) {
|
||||||
|
char* tokens[] = { "push", "constant", itoa(n) };
|
||||||
|
return mkln(tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
LINE* pushthat() {
|
||||||
|
char* pushthat[] = { "push", "that", "0" };
|
||||||
|
return mkln(pushthat);
|
||||||
|
}
|
||||||
|
|
||||||
|
int countexpressions(EXPRESSIONLIST* explist) {
|
||||||
|
int i = 0;
|
||||||
|
while(explist != NULL) {
|
||||||
|
i++;
|
||||||
|
explist = explist->next;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* toascii(char c) {
|
||||||
|
char* result = (char*)malloc(sizeof(char) * (countplaces(c) + 1));
|
||||||
|
sprintf(result, "%i", c);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dealing with singular terms
|
||||||
|
LINEBLOCK* compilestrconst(char* str) {
|
||||||
|
if(str[0] == '\0')
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
char* pushchar[] = { "push", "constant", toascii(str[0]) };
|
||||||
|
LINEBLOCK* blk = mklnblk(mksimpleln(pushchar, strcount(pushchar)));
|
||||||
|
free(pushchar[2]);
|
||||||
|
|
||||||
|
char* appendchar[] = { "call", "String.appendChar", "2" };
|
||||||
|
appendln(blk, mkln(appendchar));
|
||||||
|
|
||||||
|
int i = 1;
|
||||||
|
char c;
|
||||||
|
while(c = str[i], c != '\0') {
|
||||||
|
pushchar[2] = toascii(c);
|
||||||
|
appendln(blk, mksimpleln(pushchar, strcount(pushchar)));
|
||||||
|
free(pushchar[2]);
|
||||||
|
appendln(blk, mksimpleln(appendchar, strcount(appendchar)));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* strsize[] = { "push", "constant", itoa(i) };
|
||||||
|
char* mknew[] = { "call", "String.new", "1" };
|
||||||
|
appendlnbefore(blk, mkln(mknew));
|
||||||
|
appendlnbefore(blk, mkln(strsize));
|
||||||
|
free(strsize[2]);
|
||||||
|
|
||||||
|
return blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
LINE* pushthisadd() {
|
||||||
|
char* pushthisadd[] = { "push", "pointer", "0" };
|
||||||
|
return mkln(pushthisadd);
|
||||||
|
}
|
||||||
|
|
||||||
|
LINE* pushfalse() {
|
||||||
|
return pushconstant(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
LINEBLOCK* pushtrue() {
|
||||||
|
LINEBLOCK* blk = mklnblk(pushfalse());
|
||||||
|
appendln(blk, onetoken("not"));
|
||||||
|
return blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
LINEBLOCK* compilekeywordconst(SCOPE* s, TERM* t) {
|
||||||
|
if(!strcmp(t->string, "this")) return mklnblk(pushthisadd());
|
||||||
|
if(!strcmp(t->string, "false")) return mklnblk(pushfalse());
|
||||||
|
if(!strcmp(t->string, "true")) return pushtrue();
|
||||||
|
return mklnblk(pushconstant(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
LINEBLOCK* compilearrayitem(SCOPE* s, TERM* t) {
|
||||||
|
LINEBLOCK* blk = compileexpression(s, t->array->exp);
|
||||||
|
appendln(blk, pushvar(s, t->array->name));
|
||||||
|
|
||||||
|
appendln(blk, onetoken("add"));
|
||||||
|
|
||||||
|
appendln(blk, popthatadd());
|
||||||
|
appendln(blk, pushthat());
|
||||||
|
|
||||||
|
return blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
LINEBLOCK* compilecallln(SCOPE* s, SUBROUTDEC* d, SUBROUTCALL* call) {
|
||||||
|
LINE* ln = mkline(3);
|
||||||
|
|
||||||
|
addtoken(ln, ezheapstr("call"));
|
||||||
|
|
||||||
|
addtoken(ln, dotlabel(d->class->name, call->name));
|
||||||
|
|
||||||
|
int count = countexpressions(call->parameters);
|
||||||
|
if(d->subroutclass == method)
|
||||||
|
count++;
|
||||||
|
addtoken(ln, itoa(count));
|
||||||
|
|
||||||
|
return mklnblk(ln);
|
||||||
|
}
|
||||||
|
|
||||||
|
LINEBLOCK* compilesubroutcall(SCOPE* s, SUBROUTCALL* call) {
|
||||||
|
VAR* v;
|
||||||
|
SUBROUTDEC* d = getsubroutdecfromcall(s, call, &v);
|
||||||
|
LINEBLOCK* blk = compilecallln(s, d, call);
|
||||||
|
|
||||||
|
if(call->parameters != NULL)
|
||||||
|
blk = mergelnblks(compileexplist(s, call->parameters), blk);
|
||||||
|
|
||||||
|
if(d->subroutclass == method) {
|
||||||
|
if(call->parentname == NULL)
|
||||||
|
appendlnbefore(blk, pushthisadd());
|
||||||
|
else
|
||||||
|
appendlnbefore(blk, pushvarraw(s, v));
|
||||||
|
}
|
||||||
|
|
||||||
|
// void functions always return 0
|
||||||
|
// therefore must be thrown away
|
||||||
|
if(!strcmp(d->type, "void")) {
|
||||||
|
appendln(blk, poptemp());
|
||||||
|
}
|
||||||
|
|
||||||
|
return blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
LINEBLOCK* pushunaryopterm(SCOPE* s, TERM* t) {
|
||||||
|
LINEBLOCK* blk = compileexpression(s, t->expression);
|
||||||
|
LINE* neg;
|
||||||
|
if(t->unaryop == '-')
|
||||||
|
neg = onetoken("neg");
|
||||||
|
else
|
||||||
|
neg = onetoken("not");
|
||||||
|
appendln(blk, neg);
|
||||||
|
return blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
LINEBLOCK* compileterm(SCOPE* s, TERM* t) {
|
||||||
|
if(t->type == varname) return mklnblk(pushvar(s, t->string));
|
||||||
|
if(t->type == intconstant) return mklnblk(pushconstant(t->integer));
|
||||||
|
if(t->type == stringconstant) return compilestrconst(t->string);
|
||||||
|
if(t->type == keywordconstant) return compilekeywordconst(s, t);
|
||||||
|
if(t->type == arrayitem) return compilearrayitem(s, t);
|
||||||
|
if(t->type == subroutcall) return compilesubroutcall(s, t->call);
|
||||||
|
if(t->type == innerexpression) return compileexpression(s, t->expression);
|
||||||
|
return pushunaryopterm(s, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dealing with whole expressions
|
||||||
|
LINEBLOCK* compileexpression(SCOPE* s, TERM* e) {
|
||||||
|
LINEBLOCK* blk = NULL;
|
||||||
|
if(e != NULL) {
|
||||||
|
while(true) {
|
||||||
|
blk = mergelnblks(blk, compileterm(s, e));
|
||||||
|
if(e->next != NULL) {
|
||||||
|
appendln(blk, mathopln(e->op));
|
||||||
|
e = e->next;
|
||||||
|
}
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
LINEBLOCK* compileexplist(SCOPE* s, EXPRESSIONLIST* explist) {
|
||||||
|
LINEBLOCK* head = NULL;
|
||||||
|
while(explist != NULL) {
|
||||||
|
head = mergelnblks(head, compileexpression(s, explist->expression));
|
||||||
|
explist = explist->next;
|
||||||
|
}
|
||||||
|
return head;
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef COMPILER_EXPRESSIONS_H
|
||||||
|
#define COMPILER_EXPRESSIONS_H
|
||||||
|
#include "vm-lines.h"
|
||||||
|
#include "compiler.h"
|
||||||
|
|
||||||
|
/* compiler-expressions
|
||||||
|
* Subroutines for dealing and compiling expressions and singular terms. */
|
||||||
|
|
||||||
|
// Dealing with singular terms
|
||||||
|
LINEBLOCK* compilesubroutcall(SCOPE* s, SUBROUTCALL* call);
|
||||||
|
|
||||||
|
// Dealing with whole expressions
|
||||||
|
LINEBLOCK* compileexpression(SCOPE* s, TERM* e);
|
||||||
|
LINEBLOCK* compileexplist(SCOPE* s, EXPRESSIONLIST* explist);
|
||||||
|
#endif
|
|
@ -0,0 +1,48 @@
|
||||||
|
#include "compiler-util.h"
|
||||||
|
|
||||||
|
LINE* opvarraw(SCOPE* s, char* op, VAR* v) {
|
||||||
|
char* tokens[] = { op, v->memsegment, itoa(v->index) };
|
||||||
|
return mksimpleln(tokens, strcount(tokens));
|
||||||
|
}
|
||||||
|
|
||||||
|
LINE* opvar(SCOPE* s, char* op, const char* name) {
|
||||||
|
VAR* v = getvar(s, name);
|
||||||
|
return opvarraw(s, op, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
LINE* pushvarraw(SCOPE*s, VAR* v) {
|
||||||
|
return opvarraw(s, "push", v);
|
||||||
|
}
|
||||||
|
|
||||||
|
LINE* pushvar(SCOPE* s, const char* name) {
|
||||||
|
return opvar(s, "push", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
LINE* popvar(SCOPE* s, const char* name) {
|
||||||
|
return opvar(s, "pop", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
LINE* poptemp() {
|
||||||
|
char* poptemp[] = { "pop", "temp", "0" };
|
||||||
|
return mksimpleln(poptemp, strcount(poptemp));
|
||||||
|
}
|
||||||
|
|
||||||
|
LINE* popthatadd() {
|
||||||
|
char* popthatadd[] = { "pop", "pointer", "1" };
|
||||||
|
return mksimpleln(popthatadd, strcount(popthatadd));
|
||||||
|
}
|
||||||
|
|
||||||
|
LINE* onetoken(char* str) {
|
||||||
|
LINE* ln = mkline(1);
|
||||||
|
addtoken(ln, ezheapstr(str));
|
||||||
|
ln->next = NULL;
|
||||||
|
return ln;
|
||||||
|
}
|
||||||
|
|
||||||
|
LINE* mksimpleln(char** tokens, int count) {
|
||||||
|
LINE* ln = mkline(count);
|
||||||
|
for(int i = 0; i < count; i++)
|
||||||
|
addtoken(ln, ezheapstr(tokens[i]));
|
||||||
|
ln->next = NULL;
|
||||||
|
return ln;
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef COMPILER_UTIL_H
|
||||||
|
#define COMPILER_UTIL_H
|
||||||
|
#include "vm-lines.h"
|
||||||
|
#include "compiler-scopes.h"
|
||||||
|
#include "compiler.h"
|
||||||
|
|
||||||
|
#define mkln(id) mksimpleln(id, strcount(id))
|
||||||
|
|
||||||
|
LINE* onetoken(char* str);
|
||||||
|
LINE* mksimpleln(char** tokens, int count);
|
||||||
|
|
||||||
|
LINE* pushvarraw(SCOPE*s, VAR* v);
|
||||||
|
LINE* pushvar(SCOPE* s, const char* name);
|
||||||
|
LINE* popvar(SCOPE* s, const char* name);
|
||||||
|
LINE* poptemp();
|
||||||
|
LINE* popthatadd();
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,9 +1,10 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
|
#include "compiler-util.h"
|
||||||
|
#include "compiler-expressions.h"
|
||||||
|
|
||||||
LINEBLOCK* compilestatements(COMPILER* c, SCOPE* s, STATEMENT* sts);
|
LINEBLOCK* compilestatements(COMPILER* c, SCOPE* s, STATEMENT* sts);
|
||||||
LINEBLOCK* compilesubroutcall(SCOPE* s, SUBROUTCALL* call);
|
|
||||||
LINEBLOCK* compileexpression(SCOPE* s, TERM* e);
|
LINEBLOCK* compileexpression(SCOPE* s, TERM* e);
|
||||||
|
|
||||||
int countparameters(PARAMETER* params) {
|
int countparameters(PARAMETER* params) {
|
||||||
|
@ -15,15 +16,6 @@ int countparameters(PARAMETER* params) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
int countexpressions(EXPRESSIONLIST* explist) {
|
|
||||||
int i = 0;
|
|
||||||
while(explist != NULL) {
|
|
||||||
i++;
|
|
||||||
explist = explist->next;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
int countlocalvars(VARDEC* decs) {
|
int countlocalvars(VARDEC* decs) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while(decs != NULL) {
|
while(decs != NULL) {
|
||||||
|
@ -37,13 +29,6 @@ int countlocalvars(VARDEC* decs) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* dotlabel(char* n1, char* n2) {
|
|
||||||
int sz = (strlen(n1) + strlen(n2) + 2) * sizeof(char);
|
|
||||||
char* result = (char*)malloc(sz);
|
|
||||||
sprintf(result, "%s.%s", n1, n2);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* mkcondlabel(char* name, int count) {
|
char* mkcondlabel(char* name, int count) {
|
||||||
int sz = (strlen(name) + countplaces(count) + 1) * sizeof(char);
|
int sz = (strlen(name) + countplaces(count) + 1) * sizeof(char);
|
||||||
char* result = (char*)malloc(sz);
|
char* result = (char*)malloc(sz);
|
||||||
|
@ -51,257 +36,19 @@ char* mkcondlabel(char* name, int count) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
LINE* onetoken(char* str) {
|
|
||||||
LINE* ln = mkline(1);
|
|
||||||
addtoken(ln, ezheapstr(str));
|
|
||||||
ln->next = NULL;
|
|
||||||
return ln;
|
|
||||||
}
|
|
||||||
|
|
||||||
LINE* mksimpleln(char** tokens, int count) {
|
|
||||||
LINE* ln = mkline(count);
|
|
||||||
for(int i = 0; i < count; i++)
|
|
||||||
addtoken(ln, ezheapstr(tokens[i]));
|
|
||||||
ln->next = NULL;
|
|
||||||
return ln;
|
|
||||||
}
|
|
||||||
|
|
||||||
LINE* mathopln(char op) {
|
|
||||||
if(op == '+')
|
|
||||||
return onetoken("add");
|
|
||||||
if(op == '-')
|
|
||||||
return onetoken("sub");
|
|
||||||
if(op == '=')
|
|
||||||
return onetoken("eq");
|
|
||||||
if(op == '>')
|
|
||||||
return onetoken("gt");
|
|
||||||
if(op == '<')
|
|
||||||
return onetoken("lt");
|
|
||||||
if(op == '|')
|
|
||||||
return onetoken("or");
|
|
||||||
if(op == '&')
|
|
||||||
return onetoken("and");
|
|
||||||
if(op == '/') {
|
|
||||||
char* tokens[] = { "call", "Math.divide", "2" };
|
|
||||||
return mksimpleln(tokens, strcount(tokens));
|
|
||||||
}
|
|
||||||
char* tokens[] = { "call", "Math.multiply", "2" };
|
|
||||||
return mksimpleln(tokens, strcount(tokens));
|
|
||||||
}
|
|
||||||
|
|
||||||
LINE* pushconstant(int n) {
|
|
||||||
char* tokens[] = { "push", "constant", itoa(n) };
|
|
||||||
return mksimpleln(tokens, strcount(tokens));
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* pushunaryopterm(SCOPE* s, TERM* t) {
|
|
||||||
LINEBLOCK* blk = compileexpression(s, t->expression);
|
|
||||||
LINE* neg;
|
|
||||||
if(t->unaryop == '-')
|
|
||||||
neg = onetoken("neg");
|
|
||||||
else
|
|
||||||
neg = onetoken("not");
|
|
||||||
appendln(blk, neg);
|
|
||||||
return blk;
|
|
||||||
}
|
|
||||||
|
|
||||||
LINE* opvarraw(SCOPE* s, char* op, VAR* v) {
|
|
||||||
char* tokens[] = { op, v->memsegment, itoa(v->index) };
|
|
||||||
return mksimpleln(tokens, strcount(tokens));
|
|
||||||
}
|
|
||||||
|
|
||||||
LINE* opvar(SCOPE* s, char* op, const char* name) {
|
|
||||||
VAR* v = getvar(s, name);
|
|
||||||
return opvarraw(s, op, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
LINE* pushvarraw(SCOPE*s, VAR* v) {
|
|
||||||
return opvarraw(s, "push", v);
|
|
||||||
}
|
|
||||||
|
|
||||||
LINE* pushvar(SCOPE* s, const char* name) {
|
|
||||||
return opvar(s, "push", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
LINE* popvar(SCOPE* s, const char* name) {
|
|
||||||
return opvar(s, "pop", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
LINE* pushfalse() {
|
|
||||||
return pushconstant(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* pushtrue() {
|
|
||||||
LINEBLOCK* blk = mklnblk(pushfalse());
|
|
||||||
appendln(blk, onetoken("not"));
|
|
||||||
return blk;
|
|
||||||
}
|
|
||||||
|
|
||||||
LINE* pushthisadd() {
|
|
||||||
char* pushthisadd[] = { "push", "pointer", "0" };
|
|
||||||
return mksimpleln(pushthisadd, strcount(pushthisadd));
|
|
||||||
}
|
|
||||||
|
|
||||||
LINE* popthatadd() {
|
|
||||||
char* popthatadd[] = { "pop", "pointer", "1" };
|
|
||||||
return mksimpleln(popthatadd, strcount(popthatadd));
|
|
||||||
}
|
|
||||||
|
|
||||||
LINE* pushthatadd() {
|
LINE* pushthatadd() {
|
||||||
char* pushthatadd[] = { "push", "pointer", "1" };
|
char* pushthatadd[] = { "push", "pointer", "1" };
|
||||||
return mksimpleln(pushthatadd, strcount(pushthatadd));
|
return mkln(pushthatadd);
|
||||||
}
|
}
|
||||||
|
|
||||||
LINE* popthat() {
|
LINE* popthat() {
|
||||||
char* popthat[] = { "pop", "that", "0" };
|
char* popthat[] = { "pop", "that", "0" };
|
||||||
return mksimpleln(popthat, strcount(popthat));
|
return mkln(popthat);
|
||||||
}
|
|
||||||
|
|
||||||
LINE* pushthat() {
|
|
||||||
char* pushthat[] = { "push", "that", "0" };
|
|
||||||
return mksimpleln(pushthat, strcount(pushthat));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LINE* pushtemp() {
|
LINE* pushtemp() {
|
||||||
char* pushtemp[] = { "push", "temp", "0" };
|
char* pushtemp[] = { "push", "temp", "0" };
|
||||||
return mksimpleln(pushtemp, strcount(pushtemp));
|
return mkln(pushtemp);
|
||||||
}
|
|
||||||
|
|
||||||
LINE* poptemp() {
|
|
||||||
char* poptemp[] = { "pop", "temp", "0" };
|
|
||||||
return mksimpleln(poptemp, strcount(poptemp));
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* compilekeywordconst(SCOPE* s, TERM* t) {
|
|
||||||
if(!strcmp(t->string, "true")) return pushtrue();
|
|
||||||
if(!strcmp(t->string, "false")) return mklnblk(pushfalse());
|
|
||||||
if(!strcmp(t->string, "this")) return mklnblk(pushthisadd());
|
|
||||||
return mklnblk(pushconstant(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
char* toascii(char c) {
|
|
||||||
char* result = (char*)malloc(sizeof(char) * (countplaces(c) + 1));
|
|
||||||
sprintf(result, "%i", c);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* compilestrconst(char* str) {
|
|
||||||
if(str[0] == '\0')
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
char* pushchar[] = { "push", "constant", "" };
|
|
||||||
pushchar[2] = toascii(str[0]);
|
|
||||||
LINEBLOCK* blk = mklnblk(mksimpleln(pushchar, strcount(pushchar)));
|
|
||||||
free(pushchar[2]);
|
|
||||||
|
|
||||||
char* appendchar[] = { "call", "String.appendChar", "2" };
|
|
||||||
appendln(blk, mksimpleln(appendchar, strcount(appendchar)));
|
|
||||||
|
|
||||||
int i = 1;
|
|
||||||
char c;
|
|
||||||
while(c = str[i], c != '\0') {
|
|
||||||
pushchar[2] = toascii(c);
|
|
||||||
appendln(blk, mksimpleln(pushchar, strcount(pushchar)));
|
|
||||||
free(pushchar[2]);
|
|
||||||
appendln(blk, mksimpleln(appendchar, strcount(appendchar)));
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* strsize[] = { "push", "constant", itoa(i) };
|
|
||||||
char* mknew[] = { "call", "String.new", "1" };
|
|
||||||
appendlnbefore(blk, mksimpleln(mknew, strcount(mknew)));
|
|
||||||
appendlnbefore(blk, mksimpleln(strsize, strcount(strsize)));
|
|
||||||
free(strsize[2]);
|
|
||||||
|
|
||||||
return blk;
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* compilearrayitem(SCOPE* s, TERM* t) {
|
|
||||||
LINEBLOCK* blk = compileexpression(s, t->array->exp);
|
|
||||||
appendln(blk, pushvar(s, t->array->name));
|
|
||||||
|
|
||||||
appendln(blk, onetoken("add"));
|
|
||||||
|
|
||||||
appendln(blk, popthatadd());
|
|
||||||
appendln(blk, pushthat());
|
|
||||||
|
|
||||||
return blk;
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* compileterm(SCOPE* s, TERM* t) {
|
|
||||||
if(t->type == intconstant) return mklnblk(pushconstant(t->integer));
|
|
||||||
if(t->type == unaryopterm) return pushunaryopterm(s, t);
|
|
||||||
if(t->type == innerexpression) return compileexpression(s, t->expression);
|
|
||||||
if(t->type == varname) return mklnblk(pushvar(s, t->string));
|
|
||||||
if(t->type == subroutcall) return compilesubroutcall(s, t->call);
|
|
||||||
if(t->type == keywordconstant) return compilekeywordconst(s, t);
|
|
||||||
if(t->type == stringconstant) return compilestrconst(t->string);
|
|
||||||
return compilearrayitem(s, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* compileexpression(SCOPE* s, TERM* e) {
|
|
||||||
LINEBLOCK* blk = compileterm(s, e);
|
|
||||||
TERM* curr = e->next;
|
|
||||||
if(curr != NULL) {
|
|
||||||
while(true) {
|
|
||||||
blk = mergelnblks(blk, compileterm(s, curr));
|
|
||||||
if(curr->next != NULL) {
|
|
||||||
appendln(blk, mathopln(curr->op));
|
|
||||||
curr = curr->next;
|
|
||||||
}
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
appendln(blk, mathopln(e->op));
|
|
||||||
}
|
|
||||||
return blk;
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* compileexplist(SCOPE* s, EXPRESSIONLIST* explist) {
|
|
||||||
LINEBLOCK* head = NULL;
|
|
||||||
while(explist != NULL) {
|
|
||||||
head = mergelnblks(head, compileexpression(s, explist->expression));
|
|
||||||
explist = explist->next;
|
|
||||||
}
|
|
||||||
return head;
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* compilecallln(SCOPE* s, SUBROUTDEC* d, SUBROUTCALL* call) {
|
|
||||||
LINE* ln = mkline(3);
|
|
||||||
|
|
||||||
addtoken(ln, ezheapstr("call"));
|
|
||||||
|
|
||||||
addtoken(ln, dotlabel(d->class->name, call->name));
|
|
||||||
|
|
||||||
int count = countexpressions(call->parameters);
|
|
||||||
if(d->subroutclass == method)
|
|
||||||
count++;
|
|
||||||
addtoken(ln, itoa(count));
|
|
||||||
|
|
||||||
return mklnblk(ln);
|
|
||||||
}
|
|
||||||
|
|
||||||
LINEBLOCK* compilesubroutcall(SCOPE* s, SUBROUTCALL* call) {
|
|
||||||
VAR* v;
|
|
||||||
SUBROUTDEC* d = getsubroutdecfromcall(s, call, &v);
|
|
||||||
LINEBLOCK* blk = compilecallln(s, d, call);
|
|
||||||
|
|
||||||
if(call->parameters != NULL)
|
|
||||||
blk = mergelnblks(compileexplist(s, call->parameters), blk);
|
|
||||||
|
|
||||||
if(d->subroutclass == method) {
|
|
||||||
if(call->parentname == NULL)
|
|
||||||
appendlnbefore(blk, pushthisadd());
|
|
||||||
else
|
|
||||||
appendlnbefore(blk, pushvarraw(s, v));
|
|
||||||
}
|
|
||||||
|
|
||||||
// void functions always return 0
|
|
||||||
// therefore must be thrown away
|
|
||||||
if(!strcmp(d->type, "void")) {
|
|
||||||
appendln(blk, poptemp());
|
|
||||||
}
|
|
||||||
|
|
||||||
return blk;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LINEBLOCK* compileret(SCOPE* s, TERM* e) {
|
LINEBLOCK* compileret(SCOPE* s, TERM* e) {
|
||||||
|
@ -311,7 +58,7 @@ LINEBLOCK* compileret(SCOPE* s, TERM* e) {
|
||||||
// void subroutdecs return 0
|
// void subroutdecs return 0
|
||||||
if(e == NULL) {
|
if(e == NULL) {
|
||||||
char* tokens[] = { "push", "constant", "0" };
|
char* tokens[] = { "push", "constant", "0" };
|
||||||
appendlnbefore(blk, mksimpleln(tokens, strcount(tokens)));
|
appendlnbefore(blk, mkln(tokens));
|
||||||
} else
|
} else
|
||||||
blk = mergelnblks(compileexpression(s, e), blk);
|
blk = mergelnblks(compileexpression(s, e), blk);
|
||||||
|
|
||||||
|
@ -329,14 +76,14 @@ LINEBLOCK* compileif(COMPILER* c, SCOPE* s, IFSTATEMENT* st) {
|
||||||
|
|
||||||
char* truelabel = mkcondlabel("IF_TRUE", mycount);
|
char* truelabel = mkcondlabel("IF_TRUE", mycount);
|
||||||
char* ifgoto[] = { "if-goto", truelabel };
|
char* ifgoto[] = { "if-goto", truelabel };
|
||||||
appendln(blk, mksimpleln(ifgoto, strcount(ifgoto)));
|
appendln(blk, mkln(ifgoto));
|
||||||
|
|
||||||
char* falselabel = mkcondlabel("IF_FALSE", mycount);
|
char* falselabel = mkcondlabel("IF_FALSE", mycount);
|
||||||
char* gotofalse[] = { "goto", falselabel };
|
char* gotofalse[] = { "goto", falselabel };
|
||||||
appendln(blk, mksimpleln(gotofalse, strcount(gotofalse)));
|
appendln(blk, mkln(gotofalse));
|
||||||
|
|
||||||
char* truelabelln[] = { "label", truelabel };
|
char* truelabelln[] = { "label", truelabel };
|
||||||
appendln(blk, mksimpleln(truelabelln, strcount(truelabelln)));
|
appendln(blk, mkln(truelabelln));
|
||||||
|
|
||||||
blk = mergelnblks(blk, compilestatements(c, s, st->base->statements));
|
blk = mergelnblks(blk, compilestatements(c, s, st->base->statements));
|
||||||
|
|
||||||
|
@ -345,16 +92,16 @@ LINEBLOCK* compileif(COMPILER* c, SCOPE* s, IFSTATEMENT* st) {
|
||||||
if(haselse) {
|
if(haselse) {
|
||||||
endlabel = mkcondlabel("IF_END", mycount);
|
endlabel = mkcondlabel("IF_END", mycount);
|
||||||
char* endgoto[] = { "goto", endlabel };
|
char* endgoto[] = { "goto", endlabel };
|
||||||
appendln(blk, mksimpleln(endgoto, strcount(endgoto)));
|
appendln(blk, mkln(endgoto));
|
||||||
}
|
}
|
||||||
|
|
||||||
char* falselabelln[] = { "label", falselabel};
|
char* falselabelln[] = { "label", falselabel};
|
||||||
appendln(blk, mksimpleln(falselabelln, strcount(falselabelln)));
|
appendln(blk, mkln(falselabelln));
|
||||||
|
|
||||||
if(haselse) {
|
if(haselse) {
|
||||||
blk = mergelnblks(blk, compilestatements(c, s, st->elsestatements));
|
blk = mergelnblks(blk, compilestatements(c, s, st->elsestatements));
|
||||||
char* endlabelln[] = { "label", endlabel };
|
char* endlabelln[] = { "label", endlabel };
|
||||||
appendln(blk, mksimpleln(endlabelln, strcount(endlabelln)));
|
appendln(blk, mkln(endlabelln));
|
||||||
}
|
}
|
||||||
|
|
||||||
return blk;
|
return blk;
|
||||||
|
@ -371,21 +118,21 @@ LINEBLOCK* compilewhile(COMPILER* c, SCOPE* s, CONDSTATEMENT* w) {
|
||||||
|
|
||||||
char* explabel = mkcondlabel("WHILE_EXP", mycount);
|
char* explabel = mkcondlabel("WHILE_EXP", mycount);
|
||||||
char* explabelln[] = { "label", explabel };
|
char* explabelln[] = { "label", explabel };
|
||||||
appendlnbefore(blk, mksimpleln(explabelln, strcount(explabelln)));
|
appendlnbefore(blk, mkln(explabelln));
|
||||||
|
|
||||||
appendln(blk, onetoken("not"));
|
appendln(blk, onetoken("not"));
|
||||||
|
|
||||||
char* endlabel = mkcondlabel("WHILE_END", mycount);
|
char* endlabel = mkcondlabel("WHILE_END", mycount);
|
||||||
char* ifgoto[] = { "if-goto", endlabel };
|
char* ifgoto[] = { "if-goto", endlabel };
|
||||||
appendln(blk, mksimpleln(ifgoto, strcount(ifgoto)));
|
appendln(blk, mkln(ifgoto));
|
||||||
|
|
||||||
blk = mergelnblks(blk, compilestatements(c, s, w->statements));
|
blk = mergelnblks(blk, compilestatements(c, s, w->statements));
|
||||||
|
|
||||||
char* gotoln[] = { "goto", explabel };
|
char* gotoln[] = { "goto", explabel };
|
||||||
appendln(blk, mksimpleln(gotoln, strcount(gotoln)));
|
appendln(blk, mkln(gotoln));
|
||||||
|
|
||||||
char* endlabelln[] = { "label", endlabel };
|
char* endlabelln[] = { "label", endlabel };
|
||||||
appendln(blk, mksimpleln(endlabelln, strcount(endlabelln)));
|
appendln(blk, mkln(endlabelln));
|
||||||
|
|
||||||
return blk;
|
return blk;
|
||||||
}
|
}
|
||||||
|
@ -439,7 +186,7 @@ LINEBLOCK* compilefunbody(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTBODY* b) {
|
||||||
|
|
||||||
LINE* mksubdeclabel(CLASS* c, SUBROUTDEC* sd) {
|
LINE* mksubdeclabel(CLASS* c, SUBROUTDEC* sd) {
|
||||||
char* labelstrs[] = { "function", dotlabel(c->name, sd->name), itoa(countlocalvars(sd->body->vardecs)) };
|
char* labelstrs[] = { "function", dotlabel(c->name, sd->name), itoa(countlocalvars(sd->body->vardecs)) };
|
||||||
LINE* label = mksimpleln(labelstrs, strcount(labelstrs));
|
LINE* label = mkln(labelstrs);
|
||||||
free(labelstrs[1]);
|
free(labelstrs[1]);
|
||||||
free(labelstrs[2]);
|
free(labelstrs[2]);
|
||||||
label->next = NULL;
|
label->next = NULL;
|
||||||
|
@ -485,9 +232,9 @@ LINEBLOCK* compileconstructor(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* con)
|
||||||
char* size[] = { "push", "constant", itoa(getobjsize(cl)) };
|
char* size[] = { "push", "constant", itoa(getobjsize(cl)) };
|
||||||
char* memalloc[] = { "call", "Memory.alloc", "1" };
|
char* memalloc[] = { "call", "Memory.alloc", "1" };
|
||||||
char* poppointer[] = { "pop", "pointer", "0" };
|
char* poppointer[] = { "pop", "pointer", "0" };
|
||||||
appendln(blk, mksimpleln(size, strcount(size)));
|
appendln(blk, mkln(size));
|
||||||
appendln(blk, mksimpleln(memalloc, strcount(memalloc)));
|
appendln(blk, mkln(memalloc));
|
||||||
appendln(blk, mksimpleln(poppointer, strcount(poppointer)));
|
appendln(blk, mkln(poppointer));
|
||||||
free(size[2]);
|
free(size[2]);
|
||||||
|
|
||||||
if(con->body != NULL)
|
if(con->body != NULL)
|
||||||
|
@ -502,8 +249,8 @@ LINEBLOCK* compilemethod(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* m) {
|
||||||
|
|
||||||
char* pusharg0[] = { "push", "argument", "0" };
|
char* pusharg0[] = { "push", "argument", "0" };
|
||||||
char* poppointer[] = { "pop", "pointer", "0" };
|
char* poppointer[] = { "pop", "pointer", "0" };
|
||||||
appendln(blk, mksimpleln(pusharg0, strcount(pusharg0)));
|
appendln(blk, mkln(pusharg0));
|
||||||
appendln(blk, mksimpleln(poppointer, strcount(poppointer)));
|
appendln(blk, mkln(poppointer));
|
||||||
|
|
||||||
if(m->body != NULL)
|
if(m->body != NULL)
|
||||||
return mergelnblks(blk, compilefunbody(c, s, cl, m->body));
|
return mergelnblks(blk, compilefunbody(c, s, cl, m->body));
|
||||||
|
|
|
@ -5,12 +5,14 @@
|
||||||
#include "vm-lines.h"
|
#include "vm-lines.h"
|
||||||
#include "compiler-scopes.h"
|
#include "compiler-scopes.h"
|
||||||
|
|
||||||
|
struct scope;
|
||||||
|
|
||||||
typedef struct compiler {
|
typedef struct compiler {
|
||||||
pthread_mutex_t ifmutex;
|
pthread_mutex_t ifmutex;
|
||||||
pthread_mutex_t whilemutex;
|
pthread_mutex_t whilemutex;
|
||||||
pthread_mutex_t staticmutex;
|
pthread_mutex_t staticmutex;
|
||||||
CLASS* classes;
|
CLASS* classes;
|
||||||
SCOPE* globalscope;
|
struct scope* globalscope;
|
||||||
} COMPILER;
|
} COMPILER;
|
||||||
|
|
||||||
COMPILER* mkcompiler(CLASS* classes);
|
COMPILER* mkcompiler(CLASS* classes);
|
||||||
|
|
|
@ -40,6 +40,13 @@ char* itoa(int i) {
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* dotlabel(char* n1, char* n2) {
|
||||||
|
int sz = (strlen(n1) + strlen(n2) + 2) * sizeof(char);
|
||||||
|
char* result = (char*)malloc(sz);
|
||||||
|
sprintf(result, "%s.%s", n1, n2);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
STRINGLIST* onestr(const char* str) {
|
STRINGLIST* onestr(const char* str) {
|
||||||
STRINGLIST* strlist = (STRINGLIST*)malloc(sizeof(STRINGLIST));
|
STRINGLIST* strlist = (STRINGLIST*)malloc(sizeof(STRINGLIST));
|
||||||
strlist->content = ezheapstr(str);
|
strlist->content = ezheapstr(str);
|
||||||
|
|
|
@ -27,6 +27,7 @@ char* ezheapstr(const char* str);
|
||||||
int countplaces(int n);
|
int countplaces(int n);
|
||||||
char* itoa(int i);
|
char* itoa(int i);
|
||||||
void* copy(void* v, int size);
|
void* copy(void* v, int size);
|
||||||
|
char* dotlabel(char* n1, char* n2);
|
||||||
|
|
||||||
STRINGLIST* onestr(const char* str);
|
STRINGLIST* onestr(const char* str);
|
||||||
STRINGLIST* initstrlist(const char** strs, int count);
|
STRINGLIST* initstrlist(const char** strs, int count);
|
||||||
|
|
Loading…
Reference in New Issue