diff options
| -rw-r--r-- | c/lex.c | 85 | ||||
| -rw-r--r-- | common.h | 5 | ||||
| -rw-r--r-- | io.c | 75 |
3 files changed, 137 insertions, 28 deletions
@@ -895,6 +895,7 @@ static void expecteol(struct lexer *lx, const char *ppname) { struct token tk; + assert(!lx->macstk); if (lex0(lx, &tk) != '\n' && tk.t != TKEOF) { (ccopt.pedant ? error : warn)(&tk.span, "extra tokens after #%s", ppname); ppskipline(lx); @@ -1580,7 +1581,7 @@ ppinclude(struct lexer *lx, const struct span *span0) if (tk.s[0] == '/') goto NotFound; /* try relative to current file's directory */ - base = getfilename(lx->fileid); + base = getfilename(lx->fileid, 0); for (end = base; *end != 0; ++end) {} for (--end; *end != '/' && end != base; --end) {} if (*end == '/') ++end; @@ -1616,6 +1617,68 @@ ppinclude(struct lexer *lx, const struct span *span0) } static void +ppline(struct lexer *lx, struct token *tk0) +{ + struct token tk, tks[2]; + int ntk = 0; + struct span span = tk0->span; + bool ext = 0; + if (tk0->t == TKNUMLIT) { /* handles GNU-style post preprocessing directive '# n ...' */ + tks[ntk++] = *tk0; + ext = 1; + } + while (ntk < 2) { + if (lx->macstk && advancemacro(lx, &tk)) { + tks[ntk++] = tk; + if (lx->macstk->idx >= lx->macstk->rlist.n) popmac(lx); + } else if (!lx->macstk && (lex0(lx, &tk) == '\n' || tk.t == TKEOF)) { + break; + } else if (isppident(tk) && tryexpand(lx, &tk)) { + continue; + } else { + tks[ntk++] = tk; + } + } + uvlong lineno = 0; + char *file = NULL; + if (ntk > 0 && tks[0].t == TKNUMLIT) { + if (!parsenumlit(&lineno, NULL, &tks[0], 1) || (lineno == 0 && !ext)) + goto BadNum; + if (lineno >= 1<<(32-SPANFILEBITS)) { + warn(&tks[0].span, "ignoring #line number that is too big"); + lineno = 0; + goto Err; + } + } else { + BadNum: + error(ntk ? &tks[0].span : &span, "#line requires a positive integer argument"); + Err: + if (lx->macstk || (tk.t != '\n' && tk.t != TKEOF)) ppskipline(lx); + return; + } + if (ntk > 1) { + if (tks[1].t == TKSTRLIT && !tks[1].wide) { + file = alloc(&globarena, tks[1].len+1, 0); + memcpy(file, tks[1].s, tks[1].len); + file[tks[1].len] = 0; + } else { + error(&tks[1].span, "invalid filename for #line directive"); + } + } + if (lineno) setfileline(lx->fileid, lx->chridx, lineno, file); + if (lx->macstk) { + span.sl.off = span.ex.off = lx->chridx; + span.sl.len = span.ex.len = 1; + ppskipline(lx); + if (!ext) + (ccopt.pedant ? error : warn)(&span, "extra tokens after #line"); + } else if (tk.t != '\n' && tk.t != TKEOF) { + if (ext) ppskipline(lx); + else expecteol(lx, "line"); + } +} + +static void pppragma(struct lexer *lx, const struct span *span0) { struct token tk; @@ -1726,8 +1789,8 @@ lex(struct lexer *lx, struct token *tk_) while ((t = lex0(lx, tk)) == '\n') linebegin = 1; if (t == '#' && linebegin) { if (lex0(lx, tk) == '\n') { } - else if (isppident(*tk)) { - lastcmd = findppcmd(tk); + else if (tk->t == TKNUMLIT || isppident(*tk)) { + lastcmd = tk->t == TKNUMLIT ? PPLINE : findppcmd(tk); if (nppcnd == lx->nppcnd0) lx->inclguard = NULL; if (!skip) { switch (lastcmd) { @@ -1743,7 +1806,7 @@ 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 PPLINE: ppline(lx, tk); break; case PPPRAGMA: pppragma(lx, &tk->span); break; case PPWARNING: ppdiag(lx, &tk->span, 0); break; case PPERROR: ppdiag(lx, &tk->span, 1); break; @@ -1845,7 +1908,7 @@ static void mac__file__handler(struct lexer *lx, struct token *tk) { tk->t = TKSTRLIT; - tk->s = getfilename(lx->fileid); + tk->s = getfilename(lx->fileid, lx->chridx); tk->wide = 0; tk->len = strlen(tk->s); } @@ -2011,7 +2074,7 @@ initlexer(struct lexer *lx, const char **err, const char *file) lx->chrbuf0 = countof(lx->chrbuf); lx->firstdirective = 1; lx->nppcnd0 = nppcnd; - return getfilename(fileid) != file ? LXFILESEEN : LXOK; + return getfilename(fileid, 0) != file ? LXFILESEEN : LXOK; } /* callback to let lexer release temp memory for arena allocated token data */ @@ -2029,15 +2092,17 @@ lexerdump(struct lexer *lx, struct wbuf *out) { struct token prev = {0}, tok; int file = lx->fileid, line = 1, col = 1; - bfmt(out, "# %d %'s\n", 1, getfilename(file)); + const char *lastfile = getfilename(file, 0); + bfmt(out, "# %d %'s\n", 1, lastfile); while (lex(lx, &tok) != TKEOF) { int tkline, tkcol; - getfilepos(&tkline, &tkcol, tok.span.ex.file, tok.span.ex.off); - if (tok.span.ex.file != file) { + const char *fname = getfilepos(&tkline, &tkcol, tok.span.ex.file, tok.span.ex.off); + if (tok.span.ex.file != file || fname != lastfile) { file = tok.span.ex.file; - bfmt(out, "\n# %d %'s\n", tkline, getfilename(file)); + bfmt(out, "\n# %d %'s\n", tkline, fname); col = 1; lexerfreetemps(lx); + lastfile = fname; } else if (line < tkline && tkline - line < 5) { do ioputc(out, '\n'); @@ -396,10 +396,11 @@ void *mapzeros(uint); int munmap(void *, size_t); int getpredeffile(struct memfile **, const char *name); int openfile(const char **err, struct memfile **, const char *path); -const char *getfilename(int id); +const char *getfilename(int id, uint atoff); struct memfile *getfile(int id); void addfileline(int id, uint off); -void getfilepos(int *line, int *col, int id, uint off); +void setfileline(int id, uint off, int line, const char *file); +const char *getfilepos(int *line, int *col, int id, uint off); bool isoncefile(int id, const char **guard); void markfileonce(int id, const char *guard); void markfileseen(int id); @@ -794,11 +794,19 @@ struct fileuid { long dev, ino; }; +/* one entry per #line */ +struct linemap { + int phys; + int toline; + const char *tofile; +}; + static struct file { struct fileuid uid; const char *path; struct memfile f; vec_of(uint) lineoffs; + vec_of(struct linemap) linemap; bool once; bool seen; const char *guardmac; @@ -880,10 +888,12 @@ openfile(const char **err, struct memfile **pf, const char *path) } const char * -getfilename(int id) +getfilename(int id, uint atoff) { assert((uint)id < countof(fileht) && fileht[id]); - return fileht[id]->path; + if (!fileht[id]->linemap.n || !atoff) + return fileht[id]->path; + return getfilepos(NULL, NULL, id, atoff); } struct memfile * @@ -896,26 +906,40 @@ getfile(int id) void addfileline(int id, uint off) { - vec_of(uint) *lineoffs; - assert((uint)id < countof(fileht) && fileht[id]); - lineoffs = (void *)&fileht[id]->lineoffs; + vec_of(uint) *lineoffs = (void *)&fileht[id]->lineoffs; if (lineoffs->n && off > lineoffs->p[lineoffs->n-1]) vpush(lineoffs, off); } void -getfilepos(int *line, int *col, int id, uint off) +setfileline(int id, uint off, int line, const char *file) { - uint *offs, n; - int l = 0, h, i = 0; + assert((uint)id < countof(fileht) && fileht[id]); + vec_of(struct linemap) *linemap = (void *)&fileht[id]->linemap; + vec_of(uint) *lineoffs = (void *)&fileht[id]->lineoffs; + int phys = 2; + for (int i = lineoffs->n-1; i >= 0; --i) { + if (lineoffs->p[i] < off) { + phys = i+2; + break; + } + } + if (linemap->n > 0) { + assert(linemap->p[linemap->n-1].phys < phys); + if (!file) file = linemap->p[linemap->n-1].tofile; + } + vpush(linemap, ((struct linemap){ phys, line, file })); +} +const char * +getfilepos(int *pline, int *pcol, int id, uint off) +{ assert((uint)id < countof(fileht) && fileht[id]); - offs = fileht[id]->lineoffs.p; - n = fileht[id]->lineoffs.n; - h = n - 1; - + uint *offs = fileht[id]->lineoffs.p; + uint n = fileht[id]->lineoffs.n; /* binary search over offsets array */ + int l = 0, h = n - 1, i = 0; while (l <= h) { i = (l + h) / 2; if (offs[i] < off) l = i + 1; @@ -923,8 +947,27 @@ getfilepos(int *line, int *col, int id, uint off) else break; } i -= offs[i] > off; - if (line) *line = i + 1; - if (col) *col = off - offs[i] + 1; + int line = i + 1, col = off - offs[i] + 1; + const char *file = fileht[id]->path; + vec_of(struct linemap) *linemap = (void *)&fileht[id]->linemap; + if (linemap->n) { + /* binary search over linemap array */ + l = 0, h = linemap->n - 1, i = 0; + while (l <= h) { + i = (l + h) / 2; + if (linemap->p[i].phys < line) l = i + 1; + else if (linemap->p[i].phys > line) h = i - 1; + else break; + } + i -= linemap->p[i].phys > line; + if (i >= 0) { + line = linemap->p[i].toline + (line - linemap->p[i].phys); + if (linemap->p[i].tofile) file = linemap->p[i].tofile; + } + } + if (pline) *pline = line; + if (pcol) *pcol = col; + return file; } bool @@ -978,8 +1021,8 @@ vdiag(const struct span *span, enum diagkind kind, const char *fmt, va_list ap) if (span) { loc = span->ex.len ? &span->ex : &span->sl; f = getfile(loc->file); - getfilepos(&line, &col, loc->file, loc->off); - efmt("%s:%d:%d: ", getfilename(loc->file), line, col); + const char *file = getfilepos(&line, &col, loc->file, loc->off); + efmt("%s:%d:%d: ", file, line, col); } efmt(color[kind]); efmt("%s: %g.", label[kind]); |