diff options
| author | 2023-05-26 09:20:58 +0200 | |
|---|---|---|
| committer | 2023-05-26 09:20:58 +0200 | |
| commit | 640a3dac2b18d037169af15dfd5502c386c7e828 (patch) | |
| tree | 79e7ee3fa81e73855ce1bc78d7c4bf1ad3ac8f0d | |
| parent | 9100ed2b5dd01df8e6b766c7bc2a12c0dd44f1ff (diff) | |
hm
| -rw-r--r-- | common.h | 10 | ||||
| -rw-r--r-- | io.c | 33 | ||||
| -rw-r--r-- | ir.c | 10 | ||||
| -rw-r--r-- | ir.h | 2 | ||||
| -rw-r--r-- | irdump.c | 4 | ||||
| -rw-r--r-- | lex.c | 513 | ||||
| -rw-r--r-- | main.c | 38 | ||||
| -rw-r--r-- | mem.c | 93 | ||||
| -rw-r--r-- | parse.c | 257 | ||||
| -rw-r--r-- | parse.h | 54 | ||||
| -rw-r--r-- | targ.c | 12 | ||||
| -rw-r--r-- | test.c | 40 | ||||
| -rw-r--r-- | type.c | 6 |
13 files changed, 876 insertions, 196 deletions
@@ -57,15 +57,19 @@ ptrhash(const void *p) { return (uint)(size_t)p * 2654435761; } static inline uint -popcnt(uint x) { +popcnt(uvlong x) { #ifdef __GNUC__ - return __builtin_popcount(x); + return __builtin_popcountll(x); #else uint n = 0; while (x) x >>= 1, ++n; return n; #endif } +static inline bool +ispo2(uvlong x) { + return (x & (x - 1)) == 0; +} /******************/ /* COMPILER STATE */ @@ -256,7 +260,7 @@ typearrlen(union type t) extern uchar targ_primsizes[]; extern uchar targ_primalign[]; -extern enum typetag targ_sizetype; +extern enum typetag targ_sizetype, targ_ptrdifftype; extern bool targ_charsigned, targ_bigendian; void targ_init(const char *targ); @@ -185,6 +185,7 @@ pritypebefore(struct wbuf *buf, union type ty, int qual) case TYFLOAT: s = "float"; goto Prim; case TYDOUBLE: s = "double"; goto Prim; case TYLDOUBLE:s = "long double"; goto Prim; + case TYVALIST: s = "va_list"; goto Prim; case TYPTR: chld = typechild(ty); n = pritypebefore(buf, chld, ty.flag & TFCHLDQUAL); @@ -432,7 +433,7 @@ vbfmt(struct wbuf *out, const char *fmt, va_list ap) Tok: switch (tok->t) { case TKXXX: - n += bwriteS(buf, "???"); + n += bwriteS(buf, "\?\?\?"); break; case TKNUMLIT: s = (const char *)(getfile(tok->span.sl.file)->p + tok->span.sl.off); @@ -450,19 +451,37 @@ vbfmt(struct wbuf *out, const char *fmt, va_list ap) case TKEOF: n += bwriteS(buf, "<end-of-file>"); break; + case TKEQU: s = "=="; C2: iowrite(buf, s, 2); n += 2; break; + case TKNEQ: s = "!="; goto C2; + case TKLTE: s = "<="; goto C2; + case TKGTE: s = ">="; goto C2; + case TKSHR: s = ">>"; goto C2; + case TKSHL: s = "<<"; goto C2; + case TKINC: s = "++"; goto C2; + case TKDEC: s = "--"; goto C2; + case TKDOTS: n += bwriteS(buf, "..."); break; + case TKARROW: s = "->"; goto C2; + case TKPPCAT: s = "##"; goto C2; + case TKLOGAND: s = "&&"; goto C2; + case TKLOGIOR: s = "||"; goto C2; + case TKSETADD: s = "+="; goto C2; + case TKSETSUB: s = "-="; goto C2; + case TKSETMUL: s = "*="; goto C2; + case TKSETDIV: s = "/="; goto C2; + case TKSETMOD: s = "%="; goto C2; + case TKSETIOR: s = "|="; goto C2; + case TKSETXOR: s = "^="; goto C2; + case TKSETAND: s = "&="; goto C2; + case TKSETSHR: n += bwriteS(buf, ">>="); break; + case TKSETSHL: n += bwriteS(buf, "<<="); break; default: if (quote) n += bputc(buf, '`'); if (in_range(tok->t, TKWBEGIN_, TKWEND_)) { n += bfmt(buf, "%s", tok->ident); } else if (aisprint(tok->t)) { n += bputc(buf, tok->t); - } else if (tok->t >> 16) { - n += bputc(buf, tok->t >> 0); - n += bputc(buf, tok->t >> 8); - n += bputc(buf, tok->t >> 16); } else { - n += bputc(buf, tok->t >> 0); - n += bputc(buf, tok->t >> 8); + n += bwriteS(buf, "??"); } if (quote) n += bputc(buf, '\''); break; @@ -24,11 +24,11 @@ irinit(struct function *fn) } type2cls[TYFLOAT] = KF4; type2cls[TYDOUBLE] = KF8; - type2cls[TYPTR] = KIP; - type2cls[TYARRAY] = KIP; + type2cls[TYPTR] = KPTR; + type2cls[TYARRAY] = KPTR; cls2siz[KI4] = cls2siz[KF4] = 4; cls2siz[KI8] = cls2siz[KF8] = 8; - cls2siz[KIP] = targ_primsizes[TYPTR]; + cls2siz[KPTR] = targ_primsizes[TYPTR]; } fn->entry = fn->curblk = alloc(&fn->arena, sizeof(struct block), 0); fn->entry->lprev = fn->entry->lnext = fn->entry; @@ -154,7 +154,7 @@ mkfltcon(struct function *fn, enum irclass k, double f) union irref mksymref(struct function *fn, const char *s) { - struct xcon con = { 1, KIP, .sym = s }; + struct xcon con = { 1, KPTR, .sym = s }; return mkref(RXCON, addcon(&con)); } @@ -164,7 +164,7 @@ mkcall(struct function *fn, union type fnty, uint narg, union irref *args, union const struct typedata *td = &typedata[fnty.dat]; struct ircall call = { narg, td->variadic ? td->nmemb : -1 }; - assert(td->variadic ? narg >= td->nmemb : narg == td->nmemb); + if (!td->kandr) assert(td->variadic ? narg >= td->nmemb : narg == td->nmemb); if (narg) { call.args = alloc(&fn->arena, narg*sizeof *args + narg*sizeof(union irtype), 0); call.typs = (union irtype *)((char *)call.args + narg*sizeof *args); @@ -2,7 +2,7 @@ enum irclass { KXXX, - KI4, KI8, KIP, + KI4, KI8, KPTR, KF4, KF8, }; @@ -5,7 +5,7 @@ extern struct xcon conht[]; extern vec_of(struct ircall) calls; static const char *clsname[] = { - "?", "i4", "i8", "iP", "f4", "f8" + "?", "i4", "i8", "ptr", "f4", "f8" }; static void @@ -38,7 +38,7 @@ dumpref(union irref ref) else switch (con->cls) { case KI4: efmt("%d", con->i4); break; case KI8: efmt("%ld", con->i8); break; - case KIP: efmt("%'x", con->i8); break; + case KPTR: efmt("%'x", con->i8); break; case KF4: efmt("%f", con->fs); break; case KF8: efmt("%f", con->fd); break; default: assert(0); @@ -1,7 +1,8 @@ +#include "common.h" #include "parse.h" #include <string.h> -static const char * +const char * intern(const char *s) { static vec_of(char) mem; @@ -24,7 +25,7 @@ intern(const char *s) } static void -identkeyword(struct token *tk, const char *s, int n) +identkeyword(struct token *tk, const char *s, int len) { static const struct { const char *s; enum toktag t; enum cstd cstd; } kwtab[] = { #define _(kw, cstd) { #kw, TKW##kw, cstd }, @@ -33,7 +34,7 @@ identkeyword(struct token *tk, const char *s, int n) }; int l = 0, h = arraylength(kwtab) - 1, i, cmp; - if (n > TKWMAXLEN_) goto ident; + if (len > TKWMAXLEN_) goto ident; /* binary search over sorted array */ while (l <= h) { i = (l + h) / 2; @@ -66,14 +67,14 @@ next0(struct parser *pr) return TKEOF; if (trigraph && !memcmp(pr->dat+pr->idx, "??", 2)) { switch (pr->dat[pr->idx+2]) { - case '=': pr->idx += 3; return '#'; - case '(': pr->idx += 3; return '['; - case ')': pr->idx += 3; return ']'; - case '!': pr->idx += 3; return '|'; - case '<': pr->idx += 3; return '{'; - case '>': pr->idx += 3; return '}'; - case '-': pr->idx += 3; return '~'; - case '/': pr->idx += 3; return '\\'; + case '=': pr->idx += 3; return '#'; + case '(': pr->idx += 3; return '['; + case ')': pr->idx += 3; return ']'; + case '!': pr->idx += 3; return '|'; + case '<': pr->idx += 3; return '{'; + case '>': pr->idx += 3; return '}'; + case '-': pr->idx += 3; return '~'; + case '/': pr->idx += 3; return '\\'; case '\'': pr->idx += 3; return '^'; } } @@ -141,46 +142,76 @@ aissep(int c) { } static void -strtonum(struct token *tk, char *s) +strtonum(struct token *tk, const char *s) { - extern int sscanf(const char *, const char *, ...); extern uvlong strtoull(const char *, char **, int); - char *suffix; + extern double strtod(const char *, char **); + char *sx; /*suffix*/ tk->ty = TYXXX; - if (strchr(s, '.')) { - /* float literal */ - int n; - - if (!sscanf(s, "%lf%n", &tk->f, &n)) - return; - suffix = s + n; - tk->ty = TYDOUBLE; - } else { - tk->u = strtoull(s, &suffix, 0); - if (suffix == s) + if (strchr(s, '.')) { /* float literal */ + Float: + tk->f = strtod(s, &sx); + if (sx == s) return; - /* XXX proper int lit types */ - tk->ty = TYINT; - } - if (!*suffix) return; - - for (s = suffix; *s; ++s) - *s |= 0x20; /* make lowercase */ - if (tk->ty == TYDOUBLE) { - if (!strcmp(suffix, "f")) { + if (!*sx) + tk->ty = TYDOUBLE; + else if ((sx[0]|0x20) == 'f' && !sx[1]) { tk->ty = TYFLOAT; tk->f = (float) tk->f; } else tk->ty = TYXXX; - } else { - if (!strcmp(suffix, "u")) tk->ty = TYUINT; - else if (!strcmp(suffix, "ul")) tk->ty = TYULONG; - else if (!strcmp(suffix, "lu")) tk->ty = TYULONG; - else if (!strcmp(suffix, "ull")) tk->ty = TYUVLONG; - else if (!strcmp(suffix, "llu")) tk->ty = TYUVLONG; - else if (!strcmp(suffix, "ll")) tk->ty = TYVLONG; - else if (!strcmp(suffix, "l")) tk->ty = TYLONG; - else tk->ty = TYXXX; + } else { /* int literal */ + static uvlong max4typ[TYUVLONG-TYINT+1]; + enum typetag t; + bool u = 0, dec = s[0] != '0'; + bool c99 = ccopt.cstd >= STDC99; + + tk->u = strtoull(s, &sx, 0); + if (sx == s) + return; + + if (!max4typ[0]) + for (t = TYINT; t <= TYUVLONG; ++t) + max4typ[t-TYINT] = ((1ull << (8*targ_primsizes[t]-1))-1) << isunsignedt(t) | 1; + + if (!*sx) /* '' */ {} + else if ((sx[0]|0x20) == 'u') { + u = 1; + if (!sx[1]) /* 'u' */ {} + else if ((sx[1]|0x20) == 'l') { + if (!sx[2]) /* 'ul' */ goto L; + if (c99 && sx[1] == sx[2] && !sx[3]) /* 'ull' */ goto LL; + return; + } else return; + } else if ((sx[0]|0x20) == 'l') { + if (!sx[1]) /* 'l' */ goto L; + if ((sx[1]|0x20) == 'u' && !sx[2]) /* 'lu' */ { u=1; goto L; } + if (c99 && sx[1] == sx[0]) { + if (!sx[2]) /* 'll' */ goto LL; + if ((sx[2]|0x20) == 'u' && !sx[3]) /* 'llu' */ { u=1; goto LL; } + } + return; + } else if ((sx[0]|0x20) == 'e' || (sx[0]|0x20) == 'p') + goto Float; + else return; + +#define I(T) if (tk->u <= max4typ[T - TYINT]) { t = T; goto Ok; } + I(TYINT) + if (u || !dec) I(TYUINT) + L: + I(TYLONG) + if (u || !dec || !c99) I(TYULONG) + if (c99) { + LL: + I(TYVLONG) + if (u || !dec) I(TYUVLONG) + } +#undef I + /* too big */ + return; + Ok: + if (u && issignedt(t)) ++t; /* make unsigned */ + tk->ty = t; } } @@ -273,6 +304,16 @@ readstrchrlit(struct parser *pr, struct token *tk, char delim) vfree(&b); } +static bool +isppnum(char prev, char c) +{ + if (!aissep(c) || c == '.') + return 1; + if (c == '+' || c == '-') + return (prev|0x20) == 'e' || (prev|0x20) == 'p'; + return 0; +} + static int lex0(struct parser *pr, struct token *tk) { @@ -351,22 +392,24 @@ Begin: if (match(pr, '|')) RET(TKLOGIOR); if (match(pr, '=')) RET(TKSETIOR); RET(c); + case '\'': + case '"': + readstrchrlit(pr, tk, c); + goto End; case '.': if (peek(pr, 0) == '.' && peek(pr, 1) == '.') { next(pr), next(pr); RET(TKDOTS); + } else if (aisdigit(peek(pr, 0))) { + goto Numlit; } RET(c); - case '\'': - case '"': - readstrchrlit(pr, tk, c); - goto End; default: - if (aisdigit(c)) { + if (aisdigit(c)) Numlit: { char tmp[70]; int n = 0; tmp[n++] = c; - while (!aissep(c = peek(pr, 0)) || c == '.' || ((tmp[n-1]|0x20) == 'e' && (c == '+' || c == '-'))) { + while (isppnum(tmp[n-1], peek(pr, 0))) { assert(n < arraylength(tmp)-1 && "too big"); tmp[n++] = next(pr); } @@ -386,7 +429,8 @@ Begin: goto End; } } - fatal(&(struct span) {{ idx, pr->chridx - idx, pr->fileid }}, "unexpected character %'c at %d", c, idx); + fatal(&(struct span) {{ idx, pr->chridx - idx, pr->fileid }}, + "unexpected character %'c at %d", c, idx); End: tk->span.sl.file = pr->fileid; tk->span.sl.off = idx; @@ -402,7 +446,7 @@ End: /* PREPROCESSOR */ /****************/ -#define isppident(tk) ((tk).t == TKIDENT || in_range((tk).t, TKWBEGIN_, TKWEND_)) +#define isppident(tk) (in_range((tk).t, TKIDENT, TKWEND_)) static vec_of(struct macro) macros; static ushort macroht[1<<10]; @@ -516,7 +560,7 @@ putmac(struct macro *mac) static void ppskipline(struct parser *pr) { - while (peek(pr, 0) != '\n' && peek(pr, 0 != TKEOF)) + while (peek(pr, 0) != '\n' && peek(pr, 0) != TKEOF) next(pr); } @@ -536,7 +580,7 @@ ppdefine(struct parser *pr) mac.name = tk0.ident; mac.span = tk0.span.sl; - if (peek(pr, 0) != '(') { + if (peek(pr, 0) == '(') { mac.fnlike = 1; } @@ -550,6 +594,253 @@ ppdefine(struct parser *pr) putmac(&mac); } +static struct token epeektk; +static int +elex(struct parser *pr, struct token *tk) +{ + if (epeektk.t) { + int tt = epeektk.t; + if (tk) *tk = epeektk; + epeektk.t = 0; + return tt; + } + return lex0(pr, tk); +} + +static int +epeek(struct parser *pr, struct token *tk) +{ + if (!epeektk.t) elex(pr, &epeektk); + if (tk) *tk = epeektk; + return epeektk.t; +} + +static int +tkprec(int tt) +{ + static const char tab[] = { + ['*'] = 12, ['/'] = 12, ['%'] = 12, + ['+'] = 11, ['-'] = 11, + [TKSHL] = 10, [TKSHR] = 10, + ['<'] = 9, ['>'] = 9, [TKLTE] = 9, [TKGTE] = 9, + [TKEQU] = 8, [TKNEQ] = 8, + ['&'] = 7, + ['^'] = 6, + ['|'] = 5, + [TKLOGAND] = 4, + [TKLOGIOR] = 3, + ['?'] = 2, + }; + if ((uint)tt < arraylength(tab)) + return tab[tt] - 1; + return -1; +} + +static vlong +expr(struct parser *pr, bool *pu, int prec) +{ + vlong x, y; + struct token tk; + int opprec; + char unops[16]; + int nunop = 0; + bool xu = 0, yu; /* x unsigned?; y unsigned? */ + +Unary: + switch (elex(pr, &tk)) { + case '-': case '~': case '!': + unops[nunop++] = tk.t; + if (nunop >= arraylength(unops)) { + x = expr(pr, &xu, 999); + break; + } + /* fallthru */ + case '+': goto Unary; + case '(': + x = expr(pr, &xu, 1); + if (elex(pr, &tk) != ')') { + error(&tk.span, "expected ')'"); + goto Err; + } + break; + case TKNUMLIT: + if (!tk.ty) { + error(&tk.span, "bad number literal"); + goto Err; + } else if (isfltt(tk.ty)) { + error(&tk.span, "float literal in preprocessor expresion"); + goto Err; + } + x = tk.i; + xu = isunsignedt(tk.ty); + break; + default: + if (in_range(tk.t, TKWBEGIN_, TKWEND_)) { + case TKIDENT: + x = 0; + xu = 0; + break; + } + error(&tk.span, "expected preprocessor integer expression"); + goto Err; + } + + while (nunop > 0) + switch (unops[--nunop]) { + case '-': x = -x; break; + case '~': x = ~x; break; + case '!': x = !x; break; + default: assert(0); + } + + while ((opprec = tkprec(epeek(pr, &tk))) >= prec) { + elex(pr, &tk); + if (tk.t != '?') { + bool u; + y = expr(pr, &yu, opprec + 1); + u = xu | yu; + switch ((int) tk.t) { + case '+': x += y; break; + case '-': x -= y; break; + case '*': x *= y; break; + case '&': x &= y; break; + case '^': x ^= y; break; + case '|': x |= y; break; + case '/': if (y) x = u ? (uvlong) x / y : x / y; + else goto Div0; + break; + case '%': if (y) x = u ? (uvlong) x % y : x % y; + else Div0: error(&tk.span, "division by zero"); + break; + case TKSHL: if ((uvlong)y < 64) x <<= y; + else goto BadShift; + break; + case TKSHR: if ((uvlong)y < 64) x = u ? (uvlong) x >> y : x >> y; + else BadShift: error(&tk.span, "bad shift by %ld", y); + break; + case '<': x = u ? (uvlong) x < y : x < y; goto BoolRes; + case '>': x = u ? (uvlong) x > y : x > y; goto BoolRes; + case TKLTE: x = u ? (uvlong) x <= y : x <= y; goto BoolRes; + case TKGTE: x = u ? (uvlong) x >= y : x >= y; goto BoolRes; + case TKEQU: x = x == y; goto BoolRes; + case TKNEQ: x = x != y; goto BoolRes; + case TKLOGAND: x = x && y; goto BoolRes; + case TKLOGIOR: x = x || y; BoolRes: u = 0; break; + default: assert(0); + } + xu = u; + } else { + struct span span = tk.span; + vlong m = expr(pr, &xu, 1); + if (elex(pr, &tk) != ':') { + error(&tk.span, "expected ':'"); + note(&span, "to match conditional expression here"); + goto Err; + } + y = expr(pr, &yu, 1); + efmt("%ld ? %ld : %ld\n", x, m, y); + x = x ? m : y; + xu |= yu; + } + } + if (!prec) /* not a sub expr */ + if (elex(pr, &tk) != '\n' && tk.t != TKEOF) { + error(&tk.span, "garbage after preprocessor expression"); + ppskipline(pr); + } + if (pu) *pu = xu; + return x; + +Err: + ppskipline(pr); + if (pu) *pu = xu; + return 0; +} + +enum { + PPCNDFALSE, /* the condition was zero, skip until #else/#elif */ + PPCNDTRUE, /* the condition was non-zero, emit until #else/#elif */ + PPCNDTAKEN /* some branch was already taken, skip until #else */ +}; +static struct ppcnd { + struct span0 ifspan; + uchar cnd; + bool elsep; +} ppcndstk[32]; +static int nppcnd; + +static void +ppif(struct parser *pr, const struct span *span) +{ + vlong v = expr(pr, NULL, 0); + assert(nppcnd < arraylength(ppcndstk) && "too many nested #if"); + ppcndstk[nppcnd].ifspan = span->sl; + ppcndstk[nppcnd].cnd = v ? PPCNDTRUE : PPCNDFALSE; + ppcndstk[nppcnd++].elsep = 0; +} + +static void +ppelif(struct parser *pr, const struct span *span) +{ + vlong v; + struct ppcnd *cnd; + + if (!nppcnd) { + error(span, "#elif without matching #if"); + ppif(pr, span); + return; + } + v = expr(pr, NULL, 0); + cnd = &ppcndstk[nppcnd-1]; + if (cnd->elsep) { + error(span, "#elif after #else"); + return; + } + switch (cnd->cnd) { + case PPCNDTRUE: cnd->cnd = PPCNDTAKEN; break; + case PPCNDFALSE: cnd->cnd = v ? PPCNDTRUE : PPCNDFALSE; break; + case PPCNDTAKEN: assert(0); + } +} + +static void +ppendif(struct parser *pr, const struct span *span) +{ + struct token tk; + if (lex0(pr, &tk) != '\n' && tk.t != TKEOF) { + error(&tk.span, "garbage after #endif"); + ppskipline(pr); + } + if (!nppcnd) { + error(span, "#endif without matching #if"); + return; + } + --nppcnd; +} + +static void +ppelse(struct parser *pr, const struct span *span) +{ + struct token tk; + struct ppcnd *cnd; + if (lex0(pr, &tk) != '\n' && tk.t != TKEOF) { + error(&tk.span, "garbage after #else"); + ppskipline(pr); + } + if (!nppcnd) { + error(span, "#else without matching #if"); + return; + } + cnd = &ppcndstk[nppcnd-1]; + if (cnd->elsep) + error(span, "#else after #else"); + switch (cnd->cnd) { + case PPCNDFALSE: cnd->cnd = PPCNDTRUE; break; + case PPCNDTRUE: cnd->cnd = PPCNDTAKEN; break; + } + cnd->elsep = 1; +} + static struct macrostack mstk[64], *mfreelist; static bool tryexpand(struct parser *pr, const struct token *tk) @@ -557,18 +848,19 @@ tryexpand(struct parser *pr, const struct token *tk) static bool inimstk; struct macro *mac; struct macrostack *l; - int macidx; + int macidx, i; + + if (!isppident(*tk) || !(mac = findmac(tk->ident))) + return 0; + if (!inimstk) { inimstk = 1; - for (int i = 0; i < arraylength(mstk); ++i) { + for (i = 0; i < arraylength(mstk); ++i) { mstk[i].link = mfreelist; mfreelist = &mstk[i]; } } - if (!isppident(*tk) || !(mac = findmac(tk->ident))) - return 0; - macidx = mac - macros.p; /* prevent infinite recursion */ for (l = pr->macstk; l; l = l->link) @@ -603,12 +895,69 @@ popmac(struct parser *pr) } while ((stk = pr->macstk) && stk->idx >= macros.p[stk->mac].rlist.n); } +enum directive { + PPXXX, + /* !sorted */ + PPDEFINE, + PPELIF, + PPELIFDEF, + PPELIFNDEF, + PPELSE, + PPENDIF, + PPERROR, + PPIF, + PPIFDEF, + PPIFNDEF, + PPINCLUDE, + PPLINE, + PPPRAGMA, + PPUNDEF, + PPWARNING, +}; + +static enum directive +findppcmd(const struct token *tk) +{ + static const char *tab[] = { + /* !sorted */ + "define", + "elif", + "elifdef", + "elifndef", + "else", + "endif", + "error", + "if", + "ifdef", + "ifndef", + "include", + "line", + "pragma", + "undef", + "warning", + }; + int l = 0, h = arraylength(tab) - 1, i, cmp; + const char *s = tk->ident; + + if (tk->t == TKWif) return PPIF; + if (tk->t == TKWelse) return PPELSE; + /* binary search over sorted array */ + while (l <= h) { + i = (l + h) / 2; + cmp = strcmp(tab[i], s); + if (cmp < 0) l = i + 1; + else if (cmp > 0) h = i - 1; + else return i + 1; + } + return PPXXX; +} + int lex(struct parser *pr, struct token *tk_) { struct token tkx[1], *tk; int t; - bool linebegin = 0; + bool linebegin, skip; assert(tk_ != &pr->peektok); tk = tk_ ? tk_ : tkx; @@ -631,19 +980,53 @@ lex(struct parser *pr, struct token *tk_) return tk->t; } - for (;;) { + skip = nppcnd ? ppcndstk[nppcnd-1].cnd != PPCNDTRUE : 0; + for (linebegin = 0;;) { while ((t = lex0(pr, tk)) == '\n') linebegin = 1; if (t == '#' && linebegin) { - if (lex0(pr, tk) == '\n') break; - else if (tk->t == TKIDENT && !strcmp(tk->ident, "define")) - ppdefine(pr); - else { - error(&tk->span, "invalid preprocessor directive"); + if (lex0(pr, tk) == '\n') { } + else if (isppident(*tk)) { + if (!skip) { + switch (findppcmd(tk)) { + case PPXXX: goto BadPP; + case PPDEFINE: ppdefine(pr); break; + case PPIF: ppif(pr, &tk->span); break; + case PPELIF: ppelif(pr, &tk->span); break; + case PPENDIF: ppendif(pr, &tk->span); break; + case PPELSE: ppelse(pr, &tk->span); break; + default: assert(0&&"nyi"); + } + } else { + switch (findppcmd(tk)) { + case PPIF: /* increment nesting level */ + assert(nppcnd < arraylength(ppcndstk) && "too many nested #if"); + ppcndstk[nppcnd].ifspan = tk->span.sl; + ppcndstk[nppcnd].cnd = PPCNDTAKEN; + ppcndstk[nppcnd++].elsep = 0; + break; + case PPELIF: ppelif(pr, &tk->span); break; + case PPENDIF: ppendif(pr, &tk->span); break; + case PPELSE: ppelse(pr, &tk->span); break; + default: ppskipline(pr); break; + } + } + skip = nppcnd ? ppcndstk[nppcnd-1].cnd != PPCNDTRUE : 0; + } else { + if (!skip) { + BadPP: + error(&tk->span, "invalid preprocessor directive"); + } ppskipline(pr); } } else { + linebegin = 0; + if (skip && tk->t != TKEOF) continue; if (tryexpand(pr, tk)) return lex(pr, tk_); + if (t == TKEOF && nppcnd) { + struct span span = { ppcndstk[nppcnd-1].ifspan }; + error(&span, "#if is not matched by #endif"); + } return t; } } @@ -1,3 +1,4 @@ +#include "common.h" #include "parse.h" #include <stdlib.h> @@ -10,18 +11,51 @@ flushstd(void) ioflush(&bstderr); } +static const char * +optval(const char *arg, const char *opt) +{ + /* arg="foo=bar123"; opt="foo"; returns "bar123" */ + uint n1 = strlen(arg), n2 = strlen(opt); + if (n1 < n2+1 || memcmp(arg, opt, n2) != 0 || arg[n2] != '=') + return NULL; + return arg + n2 + 1; +} + +static void +optparse(const char **file, const char **targ, char **args) +{ + const char *arg, *x; + *file = *targ = NULL; + while ((arg = *++args)) { + if (*arg++ != '-') { + *file = arg-1; + continue; + } + if ((x = optval(arg, "std"))) { + if (!strcmp(x, "c89")) ccopt.cstd = STDC89; + else if (!strcmp(x, "c99")) ccopt.cstd = STDC99; + else if (!strcmp(x, "c11")) ccopt.cstd = STDC11; + else if (!strcmp(x, "c2x")) ccopt.cstd = STDC23; + else if (!strcmp(x, "c23")) ccopt.cstd = STDC23; + else goto Bad; + } else Bad: warn(NULL, "invalid option: %'s", arg-1); + } +} + int main(int argc, char **argv) { struct parser pr; + const char *file, *targ; atexit(flushstd); if (argc < 2) { efmt("usage: %s [options] <file>\n", *argv); return 1; } + optparse(&file, &targ, argv); - targ_init("amd64-sysv"); - initparser(&pr, argv[1]); + targ_init(targ ? targ : "amd64-sysv"); + initparser(&pr, file); parse(&pr); } @@ -114,4 +114,97 @@ freearena(struct arena *ar) } } +#if 0 + +int +map_get_(struct mapbase *m, int k) +{ + if (!m->N) return 0; + for (int i = k;; ++i) { + bool notempty = bstest(m->bs, k); + i &= m->N - 1; + if (notempty && m->k[i] == k) + return i; + if (!notempty) + return -1; + } +} + + +void +map_init_(struct mapbase *m, void **v, uint vsiz, uint N) +{ + uint sizk = N*sizeof(int), + sizv = N*vsiz, + sizbs = BSCOUNT(N)*sizeof(struct bitset); + + assert(N && (N & (N - 1)) == 0); + m->k = xcalloc(sizk + sizv + sizbs, "map_rehash"); + *v = (char *)m->k + sizk; + m->bs = (struct bitset *)((char *)*v + sizv); + m->N = N; +} + +static void +map_rehash(struct mapbase *m, void **v, uint vsiz) +{ + int *newk, i, k, j; + void *newv; + struct bitset *newbs; + uint N2 = m->N << 1, + sizk = N2*sizeof(int), + sizv = N2*vsiz, + sizbs = BSCOUNT(N2)*sizeof(struct bitset); + + assert(N2); + newk = xrealloc(NULL, sizk + sizv + sizbs, "map_rehash"); + newv = (char *)newk + sizk; + newbs = (struct bitset *)((char *)newv + sizv); + for (i = 0; i < m->N; ++i) { + if (!bstest(m->bs, i)) + continue; + j = k = m->k[i]; + for (;; ++j) { + j &= N2 - 1; + if (!bstest(newbs, i)) { + bsset(newbs, i); + m->k[j] = k; + memcpy((char *)newv + j*vsiz, (char *)*v + i*vsiz, vsiz); + break; + } + } + } + free(m->k); + free(*v); + free(m->bs); + m->k = newk; + *v = newv; + m->bs = newbs; + m->N = N2; +} + +int +map_set_(struct mapbase *m, void **v, uint vsiz, int k) +{ + if (!m->N) return 0; + if (m->n >= m->N >> 1) { + map_rehash(m, v, vsiz); + assert(m->n < m->N); + } + for (int i = k;; ++i) { + bool notempty = bstest(m->bs, k); + i &= m->N - 1; + if (notempty && m->k[i] == k) + return i; + if (!notempty) { + m->k[i] = k; + bsset(m->bs, i); + ++m->n; + return i; + } + } +} + +#endif + /* vim:set ts=3 sw=3 expandtab: */ @@ -90,6 +90,7 @@ struct declstate { uint align; bool more, varini, funcdef, tagdecl; const char **pnames; + struct span *pspans; }; static struct decl pdecl(struct declstate *st, struct parser *pr); @@ -256,6 +257,19 @@ argpromote(union type t) } static void +incdeccheck(enum toktag tt, const struct expr *ex, const struct span *span) +{ + if (!isscalar(ex->ty)) + error(&ex->span, "invalid operand to %tt (%ty)", tt, ex->ty); + else if (!islvalue(ex)) + error(&ex->span, "operand to %tt is not an lvalue", tt); + else if (ex->ty.t == TYPTR && isincomplete(typechild(ex->ty))) + error(span, "arithmetic on pointer to incomplete type (%ty)", ex->ty); + else if (ex->ty.t == TYPTR && typechild(ex->ty).t == TYFUNC) + error(span, "arithmetic on function pointer (%ty)", ex->ty); +} + +static void postfixops(struct parser *pr, struct expr *lhs) { struct expr ex, tmp; @@ -269,17 +283,12 @@ postfixops(struct parser *pr, struct expr *lhs) case TKINC: case TKDEC: lex(pr, &tk); - if (!isscalar(lhs->ty)) - error(&lhs->span, "invalid operand to postfix %tt (%ty)", &tk, lhs->ty); span = lhs->span; if (!joinspan(&span.ex, tk.span.ex)) span = tk.span; - if (lhs->ty.t == TYPTR && isincomplete(typechild(lhs->ty))) - error(&span, "arithmetic on pointer to incomplete type (%ty)", lhs->ty); - else if (lhs->ty.t == TYPTR && typechild(lhs->ty).t == TYFUNC) - error(&span, "arithmetic on function pointer", &tk, lhs->ty); + incdeccheck(tk.t, lhs, &span); *lhs = mkexpr(tk.t == TKINC ? EPOSTINC : EPOSTDEC, span, lhs->ty, .sub = exprdup(pr, lhs)); break; - case '[': + case '[': /* a[subscript] */ lex(pr, NULL); ex = commaexpr(pr); span = lhs->span; @@ -296,10 +305,13 @@ postfixops(struct parser *pr, struct expr *lhs) } if (lhs->ty.t == TYPTR || lhs->ty.t == TYARRAY) { - if (isincomplete(ty = typechild(lhs->ty))) + if (isincomplete(ty = typechild(lhs->ty))) { error(&span, "cannot dereference pointer to incomplete type (%ty)", ty); - else if (ty.t == TYFUNC) + ty = mktype(TYINT); + } else if (ty.t == TYFUNC) { error(&span, "subscripted value is pointer to function"); + ty = mktype(TYINT); + } } else { error(&lhs->span, "subscripted value is not pointer-convertible (%ty)", ex.ty); ty = mktype(TYINT); @@ -311,19 +323,19 @@ postfixops(struct parser *pr, struct expr *lhs) ex.t = EADD; ex.span = span; ex.ty = typedecay(lhs->ty); - } + } ex.sub = exprdup(pr, iszero(ex) ? lhs : &ex); ex.span = span; ex.t = EDEREF; ex.ty = ty; *lhs = ex; break; - case '(': + case '(': /* call(args) */ span = lhs->span; lex(pr, &tk); - if (lhs->ty.t == TYPTR) /* auto-deref when calling a function pointer */ - *lhs = mkexpr(EDEREF, lhs->span, typechild(lhs->ty), .sub = exprdup(pr, lhs)); ty = lhs->ty; + if (ty.t == TYPTR) /* auto-deref when calling a function pointer */ + ty = typechild(ty); if (ty.t != TYFUNC) error(&lhs->span, "calling a value of type '%ty'", lhs->ty); { const struct typedata *td = &typedata[ty.dat]; @@ -342,6 +354,7 @@ postfixops(struct parser *pr, struct expr *lhs) ex.ty, td->param[args.n]); } vpush(&args, ex); + peek(pr, &tk); if (match(pr, &tk, ',')) { spanok = spanok && joinspan(&span.ex, tk.span.ex); } else if (expect(pr, ')', "or ',' after arg")) { @@ -349,6 +362,8 @@ postfixops(struct parser *pr, struct expr *lhs) } } if (!spanok || !joinspan(&span.ex, tk.span.ex)) span = spanbck; + if (!td->variadic && !td->kandr && args.n < td->nmemb) + error(&tk.span, "not enough args to function taking %d params", td->nmemb); ex = mkexpr(ECALL, span, ty.t == TYFUNC ? td->ret : ty, .narg = args.n, .sub = alloc(&pr->exarena, (args.n+1)*sizeof(struct expr), 0)); ex.sub[0] = *lhs; @@ -414,7 +429,7 @@ static struct expr unaryex(struct parser *pr) { enum exprkind ek; - struct token tk; + struct token tk, tk2; struct span span; struct expr ex; union type ty; @@ -444,6 +459,20 @@ unaryex(struct parser *pr) ty = mktype(TYINT); } return mkexpr(ek, span, ty, .sub = exprdup(pr, &ex)); + case TKINC: + ek = EPREINC; + goto IncDec; + case TKDEC: + ek = EPREDEC; + IncDec: + lex(pr, NULL); + span = tk.span; + ex = unaryex(pr); + joinspan(&span.ex, ex.span.ex); + ty = ex.ty; + incdeccheck(tk.t, &ex, &span); + return mkexpr(ek, span, ty, .sub = exprdup(pr, &ex)); + break; case '*': lex(pr, NULL); span = tk.span; @@ -451,11 +480,13 @@ unaryex(struct parser *pr) joinspan(&span.ex, ex.span.ex); if (ex.ty.t == TYPTR || ex.ty.t == TYARRAY) { ty = typechild(ex.ty); - if (isincomplete(ty)) + if (isincomplete(ty)) { error(&span, "cannot dereference pointer to incomplete type (%ty)", ty); + ty = mktype(TYINT); + } } else { error(&span, "invalid operand to unary * (%ty)", ex.ty); - ty = ex.ty; + ty = mktype(TYINT); } return mkexpr(EDEREF, span, ty, .qual = ex.ty.flag & TFCHLDQUAL, .sub = exprdup(pr, &ex)); case '&': @@ -482,13 +513,13 @@ unaryex(struct parser *pr) } else { ex = commaexpr(pr); expect(pr, ')', NULL); + postfixops(pr, &ex); return ex; } case TKWsizeof: lex(pr, NULL); span = tk.span; if (match(pr, NULL, '(')) { - struct token tk2; if (isdecltok(pr)) { /* sizeof(type) */ struct declstate st = { DCASTEXPR }; struct decl decl = pdecl(&st, pr); @@ -511,9 +542,33 @@ unaryex(struct parser *pr) else if (ty.t == TYFUNC) error(&span, "cannot apply sizeof to function type (%ty)", ty); return mkexpr(ENUMLIT, span, mktype(targ_sizetype), .u = siz); + case TKW_Alignof: + lex(pr, NULL); + expect(pr, '(', NULL); + span = tk.span; + if (isdecltok(pr)) { + struct declstate st = { DCASTEXPR }; + struct decl decl = pdecl(&st, pr); + ty = decl.t; + } else { + peek(pr, &tk2); + error(&tk2.span, "expected type name"); + ty = mktype(TYINT); + } + peek(pr, &tk2); + expect(pr, ')', NULL); + joinspan(&span.ex, tk2.span.ex); + siz = typealign(ty); + if (isincomplete(ty)) + error(&span, "cannot apply alignof to incomplete type (%ty)", ty); + else if (ty.t == TYFUNC) + error(&span, "cannot apply alignof to function type (%ty)", ty); + return mkexpr(ENUMLIT, span, mktype(targ_sizetype), .u = siz); + } } + static void bintypeerr(const struct span *span, enum toktag tt, union type lhs, union type rhs) { @@ -582,20 +637,37 @@ additiveex(struct parser *pr) if (!joinspan(&span.ex, tk.span.ex) || !joinspan(&span.ex, rhs.span.ex)) span.ex = tk.span.ex; if (tk.t == '+' && isptrcvt(rhs.ty)) { + /* int + ptr -> ptr + int */ struct expr swaptmp = ex; ex = rhs; rhs = swaptmp; ty = ex.ty; } - if (isarith(ty) && isarith(rhs.ty)) ty = cvtarith(ty, rhs.ty); - else if (!in_range(ty.t, TYPTR, TYARRAY) || !isint(rhs.ty)) - bintypeerr(&span, tk.t, ty, rhs.ty); - else { + if (isarith(ty) && isarith(rhs.ty)) { + /* num +/- num */ + ty = cvtarith(ty, rhs.ty); + } else if (in_range(ty.t, TYPTR, TYARRAY) && isint(rhs.ty)) { + /* ptr +/- int */ union type pointee = typechild(typedecay(ty)); if (isincomplete(pointee)) error(&span, "arithmetic on pointer to incomplete type (%ty)", ty); else if (pointee.t == TYFUNC) error(&span, "arithmetic on function pointer (%ty)", ex.ty); + } else if (tk.t == '-' && isptrcvt(ty) && isptrcvt(rhs.ty)) { + /* ptr - ptr */ + union type pointee1 = typechild(typedecay(ty)), + pointee2 = typechild(typedecay(rhs.ty)); + if (isincomplete(pointee1)) + error(&span, "arithmetic on pointer to incomplete type (%ty)", ty); + else if (pointee1.t == TYFUNC) + error(&span, "arithmetic on function pointer (%ty)", ex.ty); + else if (pointee1.bits != pointee2.bits) { + error(&span, "arithmetic on incompatible pointer types (%ty, %ty)", + ty, rhs.ty); + } + ty = mktype(targ_ptrdifftype); + } else { + bintypeerr(&span, tk.t, ty, rhs.ty); } ex = mkexpr(tk.t == '+' ? EADD : ESUB, span, ty, .sub = exprdup2(pr, &ex, &rhs)); } @@ -780,7 +852,7 @@ condex(struct parser *pr) error(&ex.span, "?: condition is not a scalar type (%ty)", ex.ty); span.sl = tk.span.sl; span.ex = ex.span.ex; - tr = condex(pr); + tr = expr(pr); joinspan(&tk.span.ex, tr.span.ex); expect(pr, ':', NULL); fl = condex(pr); @@ -983,8 +1055,8 @@ cvt(struct function *fn, enum typetag to, enum typetag from, union irref ref) ins.cls = kto; ins.l = ref; if (kisflt(kto) || kisflt(kfrom)) { - if (kto == KIP) kto = siz2intcls[cls2siz[kto]]; - if (kfrom == KIP) kfrom = siz2intcls[cls2siz[kfrom]]; + if (kto == KPTR) kto = siz2intcls[cls2siz[kto]]; + if (kfrom == KPTR) kfrom = siz2intcls[cls2siz[kfrom]]; if (kisflt(kto) && kfrom == KI4) ins.op = issignedt(from) ? Ocvts4f : Ocvtu4f; else if (kisflt(kto) && kfrom == KI8) ins.op = issignedt(from) ? Ocvts8f : Ocvtu8f; else if (kto == KF8 && kfrom == KF4) ins.op = Ocvtf4f8; @@ -1004,7 +1076,7 @@ static union irref narrow(struct function *fn, enum irclass to, enum typetag tt, union irref ref) { struct instr ins; - assert(isintt(tt)); + assert(isintt(tt) || tt == TYPTR); if (targ_primsizes[tt] >= cls2siz[to]) return ref; ins.cls = to; switch (targ_primsizes[tt]) { @@ -1017,6 +1089,47 @@ narrow(struct function *fn, enum irclass to, enum typetag tt, union irref ref) return addinstr(fn, ins); } +static inline uint +ilog2(uint x) { /* assumes x is a power of 2 */ +#ifdef __GNUC__ + return __builtin_ctz(x); +#else + uint n = 0; + while (x >>= 1) ++n; + return n; +#endif +} + +union irref +genptroff(struct function *fn, enum op op, uint siz, union irref ptr, + enum typetag tt, union irref idx) +{ + uint cls = type2cls[targ_sizetype]; + union irref off; + assert(siz); + idx = cvt(fn, targ_sizetype, tt, idx); + if (siz == 1) off = idx; + else if ((siz & siz-1) == 0) /* is power of 2 */ + off = addinstr(fn, (struct instr) { Oshl, cls, idx, mkintcon(fn, cls, ilog2(siz)) }); + else + off = addinstr(fn, (struct instr) { Omul, cls, idx, mkintcon(fn, cls, siz) }); + assert(in_range(op, Oadd, Osub)); + return addinstr(fn, (struct instr) { op, KPTR, ptr, off }); +} + +union irref +genptrdiff(struct function *fn, uint siz, union irref a, union irref b) +{ + uint cls = type2cls[targ_ptrdifftype]; + assert(siz > 0); + a = addinstr(fn, (struct instr) { Osub, cls, a, b }); + if (siz == 1) return a; + else if ((siz & siz-1) == 0) /* is power of 2 */ + return addinstr(fn, (struct instr) { Osar, cls, a, mkintcon(fn, cls, ilog2(siz)) }); + else + return addinstr(fn, (struct instr) { Odiv, cls, a, mkintcon(fn, cls, siz) }); +} + static union irref exprvalue(struct function *fn, const struct expr *ex) { @@ -1027,7 +1140,8 @@ exprvalue(struct function *fn, const struct expr *ex) int swp = 0; struct expr *sub = ex->sub; - if (ex->ty.t == TYARRAY) return expraddr(fn, ex); + if (ex->ty.t == TYARRAY || ex->ty.t == TYFUNC) + return expraddr(fn, ex); switch (ex->t) { case ENUMLIT: if (isflt(ex->ty)) @@ -1084,16 +1198,17 @@ exprvalue(struct function *fn, const struct expr *ex) ins.op = Oadd; BinArith: ins.l = exprvalue(fn, &sub[0]); - ins.l = cvt(fn, ex->ty.t, sub[0].ty.t, ins.l); ins.r = exprvalue(fn, &sub[1]); - if ((ins.op != Oadd && ins.op != Osub) || cls != KIP) + if (ins.op == Osub && isptrcvt(sub[0].ty) && isptrcvt(sub[1].ty)) { + /* ptr - ptr */ + return genptrdiff(fn, typesize(typechild(sub[0].ty)), ins.l, ins.r); + } else if ((ins.op != Oadd && ins.op != Osub) || cls != KPTR) { + /* num OP num */ + ins.l = cvt(fn, ex->ty.t, sub[0].ty.t, ins.l); ins.r = cvt(fn, ex->ty.t, sub[1].ty.t, ins.r); - else { - uint siz = typesize(typechild(ex->ty)); - enum typetag tt = intpromote(sub[1].ty.t); - struct instr scale = { Omul, type2cls[tt], ins.r }; - scale.r = mkintcon(fn, type2cls[tt], siz); - ins.r = addinstr(fn, scale); + } else { + /* ptr +/- num */ + return genptroff(fn, ins.op, typesize(typechild(sub[0].ty)), ins.l, sub[1].ty.t, ins.r); } ins.cls = cls; return addinstr(fn, ins); @@ -1109,6 +1224,19 @@ exprvalue(struct function *fn, const struct expr *ex) ins.r = mkref(RICON, 1); genstore(fn, sub->ty, r, addinstr(fn, ins)); return ins.l; + case EPREINC: + case EPREDEC: + ins.op = ex->t == EPREINC ? Oadd : Osub; + ins.cls = cls; + r = expraddr(fn, sub); + ins.l = genload(fn, sub->ty, r); + if (ex->ty.t == TYPTR) + ins.r = mkintcon(fn, KI4, typesize(typechild(ex->ty))); + else + ins.r = mkref(RICON, 1); + q = addinstr(fn, ins); + genstore(fn, sub->ty, r, q); + return narrow(fn, cls, ex->ty.t, q); case EEQU: ins.op = Oequ; goto Cmp; @@ -1176,18 +1304,15 @@ exprvalue(struct function *fn, const struct expr *ex) ty = in_range(ex->t, ESETSHL, ESETSHR) ? mktype(intpromote(ex->ty.t)) : cvtarith(sub[0].ty, sub[1].ty); ins.cls = cls; - ins.l = cvt(fn, ty.t, sub[0].ty.t, genload(fn, ex->ty, r)); + ins.l = genload(fn, ex->ty, r); ins.r = exprvalue(fn, &sub[1]); - if ((ins.op != Oadd && ins.op != Osub) || cls != KIP) + if ((ins.op != Oadd && ins.op != Osub) || cls != KPTR) { + ins.l = cvt(fn, ty.t, sub[0].ty.t, ins.l); ins.r = cvt(fn, ex->ty.t, sub[1].ty.t, ins.r); - else { - uint siz = typesize(typechild(ex->ty)); - enum typetag tt = intpromote(sub[1].ty.t); - struct instr scale = { Omul, type2cls[tt], ins.r }; - scale.r = mkintcon(fn, type2cls[tt], siz); - ins.r = addinstr(fn, scale); + q = addinstr(fn, ins); + } else { + q = genptroff(fn, ins.op, typesize(typechild(ex->ty)), ins.l, sub[1].ty.t, ins.r); } - q = addinstr(fn, ins); genstore(fn, ex->ty, r, q); return narrow(fn, cls, ex->ty.t, q); case ECALL: @@ -1199,9 +1324,8 @@ exprvalue(struct function *fn, const struct expr *ex) vec_of(union irtype) typs = VINIT(typbuf, arraylength(typbuf)); ins.op = Ocall; assert(isscalar(ex->ty) || ex->ty.t == TYVOID); - assert(sub[0].ty.t == TYFUNC); ins.cls = type2cls[ex->ty.t]; - ins.l = expraddr(fn, &sub[0]); + ins.l = exprvalue(fn, &sub[0]); for (int i = 0; i < ex->narg; ++i) { struct expr *arg = &sub[i+1]; union type ty = i < td->nmemb ? td->param[i] : argpromote(arg->ty); @@ -1376,15 +1500,19 @@ block(struct parser *pr, struct function *fn) nalloc = siz/align + ((siz&(align-1)) != 0); EMITS { decl.id = addinstr(fn, - (struct instr) { op, KIP, mkintcon(fn, KI4, nalloc) }).idx; + (struct instr) { op, KPTR, mkintcon(fn, KI4, nalloc) }).idx; } if (st.varini) { putdecl(pr, &decl); put = 1; ini = expr(pr); pdecl(&st, pr); - if (!assigncheck(decl.t, &ini)) - error(&ini.span, "cannot initialize %ty with %ty", decl.t, ini.ty); + if (!assigncheck(decl.t, &ini)) { + struct span span = decl.span; + joinspan(&span.ex, ini.span.ex); + error(&span, "cannot initialize '%ty' variable with '%ty'", + decl.t, ini.ty); + } EMITS genstore(fn, decl.t, mkref(RTMP, decl.id), exprvalue(fn, &ini)); } break; @@ -1402,7 +1530,7 @@ block(struct parser *pr, struct function *fn) } static void -function(struct parser *pr, struct function *fn, const char **pnames) +function(struct parser *pr, struct function *fn, const char **pnames, const struct span *pspans) { const struct typedata *td = &typedata[fn->fnty.dat]; const bool doemit = fn->curblk; @@ -1411,7 +1539,7 @@ function(struct parser *pr, struct function *fn, const char **pnames) if (pnames[i]) { uint siz, align, nalloc; struct decl arg = { .t = td->param[i], .qual = tdgetqual(td->quals, i), - .name = pnames[i], .scls = SCAUTO }; + .name = pnames[i], .scls = SCAUTO, .span = pspans[i] }; enum op op; switch (align = typealign(arg.t)) { case 1: op = Oalloca1; break; @@ -1424,14 +1552,14 @@ function(struct parser *pr, struct function *fn, const char **pnames) siz = typesize(arg.t); nalloc = siz/align + ((siz&(align-1)) != 0); EMITS { - struct instr alloca = { op, KIP, mkintcon(fn, KI4, nalloc) }; + struct instr alloca = { op, KPTR, mkintcon(fn, KI4, nalloc) }; arg.id = addinstr(fn, alloca).idx; genstore(fn, arg.t, mkref(RTMP, arg.id), mkref(RARG, i)); } putdecl(pr, &arg); - } /*else { - warn(NULL, "missing name of parameter #%d", i+1); - }*/ + } else { + warn(&pspans[i], "missing name of parameter #%d", i+1); + } } block(pr, fn); envup(pr); @@ -1519,7 +1647,7 @@ buildenum(struct parser *pr, const char *name) union type t; struct typedata td = {TYENUM}; enum typetag backing = TYINT; - + t = mktagtype(name, &td); t.backing = backing; return t; @@ -1537,7 +1665,7 @@ tagtype(struct parser *pr, enum toktag kind) if (match(pr, &tk, TKIDENT)) tag = tk.ident; span = tk.span; - if (!match(pr, NULL, '{')) { + if (!match(pr, NULL, '{')) { if (!tag) { error(&tk.span, "expected %tt name or '{'", kind); return mktype(0); @@ -1729,6 +1857,7 @@ static struct decllist { struct { /* TYFUNC */ union type *param; const char **pnames; + struct span *pspans; uchar *pqual; short npar; bool kandr : 1, variadic : 1; @@ -1738,6 +1867,7 @@ static struct decllist { } decltmp[64], *declfreelist; static union type declparamtmp[16]; static const char *declpnamestmp[16]; +static struct span declpspanstmp[16]; static uchar declpqualtmp[tdqualsiz(16)]; static void @@ -1863,12 +1993,14 @@ decltypes(struct parser *pr, struct decllist *list, const char **name, struct sp vec_of(union type) params = {0}; vec_of(uchar) qual = {0}; vec_of(const char *) names = {0}; + vec_of(struct span) spans = {0}; bool anyqual = 0; if (depth++ == 0) { vinit(¶ms, declparamtmp, arraylength(declparamtmp)); vinit(&qual, declpqualtmp, arraylength(declpqualtmp)); vinit(&names, declpnamestmp, arraylength(declpnamestmp)); + vinit(&spans, declpspanstmp, arraylength(declpspanstmp)); } node.span = tk.span; node.kandr = 0; @@ -1886,6 +2018,7 @@ decltypes(struct parser *pr, struct decllist *list, const char **name, struct sp decl.t = typedecay(decl.t); vpush(¶ms, decl.t); vpush(&names, decl.name); + vpush(&spans, decl.span); if (decl.qual) { anyqual = 1; while (qual.n < tdqualsiz(params.n)) vpush(&qual, 0); @@ -1909,6 +2042,7 @@ decltypes(struct parser *pr, struct decllist *list, const char **name, struct sp if (params.n == 1 && params.p[0].t == TYVOID && !qual.n && !names.p[0]) { /* (void) */ vfree(¶ms); vfree(&names); + vfree(&spans); } else if (params.n && params.p[0].t == TYVOID && !qual.n && !names.p[0]) { error(&node.span, "function parameter #1 has incomplete type (%tq)", params.p[0], tdgetqual(qual.p, 0)); @@ -1917,6 +2051,7 @@ decltypes(struct parser *pr, struct decllist *list, const char **name, struct sp node.param = params.n ? params.p : NULL; node.pqual = anyqual ? qual.p : NULL; node.pnames = params.n ? names.p : NULL; + node.pspans = params.n ? spans.p : NULL; node.npar = params.n; declinsert(ptr->prev, &node); } else break; @@ -1935,7 +2070,7 @@ declarator(struct declstate *st, struct parser *pr) { declfreelist = &decltmp[i]; } } - + decltypes(pr, &list, st->kind == DCASTEXPR ? NULL : &decl.name, &decl.span); if (!decl.name && st->kind != DCASTEXPR && st->kind != DFUNCPARAM) { if (list.prev == &list) lex(pr, NULL); @@ -1967,9 +2102,12 @@ declarator(struct declstate *st, struct parser *pr) { if (l->pqual != declpqualtmp) free(l->pqual); if (l->prev == &list && l->npar) { /* last */ st->pnames = alloc(&pr->fnarena, l->npar * sizeof(char *), 0); + st->pspans = alloc(&pr->fnarena, l->npar * sizeof(struct span), 0); memcpy(st->pnames, l->pnames, l->npar * sizeof(char *)); + memcpy(st->pspans, l->pspans, l->npar * sizeof(struct span)); } if (l->pnames != declpnamestmp) free(l->pnames); + if (l->pspans != declpspanstmp) free(l->pspans); decl.qual = 0; break; } @@ -2060,6 +2198,9 @@ parse(struct parser *pr) pr->exarena = (void *)amem[2].m; pr->exarena->cap = N; } + + putdecl(pr, &(struct decl) { mktype(TYVALIST), SCTYPEDEF, .name = intern("__builtin_va_list") }); + while (peek(pr, tk) != TKEOF) { struct expr ini; struct declstate st = { DTOPLEVEL, }; @@ -2082,7 +2223,7 @@ parse(struct parser *pr) fn.retty = td->ret; putdecl(pr, &decl); irinit(&fn); - function(pr, &fn, st.pnames); + function(pr, &fn, st.pnames, st.pspans); if (!nerror) irdump(&fn, decl.name); } else if (decl.name) { putdecl(pr, &decl); @@ -18,38 +18,33 @@ enum toktag { /* single-character tokens' tag value is the character itself */ TKXXX, TKNUMLIT, TKSTRLIT, - TKIDENT, - TKDUMMY_ = 0x7F, + TKEQU = '@', + TKNEQ, + TKLTE, + TKGTE, + TKSHR, + TKSHL, + TKINC, + TKDEC, + TKDOTS, + TKARROW, + TKPPCAT, + TKLOGAND, + TKLOGIOR, + TKSETADD, + TKSETSUB, + TKSETMUL, + TKSETDIV, + TKSETMOD, + TKSETIOR, + TKSETXOR, + TKSETAND, + TKSETSHR, + TKSETSHL, + TKIDENT = 0x80, #define _(kw, stdc) TKW##kw, #include "keywords.def" #undef _ -#define C2(a,b) (a | b<<8) -#define C3(a,b,c) (a | b<<8 | c<<16) - TKEQU = C2('=','='), - TKNEQ = C2('!','='), - TKLTE = C2('<','='), - TKGTE = C2('>','='), - TKSHR = C2('>','>'), - TKSHL = C2('<','<'), - TKINC = C2('+','+'), - TKDEC = C2('-','-'), - TKARROW = C2('-','>'), - TKPPCAT = C2('#', '#'), - TKLOGAND = C2('&','&'), - TKLOGIOR = C2('|','|'), - TKSETADD = C2('+','='), - TKSETSUB = C2('-','='), - TKSETMUL = C2('*','='), - TKSETDIV = C2('/','='), - TKSETMOD = C2('%','='), - TKSETIOR = C2('|','='), - TKSETXOR = C2('^','='), - TKSETAND = C2('&','='), - TKSETSHR = C3('>','>','='), - TKSETSHL = C3('<','<','='), - TKDOTS = C3('.','.','.'), -#undef C2 -#undef C3 }; struct token { @@ -103,6 +98,7 @@ struct parser { struct span fnblkspan; }; +const char *intern(const char *); int lex(struct parser *, struct token *); int lexpeek(struct parser *, struct token *); void initparser(struct parser *, const char *file); @@ -2,23 +2,24 @@ uchar targ_primsizes[TYPTR+1]; uchar targ_primalign[TYPTR+1]; -enum typetag targ_sizetype; +enum typetag targ_sizetype, targ_ptrdifftype; bool targ_charsigned, targ_bigendian; -struct targ { +static const struct targ { const char *name; struct { uchar longsize, vlongsize, ptrsize, valistsize; }; struct { uchar longalign, vlongalign, doublealign, ptralign; }; bool charsigned; - uchar sizetype; + uchar sizetype, ptrdifftype; } targs[] = { - { "amd64-sysv", {8, 8, 8, 24}, {8, 8, 8, 8}, 1, TYULONG } + { "amd64-sysv", {8, 8, 8, 24}, {8, 8, 8, 8}, 1, TYULONG, TYLONG }, + { "i686-sysv", {4, 8, 4, 8}, {4, 4, 4, 4}, 1, TYUINT, TYINT } }; void targ_init(const char *starg) { - struct targ *t = &targs[0]; + const struct targ *t = &targs[0]; uchar *sizes = targ_primsizes, *align = targ_primalign; sizes[TYBOOL] = sizes[TYCHAR] = sizes[TYSCHAR] = sizes[TYUCHAR] = 1; @@ -36,6 +37,7 @@ targ_init(const char *starg) align[TYDOUBLE] = t->doublealign; align[TYVALIST] = align[TYPTR] = t->ptralign; targ_sizetype = t->sizetype; + targ_ptrdifftype = t->ptrdifftype; targ_charsigned = t->charsigned; targ_bigendian = 0; } @@ -1,13 +1,20 @@ /* coment */ -int glob; +#if 1+1 < (-2*2) +wawa +#elif 9<<1 +#define wow 3 +#else +boop +#endif +int glob [ wow+wow]; int add (int x, int y) { - return x + y + glob; + return x + y + *glob; } int abs(int x){ - return (x ^ x >> 31) + ((unsigned)x >> 31); + return (x ^ x >> 31) - (x >> 31); } int popcnt(unsigned x) { @@ -16,24 +23,23 @@ int popcnt(unsigned x) { return n; } -int foo(int x) { - int work[10]; - work[x]=x; - if (x == 0) - return 1; - else if (x == 1) - return -1; - else if (x < 0) - return x; - else - return 0; +struct f { + char x[(1<<12)-1]; +}; + +int diff(struct f *x, struct f *y) +{ + x += 3; + --x; + return x - y; } -extern void printf(char *, ...); + +extern int printf(char *, ...); int main() { - char x; + unsigned char x = 255; int k = x += 1; - return abs(-33); + return abs(k); } // @@ -139,7 +139,9 @@ typesize(union type t) case TYENUM: return targ_primsizes[t.backing]; case TYARRAY: - return t.flag & TFCHLDPRIM ? targ_primsizes[t.child] * t.arrlen : typedata[t.dat].siz; + if (t.flag & TFCHLDPRIM) + return targ_primsizes[t.child] * t.arrlen; + /* fallthru */ case TYSTRUCT: case TYUNION: return typedata[t.dat].siz; @@ -180,7 +182,7 @@ mkarrtype(union type t, int qual, uint n) if (isprim(t) && n < 256) return mktype(TYARRAY, .flag = TFCHLDPRIM | (qual & TFCHLDQUAL), .child = t.t, .arrlen = n); return mktype(TYARRAY, .flag = qual & TFCHLDQUAL, - .dat = interntd(&(struct typedata) { TYARRAY, .child = t, .arrlen = n })); + .dat = interntd(&(struct typedata) { TYARRAY, .child = t, .arrlen = n, .siz = n * typesize(t) })); } union type |