From 78145f612583750e25090c4d37e418db9aa9c5e2 Mon Sep 17 00:00:00 2001 From: lemon Date: Mon, 13 Oct 2025 19:44:50 +0200 Subject: lex: allow ## in non func macros. and error reporting --- lex.c | 103 ++++++++++++++++++++++++++++++++++---------------------------- test/pp.c | 9 +++++- 2 files changed, 65 insertions(+), 47 deletions(-) diff --git a/lex.c b/lex.c index 20e4c5c..4bc5286 100644 --- a/lex.c +++ b/lex.c @@ -719,6 +719,56 @@ ppskipline(struct lexer *lx) next(lx); } +static bool +tokpaste(struct lexer *lx, struct token *dst, const struct token *l, const struct token *r) +{ + char *s; + dst->span = l->span; + if (dst->span.ex.file == r->span.ex.file && dst->span.ex.off < r->span.ex.off) + joinspan(&dst->span.ex, r->span.ex); + if (isppident(*l) && (isppident(*r) || r->t == TKNUMLIT)) { + /* foo ## bar ; foo ## 123 */ + dst->t = TKIDENT; + } else if (l->t == TKNUMLIT && (isppident(*r) || r->t == TKNUMLIT)) { + /* 0x ## abc ; 213 ## 456 */ + dst->t = TKNUMLIT; + } else if (l->t && !r->t) { + *dst = *l; + return 1; + } else if (!l->t && r->t) { + *dst = *r; + return 1; + } else { + static const struct { char s[2]; char t; } tab[] = { + {"==", TKEQU}, {"!=", TKNEQ}, {"<=", TKLTE}, {">=", TKGTE}, + {">>", TKSHR}, {"<<", TKSHL}, {"++", TKINC}, {"--", TKDEC}, + {"->", TKARROW}, {"##", TKPPCAT}, {"&&", TKLOGAND}, {"||", TKLOGIOR}, + {"+=", TKSETADD}, {"-=", TKSETSUB}, {"*=", TKSETMUL}, {"/=", TKSETDIV}, + {"%=", TKSETREM}, {"|=", TKSETIOR}, {"^=", TKSETXOR}, {"&=", TKSETAND}, + {{TKSHL,'='}, TKSETSHL}, {{TKSHR,'='}, TKSETSHR} + }; + struct span span = l->span; + + for (int i = 0; i < arraylength(tab); ++i) + if (tab[i].s[0] == l->t && tab[i].s[1] == r->t) + return dst->t = tab[i].t, 1; + + joinspan(&span.ex, r->span.ex); + error(&span, "pasting %'tk and %'tk does not form a valid preprocessing token", l, r); + return 0; + } + + /* shared for ident,keyword,numlit */ + dst->len = l->len + r->len; + s = alloc(lx->tmparena, dst->len + 1, 1); + memcpy(s, l->s, l->len); + memcpy(s + l->len, r->s, r->len); + s[l->len + r->len] = 0; + if (dst->t == TKIDENT) identkeyword(dst, s, dst->len); + else dst->s = s; + return 1; +} + static void ppdefine(struct lexer *lx) { @@ -787,6 +837,13 @@ ppdefine(struct lexer *lx) } } } + } else if (!mac.fnlike && rlist.n > 1 && rlist.p[rlist.n-1].t == TKPPCAT) { + struct token new; + if (tokpaste(lx, &new, &rlist.p[rlist.n-2], &tk)) { + rlist.p[rlist.n-2] = new; + --rlist.n; + continue; + } } vpush(&rlist, tk); Next:; @@ -861,52 +918,6 @@ popmac(struct lexer *lx) } while ((stk = lx->macstk) && stk->idx >= stk->rlist.n && !stk->stop); } -static bool -tokpaste(struct lexer *lx, struct token *dst, const struct token *l, const struct token *r) -{ - char *s; - dst->span = l->span; - if (dst->span.ex.file == r->span.ex.file && dst->span.ex.off < r->span.ex.off) - joinspan(&dst->span.ex, r->span.ex); - if (isppident(*l) && (isppident(*r) || r->t == TKNUMLIT)) { - /* foo ## bar ; foo ## 123 */ - dst->t = TKIDENT; - } else if (l->t == TKNUMLIT && (isppident(*r) || r->t == TKNUMLIT)) { - /* 0x ## abc ; 213 ## 456 */ - dst->t = TKNUMLIT; - } else if (l->t && !r->t) { - *dst = *l; - return 1; - } else if (!l->t && r->t) { - *dst = *r; - return 1; - } else { - static const struct { char s[2]; char t; } tab[] = { - {"==", TKEQU}, {"!=", TKNEQ}, {"<=", TKLTE}, {">=", TKGTE}, - {">>", TKSHR}, {"<<", TKSHL}, {"++", TKINC}, {"--", TKDEC}, - {"->", TKARROW}, {"##", TKPPCAT}, {"&&", TKLOGAND}, {"||", TKLOGIOR}, - {"+=", TKSETADD}, {"-=", TKSETSUB}, {"*=", TKSETMUL}, {"/=", TKSETDIV}, - {"%=", TKSETREM}, {"|=", TKSETIOR}, {"^=", TKSETXOR}, {"&=", TKSETAND}, - {{TKSHL,'='}, TKSETSHL}, {{TKSHR,'='}, TKSETSHR} - }; - for (int i = 0; i < arraylength(tab); ++i) - if (tab[i].s[0] == l->t && tab[i].s[1] == r->t) - return dst->t = tab[i].t, 1; - return 0; - } - - /* shared for ident,keyword,numlit */ - dst->len = l->len + r->len; - s = alloc(lx->tmparena, dst->len + 1, 1); - memcpy(s, l->s, l->len); - memcpy(s + l->len, r->s, r->len); - s[l->len + r->len] = 0; - if (dst->t == TKIDENT) identkeyword(dst, s, dst->len); - else dst->s = s; - return 1; -} - - static bool tryexpand(struct lexer *lx, struct token *tk) { diff --git a/test/pp.c b/test/pp.c index 0aa5287..7c34542 100644 --- a/test/pp.c +++ b/test/pp.c @@ -8,6 +8,11 @@ #define CATr(a) foo##a #define CAT(a,b) a##b +#define hash_hash # ## # +#define mkstr(a) # a +#define in_between(a) mkstr(a) +#define join(c, d) in_between(c hash_hash d) +char p[] = join(x, y); // equivalent to char p[] = "x ## y"; int main(void) @@ -20,5 +25,7 @@ main(void) 05.5), STR(ADD(1,2))); hi(ADD(Foo, SQR(Bar+1))); int foo123 = 77; - printf("%s %s %g\n", str(Foo,5), xstr(Foo), CAT(1.5,e3f) + CAT(7,)-CAT(1,)); + printf("%s %s %g\n", str(Foo,5), xstr(Foo), CAT(1.5,e3f) + CAT(7,)-CAT(,1)); + printf("join: \"%s\"\n", p); + CAT(ret,urn) 0; } -- cgit v1.2.3