75 implicit none;
private
99 character(*),
intent(in) :: expr
100 type(
macro),
intent(in) :: macros(:)
101 integer,
intent(out),
optional :: val
123 character(*),
intent(in) :: expr
124 type(
macro),
intent(in) :: macros(:)
125 type(
context),
intent(in) :: ctx
126 integer,
intent(out),
optional :: val
128 type(
token),
allocatable :: tokens(:)
129 integer :: ntokens, pos, result
131 call tokenize(expr, tokens, ntokens)
132 if (ntokens == 0)
then
134 message=
'Tokenization failed', &
136 source=
trim(ctx%path)), &
144 if (pos <= ntokens)
then
146 message=
'Tokenization failed', &
147 label=
label_type(
'Extra tokens found', tokens(pos)%start,
len_trim(tokens(pos)%value)), &
148 source=
trim(ctx%path)), &
154 if (
present(val)) val = result
169 recursive integer function parse_expression(expr, tokens, ntokens, pos, macros, ctx)
result(val)
170 character(*),
intent(in) :: expr
171 type(
token),
intent(in) :: tokens(:)
172 integer,
intent(in) :: ntokens
173 integer,
intent(inout) :: pos
174 type(
macro),
intent(in) :: macros(:)
175 type(
context),
intent(in) :: ctx
191 recursive integer function parse_conditional(expr, tokens, ntokens, pos, macros, ctx)
result(val)
192 character(*),
intent(in) :: expr
193 type(
token),
intent(in) :: tokens(:)
194 integer,
intent(in) :: ntokens
195 integer,
intent(inout) :: pos
196 type(
macro),
intent(in) :: macros(:)
197 type(
context),
intent(in) :: ctx
199 integer :: condition, true_val, false_val
202 condition =
parse_or(expr, tokens, ntokens, pos, macros, ctx)
205 if (pos <= ntokens .and. tokens(pos)%value ==
'?')
then
211 if (pos > ntokens .or. tokens(pos)%value /=
':')
then
213 message=
'Synthax error', &
214 label=
label_type(
'Expected ":" in conditional expression', 1,
len(expr)), &
215 source=
trim(ctx%path)), &
227 val = merge(true_val, false_val, condition /= 0)
245 recursive integer function parse_or(expr, tokens, ntokens, pos, macros, ctx)
result(val)
246 character(*),
intent(in) :: expr
247 type(
token),
intent(in) :: tokens(:)
248 integer,
intent(in) :: ntokens
249 integer,
intent(inout) :: pos
250 type(
macro),
intent(in) :: macros(:)
251 type(
context),
intent(in) :: ctx
255 left =
parse_and(expr, tokens, ntokens, pos, macros, ctx)
256 do while (pos <= ntokens .and. tokens(pos)%value ==
'||')
258 val = merge(1, 0, left /= 0 .or.
parse_and(expr, tokens, ntokens, pos, macros, ctx) /= 0)
275 recursive integer function parse_and(expr, tokens, ntokens, pos, macros, ctx)
result(val)
276 character(*),
intent(in) :: expr
277 type(
token),
intent(in) :: tokens(:)
278 integer,
intent(in) :: ntokens
279 integer,
intent(inout) :: pos
280 type(
macro),
intent(in) :: macros(:)
281 type(
context),
intent(in) :: ctx
286 do while (pos <= ntokens .and. tokens(pos)%value ==
'&&')
288 val = merge(1, 0, left /= 0 .and.
parse_bitwise_or(expr, tokens, ntokens, pos, macros, ctx) /= 0)
305 recursive integer function parse_bitwise_or(expr, tokens, ntokens, pos, macros, ctx)
result(val)
306 character(*),
intent(in) :: expr
307 type(
token),
intent(in) :: tokens(:)
308 integer,
intent(in) :: ntokens
309 integer,
intent(inout) :: pos
310 type(
macro),
intent(in) :: macros(:)
311 type(
context),
intent(in) :: ctx
316 do while (pos <= ntokens .and. tokens(pos)%value ==
'|')
319 left = ior(left, val)
335 recursive integer function parse_bitwise_xor(expr, tokens, ntokens, pos, macros, ctx)
result(val)
336 character(*),
intent(in) :: expr
337 type(
token),
intent(in) :: tokens(:)
338 integer,
intent(in) :: ntokens
339 integer,
intent(inout) :: pos
340 type(
macro),
intent(in) :: macros(:)
341 type(
context),
intent(in) :: ctx
346 do while (pos <= ntokens .and. tokens(pos)%value ==
'^')
349 left = ieor(left, val)
365 recursive integer function parse_bitwise_and(expr, tokens, ntokens, pos, macros, ctx)
result(val)
366 character(*),
intent(in) :: expr
367 type(
token),
intent(in) :: tokens(:)
368 integer,
intent(in) :: ntokens
369 integer,
intent(inout) :: pos
370 type(
macro),
intent(in) :: macros(:)
371 type(
context),
intent(in) :: ctx
376 do while (pos <= ntokens .and. tokens(pos)%value ==
'&')
379 left = iand(left, val)
395 recursive integer function parse_equality(expr, tokens, ntokens, pos, macros, ctx)
result(val)
396 character(*),
intent(in) :: expr
397 type(
token),
intent(in) :: tokens(:)
398 integer,
intent(in) :: ntokens
399 integer,
intent(inout) :: pos
400 type(
macro),
intent(in) :: macros(:)
401 type(
context),
intent(in) :: ctx
403 integer :: left, right
406 do while (pos <= ntokens .and. (tokens(pos)%value ==
'==' .or. tokens(pos)%value ==
'!='))
407 if (tokens(pos)%value ==
'==')
then
410 val = merge(1, 0, left == right)
414 val = merge(1, 0, left /= right)
432 recursive integer function parse_relational(expr, tokens, ntokens, pos, macros, ctx)
result(val)
433 character(*),
intent(in) :: expr
434 type(
token),
intent(in) :: tokens(:)
435 integer,
intent(in) :: ntokens
436 integer,
intent(inout) :: pos
437 type(
macro),
intent(in) :: macros(:)
438 type(
context),
intent(in) :: ctx
440 integer :: left, right
443 do while (pos <= ntokens .and. (tokens(pos)%value ==
'<' .or. tokens(pos)%value ==
'>' .or. &
444 tokens(pos)%value ==
'<=' .or. tokens(pos)%value ==
'>='))
445 if (tokens(pos)%value ==
'<')
then
448 val = merge(1, 0, left < right)
449 else if (tokens(pos)%value ==
'>')
then
452 val = merge(1, 0, left > right)
453 else if (tokens(pos)%value ==
'<=')
then
456 val = merge(1, 0, left <= right)
460 val = merge(1, 0, left >= right)
478 recursive integer function parse_shifting(expr, tokens, ntokens, pos, macros, ctx)
result(val)
479 character(*),
intent(in) :: expr
480 type(
token),
intent(in) :: tokens(:)
481 integer,
intent(in) :: ntokens
482 integer,
intent(inout) :: pos
483 type(
macro),
intent(in) :: macros(:)
484 type(
context),
intent(in) :: ctx
486 integer :: left, right
489 do while (pos <= ntokens .and. (tokens(pos)%value ==
'<<' .or. tokens(pos)%value ==
'>>'))
490 if (tokens(pos)%value ==
'<<')
then
493 val = lshift(left, right)
497 val = rshift(left, right)
515 recursive integer function parse_additive(expr, tokens, ntokens, pos, macros, ctx)
result(val)
516 character(*),
intent(in) :: expr
517 type(
token),
intent(in) :: tokens(:)
518 integer,
intent(in) :: ntokens
519 integer,
intent(inout) :: pos
520 type(
macro),
intent(in) :: macros(:)
521 type(
context),
intent(in) :: ctx
523 integer :: left, right
526 do while (pos <= ntokens .and. (tokens(pos)%value ==
'+' .or. tokens(pos)%value ==
'-'))
527 if (tokens(pos)%value ==
'+')
then
553 character(*),
intent(in) :: expr
554 type(
token),
intent(in) :: tokens(:)
555 integer,
intent(in) :: ntokens
556 integer,
intent(inout) :: pos
557 type(
macro),
intent(in) :: macros(:)
558 type(
context),
intent(in) :: ctx
560 integer :: left, right
562 left =
parse_power(expr, tokens, ntokens, pos, macros, ctx)
563 do while (pos <= ntokens .and. (tokens(pos)%value ==
'*' .or. tokens(pos)%value ==
'/' .or. tokens(pos)%value ==
'%'))
564 if (tokens(pos)%value ==
'*')
then
566 right =
parse_power(expr, tokens, ntokens, pos, macros, ctx)
568 else if (tokens(pos)%value ==
'/')
then
570 right =
parse_power(expr, tokens, ntokens, pos, macros, ctx)
574 right =
parse_power(expr, tokens, ntokens, pos, macros, ctx)
575 val = modulo(left, right)
593 recursive integer function parse_power(expr, tokens, ntokens, pos, macros, ctx)
result(val)
594 character(*),
intent(in) :: expr
595 type(
token),
intent(in) :: tokens(:)
596 integer,
intent(in) :: ntokens
597 integer,
intent(inout) :: pos
598 type(
macro),
intent(in) :: macros(:)
599 type(
context),
intent(in) :: ctx
601 integer :: left, right
603 left =
parse_unary(expr, tokens, ntokens, pos, macros, ctx)
604 do while (pos <= ntokens .and. (tokens(pos)%value ==
'**'))
606 right =
parse_unary(expr, tokens, ntokens, pos, macros, ctx)
624 recursive integer function parse_unary(expr, tokens, ntokens, pos, macros, ctx)
result(val)
625 character(*),
intent(in) :: expr
626 type(
token),
intent(in) :: tokens(:)
627 integer,
intent(in) :: ntokens
628 integer,
intent(inout) :: pos
629 type(
macro),
intent(in) :: macros(:)
630 type(
context),
intent(in) :: ctx
632 if (pos <= ntokens .and. tokens(pos)%value ==
'!')
then
634 val = merge(0, 1,
parse_unary(expr, tokens, ntokens, pos, macros, ctx) /= 0)
635 else if (pos <= ntokens .and. tokens(pos)%value ==
'-')
then
637 val = -
parse_unary(expr, tokens, ntokens, pos, macros, ctx)
638 else if (pos <= ntokens .and. tokens(pos)%value ==
'+')
then
640 val =
parse_unary(expr, tokens, ntokens, pos, macros, ctx)
641 else if (pos <= ntokens .and. tokens(pos)%value ==
'~')
then
643 val = not(
parse_unary(expr, tokens, ntokens, pos, macros, ctx))
645 val =
parse_atom(expr, tokens, ntokens, pos, macros, ctx)
660 recursive integer function parse_atom(expr, tokens, ntokens, pos, macros, ctx)
result(val)
661 character(*),
intent(in) :: expr
662 type(
token),
intent(in) :: tokens(:)
663 integer,
intent(in) :: ntokens
664 integer,
intent(inout) :: pos
665 type(
macro),
intent(in) :: macros(:)
666 type(
context),
intent(in) :: ctx
669 character(:),
allocatable :: expanded
672 if (pos > ntokens)
then
674 message=
'Synthax error', &
675 label=
label_type(
'Unexpected end of expression', pos, 1), &
676 source=
trim(ctx%path)), &
682 if (tokens(pos)%type == 0)
then
683 val =
strtol(tokens(pos)%value)
685 else if (tokens(pos)%type == 2)
then
686 if (
is_defined(tokens(pos)%value, macros))
then
687 expanded =
expand_macros(tokens(pos)%value, macros, stitch,
global%implicit_continuation, ctx)
693 else if (tokens(pos)%value ==
'(')
then
696 if (pos > ntokens .or. tokens(pos)%value /=
')')
then
698 message=
'Synthax error', &
699 label=
label_type(
'Missing closing parenthesis in expression',
len(expr), 1), &
700 source=
trim(ctx%path)), &
706 else if (tokens(pos)%type == 4)
then
707 expanded =
trim(tokens(pos)%value)
708 val = merge(1, 0,
is_defined(expanded, macros))
712 message=
'Invalid expression', &
714 source=
trim(ctx%path)), &
type(global_settings), public global
The single global instance used throughout fpx Initialized automatically with sensible defaults value...
character(:) function, allocatable, public expand_macros(line, macros, stitch, implicit_conti, ctx)
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_power(expr, tokens, ntokens, pos, macros, ctx)
Parses exponentiation (**). Right-associative.
recursive integer function parse_bitwise_or(expr, tokens, ntokens, pos, macros, ctx)
Parses bitwise OR expressions (|).
recursive integer function parse_additive(expr, tokens, ntokens, pos, macros, ctx)
Parses additive expressions (+, -).
recursive integer function parse_unary(expr, tokens, ntokens, pos, macros, ctx)
Parses unary operators ( @param[in] expr Expression to be processed @param[in] tokens Array of tokens...
recursive integer function parse_bitwise_xor(expr, tokens, ntokens, pos, macros, ctx)
Parses bitwise XOR expressions (^).
recursive integer function parse_atom(expr, tokens, ntokens, pos, macros, ctx)
Parses primary expressions: numbers, identifiers, defined(...), parentheses.
recursive integer function parse_expression(expr, tokens, ntokens, pos, macros, ctx)
Parses a sequence of tokens starting at position pos as a full expression. Entry point for the recurs...
recursive integer function parse_bitwise_and(expr, tokens, ntokens, pos, macros, ctx)
Parses bitwise AND expressions (&).
recursive integer function parse_shifting(expr, tokens, ntokens, pos, macros, ctx)
Parses shift expressions (<<, >>).
logical function evaluate_expression_with_context(expr, macros, ctx, val)
Evaluates a preprocessor-style expression with macro substitution. Tokenizes the input expression,...
recursive integer function parse_conditional(expr, tokens, ntokens, pos, macros, ctx)
Parses conditional expressions (?:). Right-associative.
recursive integer function parse_relational(expr, tokens, ntokens, pos, macros, ctx)
Parses relational expressions (<, >, <=, >=).
recursive integer function parse_or(expr, tokens, ntokens, pos, macros, ctx)
Parses logical OR expressions (||).
recursive integer function parse_multiplicative(expr, tokens, ntokens, pos, macros, ctx)
Parses multiplicative expressions (*, /, %).
logical function evaluate_expression_default(expr, macros, val)
Evaluates a preprocessor-style expression with macro substitution. Tokenizes the input expression,...
recursive integer function parse_and(expr, tokens, ntokens, pos, macros, ctx)
Parses logical AND expressions (&&).
recursive integer function parse_equality(expr, tokens, ntokens, pos, macros, ctx)
Parses equality/inequality expressions (==, @param[in] expr Expression to be processed @param[in] to...
subroutine, public tokenize(expr, tokens, ntokens)
Tokenizes a preprocessor expression into an array of token structures. Handles whitespace,...
Interface to render diagnostic messages and labels.
Return the trimmed length of a string.
Return the length of a string.
Return the trimmed string.
Converts a string to integer.
Source location and content snapshot for precise diagnostics Instances of this type are created for e...
Definition of diagnostic message.
Represents text as a sequence of ASCII code units. The derived type wraps an allocatable character ar...
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...