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