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
最近のコメント