aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2025-10-18 18:12:19 +0200
committerlemon <lsof@mailbox.org>2025-10-18 18:12:19 +0200
commit99adb48d94c59cb2e5701ca39d7c40d4f63459b3 (patch)
treebe3c432db54dd7f4e1ceab70848543bba1a4ead8
parentffca6b54a9654005a121c3557bb8b245ae65ce55 (diff)
#pragma once
-rw-r--r--c.c18
-rw-r--r--common.h9
-rw-r--r--elf.c2
-rw-r--r--embedfilesdir.c4
-rw-r--r--io.c106
-rw-r--r--lex.c97
-rw-r--r--lex.h8
-rw-r--r--main.c6
-rw-r--r--obj.c11
-rw-r--r--obj.h4
10 files changed, 195 insertions, 70 deletions
diff --git a/c.c b/c.c
index 58a3147..ac3b863 100644
--- a/c.c
+++ b/c.c
@@ -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
diff --git a/common.h b/common.h
index c5b7513..c6ebf9d 100644
--- a/common.h
+++ b/common.h
@@ -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 *, ...);
diff --git a/elf.c b/elf.c
index d754800..be83118 100644
--- a/elf.c
+++ b/elf.c
@@ -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\
diff --git a/io.c b/io.c
index 67b23b6..f28499d 100644
--- a/io.c
+++ b/io.c
@@ -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, };
diff --git a/lex.c b/lex.c
index 605b3d2..951bb5a 100644
--- a/lex.c
+++ b/lex.c
@@ -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;
diff --git a/lex.h b/lex.h
index 6adbad9..20fb2ee 100644
--- a/lex.h
+++ b/lex.h
@@ -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 *);
diff --git a/main.c b/main.c
index ad40096..8020653 100644
--- a/main.c
+++ b/main.c
@@ -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;
diff --git a/obj.c b/obj.c
index 748e1e7..93a0a50 100644
--- a/obj.c
+++ b/obj.c
@@ -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;
diff --git a/obj.h b/obj.h
index 750ad48..fffc54c 100644
--- a/obj.h
+++ b/obj.h
@@ -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);