aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--common.h10
-rw-r--r--io.c33
-rw-r--r--ir.c10
-rw-r--r--ir.h2
-rw-r--r--irdump.c4
-rw-r--r--lex.c513
-rw-r--r--main.c38
-rw-r--r--mem.c93
-rw-r--r--parse.c257
-rw-r--r--parse.h54
-rw-r--r--targ.c12
-rw-r--r--test.c40
-rw-r--r--type.c6
13 files changed, 876 insertions, 196 deletions
diff --git a/common.h b/common.h
index ab3c8ff..2bd42bc 100644
--- a/common.h
+++ b/common.h
@@ -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);
diff --git a/io.c b/io.c
index 83b15b8..548e5ae 100644
--- a/io.c
+++ b/io.c
@@ -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;
diff --git a/ir.c b/ir.c
index 2cb1783..9812f21 100644
--- a/ir.c
+++ b/ir.c
@@ -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);
diff --git a/ir.h b/ir.h
index 02c9a2d..6b5446e 100644
--- a/ir.h
+++ b/ir.h
@@ -2,7 +2,7 @@
enum irclass {
KXXX,
- KI4, KI8, KIP,
+ KI4, KI8, KPTR,
KF4, KF8,
};
diff --git a/irdump.c b/irdump.c
index b7fbcc0..7855244 100644
--- a/irdump.c
+++ b/irdump.c
@@ -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);
diff --git a/lex.c b/lex.c
index 635c838..5cf12eb 100644
--- a/lex.c
+++ b/lex.c
@@ -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;
}
}
diff --git a/main.c b/main.c
index 6dcd6ea..edea3de 100644
--- a/main.c
+++ b/main.c
@@ -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);
}
diff --git a/mem.c b/mem.c
index 11c1c8c..c16fe54 100644
--- a/mem.c
+++ b/mem.c
@@ -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: */
diff --git a/parse.c b/parse.c
index 44979d0..d973b20 100644
--- a/parse.c
+++ b/parse.c
@@ -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(&params, 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(&params, 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(&params);
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);
diff --git a/parse.h b/parse.h
index 732d764..843550a 100644
--- a/parse.h
+++ b/parse.h
@@ -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);
diff --git a/targ.c b/targ.c
index 7368fa5..e323148 100644
--- a/targ.c
+++ b/targ.c
@@ -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;
}
diff --git a/test.c b/test.c
index 9eac7de..ee2b4d2 100644
--- a/test.c
+++ b/test.c
@@ -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);
}
//
diff --git a/type.c b/type.c
index c973906..3aeb8a1 100644
--- a/type.c
+++ b/type.c
@@ -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