Ratforプリプロセッサー -- 字句解析2017年05月13日 15:55

Ratforで書かれたプログラムからtokenを切り出すのは、defineやmacroと同様であるが、 引用符の通り扱いに注意が必要である。引用符は、ほとんどの場合ペアで使われ、その間に NEWLINEが入ることはない。この点に配慮する必要がある。

Ratofor版は以下の通り。

# gtoken.f -- get token for ratfor
      include ratfor.def
      character function gtoken(lexstr,toksiz)
      integer toksiz
      character lexstr(toksiz)
      character ngetc,type
      integer i
      character c

      include cline.ri

      while (ngetc(c) != EOF)
          if ((c != BLANK) & (c != TAB))
              break
      call putbak(c)
      for(i = 1;i < toksiz-1;i = i +1) {
          gtoken = type(ngetc(lexstr(i)))
          if ((gtoken != LETTER) & (gtoken != DIGIT))
              break
          }
      if (i >= toksiz-1)
          call synerr('token too long.')
      if (i > 1)
          call putbak(lexstr(i))
          lexstr(i) = EOS
          gtoken = ALPHA
      else if ((lexstr(1) == SQUOTE) | (lexstr(1) == DQUOTE))
          for (i = 2;ngetc(lexstr(i)) != lexstr(1)) {
              if (lexstr(i) == NEWLINE) {
                  call synerr('missing quote.')
                  lexstr(i) = lexstr(1)
                  call putbak(NEWLINE)
                  break
                  }
              }
      else if (lexstr(1) == SHARP) { # strip comments
          while (ngetc(lexstr(1)) != NEWLINE)
              ;
          gtoken = NEWLINE
          }
      lexstr(i+1) = EOS
      if (lexstr(1) == NEWLINE)
          linect = linect + 1
      return
      end

WATCOM Fortran77版は以下の通り。

c gtoken.f -- get token for ratfor
      include ratfor.def
      integer*1 function gtoken(lexstr,toksiz)
      integer toksiz
      integer*1 lexstr(toksiz)
      integer*1 ngetc,type
      integer i
      integer*1 c

      include cline.fi

      while (ngetc(c) .ne. EOF) do
          if ((c .ne. BLANK) .and. (c .ne. TAB)) then
              exit
          end if
      end while
      call putbak(c)
      i = 1
      while (i .lt. toksiz-1) do
          gtoken = type(ngetc(lexstr(i)))
          if ((gtoken .ne. LETTER) .and. (gtoken .ne. DIGIT)) then
              exit
          end if
          i = i + 1
      end while
      if (i .ge. toksiz-1) then
          call synerr('token too long.')
      end if
      if (i .gt. 1) then
          call putbak(lexstr(i))
          lexstr(i) = EOS
          gtoken = ALPHA
      else if (lexstr(1) .eq. SQUOTE .or. lexstr(1) .eq. DQUOTE) then
          i = 2
          while (ngetc(lexstr(i)) .ne. lexstr(1)) do
              if (lexstr(i) .eq. NEWLINE) then
                  call synerr('missing quote.')
                  lexstr(i) = lexstr(1)
                  call putbak(NEWLINE)
                  exit
              end if
              i = i + 1
          end while
      else if (lexstr(1) .eq. SHARP) then ! strip comments
          while (ngetc(lexstr(1)) .ne. NEWLINE) do
              ! nothing to do
          end while
          gtoken = NEWLINE
      end if
      lexstr(i+1) = EOS
      if (lexstr(1) .eq. NEWLINE) then
          linect = linect + 1
      end if
      return
      end

gtoken()の下請けルーチンsynerr()はsyntax errorを出力する。errorは、行番号とともに出力されるが、 行番号linectは、必要なモジュールで共有できるように、共通領域clineにおいている。

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

# synerr -- report Ratfor syntax error
      include ratfor.def
      subroutine synerr(msg)
      character msg(MAXLINE)
      character lc(MAXLINE)
      integer itoc
      integer junk

      include cline.ri

      call remark('error at line.')
      junk = itoc(linect,lc,MAXLINE)
      call putlin(lc,ERROUT)
      call fputc(ERROUT,COLON)
      call remark(msg)
      return
      end

WATCOM Fortran77版は以下の通り。

c synerr -- report Ratfor syntax error
      include ratfor.def
      subroutine synerr(msg)
      character msg(MAXLINE)
      integer*1 lc(MAXLINE)
      integer itoc
      integer junk

      include cline.fi

      call remark('error at line.')
      junk = itoc(linect,lc,MAXLINE)
      call putlin(lc,ERROUT)
      call fputc(ERROUT,BLANK)
      call remark(msg)
      return
      end

clineのRatofor版は以下の通り。

# cline.ri
      common /cline/linect
      integer linect
      data linect/1/

WATCOM Fortran77版は以下の通り。

c cline.fi
      common /cline/linect
      integer linect
      data linect/1/

gtoken()で切り出されたtokenは、次のlex()に引き継がれ解析される。 ここでも字句の判定に、lookup()を使用する。

lex()のRatfor版は以下の通り。

# lex.r4- return lexical type of token
      include ratfor.def
      character function lex(lexstr)
      character lexstr(MAXTOK)
      character gtoken
      integer alldig,lookup
      character ltype(2)

      while (gtoken(lexstr,MAXTOK) == NEWLINE)
          ;
      lex = lexstr(1)
      if (lex == EOF | lex == SEMICOL | lex == LBRACE | lex == RBRACE))
          return
      if (alldig(lexstr)==YES)
          lex = LEXDIGITS
      else if(lookup(lexstr,ltype) == YES)
          lex = ltype(1)
      else
          lex = LEXOTHER
      return
      end

WATCOM Fortran77版は以下の通り。

c lex.f- return lexical type of token
      include ratfor.def
      integer function lex(lexstr)
      integer*1 lexstr(MAXTOK)
      integer*1 gtoken
      integer alldig,lookup
      integer*1 ltype(2)

      while (gtoken(lexstr,MAXTOK) .eq. NEWLINE) do
          ! nothing to do
      end while
      lex = lexstr(1)
      if ((lex .eq. EOF) .or. (lex .eq. SEMICOL) .or.
     1    (lex .eq. LBRACE) .or. (lex .eq. RBRACE)) then
          return
      end if
      if (alldig(lexstr)) then
          lex = LEXDIGITS
      else if(lookup(lexstr,ltype) .eq. YES) then
          lex = ltype(1)
      else
          lex = LEXOTHER
      end if
      return
      end

lex()の下請けルーチンalldig()は、tokenが数字列か否かを判定する。

alldig()のRatfor版は以下の通り。

# alldig.r4 -- return YES if str is all digis
      include ratfor.def
      integer function alldig(s)
      character s(ARB)
      character type
      character i

      alldig = NO
      if (s(1) == EOS)
          return
      for (i = 1; s(i) != EOS; i = i +1)
          if (type(s(i)) != DIGIT)
              return
      alldig = YES
      return
      end

WATCOM Fortran77版は以下の通り。

c alldig -- return YES if str is all digis
      include ratfor.def
      integer function alldig(s)
      integer*1 s(ARB)
      integer*1 type
      integer i

      alldig = NO
      if (s(1) .eq. EOS) then
          return
      end if
      i = 1
      while (s(i) .ne. EOS) do
          if (type(s(i)) .ne. DIGIT) then
              return
          end if
          i = i + 1
      end while
      alldig = YES
      return
      end

OS/2 Warp Server for e-businessの立ち上げ2017年05月22日 17:48

長いこと眠らせておいたPCに、OS/2 Warp Server for e-businessのセットアップをしました。 H/Wの不具合やら勘違いなどで、結構時間がかかりました。最終的に家庭内超私的FTPサーバーとして、 動いています。

最終的なH/W構成は、以下の通り。いずれもこの10年間に入手したものばかりです。

  • Mother Board: AOpen i855GMEm-LFS
  • CPU: Intel Pentiumn M 2GHz
  • Memry: 2GB
  • Storages
    • E-IDE Primary
      • Master: Seagate製 30GB
      • Slave: Seagate製 40GB
    • E-IDE Secondary
      • Master: LG製 GSA-H44N DVDRAM Drive
      • Slave: (空き)
  • Removable Media: 3.5Inch 2HD FDD
  • Display Adpter: nVIDIA RIVA128 (RAM:4MB)
  • Network: RealTek RTL8139 Ethernet Adapter
  • Sound: (なし)
  • Printer: (なし)

当初、DVDRAM DriveをSlaveに設定していたところ、 不可解な現象に悩まされました(詳細は後述)。

OS/2のインストールは、このバージョンからCD-ROMから起動できるように なりましたので、早速、"インストール"CD-ROMをDVDRAMドライブに入れて 電源を入れると、一見順調に起動するのですが、指示に従いCD-ROMを"ServerPak"に入れ替えて 動き出すと、エラーメッセージを表示しインストールプロセスが停止してしまいます。

原因をつかみたくても、皆目訳がわからない状態なので、インストール用ディスケット 3枚を 作って従来通りのインストール手順を踏むことにしました。 ついでに、IDEDASDをVer.5.02に置き換えて、"Config.sys"を書き換えました。

IDEDASDの置き換え手順は下記のとおりです。

  1. IDEDASD.EXEを適当なディレクトリーに展開。
  2. インストール用ディスケット 1のコピーを作成。(D1)
  3. D1から"README.INS"を削除。
  4. 展開したIDEDASDのファイルから、"IBM1S506.ADD"と"IBMIDECD.FLT"をD1にコピー。
  5. "DASD32.DMD"を"OS2DASD.DMD"としてD1にコピー。
  6. D1にある"Config.sys"を編集。
    • 第一行目に"SET COPYFROMFLOPPY=1"を追加。
    • 動作確認のため、"IBM1S506.ADD"に"/V"オプションを追加しロード時にメッセージを表示。
                SET COPYFROMFLOPPY=1
                          :
                basedev=ibm1s506.add /V
                          :
      

このインストール用ディスケットを使って導入を開始します。

導入開始時点では、すべてのデバイスドライバは、ディスケットから読み取られます。 "IBM1S506.ADD"がロードされた時点で表示されるメッセージを確認すると、 正常にHDDやDVDRAMドライブが検出されていることが確認できました。

一度目のリブート後作業を進めようとすると、CD-ROMを入れるようメッセージが表示されました。 不思議に思い、再度、リブートして"IBM1S506.ADD"のメッセージを確認すると、 DVDRAMドライブを今度は検出しました。しかし、作業を進めリブートを繰り返していくと、 DVDRAMドライブを検出しないことが多々見受けられました。

"IBM1S506.ADD"以外にもSCSI用デバイスドライバがロードされますが、これらがH/Wの 誤検出をしてるのかと考え、"Config.sys"のSCSI用デバイスドライバをロードする部分をREM化して みましたが、状況は変わりません。

"Config.sys"の変更点は以下の通りです。

                    :
          REM basedev=aha152x.add
          REM basedev=aha154x.add
          REM basedev=aha164x.add
          REM basedev=aha174x.add
          REM basedev=aic7770.add
          REM basedev=aic7870.add
          REM basedev=aic78u2.add
          REM basedev=dpt20xx.add
          REM basedev=flashpt.add
          REM basedev=ql10os2.add
          REM basedev=ql40os2.add
          REM basedev=ql510.add
                    :

となると、悪いのはDVDRAMドライブではないかと、代替え品をと考え、手持ちのCD-ROMドライブを あてがってみたのですが、なにぶん、長期保存品につき不良品になっていました。 残るは、DVDRAMドライブを設定をMASTERにすることぐらいです。先に変更した"Config.sys"を元に 戻し、ついでに"OS2CDROM.DMD"に"/V"オプションをつけロード時にメッセージが表示されるようにしました。

                    :
          device=\os2cdrom.dmd /V
                    :

今度は、リブート後もDVDRAMドライブが確実に検出されるようになり、インストール作業が順調に 進み、完了することができました。

ほかのマシンでは、他社のDVDROMドライブだがSLAVEの設定で問題なく動作しているので、DVDRAMに 問題があり、動作が不安定になったものと思われます。

次に、Display Adpterを"On Board VGA"から"nVIDIA RIVA128"に変更しました。

最終的に、以下のFIXをあてて、導入作業を完了としました。

導入順に示します。FIXは"ftp.boulder.ibm.com"から入手しました。

  • Base Operating System
    1. IC24998.EXE
    2. JFS0905.ZIP
    3. XRJE001
    4. JFS1009.ZIP
    5. XRJE002
  • TCP/IP
    1. IC22633
    2. IC27255
    3. IC27869
    4. UN_2101
  • MPTS
    1. WR_8650

FIXを導入するに当たり、下記のツールを使っています。VFDiskは"hobbes.nmsu.edu"から、 その他は"ftp.boulder.ibm.com"から入手できます。

  • VFDisk -- 仮想ディスケットドライバー
  • Loaddskf -- ディスケット作成ツール
  • CSJ144 -- コレクティブサービスツール

Ratforプリプロセッサー -- 構文解析2017年05月25日 16:50

Ratforで書かれたプログラム文は、parse()で解析され、lex()が返す綴り別に それがコードの始まりの時は、コード生成ルーチンを呼び出し、スタックに綴りの種類と 名札が積まれる。コードの終わりの時は、unstak()が呼ばれスタックから取りおろしをします。 綴りは、defineやmacroのように、initkw()でテーブルにセットします。

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

# parse.r4 -- parse Ratfor source program
      include ratfor.def
      subroutine parse
      character lexstr(MAXTOK)
      character lex, token
      integer lab,sp
      integer labval(MAXSTACK)
      character lextyp(MAXSTACK)

      call initkw                       # install keywords in table
      sp = 1
      lextyp(1) = EOF
      for (token = lex(lexstr); token != EOF; token = lex(lexstr) ) {
          if (token == LEXIF)
              call ifcode(lab)
          else if (token == LEXDO)
              call docode(lab)
          else if (token == LEXWHILE)
              call whilec(lab)
          else if (token == LEXFOR)
              call forcod(lab)
          else if (token == LEXREPEAT)
              call repcod(lab)
          else if (token == LEXUNTIL) {
              if (lextyp(sp) == LEXREPEAT)
                  call synerr('illegal until.')
              }
          else if (token == LEXSTRING)
              call strngc
          else if (token == LEXDIGITS)
              call labelc(lexstr)
          else if (token == LEXELSE) {
              if (lextyp(sp) == LEXIF)
                  call elseif(labval(sp))
              else
                  call synerr('illegal else.')
              }
          if (token == LEXIF | token == LEXELSE
              | token == LEXWHILE | token == LEXDO
              | token == LEXDIGITS | token == LBRACE
              | token == LEXFOR | token == LEXREPEAT) {
              sp = sp + 1
              if (sp > MAXSTACK)
                  call synerr('stack overflow in paser.')
              lextyp(sp) = token
              labval(sp) = lab
              }
          else }
              if (token == RBRACE)
                  if (lextyp(sp) == LBRACE)
                      sp = sp - 1
                  else
                      call synerr('illegal right brace.')
              else if (token == LEXOTHER)
                  call otherc(lexstr)
              else if (token == LEXBREAK | token == LEXNEXT)
                  call brknxt(sp,lextyp,labval,token)
              token = lex(lexstr)       # peek at next token
              call pbstr(lexstr)
              call unstak(sp,lextyp,labval,token)
              }
          }
      if (sp != 1)
          call synerr('unexpected EOF.')
      return
      end

WATCOM Fortran77版は以下の通り。

c parse.f -- parse Ratfor source program
      include ratfor.def
      subroutine parse
      integer*1 lexstr(MAXTOK)
      integer*1 lex,lextyp(MAXSTACK),token
      integer lab,labval(MAXSTACK),sp

      call initkw                       ! install keywords in table
      sp = 1
      lextyp(1) = EOF
      token = lex(lexstr)
      while (token .ne. EOF) do
          if (token .eq. LEXIF) then
              call ifcode(lab)
          else if (token .eq. LEXDO) then
              call docode(lab)
          else if (token .eq. LEXWHILE) then
              call whilec(lab)
          else if (token .eq. LEXFOR) then
              call forcod(lab)
          else if (token .eq. LEXREPEAT) then
              call repcod(lab)
          else if (token .eq. LEXUNTIL) then
              if (lextyp(sp) .ne. LEXREPEAT) then
                  call synerr('illegal until.')
              end if
          else if (token .eq. LEXSTRING) then
              call strngc
          else if (token .eq. LEXDIGITS) then
              call labelc(lexstr)
          else if (token .eq. LEXELSE) then
              if (lextyp(sp) .eq. LEXIF) then
                  call elseif(labval(sp))
              else
                  call synerr('illegal else.')
              end if
          end if
          if ((token .eq. LEXIF) .or. (token .eq. LEXELSE) .or.
     1        (token .eq. LEXWHILE) .or. (token .eq. LEXDO) .or.
     2        (token .eq. LEXDIGITS) .or. (token .eq. LBRACE) .or.
     3        (token .eq. LEXFOR) .or. (token .eq. LEXREPEAT)) then
              sp = sp + 1
              if (sp .gt. MAXSTACK) then
                  call synerr('stack overflow in paser.')
              end if
              lextyp(sp) = token
              labval(sp) = lab
          else
              if (token .eq. RBRACE) then
                  if (lextyp(sp) .eq. LBRACE) then
                      sp = sp - 1
                  else
                      call synerr('illegal right brace.')
                  end if
              else if (token .eq. LEXOTHER) then
                  call otherc(lexstr)
              else if (token .eq. LEXBREAK .or. token .eq. LEXNEXT) then
                  call brknxt(sp,lextyp,labval,token)
              end if
              token = lex(lexstr)       ! peek at next token
              call pbstr(lexstr)
              call unstak(sp,lextyp,labval,token)
          end if
          token = lex(lexstr)
      end while
      if (sp .ne. 1) then
          call synerr('unexpected EOF.')
      end if

      return
      end

initkw()は、見出し語をinstal()を使って登録します。

Ratofor版は以下の通り。

# initkw.f -- install Ratfor keyword
      include ratfor.def
      subroutine initkw
      string(ifst,"if")
      character iftyp(2)
      data iftyp(1)/LEXIF/
      data iftyp(2)/EOS/
      string(elsest,"else")
      character elstyp(2)
      data elstyp(1)/LEXELSE/
      data elstyp(2)/EOS/
      string(whilst,"while")
      character whityp(2)
      data whityp(1)/LEXWHILE/
      data whityp(2)/EOS/
      string(forst,"for")
      character fortyp(2)
      data fortyp(1)/LEXFOR/
      data fortyp(2)/EOS/
      string(repest,"repeat")
      character reptyp(2)
      data reptyp(1)/LEXREPEAT/
      data reptyp(2)/EOS/
      string(untist,"until")
      character unttyp(2)
      data unttyp(1)/LEXUNTIL/
      data unttyp(2)/EOS/
      string(dost,"do")
      character dotyp(2)
      data dotyp(1)/LEXDO/
      data dotyp(2)/EOS/
      string(breast,"break")
      character bretyp(2)
      data bretyp(1)/LEXBREAK/
      data bretyp(2)/EOS/
      string(nextst,"next")
      character nextyp(2)
      data nextyp(1)/LEXNEXT/
      data nextyp(2)/EOS/
      integer*1 strtyp(2)
      data strtyp(1)/LEXSTRING/
      data strtyp(2)/EOS/

      call instal(ifst,iftyp)
      call instal(elsest,elstyp)
      call instal(whilst,whityp)
      call instal(forst,fortyp)
      call instal(repest,reptyp)
      call instal(untist,unttyp)
      call instal(dost,dotyp)
      call instal(breast,bretyp)
      call instal(nextst,nextyp)
      call instal(strst,strtyp)
      return
      end

WATCOM Fortran77版は以下の通り。

c initkw.f -- install Ratfor keyword
      include ratfor.def
      subroutine initkw
      string(ifst,"if")
      integer*1 iftyp(2)
      data iftyp(1)/LEXIF/
      data iftyp(2)/EOS/
      string(elsest,"else")
      integer*1 elstyp(2)
      data elstyp(1)/LEXELSE/
      data elstyp(2)/EOS/
      string(whilst,"while")
      integer*1 whityp(2)
      data whityp(1)/LEXWHILE/
      data whityp(2)/EOS/
      string(forst,"for")
      integer*1 fortyp(2)
      data fortyp(1)/LEXFOR/
      data fortyp(2)/EOS/
      string(repest,"repeat")
      integer*1 reptyp(2)
      data reptyp(1)/LEXREPEAT/
      data reptyp(2)/EOS/
      string(untist,"until")
      integer*1 unttyp(2)
      data unttyp(1)/LEXUNTIL/
      data unttyp(2)/EOS/
      string(dost,"do")
      integer*1 dotyp(2)
      data dotyp(1)/LEXDO/
      data dotyp(2)/EOS/
      string(breast,"break")
      integer*1 bretyp(2)
      data bretyp(1)/LEXBREAK/
      data bretyp(2)/EOS/
      string(nextst,"next")
      integer*1 nextyp(2)
      data nextyp(1)/LEXNEXT/
      data nextyp(2)/EOS/
      integer*1 strst(7)
      data strst(1)/LETs/
      data strst(2)/LETt/
      data strst(3)/LETr/
      data strst(4)/LETi/
      data strst(5)/LETn/
      data strst(6)/LETg/
      data strst(7)/EOS/
      integer*1 strtyp(2)
      data strtyp(1)/LEXSTRING/
      data strtyp(2)/EOS/

      call instal(ifst,iftyp)
      call instal(elsest,elstyp)
      call instal(whilst,whityp)
      call instal(forst,fortyp)
      call instal(repest,reptyp)
      call instal(untist,unttyp)
      call instal(dost,dotyp)
      call instal(breast,bretyp)
      call instal(nextst,nextyp)
      call instal(strst,strtyp)
      return
      end

unstak()は、スタックに最後に積まれた綴りに応じた構文の終わりのコードを生成し、 スタックから取り下ろします。

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

# unstack.f -- unstack at end of statment
      include ratfor.def
      subroutine unstak(sp,lextyp,labval,token)
      integer sp
      integer labval(MAXSTACK)
      character token
      character lextyp(MAXSTACK)

      for ( ; sp > 1; sp = sp -1) {
          if (lextyp(sp) == LBRACE)
              break
          if ((lextyp(sp) == LEXIF) & (token == LEXELSE))
              break
          if (lextyp(sp) == LEXIF)
              call outcon(labval(sp))
          else if (lextyp(sp) == LEXELSE) {
              if (sp > 2)
                  sp = sp - 1
              call outcon(labval(sp)+1)
              }
          else if (lextyp(sp) == LEXDO)
              call dostat(labval(sp))
          else if (lextyp(sp) == LEXFOR)
              call forsta(labval(sp))
          else if (lextyp(sp) == LEXREPEAT)
              call repats(labval(sp))
          else if (lextyp(sp) == LEXWHILE)
              call whiles(labval(sp))
          }
      return
      end

WATCOM Fortran77版は以下の通り。

c unstack.f -- unstack at end of statment
      include ratfor.def
      subroutine unstak(sp,lextyp,labval,token)
      integer labval(MAXSTACK),sp
      integer*1 lextyp(MAXSTACK),token

      while (sp .gt. 1) do
          if (lextyp(sp) .eq. LBRACE) then
              exit
          end if
          if ((lextyp(sp) .eq. LEXIF) .and. (token .eq. LEXELSE)) then
              exit
          end if
          if (lextyp(sp) .eq. LEXIF) then
              call outcon(labval(sp))
          else if (lextyp(sp) .eq. LEXELSE) then
              if (sp .gt. 2) then
                  sp = sp - 1
              end if
              call outcon(labval(sp)+1)
          else if (lextyp(sp) .eq. LEXDO) then
              call dostat(labval(sp))
          else if (lextyp(sp) .eq. LEXFOR) then
              call forsta(labval(sp))
          else if (lextyp(sp) .eq. LEXREPEAT) then
              call repats(labval(sp))
          else if (lextyp(sp) .eq. LEXWHILE) then
              call whiles(labval(sp))
          end if
          sp = sp - 1
      end while
      return
      end

Ratforのメインプリグラムはとても簡単です。

Ratofor版は以下の通り。

# ratfor.r4 -- main program for Ratfor
      program ratfor
      call initfile
      call parse
      stop
      end

WATCOM Fortran77版は以下の通り。

c ratfor.f -- main program for Ratfor
      program ratfor
      call initfile
      call parse
      stop
      end