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:
The implementation consists of two major phases:
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:
The parser is fully re-entrant and has no global state.
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... | |
|
private |
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 98 of file operators.f90.
|
private |
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 |
| [in] | ctx | Context |
| [out] | val | (optional) integer result of the evaluation |
Remarks
Definition at line 122 of file operators.f90.
|
private |
Parses additive expressions (+, -).
| [in] | expr | Expression to be processed |
| [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 |
| [in] | ctx | Context |
Remarks
Definition at line 515 of file operators.f90.
|
private |
Parses logical AND expressions (&&).
| [in] | expr | Expression to be processed |
| [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 |
| [in] | ctx | Context |
Remarks
Definition at line 275 of file operators.f90.
|
private |
Parses primary expressions: numbers, identifiers, defined(...), parentheses.
| [in] | expr | Input expression |
| [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 |
| [in] | ctx | Context |
Remarks
Definition at line 660 of file operators.f90.
|
private |
Parses bitwise AND expressions (&).
| [in] | expr | Expression to be processed |
| [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 |
| [in] | ctx | Context |
Remarks
Definition at line 365 of file operators.f90.
|
private |
Parses bitwise OR expressions (|).
| [in] | expr | Expression to be processed |
| [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 |
| [in] | ctx | Context |
Remarks
Definition at line 305 of file operators.f90.
|
private |
Parses bitwise XOR expressions (^).
| [in] | expr | Expression to be processed |
| [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 |
| [in] | ctx | Context |
Remarks
Definition at line 335 of file operators.f90.
|
private |
Parses conditional expressions (?:). Right-associative.
| [in] | expr | Expression to be processed |
| [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 |
| [in] | ctx | Context |
Remarks
Definition at line 191 of file operators.f90.
|
private |
Parses equality/inequality expressions (==, @param[in] expr Expression to be processed @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 and defined()` checks.
| [in] | ctx | Context |
Remarks
Definition at line 395 of file operators.f90.
|
private |
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] | expr | Expression to be processed |
| [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 |
| [in] | ctx | Context |
Remarks
Definition at line 169 of file operators.f90.
|
private |
Parses multiplicative expressions (*, /, %).
| [in] | expr | Expression to be processed |
| [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 |
| [in] | ctx | Context |
Remarks
Definition at line 552 of file operators.f90.
|
private |
Parses logical OR expressions (||).
| [in] | expr | Expression to be processed |
| [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 |
| [in] | ctx | Context |
Remarks
Definition at line 245 of file operators.f90.
|
private |
Parses exponentiation (**). Right-associative.
| [in] | expr | Expression to be processed |
| [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 |
| [in] | ctx | Context |
Remarks
Definition at line 593 of file operators.f90.
|
private |
Parses relational expressions (<, >, <=, >=).
| [in] | expr | Expression to be processed |
| [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 |
| [in] | ctx | Context |
Remarks
Definition at line 432 of file operators.f90.
|
private |
Parses shift expressions (<<, >>).
| [in] | expr | Expression to be processed |
| [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 |
| [in] | ctx | Context |
Remarks
Definition at line 478 of file operators.f90.
|
private |
Parses unary operators ( @param[in] expr Expression to be processed @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 and defined()` checks.
| [in] | ctx | Context |
Remarks
Definition at line 624 of file operators.f90.