cproc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/cproc
Log | Files | Refs | Submodules | README | LICENSE

commit ba46d27318f9eae963634e6bf80e4f0290c37698
parent a62e33a86dc36fff10c0a0d9d2aaecd311c2b08f
Author: Nihal Jere <nihal@nihaljere.xyz>
Date:   Fri, 26 Mar 2021 00:33:39 -0500

expr.c: handle prefixed string literals

Diffstat:
Mexpr.c | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Mqbe.c | 2+-
2 files changed, 88 insertions(+), 10 deletions(-)

diff --git a/expr.c b/expr.c @@ -7,9 +7,51 @@ #include <stdlib.h> #include <string.h> #include <strings.h> +#include <wchar.h> +#include <uchar.h> #include "util.h" #include "cc.h" +static size_t +mbstoc16s(char16_t *dest, const char *src, size_t n) +{ + size_t ret, w = 0; + do { + ret = mbrtoc16(dest ? dest + w : NULL, src, n, 0); + if (ret > 0) { + src += ret; + n -= ret; + w += 1; + } else if (ret == -3) { + w += 1; + } else if (ret == -1) { + return -1; + } + } while (ret != 0 && n > 0); + + return w; +} + +static size_t +mbstoc32s(char32_t *dest, const char *src, size_t n) +{ + size_t ret, w = 0; + do { + ret = mbrtoc32(dest ? dest + w : NULL, src, n, 0); + if (ret > 0) { + src += ret; + n -= ret; + w += 1; + } else if (ret == -3) { + w += 1; + } else if (ret == -1) { + return -1; + } + } while (ret != 0 && n > 0); + + return w; +} + static struct expr * mkexpr(enum exprkind k, struct type *t) { @@ -456,9 +498,9 @@ primaryexpr(struct scope *s) struct expr *e; struct decl *d; struct type *t; - char *src, *dst, *end, *tmp; + char *src, *dst, *end, *tmp, p = 0, np; int base; - size_t tmpsize; + size_t tmpsize, count; switch (tok.kind) { case TIDENT: @@ -476,21 +518,57 @@ primaryexpr(struct scope *s) case TSTRINGLIT: tmp = NULL; tmpsize = 0; - e = mkexpr(EXPRSTRING, mkarraytype(&typechar, QUALNONE, 0)); - e->lvalue = true; do { - tmp = xreallocarray(e->string.data, tmpsize + strlen(tok.lit), 1); - dst = tmp + tmpsize; src = tok.lit; - if (*src != '"') - fatal("wide string literal not yet implemented"); + switch (*src) { + default: error(&tok.loc, "invalid prefix for string literal"); + case 'L': ++src; t = targ->typewchar; np = 'w'; goto litknown; + case 'U': ++src; t = &typeushort; np = 'U'; goto litknown; + case '"': t = &typechar; np = 'c'; goto litknown; + case 'u': ++src; break; + } + switch (*src) { + default: error(&tok.loc, "invalid prefix for string literal"); + case '"': t = &typeushort; np = 'u'; break; + case '8': ++src; t = &typechar; np = '8'; break; + } + if (p && p != np && !(p == 'c' || np == 'c')) + error(&tok.loc, "cannot have adjacent string literals with different prefixes"); +litknown: + p = np; + tmp = xreallocarray(tmp, tmpsize + strlen(tok.lit), 1); + /* mbsto* will calculate length incorrectly if this isn't cleared */ + memset(tmp + tmpsize, 0, strlen(tok.lit)); + dst = tmp + tmpsize; for (++src; *src != '"'; ++dst) *dst = unescape(&src); tmpsize = dst - tmp; next(); } while (tok.kind == TSTRINGLIT); - e->string.data = tmp; + e = mkexpr(EXPRSTRING, mkarraytype(t, QUALNONE, 0)); + e->lvalue = true; + e->string.data = NULL; e->string.size = tmpsize; + switch (p) { + case 'c': + case '8': e->string.size = tmpsize; e->string.data = tmp; goto litdone; + case 'w': e->string.size = mbstowcs(NULL, tmp, tmpsize) + 1; break; + case 'u': e->string.size = mbstoc16s(NULL, tmp, tmpsize) + 1; break; + case 'U': e->string.size = mbstoc32s(NULL, tmp, tmpsize) + 1; break; + default: assert(0); + } + e->string.data = xreallocarray(e->string.data, e->string.size, t->size); + switch (p) { + case 'w': count = mbstowcs(e->string.data, tmp, e->string.size); break; + case 'u': count = mbstoc16s(e->string.data, tmp, e->string.size); break; + case 'U': count = mbstoc32s(e->string.data, tmp, e->string.size); break; + default: assert(0); + } + if (count == -1) + error(&tok.loc, "string literal contains invalid multibyte sequence"); + assert(count == e->string.size - 1); + free(tmp); +litdone: e->type->array.length = e->string.size + 1; e->type->size = e->type->array.length * e->type->base->size; e->type->incomplete = false; diff --git a/qbe.c b/qbe.c @@ -1257,7 +1257,7 @@ dataitem(struct expr *expr, uint64_t size) break; case EXPRSTRING: fputc('"', stdout); - for (i = 0; i < expr->string.size && i < size; ++i) { + for (i = 0; i < expr->string.size * expr->type->base->size && i < size; ++i) { c = expr->string.data[i]; if (isprint(c) && c != '"' && c != '\\') putchar(c);