60 implicit none;
private
76 enumerator :: unknown = -1
77 enumerator :: number = 0
78 enumerator :: operation = 1
79 enumerator :: identifier = 2
80 enumerator :: parenthesis = 3
81 enumerator :: defined = 4
106 character(:),
allocatable ::
value
107 integer(tokens_enum) ::
type
142 module procedure :: strtol_default
143 module procedure :: strtol_with_base
159 character(*),
intent(in) :: expr
160 type(
token),
allocatable,
intent(out) :: tokens(:)
161 integer,
intent(out) :: ntokens
163 character(:),
allocatable :: temp
164 integer :: i, pos, len_expr
166 logical,
save :: in_comment
168 if (
allocated(tokens))
deallocate(tokens)
171 temp =
trim(adjustl(expr)) //
' '
176 do while (i <= len_expr)
177 if (temp(i:i) ==
' ')
then
183 if (.not. in_word)
then
184 ntokens = ntokens + 1
187 message=
'The maximum number of tokens has been reached', &
188 label=
label_type(
'Too many tokens in expression.', 1, 1)), &
195 if (temp(i:i) ==
'(' .or. temp(i:i) ==
')')
then
196 tokens(ntokens)%value = temp(i:i)
197 tokens(ntokens)%type = parenthesis
198 tokens(ntokens)%start = i
201 else if (temp(i:i + 1) ==
'&&' .or. temp(i:i + 1) ==
'||' .or. temp(i:i + 1) ==
'==' .or. &
202 temp(i:i + 1) ==
'!=' .or. temp(i:i + 1) ==
'<=' .or. temp(i:i + 1) ==
'>=')
then
203 tokens(ntokens)%value = temp(i:i + 1)
204 tokens(ntokens)%type = operation
205 tokens(ntokens)%start = i
208 else if (temp(i:i) ==
'!')
then
209 tokens(ntokens)%value = temp(i:i)
210 tokens(ntokens)%type = operation
211 tokens(ntokens)%start = i
214 else if (temp(i:i + 1) ==
'**')
then
215 tokens(ntokens)%value = temp(i:i + 1)
216 tokens(ntokens)%type = operation
217 tokens(ntokens)%start = i
220 else if (temp(i:i + 1) ==
'<<' .or. temp(i:i + 1) ==
'>>')
then
221 tokens(ntokens)%value = temp(i:i + 1)
222 tokens(ntokens)%type = operation
223 tokens(ntokens)%start = i
226 else if (temp(i:i) ==
'<' .or. temp(i:i) ==
'>' .or. temp(i:i) ==
'=' .or. &
227 temp(i:i) ==
'+' .or. temp(i:i) ==
'-' .or. temp(i:i) ==
'*' .or. &
228 temp(i:i) ==
'/' .or. temp(i:i) ==
'%' .or. &
229 temp(i:i) ==
'?' .or. temp(i:i) ==
':')
then
230 tokens(ntokens)%value = temp(i:i)
231 tokens(ntokens)%type = operation
232 tokens(ntokens)%start = i
235 else if (temp(i:i) ==
'&' .or. temp(i:i) ==
'|' .or. temp(i:i) ==
'^' .or. &
236 temp(i:i) ==
'~')
then
237 tokens(ntokens)%value = temp(i:i)
238 tokens(ntokens)%type = operation
239 tokens(ntokens)%start = i
244 do while (i <= len_expr .and. temp(i:i) ==
' ')
247 if (i <= len_expr .and. temp(i:i) ==
'(')
then
250 do while (pos <= len_expr .and. temp(pos:pos) /=
')')
253 tokens(ntokens)%value =
trim(adjustl(temp(i:pos - 1)))
254 tokens(ntokens)%type = defined
255 tokens(ntokens)%start = i
259 do while (pos <= len_expr .and. temp(pos:pos) /=
' ')
262 tokens(ntokens)%value =
trim(adjustl(temp(i:pos - 1)))
263 tokens(ntokens)%type = defined
264 tokens(ntokens)%start = i
268 else if (is_typeless(temp(i:), pos))
then
270 tokens(ntokens)%value =
trim(adjustl(temp(i:pos - 1)))
271 tokens(ntokens)%type = number
272 tokens(ntokens)%start = i
275 else if (is_digit(temp(i:i)))
then
277 do while (pos <= len_expr .and. is_digit(temp(pos:pos)))
280 tokens(ntokens)%value =
trim(adjustl(temp(i:pos - 1)))
281 tokens(ntokens)%type = number
282 tokens(ntokens)%start = i
287 do while (pos <= len_expr .and. temp(pos:pos) /=
' ' .and. &
288 temp(pos:pos) /=
'(' .and. temp(pos:pos) /=
')')
291 tokens(ntokens)%value =
trim(temp(i:pos - 1))
292 tokens(ntokens)%type = identifier
293 tokens(ntokens)%start = i
305 logical elemental function is_digit(ch) result(res)
306 character(*),
intent(in) :: ch
308 res = verify(ch,
'0123456789') == 0
318 logical function is_typeless(str, pos)
result(res)
319 character(*),
intent(in) :: str
320 integer,
intent(out) :: pos
322 integer :: i, base, n
324 pos = 0; base = 0; n = len(str)
326 if (verify(str(i:i),
'0123456789xXaAbBcCdDeEfF') /= 0)
then
331 if (pos > 0) i =
strtol(str(:pos - 1), base, success=res)
332 if (base == 10) res = .false.
336 integer function strtol_default(str, success)
result(val)
337 character(*),
intent(in) :: str
338 logical,
intent(out),
optional :: success
343 val = strtol_with_base(str, base, success)
347 integer function strtol_with_base(str, base, success)
result(val)
348 character(*),
intent(in) :: str
349 integer,
intent(inout) :: base
350 logical,
intent(out),
optional :: success
352 integer :: i, len, digit
354 logical :: is_valid, isdigit, is_lower_hex, is_upper_hex
355 character(len=len_trim(str)) :: work_str
357 val = 0; is_valid = .true.
358 work_str = adjustl(str)
359 len = len_trim(work_str)
364 if (work_str(1:2) ==
'0x' .or. work_str(1:2) ==
'0X')
then
366 work_str = work_str(3:len)
368 else if (work_str(1:2) ==
'0b' .or. work_str(1:2) ==
'0B')
then
370 work_str = work_str(3:len)
374 if (work_str(1:1) ==
'0')
then
389 if (base /= 2 .and. base /= 8 .and. base /= 10 .and. base /= 16)
then
391 if (
present(success)) success = .false.
401 isdigit = c >=
'0' .and. c <=
'9'
402 if (isdigit) digit = ichar(c) - ichar(
'0')
404 is_lower_hex = base == 16 .and. c >=
'a' .and. c <=
'f'
405 if (is_lower_hex) digit = ichar(c) - ichar(
'a') + 10
407 is_upper_hex = base == 16 .and. c >=
'A' .and. c <=
'F'
408 if (is_upper_hex) digit = ichar(c) - ichar(
'A') + 10
411 if (digit == -1)
then
415 if (digit >= base)
then
421 if (val > (huge(val) - digit) / base)
then
427 val = val * base + digit
431 if (
present(success)) success = is_valid
integer, parameter, public max_tokens
Maximum number of tokens generated during tokenization.
logical function, public starts_with(str, arg1, idx)
Checks if a string starts with a given prefix Returns .true. if the string str (after trimming leadin...
integer, parameter, public tokens_enum
Kind parameter for token type enumeration. Values are (unknown, number, operation,...
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.
Return the trimmed length of a string object.
Remove trailing blanks from a string object.
Converts a string to integer.
Structured compiler diagnostic.
Diagnostic label identifying a region of source text.
Represents a single token in a parsed expression. Holds the string value of the token and its classif...