MCL(63)

インデックスに戻る

前のMCLへ  次のMCLへ

▼ My Computer Life (63)

63. プログラミング言語(前編)

 確か96年の秋頃だったと思うが、私は急にPC-486用の開発環境が欲しくなり、Borlandの「Turbo C++」を購入した。特に大きな何かを作りたかったというわけではないが、とりあえずC++について勉強したいという気持ちがあったのだ。

 私がC++について知ったのはいつ頃だっけな。名前自体は結構初期のうちから聞いていたような気がするけど、それがどういうものなのかを知ったのは、Cマガジンだったと思う。前に書いたけども、X68k用のGCCが欲しくて何号か買った時があり、その時に紹介されていたのだ。1991年の事である。
 当時私はC言語についてはなんとか読める程度だったものの、大体要点はつかんでいた。その私が、その時のCマガジンに書いてあったC++の紹介記事及び例として挙げられたソースコードを読んだ時、大変感動した。素晴らしいシステムだと。こういう言語仕様を備えていれば、プログラミング自体(複雑ではあるけども)楽しいのではないかと思う。
 その記事自体が、C++の良さを(すでにC言語を知っている人にとって)非常に分かりやすく説明しており、これに最初に触れたのはとても良かったと思う。もっと難しい書き方をされていたら、分からなかった。

 という事で、C++言語について書いていこうとして、実はかなり長い文章を用意していたのだが、少し趣向を変えて、プログラミング言語そのものについて色々書いていきたいと思う。

 初期のコンピュータというものは、本当に限定的な機械で、プログラムが不可能であった。これに、内部を操作して動作を変更したり、外部からの指令を受け付けたりするように、少しずつ進化し、やがて命令の塊である「プログラム」を解釈、実行するようになった。
 しかしコンピュータの回路というものは、そこまで複雑な命令を直接実行できるようにはなっていない。内部的には、ごくごく簡単な計算や、メモリへの読み書き等しか出来ない。これらの原始的な命令を組み合わせてプログラムするのだが、そのような言語は「機械語」と呼ばれた(機械語とは010001101のようなもので、人に読めるようにmove a,bのようなニーモニック形式で書いたものをアセンブリ言語と呼ぶという説明があるが、個人的には別言語のように表記する意味は特に感じない)。
 このように、直接CPUに結びついた機械語を、もっと使い勝手を良くして、人間にわかりやすいようにするために、様々な高級言語が生まれた。

 ごく初期の高級言語と言えば、FORTRAN(1957)がまず思い浮かぶだろう。
 これはIBMで開発された言語で、主に数式の計算等に焦点を合わせた、手続き型の言語である。一通りの算術要素が盛り込まれ、またIF文やGOTO文、DO文などによる制御構文が用意されている。その、数式表現も制御構文も、様々な形で現代のプログラミング言語に受け継がれている。まさに、始祖である。
 現代的な基準で見ると、FORTRANは非常に古めかしく、固定的だ。記述が静的で、柔軟性が無いので、例えばコードの再利用であるとか、グループでの開発とか、そういう視点で見ると、全く向いていない言語と言える。しかし、当時のコンピュータの性能を考えると、驚異的と言えるほど良く出来た仕様とコンパイラとも言える。そのおかげか、FORTRANでは現在でも使われている。

 FORTRANと同じくらいの古株が、COBOL(1960)である。先に生まれたFORTRANが、数式計算を得意とし、理系の舞台で活躍する事が多かったため、事務処理などの商業シーンでの需要に応えるために作られたのがCOBOLである。
 COBOLも、言ってみればFORTRANと同じく、マクロ付きアセンブラに毛の生えたような原始的な言語なのだが、記述の手法に特徴がある。FORTRANがいかにもコンピュータ的で、素人には分かりづらいのに対し、COBOLはなるべく英語での自然な表記に近づけている。例えば、C言語では「a += b」(変数aに、変数bの数値を加える)となる記述を、COBOLでは「ADD b TO a」と書く。万事この調子で、「a += b」が何を言ってるのか分かりづらいのに比べれば、理解しやすい。しかしその反面、記述がどんどん長くなる傾向があり、ちょっと複雑な数式を書き下そうと思うと、かなり長いコードになる。これが分かりやすいかどうかは、個人的には微妙なところだと思う。
 このCOBOLも、FORTRAN同様長い伝統に支えられて今日でも使用されている。

 COBOLとほぼ同時期(実際にはCOBOLより少し前)に作られた言語に、LISP(1960)がある。これはリスト処理言語と呼ばれており、FORTRAN及びCOBOLとはかなり違った性格を持っている。分類上は関数型言語と呼ばれるが、純粋関数型ではないので、FORTRANらと同様に手続き型であるという指摘もある。
 記法は上記二つとも大きく違っており、カッコを多用する書き方と、演算子の前置記法が特徴である。典型的には、「(car (quote (a b c))) (+ (* a b) (* c d))」のようなソースコードになり、その他の言語に慣れた人からすると、さっぱり理解できない。カッコに囲まれた要素の羅列を「リスト」と呼び、様々な形式のリストを操作するところから、リスト処理言語の名前がついている。リストの要素には、値や変数や演算子の他、関数や制御文を含む事もできる。これも自由に操作できるので、LISPはこれから動かすプログラムのコードを、実行中に動的に生成できる。他の言語にはなかなかない、珍しい特徴だ。
 このように、カッコまみれの見づらさそうな言語であるものの、カッコの対応をきっちりさせればむしろコンピュータにとっては解釈がたやすく、つまりコンパイラの作成が単純という事であり、60年代の貧弱なコンピュータ上でも良く実装されていた。
 現在では、FORTRANやCOBOLほどは実用に供されているとは言いがたいが、Common Lispやschemeに継承され、今日でも使われている。

 上記の、プログラミング言語元祖の御三家が成立して以降、1960年代から次第に多様化していき、またコンピュータそのものの性能向上も伴って、色々な考えが言語に盛り込まれていく。

 まずFORTRANの派生言語として有名なのは、BASIC(1964)がある。その名の通り、初心者にもとっつきやすくするのを目的とした言語である。
 内容は、FORTRANと良く似ている。ただ、パンチカードでプログラムを組んでいた時代の名残りが多いFORTRANをブラッシュアップし、更に簡素化してある。行番号というシステムを採用し、インタプリタとコマンドラインでの直接実行を両立させている。
 本質的には、FORTRANと同じ古臭さを持っており、固定的、非局所的、静的な言語であるが、何しろとっつきやすいという特徴があるので、特に8ビットPCなどにはデフォルトで実装される事も多く、80年代くらいには馴染みの深い人も多かったと思う。

 もう一つ、FORTRANからの派生としてはForth(1968)もある。だが、仕様が大きく変わっているので、スタック指向言語などという別の呼ばれ方もする。
 スタックというのは、いわゆるLIFOで、最後に入れたデータが最初に出てくるメモリ構造の事。机に物を積むイメージかな。最後に置いたものが、最初に取り出される。一番最初に置いたものは、一番最後に取り出される。機械語レベルでは、つまりCPUの処理レベルでは一番ありふれた一時記憶の方法で、ほぼ全てのCPUがスタック処理の機構を備えている。従って、どんな言語のコンパイラも、内部ではこのスタックを使うような実行コードを吐き出すのだが、言語仕様としてこのスタックを多用するのがForthの特徴だ。
 スタックの使用は、単にプログラミングスタイルだけではなく、算術演算の式にも応用される。逆ポーランド記法という、ちょっと見慣れない書き方をするのだ。
 例えば、「2+3」という式を表現するのに、Forthでは「2 3 +」という書き方をする。こう書くと、まず2がpush(スタックに入れる)され、3もpushされる。+が出た時点で、直前にpushされた2つの数値をpop(スタックから取り出す)し、計算結果をpushする。従って、この式のあと、5という数値だけスタックされている状態になる。それから値を取り出すわけだ。「(1+2)*(3+4)」を計算するには、「1 2 + 3 4 + *」というように書く。まず1と2がpushされ、+の時点で1と2はpopされて結果の3がpushされる。続けて3と4もpushされ、スタックは下から3・3・4の状態になる。次の+で、3と4がpopされ、計算結果の7がpushされ、スタックは3・7になる。次の*で3と7が取り出され、計算結果の21が入る。見ての通り、カッコを使わず、スタックという仕組みを使用して数式を表現する。
 この仕組みは、慣れないと人間には難しいが、コンピュータには非常に理に適っている。従って、コンパイラは大変実装しやすい。その他も万事この調子で、コンピュータ側にとって都合のいい仕様が多く、その結果Forthのインタープリタやコンパイラは非常に簡単に作れ、サイズも小さくなった。そのため、組み込み用など小規模なマシンなどに幅広く導入された。

 FORTRAN、BASIC、Forthなどと続くFORTRAN系列の言語に続き、プログラミング言語界で一大勢力となっていったのは、ALGOL(1958)に端を発する構造化言語の流れである。
 構造化という言葉が何を示すのかを説明するのは難しいが、簡単に言うと、今までひとつながりだったプログラムを、処理単位ごとにサブルーチンに切り分け、更にそのサブルーチンももっと細かいサブルーチンに切り分け、細かいパーツを組み合わせてプログラムするようにしましょうね、という話だ。
 FORTRANの誕生以降、コンピュータの進化にも従い、プログラムも肥大化していったので、もっと分かりやすく、作りやすくする必要性が生まれた。当時のプログラミング言語というのは、局所性がなく、つまりなんでもかんでもグローバルで、そしてプログラムのあちこちでgoto文のような仕組みの大域ジャンプを使っていた。従って、プログラム全体が密接に絡み合い、読みづらくなるし、また部分部分が独立していないので、デバッグしづらい、次のプロジェクトで再利用しづらいなどと様々な弊害が起きていた。そこをパーツに分けて対処しようというのが構造化の考え方だ。
 その始祖であるALGOLは、元々はコンピュータの開発言語として実装されたものではなく、仮想的・抽象的な言語として、学術研究用に作られたものだった。もちろん、後にはきちんとコンピュータで動く環境が作られたが、あまり開発言語としては流行らなかった。しかし構造化の考え方自体は重要で、これが開花するのがALGOLの子孫であるC言語(1973)だった。
 C言語は、ALGOLから始まり、BCPL(1966)B(1969)と言う構造化言語の流れを継承し、UNIXのシステム記述言語として成立した。
 C言語は、関数と呼ばれる処理単位でプログラムを組み立てる事が可能で、関数ごとに変数の名前が独立しており、衝突しない。従って関数同士の独立性が高く、別々のプログラムで使われていた関数を組み合わせても動作するし、プログラムの見通しも良くなる。これこそ構造化信者の目指した事であった。
 C言語自体については#0052で書いたので、このへんにしておく。

 C言語と同じく、ALGOLの系譜を継ぐもう一つの構造化言語の柱が、Pascal(1970)である。
 構造化言語なので、指向としてはC言語に良く似ている。LL文法で体系化されているPascalは、LR文法のC言語よりも単純で、同じワンパスコンパイラでも速度が上だった。のちにボーランドのTurbo Pascalが出ると、その高速性に飛びついた人たちもいた。当時は、コンパイルというのはものすごく時間のかかる作業だと考えられており、それが短時間で終わるというだけで作業効率に大きな影響があったからだ。
 ちなみに、初期のコンピュータRPGの傑作であるWizardryは、Pascalで記述されている。
 Pascalは、C言語ほどの隆盛にはならなかったが、現在も、Delphi(1995)のような派生言語とともに、愛用されている。


 むむ…。
 なんか予定していたよりも文章量が多くなってしまったな…。
 よし、予定を変更して、前後編に分けよう。という事で、今回はここらへんまで。


前のMCLへ  次のMCLへ

戻る

TOM 2011