Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Fixes for function and variable declarations #631

Open
wants to merge 27 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
521f958
Allow a combination of `static` and `stock` specifiers in new-style f…
Daniel-Cortez Dec 22, 2020
4a93ebd
Forbid the use of `static` and `stock` specifiers on functions/variab…
Daniel-Cortez Dec 23, 2020
a03a041
Require specifiers `public`, `static` and `stock` in function definit…
Daniel-Cortez Dec 25, 2020
43b7431
Unset function class specifier flags at the end of compiler pass, so …
Daniel-Cortez Dec 27, 2020
a4a55f0
Don't accept new class specifiers in "forward" re-declarations if the…
Daniel-Cortez Dec 27, 2020
bb707e8
Add a separate flag to memoize the use of "public" specifier in funct…
Daniel-Cortez Jan 5, 2021
9658c87
Add tests
Daniel-Cortez Jan 7, 2021
76a4cb2
Rename the "stock" argument into "fstock" to better match the naming …
Daniel-Cortez Jan 7, 2021
60222eb
Simplify a few lines of code in `funcstub()`
Daniel-Cortez Feb 11, 2021
95f017a
funcstub(): Expect the function tag and the return array size after t…
Daniel-Cortez Feb 11, 2021
65f4b30
Update tests
Daniel-Cortez Feb 13, 2021
1e9418d
Move the code for handling operator `__pragma` out of `newfunc()`
Daniel-Cortez Feb 13, 2021
0e345d1
Expect `__pragma` before the tag in function/variable declarations
Daniel-Cortez Feb 13, 2021
740b6de
Move the code for handling `__pragma` in prefix form out of `newfunc()`
Daniel-Cortez Feb 13, 2021
91e3d42
Update tests
Daniel-Cortez Feb 13, 2021
1b134d4
Only require function definitions to have all specifiers introduced i…
Daniel-Cortez May 2, 2021
b15eb44
Update tests
Daniel-Cortez May 2, 2021
cb8ada3
Do not require specifier `stock`, even if it was previously introduce…
Daniel-Cortez May 2, 2021
32819a3
Allow introduction of specifier `stock` in post-definition forward de…
Daniel-Cortez May 2, 2021
3f762c7
Update tests
Daniel-Cortez May 2, 2021
e7bd543
Don't accept new class specifiers in "old-style" re-declarations if t…
Daniel-Cortez Jan 15, 2022
8c3a09d
Update tests
Daniel-Cortez Jan 15, 2022
e649db0
Allow function class specifiers to be "additive", so they aren't requ…
Daniel-Cortez Mar 19, 2022
6d10a24
Clarify that specifier `stock` can be accepted even after the functio…
Daniel-Cortez Mar 19, 2022
daad976
Detect invalid combinations of "static" and "public" when each specif…
Daniel-Cortez Mar 19, 2022
af265da
Don't repeat error 042 twice when a function is defined as `static` a…
Daniel-Cortez Mar 19, 2022
8a9d5cc
Update tests
Daniel-Cortez Mar 19, 2022
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
13 changes: 13 additions & 0 deletions source/compiler/sc.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,19 @@ typedef struct s_symbol {
#define uRETNONE 0x010
/* uASSIGNED indicates that a value assigned to the variable is not used yet */
#define uASSIGNED 0x080
/* function is declared/defined with the "static" specifier; this flag is being
* reset before the next compilation pass so "forward" declarations won't be
* required to have this specifier if the function was defined/re-declared with
* it only later */
#define uDECLSTATIC 0x200
/* function is declared/defined with the "public" specifier; this flag is
* similar to "uPUBLIC", except that it's being reset before the next
* compilation pass so "forward" declarations won't be required to have this
* specifier if the function was defined/re-declared with it only later
* (the original "uPUBLIC" flag can't be reset at the end of compilation pass,
* as later it's used for generation of the table of public functions and the
* stubs for state functions) */
#define uDECLPUBLIC 0x800
/* uLOOPVAR is set when a variable is read inside of a loop condition. This is
* used to detect situations when a variable is used in a loop condition, but
* not modified inside of a loop body. */
Expand Down
113 changes: 73 additions & 40 deletions source/compiler/sc1.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ static cell init(int ident,int *tag,int *errorfound);
static int getstates(const char *funcname);
static void attachstatelist(symbol *sym, int state_id);
static void funcstub(int fnative);
static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stock);
static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int fstock);
static int declargs(symbol *sym,int chkshadow);
static void doarg(char *name,int ident,int offset,int tags[],int numtags,
int fpublic,int fconst,int written,int chkshadow,arginfo *arg);
Expand Down Expand Up @@ -1795,8 +1795,11 @@ static void parse(void)
emit_flags &= ~efGLOBAL;
break;
case tNEW:
if (getclassspec(tok,&fpublic,&fstatic,&fstock,&fconst))
if (getclassspec(tok,&fpublic,&fstatic,&fstock,&fconst)) {
if (matchtoken(t__PRAGMA))
dopragma();
declglb(NULL,0,fpublic,fstatic,fstock,fconst);
} /* if */
break;
case tSTATIC:
if (matchtoken(tENUM)) {
Expand Down Expand Up @@ -1842,7 +1845,10 @@ static void parse(void)
case tLABEL:
case tSYMBOL:
case tOPERATOR:
lexpush();
if (tok==t__PRAGMA)
dopragma();
else
lexpush();
if (!newfunc(NULL,-1,FALSE,FALSE,FALSE)) {
error(10); /* illegal function or declaration */
lexclr(TRUE); /* drop the rest of the line */
Expand Down Expand Up @@ -2044,6 +2050,9 @@ static void declfuncvar(int fpublic,int fstatic,int fstock,int fconst)
cell val;
int invalidfunc;

if (matchtoken(t__PRAGMA))
dopragma();

tag=pc_addtag(NULL);
tok=lex(&val,&str);
/* if we arrived here, this may not be a declaration of a native function
Expand All @@ -2054,11 +2063,6 @@ static void declfuncvar(int fpublic,int fstatic,int fstock,int fconst)
return;
} /* if */

if (tok==t__PRAGMA) {
dopragma();
tok=lex(&val,&str);
} /* if */

if (tok!=tSYMBOL && tok!=tOPERATOR) {
lexpush();
needtoken(tSYMBOL);
Expand Down Expand Up @@ -2126,8 +2130,6 @@ static void declglb(char *firstname,int firsttag,int fpublic,int fstatic,int fst
firstname=NULL;
} else {
tag=pc_addtag(NULL);
if (matchtoken(t__PRAGMA))
dopragma();
if (lex(&val,&str)!=tSYMBOL) /* read in (new) token */
error_suggest(20,str,NULL,estSYMBOL,esfFUNCTION); /* invalid symbol name */
assert(strlen(str)<=sNAMEMAX);
Expand All @@ -2136,7 +2138,8 @@ static void declglb(char *firstname,int firsttag,int fpublic,int fstatic,int fst
ispublic=fpublic;
if (name[0]==PUBLIC_CHAR) {
ispublic=TRUE; /* implicitly public variable */
assert(!fstatic);
if (fstatic || fstock)
error(42); /* invalid combination of class specifiers */
} /* if */
while (matchtoken('[')) {
ident=iARRAY;
Expand Down Expand Up @@ -3748,7 +3751,7 @@ static void check_reparse(symbol *sym)

static void funcstub(int fnative)
{
int tok,tag,fpublic;
int tok,tag,fpublic,fstatic,fstock,fconst;
char *str;
cell val,size;
char symbolname[sNAMEMAX+1];
Expand All @@ -3757,6 +3760,7 @@ static void funcstub(int fnative)
int numdim;
symbol *sym,*sub;
int opertok;
short filenum;
unsigned int bck_attributes;
char *bck_deprecate; /* in case the user tries to use __pragma("deprecated")
* on a function argument */
Expand All @@ -3765,6 +3769,17 @@ static void funcstub(int fnative)
lastst=0;
litidx=0; /* clear the literal pool */
assert(loctab.next==NULL); /* local symbol table should be empty */
filenum=fcurrent; /* save file number at the start of the declaration */

getclassspec(0,&fpublic,&fstatic,&fstock,&fconst);
/* a combination of 'public' and 'stock' is already checked in getclassspec() */
if (fnative && (fpublic || fstatic || fstock) || (fpublic && fstock))
error(42); /* invalid combination of class specifiers */
else if (fconst)
error(10); /* illegal function or declaration */

if (matchtoken(t__PRAGMA))
dopragma();

tag=pc_addtag(NULL); /* get the tag of the return value */
numdim=0;
Expand All @@ -3785,22 +3800,8 @@ static void funcstub(int fnative)
#endif
dim[numdim++]=(int)size;
} /* while */

tok=lex(&val,&str);
fpublic=(tok==tPUBLIC) || (tok==tSYMBOL && str[0]==PUBLIC_CHAR);
if (fnative) {
if (fpublic || tok==tSTOCK || tok==tSTATIC || (tok==tSYMBOL && *str==PUBLIC_CHAR))
error(42); /* invalid combination of class specifiers */
} else {
if (tok==tPUBLIC || tok==tSTOCK || tok==tSTATIC)
tok=lex(&val,&str);
} /* if */

if (tok==t__PRAGMA) {
dopragma();
tok=lex(&val,&str);
} /* if */

if (tok==tOPERATOR) {
opertok=operatorname(symbolname);
if (opertok==0)
Expand All @@ -3811,6 +3812,12 @@ static void funcstub(int fnative)
error(10); /* illegal function or declaration */
return;
} /* if */
if (str[0]==PUBLIC_CHAR) {
if (fnative || fstatic || fstock)
error(42); /* invalid combination of class specifiers */
if (!fnative)
fpublic=TRUE;
} /* if */
strcpy(symbolname,str);
} /* if */
needtoken('('); /* only functions may be native/forward */
Expand All @@ -3821,8 +3828,24 @@ static void funcstub(int fnative)
if (fnative) {
sym->usage=(short)(uNATIVE | uRETVALUE | uDEFINE | (sym->usage & uPROTOTYPED));
sym->x.lib=curlibrary;
} else if (fpublic && opertok==0) {
sym->usage|=uPUBLIC;
} else {
if ((sym->usage & uDEFINE)!=0) {
/* if the function has already been defined ("finalized"), we can't accept
* any new class specifiers */
if ((fpublic && (sym->usage & uDECLPUBLIC)==0) || (fstatic && (sym->usage & uDECLSTATIC)==0))
error(25); /* function heading differs from prototype */
} else {
if ((fpublic && (sym->usage & uDECLSTATIC)!=0) || (fstatic && (sym->usage & uDECLPUBLIC)!=0))
error(42); /* invalid combination of class specifiers */
if (fpublic && opertok==0)
sym->usage |= (uPUBLIC | uDECLPUBLIC);
if (fstatic) {
sym->usage |= uDECLSTATIC;
sym->fnumber=filenum;
} /* if */
} /* if */
if (fstock)
sym->usage |= uSTOCK;
} /* if */
sym->usage|=uFORWARD;
check_reparse(sym);
Expand Down Expand Up @@ -3906,7 +3929,7 @@ static void funcstub(int fnative)
* glb_declared (altered)
* sc_alignnext (altered)
*/
static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stock)
static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int fstock)
{
symbol *sym,*lvar,*depend;
int argcnt,tok,tag,funcline,i;
Expand All @@ -3916,6 +3939,7 @@ static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stoc
cell val,cidx,glbdecl;
short filenum;
int state_id;
int funcusage;
unsigned int bck_attributes;
char *bck_deprecate; /* in case the user tries to use __pragma("deprecated")
* on a function argument */
Expand All @@ -3936,12 +3960,8 @@ static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stoc
} else {
tag= (firsttag>=0) ? firsttag : pc_addtag(NULL);
tok=lex(&val,&str);
if (tok==tNATIVE || (tok==tPUBLIC && stock))
if (tok==tNATIVE || (tok==tPUBLIC && fstock))
error(42); /* invalid combination of class specifiers */
if (tok==t__PRAGMA) {
dopragma();
tok=lex(&val,&str);
} /* if */
if (tok==tOPERATOR) {
opertok=operatorname(symbolname);
if (opertok==0)
Expand All @@ -3963,16 +3983,25 @@ static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stoc
funcline=fline; /* save line at which the function is defined */
if (symbolname[0]==PUBLIC_CHAR) {
fpublic=TRUE; /* implicitly public function */
if (stock)
if (fstock || fstatic)
error(42); /* invalid combination of class specifiers */
} /* if */
sym=fetchfunc(symbolname,tag);/* get a pointer to the function entry */
if (sym==NULL || (sym->usage & uNATIVE)!=0)
return TRUE; /* it was recognized as a function declaration, but not as a valid one */
funcusage=sym->usage; /* before setting flags `uDECLPUBLIC` and `uDECLSTATIC`,
* back up the current usage state, we'll need it later */
if (symbolname[0]!=PUBLIC_CHAR && ((fpublic && (sym->usage & uDECLSTATIC)!=0)
|| (fstatic && (sym->usage & uDECLPUBLIC)!=0)))
error(42); /* invalid combination of class specifiers */
if (fpublic && opertok==0)
sym->usage|=uPUBLIC;
if (fstatic)
sym->usage |= (uPUBLIC | uDECLPUBLIC);
if (fstatic) {
sym->usage |= uDECLSTATIC;
sym->fnumber=filenum;
} /* if */
if (fstock)
sym->usage|=uSTOCK;
check_reparse(sym);
/* we want public functions to be explicitly prototyped, as they are called
* from the outside
Expand Down Expand Up @@ -4012,6 +4041,12 @@ static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stoc
error(218); /* old style prototypes used with optional semicolons */
if (state_id!=0)
error(231); /* state specification on forward declaration is ignored */
/* if the function has already been defined ("finalized"), we can't accept
* any new class specifiers (except for 'stock', as it doesn't affect code
* generation) */
if ((sym->usage & uDEFINE)!=0
&& ((fpublic && (funcusage & uDECLPUBLIC)==0) || (fstatic && (funcusage & uDECLSTATIC)==0)))
error(25); /* function heading differs from prototype */
delete_symbols(&loctab,0,TRUE,TRUE); /* prototype is done; forget everything */
return TRUE;
} /* if */
Expand All @@ -4036,8 +4071,6 @@ static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stoc
} /* if */
begcseg();
sym->usage|=uDEFINE; /* set the definition flag */
if (stock)
sym->usage|=uSTOCK;
if (opertok!=0 && opererror)
sym->usage &= ~uDEFINE;
/* if the function has states, dump the label to the start of the function */
Expand Down
17 changes: 12 additions & 5 deletions source/compiler/sc2.c
Original file line number Diff line number Diff line change
Expand Up @@ -3155,11 +3155,18 @@ SC_FUNC void delete_symbols(symbol *root,int level,int delete_labels,int delete_
if (sym->states!=NULL)
for (stateptr=sym->states->first; stateptr!=NULL; stateptr=stateptr->next)
stateptr->value=0;
/* for user defined operators, also remove the "prototyped" flag, as
* user-defined operators *must* be declared before use
*/
if (sym->ident==iFUNCTN && !alpha(*sym->name))
sym->usage &= ~uPROTOTYPED;
if (sym->ident==iFUNCTN) {
/* for user defined operators, also remove the "prototyped" flag, as
* user-defined operators *must* be declared before use
*/
if (!alpha(*sym->name))
sym->usage &= ~uPROTOTYPED;
/* unset the class specifier flags, so on the next compilation pass
* the declaration(s) for this function won't be required to have all
* specifiers the function has been defined with on the previous pass
*/
sym->usage &= ~(uDECLPUBLIC | uDECLSTATIC | uSTOCK);
} /* if */
root=sym; /* skip the symbol */
} /* if */
} /* while */
Expand Down
26 changes: 14 additions & 12 deletions source/compiler/tests/__pragma.meta
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@
'errors': """
__pragma.pwn(6) : error 001: expected token: "-identifier-", but found "const"
__pragma.pwn(10) : error 001: expected token: "-identifier-", but found "__pragma"
__pragma.pwn(36) : warning 234: function is deprecated (symbol "Func") - use OtherFunc() instead
__pragma.pwn(40) : warning 234: function is deprecated (symbol "NakedFunc") - use NakedFunc2() instead
__pragma.pwn(43) : warning 207: unknown #pragma
__pragma.pwn(44) : warning 207: unknown #pragma
__pragma.pwn(48) : warning 207: unknown #pragma
__pragma.pwn(62) : warning 200: symbol "long_name2_zzzzzzzz_zzzzzzzzz_z" is truncated to 31 characters
__pragma.pwn(66) : warning 207: unknown #pragma
__pragma.pwn(67) : warning 207: unknown #pragma
__pragma.pwn(68) : warning 207: unknown #pragma
__pragma.pwn(33) : warning 203: symbol is never used: "f"
__pragma.pwn(29) : warning 204: symbol is assigned a value that is never used: "e"
__pragma.pwn(70) : warning 203: symbol is never used: "operator~(Tag:)"
__pragma.pwn(22) : error 001: expected token: "-identifier-", but found "__pragma"
__pragma.pwn(23) : error 001: expected token: "-identifier-", but found "__pragma"
__pragma.pwn(47) : warning 234: function is deprecated (symbol "Func") - use OtherFunc() instead
__pragma.pwn(51) : warning 234: function is deprecated (symbol "NakedFunc") - use NakedFunc2() instead
__pragma.pwn(54) : warning 207: unknown #pragma
__pragma.pwn(55) : warning 207: unknown #pragma
__pragma.pwn(59) : warning 207: unknown #pragma
__pragma.pwn(73) : warning 200: symbol "long_name2_zzzzzzzz_zzzzzzzzz_z" is truncated to 31 characters
__pragma.pwn(77) : warning 207: unknown #pragma
__pragma.pwn(78) : warning 207: unknown #pragma
__pragma.pwn(79) : warning 207: unknown #pragma
__pragma.pwn(44) : warning 203: symbol is never used: "f"
__pragma.pwn(40) : warning 204: symbol is assigned a value that is never used: "e"
__pragma.pwn(81) : warning 203: symbol is never used: "operator~(Tag:)"
"""
}
11 changes: 11 additions & 0 deletions source/compiler/tests/__pragma.pwn
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,19 @@ stock Func3(__pragma("unread") const arg) {}
// "__pragma" can't be used between the tag and the symbol name
stock Func4(Tag: __pragma("unread") arg) {}

// The compiler should expect "__pragma" before the tag
forward stock __pragma("unused") Tag:Func5();
stock __pragma("unused") Tag:Func5(){}
__pragma("unused") Tag:Func6(){}
stock __pragma("unused") Tag:global_var1 = 0;

operator~(Tag:val[],count) {}

// The compiler shouldn't expect "__pragma" in prefix form twice in declarations
// starting with keywords "public", "static" or "stock"
static __pragma("unread") __pragma("unwritten") Func7(); // error 001: expected token: "-identifier-", but found "__pragma"
public __pragma("unread") __pragma("unwritten") global_var2 = 0; // error 001: expected token: "-identifier-", but found "__pragma"

NakedFunc()
{
__pragma("naked", "deprecated - use NakedFunc2() instead");
Expand Down
29 changes: 29 additions & 0 deletions source/compiler/tests/class_specifiers_p1.meta
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
'test_type': 'output_check',
'errors': """
class_specifiers_p1.pwn(22) : error 010: invalid function or declaration
class_specifiers_p1.pwn(23) : error 010: invalid function or declaration
class_specifiers_p1.pwn(24) : error 010: invalid function or declaration
class_specifiers_p1.pwn(27) : error 042: invalid combination of class specifiers
class_specifiers_p1.pwn(28) : error 042: invalid combination of class specifiers
class_specifiers_p1.pwn(29) : error 042: invalid combination of class specifiers
class_specifiers_p1.pwn(30) : error 042: invalid combination of class specifiers
class_specifiers_p1.pwn(31) : error 042: invalid combination of class specifiers
class_specifiers_p1.pwn(32) : error 042: invalid combination of class specifiers
class_specifiers_p1.pwn(33) : error 001: expected token: ";", but found "("
class_specifiers_p1.pwn(34) : error 001: expected token: ";", but found "("
class_specifiers_p1.pwn(37) : error 042: invalid combination of class specifiers
class_specifiers_p1.pwn(38) : error 042: invalid combination of class specifiers
class_specifiers_p1.pwn(39) : error 042: invalid combination of class specifiers
class_specifiers_p1.pwn(40) : error 042: invalid combination of class specifiers
class_specifiers_p1.pwn(41) : error 042: invalid combination of class specifiers
class_specifiers_p1.pwn(42) : error 042: invalid combination of class specifiers
class_specifiers_p1.pwn(53) : error 042: invalid combination of class specifiers
class_specifiers_p1.pwn(54) : error 042: invalid combination of class specifiers
class_specifiers_p1.pwn(55) : error 042: invalid combination of class specifiers
class_specifiers_p1.pwn(56) : error 042: invalid combination of class specifiers
class_specifiers_p1.pwn(57) : error 042: invalid combination of class specifiers
class_specifiers_p1.pwn(58) : error 042: invalid combination of class specifiers
class_specifiers_p1.pwn(59) : error 042: invalid combination of class specifiers
"""
}
Loading