################################################################# # f77proto.rb : prototype extraction from FORTRAN77 sources # # 2000/05/28 堀之内 武 # # 使用法: # ruby [-v] f77proto.rb [files...] # # -v を与えるとC言語の形式のコメントがプリントされる(推奨). # [files...] は 0 個以上の fortran77 のソースファイル。0個の場合 # 標準入力から読み込む。 # # 機能: # FORTRAN77のソースプログラム中の副プログラム引用仕様を以下のように # 書き出す。 # # <副プログラム宣言> ( # <引数宣言> # <引数宣言> # ... # ) # # ここで引数宣言は一行一引数で引数の個数分だけある(ゼロの場合もあり) # # <副プログラム宣言> = <副プログラム種類> 副プログラム名 # <副プログラム種類> = "SUBROUTINE" | <型指定> "FUNCTION" # # 備考:ENTRY も上の<副プログラム種類>のいずれか適当な方で宣言される # # <引数宣言> = <型指定> 変数名 # # <型指定> = <型> <配列情報> # | <型> # # <型> = fortranの基本型 # <配列情報> = "(" <サイズ列> ")" # <サイズ列> = <サイズ> <サイズ列> # | <サイズ> # <サイズ> = "*" | <変数名> | <整数> # # 制限: # # 一つのIMPLICIT文で2つ以上の型を宣言している場合には対応してない # # プリプロセッサー利用の F77 ネイティブでない型宣言には対応してない # # 備考: # # 大文字・小文字混じりでも大丈夫(なはず) # IMPLICIT文は解釈される # !から始まるコメントが入っていても大丈夫(なはず) # DIMENSION文対応有 # ################################################################# while gets() if /^ *SUBROUTINE/i || /^ *ENTRY/i || /^ .*FUNCTION/i then # sdef = subprogram definition sdef = $_ if sdef =~ '\(' && sdef !~ '\)' then # definition continues while gets() sdef += $_ break if $_ =~ '\)' end print sdef if $DEBUG end sdef.gsub!(/!.*$/,'') ## delete comments # dcomposition into subprogram type, name & arguments case sdef when /SUBROUTINE/i stype = 'SUBROUTINE' when /(\w.*FUNCTION)/i stype = $1 when /ENTRY/i ## function or subroutine end /(\w+) *\( *(.*?) *\)/p =~ sdef if $1 != nil then sname = $1 # subprogram name args = $2 # arguments -> will be an array later else # has no parentheses: case sdef when /^ *SUBROUTINE +(\w+)/i sname = $1 args = "" when /^ *ENTRY +(\w+)/i sname = $1 args = "" when /^ *FUNCTION +(\w+)/i sname = $1 args = "" end end args.gsub!('^ \S','') # delete continuation marks args = args.split(/,[ \n]*/p) # -> array p args if $DEBUG # get variable definition statements & implicit types if /^ *ENTRY/i !~ sdef dstat = [] impl = [] while gets() break if /^ *END/i || /^ *RETURN/i # def must have completed if /^ *REAL /i || /^ *COMPLEX/i || /^ *LOGICAL/i || \ /^ *CHARACTER/i || /^ *INTEGER/i || /^ *DOUBLE/i || \ /^ *DIMENSION/i then dstat += $_.sub(/!.*$/,'') elsif /^ *IMPLICIT/i impl += $_.sub(/!.*$/,'') end end # set implicit type rule impltype = [ [/[I-N]/i,'INTEGER'], [/[A-H,O-Z]/i,'REAL'] ] for ip in impl /IMPLICIT +(\S[\S ]*\S)\s*\((.*)\)/i =~ ip impltype = [[ /[#{$2}]/i, $1 ]] + impltype # supersade defaults p impltype if $DEBUG end end # argument prototype definitions (prts) prts = [] dsmatched = [] # for verbose output for ar in args match = false for ds in dstat if ds =~ /[\W\s]#{ar}[\W\s]/i && ds !~ /\([^\)]*#{ar}[^\(]*\)/i then match = true if $VERBOSE && ! dsmatched.include?(ds) dsmatched += ds end break end end if match then /^ *([\w\*]+).*#{ar}(.*)/i =~ ds type = $1 if $2 != nil then s=$2 if s =~ /^ *\(/ # array shape n=0 ; b=0 s.each_byte{ |i| n += 1 if i==?( n -= 1 if i==?) break if n==0 b += 1 } type += ' '+s[0..b] s = s[(b+1)..-1] end if type =~ /CHARACTER/i && s =~ /^ *(\* *[^,]*)/ # character length type.sub!(/CHARACTER( *\*\w*)?/i,'CHARACTER'+$1) end # remeady for the \w+ type matching type.sub!(/DOUBLE/i,'DOUBLE PRECISION') type.sub!(/CHARACTER[ \*]*$/i,'CHARACTER*(*)') # dimension -> implicit type if type =~ /DIMENSION/i for it in impltype if ar[0..0] =~ it[0] type.sub!(/DIMENSION/i, it[1]) break end end end end else # implicit type for it in impltype if ar[0..0] =~ it[0] type = it[1] print ar," matches ",it[0].inspect," -> ",type,"\n" if $DEBUG break end end end prts += type+' '+ar end # print prototype if $VERBOSE print "/* \n",sdef.gsub(/^/,' *') for ip in impl print ip.sub(/^/,' *') end for ds in dsmatched print ds.sub(/^/,' *') end print " */\n" end print ' ',stype,' ',sname,"(\n" for prt in prts print ' ',prt,"\n" end print " )\n\n" end end