aboutsummaryrefslogtreecommitdiff
path: root/bootstrap/parse.c
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-04 07:39:23 +0200
committerlemon <lsof@mailbox.org>2022-08-04 07:39:23 +0200
commitbb1d4b4a3e51a06fb0530dfc271a97a6cd88cc73 (patch)
treef300325814bc30e64f858ee313b8260a14d8df90 /bootstrap/parse.c
parent1625c50f0c0e4b1c7ba01a5df5713efaf6dce606 (diff)
stuff
Diffstat (limited to 'bootstrap/parse.c')
-rw-r--r--bootstrap/parse.c207
1 files changed, 150 insertions, 57 deletions
diff --git a/bootstrap/parse.c b/bootstrap/parse.c
index 96a185c..3d609c4 100644
--- a/bootstrap/parse.c
+++ b/bootstrap/parse.c
@@ -227,6 +227,7 @@ readstrlit(struct parser *P, u8 delim, char *s, size_t n) {
#define MAX_MACROEXPAND_ITER 100
+/*
// guard used at macro arg expansion to avoid it expanding into itself, e.g.:
// defmacro foo(x,y) [(x+y)]
// let x, y ...;
@@ -240,6 +241,7 @@ ismacrodupe(struct parser *P, struct toktree toks) {
}
return 0;
}
+*/
static struct tok
lex(struct parser *P) {
@@ -269,18 +271,15 @@ lex(struct parser *P) {
}
tok = ep->toks.d[ep->idx++];
// expand macro arg?
- if (tok.t == TKident) {
+ if (tok.t == TKmacident) {
for (struct expan *ep = P->curexpan; ep; ep = ep->prev) {
for (int i = 0; i < ep->args.n; ++i) {
if (!strcmp(tok.str, ep->args.d[i].name)) {
- if (!ismacrodupe(P, ep->args.d[i].toks)) {
- ++P->expanno;
- P->curexpan = memcpy(xmalloc(sizeof *ep), &(struct expan) {
- P->curexpan, {0}, ep->args.d[i].toks,
- }, sizeof *ep);
- return lex(P);
- } else
- return tok;
+ ++P->expanno;
+ P->curexpan = memcpy(xmalloc(sizeof *ep), &(struct expan) {
+ P->curexpan, {0}, ep->args.d[i].toks,
+ }, sizeof *ep);
+ return lex(P);
}
}
}
@@ -314,6 +313,8 @@ lex(struct parser *P) {
tok.boolit = s[1] == 't';
} else if (!strcmp(s, "#null")) {
tok.t = TKnullit;
+ } else if (!strcmp(s, "##")) {
+ tok.t = '##';
} else if (c == '#') {
fatal(P, P->tokspan, "identifier cannot start with '#'");
} else if (c == '$') {
@@ -333,7 +334,7 @@ lex(struct parser *P) {
n = readstrlit(P, delim, s, sizeof s);
if (delim == '"') {
tok.t = TKstrlit;
- tok.str = strcpy(xmalloc(n + 1), s);
+ tok.str = memcpy(xmalloc(n + 1), s, n + 1);
tok.strlen = n;
} else {
if (n == 0)
@@ -651,6 +652,12 @@ typeof2(const struct type *a, const struct type *b) {
}
if (a == b)
return a;
+ if (unconstify(a) == b)
+ return a;
+ if (a == unconstify(b))
+ return b;
+ if (a->t == TYarr && b->t == TYarr)
+ a = arraydecay(a);
if (a->t == TYptr && b->t == TYarr)
b = arraydecay(b);
if (a->t == TYarr && b->t == TYptr)
@@ -707,6 +714,13 @@ exprdup(struct expr ex) {
static struct blockstmt parseblock0(struct parser *P);
static struct stmt parseblock(struct parser *P);
static void parseexpandmacro(struct parser *P, const struct macro *macro);
+static const struct type *
+mkarraytype(const struct type *child, size_t n) {
+ return interntype((struct type) {
+ TYarr, n * child->size, 1, 0,
+ .child = child, .length = n
+ });
+}
static struct expr
pexprimary(struct parser *P) {
@@ -728,10 +742,13 @@ pexprimary(struct parser *P) {
ex.span = tok.span;
ex.strlit.d = tok.str;
ex.strlit.n = tok.strlen;
- ex.ty = interntype((struct type) {
- TYarr, tok.strlen + 1, 1, 0,
- .child = constify(ty_u8), .length = tok.strlen + 1
- });
+ while (lexmatch(P, &tok, TKstrlit)) {
+ ex.strlit.d = xrealloc((char *)ex.strlit.d, ex.strlit.n + tok.strlen + 1);
+ memcpy((char *)ex.strlit.d + ex.strlit.n, tok.str, tok.strlen + 1);
+ free((char *)tok.str);
+ ex.strlit.n += tok.strlen;
+ }
+ ex.ty = mkarraytype(constify(ty_u8), ex.strlit.n + 1);
} else if (lexmatch(P, &tok, TKboolit)) {
ex.t = Eboolit;
ex.span = tok.span;
@@ -759,18 +776,35 @@ pexprimary(struct parser *P) {
ex.t = Ename;
ex.span = tok.span;
ex.ref = decl;
- if (decl->t == Dvar) {
+ if (decl->t == Dlet) {
if (decl->var.fnid != P->curfn->id)
fatal(P, tok.span,
"cannot access local variable `%s' belonging to outer function",
tok.str);
ex.ty = decl->var.ty;
+ } else if (decl->t == Dstatic) {
+ ex.ty = decl->var.ty;
} else if (decl->t == Dfn) {
ex.ty = decl->fn.selfty;
} else assert(0);
}
} else if (lexmatch(P, &tok, '(')) {
- ex = parseexpr(P);
+ if (lexpeek(P).t == TKkw_do) {
+ struct blockstmt block;
+ lex(P);
+ block = parseblock0(P);
+ ex.t = Eblock;
+ ex.block = block;
+ ex.ty = ty_void;
+ if (ex.block.stmts.n > 0) {
+ struct stmt *last = &block.stmts.d[block.stmts.n - 1];
+ if (last->t == Sexpr)
+ ex.ty = last->expr.ty;
+
+ }
+ } else {
+ ex = parseexpr(P);
+ }
lexexpect(P, ')');
} else {
fatal(P, tok.span, "expected expression (near %s)", tok2str(tok));
@@ -894,7 +928,7 @@ pexprefix(struct parser *P) {
struct expr ex = pexprefix(P);
if (ex.ty->t != TYptr)
fatal(P, ex.span, "invalid operand type to dereference, not pointer");
- if (!completetype(ex.ty->child))
+ if (!completetype(ex.ty->child) && ex.ty->child->t != TYfn)
fatal(P, ex.span, "invalid operand type to dereference, incomplete");
return (struct expr) {
Eprefix, tok.span, ex.ty->child, .unop = {
@@ -904,7 +938,7 @@ pexprefix(struct parser *P) {
} else if (lexmatch(P, &tok, '&')) {
struct expr ex = pexprefix(P);
struct type ty2 = { TYptr, g_targ.ptrsize, .child = ex.ty};
- if (!islvalue(&ex))
+ if (!islvalue(&ex) && !(ex.t == Ename && ex.ref->t == Dfn))
fatal(P, ex.span, "invalid operand type to address-of, not an lvalue");
return (struct expr) {
Eprefix, tok.span, interntype(ty2), .unop = {
@@ -927,6 +961,8 @@ peeksbitarithop(struct parser *P, struct tok* tokp) {
return 1;
case '&': case '|': case '^': case '<<': case '>>':
return 2;
+ case '##':
+ return 3;
}
return 0;
}
@@ -957,7 +993,7 @@ pexbitarith(struct parser *P) {
}
} else if (tokt == '-' && ex.ty->t == TYptr && rhs.ty->t == TYptr) {
ty = ty_isize;
- } else if (!isnumtype(ty)) {
+ } else if (tokt != '##' && !isnumtype(ty)) {
err:
fatal(P, tok.span, "invalid operands to binary operator %s",
tokt2str(tokt));
@@ -965,11 +1001,28 @@ pexbitarith(struct parser *P) {
if (oret == 2 && ty->t == TYfloat)
fatal(P, tok.span, "invalid operands to bitwise operator: not integral",
tokt2str(tokt));
- ex = (struct expr) {
- Ebinop, tok.span, ty, .binop = {
- tokt, exprdup(ex), exprdup(rhs)
- }
- };
+ if (tokt != '##') {
+ ex = (struct expr) {
+ Ebinop, tok.span, ty, .binop = {
+ tokt, exprdup(ex), exprdup(rhs)
+ }
+ };
+ } else {
+ char *s;
+ size_t n = ex.strlit.n + rhs.strlit.n;
+
+ /// TODO fold
+ if (ex.t != Estrlit || rhs.t != Estrlit)
+ fatal(P, tok.span,
+ "operands to `##' operator are not string literals");
+ s = xmalloc(n + 1);
+ memcpy(s, ex.strlit.d, ex.strlit.n);
+ memcpy(s + ex.strlit.n, rhs.strlit.d, rhs.strlit.n + 1);
+ ex = (struct expr) {
+ Estrlit, tok.span, mkarraytype(constify(ty_u8), n + 1),
+ .strlit.d = s, .strlit.n = n,
+ };
+ }
}
@@ -1128,9 +1181,8 @@ stmtdup(struct stmt st) {
return memcpy(xmalloc(sizeof st), &st, sizeof st);
}
-static struct stmt
-pstlet(struct parser *P) {
- struct stmt st = {0};
+static void
+parsevardecl(struct parser *P, struct decl *decl) {
struct tok tok;
const char *name;
const struct type *ty = NULL;
@@ -1148,10 +1200,13 @@ pstlet(struct parser *P) {
ty = ini->ty;
} else {
ty = parsetype(P);
- lexexpect(P, '=');
- ini = exprdup(parseexpr(P));
+ if (lexmatch(P, NULL, '=')) {
+ ini = exprdup(parseexpr(P));
+ } else if (decl->t == Dlet) {
+ fatal(P, tok.span, "variable must be initialized");
+ }
}
- if (!typeof2(ty, ini->ty))
+ if (ini && !typeof2(ty, ini->ty))
fatal(P, tok.span, "incompatible initializer type");
if (!completetype(ty))
@@ -1161,15 +1216,18 @@ pstlet(struct parser *P) {
ty = constify(ty);
assert(ty);
- st.t = Sdecl;
- st.decl = (struct decl) {
- Dvar, name, .var = {
- .ty = ty,
- .ini = ini,
- .fnid = P->curfn->id,
- }
- };
- putdecl(P, tok.span, &st.decl);
+ decl->name = name;
+ decl->var.ty = ty;
+ decl->var.ini = ini;
+ decl->var.fnid = P->curfn ? P->curfn->id : -1;
+}
+
+static struct stmt
+pstlet(struct parser *P) {
+ struct stmt st = {Sdecl};
+ st.decl.t = Dlet;
+ parsevardecl(P, &st.decl);
+ putdecl(P, st.decl.span, &st.decl);
return st;
}
@@ -1296,7 +1354,8 @@ static void parsedecl(struct decl *, struct parser *, bool toplevel);
static bool
isdecltokt(int tokt) {
switch (tokt)
- case TKkw_extern: case TKkw_fn: case TKkw_typedef: case TKkw_defmacro:
+ case TKkw_extern: case TKkw_fn: case TKkw_typedef:
+ case TKkw_defmacro: case TKkw_static:
return 1;
return 0;
}
@@ -1404,39 +1463,49 @@ parsestmt(struct parser *P) {
struct stmt st = {0};
struct tok tok;
- if (lexmatch(P, NULL, '{')) {
- return parseblock(P);
- } else if (lexmatch(P, NULL, TKkw_let)) {
+ if (lexmatch(P, &tok, '{')) {
+ st.span = tok.span;
+ st = parseblock(P);
+ } else if (lexmatch(P, &tok, TKkw_let)) {
st = pstlet(P);
+ st.span = tok.span;
lexexpect(P, ';');
- } else if (lexmatch(P, NULL, TKkw_if)) {
+ } else if (lexmatch(P, &tok, TKkw_if)) {
+ st.span = tok.span;
st = pstifelse(P);
- } else if (lexmatch(P, NULL, TKkw_while)) {
+ } else if (lexmatch(P, &tok, TKkw_while)) {
st.t = Swhile;
+ st.span = tok.span;
st.loop.test = parseexpr(P);
if (st.loop.test.ty->t != TYbool && st.loop.test.ty->t != TYptr)
fatal(P, st.loop.test.span,
"while statement condition must be bool or pointer");
lexexpect(P, '{');
st.loop.body = parseblock(P).block;
- } else if (lexmatch(P, NULL, TKkw_for)) {
+ } else if (lexmatch(P, &tok, TKkw_for)) {
+ st.span = tok.span;
st = pstfor(P);
- } else if (lexmatch(P, NULL, TKkw_switch)) {
+ } else if (lexmatch(P, &tok, TKkw_switch)) {
st = pstswitch(P);
+ st.span = tok.span;
} else if (lexmatch(P, &tok, TKkw_return)) {
+ if (!P->curfn)
+ fatal(P, tok.span, "return disallowed here");
st.t = Sreturn;
- if (!lexmatch(P, NULL, ';')) {
+ st.span = tok.span;
+ if (!lexmatch(P, &tok, ';')) {
st.retex = exprdup(parseexpr(P));
lexexpect(P, ';');
- if (P->curfn->retty == ty_void)
+ if (!typeof2(st.retex->ty, P->curfn->retty))
fatal(P, st.retex->span,
- "return statement in void function must not return a value");
+ "incompatible type in return statement");
} else if (P->curfn->retty != ty_void) {
fatal(P, tok.span,
"return statement in non-void function must return a value");
}
} else if (isdecltokt((tok = lexpeek(P)).t)) {
st.t = Sdecl;
+ st.span = tok.span;
parsedecl(&st.decl, P, 0);
if (st.decl.t == Dfn && !st.decl.externp && !st.decl.fn.body)
fatal(P, tok.span,
@@ -1447,6 +1516,7 @@ parsestmt(struct parser *P) {
"cannot define external function inside another function");
} else {
struct expr ex;
+ st.span = tok.span;
if ((tok = lexpeek(P)).t == TKident) {
const struct decl *decl;
@@ -1550,7 +1620,7 @@ parsefn(struct decl *decl, struct parser *P) {
});
for (int i = 0; i < params.length; ++i) {
struct decl decl = {
- Dvar, params.data[i].name, .var = {
+ Dlet, params.data[i].name, .var = {
.ty = params.data[i].ty,
.fnid = fn->id,
}
@@ -1613,7 +1683,11 @@ parsemacrocase(struct parser *P) {
case TKeof:
fatal(P, espan, "unterminated macro definition");
}
- if (tok.t == TKgensym) {
+ if (tok.t == TKident) {
+ for (int i = 0; i < params.length; ++i)
+ if (!strcmp(params.data[i], tok.str))
+ tok.t = TKmacident;
+ } else if (tok.t == TKgensym) {
struct gensyms *gs;
for (gs = gensyms; gs; gs = gs->next) {
if (!strcmp(gs->name, tok.str)) {
@@ -1625,8 +1699,7 @@ parsemacrocase(struct parser *P) {
gs->name = tok.str;
gs->tok.t = TKident;
gs->tok.span = tok.span;
- gs->tok.str = xmalloc(strlen(tok.str) + 24);
- sprintf((char *)gs->tok.str, "__fG%s_%d", tok.str, gensymid++);
+ gs->tok.str = xasprintf("__fG%s_%d", tok.str, gensymid++);
tok = gs->tok;
gs->next = gensyms;
gensyms = gs;
@@ -1636,6 +1709,12 @@ parsemacrocase(struct parser *P) {
}
(void)vec_pop(&body);
+ for (struct gensyms *gs = gensyms, *next; gs; gs = next) {
+ next = gs->next;
+ free((char *)gs->name);
+ free(gs);
+ }
+
vec_slice_cpy(&c.params, &params);
vec_slice_cpy(&c.body, &body);
return c;
@@ -1673,9 +1752,8 @@ parsedecl(struct decl *decl, struct parser *P, bool toplevel) {
bool externp = 0;
memset(decl, 0, sizeof *decl);
- if (lexmatch(P, &tok, TKkw_extern)) {
+ if (lexmatch(P, &tok, TKkw_extern))
externp = 1;
- }
if (lexmatch(P, &tok, TKkw_fn)) {
const char *name = lexexpects(P, TKident, "function name").str;
@@ -1685,19 +1763,34 @@ parsedecl(struct decl *decl, struct parser *P, bool toplevel) {
decl->_cname = xcalloc(1, sizeof (char *));
parsefn(decl, P);
decl->externp = externp;
+ } else if (lexmatch(P, &tok, TKkw_static)) {
+ decl->t = Dstatic;
+ decl->externp = externp;
+ decl->_cname = xcalloc(1, sizeof (char *));
+ parsevardecl(P, decl);
+ if (!toplevel && !externp && !decl->var.ini)
+ fatal(P, decl->span,
+ "static variable inside function cannot be forward-declared");
+ if (!toplevel && externp && decl->var.ini)
+ fatal(P, decl->span,
+ "extern static variable inside function cannot be initialized");
+ lexexpect(P, ';');
} else if (lexmatch(P, &tok, TKkw_typedef)) {
+ if (externp)
+ fatal(P, tok.span, "typedef cannot be `extern'");
decl->t = Dtype;
decl->name = lexexpects(P, TKident, "typedef name").str;
decl->ty = parsetype(P);
decl->_cname = xcalloc(1, sizeof(char *));
lexexpect(P, ';');
} else if (lexmatch(P, &tok, TKkw_defmacro)) {
+ if (externp)
+ fatal(P, tok.span, "macro cannot be `extern'");
const char *name = lexexpects(P, TKident, "macro name").str;
decl->t = Dmacro;
decl->name = name;
decl->macro = parsemacro(P);
decl->macro.name = name;
-
} else {
fatal(P, tok.span, "expected declaration (near %s)",
tok2str(tok));