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プリプロセッサー -- コード生成 "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プリプロセッサー -- コード生成 "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ファイルのインクルードが必要なこととなど、 まだまだ、手を加える部分があります。これについては、次回から、必要な部分を取り出して、 説明します。

コードの改修 -- 名前付き共通領域の初期化の改善 ファイル入出力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

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

コードの改修 -- 名前付き共通領域の初期化の改善 先読み入出力バッファー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

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