From d1413d45c1cc5b3e807e0eb153922cb6c63877fb Mon Sep 17 00:00:00 2001 From: coderJeff Date: Sat, 30 Sep 2023 09:04:25 -0400 Subject: [PATCH] fbc: #ELSEIFDEF, #ELSEIFNDEF pre-processor conditional compilation directives - add '#elseifdef SYMBOL' to test symbol defined - add '#elseifndef SYMBOL' to test symbol not definde Abbreviated conditionals: - #ifdef A - #elseifdef B - #elseifndef C - ... etc - #endif Instead of: - #if defined( A ) - #elseif defined( B ) - #elseif not defined( C ) - ... etc - #endif --- changelog.txt | 1 + doc/manual/templates/default/keywords.lst | 2 + src/compiler/pp-cond.bas | 28 +++-- src/compiler/pp.bas | 52 +++++----- src/compiler/pp.bi | 2 + tests/pp/ifdef.bas | 119 ++++++++++++++++++++++ 6 files changed, 172 insertions(+), 32 deletions(-) create mode 100644 tests/pp/ifdef.bas diff --git a/changelog.txt b/changelog.txt index 94b761e37c..5df9fa9c22 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,7 @@ Version 1.20.0 [added] - x86_64: optimize SHL MOD INTDIV to use 32-bit operation when result will be converted to long/ulong +- fbc: #ELSEIFDEF and #ELSEIFNDEF pre-processor conditional compilation directives [fixed] - github #410: give consistent floating point comparisons results involving NaNs. diff --git a/doc/manual/templates/default/keywords.lst b/doc/manual/templates/default/keywords.lst index cffbbefc2c..a880388da3 100644 --- a/doc/manual/templates/default/keywords.lst +++ b/doc/manual/templates/default/keywords.lst @@ -2,6 +2,8 @@ #define #else #elseif +#elseifdef +#elseifndef #endif #endmacro #error diff --git a/src/compiler/pp-cond.bas b/src/compiler/pp-cond.bas index 34bfeeb880..1e373722f4 100644 --- a/src/compiler/pp-cond.bas +++ b/src/compiler/pp-cond.bas @@ -112,11 +112,22 @@ sub ppCondElse( ) exit sub end if - '' ELSEIF? - if( lexGetToken( LEXCHECK_KWDNAMESPC ) = FB_TK_PP_ELSEIF ) then - lexSkipToken( LEXCHECK_POST_SUFFIX ) + select case as const lexGetToken( LEXCHECK_KWDNAMESPC ) - istrue = ppExpression( ) + '' ELSEIF | ELSEIFDEF | ELSEIFNDEF? + case FB_TK_PP_ELSEIF, FB_TK_PP_ELSEIFDEF, FB_TK_PP_ELSEIFNDEF + + select case as const lexGetToken( LEXCHECK_KWDNAMESPC ) + case FB_TK_PP_ELSEIF + lexSkipToken( LEXCHECK_POST_SUFFIX ) + istrue = ppExpression( ) + case FB_TK_PP_ELSEIFDEF + lexSkipToken( LEXCHECK_NODEFINE or LEXCHECK_POST_SUFFIX ) + istrue = (cIdentifierOrUDTMember( ) <> NULL) + case FB_TK_PP_ELSEIFNDEF + lexSkipToken( LEXCHECK_NODEFINE or LEXCHECK_POST_SUFFIX ) + istrue = (cIdentifierOrUDTMember( ) = NULL) + end select if( pptb(pp.level).istrue ) then ppSkip( ) @@ -124,13 +135,15 @@ sub ppCondElse( ) end if pptb(pp.level).istrue = istrue + '' ELSE - else + case else lexSkipToken( LEXCHECK_POST_SUFFIX ) pptb(pp.level).elsecnt += 1 pptb(pp.level).istrue = not pptb(pp.level).istrue - end if + + end select if( pptb(pp.level).istrue = FALSE ) then ppSkip( ) @@ -199,7 +212,8 @@ private sub ppSkip( ) case FB_TK_PP_IF, FB_TK_PP_IFDEF, FB_TK_PP_IFNDEF iflevel += 1 - case FB_TK_PP_ELSE, FB_TK_PP_ELSEIF + case FB_TK_PP_ELSE, FB_TK_PP_ELSEIF, _ + FB_TK_PP_ELSEIFDEF, FB_TK_PP_ELSEIFNDEF select case( iflevel ) case pp.level pp.skipping = FALSE diff --git a/src/compiler/pp.bas b/src/compiler/pp.bas index c186ff19c0..8a476cc163 100644 --- a/src/compiler/pp.bas +++ b/src/compiler/pp.bas @@ -45,33 +45,35 @@ declare sub ppLookup _ '' globals dim shared as PP_CTX pp -const SYMB_MAXKEYWORDS = 24 +const SYMB_MAXKEYWORDS = 26 dim shared kwdTb( 0 to SYMB_MAXKEYWORDS-1 ) as SYMBKWD => _ { _ - (@"IF" , FB_TK_PP_IF ), _ - (@"IFDEF" , FB_TK_PP_IFDEF ), _ - (@"IFNDEF" , FB_TK_PP_IFNDEF ), _ - (@"ELSE" , FB_TK_PP_ELSE ), _ - (@"ELSEIF" , FB_TK_PP_ELSEIF ), _ - (@"ENDIF" , FB_TK_PP_ENDIF ), _ - (@"DEFINE" , FB_TK_PP_DEFINE ), _ - (@"UNDEF" , FB_TK_PP_UNDEF ), _ - (@"MACRO" , FB_TK_PP_MACRO ), _ - (@"ENDMACRO", FB_TK_PP_ENDMACRO ), _ - (@"INCLUDE" , FB_TK_PP_INCLUDE ), _ - (@"LIBPATH" , FB_TK_PP_LIBPATH ), _ - (@"INCLIB" , FB_TK_PP_INCLIB ), _ - (@"PRAGMA" , FB_TK_PP_PRAGMA ), _ - (@"PRINT" , FB_TK_PP_PRINT ), _ - (@"ERROR" , FB_TK_PP_ERROR ), _ - (@"LINE" , FB_TK_PP_LINE ), _ - (@"LANG" , FB_TK_PP_LANG ), _ - (@"ASSERT" , FB_TK_PP_ASSERT ), _ - (@"CMDLINE" , FB_TK_PP_CMDLINE ), _ - (@"DUMP" , FB_TK_PP_DUMP ), _ - (@"ODUMP" , FB_TK_PP_ODUMP ), _ - (@"LOOKUP" , FB_TK_PP_LOOKUP ), _ + (@"IF" , FB_TK_PP_IF ), _ + (@"IFDEF" , FB_TK_PP_IFDEF ), _ + (@"IFNDEF" , FB_TK_PP_IFNDEF ), _ + (@"ELSE" , FB_TK_PP_ELSE ), _ + (@"ELSEIF" , FB_TK_PP_ELSEIF ), _ + (@"ELSEIFDEF" , FB_TK_PP_ELSEIFDEF ), _ + (@"ELSEIFNDEF", FB_TK_PP_ELSEIFNDEF ), _ + (@"ENDIF" , FB_TK_PP_ENDIF ), _ + (@"DEFINE" , FB_TK_PP_DEFINE ), _ + (@"UNDEF" , FB_TK_PP_UNDEF ), _ + (@"MACRO" , FB_TK_PP_MACRO ), _ + (@"ENDMACRO" , FB_TK_PP_ENDMACRO ), _ + (@"INCLUDE" , FB_TK_PP_INCLUDE ), _ + (@"LIBPATH" , FB_TK_PP_LIBPATH ), _ + (@"INCLIB" , FB_TK_PP_INCLIB ), _ + (@"PRAGMA" , FB_TK_PP_PRAGMA ), _ + (@"PRINT" , FB_TK_PP_PRINT ), _ + (@"ERROR" , FB_TK_PP_ERROR ), _ + (@"LINE" , FB_TK_PP_LINE ), _ + (@"LANG" , FB_TK_PP_LANG ), _ + (@"ASSERT" , FB_TK_PP_ASSERT ), _ + (@"CMDLINE" , FB_TK_PP_CMDLINE ), _ + (@"DUMP" , FB_TK_PP_DUMP ), _ + (@"ODUMP" , FB_TK_PP_ODUMP ), _ + (@"LOOKUP" , FB_TK_PP_LOOKUP ), _ (NULL) _ } @@ -248,7 +250,7 @@ sub ppParse( ) ppCondIf( ) '' ELSE - case FB_TK_PP_ELSE, FB_TK_PP_ELSEIF + case FB_TK_PP_ELSE, FB_TK_PP_ELSEIF, FB_TK_PP_ELSEIFDEF, FB_TK_PP_ELSEIFNDEF ppCondElse( ) '' ENDIF diff --git a/src/compiler/pp.bi b/src/compiler/pp.bi index e8efb61c06..823070f00c 100644 --- a/src/compiler/pp.bi +++ b/src/compiler/pp.bi @@ -9,6 +9,8 @@ enum FB_TOKEN_PP FB_TK_PP_IFNDEF FB_TK_PP_ELSE FB_TK_PP_ELSEIF + FB_TK_PP_ELSEIFDEF + FB_TK_PP_ELSEIFNDEF FB_TK_PP_ENDIF FB_TK_PP_DEFINE FB_TK_PP_UNDEF diff --git a/tests/pp/ifdef.bas b/tests/pp/ifdef.bas new file mode 100644 index 0000000000..8e216f116b --- /dev/null +++ b/tests/pp/ifdef.bas @@ -0,0 +1,119 @@ +#include "fbcunit.bi" + +'' - don't mix false/true intrinsic constants +'' of the compiler in with these tests +#undef FALSE +#undef TRUE + +#define FALSE 0 +#define TRUE NOT FALSE + +#define A_DEFINED + +SUITE( fbc_tests.pp.ifdef ) + + TEST( ifdefTestDefined ) + #ifdef A_DEFINED + CU_PASS("") + #else + CU_FAIL_FATAL("") + #endif + END_TEST + + TEST( ifdefTestNotDefined ) + #ifdef B_NOT_DEFINED + CU_FAIL_FATAL("") + #else + CU_PASS("") + #endif + END_TEST + + TEST( ifndefTestDefined ) + #ifndef A_DEFINED + CU_FAIL_FATAL("") + #else + CU_PASS("") + #endif + END_TEST + + TEST( ifndefTestNotDefined ) + #ifndef B_NOT_DEFINED + CU_PASS("") + #else + CU_FAIL_FATAL("") + #endif + END_TEST + + TEST( elseifdefTestDefined ) + #if 0 + CU_FAIL_FATAL("") + #elseifdef A_DEFINED + CU_PASS("") + #else + CU_FAIL_FATAL("") + #endif + + #if 1 + CU_PASS("") + #elseifdef A_DEFINED + CU_FAIL_FATAL("") + #else + CU_FAIL_FATAL("") + #endif + END_TEST + + TEST( elseifdefTestNotDefined ) + #if 0 + CU_FAIL_FATAL("") + #elseifdef B_NOT_DEFINED + CU_FAIL_FATAL("") + #else + CU_PASS("") + #endif + + #if 1 + CU_PASS("") + #elseifdef B_NOT_DEFINED + CU_FAIL_FATAL("") + #else + CU_FAIL_FATAL("") + #endif + END_TEST + + TEST( elseifndefTestDefined ) + #if 0 + CU_FAIL_FATAL("") + #elseifndef A_DEFINED + CU_FAIL_FATAL("") + #else + CU_PASS("") + #endif + + #if 1 + CU_PASS("") + #elseifndef A_DEFINED + CU_FAIL_FATAL("") + #else + CU_FAIL_FATAL("") + #endif + END_TEST + + TEST( elseifndefTestNotDefined ) + #if 0 + CU_FAIL_FATAL("") + #elseifndef B_NOT_DEFINED + CU_PASS("") + #else + CU_FAIL_FATAL("") + #endif + + #if 1 + CU_PASS("") + #elseifndef B_NOT_DEFINED + CU_FAIL_FATAL("") + #else + CU_FAIL_FATAL("") + #endif + END_TEST + +END_SUITE