aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--io.c11
-rw-r--r--lex.c66
-rw-r--r--lex.h5
-rw-r--r--test/pp.c2
-rw-r--r--test/pp.h9
5 files changed, 70 insertions, 23 deletions
diff --git a/io.c b/io.c
index 9b1720b..c8e338f 100644
--- a/io.c
+++ b/io.c
@@ -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>");
diff --git a/lex.c b/lex.c
index 62d81e0..f6e5ebd 100644
--- a/lex.c
+++ b/lex.c
@@ -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;
diff --git a/lex.h b/lex.h
index 3197cc8..3315d6b 100644
--- a/lex.h
+++ b/lex.h
@@ -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
*/
diff --git a/test/pp.c b/test/pp.c
index 2e6193e..f850c08 100644
--- a/test/pp.c
+++ b/test/pp.c
@@ -5,5 +5,7 @@
int
main(void)
{
+ printf("%s\n",STR ( ok /1 "\n"\n ;.&
+ 05.5));
hi(ADD(Foo, SQR(Bar+1)));
}
diff --git a/test/pp.h b/test/pp.h
index e914800..5ac7aac 100644
--- a/test/pp.h
+++ b/test/pp.h
@@ -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 *, ...);