summaryrefslogtreecommitdiff
path: root/cgen.c
diff options
context:
space:
mode:
Diffstat (limited to 'cgen.c')
-rw-r--r--cgen.c166
1 files changed, 166 insertions, 0 deletions
diff --git a/cgen.c b/cgen.c
new file mode 100644
index 0000000..46ea085
--- /dev/null
+++ b/cgen.c
@@ -0,0 +1,166 @@
+#include "cgen.h"
+#include "fn.h"
+#include "lex.h"
+#include "lit.h"
+#include "parse.h"
+#include "storage.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+void cgen_free(struct cgen *c)
+{
+}
+
+const char *cgen_sz(const size_t sz)
+{
+ switch (sz)
+ {
+ case 1:
+ return "b";
+ case 2:
+ return "h";
+ case 4:
+ return "w";
+ case 8:
+ return "l";
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+const char *cgen_type(const struct type *t)
+{
+ switch (t->sz)
+ {
+ case 1:
+ return t->sign ? "b" : "ub";
+ case 2:
+ return t->sign ? "h" : "uh";
+ case 4:
+ return t->sign ? "w" : "uw";
+ case 8:
+ return t->sign ? "l" : "ul";
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+const char *cgen_abity(const struct type *t)
+{
+ switch (t->sz)
+ {
+ case 1:
+ return t->sign ? "b" : "ub";
+ case 2:
+ return t->sign ? "h" : "uh";
+ case 4:
+ return "w";
+ case 8:
+ return "l";
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+const char *cgen_load(const struct type *t)
+{
+ switch (t->sz)
+ {
+ case 1:
+ return t->sign ? "sb" : "ub";
+ case 2:
+ return t->sign ? "sh" : "uh";
+ case 4:
+ return t->sign ? "sw" : "uw";
+ case 8:
+ return "l";
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+int cgen_param(const struct fn *fn, const struct stentry *e)
+{
+ const struct pr *pr = fn->pr;
+ const char *name = e->tk->s;
+
+ for (size_t i = 0; i < pr->nparams; i++)
+ if (!strcmp(pr->params[i].tk->s, name))
+ return 1;
+
+ return 0;
+}
+
+int cgen_global(const struct fn *fn, const struct stentry *e)
+{
+ const struct storage *ws = fn->ws, *gl = fn->gl;
+ const struct pr *pr = fn->pr;
+ const struct param *ret = pr->ret;
+ const char *name = e->tk->s;
+
+ /* A variable is only global if it is defined inside the global
+ * variables section ("gl"), or if it is not listed on the working
+ * storage section ("ws"), as a function parameter or a return value. */
+
+ if (gl)
+ for (size_t i = 0; i < gl->nentries; i++)
+ if (!strcmp(gl->entries[i].tk->s, name))
+ return 1;
+
+ if (cgen_param(fn, e))
+ return 0;
+
+ if (ret && !strcmp(ret->tk->s, name))
+ return 0;
+
+ if (ws)
+ for (size_t i = 0; i < ws->nentries; i++)
+ if (!strcmp(ws->entries[i].tk->s, name))
+ return 0;
+
+ return 1;
+}
+
+static void pushfmt(const char *type, const char *fmt)
+{
+ printf("data $____fmt%s = { b \"%s\" , b 0 }\n", type, fmt);
+}
+
+int cgen(const struct ast *ast, struct cgen *c)
+{
+ /* generate literals to use with printf(3) */
+ pushfmt("b", "%hhd");
+ pushfmt("h", "%hd");
+ pushfmt("w", "%d");
+ pushfmt("l", "%ld");
+ pushfmt("ub", "%hhu");
+ pushfmt("uh", "%hu");
+ pushfmt("uw", "%u");
+ pushfmt("ul", "%lu");
+ pushfmt("bx", "%#hhx");
+ pushfmt("hx", "%#hx");
+ pushfmt("wx", "%#x");
+ pushfmt("lx", "%#lx");
+
+ for (const struct lit *l = ast->lits; l; l = l->next)
+ if (lit_cgen(l))
+ return-1;
+
+ for (size_t i = 0; i < ast->nfns; i++)
+ if (fn_cgen((c->fn = &ast->fns[i]), c))
+ return -1;
+
+ return 0;
+}