cppinternals: Guard Macros

1 
1 The Multiple-Include Optimization
1 *********************************
1 
1 Header files are often of the form
1 
1      #ifndef FOO
1      #define FOO
1      ...
1      #endif
1 
1 to prevent the compiler from processing them more than once.  The
1 preprocessor notices such header files, so that if the header file
1 appears in a subsequent '#include' directive and 'FOO' is defined, then
1 it is ignored and it doesn't preprocess or even re-open the file a
1 second time.  This is referred to as the "multiple include
1 optimization".
1 
1    Under what circumstances is such an optimization valid?  If the file
1 were included a second time, it can only be optimized away if that
1 inclusion would result in no tokens to return, and no relevant
1 directives to process.  Therefore the current implementation imposes
1 requirements and makes some allowances as follows:
1 
1   1. There must be no tokens outside the controlling '#if'-'#endif'
1      pair, but whitespace and comments are permitted.
1 
1   2. There must be no directives outside the controlling directive pair,
1      but the "null directive" (a line containing nothing other than a
1      single '#' and possibly whitespace) is permitted.
1 
1   3. The opening directive must be of the form
1 
1           #ifndef FOO
1 
1      or
1 
1           #if !defined FOO     [equivalently, #if !defined(FOO)]
1 
1   4. In the second form above, the tokens forming the '#if' expression
1      must have come directly from the source file--no macro expansion
1      must have been involved.  This is because macro definitions can
1      change, and tracking whether or not a relevant change has been made
1      is not worth the implementation cost.
1 
1   5. There can be no '#else' or '#elif' directives at the outer
1      conditional block level, because they would probably contain
1      something of interest to a subsequent pass.
1 
1    First, when pushing a new file on the buffer stack,
1 '_stack_include_file' sets the controlling macro 'mi_cmacro' to 'NULL',
1 and sets 'mi_valid' to 'true'.  This indicates that the preprocessor has
1 not yet encountered anything that would invalidate the multiple-include
1 optimization.  As described in the next few paragraphs, these two
1 variables having these values effectively indicates top-of-file.
1 
1    When about to return a token that is not part of a directive,
1 '_cpp_lex_token' sets 'mi_valid' to 'false'.  This enforces the
1 constraint that tokens outside the controlling conditional block
1 invalidate the optimization.
1 
1    The 'do_if', when appropriate, and 'do_ifndef' directive handlers
1 pass the controlling macro to the function 'push_conditional'.  cpplib
1 maintains a stack of nested conditional blocks, and after processing
1 every opening conditional this function pushes an 'if_stack' structure
1 onto the stack.  In this structure it records the controlling macro for
1 the block, provided there is one and we're at top-of-file (as described
1 above).  If an '#elif' or '#else' directive is encountered, the
1 controlling macro for that block is cleared to 'NULL'.  Otherwise, it
1 survives until the '#endif' closing the block, upon which 'do_endif'
1 sets 'mi_valid' to true and stores the controlling macro in 'mi_cmacro'.
1 
1    '_cpp_handle_directive' clears 'mi_valid' when processing any
1 directive other than an opening conditional and the null directive.
1 With this, and requiring top-of-file to record a controlling macro, and
1 no '#else' or '#elif' for it to survive and be copied to 'mi_cmacro' by
1 'do_endif', we have enforced the absence of directives outside the main
1 conditional block for the optimization to be on.
1 
1    Note that whilst we are inside the conditional block, 'mi_valid' is
1 likely to be reset to 'false', but this does not matter since the
1 closing '#endif' restores it to 'true' if appropriate.
1 
1    Finally, since '_cpp_lex_direct' pops the file off the buffer stack
1 at 'EOF' without returning a token, if the '#endif' directive was not
1 followed by any tokens, 'mi_valid' is 'true' and '_cpp_pop_file_buffer'
1 remembers the controlling macro associated with the file.  Subsequent
1 calls to 'stack_include_file' result in no buffer being pushed if the
1 controlling macro is defined, effecting the optimization.
1 
1    A quick word on how we handle the
1 
1      #if !defined FOO
1 
1 case.  '_cpp_parse_expr' and 'parse_defined' take steps to see whether
1 the three stages '!', 'defined-expression' and 'end-of-directive' occur
1 in order in a '#if' expression.  If so, they return the guard macro to
1 'do_if' in the variable 'mi_ind_cmacro', and otherwise set it to 'NULL'.
1 'enter_macro_context' sets 'mi_valid' to false, so if a macro was
1 expanded whilst parsing any part of the expression, then the top-of-file
1 test in 'push_conditional' fails and the optimization is turned off.
1