Class | Fortran90Dependency::Fortran90DependencyEntry |
In: |
../script/f90/f90depend.rb
|
Parent: | Object |
引数 file には Fortran 90/95 ファイル名を与える. ファイルが存在しない場合, エラーを返す.
strictly に true を与えると Fortran 90/95 ファイル内の 継続行マーカ "&" や 改行マーカ ";" に関しても正しく 解析しますが, 実行時間が大幅に増えます.
# 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
RDoc Fortran 90/95 解析機能強化版 の Fortran 95 パーサから移植したメソッド.
Which "line" is end of block (module, program, block data, subroutine, function) statement ?
# 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 ?
# 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 を返す
# 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 名を取り出す.
# 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 文を取り出す.
# 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.
# 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
# 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