This parser parses Fortran95 files with suffixes “f90”, “F90”, “f95” and “F95”. Fortran95 files are expected to be conformed to Fortran95 standards.
Fundamental rules are same as that of the Ruby parser. But comment markers are '!' not '#'.
F95 parses main programs, modules, subroutines, functions, derived-types, public variables, public constants, defined operators and defined assignments. These components are described in items of RDoc documentation, as follows.
Files (same as Ruby)
Modules
Subroutines, functions, variables, constants, derived-types, defined operators, defined assignments
Files in which imported modules, external subroutines and external functions are defined.
List of imported modules
List of derived-types, List of imported modules all of whose components are published again
Components listed in 'Methods' (subroutines, functions, …) defined in modules are described in the item of 'Classes'. On the other hand, components defined in main programs or as external procedures are described in the item of 'Files'.
By default, documentation on public components (subroutines, functions, variables, constants, derived-types, defined operators, defined assignments) are generated.
With “–all” option, documentation on all components are generated (almost same as the Ruby parser).
The following information is automatically parsed.
Types of arguments
Types of variables and constants
Types of variables in the derived types, and initial values
NAMELISTs and types of variables in them, and initial values
Aliases by interface statement are described in the item of 'Methods'.
Components which are imported from other modules and published again are described in the item of 'Methods'.
Comment blocks should be written as follows.
Comment blocks are considered to be ended when the line without '!' appears.
The indentation is not necessary.
! (Top of file) ! ! Comment blocks for the files. ! !-- ! The comment described in the part enclosed by ! "!--" and "!++" is ignored. !++ ! module hogehoge ! ! Comment blocks for the modules (or the programs). ! private logical :: a ! a private variable real, public :: b ! a public variable integer, parameter :: c = 0 ! a public constant public :: c public :: MULTI_ARRAY public :: hoge, foo type MULTI_ARRAY ! ! Comment blocks for the derived-types. ! real, pointer :: var(:) =>null() ! Comments block for the variables. integer :: num = 0 end type MULTI_ARRAY contains subroutine hoge( in, & ! Comment blocks between continuation lines are ignored. & out ) ! ! Comment blocks for the subroutines or functions ! character(*),intent(in):: in ! Comment blocks for the arguments. character(*),intent(out),allocatable,target :: in ! Comment blocks can be ! written under Fortran statements. character(32) :: file ! This comment parsed as a variable in below NAMELIST. integer :: id namelist /varinfo_nml/ file, id ! ! Comment blocks for the NAMELISTs. ! Information about variables are described above. ! .... end subroutine hoge integer function foo( in ) ! ! This part is considered as comment block. ! Comment blocks under blank lines are ignored. ! integer, intent(in):: inA ! This part is considered as comment block. ! This part is ignored. end function foo subroutine hide( in, & & out ) !:nodoc: ! ! If "!:nodoc:" is described at end-of-line in subroutine ! statement as above, the subroutine is ignored. ! This assignment can be used to modules, subroutines, ! functions, variables, constants, derived-types, ! defined operators, defined assignments, ! list of imported modules ("use" statement). ! .... end subroutine hide end module hogehoge
Comments are below source code
Comments are upper source code
External alias message
Internal alias message
Define code constructs
# File rdoc/parser/f95.rb, line 201 def scan # remove private comment remaining_code = remove_private_comments(@content) # continuation lines are united to one line remaining_code = united_to_one_line(remaining_code) # semicolons are replaced to line feed remaining_code = semicolon_to_linefeed(remaining_code) # collect comment for file entity whole_comment, remaining_code = collect_first_comment(remaining_code) @top_level.comment = whole_comment # String "remaining_code" is converted to Array "remaining_lines" remaining_lines = remaining_code.split("\n") # "module" or "program" parts are parsed (new) # level_depth = 0 block_searching_flag = nil block_searching_lines = [] pre_comment = [] module_program_trailing = "" module_program_name = "" other_block_level_depth = 0 other_block_searching_flag = nil remaining_lines.collect!{|line| if !block_searching_flag && !other_block_searching_flag if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i block_searching_flag = :module block_searching_lines << line module_program_name = $1 module_program_trailing = find_comments($2) next false elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i || line =~ /^\s*?\w/ && !block_start?(line) block_searching_flag = :program block_searching_lines << line module_program_name = $1 || "" module_program_trailing = find_comments($2) next false elsif block_start?(line) other_block_searching_flag = true next line elsif line =~ /^\s*?!\s?(.*)/ pre_comment << line next line else pre_comment = [] next line end elsif other_block_searching_flag other_block_level_depth += 1 if block_start?(line) other_block_level_depth -= 1 if block_end?(line) if other_block_level_depth < 0 other_block_level_depth = 0 other_block_searching_flag = nil end next line end block_searching_lines << line level_depth += 1 if block_start?(line) level_depth -= 1 if block_end?(line) if level_depth >= 0 next false end # "module_program_code" is formatted. # ":nodoc:" flag is checked. # module_program_code = block_searching_lines.join("\n") module_program_code = remove_empty_head_lines(module_program_code) if module_program_trailing =~ /^:nodoc:/ # next loop to search next block level_depth = 0 block_searching_flag = false block_searching_lines = [] pre_comment = [] next false end # NormalClass is created, and added to @top_level # if block_searching_flag == :module module_name = module_program_name module_code = module_program_code module_trailing = module_program_trailing f9x_module = @top_level.add_module NormalClass, module_name f9x_module.record_location @top_level @stats.add_module f9x_module f9x_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) + "\n" + module_trailing : module_trailing + "\n" + find_comments(module_code.sub(/^.*$\n/i, '')) f9x_module.comment = f9x_comment parse_program_or_module(f9x_module, module_code) TopLevel.all_files.each do |name, toplevel| if toplevel.include_includes?(module_name, @options.ignore_case) if !toplevel.include_requires?(@file_name, @options.ignore_case) toplevel.add_require(Require.new(@file_name, "")) end end toplevel.each_classmodule{|m| if m.include_includes?(module_name, @options.ignore_case) if !m.include_requires?(@file_name, @options.ignore_case) m.add_require(Require.new(@file_name, "")) end end } end elsif block_searching_flag == :program program_name = module_program_name program_code = module_program_code program_trailing = module_program_trailing # progress "p" # HACK what stats thingy does this correspond to? program_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) + "\n" + program_trailing : program_trailing + "\n" + find_comments(program_code.sub(/^.*$\n/i, '')) program_comment = "\n\n= <i>Program</i> <tt>#{program_name}</tt>\n\n" \ + program_comment @top_level.comment << program_comment parse_program_or_module(@top_level, program_code, :private) end # next loop to search next block level_depth = 0 block_searching_flag = false block_searching_lines = [] pre_comment = [] next false } remaining_lines.delete_if{ |line| line == false } # External subprograms and functions are parsed # parse_program_or_module(@top_level, remaining_lines.join("\n"), :public, true) @top_level end