The unified diff between revisions [9a6e8df1..] and [26704bfc..] 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 [26704bfc7dde9382e68dbefa013c51b37b934b1d]
#
# patch "src/lsc/codegen.c"
#  from [3f17dcc09e552288f4a68b0ac58692cffd524364]
#    to [f72bb89ce47000e8908b8539ab2df2c84fefb118]
#
============================================================
--- src/lsc/codegen.c	3f17dcc09e552288f4a68b0ac58692cffd524364
+++ src/lsc/codegen.c	f72bb89ce47000e8908b8539ab2df2c84fefb118
@@ -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;
@@ -545,6 +549,7 @@ void codegen(ast *node)
 	int hasdefault;
 	int i;
 	int savedlineno;
+	int ncallargs;
 
 	union {
 		int i;
@@ -612,9 +617,11 @@ void codegen(ast *node)
 				 * Arguments on the stack directly above
 				 * local variables, and then return address
 				 */
+				printf("(argument)\n");
 				emit_instr_imm_const(OP_LOAD,
 				    sp + 1 + nargs - var.addr, fnconst);
 			} else {
+				printf("(non-argument)\n");
 				emit_instr_imm_const(OP_LOAD, sp - var.addr - 1, fnconst);
 			}
 			sp++;
@@ -644,12 +651,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 +780,36 @@ void codegen(ast *node)
 
 //			printf("savedsp = %d\n", savedsp);
 
+			ncallargs = 0;
+
 			/* Evaluate the arguments first */
 			for (ptr =
 			    node->info.node.head->next->elem->info.node.head;
 			    ptr; ptr = ptr->next) {
 				codegen(ptr->elem);
+				ncallargs++;
 			}
 
 //			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, ncallargs);
+				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 +1172,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;