diff --git a/Makefile b/Makefile index e0a4639..8df8b4c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -FILES = parser.c main.c +FILES = parser.c main.c translator.c INCLUDES = -I. -CFLAGS = -std=c99 +CFLAGS = -std=c99 -g OUTFILE = vmtranslator main: ${FILES} diff --git a/main.c b/main.c index 3249d52..9cc0456 100644 --- a/main.c +++ b/main.c @@ -2,6 +2,7 @@ #include #include #include "parser.h" +#include "translator.h" int main(int argc, char* argv[]) { if(argc < 2) { @@ -23,8 +24,16 @@ int main(int argc, char* argv[]) { // parsing struct line** lns = parse(input, lncount, widestln, maxtokens); fclose(input); + + // translating + int asmind = 0; + struct asmln** asmlns = translate(lns, lncount, &asmind); // printing + for(int i = 0; i < asmind; i++) { + printf("%s\n", asmlns[i]->instr); + } + /* for(int i = 0; i < lncount; i++) { int tkcount = lns[i]->tokenscount; for(int j = 0; j < tkcount; j++) { @@ -32,6 +41,7 @@ int main(int argc, char* argv[]) { } printf("\n"); } + */ // freeing freelns(lns, lncount); diff --git a/parser.h b/parser.h index da75d49..4c69a97 100644 --- a/parser.h +++ b/parser.h @@ -1,6 +1,5 @@ -#include -#include - +#ifndef parser +#define parser struct line { char** tokens; int tokenscount; @@ -10,3 +9,4 @@ struct line { void getinfo(FILE* input, int* lncount, int* widestln, int* maxtokens); void freelns(struct line** lns, int lnscount); struct line** parse(FILE* input, int lncount, int widestln, int maxtokens); +#endif diff --git a/translator.c b/translator.c new file mode 100644 index 0000000..4f8ff48 --- /dev/null +++ b/translator.c @@ -0,0 +1,190 @@ +#include +#include +#include +#include +#include "translator.h" + +enum operation { push, pop }; + +enum operation getop(struct line* ln) { + char* tok = ln->tokens[0]; + if(strcmp(tok, "push") == 0) + return push; + if(strcmp(tok, "pop") == 0) + return pop; + fprintf(stderr, "Invalid operation '%s'; line %i", tok, ln->truen); + exit(1); +} + +char* heapstr(const char* input) { + char* newstr = (char*)malloc(sizeof(char)*(strlen(input)+1)); + strcpy(newstr, input); + return newstr; +} + +char* switchseg(struct line* ln) { + char* seg = ln->tokens[1]; + if(strcmp(seg, "local") == 0) + return heapstr("@LCL"); + if(strcmp(seg, "argument") == 0) + return heapstr("@ARG"); + if(strcmp(seg, "this") == 0) + return heapstr("@THIS"); + if(strcmp(seg, "that") == 0) + return heapstr("@THAT"); +} + +// produce comment as follows: +// pop/push segment i +char* mkcom(struct line* ln, int indlen) { + int comlen = sizeof(char) * (strlen(ln->tokens[0]) + strlen(ln->tokens[1]) + indlen + 6); + char* comment = (char*)malloc(comlen); + snprintf(comment, comlen, "// %s %s %s", ln->tokens[0], ln->tokens[1], ln->tokens[2]); + return comment; +} + +void checkind(struct line* ln, int indsz) { + for(int i = 0; i < indsz; i++) { + if(!isdigit(ln->tokens[2][i])) { + fprintf(stderr, "Invalid index '%s'; line %i\n", ln->tokens[2], ln->truen); + exit(1); + } + } +} + +char* mkind(char* ind, int indsz) { + int newsz = sizeof(char) * (indsz + 2); + char* newind = (char*)malloc(newsz); + snprintf(newind, newsz, "@%s", ind); + return newind; +} + +void checkasmsize(int* size, struct asmln** lns, int targ) { + if(targ >= (*size)) { + printf("realloc'd"); + (*size)=targ*2; + (*lns) = realloc((*lns), (*size)); + } +} + +struct asmln* mkasmln(struct line* ln, char* content) { + struct asmln* newln = (struct asmln*)malloc(sizeof(struct asmln)); + newln->truen = ln->truen; + newln->instr = content; + return newln; +} + +void startpoppush(struct line* ln, struct asmln** asmlns, int* asmind) { + int asmi = *asmind; + + // //operation segment i + int indlen = strlen(ln->tokens[2]); + asmlns[asmi] = mkasmln(ln, mkcom(ln, indlen)); + asmi++; + + // @segment + asmlns[asmi] = mkasmln(ln, switchseg(ln)); + asmi++; + + // D=M + asmlns[asmi] = mkasmln(ln, heapstr("D=M")); + asmi++; + + // @i + checkind(ln, indlen); + asmlns[asmi] = mkasmln(ln, mkind(ln->tokens[2], indlen)); + asmi++; + + (*asmind) = asmi; +} + +void mkpush(struct line* ln, struct asmln** asmlns, int* asmind, int* asmsize) { + int asmi = *asmind; + int totalinstrs = 11; + checkasmsize(asmsize, asmlns, sizeof(struct asmln*)*(asmi+totalinstrs)); + + startpoppush(ln, asmlns, &asmi); + + const int instcount = 7; + const char* instrs[] = { + "A=D+A", + "D=M", + "@SP", + "A=M", + "M=D", + "@SP", + "M=M+1" + }; + + for(int i = 0; i < instcount; i++) { + asmlns[asmi] = mkasmln(ln, heapstr(instrs[i])); + asmi++; + } + + (*asmind) = asmi; +} + +void mkpop(struct line* ln, struct asmln** asmlns, int* asmind, int* asmsize) { + int asmi = *asmind; + int finalasmi = 14; + checkasmsize(asmsize, asmlns, sizeof(struct asmln*)*(asmi+finalasmi)); + + startpoppush(ln, asmlns, &asmi); + + const int instcount = 10; + const char* instrs[] = { + "D=D+A", + "@R13", + "M=D", + "@SP", + "M=M-1", + "A=M", + "D=M", + "@R13", + "A=M", + "M=D" + }; + + for(int i = 0; i < instcount; i++) { + asmlns[asmi] = mkasmln(ln, heapstr(instrs[i])); + asmi++; + } + + (*asmind) = asmi; +} + +void mkpoppush(struct line* ln, struct asmln** asmlns, int* asmind, int* asmsize, enum operation op) { + if(op == push) + mkpush(ln, asmlns, asmind, asmsize); + else if(op == pop) + mkpop(ln, asmlns, asmind, asmsize); +} + +void checkopamnt(struct line* ln) { + if(ln->tokenscount < 2) { + fprintf(stderr, "Missing memory segment; line %i", ln->truen); + exit(1); + } + if(ln->tokenscount < 3) { + fprintf(stderr, "Missing operation index; line %i", ln->truen); + exit(1); + } +} + +struct asmln** translate(struct line** lns, int lnscount, int* asmind) { + int sizebet = sizeof(struct asmln*)*(lnscount * 15); + int asmi = (*asmind); + struct asmln** asmlns = (struct asmln**)malloc(sizebet); + + for(int i = 0; i < lnscount; i++) { + struct line* ln = lns[i]; + enum operation op = getop(ln); + if(op == pop || op == push) { + checkopamnt(ln); + mkpoppush(ln, asmlns, &asmi, &sizebet, op); + } + } + + (*asmind) = asmi; + return asmlns; +} diff --git a/translator.h b/translator.h new file mode 100644 index 0000000..62832c5 --- /dev/null +++ b/translator.h @@ -0,0 +1,10 @@ +#ifndef translator +#define translator +#include "parser.h" +struct asmln { + char* instr; + int truen; +}; + +struct asmln** translate(struct line** lns, int lnscount, int* asmind); +#endif