diff options
Diffstat (limited to 'sem3/osc/miniproject/cnasm/codegen.c')
-rw-r--r-- | sem3/osc/miniproject/cnasm/codegen.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/sem3/osc/miniproject/cnasm/codegen.c b/sem3/osc/miniproject/cnasm/codegen.c new file mode 100644 index 0000000..c995df9 --- /dev/null +++ b/sem3/osc/miniproject/cnasm/codegen.c @@ -0,0 +1,132 @@ +#include "codegen.h" + +#include <stdio.h> +#include <stdbool.h> +#include <stdlib.h> +#include "ast.h" + +static void gencondjmp(FILE *f, cond_t *c, bool neg) { + uint8_t cmp = neg ? c->cmp^0x80 : c->cmp; + fprintf(f, "cmp %s %s\n", c->a, c->b); + switch(cmp) { + case CEQ: + fprintf(f, "je "); + break; + case CNEQ: + fprintf(f, "jne "); + break; + case CGT: + fprintf(f, "jg "); + break; + case CLT: + fprintf(f, "jl "); + break; + case CLEQ: + fprintf(f, "jle "); + break; + case CGEQ: + fprintf(f, "jge "); + break; + default: + fprintf(stderr, "Invalid cmp type %x", cmp); + fprintf(f, "jmp "); + } +} + +static void genif(FILE *f, struct genctx *ctx, ast_node_t *n) { + bool doElse = n->flowctrl.iffalse; + // Create conditional jump + gencondjmp(f, n->flowctrl.condition, true); + if( doElse ) { + fprintf(f, "else_%d\n", ctx->nested); + } else { + fprintf(f, "end_%d\n", ctx->nested); + } + + struct genctx octx = { ctx->nested+1 }; + // Paste code + gentree(f, &octx, n->flowctrl.iftrue); + + // Do else + if( doElse ) { + fprintf(f, "jmp end_%d\n", ctx->nested); + fprintf(f, "else_%d:\n", ctx->nested); + gentree(f, &octx, n->flowctrl.iffalse); + } + + // End block + fprintf(f, "end_%d:\n", ctx->nested); +} + +static void genwhile(FILE *f, struct genctx *ctx, ast_node_t *n) { + // Create loop label + fprintf(f, "loop_%d:\n", ctx->nested); + + // Create conditional jump + gencondjmp(f, n->flowctrl.condition, true); + fprintf(f, "end_%d\n", ctx->nested); + + struct genctx octx = { ctx->nested+1 }; + // Paste code + gentree(f, &octx, n->flowctrl.iftrue); + + // Jump to start + fprintf(f, "jmp loop_%d\n", ctx->nested); + + // End block + fprintf(f, "end_%d:\n", ctx->nested); +} + +static void genfor(FILE *f, struct genctx *ctx, ast_node_t *n) { + // Do pre stuff + fprintf(f, "%s\n", n->forloop.pre); + + // Create loop label + fprintf(f, "loop_%d:\n", ctx->nested); + + // Create conditional jump + gencondjmp(f, n->flowctrl.condition, true); + fprintf(f, "end_%d\n", ctx->nested); + + struct genctx octx = { ctx->nested+1 }; + // Paste code + gentree(f, &octx, n->forloop.stuff); + + // Do inc stuff + fprintf(f, "%s\n", n->forloop.inc); + // Jump to start + fprintf(f, "jmp loop_%d\n", ctx->nested); + + // End block + fprintf(f, "end_%d:\n", ctx->nested); +} + +void gentree(FILE *f, struct genctx *ctx, ast_node_t *n) { + if( !n ) { + return; + } + if( ctx == NULL ) { + ctx = malloc(sizeof(struct genctx)); + ctx->nested = 0; + } + switch(n->t) { + case TSTM_LIST: + gentree(f, ctx, n->list.children[0]); + gentree(f, ctx, n->list.children[1]); + break; + case TIF: + genif(f, ctx, n); + break; + case TIDENT: + fprintf(f, "%s\n", n->ident); + break; + case TFOR: + genfor(f, ctx, n); + break; + case TWHILE: + genwhile(f, ctx, n); + break; + default: + return; + } +} |