Class Fortran90Dependency::Fortran90DependencyEntry
In: ../script/f90/f90depend.rb
Parent: Object

Methods

Public Class methods

引数 file には Fortran 90/95 ファイル名を与える. ファイルが存在しない場合, エラーを返す.

strictly に true を与えると Fortran 90/95 ファイル内の 継続行マーカ "&" や 改行マーカ ";" に関しても正しく 解析しますが, 実行時間が大幅に増えます.

[Source]

     # File ../script/f90/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

Public Instance methods

RDoc Fortran 90/95 解析機能強化版 の Fortran 95 パーサから移植したメソッド.

Which "line" is end of block (module, program, block data, subroutine, function) statement ?

[Source]

     # File ../script/f90/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 ?

[Source]

     # File ../script/f90/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 を返す

[Source]

     # File ../script/f90/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 名を取り出す.

[Source]

     # File ../script/f90/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 文を取り出す.

[Source]

     # File ../script/f90/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.

[Source]

     # File ../script/f90/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

[Source]

     # File ../script/f90/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