Simplify functag handling.
This commit is contained in:
parent
942a3cd155
commit
e5e2c1fa3d
@ -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 */
|
||||
|
@ -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 {
|
||||
|
@ -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; 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)
|
||||
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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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_
|
||||
|
Loading…
Reference in New Issue
Block a user