import "vec.hff"; import "all.hff"; extern fn xmalloc(n usize) *void { let p = malloc(n); assert(p != #null, "malloc"); return p; } extern fn xcalloc(n usize, m usize) *void { let p = calloc(n, n); assert(p != #null, "calloc"); return p; } extern fn xrealloc(p *void, n usize) *void { let p = realloc(p, n); assert(p != #null, "realloc"); return p; } extern fn xstrdup(str *const u8) *u8 { let p = xmalloc(strlen(str) + 1); strcpy(p, str); return p; } extern fn fnv1a(h u32, d [#]const u8) u32 { foreach(i, x, d, h ^= x; h *= 0x01000193; ) return h; } extern fn fnv1a_s(h u32, str *const u8) u32 { while *str != 0 { h ^= *str++; h *= 0x01000193; } return h; } static filepaths [64]*const u8 = {}; static nfilepaths int = 0; extern fn addfilepath(s *const u8) int { let i0 = fnv1a_s(FNV1A_INI, s) % filepaths.#len; let i int = i0; do { if filepaths[i] == #null { break; } else if streq(filepaths[i], s) { return i; } } while ++i != i0; assert(nfilepaths++ < filepaths.#len, "too many files"); filepaths[i] = s; return i; } fn fileid2path(id int) *const u8 { assert(id >= 0 and id < filepaths.#len, "fileid"); let s = filepaths[id]; assert(s != #null, "fileid"); return s; } extern fn fatal(P *Parser, loc Loc, fmt *const u8, ...) void { let ap va_list #?; ap->start(fmt); efmt("%s:%i:%i: error: ", fileid2path(loc.fileid), loc.line, loc.col); vefmt(fmt, ap); efmt("\n"); ap->end(); exit(1); } extern fn internstr(s *const u8) *const u8 { static buf Vec<*const u8> = {}; static set **const u8 = {}; static N int = {}; static count int = {}; if set == #null { set = xcalloc(N = 16, sizeof int); } if count == N / 2 { free(set); set = xcalloc(N *= 2, sizeof int); vec_each(s, i, buf, let i = fnv1a_s(FNV1A_INI, s) & (N - 1); for ;; { if set[i] == #null { set[i] = s; break; } i = (i + 1) & (N - 1); } ) } let i0 = fnv1a_s(FNV1A_INI, s) & (N - 1); let i int = i0; do { if set[i] == #null { ++count; buf->push(xstrdup(s)); set[i] = buf.dat[buf.len - 1]; return set[i]; } else if streq(set[i], s) { return set[i]; } i = (i + 1) & (N - 1); } while i != i0; assert(#f, "unreachable"); }