117 implicit none;
private
172 module procedure :: evaluate_expression_default
173 module procedure :: evaluate_expression_with_context
189 logical function evaluate_expression_default(expr, macros, val)
result(res)
190 character(*),
intent(in) :: expr
191 type(
macro),
allocatable,
intent(inout) :: macros(:)
192 integer,
intent(out),
optional :: val
212 logical function evaluate_expression_with_context(expr, macros, ctx, val)
result(res)
213 character(*),
intent(in) :: expr
214 type(
macro),
allocatable,
intent(inout) :: macros(:)
215 type(
context),
intent(in) :: ctx
216 integer,
intent(out),
optional :: val
218 type(
token),
allocatable :: tokens(:)
219 integer :: ntokens, pos, result
221 call tokenize(expr, tokens, ntokens)
222 if (ntokens == 0)
then
224 message=
'Tokenization failed', &
226 source=
trim(ctx%path)), &
234 if (pos <= ntokens)
then
236 message=
'Tokenization failed', &
237 label=
label_type(
'Extra tokens found', tokens(pos)%start,
len_trim(tokens(pos)%value)), &
238 source=
trim(ctx%path)), &
244 if (
present(val)) val = result
265 recursive integer function parse_expression(expr, tokens, ntokens, pos, macros, ctx)
result(val)
266 character(*),
intent(in) :: expr
267 type(
token),
intent(in) :: tokens(:)
268 integer,
intent(in) :: ntokens
269 integer,
intent(inout) :: pos
270 type(
macro),
allocatable,
intent(inout) :: macros(:)
271 type(
context),
intent(in) :: ctx
273 val = parse_conditional(expr, tokens, ntokens, pos, macros, ctx)
286 recursive integer function parse_conditional(expr, tokens, ntokens, pos, macros, ctx)
result(val)
287 character(*),
intent(in) :: expr
288 type(
token),
intent(in) :: tokens(:)
289 integer,
intent(in) :: ntokens
290 integer,
intent(inout) :: pos
291 type(
macro),
allocatable,
intent(inout) :: macros(:)
292 type(
context),
intent(in) :: ctx
294 integer :: condition, true_val, false_val
297 condition = parse_or(expr, tokens, ntokens, pos, macros, ctx)
298 if (pos > ntokens)
then
303 if (pos <= ntokens .and. tokens(pos)%value ==
'?')
then
309 if (pos > ntokens .or. tokens(pos)%value /=
':')
then
311 message=
'Syntax error', &
312 label=
label_type(
'Expected ":" in conditional expression', 1,
len(expr)), &
313 source=
trim(ctx%path)), &
322 false_val = parse_conditional(expr, tokens, ntokens, pos, macros, ctx)
325 val = merge(true_val, false_val, condition /= 0)
342 recursive integer function parse_or(expr, tokens, ntokens, pos, macros, ctx)
result(val)
343 character(*),
intent(in) :: expr
344 type(
token),
intent(in) :: tokens(:)
345 integer,
intent(in) :: ntokens
346 integer,
intent(inout) :: pos
347 type(
macro),
allocatable,
intent(inout) :: macros(:)
348 type(
context),
intent(in) :: ctx
352 left = parse_and(expr, tokens, ntokens, pos, macros, ctx)
353 if (pos > ntokens)
then
357 do while (pos <= ntokens .and. tokens(pos)%value ==
'||')
359 val = merge(1, 0, left /= 0 .or. parse_and(expr, tokens, ntokens, pos, macros, ctx) /= 0)
375 recursive integer function parse_and(expr, tokens, ntokens, pos, macros, ctx)
result(val)
376 character(*),
intent(in) :: expr
377 type(
token),
intent(in) :: tokens(:)
378 integer,
intent(in) :: ntokens
379 integer,
intent(inout) :: pos
380 type(
macro),
allocatable,
intent(inout) :: macros(:)
381 type(
context),
intent(in) :: ctx
385 left = parse_bitwise_or(expr, tokens, ntokens, pos, macros, ctx)
386 if (pos > ntokens)
then
390 do while (pos <= ntokens .and. tokens(pos)%value ==
'&&')
392 val = merge(1, 0, left /= 0 .and. parse_bitwise_or(expr, tokens, ntokens, pos, macros, ctx) /= 0)
408 recursive integer function parse_bitwise_or(expr, tokens, ntokens, pos, macros, ctx)
result(val)
409 character(*),
intent(in) :: expr
410 type(
token),
intent(in) :: tokens(:)
411 integer,
intent(in) :: ntokens
412 integer,
intent(inout) :: pos
413 type(
macro),
allocatable,
intent(inout) :: macros(:)
414 type(
context),
intent(in) :: ctx
418 left = parse_bitwise_xor(expr, tokens, ntokens, pos, macros, ctx)
419 if (pos > ntokens)
then
423 do while (pos <= ntokens .and. tokens(pos)%value ==
'|')
425 val = parse_bitwise_xor(expr, tokens, ntokens, pos, macros, ctx)
426 left = ior(left, val)
441 recursive integer function parse_bitwise_xor(expr, tokens, ntokens, pos, macros, ctx)
result(val)
442 character(*),
intent(in) :: expr
443 type(
token),
intent(in) :: tokens(:)
444 integer,
intent(in) :: ntokens
445 integer,
intent(inout) :: pos
446 type(
macro),
allocatable,
intent(inout) :: macros(:)
447 type(
context),
intent(in) :: ctx
451 left = parse_bitwise_and(expr, tokens, ntokens, pos, macros, ctx)
452 if (pos > ntokens)
then
456 do while (pos <= ntokens .and. tokens(pos)%value ==
'^')
458 val = parse_bitwise_and(expr, tokens, ntokens, pos, macros, ctx)
459 left = ieor(left, val)
474 recursive integer function parse_bitwise_and(expr, tokens, ntokens, pos, macros, ctx)
result(val)
475 character(*),
intent(in) :: expr
476 type(
token),
intent(in) :: tokens(:)
477 integer,
intent(in) :: ntokens
478 integer,
intent(inout) :: pos
479 type(
macro),
allocatable,
intent(inout) :: macros(:)
480 type(
context),
intent(in) :: ctx
484 left = parse_equality(expr, tokens, ntokens, pos, macros, ctx)
485 if (pos > ntokens)
then
489 do while (pos <= ntokens .and. tokens(pos)%value ==
'&')
491 val = parse_equality(expr, tokens, ntokens, pos, macros, ctx)
492 left = iand(left, val)
507 recursive integer function parse_equality(expr, tokens, ntokens, pos, macros, ctx)
result(val)
508 character(*),
intent(in) :: expr
509 type(
token),
intent(in) :: tokens(:)
510 integer,
intent(in) :: ntokens
511 integer,
intent(inout) :: pos
512 type(
macro),
allocatable,
intent(inout) :: macros(:)
513 type(
context),
intent(in) :: ctx
515 integer :: left, right
517 left = parse_relational(expr, tokens, ntokens, pos, macros, ctx)
518 if (pos > ntokens)
then
522 do while (pos <= ntokens .and. (tokens(pos)%value ==
'==' .or. tokens(pos)%value ==
'!='))
523 if (tokens(pos)%value ==
'==')
then
525 right = parse_relational(expr, tokens, ntokens, pos, macros, ctx)
526 val = merge(1, 0, left == right)
529 right = parse_relational(expr, tokens, ntokens, pos, macros, ctx)
530 val = merge(1, 0, left /= right)
547 recursive integer function parse_relational(expr, tokens, ntokens, pos, macros, ctx)
result(val)
548 character(*),
intent(in) :: expr
549 type(
token),
intent(in) :: tokens(:)
550 integer,
intent(in) :: ntokens
551 integer,
intent(inout) :: pos
552 type(
macro),
allocatable,
intent(inout) :: macros(:)
553 type(
context),
intent(in) :: ctx
555 integer :: left, right
557 left = parse_shifting(expr, tokens, ntokens, pos, macros, ctx)
558 if (pos > ntokens)
then
562 do while (pos <= ntokens .and. (tokens(pos)%value ==
'<' .or. tokens(pos)%value ==
'>' .or. &
563 tokens(pos)%value ==
'<=' .or. tokens(pos)%value ==
'>='))
564 if (tokens(pos)%value ==
'<')
then
566 right = parse_shifting(expr, tokens, ntokens, pos, macros, ctx)
567 val = merge(1, 0, left < right)
568 else if (tokens(pos)%value ==
'>')
then
570 right = parse_shifting(expr, tokens, ntokens, pos, macros, ctx)
571 val = merge(1, 0, left > right)
572 else if (tokens(pos)%value ==
'<=')
then
574 right = parse_shifting(expr, tokens, ntokens, pos, macros, ctx)
575 val = merge(1, 0, left <= right)
578 right = parse_shifting(expr, tokens, ntokens, pos, macros, ctx)
579 val = merge(1, 0, left >= right)
596 recursive integer function parse_shifting(expr, tokens, ntokens, pos, macros, ctx)
result(val)
597 character(*),
intent(in) :: expr
598 type(
token),
intent(in) :: tokens(:)
599 integer,
intent(in) :: ntokens
600 integer,
intent(inout) :: pos
601 type(
macro),
allocatable,
intent(inout) :: macros(:)
602 type(
context),
intent(in) :: ctx
604 integer :: left, right
606 left = parse_additive(expr, tokens, ntokens, pos, macros, ctx)
607 if (pos > ntokens)
then
611 do while (pos <= ntokens .and. (tokens(pos)%value ==
'<<' .or. tokens(pos)%value ==
'>>'))
612 if (tokens(pos)%value ==
'<<')
then
614 right = parse_additive(expr, tokens, ntokens, pos, macros, ctx)
615 val = lshift(left, right)
618 right = parse_additive(expr, tokens, ntokens, pos, macros, ctx)
619 val = rshift(left, right)
636 recursive integer function parse_additive(expr, tokens, ntokens, pos, macros, ctx)
result(val)
637 character(*),
intent(in) :: expr
638 type(
token),
intent(in) :: tokens(:)
639 integer,
intent(in) :: ntokens
640 integer,
intent(inout) :: pos
641 type(
macro),
allocatable,
intent(inout) :: macros(:)
642 type(
context),
intent(in) :: ctx
644 integer :: left, right
646 left = parse_multiplicative(expr, tokens, ntokens, pos, macros, ctx)
647 if (pos > ntokens)
then
651 do while (pos <= ntokens .and. (tokens(pos)%value ==
'+' .or. tokens(pos)%value ==
'-'))
652 if (tokens(pos)%value ==
'+')
then
654 right = parse_multiplicative(expr, tokens, ntokens, pos, macros, ctx)
658 right = parse_multiplicative(expr, tokens, ntokens, pos, macros, ctx)
676 recursive integer function parse_multiplicative(expr, tokens, ntokens, pos, macros, ctx)
result(val)
677 character(*),
intent(in) :: expr
678 type(
token),
intent(in) :: tokens(:)
679 integer,
intent(in) :: ntokens
680 integer,
intent(inout) :: pos
681 type(
macro),
allocatable,
intent(inout) :: macros(:)
682 type(
context),
intent(in) :: ctx
684 integer :: left, right
686 left = parse_unary(expr, tokens, ntokens, pos, macros, ctx)
687 if (pos > ntokens)
then
691 do while (pos <= ntokens .and. (tokens(pos)%value ==
'*' .or. tokens(pos)%value ==
'/' .or. tokens(pos)%value ==
'%'))
692 if (tokens(pos)%value ==
'*')
then
694 right = parse_unary(expr, tokens, ntokens, pos, macros, ctx)
696 else if (tokens(pos)%value ==
'/')
then
698 right = parse_unary(expr, tokens, ntokens, pos, macros, ctx)
702 right = parse_unary(expr, tokens, ntokens, pos, macros, ctx)
703 val = modulo(left, right)
720 recursive integer function parse_power(expr, tokens, ntokens, pos, macros, ctx)
result(val)
721 character(*),
intent(in) :: expr
722 type(
token),
intent(in) :: tokens(:)
723 integer,
intent(in) :: ntokens
724 integer,
intent(inout) :: pos
725 type(
macro),
allocatable,
intent(inout) :: macros(:)
726 type(
context),
intent(in) :: ctx
728 integer :: left, right
730 left = parse_atom(expr, tokens, ntokens, pos, macros, ctx)
731 if (pos > ntokens)
then
735 if (pos <= ntokens .and. tokens(pos)%value ==
'**')
then
738 right = parse_power(expr, tokens, ntokens, pos, macros, ctx)
755 recursive integer function parse_unary(expr, tokens, ntokens, pos, macros, ctx)
result(val)
756 character(*),
intent(in) :: expr
757 type(
token),
intent(in) :: tokens(:)
758 integer,
intent(in) :: ntokens
759 integer,
intent(inout) :: pos
760 type(
macro),
allocatable,
intent(inout) :: macros(:)
761 type(
context),
intent(in) :: ctx
763 if (pos <= ntokens .and. tokens(pos)%value ==
'!')
then
765 val = merge(0, 1, parse_unary(expr, tokens, ntokens, pos, macros, ctx) /= 0)
766 else if (pos <= ntokens .and. tokens(pos)%value ==
'-')
then
768 val = -parse_unary(expr, tokens, ntokens, pos, macros, ctx)
769 else if (pos <= ntokens .and. tokens(pos)%value ==
'+')
then
771 val = parse_unary(expr, tokens, ntokens, pos, macros, ctx)
772 else if (pos <= ntokens .and. tokens(pos)%value ==
'~')
then
774 val = not(parse_unary(expr, tokens, ntokens, pos, macros, ctx))
776 val = parse_power(expr, tokens, ntokens, pos, macros, ctx)
790 recursive integer function parse_atom(expr, tokens, ntokens, pos, macros, ctx)
result(val)
791 character(*),
intent(in) :: expr
792 type(
token),
intent(in) :: tokens(:)
793 integer,
intent(in) :: ntokens
794 integer,
intent(inout) :: pos
795 type(
macro),
allocatable,
intent(inout) :: macros(:)
796 type(
context),
intent(in) :: ctx
799 character(:),
allocatable :: expanded
802 if (pos > ntokens)
then
804 message=
'Syntax error', &
805 label=
label_type(
'Unexpected end of expression', pos, 1), &
806 source=
trim(ctx%path)), &
812 if (tokens(pos)%type == 0)
then
813 val =
strtol(tokens(pos)%value)
815 else if (tokens(pos)%type == 2)
then
816 if (
is_defined(tokens(pos)%value, macros))
then
817 expanded =
expand_macros(tokens(pos)%value, macros, stitch,
global%implicit_continuation, &
818 global%support_dollar_insert, ctx)
824 else if (tokens(pos)%value ==
'(')
then
827 if (pos > ntokens .or. tokens(pos)%value /=
')')
then
829 message=
'Syntax error', &
830 label=
label_type(
'Missing closing parenthesis in expression',
len(expr), 1), &
831 source=
trim(ctx%path)), &
837 else if (tokens(pos)%type == 4)
then
838 expanded =
trim(tokens(pos)%value)
839 val = merge(1, 0,
is_defined(expanded, macros))
843 message=
'Invalid expression', &
845 source=
trim(ctx%path)), &
type(global_settings), public global
Global preprocessor configuration instance.
character(:) function, allocatable, public expand_macros(line, macros, stitch, implicit_conti, dollar_insert, ctx)
Recursively expand user-defined macros.
logical function, public is_defined(name, macros, idx)
Determine whether a macro is currently defined.
recursive integer function, public parse_expression(expr, tokens, ntokens, pos, macros, ctx)
Parse and evaluate an already-tokenized expression.
subroutine, public tokenize(expr, tokens, ntokens)
Tokenizes a preprocessor expression into an array of token structures. Handles whitespace,...
Generic renderer for diagnostics and source excerpts.
Evaluates a preprocessor-style expression with macro substitution. Tokenizes the input expression,...
Return the trimmed length of a string object.
Return the length of a string object.
Remove trailing blanks from a string object.
Converts a string to integer.
Snapshot of a source location within the preprocessing stream.
Structured compiler diagnostic.
Diagnostic label identifying a region of source text.
Representation of a preprocessor macro.
Represents a single token in a parsed expression. Holds the string value of the token and its classif...