diff --git a/source/compiler/sc.h b/source/compiler/sc.h index ff1f8dc..67d57fa 100644 --- a/source/compiler/sc.h +++ b/source/compiler/sc.h @@ -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 diff --git a/source/compiler/sc1.c b/source/compiler/sc1.c index e419d4a..0040950 100644 --- a/source/compiler/sc1.c +++ b/source/compiler/sc1.c @@ -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; inumrefers; 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 */ diff --git a/source/compiler/sc2.c b/source/compiler/sc2.c index 15063ee..62aa12b 100644 --- a/source/compiler/sc2.c +++ b/source/compiler/sc2.c @@ -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 */ } diff --git a/source/compiler/sc3.c b/source/compiler/sc3.c index d571b84..3a9e121 100644 --- a/source/compiler/sc3.c +++ b/source/compiler/sc3.c @@ -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('(')) diff --git a/source/compiler/sc5.c b/source/compiler/sc5.c index a9088d2..df567f9 100644 --- a/source/compiler/sc5.c +++ b/source/compiler/sc5.c @@ -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: diff --git a/source/compiler/tests/__addressof.meta b/source/compiler/tests/__addressof.meta new file mode 100644 index 0000000..fe4d61b --- /dev/null +++ b/source/compiler/tests/__addressof.meta @@ -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-" + """ +} diff --git a/source/compiler/tests/__addressof.pwn b/source/compiler/tests/__addressof.pwn new file mode 100644 index 0000000..f7a6141 --- /dev/null +++ b/source/compiler/tests/__addressof.pwn @@ -0,0 +1,52 @@ +#include + +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 +}