プログラミング言語について知っておいて欲しいこと

プログラミング言語のパラダイムの変遷

アセンブリ言語から手続き型言語へ

ビットイメージをいちいち人間が打ち込むのはあまりに非効率なので、命令コー ドをその意味をなんとなくあらわすアルファベットに対応させ、加えてアドレ スや定数なんかも10進数とかラベルふったりして簡単にプログラムが書ける ようにしたものがアセンブリ言語でした。

しかし、これにしても計算機の動作が把握できていないとプログラムは書けな いわけで、もうちょっとプログラムを抽象化した形で書きたいということで、 プログラミング言語(その当時はアセンブリ言語と対比して「高級」言語と呼 ばれてました)がいろいろ考案されました。代表的なものが FORTRAN や COBOL です。つまり、これらは、プログラムを「変数操作や演算などの一連の 処理=手続き」ととらえ、それを(人間にとって)書きやすいように設計した 言語です。

たとえば FORTRAN とは Formula Translation から来たもので、数値計算式を 簡単にコンピュータで計算できるように設計されました。四則演算の数式はほ ぼそのまま書き表せますし、冪乗などそのほかの式も関数を用意することで実 現されています。

コンパイラって、具体的にどんなことしてるの?

ここで、一般的にコンパイラはどんなことをしているのかを見てみましょう。大 抵の場合、コンパイラはまずソースプログラムをアセンブリ言語に一旦変換して、 それをアセンブルすることで機械語におとします。ほとんどの場合、この時同時 に標準関数のライブラリ(事前に用意された関数の実行モジュール)をリンクす ることで、printf() などが使えるようになるわけです。
以下に拙作のCOMET 上でのC言語(の超サブセット)プログラムのコンパ イル作業の各ステップ毎の結果を示しておきます。
::::::::::::::
p1.c
::::::::::::::
#include <stdio.h>
main() {
  int i;
  int j;
  i = 1;
  while (i <= 26) {
    j = i + 64 ;
    putchar(j);
    i = i + 1;
  }
}
::::::::::::::
p1.s2
::::::::::::::
# Genarated from c---
#
	JMP __MAIN
____buf	DS 1

_i	DS 1
_j	DS 1
__MAIN	LEA R1,1
	ST  R1,_i
_R_A	LEA R1,26
	CPA R1,_i
	JMI _J_A
	LD  R1,_i
	LEA R2,64
	ST  R2,____buf
	ADD R1,____buf
	ST  R1,_j
	WRT _j
	LD  R1,_i
	LEA R2,1
	ST  R2,____buf
	ADD R1,____buf
	ST  R1,_i
	JMP _R_A
_J_A	
	END
::::::::::::::
p1.i
::::::::::::::
0E000005
0000
0000
0000
03100001
02100003
0310001A
08100003
0B000027
01100003
03200040
02200002
04100002
02100004
12000004
01100003
03200001
02200002
04100002
02100003
0E000009

処理の差:コンパイラ言語とインタープリタ

コンパイラ言語はプログラムを最終的に機械語におとし、それを実行するもので した。それに対して、インタープリタ言語はプログラムを直接解釈する翻訳機 (これ自身もまたプログラムなのですが)の上で、1ステップごとに実行するも のです。

しかし実はその間の立場である「中間コード」型というものがあります。これ は、プログラムをコンパイルをするのは確かなのですが、その結果は機械語で はなくある程度抽象化した仮想機械 (VM, virtual machine) で動くコードで す。そして、この VM がインタープリタのような役割をしてプログラムが走る ことになります。このやりかただと、仮想機械はその機械(CPU)によって 個別につくる必要はありますが、その上で走るプログラムは機種に依存しなく なるので、(エンド)ユーザーにとっては便利です。

昔は UCSD pascal での p-code というものが有名でした。最近は emacs 上の e-lisp bytecode もありますが、なんといってもJava のバイトコードが今は 旬です。上で述べた機種に依存しない、という特徴により、Windows でも Mac でも UNIX でもおなじ Java のコード (applet) が走るわけです。アプレット の場合、VM は (IE や NN などの) ブラウザに組み込まれています。

手続き型言語での構造化プログラミング

さて、(FORTRAN など)高級言語が生まれてから、それらを使っていろいろプ ログラミングされたのですが、人間のすることですからいろいろ間違い(プロ グラミングの誤りを伝統的にバグといいます)もおこります。そこで、どうす ればバグの無い(少ない)プログラミングができるかがいろいろ考えられまし た。

その中でもよく言われたのが、「GOTO 文の害」です。機械語レベルの jump を 表したものなのですが、これを不用意に使うと、手続きの流れがめちゃくちゃに なり、全体が見通せなくなってしまいます。そこで、GOTO 排除、言い替えると GOTO を使わなくてもちゃんとプログラムは書けるための仕掛、すなわち新しい プログラミング言語がいろいろ考えられたのですが、そのうちの代表的なものが pascal です。これは、プログラムの構造、つまり、手続きは小さな手続きのあ つまりで、それらの手続きはさらに小さな操作のあつまりで…というトップダウ ン的にプログラムを書くことを推奨しました。ここではプログラムの流れの制御 は if 文による条件分岐と while や for による繰り返しのみです。そして手続 きのまとまりを "procedure" "function"などとモジュール化し、変数の有効範 囲という考え方もとりいれて、プログラムに構造をとりいれることに成功しまし た。

C言語も、この構造化プログラミングの流れをうけて、かつ出来るだけ 効率的な実行を可能とするように設計されました。


以下はC言語とは直接関係ないかもしれませんが、ご参考まで。

抽象データ型からオブジェクト指向へ

プログラムを構造化すると、その処理対象となるデータについても、たんなる 変数というだけではなく、一連の処理の対象になるデータはまとめて構造をも たせて意味をもたせる、ということでさらにプログラムが書きやすく見やすく なることが期待出来ます。これが抽象データ型です。Cでは構造体がそれに対 応します。

さらにこれを一歩すすめると、プログラムを仮想的に「もの=オブジェクト」の あつまりとして、そのオブジェクトの中身は一切関知せず、あくまでもその外部 仕様のみをお互いに知っており、それらオブジェクトの間の情報のやりとりで処 理をすすめていく、という考え方がでてきました。この場合、それぞれのオブジェ クトがしっかりと設計されていれば、相互に干渉することはないので、プログラ ムが機能的にきちんと分離されます。さらに、機能がはっきりしているのですか らそれを部品化して再利用するのも容易になるでしょう。

Xerox PARC の smalltalk はこの思想(?)を忠実に実現しようとしたもので、 その流れが C++ や Java などにつながっています。

オブジェクト指向の特徴

本来ならこのあとアプリケーション・フレームワークの話に継っていきたいと ころなのですが、ここでは省略します。