The unified diff between revisions [58a3ccba..] and [1c51f984..] 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 [58a3ccba47e51398ea76582c5b4a94bf8af04187]
# new_revision [1c51f9845a06bd04df9a862c18893be750860d82]
#
# patch "src/lsc/codegen.c"
#  from [0066fecf055581632eaebac395d4caacee9c44d2]
#    to [400424bebce5876e321c5ffa9a3271c0993d48e9]
#
============================================================
--- src/lsc/codegen.c	0066fecf055581632eaebac395d4caacee9c44d2
+++ src/lsc/codegen.c	400424bebce5876e321c5ffa9a3271c0993d48e9
@@ -6,6 +6,7 @@
 #include <assert.h>
 #include <err.h>
 #include <limits.h>
+#include <stdarg.h>
 #include "types.h"
 #include "ast.h"
 #include "codegen.h"
@@ -32,11 +33,12 @@ struct label {
 	char *name;
 };
 
-#define DEBUG 1
+#define DEBUG 0
 #define MOREDEBUG 0
 
 #define MAX_LABELS 4096
 #define MAX_CONSTS 4096
+#define ERROR_MAXLEN 1024
 
 struct label *labels = NULL;
 int nlabels = 0;
@@ -93,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;
@@ -104,6 +110,8 @@ int constant_count = -1;
 int function_count = -1;
 int constant_count = -1;
 
+int lineno;
+
 #define HASHSIZE 512
 #define HASHMASK (HASHSIZE - 1)
 
@@ -111,9 +119,16 @@ struct hashentry *constanthash[HASHSIZE]
 struct hashentry *fnhash[HASHSIZE];
 struct hashentry *constanthash[HASHSIZE];
 
-void compiler_error(char *str)
+void compiler_error(char *str, ...)
 {
-	errx(1, str);
+	char buf[ERROR_MAXLEN];
+	va_list args;
+
+	snprintf(buf, ERROR_MAXLEN, "%d: %s", lineno, str);
+
+	va_start(args, str);
+	verrx(1, buf, args);
+	va_end(args); /* Not really necessary if errx exits */
 }
 
 int count_local_variables(void)
@@ -135,12 +150,12 @@ 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);
 		output_int(0);	/* type */
-		output_int(get_label(ptr->value) + 8);
+		output_int(get_label(ptr->value) + 28);
 		output_int(0);	/* nargs */
 		output_string(ptr->name);
 		output_byte(0);	/* terminator */
@@ -267,9 +282,11 @@ int lookup_function(ast *node, struct fn
 	return 1;
 }
 
-int lookup_constant(ast *node, int *constant)
+#define lookup_constant(node, constant) \
+	lookup_constant_string(node->info.string, constant)
+
+int lookup_constant_string(char *constantname, int *constant)
 {
-	char *constantname = node->info.string;
 	struct hashentry *hashptr;
 
 	if (constant_count < 0)
@@ -298,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;
@@ -531,12 +548,16 @@ void codegen(ast *node)
 	int stackfixlabel;
 	int hasdefault;
 	int i;
+	int savedlineno;
 
 	union {
 		int i;
 		float f;
 	} conv;
 
+	savedlineno = lineno;
+
+	lineno = node->lineno;
 #if DEBUG
 	printf("entering codegen with node %p, sp = %d, tag = %d\n", node, sp, node->tag);
 	if (node->tag == node_ast)
@@ -580,9 +601,8 @@ void codegen(ast *node)
 				real = (*node->info.string == '%');
 				break;
 			}
-			printf("error: variable '%s' used before assignment\n",
+			compiler_error("variable '%s' used before assignment",
 			    var.name);
-			exit(EXIT_FAILURE);
 		}
 //		printf("sp = %d\n", sp);
 		if (var.flags & VAR_REAL)
@@ -628,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:
@@ -755,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);
@@ -1131,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;
@@ -1185,6 +1227,7 @@ void output_code(void)
 	int morepasses = 1;
 	int passno = 0;
 	int pc;
+	int abiver;
 
 	while (morepasses) {
 		ptr = instr_head;
@@ -1259,10 +1302,24 @@ void output_code(void)
 	output_byte(VERSION1);
 	output_byte(VERSION2);
 
+#define ABIVERSION(x) do {					\
+		abiver = 0;					\
+		if (!lookup_constant_string(x, &abiver))	\
+			printf("%s not defined\n", x);		\
+		output_int(abiver);				\
+		printf("ABIVERSION(%s) = %x\n", x, abiver);				\
+	} while (0)
+
 	pc = (pc + 3) & ~3;	/* Align table */
 
-	output_int(pc+8);	/* Pointer to function table */
+	output_int(pc+28);	/* Pointer to function table */
 
+	ABIVERSION("__abiversion1");
+	ABIVERSION("__abiversion2");
+	ABIVERSION("__abiversion3");
+	ABIVERSION("__abiversion4");
+	ABIVERSION("__abiversion5");
+
 	ptr = instr_head;
 	pc = 0;
 	while (ptr) {