Loading...
Searching...
No Matches
line.f90
Go to the documentation of this file.
1!> @file
2!! @defgroup group_line Line
3!! Standard `#line` directive support for the fpx Fortran preprocessor
4!!
5!! This module implements full support for the ISO C99/C11 `#line` directive,
6!! which is also widely used in Fortran preprocessors.
7!!
8!! The `#line` directive allows changing the logical line number and/or source
9!! filename reported by the preprocessor. It is particularly useful for:
10!! - Code generators
11!! - Literate programming tools
12!! - Macro-heavy generated code
13!! - Accurate `__LINE__` and `__FILE__` expansion in included/generated files
14!!
15!! Supported forms (standard compliant):
16!! - `#line <number>`
17!! - `#line <number> "<filename>"`
18!!
19!! When a `#line` directive is encountered, the current context (line number and
20!! filename) is updated immediately. This affects all subsequent diagnostics,
21!! `__LINE__`, `__FILE__`, and `__FILENAME__` macros.
22!!
23!! <h2 class="groupheader">Examples</h2>
24!!
25!! 1. Basic line number reset:
26!! @code{.f90}
27!! #line 100
28!! print *, "This line will be reported as line 100"
29!! @endcode
30!!
31!! 2. Changing both line number and filename (common in generated code):
32!! @code{.f90}
33!! #line 42 "generated_code.f90"
34!! integer :: x = 1 ! This will appear as line 42 in generated_code.f90
35!! @endcode
36!!
37!! @par Remarks
38!! - The line number in `#line N` refers to the **next** line after the directive.
39!! - Filename must be quoted if provided.
40!! - Invalid line numbers or malformed directives emit a warning but are ignored.
41!! - Updates the shared `context` object used by the logging and macro systems.
42module fpx_line
43 use fpx_path
44 use fpx_logging
45 use fpx_context
46
47 implicit none; private
48
49 public :: handle_line
50
51contains
52
53 !> Handle the standard #line directive
54 !! Supports two standard forms:
55 !! #line <number>
56 !! #line <number> "<filename>"
57 !!
58 !! This updates the current line number (`ctx%line`) and optionally the current
59 !! filename (`ctx%path`) for subsequent diagnostics, `__LINE__`, and `__FILE__`
60 !! expansions.
61 !!
62 !! Fully compliant with ISO C99 / C11 �6.10.4 and common Fortran preprocessor behavior.
63 !!
64 !! @param[inout] ctx Context source line containing the #line directive
65 !! @param[in] token Usually 'DEFINE' � keyword matched in lowercase
66 !!
67 !! @b Remarks
68 !! @ingroup group_line
69 subroutine handle_line(ctx, token)
70 type(context), intent(inout) :: ctx
71 character(*), intent(in) :: token
72 !private
73 character(:), allocatable :: temp, num_str, fname
74 integer :: pos, iostat, new_line
75 logical :: has_filename
76
77 ! Skip #line keyword
78 pos = index(lowercase(ctx%content), token) + len(token)
79 temp = trim(adjustl(ctx%content(pos:)))
80
81 if (len_trim(temp) == 0) then
82 call printf(render(diagnostic_report(level_warning, &
83 message='Synthax error', &
84 label=label_type('#line directive with no arguments', index(token, lowercase(ctx%content)) + len(token) + 1, 1), &
85 source=ctx%path), &
86 trim(ctx%content), ctx%line))
87 return
88 end if
89
90 ! Extract line number
91 pos = index(temp, ' ')
92 if (pos > 0) then
93 num_str = temp(:pos-1)
94 fname = trim(adjustl(temp(pos:)))
95 has_filename = .true.
96 else
97 num_str = trim(temp)
98 has_filename = .false.
99 end if
100
101 ! Parse line number
102 read(num_str, *, iostat=iostat) new_line
103 if (iostat /= 0 .or. new_line < 1) then
104 call printf(render(diagnostic_report(level_warning, &
105 message='Synthax error', &
106 label=label_type('Invalid line number in #line directive', index(token, lowercase(ctx%content)) + len(token) + 1, len(num_str)), &
107 source=ctx%path), &
108 trim(ctx%content), ctx%line))
109 end if
110
111 ! Update current line number (subtract 1 because the next line will be +1)
112 ctx%line = new_line - 1
113
114 ! Update filename if provided (strip quotes)
115 if (has_filename) then
116 if (fname(1:1) == '"' .and. len(fname) > 1) then
117 fname = fname(2:index(fname(2:), '"'))
118 end if
119 if (len_trim(fname) > 0) then
120 ctx%path = trim(fname)
121 end if
122 end if
123 end subroutine
124end module
subroutine, public handle_line(ctx, token)
Handle the standard line directive Supports two standard forms: line <number> line <number> "<filenam...
Definition line.f90:70
Interface to render diagnostic messages and labels.
Definition logging.f90:185
Source location and content snapshot for precise diagnostics Instances of this type are created for e...
Definition context.f90:99
Definition of diagnostic message.
Definition logging.f90:269
Represents text as a sequence of ASCII code units. The derived type wraps an allocatable character ar...
Definition logging.f90:246