257 integer,
intent(in) :: iunit
258 integer,
intent(in) :: ounit
259 type(macro),
allocatable,
intent(inout) :: macros(:)
260 logical,
intent(in) :: from_include
263 character(:),
allocatable :: uline
264 logical :: interactive
266 interactive = iunit == stdin
268 if (interactive)
then
270 write(*, *)
' Welcome to fpx, the extended Fortran preprocessor. '
271 write(*, *)
' The program can be exited at any time by hitting'
272 write(*, *)
" 'Enter' at the prompt without entering any data, "
273 write(*, *)
" or with the 'quit' command."
276 if (interactive)
write(*,
'(/a)', advance=
'no')
' [in] '
277 read(iunit,
'(A)', iostat=ierr) line
279 if (interactive)
then
281 uline = uppercase(trim(adjustl(line)))
282 if (uline ==
'QUIT')
exit
285 if (ierr == iostat_end .and. from_include) f_continue = tail(tmp) ==
'&'
288 if (.not. from_include) iline = iline + 1
291 continued_line = continued_line(:icontinuation) // trim(adjustl(line))
293 continued_line = trim(adjustl(line))
295 n = len_trim(continued_line);
if (n == 0) cycle
298 if (verify(continued_line(n:n),
'\') == 0)
then
300 if (continued_line(len_trim(continued_line) - 1:len_trim(continued_line)) ==
'\\' .and. global%line_break)
then
302 continued_line = continued_line(:len_trim(continued_line) - 2) // new_line(
'A')
303 icontinuation = len_trim(continued_line)
306 icontinuation = len_trim(continued_line) - 1
307 continued_line = continued_line(:icontinuation)
313 tmp =
process_line(continued_line, ounit, name, iline, macros, stitch)
314 if (len_trim(tmp) == 0) cycle
316 in_comment = head(tmp) ==
'!'
318 if (merge(head(res) ==
'!', in_comment, len_trim(res) > 0))
then
319 f_continue = tail(tmp) ==
'&'
321 if (in_comment .and. f_continue) cycle
322 f_continue = .not. in_comment .and. tail(tmp) ==
'&'
325 if (f_continue .or. stitch)
then
327 res = concat(res, tmp)
330 if (.not. in_comment .and. head(res) ==
'!')
then
331 write(ounit,
'(A)') res
332 res =
process_line(tmp, ounit, name, iline, macros, stitch)
334 res =
process_line(concat(res, tmp), ounit, name, iline, macros, stitch)
340 if (interactive)
write(*,
'(/a)', advance=
'no')
' [out] '
341 write(ounit,
'(A)') res
347 if (cond_depth > 0)
then
348 if (verbose) print *,
"Error: Unclosed conditional block at end of file ", trim(name)
368 recursive function process_line(current_line, ounit, filepath, linenum, macros, stch)
result(rst)
369 character(*),
intent(in) :: current_line
370 integer,
intent(in) :: ounit
371 character(*),
intent(in) :: filepath
372 integer,
intent(in) :: linenum
373 type(macro),
allocatable,
intent(inout) :: macros(:)
374 logical,
intent(out) :: stch
375 character(:),
allocatable :: rst
377 character(:),
allocatable :: trimmed_line
379 logical,
save :: l_in_comment = .false.
380 integer :: idx, comment_start, comment_end, n
382 trimmed_line = trim(adjustl(current_line))
384 comment_end = index(trimmed_line,
'*/')
385 if (l_in_comment .and. comment_end > 0)
then
386 trimmed_line = trimmed_line(comment_end + 2:)
387 l_in_comment = .false.
390 if (l_in_comment)
return
391 comment_start = index(trimmed_line,
'/*')
392 if (comment_start > 0)
then
393 trimmed_line = trimmed_line(:comment_start - 1)
394 l_in_comment = comment_end == 0
396 n = len(trimmed_line);
if (n == 0)
return
399 if (verbose) print *,
"Processing line ", linenum,
": '", trim(trimmed_line),
"'"
400 if (verbose) print *,
"is_active() = ", active,
", cond_depth = ", cond_depth
401 if (head(trimmed_line) ==
'#')
then
402 if (len(trimmed_line) == 1)
then
404 else if (starts_with(uppercase(adjustl(trimmed_line(2:))),
'DEFINE') .and. active)
then
405 call handle_define(trimmed_line, macros,
'DEFINE')
406 else if (starts_with(uppercase(adjustl(trimmed_line(2:))),
'UNDEF') .and. active)
then
407 call handle_undef(trimmed_line, macros,
'UNDEF')
408 else if (starts_with(uppercase(adjustl(trimmed_line(2:))),
'WARNING') .and. active)
then
409 call handle_warning(trimmed_line, macros,
'WARNING')
410 else if (starts_with(uppercase(adjustl(trimmed_line(2:))),
'ERROR') .and. active)
then
411 call handle_error(trimmed_line, macros,
'ERROR')
412 else if (starts_with(uppercase(adjustl(trimmed_line(2:))),
'INCLUDE') .and. active)
then
413 call handle_include(trimmed_line, ounit, filepath, linenum,
preprocess_unit, macros,
'INCLUDE')
414 else if (starts_with(uppercase(adjustl(trimmed_line(2:))),
'IFDEF'))
then
415 call handle_ifdef(trimmed_line, filepath, linenum, macros,
'IFDEF')
416 else if (starts_with(uppercase(adjustl(trimmed_line(2:))),
'IFNDEF'))
then
417 call handle_ifndef(trimmed_line, filepath, linenum, macros,
'IFNDEF')
418 else if (starts_with(uppercase(adjustl(trimmed_line(2:))),
'ELIFDEF'))
then
419 call handle_elifdef(trimmed_line, filepath, linenum, macros,
'ELIFDEF')
420 else if (starts_with(uppercase(adjustl(trimmed_line(2:))),
'ELIFNDEF'))
then
421 call handle_elifndef(trimmed_line, filepath, linenum, macros,
'ELIFNDEF')
422 else if (starts_with(uppercase(adjustl(trimmed_line(2:))),
'IF'))
then
423 call handle_if(trimmed_line, filepath, linenum, macros,
'IF')
424 else if (starts_with(uppercase(adjustl(trimmed_line(2:))),
'ELIF'))
then
425 call handle_elif(trimmed_line, filepath, linenum, macros,
'ELIF')
426 else if (starts_with(uppercase(adjustl(trimmed_line(2:))),
'ELSE'))
then
427 call handle_else(filepath, linenum)
428 else if (starts_with(uppercase(adjustl(trimmed_line(2:))),
'ENDIF'))
then
429 call handle_endif(filepath, linenum)
430 else if (starts_with(uppercase(adjustl(trimmed_line(2:))),
'PRAGMA') .and. active)
then
433 else if (active)
then
434 if (.not. global%expand_macros)
then
437 rst = adjustl(expand_all(trimmed_line, macros, filepath, linenum, stch, global%extra_macros))
438 if (verbose) print *,
"Writing to output: '", trim(rst),
"'"