summaryrefslogtreecommitdiff
path: root/lit.c
diff options
context:
space:
mode:
Diffstat (limited to 'lit.c')
-rw-r--r--lit.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/lit.c b/lit.c
new file mode 100644
index 0000000..09528a2
--- /dev/null
+++ b/lit.c
@@ -0,0 +1,102 @@
+#include "lit.h"
+#include "fn.h"
+#include "lex.h"
+#include "parse.h"
+#include "prv.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+void lit_free(struct lit *l)
+{
+ free(l->name);
+}
+
+static char *gen(struct ast *ast, struct fn *fn)
+{
+ static const char fmt[] = "__str_%zu";
+ int n = snprintf(NULL, 0, fmt, ast->litcnt);
+ char *ret = NULL;
+ size_t sz;
+
+ if (n < 0)
+ {
+ fprintf(stderr, "%s: snprintf(3) failed\n", __func__);
+ goto failure;
+ }
+ else if (!(ret = malloc((sz = n + 1))))
+ {
+ perror("malloc(3)");
+ goto failure;
+ }
+
+ n = snprintf(ret, sz, fmt, ast->litcnt);
+
+ if (n < 0 || n >= sz)
+ {
+ fprintf(stderr, "%s: snprintf(3) failed with %d\n", __func__, n);
+ goto failure;
+ }
+
+ ast->litcnt++;
+ return ret;
+
+failure:
+ free(ret);
+ return NULL;
+}
+
+static const struct lit *find(const struct tk *tk, const struct ast *ast)
+{
+ for (const struct lit *l = ast->lits; l; l = l->next)
+ if (!strcmp(l->tk->s, tk->s))
+ return l;
+
+ return NULL;
+}
+
+int lit_cgen(const struct lit *l)
+{
+ printf("data $%s = { b \"%s\", b 0 }\n", l->name, l->tk->s);
+ return 0;
+}
+
+const struct lit *lit_push(const struct tk *tk, struct prv *p)
+{
+ char *name = NULL;
+ struct fn *fn = fn_cur(p);
+ struct ast *ast = p->ast;
+ const struct lit *prev = find(tk, ast);
+ struct lit *l;
+
+ if (prev)
+ return prev;
+ else if (!(name = gen(ast, fn)))
+ goto failure;
+ else if (!(l = malloc(sizeof *l)))
+ {
+ perror("malloc(3)");
+ goto failure;
+ }
+
+ *l = (struct lit)
+ {
+ .name = name,
+ .fn = fn,
+ .tk = tk
+ };
+
+ if (!ast->lits)
+ ast->lits = l;
+ else if (ast->lastlit)
+ ast->lastlit->next = l;
+
+ ast->lastlit = l;
+ fprintf(stderr, "adding literal \"%s\"\n", name);
+ return l;
+
+failure:
+ free(name);
+ return NULL;
+}