Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions generator/c/c_generator_call.c2
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,15 @@ fn void Generator.emitCall(Generator* gen, string_buffer.Buf* out, Expr* e) {
MemberContext mc = {}
gen.emitMemberExpr(out, m, &mc, true);
} else {
bool no_trace = gen.no_trace;
dest = getFuncDecl(func, &no_trace);
if (gen.trace_calls && !no_trace) {
bool no_trace = true;
if (gen.trace_calls) {
no_trace = gen.no_trace;
dest = getFuncDecl(func, &no_trace);
}
if (!no_trace) {
const char* dest_name = dest ? dest.getFullName() : "*";
out.print("(c2_trace_counts[%d]++, ",
gen.addCall(dest.getFullName(), call.getStartLoc()));
gen.addCall(dest_name, call.getStartLoc()));
gen.emitExpr(out, func);
out.add1(')');
} else {
Expand Down Expand Up @@ -108,24 +112,23 @@ fn void Generator.emitCall(Generator* gen, string_buffer.Buf* out, Expr* e) {
fn Decl* getFuncDecl(Expr* func, bool* no_trace) {
switch (func.getKind()) {
case Identifier:
// TODO check for pointer
IdentifierExpr* i = (IdentifierExpr*)func;
// do not trace calls to va_start, va_arg, va_end...
const char *name = i.getName();
if (name && name[0] == 'v' && name[1] == 'a' && name[2] == '_')
*no_trace = true;
return i.getDecl();
case Member:
// TODO check for struct member
MemberExpr* m = (MemberExpr*)func;
return m.getFullDecl();
case Alternate:
AlternateExpr* a = (AlternateExpr*)func;
Expr* g = a.getGenerated();
return getFuncDecl(a.getGenerated(), no_trace);
default:
break;
return nil;
}
func.dump();
assert(0);
return nil;
}

85 changes: 85 additions & 0 deletions test/functions/indirect_calls.c2
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// @warnings{no-unused}
module test;

import ctype local;
import stdio local;
import stdlib local;

type Num i64;

type Operator enum u8 { Error, Add, Sub, Mul, Div, Mod, Show }
const u8[Operator] Operator_arity = { 0, 2, 2, 2, 2, 2, 1 }
const Evaluator[Operator] Operator_func = { error, add, sub, mul, pdiv, pmod, output }

fn Operator getop(char c) {
switch (c) {
case '+': return Add;
case '-': return Sub;
case '*': return Mul;
case '/': return Div;
case '%': return Mod;
case ',': return Show;
default: return Error;
}
}

type Evaluator fn u32 (Num *sp);

fn u32 error(Num*) { printf("invalid operator\n"); return 0; }
fn u32 add(Num* sp) { *sp += sp[1]; return 1; }
fn u32 sub(Num* sp) { *sp -= sp[1]; return 1; }
fn u32 mul(Num* sp) { *sp *= sp[1]; return 1; }
fn u32 pdiv(Num* sp) { *sp /= sp[1]; return 1; }
fn u32 pmod(Num* sp) { *sp %= sp[1]; return 1; }
fn u32 output(Num* sp) { printf(" %d", *sp); return 1; }

fn u32 dispatch(Evaluator f, Num* sp) {
// this works: return f(sp); but gets traced as a call to function f
// this used to trigger an assert in c_generator.getFuncDecl();
return (f)(sp);
}

public fn i32 main() {
char[256] buf;

for (;;) {
printf("calc > ");
fflush(stdout);
if (!getsn(buf, elemsof(buf))) break;

Num[32] stack;
Num* sp = stack;
char *p = buf;
while (*p) {
if (isspace(*p)) {
p++;
continue;
}
if (isdigit(*p)) {
if (sp >= stack + elemsof(stack)) {
printf("stack overflow\n");
break;
}
*sp++ = strtol(p, &p, 0);
continue;
}
Operator op = getop(*p++);
u32 arity = Operator_arity[op];
if (sp < stack + arity) {
printf("stack underflow\n");
break;
}
sp -= arity;
// this used to trigger an assert in c_generator.getFuncDecl();
sp += Operator_func[op](sp);
}
if (sp > stack) {
printf(" ->");
for (Num* np = stack; np < sp; np++) dispatch(output, np);
printf("\n");
}
}
printf("\n");
return 0;
}

Loading