コンパイルとリンク2014年10月01日 20:17

これまでに、copy.for,getc2.for,put2.forが出てきて、copyを実行させるパーツがそろったので、 実際に、作成し実行してみます。

ソースファイルなどを格納するフォルダーは下記の通りです。

  • ratfor\fortran\src -- Watcom Fortran77版のソースファイル
  • ratfor\fortran\obj -- Watcom Fortran77版のソースファイルから作ったオブジェクトファイル
  • ratfor\fortran\exe -- Watcom Fortran77版の実行形式ファイル
  • ratfor\fortran\bat -- Watcom Fortran77版のコンパイル・リンク用バッチファイル
  • ratfor\ratfor\src -- RATFOR版のソースファイル
  • ratfor\ratfor\obj -- RATFOR版のソースファイルから作ったオブジェクトファイル
  • ratfor\ratfor\exe -- RATFOR版の実行形式ファイル
  • ratfor\ratfor\bat -- RATFOR版ののコンパイル・リンク用バッチファイル

最初に、Watcom Fortran77用の バッチファイルを作成しておきましょう。まずは、コンパイル用。fc.bat

@echo off
rem fc.for
wfc386 ..\src\%1.for
move ..\bat\%1.obj ..\obj

リンケージ用。fl.bat

@echo off
rem fl.bat
wlink file ..\obj\%1.obj lib ..\obj\ratfor.lib
move ..\obj\%1.exe ..\exe

オブジェクト・プログラム・ライブラリーのメンテナンス用。fo.bat

@echo off
rem fo.bat 
wlib ..\obj\ratfor.lib -+..\obj\%1.obj

早速コンパイルしてみましょう。コマンド・プロンプトをあけて、 バッチファイルのあるディレクトリに移動して、 コンパイルします。

Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.

C:\Users\Hiroya>cd Documents\ratfor\fortran\bat

C:\Users\Hiroya\Documents\ratfor\fortran\bat>fc getc2
Open Watcom FORTRAN 77/32 Optimizing Compiler Version 1.9
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
..\src\getc2.for: 27 ステートメント, 166 バイト, 6 拡張メッセージ, 0 警告エラー, 0 エラー
        1 個のファイルを移動しました。

getc2.objをratfor.libに登録します。

C:\Users\Hiroya\Documents\ratfor\fortran\bat>fo getc2
Open Watcom Library Manager Version 1.9
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
Warning! '..\obj\ratfor.lib'をオープンできません - ライブラリを作成します

C:\Users\Hiroya\Documents\ratfor\fortran\bat>

同様にputc2をコンパイルしratfor.libに登録します。

C:\Users\Hiroya\Documents\ratfor\fortran\bat>fc putc2
Open Watcom FORTRAN 77/32 Optimizing Compiler Version 1.9
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
..\src\putc2.for: 16 ステートメント, 113 バイト, 4 拡張メッセージ, 0 警告エラー, 0 エラー
        1 個のファイルを移動しました。

C:\Users\Hiroya\Documents\ratfor\fortran\bat>fo putc2
Open Watcom Library Manager Version 1.9
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.

C:\Users\Hiroya\Documents\ratfor\fortran\bat>

copyをコンパイルし、ライブラリーとリンクします。

C:\Users\Hiroya\Documents\ratfor\fortran\bat>fc copy
Open Watcom FORTRAN 77/32 Optimizing Compiler Version 1.9
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
..\src\copy.for: 8 ステートメント, 35 バイト, 5 拡張メッセージ, 0 警告エラー, 0 エラー
        1 個のファイルを移動しました。

C:\Users\Hiroya\Documents\ratfor\fortran\bat>fl copy
Open Watcom Linker Version 1.9
Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
オブジェクトファイルを読込み中
ライブラリを検索中
a Windows NT character-mode 実行可能 を作成中
        1 個のファイルを移動しました。

C:\Users\Hiroya\Documents\ratfor\fortran\bat>

テストします。

C:\Users\Hiroya\Documents\ratfor\fortran\bat>cd ..\exe

C:\Users\Hiroya\Documents\ratfor\fortran\exe>.\copy
test sample
test sample
looooooooooooong text
looooooooooooong text
^Z

C:\Users\Hiroya\Documents\ratfor\fortran\exe>.\copy <..\src\copy.for
c copy.for -- copy input characters to output
      program copy
      integer*1 getc
      integer*1 c

      while (getc(c) .ne. -1) do ! EOF(-1)
          call putc(c)
      end while
      stop
      end
C:\Users\Hiroya\Documents\ratfor\fortran\exe>

いかがでしょうか。うまくいったでしょうか。でも、問題が一つあります。NEWLINEがくる前に EOFがくると、その行は、コピーされません。

C:\Users\Hiroya\Documents\ratfor\fortran\exe>.\copy
12345
12345
abcdef^Z

C:\Users\Hiroya\Documents\ratfor\fortran\exe>

これは、read文の仕様のようです。従って読み込み行の終わりには必ずNEWLINEがくる事として、 ロジックを考えていきます。また、行の書き出し中にNEWLINEの前にEOFが出現した場合、書き出し途中の 文字列を強制的に書き出すようにします。この変更をしたputc()は、下記のとおり。

c putc3.for (extended version 2)-- put sharacter on standard output
      subroutine putc(c)
      integer*1 c
      
      integer*1 buf(80) ! MAXCARD(80)
      integer i,lastc
      data lastc/0/

      if ((c .eq. -1) .and. (lastc .eq. 0)) then ! EOF(-1)
          return                           ! buffer is empty
      endif
      if ((lastc .ge. 80) .or. (c .eq. 10) .or. (c .eq. -1)) then ! MAXCARD(80) NEWLINE(10) EOF(-1)
          write(6,100) (buf(i),i=1,lastc)
  100     format(80a1)                     ! MAXCARD(80)
          lastc = 0
      endif
      if (c .ne. 10) then                  ! NEWLINE(10)
          lastc = lastc + 1
          buf(lastc) = c
      endif
      return
      end

コンパイルとライブラリーへの追加は下記のとおり。

C:\Users\Hiroya\Documents\ratfor\fortran\bat>fc putc3
Open Watcom FORTRAN 77/32 Optimizing Compiler Version 1.9
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
..\src\putc3.for: 19 ステートメント, 129 バイト, 4 拡張メッセージ, 0 警告エラー, 0 エラー
        1 個のファイルを移動しました。

C:\Users\Hiroya\Documents\ratfor\fortran\bat>cd ..\obj

C:\Users\Hiroya\Documents\ratfor\fortran\obj>wlib ratfor -putc2 +putc3
Open Watcom Library Manager Version 1.9
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.

putc()が新しくなりましたので、copyを作成し直してください。

コマンド行の引数2014年10月05日 11:01

コマンドラインのプログラムには、引数をつけることで、プログラムに様々な 情報を与えています。この引数を受け取る関数getargを作ります。これは、 Watcom Fortran77の拡張機能iargc(),igetarg()を使い実現します。プログラムは次の通り。

c getarg.for -- get n-th command line argument
      integer function getarg(n,arg,maxsiz)
      integer n, maxsiz
      integer*1 arg(maxsiz)
      
      character*100 carg
      integer*1 iarg(100)
      equivalence (carg,iarg)
      integer l
      integer iargc,igetarg

      if (n .ge. iargc()) then
          getarg = -1                   ! EOF(-1)
          arg(1) = -2                   ! EOS(-2), return NULL string
          return
      endif
      l = igetarg(n,carg)
      i = 1
      while (i .le. l .and. i .le. maxsiz) do
          arg(i) = iarg(i)
          i = i + 1
      end while
      arg(i) = -2                       ! EOS(-2) <<< BUF FIX 10/12
      getarg = i - 1                  ! <<< BUF FIX 10/12  
      return
      end

igetc()は、コマンドラインの引数の数を返します。これには、コマンド自身も含まれます。igetarg(n,str)は、 n番目の引数をcharacter型の文字列strにコピーし長さを返します。strはこのままでは使えないので、integer*1の 文字列に変換し利用します。getarg(n,arg,maxsiz)は、n番目の引数を最大maxsiz文字分argにコピーし、 引数があればYES(1)を そうでなければNO(0)を返します。

getarg()を使った例題echoを示します。コマンドラインの引数を表示する簡単なものです。

まずは、RATFOR版

# echo.r4 -- echo command line arguments
      character arg(MAXARG)
      integer i,n
      integer getarg

      for (n = 1; getarg(n,arg,MAXARG) != EOF; n = n + 1) {
          for (i = 1; arg(i) != EOS; i = i + 1)
              call putc(arg(i))
          call putc(BLANK)
          }
      call putc(NEWLINE)
      stop
      end

Watcom Fortran77版

c echo.for -- echo command line arguments
      program echo
      integer*1 arg(100)                ! MAXARG(100)
      integer i,n
      integer getarg

      n = 1
      while (getarg(n,arg,100) .ne. -1) do ! MAXARG(100) EOF(-1)
          i = 1
          while(arg(i) .ne. -2) do      ! EOS(-2)
              call putc(arg(i))
              i = i + 1
          end while
          call putc(32)                 ! BLANK(32)
          n = n + 1
      end while
      call putc(10)                     ! NEWLINE(10)
      stop
      end

早速、コンパイルしてみましょう。

C:\Users\Hiroya\Documents\ratfor\fortran\bat>fc getarg
Open Watcom FORTRAN 77/32 Optimizing Compiler Version 1.9
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
..\src\getarg.for: 23 ステートメント, 95 バイト, 7 拡張メッセージ, 0 警告エラー, 0 エラー
        1 個のファイルを移動しました。

C:\Users\Hiroya\Documents\ratfor\fortran\bat>fo getarg
Open Watcom Library Manager Version 1.9
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.

C:\Users\Hiroya\Documents\ratfor\fortran\bat>fc echo
Open Watcom FORTRAN 77/32 Optimizing Compiler Version 1.9
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
..\src\echo.for: 17 ステートメント, 112 バイト, 5 拡張メッセージ, 0 警告エラー, 0 エラー
        1 個のファイルを移動しました。

C:\Users\Hiroya\Documents\ratfor\fortran\bat>fl echo
Open Watcom Linker Version 1.9
Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
オブジェクトファイルを読込み中
ライブラリを検索中
a Windows NT character-mode 実行可能 を作成中
        1 個のファイルを移動しました。

C:\Users\Hiroya\Documents\ratfor\fortran\bat>

テストします。

C:\Users\Hiroya\Documents\ratfor\fortran\bat>cd ..\exe

C:\Users\Hiroya\Documents\ratfor\fortran\exe>.\echo one two three
one two three

C:\Users\Hiroya\Documents\ratfor\fortran\exe>.\echo one "t   w   o" three
one t   w   o three

C:\Users\Hiroya\Documents\ratfor\fortran\exe>

ダブルクォートで囲むと、ブランクも含めて引き渡すことができます。

数字出力putdec()2014年10月12日 19:32

先に出てきたputdec(n,w)をみてみましょう。 数値nをw桁で印字します。必要があれば、桁は拡張されます。

RATFOR版は下記の通り。

# putdec.r4 -- put decimal integer n in field width >= W
      subroutine putdec(n, w)
      character chars(MAXCHARS)
      integer itoc
      integer i, n, nd, w

      nd = itoc(n, chars, MAXCHARS)
      for ( i = nd + 1; i <= w; i = i + 1)
          call putc(BLANK)
      for ( i = 1; i <= nd; i = i + 1)
          call putc(chars(i))
      return
      end

ここで、itoc(n,chars,MAXCHARS)は、数値nを長さMAXCHARS文字の文字配列charsに変換します。

RATFOR版は下記の通り。

# itoc.r4 -- convert integer int to character string str
      integer fnction itoc(int, str, size)
      integer abs, mod
      integer d, i, int, intval, j, size
      character str(size), k
      string digits "0123456789"

      intval = abs(int)
      str(1) = EOS
      i = 1
      repeat {                       # generate digits
          i = i + 1
          d = mod(intval, 10)
          str(i) = digits(d + 1)
          intval = intval / 10
          } until (intval == 0 ! i >= size)
      if (int < 0 & i < size) {      # then sign
          i = i + 1
          str(i) = MINUS
          }
      itoc = i - 1
      for (i = 1; j < i; j = j + 1) { # then reverse
          k = str(i)
          str(i) = str(j)
          str(j) = k
          i = i - 1
          }
      return
      end

string deigits "0123456789"とは、文字を文字配列にセットするマクロで、

      character digits(11)
      data digit(1) /'0'/
      data digit(2) /'1'/
      data digit(3) /'2'/
      data digit(4) /'3'/
      data digit(5) /'4'/
      data digit(6) /'5'/
      data digit(7) /'6'/
      data digit(8) /'7'/
      data digit(9) /'8'/
      data digit(10) /'9'/
      data digit(11) /EOS/
と展開されます。EOSは文字列の終わりを示す記号です。

Watcom Fortran77版のputdec()、itoc()は下記の通り。

c putdec.for -- put decimal integer n in field width >= w
      subroutine putdec(n,w)
      integer n, w
      integer*1 chars(100)              ! MAXCHARS(100)
      integer itoc, nd

      nd = itoc(n, chars, 100)          ! MAXCHARS(100)
      i = nd + 1
      while (i .le. w) do
          call putc(32)                 ! BLANK(32)
          i = i + 1
      end while
      i = 1
      while (i .le. nd) do
          call putc(chars(i))
          i = i + 1
      end while
      return
      end
c itoc.for -- convert integer int to character string in str
      integer function itoc(int,str,size)
      integer int, size
      integer*1 str(size)
      integer abs, mod
      integer d, i, intval, j
      integer*1 digits(11), k
      data digits/'0','1','2','3','4','5','6','7','8','9',-2/ ! EOS(-2)

      intval = abs(int)
      str(1) = -2                       ! EOS(-2)
      i = 1
      loop
          i = i + 1                     ! generate digits
          d = mod(intval,10)
          str(i) = digits(d+1)
          intval = intval / 10
      until ((intval .eq. 0) .or. (i .ge. size))
      if ((int .lt. 0) .and. (i .lt. size)) then ! then sign
          i = i + 1
          str(i) = 45                   ! MINUS(45)
      endif
      itoc = i - 1
      j = 1
      while (j .lt. i) do               ! then reverse
          k = str(i)
          str(i) = str(j)
          str(j) = k
          i = i - 1
          j = j + 1
      end while
      return
      end

ここまでで、charcount、wordcount、linecountのパーツがそろいましたので、 この3つをビルドしてみます。

まず、putdec()、itoc()を作成します。

C:\Users\Hiroya\Documents\ratfor\fortran\bat>fc putdec
Open Watcom FORTRAN 77/32 Optimizing Compiler Version 1.9
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
..\src\putdec.for: 17 ステートメント, 92 バイト, 4 拡張メッセージ, 0 警告エラー, 0 エラー
        1 個のファイルを移動しました。

C:\Users\Hiroya\Documents\ratfor\fortran\bat>fo putdec
Open Watcom Library Manager Version 1.9
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.

C:\Users\Hiroya\Documents\ratfor\fortran\bat>fc itoc
Open Watcom FORTRAN 77/32 Optimizing Compiler Version 1.9
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
..\src\itoc.for: 31 ステートメント, 172 バイト, 6 拡張メッセージ, 0 警告エラー, 0 エラー
        1 個のファイルを移動しました。

C:\Users\Hiroya\Documents\ratfor\fortran\bat>fo itoc
Open Watcom Library Manager Version 1.9
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.

charcountをビルドします。

C:\Users\Hiroya\Documents\ratfor\fortran\bat>fc charcount
Open Watcom FORTRAN 77/32 Optimizing Compiler Version 1.9
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
..\src\charcount.for: 12 ステートメント, 69 バイト, 5 拡張メッセージ, 0 警告エラー, 0 エラー
        1 個のファイルを移動しました。

C:\Users\Hiroya\Documents\ratfor\fortran\bat>fl charcount
Open Watcom Linker Version 1.9
Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
オブジェクトファイルを読込み中
ライブラリを検索中
a Windows NT character-mode 実行可能 を作成中
        1 個のファイルを移動しました。

テストします。

C:\Users\Hiroya\Documents\ratfor\fortran\bat>..\exe\charcount
123 456 7890
^Z
13

wordcount、linecountも同様にビルドしてください。

文字から数値への変換2014年10月19日 19:22

さて、itoc()の逆の関数をctoi(c,i)を作っておきます。これは、文字配列cのi番目から数値に変換します。

RATFOR版は次の通り。

# ctoi.r4 -- convert string at in(i) to integer, increment i
      integer ctoi(in,i)
      character in(ARB)
      integer iindex
      integer d, i
      string digits "0123456789"

      while (in(i) == BLANK | in(i) == TAB)
          i = i + 1
      for (ctoi = 0; in(i) != EOS; i = i + 1) {
          d = iindex(digits, in(i))
          if (d == 0)         # non-digit
              break
          ctoi = ctoi * 10 + d - 1
          }
      return
      end

ここで、iindex(s,c)は、文字配列sの中から文字cを探しその位置を返します。Watcom Fortran77には、 同様の組み込み関数index()がありますが、引数がchracter型であるため使えません。作り直します。

RATFOR版は下記の通り。

# iindex.r4 -- find character c in string str
      integer function iindex(str,c)
      character c,str(ARB)
      
      for (iindex = 1; str(iindex) != EOS; iindex = iindex + 1)
         if (str(iindex) == c)
             return
      iindex = 0
      return
      end

ctoi()、iindex()のWatcom Fortran77版は、下記の通り。

c ctoi.for -- convert string at in(i) to integer, increment i
      integer function ctoi(in,i)
      integer*1 in(*)                   ! ARB(*)
      integer i, d
      integer iindex
      integer*1 digits(11)
      data digits/'0','1','2','3','4','5','6','7','8','9',-2/  ! EOS(-2)

      while ((in(i) .eq. 32) .or. (in(i) .eq. 9)) do ! BLANK(32) TAB(9)
          i = i + 1
      end while

      ctoi = 0
      while (in(i) .ne. -2) do          ! EOS(-2)
          d = iindex(digits,in(i))
          if (d .eq. 0) then
              exit
          end if
          ctoi = ctoi*10 + (d - 1)
          i = i + 1
      end while
      ctoi = ctoi
      return
      end
c iindex.for -- find charcter c instring str
      integer function iindex(str,c)
      integer*1 c,str(*)

      iindex = 1
      while (str(iindex) .ne. -2) do    ! EOS(-2)
         if (str(iindex) .eq. c) then
             return
         end if
         iindex = iindex + 1
      end while
      iindex = 0
      return
      end

"+"や"-"の付いた数字列を取り扱えるようにctoi()を拡張しておくのは、有意義なことです。拡張版は、次の通り。

c ctoi2.for -- (extended vertion 1) convert string at in(i) to integer, increment i
      integer function ctoi(in,i)
      integer*1 in(*)                   ! ARB(*)
      integer i
      integer iindex
      integer d, s
      integer*1 digits(11)
      data digits/'0','1','2','3','4','5','6','7','8','9',-2/    ! EOS(-2)

      while ((in(i) .eq. 32) .or. (in(i) .eq. 9)) do ! BLANK(32) TAB(9)
          i = i + 1
      end while

      ctoi = 0
      if (in(i) .eq. 43) then           ! PLUS(43)
          s = 1
          i = i + 1
      else if (in(i) .eq. 45) then      ! MINUS(45)
          s = -1
          i = i + 1
      else
          s = 1
      end if
      while (in(i) .ne. -2) do          ! EOS(-2)
          d = iindex(digits, in(i))
          if (d .eq. 0) then
              exit
          end if
          ctoi = ctoi * 10 + (d - 1)
          i = i + 1
      end while
      ctoi = s*ctoi
      return
      end