Skip to content

Commit 00a8fbe

Browse files
committed
Merge remote-tracking branch 'remotes/Daniel-Cortez/static_assert' into dev
2 parents 4f82dc9 + 58c8692 commit 00a8fbe

File tree

8 files changed

+371
-52
lines changed

8 files changed

+371
-52
lines changed

source/compiler/sc.h

+7
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,8 @@ enum {
431431
tSLEEP,
432432
tSTATE,
433433
tSTATIC,
434+
t__STATIC_ASSERT,
435+
t__STATIC_CHECK,
434436
tSTOCK,
435437
tSWITCH,
436438
tTAGOF,
@@ -715,6 +717,7 @@ SC_FUNC void emit_parse_line(void);
715717
SC_FUNC void pragma_deprecated(symbol *sym);
716718
SC_FUNC void pragma_unused(symbol *sym,int unread,int unwritten);
717719
SC_FUNC void pragma_nodestruct(symbol *sym);
720+
SC_FUNC cell do_static_check(int use_warning);
718721

719722
/* function prototypes in SC2.C */
720723
#define PUSHSTK_P(v) { stkitem s_; s_.pv=(v); pushstk(s_); }
@@ -732,6 +735,8 @@ SC_FUNC void lexinit(void);
732735
SC_FUNC int lex(cell *lexvalue,char **lexsym);
733736
SC_FUNC void lexpush(void);
734737
SC_FUNC void lexclr(int clreol);
738+
SC_FUNC void recstart(void);
739+
SC_FUNC void recstop(void);
735740
SC_FUNC int matchtoken(int token);
736741
SC_FUNC int tokeninfo(cell *val,char **str);
737742
SC_FUNC int needtoken(int token);
@@ -1021,6 +1026,8 @@ SC_VDECL int pc_retheap; /* heap space (in bytes) to be manually freed when
10211026
SC_VDECL int pc_nestlevel; /* number of active (open) compound statements */
10221027
SC_VDECL unsigned int pc_attributes;/* currently set attribute flags (for the "__pragma" operator) */
10231028
SC_VDECL int pc_ispackedstr; /* true if the last tokenized string is packed */
1029+
SC_VDECL int pc_isrecording; /* true if recording input */
1030+
SC_VDECL char *pc_recstr; /* recorded input */
10241031
SC_VDECL int pc_loopcond; /* equals to 'tFOR', 'tWHILE' or 'tDO' if the current expression is a loop condition, zero otherwise */
10251032
SC_VDECL int pc_numloopvars; /* number of variables used inside a loop condition */
10261033

source/compiler/sc1.c

+160-49
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ static void dostate(void);
195195
static void addwhile(int *ptr);
196196
static void delwhile(void);
197197
static int *readwhile(void);
198+
static char *parsestringparam(int onlycheck,int *bck_litidx);
198199
static void dopragma(void);
199200
static void pragma_apply(symbol *sym);
200201

@@ -842,6 +843,8 @@ int pc_compile(int argc, char *argv[])
842843
line_sym=NULL;
843844
free(pc_deprecate);
844845
pc_deprecate=NULL;
846+
free(pc_recstr);
847+
pc_recstr=NULL;
845848
hashtable_term(&symbol_cache_ht);
846849
delete_consttable(&tagname_tab);
847850
delete_consttable(&libname_tab);
@@ -1855,6 +1858,13 @@ static void parse(void)
18551858
case tFORWARD:
18561859
funcstub(FALSE);
18571860
break;
1861+
case t__STATIC_ASSERT:
1862+
case t__STATIC_CHECK: {
1863+
int use_warning=(tok==t__STATIC_CHECK);
1864+
do_static_check(use_warning);
1865+
needtoken(';');
1866+
break;
1867+
} /* case */
18581868
case '}':
18591869
error(54); /* unmatched closing brace */
18601870
break;
@@ -8438,76 +8448,105 @@ static int *readwhile(void)
84388448
} /* if */
84398449
}
84408450

8441-
static void dopragma(void)
8451+
/* parsestringparam()
8452+
*
8453+
* Uses the standard string parsing mechanism to parse string parameters
8454+
* for operator '__pragma'.
8455+
*/
8456+
static char *parsestringparam(int onlycheck,int *bck_litidx)
84428457
{
84438458
int tok;
8444-
int bck_litidx,bck_packstr;
8445-
int i;
8459+
int bck_packstr;
84468460
cell val;
84478461
char *str;
84488462

8449-
needtoken('(');
8463+
assert(bck_litidx!=NULL);
84508464

8451-
/* The options are specified as strings, e.g.
8452-
* native Func() __pragma("naked", "deprecated - use OtherFunc() instead");
8453-
* In order to process the options, we can reuse the standard string parsing
8454-
* mechanism. This way, as a bonus, we'll also be able to use multi-line
8455-
* strings and the stringization operator.
8456-
*/
8457-
/* first, back up litidx, so we can remove the string from the literal queue later */
8458-
bck_litidx=litidx;
8459-
/* also, force the string to be packed by default, so it would be easier to process it */
8465+
/* back up 'litidx', so we can remove the string from the literal queue later */
8466+
*bck_litidx=litidx;
8467+
/* force the string to be packed by default, so it would be easier to process it */
84608468
bck_packstr=sc_packstr;
84618469
sc_packstr=TRUE;
84628470

8463-
do {
8464-
/* read the option string */
8465-
tok=lex(&val,&str);
8466-
if (tok!=tSTRING || !pc_ispackedstr) {
8467-
/* either not a string, or the user prepended "!" to the option string */
8468-
char tokstr[2];
8469-
if (tok==tSTRING)
8470-
tok='!';
8471-
if (tok<tFIRST) {
8472-
sprintf(tokstr,"%c",tok);
8473-
str=tokstr;
8474-
} else {
8475-
str=sc_tokens[tok-tFIRST];
8476-
} /* if */
8477-
error(1,sc_tokens[tSTRING-tFIRST],str);
8478-
goto next;
8471+
/* read the string parameter */
8472+
tok=lex(&val,&str);
8473+
sc_packstr=bck_packstr;
8474+
if (tok!=tSTRING || !pc_ispackedstr) {
8475+
/* either not a string, or the user prepended "!" to the option string */
8476+
char tokstr[2];
8477+
if (tok==tSTRING) {
8478+
tok='!';
8479+
litidx=*bck_litidx; /* remove the string from the literal queue */
8480+
} /* if */
8481+
if (tok<tFIRST) {
8482+
sprintf(tokstr,"%c",tok);
8483+
str=tokstr;
8484+
} else {
8485+
str=sc_tokens[tok-tFIRST];
84798486
} /* if */
8480-
assert(litidx>bck_litidx);
8487+
error(1,sc_tokens[tSTRING-tFIRST],str);
8488+
return NULL;
8489+
} /* if */
8490+
assert(litidx>*bck_litidx);
84818491

8482-
/* swap the cell bytes if we're on a Little Endian platform */
8492+
if (onlycheck) {
8493+
/* skip the byte swapping and remove the string from the literal queue,
8494+
* as the caller only needed to check if the string was valid */
8495+
litidx=*bck_litidx;
8496+
return NULL;
8497+
} /* if */
8498+
8499+
/* swap the cell bytes if we're on a Little Endian platform */
84838500
#if BYTE_ORDER==LITTLE_ENDIAN
8484-
{ /* local */
8485-
char *bytes;
8486-
i=(int)val;
8487-
do {
8488-
char t;
8489-
bytes=(char *)&litq[i++];
8490-
t=bytes[0], bytes[0]=bytes[sizeof(cell)-1], bytes[sizeof(cell)-1]=t;
8501+
{ /* local */
8502+
char *bytes;
8503+
cell i=val;
8504+
do {
8505+
char t;
8506+
bytes=(char *)&litq[i++];
8507+
t=bytes[0], bytes[0]=bytes[sizeof(cell)-1], bytes[sizeof(cell)-1]=t;
84918508
#if PAWN_CELL_SIZE>=32
8492-
t=bytes[1], bytes[1]=bytes[sizeof(cell)-2], bytes[sizeof(cell)-2]=t;
8509+
t=bytes[1], bytes[1]=bytes[sizeof(cell)-2], bytes[sizeof(cell)-2]=t;
84938510
#if PAWN_CELL_SIZE==64
8494-
t=bytes[2], bytes[2]=bytes[sizeof(cell)-3], bytes[sizeof(cell)-3]=t;
8495-
t=bytes[3], bytes[3]=bytes[sizeof(cell)-4], bytes[sizeof(cell)-4]=t;
8511+
t=bytes[2], bytes[2]=bytes[sizeof(cell)-3], bytes[sizeof(cell)-3]=t;
8512+
t=bytes[3], bytes[3]=bytes[sizeof(cell)-4], bytes[sizeof(cell)-4]=t;
84968513
#endif // PAWN_CELL_SIZE==64
84978514
#endif // PAWN_CELL_SIZE>=32
8498-
} while (bytes[0]!='\0' && bytes[1]!='\0'
8515+
} while (bytes[0]!='\0' && bytes[1]!='\0'
84998516
#if PAWN_CELL_SIZE>=32
8500-
&& bytes[2]!='\0' && bytes[3]!='\0'
8517+
&& bytes[2]!='\0' && bytes[3]!='\0'
85018518
#if PAWN_CELL_SIZE==64
8502-
&& bytes[4]!='\0' && bytes[5]!='\0' && bytes[6]!='\0' && bytes[7]!='\0'
8519+
&& bytes[4]!='\0' && bytes[5]!='\0' && bytes[6]!='\0' && bytes[7]!='\0'
85038520
#endif // PAWN_CELL_SIZE==64
85048521
#endif // PAWN_CELL_SIZE>=32
8505-
); /* do */
8506-
} /* local */
8522+
); /* do */
8523+
} /* local */
85078524
#endif
8525+
return (char*)&litq[val];
8526+
}
8527+
8528+
static void dopragma(void)
8529+
{
8530+
int bck_litidx;
8531+
int i;
8532+
cell val;
8533+
char *str;
85088534

8535+
needtoken('(');
8536+
8537+
/* The options are specified as strings, e.g.
8538+
* native Func() __pragma("naked", "deprecated - use OtherFunc() instead");
8539+
* In order to process the options, we can reuse the standard string parsing
8540+
* mechanism. This way, as a bonus, we'll also be able to use multi-line
8541+
* strings and the stringization operator.
8542+
*/
8543+
do {
8544+
/* read the option string */
8545+
str=parsestringparam(FALSE,&bck_litidx);
8546+
if (str==NULL)
8547+
continue;
8548+
85098549
/* split the option name from parameters */
8510-
str=(char*)&litq[val];
85118550
for (i=0; str[i]!='\0' && str[i]!=' '; i++)
85128551
/* nothing */;
85138552
if (str[i]!='\0') {
@@ -8571,13 +8610,11 @@ static void dopragma(void)
85718610
error(207); /* unknown #pragma */
85728611
} /* if */
85738612

8574-
next:
85758613
/* remove the string from the literal queue */
85768614
litidx=bck_litidx;
85778615
} while (matchtoken(','));
85788616

85798617
needtoken(')');
8580-
sc_packstr=bck_packstr;
85818618
}
85828619

85838620
static void pragma_apply(symbol *sym)
@@ -8656,3 +8693,77 @@ SC_FUNC void pragma_nodestruct(symbol *sym)
86568693
if (sym->ident==iVARIABLE || sym->ident==iARRAY)
86578694
sym->usage |= uNODESTRUCT;
86588695
}
8696+
8697+
/* do_static_check()
8698+
* Checks compile-time assertions and triggers an error/warning.
8699+
*
8700+
* The 'use_warning' parameter is set to TRUE if warnings are to be
8701+
* used instead of errors to notify assertion failures.
8702+
*/
8703+
SC_FUNC cell do_static_check(int use_warning)
8704+
{
8705+
int already_staging,already_recording,optmsg;
8706+
int ident,index;
8707+
int bck_litidx,recstartpos;
8708+
cell cidx,val;
8709+
char *str;
8710+
8711+
optmsg=FALSE;
8712+
index=0;
8713+
cidx=0;
8714+
8715+
needtoken('(');
8716+
already_staging=stgget(&index,&cidx);
8717+
if (!already_staging) {
8718+
stgset(TRUE); /* start stage-buffering */
8719+
errorset(sEXPRMARK,0);
8720+
} /* if */
8721+
already_recording=pc_isrecording;
8722+
if (!already_recording) {
8723+
recstart();
8724+
recstartpos=0;
8725+
} else {
8726+
recstop(); /* trim out the part of the current line that hasn't been read by lex() yet */
8727+
recstartpos=strlen(pc_recstr);
8728+
recstart(); /* restart recording */
8729+
} /* if */
8730+
ident=expression(&val,NULL,NULL,FALSE);
8731+
if (!already_recording || val==0)
8732+
recstop();
8733+
str=&pc_recstr[recstartpos];
8734+
if (recstartpos!=0 && pc_recstr[recstartpos]==' ')
8735+
str++; /* skip leading whitespace */
8736+
if (ident!=iCONSTEXPR)
8737+
error(8); /* must be constant expression */
8738+
stgdel(index,cidx); /* scratch generated code */
8739+
if (!already_staging) {
8740+
errorset(sEXPRRELEASE,0);
8741+
stgset(FALSE); /* stop stage-buffering */
8742+
} /* if */
8743+
8744+
/* read the optional message */
8745+
if (matchtoken(',')) {
8746+
if (!already_recording) {
8747+
free(pc_recstr);
8748+
pc_recstr=NULL;
8749+
} /* if */
8750+
optmsg=TRUE;
8751+
str=parsestringparam(val!=0,&bck_litidx);
8752+
} /* if */
8753+
8754+
if (val==0) {
8755+
int errnum=use_warning ? 249 /* check failed */
8756+
: 110; /* assertion failed */
8757+
error(errnum,(str!=NULL) ? str : "");
8758+
if (optmsg)
8759+
litidx=bck_litidx; /* remove the string from the literal queue */
8760+
if (already_recording)
8761+
recstart(); /* restart recording */
8762+
} /* if */
8763+
if (!optmsg && !already_recording) {
8764+
free(pc_recstr);
8765+
pc_recstr=NULL;
8766+
} /* if */
8767+
needtoken(')');
8768+
return !!val;
8769+
}

0 commit comments

Comments
 (0)