| Class | Fortran90Dependency::Fortran90DependencyEntry |
| In: |
../script/f90depend.rb
|
| Parent: | Object |
引数 file には Fortran 90/95 ファイル名を与える. ファイルが存在しない場合, エラーを返す.
strictly に true を与えると Fortran 90/95 ファイル内の 継続行マーカ "&" や 改行マーカ ";" に関しても正しく 解析しますが, 実行時間が大幅に増えます.
# File ../script/f90depend.rb, line 158
158: def initialize(file, strictly=nil)
159: @file = file
160: if !(file =~ /\.f9(0|5)$/i)
161: $stderr.print "\n Warning: \"#{file}\" is not recognized as a Fortran 90/95 file.\n" +
162: " Please rename a suffix of this file to .f90 etc.\n"
163: return nil
164: end
165:
166: @strictly = strictly
167:
168: body = File.open(@file, 'r') {|f| f.read}
169: if @strictly
170: body = united_to_one_line(body)
171: body = semicolon_to_linefeed(body)
172: end
173: @modules = find_modules(body)
174: @mainprogram = find_mainprogram(body)
175: @uses = find_uses(body)
176: @uses.collect!{|use_item|
177: if @modules.include?(use_item)
178: nil
179: else
180: use_item
181: end
182: }
183: @uses.delete_if{|use_item| !use_item }
184: end
RDoc Fortran 90/95 解析機能強化版 の Fortran 95 パーサから移植したメソッド.
Which "line" is end of block (module, program, block data, subroutine, function) statement ?
# File ../script/f90depend.rb, line 321
321: def block_end?(line)
322: return nil if !line
323:
324: if line =~ /^\s*?end\s*?(!.*?)?$/i ||
325: line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i ||
326: line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i ||
327: line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i ||
328: line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i ||
329: line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i
330: return true
331: end
332:
333: return nil
334: end
RDoc Fortran 90/95 解析機能強化版 の Fortran 95 パーサから移植したメソッド.
Which "line" is start of block (module, program, block data, subroutine, function) statement ?
# File ../script/f90depend.rb, line 255
255: def block_start?(line, strictly=nil)
256: return nil if !line
257:
258: if strictly
259: if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i ||
260: line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
261: line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i ||
262: line =~ \
263: /^\s*?
264: (recursive|pure|elemental)?\s*?
265: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
266: /ix ||
267: line =~ \
268: /^\s*?
269: (recursive|pure|elemental)?\s*?
270: (
271: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
272: | type\s*?\([\w\s]+?\)\s+
273: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
274: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
275: | double\s+precision\s+
276: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
277: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
278: )?
279: function\s+(\w+)\s*?
280: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
281: /ix
282: return true
283: end
284: else
285: if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i ||
286: line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
287: line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i ||
288: line =~ \
289: /^\s*?
290: (recursive|pure|elemental)?\s*?
291: subroutine\s+(\w+)
292: /ix ||
293: line =~ \
294: /^\s*?
295: (recursive|pure|elemental)?\s*?
296: (
297: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
298: | type\s*?\([\w\s]+?\)\s+
299: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
300: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
301: | double\s+precision\s+
302: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
303: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
304: )?
305: function\s+(\w+)
306: /ix
307: return true
308: end
309: end
310:
311: return nil
312: end
引数 body で与えられる Fortran90/95 ソースコード内で 主プログラムが定義されていれば true を, 定義されて いない場合には false を返す
# File ../script/f90depend.rb, line 221
221: def find_mainprogram(body)
222: other_block_level_depth = 0
223: other_block_searching_flag = false
224: body.split("\n").each{ |line|
225: if !other_block_searching_flag
226: if line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
227: line =~ /^\s*?\w/ && !block_start?(line, @strictly)
228: return true
229: elsif block_start?(line, @strictly)
230: other_block_searching_flag = true
231: next
232: else
233: next
234: end
235: else
236: other_block_level_depth += 1 if block_start?(line, @strictly)
237: other_block_level_depth -= 1 if block_end?(line)
238: if other_block_level_depth < 0
239: other_block_level_depth = 0
240: other_block_searching_flag = false
241: end
242: next
243: end
244: }
245: return false
246: end
引数 body で与えられる Fortran90/95 ソースコード内で 定義される module 名を取り出す.
# File ../script/f90depend.rb, line 192
192: def find_modules(body)
193: modules = []
194: body.split("\n").each{ |line|
195: if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i
196: modules << $1
197: end
198: }
199: return modules
200: end
引数 body で与えられる Fortran90/95 ソースコード内で 定義される use 文を取り出す.
# File ../script/f90depend.rb, line 206
206: def find_uses(body)
207: uses = []
208: body.split("\n").each{ |line|
209: if line =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
210: uses << $1
211: end
212: }
213: return uses.uniq
214: end
RDoc Fortran 90/95 解析機能強化版 の Fortran 95 パーサから移植したメソッド.
Semicolons are replaced to line feed.
# File ../script/f90depend.rb, line 344
344: def semicolon_to_linefeed(text)
345: return "" unless text
346: lines = text.split("\n")
347: lines.collect!{ |line|
348: indent_space = ""
349: if line =~ /^(\s+)/
350: indent_space = $1
351: end
352: words = line.split("")
353: commentout = false
354: squote = false ; dquote = false
355: words.collect! { |char|
356: if !(squote) && !(dquote) && !(commentout)
357: case char
358: when "!" ; commentout = true ; next char
359: when "\""; dquote = true ; next char
360: when "\'"; squote = true ; next char
361: when ";" ; "\n"+indent_space
362: else next char
363: end
364: elsif commentout
365: next char
366: elsif squote
367: case char
368: when "\'"; squote = false ; next char
369: else next char
370: end
371: elsif dquote
372: case char
373: when "\""; dquote = false ; next char
374: else next char
375: end
376: end
377: }
378: words.join("")
379: }
380: return lines.join("\n")
381: end
RDoc Fortran 90/95 解析機能強化版 の Fortran 95 パーサから移植したメソッド.
Continuous lines are united.
Comments in continuous lines are removed. If delete_space=false, spaces around "&" are not deleted.
Example
before
subroutine func(a, b, c, d, e, & ! ignored comments
& f, g, h) ! valid comments
after
subroutine func(a, b, c, d, e, f, g, h) ! valid comments
# File ../script/f90depend.rb, line 403
403: def united_to_one_line(f90src, delete_space=true)
404: return "" unless f90src
405: lines = f90src.split("\n")
406: previous_continuing = false
407: now_continuing = false
408: body = ""
409: lines.each{ |line|
410: words = line.split("")
411: next if words.empty? && previous_continuing
412: commentout = false
413: brank_flag = true ; brank_char = ""
414: squote = false ; dquote = false
415: ignore = false
416: words.collect! { |char|
417: if previous_continuing && brank_flag
418: now_continuing = true
419: ignore = true
420: case char
421: when "!" ; break
422: when " " ; brank_char << char ; next ""
423: when "&"
424: brank_flag = false
425: now_continuing = false
426: next ""
427: else
428: brank_flag = false
429: now_continuing = false
430: ignore = false
431: next brank_char + char
432: end
433: end
434: ignore = false
435:
436: if now_continuing
437: next ""
438: elsif !(squote) && !(dquote) && !(commentout)
439: case char
440: when "!" ; commentout = true ; next char
441: when "\""; dquote = true ; next char
442: when "\'"; squote = true ; next char
443: when "&" ; now_continuing = true ; next ""
444: else next char
445: end
446: elsif commentout
447: next char
448: elsif squote
449: case char
450: when "\'"; squote = false ; next char
451: else next char
452: end
453: elsif dquote
454: case char
455: when "\""; dquote = false ; next char
456: else next char
457: end
458: end
459: }
460: if !ignore && !previous_continuing || !brank_flag
461: if previous_continuing
462: if delete_space
463: joined_words = words.join("")
464: body = body.rstrip + " " + joined_words.lstrip
465: else
466: body << words.join("")
467: end
468: else
469: body << "\n" + words.join("")
470: end
471: end
472: previous_continuing = now_continuing ? true : nil
473: now_continuing = nil
474: }
475: return body
476: end