Ratforファイルの公開2017年08月19日 10:51

Ratfor関連のファイルを公開します。 ファイルは、下記からダウンロードできます。

ratfor.zip (3,827,191Byte)

このファイルの内容は、以下の通りです。

ディレクトリー構成
\
|- Readme.txt -- このファイル
|- fortran -- WATCOM fortran 77版に関するのファイルを収めたサブディレクトリー
|    |- make -- コンパイルに関するバッチファイルを納めたサブディレクトリー
|    |    |- r4.bat -- マクロを使ってで書かれたソースをinclude->macroと前処理し
|    |    |            WATCOM fortran 77コンパイルできるソースに変換する
|    |    |- fc.bat -- WATCOM fortran 77で書かれたソースをコンパイルする
|    |    |- fo.bat -- オブジェクトファイルをライブラリーに登録する
|    |    |- fl.bat -- オブジェクトファイルをリンクする
|    |    +- alldone.bat -- 全ソースファイルをコンパイルし実行モジュールを作成する
|    |- src -- 全ソースファイルを納めたサブディレクトリー
|    |- for -- include->macro前処理後のソースファイルを納めたサブディレクトリー
|    |         WATCOM Fortran 77でコンパイルできるファイル
|    |- obj
|    |    |- *.obj -- メインプログラムのオブジェクトファイル
|    |    |- ratfor.lib -- メインプログラム以外のオブジェクトファイルを納めたライブラリー
|    |    |- ratfor.bak -- ratfor.libのバックアップ
|    |    |                オブジェクトファイルを追加・削除すると作成される
|    |    +- ratfor.lst -- ratfor.libに納められた、オブジェクトのリスト
|    +- exe -- 実行モジュールを納めたサブディレクトリー
+- ratfor -- Ratfor版に関するファイルを納めたサブディレクトリー
     |- make -- コンパイルに関するバッチファイルを納めたサブディレクトリー
     |    |- r4.bat -- Ratforで書かれたソースをinclude->macroと前処理し
     |    |            WATCOM fortran 77でコンパイルする
     |    |- fo.bat -- オブジェクトファイルをライブラリーに登録する
     |    |- fl.bat -- オブジェクトファイルをリンクする
     |    +- alldone.bat -- 全ソースファイルをコンパイルし実行モジュールを作成する
     |- src -- 全ソースファイルを納めたサブディレクトリー
     |- for -- include->macroと前処理後のソースファイルを納めたサブディレクトリー
     |         WATCOM Fortran 77でコンパイルできるファイル
     |- obj
     |    |- ratfor.lib -- メインプログラム以外のオブジェクトファイルを納めたライブラリー
     |    |- ratfor.bak -- ratfor.libのバックアップ
     |    |                オブジェクトファイルを追加・削除すると作成される
     |    +- ratfor.lst -- ratfor.libに納められた、オブジェクトのリスト
     |- exe -- 実行モジュールを納めたサブディレクトリー
     +- myproj -- サンプルプログラムを収めたディレクトリー
          |- r4.bat -- Ratforで書かれたソースをinclude->macroと前処理し
          |            WATCOM fortran 77でコンパイルする
          |- fo.bat -- オブジェクトファイルをライブラリーに登録する
          |- fl.bat -- オブジェクトファイルをリンクする
          |- hello.r4 -- サンプルプログラム(メイン)
          |- message.r4 -- サンプルプログラム(サブルーチン)
          +- mylib.lib -- サンプルサブルーチン

Ratforプレプロセッサー -- 変換の実例2017年08月16日 20:29

Ratforが動き出しましたので、実際に、Ratforデーコーディングしたコードが、 そのように、変換されるかをご紹介します。

Software Toolsで最初に紹介されている、copyはどのようになるでしょうか。 まずは、元となるRatforのコードをしめします。

# copy.r4 -- copy input characters to output
include ratfor.mac
program copy
character getc
character c

while (getc(c) != EOF)
    call putc(c)
stop
end

これを、include、macro、ratforを等した結果は、以下のようになります。

      programcopy
      integer*1getc
      integer*1c
      continue
50000 if (.not. (getc(c) .ne. -1)) goto 50001
      callputc(c)
      goto 50000
50001 continue
      stop
      end

いくつか注意すべき点があります。"programcopy"、"callputc"は、コンパイルエラーになりそうですが、 そうはなりません。それぞれ、"program copy"、"call putc"とWATCOM Fortran 77コンパイラーは、 解釈しますので、コンパイルエラーを生じません。

この程度の変換では、返還後のコードを人が解釈するには、抵抗を感じませんが、複雑になると抵抗を 感じます。たとえば、getfns.r4を見てみますと、

getfns.r4は以下の通りですが、

# getfns.r4 -- get file names into fname, check for duplicates
include ratfor.mac
subroutine getfns()
integer equal,getarg,i,j
character junk(2)
include carch

errcnt = 0
for (i = 1; i <= MAXFILES; i = i + 1)
     if (getarg(i+2,fname(1,i),NAMESIZE) == EOF)
         break
nfiles = i - 1
if (i > MAXFILES)
    if (getarg(i+2,junk,2) != EOF)
        call error('too many files.')
for (i = 1; i <= nfiles; i = i + 1)
    fstat(i) = NO
for (i = 1; i < nfiles; i = i + 1)
    for (j = i + 1; j <= nfiles; j = j + 1)
        if (equal(fname(1,i),fname(1,j)) == YES) {
            call putlin(fname(1,i),ERROUT)
            call error(': duplicate file name.')
            }
return
end

返還後はの要になります。

      subroutinegetfns()
      integerequal,getarg,i,j
      integer*1junk(2)
      common/carch/fname(81,20),fstat(20),nfiles,errcnt
      integer*1fname
      integerfstat
      integernfiles
      integererrcnt
      errcnt=0
      continue
      i=1
50000 if (.not. (i .le. 20))goto 50001
      if (.not. (getarg(i+2,fname(1,i),81) .eq. -1)) goto 50003
      goto 50001
50003 continue
50002 continue
      i=i+1
      goto 50000
50001 continue
      nfiles=i-1
      if (.not. (i .gt. 20)) goto 50005
      if (.not. (getarg(i+2,junk,2) .ne. -1)) goto 50007
      callerror(15Htoo many files.)
50007 continue
50005 continue
      continue
      i=1
50009 if (.not. (i .le. nfiles))goto 50010
      fstat(i)=0
50011 continue
      i=i+1
      goto 50009
50010 continue
      continue
      i=1
50012 if (.not. (i .lt. nfiles))goto 50013
      continue
      j=i+1
50015 if (.not. (j .le. nfiles))goto 50016
      if (.not. (equal(fname(1,i),fname(1,j)) .eq. 1)) goto 50018
      callputlin(fname(1,i),6)
      callerror(22H: duplicate file name.)
50018 continue
50017 continue
      j=j+1
      goto 50015
50016 continue
50014 continue
      i=i+1
      goto 50012
50013 continue
      return
      end

この程度になると、読む気が起きません。印刷して鉛筆でジャンプ先に印をつける必要があるようです。

コードの改修 -- ファイルのオープン(一部修正)2017年08月10日 17:07

WATCOM fortran 77版Ratforプリプロセッサが、動き出しましたので、 実際に、Ratforで書かれたツールの動作テストを行っています。やはり、例外なく、 プログラムのミスで不具合が出ていますので、これを修正しながら、Ratfor版の ツールの完成を目指しています。

基本的なファイル操作fopen()に不具合がありましたので、改修したコードを 掲載します。

改修したRatfor版のfopen()は以下の通りです。

# fopen.r4 -- connect internal file despter and external file
include ratfor.mac
integer function fopen(uid,fn,act)
integer act,uid
character fn(ARB)
[character]*MAXLINE cfn
include files

call is2cs(fn,cfn,MAXLINE)
for (uid = 1; uid <= MAXFILES; uid = uid + 1)
    if (finuse(uid) == NOUSE) {
        if (act == READ) {
            open(unit=uid,file=cfn,action='[READ]',status='[OLD]',err=99)
            uid = uid
            finuse(uid) = INUSE
            flastcr(uid) = MAXLINE
            fbuf(uid,MAXLINE) = NEWLINE
            fnew(uid) = NO
            fmode(uid) = act
            }
        else if (act == WRITE) {
            open(unit=uid,file=cfn,action='[WRITE]',status='[UNKNOWN]',err=99)
            uid = uid
            finuse(uid) = INUSE
            flastcw(uid) = 0
            fmode(uid) = act
            }
        else if (act == READWRITE) {
            open(unit=uid,file=cfn,action='[READWRITE]',status='[OLD]',err=99)
            uid = uid
            finuse(uid) = INUSE
            flastcr(uid) = MAXLINE
            flastcw(uid) = 0
            fbuf(uid,MAXLINE) = NEWLINE
            fnew(uid) = NO
            fmode(uid) = act
            }
        else {             # error
            uid = ERR
            fopen = ERR
            return
            }
        fopen = uid
        return
        }
99 continue
uid = ERR
fopen = ERR
return
end

WATCOM fotran77版のfopen()は以下の通りです。

c fopen.f -- connect internal file descripter and external file
      include ratfor.def
      integer function fopen(uid,fname,act)
      integer uid
      integer*1 act,fname(ARB)
      character*MAXLINE cfn
      include files.fi

      call is2cs(fname,cfn,MAXLINE)
      uid = 1
      while (uid .le. MAXFILES) do
          if (finuse(uid) .eq. NOUSE) then
              if (act .eq. READ) then
                  open(unit=uid,file=cfn,action='READ',
     1                 status='OLD',err=99)
                  fopen = uid
                  finuse(uid) = INUSE
                  flastcr(uid) = MAXLINE
                  fbuf(uid,MAXLINE) = NEWLINE
                  fnew(uid) = NO
                  fmode(uid) = act
              else if (act .eq. WRITE) then
                  open(unit=uid,file=cfn,action='WRITE',
     1                 status='UNKNOWN',err=99)
                  fopen = uid
                  finuse(uid) = INUSE
                  flastcw(uid) = 0
                  fmode(uid) = act
              else if (act .eq. READWRITE) then
                  open(unit=uid,file=cfn,action='READWRITE',
     1                 status='OLD',err=99)
                  fopen = uid
                  finuse(uid) = INUSE
                  flastcr(uid) = MAXLINE
                  flastcw(uid) = 0
                  fbuf(uid,MAXLINE) = NEWLINE
                  fnew(uid) = NO
                  fmode(uid) = act
              else                      ! error
                   uid = ERR
                   fopen = uid
              end if
              return
          endif
          uid = uid + 1
      end while
   99 continue
      uid = ERR
      fopen = ERR
      return
      end

これ以外にも、単純なタイプミスも含めて、多くの修正点があります。 近くに、まとめてご紹介できるよう考えています。

コードの改修 -- 名前付き共通領域の初期化の改善 マクロテーブル2017年08月01日 16:37

マクロテーブルに関する共通領域の初期化は、inittbl()で行っていましたが、 これをdata文で静的に初期化することとします。

Ratfor版のclook.riは以下の通りです。

# clook.ri
      common /clook/lastp,lastt,namptr,table
      integer lastp           # last used in namptr; init = 0
      integer lastt           # last used in table; init = 0
      integer namptr(MAXPTR)  # name pointers
      character table(MAXTBL) # actual text of names and defns
      data lastp/0/
      data lastt/0/

WATCOM fotran77版のfiles.fiは以下の通りです。

c clook.fi
      common /clook/lastp,lastt,namptr,table
      integer lastp           ! last used in namptr; init = 0
      integer lastt           ! last used in table; init = 0
      integer namptr(MAXPTR)  ! name pointers
      integer*1 table(MAXTBL) ! actual text of names and defns
      data lastp/0/
      data lastt/0/

files.ri、files.fiの変更により再コンパイルが必要になるファイルは、以下の通りです。

          instal.f
          lookup.f
          uninst.f

これらは、macroが動き出す前のファイルですので、macroを使用する版を再掲します。

instal()のRatfor版は以下の通りです。

# instal.r4 -- add name and definition to table
      subroutine instal(name,defn)
      character name(MAXTOK),defn(MAXDEF)
      integer length
      integer dlen,nlen
      include clook.ri

      nlen = length(name) + 1
      dlen = length(defn) + 1
      if (lastt+nlen+dlen > MAXTBL | lastp >= MAXPTR) {
         call putlin(name,ERROUT)
         call remark(':too many definitions.')
         }
      lastp = lastp + 1
      namptr(lastp) = lastt + 1
      call scopy(name,1,table,lastt+1)
      call scopy(defn,1,table,lastt+nlen+1)
      lastt = lastt + nlen + dlen
      return
      end

instal()のWATCOM fortran77版は以下の通りです。

c instal.f -- add name and definition to table
      include ratfor.def
      subroutine instal(name,defn)
      integer*1 name(MAXTOK),defn(MAXDEF)
      integer length
      integer dlen,nlen
      include clook.fi

      nlen = length(name) + 1
      dlen = length(defn) + 1
      if ((lastt+nlen+dlen .gt. MAXTBL) .or. (lastp .ge. MAXPTR)) then
         call putlin(name,ERROUT)
         call remark(':too many definitions.')
      end if
      lastp = lastp + 1
      namptr(lastp) = lastt + 1
      call scopy(name,1,table,lastt+1)
      call scopy(defn,1,table,lastt+nlen+1)
      lastt = lastt + nlen + dlen
      return
      end

lookup()のRatfor版は以下の通りです。

# lookup.r4 -- locate name, extract definition from table
      integer function lookup(name,defn)
      character name(MAXDEF),defn(MAXTOK)
      integer i,j,k
      include clook.fi

      for (i = lastp;i > 0; i = i - 1) {
         j = namptr(i)
         for (k = 1;name(k) == table(j) & name(k) != EOS; k = k + 1)
             j = j + 1
         if (name(k) == table(j)) {     # got one
             call scopy(table,j+1,defn,1)
             lookup = YES
             return
             }
         }
      lookup = NO
      return
      end

lookup()のWATCOM fortran77版は以下の通りです。

c lookup.f -- locate name, extract definition from table
      include ratfor.def
      integer function lookup(name,defn)
      integer*1 name(MAXDEF),defn(MAXTOK)
      integer i,j,k
      include clook.fi

      i = lastp
      while (i .gt. 0) do
         j = namptr(i)
         k = 1
         while ((name(k) .eq. table(j)) .and. (name(k) .ne. EOS)) do
             j = j + 1
             k = k + 1
         end while
         if (name(k) .eq. table(j)) then ! got one
             call scopy(table,j+1,defn,1)
             lookup = YES
             return
         end if
          i = i - 1
      end while
      lookup = NO
      return
      end

uninst()のRatfor版は以下の通りです。

# uninst.r4 -- undefine macro
      subroutine uninst(defnam)
      character defnam(MAXTOK)
      character name(MAXTOK),defn(MAXDEF)
      integer i,nlen,dlen
      integer length,equal
      include clook.fi

      lastt = 0
      for (i = 1; i <= lastp; i = i + 1) {
          call scopy(table,namptr(i),name,1)
          if (equal(defnam,name) == NO) {
              nlen = length(name) + 1
              call scopy(table,namptr(i) + nlen,defn,1)
              dlen = length(defn) + 1
              namptr(i) = lastt + 1
              call scopy(name,1,table,lastt+1)
              call scopy(defn,1,table,lastt+nlen+1)
              lastt = lastt + nlen + dlen
              }
          }
      lastp = lastp - 1
      return
      end

uninst()のWATCOM fortran77版は以下の通りです。

c uninst.f -- purge macro
      include ratfor.def
      subroutine uninst(defnam)
      integer*1 defnam(MAXTOK)
      integer*1 name(MAXTOK),defn(MAXDEF)
      integer i,nlen,dlen
      integer length,equal
      include clook.fi

      lastt = 0
      i = 1
      while (i .le. lastp) do
          call scopy(table,namptr(i),name,1)
          if (equal(defnam,name) .eq. NO) then
              nlen = length(name) + 1
              call scopy(table,namptr(i) + nlen,defn,1)
              dlen = length(defn) + 1
              namptr(i) = lastt + 1
              call scopy(name,1,table,lastt+1)
              call scopy(defn,1,table,lastt+nlen+1)
              lastt = lastt + nlen + dlen
          end if
          i = i + 1
      end while
      lastp = lastp - 1
      return
      end

また、inittbl()が不要になることで再コンパイルが必要になるファイルは、以下の通りです。

          define.f
          macro.f

実際の変更点については割愛します。

コードの改修 -- 名前付き共通領域の初期化の改善 先読み入出力バッファー2017年07月26日 09:31

先読み入出力に関する共通領域の初期化は、initbuf()で行っていましたが、 これをdata文で静的に初期化することとします。

Ratfor版のcdefio.riは以下の通りです。

# cdefio.ri
      common /cdefio/bp,buf
      integer bp              # next available character; init = 0
      character buf(BUFSIZE)  # pushed back character
      data bp/0/

WATCOM fotran77版のfiles.fiは以下の通りです。

c cdefio.fi
      common /cdefio/bp,buf
      integer bp              ! next available character; init = 0
      integer*1 buf(BUFSIZE)  ! pushed back character
      data bp/0/

files.ri、files.fiの変更により再コンパイルが必要になるファイルは、以下の通りです。

          ngetc.f
          putbak.f

これらは、macroが動き出す前のファイルですので、macroを使用する版を再掲します。

ngetc()のRatfor版は以下の通りです。

# ngetc.r4 -- get a (possibly pushed back) character
      character function ngetc( c )
      character c
      character getc
      include cdefio.ri

      if (bp > 0)
         c = buf(bp)
      else {
         bp = 1
         buf(bp) = getc(c)
         }
      if (c != EOF)
         bp = bp - 1
      ngetc = c
      return
      end

ngetc()のWATCOM fortran77版は以下の通りです。

c  ngetc.f -- get a (possibly pushed back) character
      include ratfor.def
      integer*1 function ngetc( c )
      integer*1 c
      integer*1 getc
      include cdefio.fi

      if (bp .gt. 0) then
         c = buf(bp)
      else
         bp = 1
         buf(bp) = getc(c)
      end if
      if (c .ne. EOF) then
         bp = bp - 1
      end if
      ngetc = c
      return
      end

putbak()のRatfor版は以下の通りです。

# putbak.r4 -- push character back onto input
      subroutine putbak(c)
      character c
      include cdefio.ri
      
      bp = bp + 1
      if (bp > BUFSIZE)
         call error('too many character pushed back.')
      buf(bp) = c
      return
      end

putbak()のWATCOM fortran77版は以下の通りです。

c putbak.f -- push character back onto input
      include ratfor.def
      subroutine putbak(c)
      integer*1 c
      include cdefio.fi
      
      bp = bp + 1
      if (bp .gt. BUFSIZE) then
         call putdec(bp,1)
         call putc(NEWLINE)
         call error('too many character pushed back.')
      end if
      buf(bp) = c

      return
      end

また、initbuf()が不要になることで再コンパイルが必要になるファイルは、以下の通りです。

          define.f
          macro.f

実際の変更点については割愛します。

コードの改修 -- 名前付き共通領域の初期化の改善 ファイル入出力2017年07月17日 16:48

ファイル入出力に関する共通領域の初期化は、initfile()で行っていましたが、 これをdata文で静的に初期化することとします。

Ratofr版のfiles.riは以下の通りです。

# files.ri -- file interface common valiables
      common /files/finuse,fbuf,flastcr,flastcw,fmode,fnew
      integer finuse(MAXFILES)          # inuse flag
      character fbuf(MAXFILES,MAXLINE)  # I/O buffer
      integer flastcr(MAXFILES)         # characters in read buffer
      integer flastcw(MAXFILES)         # characters in write buffer
      character fmode(MAXFILES)         # READ/WIRTE flag
      integer fnew(MAXFILES)            # NEWLINE flag
      data finuse/MAXFILES*NOUSE/
      data flastcr/MAXFILES*0/
      data flastcw/MAXFILES*MAXLINE/
      data fmode/MAXFILES*READ/
      data fnew/MAXFILES*NO/
      data finuse(STDIN)/INUSE/
      data flastcr(STDIN)/MAXLINE/
      data fmode(STDIN)/READ/
      data finuse(STDOUT)/INUSE/
      data flastcw(STDOUT)/0/
      data fmode(STDOUT)/WRITE/

WATCOM fotran77版のfiles.fiは以下の通りです。

c files.fi -- file interface common valiables
      common /files/finuse,fbuf,flastcr,flastcw,fmode,fnew
      integer finuse(MAXFILES)          ! inuse flag
      integer*1 fbuf(MAXFILES,MAXLINE)  ! I/O buffer
      integer flastcr(MAXFILES)         ! characters in read buffer
      integer flastcw(MAXFILES)         ! characters in write buffer
      integer*1 fmode(MAXFILES)         ! READ/WIRTE flag
      integer fnew(MAXFILES)            ! NEWLINE flag
      data finuse/MAXFILES*NOUSE/
      data flastcr/MAXFILES*0/
      data flastcw/MAXFILES*MAXLINE/
      data fmode/MAXFILES*READ/
      data fnew/MAXFILES*NO/
      data finuse(STDIN)/INUSE/
      data flastcr(STDIN)/MAXLINE/
      data fmode(STDIN)/READ/
      data finuse(STDOUT)/INUSE/
      data flastcw(STDOUT)/0/
      data fmode(STDOUT)/WRITE/

files.ri、files.fiの変更により再コンパイルが必要になるファイルは、以下の通りです。

          fopen.for
          fclose.for
          fgetc.for
          fputc.for

これらは、macroが動き出す前のファイルですので、macroを使用する版を再掲します。

fopen()のRatofor版は以下の通りです。

# fopen.r4 -- connect internal file descripter and external file
      include ratfor.def
      integer function fopen(uid, fn, act)
      integer uid
      character fn(ARB), act
      integer i
      character*MAXLINE cfn
      character*9 cact  # for 'READ'/'WRITE'/'READWRITE'
      include files.fi

      if (act == READ)
          cact = 'READ'
      else if (act == WRITE)
          cact = 'WRITE'
      else if (act == READWRITE)
          cact = 'READWRITE'
      else {             # error
           uid = ERR
           fopen = ERR
           return
           }
      end if
      call is2cs(fn,cfn,MAXNAME)
      for (i = 1; i <= MAXFILES; i = i + 1)
          if (finuse(i) == NOUSE) {
              open(unit=i, file=cfn, action=cact, err=99)
              finuse(i) = INUSE
              uid = i
              fopen = i
              if (act == READ) {
                  flastcr(i) = MAXLINE
                  fbuf(i,MAXLINE) = NEWLINE
                  fnew(i) = NO
                  fmode(i) = act
                  }
              else if (act .eq. WRITE) {
                  flastcw(i) = 0
                  fmode(i) = act
                  }
              else if (act .eq. READWIRTE) {
                  flastcr(i) = MAXLINE
                  flastcw(i) = 0
                  fbuf(i,MAXLINE) = NEWLINE
                  fnew(i) = NO
                  fmode(i) = act
                  }
              return
              }
   99 continue
      uid = ERR
      fopen = ERR
      return
      end

fopen()のWATCOM fortran77版は以下の通りです。

c fopen.f -- connect internal file descripter and external file
      include ratfor.def
      integer function fopen(uid, fn, act)
      integer uid
      integer*1 fn(ARB), act
      integer i
      character*MAXLINE cfn
      character*9 cact                  ! READ WRITE
      include files.fi

      if (act .eq. READ) then
          cact = 'READ'
      else if (act .eq. WRITE) then
          cact = 'WRITE'
      else if (act .eq. READWRITE) then
          cact = 'READWRITE'
      else                              ! error
           uid = ERR
           fopen = ERR
           return
      end if
      call is2cs(fn,cfn,MAXNAME)
      i = 1
      while (i .le. MAXFILES) do
          if (finuse(i) .eq. NOUSE) then
              open(unit=i, file=cfn, action=cact, err=99)
              finuse(i) = INUSE
              uid = i
              fopen = i
              if (act .eq. READ) then
                  flastcr(i) = MAXLINE
                  fbuf(i,MAXLINE) = NEWLINE
                  fnew(i) = NO
                  fmode(i) = act
              else if (act .eq. WRITE) then
                  flastcw(i) = 0
                  fmode(i) = act
              else if (act .eq. READWIRTE) then
                  flastcr(i) = MAXLINE
                  flastcw(i) = 0
                  fbuf(i,MAXLINE) = NEWLINE
                  fnew(i) = NO
                  fmode(i) = act
              end if
              return
          endif
          i = i + 1
      end while
   99 continue
      uid = ERR
      fopen = ERR
      return
      end

fclose()のRatofor版は以下の通りです。

# fclose.r4 -- disconnect internal filedescripter and extenal file
      include ratfor.def
      subroutine fclose(uid)
      integer uid
      include files.fi

      if (!(uid == STDIN) | (uid == STDOUT))) then
          if (fmode(uid) == WRITE) then
              call fputc(uid,EOF)        ! flush buffer
          end if
          close(unit=uid, status='keep')
          finuse(uid) = NOUSE
          uid = 0
      end if
      return
      end

fclose()のWATCOM fortran77版は以下の通りです。

c fclose.f-- disconnect internal filedescripter and extenal file
      include ratfor.def
      subroutine fclose(uid)
      integer uid
      include files.fi

      if (.not. ((uid .eq. STDIN) .or. (uid .eq. STDOUT))) then
          if (fmode(uid) .eq. WRITE) then
              call fputc(uid,EOF)        ! flush buffer
          end if
          close(unit=uid, status='keep')
          finuse(uid) = NOUSE
          uid = 0
      end if
      return
      end

fgetc()のRatofor版は以下の通りです。

c fgetc.f -- (extended version) get character from unit u
# fgetc.r4 -- (extended version) get character from unit u
      include ratfor.def
      character function fgetc(u,c)
      integer u
      character c
      integer i
      include files.fi

      flastcr(u) = flastcr(u) + 1
      if ((flastcr(u) > MAXLINE) | (fnew(u) == YES)) {
          read(u,10,end=9) (fbuf(u,i),i=1,MAXCARD)
   10     format(MAXCARD a1)
          flastcr(u) = 1
          fnew(u) = NO
          for (i = MAXCARD; (fbuf(u,i) == BLANK); i = i - 1)
              ;
          fbuf(u,i + 1) = NEWLINE
          }
      c = fbuf(u,flastcr(u))
      fgetc = fbuf(u,flastcr(u))
      if (c == NEWLINE)
          fnew(u) = YES
      return
    9 continue
      c = EOF
      fgetc = EOF
      return
      end

fgetc()のWATCOM fortran77版は以下の通りです。

c fgetc.f -- (extended version) get character from unit u
      include ratfor.def
      integer*1 function fgetc(u,c)
      integer u
      integer*1 c
      integer i
      include files.fi

      flastcr(u) = flastcr(u) + 1
      if ((flastcr(u) .gt. MAXLINE) .or. (fnew(u) .eq. YES)) then
          read(u,10,end=9) (fbuf(u,i),i=1,MAXCARD)
   10     format(MAXCARD a1)
          flastcr(u) = 1
          fnew(u) = NO
          i = MAXCARD
          while (fbuf(u,i) .eq. BLANK) do
              i = i - 1
          end while
          fbuf(u,i + 1) = NEWLINE
      endif
      c = fbuf(u,flastcr(u))
      fgetc = fbuf(u,flastcr(u))
      if (c .eq. NEWLINE) then
          fnew(u) = YES
      end if
      return
    9 continue
      c = EOF
      fgetc = EOF
      return
      end

fclose()のRatofor版は以下の通りです。

# fputc.r4 (extended version) -- put character on file
      include ratfor.def
      subroutine fputc(u,c)
      integer i,u
      character c
      include files.fi

      if ((c == EOF) & (flastcw(u) == 0))
          return                        ! buffer is empty, nothing to do
      if (flastcw(u) >= MAXCARD | c == NEWLINE | c == EOF) {
          write(u,10) (fbuf(u,i),i=1,flastcw(u))
   10     format(MAXCARD a1)
          flastcw(u) = 0
          }
      if (c != NEWLINE) {
          flastcw(u) = flastcw(u) + 1
          fbuf(u,flastcw(u)) = c
          }
      return
      end

fclose()のWATCOM fortran77版は以下の通りです。

c fputc.f (extended version) -- put character on file
      include ratfor.def
      subroutine fputc(u,c)
      integer i,u
      integer*1 c
      include files.fi

      if ((c .eq. EOF) .and. (flastcw(u) .eq. 0)) then
          return                        ! buffer is empty, nothing to do
      end if
      if (flastcw(u) .ge. MAXCARD .or. c .eq. NEWLINE .or. c .eq. EOF) then
          write(u,10) (fbuf(u,i),i=1,flastcw(u))
   10     format(MAXCARD a1)
          flastcw(u) = 0
      end if
      if (c .ne. NEWLINE) then
          flastcw(u) = flastcw(u) + 1
          fbuf(u,flastcw(u)) = c
      end if
      return
      end

また、initfile()が不要になることで修正・再コンパイルが必要になるファイルは、 以下の通りです。

          archive.for
          change.for
          compare2.for
          concat.for
          copy.for
          copyfile.for
          define.f
          edit.f
          find.for
          include.for
          macro.f
          makecopy.for
          ratfor.f
          sort.for
          typex.for
          unique.for
          xformat.f
          xprint.for

実際の変更点については割愛します。

Ratforプリプロセッサー -- コード生成 "string"2017年07月10日 21:00

stringは、文字列定数を格納するinteger*1型の配列を生成する部分と、 配列に文字を割り当てるdata文を生成する部分があるます。配列の大きさは、 格納する文字列の長さとEOSを格納する分が必要です。

          string name "data"
は、
          integer*1 name(5)
          data name(1)/100/
          data name(2)/97/
          data name(3)/116/
          data name(4)/97/
          data name(5)/-2/
          
となります。また、文字列には、空白を含め特殊文字が含まれていてもよく、
          string specs "!#$%&'( )=-"
は、
      integer*1 specs(12)
      data specs(1)/33/
      data specs(2)/35/
      data specs(3)/36/
      data specs(4)/37/
      data specs(5)/38/
      data specs(6)/39/
      data specs(7)/40/
      data specs(8)/32/
      data specs(9)/41/
      data specs(10)/61/
      data specs(11)/45/
      data specs(12)/-2/
のように、コードが生成されます。さらには、文字列をくくるのは"でも'でもよく、
          string str1 'ab"cd'
"を含んだ文字左列は下記のように
      integer*1 str1(6)
      data str1(1)/97/
      data str1(2)/98/
      data str1(3)/34/
      data str1(4)/99/
      data str1(5)/100/
      data str1(6)/-2/
となります。

strngc()のRatofor版は以下の通り。

# strngc.r4 -- generate string data
      include ratfor.def
      subroutine strngc
      character ngetc,name(MAXTOK),strng(MAXLINE)
      integer c,i,l,length,n
      string intstr "integer*1 "
      string datstr "data "

      junk = lex(name)
      for (strng(1) = ngetc(strng(1)); strng(1) == BLANK); strng(1) = ngetc(strng(1))
          ;
      if (strng(1) != DQUOTE & strng(1) != SQUOTE)
          call synerr('missing quort.')
      i = 2
      for (strng(i) = ngetc(strng(i)); strng(1) != strng(i)); strng(i) = ngetc(strng(i)) {
           if (i >= MAXLINE) {
               call synerr('string data too long.')
               break
               }
           else if (strng(i) == NEWLINE) {
               call synerr('Unexpected NEWLINE.')
               break
               }
           else if (strng(i) == EOF) {
               call synerr('Unexpected EOF.')
               exit
               }
           i = i + 1
           }
      if (i >= MAXLINE)
          strng(MAXLINE) = EOS
      else
          strng(i+1) = EOS
      l = length(strng)
      call outtab
      call outstr(intstr)
      call outstr(name)
      call outch(LPAREN)
      call outnum(l-1)
      call outch(RPAREN)
      call outdon
      i = 1
      for (c = 2; c < l; c = c + 1) {
          call outtab
          call outstr(datstr)
          call outstr(name)
          call outch(LPAREN)
          call outnum(i)
          call outch(RPAREN)
          call outch(SLASH)
          n = strng(c)
          call outnum(n)
          call outch(SLASH)
          call outdon
          i = i + 1
          }
      call outtab
      call outstr(datstr)
      call outstr(name)
      call outch(LPAREN)
      call outnum(i)
      call outch(RPAREN)
      call outch(SLASH)
      call outnum(EOS)
      call outch(SLASH)
      call outdon
      return
      end

WATCOM Fortran77版は以下の通り。

c strngc.f -- generate string data
      include ratfor.def
      subroutine strngc
      integer*1 ngetc,name(MAXTOK),strng(MAXLINE)
      integer c,i,l,length,n
      integer*1 intstr(11)
      data intstr(1)/LETi/
      data intstr(2)/LETn/
      data intstr(3)/LETt/
      data intstr(4)/LETe/
      data intstr(5)/LETg/
      data intstr(6)/LETe/
      data intstr(7)/LETr/
      data intstr(8)/STAR/
      data intstr(9)/LET1/
      data intstr(10)/BLANK/
      data intstr(11)/EOS/
      integer*1 datstr(6)
      data datstr(1)/LETd/
      data datstr(2)/LETa/
      data datstr(3)/LETt/
      data datstr(4)/LETa/
      data datstr(5)/BLANK/
      data datstr(6)/EOS/

      junk = lex(name)
      strng(1) = ngetc(strng(1))
      while (strng(1) .eq. BLANK) do
          strng(1) = ngetc(strng(1))
      end while
      if (strng(1) .ne. DQUOTE .and. strng(1) .ne. SQUOTE) then
          call synerr('missing quort.')
      end if
      i = 2
      strng(i) = ngetc(strng(i))
      while (strng(1) .ne. strng(i)) do
           if (i .ge. MAXLINE) then
               call synerr('string data too long.')
               exit
           else if (strng(i) .eq. NEWLINE) then
               call synerr('Unexpected NEWLINE.')
               exit
           else if (strng(i) .eq. EOF) then
               call synerr('Unexpected EOF.')
               exit
           end if
           i = i + 1
           strng(i) = ngetc(strng(i))
      end while
      if (i .ge. MAXLINE) then
          strng(MAXLINE) = EOS
      else
          strng(i+1) = EOS
      end if
      l = length(strng)
      call outtab
      call outstr(intstr)
      call outstr(name)
      call outch(LPAREN)
      call outnum(l-1)
      call outch(RPAREN)
      call outdon
      i = 1
      c = 2
      while (c .lt. l) do
          call outtab
          call outstr(datstr)
          call outstr(name)
          call outch(LPAREN)
          call outnum(i)
          call outch(RPAREN)
          call outch(SLASH)
          n = strng(c)
          call outnum(n)
          call outch(SLASH)
          call outdon
          i = i + 1
          c = c + 1
      end while
      call outtab
      call outstr(datstr)
      call outstr(name)
      call outch(LPAREN)
      call outnum(i)
      call outch(RPAREN)
      call outch(SLASH)
      call outnum(EOS)
      call outch(SLASH)
      call outdon
      return
      end

これで、Ratforプリプロセッサの作成は完了しました。Ratforも含めた、展開処理用の バッチプログラムを以下に示します。

          @echo off
          rem fimr.bat
          cd ..\src
          ..\exe\include < %1.f | ..\exe\macro | ..\exe\ratfor > %1.for
          cd ..\bat

ソフトウェア作法に記載されている、RatforコードをWATCOM-fortran77に ポーティングする作業は、ひとまず終わりとします。ただし、実際にポーティングの課程 で作成したコードは、そのままの状態で、完成したRatforに通すことは、 できません。ratfor.defファイルのインクルードが必要なこととなど、 まだまだ、手を加える部分があります。これについては、次回から、必要な部分を取り出して、 説明します。

Ratforプリプロセッサー -- コード生成 "repeat -- until"2017年07月07日 16:27

repeat文にであったら、ラベルL、L+1、L+2を作りだし、

          continue
        L continue
をrepcod()で出力します。そして、repeatの終わりに達したら、
      L+1 continue
          goto L
      L+2 continue
をrepats()で出力します。また、repeatの終わりに、untilがあったならば、repats()は、 条件を取り出し、
      L+1 continue
          if (.not. ( 条件 )) goto L
      L+2 continue
を出力します。ここで、L+1はnextの飛び先に、L+2はbreakの飛び先になります。

repcod()のRatofor版は以下の通り。

# repcod.r4 -- generate initial code for repeat
      subroutine repcod(lab)
      integer lab
      integer labgen

      lab = labgen(3)
      call outcon(0)
      call outcon(lab)
      return
      end

WATCOM Fortran77版は以下の通り。

c repcod.f -- generate initial code for repeat
      subroutine repcod(lab)
      integer lab
      integer labgen

      lab = labgen(3)
      call outcon(0)
      call outcon(lab)
      return
      end

repats()のRatofor版は以下の通り。

# repats.r4 -- generate end code for repeat
      include ratfor.def
      subroutine repats(lab)
      integer lab

      token = lex(lexstr) # peek at next token
      if (token == LEXUNTIL) then
          call outcon(lab + 1)
          call outtab
          call ifnot
          call balpar
          call outch(RPAREN)
          call outch(BLANK)
          call outgo(lab)
          call outcon(lab + 2)
      else
          call pbstr(lexstr)
          call outcon(lab + 1)
          call outtab
          call outgo(lab)
          call outcon(lab + 2)
      end if
      return
      end

WATCOM Fortran77版は以下の通り。

c repats.f -- generate end code for repeat
      include ratfor.def
      subroutine repats(lab)
      integer lab

      token = lex(lexstr)               ! peek at next token
      if (token .eq. LEXUNTIL) then
          call outcon(lab + 1)
          call outtab
          call ifnot
          call balpar
          call outch(RPAREN)
          call outch(BLANK)
          call outgo(lab)
          call outcon(lab + 2)
      else
          call pbstr(lexstr)
          call outcon(lab + 1)
          call outtab
          call outgo(lab)
          call outcon(lab + 2)
      end if
      return
      end

Ratforプリプロセッサー -- コード生成 "for"2017年07月01日 17:11

for文にであったら、初期設定・終了条件・再設定を取り出して、再設定は再設定用スタックに積み、 ラベルL、L+1、L+2を作りだし、

          continue
          初期設定
        L if ( .not. (終了条件)) goto L+2
を出力します。そして、forの終わりに達したら、
      L+1 continue
          再設定
          goto L
      L+2 continue
を出力します。ここで、ラベルL+2は、breakに出会ったときの行き先になります。また、ラベルL+1は、 nextに出会った時の行き先になります。具体的には、forcod()でfor文のはじめを生成します。

forcod()のRatofor版は以下の通り。

# forcod.r4 -- generate code for beginning of for
      include ratfor.def
      subroutine forcod(lab)
      integer lab
      character t,token(MAXTOK)

      lab = labgen(3)
      call outcon(0)
      t = gtoken(token,MAXTOK)
      if (token(1) != LPAREN) {
          call outstr(token)
          call eatup
          call synerr('missing left parenthesis.')
          }
      else {
          call forini
          call forcnd(lab)
          call forrei
          }
      return
      end

WATCOM Fortran77版は以下の通り。

c forcod.f -- generate code for beginning of for
      include ratfor.def
      subroutine forcod(lab)
      integer lab
      integer*1 t,token(MAXTOK)

      lab = labgen(3)
      call outcon(0)
      t = gtoken(token,MAXTOK)
      if (token(1) .ne. LPAREN) then
          call outstr(token)
          call eatup
          call synerr('missing left parenthesis.')
      else
          call forini
          call forcnd(lab)
          call forrei
      end if
      return
      end

ここで、forini()は初期設定を取り出しコードを生成し、 同様にforcnd()は終了条件を取り出し必要なコードを生成し、さらに、 forrei()は再設定を取り出しコードを生成します。

forini()のRatofor版は以下の通り。

# forini.r4 -- generate code for initialize
      include ratfor.def
      subroutine forini
      character gtoken,stmnt(MAXLINE),t,token(MAXTOK)
      integer junk,sappnd

      stmnt(1) = EOS
      for (t = gtoken(token,MAXTOK);t != SEMICOL & t != EOF;t = gtoken(token,MAXTOK))
          junk = sappnd(token,stmnt,MAXTOK)
      if (stmnt(1) != EOS) {
          call outtab
          call outstr(stmnt)
          call outdon
          }
      if (t != EOF)
          call synerr('unexpected EOF.')
      return
      end

WATCOM Fortran77版は以下の通り。

c forini.f -- generate code for beginning of for
      include ratfor.def
      subroutine forini
      integer*1 gtoken,stmnt(MAXLINE),t,token(MAXTOK)
      integer junk,sappnd

      stmnt(1) = EOS
      t = gtoken(token,MAXTOK)
      while ((t .ne. SEMICOL) .and. (t .ne. EOF)) do
          junk = sappnd(token,stmnt,MAXTOK)
          t = gtoken(token,MAXTOK)
      end while
      if (stmnt(1) .ne. EOS) then
          call outtab
          call outstr(stmnt)
          call outdon
      end if
      if (t .eq. EOF) then
          call synerr('unexpected EOF.')
      end if
      return
      end

ここで、sappnd()は、文字バッファーがあふれないように確認しながら、文字列を追加します。

sappnd()のRatofor版は以下の通り。

# sappnd.r4 -- append str to body
      include ratfor.def
      integer function sappnd(str,body,maxsiz)
      character str(ARB),body(maxsiz)
      integer maxsiz
      integer i,j,length

      i = 1
      j = length(body) + 1
      sappnd = YES
      while (str(i) != EOS) {
          if (j >= maxsiz) then
              sappnd = NO
              exit
          end if
          body(j) = str(i)
          i = i + 1
          j = j + 1
          }
      body(j) = EOS
      return
      end

WATCOM Fortran77版は以下の通り。

c sappnd.f -- append str to body
      include ratfor.def
      integer function sappnd(str,body,maxsiz)
      integer*1 str(ARB),body(maxsiz)
      integer maxsiz
      integer i,j,length

      i = 1
      j = length(body) + 1
      sappnd = YES
      while (str(i) .ne. EOS) do
          if (j .ge. maxsiz) then
              sappnd = NO
              exit
          end if
          body(j) = str(i)
          i = i + 1
          j = j + 1
      end while
      body(j) = EOS
      return
      end

outdon()は、生成しているコードを実際に出力先に書き出します。

outdon()のRatofor版は以下の通り。

# outdon.r4 -- finish off an output line
      include ratfor.def
      subroutine outdon

      include coutln.ri

      outbuf(outp+1) = NEWLINE
      outbuf(outp+2) = EOS
      call putlin(outbuf,STDOUT)
      outp = 0
      return
      end

WATCOM Fortran77版は以下の通り。

c outdon.f -- finish off an output line
      include ratfor.def
      subroutine outdon

      include coutln.fi

      outbuf(outp+1) = NEWLINE
      outbuf(outp+2) = EOS
      call putlin(outbuf,STDOUT)
      outp = 0
      return
      end

forcnd()のRatofor版は以下の通り。

# forcnd.r4 -- get condition statementr of for
      include ratfor.def
      subroutine forcnd(lab)
      integer lab
      character gtoken,opstr(MAXTOK),stmnt(MAXTOK),t,token(MAXTOK)

      stmnt(1) = EOS
      for (t = gtoken(token,MAXTOK);t != EOF & t != SEMICOL;t = gtoken(token,MAXTOK))
          if (islgop(token(1)) != YES) {
              call cnvop(token,opstr)
              junk = sappnd(opstr,stmnt,MAXTOK)
              }
          else
              junk = sappnd(token,stmnt,MAXTOK)
      if (stmnt(1) == EOS)
          call outcon(lab)
      else {
          call outnum(lab)
          call outtab
          call ifnot(stmnt,lab + 1)
          }
      if (t == EOF)
          call synerr('unexpected EOF.')
      return
      end

WATCOM Fortran77版は以下の通り。

c forcnd.f -- get condition statementr of for
      include ratfor.def
      subroutine forcnd(lab)
      integer lab
      integer*1 gtoken,opstr(MAXTOK),stmnt(MAXTOK),t,token(MAXTOK)

      stmnt(1) = EOS
      t = gtoken(token,MAXTOK)
      while ((t .ne. EOF) .and. (t .ne. SEMICOL)) do
          if (islgop(token(1)) .eq. YES) then
              call cnvop(token,opstr)
              junk = sappnd(opstr,stmnt,MAXTOK)
          else
              junk = sappnd(token,stmnt,MAXTOK)
          end if
          t = gtoken(token,MAXTOK)
      end while
      if (stmnt(1) .eq. EOS) then
          call outcon(lab)
      else
          call outnum(lab)
          call outtab
          call ifnot(stmnt,lab + 1)
      end if
      if (t .eq. EOF) then
          call synerr('unexpected EOF.')
      end if
      return
      end

ここで、islgop()は、tokenが論理演算子かどうかを判断します。

islgop()のRatofor版は以下の通り。

# islgop.r4 -- if c is operatr then return YES
      include ratfor.def
      integer function islgop(c)
      integer*1 c
      integer iindex
      integer*1 opcode(7)
      data opcode(1)/OPEQUAL/
      data opcode(2)/OPGTHAN/
      data opcode(3)/OPLTHAN/
      data opcode(4)/OPNOT/
      data opcode(5)/OPAND/
      data opcode(6)/OPOR/
      data opcode(7)/EOS/

      islgop = NO
      if (iindex(opcode,c) > 0)
          islgop = YES
      return
      end

WATCOM Fortran77版は以下の通り。

c islgop.f -- if c is operatr then return YES
      include ratfor.def
      integer function islgop(c)
      integer*1 c
      integer iindex
      integer*1 opcode(7)
      data opcode(1)/OPEQUAL/
      data opcode(2)/OPGTHAN/
      data opcode(3)/OPLTHAN/
      data opcode(4)/OPNOT/
      data opcode(5)/OPAND/
      data opcode(6)/OPOR/
      data opcode(7)/EOS/

      islgop = NO
      if (iindex(opcode,c) .gt. 0) then
          islgop = YES
      end if
      return
      end

forrei()のRatofor版は以下の通り。

# forrei.r4 -- save reinitialize statement of for
      include ratfor.def
      subroutine forrei
      character sappnd,stmnt(MAXTOK),t,token(MAXTOK)
      integer junk,nlpar

      nlpar = 0
      stmnt(1) = EOS
      for (t = gtoken(token,MAXTOK);token(1) != EOF;t = gtoken(token,MAXTOK)) {
          if (nlpar == 0 & token(1) == RPAREN)
              exit
          junk = sappnd(token,stmnt,MAXTOK)
          if (token(1) == LPAREN)
              nlpar = nlpar + 1
          else if (token(1) == RPAREN)
              nlpar = nlpar - 1
          }
      call cspush(stmnt)
      return
      end

WATCOM Fortran77版は以下の通り。

c forrei.f -- save reinitialize statement of for
      include ratfor.def
      subroutine forrei
      integer*1 sappnd,stmnt(MAXTOK),t,token(MAXTOK)
      integer junk,nlpar

      nlpar = 0
      stmnt(1) = EOS
      t = gtoken(token,MAXTOK)
      while (token(1) .ne. EOF) do
          if (nlpar .eq. 0 .and. token(1) .eq. RPAREN) then
              exit
          end if
          junk = sappnd(token,stmnt,MAXTOK)
          if (token(1) .eq. LPAREN) then
              nlpar = nlpar + 1
          else if (token(1) .eq. RPAREN) then
              nlpar = nlpar - 1
          end if
          t = gtoken(token,MAXTOK)
      end while
      call cspush(stmnt)
      return
      end

cspush()は、再設定用スタックに、再設定を積みます。

cspush()のRatofor版は以下の通り。

# cspush.r4 -- push statment into code stack
      include ratfor.def
      subroutine cspush(stmnt)
      character stmnt(MAXTOK)
      integer length
      include cstack.ri
      
      cscnt = cscnt + 1
      if (cscnt > MAXTOK) then
          call error('Code stack overflow.')
      end if
      cslast = cslast + 1
      csstat(cscnt) = cslast
      call scopy(stmnt,1,csstck,cslast)
      cslast = cslast + length(stmnt) + 1
      return
      end

WATCOM Fortran77版は以下の通り。

c cspush.f -- push statment into code stack
      include ratfor.def
      subroutine cspush(stmnt)
      integer*1 stmnt(MAXTOK)
      integer length
      include cstack.fi
      
      cscnt = cscnt + 1
      if (cscnt .gt. MAXTOK) then
          call error('Code stack overflow.')
      end if
      cslast = cslast + 1
      csstat(cscnt) = cslast
      call scopy(stmnt,1,csstck,cslast)
      cslast = cslast + length(stmnt) + 1
      return
      end

再設定用スタックは、実際には、配列で表現されています。

cstackのRatofor版は以下の通り。

# cstack.ri -- code stack
      common /cstack/csstat,cscnt,cslast,csstck
      integer csstat(MAXTOK)            ! code pointer
      integer cscnt                     ! number of statments in stack; init = 0
      integer cslast                    ! last cstack filled; init = 0
      character csstck(MAXSTACK)        ! code stack
      data cscnt/0/
      data cslast/0/

WATCOM Fortran77版は以下の通り。

c cstack.fi -- code stack
      common /cstack/csstat,cscnt,cslast,csstck
      integer csstat(MAXTOK)            ! code pointer
      integer cscnt                     ! number of statments in stack; init = 0
      integer cslast                    ! last cstack filled; init = 0
      integer*1 csstck(MAXSTACK)        ! code stack
      data cscnt/0/
      data cslast/0/

forの終わりは、cspop()で再設定をスタックから取り出し、forsta()でコードを生成します。

forsta()のRatofor版は以下の通り。

# forsta.r4 -- generate code for end of for
      include ratfor.def
      subroutine forsta(lab)
      integer lab
      character stmnt(MAXTOK)

      call cspop(stmnt)
      if (stmnt(1) == EOS) {
          call outcon(lab + 2)
          call outtab
          call outgo(lab)
          call outcon(lab + 1)
          }
      else {
          call outcon(lab + 2)
          call outtab
          call outstr(stmnt)
          call outdon
          call outgo(lab)
          call outcon(lab + 1)
          }
      return
      end

WATCOM Fortran77版は以下の通り。

c forsta.f -- generate code for end of for
      include ratfor.def
      subroutine forsta(lab)
      integer lab
      integer*1 stmnt(MAXTOK)

      call cspop(stmnt)
      if (stmnt(1) .eq. EOS) then
          call outcon(lab + 2)
          call outtab
          call outgo(lab)
          call outcon(lab + 1)
      else
          call outcon(lab + 2)
          call outtab
          call outstr(stmnt)
          call outdon
          call outgo(lab)
          call outcon(lab + 1)
      end if
      return
      end

cspop()のRatofor版は以下の通り。

# cspop.r4 -- pop statment into code stack
      include ratfor.def
      subroutine cspop(stmnt)
      character stmnt(MAXTOK)
      integer length
      integer p
      include cstack.fi
      
      if (cscnt <= 0)
          call error('Code stack underflow.')
      p = csstat(cscnt)
      call scopy(csstck(p),1,stmnt,1)
      cscnt = cscnt - 1
      cslast = cslast - length(stmnt) - 1
      return
      end

WATCOM Fortran77版は以下の通り。

c cspop.f -- pop statment into code stack
      include ratfor.def
      subroutine cspop(stmnt)
      integer*1 stmnt(MAXTOK)
      integer length
      integer p
      include cstack.fi
      
      if (cscnt .le. 0) then
          call error('Code stack underflow.')
      end if
      p = csstat(cscnt)
      call scopy(csstck(p),1,stmnt,1)
      cscnt = cscnt - 1
      cslast = cslast - length(stmnt) - 1
      return
      end

Ratforプリプロセッサー -- コード生成 "while"2017年06月24日 18:26

while文にであったら、whileの条件を取り出して、ラベルL、L+1を 作りだし、

          continue
        L if ( .not. (条件)) goto L+1
を出力します。そして、whileの終わりに達したら、
          goto L
      L+1 continue
を出力します。ここで、ラベルL+1は、breakに出会ったときの行き先になります。また、ラベルLは、 nextに出会った時の行き先になります。 具体的には、whilec()でwhile文のはじめを生成します。

whilec()のRatofor版は以下の通り。

# whilec.r4 -- generate code for beginning of while
      subroutine whilec(lab)
      integer lab

      call outcon(0)
      lab = labgen(2)
      call outnum(lab)
      call ifgo(lab+1)
      return
      end

WATCOM Fortran77版は以下の通り。

c whilec.f -- generate code for beginning of while
      subroutine whilec(lab)
      integer lab

      call outcon(0)
      lab = labgen(2)
      call outnum(lab)
      call ifgo(lab+1)
      return
      end

whileの終わりは、whiles()でコードを生成します。

whiles()のRatofor版は以下の通り。

# whiles.r4 -- generate code for end of while
      subroutine whiles(lab)
      integer lab

      call outgo(lab)
      call outcon(lab+1)
      return
      end

WATCOM Fortran77版は以下の通り。

c whiles.f -- generate code for end of while
      subroutine whiles(lab)
      integer lab

      call outgo(lab)
      call outcon(lab+1)
      return
      end