aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-12 11:20:43 +0200
committerlemon <lsof@mailbox.org>2022-08-12 11:20:43 +0200
commiteff929f0d323559f3b2e9272e3c1d4aa82fc5c80 (patch)
treec3dd54fe4ed4a3082f455c8fe37436f767760977
parent19f1093f0929b989a06cdee2e7d175e6db15559c (diff)
va list, cont fix
-rw-r--r--bootstrap/all.h10
-rw-r--r--bootstrap/cgen.c40
-rw-r--r--bootstrap/dump.c2
-rw-r--r--bootstrap/parse.c25
-rw-r--r--bootstrap/types.c7
-rw-r--r--src/all.hff23
-rw-r--r--src/fmt.cff94
-rw-r--r--src/libc.hff14
-rw-r--r--src/parse.cff83
-rw-r--r--src/util.cff18
-rw-r--r--vgcore.175407bin0 -> 6742016 bytes
-rw-r--r--vgcore.175479bin0 -> 6746112 bytes
-rw-r--r--vgcore.175493bin0 -> 6746112 bytes
13 files changed, 295 insertions, 21 deletions
diff --git a/bootstrap/all.h b/bootstrap/all.h
index 6a0de81..f8eb769 100644
--- a/bootstrap/all.h
+++ b/bootstrap/all.h
@@ -157,6 +157,7 @@ enum typetype {
TYstruct,
TYunion,
TYeunion,
+ TYvalist,
};
struct type {
@@ -327,6 +328,9 @@ enum exprtype {
Elen,
Eeuini,
Eeutag,
+ Evastart,
+ Evaarg,
+ Evaend,
};
struct blockstmt {
@@ -488,7 +492,9 @@ static const struct targ {
llongsize,
sizesize,
f32align,
- f64align;
+ f64align,
+ valistsize,
+ valistalign;
bool charsigned;
} g_targ = {
.ptrsize = sizeof(void *),
@@ -499,6 +505,8 @@ static const struct targ {
.sizesize = sizeof(size_t),
.f32align = alignof(float),
.f64align = alignof(double),
+ .valistsize = sizeof(va_list),
+ .valistalign = alignof(va_list),
.charsigned = CHAR_MIN < 0,
};
diff --git a/bootstrap/cgen.c b/bootstrap/cgen.c
index 1629151..6321e92 100644
--- a/bootstrap/cgen.c
+++ b/bootstrap/cgen.c
@@ -37,6 +37,9 @@ gentype(const struct type *ty) {
case TYenum:
gentype(ty->enu.intty);
break;
+ case TYvalist:
+ pri("__builtin_va_list");
+ break;
}
if (ty->konst)
pri(" const");
@@ -168,6 +171,7 @@ geneuiniex(struct expr *ex) {
static void
genexpr(struct expr *ex) {
+ assert(ex);
const struct type *ty = unconstify(ex->ty);
struct decl *decl;
@@ -284,6 +288,15 @@ genexpr(struct expr *ex) {
geneuiniex(ex);
pri(")");
break;
+ case Evastart:
+ pri("__builtin_va_start(%e, %e)", ex->binop.lhs, ex->binop.rhs);
+ break;
+ case Evaarg:
+ pri("__builtin_va_arg(%e, %t)", ex->child, ex->ty);
+ break;
+ case Evaend:
+ pri("__builtin_va_end(%e)", ex->child);
+ break;
}
}
@@ -343,15 +356,15 @@ genstmt(struct stmt *stmt) {
}
break;
case Swhile:
- pri("while (%e) {", &stmt->loop.test);
+ pri("while (%e) {_cont%d:;", &stmt->loop.test, stmt->loop.id);
genblock(stmt->loop.body);
- pri("_cont%d:;} _brk%d:;\n", stmt->loop.id, stmt->loop.id);
+ pri("} _brk%d:;\n", stmt->loop.id);
break;
case Sdowhile:
- pri("do {");
+ pri("do {_cont%d:;",stmt->loop.id);
genblock(stmt->loop.body);
- pri("_cont%d:;} while (%e); _brk%d:;\n",
- stmt->loop.id, &stmt->loop.test, stmt->loop.id);
+ pri("} while (%e); _brk%d:;\n",
+ &stmt->loop.test, stmt->loop.id);
break;
case Sfor:
pri("{\n");
@@ -361,10 +374,12 @@ genstmt(struct stmt *stmt) {
pri("%e;", &stmt->loop.test);
if (stmt->loop.next)
pri(" %e", stmt->loop.next);
- pri(") {");
+ pri(") {goto _skip%d; _cont%d:", stmt->loop.id, stmt->loop.id);
+ if (stmt->loop.next)
+ pri(" %e;", stmt->loop.next);
+ pri("_skip%d:;", stmt->loop.id);
genblock(stmt->loop.body);
- pri("_cont%d:; }", stmt->loop.id);
- pri("} _brk%d:;\n", stmt->loop.id);
+ pri("}} _brk%d:;\n", stmt->loop.id);
break;
case Siswitch:
pri("switch (%e) {", &stmt->iswitch.test);
@@ -505,6 +520,13 @@ liftnestedex(struct expr *ex) {
case Eeuini:
liftnestedex(ex->euini.ini);
break;
+ case Evastart:
+ liftnestedex(ex->binop.lhs);
+ liftnestedex(ex->binop.rhs);
+ break;
+ case Evaarg: case Evaend:
+ liftnestedex(ex->child);
+ break;
}
}
@@ -676,7 +698,7 @@ defctype(const struct type *ty, void *_) {
if (!ty->_cname)
switch (ty->t) {
- case TYvoid: case TYbool:
+ case TYvoid: case TYbool: case TYvalist:
case TYenum: case TYint: case TYfloat:
break;
case TYptr:
diff --git a/bootstrap/dump.c b/bootstrap/dump.c
index 3bd915f..bf63d22 100644
--- a/bootstrap/dump.c
+++ b/bootstrap/dump.c
@@ -66,6 +66,8 @@ pritype(const struct type *ty) {
epri("%bc", '>');
}
break;
+ case TYvalist:
+ epri("va_list");
}
}
diff --git a/bootstrap/parse.c b/bootstrap/parse.c
index d0bea8e..7c31ce1 100644
--- a/bootstrap/parse.c
+++ b/bootstrap/parse.c
@@ -1416,7 +1416,32 @@ pexpostfix(struct parser *P) {
if (lexpeek(P).t != '(')
lexexpect(P, '(');
+ } else if (ex.ty->t == TYvalist) {
+ if (!strcmp(fnam, "start")) {
+ lexexpect(P, '(');
+ struct expr ex2 = parseexpr(P);
+ lexexpect(P, ')');
+ ex = (struct expr) {
+ Evastart, ex.span, ty_void,
+ .binop.lhs = exprdup(ex),
+ .binop.rhs = exprdup(ex2)
+ };
+ } else if (!strcmp(fnam, "arg")) {
+ lexexpect(P, '(');
+ ty = parsetype(P);
+ lexexpect(P, ')');
+ ex = (struct expr) {
+ Evaarg, ex.span, ty, .child = exprdup(ex)
+ };
+ } else if (!strcmp(fnam, "end")) {
+ lexexpect(P, '(');
+ lexexpect(P, ')');
+ ex = (struct expr) {
+ Evaend, ex.span, ty_void, .child = exprdup(ex)
+ };
+ } else goto badmet;
} else {
+ badmet:
fatal(P, tok.span, "cannot call `->%s': left-hand-side is not an aggregate (%t)",
fnam, ex.ty);
}
diff --git a/bootstrap/types.c b/bootstrap/types.c
index 9118392..66ae840 100644
--- a/bootstrap/types.c
+++ b/bootstrap/types.c
@@ -36,7 +36,7 @@ hashtype(const struct type *ty) {
epri("");
switch (ty->t) {
- case TYvoid: case TYbool:
+ case TYvoid: case TYbool: case TYvalist:
break;
case TYint: case TYfloat:
h = fnv1az(h, ty->size);
@@ -75,7 +75,7 @@ typeeql(const struct type *lhs, const struct type *rhs) {
if (lhs->t != rhs->t || lhs->konst != rhs->konst)
return 0;
switch (lhs->t) {
- case TYvoid: case TYbool:
+ case TYvoid: case TYbool: case TYvalist:
return 1;
case TYfloat:
return lhs->size == rhs->size;
@@ -206,7 +206,7 @@ const struct type
*ty_iptrint, *ty_uptrint, *ty_c_int, *ty_c_uint,
*ty_c_char, *ty_c_schar, *ty_c_uchar, *ty_c_short,
*ty_c_ushort, *ty_c_long, *ty_c_ulong, *ty_c_llong,
- *ty_c_ullong;
+ *ty_c_ullong, *ty_valist;
void
putprimtypes(struct env *env) {
@@ -248,6 +248,7 @@ putprimtypes(struct env *env) {
{"c_ulong", &ty_c_ulong, {TYint, t.longsize, IU}},
{"c_llong", &ty_c_llong, {TYint, t.llongsize, IS}},
{"c_ullong", &ty_c_ullong, {TYint, t.llongsize, IU}},
+ {"va_list", &ty_valist, {TYvalist, t.valistsize, t.valistalign}},
#undef IS
#undef IU
};
diff --git a/src/all.hff b/src/all.hff
index e1cb26a..a35694b 100644
--- a/src/all.hff
+++ b/src/all.hff
@@ -4,11 +4,11 @@ import "option.hff";
/// Macros
defmacro assert {
-(ex, s) [
+(ex, s, ...args) [
(do
if not (ex) {
fprintf(stderr, "%s:%d: assertion failed: ", #FILE, #LINE);
- fprintf(stderr, "`%s'", (s));
+ fprintf(stderr, s, args);
fprintf(stderr, "\n");
abort();
}
@@ -44,7 +44,7 @@ struct Loc {
}
#[lax]
-enum TokT {
+enum TokT : i32 {
// !sorted
kw_and, kw_as, kw_break, kw_case, kw_const,
kw_continue, kw_def, kw_defmacro, kw_do,
@@ -68,10 +68,11 @@ enum TokT {
strify,
eof,
}
+def NUM_KEYWORDS = TokT:NUM_KEYWORDS;
struct Tok {
- t int,
+ t TokT,
loc Loc,
ty *const Type,
u union {
@@ -108,3 +109,17 @@ def FNV1A_INI u32 = 0x811c9dc5;
extern fn fnv1a(h u32, [#]const u8) u32;
extern fn fnv1a_s(h u32, *const u8) u32;
extern fn addfilepath(*const u8) int;
+extern fn fatal(*Parser, Loc, fmt *const u8, ...) void;
+
+// fmt.cff
+extern fn vpfmt(proc *fn(u8, *void) void, parg *void, fmt *const u8, va_list) void;
+extern fn vefmt(fmt *const u8, ap va_list) void;
+extern fn efmt(fmt *const u8, ...) void;
+
+// Inline functions
+fn bswap32(x u32) u32 {
+ return (x >> 24)
+ | ((x >> 8) & 0x00FF00)
+ | ((x << 8) & 0xFF0000)
+ | (x << 24);
+}
diff --git a/src/fmt.cff b/src/fmt.cff
new file mode 100644
index 0000000..885ea50
--- /dev/null
+++ b/src/fmt.cff
@@ -0,0 +1,94 @@
+import "all.hff";
+
+extern fn vpfmt(proc *fn(u8, *void) void, parg *void, fmt *const u8, ap va_list) void {
+ defmacro p(x) [ proc(x, parg) ]
+ defmacro ps(s) [
+ for let $i = 0; (s)[$i] != 0; ++$i {
+ p(s[$i]);
+ }
+ ]
+ let buf [100]u8 = {};
+ for let c u8 = *fmt; c != 0; c = *++fmt {
+ assert(c != 0, "?");
+ if c != '%' {
+ p(c);
+ if fmt[1] == 0 { break; }
+ continue;
+ }
+ let quote = #f;
+ #'fmt do {
+ switch (c = *++fmt) {
+ case 'i';
+ sprintf(buf, "%d", ap->arg(int));
+ ps(buf);
+ case 'q';
+ quote = #t;
+ continue #'fmt;
+ case 'c';
+ let ch u32 = ap->arg(int);
+ if quote {
+ extern fn isprint(int) int;
+ p('\'');
+ for ch = bswap32(ch); ch != 0; ch >>= 8 {
+ if ch & 0xFF != 0 {
+ if isprint(ch) != 0 { p(ch); }
+ else {
+ p('\\');
+ p('0' + (ch % 8));
+ p('0' + ((ch / 8) % 8));
+ p('0' + ((ch / 8 / 8) % 8));
+ }
+ }
+ }
+ p('\'');
+ } else {
+ if ch == 0 { p(0); }
+ else {
+ for ch = bswap32(ch); ch != 0; ch >>= 8 {
+ if ch & 0xFF != 0 {
+ p(ch & 0xFF);
+ }
+ }
+ }
+ }
+ case 's';
+ let s = ap->arg(*const u8);
+ if quote {
+ extern fn isprint(int) int;
+ p('\"');
+ for let c u8 #?; (c = *s++) != 0; {
+ if isprint(c) != 0 {
+ p(c);
+ } else {
+ p('\\');
+ p('0' + (c % 8));
+ p('0' + ((c / 8) % 8));
+ p('0' + ((c / 8 / 8) % 8));
+ }
+ }
+ p('\"');
+ } else {
+ ps(s);
+ }
+ case else
+ // assert(#f, "bad fmt '%c' @ %d", c, i);
+ }
+ } while #f;
+ }
+}
+
+extern fn vefmt(fmt *const u8, ap va_list) void {
+ fn epri(c u8, *void) void {
+ fputc(c, stderr);
+ }
+
+ vpfmt(&epri, #null, fmt, ap);
+}
+
+extern fn efmt(fmt *const u8, ...) void {
+ let ap va_list #?;
+ ap->start(fmt);
+
+ vefmt(fmt, ap);
+ ap->end();
+}
diff --git a/src/libc.hff b/src/libc.hff
index 7e2268c..a231614 100644
--- a/src/libc.hff
+++ b/src/libc.hff
@@ -3,11 +3,14 @@ struct FILE;
extern static stdin *FILE,
stdout *FILE,
stderr *FILE;
-extern fn printf(fmt *const u8, ...) void;
-extern fn fprintf(fp *FILE, fmt *const u8, ...) void;
+extern fn printf(fmt *const u8, ...) int;
+extern fn fprintf(fp *FILE, fmt *const u8, ...) int;
+extern fn sprintf(*u8, fmt *const u8, ...) int;
+extern fn snprintf(*u8, usize, fmt *const u8, ...) int;
extern fn fopen(path *const u8, mode *const u8) *FILE;
-extern fn fclose(fp *FILE) int;
-extern fn fgetc(fp *FILE) int;
+extern fn fclose(*FILE) int;
+extern fn fgetc(*FILE) int;
+extern fn fputc(int, *FILE) int;
def EOF = -1;
// stdlib.h
@@ -21,3 +24,6 @@ extern fn free(p *void) void;
// string.h
extern fn strlen(s *const u8) usize;
extern fn strcmp(a *const u8, b *const u8) int;
+
+//ctype.h
+extern fn tolower(int) int;
diff --git a/src/parse.cff b/src/parse.cff
index f659322..d672173 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -80,6 +80,20 @@ fn issep(c u8) bool {
return #f;
}
+fn readtilsep(P *Parser, buf [#]u8, dot bool) int {
+ let i = 0,
+ c u8 #?;
+ while (not issep(c = chrpeek(P))) or (dot and c == '.') {
+ chr(P);
+ if i >= buf.#len - 1 {
+ return -1;
+ }
+ buf[i++] = c;
+ }
+ buf[i++] = 0;
+ return i;
+}
+
fn eatspaces(P *Parser) void {
for ;;chr(P) {
if not isspace(chrpeek(P)) {
@@ -115,6 +129,59 @@ fn str2keyword(s *const u8) int {
return -1;
}
+fn readnumber(s *const u8) Option<Tok> {
+ let c u8 #?,
+ acc = 0u64,
+ accf = 0.0f64,
+ fmul = 0.1,
+ base = 10,
+ flt = #f,
+ nused = 0,
+ suffix *const u8 = #null;
+
+ for let i = 0; (c = s[i]) != 0; ++i {
+ if i == 0 and c == '0' {
+ --nused;
+ }
+ if i == 1 and tolower(c) == 'x' {
+ base = 16;
+ continue;
+ }
+ if not flt and c == '.' and base == 10 {
+ flt = #t;
+ accf = acc;
+ continue;
+ }
+ if nused > 0 and c == '_' { continue; }
+ if (base == 16 and not isdigit(c))
+ or (base != 16 and (c < '0' or c > ('0' + base) - 1)) {
+ suffix = s + i;
+ }
+
+ ++nused;
+ if flt {
+ accf = accf + ((c - '0') * fmul);
+ fmul *= 0.1;
+ } else {
+ c = tolower(c);
+ acc = (acc * base) + (c <= '9' ? c - '0' : (c - 'a') + 10);
+ }
+ }
+
+ let tok = Tok {};
+ if flt {
+ tok.t = :flo;
+ tok.u.flo = accf;
+ return :Some tok;
+ } else {
+ tok.t = :int;
+ tok.u.uint = acc;
+ return :Some tok;
+ }
+
+ return :None;
+}
+
fn lex(P *Parser) Tok {
let c int #?;
let tok Tok = {};
@@ -129,7 +196,22 @@ fn lex(P *Parser) Tok {
tok.loc = (P.tokloc = P.curloc);
if isdigit(c = chrpeek(P)) {
let s [80]u8 = {};
+ if readtilsep(P, s[0::], #t) < 0 {
+ // fatal
+ }
+ switch readnumber(s) {
+ case None;
+ fatal(P, tok.loc, "bad number literal %qs", s);
+ case Some tok;
+ tok.loc = P.tokloc;
+ return tok;
+ }
+ }
+ if c == EOF {
+ tok.t = :eof;
+ return tok;
}
+ fatal(P, tok.loc, "stray %qc in program", c);
}
extern fn parse(P *Parser) [#]Decl {
@@ -137,6 +219,7 @@ extern fn parse(P *Parser) [#]Decl {
}
extern fn parser_init(P *Parser, path *const u8) void {
+ assert(NUM_KEYWORDS - 1 < '!', "2manykw");
*P = {};
P.curfile = path;
if (P.fp = fopen(path, "r")) == #null {
diff --git a/src/util.cff b/src/util.cff
index 33bce84..c3a08cb 100644
--- a/src/util.cff
+++ b/src/util.cff
@@ -47,3 +47,21 @@ extern fn addfilepath(s *const u8) int {
filepaths[i] = s;
return i;
}
+
+fn fileid2path(id int) *const u8 {
+ assert(id >= 0 and id < filepaths.#len, "fileid");
+ let s = filepaths[id];
+ assert(s != #null, "fileid");
+ return s;
+}
+
+extern fn fatal(P *Parser, loc Loc, fmt *const u8, ...) void {
+ let ap va_list #?;
+ ap->start(fmt);
+
+ efmt("%s:%i:%i: error: ", fileid2path(loc.fileid), loc.line, loc.col);
+ vefmt(fmt, ap);
+ efmt("\n");
+ ap->end();
+ exit(1);
+}
diff --git a/vgcore.175407 b/vgcore.175407
new file mode 100644
index 0000000..a8392d9
--- /dev/null
+++ b/vgcore.175407
Binary files differ
diff --git a/vgcore.175479 b/vgcore.175479
new file mode 100644
index 0000000..45a85d8
--- /dev/null
+++ b/vgcore.175479
Binary files differ
diff --git a/vgcore.175493 b/vgcore.175493
new file mode 100644
index 0000000..99dd454
--- /dev/null
+++ b/vgcore.175493
Binary files differ