Skip to content

Commit

Permalink
fbc: #ELSEIFDEF, #ELSEIFNDEF pre-processor conditional compilation di…
Browse files Browse the repository at this point in the history
…rectives

- 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
  • Loading branch information
jayrm committed Sep 30, 2023
1 parent be87cc2 commit d1413d4
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 32 deletions.
1 change: 1 addition & 0 deletions changelog.txt
Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions doc/manual/templates/default/keywords.lst
Expand Up @@ -2,6 +2,8 @@
#define
#else
#elseif
#elseifdef
#elseifndef
#endif
#endmacro
#error
Expand Down
28 changes: 21 additions & 7 deletions src/compiler/pp-cond.bas
Expand Up @@ -112,25 +112,38 @@ 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( )
exit sub
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( )
Expand Down Expand Up @@ -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
Expand Down
52 changes: 27 additions & 25 deletions src/compiler/pp.bas
Expand Up @@ -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) _
}

Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/pp.bi
Expand Up @@ -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
Expand Down
119 changes: 119 additions & 0 deletions 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

0 comments on commit d1413d4

Please sign in to comment.