77 implicit none;
private
101 character(*),
intent(in) :: expr
102 type(
macro),
intent(in) :: macros(:)
103 integer,
intent(out),
optional :: val
125 character(*),
intent(in) :: expr
126 type(
macro),
intent(in) :: macros(:)
127 type(
context),
intent(in) :: ctx
128 integer,
intent(out),
optional :: val
130 type(
token),
allocatable :: tokens(:)
131 integer :: ntokens, pos, result
133 call tokenize(expr, tokens, ntokens)
134 if (ntokens == 0)
then
136 message=
'Tokenization failed', &
138 source=
trim(ctx%path)), &
146 if (pos <= ntokens)
then
148 message=
'Tokenization failed', &
149 label=
label_type(
'Extra tokens found', tokens(pos)%start,
len_trim(tokens(pos)%value)), &
150 source=
trim(ctx%path)), &
156 if (
present(val)) val = result
171 recursive integer function parse_expression(expr, tokens, ntokens, pos, macros, ctx)
result(val)
172 character(*),
intent(in) :: expr
173 type(
token),
intent(in) :: tokens(:)
174 integer,
intent(in) :: ntokens
175 integer,
intent(inout) :: pos
176 type(
macro),
intent(in) :: macros(:)
177 type(
context),
intent(in) :: ctx
193 recursive integer function parse_conditional(expr, tokens, ntokens, pos, macros, ctx)
result(val)
194 character(*),
intent(in) :: expr
195 type(
token),
intent(in) :: tokens(:)
196 integer,
intent(in) :: ntokens
197 integer,
intent(inout) :: pos
198 type(
macro),
intent(in) :: macros(:)
199 type(
context),
intent(in) :: ctx
201 integer :: condition, true_val, false_val
204 condition =
parse_or(expr, tokens, ntokens, pos, macros, ctx)
207 if (pos <= ntokens .and. tokens(pos)%value ==
'?')
then
213 if (pos > ntokens .or. tokens(pos)%value /=
':')
then
215 message=
'Synthax error', &
216 label=
label_type(
'Expected ":" in conditional expression', 1,
len(expr)), &
217 source=
trim(ctx%path)), &
229 val = merge(true_val, false_val, condition /= 0)
247 recursive integer function parse_or(expr, tokens, ntokens, pos, macros, ctx)
result(val)
248 character(*),
intent(in) :: expr
249 type(
token),
intent(in) :: tokens(:)
250 integer,
intent(in) :: ntokens
251 integer,
intent(inout) :: pos
252 type(
macro),
intent(in) :: macros(:)
253 type(
context),
intent(in) :: ctx
257 left =
parse_and(expr, tokens, ntokens, pos, macros, ctx)
258 do while (pos <= ntokens .and. tokens(pos)%value ==
'||')
260 val = merge(1, 0, left /= 0 .or.
parse_and(expr, tokens, ntokens, pos, macros, ctx) /= 0)
277 recursive integer function parse_and(expr, tokens, ntokens, pos, macros, ctx)
result(val)
278 character(*),
intent(in) :: expr
279 type(
token),
intent(in) :: tokens(:)
280 integer,
intent(in) :: ntokens
281 integer,
intent(inout) :: pos
282 type(
macro),
intent(in) :: macros(:)
283 type(
context),
intent(in) :: ctx
288 do while (pos <= ntokens .and. tokens(pos)%value ==
'&&')
290 val = merge(1, 0, left /= 0 .and.
parse_bitwise_or(expr, tokens, ntokens, pos, macros, ctx) /= 0)
307 recursive integer function parse_bitwise_or(expr, tokens, ntokens, pos, macros, ctx)
result(val)
308 character(*),
intent(in) :: expr
309 type(
token),
intent(in) :: tokens(:)
310 integer,
intent(in) :: ntokens
311 integer,
intent(inout) :: pos
312 type(
macro),
intent(in) :: macros(:)
313 type(
context),
intent(in) :: ctx
318 do while (pos <= ntokens .and. tokens(pos)%value ==
'|')
321 left = ior(left, val)
337 recursive integer function parse_bitwise_xor(expr, tokens, ntokens, pos, macros, ctx)
result(val)
338 character(*),
intent(in) :: expr
339 type(
token),
intent(in) :: tokens(:)
340 integer,
intent(in) :: ntokens
341 integer,
intent(inout) :: pos
342 type(
macro),
intent(in) :: macros(:)
343 type(
context),
intent(in) :: ctx
348 do while (pos <= ntokens .and. tokens(pos)%value ==
'^')
351 left = ieor(left, val)
367 recursive integer function parse_bitwise_and(expr, tokens, ntokens, pos, macros, ctx)
result(val)
368 character(*),
intent(in) :: expr
369 type(
token),
intent(in) :: tokens(:)
370 integer,
intent(in) :: ntokens
371 integer,
intent(inout) :: pos
372 type(
macro),
intent(in) :: macros(:)
373 type(
context),
intent(in) :: ctx
378 do while (pos <= ntokens .and. tokens(pos)%value ==
'&')
381 left = iand(left, val)
397 recursive integer function parse_equality(expr, tokens, ntokens, pos, macros, ctx)
result(val)
398 character(*),
intent(in) :: expr
399 type(
token),
intent(in) :: tokens(:)
400 integer,
intent(in) :: ntokens
401 integer,
intent(inout) :: pos
402 type(
macro),
intent(in) :: macros(:)
403 type(
context),
intent(in) :: ctx
405 integer :: left, right
408 do while (pos <= ntokens .and. (tokens(pos)%value ==
'==' .or. tokens(pos)%value ==
'!='))
409 if (tokens(pos)%value ==
'==')
then
412 val = merge(1, 0, left == right)
416 val = merge(1, 0, left /= right)
434 recursive integer function parse_relational(expr, tokens, ntokens, pos, macros, ctx)
result(val)
435 character(*),
intent(in) :: expr
436 type(
token),
intent(in) :: tokens(:)
437 integer,
intent(in) :: ntokens
438 integer,
intent(inout) :: pos
439 type(
macro),
intent(in) :: macros(:)
440 type(
context),
intent(in) :: ctx
442 integer :: left, right
445 do while (pos <= ntokens .and. (tokens(pos)%value ==
'<' .or. tokens(pos)%value ==
'>' .or. &
446 tokens(pos)%value ==
'<=' .or. tokens(pos)%value ==
'>='))
447 if (tokens(pos)%value ==
'<')
then
450 val = merge(1, 0, left < right)
451 else if (tokens(pos)%value ==
'>')
then
454 val = merge(1, 0, left > right)
455 else if (tokens(pos)%value ==
'<=')
then
458 val = merge(1, 0, left <= right)
462 val = merge(1, 0, left >= right)
480 recursive integer function parse_shifting(expr, tokens, ntokens, pos, macros, ctx)
result(val)
481 character(*),
intent(in) :: expr
482 type(
token),
intent(in) :: tokens(:)
483 integer,
intent(in) :: ntokens
484 integer,
intent(inout) :: pos
485 type(
macro),
intent(in) :: macros(:)
486 type(
context),
intent(in) :: ctx
488 integer :: left, right
491 do while (pos <= ntokens .and. (tokens(pos)%value ==
'<<' .or. tokens(pos)%value ==
'>>'))
492 if (tokens(pos)%value ==
'<<')
then
495 val = lshift(left, right)
499 val = rshift(left, right)
517 recursive integer function parse_additive(expr, tokens, ntokens, pos, macros, ctx)
result(val)
518 character(*),
intent(in) :: expr
519 type(
token),
intent(in) :: tokens(:)
520 integer,
intent(in) :: ntokens
521 integer,
intent(inout) :: pos
522 type(
macro),
intent(in) :: macros(:)
523 type(
context),
intent(in) :: ctx
525 integer :: left, right
528 do while (pos <= ntokens .and. (tokens(pos)%value ==
'+' .or. tokens(pos)%value ==
'-'))
529 if (tokens(pos)%value ==
'+')
then
555 character(*),
intent(in) :: expr
556 type(
token),
intent(in) :: tokens(:)
557 integer,
intent(in) :: ntokens
558 integer,
intent(inout) :: pos
559 type(
macro),
intent(in) :: macros(:)
560 type(
context),
intent(in) :: ctx
562 integer :: left, right
564 left =
parse_power(expr, tokens, ntokens, pos, macros, ctx)
565 do while (pos <= ntokens .and. (tokens(pos)%value ==
'*' .or. tokens(pos)%value ==
'/' .or. tokens(pos)%value ==
'%'))
566 if (tokens(pos)%value ==
'*')
then
568 right =
parse_power(expr, tokens, ntokens, pos, macros, ctx)
570 else if (tokens(pos)%value ==
'/')
then
572 right =
parse_power(expr, tokens, ntokens, pos, macros, ctx)
576 right =
parse_power(expr, tokens, ntokens, pos, macros, ctx)
577 val = modulo(left, right)
595 recursive integer function parse_power(expr, tokens, ntokens, pos, macros, ctx)
result(val)
596 character(*),
intent(in) :: expr
597 type(
token),
intent(in) :: tokens(:)
598 integer,
intent(in) :: ntokens
599 integer,
intent(inout) :: pos
600 type(
macro),
intent(in) :: macros(:)
601 type(
context),
intent(in) :: ctx
603 integer :: left, right
605 left =
parse_unary(expr, tokens, ntokens, pos, macros, ctx)
606 do while (pos <= ntokens .and. (tokens(pos)%value ==
'**'))
608 right =
parse_unary(expr, tokens, ntokens, pos, macros, ctx)
626 recursive integer function parse_unary(expr, tokens, ntokens, pos, macros, ctx)
result(val)
627 character(*),
intent(in) :: expr
628 type(
token),
intent(in) :: tokens(:)
629 integer,
intent(in) :: ntokens
630 integer,
intent(inout) :: pos
631 type(
macro),
intent(in) :: macros(:)
632 type(
context),
intent(in) :: ctx
634 if (pos <= ntokens .and. tokens(pos)%value ==
'!')
then
636 val = merge(0, 1,
parse_unary(expr, tokens, ntokens, pos, macros, ctx) /= 0)
637 else if (pos <= ntokens .and. tokens(pos)%value ==
'-')
then
639 val = -
parse_unary(expr, tokens, ntokens, pos, macros, ctx)
640 else if (pos <= ntokens .and. tokens(pos)%value ==
'+')
then
642 val =
parse_unary(expr, tokens, ntokens, pos, macros, ctx)
643 else if (pos <= ntokens .and. tokens(pos)%value ==
'~')
then
645 val = not(
parse_unary(expr, tokens, ntokens, pos, macros, ctx))
647 val =
parse_atom(expr, tokens, ntokens, pos, macros, ctx)
662 recursive integer function parse_atom(expr, tokens, ntokens, pos, macros, ctx)
result(val)
663 character(*),
intent(in) :: expr
664 type(
token),
intent(in) :: tokens(:)
665 integer,
intent(in) :: ntokens
666 integer,
intent(inout) :: pos
667 type(
macro),
intent(in) :: macros(:)
668 type(
context),
intent(in) :: ctx
671 character(:),
allocatable :: expanded
674 if (pos > ntokens)
then
676 message=
'Synthax error', &
677 label=
label_type(
'Unexpected end of expression', pos, 1), &
678 source=
trim(ctx%path)), &
684 if (tokens(pos)%type == 0)
then
685 val =
strtol(tokens(pos)%value)
687 else if (tokens(pos)%type == 2)
then
688 if (
is_defined(tokens(pos)%value, macros))
then
689 expanded =
expand_macros(tokens(pos)%value, macros, stitch,
global%implicit_continuation, ctx)
695 else if (tokens(pos)%value ==
'(')
then
698 if (pos > ntokens .or. tokens(pos)%value /=
')')
then
700 message=
'Synthax error', &
701 label=
label_type(
'Missing closing parenthesis in expression',
len(expr), 1), &
702 source=
trim(ctx%path)), &
708 else if (tokens(pos)%type == 4)
then
709 expanded =
trim(tokens(pos)%value)
710 val = merge(1, 0,
is_defined(expanded, macros))
714 message=
'Invalid expression', &
716 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...