Merge pull request #445 from Daniel-Cortez/__addrof
Operator '__addressof'
This commit is contained in:
commit
885031670a
@ -237,6 +237,8 @@ typedef struct s_symbol {
|
||||
#define uMISSING 0x080
|
||||
#define uFORWARD 0x100
|
||||
#define uNODESTRUCT 0x200 /* "no destruct(or)", not "node struct" */
|
||||
/* symbol is referenced "globally", e.g. via "__emit" or "#emit" used outside functions */
|
||||
#define uGLOBALREF 0x400
|
||||
/* uRETNONE is not stored in the "usage" field of a symbol. It is
|
||||
* used during parsing a function, to detect a mix of "return;" and
|
||||
* "return value;" in a few special cases.
|
||||
@ -354,6 +356,7 @@ enum {
|
||||
tMIDDLE = tDBLDOT, /* value of last multi-character operator */
|
||||
|
||||
/* reserved words (statements) */
|
||||
t__ADDRESSOF,
|
||||
tASSERT,
|
||||
tBEGIN,
|
||||
tBREAK,
|
||||
@ -520,15 +523,28 @@ enum { /* identifier types */
|
||||
estAUTOMATON,
|
||||
estSTATE
|
||||
};
|
||||
enum { /* symbol type flags */
|
||||
esfLABEL = 1 << 0,
|
||||
enum { /* search types for error_suggest() when the identifier type is "estSYMBOL" */
|
||||
/* symbol type flags */
|
||||
esfLABEL = 1 << 0, /* label */
|
||||
esfCONST = 1 << 1, /* named constant */
|
||||
esfVARIABLE = 1 << 2, /* single variable */
|
||||
esfARRAY = 1 << 3, /* array */
|
||||
esfFUNCTION = 1 << 4, /* Pawn or native function */
|
||||
esfPAWNFUNC = 1 << 4, /* Pawn function */
|
||||
esfNATIVE = 1 << 5, /* native function */
|
||||
|
||||
/* composite search types */
|
||||
/* find symbols of any type (used only to define other search types) */
|
||||
esfANY = esfLABEL | esfCONST | esfVARIABLE | esfARRAY | esfPAWNFUNC | esfNATIVE,
|
||||
|
||||
/* any function */
|
||||
esfFUNCTION = esfPAWNFUNC | esfNATIVE,
|
||||
|
||||
/* find symbols of any type but labels */
|
||||
esfNONLABEL = esfCONST | esfVARIABLE | esfARRAY | esfFUNCTION,
|
||||
esfNONLABEL = esfANY & ~esfLABEL,
|
||||
|
||||
/* find symbols of any type except constants and native functions
|
||||
* (for the "__addressof" operator) */
|
||||
esfADDRESSOF = esfANY & ~(esfCONST | esfNATIVE),
|
||||
|
||||
/* find an array, a single variable, or a named constant */
|
||||
esfVARCONST = esfCONST | esfVARIABLE | esfARRAY
|
||||
|
@ -4276,15 +4276,13 @@ static void doarg(char *name,int ident,int offset,int tags[],int numtags,
|
||||
} /* if */
|
||||
}
|
||||
|
||||
static int count_referrers(symbol *entry)
|
||||
static int has_referrers(symbol *entry)
|
||||
{
|
||||
int i,count;
|
||||
|
||||
count=0;
|
||||
int i;
|
||||
for (i=0; i<entry->numrefers; i++)
|
||||
if (entry->refer[i]!=NULL)
|
||||
count++;
|
||||
return count;
|
||||
return TRUE;
|
||||
return ((entry->usage & uGLOBALREF)!=0);
|
||||
}
|
||||
|
||||
#if !defined SC_LIGHT
|
||||
@ -4724,7 +4722,7 @@ static void reduce_referrers(symbol *root)
|
||||
if (sym->ident==iFUNCTN
|
||||
&& (sym->usage & uNATIVE)==0
|
||||
&& (sym->usage & uPUBLIC)==0 && strcmp(sym->name,uMAINFUNC)!=0 && strcmp(sym->name,uENTRYFUNC)!=0
|
||||
&& count_referrers(sym)==0)
|
||||
&& !has_referrers(sym))
|
||||
{
|
||||
sym->usage&=~(uREAD | uWRITTEN); /* erase usage bits if there is no referrer */
|
||||
/* find all symbols that are referred by this symbol */
|
||||
@ -4743,7 +4741,7 @@ static void reduce_referrers(symbol *root)
|
||||
} else if ((sym->ident==iVARIABLE || sym->ident==iARRAY)
|
||||
&& (sym->usage & uPUBLIC)==0
|
||||
&& sym->parent==NULL
|
||||
&& count_referrers(sym)==0)
|
||||
&& !has_referrers(sym))
|
||||
{
|
||||
sym->usage&=~(uREAD | uWRITTEN); /* erase usage bits if there is no referrer */
|
||||
} /* if */
|
||||
|
@ -2170,9 +2170,9 @@ char *sc_tokens[] = {
|
||||
"*=", "/=", "%=", "+=", "-=", "<<=", ">>>=", ">>=", "&=", "^=", "|=",
|
||||
"||", "&&", "==", "!=", "<=", ">=", "<<", ">>>", ">>", "++", "--",
|
||||
"...", "..",
|
||||
"assert", "*begin", "break", "case", "char", "const", "continue", "default",
|
||||
"defined", "do", "else", "__emit", "*end", "enum", "exit", "for", "forward",
|
||||
"goto", "if", "native", "new", "operator", "public", "return", "sizeof",
|
||||
"__addressof", "assert", "*begin", "break", "case", "char", "const", "continue",
|
||||
"default", "defined", "do", "else", "__emit", "*end", "enum", "exit", "for",
|
||||
"forward", "goto", "if", "native", "new", "operator", "public", "return", "sizeof",
|
||||
"sleep", "state", "static", "stock", "switch", "tagof", "*then", "while",
|
||||
"#assert", "#define", "#else", "#elseif", "#emit", "#endif", "#endinput",
|
||||
"#endscript", "#error", "#file", "#if", "#include", "#line", "#pragma",
|
||||
@ -3163,12 +3163,10 @@ SC_FUNC void markusage(symbol *sym,int usage)
|
||||
if ((usage & (uREAD | uWRITTEN))!=0) {
|
||||
/* only do this for global symbols */
|
||||
if (sym->vclass==sGLOBAL) {
|
||||
/* "curfunc" should always be valid, since statements may not occurs
|
||||
* outside functions; in the case of syntax errors, however, the
|
||||
* compiler may arrive through this function
|
||||
*/
|
||||
if (curfunc!=NULL)
|
||||
refer_symbol(sym,curfunc);
|
||||
else
|
||||
sym->usage |= uGLOBALREF;
|
||||
} /* if */
|
||||
} /* if */
|
||||
}
|
||||
|
@ -1315,6 +1315,103 @@ static int hier2(value *lval)
|
||||
lvalue=hier2(lval);
|
||||
lval->tag=tag;
|
||||
return lvalue;
|
||||
case t__ADDRESSOF: {
|
||||
extern char *sc_tokens[];
|
||||
static const char allowed_sym_types[]="-variable, array, array cell, label or function-";
|
||||
paranthese=0;
|
||||
while (matchtoken('('))
|
||||
paranthese++;
|
||||
tok=lex(&val,&st);
|
||||
if (tok!=tSYMBOL)
|
||||
return error_suggest(20,st,NULL,estNONSYMBOL,tok); /* invalid symbol name */
|
||||
sym=findloc(st);
|
||||
if (sym==NULL)
|
||||
sym=findglb(st,sSTATEVAR);
|
||||
if (sym==NULL) {
|
||||
return error_suggest(17,st,NULL,estSYMBOL,esfADDRESSOF); /* undefined symbol */
|
||||
} else if ((sym->usage & uDEFINE)==0) {
|
||||
/* the symbol is defined after the point of its use,
|
||||
so the compiler can't know its address yet
|
||||
*/
|
||||
return error(17,st); /* undefined symbol (don't suggest other symbols) */
|
||||
} /* if */
|
||||
/* Mark the symbol as read, so the compiler won't throw it away
|
||||
* if it's only indirectly used from "__addressof" */
|
||||
markusage(sym,uREAD);
|
||||
clear_value(lval);
|
||||
lval->ident=iCONSTEXPR;
|
||||
switch (sym->ident) {
|
||||
case iVARIABLE:
|
||||
case iREFERENCE:
|
||||
case iARRAY:
|
||||
case iREFARRAY:
|
||||
if (sym->vclass==sLOCAL) {
|
||||
lval->ident=iEXPRESSION;
|
||||
address(sym,sPRI);
|
||||
break;
|
||||
} /* if */
|
||||
/* fallthrough */
|
||||
case iFUNCTN:
|
||||
case iLABEL:
|
||||
lval->constval=sym->addr;
|
||||
if (sym->ident==iFUNCTN) {
|
||||
if ((sym->usage & uNATIVE)!=0)
|
||||
error(1,allowed_sym_types,sc_tokens[teNATIVE-tFIRST]);
|
||||
break;
|
||||
} else if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
|
||||
cell arrayidx=0,numoffsets=0,offsmul=1;
|
||||
int level;
|
||||
symbol *subsym=sym;
|
||||
for (level=0; matchtoken('['); level++) {
|
||||
if (subsym!=NULL) {
|
||||
if (level==subsym->dim.array.level && matchtoken(tSYMBOL)) {
|
||||
char *idxname;
|
||||
int cmptag=subsym->x.tags.index;
|
||||
tokeninfo(&val,&idxname);
|
||||
if (findconst(idxname,&cmptag)==NULL)
|
||||
error_suggest(80,idxname,NULL,estSYMBOL,esfCONST); /* unknown symbol, or non-constant */
|
||||
else if (cmptag>1)
|
||||
error(91,idxname); /* ambiguous constant */
|
||||
} else {
|
||||
int index,ident;
|
||||
cell cidx;
|
||||
stgget(&index,&cidx); /* mark position in code generator */
|
||||
ident=expression(&val,&tag,NULL,TRUE);
|
||||
stgdel(index,cidx); /* scratch generated code */
|
||||
if (ident!=iCONSTEXPR)
|
||||
error(8); /* must be constant expression */
|
||||
} /* if */
|
||||
numoffsets+=offsmul;
|
||||
offsmul*=subsym->dim.array.length;
|
||||
arrayidx=(arrayidx*subsym->dim.array.length)+val;
|
||||
subsym=finddepend(subsym);
|
||||
}
|
||||
needtoken(']');
|
||||
} /* for */
|
||||
if (level>sym->dim.array.level+1)
|
||||
error(28,sym->name); /* invalid subscript */
|
||||
while (subsym!=NULL) {
|
||||
numoffsets+=offsmul;
|
||||
offsmul*=subsym->dim.array.length;
|
||||
arrayidx*=arrayidx*subsym->dim.array.length;
|
||||
subsym=finddepend(subsym);
|
||||
} /* if */
|
||||
lval->constval+=(numoffsets-1+arrayidx)*(cell)sizeof(cell);
|
||||
ldconst(lval->constval,sPRI);
|
||||
} /* if */
|
||||
break;
|
||||
case iCONSTEXPR:
|
||||
error(1,allowed_sym_types,sc_tokens[teNUMERIC-tFIRST]);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
} /* switch */
|
||||
while (paranthese--)
|
||||
needtoken(')');
|
||||
if (strchr((char*)pline,PREPROC_TERM)!=NULL)
|
||||
return error(93); /* "__addressof" operator is invalid in preprocessor directives */
|
||||
return FALSE;
|
||||
} /* case */
|
||||
case tDEFINED:
|
||||
paranthese=0;
|
||||
while (matchtoken('('))
|
||||
|
@ -131,7 +131,8 @@ static char *errmsg[] = {
|
||||
/*089*/ "state variables may not be initialized (symbol \"%s\")\n",
|
||||
/*090*/ "public functions may not return arrays (symbol \"%s\")\n",
|
||||
/*091*/ "ambiguous constant; tag override is required (symbol \"%s\")\n",
|
||||
/*092*/ "functions may not return arrays of unknown size (symbol \"%s\")\n"
|
||||
/*092*/ "functions may not return arrays of unknown size (symbol \"%s\")\n",
|
||||
/*093*/ "\"__addressof\" operator is invalid in preprocessor expressions\n"
|
||||
};
|
||||
|
||||
static char *fatalmsg[] = {
|
||||
@ -534,7 +535,7 @@ static int find_closest_symbol_table(const char *name,const symbol *root,int sym
|
||||
break;
|
||||
case iFUNCTN:
|
||||
case iREFFUNC:
|
||||
if ((symboltype & esfFUNCTION)==0)
|
||||
if ((symboltype & (((sym->usage & uNATIVE)!=0) ? esfNATIVE : esfFUNCTION))==0)
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
|
9
source/compiler/tests/__addressof.meta
Normal file
9
source/compiler/tests/__addressof.meta
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
'test_type': 'output_check',
|
||||
'errors': """
|
||||
__addressof.pwn(3) : error 017: undefined symbol "Func1"
|
||||
__addressof.pwn(16) : error 093: "__addressof" operator is invalid in preprocessor expressions
|
||||
__addressof.pwn(21) : error 001: expected token: "-variable, array, array cell, label or function-", but found "-numeric value-"
|
||||
__addressof.pwn(24) : error 001: expected token: "-variable, array, array cell, label or function-", but found "-native function-"
|
||||
"""
|
||||
}
|
52
source/compiler/tests/__addressof.pwn
Normal file
52
source/compiler/tests/__addressof.pwn
Normal file
@ -0,0 +1,52 @@
|
||||
#include <console>
|
||||
|
||||
const func1_addr = __addressof(Func1); // error
|
||||
|
||||
Func1() {}
|
||||
Func2() {}
|
||||
Func3() {}
|
||||
|
||||
new const functions[3] =
|
||||
{
|
||||
__addressof(Func1),
|
||||
__addressof(Func2),
|
||||
__addressof(Func3)
|
||||
};
|
||||
|
||||
#if __addressof Func1 > 0 // error
|
||||
#endif
|
||||
|
||||
main()
|
||||
{
|
||||
const a = __addressof func1_addr; // error
|
||||
#pragma unused a
|
||||
|
||||
const b = __addressof printf; // error
|
||||
#pragma unused b
|
||||
|
||||
lbl:
|
||||
const c = __addressof lbl;
|
||||
#pragma unused c
|
||||
|
||||
const d = __addressof functions;
|
||||
#pragma unused d
|
||||
|
||||
const e = __addressof functions[1];
|
||||
#pragma unused e
|
||||
|
||||
static x = 0;
|
||||
const f = __addressof x;
|
||||
#pragma unused f
|
||||
|
||||
static arr1[3][2] = { { 0, ... }, ... };
|
||||
const g = __addressof arr1[2][1];
|
||||
#pragma unused g
|
||||
|
||||
new y = 0;
|
||||
new const h = __addressof y;
|
||||
#pragma unused h
|
||||
|
||||
new arr2[3][2] = { { 0, ... }, ... };
|
||||
new const i = __addressof arr2;
|
||||
#pragma unused i
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user