Module implementing a full C-preprocessor-style constant expression evaluator using a top-down recursive descent parser. The module provides the ability to evaluate integer constant expressions of the kind used in classical preprocessor. This includes support for:
defined(identifier) operator0...), hexadecimal (0x...), and binary (0b...) basesThe implementation consists of two major phases:
defined operator (with or without parentheses), numbers in all supported bases, identifiers, and parentheses. Whitespace is ignored except as a token separator.Parsing and evaluation via top-down recursive descent A classic predictive (LL(1)) recursive descent parser is used, where each non-terminal in the grammar is implemented as a separate parsing function with the exact precedence level. The grammar is directly derived from the C standard operator precedence table:
parse_expression ? parse_conditional parse_conditional ? parse_or (parse_or '?' parse_expression ':' parse_conditional) parse_or ? parse_and ( '||' parse_and )* parse_and ? parse_bitwise_or ( '&&' parse_bitwise_or )* parse_bitwise_or ? parse_bitwise_xor ( '|' parse_bitwise_xor )* parse_bitwise_xor ? parse_bitwise_and ( '^' parse_bitwise_and )* parse_bitwise_and ? parse_equality ( '&' parse_equality )* parse_equality ? parse_relational ( ('==' | '!=') parse_relational )* parse_relational ? parse_shifting ( ('<' | '>' | '<=' | '>=') parse_shifting )* parse_shifting ? parse_additive ( ('<<' | '>>') parse_additive )* parse_additive ? parse_multiplicative ( ('+' | '-') parse_multiplicative )* parse_multiplicative ? parse_power ( ('' | '/' | '') parse_power ) parse_power ? parse_unary ( '**' parse_unary )* (right-associative) parse_unary ? ('!' | '-' | '+' | '~') parse_unary | parse_atom parse_atom ? number | identifier (macro expansion) | 'defined' ( identifier ) | 'defined' identifier | '(' parse_expression ')'
Each parsing function consumes tokens from the global position pos and returns the integer value of the sub-expression it recognizes. Because the grammar is factored by precedence, left-associativity is achieved naturally via left-recursive loops, while right-associativity for the power operator (**) is handled by calling parse_unary on the right-hand side first.
Macro expansion occurs lazily inside parse_atom when an identifier token is encountered:
defined operator yields 1 or 0 depending on whether the identifier exists.The parser is fully re-entrant and has no global state except the verbose flag from the logging module (used only for debugging).
Public interface:
This design guarantees correct operator precedence without the need for an explicit abstract syntax tree or stack-based shunting-yard algorithm, while remaining easy to read, maintain, and extend.
Data Types | |
| interface | strtol |
| Converts a string to integer. More... | |
| logical function, public evaluate_expression | ( | character(*), intent(in) | expr, |
| type(macro), dimension(:), intent(in) | macros, | ||
| integer, intent(out), optional | val ) |
Evaluates a preprocessor-style expression with macro substitution. Tokenizes the input expression, expands macros where appropriate, parses it according to operator precedence, and computes the integer result. Returns .true. if evaluation succeeded and the result is non-zero.
| [in] | expr | Expression string to evaluate |
| [in] | macros | Array of defined macros for substitution and defined() checks |
| [out] | val | Optional integer result of the evaluation |
Remarks
Definition at line 92 of file operators.f90.
|
private |
Parses additive expressions (+, -).
| [in] | tokens | Array of tokens to parse |
| [in] | ntokens | Number of valid tokens in the array |
| [in,out] | pos | Current parsing position (updated as tokens are consumed) |
| [in] | macros | Defined macros for expansion and defined() checks |
Remarks
Definition at line 445 of file operators.f90.
|
private |
Parses logical AND expressions (&&).
| [in] | tokens | Array of tokens to parse |
| [in] | ntokens | Number of valid tokens in the array |
| [in,out] | pos | Current parsing position (updated as tokens are consumed) |
| [in] | macros | Defined macros for expansion and defined() checks |
Remarks
Definition at line 226 of file operators.f90.
|
private |
Parses primary expressions: numbers, identifiers, defined(...), parentheses.
| [in] | tokens | Array of tokens to parse |
| [in] | ntokens | Number of valid tokens in the array |
| [in,out] | pos | Current parsing position (updated as tokens are consumed) |
| [in] | macros | Defined macros for expansion and defined() checks |
Remarks
Definition at line 581 of file operators.f90.
|
private |
Parses bitwise AND expressions (&).
| [in] | tokens | Array of tokens to parse |
| [in] | ntokens | Number of valid tokens in the array |
| [in,out] | pos | Current parsing position (updated as tokens are consumed) |
| [in] | macros | Defined macros for expansion and defined() checks |
Remarks
Definition at line 307 of file operators.f90.
|
private |
Parses bitwise OR expressions (|).
| [in] | tokens | Array of tokens to parse |
| [in] | ntokens | Number of valid tokens in the array |
| [in,out] | pos | Current parsing position (updated as tokens are consumed) |
| [in] | macros | Defined macros for expansion and defined() checks |
Remarks
Definition at line 253 of file operators.f90.
|
private |
Parses bitwise XOR expressions (^).
| [in] | tokens | Array of tokens to parse |
| [in] | ntokens | Number of valid tokens in the array |
| [in,out] | pos | Current parsing position (updated as tokens are consumed) |
| [in] | macros | Defined macros for expansion and defined() checks |
Remarks
Definition at line 280 of file operators.f90.
|
private |
Parses conditional expressions (?:). Right-associative.
| [in] | tokens | Array of tokens to parse |
| [in] | ntokens | Number of valid tokens in the array |
| [in,out] | pos | Current parsing position (updated as tokens are consumed) |
| [in] | macros | Defined macros for expansion and defined() checks |
Remarks
Definition at line 147 of file operators.f90.
|
private |
Parses equality/inequality expressions (==, @param[in] tokens Array of tokens to parse @param[in] ntokens Number of valid tokens in the array @param[inout] pos Current parsing position (updated as tokens are consumed) @param[in] macros Defined macros for expansion anddefined()` checks.
Remarks
Definition at line 334 of file operators.f90.
| recursive integer function, public parse_expression | ( | type(token), dimension(:), intent(in) | tokens, |
| integer, intent(in) | ntokens, | ||
| integer, intent(inout) | pos, | ||
| type(macro), dimension(:), intent(in) | macros ) |
Parses a sequence of tokens starting at position pos as a full expression. Entry point for the recursive descent parser. Delegates to parse_or().
| [in] | tokens | Array of tokens to parse |
| [in] | ntokens | Number of valid tokens in the array |
| [in,out] | pos | Current parsing position (updated as tokens are consumed) |
| [in] | macros | Defined macros for expansion and defined() checks |
Remarks
Definition at line 129 of file operators.f90.
|
private |
Parses multiplicative expressions (*, /, %).
| [in] | tokens | Array of tokens to parse |
| [in] | ntokens | Number of valid tokens in the array |
| [in,out] | pos | Current parsing position (updated as tokens are consumed) |
| [in] | macros | Defined macros for expansion and defined() checks |
Remarks
Definition at line 479 of file operators.f90.
|
private |
Parses logical OR expressions (||).
| [in] | tokens | Array of tokens to parse |
| [in] | ntokens | Number of valid tokens in the array |
| [in,out] | pos | Current parsing position (updated as tokens are consumed) |
| [in] | macros | Defined macros for expansion and defined() checks |
Remarks
Definition at line 200 of file operators.f90.
|
private |
Parses exponentiation (**). Right-associative.
| [in] | tokens | Array of tokens to parse |
| [in] | ntokens | Number of valid tokens in the array |
| [in,out] | pos | Current parsing position (updated as tokens are consumed) |
| [in] | macros | Defined macros for expansion and defined() checks |
Remarks
Definition at line 517 of file operators.f90.
|
private |
Parses relational expressions (<, >, <=, >=).
| [in] | tokens | Array of tokens to parse |
| [in] | ntokens | Number of valid tokens in the array |
| [in,out] | pos | Current parsing position (updated as tokens are consumed) |
| [in] | macros | Defined macros for expansion and defined() checks |
Remarks
Definition at line 368 of file operators.f90.
|
private |
Parses shift expressions (<<, >>).
| [in] | tokens | Array of tokens to parse |
| [in] | ntokens | Number of valid tokens in the array |
| [in,out] | pos | Current parsing position (updated as tokens are consumed) |
| [in] | macros | Defined macros for expansion and defined() checks |
Remarks
Definition at line 411 of file operators.f90.
|
private |
Parses unary operators ( @param[in] tokens Array of tokens to parse @param[in] ntokens Number of valid tokens in the array @param[inout] pos Current parsing position (updated as tokens are consumed) @param[in] macros Defined macros for expansion anddefined()` checks.
Remarks
Definition at line 545 of file operators.f90.