diff options
| -rw-r--r-- | c.c | 18 | ||||
| -rw-r--r-- | common.h | 9 | ||||
| -rw-r--r-- | elf.c | 2 | ||||
| -rw-r--r-- | embedfilesdir.c | 4 | ||||
| -rw-r--r-- | io.c | 106 | ||||
| -rw-r--r-- | lex.c | 97 | ||||
| -rw-r--r-- | lex.h | 8 | ||||
| -rw-r--r-- | main.c | 6 | ||||
| -rw-r--r-- | obj.c | 11 | ||||
| -rw-r--r-- | obj.h | 4 |
10 files changed, 195 insertions, 70 deletions
@@ -44,7 +44,7 @@ lexc(struct comp *cm, struct token *tk) tk->s = memcpy(alloc(&cm->exarena, tk->len + rest.n, 1), tk->s, tk->len); memcpy((char *)tk->s + tk->len, rest.p, rest.n); tk->len += rest.n; - } else if (tk->wide && targ_primsizes[targ_wchartype] == 2) { + } else if (tk->wide == 1) { tk->ws16 = memcpy(alloc(&cm->exarena, tk->len + rest.n*2, 2), tk->ws16, tk->len*2); memcpy((short *)tk->s + tk->len, rest.p, rest.n); tk->len += rest.n * 2; @@ -4022,13 +4022,17 @@ initcm(struct comp *cm, const char *file) { enum { N = 1<<12 }; static union { char m[sizeof(struct arena) + N]; struct arena *_align; } amem[2]; - const char *err = initlexer(&cm->lx, NULL, file); - if (err) + const char *err; + switch (initlexer(&cm->lx, &err, file)) { + default: assert(0); + case LXERR: fatal(NULL, "Cannot open %'s: %s", file, err); - cm->fnarena = (void *)amem[0].m; - cm->fnarena->cap = N; - cm->exarena = (void *)amem[1].m; - cm->exarena->cap = N; + case LXOK: + cm->fnarena = (void *)amem[0].m; + cm->fnarena->cap = N; + cm->exarena = (void *)amem[1].m; + cm->exarena->cap = N; + } } void @@ -29,11 +29,12 @@ typedef unsigned uint; #define arraylength(a) (sizeof(a) / sizeof 0[a]) struct bytes { uchar *p; uint n; }; +enum { SPANFILEBITS = 10 }; struct span { struct span0 { uint off; - uint len : 24, - file : 8; + uint len : 32-SPANFILEBITS, + file : SPANFILEBITS; } sl, /* original source location */ ex; /* the location after #include/macro expansion */ }; @@ -571,6 +572,10 @@ const char *getfilename(int id); struct memfile *getfile(int id); void addfileline(int id, uint off); void getfilepos(int *line, int *col, int id, uint off); +bool isoncefile(int id); +void markfileonce(int id); +void markfileseen(int id); +bool isfileseen(int id); void closefile(int id); void fatal(const struct span *, const char *, ...); void error(const struct span *, const char *, ...); @@ -362,7 +362,7 @@ elffini(struct wbuf *out) memcpy(shstrs + shnam_reldata + 4, ".data\0", 6); } - symtab.p[1].name = str2idx(getfilename(0)); + symtab.p[1].name = str2idx(objout.infile); qsort(symtab.p+2, symtab.n-2, sizeof *symtab.p, symcmp); /* fixup relocs */ for (int i = 0; i < relocs.n; ++i) { diff --git a/embedfilesdir.c b/embedfilesdir.c index 237ea62..a686d50 100644 --- a/embedfilesdir.c +++ b/embedfilesdir.c @@ -10,6 +10,7 @@ struct embedfile { struct embedfile embedfilesdir[] = { {"stddef.h", S("\ +#pragma once\n\ typedef __typeof__((char*)0 - (char*)0) ptrdiff_t;\n\ typedef __typeof__(sizeof 0) size_t;\n\ typedef __typeof__(L'a') wchar_t;\n\ @@ -18,6 +19,7 @@ typedef __typeof__(L'a') wchar_t;\n\ ")}, {"stdarg.h", S("\ +#pragma once\n\ typedef __builtin_va_list va_list;\n\ #ifndef __GNUC_VA_LIST\n\ #define __GNUC_VA_LIST\n\ @@ -30,6 +32,7 @@ typedef __builtin_va_list __gnuc_va_list;\n\ ")}, {"stdbool.h", S("\ +#pragma once\n\ #define bool _Bool \n\ #define true 1\n\ #define false 0\n\ @@ -37,6 +40,7 @@ typedef __builtin_va_list __gnuc_va_list;\n\ ")}, {"float.h", S("\ +#pragma once\n\ #define FLT_ROUNDS (-1)\n\ #define FLT_EVAL_METHOD (-1)\n\ #define FLT_HAS_SUBNORM (-1)\n\ @@ -763,41 +763,75 @@ _assertfmt(const char *file, int line, const char *func, const char *expr) ioflush(&bstderr); } +struct fileuid { + long dev, ino; +}; + static struct file { + struct fileuid uid; const char *path; struct memfile f; vec_of(uint) lineoffs; -} files[256]; + bool once; + bool seen; +} *fileht[1<<SPANFILEBITS]; static int nfiles; int openfile(const char **err, struct memfile **pf, const char *path) { + struct stat st; struct file *f; + struct fileuid uid; + uint h, id, n = arraylength(fileht); - assert(nfiles + 1 < arraylength(files) && "too many files"); - f = &files[nfiles]; - f->path = path; - f->f = mapopen(err, path); - if (*err) return -1; - vinit(&f->lineoffs, NULL, 50); - vpush(&f->lineoffs, 0); + if (*path == '@' && path[1] == ':') { + uid.dev = -1; + uid.ino = hashs(0, path+2); + } else { + if (stat(path, &st) != 0) { + *err = strerror(errno); + return -1; + } + uid.dev = st.st_dev, uid.ino = st.st_ino; + } + for (id = h = uid.dev ^ uid.ino;; ++id) { + id &= arraylength(fileht) - 1; + f = fileht[id]; + if (f && f->uid.dev == uid.dev && f->uid.ino == uid.ino) { + break; + } else if (!f) { + struct memfile m; + m = mapopen(err, path); + if (*err) return -1; + f = allocz(&globarena, sizeof *f, 0); + f->uid = uid; + f->path = path; + f->f = m; + fileht[id] = f; + vinit(&f->lineoffs, NULL, 50); + vpush(&f->lineoffs, 0); + ++nfiles; + break; + } + assert(--n > 0 && "fileht full"); + } *pf = &f->f; - return nfiles++; + return id; } const char * getfilename(int id) { - assert(id < nfiles); - return files[id].path; + assert(id < arraylength(fileht) && fileht[id]); + return fileht[id]->path; } struct memfile * getfile(int id) { - assert(id < nfiles); - return &files[id].f; + assert(id < arraylength(fileht) && fileht[id]); + return &fileht[id]->f; } void @@ -805,10 +839,10 @@ addfileline(int id, uint off) { vec_of(uint) *lineoffs; - assert(id < nfiles); - lineoffs = (void *)&files[id].lineoffs; - if (lineoffs->n) assert(off > lineoffs->p[lineoffs->n-1]); - vpush(lineoffs, off); + assert(id < arraylength(fileht) && fileht[id]); + lineoffs = (void *)&fileht[id]->lineoffs; + if (lineoffs->n && off > lineoffs->p[lineoffs->n-1]) + vpush(lineoffs, off); } void @@ -817,9 +851,9 @@ getfilepos(int *line, int *col, int id, uint off) uint *offs, n; int l = 0, h, i = 0; - assert(id < nfiles); - offs = files[id].lineoffs.p; - n = files[id].lineoffs.n; + assert(id < arraylength(fileht) && fileht[id]); + offs = fileht[id]->lineoffs.p; + n = fileht[id]->lineoffs.n; h = n - 1; /* binary search over offsets array */ @@ -834,11 +868,39 @@ getfilepos(int *line, int *col, int id, uint off) if (col) *col = off - offs[i] + 1; } +bool +isoncefile(int id) +{ + assert(id < arraylength(fileht) && fileht[id]); + return fileht[id]->once; +} +void +markfileonce(int id) +{ + assert(id < arraylength(fileht) && fileht[id]); + fileht[id]->once = 1; +} + + +void +markfileseen(int id) +{ + assert(id < arraylength(fileht) && fileht[id]); + fileht[id]->seen = 1; +} + +bool +isfileseen(int id) +{ + assert(id < arraylength(fileht) && fileht[id]); + return fileht[id]->seen; +} + void closefile(int id) { - assert(id >= 0 && id < nfiles); - mapclose(&files[id].f); + assert(id < arraylength(fileht) && fileht[id]); + mapclose(&fileht[id]->f); } enum diagkind { DGERROR, DGWARN, DGNOTE, }; @@ -1541,15 +1541,21 @@ static bool tryinclude(struct lexer *lx, const struct span *span, const char *path) { struct lexer new; - 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); - + const char *err; + switch (initlexer(&new, &err, path)) { + default: assert(0); + case LXERR: return 0; + case LXOK: + 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); + break; + case LXFILESEEN: + break; + } return 1; } @@ -1565,16 +1571,25 @@ ppinclude(struct lexer *lx, const struct span *span0) const char *base, *end; joinspan(&span.ex, tk.span.ex); 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; + if (tk.s[0] == '/') { + /* absolute path */ + xbgrow(&path, tk.len + 1); + memcpy(path, tk.s, tk.len); + path[tk.len] = 0; + if (tryinclude(lx, &span, path)) return; + goto NotFound; + } else { + /* 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; + } } /* try system paths */ for (struct inclpaths *p = cinclpaths; p; p = p->next) { @@ -1592,6 +1607,7 @@ ppinclude(struct lexer *lx, const struct span *span0) memcpy(path+2, tk.s, tk.len); path[tk.len+2] = 0; if (tryinclude(lx, &span, path)) return; + NotFound: fatal(&tk.span, "file not found: %'S", tk.s, tk.len); } else { error(&tk.span, "garbage after #include"); @@ -1599,6 +1615,25 @@ ppinclude(struct lexer *lx, const struct span *span0) } } +static void +pppragma(struct lexer *lx, const struct span *span0) +{ + struct token tk; + struct span span = *span0; + if (lex0(lx, &tk) == TKIDENT && !strcmp(tk.s, "once")) { + markfileonce(lx->fileid); + } else { + joinspan(&span.ex, tk.span.ex); + warn(&span, "unknown pragma ignored"); + ppskipline(lx); + return; + } + if (lex0(lx, &tk) != '\n' && tk.t != TKEOF) { + warn(&tk.span, "garbage after pragma ignored"); + ppskipline(lx); + } +} + enum directive { PPXXX, /* !sorted */ @@ -1697,8 +1732,8 @@ 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 PPLINE: break; + case PPPRAGMA: pppragma(lx, &tk->span); break; case PPWARNING: break; case PPERROR: break; default: assert(0&&"nyi"); @@ -1862,27 +1897,31 @@ addpredefmacros(void) } } -const char * -initlexer(struct lexer *lx, const struct span *span, const char *file) +enum initlexer +initlexer(struct lexer *lx, const char **err, 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; + int fileid; - const char *err; struct memfile *f; if (!macros.n) addpredefmacros(); if (!tmparena->cap) tmparena->cap = NARENA; + fileid = openfile(err, &f, file); + if (fileid < 0) + return LXERR; + if (isoncefile(fileid) && isfileseen(fileid)) + return LXFILESEEN; memset(lx, 0, sizeof *lx); - lx->fileid = openfile(&err, &f, file); - if (lx->fileid < 0) - return err; + lx->fileid = fileid; + markfileseen(fileid); lx->dat = f->p; lx->ndat = f->n; lx->tmparena = &tmparena; - return NULL; + return LXOK; } /* callback to let lexer release temp memory for arena allocated token data */ @@ -1908,6 +1947,7 @@ lexerdump(struct lexer *lx, struct wbuf *out) file = tok.span.ex.file; bfmt(out, "\n# %d %'s\n", tkline, getfilename(file)); col = 1; + lexerfreetemps(lx); } else if (line < tkline && tkline - line < 5) { do ioputc(out, '\n'); @@ -1917,6 +1957,7 @@ lexerdump(struct lexer *lx, struct wbuf *out) bfmt(out, "\n# %d\n", tkline); line = tkline; col = 1; + lexerfreetemps(lx); } else if (prev.t && wsseparated(&prev, &tok)) { ioputc(out, ' '); ++col; @@ -98,11 +98,17 @@ struct lexer { struct arena **tmparena; }; +enum initlexer { + LXOK, + LXFILESEEN, + LXERR, +}; + 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); -const char *initlexer(struct lexer *, const struct span *span, const char *file); +enum initlexer initlexer(struct lexer *, const char **err, const char *file); void lexerdump(struct lexer *, struct wbuf *out); void lexerfreetemps(struct lexer *); @@ -336,7 +336,9 @@ driver(void) return 1; } } - for (int i = 0; i < task.ninf; ++i) { + if (!task.out && task.ninf == 1) + cpp(buf, task.inf[0]); + else for (int i = 0; i < task.ninf; ++i) { pid_t p; int wstat; @@ -370,7 +372,7 @@ cc1(const char *out, const char *in) extern int nerror; if (task.verbose) efmt("cc1(/*out*/ %'s, /*in*/ %'s)\n", out, in); - if (!ccopt.dbg.any) objini(out); + if (!ccopt.dbg.any) objini(in, out); ccomp(in); if (!ccopt.dbg.any && !nerror) objfini(); return !!nerror; @@ -16,10 +16,11 @@ struct objfile objout; enum { NTEXT = 4<<20 /* 4MiB */ }; void -objini(const char *file) +objini(const char *infile, const char *outfile) { - assert(!objout.file); - objout.file = file; + assert(!objout.outfile); + objout.infile = infile; + objout.outfile = outfile; objout.code = objout.textbegin = mapzeros(NTEXT); objout.textend = objout.textbegin + NTEXT; @@ -90,8 +91,8 @@ void objfini(void) { static char buf[1<<12]; - struct wbuf out = FDBUF(buf, sizeof buf, open(objout.file, O_WRONLY | O_CREAT | O_TRUNC, 0666)); - if (out.fd < 0) fatal(NULL, "could not open %'s for writing: %s", objout.file, strerror(errno)); + struct wbuf out = FDBUF(buf, sizeof buf, open(objout.outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666)); + if (out.fd < 0) fatal(NULL, "could not open %'s for writing: %s", objout.outfile, strerror(errno)); switch (mctarg->objkind) { case OBJELF: elffini(&out); break; @@ -1,7 +1,7 @@ #include "common.h" extern struct objfile { - const char *file; + const char *infile, *outfile; uchar *textbegin, *textend; uchar *code; uchar dataalign, rodataalign, bssalign; @@ -21,7 +21,7 @@ enum relockind { }; enum section { Snone, Stext, Srodata, Sdata, Sbss }; -void objini(const char *); +void objini(const char *infile, const char *outfile); void objdeffunc(const char *nam, bool globl, uint off, uint siz); uint objnewdat(const char *name, enum section, bool globl, uint siz, uint align); void objreloc(const char *sym, enum relockind, enum section, uint off, vlong addend); |