Simplify functag handling.

This commit is contained in:
David Anderson 2014-08-20 00:00:24 -07:00
parent 942a3cd155
commit e5e2c1fa3d
5 changed files with 176 additions and 171 deletions

View File

@ -966,6 +966,7 @@ SC_VDECL jmp_buf errbuf; /* target of longjmp() on a fatal error */
#if defined WIN32
# if !defined snprintf
# define snprintf _snprintf
# define vsnprintf _vsnprintf
# endif
#endif

View File

@ -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 {

View File

@ -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)
if (formal->ret_tag == actual->ret_tag)
return TRUE;
if (t->ret_tag == pc_tag_void && (sym->tag == 0 && !(sym->usage & uRETVALUE)))
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,136 +500,18 @@ 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; curarg<t->argcount; 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; i<enum_arg->dimcount; 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; i<enum_arg->tagcount; 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)
for (functag_t *formal = e->first; formal; formal = formal->next) {
if (functag_compare(formal, actual))
return TRUE;
}
t = t->next;
}
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;
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;
}
iter++;
}
if (iter->usage & uPUBLIC)
public_index++;
}
if (n == -1) {
if (!target || !(target->usage & uPUBLIC)) {
error(76);
return FALSE;
}
char faketag[sNAMEMAX+1];
funcenum_t *fe = funcenum_for_symbol(target);
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;
lval1->constval = (public_index << 1) | 1;
lval1->tag = fe->tag;
target->usage |= uREAD;
} /* if */
return lvalue;
}

View File

@ -2,6 +2,7 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdarg.h>
#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;
}

View File

@ -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_