Core real parser.
The string is validated against an explicit grammar first and only
then converted with an F edit descriptor built for the exact field
width. List directed input is avoided on purpose, see the module
documentation.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| character(len=*), | intent(in) | :: | str | |||
| real(kind=dp), | intent(out) | :: | value | |||
| type(error_t), | intent(out) | :: | err |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| character(len=16), | private | :: | field_format | ||||
| integer(kind=default_int), | private | :: | n_digits | ||||
| integer(kind=default_int), | private | :: | pos | ||||
| logical, | private | :: | seen_point | ||||
| integer(kind=int32), | private | :: | stat |
Fixed width on purpose: |
|||
| character(len=:), | private, | allocatable | :: | text |
subroutine parse_real_wide(str, value, err) !! Core real parser. !! !! The string is validated against an explicit grammar first and only !! then converted with an `F` edit descriptor built for the exact field !! width. List directed input is avoided on purpose, see the module !! documentation. character(len=*), intent(in) :: str real(dp), intent(out) :: value type(error_t), intent(out) :: err character(len=:), allocatable :: text character(len=16) :: field_format integer(default_int) :: pos, n_digits integer(int32) :: stat !! Fixed width on purpose: `iostat` takes a default integer, which is !! `int32` regardless of how PIC defines `default_int`. logical :: seen_point value = 0.0_dp text = strip(str) if (len(text) == 0) then call err%set(ERROR_PARSE, "cannot parse an empty string as a real") return end if pos = 1 call skip_sign(text, pos) n_digits = 0 seen_point = .false. do while (pos <= len(text)) if (index(digits, text(pos:pos)) > 0) then n_digits = n_digits + 1 else if (text(pos:pos) == "." .and. .not. seen_point) then seen_point = .true. else exit end if pos = pos + 1 end do if (n_digits == 0) then call err%set(ERROR_PARSE, "no digits in the mantissa of '"//text//"'") return end if if (pos <= len(text)) then call check_exponent(text, pos, err) if (err%has_error()) return end if write (field_format, '("(F",I0,".0)")') len(text) read (text, field_format, iostat=stat) value ! A failed read leaves `value` undefined, so make it safe to inspect ! before the range check below looks at it. if (stat /= 0_int32) value = 0.0_dp ! Compilers disagree on what an out of range field does: some report a ! non zero iostat, others quietly deliver an infinity. Reject both. if (stat /= 0_int32 .or. abs(value) > huge(value)) then value = 0.0_dp call err%set(ERROR_PARSE, "real out of range or not convertible: '"//text//"'") return end if end subroutine parse_real_wide