aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--c.c30
-rw-r--r--common.h11
-rw-r--r--embedfilesdir.c34
-rw-r--r--io.c17
-rw-r--r--lex.c926
-rw-r--r--lex.h3
-rw-r--r--main.c17
-rw-r--r--test/hello.c2
-rw-r--r--test/pp.c14
-rw-r--r--test/pp.h2
11 files changed, 770 insertions, 289 deletions
diff --git a/Makefile b/Makefile
index 2b2a7ca..123409d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,6 @@
SRC=main.c io.c mem.c c.c lex.c type.c targ.c eval.c ir.c irdump.c ssa.c cfg.c \
- intrin.c abi0.c optmem.c regalloc.c amd64/sysv.c amd64/isel.c amd64/emit.c obj.c elf.c
+ intrin.c abi0.c optmem.c regalloc.c amd64/sysv.c amd64/isel.c amd64/emit.c obj.c elf.c\
+ embedfilesdir.c
CFLAGS=-Wall -std=c11 -pedantic
OBJ=$(patsubst %.c,obj/%.o,$(SRC))
DEP=$(OBJ:.o=.d)
diff --git a/c.c b/c.c
index 29028b2..8109a9b 100644
--- a/c.c
+++ b/c.c
@@ -1878,6 +1878,10 @@ declspec(struct declstate *st, struct comp *cm)
case TKWconst:
st->qual |= QCONST;
break;
+ case TKWrestrict:
+ /* unimplemented */
+ /*st->qual |= QRESTRICT;*/
+ break;
case TKWvolatile:
st->qual |= QVOLATILE;
break;
@@ -1981,8 +1985,9 @@ End:
else if (arith == KDOUBLE)
t = TYDOUBLE;
else if (arith == (KLONG | KDOUBLE)) {
- t = TYLDOUBLE;
- error(&span, "`long double' is unsupported");
+ /* t = TYLDOUBLE; */
+ warn(&span, "`long double' is unsupported");
+ t = TYDOUBLE;
} else if (arith == KBOOL)
t = TYBOOL;
else if (arith == KCHAR)
@@ -2081,8 +2086,8 @@ cvqual(struct comp *cm)
{
struct token tk;
int q = 0;
- while (match(cm, &tk, TKWconst) || match(cm, &tk, TKWvolatile))
- q |= tk.t == TKWconst ? QCONST : QVOLATILE;
+ while (match(cm, &tk, TKWconst) || match(cm, &tk, TKWvolatile) || match(cm, &tk, TKWrestrict))
+ q |= tk.t == TKWconst ? QCONST : tk.t == TKWvolatile ? QVOLATILE : 0;
return q;
}
@@ -2568,7 +2573,7 @@ geninit(struct function *fn, union type t, union ref dst, const struct expr *src
for (struct initval *val = ini->vals; val; val = val->next) {
uint off = val->off;
struct expr *ex = &val->ex;
- adr = off == 0 ? dst : addinstr(fn, mkinstr(Oadd, KPTR, dst, mkref(RICON, off)));
+ adr = off == 0 ? dst : addinstr(fn, mkinstr(Oadd, KPTR, dst, mkref(RICON, off)));
genstore(fn, ex->ty, adr, exprvalue(fn, ex));
}
} else if (src->t == ESTRLIT) {
@@ -3264,7 +3269,7 @@ loopbody(struct comp *cm, struct function *fn, struct block *brk, struct block *
struct swcase {
vlong val;
- struct block *blk;
+ struct block *blk;
};
struct switchstmt {
struct block *bdefault;
@@ -3307,7 +3312,7 @@ genswitch(struct comp *cm, struct function *fn, const struct expr *ex)
* 4. jump tables? (harder)
*/
for (int i = 0; i < st.cases.n; ++i) {
- struct swcase c = st.cases.p[i];
+ struct swcase c = st.cases.p[i];
EMITS {
struct block *next = i < st.cases.n - 1 ? newblk(fn) : st.bdefault;
putcondbranch(fn, addinstr(fn, mkinstr(Oequ, k, .l = sel, .r = mkintcon(k, c.val))), c.blk, next);
@@ -3631,6 +3636,7 @@ stmt(struct comp *cm, struct function *fn)
break;
}
freearena(&cm->exarena);
+ lexerfreetemps(&cm->lx);
return fn->curblk == NULL;
}
@@ -3833,7 +3839,7 @@ docomp(struct comp *cm)
while (peek(cm, tk) != TKEOF) {
struct declstate st = { DTOPLEVEL };
do {
- bool noscls;
+ bool noscls = 0;
int nerr = nerror;
struct decl decl = pdecl(&st, cm);
@@ -3866,7 +3872,7 @@ docomp(struct comp *cm)
if (st.varini) {
(void) initializer(cm, &d->ty, EVSTATICINI, decl.scls != SCSTATIC, decl.qual, decl.name);
pdecl(&st, cm);
- } else if (decl.ty.t != TYFUNC && (decl.scls != SCEXTERN || noscls)) {
+ } else if (decl.ty.t != TYFUNC && decl.scls != SCTYPEDEF && (decl.scls != SCEXTERN || noscls)) {
objnewdat(d->name, Sbss, decl.scls == SCEXTERN, typesize(d->ty), typealign(d->ty));
}
if (ccopt.dbg.p) efmt("var %s : %tq\n", d->name, d->ty, d->qual);
@@ -3875,6 +3881,7 @@ docomp(struct comp *cm)
}
freearena(&cm->fnarena);
freearena(&cm->exarena);
+ lexerfreetemps(&cm->lx);
} while (st.more);
}
}
@@ -3885,8 +3892,9 @@ ccomp(const char *file)
enum { N = 1<<12 };
static union { char m[sizeof(struct arena) + N]; struct arena *_align; } amem[2];
struct comp cm = {0};
-
- initlexer(&cm.lx, NULL, file, &cm.exarena);
+ const char *err = initlexer(&cm.lx, NULL, file);
+ if (err)
+ fatal(NULL, "Cannot open %'s: %s", file, err);
cm.fnarena = (void *)amem[0].m;
cm.fnarena->cap = N;
cm.exarena = (void *)amem[1].m;
diff --git a/common.h b/common.h
index f9cc203..0269aa7 100644
--- a/common.h
+++ b/common.h
@@ -137,6 +137,10 @@ struct option {
} dbg;
};
extern struct option ccopt;
+extern struct inclpaths {
+ struct inclpaths *next;
+ const char *path;
+} *cinclpaths;
/*************************/
/** TYPE REPRESENTATION **/
@@ -531,6 +535,13 @@ struct wbuf {
struct memfile {
const uchar *p;
uint n;
+ bool statik;
+};
+
+struct embedfile {
+ const char *name;
+ const char *s;
+ size_t len;
};
#define MEMBUF(buf, cap) { (buf), (cap), .fd = -1 }
diff --git a/embedfilesdir.c b/embedfilesdir.c
new file mode 100644
index 0000000..e2f223b
--- /dev/null
+++ b/embedfilesdir.c
@@ -0,0 +1,34 @@
+#include <stddef.h>
+
+struct embedfile {
+ const char *name;
+ const char *s;
+ size_t len;
+};
+
+#define S(s) (char [4096]){s}, sizeof #s - 1
+
+struct embedfile embedfilesdir[] = {
+{"stddef.h", S("\
+typedef __typeof__((char*)0 - (char*)0) ptrdiff_t;\n\
+typedef __typeof__(sizeof 0) size_t;\n\
+/*typedef __typeof__(L'a') wchar_t;*/\n\
+#define NULL ((void *)0)\n\
+#define offsetof(_Type, _Memb) ((size_t)(&((_Type *)0)->_Memb - (_Type *)0))\n\
+")},
+
+{"stdarg.h", S("\
+typedef __builtin_va_list va_list;\n\
+#ifndef __GNUC_VA_LIST\n\
+#define __GNUC_VA_LIST\n\
+typedef __builtin_va_list __gnuc_va_list;\n\
+#endif\n\
+#define va_start(ap,n) __builtin_va_start(ap)\n\
+#define va_arg(ap,type) __builtin_va_arg(ap, type)\n\
+#define va_copy(dst,src) (void)((dst)=(src))\n\
+#define va_end(ap) __builtin_va_end(ap)\n\
+")},
+ {NULL}
+};
+
+/* vim:set ts=3 sw=3 expandtab: */
diff --git a/io.c b/io.c
index 592cf48..2a9e876 100644
--- a/io.c
+++ b/io.c
@@ -627,6 +627,8 @@ bfmt(struct wbuf *buf, const char *fmt, ...)
static uint pagesiz;
+extern struct embedfile embedfilesdir[];
+
struct memfile
mapopen(const char **err, const char *path)
{
@@ -641,6 +643,14 @@ mapopen(const char **err, const char *path)
if (!pagesiz) pagesiz = sysconf(_SC_PAGESIZE);
*err = NULL;
+ if (*path == '@' && path[1] == ':') {
+ for (struct embedfile *e = embedfilesdir; e->name; ++e) {
+ if (!strcmp(e->name, path+2)) {
+ return (struct memfile) { (const uchar *)e->s, e->len, .statik = 1 };
+ }
+ }
+ }
+
if ((fd = open(path, O_RDONLY)) < 0)
goto Err;
if (fstat(fd, &stat) != 0)
@@ -707,7 +717,8 @@ void
mapclose(struct memfile *f)
{
assert(f->p);
- munmap((void *)f->p, alignup(f->n, pagesiz) + pagesiz);
+ if (!f->statik)
+ munmap((void *)f->p, alignup(f->n, pagesiz) + pagesiz);
memset(f, 0, sizeof *f);
}
@@ -793,8 +804,8 @@ getfilepos(int *line, int *col, int id, uint off)
else break;
}
i -= offs[i] > off;
- *line = i + 1;
- *col = off - offs[i] + 1;
+ if (line) *line = i + 1;
+ if (col) *col = off - offs[i] + 1;
}
void
diff --git a/lex.c b/lex.c
index 401b84d..20e4c5c 100644
--- a/lex.c
+++ b/lex.c
@@ -4,23 +4,23 @@
const char *
intern(const char *s)
{
- static vec_of(char) mem;
- static uint ht[1<<10];
+ static const char *ht[1<<10];
+ static struct { char m[sizeof(struct arena) + (1<<10)]; struct arena *_a; } amem;
+ static struct arena *arena;
uint h, i, n = arraylength(ht);
- if (!mem.p) vinit(&mem, NULL, 1<<10);
-
+ if (!arena) arena = (void *)amem.m, arena->cap = 1<<10;
+
i = h = hashs(0, s);
for (;; ++i) {
i &= arraylength(ht) - 1;
if (!ht[i]) {
- ht[i] = mem.n+1;
- return vpushn(&mem, s, strlen(s)+1);
- } else if (!strcmp(s, &mem.p[ht[i]-1])) {
- return &mem.p[ht[i]-1];
+ return ht[i] = alloccopy(&arena, s, strlen(s)+1, 1);
+ } else if (!strcmp(s, ht[i])) {
+ return ht[i];
}
assert(--n > 0 && "intern full");
- }
+ }
}
static bool
@@ -50,6 +50,7 @@ identkeyword(struct token *tk, const char *s, int len)
ident:
tk->t = TKIDENT;
tk->s = intern(s);
+ tk->len = len;
return 1;
}
@@ -544,6 +545,7 @@ Begin:
"%'tk in %M is an extension", tk);
goto End;
}
+ case 0: if (lx->idx >= lx->ndat) RET(TKEOF);
}
fatal(&(struct span) {{ idx, lx->chridx - idx, lx->fileid }},
"unexpected character %'c at %d", c, idx);
@@ -561,15 +563,21 @@ End:
/****************/
struct macro {
- const char *name; /* interned */
+ const char *name; /* interned. NULL for tombstone */
const char **param;
struct span0 span;
uchar nparam;
- bool fnlike, variadic;
- struct rlist {
- const struct token *tk;
- int n;
- } rlist;
+ bool predefined,
+ special,
+ fnlike,
+ variadic;
+ union {
+ void (*handler)(struct lexer *, struct token *);
+ struct rlist {
+ const struct token *tk;
+ int n;
+ } rlist;
+ };
};
#define isppident(tk) (in_range((tk).t, TKIDENT, TKWEND_))
@@ -581,7 +589,7 @@ static struct macro *
findmac(const char *name)
{
uint h, i, n = arraylength(macroht);
-
+
i = h = ptrhash(name);
for (; n--; ++i) {
i &= arraylength(macroht) - 1;
@@ -597,6 +605,7 @@ findmac(const char *name)
static void
freemac(struct macro *mac)
{
+ if (mac->special) return;
free(mac->param);
free((void *)mac->rlist.tk);
}
@@ -626,6 +635,7 @@ macroequ(const struct macro *a, const struct macro *b)
{
int i;
if (a->name != b->name) return 0;
+ if (a->special != b->special) return 0;
if (a->fnlike != b->fnlike || a->variadic != b->variadic) return 0;
if (a->fnlike) {
if (a->nparam != b->nparam) return 0;
@@ -633,6 +643,7 @@ macroequ(const struct macro *a, const struct macro *b)
if (a->param[i] != b->param[i])
return 0;
}
+ if (a->special) return a->handler == b->handler;
if (a->rlist.n != b->rlist.n) return 0;
for (i = 0; i < a->rlist.n; ++i) {
const struct token *tka = a->rlist.tk, *tkb = b->rlist.tk;
@@ -649,7 +660,7 @@ putmac(struct macro *mac)
{
uint h, i, n = arraylength(macroht);
struct macro *slot;
-
+
i = h = ptrhash(mac->name);
for (;; ++i) {
i &= arraylength(macroht) - 1;
@@ -659,22 +670,51 @@ putmac(struct macro *mac)
return &macros.p[macros.n - 1];
} else if ((slot = &macros.p[macroht[i]-1])->name == mac->name) {
if (!macroequ(slot, mac)) {
- warn(&(struct span){mac->span}, "redefining macro");
- note(&(struct span){slot->span}, "previous definition:");
+ if (slot->predefined)
+ warn(&(struct span){mac->span}, "redefining builtin macro");
+ else {
+ warn(&(struct span){mac->span}, "redefining macro");
+ note(&(struct span){slot->span}, "previous definition:");
+ }
freemac(slot);
*slot = *mac;
} else {
freemac(mac);
}
return slot;
+ } else if (!slot->name) { /* was tomb */
+ *slot = *mac;
}
assert(--n && "macro limit");
}
}
static void
+delmac(const char *name)
+{
+ uint h, i;
+
+ i = h = ptrhash(name);
+ for (;; ++i) {
+ struct macro *slot;
+
+ i &= arraylength(macroht) - 1;
+ if (!macroht[i]) {
+ return;
+ } else if ((slot = &macros.p[macroht[i]-1])->name == name) {
+ freemac(slot);
+ slot->name = NULL;
+ return;
+ }
+ }
+}
+
+static void popmac(struct lexer *);
+
+static void
ppskipline(struct lexer *lx)
{
+ while (lx->macstk) popmac(lx);
while (peek(lx, 0) != '\n' && peek(lx, 0) != TKEOF)
next(lx);
}
@@ -696,10 +736,17 @@ ppdefine(struct lexer *lx)
}
mac.name = tk0.s;
mac.span = tk0.span.sl;
-
+
if (match(lx, '(')) {
+ //efmt("FUNCLIKE %s\n", mac.name);
mac.fnlike = 1;
while (lex0(lx, &tk0) != ')') {
+ if (mac.variadic) {
+ error(&tk0.span, "expected `)' after `...'");
+ if (tk0.t == TKEOF)
+ return;
+ else break;
+ }
if (params.n > 0) {
if (tk0.t != ',')
error(&tk0.span, "expected `,' or `)'");
@@ -708,7 +755,10 @@ ppdefine(struct lexer *lx)
}
if (isppident(tk0))
vpush(&params, tk0.s);
- else {
+ else if (tk0.t == TKDOTS) {
+ mac.variadic = 1;
+ vpush(&params, intern("__VA_ARGS__"));
+ } else {
error(&tk0.span, "expected parameter name or `)'");
if (tk0.t == TKEOF)
return;
@@ -722,19 +772,19 @@ ppdefine(struct lexer *lx)
while (lex0(lx, &tk) != '\n' && tk.t != TKEOF) {
if (!wsseparated(&tk0, &tk))
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]) {
- if (rlist.n > 0 && rlist.p[rlist.n - 1].t == '#') {
- tk.t = TKPPMACSTR;
+ if (mac.fnlike && isppident(tk)) {
+ for (int i = 0; i < mac.nparam; ++i) {
+ if (tk.s == mac.param[i]) {
tk.argidx = i;
tk.macidx = newmacidx;
- rlist.p[rlist.n - 1] = tk;
- goto Next;
- } else {
- tk.t = TKPPMACARG;
- tk.argidx = i;
- tk.macidx = newmacidx;
- break;
+ if (rlist.n > 0 && rlist.p[rlist.n - 1].t == '#') {
+ tk.t = TKPPMACSTR;
+ rlist.p[rlist.n - 1] = tk;
+ goto Next;
+ } else {
+ tk.t = TKPPMACARG;
+ break;
+ }
}
}
}
@@ -746,6 +796,367 @@ ppdefine(struct lexer *lx)
putmac(&mac);
}
+static void
+ppundef(struct lexer *lx)
+{
+ struct token tk;
+
+ lex0(lx, &tk);
+ if (!isppident(tk)) {
+ error(&tk.span, "macro name missing");
+ ppskipline(lx);
+ return;
+ }
+ delmac(tk.s);
+}
+
+/* kludge for proper expansion in the face of nested macros with arguments,
+ * stringifying, etc */
+static bool noexpandmac;
+
+static struct macrostack {
+ struct macrostack *link;
+ struct rlist rlist;
+ struct span0 exspan;
+ int idx;
+ int macno:30;
+ int prevnoexpandmac:1;
+ bool stop;
+} mstk[64], *mfreelist;
+
+static void
+pushmacstk(struct lexer *lx, const struct span *span, const struct macrostack *m)
+{
+ struct macrostack *l;
+ if (!(l = mfreelist)) fatal(span, "macro depth limit reached");
+ l = mfreelist;
+ mfreelist = l->link;
+ l->link = lx->macstk;
+ l->rlist = m->rlist;
+ l->macno = m->macno;
+ l->idx = 0;
+ l->stop = m->stop;
+ l->exspan = span->ex;
+ l->prevnoexpandmac = noexpandmac;
+ lx->macstk = l;
+ //efmt("PUSH %s %p\n", m->macno >= 0 ? macros.p[m->macno].name : "?", l);
+}
+
+static void
+popmac(struct lexer *lx)
+{
+ struct macrostack *stk;
+
+ assert(stk = lx->macstk);
+ do {
+ noexpandmac = stk->prevnoexpandmac;
+ //if(stk->macno>=0)efmt("POP %s <<\n", macros.p[stk->macno].name, noexpandmac);
+ if (stk->macno >= 0 && !macros.p[stk->macno].special
+ && stk->rlist.tk != macros.p[stk->macno].rlist.tk) {
+ free((void *)stk->rlist.tk);
+ }
+ lx->macstk = stk->link;
+ stk->link = mfreelist;
+ mfreelist = stk;
+ } 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)
+{
+ static bool inimstk;
+ int macidx, i;
+ struct span span = tk->span;
+ struct macrostack *l;
+ struct macro *mac = NULL;
+
+ if (!inimstk) {
+ inimstk = 1;
+ for (i = 0; i < arraylength(mstk); ++i) {
+ mstk[i].link = mfreelist;
+ mfreelist = &mstk[i];
+ }
+ }
+
+ if (noexpandmac || !isppident(*tk) || !(mac = findmac(tk->s)))
+ return 0;
+
+ macidx = mac - macros.p;
+ /* prevent infinite recursion */
+ for (l = lx->macstk; l; l = l->link)
+ if (l->macno == macidx)
+ return 0;
+
+ if (mac->special) {
+ mac->handler(lx, tk);
+ pushmacstk(lx, &span, &(struct macrostack){
+ .rlist = { alloccopy(lx->tmparena, tk, sizeof *tk, 0), 1 },
+ .macno = -1,
+ .idx = 0,
+ });
+ return 1;
+ }
+
+ if (mac->fnlike) {
+ vec_of(struct token) argsbuf = {0}, rlist2 = {0};
+ struct argtks { int idx, n; } args[100];
+ struct span excessspan;
+ int cur, len, i, bal, narg;
+ struct token tk;
+ bool toomany = 0;
+
+ noexpandmac = 1;
+ //efmt(">>HI %s\n", mac->name);
+ if (lexpeek(lx, &tk) != '(') {
+ noexpandmac = 0;
+ return 0;
+ }
+ lex(lx, &tk);
+
+ /* we push all arg tokens to buffer, each of args[i] is a slice (idx..idx+n) of the 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 = len = narg = 0;
+ while ((lex(lx, &tk) != ')' || bal != 0) && tk.t != TKEOF) {
+ if (tk.t == ',' && bal == 0) {
+ ++narg;
+ if (i == mac->nparam-1 && !mac->variadic) {
+ excessspan = tk.span;
+ toomany = 1;
+ } else if (i < mac->nparam - mac->variadic) {
+ args[i].idx = cur;
+ args[i].n = len;
+ cur = argsbuf.n;
+ len = 0;
+ ++i;
+ } else if (mac->variadic) {
+ vpush(&argsbuf, tk);
+ ++len;
+ }
+ } else if (!toomany) {
+ if (tk.t == '(' || tk.t == '[') ++bal;
+ else if (tk.t == ')' || tk.t == ']') --bal;
+ vpush(&argsbuf, tk);
+ ++len;
+ }
+ }
+ noexpandmac = 0;
+ if (tk.t == TKEOF)
+ error(&span, "unterminated function-like macro invocation");
+ else if (i < mac->nparam) {
+ ++narg;
+ args[i].idx = cur;
+ args[i].n = len;
+ cur = argsbuf.n;
+ len = 0;
+ ++i;
+ }
+ joinspan(&span.ex, tk.span.ex);
+ if (narg < mac->nparam)
+ error(&span, "macro `%s' passed %d arguments, but takes %d", mac->name, narg, mac->nparam);
+ else if (toomany) {
+ joinspan(&excessspan.ex, tk.span.ex);
+ error(&excessspan, "macro `%s' passed %d arguments, but takes just %d", mac->name, narg, mac->nparam);
+ }
+
+ /* make new rlist with args replaced */
+ if (mac->nparam) {
+ //efmt("invoke %s\n", mac->name);
+ struct token lhsargforpaste;
+ bool lhsargpaste = 0, rhsargpaste = 0;
+ for (int i = 0; i < mac->rlist.n; ++i) {
+ struct argtks *arg, *arg2;
+ tk = mac->rlist.tk[i];
+ if (tk.t == TKPPCAT) {
+ if (i > 0 && i < mac->rlist.n-1) {
+ const struct token *lhs = &mac->rlist.tk[i-1], *rhs = &mac->rlist.tk[i+1];
+ struct token new;
+ if (lhs->t != TKPPMACARG && rhs->t != TKPPMACARG) {
+ /* trivial case */
+ if (tokpaste(lx, &new, lhs, rhs)) {
+ rlist2.p[rlist2.n - 1] = new;
+ ++i;
+ continue;
+ }
+ } else if (rhs->t != TKPPMACARG) {
+ assert(lhsargpaste);
+ if (tokpaste(lx, &new, &lhsargforpaste, rhs)) {
+ vpush(&rlist2, new);
+ ++i;
+ continue;
+ }
+ lhsargpaste = 0;
+ } else {
+ if (lhs->t != TKPPMACARG) {
+ --rlist2.n;
+ lhsargforpaste = *lhs;
+ }
+ rhsargpaste = 1;
+ continue;
+ }
+ }
+ } else if (tk.t != TKPPMACARG && tk.t != TKPPMACSTR) {
+ //efmt(" [%tk]\n", &tk);
+ vpush(&rlist2, tk);
+ continue;
+ }
+
+ arg = &args[tk.argidx];
+ if (tk.t == TKPPMACARG) {
+ struct macrostack *l;
+ /*efmt("replcing arg %d { ", tk.argidx);
+ for (int i = 0; i < arg->n; ++i)
+ efmt("%tk ", &arg->tk[i]);
+ efmt("}: {\n");*/
+ lhsargpaste = i < mac->rlist.n-1 && mac->rlist.tk[i+1].t == TKPPCAT;
+ if (arg->n == 0) {
+ if (rhsargpaste) {
+ rhsargpaste = 0;
+ vpush(&rlist2, lhsargforpaste);
+ }
+ continue;
+ }
+ pushmacstk(lx, &tk.span, &(struct macrostack) {
+ .rlist = {argsbuf.p + arg->idx, arg->n - lhsargpaste},
+ .macno = -1,
+ .idx = 0,
+ .stop = 1,
+ });
+ l = lx->macstk;
+ if (rhsargpaste) {
+ struct token new;
+ rhsargpaste = 0;
+ if (tokpaste(lx, &new, &lhsargforpaste, &l->rlist.tk[0])) {
+ l->idx = 1;
+ vpush(&rlist2, new);
+ }
+ }
+ //efmt("saved %p\n", l);
+ while (l->idx < l->rlist.n) {
+ tk = l->rlist.tk[l->idx++];
+ /* expand argument only once */
+ if (tk.s != mac->name && tryexpand(lx, &tk)) {
+ assert(l != lx->macstk);
+ while (lx->macstk->idx < lx->macstk->rlist.n) {
+ //efmt(" [%tk]\n", &lx->macstk->rlist.tk[lx->macstk->idx]);
+ vpush(&rlist2, lx->macstk->rlist.tk[lx->macstk->idx++]);
+ }
+ popmac(lx);
+ } else {
+ //efmt(" [%tk]\n", &tk);
+ vpush(&rlist2, tk);
+ }
+ //efmt("now %p\n", lx->macstk);
+ assert(lx->macstk == l);
+ }
+ popmac(lx);
+ if (lhsargpaste)
+ lhsargforpaste = argsbuf.p[arg->idx + arg->n-1];
+ //efmt("} /%s\n", mac->name);
+ } else { /* PPMACSTR */
+ char tmp[100];
+ struct wbuf buf = MEMBUF(tmp, sizeof tmp);
+ int n = 0;
+
+ // 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'}
+ Redo:
+ for (int i = 0; i < arg->n; ++i) {
+ struct token *tk = &argsbuf.p[arg->idx + i];
+ //efmt("strify ++ (%d) %'tk\n", tk->t,tk);
+ if (i > 0 && wsseparated(tk-1, tk))
+ n += bfmt(&buf, " ");
+ n += bfmt(&buf, "%tk", tk);
+ }
+ ioputc(&buf, 0);
+ if (buf.err) {
+ struct wbuf new = MEMBUF(alloc(lx->tmparena, n+1, 1), n+1);
+ assert(buf.buf == tmp);
+ memcpy(&buf, &new, sizeof buf);
+ goto Redo;
+ }
+ tk.t = TKSTRLIT;
+ tk.s = buf.buf != tmp ? buf.buf : alloccopy(lx->tmparena, buf.buf, buf.len, 1);
+ tk.len = buf.len-1;
+ vpush(&rlist2, tk);
+ }
+ }
+ /*efmt("invoked %s has: ", mac->name);
+ for (int i = 0; i < rlist2.n; ++i)
+ efmt("%'tk ", &rlist2.p[i]);
+ efmt("\n");*/
+
+ vfree(&argsbuf);
+ if (rlist2.n) {
+ pushmacstk(lx, &span, &(struct macrostack){
+ .rlist = { rlist2.p, rlist2.n },
+ .macno = macidx,
+ .idx = 0,
+ });
+ }
+ return 1;
+ }
+ vfree(&argsbuf);
+ }
+
+ if (mac->rlist.n) {
+ pushmacstk(lx, &span, &(struct macrostack){
+ .rlist = mac->rlist,
+ .macno = macidx,
+ .idx = 0,
+ });
+ }
+ return 1;
+}
+
static struct token epeektk;
static int
elex(struct lexer *lx, struct token *tk)
@@ -756,7 +1167,22 @@ elex(struct lexer *lx, struct token *tk)
epeektk.t = 0;
return tt;
}
- return lex0(lx, tk);
+ if (lx->macstk) {
+ const struct rlist rl = lx->macstk->rlist;
+ if (lx->macstk->idx == rl.n) {
+ popmac(lx);
+ return elex(lx, tk);
+ }
+ *tk = rl.tk[lx->macstk->idx++];
+ assert(tk->t);
+ tk->span.ex = lx->macstk->exspan;
+ if (tryexpand(lx, tk))
+ return elex(lx, tk);
+ return tk->t;
+ }
+
+ lex0(lx, tk);
+ return tk->t;
}
static int
@@ -829,10 +1255,30 @@ Unary:
xu = isunsignedt(ty);
break;
default:
- if (in_range(tk.t, TKWBEGIN_, TKWEND_)) {
- case TKIDENT:
- x = 0;
+ if (isppident(tk)) {
+ //efmt("in expr>> %s\n", tk.s);
xu = 0;
+ if (!strcmp(tk.s, "defined")) {
+ /* 'defined' ppident */
+ bool paren = 0;
+ lex0(lx, &tk);
+ if ((paren = tk.t == '(')) lex0(lx, &tk);
+ if (tk.t != TKIDENT && !in_range(tk.t, TKWBEGIN_, TKWEND_)) {
+ error(&tk.span, "expected macro name");
+ goto Err;
+ }
+ if (paren && lex0(lx, &tk) != ')') {
+ error(&tk.span, "expected `)'");
+ goto Err;
+ }
+ x = findmac(tk.s) != NULL;
+ } else {
+ if (tryexpand(lx, &tk)){
+ goto Unary;}
+ //efmt(" << NOT defined %d>> %s %p\n", noexpandmac, tk.s, findmac(tk.s));
+ /* non defined pp name -> 0 */
+ x = 0;
+ }
break;
}
error(&tk.span, "expected preprocessor integer expression");
@@ -917,17 +1363,21 @@ enum {
};
static struct ppcnd {
struct span0 ifspan;
+ int filedepth;
uchar cnd;
bool elsep;
} ppcndstk[32];
static int nppcnd;
+static int includedepth;
+
static void
ppif(struct lexer *lx, const struct span *span)
{
vlong v = expr(lx, NULL, 0);
assert(nppcnd < arraylength(ppcndstk) && "too many nested #if");
ppcndstk[nppcnd].ifspan = span->sl;
+ ppcndstk[nppcnd].filedepth = includedepth;
ppcndstk[nppcnd].cnd = v ? PPCNDTRUE : PPCNDFALSE;
ppcndstk[nppcnd++].elsep = 0;
}
@@ -945,6 +1395,7 @@ ppifxdef(struct lexer *lx, bool defp, const struct span *span)
}
assert(nppcnd < arraylength(ppcndstk) && "too many nested #if");
ppcndstk[nppcnd].ifspan = span->sl;
+ ppcndstk[nppcnd].filedepth = includedepth;
ppcndstk[nppcnd].cnd = (findmac(tk.s) == NULL) ^ defp ? PPCNDTRUE : PPCNDFALSE;
ppcndstk[nppcnd++].elsep = 0;
}
@@ -969,7 +1420,6 @@ ppelif(struct lexer *lx, const struct span *span)
switch (cnd->cnd) {
case PPCNDTRUE: cnd->cnd = PPCNDTAKEN; break;
case PPCNDFALSE: cnd->cnd = v ? PPCNDTRUE : PPCNDFALSE; break;
- case PPCNDTAKEN: assert(0);
}
}
static void
@@ -1001,8 +1451,6 @@ ppelifxdef(struct lexer *lx, bool defp, const struct span *span)
}
}
-
-
static void
ppendif(struct lexer *lx, const struct span *span)
{
@@ -1041,242 +1489,66 @@ ppelse(struct lexer *lx, const struct span *span)
cnd->elsep = 1;
}
-static int includedepth;
enum { MAXINCLUDE = 200 };
-
-static void
-ppinclude(struct lexer *lx, const struct span *span0)
+static bool
+tryinclude(struct lexer *lx, const struct span *span, const char *path)
{
- char *path;
struct lexer new;
- struct token tk;
- struct span span = *span0;
-
- lexingheadername = 1;
- if (in_range(lex0(lx, &tk), TKPPHDRH, TKPPHDRQ)) {
- const char *base, *end;
-
- /* build relative path */
- base = getfilename(lx->fileid);
- for (end = base; *end != 0; ++end) {}
- for (--end; *end != '/' && end != base; --end) {}
- if (*end == '/') ++end;
- path = alloc(&globarena, end - base + tk.len + 1, 1);
- memcpy(path, base, end - base);
- memcpy(path + (end - base), tk.s, tk.len);
- path[end - base + tk.len] = 0;
- } else {
- error(&tk.span, "garbage after #include");
- ppskipline(lx);
- return;
- }
- //efmt(">include %'s\n", path);
- joinspan(&span.ex, tk.span.ex);
- initlexer(&new, &span, path, lx->tmparena);
+ const char *err = initlexer(&new, span, path);
+ if (err) return 0;
new.save = xmalloc(sizeof *new.save);
memcpy(new.save, lx, sizeof *lx);
*lx = new;
if (++includedepth == MAXINCLUDE)
- fatal(&span, "Maximum nested include depth of %d reached", includedepth);
-}
-
-/* horrible kludge for proper expansion in the face of nested macros with arguments,
- * stringifying, etc */
-static bool noexpandmac;
+ fatal(span, "Maximum nested include depth of %d reached", includedepth);
-static struct macrostack {
- struct macrostack *link;
- struct rlist *args;
- const struct rlist *rlist;
- struct span0 exspan;
- int idx;
- int macno:30;
- int prevnoexpandmac:1;
-} mstk[64], *mfreelist;
-
-static void
-pushmacstk(struct lexer *lx, const struct span *span, const struct macrostack *m)
-{
- struct macrostack *l;
- if (!(l = mfreelist)) fatal(span, "macro depth limit reached");
- l = mfreelist;
- mfreelist = l->link;
- l->link = lx->macstk;
- assert(m->rlist);
- l->rlist = m->rlist;
- l->macno = m->macno;
- l->args = m->args;
- l->idx = 0;
- l->exspan = span->ex;
- l->prevnoexpandmac = noexpandmac;
- lx->macstk = l;
+ return 1;
}
-static bool
-tryexpand(struct lexer *lx, struct token *tk)
+static void
+ppinclude(struct lexer *lx, const struct span *span0)
{
- static bool inimstk;
- int macidx, i;
- struct span span = tk->span;
- struct macrostack *l;
- struct macro *mac = NULL;
- struct rlist *args = NULL;
-
- if (!inimstk) {
- inimstk = 1;
- for (i = 0; i < arraylength(mstk); ++i) {
- mstk[i].link = mfreelist;
- mfreelist = &mstk[i];
- }
- }
-
- if (tk->t == TKPPMACARG || tk->t == TKPPMACSTR) {
- struct rlist *arg;
-
- ioflush(&bstderr);
- for (l = lx->macstk; l->macno != tk->macidx; l = l->link) ;
- arg = &l->args[tk->argidx];
- if (tk->t == TKPPMACARG && arg->n) {
- noexpandmac = 0;
- pushmacstk(lx, &span, &(struct macrostack){
- .idx = 0,
- .rlist = arg,
- .macno = -1,
- });
- return 1;
- } else {
- char tmp[100];
- struct wbuf buf = MEMBUF(tmp, sizeof tmp);
- int n = 0;
-
- // 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'}
- Redo:
- for (const struct token *tk = arg->tk, *end = tk + arg->n; tk != end; ++tk) {
- //efmt("strify ++ (%d) %'tk\n", tk->t,tk);
- if (tk != arg->tk && wsseparated(tk-1, tk))
- n += bfmt(&buf, " ");
- n += bfmt(&buf, "%tk", tk);
- }
- ioputc(&buf, 0);
- if (buf.err) {
- struct wbuf new = MEMBUF(alloc(lx->tmparena, n+1, 1), n+1);
- assert(buf.buf == tmp);
- memcpy(&buf, &new, sizeof buf);
- goto Redo;
- }
- tk->t = TKSTRLIT;
- tk->s = buf.buf != tmp ? buf.buf : alloccopy(lx->tmparena, buf.buf, buf.len, 1);
- tk->len = buf.len;
- return 0;
- }
- } else if (noexpandmac || !isppident(*tk) || !(mac = findmac(tk->s)))
- return 0;
-
- macidx = mac - macros.p;
- /* prevent infinite recursion */
- for (l = lx->macstk; l; l = l->link)
- if (l->macno == macidx)
- return 0;
-
-
- if (mac->fnlike) {
- vec_of(struct token) rlist = {0};
- bool toomany = 0;
- struct span excessspan;
- int cur, len, i, bal, narg;
- struct token tk;
-
- noexpandmac = 1;
- if (lexpeek(lx, &tk) != '(') {
- noexpandmac = 0;
- return 0;
- }
- lex(lx, &tk);
- args = xcalloc((mac->nparam + mac->variadic) * sizeof *args);
-
- /* 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 */
+ struct token tk;
+ struct span span = *span0;
- cur = i = bal = len = narg = 0;
- while ((lex(lx, &tk) != ')' || bal != 0) && tk.t != TKEOF) {
- if (tk.t == ',' && bal == 0) {
- ++narg;
- if (i == mac->nparam-1) {
- if (!mac->variadic) {
- excessspan = tk.span;
- toomany = 1;
- }
- } else if (i < mac->nparam) {
- args[i].tk = &tk + cur;
- args[i].n = len;
- cur = rlist.n;
- len = 0;
- ++i;
- }
- } else if (!toomany) {
- if (tk.t == '(' || tk.t == '[') ++bal;
- else if (tk.t == ')' || tk.t == ']') --bal;
- vpush(&rlist, tk);
- ++len;
- }
- }
- noexpandmac = 0;
- if (tk.t == TKEOF)
- error(&span, "unterminated function-like macro invocation");
- else if (i < mac->nparam) {
- ++narg;
- args[i].tk = &tk + cur;
- args[i].n = len;
- cur = rlist.n;
- len = 0;
- ++i;
- }
+ lexingheadername = 1;
+ if (in_range(lex0(lx, &tk), TKPPHDRH, TKPPHDRQ)) {
+ char *path = NULL;
+ const char *base, *end;
joinspan(&span.ex, tk.span.ex);
- if (narg < mac->nparam)
- error(&excessspan, "macro `%s' passed %d arguments, but takes %d", mac->name, narg, mac->nparam);
- else if (toomany) {
- joinspan(&excessspan.ex, tk.span.ex);
- error(&excessspan, "macro `%s' passed %d arguments, but takes just %d", mac->name, narg, mac->nparam);
+ if (tk.t == TKPPHDRQ) {
+ /* build relative path */
+ base = getfilename(lx->fileid);
+ for (end = base; *end != 0; ++end) {}
+ for (--end; *end != '/' && end != base; --end) {}
+ if (*end == '/') ++end;
+ xbgrow(&path, end - base + tk.len + 1);
+ memcpy(path, base, end - base);
+ memcpy(path + (end - base), tk.s, tk.len);
+ path[end - base + tk.len] = 0;
+ if (tryinclude(lx, &span, path)) return;
}
- /* fix up args slice pointers */
- for (int i = 0; i < mac->nparam + mac->variadic; ++i) {
- int idx = args[i].tk - &tk;
- ioflush(&bstderr);
- args[i].tk = rlist.p + idx;
+ /* try system paths */
+ for (struct inclpaths *p = cinclpaths; p; p = p->next) {
+ int ndir = strlen(p->path);
+ xbgrow(&path, ndir + tk.len + 2);
+ memcpy(path, p->path, ndir);
+ path[ndir++] = '/';
+ memcpy(path + ndir, tk.s, tk.len);
+ path[ndir + tk.len] = 0;
+ if (tryinclude(lx, &span, path)) return;
}
+ /* try embedded files pseudo-path */
+ path[0] = '@', path[1] = ':';
+ memcpy(path+2, tk.s, tk.len);
+ path[tk.len+2] = 0;
+ if (tryinclude(lx, &span, path)) return;
+ fatal(&tk.span, "file not found: %'S", tk.s, tk.len);
+ } else {
+ error(&tk.span, "garbage after #include");
+ ppskipline(lx);
}
-
- if (mac->rlist.n) {
- pushmacstk(lx, &span, &(struct macrostack){
- .rlist = &mac->rlist,
- .macno = macidx,
- .args = args,
- .idx = 0,
- });
- }
- return 1;
-}
-
-static void
-popmac(struct lexer *lx)
-{
- struct macrostack *stk;
-
- assert(stk = lx->macstk);
- do {
- noexpandmac = stk->prevnoexpandmac;
- if (stk->args) {
- free((void *)stk->args[0].tk);
- free(stk->args);
- }
- lx->macstk = stk->link;
- stk->link = mfreelist;
- mfreelist = stk;
- } while ((stk = lx->macstk) && stk->idx >= stk->rlist->n);
}
enum directive {
@@ -1352,12 +1624,13 @@ lex(struct lexer *lx, struct token *tk_)
}
if (lx->macstk) {
- const struct rlist *rl = lx->macstk->rlist;
- if (lx->macstk->idx == rl->n) {
+ const struct rlist rl = lx->macstk->rlist;
+ if (lx->macstk->idx == rl.n) {
+ if (lx->macstk->stop) return tk->t = TKEOF;
popmac(lx);
return lex(lx, tk_);
}
- *tk = rl->tk[lx->macstk->idx++];
+ *tk = rl.tk[lx->macstk->idx++];
assert(tk->t);
tk->span.ex = lx->macstk->exspan;
if (tryexpand(lx, tk))
@@ -1365,16 +1638,17 @@ lex(struct lexer *lx, struct token *tk_)
return tk->t;
}
- skip = nppcnd ? ppcndstk[nppcnd-1].cnd != PPCNDTRUE : 0;
+ skip = !noexpandmac && nppcnd ? ppcndstk[nppcnd-1].cnd != PPCNDTRUE : 0;
for (linebegin = 1;;) {
while ((t = lex0(lx, tk)) == '\n') linebegin = 1;
- if (t == '#' && linebegin) {
+ if (t == '#' && linebegin && !noexpandmac) {
if (lex0(lx, tk) == '\n') { }
else if (isppident(*tk)) {
if (!skip) {
switch (findppcmd(tk)) {
case PPXXX: goto BadPP;
case PPDEFINE: ppdefine(lx); break;
+ case PPUNDEF: ppundef(lx); break;
case PPIF: ppif(lx, &tk->span); break;
case PPIFDEF: ppifxdef(lx, 1, &tk->span); break;
case PPIFNDEF: ppifxdef(lx, 0, &tk->span); break;
@@ -1384,6 +1658,10 @@ lex(struct lexer *lx, struct token *tk_)
case PPELSE: ppelse(lx, &tk->span); break;
case PPENDIF: ppendif(lx, &tk->span); break;
case PPINCLUDE: ppinclude(lx, &tk->span); break;
+ case PPLINE: break;
+ case PPPRAGMA: break;
+ case PPWARNING: break;
+ case PPERROR: break;
default: assert(0&&"nyi");
}
} else {
@@ -1418,7 +1696,7 @@ lex(struct lexer *lx, struct token *tk_)
if (skip && tk->t != TKEOF) continue;
if (tryexpand(lx, tk))
return lex(lx, tk_);
- if (t == TKEOF && nppcnd) {
+ if (t == TKEOF && nppcnd && ppcndstk[nppcnd-1].filedepth == includedepth) {
struct span span = { ppcndstk[nppcnd-1].ifspan };
error(&span, "#if is not matched by #endif");
}
@@ -1452,19 +1730,127 @@ lexpeek(struct lexer *lx, struct token *tk_)
return t;
}
-void
-initlexer(struct lexer *lx, const struct span *span, const char *file, struct arena **tmparena)
+static void
+mac__file__handler(struct lexer *lx, struct token *tk)
{
- const char *error;
+ tk->t = TKSTRLIT;
+ tk->s = getfilename(lx->fileid);
+ tk->len = strlen(tk->s);
+}
+
+static void
+mac__line__handler(struct lexer *lx, struct token *tk)
+{
+ char buf[40];
+ int line;
+ struct wbuf wbuf = MEMBUF(buf, sizeof buf);
+ getfilepos(&line, NULL, lx->fileid, lx->chridx);
+ bfmt(&wbuf, "%d", line), buf[wbuf.len++] = 0;
+ tk->t = TKNUMLIT;
+ tk->s = alloccopy(lx->tmparena, buf, wbuf.len, 1);
+ tk->len = strlen(tk->s);
+}
+
+#include <time.h>
+
+static void
+mac__date__handler(struct lexer *lx, struct token *tk)
+{
+ char buf[20];
+ struct wbuf wbuf = MEMBUF(buf, sizeof buf);
+ time_t tm = time(NULL);
+ struct tm *ts = localtime(&tm);
+ tk->t = TKSTRLIT;
+ tk->len = 11;
+ if (ts) {
+ bfmt(&wbuf, "%S %2d %4d%c",
+ &"JanFebMarAprMayJunJulAugSepOctNovDec"[ts->tm_mon*3], 3,
+ ts->tm_mday, 1900+ts->tm_year, 0);
+ assert(wbuf.len == 11+1);
+ tk->s = alloccopy(lx->tmparena, buf, wbuf.len, 1);
+ } else {
+ tk->s = "\?\?\? \?\? \?\?\?\?";
+ }
+}
+
+
+static void
+mac__time__handler(struct lexer *lx, struct token *tk)
+{
+ char buf[20];
+ struct wbuf wbuf = MEMBUF(buf, sizeof buf);
+ time_t tm = time(NULL);
+ struct tm *ts = localtime(&tm);
+ tk->t = TKSTRLIT;
+ tk->len = 8;
+ if (ts) {
+ bfmt(&wbuf, "%.2d:%.2d:%.2d%c", ts->tm_hour, ts->tm_min, ts->tm_sec, 0);
+ tk->s = alloccopy(lx->tmparena, buf, wbuf.len, 1);
+ assert(wbuf.len == 8+1);
+ } else {
+ tk->s = "\?\?:\?\?:\?\?";
+ }
+}
+
+static void
+addpredefmacros(void)
+{
+ static const struct token tok_1 = { TKNUMLIT, .s = "1", .len = 1 };
+ static struct token tok_ver = { TKNUMLIT };
+ static struct macro macs[] = {
+ { "__FILE__", .predefined = 1, .special = 1, .handler = mac__file__handler },
+ { "__LINE__", .predefined = 1, .special = 1, .handler = mac__line__handler },
+ { "__DATE__", .predefined = 1, .special = 1, .handler = mac__date__handler },
+ { "__TIME__", .predefined = 1, .special = 1, .handler = mac__time__handler },
+ { "__STDC__", .predefined = 1, .rlist = { &tok_1, 1 } },
+ { "__STDC_VERSION__", .predefined = 1, .rlist = { &tok_ver, 1 } },
+ { "__STDC_HOSTED__", .predefined = 1, .rlist = { &tok_1, 1 } },
+ };
+ switch (ccopt.cstd) {
+ default: assert(0);
+ case STDC89: tok_ver.s = "199409L"; break;
+ case STDC99: tok_ver.s = "199901L"; break;
+ case STDC11: tok_ver.s = "201112L"; break;
+ case STDC23: tok_ver.s = "202311L"; break;
+ }
+ tok_ver.len = 7;
+ for (int i = 0; i < arraylength(macs); ++i) {
+ macs[i].name = intern(macs[i].name);
+ putmac(&macs[i]);
+ }
+}
+
+const char *
+initlexer(struct lexer *lx, const struct span *span, const char *file)
+{
+ enum { NARENA = 1<<12 };
+ static union { char m[sizeof(struct arena) + NARENA]; struct arena *_align; } amem;
+ static struct arena *tmparena = (void *)amem.m;
+
+ const char *err;
struct memfile *f;
+ if (!macros.n) addpredefmacros();
+ if (!tmparena->cap) tmparena->cap = NARENA;
+
memset(lx, 0, sizeof *lx);
- lx->fileid = openfile(&error, &f, file);
+ lx->fileid = openfile(&err, &f, file);
if (lx->fileid < 0)
- fatal(span, "Cannot open %'s: %s", file, error);
+ return err;
lx->dat = f->p;
lx->ndat = f->n;
- lx->tmparena = tmparena;
+ lx->tmparena = &tmparena;
+ return NULL;
+}
+
+/* callback to let lexer release temp memory for arena allocated token data */
+void
+lexerfreetemps(struct lexer *lx)
+{
+ if (!lx->macstk) {
+ /* some of the tokens could be somewhere in the macro stack */
+ freearena(lx->tmparena);
+ }
}
/* vim:set ts=3 sw=3 expandtab: */
diff --git a/lex.h b/lex.h
index 515613f..3c1d431 100644
--- a/lex.h
+++ b/lex.h
@@ -95,6 +95,7 @@ const char *intern(const char *);
int lex(struct lexer *, struct token *);
int lexpeek(struct lexer *, struct token *);
enum typetag parsenumlit(uvlong *, double *, const struct token *, bool ispp);
-void initlexer(struct lexer *, const struct span *span, const char *file, struct arena **tmparena);
+const char *initlexer(struct lexer *, const struct span *span, const char *file);
+void lexerfreetemps(struct lexer *);
/* vim:set ts=3 sw=3 expandtab: */
diff --git a/main.c b/main.c
index 2b98cab..1f75a50 100644
--- a/main.c
+++ b/main.c
@@ -7,6 +7,7 @@
#include <unistd.h>
struct option ccopt;
+struct inclpaths *cinclpaths;
static void
flushstd(void)
@@ -348,6 +349,21 @@ detectcolor(void)
ccopt.nocolor = 1;
}
+static void
+sysinclpaths(void)
+{
+ static const char *paths[] = {
+ "/usr/local/include",
+ "/usr/include"
+ };
+ for (int i = 0; i < arraylength(paths); ++i) {
+ struct inclpaths *p = alloc(&globarena, sizeof *cinclpaths, 0);
+ p->next = cinclpaths;
+ p->path = paths[i];
+ cinclpaths = p;
+ }
+}
+
int
main(int argc, char **argv)
{
@@ -356,6 +372,7 @@ main(int argc, char **argv)
/* setup defaults */
detectcolor();
+ sysinclpaths();
ccopt.cstd = STDC99;
ccopt.pie = 1;
diff --git a/test/hello.c b/test/hello.c
index 9d21323..e27be8d 100644
--- a/test/hello.c
+++ b/test/hello.c
@@ -1,4 +1,4 @@
-int printf(char *, ...);
+#include <stdio.h>
int main(int argc, char **argv) {
printf("hello world\n");
}
diff --git a/test/pp.c b/test/pp.c
index 1c1549f..0aa5287 100644
--- a/test/pp.c
+++ b/test/pp.c
@@ -1,12 +1,24 @@
#include "pp.h"
#include "pp.h"
+#include <stddef.h>
+#include <stdio.h>
+//
+#define CATl(a) a##bar
+#define CATr(a) foo##a
+#define CAT(a,b) a##b
+
int
main(void)
{
+ int CATl(foo);
+ ++foobar;
+ --CATr(bar);
+ CAT(foo,bar) += 3;
printf("%s %s\n",STR ( ok /1 "\n"n ;.&
05.5), STR(ADD(1,2)));
hi(ADD(Foo, SQR(Bar+1)));
- printf("%s %s\n", str(Foo), xstr(Foo));
+ int foo123 = 77;
+ printf("%s %s %g\n", str(Foo,5), xstr(Foo), CAT(1.5,e3f) + CAT(7,)-CAT(1,));
}
diff --git a/test/pp.h b/test/pp.h
index 029c6ee..63de6f5 100644
--- a/test/pp.h
+++ b/test/pp.h
@@ -17,7 +17,7 @@ void hi(int x) {
#define STR(h) #h
#define xstr(s1) str(s1)
-#define str(s) #s
+#define str(...) #__VA_ARGS__
#endif