commit 8472620074ff6434c3dacafdb411b15794a42815
parent 732522cb68bf3fd61ad9e3003cb57d293c8b2762
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 20 Dec 2020 10:54:20 -0500
Add emit scaffolding
Diffstat:
7 files changed, 91 insertions(+), 3 deletions(-)
diff --git a/configure b/configure
@@ -5,6 +5,7 @@ eval ". $srcdir/config.sh"
harec() {
genrules harec \
src/check.c \
+ src/emit.c \
src/gen.c \
src/identifier.c \
src/lex.c \
diff --git a/include/emit.h b/include/emit.h
@@ -0,0 +1,7 @@
+#ifndef HAREC_EMIT_H
+#define HAREC_EMIT_H
+
+struct qbe_program;
+void emit(struct qbe_program *program, FILE *out);
+
+#endif
diff --git a/include/qbe.h b/include/qbe.h
@@ -185,10 +185,12 @@ struct qbe_program {
struct qbe_def *defs;
};
+void qbe_append_def(struct qbe_program *prog, struct qbe_def *def);
+
// The "i" family of functions take a list of qbe_values as the parameters to
// provide to the given instruction. The "l" family takes a printf-compatible
-// set of values to match with fmt to produce the label name (plus the ID
-// postfix, which is added for you).
+// set of values to match with fmt to produce a label (plus the ID postfix,
+// which is added for you).
void geni(struct qbe_statement *stmt, enum qbe_instr instr, ...);
void genl(struct qbe_statement *stmt, uint64_t *id, const char *fmt, ...);
void pushi(struct qbe_func *func, enum qbe_instr instr, ...);
diff --git a/src/emit.c b/src/emit.c
@@ -0,0 +1,60 @@
+#include <assert.h>
+#include <stdio.h>
+#include "emit.h"
+#include "qbe.h"
+
+static void
+emit_qtype(const struct qbe_type *type, FILE *out)
+{
+ switch (type->stype) {
+ case Q_BYTE:
+ case Q_HALF:
+ case Q_WORD:
+ case Q_LONG:
+ case Q_SINGLE:
+ case Q_DOUBLE:
+ fprintf(out, "%c ", (char)type->stype);
+ break;
+ case Q__VOID:
+ break; // no-op
+ case Q__AGGREGATE:
+ assert(0); // TODO
+ }
+}
+
+static void
+emit_func(struct qbe_def *def, FILE *out)
+{
+ assert(def->type == Q_FUNC);
+ // TODO: Parameters
+ fprintf(out, "%sfunction ", def->exported ? "export " : "");
+ emit_qtype(def->func.returns, out);
+ fprintf(out, "$%s() {\n", def->name); // TODO: Parameters
+ // TODO: Body
+ fprintf(out, "}\n\n");
+}
+
+static void
+emit_def(struct qbe_def *def, FILE *out)
+{
+ switch (def->type) {
+ case Q_TYPE:
+ assert(0); // TODO
+ case Q_FUNC:
+ emit_func(def, out);
+ break;
+ case Q_DATA:
+ assert(0); // TODO
+ }
+}
+
+void
+emit(struct qbe_program *program, FILE *out)
+{
+ struct qbe_def *def = program->defs;
+ assert(def); // At least one
+ while (def) {
+ emit_def(def, out);
+ def = def->next;
+ }
+}
diff --git a/src/gen.c b/src/gen.c
@@ -178,6 +178,8 @@ gen_function_decl(struct gen_context *ctx, const struct declaration *decl)
assert(fntype->func.params == NULL); // TODO
// TODO: Gen function body
+
+ qbe_append_def(ctx->out, qdef);
}
static void
diff --git a/src/main.c b/src/main.c
@@ -3,6 +3,7 @@
#include <string.h>
#include "ast.h"
#include "check.h"
+#include "emit.h"
#include "gen.h"
#include "lex.h"
#include "parse.h"
@@ -13,13 +14,14 @@ enum stage {
STAGE_PARSE,
STAGE_CHECK,
STAGE_GEN,
+ STAGE_EMIT,
};
enum stage
parse_stage(const char *s)
{
if (s == NULL) {
- return STAGE_GEN;
+ return STAGE_EMIT;
} else if (strcmp(s, "lex") == 0) {
return STAGE_LEX;
} else if (strcmp(s, "parse") == 0) {
@@ -28,6 +30,8 @@ parse_stage(const char *s)
return STAGE_CHECK;
} else if (strcmp(s, "gen") == 0) {
return STAGE_GEN;
+ } else if (strcmp(s, "emit") == 0) {
+ return STAGE_EMIT;
} else {
fprintf(stderr, "Unknown HA_STAGE value '%s'\n", s);
exit(1);
@@ -63,5 +67,10 @@ main(int argc, char *argv[])
struct qbe_program prog = {0};
gen(&unit, &prog);
+ if (stage == STAGE_GEN) {
+ return 0;
+ }
+
+ emit(&prog, stdout);
return 0;
}
diff --git a/src/qbe.c b/src/qbe.c
@@ -137,6 +137,13 @@ const char *qbe_instr[Q_LAST_INSTR] = {
};
void
+qbe_append_def(struct qbe_program *prog, struct qbe_def *def)
+{
+ def->next = prog->defs;
+ prog->defs = def;
+}
+
+void
geni(struct qbe_statement *stmt, enum qbe_instr instr, ...)
{
assert(0); // TODO