| Class | RDoc::Fortran95parser |
| In: |
parsers/parse_f95.rb
|
| Parent: | Object |
See rdoc/parsers/parse_f95.rb
| COMMENTS_ARE_UPPER | = | false |
|
|||||
| INTERNAL_ALIAS_MES | = | "Alias for" | Internal alias message | |||||
| EXTERNAL_ALIAS_MES | = | "Original external subprogram is" | External alias message | |||||
| PROVIDED_MODULES_MES | = | "This file provides following module" | Provided modules message | |||||
| NAMELIST_REPOSITORY_NAME | = | "NAMELIST" | Repository of NAMELIST statements |
prepare to parse a Fortran 95 file
# File parsers/parse_f95.rb, line 392
392: def initialize(top_level, file_name, body, options, stats)
393: @body = body
394: @stats = stats
395: @file_name = file_name
396: @options = options
397: @top_level = top_level
398: @progress = $stderr unless options.quiet
399: end
Return lines before "contains" statement in modules. "interface", "type" statements are removed.
# File parsers/parse_f95.rb, line 1300
1300: def before_contains(code)
1301: level_depth = 0
1302: before_contains_lines = []
1303: before_contains_code = nil
1304: before_contains_flag = nil
1305: code.split("\n").each{ |line|
1306: if !before_contains_flag
1307: if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i
1308: before_contains_flag = true
1309: end
1310: else
1311: break if line =~ /^\s*?contains\s*?(!.*?)?$/i
1312: level_depth += 1 if block_start?(line)
1313: level_depth -= 1 if block_end?(line)
1314: break if level_depth < 0
1315: before_contains_lines << line
1316: end
1317:
1318: }
1319: before_contains_code = before_contains_lines.join("\n")
1320: if before_contains_code
1321: before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "")
1322: before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
1323: end
1324:
1325: before_contains_code
1326: end
Which "line" is end of block (module, program, block data, subroutine, function) statement ?
# File parsers/parse_f95.rb, line 1964
1964: def block_end?(line)
1965: return nil if !line
1966:
1967: if line =~ /^\s*?end\s*?(!.*?)?$/i ||
1968: line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i ||
1969: line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i ||
1970: line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i ||
1971: line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i ||
1972: line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i
1973: return true
1974: end
1975:
1976: return nil
1977: end
Which "line" is start of block (module, program, block data, subroutine, function) statement ?
# File parsers/parse_f95.rb, line 1928
1928: def block_start?(line)
1929: return nil if !line
1930:
1931: if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i ||
1932: line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
1933: line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i ||
1934: line =~ \
1935: /^\s*?
1936: (recursive|pure|elemental)?\s*?
1937: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
1938: /ix ||
1939: line =~ \
1940: /^\s*?
1941: (recursive|pure|elemental)?\s*?
1942: (
1943: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1944: | type\s*?\([\w\s]+?\)\s+
1945: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1946: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1947: | double\s+precision\s+
1948: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1949: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1950: )?
1951: function\s+(\w+)\s*?
1952: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
1953: /ix
1954: return true
1955: end
1956:
1957: return nil
1958: end
Check external aliases
subname というサブルーチン名, または関数名を持つファイルを 探査し, 存在する場合にはそのファイル内へメソッドを追加する.
# File parsers/parse_f95.rb, line 1686
1686: def check_external_aliases(subname, params, comment, test=nil)
1687: @@external_aliases.each{ |alias_item|
1688: if subname == alias_item["old_name"] ||
1689: subname.upcase == alias_item["old_name"].upcase &&
1690: @options.ignore_case
1691:
1692: new_meth = initialize_external_method(alias_item["new_name"],
1693: subname, params, @file_name,
1694: comment)
1695: new_meth.visibility = alias_item["visibility"]
1696:
1697: progress "e"
1698: @stats.num_methods += 1
1699: alias_item["file_or_module"].add_method(new_meth)
1700:
1701: if !alias_item["file_or_module"].include_requires?(@file_name, @options.ignore_case)
1702: alias_item["file_or_module"].add_require(Require.new(@file_name, ""))
1703: end
1704: end
1705: }
1706: end
Check public_methods
use したモジュールからそのまま引き継いで public として 公開する場合のチェックを行う. subname というサブルーチン名, または関数名を持つファイルを 探査し, 存在する場合にはそのファイル内へメソッドを追加する.
# File parsers/parse_f95.rb, line 1716
1716: def check_public_methods(method, parent)
1717: return if !method || !parent
1718: @@public_methods.each{ |alias_item|
1719: parent_is_used_module = nil
1720: alias_item["used_modules"].each{ |used_module|
1721: if used_module == parent ||
1722: used_module.upcase == parent.upcase &&
1723: @options.ignore_case
1724: parent_is_used_module = true
1725: end
1726: }
1727: next if !parent_is_used_module
1728:
1729: if method.name == alias_item["name"] ||
1730: method.name.upcase == alias_item["name"].upcase &&
1731: @options.ignore_case
1732:
1733: new_meth = initialize_public_method(method, parent)
1734: if alias_item["local_name"]
1735: new_meth.name = alias_item["local_name"]
1736: end
1737:
1738: progress "e"
1739: @stats.num_methods += 1
1740: alias_item["file_or_module"].add_method new_meth
1741: end
1742: }
1743: end
Collect comment for file entity
# File parsers/parse_f95.rb, line 1331
1331: def collect_first_comment(body)
1332: comment = ""
1333: not_comment = ""
1334: comment_start = false
1335: comment_end = false
1336: body.split("\n").each{ |line|
1337: if comment_end
1338: not_comment << line
1339: not_comment << "\n"
1340: elsif /^\s*?!\s?(.*)$/i =~ line
1341: comment_start = true
1342: comment << $1
1343: comment << "\n"
1344: elsif /^\s*?$/i =~ line
1345: comment_end = true if comment_start && COMMENTS_ARE_UPPER
1346: else
1347: comment_end = true
1348: not_comment << line
1349: not_comment << "\n"
1350: end
1351: }
1352: return comment, not_comment
1353: end
Comment out checker
# File parsers/parse_f95.rb, line 1855
1855: def comment_out?(line)
1856: return nil unless line
1857: commentout = false
1858: squote = false ; dquote = false
1859: line.split("").each { |char|
1860: if !(squote) && !(dquote)
1861: case char
1862: when "!" ; commentout = true ; break
1863: when "\""; dquote = true
1864: when "\'"; squote = true
1865: else next
1866: end
1867: elsif squote
1868: case char
1869: when "\'"; squote = false
1870: else next
1871: end
1872: elsif dquote
1873: case char
1874: when "\""; dquote = false
1875: else next
1876: end
1877: end
1878: }
1879: return commentout
1880: end
Continuous line checker
# File parsers/parse_f95.rb, line 1841
1841: def continuous_line?(line)
1842: continuous = false
1843: if /&\s*?(!.*)?$/ =~ line
1844: continuous = true
1845: if comment_out?($~.pre_match)
1846: continuous = false
1847: end
1848: end
1849: return continuous
1850: end
Parse string argument "text", and Return Array of Fortran95Definition object
# File parsers/parse_f95.rb, line 2100
2100: def definition_info(text)
2101: return nil unless text
2102: lines = "#{text}"
2103: defs = Array.new
2104: comment = ""
2105: trailing_comment = ""
2106: under_comment_valid = false
2107: lines.split("\n").each{ |line|
2108: if /^\s*?!\s?(.*)/ =~ line
2109: if COMMENTS_ARE_UPPER
2110: comment << remove_header_marker($1)
2111: comment << "\n"
2112: elsif defs[-1] && under_comment_valid
2113: defs[-1].comment << "\n"
2114: defs[-1].comment << remove_header_marker($1)
2115: end
2116: next
2117: elsif /^\s*?$/ =~ line
2118: comment = ""
2119: under_comment_valid = false
2120: next
2121: end
2122: type = ""
2123: characters = ""
2124: if line =~ /^\s*?
2125: (
2126: character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2127: | type\s*?\([\w\s]+?\)[\s\,]*
2128: | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2129: | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2130: | double\s+precision[\s\,]*
2131: | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2132: | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2133: )
2134: (.*?::)?
2135: (.+)$
2136: /ix
2137: characters = $8
2138: type = $1
2139: type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7
2140: else
2141: under_comment_valid = false
2142: next
2143: end
2144: squote = false ; dquote = false ; bracket = 0
2145: iniflag = false; commentflag = false
2146: varname = "" ; arraysuffix = "" ; inivalue = ""
2147: start_pos = defs.size
2148: characters.split("").each { |char|
2149: if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag)
2150: case char
2151: when "!" ; commentflag = true
2152: when "(" ; bracket += 1 ; arraysuffix = char
2153: when "\""; dquote = true
2154: when "\'"; squote = true
2155: when "=" ; iniflag = true ; inivalue << char
2156: when ","
2157: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2158: varname = "" ; arraysuffix = "" ; inivalue = ""
2159: under_comment_valid = true
2160: when " " ; next
2161: else ; varname << char
2162: end
2163: elsif commentflag
2164: comment << remove_header_marker(char)
2165: trailing_comment << remove_header_marker(char)
2166: elsif iniflag
2167: if dquote
2168: case char
2169: when "\"" ; dquote = false ; inivalue << char
2170: else ; inivalue << char
2171: end
2172: elsif squote
2173: case char
2174: when "\'" ; squote = false ; inivalue << char
2175: else ; inivalue << char
2176: end
2177: elsif bracket > 0
2178: case char
2179: when "(" ; bracket += 1 ; inivalue << char
2180: when ")" ; bracket -= 1 ; inivalue << char
2181: else ; inivalue << char
2182: end
2183: else
2184: case char
2185: when ","
2186: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2187: varname = "" ; arraysuffix = "" ; inivalue = ""
2188: iniflag = false
2189: under_comment_valid = true
2190: when "(" ; bracket += 1 ; inivalue << char
2191: when "\""; dquote = true ; inivalue << char
2192: when "\'"; squote = true ; inivalue << char
2193: when "!" ; commentflag = true
2194: else ; inivalue << char
2195: end
2196: end
2197: elsif !(squote) && !(dquote) && bracket > 0
2198: case char
2199: when "(" ; bracket += 1 ; arraysuffix << char
2200: when ")" ; bracket -= 1 ; arraysuffix << char
2201: else ; arraysuffix << char
2202: end
2203: elsif squote
2204: case char
2205: when "\'"; squote = false ; inivalue << char
2206: else ; inivalue << char
2207: end
2208: elsif dquote
2209: case char
2210: when "\""; dquote = false ; inivalue << char
2211: else ; inivalue << char
2212: end
2213: end
2214: }
2215: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2216: if trailing_comment =~ /^:nodoc:/
2217: defs[start_pos..-1].collect!{ |defitem|
2218: defitem.nodoc = true
2219: }
2220: end
2221: varname = "" ; arraysuffix = "" ; inivalue = ""
2222: comment = ""
2223: under_comment_valid = true
2224: trailing_comment = ""
2225: }
2226: return defs
2227: end
Return comments of definitions of arguments
If "all" argument is true, information of all arguments are returned. If "modified_params" is true, list of arguments are decorated, for exameple, optional arguments are parenthetic as "[arg]".
# File parsers/parse_f95.rb, line 1362
1362: def find_arguments(args, text, all=nil, indent=nil, modified_params=nil)
1363: return unless args || all
1364: indent = "" unless indent
1365: args = ["all"] if all
1366: params = "" if modified_params
1367: comma = ""
1368: return unless text
1369: args_rdocforms = "\n"
1370: remaining_lines = "#{text}"
1371: definitions = definition_info(remaining_lines)
1372: args.each{ |arg|
1373: arg.strip!
1374: arg.chomp!
1375: definitions.each { |defitem|
1376: if arg == defitem.varname.strip.chomp || all
1377: args_rdocforms << "\n\#{indent}<b><tt>\#{defitem.varname.chomp.strip}\#{defitem.arraysuffix} </tt></b> <tt> \#{defitem.inivalue}</tt> ::\n\#{indent} <tt>\#{defitem.types.chomp.strip}</tt>\n"
1378: if !defitem.comment.chomp.strip.empty?
1379: comment = ""
1380: defitem.comment.split("\n").each{ |line|
1381: comment << " " + line + "\n"
1382: }
1383: args_rdocforms << "\n\#{indent} <tt></tt> ::\n\#{indent} <tt></tt>\n\#{indent} \#{comment.chomp.strip}\n"
1384: end
1385:
1386: if modified_params
1387: if defitem.include_attr?("optional")
1388: params << "#{comma}[#{arg}]"
1389: else
1390: params << "#{comma}#{arg}"
1391: end
1392: comma = ", "
1393: end
1394: end
1395: }
1396: }
1397: if modified_params
1398: return args_rdocforms, params
1399: else
1400: return args_rdocforms
1401: end
1402: end
Comments just after module or subprogram, or arguments are returnd. If "COMMENTS_ARE_UPPER" is true, comments just before modules or subprograms are returnd
# File parsers/parse_f95.rb, line 1504
1504: def find_comments text
1505: return "" unless text
1506: lines = text.split("\n")
1507: lines.reverse! if COMMENTS_ARE_UPPER
1508: comment_block = Array.new
1509: lines.each do |line|
1510: break if line =~ /^\s*?\w/ || line =~ /^\s*?$/
1511: if COMMENTS_ARE_UPPER
1512: comment_block.unshift line.sub(/^\s*?!\s?/,"")
1513: else
1514: comment_block.push line.sub(/^\s*?!\s?/,"")
1515: end
1516: end
1517: nice_lines = comment_block.join("\n").split "\n\s*?\n"
1518: nice_lines[0] ||= ""
1519: nice_lines.shift
1520: end
Add namelist information to Repository (dummy module of each @top_level) of NAMELIST statements. And return comments about namelist group names
# File parsers/parse_f95.rb, line 1420
1420: def find_namelists(container, text, before_contains=nil)
1421: return nil if !text
1422: top_level = find_toplevel(container)
1423:
1424: if text =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i
1425: if top_level.include_includes?(NAMELIST_REPOSITORY_NAME)
1426: namelist_module =
1427: top_level.find_module_named(NAMELIST_REPOSITORY_NAME)
1428: else
1429: namelist_module =
1430: top_level.add_module NormalClass, NAMELIST_REPOSITORY_NAME
1431: namelist_module.record_location top_level
1432: namelist_module.comment = "This is not a module but a repository of NAMELIST group names declared\nin all Fortran 90/95 files\n"
1433: end
1434: else
1435: return ""
1436: end
1437:
1438: nml_group_name_lists = []
1439: lines = "#{text}"
1440: before_contains = "" if !before_contains
1441: while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i
1442: lines = $~.post_match
1443: pre_match = $~.pre_match ; post_match = $~.post_match
1444: nml_group_name = $1
1445: nml_vars_list = $2.split(",")
1446: nml_comment = COMMENTS_ARE_UPPER ?
1447: find_comments(pre_match.sub(/\n$/, '')) :
1448: find_comments(post_match.sub(/^\n/, ''))
1449: if lines.split("\n")[0] =~ /^\//i
1450: lines = "namelist " + lines
1451: end
1452:
1453: nml_meth = AnyMethod.new("NAMELIST", nml_group_name)
1454: nml_meth.singleton = false
1455: nml_meth.params = "( " + nml_vars_list.join(", ") + " )"
1456: nml_meth.comment = "<b><em> NAMELIST </em></b> :: <tt></tt>\n"
1457: nml_meth.comment << find_arguments(nml_vars_list, "#{text}" + "\n" + before_contains)
1458: nml_meth.comment << "\n" + nml_comment if nml_comment
1459: if container.parent.parent
1460: parent_object = container.parent.name
1461: else
1462: parent_object = container.parent.file_relative_name
1463: end
1464: nml_meth.comment << "\n\nThis namelist group name is input/output in "
1465: nml_meth.comment << parent_object + "#" + container.name
1466:
1467: progress "n"
1468: @stats.num_methods += 1
1469: namelist_module.add_method nml_meth
1470:
1471: nml_group_name_lists << NAMELIST_REPOSITORY_NAME + "#" + nml_group_name
1472: end
1473:
1474: if !nml_group_name_lists.empty?
1475: comments_in_procedures = "\n\nThis procedure input/output "
1476: comments_in_procedures << nml_group_name_lists.join(", ") + " . "
1477: else
1478: comments_in_procedures = ""
1479: end
1480:
1481: comments_in_procedures
1482: end
Return toplevel class of container
# File parsers/parse_f95.rb, line 1491
1491: def find_toplevel(container)
1492: top_level = container
1493: while top_level.parent
1494: top_level = top_level.parent
1495: end
1496: top_level
1497: end
Find visibility
# File parsers/parse_f95.rb, line 1667
1667: def find_visibility(container, subname, visibility_info)
1668: return nil if !subname || !visibility_info
1669: visibility_info.each{ |info|
1670: if info["name"] == subname ||
1671: @options.ignore_case && info["name"].upcase == subname.upcase
1672: if info["parent"] == container.name
1673: return info["visibility"]
1674: end
1675: end
1676: }
1677: return nil
1678: end
Create method for external alias
If argument "internal" is true, file is ignored.
# File parsers/parse_f95.rb, line 1549
1549: def initialize_external_method(new, old, params, file, comment, token=nil,
1550: internal=nil, nolink=nil)
1551: return nil unless new || old
1552:
1553: if internal
1554: external_alias_header = "#{INTERNAL_ALIAS_MES} "
1555: external_alias_text = external_alias_header + old
1556: elsif file
1557: external_alias_header = "#{EXTERNAL_ALIAS_MES} "
1558: external_alias_text = external_alias_header + file + "#" + old
1559: else
1560: return nil
1561: end
1562: external_meth = AnyMethod.new(external_alias_text, new)
1563: external_meth.singleton = false
1564: external_meth.params = params
1565: external_comment = remove_trailing_alias(comment) + "\n\n" if comment
1566: external_meth.comment = external_comment || ""
1567: if nolink && token
1568: external_meth.start_collecting_tokens
1569: external_meth.add_token Token.new(1,1).set_text(token)
1570: else
1571: external_meth.comment << external_alias_text
1572: end
1573:
1574: return external_meth
1575: end
Create method for internal alias
# File parsers/parse_f95.rb, line 1532
1532: def initialize_public_method(method, parent)
1533: return if !method || !parent
1534:
1535: new_meth = AnyMethod.new("External Alias for module", method.name)
1536: new_meth.singleton = method.singleton
1537: new_meth.params = method.params.clone
1538: new_meth.comment = remove_trailing_alias(method.comment.clone)
1539: new_meth.comment << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}"
1540:
1541: return new_meth
1542: end
# File parsers/parse_f95.rb, line 626
626: def parse_program_or_module(container, code,
627: visibility=:public, external=nil)
628: return unless container
629: return unless code
630: remaining_lines = code.split("\n")
631: remaining_code = "#{code}"
632:
633: #
634: # Parse variables before "contains" in module
635: #
636: # namelist 変数の定義に使われたり, これ自体が定数, 変数
637: # 提供されるのに利用される. (変数や定数として利用される場合,
638: # これもメソッドとして提供する.
639: #
640: before_contains_code = before_contains(remaining_code)
641:
642: #
643: # Parse global "use"
644: #
645: use_check_code = "#{before_contains_code}"
646: cascaded_modules_list = []
647: while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
648: use_check_code = $~.pre_match
649: use_check_code << $~.post_match
650: used_mod_name = $1.strip.chomp
651: used_list = $2 || ""
652: used_trailing = $3 || ""
653: next if used_trailing =~ /!:nodoc:/
654: if !container.include_includes?(used_mod_name, @options.ignore_case)
655: progress "."
656: container.add_include Include.new(used_mod_name, "")
657: end
658: if ! (used_list =~ /\,\s*?only\s*?:/i )
659: cascaded_modules_list << "\#" + used_mod_name
660: end
661: end
662:
663: #
664: # Parse public and private, and store information.
665: # This information is used when "add_method" and
666: # "set_visibility_for" are called.
667: #
668: visibility_default, visibility_info =
669: parse_visibility(remaining_lines.join("\n"), visibility, container)
670: @@public_methods.concat visibility_info
671: if visibility_default == :public
672: if !cascaded_modules_list.empty?
673: cascaded_modules =
674: Attr.new("Cascaded Modules",
675: "Imported modules all of whose components are published again",
676: "",
677: cascaded_modules_list.join(", "))
678: container.add_attribute(cascaded_modules)
679: end
680: end
681:
682: #
683: # Check rename elements
684: #
685: use_check_code = "#{before_contains_code}"
686: while use_check_code =~ /^\s*?use\s+(\w+)\s*?\,(.+)$/i
687: use_check_code = $~.pre_match
688: use_check_code << $~.post_match
689: used_mod_name = $1.strip.chomp
690: used_elements = $2.sub(/\s*?only\s*?:\s*?/i, '')
691: used_elements.split(",").each{ |used|
692: if /\s*?(\w+)\s*?=>\s*?(\w+)\s*?/ =~ used
693: local = $1
694: org = $2
695: @@public_methods.collect!{ |pub_meth|
696: if local == pub_meth["name"] ||
697: local.upcase == pub_meth["name"].upcase &&
698: @options.ignore_case
699: pub_meth["name"] = org
700: pub_meth["local_name"] = local
701: end
702: pub_meth
703: }
704: end
705: }
706: end
707:
708: #
709: # Parse private "use"
710: #
711: use_check_code = remaining_lines.join("\n")
712: while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
713: use_check_code = $~.pre_match
714: use_check_code << $~.post_match
715: used_mod_name = $1.strip.chomp
716: used_trailing = $3 || ""
717: next if used_trailing =~ /!:nodoc:/
718: if !container.include_includes?(used_mod_name, @options.ignore_case)
719: progress "."
720: container.add_include Include.new(used_mod_name, "")
721: end
722: end
723:
724: container.each_includes{ |inc|
725: TopLevel.all_files.each do |name, toplevel|
726: indicated_mod = toplevel.find_symbol(inc.name,
727: nil, @options.ignore_case)
728: if indicated_mod
729: indicated_name = indicated_mod.parent.file_relative_name
730: if !container.include_requires?(indicated_name, @options.ignore_case)
731: container.add_require(Require.new(indicated_name, ""))
732: end
733: break
734: end
735: end
736: }
737:
738: #
739: # Parse derived types definitions
740: #
741: derived_types_comment = ""
742: remaining_code = remaining_lines.join("\n")
743: while remaining_code =~ /^\s*?
744: type[\s\,]+(public|private)?\s*?(::)?\s*?
745: (\w+)\s*?(!.*?)?$
746: (.*?)
747: ^\s*?end\s+type.*?$
748: /imx
749: remaining_code = $~.pre_match
750: remaining_code << $~.post_match
751: typename = $3.chomp.strip
752: type_elements = $5 || ""
753: type_code = remove_empty_head_lines($&)
754: type_trailing = find_comments($4)
755: next if type_trailing =~ /^:nodoc:/
756: type_visibility = $1
757: type_comment = COMMENTS_ARE_UPPER ?
758: find_comments($~.pre_match) + "\n" + type_trailing :
759: type_trailing + "\n" + find_comments(type_code.sub(/^.*$\n/i, ''))
760: type_element_visibility_public = true
761: type_code.split("\n").each{ |line|
762: if /^\s*?private\s*?$/ =~ line
763: type_element_visibility_public = nil
764: break
765: end
766: } if type_code
767:
768: args_comment = ""
769: type_args_info = nil
770:
771: if @options.show_all
772: args_comment = find_arguments(nil, type_code, true)
773: else
774: type_public_args_list = []
775: type_args_info = definition_info(type_code)
776: type_args_info.each{ |arg|
777: arg_is_public = type_element_visibility_public
778: arg_is_public = true if arg.include_attr?("public")
779: arg_is_public = nil if arg.include_attr?("private")
780: type_public_args_list << arg.varname if arg_is_public
781: }
782: args_comment = find_arguments(type_public_args_list, type_code)
783: end
784:
785: type = AnyMethod.new("type #{typename}", typename)
786: type.singleton = false
787: type.params = ""
788: type.comment = "<b><em> Derived Type </em></b> :: <tt></tt>\n"
789: type.comment << args_comment if args_comment
790: type.comment << type_comment if type_comment
791: progress "t"
792: @stats.num_methods += 1
793: container.add_method type
794:
795: set_visibility(container, typename, visibility_default, @@public_methods)
796:
797: if type_visibility
798: type_visibility.gsub!(/\s/,'')
799: type_visibility.gsub!(/\,/,'')
800: type_visibility.gsub!(/:/,'')
801: type_visibility.downcase!
802: if type_visibility == "public"
803: container.set_visibility_for([typename], :public)
804: elsif type_visibility == "private"
805: container.set_visibility_for([typename], :private)
806: end
807: end
808:
809: check_public_methods(type, container.name)
810:
811: if @options.show_all
812: derived_types_comment << ", " unless derived_types_comment.empty?
813: derived_types_comment << typename
814: else
815: if type.visibility == :public
816: derived_types_comment << ", " unless derived_types_comment.empty?
817: derived_types_comment << typename
818: end
819: end
820:
821: end
822:
823: if !derived_types_comment.empty?
824: derived_types_table =
825: Attr.new("Derived Types", "Derived_Types", "",
826: derived_types_comment)
827: container.add_attribute(derived_types_table)
828: end
829:
830: #
831: # move interface scope
832: #
833: interface_code = ""
834: while remaining_code =~ /^\s*?
835: interface(
836: \s+\w+ |
837: \s+operator\s*?\(.*?\) |
838: \s+assignment\s*?\(\s*?=\s*?\)
839: )?\s*?$
840: (.*?)
841: ^\s*?end\s+interface.*?$
842: /imx
843: interface_code << remove_empty_head_lines($&) + "\n"
844: remaining_code = $~.pre_match
845: remaining_code << $~.post_match
846: end
847:
848: #
849: # Parse global constants or variables in modules
850: #
851: const_var_defs = definition_info(before_contains_code)
852: const_var_defs.each{|defitem|
853: next if defitem.nodoc
854: const_or_var_type = "Variable"
855: const_or_var_progress = "v"
856: if defitem.include_attr?("parameter")
857: const_or_var_type = "Constant"
858: const_or_var_progress = "c"
859: end
860: const_or_var = AnyMethod.new(const_or_var_type, defitem.varname)
861: const_or_var.singleton = false
862: const_or_var.params = ""
863: self_comment = find_arguments([defitem.varname], before_contains_code)
864: const_or_var.comment = "<b><em>" + const_or_var_type + "</em></b> :: <tt></tt>\n"
865: const_or_var.comment << self_comment if self_comment
866: progress const_or_var_progress
867: @stats.num_methods += 1
868: container.add_method const_or_var
869:
870: set_visibility(container, defitem.varname, visibility_default, @@public_methods)
871:
872: if defitem.include_attr?("public")
873: container.set_visibility_for([defitem.varname], :public)
874: elsif defitem.include_attr?("private")
875: container.set_visibility_for([defitem.varname], :private)
876: end
877:
878: check_public_methods(const_or_var, container.name)
879:
880: } if const_var_defs
881:
882: remaining_lines = remaining_code.split("\n")
883:
884: # "subroutine" or "function" parts are parsed (new)
885: #
886: level_depth = 0
887: block_searching_flag = nil
888: block_searching_lines = []
889: pre_comment = []
890: procedure_trailing = ""
891: procedure_name = ""
892: procedure_params = ""
893: procedure_prefix = ""
894: procedure_result_arg = ""
895: procedure_type = ""
896: contains_lines = []
897: contains_flag = nil
898: remaining_lines.collect!{|line|
899: if !block_searching_flag
900: # subroutine
901: if line =~ /^\s*?
902: (recursive|pure|elemental)?\s*?
903: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
904: /ix
905: block_searching_flag = :subroutine
906: block_searching_lines << line
907:
908: procedure_name = $2.chomp.strip
909: procedure_params = $3 || ""
910: procedure_prefix = $1 || ""
911: procedure_trailing = $4 || "!"
912: next false
913:
914: # function
915: elsif line =~ /^\s*?
916: (recursive|pure|elemental)?\s*?
917: (
918: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
919: | type\s*?\([\w\s]+?\)\s+
920: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
921: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
922: | double\s+precision\s+
923: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
924: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
925: )?
926: function\s+(\w+)\s*?
927: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
928: /ix
929: block_searching_flag = :function
930: block_searching_lines << line
931:
932: procedure_prefix = $1 || ""
933: procedure_type = $2 ? $2.chomp.strip : nil
934: procedure_name = $8.chomp.strip
935: procedure_params = $9 || ""
936: procedure_result_arg = $11 ? $11.chomp.strip : procedure_name
937: procedure_trailing = $12 || "!"
938: next false
939: elsif line =~ /^\s*?!\s?(.*)/
940: pre_comment << line
941: next line
942: else
943: pre_comment = []
944: next line
945: end
946: end
947: contains_flag = true if line =~ /^\s*?contains\s*?(!.*?)?$/
948: block_searching_lines << line
949: contains_lines << line if contains_flag
950:
951: level_depth += 1 if block_start?(line)
952: level_depth -= 1 if block_end?(line)
953: if level_depth >= 0
954: next false
955: end
956:
957: # "procedure_code" is formatted.
958: # ":nodoc:" flag is checked.
959: #
960: procedure_code = block_searching_lines.join("\n")
961: procedure_code = remove_empty_head_lines(procedure_code)
962: if procedure_trailing =~ /^!:nodoc:/
963: # next loop to search next block
964: level_depth = 0
965: block_searching_flag = nil
966: block_searching_lines = []
967: pre_comment = []
968: procedure_trailing = ""
969: procedure_name = ""
970: procedure_params = ""
971: procedure_prefix = ""
972: procedure_result_arg = ""
973: procedure_type = ""
974: contains_lines = []
975: contains_flag = nil
976: next false
977: end
978:
979: # AnyMethod is created, and added to container
980: #
981: subroutine_function = nil
982: if block_searching_flag == :subroutine
983: subroutine_prefix = procedure_prefix
984: subroutine_name = procedure_name
985: subroutine_params = procedure_params
986: subroutine_trailing = procedure_trailing
987: subroutine_code = procedure_code
988:
989: subroutine_comment = COMMENTS_ARE_UPPER ?
990: pre_comment.join("\n") + "\n" + subroutine_trailing :
991: subroutine_trailing + "\n" + subroutine_code.sub(/^.*$\n/i, '')
992: subroutine = AnyMethod.new("subroutine", subroutine_name)
993: parse_subprogram(subroutine, subroutine_params,
994: subroutine_comment, subroutine_code,
995: before_contains_code, nil, subroutine_prefix)
996: progress "s"
997: @stats.num_methods += 1
998: container.add_method subroutine
999: subroutine_function = subroutine
1000:
1001: namelist_comment =
1002: find_namelists(subroutine, subroutine_code, before_contains_code)
1003: subroutine.comment << namelist_comment if namelist_comment
1004:
1005: elsif block_searching_flag == :function
1006: function_prefix = procedure_prefix
1007: function_type = procedure_type
1008: function_name = procedure_name
1009: function_params_org = procedure_params
1010: function_result_arg = procedure_result_arg
1011: function_trailing = procedure_trailing
1012: function_code_org = procedure_code
1013:
1014: function_comment = COMMENTS_ARE_UPPER ?
1015: pre_comment.join("\n") + "\n" + function_trailing :
1016: function_trailing + "\n " + function_code_org.sub(/^.*$\n/i, '')
1017:
1018: function_code = "#{function_code_org}"
1019: if function_type
1020: function_code << "\n" + function_type + " :: " + function_result_arg
1021: end
1022:
1023: function_params =
1024: function_params_org.sub(/^\(/, "\(#{function_result_arg}, ")
1025:
1026: function = AnyMethod.new("function", function_name)
1027: parse_subprogram(function, function_params,
1028: function_comment, function_code,
1029: before_contains_code, true, function_prefix)
1030:
1031: # Specific modification due to function
1032: function.params.sub!(/\(\s*?#{function_result_arg}\s*?,\s*?/, "\( ")
1033: function.params << " result(" + function_result_arg + ")"
1034: function.start_collecting_tokens
1035: function.add_token Token.new(1,1).set_text(function_code_org)
1036:
1037: progress "f"
1038: @stats.num_methods += 1
1039: container.add_method function
1040: subroutine_function = function
1041:
1042: namelist_comment =
1043: find_namelists(function, function_code, before_contains_code)
1044: function.comment << namelist_comment if namelist_comment
1045:
1046: end
1047:
1048: # The visibility of procedure is specified
1049: #
1050: set_visibility(container, procedure_name,
1051: visibility_default, @@public_methods)
1052:
1053: # The alias for this procedure from external modules
1054: #
1055: check_external_aliases(procedure_name,
1056: subroutine_function.params,
1057: subroutine_function.comment, subroutine_function) if external
1058: check_public_methods(subroutine_function, container.name)
1059:
1060:
1061: # contains_lines are parsed as private procedures
1062: if contains_flag
1063: parse_program_or_module(container,
1064: contains_lines.join("\n"), :private)
1065: end
1066:
1067: # next loop to search next block
1068: level_depth = 0
1069: block_searching_flag = nil
1070: block_searching_lines = []
1071: pre_comment = []
1072: procedure_trailing = ""
1073: procedure_name = ""
1074: procedure_params = ""
1075: procedure_prefix = ""
1076: procedure_result_arg = ""
1077: contains_lines = []
1078: contains_flag = nil
1079: next false
1080: } # End of remaining_lines.collect!{|line|
1081:
1082: # Array remains_lines is converted to String remains_code again
1083: #
1084: remaining_code = remaining_lines.join("\n")
1085:
1086: #
1087: # Parse interface
1088: #
1089: interface_scope = false
1090: generic_name = ""
1091: interface_code.split("\n").each{ |line|
1092: if /^\s*?
1093: interface(
1094: \s+\w+|
1095: \s+operator\s*?\(.*?\)|
1096: \s+assignment\s*?\(\s*?=\s*?\)
1097: )?
1098: \s*?(!.*?)?$
1099: /ix =~ line
1100: generic_name = $1 ? $1.strip.chomp : nil
1101: interface_trailing = $2 || "!"
1102: interface_scope = true
1103: interface_scope = false if interface_trailing =~ /!:nodoc:/
1104: # if generic_name =~ /operator\s*?\((.*?)\)/i
1105: # operator_name = $1
1106: # if operator_name && !operator_name.empty?
1107: # generic_name = "#{operator_name}"
1108: # end
1109: # end
1110: # if generic_name =~ /assignment\s*?\((.*?)\)/i
1111: # assignment_name = $1
1112: # if assignment_name && !assignment_name.empty?
1113: # generic_name = "#{assignment_name}"
1114: # end
1115: # end
1116: end
1117: if /^\s*?end\s+interface/i =~ line
1118: interface_scope = false
1119: generic_name = nil
1120: end
1121: # internal alias
1122: if interface_scope && /^\s*?module\s+procedure\s+(.*?)(!.*?)?$/i =~ line
1123: procedures = $1.strip.chomp
1124: procedures_trailing = $2 || "!"
1125: next if procedures_trailing =~ /!:nodoc:/
1126: procedures.split(",").each{ |proc|
1127: proc.strip!
1128: proc.chomp!
1129: next if generic_name == proc || !generic_name
1130: old_meth = container.find_symbol(proc, nil, @options.ignore_case)
1131: next if !old_meth
1132: nolink = old_meth.visibility == :private ? true : nil
1133: nolink = nil if @options.show_all
1134: new_meth =
1135: initialize_external_method(generic_name, proc,
1136: old_meth.params, nil,
1137: old_meth.comment,
1138: old_meth.clone.token_stream[0].text,
1139: true, nolink)
1140: new_meth.singleton = old_meth.singleton
1141:
1142: progress "i"
1143: @stats.num_methods += 1
1144: container.add_method new_meth
1145:
1146: set_visibility(container, generic_name, visibility_default, @@public_methods)
1147:
1148: check_public_methods(new_meth, container.name)
1149:
1150: }
1151: end
1152:
1153: # external aliases
1154: if interface_scope
1155: # subroutine
1156: proc = nil
1157: params = nil
1158: procedures_trailing = nil
1159: if line =~ /^\s*?
1160: (recursive|pure|elemental)?\s*?
1161: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
1162: /ix
1163: proc = $2.chomp.strip
1164: generic_name = proc unless generic_name
1165: params = $3 || ""
1166: procedures_trailing = $4 || "!"
1167:
1168: # function
1169: elsif line =~ /^\s*?
1170: (recursive|pure|elemental)?\s*?
1171: (
1172: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1173: | type\s*?\([\w\s]+?\)\s+
1174: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1175: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1176: | double\s+precision\s+
1177: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1178: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1179: )?
1180: function\s+(\w+)\s*?
1181: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
1182: /ix
1183: proc = $8.chomp.strip
1184: generic_name = proc unless generic_name
1185: params = $9 || ""
1186: procedures_trailing = $12 || "!"
1187: else
1188: next
1189: end
1190: next if procedures_trailing =~ /!:nodoc:/
1191: indicated_method = nil
1192: indicated_file = nil
1193: TopLevel.all_files.each do |name, toplevel|
1194: indicated_method = toplevel.find_local_symbol(proc, @options.ignore_case)
1195: indicated_file = name
1196: break if indicated_method
1197: end
1198:
1199: if indicated_method
1200: external_method =
1201: initialize_external_method(generic_name, proc,
1202: indicated_method.params,
1203: indicated_file,
1204: indicated_method.comment)
1205:
1206: progress "e"
1207: @stats.num_methods += 1
1208: container.add_method external_method
1209: set_visibility(container, generic_name, visibility_default, @@public_methods)
1210: if !container.include_requires?(indicated_file, @options.ignore_case)
1211: container.add_require(Require.new(indicated_file, ""))
1212: end
1213: check_public_methods(external_method, container.name)
1214:
1215: else
1216: @@external_aliases << {
1217: "new_name" => generic_name,
1218: "old_name" => proc,
1219: "file_or_module" => container,
1220: "visibility" => find_visibility(container, generic_name, @@public_methods) || visibility_default
1221: }
1222: end
1223: end
1224:
1225: } if interface_code # End of interface_code.split("\n").each ...
1226:
1227: #
1228: # Already imported methods are removed from @@public_methods.
1229: # Remainders are assumed to be imported from other modules.
1230: #
1231: # 既に参照済みのメソッドは @@public_methods から取り除く.
1232: # 残りは外部モジュールからの参照と仮定する.
1233: #
1234: @@public_methods.delete_if{ |method| method["entity_is_discovered"]}
1235:
1236: @@public_methods.each{ |pub_meth|
1237: next unless pub_meth["file_or_module"].name == container.name
1238: pub_meth["used_modules"].each{ |used_mod|
1239: TopLevel.all_classes_and_modules.each{ |modules|
1240: if modules.name == used_mod ||
1241: modules.name.upcase == used_mod.upcase &&
1242: @options.ignore_case
1243: modules.method_list.each{ |meth|
1244: if meth.name == pub_meth["name"] ||
1245: meth.name.upcase == pub_meth["name"].upcase &&
1246: @options.ignore_case
1247: new_meth = initialize_public_method(meth,
1248: modules.name)
1249: if pub_meth["local_name"]
1250: new_meth.name = pub_meth["local_name"]
1251: end
1252: progress "e"
1253: @stats.num_methods += 1
1254: container.add_method new_meth
1255: end
1256: }
1257: end
1258: }
1259: }
1260: }
1261:
1262: container
1263: end
Parse arguments, comment, code of subroutine and function. Return AnyMethod object.
# File parsers/parse_f95.rb, line 1269
1269: def parse_subprogram(subprogram, params, comment, code,
1270: before_contains=nil, function=nil, prefix=nil)
1271: subprogram.singleton = false
1272: prefix = "" if !prefix
1273: arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params
1274: args_comment, params_opt =
1275: find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""),
1276: nil, nil, true)
1277: params_opt = "( " + params_opt + " ) " if params_opt
1278: subprogram.params = params_opt || ""
1279:
1280: block_comment = find_comments comment
1281: if function
1282: subprogram.comment = "<b><em> Function </em></b> :: <em>#{prefix}</em>\n"
1283: else
1284: subprogram.comment = "<b><em> Subroutine </em></b> :: <em>#{prefix}</em>\n"
1285: end
1286: subprogram.comment << args_comment if args_comment
1287: subprogram.comment << block_comment if block_comment
1288:
1289: # For output source code
1290: subprogram.start_collecting_tokens
1291: subprogram.add_token Token.new(1,1).set_text(code)
1292:
1293: subprogram
1294: end
Parse visibility
# File parsers/parse_f95.rb, line 1582
1582: def parse_visibility(code, default, container)
1583: result = []
1584: visibility_default = default || :public
1585:
1586: used_modules = []
1587: container.includes.each{|i| used_modules << i.name} if container
1588:
1589: remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
1590: remaining_code.split("\n").each{ |line|
1591: if /^\s*?private\s*?$/ =~ line
1592: visibility_default = :private
1593: break
1594: end
1595: } if remaining_code
1596:
1597: remaining_code.split("\n").each{ |line|
1598: if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
1599: methods = $2.sub(/!.*$/, '')
1600: methods.split(",").each{ |meth|
1601: meth.sub!(/!.*$/, '')
1602: meth.gsub!(/:/, '')
1603: result << {
1604: "name" => meth.chomp.strip,
1605: "visibility" => :private,
1606: "used_modules" => used_modules.clone,
1607: "file_or_module" => container,
1608: "entity_is_discovered" => nil,
1609: "local_name" => nil
1610: }
1611: }
1612: elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
1613: methods = $2.sub(/!.*$/, '')
1614: methods.split(",").each{ |meth|
1615: meth.sub!(/!.*$/, '')
1616: meth.gsub!(/:/, '')
1617: result << {
1618: "name" => meth.chomp.strip,
1619: "visibility" => :public,
1620: "used_modules" => used_modules.clone,
1621: "file_or_module" => container,
1622: "entity_is_discovered" => nil,
1623: "local_name" => nil
1624: }
1625: }
1626: end
1627: } if remaining_code
1628:
1629: if container
1630: result.each{ |vis_info|
1631: vis_info["parent"] = container.name
1632: }
1633: end
1634:
1635: return visibility_default, result
1636: end
# File parsers/parse_f95.rb, line 1522
1522: def progress(char)
1523: unless @options.quiet
1524: @progress.print(char)
1525: @progress.flush
1526: end
1527: end
Empty lines in header are removed
# File parsers/parse_f95.rb, line 2003
2003: def remove_empty_head_lines(text)
2004: return "" unless text
2005: lines = text.split("\n")
2006: header = true
2007: lines.delete_if{ |line|
2008: header = false if /\S/ =~ line
2009: header && /^\s*?$/ =~ line
2010: }
2011: lines.join("\n")
2012: end
header marker "=", "==", … are removed
# File parsers/parse_f95.rb, line 2016
2016: def remove_header_marker(text)
2017: return text.gsub(/^\s?(=+)/, '<tt></tt>\1')
2018: end
# File parsers/parse_f95.rb, line 2020
2020: def remove_private_comments(body)
2021: body.gsub!(/^(\s*)!--\s*?$.*?^\s*!\+\+\s*?$/m, '\\1!')
2022: return body
2023: end
Remove "Alias for" in end of comments
# File parsers/parse_f95.rb, line 1982
1982: def remove_trailing_alias(text)
1983: return "" if !text
1984: lines = text.split("\n").reverse
1985: comment_block = Array.new
1986: checked = false
1987: lines.each do |line|
1988: if !checked
1989: if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line ||
1990: /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line
1991: checked = true
1992: next
1993: end
1994: end
1995: comment_block.unshift line
1996: end
1997: nice_lines = comment_block.join("\n")
1998: nice_lines ||= ""
1999: return nice_lines
2000: end
devine code constructs
# File parsers/parse_f95.rb, line 402
402: def scan
403:
404: # remove private comment
405: remaining_code = remove_private_comments(@body)
406:
407: # continuation lines are united to one line
408: remaining_code = united_to_one_line(remaining_code)
409:
410: # semicolons are replaced to line feed
411: remaining_code = semicolon_to_linefeed(remaining_code)
412:
413: # collect comment for file entity
414: whole_comment, remaining_code = collect_first_comment(remaining_code)
415: @top_level.comment = whole_comment
416:
417: # String "remaining_code" is converted to Array "remaining_lines"
418: remaining_lines = remaining_code.split("\n")
419:
420: # "module" or "program" parts are parsed (new)
421: #
422: level_depth = 0
423: block_searching_flag = nil
424: block_searching_lines = []
425: pre_comment = []
426: module_program_trailing = ""
427: module_program_name = ""
428: other_block_level_depth = 0
429: other_block_searching_flag = nil
430: remaining_lines.collect!{|line|
431: if !block_searching_flag && !other_block_searching_flag
432: if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i
433: block_searching_flag = :module
434: block_searching_lines << line
435: module_program_name = $1
436: module_program_trailing = find_comments($2)
437: next false
438: elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
439: line =~ /^\s*?\w/ && !block_start?(line)
440: block_searching_flag = :program
441: block_searching_lines << line
442: module_program_name = $1 || ""
443: module_program_trailing = find_comments($2)
444: next false
445:
446: elsif block_start?(line)
447: other_block_searching_flag = true
448: next line
449:
450: elsif line =~ /^\s*?!\s?(.*)/
451: pre_comment << line
452: next line
453: else
454: pre_comment = []
455: next line
456: end
457: elsif other_block_searching_flag
458: other_block_level_depth += 1 if block_start?(line)
459: other_block_level_depth -= 1 if block_end?(line)
460: if other_block_level_depth < 0
461: other_block_level_depth = 0
462: other_block_searching_flag = nil
463: end
464: next line
465: end
466:
467: block_searching_lines << line
468: level_depth += 1 if block_start?(line)
469: level_depth -= 1 if block_end?(line)
470: if level_depth >= 0
471: next false
472: end
473:
474: # "module_program_code" is formatted.
475: # ":nodoc:" flag is checked.
476: #
477: module_program_code = block_searching_lines.join("\n")
478: module_program_code = remove_empty_head_lines(module_program_code)
479: if module_program_trailing =~ /^:nodoc:/
480: # next loop to search next block
481: level_depth = 0
482: block_searching_flag = false
483: block_searching_lines = []
484: pre_comment = []
485: next false
486: end
487:
488: # NormalClass is created, and added to @top_level
489: #
490: if block_searching_flag == :module
491: module_name = module_program_name
492: module_code = module_program_code
493: module_trailing = module_program_trailing
494: progress "m"
495: @stats.num_modules += 1
496: f9x_module = @top_level.add_module NormalClass, module_name
497: f9x_module.record_location @top_level
498:
499: #
500: # Add provided modules information to @top_level comment
501: #
502: provided_modules = []
503: provided_mes_line_num = nil
504: top_level_comment_lines = []
505: line_num = 0
506: @top_level.comment.split("\n").each{|line|
507: top_level_comment_lines << line
508: line_num += 1
509: next if line.empty?
510: if !provided_mes_line_num && /^\s?#{PROVIDED_MODULES_MES}/ =~ line
511: provided_mes_line_num = line_num
512: next
513: end
514: if provided_mes_line_num
515: if /^\s?\*\s+<b>(\w+)<\/b>/ =~ line
516: provided_modules << $1
517: else
518: provided_mes_line_num = nil
519: end
520: end
521: }
522: line_num = 0
523: if provided_mes_line_num
524: top_level_comment_lines.collect!{ |line|
525: line_num += 1
526: if line_num < provided_mes_line_num
527: line
528: else
529: nil
530: end
531: }
532: top_level_comment_lines.delete_if{|line| !line }
533: end
534: top_level_comment_lines << "\n" + PROVIDED_MODULES_MES + "."
535: if provided_mes_line_num
536: top_level_comment_lines[-1].sub!(/\.$/, '')
537: top_level_comment_lines[-1] << "s."
538: end
539: provided_modules.each{ |mod|
540: top_level_comment_lines << "* <b>" + mod + "</b>"
541: }
542: top_level_comment_lines << "* <b>" + module_name + "</b>"
543: @top_level.comment = top_level_comment_lines.join("\n")
544:
545: #
546: # Information about the module is parsed
547: #
548: f9x_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) +
549: "\n" + module_trailing : module_trailing + "\n" +
550: find_comments(module_code.sub(/^.*$\n/i, ''))
551: f9x_module.comment = f9x_comment
552: parse_program_or_module(f9x_module, module_code)
553:
554: TopLevel.all_files.each do |name, toplevel|
555: if toplevel.include_includes?(module_name, @options.ignore_case)
556: if !toplevel.include_requires?(@file_name, @options.ignore_case)
557: toplevel.add_require(Require.new(@file_name, ""))
558: end
559: end
560: toplevel.each_classmodule{|m|
561: if m.include_includes?(module_name, @options.ignore_case)
562: if !m.include_requires?(@file_name, @options.ignore_case)
563: m.add_require(Require.new(@file_name, ""))
564: end
565: end
566: }
567: end
568:
569: namelist_comment =
570: find_namelists(f9x_module, before_contains(module_code))
571: f9x_module.comment << namelist_comment if namelist_comment
572:
573: elsif block_searching_flag == :program
574: program_name = module_program_name
575: program_name = "main_program" if program_name.empty?
576: program_code = module_program_code
577: program_trailing = module_program_trailing
578: program_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) +
579: "\n" + program_trailing : program_trailing + "\n" +
580: find_comments(program_code.sub(/^.*$\n/i, ''))
581:
582: progress "p"
583: @stats.num_methods += 1
584: f9x_mainprogram = AnyMethod.new("main_program", program_name)
585: f9x_mainprogram.singleton = false
586: f9x_mainprogram.comment = "<b><em> Main Program </em></b> :\n"
587: f9x_mainprogram.comment << program_comment
588: f9x_mainprogram.params = ""
589:
590: # For output source code
591: f9x_mainprogram.start_collecting_tokens
592: f9x_mainprogram.add_token Token.new(1,1).set_text(program_code)
593:
594: @top_level.add_method f9x_mainprogram
595: parse_program_or_module(@top_level, program_code, :private)
596:
597: namelist_comment = find_namelists(f9x_mainprogram, program_code)
598: f9x_mainprogram.comment << namelist_comment if namelist_comment
599: end
600:
601: # next loop to search next block
602: level_depth = 0
603: block_searching_flag = false
604: block_searching_lines = []
605: pre_comment = []
606: next false
607: }
608:
609: remaining_lines.delete_if{ |line|
610: line == false
611: }
612:
613: # External subprograms and functions are parsed
614: #
615: # 単一のファイル内において program や module に格納されない,
616: # 外部サブルーチン, 外部関数部分の解析.
617: #
618: parse_program_or_module(@top_level, remaining_lines.join("\n"),
619: :public, true)
620:
621: @top_level
622: end
Semicolons are replaced to line feed.
# File parsers/parse_f95.rb, line 1885
1885: def semicolon_to_linefeed(text)
1886: return "" unless text
1887: lines = text.split("\n")
1888: lines.collect!{ |line|
1889: indent_space = ""
1890: if line =~ /^(\s+)/
1891: indent_space = $1
1892: end
1893: words = line.split("")
1894: commentout = false
1895: squote = false ; dquote = false
1896: words.collect! { |char|
1897: if !(squote) && !(dquote) && !(commentout)
1898: case char
1899: when "!" ; commentout = true ; next char
1900: when "\""; dquote = true ; next char
1901: when "\'"; squote = true ; next char
1902: when ";" ; "\n"+indent_space
1903: else next char
1904: end
1905: elsif commentout
1906: next char
1907: elsif squote
1908: case char
1909: when "\'"; squote = false ; next char
1910: else next char
1911: end
1912: elsif dquote
1913: case char
1914: when "\""; dquote = false ; next char
1915: else next char
1916: end
1917: end
1918: }
1919: words.join("")
1920: }
1921: return lines.join("\n")
1922: end
Set visibility
"subname" element of "visibility_info" is deleted.
# File parsers/parse_f95.rb, line 1643
1643: def set_visibility(container, subname, visibility_default, visibility_info)
1644: return unless container || subname || visibility_default || visibility_info
1645: not_found = true
1646: visibility_info.collect!{ |info|
1647: if info["name"] == subname ||
1648: @options.ignore_case && info["name"].upcase == subname.upcase
1649: if info["file_or_module"].name == container.name
1650: container.set_visibility_for([subname], info["visibility"])
1651: info["entity_is_discovered"] = true
1652: not_found = false
1653: end
1654: end
1655: info
1656: }
1657: if not_found
1658: return container.set_visibility_for([subname], visibility_default)
1659: else
1660: return container
1661: end
1662: end
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 parsers/parse_f95.rb, line 1762
1762: def united_to_one_line(f90src, delete_space=true)
1763: return "" unless f90src
1764: lines = f90src.split("\n")
1765: previous_continuing = false
1766: now_continuing = false
1767: body = ""
1768: lines.each{ |line|
1769: words = line.split("")
1770: next if words.empty? && previous_continuing
1771: commentout = false
1772: brank_flag = true ; brank_char = ""
1773: squote = false ; dquote = false
1774: ignore = false
1775: words.collect! { |char|
1776: if previous_continuing && brank_flag
1777: now_continuing = true
1778: ignore = true
1779: case char
1780: when "!" ; break
1781: when " " ; brank_char << char ; next ""
1782: when "&"
1783: brank_flag = false
1784: now_continuing = false
1785: next ""
1786: else
1787: brank_flag = false
1788: now_continuing = false
1789: ignore = false
1790: next brank_char + char
1791: end
1792: end
1793: ignore = false
1794:
1795: if now_continuing
1796: next ""
1797: elsif !(squote) && !(dquote) && !(commentout)
1798: case char
1799: when "!" ; commentout = true ; next char
1800: when "\""; dquote = true ; next char
1801: when "\'"; squote = true ; next char
1802: when "&" ; now_continuing = true ; next ""
1803: else next char
1804: end
1805: elsif commentout
1806: next char
1807: elsif squote
1808: case char
1809: when "\'"; squote = false ; next char
1810: else next char
1811: end
1812: elsif dquote
1813: case char
1814: when "\""; dquote = false ; next char
1815: else next char
1816: end
1817: end
1818: }
1819: if !ignore && !previous_continuing || !brank_flag
1820: if previous_continuing
1821: if delete_space
1822: joined_words = words.join("")
1823: body = body.rstrip + " " + joined_words.lstrip
1824: else
1825: body << words.join("")
1826: end
1827: else
1828: body << "\n" + words.join("")
1829: end
1830: end
1831: previous_continuing = now_continuing ? true : nil
1832: now_continuing = nil
1833: }
1834: return body
1835: end