From e5e2c1fa3d0960959c7d894fc6bb492d8dd78429 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 20 Aug 2014 00:00:24 -0700 Subject: [PATCH] Simplify functag handling. --- sourcepawn/compiler/sc.h | 7 +- sourcepawn/compiler/sc1.c | 8 +- sourcepawn/compiler/sc3.c | 250 ++++++++++++-------------------- sourcepawn/compiler/sctracker.c | 70 ++++++++- sourcepawn/compiler/sctracker.h | 12 +- 5 files changed, 176 insertions(+), 171 deletions(-) diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index bc3235fd..9741b46e 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -964,9 +964,10 @@ SC_VDECL jmp_buf errbuf; /* target of longjmp() on a fatal error */ #endif #if defined WIN32 -#if !defined snprintf -#define snprintf _snprintf -#endif +# if !defined snprintf +# define snprintf _snprintf +# define vsnprintf _vsnprintf +# endif #endif #endif /* SC_SKIP_VDECL */ diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 154e33c4..94f6e2d0 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -705,7 +705,7 @@ int pc_addtag_flags(char *name, int flags) constvalue *ptr; int last,tag; - assert(strchr(name,':')==NULL); /* colon should already have been stripped */ + assert((flags & FUNCTAG) || strchr(name,':')==NULL); /* colon should already have been stripped */ last=0; ptr=tagname_tab.next; while (ptr!=NULL) { @@ -4201,7 +4201,7 @@ static void parse_function_type(functag_t *type) needtoken(tFUNCTION); type->ret_tag = parse_new_typename(NULL); - type->type = uPUBLIC; + type->usage = uPUBLIC; needtoken('('); @@ -4367,13 +4367,13 @@ static void dofuncenum(int listmode) * rather than the constant value. And even if we could, we'd have to change the assembler recognize that. */ if (l == tPUBLIC) { - func.type = uPUBLIC; + func.usage = uPUBLIC; } else { error(1, "-public-", str); } } else { func.ret_tag = newStyleTag; - func.type = uPUBLIC; + func.usage = uPUBLIC; } needtoken('('); do { diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index 14282351..ff509bb3 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -413,15 +413,82 @@ static int matchobjecttags(int formaltag, int actualtag, int flags) return obj_typeerror(133, formaltag, actualtag); } -static int matchreturntag(functag_t *t, symbol *sym) +static int matchreturntag(const functag_t *formal, const functag_t *actual) { - if (t->ret_tag == sym->tag) - return TRUE; - if (t->ret_tag == pc_tag_void && (sym->tag == 0 && !(sym->usage & uRETVALUE))) + if (formal->ret_tag == actual->ret_tag) return TRUE; + if (formal->ret_tag == pc_tag_void) { + if (actual->ret_tag == 0 && !(actual->usage & uRETVALUE)) + return TRUE; + } return FALSE; } +static int funcarg_compare(const funcarg_t *formal, const funcarg_t *actual) +{ + // Check type. + if (actual->ident != formal->ident) + return FALSE; + + // Check rank. + if (actual->dimcount != formal->dimcount) + return FALSE; + + // Check arity. + for (int i = 0; i < formal->dimcount; i++) { + if (actual->dims[i] != formal->dims[i]) + return FALSE; + } + + // Check tags. + if (actual->tagcount != formal->tagcount) + return FALSE; + for (int i = 0; i < formal->tagcount; i++) { + // Note we invert the order we pass things to matchtag() here. If the + // typedef specifies base type X, and the function specifies derived + // type Y, we want this to type since such an assignment is valid. + // + // Most programming languages do not subtype arguments like this. We do + // it in SourcePawn to preserve compatibility during the Transitional + // Syntax effort. + int actual_tag = actual->tags[i]; + int formal_tag = formal->tags[i]; + if (!matchtag(actual_tag, formal_tag, MATCHTAG_SILENT|MATCHTAG_COERCE)) + return FALSE; + } + + return TRUE; +} + +static int functag_compare(const functag_t *formal, const functag_t *actual) +{ + // Check return types. + if (!matchreturntag(formal, actual)) + return FALSE; + + // Make sure there are no trailing arguments. + if (actual->argcount > formal->argcount) + return FALSE; + + // Check arguments. + for (int i = 0; i < formal->argcount; i++) { + const funcarg_t *formal_arg = &formal->args[i]; + + if (i >= actual->argcount) { + if (formal_arg->ommittable) + return TRUE; + return FALSE; + } + + const funcarg_t *actual_arg = &actual->args[i]; + + if (!funcarg_compare(formal_arg, actual_arg)) + return FALSE; + } + + return TRUE; +} + static int matchfunctags(int formaltag, int actualtag) { if (formaltag == pc_functag && (actualtag & FUNCTAG)) @@ -433,135 +500,17 @@ static int matchfunctags(int formaltag, int actualtag) if (!(actualtag & FUNCTAG)) return FALSE; - constvalue *v = find_tag_byval(actualtag); - int index; - short usage = uPUBLIC; - symbol *sym, *found = NULL; - funcenum_t *e; - functag_t *t; - - if (strncmp(v->name, "$Func", 5) != 0) + functag_t *actual = functag_find_intrinsic(actualtag); + if (!actual) return FALSE; - /* Now we have to go about looking up each function in this enum. WHICH IS IT. */ - e = funcenums_find_byval(formaltag); + funcenum_t *e = funcenums_find_by_tag(formaltag); if (!e) return FALSE; - assert(v->name[5] == '@' || v->name[5] == '!'); - - /* Deduce which function type this is */ - if (v->name[5] == '@') - { - usage = uPUBLIC; - } else if (v->name[5] == '!') { - usage = uSTOCK; - } - - index = atoi(&v->name[6]); - - assert(index >= 0); - - /* Find the function, either by public idx or code addr */ - if (usage == uPUBLIC) { - for (sym=glbtab.next; sym!=NULL; sym=sym->next) { - if (sym->ident==iFUNCTN && (sym->usage & uPUBLIC)!=0 && (sym->vclass == sGLOBAL)) { - if (index-- == 0) { - found = sym; - break; - } - } - } - } else if (usage == uSTOCK) { - for (sym=glbtab.next; sym!=NULL; sym=sym->next) { - if (sym->ident==iFUNCTN && (sym->vclass == sGLOBAL)) { - if (sym->codeaddr == index) { - found = sym; - break; - } - } - } - } - - if (!found) { - assert(found); - return FALSE; - } - - /* Wow, we now have: - * 1) The functional enum deduced from formaltag - * 2) The function trying to be shoved in deduced from actualtag - * Now we have to check if it matches any one of the functags inside the enum. - */ - t = e->first; - while (t) { - int curarg,skip=0,i; - arginfo *func_arg; - funcarg_t *enum_arg; - /* Check return type first. */ - if (!matchreturntag(t, sym)) { - t = t->next; - continue; - } - /* Check usage */ - if (t->type != usage) { - t = t->next; - continue; - } - /* Begin iterating arguments */ - for (curarg=0; curargargcount; curarg++) { - enum_arg = &t->args[curarg]; - /* Check whether we've exhausted our arguments */ - if (sym->dim.arglist[curarg].ident == 0) { - /* Can we bail out early? */ - if (!enum_arg->ommittable) { - /* No! */ - skip = 1; - } - break; - } - func_arg = &sym->dim.arglist[curarg]; - /* First check the ident type */ - if (enum_arg->ident != func_arg->ident) { - skip = 1; - break; - } - /* Next check arrayness */ - if (enum_arg->dimcount != func_arg->numdim) { - skip = 1; - break; - } - if (enum_arg->dimcount > 0) { - for (i=0; idimcount; i++) { - if (enum_arg->dims[i] != func_arg->dim[i]) { - skip = 1; - break; - } - } - if (skip) - break; - } - /* Lastly, check the tags */ - if (enum_arg->tagcount != func_arg->numtags) { - skip = 1; - break; - } - /* They should all be in the same order just for clarity... */ - for (i=0; itagcount; i++) { - if (!matchtag(func_arg->tags[i], enum_arg->tags[i], MATCHTAG_SILENT|MATCHTAG_COERCE)) { - skip = 1; - break; - } - } - if (skip) - break; - } - if (!skip) { - /* Make sure there are no trailing arguments */ - if (sym->dim.arglist[curarg].ident == 0) - return TRUE; - } - t = t->next; + for (functag_t *formal = e->first; formal; formal = formal->next) { + if (functag_compare(formal, actual)) + return TRUE; } return FALSE; @@ -2287,41 +2236,30 @@ restart: return FALSE; } - symbol *oldsym=sym; - int n=-1,iter=0; - int usage = ((sym->usage & uPUBLIC) == uPUBLIC) ? uPUBLIC : 0; - cell code_addr=0; - for (sym=glbtab.next; sym!=NULL; sym=sym->next) { - if (sym->ident==iFUNCTN && sym->vclass == sGLOBAL && (!usage || (sym->usage & usage))) { - if (strcmp(sym->name, lval1->sym->name)==0) { - n = iter; - code_addr = sym->codeaddr; - break; - } - iter++; + int public_index = 0; + symbol *target = NULL; + for (symbol *iter = glbtab.next; iter; iter = iter->next) { + if (iter->ident != iFUNCTN || iter->vclass != sGLOBAL) + continue; + if (strcmp(iter->name, lval1->sym->name) == 0) { + target = iter; + break; } + if (iter->usage & uPUBLIC) + public_index++; } - if (n == -1) { + if (!target || !(target->usage & uPUBLIC)) { error(76); return FALSE; } - char faketag[sNAMEMAX+1]; - lval1->sym=NULL; - lval1->ident=iCONSTEXPR; - /* Generate a quick pseudo-tag! */ - if (usage == uPUBLIC) { - lval1->constval=(n<<1)|1; - snprintf(faketag, sizeof(faketag)-1, "$Func@%d", n); - } else { - lval1->constval=(code_addr<<1)|0; - snprintf(faketag, sizeof(faketag)-1, "$Func!%d", code_addr); - error(153); - } - lval1->tag=pc_addtag_flags(faketag, FIXEDTAG|FUNCTAG); - oldsym->usage |= uREAD; - sym->usage |= uREAD; + funcenum_t *fe = funcenum_for_symbol(target); + lval1->sym = NULL; + lval1->ident = iCONSTEXPR; + lval1->constval = (public_index << 1) | 1; + lval1->tag = fe->tag; + target->usage |= uREAD; } /* if */ return lvalue; } diff --git a/sourcepawn/compiler/sctracker.c b/sourcepawn/compiler/sctracker.c index 74f17058..b575adcf 100644 --- a/sourcepawn/compiler/sctracker.c +++ b/sourcepawn/compiler/sctracker.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "sc.h" #include "sctracker.h" @@ -127,12 +128,12 @@ void funcenums_free() lastenum = NULL; } -funcenum_t *funcenums_find_byval(int value) +funcenum_t *funcenums_find_by_tag(int tag) { funcenum_t *e = firstenum; while (e) { - if (e->value == value) + if (e->tag == tag) return e; e = e->next; } @@ -146,7 +147,7 @@ funcenum_t *funcenums_add(const char *name) memset(e, 0, sizeof(funcenum_t)); - if (firstenum == NULL) { + if (!firstenum) { firstenum = e; lastenum = e; } else { @@ -155,11 +156,57 @@ funcenum_t *funcenums_add(const char *name) } strcpy(e->name, name); - e->value = pc_addtag_flags((char *)name, FIXEDTAG|FUNCTAG); + e->tag = pc_addtag_flags((char *)name, FIXEDTAG|FUNCTAG); return e; } +funcenum_t *funcenum_for_symbol(symbol *sym) +{ + functag_t ft; + memset(&ft, 0, sizeof(ft)); + + ft.ret_tag = sym->tag; + ft.usage = uPUBLIC & (sym->usage & uRETVALUE); + ft.argcount = 0; + ft.ommittable = FALSE; + for (arginfo *arg = sym->dim.arglist; arg->ident; arg++) { + funcarg_t *dest = &ft.args[ft.argcount++]; + + dest->tagcount = arg->numtags; + memcpy(dest->tags, arg->tags, arg->numtags * sizeof(int)); + + dest->dimcount = arg->numdim; + memcpy(dest->dims, arg->dim, arg->numdim * sizeof(int)); + + dest->ident = arg->ident; + dest->fconst = !!(arg->usage & uCONST); + dest->ommittable = FALSE; + } + + char name[METHOD_NAMEMAX+1]; + UTIL_Format(name, sizeof(name), "::ft:%s:%d:%d", sym->name, sym->addr, sym->codeaddr); + + funcenum_t *fe = funcenums_add(name); + functags_add(fe, &ft); + + return fe; +} + +// Finds a functag that was created intrinsically. +functag_t *functag_find_intrinsic(int tag) +{ + funcenum_t *fe = funcenums_find_by_tag(tag); + if (!fe) + return NULL; + + if (strncmp(fe->name, "::ft:", 5) != 0) + return NULL; + + assert(fe->first && fe->first == fe->last); + return fe->first; +} + functag_t *functags_add(funcenum_t *en, functag_t *src) { functag_t *t = (functag_t *)malloc(sizeof(functag_t)); @@ -550,3 +597,18 @@ int can_redef_layout_spec(LayoutSpec def1, LayoutSpec def2) } return FALSE; } + +size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + size_t len = vsnprintf(buffer, maxlength, fmt, ap); + va_end(ap); + + if (len >= maxlength) { + buffer[maxlength - 1] = '\0'; + return maxlength - 1; + } + return len; +} diff --git a/sourcepawn/compiler/sctracker.h b/sourcepawn/compiler/sctracker.h index 439d97b4..a9ff552c 100644 --- a/sourcepawn/compiler/sctracker.h +++ b/sourcepawn/compiler/sctracker.h @@ -31,7 +31,7 @@ typedef struct funcarg_s typedef struct functag_s { int ret_tag; - int type; + int usage; int argcount; int ommittable; funcarg_t args[sARGS_MAX]; @@ -40,8 +40,8 @@ typedef struct functag_s typedef struct funcenum_s { - int value; - char name[sNAMEMAX+1]; + int tag; + char name[METHOD_NAMEMAX+1]; functag_t *first; functag_t *last; struct funcenum_s *next; @@ -116,8 +116,10 @@ structarg_t *pstructs_getarg(pstruct_t *pstruct, const char *member); */ void funcenums_free(); funcenum_t *funcenums_add(const char *name); -funcenum_t *funcenums_find_byval(int value); +funcenum_t *funcenums_find_by_tag(int tag); functag_t *functags_add(funcenum_t *en, functag_t *src); +funcenum_t *funcenum_for_symbol(symbol *sym); +functag_t *functag_find_intrinsic(int tag); /** * Given a name or tag, find any extra weirdness it has associated with it. @@ -167,4 +169,6 @@ void methodmaps_free(); extern memuse_list_t *heapusage; extern memuse_list_t *stackusage; +size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...); + #endif //_INCLUDE_SOURCEPAWN_COMPILER_TRACKER_H_