FORTRAN 77の言語仕様は、FORTRAN 66とFORTRAN 77の言語仕様と、言語仕様にまつわるエピソードについて解説している。なお、Fortran 90以降の言語仕様については、Fortranの言語仕様を参照のこと。

## 言語仕様

Fortranの言語仕様は、年代によってかなり変化して来ている。他のプログラミング言語で実装された構造化プログラミングの機能などがどんどん取り入れられて来ているからである。

### FORTRAN 66

FORTRAN 66の言語仕様はおおよそ下記のとおり。

#### 利用できる文字

- 英数字(大文字)
- 特殊文字(空白 = + - \* / ( ) , . ' : ; & % $ # " @)

#### プログラムの書式

プログラムは以下の形式で記述する。もともとパンチカードに書くことを前提としていたので、1行は80文字で構成されていた。行の左端からの文字位置を桁(けた)またはカラムと呼んだ。

もともとのFORTRANは、字句解析の仕組みがCやJavaと大きく異なり、桁位置(行の左端からの文字位置)に依存していた。これを固定プログラム形式という。これは、当時、データの入力にパンチカードを 使用していたためである。1桁目から5桁目が文番号で、6桁目が継続行の指定、7桁目から72桁目に文の本体を記述する。73桁目から80桁目は任意に指定可能な、行を識別するための文字列を記述する領域である。また、文字列定数中以外の空白文字は一切無視されていた。二つ以上の字句を空白無しで続けて書 いたり、逆に一つの字句の途中に空白文字を入れても構わない。

物理的に穴を開けるパンチカードのほかに、鉛筆で塗りつぶすマークシート方式も存在した。消しゴムで消せば楽に修正できるわけである。いずれも、カード1枚がプログラム1行に相当する。これらは「FORTRANカード」と呼ばれた。

#### 数など

以下の数を扱える。

- 整数(範囲は機種依存、4バイトであればその範囲)
- 単精度実数(整数部+小数部、指数表示可能、精度は機種依存)
- 倍精度実数(単精度の倍の精度を持つ)
- 複素数(単精度または倍精度の実数の組み合わせ。2つの数字を()でくくる)
- 論理型(.TRUE. または .FALSE. 両脇にドットがある)
- 文字型(桁数のあとにHを記述し、その後に文字列を記述する。例えば 7HFORTRAN など)

#### 変数など

以下の変数宣言を扱える。

- 暗黙の型宣言
  - 整数型(変数名の先頭がI~Nのもの)
  - 実数型(上記以外)
- 明示的な型宣言
  - INTEGER宣言文
  - REAL宣言文
  - DOUBLE宣言文
  - COMPLEX宣言文
  - LOGICAL宣言文
- 配列(宣言文のあとに()をつけ、要素数を記述する)

#### 式

- 算術式(+、-、\*、/、\*\*(べき乗))
- 比較(.LT.、.LE.、.GT.、.GE.、.EQ.、.NE. 両脇にドットがある)
- 論理演算(.OR.、.AND.、.NOT. 両脇にドットがある)

#### 関数

以下の関数を扱える。

### FORTRAN 77

FORTRAN 77は、FORTRAN 66に、よりプログラムを書きやすくするための文や、動作の明確化をはかっている。FORTRAN 66でのプログラムはほぼそのまま動くようになっている。以下はFORTRAN 77で追加/変更になった点の概要である。

#### 数など

- 文字列を指定するのに、アポストロフィ(')が使えるようになった。例えば'FORTRAN'。

#### 変数など

変数などについて以下の変更が加えられた。

- IMPLICIT文で、暗黙の型宣言の範囲を変更できるようになった。一部のコンパイラではすでに実装されていたものを仕様化したものである。整数、実数だけではなく、文字型なども指定できる。
- PARAMETER文で、定数に名前を与えられるようになった。FORTRAN 66では、定数は、直接式に書くか、変数を定数代わりに使う方法しかなかった。前者は定数の変更に手間がかかり、後者は定数を変更されてしまう危険性があった。
- 配列の宣言に寸法宣言子を指定できるようになった。FORTRAN 66では配列は1から始まるだけだったが、FORTRAN 77ではマイナスの領域も定義できるようになった。たとえば以下のように定義できる。

  :   DIMENSION ARRAY (-10:10)
- 部分文字列が利用できるようになった。配列と同じような形で指定できる。

  :   CHARACTER\*4 CHR
  :   CHR(1:2) = "2B"
- 配列の初期化にDO形並びが利用できるようになった

#### 式

- 型の異なる変数/定数間での型の変換方法が定義された(?)
- 文字の連結演算子(//)が定義された
- 論理演算子に、等しければ真となる.EQV.と、異なれば真となる.NEQV.(XORと同じ)が定義された

#### 文

- 宣言文
  - IMPLICIT文が追加された
  - (関数)副プログラムで、そのプログラム内で定義した変数を、そのプログラム内から抜け出たときも値が不定にならないように、保存するSAVE文が追加された。
  - 主プログラム名を指定するPROGRAM文が追加された。
- 実行文
  - IF構造として、IF THEN~ と IF THEN~ELSE~END が利用できるようになった。
- 入出力文
  - 入出力文の書式が大幅に強化された。以下のパラメータが利用できるようになった。これらを使うことで、入出力操作の柔軟性が向上した。
    - UNIT=(装置指定子)
    - FMT=(書式指定子)
    - ERR=(誤り指定子)
    - END=(ファイル終了指定子)
    - IOSTAT=(入出力状態指定子)
    - REC=(記録指定子)
  - 補助入出力文に以下の文が追加された
    - OPEN文
    - CLOSE文
    - INQUIRE文

#### 関数

以下の関数が追加された。

- 文字長(LEN)
- 部分列の位置(INDEX)
- 正接(TAN、DTAN)
- 逆正接(ASIN、DASIN)
- 逆余弦(ACOS、DACOS)
- 逆正接(ATAN、DATAN)
- 双曲線正弦(SINH、DSINH)
- 双曲線余弦(COSH、DCOSH)
- 双曲線正接(TANH、DTANH)
- 文字列の大小比較(LGE、LGT、LLE、LLT)

## FORTRANの言語仕様にまつわるエピソード

### 「暗黙の型宣言」による伝統的・慣習上の変数命名規則

FORTRANのプログラムにおいては、とくに型宣言をしない場合、アルファベットI,J,K,L,M,Nのいずれかで始まる変数名で表される変数は整数型(integer)になり、その他のアルファベット(A~H, O~Z)で始まるものは実数型(real)になる。これが「暗黙の型宣言」といわれるFORTRANの文法上の規則である。なお、この命名規則についてBakusは『Iから始まる6文字に決まったのは、みんな添え字にI、J、Kをつかっていたので、(L、M、Nを)気前よく増やした。』と言っている。

FORTRANのプログラムでは、特にループ構造を表すDO構文におけるカウンター変数としてアルファベットI~Nの1文字の変数名が伝統的によく使用されており、プログラミングにおける慣習上の変数命名規則の一つとなっている。i, j,...の1文字変数をインデックス参照などに使われるループカウンタに使うことは、他の多くのプログラミング言語に伝搬したが、プログラミング言語における慣習としてはFORTRANに由来する(数学の総和などでもiを使う慣習があるので、プログラミング言語以外について含めたら、必ずしもFORTRANが元祖とは言い切れない)。

いくつかの観点から、変数には明示的な宣言が必要とされることもある。Fortran 90以降ではIMPLICIT NONE文により暗黙の型宣言を無効にできるようになった。コンパイラのエラーメッセージや警告により暗黙の型宣言に起因するバグの発見が容易になるので積極的に用いるべきである。

### 言語仕様と宇宙開発にまつわるエピソード

FORTRANの「空白は無視する」という言語仕様が招く、コンマとピリオドの打ち間違いがコンパイルエラーにならず、間違ったプログラムになる、という例を説明する。

Cで、次のように書くプログラムの一部があったとする。

これをFORTRAN 66で書くと次のように書ける。

最初の行は、整数型変数Iを1から5まで1ずつ増加させつつ、行ラベル10の行までを繰り返し実行することを表す。行ラベル10のCONTINUE文はループ制御の端末文ではなく、どこにでも置ける「何もしない」機能の文である。

この、DO文のコンマをピリオドに打ち間違えたとする。すると、空白を無視するFORTRAN 66では、この行は、

という、「DO10Iという実数型変数に1.5という実数を代入する代入文」と解釈される。FORTRANでは変数宣言が無い場合、DO10Iは実数型変数を暗黙に示すからである。
この結果、このプログラムは(他のどこからも参照されない)変数DO10Iへの代入とただ1回の「何らかの処理」が実行されるだけとなり、意図した繰り返し処理は起こらない。

C言語などでは、空白文字は字句要素の切れ目として解釈されるため、DO と 10 と Iが結合して一つの字句要素になることはない。

「これが原因でNASAの宇宙ロケットが制御不能になり爆破された」という話が度々語られる。しかしこの話は、1960年代前半のほぼ同時期にあった、二つの異なった事件の混同による、ある種の「都市伝説」である。

要約すると、

- FORTRANの言語仕様が原因で生じたバグは、実機ではなくソフトウェアだけでの実行結果の異常として発覚し修正されたため、実際のロケット打ち上げには関係していない。これはマーキュリー計画において起きた。
- 宇宙機のロストにつながったプログラムのミスは言語仕様とは関係なく、プログラムするべき、として示された数式において、必要な線が欠けていたため発生した。これはマリナー1号において起きた。プログラミング(コーディング)に間違いは無くても、要求された仕様の時点でその中にバグがあるかもしれない、という教訓となっている。

DO文によるバグは、1963年、マーキュリー宇宙船の軌道計算ソフトウェアを開発中に、スタッフの一人が計算精度に問題があることに気づいた。コードを調査した結果、「DO 10 I=1.10」という行を発見した。それが原因で、ループにより近似の精度を高めるはずのコードが、ループしないため精度を高めることなく通り過ぎてしまっていた。これを「DO 10 I=1,10」と修正したところ、期待した精度が得られるようになった。

宇宙機の喪失につながった事故は、1962年、金星探査機マリナー1号を打ち上げるアトラスロケットには、Rate SystemおよびTrack Systemと呼ばれる二種類の制御系統が搭載されていた。Rate Systemは搭載型であり、地上型のTrack Systemは前者に対するバックアップとして動作する。1962年7月、マリナー1号の打ち上げ直後に、ロケットのguidanceアンテナは必要な性能を発揮しなくなり、搭載型システムのみに頼ってロケットは制御されることになった。しかし搭載型システムには次のような仕様バグがあった。「このようにプログラムすべき」として指示されていた手書きの数式中の、平均化を示す線(しばしば「ハイフン」と言及されるが、正確にはオーバーライン)が欠落しており、そのため平均化した値を使うべきところでそのままの値が使われ、微妙なタイミング差の平滑化処理に問題があった(プログラム自体は「指示された仕様の通り」正しく書かれていた。指示された仕様が間違っていたのである)。結果として、制御コンピュータは、ロケットが正常に上昇しているにもかかわらず、異常な補正動作をロケットに指示し続け、正常なコースから外れていった。結局、ロケットには破壊指令が送られ自爆し、マリナー1号は大西洋へと沈んだ。