diff options
| author | 2025-09-10 20:15:56 +0200 | |
|---|---|---|
| committer | 2025-09-10 22:41:39 +0200 | |
| commit | 5bcdee9f0702e4f54897166250898475f0d26ca3 (patch) | |
| tree | abc9087456157ab2b182b25a3ab65c3dfcf4433b | |
| parent | 3fc3b2680581a59b3d08244a190d5d7bdcf80e45 (diff) | |
lex: stringify args in function macros
| -rw-r--r-- | io.c | 11 | ||||
| -rw-r--r-- | lex.c | 66 | ||||
| -rw-r--r-- | lex.h | 5 | ||||
| -rw-r--r-- | test/pp.c | 2 | ||||
| -rw-r--r-- | test/pp.h | 9 |
5 files changed, 70 insertions, 23 deletions
@@ -475,9 +475,16 @@ vbfmt(struct wbuf *out, const char *fmt, va_list ap) case TKSTRLIT: n += bfmt(buf, "%'S", tok->s, tok->len); break; - case TKIDENT: + case TKPPMACSTR: + if (quote) n += bputc(buf, '`'); + n += bfmt(buf, "#%s", tok->s); + if (quote) n += bputc(buf, '\''); + break; case TKPPMACARG: - n += bfmt(buf, "`%s'", tok->s); + case TKIDENT: + if (quote) n += bputc(buf, '`'); + n += bfmt(buf, "%s", tok->s); + if (quote) n += bputc(buf, '\''); break; case TKEOF: n += bwriteS(buf, "<end-of-file>"); @@ -571,7 +571,7 @@ struct macro { uchar nparam; bool fnlike, variadic; struct rlist { - struct token *tk; + const struct token *tk; int n; } rlist; }; @@ -602,7 +602,7 @@ static void freemac(struct macro *mac) { free(mac->param); - free(mac->rlist.tk); + free((void *)mac->rlist.tk); } static bool @@ -639,7 +639,7 @@ macroequ(const struct macro *a, const struct macro *b) } if (a->rlist.n != b->rlist.n) return 0; for (i = 0; i < a->rlist.n; ++i) { - struct token *tka = a->rlist.tk, *tkb = b->rlist.tk; + const struct token *tka = a->rlist.tk, *tkb = b->rlist.tk; if (!tokequ(&tka[i], &tkb[i])) return 0; if (i && wsseparated(&tka[i-1], &tka[i]) != wsseparated(&tkb[i-1], &tkb[i])) @@ -726,12 +726,20 @@ ppdefine(struct lexer *lx) warn(&tk.span, "no whitespace after macro name"); if (mac.fnlike && isppident(tk)) for (int i = 0; i < mac.nparam; ++i) { if (tk.s == mac.param[i]) { - tk.t = TKPPMACARG; - tk.argidx = i; - break; + if (rlist.n > 0 && rlist.p[rlist.n - 1].t == '#') { + tk.t = TKPPMACSTR; + tk.argidx = i; + rlist.p[rlist.n - 1] = tk; + goto Next; + } else { + tk.t = TKPPMACARG; + tk.argidx = i; + break; + } } } vpush(&rlist, tk); + Next:; } mac.rlist.tk = rlist.p; mac.rlist.n = rlist.n; @@ -1100,7 +1108,7 @@ pushmacstk(struct lexer *lx, const struct span *span, const struct macrostack *m } static bool -tryexpand(struct lexer *lx, const struct token *tk) +tryexpand(struct lexer *lx, struct token *tk) { static bool inimstk; int macidx, i; @@ -1117,18 +1125,38 @@ tryexpand(struct lexer *lx, const struct token *tk) } } - if (tk->t == TKPPMACARG) { + if (tk->t == TKPPMACARG || tk->t == TKPPMACSTR) { struct rlist *arg; l = lx->macstk; arg = &l->args[tk->argidx]; - if (arg->n) { + if (tk->t == TKPPMACARG && arg->n) { pushmacstk(lx, &span, &(struct macrostack){ .idx = 0, .rlist = arg, .macno = -1, }); + return 1; + } else { + char tmp[200]; + struct wbuf buf = MEMBUF(tmp, sizeof tmp); + //vec_of(uchar) b = VINIT(tmp, sizeof tmp); + + // XXX this is wrong bc the string literal produced should be re-parsed later + // i.e. stringifying the token sequence '\n' should ultimately produce a + // string with an actual newline, not {'\\','n'} + + for (const struct token *tk = arg->tk, *end = tk + arg->n; tk != end; ++tk) { + if (tk != arg->tk && wsseparated(tk-1, tk)) + bfmt(&buf, " "); + bfmt(&buf, "%tk", tk); + } + ioputc(&buf, 0); + assert(!buf.err && "strify too long"); + tk->t = TKSTRLIT; + tk->s = alloccopy(lx->tmparena, buf.buf, buf.len, 1); + tk->len = buf.len; + return 0; } - return 1; } else if (!isppident(*tk) || !(mac = findmac(tk->s))) return 0; @@ -1142,7 +1170,7 @@ tryexpand(struct lexer *lx, const struct token *tk) if (mac->fnlike) { vec_of(struct token) rlist = {0}; bool toomany = 0; - struct span endspan; + struct span excessspan; int cur, n, i, bal; struct token tk; @@ -1151,11 +1179,16 @@ tryexpand(struct lexer *lx, const struct token *tk) lex(lx, &tk); args = xcalloc((mac->nparam + mac->variadic) * sizeof *args); - for (cur = 0, i = 0, bal = 0, n = 0; (lex(lx, &tk) != ')' || bal != 0) && tk.t != TKEOF; ) { + /* we push all arg tokens to rlist, each of args[i] is a slice (idx..idx+n) of the rlist vector; + * while we're building the list, args[i].tk points to &tk + idx, because rlist.p can move, + * then we fix them up in the end to point to rlist.p + idx */ + + cur = i = bal = n = 0; + while ((lex(lx, &tk) != ')' || bal != 0) && tk.t != TKEOF) { if (tk.t == ',' && bal == 0) { if (i == mac->nparam-1) { if (!mac->variadic) { - endspan = tk.span; + excessspan = tk.span; toomany = 1; } } else if (i < mac->nparam) { @@ -1185,9 +1218,10 @@ tryexpand(struct lexer *lx, const struct token *tk) if (i < mac->nparam) error(&span, "not enough arguments in function-like macro invocation"); else if (toomany) { - joinspan(&endspan.ex, tk.span.ex); - error(&endspan, "excess arguments in function-like macro invocation"); + joinspan(&excessspan.ex, tk.span.ex); + error(&excessspan, "excess arguments in function-like macro invocation"); } + /* fix up args slice pointers */ for (int i = 0; i < mac->nparam + mac->variadic; ++i) { int idx = args[i].tk ? args[i].tk - &tk : rlist.n; args[i].tk = rlist.p + idx; @@ -1213,7 +1247,7 @@ popmac(struct lexer *lx) assert(stk = lx->macstk); do { if (stk->args) { - free(stk->args->tk); + free((void *)stk->args->tk); free(stk->args); } lx->macstk = stk->link; @@ -17,7 +17,8 @@ enum toktag { /* single-character tokens' tag value is the character itself */ TKSTRLIT, TKPPHDRH, /* <hdr> (for #include) */ TKPPHDRQ, /* "hdr" (for #include) */ - TKPPMACARG, /* macro param in repl list */ + TKPPMACARG, /* macro param, in repl list */ + TKPPMACSTR, /* stringify macro param, in repl list */ TKEQU = '@', /* == */ TKNEQ, /* != */ TKLTE, /* <= */ @@ -66,7 +67,7 @@ struct token { * when litlit : s points to start of token within file buffer (normal case) * len == span.sl.len (number literal appears literally in source code) * otherwise s is heap allocated buffer of len bytes - * for macro arg: + * for macro arg/stringify: * s is like keyword/ident * argidx is index in macro param list */ @@ -5,5 +5,7 @@ int main(void) { + printf("%s\n",STR ( ok /1 "\n"\n ;.& + 05.5)); hi(ADD(Foo, SQR(Bar+1))); } @@ -1,18 +1,21 @@ #ifndef GUARD #define GUARD +extern int printf(const char *, ...); extern warnhere(); #define Foo 9 void hi(int x) { - extern int printf(const char *, ...); printf("hi from header ;%d\n", x); } #if 1 #endif #elifndef Ww #define Bar 7 -#define SQR_(x) (x)*(x) -#define SQR(y) SQR_(y) +#define SQR_(x) ((x)*(x)) +#define SQR(y) SQR_(1+(y)-1) #define ADD(a,b) (a)+(b) +#define STR(h) #h #endif + +extern int printf(const char *, ...); |