aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2026-03-21 17:55:01 +0100
committerlemon <lsof@mailbox.org>2026-03-21 17:55:01 +0100
commit0e75fc383becccd113416677b7e26e0caf21e28b (patch)
tree356cf6c271ea8e0b2ca0211ac0c9efe776cc2118 /src
parent8b846d0245744f4eefc32f3c98b6359a3d21e659 (diff)
Rework handling of predefined macros.
And add some GCC predefs like __SIZE_TYPE__, __LONG_SIZE__, etc
Diffstat (limited to 'src')
-rw-r--r--src/a_embedfilesdir.c6
-rw-r--r--src/a_main.c28
-rw-r--r--src/a_targ.c83
-rw-r--r--src/antcc.h4
-rw-r--r--src/c.c6
-rw-r--r--src/c_lex.c129
-rw-r--r--src/c_type.c31
-rw-r--r--src/c_type.h3
-rw-r--r--src/ir_dump.c4
-rw-r--r--src/u_io.c25
10 files changed, 227 insertions, 92 deletions
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, "<command line>");
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";