Simplify functag handling.
This commit is contained in:
parent
942a3cd155
commit
e5e2c1fa3d
@ -966,6 +966,7 @@ SC_VDECL jmp_buf errbuf; /* target of longjmp() on a fatal error */
|
|||||||
#if defined WIN32
|
#if defined WIN32
|
||||||
# if !defined snprintf
|
# if !defined snprintf
|
||||||
# define snprintf _snprintf
|
# define snprintf _snprintf
|
||||||
|
# define vsnprintf _vsnprintf
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -705,7 +705,7 @@ int pc_addtag_flags(char *name, int flags)
|
|||||||
constvalue *ptr;
|
constvalue *ptr;
|
||||||
int last,tag;
|
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;
|
last=0;
|
||||||
ptr=tagname_tab.next;
|
ptr=tagname_tab.next;
|
||||||
while (ptr!=NULL) {
|
while (ptr!=NULL) {
|
||||||
@ -4201,7 +4201,7 @@ static void parse_function_type(functag_t *type)
|
|||||||
needtoken(tFUNCTION);
|
needtoken(tFUNCTION);
|
||||||
|
|
||||||
type->ret_tag = parse_new_typename(NULL);
|
type->ret_tag = parse_new_typename(NULL);
|
||||||
type->type = uPUBLIC;
|
type->usage = uPUBLIC;
|
||||||
|
|
||||||
needtoken('(');
|
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.
|
* rather than the constant value. And even if we could, we'd have to change the assembler recognize that.
|
||||||
*/
|
*/
|
||||||
if (l == tPUBLIC) {
|
if (l == tPUBLIC) {
|
||||||
func.type = uPUBLIC;
|
func.usage = uPUBLIC;
|
||||||
} else {
|
} else {
|
||||||
error(1, "-public-", str);
|
error(1, "-public-", str);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
func.ret_tag = newStyleTag;
|
func.ret_tag = newStyleTag;
|
||||||
func.type = uPUBLIC;
|
func.usage = uPUBLIC;
|
||||||
}
|
}
|
||||||
needtoken('(');
|
needtoken('(');
|
||||||
do {
|
do {
|
||||||
|
@ -413,15 +413,82 @@ static int matchobjecttags(int formaltag, int actualtag, int flags)
|
|||||||
return obj_typeerror(133, formaltag, actualtag);
|
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;
|
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 TRUE;
|
||||||
return FALSE;
|
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)
|
static int matchfunctags(int formaltag, int actualtag)
|
||||||
{
|
{
|
||||||
if (formaltag == pc_functag && (actualtag & FUNCTAG))
|
if (formaltag == pc_functag && (actualtag & FUNCTAG))
|
||||||
@ -433,136 +500,18 @@ static int matchfunctags(int formaltag, int actualtag)
|
|||||||
if (!(actualtag & FUNCTAG))
|
if (!(actualtag & FUNCTAG))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
constvalue *v = find_tag_byval(actualtag);
|
functag_t *actual = functag_find_intrinsic(actualtag);
|
||||||
int index;
|
if (!actual)
|
||||||
short usage = uPUBLIC;
|
|
||||||
symbol *sym, *found = NULL;
|
|
||||||
funcenum_t *e;
|
|
||||||
functag_t *t;
|
|
||||||
|
|
||||||
if (strncmp(v->name, "$Func", 5) != 0)
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* Now we have to go about looking up each function in this enum. WHICH IS IT. */
|
funcenum_t *e = funcenums_find_by_tag(formaltag);
|
||||||
e = funcenums_find_byval(formaltag);
|
|
||||||
if (!e)
|
if (!e)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
assert(v->name[5] == '@' || v->name[5] == '!');
|
for (functag_t *formal = e->first; formal; formal = formal->next) {
|
||||||
|
if (functag_compare(formal, actual))
|
||||||
/* 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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
t = t->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -2287,41 +2236,30 @@ restart:
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
symbol *oldsym=sym;
|
int public_index = 0;
|
||||||
int n=-1,iter=0;
|
symbol *target = NULL;
|
||||||
int usage = ((sym->usage & uPUBLIC) == uPUBLIC) ? uPUBLIC : 0;
|
for (symbol *iter = glbtab.next; iter; iter = iter->next) {
|
||||||
cell code_addr=0;
|
if (iter->ident != iFUNCTN || iter->vclass != sGLOBAL)
|
||||||
for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
|
continue;
|
||||||
if (sym->ident==iFUNCTN && sym->vclass == sGLOBAL && (!usage || (sym->usage & usage))) {
|
if (strcmp(iter->name, lval1->sym->name) == 0) {
|
||||||
if (strcmp(sym->name, lval1->sym->name)==0) {
|
target = iter;
|
||||||
n = iter;
|
|
||||||
code_addr = sym->codeaddr;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
iter++;
|
if (iter->usage & uPUBLIC)
|
||||||
}
|
public_index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n == -1) {
|
if (!target || !(target->usage & uPUBLIC)) {
|
||||||
error(76);
|
error(76);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
char faketag[sNAMEMAX+1];
|
funcenum_t *fe = funcenum_for_symbol(target);
|
||||||
lval1->sym = NULL;
|
lval1->sym = NULL;
|
||||||
lval1->ident = iCONSTEXPR;
|
lval1->ident = iCONSTEXPR;
|
||||||
/* Generate a quick pseudo-tag! */
|
lval1->constval = (public_index << 1) | 1;
|
||||||
if (usage == uPUBLIC) {
|
lval1->tag = fe->tag;
|
||||||
lval1->constval=(n<<1)|1;
|
target->usage |= uREAD;
|
||||||
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;
|
|
||||||
} /* if */
|
} /* if */
|
||||||
return lvalue;
|
return lvalue;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include "sc.h"
|
#include "sc.h"
|
||||||
#include "sctracker.h"
|
#include "sctracker.h"
|
||||||
|
|
||||||
@ -127,12 +128,12 @@ void funcenums_free()
|
|||||||
lastenum = NULL;
|
lastenum = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
funcenum_t *funcenums_find_byval(int value)
|
funcenum_t *funcenums_find_by_tag(int tag)
|
||||||
{
|
{
|
||||||
funcenum_t *e = firstenum;
|
funcenum_t *e = firstenum;
|
||||||
|
|
||||||
while (e) {
|
while (e) {
|
||||||
if (e->value == value)
|
if (e->tag == tag)
|
||||||
return e;
|
return e;
|
||||||
e = e->next;
|
e = e->next;
|
||||||
}
|
}
|
||||||
@ -146,7 +147,7 @@ funcenum_t *funcenums_add(const char *name)
|
|||||||
|
|
||||||
memset(e, 0, sizeof(funcenum_t));
|
memset(e, 0, sizeof(funcenum_t));
|
||||||
|
|
||||||
if (firstenum == NULL) {
|
if (!firstenum) {
|
||||||
firstenum = e;
|
firstenum = e;
|
||||||
lastenum = e;
|
lastenum = e;
|
||||||
} else {
|
} else {
|
||||||
@ -155,11 +156,57 @@ funcenum_t *funcenums_add(const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
strcpy(e->name, 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;
|
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 *functags_add(funcenum_t *en, functag_t *src)
|
||||||
{
|
{
|
||||||
functag_t *t = (functag_t *)malloc(sizeof(functag_t));
|
functag_t *t = (functag_t *)malloc(sizeof(functag_t));
|
||||||
@ -550,3 +597,18 @@ int can_redef_layout_spec(LayoutSpec def1, LayoutSpec def2)
|
|||||||
}
|
}
|
||||||
return FALSE;
|
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
|
typedef struct functag_s
|
||||||
{
|
{
|
||||||
int ret_tag;
|
int ret_tag;
|
||||||
int type;
|
int usage;
|
||||||
int argcount;
|
int argcount;
|
||||||
int ommittable;
|
int ommittable;
|
||||||
funcarg_t args[sARGS_MAX];
|
funcarg_t args[sARGS_MAX];
|
||||||
@ -40,8 +40,8 @@ typedef struct functag_s
|
|||||||
|
|
||||||
typedef struct funcenum_s
|
typedef struct funcenum_s
|
||||||
{
|
{
|
||||||
int value;
|
int tag;
|
||||||
char name[sNAMEMAX+1];
|
char name[METHOD_NAMEMAX+1];
|
||||||
functag_t *first;
|
functag_t *first;
|
||||||
functag_t *last;
|
functag_t *last;
|
||||||
struct funcenum_s *next;
|
struct funcenum_s *next;
|
||||||
@ -116,8 +116,10 @@ structarg_t *pstructs_getarg(pstruct_t *pstruct, const char *member);
|
|||||||
*/
|
*/
|
||||||
void funcenums_free();
|
void funcenums_free();
|
||||||
funcenum_t *funcenums_add(const char *name);
|
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);
|
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.
|
* 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 *heapusage;
|
||||||
extern memuse_list_t *stackusage;
|
extern memuse_list_t *stackusage;
|
||||||
|
|
||||||
|
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...);
|
||||||
|
|
||||||
#endif //_INCLUDE_SOURCEPAWN_COMPILER_TRACKER_H_
|
#endif //_INCLUDE_SOURCEPAWN_COMPILER_TRACKER_H_
|
||||||
|
Loading…
Reference in New Issue
Block a user