1
+ module CodeRay
2
+ module Scanners
3
+
4
+ # by Ralf Mueller
5
+ class Fortran < Scanner
6
+
7
+ register_for :fortran
8
+
9
+ include Streamable
10
+
11
+ KEYWORDS = %w[
12
+ allocatable allocate assign assignment backspace
13
+ block call close common
14
+ contains continue cycle data deallocate
15
+ dimension endfile end entry equivalence exit
16
+ external format goto
17
+ implicit include inquire intent
18
+ intrinsic namelist none
19
+ nully only open operator optional parameter
20
+ pause pointer print private procedure
21
+ public read recursive result return
22
+ rewind save sequence stop
23
+ target use while write ] +
24
+ # F95 keywords.
25
+ %w[ elemental pure ] +
26
+ # F2003
27
+ %w[ abstract associate asynchronous bind class
28
+ deferred enum enumerator extends extends_type_of
29
+ final generic import non_intrinsic non_overridable
30
+ nopass pass protected same_type_as value volatile ]
31
+
32
+ BLOCKS = %w[
33
+ do if interface function module program then case end else elseif elsewhere
34
+ enddo endif
35
+ select subroutine type where forall ] +
36
+ # F2003.
37
+ %w[ enum associate ]
38
+
39
+ OPERATORS = %w[
40
+ and eq eqv false ge gt le lt ne neqv not or true ]
41
+
42
+ TYPES = %w[
43
+ character complex integer logical real double precision ]
44
+
45
+ PROCEDURES = %w[
46
+ abs achar acos adjustl adjustr aimag aint
47
+ all allocated anint any asin associated
48
+ atan atan2 bit_size btest ceiling char cmplx
49
+ conjg cos cosh count cshift date_and_time dble
50
+ digits dim dot_product dprod eoshift epsilon
51
+ exp exponent floor fraction huge iachar iand
52
+ ibclr ibits ibset ichar ieor index int ior
53
+ ishft ishftc kind lbound len len_trim lge lgt
54
+ lle llt log log10 matmul max
55
+ maxexponent maxloc maxval merge min minexponent
56
+ minloc minval mod modulo mvbits nearest nint
57
+ not pack precision present product radix ] +
58
+ # Real is taken out here to avoid highlighting declarations.
59
+ %w[ random_number random_seed range
60
+ repeat reshape rrspacing scale scan
61
+ selected_int_kind selected_real_kind set_exponent
62
+ shape sign sin sinh size spacieg spread sqrt
63
+ sum system_clock tan tanh tiny transfer
64
+ transpose trim ubound unpack verify ] +
65
+ # F95 intrinsic functions.
66
+ %w[ null cpu_time ] +
67
+ # F2003.
68
+ %w[ move_alloc command_argument_count get_command
69
+ get_command_argument get_environment_variable
70
+ selected_char_kind wait flush new_line
71
+ extends extends_type_of same_type_as bind ] +
72
+ # F2003 ieee_arithmetic intrinsic module.
73
+ %w[ ieee_support_underflow_control ieee_get_underflow_mode
74
+ ieee_set_underflow_mode ] +
75
+ # F2003 iso_c_binding intrinsic module.
76
+ %w[ c_loc c_funloc c_associated c_f_pointer
77
+ c_f_procpointer ] +
78
+ # more intrinsic hpf
79
+ %w[ all_prefix all_scatter all_suffix any_prefix
80
+ any_scatter any_suffix copy_prefix copy_scatter
81
+ copy_suffix count_prefix count_scatter count_suffix
82
+ grade_down grade_up
83
+ hpf_alignment hpf_distribution hpf_template iall iall_prefix
84
+ iall_scatter iall_suffix iany iany_prefix iany_scatter
85
+ iany_suffix ilen iparity iparity_prefix
86
+ iparity_scatter iparity_suffix leadz maxval_prefix
87
+ maxval_scatter maxval_suffix minval_prefix minval_scatter
88
+ minval_suffix number_of_processors parity
89
+ parity_prefix parity_scatter parity_suffix popcnt poppar
90
+ processors_shape product_prefix product_scatter
91
+ product_suffix sum_prefix sum_scatter sum_suffix ] +
92
+ # Directives.
93
+ %w[ align distribute dynamic independent inherit processors
94
+ realign redistribute template ] +
95
+ # Keywords.
96
+ %w[ block cyclic extrinsic new onto pure with ]
97
+
98
+ CONSTANTS = %w[
99
+ # F2003 iso_fortran_env constants.
100
+ iso_fortran_env
101
+ input_unit output_unit error_unit
102
+ iostat_end iostat_eor
103
+ numeric_storage_size character_storage_size
104
+ file_storage_size ] +
105
+ # F2003 iso_c_binding constants.
106
+ %w[ iso_c_binding
107
+ c_int c_short c_long c_long_long c_signed_char
108
+ c_size_t
109
+ c_int8_t c_int16_t c_int32_t c_int64_t
110
+ c_int_least8_t c_int_least16_t c_int_least32_t
111
+ c_int_least64_t
112
+ c_int_fast8_t c_int_fast16_t c_int_fast32_t
113
+ c_int_fast64_t
114
+ c_intmax_t c_intptr_t
115
+ c_float c_double c_long_double
116
+ c_float_complex c_double_complex c_long_double_complex
117
+ c_bool c_char
118
+ c_null_char c_alert c_backspace c_form_feed
119
+ c_new_line c_carriage_return c_horizontal_tab
120
+ c_vertical_tab
121
+ c_ptr c_funptr c_null_ptr c_null_funptr
122
+ ieee_exceptions
123
+ ieee_arithmetic
124
+ ieee_features ]
125
+
126
+ IDENT_KIND = CaseIgnoringWordList . new ( :ident ) .
127
+ add ( KEYWORDS , :reserved ) .
128
+ add ( BLOCKS , :class ) .
129
+ add ( OPERATORS , :operator_fat ) .
130
+ add ( PROCEDURES , :function ) .
131
+ add ( TYPES , :pre_type ) .
132
+ add ( CONSTANTS , :pre_constant )
133
+
134
+ ESCAPE = / [rbfnrtv\n \\ '"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x
135
+ UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x
136
+
137
+ def scan_tokens tokens , options
138
+
139
+ state = :initial
140
+
141
+ until eos?
142
+
143
+ kind = nil
144
+ match = nil
145
+
146
+ case state
147
+
148
+ when :initial
149
+
150
+ if scan ( / \s + | \\ \n /x )
151
+ kind = :space
152
+
153
+ elsif scan ( %r@ \! [^\n \\ ]* (?: \\ . [^\n \\ ]* )* @imx )
154
+ kind = :comment
155
+
156
+ elsif match = scan ( / \# \s * if \s * 0 /x )
157
+ match << scan_until ( / ^\# (?:elif|else|endif) .*? $ | \z /xm ) unless eos?
158
+ kind = :comment
159
+
160
+ elsif scan ( / [-+*\/ =<>?:;,!&^|()\[ \] {}~%]+ | \. (?!\d ) /x )
161
+ kind = :operator_fat
162
+
163
+ elsif match = scan ( / [A-Za-z_][A-Za-z_0-9]* /x )
164
+ kind = IDENT_KIND [ match ]
165
+ if kind == :ident and check ( /:(?!:)/ )
166
+ match << scan ( /:/ )
167
+ kind = :label
168
+ end
169
+
170
+ elsif match = scan ( /L?["']/ )
171
+ tokens << [ :open , :string ]
172
+ if match [ 0 ] == ?L
173
+ tokens << [ 'L' , :modifier ]
174
+ match = '"'
175
+ end
176
+ state = :string
177
+ kind = :delimiter
178
+
179
+ elsif scan ( /#\s *(\w *)/ )
180
+ kind = :preprocessor # FIXME multiline preprocs
181
+ state = :include_expected if self [ 1 ] == 'include'
182
+
183
+ elsif scan ( /0[xX][0-9A-Fa-f]+/ )
184
+ kind = :hex
185
+
186
+ elsif scan ( /(?:0[0-7]+)(?![89.eEfF])/ )
187
+ kind = :oct
188
+
189
+ elsif scan ( /[-+]?((\d +\. \d *|\. \d +)([ED][-+]?\d +(?!_)|(E[-+]?\d +)?_\w +)?|\d +([ED][-+]?\d +(?!_)|(E[-+]?\d +)?_\w +))/i )
190
+ kind = :float
191
+
192
+ elsif scan ( /(?:\d +)(?![.eEfF])/ )
193
+ kind = :integer
194
+
195
+ else
196
+ getch
197
+ kind = :error
198
+
199
+ end
200
+
201
+ when :string
202
+ if scan ( /[^\\ \n "']+/ )
203
+ kind = :content
204
+ elsif md = scan ( /["']/ )
205
+ tokens << [ md , :delimiter ]
206
+ tokens << [ :close , :string ]
207
+ state = :initial
208
+ next
209
+ elsif scan ( / \\ (?: #{ ESCAPE } | #{ UNICODE_ESCAPE } ) /mox )
210
+ kind = :char
211
+ elsif scan ( / \\ | $ /x )
212
+ tokens << [ :close , :string ]
213
+ kind = :error
214
+ state = :initial
215
+ else
216
+ raise_inspect "else case \" reached; %p not handled." % peek ( 1 ) , tokens
217
+ end
218
+
219
+ when :include_expected
220
+ if scan ( /[^\n ]+/ )
221
+ kind = :include
222
+ state = :initial
223
+
224
+ elsif match = scan ( /\s +/ )
225
+ kind = :space
226
+ state = :initial if match . index ?\n
227
+
228
+ else
229
+ getch
230
+ kind = :error
231
+
232
+ end
233
+
234
+ else
235
+ raise_inspect 'Unknown state' , tokens
236
+
237
+ end
238
+
239
+ match ||= matched
240
+ if $DEBUG and not kind
241
+ raise_inspect 'Error token %p in line %d' %
242
+ [ [ match , kind ] , line ] , tokens
243
+ end
244
+ raise_inspect 'Empty token' , tokens unless match
245
+
246
+ tokens << [ match , kind ]
247
+
248
+ end
249
+
250
+ if state == :string
251
+ tokens << [ :close , :string ]
252
+ end
253
+
254
+ tokens
255
+ end
256
+
257
+ end
258
+
259
+ end
260
+ end
0 commit comments