aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-19 16:31:16 +0200
committerlemon <lsof@mailbox.org>2022-08-19 16:31:16 +0200
commit57af02b91cb3a9eef66137c85aab7e47bdd7d0a5 (patch)
treec0597811c61d473263559ab7ffefe68ab8785c47 /src
parent9e408967cbdfa1d04e4bd4bc963399e7be78c0a7 (diff)
labels, #FILE #LINE, some bugfixes, c types
Diffstat (limited to 'src')
-rw-r--r--src/cffc.hff48
-rw-r--r--src/env.cff8
-rw-r--r--src/mem.hff2
-rw-r--r--src/parse.cff92
-rw-r--r--src/type.cff52
5 files changed, 136 insertions, 66 deletions
diff --git a/src/cffc.hff b/src/cffc.hff
index 131b3d9..920f74a 100644
--- a/src/cffc.hff
+++ b/src/cffc.hff
@@ -108,6 +108,7 @@ struct Type {
flds [#]AggField,
decls *Env,
},
+ VaList,
},
fn is(ty *const Type, tag typeof((Type{}).u.#tag)) bool {
@@ -282,6 +283,7 @@ struct Decl {
Fn Fn,
Macro Macro,
Tepl Tepl,
+ Label #{loopid} int,
},
myenv *Env,
}
@@ -297,8 +299,8 @@ struct Expan {
name *const u8,
loc Loc,
tepl bool,
+ peektok Option<Tok>,
idx int,
- peektok Option<Tok>
}
struct DeclList {
@@ -340,25 +342,31 @@ extern static g_targ *const Targ;
extern fn targ_ini(name *const u8) bool;
// type.cff
-extern static ty_void *const Type,
- ty_bool *const Type,
- ty_i8 *const Type,
- ty_u8 *const Type,
- ty_i16 *const Type,
- ty_u16 *const Type,
- ty_i32 *const Type,
- ty_u32 *const Type,
- ty_int *const Type,
- ty_uint *const Type,
- ty_i64 *const Type,
- ty_u64 *const Type,
- ty_isize *const Type,
- ty_usize *const Type,
- ty_iptrint *const Type,
- ty_uptrint *const Type,
- ty_f32 *const Type,
- ty_f64 *const Type,
- ty_voidptr *const Type;
+extern static ty_void *const Type,
+ ty_bool *const Type,
+ ty_i8 *const Type,
+ ty_u8 *const Type,
+ ty_i16 *const Type,
+ ty_u16 *const Type,
+ ty_i32 *const Type,
+ ty_u32 *const Type,
+ ty_int *const Type,
+ ty_uint *const Type,
+ ty_i64 *const Type,
+ ty_u64 *const Type,
+ ty_isize *const Type,
+ ty_usize *const Type,
+ ty_iptrint *const Type,
+ ty_uptrint *const Type,
+ ty_f32 *const Type,
+ ty_f64 *const Type,
+ ty_voidptr *const Type,
+ ty_c_char *const Type,
+ ty_c_long *const Type,
+ ty_c_ulong *const Type,
+ ty_c_llong *const Type,
+ ty_c_ullong *const Type,
+ ty_c_valist *const Type;
extern fn interntype(Type) *const Type;
extern fn putprimtypes(env *Env) void;
fn constify(ty *const Type) *const Type {
diff --git a/src/env.cff b/src/env.cff
index aa5c6d4..816053e 100644
--- a/src/env.cff
+++ b/src/env.cff
@@ -30,7 +30,13 @@ extern fn envput(env *Env, decl Decl, old **const Decl) *Decl {
if *l { // decl with this name exists
let old = (*old = &(*l).decl);
switch {
- case old.u.#tag == :Fn and decl.u.#tag == :Fn and decl.u.Fn.ty == old.u.Fn.ty and old.u.Fn.body->empty();
+ case old.u.#tag == :Fn and decl.u.#tag == :Fn
+ and decl.u.Fn.ty == old.u.Fn.ty and (old.u.Fn.body->empty() or decl.u.Fn.body->empty());
+ case old.u.#tag == :Ty and decl.u.#tag == :Ty and old.u.Ty == decl.u.Ty;
+ case old.u.#tag == :Def and decl.u.#tag == :Def
+ and memcmp(&old.u.Def, &decl.u.Def, sizeof(old.u.Def)) == 0;
+ case old.u.#tag == :Macro and decl.u.#tag == :Macro
+ and memcmp(&old.u.Macro, &decl.u.Macro, sizeof(old.u.Macro)) == 0;
case decl.u.#tag == :Let;
case env != old.myenv;
diff --git a/src/mem.hff b/src/mem.hff
index 3f3b8c9..f3689ac 100644
--- a/src/mem.hff
+++ b/src/mem.hff
@@ -1,7 +1,7 @@
import "libc.hff";
defmacro ALIGNUP(x,a) [ (((x) + ((a) - 1)) & -(a)) ]
-def ARENA_SIZE = 4 * 1024;
+def ARENA_SIZE = 4z * 1024;
extern fn xmalloc(n usize) *void;
extern fn xcalloc(n usize, m usize) *void;
extern fn xrealloc(p *void, n usize) *void;
diff --git a/src/parse.cff b/src/parse.cff
index cbeccb1..2f5fbe2 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -299,7 +299,9 @@ fn lex(P *Parser) Tok {
--P.expanno;
free(ep.args.#ptr);
P.curexpan = ep.prev;
- P.peektok = ep.peektok;
+ if !ep.tepl {
+ P.peektok = ep.peektok;
+ }
free(ep);
return lex(P);
}
@@ -395,11 +397,15 @@ fn lex(P *Parser) Tok {
tok.t = '#len';
case streq(s, "#tag");
tok.t = '#tag';
+ case streq(s, "#FILE");
+ tok.t = '#FIL';
+ case streq(s, "#LINE");
+ tok.t = '#LIN';
case streq(s, "#?");
tok.t = '#?';
case s[0] == '#' and s[1] == '\'';
tok.t = :label;
- tok.u.str = spanz(internstr(s));
+ tok.u.ident = internstr(s);
case else
fatal(P, P.tokloc, "invalid #keyword `%s'", s);
}
@@ -677,6 +683,8 @@ fn parseagg(P *Parser, loc Loc, kind AggKind, name *const u8, retdecl **Decl) *c
if !ty->is(:Agg) or !ty.u.Agg.fwd or ty.u.Agg.kind != kind {
decl = #null;
}
+ case else
+ decl = #null;
}
}
let ty = decl ? decl.u.Ty : interntype({ .u: :Agg { kind, name, id++ }});
@@ -904,12 +912,14 @@ fn parseexpandtepl(P *Parser, tepl *Tepl) *const Type {
let env = mkenv(tepl.env, P.alloc);
with_tmpchange(P.curenv, env) {
let decl *Decl #?;
- let expan Expan = { P.curexpan, args[0::nparam], tepl.toks, tname, tok.loc, #{tepl?} #t };
+ let expan Expan = {
+ P.curexpan, args[0::nparam], tepl.toks, tname, tok.loc, #{tepl?} #t,
+ };
++P.expanno;
P.curexpan = memcpy(xmalloc(sizeof Expan), &expan, sizeof Expan);
ty = parseagg(P, loc, tepl.kind, tname, &decl);
-
}
+ P.peektok = :None;
envfree(env);
(as(*Type)ty).u.Agg.tpargs = tpargs;
cache = P.alloc->alloc(sizeof(*cache), alignof(*cache));
@@ -1275,6 +1285,7 @@ fn pexprimary(P *Parser) Expr {
case :ident;
let ident = tok.u.ident;
let decl = finddecl(P, ident);
+ let fakedecl Decl = {};
if decl == #null {
fatal(P, tok.loc, "%qT is not defined", tok);
}
@@ -1294,7 +1305,7 @@ fn pexprimary(P *Parser) Expr {
ex = parseexpr(P);
case Ty ty;
if (tok = lexpeek(P)).t != ':' and tok.t != '{' {
- fatal(P, tok.loc, "expected `:' or `{' after type name");
+ lexexpects(P, ':', "`:' or `{' after type name");
}
if tok.t == ':' and ty->is(:Agg) and ty.u.Agg.kind != :EUnion {
lex(P);
@@ -1310,6 +1321,10 @@ fn pexprimary(P *Parser) Expr {
P.targty = ty;
return parseexpr(P);
}
+ case Tepl *tepl;
+ fakedecl = { .u: :Ty(parseexpandtepl(P, tepl)) };
+ decl = &fakedecl;
+ continue;
}
break;
}
@@ -1949,20 +1964,27 @@ fn pstreturn(P *Parser, loc Loc) Stmt {
}
}
-fn pstwhile(P *Parser, loc Loc) Stmt {
+fn pstwhile(P *Parser, loc Loc, label *const u8) Stmt {
let test = parseexpr(P);
if !test.ty->is(:Bool) and !test.ty->is(:Ptr) {
err(P, test.loc, "while condition must be bool or pointer (%t)", test.ty);
}
lexexpect(P, '{');
- let t [#]Stmt #?;
+ let body [#]Stmt #?;
with_tmpchange(P.curloop, ++P.loopid) {
- t = parseblock(P);
+ let env = mkenv(P.curenv, P.alloc);
+ pushenv(P, env);
+ if label {
+ putdecl(P, loc, { label, loc, .u: :Label(P.loopid) });
+ }
+ body = parseblock(P);
+ popenv(P);
+ envfree(env);
}
- return { loc, :While { test, t, P.loopid }};
+ return { loc, :While { test, body, P.loopid }};
}
-fn pstfor(P *Parser, loc Loc) Stmt {
+fn pstfor(P *Parser, loc Loc, label *const u8) Stmt {
let ini [#]Stmt = {};
let test Expr #?;
let next = Option<Expr>:None;
@@ -1998,7 +2020,14 @@ fn pstfor(P *Parser, loc Loc) Stmt {
}
let body [#]Stmt #?;
with_tmpchange(P.curloop, ++P.loopid) {
+ let env = mkenv(P.curenv, P.alloc);
+ pushenv(P, env);
+ if label {
+ putdecl(P, loc, { label, loc, .u: :Label(P.loopid) });
+ }
body = parseblock(P);
+ popenv(P);
+ envfree(env);
}
return { loc, :For { ini, test, next, body, P.loopid }};
}
@@ -2129,25 +2158,39 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void {
case lexmatch(P, &tok, :kw_return);
return yield(pstreturn(P, tok.loc), yarg);
+ case lexmatch(P, &tok, :label);
+ let label = tok.u.ident;
+ switch {
+ case lexmatch(P, &tok, :kw_while);
+ return yield(pstwhile(P, tok.loc, label), yarg);
+ case lexmatch(P, &tok, :kw_for);
+ return yield(pstfor(P, tok.loc, label), yarg);
+ case else
+ fatal(P, tok.loc, "label can only precede looping statement");
+ }
+
case lexmatch(P, &tok, :kw_while);
- return yield(pstwhile(P, tok.loc), yarg);
+ return yield(pstwhile(P, tok.loc, #null), yarg);
case lexmatch(P, &tok, :kw_for);
- return yield(pstfor(P, tok.loc), yarg);
+ return yield(pstfor(P, tok.loc, #null), yarg);
- case lexmatch(P, &tok, :kw_break);
+ case lexmatch(P, &tok, :kw_break) or lexmatch(P, &tok, :kw_continue);
if P.curloop == 0 {
- err(P, tok.loc, "break outside loop");
+ err(P, tok.loc, "%s outside loop", tok.t == :kw_break ? "break" : "continue");
}
- lexexpect(P, ';');
- return yield({ tok.loc, :Break(P.curloop) }, yarg);
-
- case lexmatch(P, &tok, :kw_continue);
- if P.curloop == 0 {
- err(P, tok.loc, "continue outside loop");
+ let tok2 Tok #?;
+ let loop = P.curloop;
+ if lexmatch(P, &tok2, :label) {
+ let decl = finddecl(P, tok2.u.ident);
+ if decl == #null {
+ fatal(P, tok2.loc, "no such label %qT", tok2);
+ }
+ assert(decl.u.#tag == :Label, "label?");
+ loop = decl.u.Label;
}
lexexpect(P, ';');
- return yield({ tok.loc, :Continue(P.curloop) }, yarg);
+ return yield({ tok.loc, tok.t == :kw_break ? :Break(loop) : :Continue(loop) }, yarg);
case lexmatch(P, &tok, :kw_switch);
return yield(pstswitch(P, tok.loc), yarg);
@@ -2622,9 +2665,10 @@ fn parsedecls(P *Parser, loc Loc, yield DeclYielder, yarg *void, toplevel bool)
err(P, ini.loc, "incompatible initializer (%t, expected %t)", ini.ty, ty);
}
fold(&ini);
- yield(putdecl(P, tok.loc, {
- name, tok.loc, .u: :Def(ini)
- }), yarg);
+ decl = putdecl(P, tok.loc, { name, tok.loc, .u: :Def(ini) });
+ if yield {
+ yield(decl, yarg);
+ }
if !lexmatch(P, &tok, ',') {
lexexpects(P, ';', "`,' or `;'");
break;
diff --git a/src/type.cff b/src/type.cff
index 713716b..b0cb259 100644
--- a/src/type.cff
+++ b/src/type.cff
@@ -135,26 +135,32 @@ extern fn completetype(ty *const Type) bool {
return #t;
}
-extern static ty_void *const Type = {},
- ty_bool *const Type = {},
- ty_intbool *const Type = {},
- ty_i8 *const Type = {},
- ty_u8 *const Type = {},
- ty_i16 *const Type = {},
- ty_u16 *const Type = {},
- ty_i32 *const Type = {},
- ty_u32 *const Type = {},
- ty_int *const Type = {},
- ty_uint *const Type = {},
- ty_i64 *const Type = {},
- ty_u64 *const Type = {},
- ty_isize *const Type = {},
- ty_usize *const Type = {},
- ty_iptrint *const Type = {},
- ty_uptrint *const Type = {},
- ty_f32 *const Type = {},
- ty_f64 *const Type = {},
- ty_voidptr *const Type = {};
+extern static ty_void *const Type = {},
+ ty_bool *const Type = {},
+ ty_intbool *const Type = {},
+ ty_i8 *const Type = {},
+ ty_u8 *const Type = {},
+ ty_i16 *const Type = {},
+ ty_u16 *const Type = {},
+ ty_i32 *const Type = {},
+ ty_u32 *const Type = {},
+ ty_int *const Type = {},
+ ty_uint *const Type = {},
+ ty_i64 *const Type = {},
+ ty_u64 *const Type = {},
+ ty_isize *const Type = {},
+ ty_usize *const Type = {},
+ ty_iptrint *const Type = {},
+ ty_uptrint *const Type = {},
+ ty_f32 *const Type = {},
+ ty_f64 *const Type = {},
+ ty_voidptr *const Type = {},
+ ty_c_char *const Type = {},
+ ty_c_long *const Type = {},
+ ty_c_ulong *const Type = {},
+ ty_c_llong *const Type = {},
+ ty_c_ullong *const Type = {},
+ ty_c_valist *const Type = {};
extern fn putprimtypes(env *Env) void {
let types []struct { name *const u8, gty **const Type, ty Type } = {
@@ -177,6 +183,12 @@ extern fn putprimtypes(env *Env) void {
{ "u64", &ty_u64, { .size: 8, g_targ.i64align, .u: :Int { .sgn: #f }}},
{ "iptrint",&ty_iptrint, { g_targ.ptrsize, .u: :Int { .sgn: #t }}},
{ "uptrint",&ty_uptrint, { g_targ.ptrsize, .u: :Int { .sgn: #f }}},
+ { "c_char", &ty_c_char, { .size: 1, .u: :Int { .sgn: g_targ.charsigned }}},
+ { "c_long", &ty_c_long, { g_targ.longsize, g_targ.longalign, .u: :Int { .sgn : #t }}},
+ { "c_ulong",&ty_c_ulong, { g_targ.longsize, g_targ.longalign, .u: :Int { .sgn : #f }}},
+ { "c_llong",&ty_c_llong, { g_targ.llongsize, g_targ.llongalign, .u: :Int { .sgn : #t }}},
+ { "c_ullong",&ty_c_ullong,{ g_targ.llongsize, g_targ.llongalign, .u: :Int { .sgn : #f }}},
+ { "c_valist",&ty_c_valist,{ g_targ.valistsize, g_targ.valistalign, .u: :VaList }},
};
foreach(type, _, types[0::]) {