1"""
2 pygments.lexers.fortran
3 ~~~~~~~~~~~~~~~~~~~~~~~
4
5 Lexers for Fortran languages.
6
7 :copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
8 :license: BSD, see LICENSE for details.
9"""
10
11import re
12
13from pygments.lexer import RegexLexer, bygroups, include, words, using, default
14from pygments.token import Text, Comment, Operator, Keyword, Name, String, \
15 Number, Punctuation, Generic
16
17__all__ = ['FortranLexer', 'FortranFixedLexer']
18
19
20class FortranLexer(RegexLexer):
21 """
22 Lexer for FORTRAN 90 code.
23 """
24 name = 'Fortran'
25 url = 'https://fortran-lang.org/'
26 aliases = ['fortran', 'f90']
27 filenames = ['*.f03', '*.f90', '*.F03', '*.F90']
28 mimetypes = ['text/x-fortran']
29 version_added = '0.10'
30 flags = re.IGNORECASE | re.MULTILINE
31
32 # Data Types: INTEGER, REAL, COMPLEX, LOGICAL, CHARACTER and DOUBLE PRECISION
33 # Operators: **, *, +, -, /, <, >, <=, >=, ==, /=
34 # Logical (?): NOT, AND, OR, EQV, NEQV
35
36 # Builtins:
37 # http://gcc.gnu.org/onlinedocs/gcc-3.4.6/g77/Table-of-Intrinsic-Functions.html
38
39 tokens = {
40 'root': [
41 (r'^#.*\n', Comment.Preproc),
42 (r'!.*\n', Comment),
43 include('strings'),
44 include('core'),
45 (r'[a-z][\w$]*', Name),
46 include('nums'),
47 (r'[\s]+', Text.Whitespace),
48 ],
49 'core': [
50 # Statements
51
52 (r'\b(DO)(\s+)(CONCURRENT)\b', bygroups(Keyword, Text.Whitespace, Keyword)),
53 (r'\b(GO)(\s*)(TO)\b', bygroups(Keyword, Text.Whitespace, Keyword)),
54
55 (words((
56 'ABSTRACT', 'ACCEPT', 'ALL', 'ALLSTOP', 'ALLOCATABLE', 'ALLOCATE',
57 'ARRAY', 'ASSIGN', 'ASSOCIATE', 'ASYNCHRONOUS', 'BACKSPACE', 'BIND',
58 'BLOCK', 'BLOCKDATA', 'BYTE', 'CALL', 'CASE', 'CLASS', 'CLOSE',
59 'CODIMENSION', 'COMMON', 'CONTIGUOUS', 'CONTAINS',
60 'CONTINUE', 'CRITICAL', 'CYCLE', 'DATA', 'DEALLOCATE', 'DECODE',
61 'DEFERRED', 'DIMENSION', 'DO', 'ELEMENTAL', 'ELSE', 'ELSEIF', 'ENCODE',
62 'END', 'ENDASSOCIATE', 'ENDBLOCK', 'ENDDO', 'ENDENUM', 'ENDFORALL',
63 'ENDFUNCTION', 'ENDIF', 'ENDINTERFACE', 'ENDMODULE', 'ENDPROGRAM',
64 'ENDSELECT', 'ENDSUBMODULE', 'ENDSUBROUTINE', 'ENDTYPE', 'ENDWHERE',
65 'ENTRY', 'ENUM', 'ENUMERATOR', 'EQUIVALENCE', 'ERROR STOP', 'EXIT',
66 'EXTENDS', 'EXTERNAL', 'EXTRINSIC', 'FILE', 'FINAL', 'FORALL', 'FORMAT',
67 'FUNCTION', 'GENERIC', 'IF', 'IMAGES', 'IMPLICIT',
68 'IMPORT', 'IMPURE', 'INCLUDE', 'INQUIRE', 'INTENT', 'INTERFACE',
69 'INTRINSIC', 'IS', 'LOCK', 'MEMORY', 'MODULE', 'NAMELIST', 'NULLIFY',
70 'NONE', 'NON_INTRINSIC', 'NON_OVERRIDABLE', 'NOPASS', 'ONLY', 'OPEN',
71 'OPTIONAL', 'OPTIONS', 'PARAMETER', 'PASS', 'PAUSE', 'POINTER', 'PRINT',
72 'PRIVATE', 'PROGRAM', 'PROCEDURE', 'PROTECTED', 'PUBLIC', 'PURE', 'READ',
73 'RECURSIVE', 'RESULT', 'RETURN', 'REWIND', 'SAVE', 'SELECT', 'SEQUENCE',
74 'STOP', 'SUBMODULE', 'SUBROUTINE', 'SYNC', 'SYNCALL', 'SYNCIMAGES',
75 'SYNCMEMORY', 'TARGET', 'THEN', 'TYPE', 'UNLOCK', 'USE', 'VALUE',
76 'VOLATILE', 'WHERE', 'WRITE', 'WHILE'), prefix=r'\b', suffix=r'\s*\b'),
77 Keyword),
78
79 # Data Types
80 (words((
81 'CHARACTER', 'COMPLEX', 'DOUBLE PRECISION', 'DOUBLE COMPLEX', 'INTEGER',
82 'LOGICAL', 'REAL', 'C_INT', 'C_SHORT', 'C_LONG', 'C_LONG_LONG',
83 'C_SIGNED_CHAR', 'C_SIZE_T', 'C_INT8_T', 'C_INT16_T', 'C_INT32_T',
84 'C_INT64_T', 'C_INT_LEAST8_T', 'C_INT_LEAST16_T', 'C_INT_LEAST32_T',
85 'C_INT_LEAST64_T', 'C_INT_FAST8_T', 'C_INT_FAST16_T', 'C_INT_FAST32_T',
86 'C_INT_FAST64_T', 'C_INTMAX_T', 'C_INTPTR_T', 'C_FLOAT', 'C_DOUBLE',
87 'C_LONG_DOUBLE', 'C_FLOAT_COMPLEX', 'C_DOUBLE_COMPLEX',
88 'C_LONG_DOUBLE_COMPLEX', 'C_BOOL', 'C_CHAR', 'C_PTR', 'C_FUNPTR'),
89 prefix=r'\b', suffix=r'\s*\b'),
90 Keyword.Type),
91
92 # Operators
93 (r'(\*\*|\*|\+|-|\/|<|>|<=|>=|==|\/=|=)', Operator),
94
95 (r'(::)', Keyword.Declaration),
96
97 (r'[()\[\],:&%;.]', Punctuation),
98 # Intrinsics
99 (words((
100 'Abort', 'Abs', 'Access', 'AChar', 'ACos', 'ACosH', 'AdjustL',
101 'AdjustR', 'AImag', 'AInt', 'Alarm', 'All', 'Allocated', 'ALog',
102 'AMax', 'AMin', 'AMod', 'And', 'ANInt', 'Any', 'ASin', 'ASinH',
103 'Associated', 'ATan', 'ATanH', 'Atomic_Define', 'Atomic_Ref',
104 'BesJ', 'BesJN', 'Bessel_J0', 'Bessel_J1', 'Bessel_JN', 'Bessel_Y0',
105 'Bessel_Y1', 'Bessel_YN', 'BesY', 'BesYN', 'BGE', 'BGT', 'BLE',
106 'BLT', 'Bit_Size', 'BTest', 'CAbs', 'CCos', 'Ceiling', 'CExp',
107 'Char', 'ChDir', 'ChMod', 'CLog', 'Cmplx', 'Command_Argument_Count',
108 'Complex', 'Conjg', 'Cos', 'CosH', 'Count', 'CPU_Time', 'CShift',
109 'CSin', 'CSqRt', 'CTime', 'C_Loc', 'C_Associated',
110 'C_Null_Ptr', 'C_Null_Funptr', 'C_F_Pointer', 'C_F_ProcPointer',
111 'C_Null_Char', 'C_Alert', 'C_Backspace', 'C_Form_Feed', 'C_FunLoc',
112 'C_Sizeof', 'C_New_Line', 'C_Carriage_Return',
113 'C_Horizontal_Tab', 'C_Vertical_Tab', 'DAbs', 'DACos', 'DASin',
114 'DATan', 'Date_and_Time', 'DbesJ', 'DbesJN', 'DbesY',
115 'DbesYN', 'Dble', 'DCos', 'DCosH', 'DDiM', 'DErF',
116 'DErFC', 'DExp', 'Digits', 'DiM', 'DInt', 'DLog', 'DMax',
117 'DMin', 'DMod', 'DNInt', 'Dot_Product', 'DProd', 'DSign', 'DSinH',
118 'DShiftL', 'DShiftR', 'DSin', 'DSqRt', 'DTanH', 'DTan', 'DTime',
119 'EOShift', 'Epsilon', 'ErF', 'ErFC', 'ErFC_Scaled', 'ETime',
120 'Execute_Command_Line', 'Exit', 'Exp', 'Exponent', 'Extends_Type_Of',
121 'FDate', 'FGet', 'FGetC', 'FindLoc', 'Float', 'Floor', 'Flush',
122 'FNum', 'FPutC', 'FPut', 'Fraction', 'FSeek', 'FStat', 'FTell',
123 'Gamma', 'GError', 'GetArg', 'Get_Command', 'Get_Command_Argument',
124 'Get_Environment_Variable', 'GetCWD', 'GetEnv', 'GetGId', 'GetLog',
125 'GetPId', 'GetUId', 'GMTime', 'HostNm', 'Huge', 'Hypot', 'IAbs',
126 'IAChar', 'IAll', 'IAnd', 'IAny', 'IArgC', 'IBClr', 'IBits',
127 'IBSet', 'IChar', 'IDate', 'IDiM', 'IDInt', 'IDNInt', 'IEOr',
128 'IErrNo', 'IFix', 'Imag', 'ImagPart', 'Image_Index', 'Index',
129 'Int', 'IOr', 'IParity', 'IRand', 'IsaTty', 'IShft', 'IShftC',
130 'ISign', 'Iso_C_Binding', 'Is_Contiguous', 'Is_Iostat_End',
131 'Is_Iostat_Eor', 'ITime', 'Kill', 'Kind', 'LBound', 'LCoBound',
132 'Len', 'Len_Trim', 'LGe', 'LGt', 'Link', 'LLe', 'LLt', 'LnBlnk',
133 'Loc', 'Log', 'Log_Gamma', 'Logical', 'Long', 'LShift', 'LStat',
134 'LTime', 'MaskL', 'MaskR', 'MatMul', 'Max', 'MaxExponent',
135 'MaxLoc', 'MaxVal', 'MClock', 'Merge', 'Merge_Bits', 'Move_Alloc',
136 'Min', 'MinExponent', 'MinLoc', 'MinVal', 'Mod', 'Modulo', 'MvBits',
137 'Nearest', 'New_Line', 'NInt', 'Norm2', 'Not', 'Null', 'Num_Images',
138 'Or', 'Pack', 'Parity', 'PError', 'Precision', 'Present', 'Product',
139 'Radix', 'Rand', 'Random_Number', 'Random_Seed', 'Range', 'Real',
140 'RealPart', 'Rename', 'Repeat', 'Reshape', 'RRSpacing', 'RShift',
141 'Same_Type_As', 'Scale', 'Scan', 'Second', 'Selected_Char_Kind',
142 'Selected_Int_Kind', 'Selected_Real_Kind', 'Set_Exponent', 'Shape',
143 'ShiftA', 'ShiftL', 'ShiftR', 'Short', 'Sign', 'Signal', 'SinH',
144 'Sin', 'Sleep', 'Sngl', 'Spacing', 'Spread', 'SqRt', 'SRand',
145 'Stat', 'Storage_Size', 'Sum', 'SymLnk', 'System', 'System_Clock',
146 'Tan', 'TanH', 'Time', 'This_Image', 'Tiny', 'TrailZ', 'Transfer',
147 'Transpose', 'Trim', 'TtyNam', 'UBound', 'UCoBound', 'UMask',
148 'Unlink', 'Unpack', 'Verify', 'XOr', 'ZAbs', 'ZCos', 'ZExp',
149 'ZLog', 'ZSin', 'ZSqRt'), prefix=r'\b', suffix=r'\s*\b'),
150 Name.Builtin),
151
152 # Booleans
153 (r'\.(true|false)\.', Name.Builtin),
154 # Comparing Operators
155 (r'\.(eq|ne|lt|le|gt|ge|not|and|or|eqv|neqv)\.', Operator.Word),
156 ],
157
158 'strings': [
159 (r'"(\\[0-7]+|\\[^0-7]|[^"\\])*"', String.Double),
160 (r"'(\\[0-7]+|\\[^0-7]|[^'\\])*'", String.Single),
161 ],
162
163 'nums': [
164 (r'\d+(?![.e])(_([1-9]|[a-z]\w*))?', Number.Integer),
165 (r'[+-]?\d*\.\d+([ed][-+]?\d+)?(_([1-9]|[a-z]\w*))?', Number.Float),
166 (r'[+-]?\d+\.\d*([ed][-+]?\d+)?(_([1-9]|[a-z]\w*))?', Number.Float),
167 (r'[+-]?\d+(\.\d*)?[ed][-+]?\d+(_([1-9]|[a-z]\w*))?', Number.Float),
168 ],
169 }
170
171
172class FortranFixedLexer(RegexLexer):
173 """
174 Lexer for fixed format Fortran.
175 """
176 name = 'FortranFixed'
177 aliases = ['fortranfixed']
178 filenames = ['*.f', '*.F']
179 url = 'https://fortran-lang.org/'
180 version_added = '2.1'
181
182 flags = re.IGNORECASE
183
184 def _lex_fortran(self, match, ctx=None):
185 """Lex a line just as free form fortran without line break."""
186 lexer = FortranLexer()
187 text = match.group(0) + "\n"
188 for index, token, value in lexer.get_tokens_unprocessed(text):
189 value = value.replace('\n', '')
190 if value != '':
191 yield index, token, value
192
193 tokens = {
194 'root': [
195 (r'[C*].*\n', Comment),
196 (r'#.*\n', Comment.Preproc),
197 (r' {0,4}!.*\n', Comment),
198 (r'(.{5})', Name.Label, 'cont-char'),
199 (r'.*\n', using(FortranLexer)),
200 ],
201 'cont-char': [
202 (' ', Text, 'code'),
203 ('0', Comment, 'code'),
204 ('.', Generic.Strong, 'code'),
205 ],
206 'code': [
207 (r'(.{66})(.*)(\n)',
208 bygroups(_lex_fortran, Comment, Text.Whitespace), 'root'),
209 (r'(.*)(\n)', bygroups(_lex_fortran, Text.Whitespace), 'root'),
210 default('root'),
211 ]
212 }