@@ -195,6 +195,7 @@ static void dostate(void);
195
195
static void addwhile (int * ptr );
196
196
static void delwhile (void );
197
197
static int * readwhile (void );
198
+ static char * parsestringparam (int onlycheck ,int * bck_litidx );
198
199
static void dopragma (void );
199
200
static void pragma_apply (symbol * sym );
200
201
@@ -842,6 +843,8 @@ int pc_compile(int argc, char *argv[])
842
843
line_sym = NULL ;
843
844
free (pc_deprecate );
844
845
pc_deprecate = NULL ;
846
+ free (pc_recstr );
847
+ pc_recstr = NULL ;
845
848
hashtable_term (& symbol_cache_ht );
846
849
delete_consttable (& tagname_tab );
847
850
delete_consttable (& libname_tab );
@@ -1855,6 +1858,13 @@ static void parse(void)
1855
1858
case tFORWARD :
1856
1859
funcstub (FALSE);
1857
1860
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 */
1858
1868
case '}' :
1859
1869
error (54 ); /* unmatched closing brace */
1860
1870
break ;
@@ -8438,76 +8448,105 @@ static int *readwhile(void)
8438
8448
} /* if */
8439
8449
}
8440
8450
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 )
8442
8457
{
8443
8458
int tok ;
8444
- int bck_litidx ,bck_packstr ;
8445
- int i ;
8459
+ int bck_packstr ;
8446
8460
cell val ;
8447
8461
char * str ;
8448
8462
8449
- needtoken ( '(' );
8463
+ assert ( bck_litidx != NULL );
8450
8464
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 */
8460
8468
bck_packstr = sc_packstr ;
8461
8469
sc_packstr = TRUE;
8462
8470
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 ];
8479
8486
} /* if */
8480
- assert (litidx > bck_litidx );
8487
+ error (1 ,sc_tokens [tSTRING - tFIRST ],str );
8488
+ return NULL ;
8489
+ } /* if */
8490
+ assert (litidx > * bck_litidx );
8481
8491
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 */
8483
8500
#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 ;
8491
8508
#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 ;
8493
8510
#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 ;
8496
8513
#endif // PAWN_CELL_SIZE==64
8497
8514
#endif // PAWN_CELL_SIZE>=32
8498
- } while (bytes [0 ]!= '\0' && bytes [1 ]!= '\0'
8515
+ } while (bytes [0 ]!= '\0' && bytes [1 ]!= '\0'
8499
8516
#if PAWN_CELL_SIZE >=32
8500
- && bytes [2 ]!= '\0' && bytes [3 ]!= '\0'
8517
+ && bytes [2 ]!= '\0' && bytes [3 ]!= '\0'
8501
8518
#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'
8503
8520
#endif // PAWN_CELL_SIZE==64
8504
8521
#endif // PAWN_CELL_SIZE>=32
8505
- ); /* do */
8506
- } /* local */
8522
+ ); /* do */
8523
+ } /* local */
8507
8524
#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 ;
8508
8534
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
+
8509
8549
/* split the option name from parameters */
8510
- str = (char * )& litq [val ];
8511
8550
for (i = 0 ; str [i ]!= '\0' && str [i ]!= ' ' ; i ++ )
8512
8551
/* nothing */ ;
8513
8552
if (str [i ]!= '\0' ) {
@@ -8571,13 +8610,11 @@ static void dopragma(void)
8571
8610
error (207 ); /* unknown #pragma */
8572
8611
} /* if */
8573
8612
8574
- next :
8575
8613
/* remove the string from the literal queue */
8576
8614
litidx = bck_litidx ;
8577
8615
} while (matchtoken (',' ));
8578
8616
8579
8617
needtoken (')' );
8580
- sc_packstr = bck_packstr ;
8581
8618
}
8582
8619
8583
8620
static void pragma_apply (symbol * sym )
@@ -8656,3 +8693,77 @@ SC_FUNC void pragma_nodestruct(symbol *sym)
8656
8693
if (sym -> ident == iVARIABLE || sym -> ident == iARRAY )
8657
8694
sym -> usage |= uNODESTRUCT ;
8658
8695
}
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