aboutsummaryrefslogtreecommitdiff
path: root/end.c
diff options
context:
space:
mode:
Diffstat (limited to 'end.c')
-rw-r--r--end.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/end.c b/end.c
new file mode 100644
index 0000000..b9ad790
--- /dev/null
+++ b/end.c
@@ -0,0 +1,80 @@
+#include "end.h"
+#include "errloc.h"
+#include "fn.h"
+#include "stmt.h"
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void end_free(struct end *e)
+{
+}
+
+int end_cgen(const struct end *e, struct cgen *c)
+{
+ const struct stmt *s = &c->fn->stmts[e->block_i];
+
+ if (!s->end)
+ {
+ fprintf(stderr, "%s: unreachable\n", __func__);
+ return -1;
+ }
+ else if (s->end(s, c))
+ return -1;
+
+ printf("@__end%zu\n", e->block_i);
+ return 0;
+}
+
+int end(const struct lex *l, struct prv *p)
+{
+ struct pos *pos = &p->pos[p->i];
+ struct fn *fn = fn_cur(p);
+ size_t nst = fn->nstmts + 1, *bl, bl_i;
+ struct stmt *s;
+
+ if (!fn->nblocks)
+ {
+ errloc(p->stk, "unexpected \"end\" statement");
+ return -1;
+ }
+
+ bl_i = fn->blocks[fn->nblocks - 1];
+
+ if (fn->nblocks > 1)
+ {
+ if (!(bl = realloc(fn->blocks, (fn->nblocks - 1) * sizeof *bl)))
+ {
+ perror("realloc(3)");
+ return -1;
+ }
+
+ fn->blocks = bl;
+ }
+ else
+ {
+ free(fn->blocks);
+ fn->blocks = NULL;
+ }
+
+ fn->nblocks--;
+
+ if (!(s = realloc(fn->stmts, nst * sizeof *s)))
+ {
+ perror("realloc(3)");
+ return -1;
+ }
+
+ s[fn->nstmts++] = (struct stmt)
+ {
+ .type = END,
+ .u.end.block_i = bl_i
+ };
+
+ fn->stmts = s;
+ pos->seq = pos->stseq = stmts;
+ pos->step = stmts->steps;
+ p->stk = p->tk;
+ fprintf(stderr, "\t\tadding end statement, block index %zu\n", bl_i);
+ return 1;
+}