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
実際の変更点については割愛します。
最近のコメント