The unified diff between revisions [9a6e8df1..] and [697c3a55..] is displayed below. It can also be downloaded as a raw diff.
This diff has been restricted to the following files: 'src/lsc/codegen.c'
# # old_revision [9a6e8df1d6b102f467702e274d53d90f9151e2c8] # new_revision [697c3a55915ad7eda83ba73798ce0c4b8b2544ba] # # patch "src/lsc/codegen.c" # from [3f17dcc09e552288f4a68b0ac58692cffd524364] # to [400424bebce5876e321c5ffa9a3271c0993d48e9] # ============================================================ --- src/lsc/codegen.c 3f17dcc09e552288f4a68b0ac58692cffd524364 +++ src/lsc/codegen.c 400424bebce5876e321c5ffa9a3271c0993d48e9 @@ -33,7 +33,7 @@ struct label { char *name; }; -#define DEBUG 1 +#define DEBUG 0 #define MOREDEBUG 0 #define MAX_LABELS 4096 @@ -95,10 +95,14 @@ struct instr *instr_tail = NULL; #define VAR_ARG 1 #define VAR_REAL 2 +#define FN_TYPE_BASE 0xff + #define FN_INT 1 #define FN_STR 2 #define FN_LOCAL 3 +#define FN_VARARGS 0x100 + int fnconst; int nargs; int local_variable_count = -1; @@ -146,7 +150,7 @@ void output_functions_action(struct hash { int len, pad; - if (ptr->flags == FN_LOCAL) { + if ((ptr->flags & FN_TYPE_BASE) == FN_LOCAL) { len = strlen(ptr->name) + 1 + 16; pad = (4 - (len % 4)) % 4; output_int(len+pad); @@ -311,7 +315,7 @@ void create_function(char *fnname, int t compiler_error("Function already exists"); if (output_asm) { - switch (type) { + switch (type & FN_TYPE_BASE) { case FN_INT: printf("%%fnint %s %d\n", fnname, num); break; @@ -644,12 +648,14 @@ void codegen(ast *node) case node_ast: switch (node->info.node.tag) { case kind_fndefint: + case kind_fndefint_v: assert(sp == 0); assert(node->info.node.head != NULL); assert(node->info.node.head->next != NULL); create_function(node->info.node.head->elem->info.string, - FN_INT, + FN_INT | ((node->info.node.tag == + kind_fndefint_v) ? FN_VARARGS : 0), node->info.node.head->next->elem->info.integer); break; case kind_constant: @@ -771,20 +777,36 @@ void codegen(ast *node) // printf("savedsp = %d\n", savedsp); + nargs = 0; + /* Evaluate the arguments first */ for (ptr = node->info.node.head->next->elem->info.node.head; ptr; ptr = ptr->next) { codegen(ptr->elem); + nargs++; } // printf("sp = %d\n", sp); + if (!lookup_function(node->info.node.head->elem, &fn)) + compiler_error("Function not found"); + + if (fn.type & FN_VARARGS) { + /* + * The last argument is the number of + * arguments to expect in the case + * of variable argument length. + * This is something only supported for + * builtin functions at present. + */ + emit_instr_immediate(OP_PUSH, nargs); + sp++; + } + emit_instr_immediate(OP_ALLOC, 1); sp++; - if (!lookup_function(node->info.node.head->elem, &fn)) - compiler_error("Function not found"); switch (fn.type) { case FN_INT: emit_instr_immediate(OP_CALLNUM, fn.num); @@ -1147,8 +1169,12 @@ void codegen(ast *node) emit_instr_label(OP_B, breaklabel); break; case stmt_return: - assert(node->info.node.head == NULL); - + if (node->info.node.head) { + /* Return value */ + codegen(node->info.node.head->elem); + emit_instr_imm_const(OP_STORE, sp, fnconst); + sp--; + } emit_instr_imm_const(OP_POP, sp, fnconst); emit_simple_instr(OP_RET); break;