diff --git a/examples/asm/elmer/include/cdrom.asm b/examples/asm/elmer/include/cdrom.asm index bf200477..49e706c6 100644 --- a/examples/asm/elmer/include/cdrom.asm +++ b/examples/asm/elmer/include/cdrom.asm @@ -1454,7 +1454,7 @@ cdr_cplay_next .proc ; Timeout, retry. - bra cdr_cplay_next + jmp cdr_cplay_next ; Not a BRA because a .proc! ; Process SCSI phases. diff --git a/examples/asm/elmer/include/ted2-fat32.asm b/examples/asm/elmer/include/ted2-fat32.asm index 63a909ed..81b79981 100644 --- a/examples/asm/elmer/include/ted2-fat32.asm +++ b/examples/asm/elmer/include/ted2-fat32.asm @@ -1391,7 +1391,7 @@ f32_seek_cur .proc sta <_ax + 0 bsr f32_next_frag ; Move forward to next fragment. - bra f32_seek_cur ; Try again. + jmp f32_seek_cur ; Try again. ; frag_len > seek_len diff --git a/include/hucc/hucc-codegen.asm b/include/hucc/hucc-codegen.asm index 23541659..1b7778a6 100644 --- a/include/hucc/hucc-codegen.asm +++ b/include/hucc/hucc-codegen.asm @@ -318,13 +318,18 @@ __call .macro ; ************** +__funcp.wr .macro + sta.l __func + sty.h __func + .endm + +; ************** + __callp .macro - sta.l __ptr - sty.h __ptr jsr call_indirect .endm -call_indirect: jmp [__ptr] +call_indirect: jmp [__func] @@ -342,8 +347,9 @@ __enter .macro ; ************** ; function epilog +; \1 == 0 if no return value -__leave .macro +__return .macro .if (\1 != 0) sta <__hucc_ret .endif diff --git a/include/hucc/hucc.asm b/include/hucc/hucc.asm index 51130eeb..280a3053 100644 --- a/include/hucc/hucc.asm +++ b/include/hucc/hucc.asm @@ -130,6 +130,10 @@ __ptr .ds 2 __poke = __si + ; Used for indirect calls because __ptr could be overwritten. + +__func = __si + ; Data pointer used by SDCC for indirect indexed memory access. DPTR = __ptr diff --git a/src/hucc/code.c b/src/hucc/code.c index fbb8a21d..bb3cc8be 100644 --- a/src/hucc/code.c +++ b/src/hucc/code.c @@ -412,6 +412,10 @@ void gen_code (INS *tmp) nl(); break; + case I_FUNCP_WR: + ol("__funcp.wr"); + break; + case I_CALLP: ol("__callp"); break; @@ -424,8 +428,8 @@ void gen_code (INS *tmp) nl(); break; - case I_LEAVE: - ot("__leave\t\t"); + case I_RETURN: + ot("__return\t\t"); outdec((int)data); nl(); break; diff --git a/src/hucc/const.c b/src/hucc/const.c index 07dc8dd5..c0f739bc 100644 --- a/src/hucc/const.c +++ b/src/hucc/const.c @@ -59,15 +59,11 @@ void add_const (char typ) * array initializer * */ -int array_initializer (char typ, char id, char stor) +int array_initializer (char typ, char id, char stor, int k) { - int nb; - int k; + int nb = 0; int i; - nb = 0; - k = needsub(); - if (stor == CONST) new_const(); if (match("=")) { diff --git a/src/hucc/const.h b/src/hucc/const.h index 63a29400..045de38a 100644 --- a/src/hucc/const.h +++ b/src/hucc/const.h @@ -8,7 +8,7 @@ void new_const (void); void add_const (char typ); -int array_initializer (char typ, char id, char stor); +int array_initializer (char typ, char id, char stor, int k); int scalar_initializer (char typ, char id, char stor); int get_string_ptr (char typ); int get_raw_value (char sep); diff --git a/src/hucc/defs.h b/src/hucc/defs.h index 76a8dbb4..78e099f3 100644 --- a/src/hucc/defs.h +++ b/src/hucc/defs.h @@ -38,12 +38,13 @@ enum ICODE { I_MACRO, I_CALL, + I_FUNCP_WR, I_CALLP, /* i-codes for C functions and the C parameter stack */ I_ENTER, - I_LEAVE, + I_RETURN, I_GETACC, I_SAVESP, I_LOADSP, @@ -421,15 +422,17 @@ enum ICOMPARE { typedef struct symbol { char name[NAMEALLOC]; /* symbol name */ struct symbol *linked; /* HuC: linked local and global symbols */ + int alloc_size; char identity; /* variable, array, pointer, function */ char sym_type; /* char, int, uchar, unit */ char storage; /* public, auto, extern, static, lstatic, defauto*/ char far; /* HuC: 1 if array of data in far memory */ + char ptr_order; /* HuC: 1 if array of data in far memory */ + char funcptr_type; /* HuC: return type if function pointer */ + char funcptr_order; /* HuC: return order if function pointer */ + char arg_count; /* HuC: #arguments for function or function pointer */ short offset; /* offset*/ short tagidx; /* index of struct in tag table*/ - short ptr_order; - short arg_count; - int alloc_size; } SYMBOL; /* Define the structure tag table parameters */ diff --git a/src/hucc/expr.c b/src/hucc/expr.c index 5d5cdeac..3b0b7696 100644 --- a/src/hucc/expr.c +++ b/src/hucc/expr.c @@ -196,7 +196,6 @@ int heir1 (LVALUE *lval, int comma) int heir1a (LVALUE *lval, int comma) { int k, lab1, lab2; - LVALUE lval2[1] = {{0}}; k = heir1b(lval, comma); blanks(); @@ -210,10 +209,10 @@ int heir1a (LVALUE *lval, int comma) FOREVER if (match("?")) { testjump(lab1 = getlabel(), FALSE); - if (heir1b(lval2, comma)) - rvalue(lval2); - if (lval2->val_type == CVOID) - void_value_error(lval2); + if (heir1b(lval, comma)) + rvalue(lval); + if (lval->val_type == CVOID) + void_value_error(lval); jump(lab2 = getlabel()); gnlabel(lab1); blanks(); @@ -221,10 +220,10 @@ int heir1a (LVALUE *lval, int comma) error("missing colon"); return (0); } - if (heir1b(lval2, comma)) - rvalue(lval2); - if (lval2->val_type == CVOID) - void_value_error(lval2); + if (heir1b(lval, comma)) + rvalue(lval); + if (lval->val_type == CVOID) + void_value_error(lval); gnlabel(lab2); } else @@ -779,19 +778,22 @@ int heir10 (LVALUE *lval, int comma) k = heir10(lval, comma); indflg = 0; ptr = lval->symbol; + if (ptr && ptr->funcptr_type && lval->ptr_order == 0) { + /* ignore optional dereference of a function pointer */ + return (k); + } if (k) rvalue(lval); if (lval->val_type == CVOID) void_value_error(lval); - if (lval->ptr_order < 2) - lval->indirect = lval->ptr_type; - else + if (lval->ptr_order > 1) { lval->indirect = CUINT; - /* XXX: what about multiple indirection? */ - if (lval->ptr_order > 1) lval->ptr_order--; - else { - lval->ptr_type = 0; /* flag as not pointer or array */ + } else { + if (lval->ptr_type == 0) + error("not a pointer"); + lval->indirect = lval->ptr_type; + lval->ptr_type = 0; /* flag as not pointer or array */ lval->ptr_order = 0; } return (1); @@ -805,7 +807,9 @@ int heir10 (LVALUE *lval, int comma) return (0); } if (k == 0) { - error("illegal address"); + /* allow "&function" in function pointer assignment */ + if (lval->symbol == NULL || lval->symbol->identity != FUNCTION) + error("illegal address"); return (0); } if (lval->symbol) { @@ -885,11 +889,11 @@ int heir11 (LVALUE *lval, int comma) if (lval->val_type == CVOID) void_value_error(lval); if (ptr == 0) { - if (lval->ptr_type) { - /* subscription of anonymous array - ATM this can only happen for a - string literal. */ - if (lval->ptr_type != CCHAR) + if (lval->ptr_type && lval->ptr_order == 1) { + /* subscription of anonymous array which is currently + only supported for a string literal, primarily for + the testsuite, such as "921218-1.c". */ + if (lval->ptr_type != ((user_signed_char) ? CCHAR : CUCHAR)) error("internal error: cannot subscript non-character literals"); /* Primary contains literal pointer, add subscript. */ gpush(); @@ -915,18 +919,18 @@ int heir11 (LVALUE *lval, int comma) return (0); } } - else if (ptr->identity == POINTER) - rvalue(lval); - else if (ptr->identity != ARRAY) { + else if (ptr->identity != POINTER && ptr->identity != ARRAY) { error("can't subscript"); k = 0; } + if (k) + rvalue(lval); if (!deferred && !ptr->far) gpush(); expression(YES); needbracket("]"); - if (ptr->sym_type == CINT || ptr->sym_type == CUINT || lval->ptr_order > 1 || - (ptr->identity == ARRAY && lval->ptr_order > 0)) + if (ptr->sym_type == CINT || ptr->sym_type == CUINT || + lval->ptr_order > ((ptr->identity == ARRAY) ? 0 : 1)) gaslint(); else if (ptr->sym_type == CSTRUCT) { int size = tag_table[ptr->tagidx].size; @@ -935,8 +939,6 @@ int heir11 (LVALUE *lval, int comma) else if (size > 1) gmult_imm(size); } - if (!deferred && !ptr->far) - gadd(NULL, NULL); if (deferred) { #if ULI_NORECURSE if ((ptr->storage & STORAGE) == AUTO && norecurse && glint(ptr) < 0) { @@ -956,29 +958,21 @@ int heir11 (LVALUE *lval, int comma) out_ins(I_ADD_WI, T_SYMBOL, (intptr_t)ptr); deferred = false; } - lval->symbol = 0; - if (lval->ptr_order > 1 || (ptr->identity == ARRAY && lval->ptr_order > 0)) - lval->indirect = CUINT; else - lval->indirect = ptr->sym_type; - if (lval->ptr_order > 1) + if (!ptr->far) + gadd(NULL, NULL); + if (lval->ptr_order > ((ptr->identity == ARRAY) ? 0 : 1)) { + lval->indirect = CUINT; lval->ptr_order--; + } else { + lval->indirect = lval->ptr_type; + lval->ptr_type = 0; + lval->ptr_order = 0; blanks(); - if (ptr->identity == ARRAY && ch() == '[') { - /* Back-to-back indexing: We loop - right inside this function, so - nobody else takes care of - actually loading the pointer. */ - rvalue(lval); - lval->indirect = ptr->sym_type; - lval->ptr_type = ptr->sym_type; - lval->ptr_order = 0; - } - else { -// lval->val_type = lval->ptr_type; - lval->ptr_type = 0; // VARIABLE; /* David, bug patch ?? */ - lval->ptr_order = 0; + if (ch() == '[') { + /* force an error in the next subscript attempt */ + lval->symbol = NULL; } } lval->symbol2 = ptr->far ? ptr : NULL; @@ -989,30 +983,44 @@ int heir11 (LVALUE *lval, int comma) void_value_error(lval); if (ptr == 0) { error("invalid or unsupported function call"); - callfunction(0); - } - else if (ptr->identity != FUNCTION) { - rvalue(lval); - callfunction(0); + junk(); + return (0); } else - callfunction(ptr->name); - k = 0; - /* Encode return type in lval. */ - SYMBOL *s = lval->symbol; - if (s) { - if (s->sym_type == 0) - error("function return type is unknown"); - if (s->ptr_order >= 1) { - lval->ptr_type = s->sym_type; - lval->ptr_order = s->ptr_order; + if (ptr->identity == FUNCTION) { + callfunction(ptr); + if (ptr->ptr_order) { + lval->val_type = 0; + lval->ptr_type = ptr->sym_type; + lval->ptr_order = ptr->ptr_order; + } else { + lval->val_type = ptr->sym_type; + lval->ptr_type = 0; + lval->ptr_order = 0; + } + if (ptr->sym_type == CSTRUCT) + lval->tagsym = &tag_table[ptr->tagidx]; + } + else { + if (ptr->funcptr_type == 0 || lval->ptr_order != 0) + error("not a function pointer"); + if (k) + rvalue(lval); + callfunction(ptr); + if (ptr->funcptr_order) { + lval->val_type = 0; + lval->ptr_type = ptr->funcptr_type; + lval->ptr_order = ptr->funcptr_order; } else { - lval->val_type = s->sym_type; + lval->val_type = ptr->funcptr_type; + lval->ptr_type = 0; + lval->ptr_order = 0; } - if (s->sym_type == CSTRUCT) - lval->tagsym = &tag_table[s->tagidx]; - lval->symbol = 0; + if (ptr->funcptr_type == CSTRUCT) + lval->tagsym = &tag_table[ptr->tagidx]; } + k = 0; + lval->symbol = 0; } else if ((direct = match(".")) || match("->")) { if (lval->val_type == CVOID) diff --git a/src/hucc/function.c b/src/hucc/function.c index 8d2b4cb9..8434cc90 100644 --- a/src/hucc/function.c +++ b/src/hucc/function.c @@ -405,7 +405,14 @@ void newfunc (const char *sname, int ret_ptr_order, int ret_type, int ret_otag, gtext(); gnlabel(fexitlab); modstk(nbarg * INTSIZE); - out_ins(I_LEAVE, T_VALUE, ret_type != CVOID || ret_ptr_order != 0); /* generate the return statement */ + if (ret_ptr_order == 0) { + if (ret_type == CCHAR) + out_ins(I_EXT_BR, 0, 0); + else + if (ret_type == CUCHAR) + out_ins(I_EXT_UR, 0, 0); + } + out_ins(I_RETURN, T_VALUE, ret_type != CVOID || ret_ptr_order != 0); /* generate the return statement */ flush_ins(); /* David, optimize.c related */ ol(".endp"); /* David, .endp directive support */ @@ -558,11 +565,9 @@ int getarg (int t, int syntax, int otag, int is_fastcall) out_ins(I_SPUSH_WR, 0, 0); \ } -void callfunction (char *ptr) +void callfunction (SYMBOL *ptr) { - extern char *new_string (int, char *); struct fastcall *fast = NULL; - SYMBOL *func = NULL; int is_fc = 0; int argcnt = 0; int argsiz = 0; @@ -587,30 +592,28 @@ void callfunction (char *ptr) /* check if it's a special function, * if yes handle it externaly */ - if (ptr) { - if (!strcmp(ptr, "bank")) { - do_asm_func(T_BANK); return; - } - else if (!strcmp(ptr, "vram")) { - do_asm_func(T_VRAM); return; - } - else if (!strcmp(ptr, "pal")) { - do_asm_func(T_PAL); return; - } + if (!strcmp(ptr->name, "bank")) { + do_asm_func(T_BANK); return; + } + else + if (!strcmp(ptr->name, "vram")) { + do_asm_func(T_VRAM); return; + } + else + if (!strcmp(ptr->name, "pal")) { + do_asm_func(T_PAL); return; } // flush_ins(); // ot("__calling\n"); - if (ptr == NULL) { - /* save indirect call function-ptr on the hardware-stack */ - out_ins(I_SPUSH_WR, 0, 0); - } else { + if (ptr->identity == FUNCTION) { /* fastcall check, but don't know how many parameters */ - if ((is_fc = fastcall_look(ptr, -1, NULL)) == 0) { - /* N.B. functions are not required to be pre-declared! */ - func = findglb(ptr); - } + is_fc = fastcall_look(ptr->name, -1, NULL); + } else { +// /* save indirect call function-ptr on the hardware-stack */ +// out_ins(I_SPUSH_WR, 0, 0); + out_ins(I_FUNCP_WR, 0, 0); } /* calling regular functions in fastcall arguments is OK */ @@ -667,7 +670,7 @@ void callfunction (char *ptr) /* fastcall func */ if (is_fc) { - is_fc = fastcall_look(ptr, argcnt, &fast); + is_fc = fastcall_look(ptr->name, argcnt, &fast); /* flush arg instruction stacks */ if (is_fc) { @@ -752,16 +755,19 @@ void callfunction (char *ptr) error("__fastcall function was declared with a different parameter count"); } } - - /* check for function usage with differing numbers of parameters */ - if (func) { - if (func->arg_count < 0) { + else + if (ptr->identity == FUNCTION || ptr->funcptr_type) { + /* check for function usage with differing numbers of parameters */ + if (ptr->arg_count < 0) { /* function was automatically declared in primary() */ - func->arg_count = argcnt; + ptr->arg_count = argcnt; } else - if (func->arg_count != argcnt) { - error("function was declared with a different parameter count"); + if (ptr->arg_count != argcnt) { + if (ptr->identity == FUNCTION) + error("function was declared with a different parameter count"); + else + error("function pointer was declared with a different parameter count"); } } @@ -803,11 +809,7 @@ void callfunction (char *ptr) out_ins(I_LD_WM, T_LITERAL, (intptr_t)"__temp"); } - if (ptr == NULL) { - /* restore indirect call function-ptr from the hardware-stack */ - out_ins(I_SPOP_WR, 0, 0); - out_ins(I_CALLP, 0, 0); - } else { + if (ptr->identity == FUNCTION) { if (fast && !(fast->flags & FASTCALL_XSAFE)) out_ins(I_SAVESP, 0, 0); if (fast && (fast->flags & (FASTCALL_NOP | FASTCALL_MACRO))) { @@ -815,18 +817,22 @@ void callfunction (char *ptr) // Only macro fastcalls get a name generated if (fast->flags & FASTCALL_MACRO) { if (is_fc) - gmacro(ptr, argcnt); + gmacro(ptr->name, argcnt); else - gmacro(ptr, 0); + gmacro(ptr->name, 0); } } // Else not a NOP or MACRO fastcall else if (is_fc) - gcall(ptr, argcnt); + gcall(ptr->name, argcnt); else - gcall(ptr, 0); + gcall(ptr->name, 0); if (fast && !(fast->flags & FASTCALL_XSAFE)) out_ins(I_LOADSP, 0, 0); + } else { +// /* restore indirect call function-ptr from the hardware-stack */ +// out_ins(I_SPOP_WR, 0, 0); + out_ins(I_CALLP, 0, 0); } // flush_ins(); @@ -845,8 +851,14 @@ void callfunction (char *ptr) /* load acc.l if this a standard func returning a value */ if (!is_fc) { - if (func == NULL || func->sym_type != CVOID || func->ptr_order != 0) + if (ptr->identity == FUNCTION) { + if (ptr->sym_type != CVOID || ptr->ptr_order != 0) out_ins(I_GETACC, 0, 0); + } + else { + if (ptr->funcptr_type != CVOID || ptr->funcptr_order != 0) + out_ins(I_GETACC, 0, 0); + } } } diff --git a/src/hucc/function.h b/src/hucc/function.h index b91ea3df..bfa440ad 100644 --- a/src/hucc/function.h +++ b/src/hucc/function.h @@ -8,7 +8,7 @@ void newfunc (const char *sname, int ret_ptr_order, int ret_type, int ret_otag, int is_fastcall); int getarg (int t, int syntax, int otag, int is_fastcall); -void callfunction (char *ptr); +void callfunction (SYMBOL *ptr); void arg_stack (int arg); void arg_push_ins (INS *ptr); void arg_flush (int arg, int adj); diff --git a/src/hucc/main.c b/src/hucc/main.c index eabf484b..cc89b31a 100644 --- a/src/hucc/main.c +++ b/src/hucc/main.c @@ -481,6 +481,8 @@ void usage (char *exename) fprintf(stderr, "-O[val] invoke optimization (level )\n"); fprintf(stderr, "-fno-recursive optimize assuming non-recursive code\n"); fprintf(stderr, "-fno-short-enums always use signed int for enums\n"); + fprintf(stderr, "-funsigned-char make \"char\" unsigned (the default)\n"); + fprintf(stderr, "-fsigned-char make \"char\" signed\n"); fprintf(stderr, "\nOutput options:\n"); fprintf(stderr, "-s/-S create asm output only (do not invoke assembler)\n"); fprintf(stderr, "\nLinker options:\n"); diff --git a/src/hucc/optimize.c b/src/hucc/optimize.c index b41946af..cbbbab73 100644 --- a/src/hucc/optimize.c +++ b/src/hucc/optimize.c @@ -73,12 +73,13 @@ unsigned char icode_flags[] = { /* I_MACRO */ 0, /* I_CALL */ 0, + /* I_FUNCP_WR */ 0, /* I_CALLP */ 0, // i-codes for C functions and the C parameter stack /* I_ENTER */ 0, - /* I_LEAVE */ 0, + /* I_RETURN */ 0, /* I_GETACC */ 0, /* I_SAVESP */ 0, /* I_LOADSP */ 0, diff --git a/src/hucc/primary.c b/src/hucc/primary.c index 79fdfd64..fae91cc7 100644 --- a/src/hucc/primary.c +++ b/src/hucc/primary.c @@ -307,8 +307,7 @@ int primary (LVALUE *lval, int comma, bool *deferred) getloc(ptr); lval->ptr_type = ptr->sym_type; lval->ptr_order = ptr->ptr_order; -// lval->ptr_type = 0; - if (ptr->sym_type == CSTRUCT && ptr->identity == VARIABLE) + if (ptr->identity == VARIABLE && ptr->sym_type == CSTRUCT) return (1); else return (0); @@ -349,9 +348,9 @@ int primary (LVALUE *lval, int comma, bool *deferred) // error ("can't access far array"); } } - lval->indirect = lval->ptr_type = ptr->sym_type; + lval->indirect = + lval->ptr_type = ptr->sym_type; lval->ptr_order = ptr->ptr_order; -// lval->ptr_type = 0; if (ptr->identity == VARIABLE && ptr->sym_type == CSTRUCT) return (1); else @@ -379,7 +378,7 @@ int primary (LVALUE *lval, int comma, bool *deferred) lval->indirect = 0; if (k == 2) { /* a string constant */ - lval->ptr_type = CCHAR; + lval->ptr_type = (user_signed_char) ? CCHAR : CUCHAR; lval->ptr_order = 1; #if 1 } else { diff --git a/src/hucc/struct.c b/src/hucc/struct.c index 234d83c8..9444c000 100644 --- a/src/hucc/struct.c +++ b/src/hucc/struct.c @@ -61,7 +61,7 @@ SYMBOL *find_member (TAG_SYMBOL *tag, char *sname) * @param storage * @return */ -void add_member (char *sname, char identity, char type, int offset, int storage_class, int otag, int ptr_order) +void add_member (char *sname, char identity, char type, int offset, int storage_class, int otag, int ptr_order, int funcptr_type, int funcptr_order, int arg_count) { char *buffer_ptr; SYMBOL *symbol; @@ -78,6 +78,10 @@ void add_member (char *sname, char identity, char type, int offset, int storage_ symbol->storage = storage_class; symbol->offset = offset; symbol->ptr_order = ptr_order; + symbol->funcptr_type = funcptr_type; + symbol->funcptr_order = funcptr_order; + symbol->arg_count = arg_count; + if (type == CSTRUCT) symbol->tagidx = otag; diff --git a/src/hucc/struct.h b/src/hucc/struct.h index e8e51dec..aeeae10b 100644 --- a/src/hucc/struct.h +++ b/src/hucc/struct.h @@ -1,3 +1,3 @@ int find_tag (char *sname); int define_struct (char *sname, int storage, int is_struct); -void add_member (char *sname, char identity, char type, int offset, int storage_class, int otag, int ptr_order); +void add_member (char *sname, char identity, char type, int offset, int storage_class, int otag, int ptr_order, int funcptr_type, int funcptr_order, int arg_count); diff --git a/src/hucc/sym.c b/src/hucc/sym.c index ad1fd8ee..4e2ae5c9 100644 --- a/src/hucc/sym.c +++ b/src/hucc/sym.c @@ -158,12 +158,20 @@ int declglb (char typ, char stor, TAG_SYMBOL *mtag, int otag, int is_struct) { int k, id; char sname[NAMESIZE]; + char typ_now; int ptr_order; + int funcptr_type; + int funcptr_order; + int arg_count; SYMBOL *s; for (;;) { for (;;) { + typ_now = typ; ptr_order = 0; + funcptr_type = 0; + funcptr_order = 0; + arg_count = -1; if (endst()) return (0); @@ -177,9 +185,38 @@ int declglb (char typ, char stor, TAG_SYMBOL *mtag, int otag, int is_struct) newfunc(NULL, ptr_order, typ, otag, 1); return (2); } + if (match("(")) { + if (typ == 0) { + error("syntax error, a function pointer must declare its return type"); + typ_now = CINT; + } + funcptr_type = typ_now; + funcptr_order = ptr_order; + typ_now = CUINT; + ptr_order = 0; + while (match("*")) { + id = POINTER; + ptr_order++; + } + if (ptr_order == 0) { + error("syntax error, expected function pointer declaration"); + return (1); + } + id = (--ptr_order) ? POINTER : VARIABLE; + +// if (ptr_order >= 2) { +// error("syntax error, no pointer to a function pointer in HuCC"); +// return (1); +// } + } + if (!symname(sname)) illname(); if (match("(")) { + if (funcptr_type) { + error("syntax error, expected function pointer declaration"); + return (1); + } newfunc(sname, ptr_order, typ, otag, 0); return (2); } @@ -189,17 +226,26 @@ int declglb (char typ, char stor, TAG_SYMBOL *mtag, int otag, int is_struct) } if (mtag && find_member(mtag, sname)) multidef(sname); + if (match("[")) { + k = needsub(); + + if (funcptr_type) { + arg_count = needarguments(); + if (arg_count < 0) { + error("syntax error, expected function pointer declaration"); + junk(); + return (1); + } + } if (stor == CONST) - k = array_initializer(typ, id, stor); - else - k = needsub(); + k = array_initializer(typ_now, id, stor, k); if (k == -1) return (1); - /* XXX: This doesn't really beint here, but I + /* XXX: This doesn't really belong here, but I can't think of a better place right now. */ - if (id == POINTER && (typ == CCHAR || typ == CUCHAR || typ == CVOID)) + if (id == POINTER && (typ_now == CCHAR || typ_now == CUCHAR || typ_now == CVOID)) k *= INTSIZE; if (k || (stor == EXTERN)) id = ARRAY; @@ -217,13 +263,22 @@ int declglb (char typ, char stor, TAG_SYMBOL *mtag, int otag, int is_struct) } } else { + if (funcptr_type) { + arg_count = needarguments(); + if (arg_count < 0) { + error("syntax error, expected function pointer declaration"); + junk(); + return (1); + } + } if (stor == CONST) { /* stor = PUBLIC; XXX: What is this for? */ - scalar_initializer(typ, id, stor); + scalar_initializer(typ_now, id, stor); } } + if (mtag == 0) { - if (typ == CSTRUCT) { + if (typ_now == CSTRUCT) { if (id == VARIABLE) k = tag_table[otag].size; else if (id == POINTER) @@ -232,34 +287,40 @@ int declglb (char typ, char stor, TAG_SYMBOL *mtag, int otag, int is_struct) k *= tag_table[otag].size; } if (stor != CONST) { - id = initials(sname, typ, id, k, otag); - SYMBOL *c = addglb(sname, id, typ, k, stor, s); - if (typ == CSTRUCT) + id = initials(sname, typ_now, id, k, otag); + SYMBOL *c = addglb(sname, id, typ_now, k, stor, s); + if (typ_now == CSTRUCT) c->tagidx = otag; c->ptr_order = ptr_order; + c->funcptr_type = funcptr_type; + c->funcptr_order = funcptr_order; + c->arg_count = arg_count; } else { - SYMBOL *c = addglb(sname, id, typ, k, CONST, s); + SYMBOL *c = addglb(sname, id, typ_now, k, CONST, s); if (c) { - add_const(typ); - if (typ == CSTRUCT) + add_const(typ_now); + if (typ_now == CSTRUCT) c->tagidx = otag; } c->ptr_order = ptr_order; + c->funcptr_type = funcptr_type; + c->funcptr_order = funcptr_order; + c->arg_count = arg_count; } } else if (is_struct) { - add_member(sname, id, typ, mtag->size, stor, otag, ptr_order); + add_member(sname, id, typ_now, mtag->size, stor, otag, ptr_order, funcptr_type, funcptr_order, arg_count); if (id == POINTER) - typ = CUINT; - scale_const(typ, otag, &k); + typ_now = CUINT; + scale_const(typ_now, otag, &k); mtag->size += k; } else { - add_member(sname, id, typ, 0, stor, otag, ptr_order); + add_member(sname, id, typ_now, 0, stor, otag, ptr_order, funcptr_type, funcptr_order, arg_count); if (id == POINTER) - typ = CUINT; - scale_const(typ, otag, &k); + typ_now = CUINT; + scale_const(typ_now, otag, &k); if (mtag->size < k) mtag->size = k; } @@ -498,6 +559,38 @@ int needsub (void) return (num[0]); } +/* + * get definition of function pointer arguments + */ +int needarguments (void) +{ + struct type_type t; + int arg_count = 0; + + if (!match(")")) + return (-1); + if (!match("(")) + return (-1); + if (match(")")) + return (0); + + do { + if (!match_type(&t, YES, NO)) + return (-1); + if (t.type_type == CVOID && t.ptr_order == 0) { + if (arg_count > 0) + return (-1); + break; + } + ++arg_count; + } while (match(",")); + + if (!match(")")) + return (-1); + + return arg_count; +} + SYMBOL *findglb (char *sname) { SYMBOL *ptr; @@ -538,7 +631,8 @@ SYMBOL *addglb (char *sname, char id, char typ, int value, char stor, SYMBOL *re /* the compiler can't recover from this */ /* and will write to NULL* if we return */ errcnt = 0; - error("too many global symbols, aborting"); + error("too many global C symbols, aborting"); + error("fix SYMTBSZ and NUMGLBS then rebuild the compiler"); exit(1); } cptr = symtab + glbsym_index; @@ -546,9 +640,11 @@ SYMBOL *addglb (char *sname, char id, char typ, int value, char stor, SYMBOL *re } else cptr = replace; + memset(cptr, 0, sizeof(SYMBOL)); ptr = cptr->name; while (alphanum(*ptr++ = *sname++)) ; + cptr->identity = id; cptr->sym_type = typ; cptr->storage = stor; @@ -557,6 +653,9 @@ SYMBOL *addglb (char *sname, char id, char typ, int value, char stor, SYMBOL *re cptr->far = 0; cptr->linked = NULL; cptr->arg_count = -1; + cptr->ptr_order = 0; + cptr->funcptr_order = 0; + if (id == FUNCTION) cptr->alloc_size = 0; else if (id == POINTER) @@ -586,18 +685,26 @@ SYMBOL *addloc (char *sname, char id, char typ, int value, char stclass, int siz return (cptr); if (locsym_index >= ENDLOC) { - error("local symbol table overflow"); - return (NULL); + /* the compiler can't recover from this */ + /* and will write to NULL* if we return */ + errcnt = 0; + error("too many local C symbols, aborting"); + error("fix SYMTBSZ and NUMGLBS then rebuild the compiler"); + exit(1); } cptr = symtab + locsym_index; + memset(cptr, 0, sizeof(SYMBOL)); + ptr = symtab[locsym_index].name; while (alphanum(*ptr++ = *sname++)) ; + cptr->identity = id; cptr->sym_type = typ; cptr->storage = stclass; cptr->offset = value; cptr->alloc_size = size; cptr->linked = NULL; + cptr->arg_count = -1; locsym_index++; return (cptr); } diff --git a/src/hucc/sym.h b/src/hucc/sym.h index 9ec78269..ff4ab66c 100644 --- a/src/hucc/sym.h +++ b/src/hucc/sym.h @@ -4,6 +4,7 @@ int declglb (char typ, char stor, TAG_SYMBOL *mtag, int otag, int is_struct); void declloc (char typ, char stclass, int otag); int needsub (void); +int needarguments (void); SYMBOL *findglb (char *sname); SYMBOL *findloc (char *sname); SYMBOL *addglb (char *sname, char id, char typ, int value, char stor, SYMBOL *replace); diff --git a/src/mkit/as/expr.c b/src/mkit/as/expr.c index 0b3b6431..33320f25 100644 --- a/src/mkit/as/expr.c +++ b/src/mkit/as/expr.c @@ -716,9 +716,22 @@ push_val(int type) undef++; } else { - expr_overlay = expr_lablptr->overlay; - expr_mprbank = expr_lablptr->mprbank; - val = expr_lablptr->value; + /* resolve newproc procedure labels to their thunk location in the last pass */ + struct t_proc *proc; + + if ((pass == LAST_PASS) && (newproc_opt != 0) && + ((proc = expr_lablptr->proc) != NULL) && (proc->label == expr_lablptr)) { + if (!proc->call) + add_thunk(proc); + expr_overlay = 0; + expr_mprbank = bank2mprbank(call_bank, S_CODE); + val = proc->call; + } else { + expr_overlay = expr_lablptr->overlay; + expr_mprbank = expr_lablptr->mprbank; + val = expr_lablptr->value; + } + if (expr_lablptr->defthispass == 0) { notyetdef++; } diff --git a/src/mkit/as/proc.c b/src/mkit/as/proc.c index abe8e210..e56be7c6 100644 --- a/src/mkit/as/proc.c +++ b/src/mkit/as/proc.c @@ -40,6 +40,83 @@ void poke(int addr, int data); void proc_sortlist(void); +/* ---- + * add_thunk() + * ---- + * add a procedure thunk + */ + +void +add_thunk(struct t_proc *proc) +{ + if (!proc->call) { + /* init */ + if (call_bank > max_bank) { + /* don't increase ROM size until we need a thunk */ + if (call_bank > bank_limit) { + fatal_error("There is no target memory left to allocate a bank for .PROC thunks!"); + if (asm_opt[OPT_OPTIMIZE] == 0) { + fprintf(ERROUT, "Optimized procedure packing is currently disabled, use \"-O\" to enable.\n\n"); + } + return; + } + max_bank = call_bank; + } + + /* new call */ + if (newproc_opt == 0) { + /* check that the new thunk won't overrun the bank */ + if (((call_ptr + 17) & 0xE000) != (call_1st & 0xE000)) { + error("The .PROC thunk bank is full, there are too many procedures!"); + return; + } + + /* install HuC thunks at start of MPR4, map code into MPR5 */ + proc->call = call_ptr; + + poke(call_ptr++, 0xA8); // tay + poke(call_ptr++, 0x43); // tma #5 + poke(call_ptr++, 0x20); + poke(call_ptr++, 0x48); // pha + poke(call_ptr++, 0xA9); // lda #... + poke(call_ptr++, proc->label->mprbank); + poke(call_ptr++, 0x53); // tam #5 + poke(call_ptr++, 0x20); + poke(call_ptr++, 0x98); // tya + poke(call_ptr++, 0x20); // jsr ... + poke(call_ptr++, (proc->org + 0xA000) & 255); + poke(call_ptr++, (proc->org + 0xA000) >> 8); + poke(call_ptr++, 0xA8); // tay + poke(call_ptr++, 0x68); // pla + poke(call_ptr++, 0x53); // tam #5 + poke(call_ptr++, 0x20); + poke(call_ptr++, 0x98); // tya + poke(call_ptr++, 0x60); // rts + } else { + /* check that the new thunk won't overrun the bank */ + if (((call_ptr - 9) & 0xE000) != (call_1st & 0xE000)) { + error("The .PROC thunk bank is full, there are too many procedures!"); + return; + } + + /* install new thunks at end of MPR7, map code into MPR6 */ + poke(call_ptr--, (proc->org + 0xC000) >> 8); + poke(call_ptr--, (proc->org + 0xC000) & 255); + poke(call_ptr--, 0x4C); // jmp ... + poke(call_ptr--, 0x40); + poke(call_ptr--, 0x53); // tam #6 + poke(call_ptr--, proc->label->mprbank); + poke(call_ptr--, 0xA9); // lda #... + poke(call_ptr--, 0x48); // pha + poke(call_ptr--, 0x40); + poke(call_ptr--, 0x43); // tma #6 + + proc->call = call_ptr + 1; + } + } +} + + /* ---- * do_call() * ---- @@ -75,75 +152,9 @@ do_call(int *ip) value = proc->org + 0xA000; } else { /* different bank */ - if (proc->call) { - value = proc->call; - } else { - /* init */ - if (call_bank > max_bank) { - /* don't increase ROM size until we need a thunk */ - if (call_bank > bank_limit) { - fatal_error("There is no target memory left to allocate a bank for .PROC thunks!"); - if (asm_opt[OPT_OPTIMIZE] == 0) { - fprintf(ERROUT, "Optimized procedure packing is currently disabled, use \"-O\" to enable.\n\n"); - } - return; - } - max_bank = call_bank; - } - - /* new call */ - if (newproc_opt == 0) { - /* check that the new thunk won't overrun the bank */ - if (((call_ptr + 17) & 0xE000) != (call_1st & 0xE000)) { - error("The .PROC thunk bank is full, there are too many procedures!"); - return; - } - - /* install HuC thunks at start of MPR4, map code into MPR5 */ - value = call_ptr; - - poke(call_ptr++, 0xA8); // tay - poke(call_ptr++, 0x43); // tma #5 - poke(call_ptr++, 0x20); - poke(call_ptr++, 0x48); // pha - poke(call_ptr++, 0xA9); // lda #... - poke(call_ptr++, proc->label->mprbank); - poke(call_ptr++, 0x53); // tam #5 - poke(call_ptr++, 0x20); - poke(call_ptr++, 0x98); // tya - poke(call_ptr++, 0x20); // jsr ... - poke(call_ptr++, (proc->org + 0xA000) & 255); - poke(call_ptr++, (proc->org + 0xA000) >> 8); - poke(call_ptr++, 0xA8); // tay - poke(call_ptr++, 0x68); // pla - poke(call_ptr++, 0x53); // tam #5 - poke(call_ptr++, 0x20); - poke(call_ptr++, 0x98); // tya - poke(call_ptr++, 0x60); // rts - } else { - /* check that the new thunk won't overrun the bank */ - if (((call_ptr - 9) & 0xE000) != (call_1st & 0xE000)) { - error("The .PROC thunk bank is full, there are too many procedures!"); - return; - } - - /* install new thunks at end of MPR7, map code into MPR6 */ - poke(call_ptr--, (proc->org + 0xC000) >> 8); - poke(call_ptr--, (proc->org + 0xC000) & 255); - poke(call_ptr--, 0x4C); // jmp ... - poke(call_ptr--, 0x40); - poke(call_ptr--, 0x53); // tam #6 - poke(call_ptr--, proc->label->mprbank); - poke(call_ptr--, 0xA9); // lda #... - poke(call_ptr--, 0x48); // pha - poke(call_ptr--, 0x40); - poke(call_ptr--, 0x43); // tma #6 - - value = call_ptr + 1; - } - - proc->call = value; - } + if (!proc->call) + add_thunk(proc); + value = proc->call; /* special handling for a jmp between procedures */ if ((newproc_opt != 0) && (optype == 1)) { diff --git a/src/mkit/as/protos.h b/src/mkit/as/protos.h index 2c4f1625..88c20306 100644 --- a/src/mkit/as/protos.h +++ b/src/mkit/as/protos.h @@ -150,6 +150,7 @@ int png_load(char *name); int bmp_load(char *name); /* PROC.C */ +void add_thunk(struct t_proc *proc); void do_call(int *ip); void do_leave(int *ip); void do_proc(int *ip); diff --git a/test/tests/huc-funcptr.c b/test/tests/huc-funcptr.c new file mode 100644 index 00000000..e9edecfd --- /dev/null +++ b/test/tests/huc-funcptr.c @@ -0,0 +1,190 @@ +#ifdef __HUCC__ + +unsigned char func1(int a, unsigned char b) +{ + return (a + b); +} + +unsigned char func2(int a, unsigned char b) +{ + return (a - b); +} + +unsigned char func3(int a, unsigned char b) +{ + return (a * b); +} + +unsigned char func4(int a, unsigned char b) +{ + return (a / b); +} + +unsigned char c; +unsigned char d; + +unsigned char *func5(int a, unsigned char b) +{ + c = (a + b); + return &c; +} + +unsigned char (*p)(int, unsigned char); +unsigned char (**pp)(int, unsigned char); +unsigned char (***ppp)(int, unsigned char); + +const unsigned char (*k)(int, unsigned char) = &func1; + +const unsigned char (*fa[])(int, int) = { &func1, &func2 }; +const unsigned char (*fb[])(int, int) = { &func3, &func4 }; +const unsigned char (**pf[])(int, int) = { &fa, &fb }; + +unsigned char *(*q)(int, unsigned char); +unsigned char *(**pq)(int, unsigned char); + +int main() +{ + p = func2; + q = &func5; + c = 0; + d = 1; + + if (k(3,4) != 7) + abort(); + + if (p(4,3) != 1) + abort(); + if ((*p)(4,3) != 1) + abort(); + + if ((*q)(5,6) != &c) + abort(); + if (*(*q)(5,6) != 11) + abort(); + + c = 0; + + if (fa[0](1,2) != 3) + abort(); + if (fa[c](3,4) != 7) + abort(); + + c = 1; + + if ((fa[1])(7,5) != 2) + abort(); + if ((fa[c])(5,4) != 1) + abort(); + + c = 1; + + if ((*fa[1])(7,5) != 2) + abort(); + if ((*fa[c])(5,4) != 1) + abort(); + + c = 0; + p = fa[c]; + + if (p(1,2) != 3) + abort(); + + pp = &fa[1]; + + if ((**pp)(8,4) != 4) + abort(); + + c = 1; + pp = &fb[c]; + + if ((**pp)(8,4) != 2) + abort(); + + pp = fb; + + if (pp[1](8,2) != 4) + abort(); + if ((pp[1])(8,4) != 2) + abort(); + if ((*pp[1])(6,2) != 3) + abort(); + + c = 0; + + if (pf[c][d](6,2) != 4) + abort(); + if ((pf[c][d])(6,2) != 4) + abort(); + if ((*pf[c][d])(6,2) != 4) + abort(); + + if (pf[c][1](6,2) != 4) + abort(); + if ((pf[c][1])(6,2) != 4) + abort(); + if ((*pf[c][1])(6,2) != 4) + abort(); + + if (pf[1][d](6,2) != 3) + abort(); + if ((pf[1][d])(6,2) != 3) + abort(); + if ((*pf[1][d])(6,2) != 3) + abort(); + + if (pf[1][1](6,2) != 3) + abort(); + if ((pf[1][1])(6,2) != 3) + abort(); + if ((*pf[1][1])(6,2) != 3) + abort(); + + c = 1; + ppp = pf; + + if ((**ppp)(8,4) != 12) + abort(); + + if ((***ppp)(8,4) != 12) + abort(); + + if (ppp[c][d](8,2) != 4) + abort(); + if ((ppp[c][d])(8,4) != 2) + abort(); + if ((*ppp[c][d])(6,2) != 3) + abort(); + + if (ppp[c][1](8,2) != 4) + abort(); + if ((ppp[c][1])(8,4) != 2) + abort(); + if ((*ppp[c][1])(6,2) != 3) + abort(); + + if (ppp[1][d](8,2) != 4) + abort(); + if ((ppp[1][d])(8,4) != 2) + abort(); + if ((*ppp[1][d])(6,2) != 3) + abort(); + + if (ppp[1][1](8,2) != 4) + abort(); + if ((ppp[1][1])(8,4) != 2) + abort(); + if ((*ppp[1][1])(6,2) != 3) + abort(); + + return 0; +} + +#else + +/* HuC does not support function pointers */ +int main() +{ + return 0; +} + +#endif