Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions source/compiler/sc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -354,6 +356,7 @@ enum {
tMIDDLE = tDBLDOT, /* value of last multi-character operator */

/* reserved words (statements) */
t__ADDRESSOF,
tASSERT,
tBEGIN,
tBREAK,
Expand Down Expand Up @@ -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
Expand Down
14 changes: 6 additions & 8 deletions source/compiler/sc1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 */
Expand All @@ -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 */
Expand Down
12 changes: 5 additions & 7 deletions source/compiler/sc2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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 */
}
Expand Down
97 changes: 97 additions & 0 deletions source/compiler/sc3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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('('))
Expand Down
5 changes: 3 additions & 2 deletions source/compiler/sc5.c
Original file line number Diff line number Diff line change
Expand Up @@ -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[] = {
Expand Down Expand Up @@ -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:
Expand Down
9 changes: 9 additions & 0 deletions source/compiler/tests/__addressof.meta
Original file line number Diff line number Diff line change
@@ -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 changes: 52 additions & 0 deletions source/compiler/tests/__addressof.pwn
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include <console>

const func1_addr = __addressof(Func1); // error
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a little surprising. Functions can otherwise be used before declaration. Would this work if it were forwarded?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functions can otherwise be used before declaration.

This is because in order to call functions the compiler outputs call .funcname, so it could look up the function and obtain its address later, when assembling the code. But __addressof works as an expression, and expressions are handled at the first two compilation stages (parsing), and the compiler can't know a function/label address until it parses its definition at the 2'nd pass; it doesn't keep function addresses obtained at the 1'st pass since at the 2'nd one the generated code can change (e.g. because of #if defined <func> being used for conditional compilation). I think the only solution for this is to add an ability to force a "second" second pass, but this sounds more like a work for a separate PR, IMO.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could build up a list of unresolved addressof calls, just as CONST.pri locations (or however it is actually implemented), then iterate through them once the function is resolved. A third compiler pass would very probably break a lot of stuff.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or, as I said, would forward fix this? I somewhat doubt it as address isn't in the metadata that could be stored in that way. But maybe the pending addresses could be added to the metadata for a function, thus require forward for this case as well (for something like consistency).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realised this works:

main()
{
    new a = __emit(CONST.pri Func);
}

Func()
{
}

Copy link
Contributor Author

@Daniel-Cortez Daniel-Cortez Sep 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realised this works:
new a = __emit(CONST.pri Func);

Indeed. As I already mentioned, __emit implements its own code generation mechanism, so it isn't bound by the limits of the standard codegen. But either way it generates code, so it can't be used to initialize constants and/or global variables.


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
}