Skip to content

Commit 84685d0

Browse files
committed
Ralf Mueller's Fortran scanner
from FortranScanner.diff on Redmine http://odd-eyed-code.org/issues/202
1 parent 3effca8 commit 84685d0

File tree

1 file changed

+260
-0
lines changed

1 file changed

+260
-0
lines changed

lib/coderay/scanners/fortran.rb

+260
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
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

Comments
 (0)