The unified diff between revisions [58a3ccba..] and [a81fe555..] 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 [a81fe5550c21fa983b4e344e07c29b9cecdf75ea] # # patch "src/lsc/codegen.c" # from [0066fecf055581632eaebac395d4caacee9c44d2] # to [59287d90158eaceceb9a87f9fe6f6c45059c6cb6] # ============================================================ --- src/lsc/codegen.c 0066fecf055581632eaebac395d4caacee9c44d2 +++ src/lsc/codegen.c 59287d90158eaceceb9a87f9fe6f6c45059c6cb6 @@ -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" @@ -37,6 +38,7 @@ struct label { #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) {