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