Expanded weak function pointers with type checking

Added function typing enumeration

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40137
This commit is contained in:
David Anderson 2006-11-03 06:14:43 +00:00
parent fca7456f4d
commit bc16901bd6
7 changed files with 596 additions and 53 deletions

View File

@ -45,7 +45,7 @@ int main(int argc, char *argv[])
int err;
uint32_t i;
sp_file_t *spf;
memfile_t *dbgtab = NULL;
memfile_t *dbgtab = NULL; //dbgcrab
unsigned char *dbgptr = NULL;
uint32_t sections[FS_Number] = {1,1,0,0,0,1,0,0,0,0,0,0};
FILE *fp;

View File

@ -57,6 +57,8 @@
#define sDEF_AMXSTACK 4096 /* default stack size for AMX files */
#define PREPROC_TERM '\x7f'/* termination character for preprocessor expressions (the "DEL" code) */
#define sDEF_PREFIX "sourcemod.inc" /* default prefix filename */
#define sARGS_MAX 32 /* number of arguments a function can have, max */
#define sTAGS_MAX 16 /* maximum number of tags on an argument */
typedef union {
void *pv; /* e.g. a name */
@ -283,7 +285,7 @@ typedef struct s_stringpair {
*/
#define tFIRST 256 /* value of first multi-character operator */
#define tMIDDLE 280 /* value of last multi-character operator */
#define tLAST 329 /* value of last multi-character match-able token */
#define tLAST 330 /* value of last multi-character match-able token */
/* multi-character operators */
#define taMULT 256 /* *= */
#define taDIV 257 /* /= */
@ -327,51 +329,52 @@ typedef struct s_stringpair {
#define tEXIT 294
#define tFOR 295
#define tFORWARD 296
#define tGOTO 297
#define tIF 298
#define tNATIVE 299
#define tNEW 300
#define tDECL 301
#define tOPERATOR 302
#define tPUBLIC 303
#define tRETURN 304
#define tSIZEOF 305
#define tSLEEP 306
#define tSTATE 307
#define tSTATIC 308
#define tSTOCK 309
#define tSWITCH 310
#define tTAGOF 311
#define tTHEN 312
#define tWHILE 313
#define tFUNCENUM 297
#define tGOTO 298
#define tIF 299
#define tNATIVE 300
#define tNEW 301
#define tDECL 302
#define tOPERATOR 303
#define tPUBLIC 304
#define tRETURN 305
#define tSIZEOF 306
#define tSLEEP 307
#define tSTATE 308
#define tSTATIC 309
#define tSTOCK 310
#define tSWITCH 311
#define tTAGOF 312
#define tTHEN 313
#define tWHILE 314
/* compiler directives */
#define tpASSERT 314 /* #assert */
#define tpDEFINE 315
#define tpELSE 316 /* #else */
#define tpELSEIF 317 /* #elseif */
#define tpEMIT 318
#define tpENDIF 319
#define tpENDINPUT 320
#define tpENDSCRPT 321
#define tpERROR 322
#define tpFILE 323
#define tpIF 324 /* #if */
#define tINCLUDE 325
#define tpLINE 326
#define tpPRAGMA 327
#define tpTRYINCLUDE 328
#define tpUNDEF 329
#define tpASSERT 315 /* #assert */
#define tpDEFINE 316
#define tpELSE 317 /* #else */
#define tpELSEIF 318 /* #elseif */
#define tpEMIT 319
#define tpENDIF 320
#define tpENDINPUT 321
#define tpENDSCRPT 322
#define tpERROR 323
#define tpFILE 324
#define tpIF 325 /* #if */
#define tINCLUDE 326
#define tpLINE 327
#define tpPRAGMA 328
#define tpTRYINCLUDE 329
#define tpUNDEF 330
/* semicolon is a special case, because it can be optional */
#define tTERM 330 /* semicolon or newline */
#define tENDEXPR 331 /* forced end of expression */
#define tTERM 331 /* semicolon or newline */
#define tENDEXPR 332 /* forced end of expression */
/* other recognized tokens */
#define tNUMBER 332 /* integer number */
#define tRATIONAL 333 /* rational number */
#define tSYMBOL 334
#define tLABEL 335
#define tSTRING 336
#define tEXPR 337 /* for assigment to "lastst" only (see SC1.C) */
#define tENDLESS 338 /* endless loop, for assigment to "lastst" only */
#define tNUMBER 333 /* integer number */
#define tRATIONAL 334 /* rational number */
#define tSYMBOL 335
#define tLABEL 336
#define tSTRING 337
#define tEXPR 338 /* for assigment to "lastst" only (see SC1.C) */
#define tENDLESS 339 /* endless loop, for assigment to "lastst" only */
/* (reversed) evaluation of staging buffer */
#define sSTARTREORDER 0x01
@ -432,9 +435,11 @@ typedef enum s_optmark {
#if INT_MAX<0x8000u
#define PUBLICTAG 0x8000u
#define FIXEDTAG 0x4000u
#define FUNCTAG 0x2000u
#else
#define PUBLICTAG 0x80000000Lu
#define FIXEDTAG 0x40000000Lu
#define FUNCTAG 0x20000000Lu
#endif
#define TAGMASK (~PUBLICTAG)
#define CELL_MAX (((ucell)1 << (sizeof(cell)*8-1)) - 1)
@ -451,6 +456,7 @@ typedef enum s_optmark {
int pc_compile(int argc, char **argv);
int pc_addconstant(char *name,cell value,int tag);
int pc_addtag(char *name);
int pc_addfunctag(char *name);
int pc_enablewarning(int number,int enable);
/*
@ -517,6 +523,7 @@ SC_FUNC void delete_consttable(constvalue *table);
SC_FUNC symbol *add_constant(char *name,cell val,int vclass,int tag);
SC_FUNC void exporttag(int tag);
SC_FUNC void sc_attachdocumentation(symbol *sym);
SC_FUNC constvalue *find_tag_byval(int tag);
/* function prototypes in SC2.C */
#define PUSHSTK_P(v) { stkitem s_; s_.pv=(v); pushstk(s_); }
@ -801,6 +808,7 @@ SC_VDECL char *pc_deprecate; /* if non-NULL, mark next declaration as deprecate
SC_VDECL int sc_curstates; /* ID of the current state list */
SC_VDECL int pc_optimize; /* (peephole) optimization level */
SC_VDECL int pc_memflags; /* special flags for the stack/heap usage */
SC_VDECL int pc_functag; /* global function tag */
SC_VDECL constvalue sc_automaton_tab; /* automaton table */
SC_VDECL constvalue sc_state_tab; /* state table */
@ -815,6 +823,12 @@ SC_VDECL jmp_buf errbuf; /* target of longjmp() on a fatal error */
SC_VDECL int sc_makereport; /* generate a cross-reference report */
#endif
#if defined WIN32
#if !defined snprintf
#define snprintf _snprintf
#endif
#endif
#endif /* SC_SKIP_VDECL */
#endif /* SC_H_INCLUDED */

View File

@ -70,6 +70,8 @@
#define VERSION_STR "3.2." SVN_REVSTR
#define VERSION_INT 0x0302
int pc_functag = 0;
static void resetglobals(void);
static void initglobals(void);
static char *get_extension(char *filename);
@ -126,6 +128,7 @@ static void doswitch(void);
static void dogoto(void);
static void dolabel(void);
static void doreturn(void);
static void dofuncenum(void);
static void dobreak(void);
static void docont(void);
static void dosleep(void);
@ -320,6 +323,7 @@ int pc_compile(int argc, char *argv[])
inst_datetime_defines();
#endif
resetglobals();
funcenums_free();
sc_ctrlchar=sc_ctrlchar_org;
sc_packstr=lcl_packstr;
sc_needsemicolon=lcl_needsemicolon;
@ -380,6 +384,7 @@ int pc_compile(int argc, char *argv[])
/* reset "defined" flag of all functions and global variables */
reduce_referrers(&glbtab);
delete_symbols(&glbtab,0,TRUE,FALSE);
funcenums_free();
#if !defined NO_DEFINE
delete_substtable();
inst_datetime_defines();
@ -577,6 +582,7 @@ int pc_addtag(char *name)
if (strcmp(name,ptr->name)==0)
return tag; /* tagname is known, return its sequence number */
tag &= (int)~FIXEDTAG;
tag &= (int)~FUNCTAG;
if (tag>last)
last=tag;
ptr=ptr->next;
@ -590,6 +596,43 @@ int pc_addtag(char *name)
return tag;
}
int pc_addfunctag(char *name)
{
cell val;
constvalue *ptr;
int last,tag;
if (name==NULL) {
/* no tagname was given, check for one */
if (lex(&val,&name)!=tLABEL) {
lexpush();
return 0; /* untagged */
} /* if */
} /* if */
assert(strchr(name,':')==NULL); /* colon should already have been stripped */
last=0;
ptr=tagname_tab.next;
while (ptr!=NULL) {
tag=(int)(ptr->value & TAGMASK);
if (strcmp(name,ptr->name)==0)
return tag; /* tagname is known, return its sequence number */
tag &= (int)~FIXEDTAG;
tag &= (int)~FUNCTAG;
if (tag>last)
last=tag;
ptr=ptr->next;
} /* while */
/* tagname currently unknown, add it */
tag=last+1; /* guaranteed not to exist already */
if (isupper(*name))
tag |= (int)FIXEDTAG;
tag |= (int)FUNCTAG;
append_constval(&tagname_tab,name,(cell)tag,0);
return tag;
}
static void resetglobals(void)
{
/* reset the subset of global variables that is modified by the first pass */
@ -1204,6 +1247,7 @@ static void setconstants(void)
assert(sc_status==statIDLE);
append_constval(&tagname_tab,"_",0,0);/* "untagged" */
append_constval(&tagname_tab,"bool",1,0);
pc_functag = pc_addfunctag("Function");
add_constant("true",1,sGLOBAL,1); /* boolean flags */
add_constant("false",0,sGLOBAL,1);
@ -1363,6 +1407,9 @@ static void parse(void)
case tENUM:
decl_enum(sGLOBAL);
break;
case tFUNCENUM:
dofuncenum();
break;
case tPUBLIC:
/* This can be a public function or a public variable; see the comment
* above (for static functions/variables) for details.
@ -2536,6 +2583,185 @@ static void decl_const(int vclass)
needtoken(tTERM);
}
/* dofuncenum - declare function enumerations
*
*/
static void dofuncenum(void)
{
cell val;
char *str,*ptr;
char tagname[sNAMEMAX+1];
constvalue *cur;
funcenum_t *fenum = NULL;
int i;
/* get the explicit tag (required!) */
int l = lex(&val,&str);
if (l != tSYMBOL)
{
/* Incomprehensible but it works for now! */
error(57);
}
/* This tag can't already exist! */
cur=tagname_tab.next;
while (cur)
{
if (strcmp(cur->name, str) == 0)
{
/* Another bad one... */
if (!(cur->value & FUNCTAG))
{
error(213);
}
break;
}
cur = cur->next;
}
strcpy(tagname, str);
fenum = funcenums_add(tagname);
needtoken('{');
do
{
functag_t func;
if (matchtoken('}'))
{
/* Quick exit */
lexpush();
break;
}
memset(&func, 0, sizeof(func));
func.ret_tag = pc_addtag(NULL); /* Get the return tag */
l = lex(&val, &str);
if (l == tFORWARD)
{
func.type = uFORWARD;
} else if (l == tPUBLIC) {
func.type = uPUBLIC;
} else {
error(1, "[forward,public]", str);
}
needtoken('(');
do
{
funcarg_t *arg = &(func.args[func.argcount]);
/* Quick exit */
if (matchtoken(')'))
{
lexpush();
break;
}
l = lex(&val, &str);
if (l == '&')
{
if ((arg->ident != iVARIABLE && arg->ident != 0) || arg->tagcount > 0)
{
error(1, "-identifier-", "&");
}
arg->ident = iREFERENCE;
} else if (l == tCONST) {
if ((arg->ident != iVARIABLE && arg->ident != 0) || arg->tagcount > 0)
{
error(1, "-identifier-", "const");
}
arg->fconst=TRUE;
} else if (l == tLABEL) {
if (arg->tagcount > 0)
{
error(1, "-identifier-", "-tagname-");
}
arg->tags[arg->tagcount++] = pc_addtag(str);
#if 0
while (arg->tagcount < sTAGS_MAX)
{
if (!matchtoken('_') && !needtoken(tSYMBOL))
{
break;
}
tokeninfo(&val, &ptr);
arg->tags[arg->tagcount++] = pc_addtag(ptr);
if (matchtoken('}'))
{
break;
}
needtoken(',');
}
needtoken(':');
#endif
l=tLABEL;
} else if (l == tSYMBOL) {
if (func.argcount >= sARGS_MAX)
{
error(45);
}
if (str[0] == PUBLIC_CHAR)
{
error(56, str);
}
if (matchtoken('['))
{
if (arg->ident == iREFERENCE)
{
error(67, str);
}
do
{
constvalue *enumroot;
cell size;
int ignore_tag;
if (arg->dimcount == sDIMEN_MAX)
{
error(53);
break;
}
size = needsub(&ignore_tag, &enumroot);
arg->dims[arg->dimcount] = size;
arg->dimcount += 1;
} while (matchtoken('['));
arg->ident=iREFARRAY;
} else if (arg->ident == 0) {
arg->ident = iVARIABLE;
}
if (matchtoken('='))
{
needtoken('0');
arg->ommittable = TRUE;
func.ommittable = TRUE;
} else if (func.ommittable) {
/* :TODO: ERROR HERE! */
}
func.argcount++;
} else if (l == tELLIPS) {
if (arg->ident == iVARIABLE)
{
error(10);
}
arg->ident = iVARARGS;
func.argcount++;
} else {
error(10);
}
} while (l == '&' || l == tLABEL || l == tCONST || l != tELLIPS && matchtoken(','));
needtoken(')');
for (i=0; i<func.argcount; i++)
{
if (func.args[i].tagcount == 0)
{
func.args[i].tags[0] = 0;
func.args[i].tagcount = 1;
}
}
functags_add(fenum, &func);
} while (matchtoken(','));
needtoken('}');
matchtoken(';'); /* eat an optional semicolon. nom nom nom */
errorset(sRESET, 0);
}
/* decl_enum - declare enumerated constants
*
*/
@ -3054,7 +3280,7 @@ static int parse_funcname(char *fname,int *tag1,int *tag2,char *opname)
return unary;
}
static constvalue *find_tag_byval(int tag)
constvalue *find_tag_byval(int tag)
{
constvalue *tagsym;
tagsym=find_constval_byval(&tagname_tab,tag & ~PUBLICTAG);

View File

@ -1833,7 +1833,7 @@ char *sc_tokens[] = {
"||", "&&", "==", "!=", "<=", ">=", "<<", ">>>", ">>", "++", "--",
"...", "..", "::",
"assert", "*begin", "break", "case", "char", "const", "continue", "default",
"defined", "do", "else", "*end", "enum", "exit", "for", "forward", "goto",
"defined", "do", "else", "*end", "enum", "exit", "for", "forward", "funcenum", "goto",
"if", "native", "new", "decl", "operator", "public", "return", "sizeof",
"sleep", "state", "static", "stock", "switch", "tagof", "*then", "while",
"#assert", "#define", "#else", "#elseif", "#emit", "#endif", "#endinput",

View File

@ -288,8 +288,178 @@ SC_FUNC int matchtag(int formaltag,int actualtag,int allowcoerce)
/* if the formal tag is zero and the actual tag is not "fixed", the actual
* tag is "coerced" to zero
*/
if (!allowcoerce || formaltag!=0 || (actualtag & FIXEDTAG)!=0)
return FALSE;
if (!allowcoerce || formaltag!=0 || (actualtag & FIXEDTAG)!=0) {
if (formaltag & FUNCTAG)
{
if (actualtag == pc_functag || (formaltag == pc_functag && actualtag & FUNCTAG))
{
return TRUE;
} else if (actualtag & FUNCTAG) {
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)
{
return FALSE;
}
/* Now we have to go about looking up each function in this enum. WHICH IS IT. */
e = funcenums_find_byval(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 = uFORWARD;
}
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 == uFORWARD) {
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 (t->ret_tag != sym->tag)
{
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 (enum_arg->tags[i] != func_arg->tags[i])
{
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;
}
}
}
return FALSE;
}
} /* if */
return TRUE;
}
@ -1723,24 +1893,35 @@ restart:
if (sc_allowproccall) {
callfunction(sym,lval1,FALSE);
} else {
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->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0)
if (sym->ident==iFUNCTN && sym->vclass == sGLOBAL && (!usage || (sym->usage & usage)))
{
assert(sym->vclass==sGLOBAL);
if (strcmp(sym->name, lval1->sym->name)==0) {
n = iter;
code_addr = sym->codeaddr;
break;
}
iter++;
}
}
if (n!=-1) {
char faketag[sNAMEMAX+1];
lval1->sym=NULL;
lval1->ident=iCONSTEXPR;
lval1->constval=n;
lval1->tag=pc_addtag("Function");
/* Generate a quick pseudo-tag! */
if (usage == uPUBLIC) {
lval1->constval=(n>>1)|(1<<1);
snprintf(faketag, sizeof(faketag)-1, "$Func@%d", n);
} else {
lval1->constval=(code_addr>>1)|(1<<0);
snprintf(faketag, sizeof(faketag)-1, "$Func!%d", code_addr);
}
lval1->tag=pc_addfunctag(faketag);
oldsym->usage |= uREAD;
} else {
error(76); /* invalid function call, or syntax error */
} /* if */

View File

@ -1,10 +1,94 @@
#include <malloc.h>
#include <string.h>
#include <assert.h>
#include "sc.h"
#include "sctracker.h"
memuse_list_t *heapusage = NULL;
memuse_list_t *stackusage = NULL;
funcenum_t *firstenum = NULL;
funcenum_t *lastenum = NULL;
void funcenums_free()
{
funcenum_t *e, *next;
e = firstenum;
while (e)
{
functag_t *tag, *nexttag;
tag = e->first;
while (tag)
{
nexttag = tag->next;
free(tag);
tag = nexttag;
}
next = e->next;
free(e);
e = next;
}
firstenum = NULL;
lastenum = NULL;
}
funcenum_t *funcenums_find_byval(int value)
{
funcenum_t *e = firstenum;
while (e)
{
if (e->value == value)
{
return e;
}
e = e->next;
}
return NULL;
}
funcenum_t *funcenums_add(const char *name)
{
funcenum_t *e = (funcenum_t *)malloc(sizeof(funcenum_t));
memset(e, 0, sizeof(funcenum_t));
if (firstenum == NULL)
{
firstenum = e;
lastenum = e;
} else {
lastenum->next = e;
lastenum = e;
}
strcpy(e->name, name);
e->value = pc_addfunctag((char *)name);
return e;
}
functag_t *functags_add(funcenum_t *en, functag_t *src)
{
functag_t *t = (functag_t *)malloc(sizeof(functag_t));
memcpy(t, src, sizeof(functag_t));
t->next = NULL;
if (en->first == NULL)
{
en->first = t;
en->last = t;
} else {
en->last->next = t;
en->last = t;
}
return t;
}
/**
* Creates a new mem usage tracker entry

View File

@ -16,6 +16,44 @@ typedef struct memuse_list_s {
memuse_t *head; /* head of the current list */
} memuse_list_t;
typedef struct funcarg_s
{
int tagcount;
int tags[sTAGS_MAX];
int dimcount;
cell dims[sDIMEN_MAX];
int ident;
int fconst;
int ommittable;
} funcarg_t;
typedef struct functag_s
{
int ret_tag;
int type;
int argcount;
int ommittable;
funcarg_t args[sARGS_MAX];
struct functag_s *next;
} functag_t;
typedef struct funcenum_s
{
int value;
char name[sNAMEMAX+1];
functag_t *first;
functag_t *last;
struct funcenum_s *next;
} funcenum_t;
/**
* Function enumeration tags
*/
void funcenums_free();
funcenum_t *funcenums_add(const char *name);
funcenum_t *funcenums_find_byval(int value);
functag_t *functags_add(funcenum_t *en, functag_t *src);
/**
* Heap functions
*/