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 uMISSING 0x080
|
||||||
#define uFORWARD 0x100
|
#define uFORWARD 0x100
|
||||||
#define uNODESTRUCT 0x200 /* "no destruct(or)", not "node struct" */
|
#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
|
/* 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
|
* used during parsing a function, to detect a mix of "return;" and
|
||||||
* "return value;" in a few special cases.
|
* "return value;" in a few special cases.
|
||||||
@ -354,6 +356,7 @@ enum {
|
|||||||
tMIDDLE = tDBLDOT, /* value of last multi-character operator */
|
tMIDDLE = tDBLDOT, /* value of last multi-character operator */
|
||||||
|
|
||||||
/* reserved words (statements) */
|
/* reserved words (statements) */
|
||||||
|
t__ADDRESSOF,
|
||||||
tASSERT,
|
tASSERT,
|
||||||
tBEGIN,
|
tBEGIN,
|
||||||
tBREAK,
|
tBREAK,
|
||||||
@ -520,15 +523,28 @@ enum { /* identifier types */
|
|||||||
estAUTOMATON,
|
estAUTOMATON,
|
||||||
estSTATE
|
estSTATE
|
||||||
};
|
};
|
||||||
enum { /* symbol type flags */
|
enum { /* search types for error_suggest() when the identifier type is "estSYMBOL" */
|
||||||
esfLABEL = 1 << 0,
|
/* symbol type flags */
|
||||||
|
esfLABEL = 1 << 0, /* label */
|
||||||
esfCONST = 1 << 1, /* named constant */
|
esfCONST = 1 << 1, /* named constant */
|
||||||
esfVARIABLE = 1 << 2, /* single variable */
|
esfVARIABLE = 1 << 2, /* single variable */
|
||||||
esfARRAY = 1 << 3, /* array */
|
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 */
|
/* 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 */
|
/* find an array, a single variable, or a named constant */
|
||||||
esfVARCONST = esfCONST | esfVARIABLE | esfARRAY
|
esfVARCONST = esfCONST | esfVARIABLE | esfARRAY
|
||||||
|
@ -4276,15 +4276,13 @@ static void doarg(char *name,int ident,int offset,int tags[],int numtags,
|
|||||||
} /* if */
|
} /* if */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int count_referrers(symbol *entry)
|
static int has_referrers(symbol *entry)
|
||||||
{
|
{
|
||||||
int i,count;
|
int i;
|
||||||
|
|
||||||
count=0;
|
|
||||||
for (i=0; i<entry->numrefers; i++)
|
for (i=0; i<entry->numrefers; i++)
|
||||||
if (entry->refer[i]!=NULL)
|
if (entry->refer[i]!=NULL)
|
||||||
count++;
|
return TRUE;
|
||||||
return count;
|
return ((entry->usage & uGLOBALREF)!=0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined SC_LIGHT
|
#if !defined SC_LIGHT
|
||||||
@ -4724,7 +4722,7 @@ static void reduce_referrers(symbol *root)
|
|||||||
if (sym->ident==iFUNCTN
|
if (sym->ident==iFUNCTN
|
||||||
&& (sym->usage & uNATIVE)==0
|
&& (sym->usage & uNATIVE)==0
|
||||||
&& (sym->usage & uPUBLIC)==0 && strcmp(sym->name,uMAINFUNC)!=0 && strcmp(sym->name,uENTRYFUNC)!=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 */
|
sym->usage&=~(uREAD | uWRITTEN); /* erase usage bits if there is no referrer */
|
||||||
/* find all symbols that are referred by this symbol */
|
/* 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)
|
} else if ((sym->ident==iVARIABLE || sym->ident==iARRAY)
|
||||||
&& (sym->usage & uPUBLIC)==0
|
&& (sym->usage & uPUBLIC)==0
|
||||||
&& sym->parent==NULL
|
&& sym->parent==NULL
|
||||||
&& count_referrers(sym)==0)
|
&& !has_referrers(sym))
|
||||||
{
|
{
|
||||||
sym->usage&=~(uREAD | uWRITTEN); /* erase usage bits if there is no referrer */
|
sym->usage&=~(uREAD | uWRITTEN); /* erase usage bits if there is no referrer */
|
||||||
} /* if */
|
} /* if */
|
||||||
|
@ -2170,9 +2170,9 @@ char *sc_tokens[] = {
|
|||||||
"*=", "/=", "%=", "+=", "-=", "<<=", ">>>=", ">>=", "&=", "^=", "|=",
|
"*=", "/=", "%=", "+=", "-=", "<<=", ">>>=", ">>=", "&=", "^=", "|=",
|
||||||
"||", "&&", "==", "!=", "<=", ">=", "<<", ">>>", ">>", "++", "--",
|
"||", "&&", "==", "!=", "<=", ">=", "<<", ">>>", ">>", "++", "--",
|
||||||
"...", "..",
|
"...", "..",
|
||||||
"assert", "*begin", "break", "case", "char", "const", "continue", "default",
|
"__addressof", "assert", "*begin", "break", "case", "char", "const", "continue",
|
||||||
"defined", "do", "else", "__emit", "*end", "enum", "exit", "for", "forward",
|
"default", "defined", "do", "else", "__emit", "*end", "enum", "exit", "for",
|
||||||
"goto", "if", "native", "new", "operator", "public", "return", "sizeof",
|
"forward", "goto", "if", "native", "new", "operator", "public", "return", "sizeof",
|
||||||
"sleep", "state", "static", "stock", "switch", "tagof", "*then", "while",
|
"sleep", "state", "static", "stock", "switch", "tagof", "*then", "while",
|
||||||
"#assert", "#define", "#else", "#elseif", "#emit", "#endif", "#endinput",
|
"#assert", "#define", "#else", "#elseif", "#emit", "#endif", "#endinput",
|
||||||
"#endscript", "#error", "#file", "#if", "#include", "#line", "#pragma",
|
"#endscript", "#error", "#file", "#if", "#include", "#line", "#pragma",
|
||||||
@ -3163,12 +3163,10 @@ SC_FUNC void markusage(symbol *sym,int usage)
|
|||||||
if ((usage & (uREAD | uWRITTEN))!=0) {
|
if ((usage & (uREAD | uWRITTEN))!=0) {
|
||||||
/* only do this for global symbols */
|
/* only do this for global symbols */
|
||||||
if (sym->vclass==sGLOBAL) {
|
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)
|
if (curfunc!=NULL)
|
||||||
refer_symbol(sym,curfunc);
|
refer_symbol(sym,curfunc);
|
||||||
|
else
|
||||||
|
sym->usage |= uGLOBALREF;
|
||||||
} /* if */
|
} /* if */
|
||||||
} /* if */
|
} /* if */
|
||||||
}
|
}
|
||||||
|
@ -1315,6 +1315,103 @@ static int hier2(value *lval)
|
|||||||
lvalue=hier2(lval);
|
lvalue=hier2(lval);
|
||||||
lval->tag=tag;
|
lval->tag=tag;
|
||||||
return lvalue;
|
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:
|
case tDEFINED:
|
||||||
paranthese=0;
|
paranthese=0;
|
||||||
while (matchtoken('('))
|
while (matchtoken('('))
|
||||||
|
@ -131,7 +131,8 @@ static char *errmsg[] = {
|
|||||||
/*089*/ "state variables may not be initialized (symbol \"%s\")\n",
|
/*089*/ "state variables may not be initialized (symbol \"%s\")\n",
|
||||||
/*090*/ "public functions may not return arrays (symbol \"%s\")\n",
|
/*090*/ "public functions may not return arrays (symbol \"%s\")\n",
|
||||||
/*091*/ "ambiguous constant; tag override is required (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[] = {
|
static char *fatalmsg[] = {
|
||||||
@ -534,7 +535,7 @@ static int find_closest_symbol_table(const char *name,const symbol *root,int sym
|
|||||||
break;
|
break;
|
||||||
case iFUNCTN:
|
case iFUNCTN:
|
||||||
case iREFFUNC:
|
case iREFFUNC:
|
||||||
if ((symboltype & esfFUNCTION)==0)
|
if ((symboltype & (((sym->usage & uNATIVE)!=0) ? esfNATIVE : esfFUNCTION))==0)
|
||||||
continue;
|
continue;
|
||||||
break;
|
break;
|
||||||
default:
|
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