commit 1e39643dc342926d80fedd5ce6bc6aae7e075060
parent 084a4e9d986baf52f29235dba2bebe6b041d012b
Author: Drew DeVault <sir@cmpwn.com>
Date: Thu, 31 Dec 2020 15:55:07 -0500
gen, emit: escape string constants
Diffstat:
3 files changed, 34 insertions(+), 3 deletions(-)
diff --git a/include/qbe.h b/include/qbe.h
@@ -228,7 +228,10 @@ struct qbe_data_item {
union {
struct qbe_value value;
size_t zeroed;
- char *str;
+ struct {
+ char *str;
+ size_t sz;
+ };
};
struct qbe_data_item *next;
};
diff --git a/src/emit.c b/src/emit.c
@@ -1,4 +1,5 @@
#include <assert.h>
+#include <ctype.h>
#include <stdio.h>
#include "emit.h"
#include "qbe.h"
@@ -192,6 +193,33 @@ emit_func(struct qbe_def *def, FILE *out)
}
static void
+emit_data_string(const char *str, size_t sz, FILE *out)
+{
+ bool q = false;
+ for (size_t i = 0; i < sz; ++i) {
+ /* XXX: We could stand to emit less conservatively */
+ if (!isprint(str[i]) || str[i] == '"' || str[i] == '\\') {
+ if (q) {
+ q = false;
+ fprintf(out, "\", ");
+ }
+ fprintf(out, "b %d, ", str[i]);
+ } else {
+ if (!q) {
+ q = true;
+ fprintf(out, "b \"");
+ }
+ fprintf(out, "%c", str[i]);
+ }
+ }
+ if (q) {
+ fprintf(out, "\", b 0, ");
+ } else {
+ fprintf(out, "b 0, ");
+ }
+}
+
+static void
emit_data(struct qbe_def *def, FILE *out)
{
assert(def->kind == Q_DATA);
@@ -207,7 +235,7 @@ emit_data(struct qbe_def *def, FILE *out)
case QD_ZEROED:
assert(0); // TODO
case QD_STRING:
- fprintf(out, " b \"%s\", b 0", item->str);
+ emit_data_string(item->str, item->sz, out);
break;
}
diff --git a/src/gen.c b/src/gen.c
@@ -686,8 +686,8 @@ gen_string(struct gen_context *ctx,
def->name = temp.name;
def->kind = Q_DATA;
def->data.items.type = QD_STRING;
- // TODO: Escape special characters
def->data.items.str = strdup(expr->constant.string.value);
+ def->data.items.sz = expr->constant.string.len;
qbe_append_def(ctx->out, def);
struct qbe_value str = {0};