From a287fe5aeb6b681ab405c0297841dce64ab4b946 Mon Sep 17 00:00:00 2001 From: lemon Date: Fri, 14 Nov 2025 18:49:04 +0100 Subject: preeliminary va_list support --- c/builtin.c | 101 +++++++++++++++++++++++ c/c.c | 252 ++++++++++++++++++++++++++++++++++----------------------- c/c.h | 38 ++++++++- c/keywords.def | 123 ++++++++++++++-------------- 4 files changed, 346 insertions(+), 168 deletions(-) create mode 100644 c/builtin.c (limited to 'c') diff --git a/c/builtin.c b/c/builtin.c new file mode 100644 index 0000000..d386480 --- /dev/null +++ b/c/builtin.c @@ -0,0 +1,101 @@ +#include "c.h" +#include "../ir/ir.h" + +static bool +callcheck(const struct span *span, int nparam, const union type *param, int narg, struct expr *args) +{ + bool ok = 1; + for (int i = 0, n = narg < nparam ? narg : nparam; i < n; ++i) { + if (!assigncheck(typedecay(param[i]), &args[i])) { + ok = 0; + error(&args[i].span, "arg #%d of type '%ty' is incompatible with '%ty'", + i, args[i].ty, param[i]); + } + } + + if (narg > nparam) { + error(&args[nparam].span, "too many args to builtin function taking %d params", nparam); + ok = 0; + } else if (narg < nparam) { + error(span, "not enough args to builtin function taking %d param%s", nparam, + nparam != 1 ? "s" : ""); + ok = 0; + } + return ok; +} + +#define DEF_FNLIKE_SEMA(name, retty, ...) \ + static bool \ + name##_sema(struct comp *cm, struct expr *ex) { \ + static union type par[] = { __VA_ARGS__, {0} }; \ + ex->ty = retty; \ + return callcheck(&ex->span, arraylength(par)-1, par, ex->narg, ex->sub+1); \ + } + +static bool +va_start_sema(struct comp *cm, struct expr *ex) +{ + ex->ty = mktype(TYVOID); + return callcheck(&ex->span, 1, &cvalistty, ex->narg, ex->sub+1); +} + +static union ref +va_start_comp(struct function *fn, struct expr *ex, bool discard) +{ + assert(ex->t == ECALL && ex->narg == 1); + assert(ex->sub[1].ty.bits == cvalistty.bits); + if (!typedata[fn->fnty.dat].variadic) + error(&ex->span, "va_start used in non-variadic function"); + addinstr(fn, mkinstr(Ovastart, 0, compileexpr(fn, &ex->sub[1], 0))); + return NOREF; +} + +static bool +va_end_sema(struct comp *cm, struct expr *ex) +{ + ex->ty = mktype(TYVOID); + return callcheck(&ex->span, 1, &cvalistty, ex->narg, ex->sub+1); +} + +static union ref +va_end_comp(struct function *fn, struct expr *ex, bool discard) +{ + return NOREF; +} + +union ref +builtin_va_arg_comp(struct function *fn, const struct expr *ex, bool discard) +{ + assert(ex->t == EVAARG && ex->ty.t); + enum irclass k = isagg(ex->ty) ? KPTR : type2cls[scalartypet(ex->ty)]; + return addinstr(fn, mkinstr(Ovaarg, k, compileexpr(fn, ex->sub, 0), mktyperef(mkirtype(ex->ty)))); +} + +#define LIST_BUILTINS(_) \ + _(va_start) \ + _(va_end) \ + +static const struct { + const char *name; + struct builtin b; +} tab[] = { +#define FNS(x) { "__builtin_" #x, { x##_sema, x##_comp } }, + LIST_BUILTINS(FNS) +#undef FNS +}; + +const char *intern(const char *); +void +putbuiltins(struct env *env) +{ + for (int i = 0; i < arraylength(tab); ++i) { + envadddecl(env, &(struct decl) { + .name = intern(tab[i].name), + .isbuiltin = 1, + .builtin = &tab[i].b, + }); + } +} + + +/* vim:set ts=3 sw=3 expandtab: */ diff --git a/c/c.c b/c/c.c index 415b584..3755261 100644 --- a/c/c.c +++ b/c/c.c @@ -4,31 +4,19 @@ #include "../ir/ir.h" #include "../obj/obj.h" -/** C compiler state **/ -struct comp { - struct lexer lx; - struct env *env; - struct arena *fnarena, *exarena; - struct span fnblkspan; - uint loopdepth, switchdepth; - struct block *breakto, *loopcont; - struct switchstmt *switchstmt; - struct label *labels; -}; - /** Parsing helper functions **/ -#define peek(Cm,Tk) lexpeek(&(Cm)->lx,Tk) +#define peek(Cm,Tk) lexpeek((Cm)->lx,Tk) static int lexc(struct comp *cm, struct token *tk) { struct token tk2; - int t = lex(&cm->lx, tk); + int t = lex(cm->lx, tk); if (t == TKSTRLIT && peek(cm, &tk2) == TKSTRLIT && tk2.wide == tk->wide) { /* 5.1.1.2 Translation phase 6: concatenate adjacent string literal tokens */ static char buf[200]; vec_of(char) rest = VINIT(buf, sizeof buf); do { - lex(&cm->lx, NULL); + lex(cm->lx, NULL); if (tk) { joinspan(&tk->span.ex, tk2.span.ex); if (!tk->wide) @@ -171,7 +159,6 @@ struct env { /* ditto for envtagged[] */ ushort tagged, ntagged; }; -static struct env toplevel; static void envdown(struct comp *cm, struct env *e) @@ -196,7 +183,7 @@ envup(struct comp *cm) cm->env = env->up; } -static struct decl * +struct decl * envadddecl(struct env *env, const struct decl *d) { assert(env->decl + env->ndecl == envdecls.n); @@ -264,8 +251,8 @@ redeclarationok(const struct decl *old, const struct decl *new) static struct decl * putdecl(struct comp *cm, const struct decl *decl) { - struct decl *l; - for (l = NULL; enviterdecl(&l, cm->env);) { + assert(!decl->isbuiltin); + for (struct decl *l = NULL; enviterdecl(&l, cm->env);) { if (decl->name == l->name) { if (l->isdef && decl->isdef) { error(&decl->span, "redefinition of '%s'", decl->name); @@ -278,18 +265,15 @@ putdecl(struct comp *cm, const struct decl *decl) } } } - l = envadddecl(cm->env, decl); - return l; + return envadddecl(cm->env, decl); } static struct decl * finddecl(struct comp *cm, const char *name) { - struct env *e; - struct decl *l; assert(name); - for (e = cm->env; e; e = e->up) { - for (l = NULL; enviterdecl(&l, e);) { + for (struct env *e = cm->env; e; e = e->up) { + for (struct decl *l = NULL; enviterdecl(&l, e);) { if (name == l->name) return l; } @@ -300,12 +284,10 @@ finddecl(struct comp *cm, const char *name) static union type gettagged(struct comp *cm, struct span *span, enum typetag tt, const char *name, bool dodef) { - struct env *e; - struct tagged *l; struct typedata td = {0}; assert(name); - for (e = cm->env; e; e = e->up) { - for (l = NULL; envitertagged(&l, e);) { + for (struct env *e = cm->env; e; e = e->up) { + for (struct tagged *l = NULL; envitertagged(&l, e);) { if (name == ttypenames[typedata[l->ty.dat].id]) { if (dodef && e != cm->env) goto Break2; @@ -324,10 +306,9 @@ Break2: static union type deftagged(struct comp *cm, struct span *span, enum typetag tt, const char *name, union type ty) { - struct tagged *l; struct typedata td = {0}; assert(name); - for (l = NULL; envitertagged(&l, cm->env);) { + for (struct tagged *l = NULL; envitertagged(&l, cm->env);) { if (name == ttypenames[typedata[l->ty.dat].id]) { *span = l->span; return l->ty; @@ -359,7 +340,7 @@ argpromote(union type t) return t; } -static bool +bool assigncheck(union type t, const struct expr *src) { if (assigncompat(t, typedecay(src->ty))) return 1; @@ -653,6 +634,8 @@ exprdup2(struct comp *cm, const struct expr *e1, const struct expr *e2) static struct expr expr(struct comp *cm); static struct expr commaexpr(struct comp *cm); +enum { IMPLICITFUNCTY = 0xFF, }; + static struct expr /* 6.5.2.2 Function calls */ callexpr(struct comp *cm, const struct span *span_, const struct expr *callee) { @@ -665,11 +648,17 @@ callexpr(struct comp *cm, const struct span *span_, const struct expr *callee) vec_of(struct expr) args = VINIT(argbuf, arraylength(argbuf)); bool spanok = joinspan(&span.ex, span_->ex); bool printsig = 0; + const struct builtin *builtin = NULL; + + if (callee->t == ESYM && !callee->ty.t && callee->sym->isbuiltin) { + builtin = callee->sym->builtin; + assert(!ty.t); + } - if (callee->t == ESYM && !callee->ty.t) { /* implicit function decl.. */ + if (callee->t == ESYM && ty.t == IMPLICITFUNCTY) { /* implicit function decl.. */ const char *name = (void *)callee->sym; struct decl decl = { - ty = mkfntype(mktype(TYINT), 0, NULL, NULL, /* kandr */ 1, 0), + (ty = mkfntype(mktype(TYINT), 0, NULL, NULL, /* kandr */ 1, 0)), .scls = SCEXTERN, .span = callee->span, .name = name }; warn(&callee->span, "call to undeclared function '%s'", name); @@ -678,9 +667,12 @@ callexpr(struct comp *cm, const struct span *span_, const struct expr *callee) td = &typedata[ty.dat]; } - if (ty.t == TYPTR) /* auto-deref when calling a function pointer */ - ty = typechild(ty); - if (ty.t != TYFUNC) error(&callee->span, "calling a value of type '%ty'", callee->ty); + if (!builtin) { + if (ty.t == TYPTR) /* auto-deref when calling a function pointer */ + ty = typechild(ty); + if (ty.t != TYFUNC) + error(&callee->span, "calling a value of type '%ty'", callee->ty); + } if (!match(cm, &tk, ')')) for (;;) { arg = expr(cm); spanok = spanok && joinspan(&span.ex, callee->span.ex); @@ -705,7 +697,7 @@ callexpr(struct comp *cm, const struct span *span_, const struct expr *callee) } if (!spanok || !joinspan(&span.ex, tk.span.ex)) span = *span_; - if (!td->variadic && !td->kandr && args.n < td->nmemb) { + if (ty.t == TYFUNC && !td->variadic && !td->kandr && args.n < td->nmemb) { error(&tk.span, "not enough args to function taking %d param%s", td->nmemb, td->nmemb != 1 ? "s" : ""); printsig = 1; @@ -717,6 +709,9 @@ callexpr(struct comp *cm, const struct span *span_, const struct expr *callee) ex.sub[0] = *callee; memcpy(ex.sub+1, args.p, args.n*sizeof(struct expr)); vfree(&args); + if (builtin) { + builtin->sema(cm, &ex); + } return ex; } @@ -810,6 +805,38 @@ ppostfixopers(struct comp *cm, struct expr *ex) } } +static struct expr +vaargexpr(struct comp *cm, struct span *span) +{ + struct token tk; + struct expr ex = mkexpr(EXXX, *span, mktype(TYVOID), ); + if (expect(cm, '(', "after __builtin_va_arg")) { + struct expr arg = expr(cm); + struct decl decl; + union type ty; + expect(cm, ',', NULL); + decl = pdecl(&(struct declstate){DCASTEXPR}, cm); + ty = decl.ty; + peek(cm, &tk); + if (expect(cm, ')', NULL)) + joinspan(&span->ex, tk.span.ex); + if (ty.t == TYARRAY) + warn(&decl.span, "va_arg type argument is array type '%ty', which is undefined behavior", decl.ty); + else if (ty.t == TYFUNC) + error(&decl.span, "va_arg type argument is function type '%ty'", decl.ty); + else { + ty = argpromote(ty); + if (ty.bits != decl.ty.bits) { + warn(&decl.span, + "va_arg type argument is promotable type '%ty', which has undefined behavior" + " (it will be promoted to '%ty')", decl.ty, ty); + } + } + ex = mkexpr(EVAARG, *span, decl.ty, .sub = exprdup(cm, &arg)); + } + return ex; +} + static inline int tkprec(int tt) { @@ -866,12 +893,41 @@ Unary: } goto Unary; + /* might be unary op (cast) or primary expr */ + case '(': + if (!isdecltok(cm)) { /* (expr) */ + ex = commaexpr(cm); + expect(cm, ')', NULL); + } else { /* (type) expr */ + struct declstate st = { DCASTEXPR }; + struct decl decl = pdecl(&st, cm); + struct span span = tk.span; + assert(decl.ty.t); + peek(cm, &tk); + if (expect(cm, ')', NULL)) + joinspan(&span.ex, tk.span.ex); + if (peek(cm, NULL) == '{') { + if (ccopt.cstd < STDC99) + warn(&tk.span, "compound literals are a c99 feature"); + ex = initializer(cm, &decl.ty, (decl.scls & SCSTATIC) ? EVSTATICINI : EVFOLD, + /* globl */ 0, decl.qual, NULL); + break; + } + unops[nunop].span = span; + unops[nunop].ty = decl.ty; + if (++nunop >= arraylength(unops)) { + ex = exprparse(cm, 999, NULL, 0); + break; + } + goto Unary; + } + break; /* base exprs */ case TKNUMLIT: case TKCHRLIT: ex = mkexpr(ENUMLIT, tk.span, mktype(0), ); if (!(ty.t = parsenumlit(&ex.u, &ex.f, &tk, 0))) - error(&tk.span, "bad number literal %'tk", &tk); + error(&tk.span, "bad %s literal %'tk", tk.t == TKNUMLIT ? "number" : "character", &tk); ex.ty.t = ty.t ? ty.t : TYINT; break; case TKSTRLIT: @@ -883,7 +939,7 @@ Unary: decl = finddecl(cm, tk.s); if (!decl) { if (peek(cm, NULL) == '(') { /* implicit function decl? */ - ex = mkexpr(ESYM, tk.span, mktype(0), .sym = (void *)tk.s); + ex = mkexpr(ESYM, tk.span, mktype(IMPLICITFUNCTY), .sym = (void *)tk.s); } else { error(&tk.span, "undeclared identifier %'tk", &tk); ex = mkexpr(ESYM, tk.span, mktype(TYINT), .sym = NULL); @@ -897,33 +953,6 @@ Unary: ex = mkexpr(ESYM, tk.span, decl->ty, .qual = decl->qual, .sym = decl); } break; - - /* might be unary op or primary expr */ - case '(': - if (!isdecltok(cm)) { /* (expr) */ - ex = commaexpr(cm); - expect(cm, ')', NULL); - break; - } else { /* (type) expr */ - struct declstate st = { DCASTEXPR }; - struct decl decl = pdecl(&st, cm); - expect(cm, ')', NULL); - assert(decl.ty.t); - if (peek(cm, NULL) == '{') { - if (ccopt.cstd < STDC99) - warn(&tk.span, "compound literals are a c99 feature"); - ex = initializer(cm, &decl.ty, (decl.scls & SCSTATIC) ? EVSTATICINI : EVFOLD, - /* globl */ 0, decl.qual, NULL); - break; - } - unops[nunop].span = tk.span; - unops[nunop].ty = decl.ty; - if (++nunop >= arraylength(unops)) { - ex = exprparse(cm, 999, NULL, 0); - break; - } - goto Unary; - } case TKWsizeof: span = tk.span; if (!match(cm, NULL, '(')) /* sizeof expr */ @@ -945,6 +974,10 @@ Unary: sizeofcheck(&span, ty); ex = mkexpr(ENUMLIT, span, mktype(targ_sizetype), .u = typesize(ty)); break; + case TKW__builtin_va_arg: + span = tk.span; + return vaargexpr(cm, &span); + break; default: fatal(&tk.span, "expected %s (near %'tk)", fromstmt ? "statement" : "expression", &tk); } @@ -1193,7 +1226,6 @@ dumpini(struct initparser *ip) } #endif -static union ref expraddr(struct function *, const struct expr *); static bool globsym(union ref *psym, const struct expr *ex) { @@ -1981,7 +2013,7 @@ ptypeof(struct comp *cm) } static bool -declspec(struct declstate *st, struct comp *cm) +declspec(struct declstate *st, struct comp *cm, struct span *pspan) { struct token tk; struct decl *decl; @@ -2001,6 +2033,7 @@ declspec(struct declstate *st, struct comp *cm) for (;;) { peek(cm, &tk); + if (!span.ex.len) span = tk.span; switch (tk.t) { case TKWconst: st->qual |= QCONST; @@ -2068,13 +2101,11 @@ declspec(struct declstate *st, struct comp *cm) lex(cm, &tk); st->base = tagtype(cm, tk.t); st->tagdecl = 1; - if (!span.ex.len) span.ex = tk.span.ex; joinspan(&span.ex, tk.span.ex); goto End; case TKW__typeof__: case TKWtypeof: lex(cm, &tk); st->base = ptypeof(cm); - if (!span.ex.len) span.ex = tk.span.ex; joinspan(&span.ex, tk.span.ex); goto End; case TKIDENT: @@ -2085,7 +2116,6 @@ declspec(struct declstate *st, struct comp *cm) } /* fallthru */ default: - if (!span.ex.len) span.ex = tk.span.ex; goto End; case TKW_BitInt: case TKW_Complex: case TKW_Decimal128: case TKW_Decimal32: @@ -2093,12 +2123,12 @@ declspec(struct declstate *st, struct comp *cm) error(&tk.span, "%'tk is unsupported", &tk); arith = arith ? arith : KINT; } - if (!span.ex.len) span.ex = tk.span.ex; joinspan(&span.ex, tk.span.ex); lex(cm, &tk); if (st->base.t) break; } End: + if (pspan) *pspan = span; if (st->base.t && arith) { /* combining arith type specifiers and other types */ Bad: @@ -2221,7 +2251,7 @@ cvqual(struct comp *cm) } static void -decltypes(struct comp *cm, struct decllist *list, const char **name, struct span *span) { +decltypes(struct comp *cm, struct decllist *list, const char **name, struct span *span, struct span *namespan) { struct token tk; struct decllist *ptr, node; @@ -2230,6 +2260,7 @@ decltypes(struct comp *cm, struct decllist *list, const char **name, struct span node.qual = cvqual(cm); node.span = tk.span; declinsert(list, &node); + joinspan(&span->ex, tk.span.ex); } ptr = list->next; switch (peek(cm, &tk)) { @@ -2248,10 +2279,12 @@ decltypes(struct comp *cm, struct decllist *list, const char **name, struct span node.kandr = 1; node.npar = 0; declinsert(ptr->prev, &node); + joinspan(&span->ex, tk.span.ex); break; } else { - decltypes(cm, list, name, span); + decltypes(cm, list, name, span, namespan); expect(cm, ')', NULL); + joinspan(&span->ex, tk.span.ex); } break; case TKIDENT: @@ -2259,12 +2292,12 @@ decltypes(struct comp *cm, struct decllist *list, const char **name, struct span error(&tk.span, "unexpected identifier in type name"); else { *name = tk.s; - *span = tk.span; + *namespan = tk.span; } lex(cm, &tk); + joinspan(&span->ex, tk.span.ex); break; default: - *span = tk.span; if (name) *name = NULL; } @@ -2292,6 +2325,7 @@ decltypes(struct comp *cm, struct decllist *list, const char **name, struct span node.t = TYARRAY; node.len = n; declinsert(ptr->prev, &node); + joinspan(&span->ex, node.span.ex); } else if (match(cm, &tk, '(')) Func: { static int depth = 0; vec_of(union type) params = {0}; @@ -2335,7 +2369,8 @@ decltypes(struct comp *cm, struct decllist *list, const char **name, struct span params.n, decl.ty, tdgetqual(qual.p, params.n-1)); } } - joinspan(&node.span.ex, tk.span.ex); + peek(cm, &tk); + joinspan(&span->ex, tk.span.ex); if (!match(cm, &tk, ',')) { expect(cm, ')', NULL); break; @@ -2359,15 +2394,17 @@ decltypes(struct comp *cm, struct decllist *list, const char **name, struct span node.pspans = params.n ? spans.p : NULL; node.npar = params.n; declinsert(ptr->prev, &node); + joinspan(&span->ex, node.span.ex); } else break; } } static struct decl -declarator(struct declstate *st, struct comp *cm) { - struct decl decl = { st->base, st->scls, st->qual, st->align }; +declarator(struct declstate *st, struct comp *cm, struct span span0) { + struct decl decl = { st->base, st->scls, st->qual, st->align, .span = span0 }; struct decllist list = { &list, &list }, *l; static bool inidecltmp = 0; + struct span namespan ={0}; if (!inidecltmp) { inidecltmp = 1; for (int i = 0; i < arraylength(decltmp); ++i) { @@ -2376,7 +2413,7 @@ declarator(struct declstate *st, struct comp *cm) { } } - decltypes(cm, &list, st->kind == DCASTEXPR ? NULL : &decl.name, &decl.span); + decltypes(cm, &list, st->kind == DCASTEXPR ? NULL : &decl.name, &decl.span, &namespan); if (!decl.name && st->kind != DCASTEXPR && st->kind != DFUNCPARAM) { if (list.prev == &list) lex(cm, NULL); error(&decl.span, "expected `(', `*' or identifier"); @@ -2398,7 +2435,7 @@ declarator(struct declstate *st, struct comp *cm) { if (decl.ty.t == TYFUNC) error(&decl.span, "function cannot return function type '%ty'", decl.ty); else if (decl.ty.t == TYARRAY) - error(&decl.span, "function cannot return array type", decl.ty); + error(&decl.span, "function cannot return array type '%ty'", decl.ty); else if (decl.ty.t != TYVOID && isincomplete(decl.ty)) error(&decl.span, "function cannot return incomplete type '%ty'", decl.ty); if (l->kandr && ccopt.cstd > STDC89) @@ -2419,7 +2456,8 @@ declarator(struct declstate *st, struct comp *cm) { l->next = declfreelist; declfreelist = l; } - + if (st->kind != DCASTEXPR) + decl.span = namespan; return decl; } @@ -2499,22 +2537,25 @@ pdecl(struct declstate *st, struct comp *cm) { st->scls &= allowed; } peek(cm, &tk); - if (!declspec(st, cm) && st->kind != DTOPLEVEL) { + if (!declspec(st, cm, &decl.span) && st->kind != DTOPLEVEL) { lex(cm, &tk); error(&tk.span, "unknown type name %'s", tk.s); } + } else { + peek(cm, &tk); + decl.span = tk.span; } if (st->scls == SCTYPEDEF) iniallowed = 0; if (first && st->tagdecl && match(cm, &tk, ';')) { - decl = (struct decl) { st->base, st->scls, st->qual, st->align, 0, tk.span }; + decl = (struct decl) { st->base, st->scls, st->qual, st->align, .span = decl.span }; return decl; } else if (st->kind == DFIELD && match(cm, &tk, ':')) { - decl = (struct decl) { st->base, st->scls, st->qual, st->align, 0, tk.span }; + decl = (struct decl) { st->base, st->scls, st->qual, st->align, .span = decl.span }; st->bitf = 1; return decl; } - decl = declarator(st, cm); + decl = declarator(st, cm, decl.span); if (iniallowed && match(cm, &tk, '=')) { st->varini = 1; @@ -2543,8 +2584,6 @@ AfterIniBitf: /* IR Generation */ /*****************/ -static union ref expraddr(struct function *, const struct expr *); -static union ref compileexpr(struct function *, const struct expr *, bool discard); static inline union ref exprvalue(struct function *fn, const struct expr *ex) { @@ -2588,7 +2627,7 @@ mkhiddensym(const char *fnname, const char *name, int id) static void geninit(struct function *fn, union type t, union ref dst, const struct expr *src); static union ref condexprvalue(struct function *fn, const struct expr *ex, bool discard); -static union ref +union ref expraddr(struct function *fn, const struct expr *ex) { struct decl *decl; @@ -3042,6 +3081,9 @@ compilecall(struct function *fn, const struct expr *ex) struct instr insnsbuf[10]; vec_of(struct instr) insns = VINIT(insnsbuf, arraylength(insnsbuf)); + if (ex->sub[0].t == ESYM && ex->sub[0].sym->isbuiltin) { + return ex->sub[0].sym->builtin->comp(fn, (struct expr *)ex, 0); + } ins.op = Ocall; if (isagg(ex->ty)) { ins.cls = KPTR; @@ -3127,7 +3169,7 @@ genbitfstore(struct function *fn, const union type ty, union ref addr, genstore(fn, ty, addr, val); } -static union ref +union ref compileexpr(struct function *fn, const struct expr *ex, bool discard) { union type ty; @@ -3154,6 +3196,8 @@ compileexpr(struct function *fn, const struct expr *ex, bool discard) case ESYM: if (discard && !(ex->qual & QVOLATILE)) return NOREF; return genload(fn, ex->ty, expraddr(fn, ex), ex->qual & QVOLATILE); + case EVAARG: + return builtin_va_arg_comp(fn, ex, discard); case EGETF: if (discard && !(ex->qual & QVOLATILE)) return NOREF; if (ex->fld.bitsiz) { @@ -3904,7 +3948,7 @@ stmt(struct comp *cm, struct function *fn) break; } freearena(&cm->exarena); - lexerfreetemps(&cm->lx); + lexerfreetemps(cm->lx); return fn->curblk == NULL; } @@ -4120,22 +4164,24 @@ function(struct comp *cm, struct function *fn, const char **pnames, const struct } } +union type cvalistty; void docomp(struct comp *cm) { - static union type valistty; + static struct env toplevel; struct token tk[1]; if (!cm->env) cm->env = &toplevel; - - if (!valistty.t) { + if (!cvalistty.t) { struct typedata td = { .t = TYSTRUCT, .siz = targ_valistsize, .align = targ_primalign[TYPTR], .nmemb = 1, - .fld = (struct namedfield [1]){{"?"}} + .fld = &(struct namedfield){"-", {mkarrtype(mktype(TYPTR), 0, 3)}} }; - valistty = mktagtype(intern("__builtin_va_list"), &td); + cvalistty = mkarrtype(mktagtype(intern("__builtin_va_list"), &td), 0, 1); } - putdecl(cm, &(struct decl) { valistty, SCTYPEDEF, .name = intern("__builtin_va_list") }); + peek(cm, tk); + envadddecl(cm->env, &(struct decl) { cvalistty, SCTYPEDEF, .span = tk->span, .name = intern("__builtin_va_list") }); + putbuiltins(cm->env); while (peek(cm, tk) != TKEOF) { struct declstate st = { DTOPLEVEL }; @@ -4181,7 +4227,7 @@ docomp(struct comp *cm) } freearena(&cm->fnarena); freearena(&cm->exarena); - lexerfreetemps(&cm->lx); + lexerfreetemps(cm->lx); } while (st.more); } } @@ -4192,7 +4238,7 @@ initcm(struct comp *cm, const char *file) enum { N = 1<<12 }; static union { char m[sizeof(struct arena) + N]; struct arena *_align; } amem[2]; const char *err; - switch (initlexer(&cm->lx, &err, file)) { + switch (initlexer(cm->lx, &err, file)) { default: assert(0); case LXERR: fatal(NULL, "Cannot open %'s: %s", file, err); @@ -4207,7 +4253,7 @@ initcm(struct comp *cm, const char *file) void ccomp(const char *file) { - struct comp cm = {0}; + struct comp cm = {&(struct lexer){0}}; initcm(&cm, file); docomp(&cm); } @@ -4215,9 +4261,9 @@ ccomp(const char *file) void cpp(struct wbuf *out, const char *file) { - struct comp cm = {0}; + struct comp cm = {&(struct lexer){0}}; initcm(&cm, file); - lexerdump(&cm.lx, out); + lexerdump(cm.lx, out); } /* vim:set ts=3 sw=3 expandtab: */ diff --git a/c/c.h b/c/c.h index 81c07f9..e8e797c 100644 --- a/c/c.h +++ b/c/c.h @@ -5,7 +5,7 @@ /*************/ enum exprkind { - EXXX, ENUMLIT, ESTRLIT, ESYM, EINIT, EGETF, ECALL, ECOND, + EXXX, ENUMLIT, ESTRLIT, ESYM, EVAARG, EINIT, EGETF, ECALL, ECOND, /* unary */ EPLUS, ENEG, ECOMPL, ELOGNOT, EDEREF, EADDROF, ECAST, EPREINC, EPOSTINC, EPREDEC, EPOSTDEC, @@ -59,6 +59,18 @@ struct init { } *vals, **tail; }; +/** C compiler state **/ +struct comp { + struct lexer *lx; + struct env *env; + struct arena *fnarena, *exarena; + struct span fnblkspan; + uint loopdepth, switchdepth; + struct block *breakto, *loopcont; + struct switchstmt *switchstmt; + struct label *labels; +}; + enum storageclass { SCNONE, SCTYPEDEF = 1<<0, @@ -72,17 +84,35 @@ enum storageclass { struct decl { union type ty; uchar scls; - uchar qual : 2; - uchar isenum : 1; - uchar isdef : 1; + uchar qual : 2, + isenum : 1, + isdef : 1, + isbuiltin : 1; struct span span; const char *name; union { struct { ushort align; int id; }; vlong value; + const struct builtin *builtin; }; }; +extern union type cvalistty; +struct function; +struct decl *envadddecl(struct env *env, const struct decl *d); +bool assigncheck(union type t, const struct expr *src); +union ref expraddr(struct function *, const struct expr *); +union ref compileexpr(struct function *, const struct expr *, bool discard); + +/** builtin.c **/ +struct builtin { + bool (*sema)(struct comp *, struct expr *); + union ref (*comp)(struct function *, struct expr *, bool discard); +}; +void putbuiltins(struct env *); +union ref builtin_va_arg_comp(struct function *, const struct expr *, bool discard); + +/** eval.c **/ enum evalmode { EVNONE, EVINTCONST, diff --git a/c/keywords.def b/c/keywords.def index 258a396..f971830 100644 --- a/c/keywords.def +++ b/c/keywords.def @@ -1,64 +1,65 @@ /* !SORTED */ -_(_Alignas, STDC11) -_(_Alignof, STDC11) -_(_Atomic, STDC11) -_(_BitInt, STDC23) -_(_Bool, STDC99) -_(_Complex, STDC99) -_(_Decimal128, STDC23) -_(_Decimal32, STDC23) -_(_Decimal64, STDC23) -_(_Generic, STDC11) -_(_Imaginary, STDC99) -_(_Noreturn, STDC11) -_(_Static_assert, STDC11) -_(_Thread_local, STDC11) -_(__typeof__, 0) -_(alignas, STDC23) -_(alignof, STDC23) -_(auto, 0) -_(bool, STDC23) -_(break, 0) -_(case, 0) -_(char, 0) -_(const, 0) -_(constexpr, STDC23) -_(continue, 0) -_(default, 0) -_(do, 0) -_(double, 0) -_(else, 0) -_(enum, 0) -_(extern, 0) -_(false, STDC23) -_(float, 0) -_(for, 0) -_(goto, 0) -_(if, 0) -_(inline, STDC99) -_(int, 0) -_(long, 0) -_(nullptr, STDC23) -_(register, 0) -_(restrict, STDC99) -_(return, 0) -_(short, 0) -_(signed, 0) -_(sizeof, 0) -_(static, 0) -_(static_assert, STDC23) -_(struct, 0) -_(switch, 0) -_(thread_local, STDC23) -_(true, STDC23) -_(typedef, 0) -_(typeof, STDC23) -_(typeof_unqual, STDC23) -_(union, 0) -_(unsigned, 0) -_(void, 0) -_(volatile, 0) -_(while, 0) +_(_Alignas, STDC11) +_(_Alignof, STDC11) +_(_Atomic, STDC11) +_(_BitInt, STDC23) +_(_Bool, STDC99) +_(_Complex, STDC99) +_(_Decimal128, STDC23) +_(_Decimal32, STDC23) +_(_Decimal64, STDC23) +_(_Generic, STDC11) +_(_Imaginary, STDC99) +_(_Noreturn, STDC11) +_(_Static_assert, STDC11) +_(_Thread_local, STDC11) +_(__builtin_va_arg, 0) +_(__typeof__, 0) +_(alignas, STDC23) +_(alignof, STDC23) +_(auto, 0) +_(bool, STDC23) +_(break, 0) +_(case, 0) +_(char, 0) +_(const, 0) +_(constexpr, STDC23) +_(continue, 0) +_(default, 0) +_(do, 0) +_(double, 0) +_(else, 0) +_(enum, 0) +_(extern, 0) +_(false, STDC23) +_(float, 0) +_(for, 0) +_(goto, 0) +_(if, 0) +_(inline, STDC99) +_(int, 0) +_(long, 0) +_(nullptr, STDC23) +_(register, 0) +_(restrict, STDC99) +_(return, 0) +_(short, 0) +_(signed, 0) +_(sizeof, 0) +_(static, 0) +_(static_assert, STDC23) +_(struct, 0) +_(switch, 0) +_(thread_local, STDC23) +_(true, STDC23) +_(typedef, 0) +_(typeof, STDC23) +_(typeof_unqual, STDC23) +_(union, 0) +_(unsigned, 0) +_(void, 0) +_(volatile, 0) +_(while, 0) #ifndef TKWBEGIN_ # define TKWBEGIN_ TKW_Alignas @@ -67,5 +68,5 @@ _(while, 0) # define TKWEND_ TKWwhile #endif #ifndef TKWMAXLEN_ -# define TKWMAXLEN_ (sizeof "_Static_assert" - 1) +# define TKWMAXLEN_ (sizeof "__builtin_va_arg" - 1) #endif -- cgit v1.2.3