73 implicit none;
private
93 character(*),
intent(in) :: expr
94 type(
macro),
intent(in) :: macros(:)
95 integer,
intent(out),
optional :: val
97 type(
token),
allocatable :: tokens(:)
98 integer :: ntokens, pos, result
100 call tokenize(expr, tokens, ntokens)
101 if (ntokens == 0)
then
102 if (
verbose) print *,
"No tokens found for expression"
109 if (
verbose) print *,
"Parsed '",
trim(expr),
"': pos = ", pos,
", ntokens = ", ntokens,
", result = ", result
110 if (pos <= ntokens)
then
111 if (
verbose) print *,
"Error: Extra tokens in expression: ",
trim(tokens(pos)%value)
116 if (
present(val)) val = result
130 type(
token),
intent(in) :: tokens(:)
131 integer,
intent(in) :: ntokens
132 integer,
intent(inout) :: pos
133 type(
macro),
intent(in) :: macros(:)
148 type(
token),
intent(in) :: tokens(:)
149 integer,
intent(in) :: ntokens
150 integer,
intent(inout) :: pos
151 type(
macro),
intent(in) :: macros(:)
153 integer :: condition, true_val, false_val
156 condition =
parse_or(tokens, ntokens, pos, macros)
159 if (pos <= ntokens .and. tokens(pos)%value ==
'?')
then
161 if (
verbose) print *,
"Parsing ? at pos ", pos
169 if (pos > ntokens .or. tokens(pos)%value /=
':')
then
170 if (
verbose) print *,
"Error: expected ':' in conditional expression"
181 val = merge(true_val, false_val, condition /= 0)
200 recursive integer function parse_or(tokens, ntokens, pos, macros)
result(val)
201 type(
token),
intent(in) :: tokens(:)
202 integer,
intent(in) :: ntokens
203 integer,
intent(inout) :: pos
204 type(
macro),
intent(in) :: macros(:)
207 left =
parse_and(tokens, ntokens, pos, macros)
208 do while (pos <= ntokens .and. tokens(pos)%value ==
'||')
209 if (
verbose) print *,
"Parsing || at pos ", pos
211 val = merge(1, 0, left /= 0 .or.
parse_and(tokens, ntokens, pos, macros) /= 0)
226 recursive integer function parse_and(tokens, ntokens, pos, macros)
result(val)
227 type(
token),
intent(in) :: tokens(:)
228 integer,
intent(in) :: ntokens
229 integer,
intent(inout) :: pos
230 type(
macro),
intent(in) :: macros(:)
235 do while (pos <= ntokens .and. tokens(pos)%value ==
'&&')
236 if (
verbose) print *,
"Parsing && at pos ", pos
238 val = merge(1, 0, left /= 0 .and.
parse_bitwise_or(tokens, ntokens, pos, macros) /= 0)
254 type(
token),
intent(in) :: tokens(:)
255 integer,
intent(in) :: ntokens
256 integer,
intent(inout) :: pos
257 type(
macro),
intent(in) :: macros(:)
262 do while (pos <= ntokens .and. tokens(pos)%value ==
'|')
263 if (
verbose) print *,
"Parsing | at pos ", pos
266 left = ior(left, val)
281 type(
token),
intent(in) :: tokens(:)
282 integer,
intent(in) :: ntokens
283 integer,
intent(inout) :: pos
284 type(
macro),
intent(in) :: macros(:)
289 do while (pos <= ntokens .and. tokens(pos)%value ==
'^')
290 if (
verbose) print *,
"Parsing ^ at pos ", pos
293 left = ieor(left, val)
308 type(
token),
intent(in) :: tokens(:)
309 integer,
intent(in) :: ntokens
310 integer,
intent(inout) :: pos
311 type(
macro),
intent(in) :: macros(:)
316 do while (pos <= ntokens .and. tokens(pos)%value ==
'&')
317 if (
verbose) print *,
"Parsing && at pos ", pos
320 left = iand(left, val)
334 recursive integer function parse_equality(tokens, ntokens, pos, macros)
result(val)
335 type(
token),
intent(in) :: tokens(:)
336 integer,
intent(in) :: ntokens
337 integer,
intent(inout) :: pos
338 type(
macro),
intent(in) :: macros(:)
340 integer :: left, right
343 do while (pos <= ntokens .and. (tokens(pos)%value ==
'==' .or. tokens(pos)%value ==
'!='))
344 if (
verbose) print *,
"Parsing ",
trim(tokens(pos)%value),
" at pos ", pos
345 if (tokens(pos)%value ==
'==')
then
348 val = merge(1, 0, left == right)
352 val = merge(1, 0, left /= right)
369 type(
token),
intent(in) :: tokens(:)
370 integer,
intent(in) :: ntokens
371 integer,
intent(inout) :: pos
372 type(
macro),
intent(in) :: macros(:)
374 integer :: left, right
377 do while (pos <= ntokens .and. (tokens(pos)%value ==
'<' .or. tokens(pos)%value ==
'>' .or. &
378 tokens(pos)%value ==
'<=' .or. tokens(pos)%value ==
'>='))
379 if (
verbose) print *,
"Parsing ",
trim(tokens(pos)%value),
" at pos ", pos
380 if (tokens(pos)%value ==
'<')
then
383 val = merge(1, 0, left < right)
384 else if (tokens(pos)%value ==
'>')
then
387 val = merge(1, 0, left > right)
388 else if (tokens(pos)%value ==
'<=')
then
391 val = merge(1, 0, left <= right)
395 val = merge(1, 0, left >= right)
411 recursive integer function parse_shifting(tokens, ntokens, pos, macros)
result(val)
412 type(
token),
intent(in) :: tokens(:)
413 integer,
intent(in) :: ntokens
414 integer,
intent(inout) :: pos
415 type(
macro),
intent(in) :: macros(:)
417 integer :: left, right
420 do while (pos <= ntokens .and. (tokens(pos)%value ==
'<<' .or. tokens(pos)%value ==
'>>'))
421 if (
verbose) print *,
"Parsing ",
trim(tokens(pos)%value),
" at pos ", pos
422 if (tokens(pos)%value ==
'<<')
then
425 val = lshift(left, right)
429 val = rshift(left, right)
445 recursive integer function parse_additive(tokens, ntokens, pos, macros)
result(val)
446 type(
token),
intent(in) :: tokens(:)
447 integer,
intent(in) :: ntokens
448 integer,
intent(inout) :: pos
449 type(
macro),
intent(in) :: macros(:)
451 integer :: left, right
454 do while (pos <= ntokens .and. (tokens(pos)%value ==
'+' .or. tokens(pos)%value ==
'-'))
455 if (
verbose) print *,
"Parsing ",
trim(tokens(pos)%value),
" at pos ", pos
456 if (tokens(pos)%value ==
'+')
then
480 type(
token),
intent(in) :: tokens(:)
481 integer,
intent(in) :: ntokens
482 integer,
intent(inout) :: pos
483 type(
macro),
intent(in) :: macros(:)
485 integer :: left, right
488 do while (pos <= ntokens .and. (tokens(pos)%value ==
'*' .or. tokens(pos)%value ==
'/' .or. tokens(pos)%value ==
'%'))
489 if (
verbose) print *,
"Parsing ",
trim(tokens(pos)%value),
" at pos ", pos
490 if (tokens(pos)%value ==
'*')
then
494 else if (tokens(pos)%value ==
'/')
then
501 val = modulo(left, right)
517 recursive integer function parse_power(tokens, ntokens, pos, macros)
result(val)
518 type(
token),
intent(in) :: tokens(:)
519 integer,
intent(in) :: ntokens
520 integer,
intent(inout) :: pos
521 type(
macro),
intent(in) :: macros(:)
523 integer :: left, right
526 do while (pos <= ntokens .and. (tokens(pos)%value ==
'**'))
527 if (
verbose) print *,
"Parsing ",
trim(tokens(pos)%value),
" at pos ", pos
545 recursive integer function parse_unary(tokens, ntokens, pos, macros)
result(val)
546 type(
token),
intent(in) :: tokens(:)
547 integer,
intent(in) :: ntokens
548 integer,
intent(inout) :: pos
549 type(
macro),
intent(in) :: macros(:)
551 if (pos <= ntokens .and. tokens(pos)%value ==
'!')
then
552 if (
verbose) print *,
"Parsing ! at pos ", pos
554 val = merge(0, 1,
parse_unary(tokens, ntokens, pos, macros) /= 0)
555 else if (pos <= ntokens .and. tokens(pos)%value ==
'-')
then
556 if (
verbose) print *,
"Parsing - at pos ", pos
559 else if (pos <= ntokens .and. tokens(pos)%value ==
'+')
then
560 if (
verbose) print *,
"Parsing + at pos ", pos
563 else if (pos <= ntokens .and. tokens(pos)%value ==
'~')
then
564 if (
verbose) print *,
"Parsing + at pos ", pos
566 val = not(
parse_unary(tokens, ntokens, pos, macros))
568 val =
parse_atom(tokens, ntokens, pos, macros)
581 recursive integer function parse_atom(tokens, ntokens, pos, macros)
result(val)
582 type(
token),
intent(in) :: tokens(:)
583 integer,
intent(in) :: ntokens
584 integer,
intent(inout) :: pos
585 type(
macro),
intent(in) :: macros(:)
588 character(:),
allocatable :: expanded
591 if (pos > ntokens)
then
592 if (
verbose) print *,
"Error: Unexpected end of expression at pos ", pos
597 if (
verbose) print *,
"Parsing primary: ",
trim(tokens(pos)%value),
" at pos ", pos
598 if (tokens(pos)%type == 0)
then
599 val =
strtol(tokens(pos)%value)
601 else if (tokens(pos)%type == 2)
then
602 if (
is_defined(tokens(pos)%value, macros))
then
605 if (
verbose) print *,
"Expanded ",
trim(tokens(pos)%value),
" to ",
trim(expanded),
", val = ", val
610 else if (tokens(pos)%value ==
'(')
then
613 if (pos > ntokens .or. tokens(pos)%value /=
')')
then
614 if (
verbose) print *,
"Error: Missing closing parenthesis at pos ", pos
617 if (
verbose) print *,
"Parsed ) at pos ", pos
620 else if (tokens(pos)%type == 4)
then
621 expanded =
trim(tokens(pos)%value)
622 val = merge(1, 0,
is_defined(expanded, macros))
623 if (
verbose) print *,
"defined(",
trim(expanded),
") = ", val
626 if (
verbose) print *,
"Error: Invalid token in expression: ",
trim(tokens(pos)%value)
logical, public verbose
Master switch for verbose diagnostic output Default value is .false. (quiet mode)....
character(:) function, allocatable, public expand_macros(line, macros, stitch)
Core recursive macro expander (handles function-like, variadic, #, ##)
logical function, public is_defined(name, macros, idx)
Check if a macro with given name exists in table.
recursive integer function parse_equality(tokens, ntokens, pos, macros)
Parses equality/inequality expressions (==, @param[in] tokens Array of tokens to parse @param[in] nt...
recursive integer function parse_relational(tokens, ntokens, pos, macros)
Parses relational expressions (<, >, <=, >=).
recursive integer function parse_unary(tokens, ntokens, pos, macros)
Parses unary operators ( @param[in] tokens Array of tokens to parse @param[in] ntokens Number of vali...
recursive integer function parse_shifting(tokens, ntokens, pos, macros)
Parses shift expressions (<<, >>).
recursive integer function, public parse_expression(tokens, ntokens, pos, macros)
Parses a sequence of tokens starting at position pos as a full expression. Entry point for the recurs...
recursive integer function parse_bitwise_xor(tokens, ntokens, pos, macros)
Parses bitwise XOR expressions (^).
recursive integer function parse_atom(tokens, ntokens, pos, macros)
Parses primary expressions: numbers, identifiers, defined(...), parentheses.
recursive integer function parse_multiplicative(tokens, ntokens, pos, macros)
Parses multiplicative expressions (*, /, %).
recursive integer function parse_or(tokens, ntokens, pos, macros)
Parses logical OR expressions (||).
recursive integer function parse_conditional(tokens, ntokens, pos, macros)
Parses conditional expressions (?:). Right-associative.
recursive integer function parse_additive(tokens, ntokens, pos, macros)
Parses additive expressions (+, -).
logical function, public evaluate_expression(expr, macros, val)
Evaluates a preprocessor-style expression with macro substitution. Tokenizes the input expression,...
recursive integer function parse_and(tokens, ntokens, pos, macros)
Parses logical AND expressions (&&).
recursive integer function parse_bitwise_and(tokens, ntokens, pos, macros)
Parses bitwise AND expressions (&).
recursive integer function parse_bitwise_or(tokens, ntokens, pos, macros)
Parses bitwise OR expressions (|).
recursive integer function parse_power(tokens, ntokens, pos, macros)
Parses exponentiation (**). Right-associative.
subroutine, public tokenize(expr, tokens, ntokens)
Tokenizes a preprocessor expression into an array of token structures. Handles whitespace,...
Return the trimmed string.
Converts a string to integer.
Derived type representing a single preprocessor macro Extends string with macro-specific fields: rep...
Represents a single token in a parsed expression. Holds the string value of the token and its classif...