Merge pull request #445 from Daniel-Cortez/__addrof

Operator '__addressof'
This commit is contained in:
Y-Less 2019-11-07 01:39:52 +01:00 committed by GitHub
commit 885031670a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 192 additions and 21 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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 */
}

View File

@ -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('('))

View File

@ -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:

View 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-"
"""
}

View 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
}