aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cffc.hff6
-rw-r--r--src/fold.cff31
-rw-r--r--src/parse.cff118
-rw-r--r--src/type.cff2
4 files changed, 129 insertions, 28 deletions
diff --git a/src/cffc.hff b/src/cffc.hff
index 4563583..53b4db5 100644
--- a/src/cffc.hff
+++ b/src/cffc.hff
@@ -195,6 +195,11 @@ struct EUSwitchCase {
t [#]Stmt
}
+struct CSwitchCase {
+ test Expr,
+ t [#]Stmt,
+}
+
struct Stmt {
loc Loc,
u enum union {
@@ -215,6 +220,7 @@ struct Stmt {
Decl *Decl,
ISwitch struct { ex Expr, cs [#]ISwitchCase, f [#]Stmt },
EUSwitch struct { ex Expr, cs [#]EUSwitchCase, f [#]Stmt },
+ CSwitch struct { cs [#]CSwitchCase, f [#]Stmt }
}
}
diff --git a/src/fold.cff b/src/fold.cff
index a2c95b8..c9991b7 100644
--- a/src/fold.cff
+++ b/src/fold.cff
@@ -53,6 +53,37 @@ fn numcast(ex *Expr, to *const Type) void {
}
fn funary(ex *Expr) void {
+ let r = ex.u.UnOp.ex;
+ let ty = ex.ty;
+ let iu = &ex.u.IntLit;
+ let f = &ex.u.FloLit;
+ let b = &ex.u.BoolLit;
+
+ if !fold(r) {
+ return;
+ }
+ switch ex.u.UnOp.op {
+ case :neg;
+ *ex = *r;
+ if r.ty->is(:Int) {
+ iu.i = -iu.i;
+ } else if r.ty->is(:Flo) {
+ *f = -*f;
+ } else {
+ assert(#f, "neg");
+ }
+ numcast(ex, ty);
+ case :compl;
+ *ex = *r;
+ iu.i = ~iu.i;
+ assert(r.ty->is(:Int), "compl");
+ numcast(ex, ty);
+ case :not;
+ *ex = *r;
+ *b = !*b;
+ assert(r.ty->is(:Bool), "not");
+ }
+ ex.ty = ty;
}
fn fbinary(ex *Expr) void {
diff --git a/src/parse.cff b/src/parse.cff
index 89a059f..379fa90 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -176,6 +176,29 @@ fn xdigit2num(c u8) int {
return -1;
}
+fn ty4intX(i u64) *const Type {
+ if i < 1u64 << ((g_targ.intsize * 8) - 1) {
+ return ty_int;
+ }
+ if i < 1u64 << 31 {
+ return ty_i32;
+ }
+ if i < 1u64 << 63 {
+ return ty_i64;
+ }
+ return ty_u64;
+}
+
+fn ty4uintX(i u64) *const Type {
+ if i < 1u64 << (g_targ.intsize * 8) {
+ return ty_uint;
+ }
+ if i < 1u64 << 32 {
+ return ty_u32;
+ }
+ return ty_u64;
+}
+
fn readnumber(s *const u8) Option<Tok> {
let c u8 #?,
acc = 0u64,
@@ -203,6 +226,7 @@ fn readnumber(s *const u8) Option<Tok> {
if (base == 16 and !isxdigit(c))
or (base != 16 and (c < '0' or c > ('0' + base) - 1)) {
suffix = s + i;
+ break;
}
++nused;
@@ -232,29 +256,6 @@ fn readnumber(s *const u8) Option<Tok> {
tok.t = :int;
tok.u.uint = acc;
- fn ty4intX(i u64) *const Type {
- if i < 1u64 << ((g_targ.intsize * 8) - 1) {
- return ty_int;
- }
- if i < 1u64 << 31 {
- return ty_i32;
- }
- if i < 1u64 << 63 {
- return ty_i64;
- }
- return ty_u64;
- }
-
- fn ty4uintX(i u64) *const Type {
- if i < 1u64 << (g_targ.intsize * 8) {
- return ty_uint;
- }
- if i < 1u64 << 32 {
- return ty_u32;
- }
- return ty_u64;
- }
-
switch {
case suffix == #null; tok.ty = ty4intX(tok.u.uint);
case strcieq(suffix, "u"); tok.ty = ty4uintX(tok.u.uint);
@@ -395,6 +396,8 @@ fn lex(P *Parser) Tok {
tok.t = '##';
case streq(s, "#len");
tok.t = '#len';
+ case streq(s, "#ptr");
+ tok.t = '#ptr';
case streq(s, "#tag");
tok.t = '#tag';
case streq(s, "#FILE");
@@ -461,6 +464,7 @@ fn lex(P *Parser) Tok {
vec_each(c0, i, str) {
tok.u.uint = (tok.u.uint << 8) | c0;
}
+ tok.ty = ty4intX(tok.u.uint);
}
return tok;
}
@@ -856,7 +860,7 @@ fn parseexpandtepl(P *Parser, tepl *Tepl) *const Type {
case else
fatal(P, ex.loc, "expected constant expression");
}
-
+ case else assert(#f, "unreachable %d", par.u.#tag);
}
args[i].name = par.name;
@@ -1017,7 +1021,8 @@ fn parsetype(P *Parser) *const Type {
} else if !lexmatch(P, &tok, ']') {
let ex = parseexpr(P);
lexexpect(P, ']');
- if !fold(&ex) or ex.u.#tag != :IntLit or ex.u.IntLit.i < 0 {
+ if !fold(&ex) or !(ex.u.#tag == :IntLit or (ex.u.#tag == :EnumIni and ex.ty.u.Enum.lax))
+ or ex.u.IntLit.i < 0 {
fatal(P, ex.loc, "expected constant non-negative integer expression for array length");
}
len = ex.u.IntLit.i;
@@ -1474,6 +1479,7 @@ fn pexpostfix(P *Parser) Expr {
let params = Fn.params;
let param = &params[0];
while !lexmatch(P, #null, ')') {
+ P.targty = args.len + 1 <= params.#len ? *param : #null;
let ex = parseexpr(P);
args->push(ex);
if args.len >= params.#len and !Fn.variadic {
@@ -1629,7 +1635,9 @@ fn pexpostfix(P *Parser) Expr {
}
let args Vec<Expr> = {};
args->push(ex);
+ let param = &Fn.params[1];
while !lexmatch(P, #null, ')') {
+ P.targty = *param++;
args->push(parseexpr(P));
if args.len > Fn.params.#len and !Fn.variadic {
fatal(P, args->last().loc, "too many args (%z, expected %z)", args.len, Fn.params.#len);
@@ -1791,7 +1799,11 @@ fn pexcmp(P *Parser) Expr {
let ex = pexbitarith(P);
let tok Tok = {};
if matchcmpop(P, &tok) {
+ if tok.t == '==' or tok.t == '!=' {
+ P.targty = ex.ty;
+ }
let rhs = pexbitarith(P);
+ P.targty = #null;
if typeof2(ex.ty, rhs.ty) == #null {
fatal(P, tok.loc, "incompatible operands %t and %t to binary operator %qT",
ex.ty, rhs.ty, tok);
@@ -1900,6 +1912,9 @@ fn pexassign(P *Parser) Expr {
if okind == :None {
return ex;
}
+ if tok.t == '=' {
+ P.targty = ex.ty;
+ }
let rhs = pexcond(P);
switch {
case !islvalue(ex);
@@ -1978,6 +1993,7 @@ fn pstreturn(P *Parser, loc Loc) Stmt {
}
return { loc, :Return{} };
} else {
+ P.targty = retty;
let ex = parseexpr(P);
lexexpect(P, ';');
if !typematchestarg(retty, ex.ty) {
@@ -2026,6 +2042,7 @@ fn pstfor(P *Parser, loc Loc, label *const u8) Stmt {
} else {
let ex = parseexpr(P);
ini = stmtdup(P.alloc, { ex.loc, :Expr(ex) })[0::1];
+ lexexpect(P, ';');
}
if lexmatch(P, &tok, ';') {
@@ -2149,9 +2166,36 @@ fn psteuswitch(P *Parser, loc Loc, test Expr) Stmt {
return { loc, :EUSwitch { test, cs->move(P.alloc), f }};
}
+fn pstcswitch(P *Parser, loc Loc) Stmt {
+ let cs Vec<CSwitchCase> = {};
+ let tok Tok #?;
+ let f [#]Stmt = {};
+ let elsep = #f;
+
+ while !lexmatch(P, &tok, '}') {
+ let c CSwitchCase = {};
+ lexexpect(P, :kw_case);
+ if lexmatch(P, &tok, :kw_else) {
+ if elsep {
+ err(P, tok.loc, "duplicate 'case else' block");
+ }
+ elsep = #t;
+ f = parseblock0(P);
+ continue;
+ }
+ c.test = parseexpr(P);
+ lexexpect(P, ';');
+ c.t = parseblock0(P);
+ }
+
+
+ return { loc, :CSwitch { cs->move(P.alloc), f }};
+}
+
fn pstswitch(P *Parser, loc Loc) Stmt {
let tok Tok #?;
if lexmatch(P, &tok, '{') {
+ return pstcswitch(P, loc);
} else {
let ex = parseexpr(P);
lexexpect(P, '{');
@@ -2380,6 +2424,7 @@ fn parsefn(P *Parser, loc Loc, externp bool, name *const u8) *Decl {
return decl;
}
+fn parse4import(P *Parser) [#]Decl;
fn doimport(P *Parser, loc Loc, path *const u8) [#]Decl {
struct Entry {
decls [#]Decl,
@@ -2415,11 +2460,12 @@ fn doimport(P *Parser, loc Loc, path *const u8) [#]Decl {
return d0.decls;
}
rpath = strcpy(malloc(strlen(rpath) + 1), rpath);
+ let e = seen->put(rpath, { {}, #t });
let P2 Parser #?;
parser_init(&P2, rpath);
P2.is_header = #t;
- let e = seen->put(rpath, { {}, #t });
- let decls = parse(&P2);
+ P2.alloc = P.alloc;
+ let decls = parse4import(&P2);
*e = { decls, #f };
return decls;
@@ -2734,6 +2780,24 @@ fn parsedecls(P *Parser, loc Loc, yield DeclYielder, yarg *void, toplevel bool)
}
}
+fn parse4import(P *Parser) [#]Decl {
+ let decls Vec<Decl> = {};
+ P.curenv = mkenv(#null, P.alloc);
+
+ while !P.eof {
+ fn yield(decl *Decl, arg *void) void {
+ let decls *Vec<Decl> = arg;
+ decls->push(*decl);
+ }
+ parsedecls(P, P.tokloc, &yield, &decls, #{toplevel} #t);
+ if lexmatch(P, #null, :eof) {
+ break;
+ }
+ }
+
+ return decls.dat[0::decls.len];
+}
+
extern fn parse(P *Parser) [#]Decl {
let aralloc = Arena {};
let alloc = Allocator { &aralloc, &Arena:allocf, #null };
diff --git a/src/type.cff b/src/type.cff
index a07ea0d..dd59517 100644
--- a/src/type.cff
+++ b/src/type.cff
@@ -188,7 +188,7 @@ extern fn putprimtypes(env *Env) void {
{ "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 }},
+ { "va_list",&ty_c_valist,{ g_targ.valistsize, g_targ.valistalign, .u: :VaList }},
};
foreach(type, _, types[0::]) {