#include "all.h" u32 fnv1a(u32 h, const void *p, size_t length) { const u8 *data = p; size_t i = 0; while (i != length) { h ^= data[i++]; h *= 0x01000193; } return h; } u32 fnv1ai(u32 hash, int i) { return fnv1a(hash, &i, sizeof i); } u32 fnv1aI(u32 hash, i64 i) { return fnv1a(hash, &i, sizeof i); } u32 fnv1az(u32 hash, size_t i) { return fnv1a(hash, &i, sizeof i); } static const char *filepaths[100]; static const char *filemmaps[100]; static int nfilepaths = 0; int addfilepath(const char *s) { for (int i = 0; i < nfilepaths; ++i) if (!strcmp(filepaths[i], s)) return i; assert(nfilepaths < sizeof filepaths); filepaths[nfilepaths] = s; return nfilepaths++; } const char *fileid2path(int id) { assert(id < nfilepaths); return filepaths[id]; } void * xmalloc(size_t n) { void *p = malloc(n); assert(p && "malloc"); return p; } void * xcalloc(size_t n, size_t m) { void *p = calloc(n,m); assert(p && "calloc"); return p; } void * xrealloc(void *p, size_t n) { if (!p) return xmalloc(n); if (!n) return free(p), NULL; p = realloc(p, n); assert(p && "realloc"); return p; } char * xasprintf(const char *fmt, ...) { va_list ap, aq; int n = 32, m; char *str = xcalloc(n, 1); va_start(ap, fmt); m = vsnprintf(str, n, fmt, ap) + 1; str = xrealloc(str, m); if (m > n) { va_copy(aq, ap); vsprintf(str, fmt, aq); va_end(aq); } va_end(ap); assert(str); return str; } char * xstrdup(const char *s) { return strcpy(xmalloc(strlen(s) + 1), s); } #include #include #include #include static void eprifileline(struct span span) { const char *src = filemmaps[span.fileid]; long i, j, n; if (!src) { const char *path = fileid2path(span.fileid); struct stat st; int fd = open(path, O_RDONLY); if (fd < -1) { perror("open()"); return; } if (stat(path, &st) < 0) { perror("stat()"); close(fd); return; } // XXX this maybe causes SIGBUS later if we're at last line + no ending newline + st_size multiple of 4096 filemmaps[span.fileid] = src = mmap(NULL, st.st_size + 1, PROT_READ, MAP_PRIVATE, fd, 0); assert(src && src != (void *)-1 && "mmap"); close(fd); } // line begin for (i = span.idx; i > 0 && src[i] != '\n'; --i) ; if (i > 0) ++i; // line end for (j = span.idx; src[j] && src[j] != '\n'; ++j) ; --j; n = fprintf(stderr, "%4d | ", span.line); for (long k = i; k <= j; ++k) epri("%c", src[k]); epri("\n"); while (n--) epri(" "); for (long k = i, j = 0; src[k] && src[k] != '\n'; ++k, ++j) fprintf(stderr, "%s", j + 1 == span.col ? "^" : " "); epri("\n"); } void noreturn fatal(struct parser *P, struct span span, const char *fmt, ...) { va_list ap; va_start(ap, fmt); int i = 0; epri("%s:%d:%d: error: ", fileid2path(span.fileid), span.line, span.col); vepri(fmt, ap); epri("\n"); eprifileline(span); for (struct expan *ep = P->curexpan; ep; ep = ep->prev, ++i) { if (ep->name && (i < 8 || !ep->prev || !ep->prev->prev)) { span = ep->span; epri("* while expanding %s `%s' at %s:%d:%d\n", ep->tepl ? "template" : "macro", ep->name, fileid2path(ep->span.fileid), span.line, span.col); eprifileline(span); } else if (ep->name && i == 10) { epri(" ... (some expansions omitted)\n"); } } va_end(ap); exit(127); }