RATFORのご紹介 ― 2014年09月14日 11:57

「ソフトウェア作法」(Software Tools)で紹介されているFortranにいくつかの構文を追加した、ものです。
これから、「プログラム作法」で紹介されたプログラムを、Watcom Fortran 77で、インプリメントした経過を報告したいと思います。
Watcom Fortrann 77でのダウンロードはこちらです。http://www.openwatcom.org/index.php/Download
まずはじめに、copyプログラム ― 2014年09月21日 09:43
RATFORは、FORTRANを拡張した言語です。拡張した部分は、ほとんど、 構造化プログラミング向けの構文です。BNF記法でRATFORのプログラムを まとめると、次のようになります。
プログラム | 文 | プログラム 文 文 | if ( 条件 ) 文 | if ( 条件 ) 文 else 文 | while ( 条件 ) 文 | for ( 初期設定; 条件; 再設定 ) 文 | repeat 文 | repeat 文 until ( 条件 ) | do 限界指定部 文 | 数字の列 文 | break | next | {プログラム} | その他
構造化プログラミングでおなじみの文が追加、または、使いやすいように、変更されています。 元々のFORTRANの文は、ほとんど、その他に分類されます。
では、簡単な例を挙げます。標準入力から、標準出力に書き出すcopyです。
# copy.r4 -- copy input characters to output character getc character c while (getc(c) != EOF) call putc(c) stop end
#はコメントの始まりです。"!="は、等しくない(オリジナルは、PL/IのNOT記号を使っていますが、 ASCIIキーボードにはないので、!で代用します)。
getc()は、標準入力から一文字読み込んでくる関数、putc()は、標準出力へ一文字書き出すサブルーチンです。
プログラムの内容は、標準入力から一文字ずつ読み込み、EOF文字がくるまで、標準出力へ一文字ずつ 書き出します。
これを、Watcom Fortrann 77で、書いてみましょう。
c copy.for --copy input characters to output program copy integer*1 getc integer*1 c while (getc(c) .ne. -1) do ! EOF(-1) call putc(c) end while stop end
Watcom Fortrann 77では、FORTRAN77を拡張してあり、while () do -- end whileが追加されています。 また、"!"は、コメントの始まりです。文字定数を扱えないので、EOFの値"-1"を直接プログラム中に書き込んでいます。
Watcom Fortrann 77には、character型がありますが、文字以外を扱うとコンパイルエラーになるので、 文字を扱うのにinteger*1型を使用しています。
いかがでしょうか。Watcom Fortrann 77は、文を拡張してあるので、メリットがあまりないように感じますが。 これから、RATFORでツールを作成し、最後にはRATFORプリプロセッサーを完成させます。すると、RATFORの ありがたみが、ご理解いただけるのではないでしょうか。
getc()とputc() ― 2014年09月23日 08:17
前回取り上げたcopyプログラムで使用している、getc()とputc()を紹介します。
まずは、getc()。RATFOR版は以下の通り。
# getc.r4 (simple version) -- get one characters from standard input character function getc(c) character c character buf(MAXLINE) integer i, lastc data lastc /MAXLINE/, buf(MAXLINE) /NEWLINE/ # note : MAXLINE = MACCARD + 1 lastc = lastc + 1 if (lastc > MAXLINE) { read(STDIN, 100,end=10) (buf(i),i = 1,MAXCARD) 100 format(MAXCARD a1) lastc = 1 } c = buf(lastc) getc = c return 10 c = EOF getc = EOF return end
RATFORのif文が出てきています。"{" -- "}"で複数の文をブロック化しています。
Watcom Fortran 77では、if文が、"if () then -- else -- endif"に拡張されています。
Watcom Fortran 77版では、character型がありますが、数値定数を代入することができません。 integer*1型に文字を格納することとします。
c getc.for -- (simple version) get character from standard input integer*1 function getc(c) integer*1 c integer col,lastc integer*1 buf(81) ! MAXLINE(81) data lastc/81/ ! MAXLINE(81) lastc = lastc + 1 if (lastc .gt. 81) then ! MAXLINE(81) read(5,100,end=999) (buf(col),col=1,80) ! MAXCARD(80) 100 format(80a1) ! MAXCARD(80) lastc = 1 endif c = buf(lastc) getc = buf(lastc) return 999 continue c = -1 ! EOF(-1) getc = -1 ! EOF(-1) return end
これで、良さそうなのですが、問題が一つあります。それは、本来の行末に空白文字が 追加され、1行が80文字になってしまうのです。この問題を回避したのが、次の版です。
c getc2.for -- (extended version) get character from standard input integer*1 function getc(c) integer*1 c integer col,lastc integer*1 buf(82) ! MAXLINE(81)+1 data lastc/81/ ! MAXLINE(81) data buf(81)/10/ ! MAXLINE(81) NEWLINE(10) data buf(82)/-2/ ! MAXLINE(81)+1 EOS(-2) lastc = lastc + 1 if (buf(lastc) .eq. -2) then ! EOS(-2) read(5,100,end=999) (buf(col),col=1,80) ! MAXCARD(80) 100 format(80A1) ! MAXCARD(80) lastc = 1 col = 80 while (buf(col) .eq. 32) do ! BLANK(32) col = col - 1 end while buf(col+1) = 10 ! NEWLINE(10) buf(col+2) = -2 ! EOS(-2) endif c = buf(lastc) getc = buf(lastc) return 999 continue c = -1 ! EOF(-1) getc = -1 ! EOF(-1) return end
一行読みとった後、行末から、行頭に向かって空白をスキャンし、空白以外の文字が出てきたら、 改めて、行末のマーキングをします。これで、余分な行末の空白の処理ができるようになりましたが、 一つ問題があります。全くの空白のみの行は、長さ0の行になってしまいます。今回は、これはまれな事とし、 めをつぶることとしました。
次は、サブルーチンputc()です。RATFOR版は次の通り。
# putc.r4 (simple version) -- put characters on standard output subroutine putc(c) character c character buf(MAXCARD) integer i,lastc data lastc /0/ if (lastc >= MAXCARD | c == NEWLINE) { for (i = lastc+1; i <= MAXCARD; i = i + 1) buf(i) = BLANK write(STDOUT,100) (buf(i), i = 1, MAXCARD) 100 format(MAXCARD a1) lastc = 0 } if (c != NEWLINE) lastc = lastc + 1 buf(lastc) = c } return end
for文が出てきています。これは、Watcom Fortran77にありません。 Cと同じように、初期設定、終了条件、再設定がコンパクトに書けます。 Watcom Fortran77では、while () do -- end whileを使用します。
c putc.for (simple version) -- put sharacter on standard output subroutine putc(c) integer*1 c integer*1 buf(80) ! MAXCARD(80) integer i,lastc data lastc/0/ if ((lastc .ge. 80) .or. (c .eq. 10)) then ! MAXCARD(80) NEWLINE(10) i = lastc + 1 while (i .le. 80) do ! MAXCARD(80) buf(i) = 32 ! BLANK(32) i = i + 1 end while write(6,100) (buf(i),i=1,80) ! MAXCARD(80) 100 format(80a1) ! MAXCARD(80) lastc = 0 endif if (c .ne. 10) then ! NEWLINE(10) lastc = lastc + 1 buf(lastc) = c endif return end
一行80文字にするために、空白文字を詰め合わせています。これでは、元の空白文字なのか、 詰め物か判別できませんし、固定長レコードにする、意味がWindowsにはありません。 行末の無駄な空白文字を書き出さないよう、lastc文字分しか書き出さないように変更しました。
c putc2.for (extended version 1) -- put sharacter on standard output subroutine putc(c) integer*1 c integer*1 buf(80) ! MAXCARD(80) integer i,lastc data lastc/0/ if ((lastc .ge. 80) .or. (c .eq. 10)) then ! MAXCARD(80) NEWLINE(10) write(6,100) (buf(i),i=1,lastc) 100 format(80a1) ! MAXCARD(80) lastc = 0 endif if (c .ne. 10) then ! NEWLINE(10) lastc = lastc + 1 buf(lastc) = c endif return end
最近のコメント