Files
tompzf 6ed4b1534e Precommit (#1)
* first commit

* cleanup
2025-11-04 13:28:06 +01:00

240 lines
12 KiB
C++

#ifndef PREPROC_H
#define PREPROC_H
#include "token.h"
#include "codepos.h"
#include "environment.h"
#include <filesystem>
// Forward declaration
class CLexer;
class CParser;
/**
* @brief Preprocessing class
*/
class CPreprocessor
{
public:
/**
* @brief Constructor
* @param[in] rParser Reference to the parser.
*/
CPreprocessor(CParser& rParser);
/**
* @brief Process preprocessor line
* @param[in] rCode Reference to the code holding the line the might contain a preprocessor direction.
* @param[in] rptrContext Reference to the smart pointer to the source code context.
* @return Returns a meta token if one is available; an empty token otherwise.
*/
CToken ProcessPreproc(CCodePos& rCode, const CContextPtr& rptrContext);
/**
* @brief Checks whether currently a conditional section is being processed. If so, this function will trigger an exception
* for a missing @c \#endif' directive.
* @param[in] rCode Reference to the code holding the line the might contain a preprocessor direction.
*/
void FinalProcessing(const CCodePos& rCode);
/**
* @brief Processing enabled. Part of conditional inclusion.
* @remarks If processing is disabled, lines should be skipped. Preprocessor directives should be processed anyway.
* @return Returns whether to process current code.
*/
bool CurrentSectionEnabled() const;
/**
* @brief Include a file. Function prototype to be implemented by the parser.
* @param[in] rpath Reference to the source file path. Must be a valid path.
* @param[in] bLocal When set, the include file is a local include. Otherwise it represents a global include.
*/
virtual void IncludeFile(const std::filesystem::path& rpath, bool bLocal) = 0;
/**
* @brief Get the environment. Function prototype to be implemented by the parser.
* @return Reference to the environment.
*/
virtual CIdlCompilerEnvironment& GetEnvironment() = 0;
private:
/**
* @brief Process the define macro directive.
* @details The code contains the 'define' directive followed by a macro name and optionally by zero or more parameters
* between parenthesis and optionally the value the macro should be replaced with. The value could contain the operator '#'
* preceding the parameter to stringificate the parameter content and the operator '##' preceding or succeeding the parameter
* to concatenate the result to the identifier adjacent identifier.
* @param[in, out] rLexer Reference to the lexer to use for parsing.
* @param[in, out] rCode Reference to the code following the define keyword.
* @param[in] rptrContext Reference to the smart pointer to the source code context.
*/
void ProcessDefine(CLexer& rLexer, CCodePos& rCode, const CContextPtr& rptrContext);
/**
* @brief Process the undef macro directive.
* @details The code contains the 'undef' directive followed by a macro name.
* @param[in, out] rLexer Reference to the lexer to use for parsing.
* @param[in, out] rCode Reference to the code following the define keyword.
* @param[in] rptrContext Reference to the smart pointer to the source code context.
*/
void ProcessUndef(CLexer& rLexer, CCodePos& rCode, const CContextPtr& rptrContext);
/**
* @brief Process the include directive.
* @details The code contains 'include' directive followed by the file to include between quotes or between angle-brackets.
* Filenames between quotes can be relative using the current directory as a start or absolute. First the current directory
* is used to search for the file, then the directories of the provided search path is used to search for the file. Filenames
* between angle-brackets must be relative. The search path is used to search for the file.
* @param[in, out] rLexer Reference to the lexer to use for parsing.
* @param[in, out] rCode Reference to the code following the define keyword.
* @param[out] rbLocal When set, the include statement was referring to a local file; otherwise global include.
* @param[in] rptrContext Reference to the smart pointer to the source code context.
*/
void ProcessInclude(CLexer& rLexer, CCodePos& rCode, const CContextPtr& rptrContext, bool& rbLocal);
/**
* @brief Process the if directive.
* @details The code contains the 'if' directive followed by a conditional expression.
* @param[in, out] rLexer Reference to the lexer to use for parsing.
* @param[in, out] rCode Reference to the code following the if or elif keyword.
* @param[in] rptrContext Reference to the smart pointer to the source code context.
*/
void ProcessIf(CLexer& rLexer, CCodePos& rCode, const CContextPtr& rptrContext);
/**
* @brief Process the ifdef or ifndef directive.
* @details The code contains the 'ifdef' or the 'ifndef' directive followed by a macro name.
* @param[in, out] rLexer Reference to the lexer to use for parsing.
* @param[in, out] rCode Reference to the code following the ifdef or ifndef keyword.
* @param[in] bInverted When set, the ifndef directive should be used; otherwise the ifdef directive.
* @param[in] rptrContext Reference to the smart pointer to the source code context.
*/
void ProcessIfDef(CLexer& rLexer, CCodePos& rCode, const CContextPtr& rptrContext, bool bInverted);
/**
* @brief Process the elif directive.
* @details The code contains the 'elif' directive followed by a conditional expression.
* @param[in, out] rLexer Reference to the lexer to use for parsing.
* @param[in, out] rCode Reference to the code following the if or elif keyword.
* @param[in] rptrContext Reference to the smart pointer to the source code context.
*/
void ProcessElif(CLexer& rLexer, CCodePos& rCode, const CContextPtr& rptrContext);
/**
* @brief Process the else directive.
* @details The code contains the 'else' directive.
* @param[in, out] rLexer Reference to the lexer to use for parsing.
* @param[in, out] rCode Reference to the code following the else keyword.
* @param[in] rptrContext Reference to the smart pointer to the source code context.
*/
void ProcessElse(CLexer& rLexer, const CCodePos& rCode, const CContextPtr& rptrContext);
/**
* @brief Process the endif directive.
* @details The code contains the 'endif' directive.
* @param[in, out] rLexer Reference to the lexer to use for parsing.
* @param[in, out] rCode Reference to the code following the endif keyword.
* @param[in] rptrContext Reference to the smart pointer to the source code context.
*/
void ProcessEndif(CLexer& rLexer, const CCodePos& rCode, const CContextPtr& rptrContext);
/**
* @brief Process the verbatim directive.
* @details The code contains the 'verbatim' directive.
* @param[in, out] rLexer Reference to the lexer to use for parsing.
* @param[in, out] rCode Reference to the code following the endif keyword.
* @param[in] rptrContext Reference to the smart pointer to the source code context.
*/
void ProcessVerbatim(CLexer& rLexer, CCodePos& rCode, const CContextPtr& rptrContext);
/**
* @brief Process the verbatim block directives.
* @details The code contains the 'verbatim_begin' and "verbatim_end" directives.
* @param[in, out] rLexer Reference to the lexer to use for parsing.
* @param[in, out] rCode Reference to the code following the endif keyword.
* @param[in] rptrContext Reference to the smart pointer to the source code context.
*/
void ProcessVerbatimBlock(CLexer& rLexer, CCodePos& rCode, const CContextPtr& rptrContext);
/**
* @brief Calculate the conditional value based on the precedence of operators.
* @details Parse through the condition string and calculate a value. Values and arithmetic operators are read and a result
* is calculated as long as the operator precedence doesn't undercut the current precedence.
* - macros are expanded
* - defined operator can be used to check for the existence of a macro
* - unknown identifiers are zero
* - integers are casted to int64_t
* - chars are casted to int64_t
* - operators that are allowed + - / % * & | ^ ~ << >> && || ! > >= < <= == !=
* - parenthesis are allowed
*
* Operator precedence:
* +------------+-----------------+-------------------------------------------+
* | precedence | operators | description |
* +============+=================+===========================================+
* | 0 | ~ ! ( ) defined | Bitwise NOT, logical NOT and parenthesis |
* +------------+-----------------+-------------------------------------------+
* | 1 | * / % | Multiplication, division, and remainder |
* +------------+-----------------+-------------------------------------------+
* | 2 | + - | Addition and subtraction |
* +------------+-----------------+-------------------------------------------+
* | 3 | << >> | Bitwise left shift and right shift |
* +------------+-----------------+-------------------------------------------+
* | 4 | < <= > >= | Relational operators |
* +------------+-----------------+-------------------------------------------+
* | 5 | == != | Equality operators |
* +------------+-----------------+-------------------------------------------+
* | 6 | & | Bitwise AND |
* +------------+-----------------+-------------------------------------------+
* | 7 | ^ | Bitwise XOR |
* +------------+-----------------+-------------------------------------------+
* | 8 | | | Bitwise OR |
* +------------+-----------------+-------------------------------------------+
* | 9 | && | Logical AND |
* +------------+-----------------+-------------------------------------------+
* | 10 | || | Logical OR |
* +------------+-----------------+-------------------------------------------+
* @param[in, out] rLexer Reference to the lexer.
* @param[in, out] rCode Reference to the code. The code position will be updated.
* @param[in] rptrContext Reference to the smart pointer to the source code context.
* @param[in] uiPrecedence [in] Current precedence level (default 100).
* @return Returns the calculated value
*/
int64_t ConditionalCalc(CLexer& rLexer, CCodePos& rCode, const CContextPtr& rptrContext, uint32_t uiPrecedence = 100);
/**
* @brief Conditional inclusion control
*/
enum class EConditionalInclusion
{
if_section, ///< Within if section: endif, elif, else could be defined
else_section ///< Within else section: endif could be defined
};
/**
* @brief Conditional processing control
*/
enum class EConditionalProcessing
{
disabled, ///< Disabled by a parent conditional section.
current, ///< The current conditional section is being processed.
previous, ///< A previous conditional section was processed.
future ///< A future conditional section might be processed.
};
/**
* @brief Conditional processing control.
*/
struct SConditionalControl
{
EConditionalInclusion m_eInclusionControl; ///< The current level of inclusion
EConditionalProcessing m_eProcessingControl; ///< The current level of processing.
};
CParser& m_rParser; ///< Reference to the parser
std::stack<SConditionalControl> m_stackConditional; ///< Stack with the current valid
};
#endif // !defined PREPROC_H