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