|
|
@ -95,10 +95,14 @@ struct instr *instr_tail = NULL; |
|
|
|
#define VAR_ARG 1 |
|
|
|
#define VAR_ARG 1 |
|
|
|
#define VAR_REAL 2 |
|
|
|
#define VAR_REAL 2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define FN_TYPE_BASE 0xff |
|
|
|
|
|
|
|
|
|
|
|
#define FN_INT 1 |
|
|
|
#define FN_INT 1 |
|
|
|
#define FN_STR 2 |
|
|
|
#define FN_STR 2 |
|
|
|
#define FN_LOCAL 3 |
|
|
|
#define FN_LOCAL 3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define FN_VARARGS 0x100 |
|
|
|
|
|
|
|
|
|
|
|
int fnconst; |
|
|
|
int fnconst; |
|
|
|
int nargs; |
|
|
|
int nargs; |
|
|
|
int local_variable_count = -1; |
|
|
|
int local_variable_count = -1; |
|
|
@ -146,7 +150,7 @@ void output_functions_action(struct hashentry *ptr) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int len, pad; |
|
|
|
int len, pad; |
|
|
|
|
|
|
|
|
|
|
|
if (ptr->flags == FN_LOCAL) { |
|
|
|
if ((ptr->flags & FN_TYPE_BASE) == FN_LOCAL) { |
|
|
|
len = strlen(ptr->name) + 1 + 16; |
|
|
|
len = strlen(ptr->name) + 1 + 16; |
|
|
|
pad = (4 - (len % 4)) % 4; |
|
|
|
pad = (4 - (len % 4)) % 4; |
|
|
|
output_int(len+pad); |
|
|
|
output_int(len+pad); |
|
|
@ -311,7 +315,7 @@ void create_function(char *fnname, int type, int num) |
|
|
|
compiler_error("Function already exists"); |
|
|
|
compiler_error("Function already exists"); |
|
|
|
|
|
|
|
|
|
|
|
if (output_asm) { |
|
|
|
if (output_asm) { |
|
|
|
switch (type) { |
|
|
|
switch (type & FN_TYPE_BASE) { |
|
|
|
case FN_INT: |
|
|
|
case FN_INT: |
|
|
|
printf("%%fnint %s %d\n", fnname, num); |
|
|
|
printf("%%fnint %s %d\n", fnname, num); |
|
|
|
break; |
|
|
|
break; |
|
|
@ -644,12 +648,14 @@ void codegen(ast *node) |
|
|
|
case node_ast: |
|
|
|
case node_ast: |
|
|
|
switch (node->info.node.tag) { |
|
|
|
switch (node->info.node.tag) { |
|
|
|
case kind_fndefint: |
|
|
|
case kind_fndefint: |
|
|
|
|
|
|
|
case kind_fndefint_v: |
|
|
|
assert(sp == 0); |
|
|
|
assert(sp == 0); |
|
|
|
assert(node->info.node.head != NULL); |
|
|
|
assert(node->info.node.head != NULL); |
|
|
|
assert(node->info.node.head->next != NULL); |
|
|
|
assert(node->info.node.head->next != NULL); |
|
|
|
|
|
|
|
|
|
|
|
create_function(node->info.node.head->elem->info.string, |
|
|
|
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); |
|
|
|
node->info.node.head->next->elem->info.integer); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case kind_constant: |
|
|
|
case kind_constant: |
|
|
@ -771,20 +777,36 @@ void codegen(ast *node) |
|
|
|
|
|
|
|
|
|
|
|
// printf("savedsp = %d\n", savedsp);
|
|
|
|
// printf("savedsp = %d\n", savedsp);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nargs = 0; |
|
|
|
|
|
|
|
|
|
|
|
/* Evaluate the arguments first */ |
|
|
|
/* Evaluate the arguments first */ |
|
|
|
for (ptr = |
|
|
|
for (ptr = |
|
|
|
node->info.node.head->next->elem->info.node.head; |
|
|
|
node->info.node.head->next->elem->info.node.head; |
|
|
|
ptr; ptr = ptr->next) { |
|
|
|
ptr; ptr = ptr->next) { |
|
|
|
codegen(ptr->elem); |
|
|
|
codegen(ptr->elem); |
|
|
|
|
|
|
|
nargs++; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// printf("sp = %d\n", sp);
|
|
|
|
// 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); |
|
|
|
emit_instr_immediate(OP_ALLOC, 1); |
|
|
|
sp++; |
|
|
|
sp++; |
|
|
|
|
|
|
|
|
|
|
|
if (!lookup_function(node->info.node.head->elem, &fn)) |
|
|
|
|
|
|
|
compiler_error("Function not found"); |
|
|
|
|
|
|
|
switch (fn.type) { |
|
|
|
switch (fn.type) { |
|
|
|
case FN_INT: |
|
|
|
case FN_INT: |
|
|
|
emit_instr_immediate(OP_CALLNUM, fn.num); |
|
|
|
emit_instr_immediate(OP_CALLNUM, fn.num); |
|
|
@ -1147,8 +1169,12 @@ void codegen(ast *node) |
|
|
|
emit_instr_label(OP_B, breaklabel); |
|
|
|
emit_instr_label(OP_B, breaklabel); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case stmt_return: |
|
|
|
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_instr_imm_const(OP_POP, sp, fnconst); |
|
|
|
emit_simple_instr(OP_RET); |
|
|
|
emit_simple_instr(OP_RET); |
|
|
|
break; |
|
|
|
break; |
|
|
|