From 0e75fc383becccd113416677b7e26e0caf21e28b Mon Sep 17 00:00:00 2001 From: lemon Date: Sat, 21 Mar 2026 17:55:01 +0100 Subject: Rework handling of predefined macros. And add some GCC predefs like __SIZE_TYPE__, __LONG_SIZE__, etc --- src/a_embedfilesdir.c | 6 +-- src/a_main.c | 28 +++++++++-- src/a_targ.c | 83 ++++++++++++++++++++++++++++++++ src/antcc.h | 4 ++ src/c.c | 6 +-- src/c_lex.c | 129 +++++++++++++++++++++++++++++--------------------- src/c_type.c | 31 ++++++++++-- src/c_type.h | 3 +- src/ir_dump.c | 4 +- src/u_io.c | 25 ++-------- 10 files changed, 227 insertions(+), 92 deletions(-) (limited to 'src') diff --git a/src/a_embedfilesdir.c b/src/a_embedfilesdir.c index da6a9cb..64189ef 100644 --- a/src/a_embedfilesdir.c +++ b/src/a_embedfilesdir.c @@ -9,9 +9,9 @@ struct EmbedFile { } embedfilesdir[] = { {"stddef.h", S("\ #pragma once\n\ -typedef __typeof__((char*)0 - (char*)0) ptrdiff_t;\n\ -typedef __typeof__(sizeof 0) size_t;\n\ -typedef __typeof__(L'a') wchar_t;\n\ +typedef __PTRDIFF_TYPE__ ptrdiff_t;\n\ +typedef __SIZE_TYPE__ size_t;\n\ +typedef __WCHAR_TYPE__ wchar_t;\n\ #undef NULL\n\ #define NULL ((void*)0)\n\ #undef offsetof\n\ diff --git a/src/a_main.c b/src/a_main.c index 8004dd3..309fe23 100644 --- a/src/a_main.c +++ b/src/a_main.c @@ -121,7 +121,29 @@ static Task task = { .inf = VINIT(infilebuf, countof(infilebuf)) }; static void prihelp(void); -void cpppredef(bool undef, const char *cmd); +void cpp0define(const char *name, const char *body); +void cpp0undef(const char *name); + +static void +predef(bool undef, const char *cmd) +{ + char buf[1024]; + const char *sep = strchr(cmd, '='), + *body = sep ? sep+1 : "1"; + const char *name; + if (sep) { + uint n = sep - cmd; + assert(n < sizeof buf - 1); + memcpy(buf, cmd, n); + buf[n] = 0; + name = buf; + } else { + name = cmd; + } + if (undef) cpp0undef(name); + else cpp0define(name, body); +} + static void optparse(char **args) @@ -251,7 +273,7 @@ optparse(char **args) } else if (*arg == 'D' || *arg == 'U') { const char *def = arg[1] ? arg+1 : *++args; if (!def) fatal(NULL, "macro name missing after `-%c`", *arg); - cpppredef(*arg == 'U', def); + predef(*arg == 'U', def); } else if (*arg == 'O') { /* TODO optimization level */ } else if (*arg == 'I' || !strcmp(arg, "-include-directory")) { @@ -754,7 +776,7 @@ main(int argc, char **argv) } for (const char *const *p = host_predefs; *p; ++p) - cpppredef(0, *p); + predef(0, *p); return driver(); } diff --git a/src/a_targ.c b/src/a_targ.c index 1513bc6..f6e060c 100644 --- a/src/a_targ.c +++ b/src/a_targ.c @@ -67,6 +67,87 @@ parsetriple(TargTriple *trg, const char *str) return 1; } +static const char *const ospredefs[] = { + [OSlinux] = "__linux\0__linux__\0linux\0unix\0__unix\0__unix__\0__ELF__\0", + [OSopenbsd] = "__OpenBSD__\0unix\0__unix\0__unix__\0__ELF__\0" +}, *archpredefs[] = { + [ISx86_64] = "__x86_64__\0__x86_64\0__amd64__\0__amd64\0", + [ISaarch64] = "__aarch64__\0__aarch64\0", +}; + +/* https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html */ +static void +putpredefmacros(void) +{ + for (const char *s = ospredefs[target.os]; s && *s; s = s + strlen(s)+1) + cpp0define(s, NULL); + for (const char *s = archpredefs[target.arch]; s && *s; s = s + strlen(s)+1) + cpp0define(s, NULL); + if (ccopt.pie) + cpp0define("__pie__", NULL), cpp0define("__PIE__", NULL); + if (ccopt.pic) + cpp0define("__pic__", NULL), cpp0define("__PIC__", NULL); + + if (targ_primsizes[TYPTR] == 4) + cpp0define("_ILP32", NULL), cpp0define("__ILP32__", NULL); + else if (targ_primsizes[TYLONG] == 4) + cpp0define("_LLP64", NULL), cpp0define("__LLP64__", NULL); + else { + assert(targ_primsizes[TYINT] == 4); + cpp0define("_LP64", NULL), cpp0define("__LP64__", NULL); + } + + if (!targ_charsigned) cpp0define("__CHAR_UNSIGNED__", NULL); + /* __SIZE_TYPE__ & co. */ + int i64t = targ_primsizes[TYLONG] == 8 ? TYLONG : TYVLONG; +#define DEFTYP(T,tt) cpp0define("__"T"_TYPE__", primtypenames[tt]); + DEFTYP("SIZE", targ_sizetype); + DEFTYP("PTRDIFF", targ_ptrdifftype); + DEFTYP("WCHAR", targ_wchartype); + DEFTYP("WINT", targ_wchartype - isunsignedt(targ_wchartype)); + DEFTYP("INTMAX", i64t); + DEFTYP("UINTMAX", i64t+1); + DEFTYP("SIG_ATOMIC", TYINT); + DEFTYP("INT8", TYSCHAR); + DEFTYP("INT16", TYSHORT); + DEFTYP("INT32", TYINT); + DEFTYP("INT64", i64t); + DEFTYP("UINT8", TYUCHAR); + DEFTYP("UINT16", TYUSHORT); + DEFTYP("UINT32", TYUINT); + DEFTYP("UINT64", i64t+1); + DEFTYP("INT_LEAST8", TYSCHAR); + DEFTYP("INT_LEAST16", TYSHORT); + DEFTYP("INT_LEAST32", TYINT); + DEFTYP("INT_LEAST64", i64t); + DEFTYP("UINT_LEAST8", TYUCHAR); + DEFTYP("UINT_LEAST16", TYUSHORT); + DEFTYP("UINT_LEAST32", TYUINT); + DEFTYP("UINT_LEAST64", i64t+1); + DEFTYP("INTPTR", targ_64bit ? i64t : TYINT); + DEFTYP("UINTPTR", targ_64bit ? i64t : TYINT); +#undef DEFTYP + static const char atoi[][3] = {[1]="1",[2]="2",[4]="4",[8]="8",[16]="16"}; +#define TYPSIZ(T,n) cpp0define("__SIZEOF_"T"__", atoi[targ_primsizes[n]]) + TYPSIZ("INT", TYINT); + TYPSIZ("LONG", TYLONG); + TYPSIZ("LONG_LONG", TYVLONG); + TYPSIZ("SHORT", TYSHORT); + TYPSIZ("POINTER", TYPTR); + TYPSIZ("FLOAT", TYFLOAT); + TYPSIZ("DOUBLE", TYDOUBLE); + TYPSIZ("LONG_DOUBLE", TYLDOUBLE); + TYPSIZ("SIZE_T", targ_sizetype); + TYPSIZ("WCHAR_T", targ_wchartype); + TYPSIZ("WINT_T", targ_wchartype); + TYPSIZ("PTRDIFF_T", targ_ptrdifftype); + + cpp0define("__ORDER_LITTLE_ENDIAN__", "1234"); + cpp0define("__ORDER_BIG_ENDIAN__", "4321"); + cpp0define("__BYTE_ORDER__", + targ_bigendian ? "__ORDER_BIG_ENDIAN__" : "__ORDER_LITTLE_ENDIAN__"); +} + bool targ_init(const char *starg, const TargTriple *dfault) { @@ -120,5 +201,7 @@ targ_init(const char *starg, const TargTriple *dfault) mctarg = t->mctarg; targ_arch = ISx86_64; + putpredefmacros(); + return 1; } diff --git a/src/antcc.h b/src/antcc.h index 59ae690..61170b9 100644 --- a/src/antcc.h +++ b/src/antcc.h @@ -144,6 +144,10 @@ enum { /* GCC include directory search order: https://gcc.gnu.org/onlinedocs/gcc }; extern CInclPath *cinclpaths[5]; +/** c_lex.c **/ +void cpp0define(const char *name, const char *body); +void cpp0undef(const char *name); + /**********/ /* Target */ /**********/ diff --git a/src/c.c b/src/c.c index a423697..90ff923 100644 --- a/src/c.c +++ b/src/c.c @@ -349,7 +349,7 @@ gettagged(CComp *cm, Span *span, enum typetag tt, internstr name, bool dodef) assert(name); for (Env *e = cm->env; e; e = e->up) { for (Tagged *l = NULL; envitertagged(&l, e);) { - if (name == ttypenames[typedata[l->ty.dat].id]) { + if (name == tagtypetags[typedata[l->ty.dat].id]) { if (dodef && e != cm->env) goto Break2; *span = l->span; @@ -371,7 +371,7 @@ deftagged(CComp *cm, Span *span, enum typetag tt, internstr name, Type ty) TypeData td = {0}; assert(name); for (Tagged *l = NULL; envitertagged(&l, cm->env);) { - if (name == ttypenames[typedata[l->ty.dat].id]) { + if (name == tagtypetags[typedata[l->ty.dat].id]) { *span = l->span; return l->ty; } @@ -2063,7 +2063,7 @@ buildagg(CComp *cm, enum typetag tt, internstr name, int id) f.f.bitoff -= 8*siz; } if (!decl.name && !bitftypesiz) { - if (!isagg(decl.ty) || ttypenames[typedata[decl.ty.dat].id]) { + if (!isagg(decl.ty) || tagtypetags[typedata[decl.ty.dat].id]) { warn(&decl.span, "declaration does not declare anything"); continue; } else if (ccopt.cstd < STDC11 && ccopt.pedant) { diff --git a/src/c_lex.c b/src/c_lex.c index 1c8dc93..7b817fd 100644 --- a/src/c_lex.c +++ b/src/c_lex.c @@ -614,6 +614,8 @@ End: static bool tokequ(const Token *a, const Token *b) { + if (a == b) return 1; + if (!a || !b) return 0; if (a->t != b->t) return 0; if (a->t == TKNUMLIT || a->t == TKSTRLIT || a->t == TKCHRLIT) { if (a->len != b->len) return 0; @@ -640,13 +642,13 @@ typedef struct Macro { variadic : 1; short id; union { - void (*handler)(Lexer *, Token *); + void (*handler)(Lexer *, Token *); /* special && !fnlike */ + void (*handlerfn)(Lexer *, Token *, const Token *, int); /* special && fnlike */ + const Token *single; /* predef && !special */ struct TokList { uint off; /* mtoksbuf[] */ int n; } rl; - const Token *single; /* predef */ - void (*handlerfn)(Lexer *, Token *ret, const Token *arg, int narg); }; } Macro; @@ -662,6 +664,16 @@ macroequ(const Macro *a, const Macro *b) return 0; } if (a->special) return a->handler == b->handler; + if (a->predef || b->predef) { + if (a->predef && b->predef) + return tokequ(a->single, b->single); + if (a->predef && !b->predef) { + return (!!a->single) == b->rl.n + && (!a->single || tokequ(a->single, &mtoksbuf.p[b->rl.off])); + } + return (!!b->single) == a->rl.n + && (!b->single || tokequ(b->single, &mtoksbuf.p[a->rl.off])); + } if (a->rl.n != b->rl.n) return 0; const Token *tka = &mtoksbuf.p[a->rl.off], *tkb = &mtoksbuf.p[b->rl.off]; for (int i = 0; i < a->rl.n; ++i) { @@ -2215,23 +2227,57 @@ lexpeek(Lexer *lx, Token *tk_) /* Predefined/builtin macros */ -static vec_of(uchar) ppcmdline; +static char ppcmdlinebuf0[4000]; +static WriteBuf ppcmdline = MEMBUF(ppcmdlinebuf0, sizeof ppcmdlinebuf0); + +static void +ppcmdappendf(const char *fmt, ...) +{ + va_list ap; + uint lensave = ppcmdline.len; +Redo: + va_start(ap, fmt); + uint n = vbfmt(&ppcmdline, fmt, ap); + va_end(ap); + if (ppcmdline.err) { + uint newcap = ppcmdline.cap + n + 100; + if (ppcmdline.buf == ppcmdlinebuf0) { + ppcmdline.buf = xcalloc(newcap); + memcpy(ppcmdline.buf, ppcmdlinebuf0, sizeof ppcmdlinebuf0); + } else { + ppcmdline.buf = xrealloc(ppcmdline.buf, newcap); + memset(ppcmdline.buf + ppcmdline.cap, 0, newcap - ppcmdline.cap); + } + ppcmdline.cap = newcap; + ppcmdline.len = lensave; + ppcmdline.err = 0; + goto Redo; + } +} + +static void +putdef1(const char *name) +{ + static const Token tok_1 = { TKNUMLIT, .s = "1", .len = 1, .litlit = 1 }; + putmac(intern(name), &(Macro) { + .predef = 1, + .single = &tok_1 + }); +} void -cpppredef(bool undef, const char *cmd) +cpp0define(const char *name, const char *body) { - const char *sep = strchr(cmd, '='), *body = sep ? sep+1 : "1"; - uint namelen = sep ? sep - cmd : strlen(cmd); - char line[1024]; - WriteBuf wbuf = MEMBUF(line, sizeof line); - if (!ppcmdline.p) vinit(&ppcmdline, NULL, 1<<10); - int n; - if (undef) - n = bfmt(&wbuf, "#undef %S\n", cmd, namelen); + if (!body || !strcmp(body, "1")) + putdef1(name); else - n = bfmt(&wbuf, "#define %S %s\n", cmd, namelen, body); - assert(n <= sizeof line); - vpushn(&ppcmdline, line, n); + ppcmdappendf("#define %s %s\n", name, body); +} + +void +cpp0undef(const char *name) +{ + ppcmdappendf("#undef %s\n", name); } static void @@ -2330,17 +2376,6 @@ mac__has_builtin(Lexer *lx, Token *tk, const Token *args, int narg) tk->s = &"01"[has]; } - -static void -putdef1(const char *name) -{ - static const Token tok_1 = { TKNUMLIT, .s = "1", .len = 1, .litlit = 1 }; - putmac(intern(name), &(Macro) { - .predef = 1, - .single = &tok_1 - }); -} - static void putdefs1(const char *s) { @@ -2373,13 +2408,7 @@ addpredefmacros(Arena **tmparena) static const char cpredefs[] = "__antcc__\0__STDC__\0__STDC_NO_ATOMICS__\0__STDC_NO_COMPLEX__\0__STDC_NO_THREADS__\0__STDC_NO_VLA__\0", - *ospredefs[] = { - [OSlinux] = "__linux\0__linux__\0linux\0unix\0__unix\0__unix__\0", - [OSopenbsd] = "__OpenBSD__\0unix\0__unix\0__unix__\0" - }, *archpredefs[] = { - [ISx86_64] = "__x86_64__\0__x86_64\0__amd64__\0__amd64\0", - [ISaarch64] = "__aarch64__\0__aarch64\0", - }, cstdver[][8] = { + cstdver[][8] = { [STDC89] = "199409L", [STDC99] = "199901L", [STDC11] = "201112L", @@ -2388,36 +2417,22 @@ addpredefmacros(Arena **tmparena) tok_stdc.s = cstdver[ccopt.cstd]; tok_stdc.len = 7; + if (ccopt.cstd >= STDC99) + putdef1("__GNUC_STDC_INLINE__"); for (int i = 0; i < countof(macs); ++i) putmac(intern(macs[i].name), &macs[i].m); putdefs1(cpredefs); if (target.os != OSunknown) putdef1("__STDC_HOSTED__"); - putdefs1(ospredefs[target.os]); - putdefs1(archpredefs[target.arch]); - if (ccopt.pie) { - putdef1("__pie__"), putdef1("__PIE__"); - } - if (ccopt.pic) { - putdef1("__pic__"), putdef1("__PIC__"); - } - if (targ_primsizes[TYPTR] == 4) { - putdef1("_ILP32"), putdef1("__ILP32__"); - } else if (targ_primsizes[TYLONG] == 4) { - putdef1("_LLP64"), putdef1("__LLP64__"); - } else { - assert(targ_primsizes[TYINT] == 4); - putdef1("_LP64"), putdef1("__LP64__"); - } - if (ppcmdline.n) { + if (ppcmdline.len) { MemFile *f; Lexer lx[1] = {0}; lx->fileid = getpredeffile(&f, ""); assert(!f->p); - lx->ndat = f->n = ppcmdline.n; - vpushn(&ppcmdline, "\0\0\0\0\0\0", 6); - lx->dat = f->p = ppcmdline.p; + lx->ndat = f->n = ppcmdline.len; + ppcmdappendf("%S", "\0\0\0\0\0\0", 6); + lx->dat = f->p = (uchar *)ppcmdline.buf; lx->tmparena = tmparena; lx->chrbuf0 = countof(lx->chrbuf); lx->firstdirective = 1; @@ -2431,11 +2446,15 @@ initlexer(Lexer *lx, const char **err, const char *file) enum { NARENA = 1<<12 }; static union { char m[sizeof(Arena) + NARENA]; Arena *_align; } amem; static Arena *tmparena = (void *)amem.m; + static bool predefs; if (!tmparena->cap) tmparena->cap = NARENA; if (!mtoksbuf.p) vinit(&mtoksbuf, NULL, 1024); if (!mdyntoksbuf.p) vinit(&mdyntoksbuf, NULL, 256); - if (!macroht.v) addpredefmacros(&tmparena); + if (!predefs) { + addpredefmacros(&tmparena); + predefs = 1; + } MemFile *f; int fileid = openfile(err, &f, file); diff --git a/src/c_type.c b/src/c_type.c index 5fed20e..bf24653 100644 --- a/src/c_type.c +++ b/src/c_type.c @@ -2,7 +2,28 @@ #include "u_hash.h" TypeData typedata[1<<13]; -internstr ttypenames[1<<10]; +internstr tagtypetags[1<<10]; +const char *const primtypenames[] = { + [TYBOOL] = "bool", + [TYCHAR] = "char", + [TYSCHAR] = "signed char", + [TYUCHAR] = "unsigned char", + [TYSHORT] = "short", + [TYUSHORT] = "unsigned short", + [TYINT] = "int", + [TYUINT] = "unsigned int", + [TYLONG] = "long", + [TYULONG] = "unsigned long", + [TYVLONG] = "long long", + [TYUVLONG] = "unsigned long long", + [TYFLOAT] = "float", + [TYDOUBLE] = "double", + [TYLDOUBLE] = "long double", + [TYCOMPLEXF] = "float complex", + [TYCOMPLEX] = "double complex", + [TYCOMPLEXL] = "long double complex", + [TYVOID] = "void", +}; static ushort hashtd(const TypeData *td) @@ -188,11 +209,11 @@ completetype(internstr name, int id, TypeData *td) { assert(td->t == TYENUM || td->t == TYSTRUCT || td->t == TYUNION); td->id = id; - assert(id < countof(ttypenames) && "too many tag types"); - if (ttypenames[id]) - assert(ttypenames[id] == name && "bad redefn"); + assert(id < countof(tagtypetags) && "too many tag types"); + if (tagtypetags[id]) + assert(tagtypetags[id] == name && "bad redefn"); else - ttypenames[id] = name; + tagtypetags[id] = name; return mktype(td->t, .dat = interntd(td), .backing = td->t == TYENUM ? td->backing : 0); } diff --git a/src/c_type.h b/src/c_type.h index 8171366..a9d95c4 100644 --- a/src/c_type.h +++ b/src/c_type.h @@ -122,7 +122,8 @@ typedef struct TypeData { } TypeData; extern TypeData typedata[]; -extern internstr ttypenames[/*id*/]; +extern internstr tagtypetags[/*id*/]; +extern const char *const primtypenames[/*enum typetag*/]; bool isincomplete(Type); uint typesize(Type); diff --git a/src/ir_dump.c b/src/ir_dump.c index a3f59f7..7534370 100644 --- a/src/ir_dump.c +++ b/src/ir_dump.c @@ -81,8 +81,8 @@ prityp(IRType typ) else { const TypeData *td = &typedata[typ.dat]; const char *tag = td->t == TYSTRUCT ? "struct" : "union"; - if (ttypenames[td->id]) - bfmt(out, "%s.%s.%d", tag, ttypenames[td->id], td->id); + if (tagtypetags[td->id]) + bfmt(out, "%s.%s.%d", tag, tagtypetags[td->id], td->id); else bfmt(out, "%s.%d", tag, td->id); } diff --git a/src/u_io.c b/src/u_io.c index e331f3e..8de02e3 100644 --- a/src/u_io.c +++ b/src/u_io.c @@ -194,26 +194,11 @@ pritypebefore(WriteBuf *buf, Type ty, int qual) const char *s, *s2; Type chld; int n; + if (isprim(ty)) { + n = bfmt(buf, "%s", primtypenames[ty.t]); + return n + priquals(buf, qual); + } switch (ty.t) { - case TYVOID: s = "void"; Prim: n = bfmt(buf, "%s", s); return n + priquals(buf, qual); - case TYBOOL: s = "bool"; goto Prim; - case TYCHAR: s = "char"; goto Prim; - case TYSCHAR: s = "signed char"; goto Prim; - case TYUCHAR: s = "unsigned char"; goto Prim; - case TYSHORT: s = "short"; goto Prim; - case TYUSHORT: s = "unsigned short"; goto Prim; - case TYINT: s = "int"; goto Prim; - case TYUINT: s = "unsigned int"; goto Prim; - case TYLONG: s = "long"; goto Prim; - case TYULONG: s = "unsigned long"; goto Prim; - case TYVLONG: s = "long long"; goto Prim; - case TYUVLONG: s = "unsigned long long"; goto Prim; - case TYFLOAT: s = "float"; goto Prim; - case TYDOUBLE: s = "double"; goto Prim; - case TYLDOUBLE:s = "long double"; goto Prim; - case TYCOMPLEXF:s = "float complex"; goto Prim; - case TYCOMPLEX: s = "double complex"; goto Prim; - case TYCOMPLEXL:s = "long double complex"; goto Prim; case TYPTR: chld = typechild(ty); n = pritypebefore(buf, chld, ty.flag & TFCHLDQUAL); @@ -231,7 +216,7 @@ pritypebefore(WriteBuf *buf, Type ty, int qual) case TYSTRUCT: s = "struct"; Tagged: - n = bfmt(buf, "%s %s", s, (s2 = (char *)ttypenames[typedata[ty.dat].id]) ? s2 : "(anonymous)"); + n = bfmt(buf, "%s %s", s, (s2 = (char *)tagtypetags[typedata[ty.dat].id]) ? s2 : "(anonymous)"); return n + priquals(buf, qual); case TYUNION: s = "union"; -- cgit v1.2.3