しかし、これにしても、正直素人にはかなり難しいわけで、すこし考えても以 下のような問題があります。
というわけで、もうちょっとプログラムを抽象化した形で書きたいというのは 自然の流れです。そこで、プログラミング言語(その当時はアセンブリ言語と 対比して「高級」言語 と呼ばれてました)がいろいろ考案されました。 代表的なものが FORTRAN や COBOL です。つまり、これらは、プログラムを 「変数操作 や演算 などの一連の処理=手続き 」と とらえ、それを(人間にとって)書きやすいように設計した言語です。
当初はプログラミング言語はほとんどコンパイラ言語 =コンパイラ によって 事前に 実行形式に変換され、その実行形式を必要な時に実 行する、という方式でした。インタープリタ(逐次実行)方式は、当時の計算 機能力からすると処理速度の点 で不利だったからと思われます。たとえば FORTRAN と は FORmula TRANslation か ら来たもので、数値計算式を簡単にコンピュータで計算できるように設計され ました。四則演算(加減乗除)の数式 はほぼそのまま書き表せますし、 その他についてもべき乗などいろいろな関数がライブラリの形で用意されてお り、簡単に利用できます。
どういうことかというと、 TD4 で足し算をする場合、オペランドに足したい数を指定した上で
MOV A 2 MOV B A ADD B 3のような手順を考えないといけないわけですが、高級言語だと
print var1+var2のような形式で変数 var1,var2 和の出力を得られる、ということです。
さて、変数に付随する概念として、多くのプログラミング言語では「型」 というものが登場します。データを変数が受け入れる際、データの型とあっ た変数でなければなりません。型が異なる場合は原則として入力しようとして も代入しようとしても、変数が受け取ることはできなくなっています。プログ ラミングにとって型という概念を知ることはとても重要です。
初期の BASIC を含め、インタープリタで動く言語(主にスクリプト系)は、デー タ型が無いものもあります。この場合、動的に=動作しているまさにそのとき にデータの型が決定して、さらに必要に応じて適宜変換されます。これは計算 機にとっては余分な処理を強いられるわけです(後述)型というのは、データの性質 と考えてください。そのデータはどう いう特徴をしたデータなのか、それを説明するものです。型が違うと、データ の 計算機内部での表現形式 が異なります。重要なことは、自分が 使いたいデータは何型で、それを格納するための変数を、その型にしなければ ならない、ということです。
しかし、素朴な疑問としてなぜ面倒くさいデータ型というものが存在するか、 ということがあるかもしれません。ざっくり説明すると
各プログラミング言語には、その特徴・使い道に沿った型が用意されています。 FORTRANは科学計算を対象に開発された言語なので、必然的に数に関する型が豊富 にそろっています。
integer i,sum で変数を宣言して、read, write は入出力文で、format で出力 形式を指定して…等ありますが、とりあえず雰囲気だけでも理解してください。
:::::::::::::: fsample.f90 :::::::::::::: program test2 integer i,cnt,sum sum=0 cnt=1 write(*,*)'Input integer:' read(*,*)i 10 sum=sum+cnt cnt=cnt+1 if (cnt <= i) goto 10 write(*,20)i,sum 20 format('Sum from 0 to ',i4,' is ',i6) stop end program test2 :::::::::::::: fsample.s :::::::::::::: .file "fsample.f90" .section .rodata .LC0: .string "fsample.f90" .LC1: .ascii "Input integer:" .align 4 .LC2: .ascii "('Sum from 0 to ',i4,' is ',i6)" .text .globl MAIN__ .type MAIN__, @function MAIN__: pushl %ebp movl %esp, %ebp subl $312, %esp movl $0, 8(%esp) movl $127, 4(%esp) movl $70, (%esp) call _gfortran_set_std movl $0, -12(%ebp) movl $1, -4(%ebp) movl $.LC0, -276(%ebp) movl $5, -272(%ebp) movl $6, -280(%ebp) movl $128, -284(%ebp) leal -284(%ebp), %eax movl %eax, (%esp) call _gfortran_st_write movl $14, 8(%esp) movl $.LC1, 4(%esp) leal -284(%ebp), %eax movl %eax, (%esp) call _gfortran_transfer_character leal -284(%ebp), %eax movl %eax, (%esp) call _gfortran_st_write_done movl $.LC0, -276(%ebp) movl $6, -272(%ebp) movl $5, -280(%ebp) movl $128, -284(%ebp) leal -284(%ebp), %eax movl %eax, (%esp) call _gfortran_st_read movl $4, 8(%esp) leal -8(%ebp), %eax movl %eax, 4(%esp) leal -284(%ebp), %eax movl %eax, (%esp) call _gfortran_transfer_integer leal -284(%ebp), %eax movl %eax, (%esp) call _gfortran_st_read_done .L2: movl -12(%ebp), %eax addl -4(%ebp), %eax movl %eax, -12(%ebp) addl $1, -4(%ebp) movl -8(%ebp), %eax cmpl %eax, -4(%ebp) jle .L2 movl $.LC0, -276(%ebp) movl $10, -272(%ebp) movl $6, -280(%ebp) movl $.LC2, -240(%ebp) movl $31, -236(%ebp) movl $4096, -284(%ebp) leal -284(%ebp), %eax movl %eax, (%esp) call _gfortran_st_write movl $4, 8(%esp) leal -8(%ebp), %eax movl %eax, 4(%esp) leal -284(%ebp), %eax movl %eax, (%esp) call _gfortran_transfer_integer movl $4, 8(%esp) leal -12(%ebp), %eax movl %eax, 4(%esp) leal -284(%ebp), %eax movl %eax, (%esp) call _gfortran_transfer_integer leal -284(%ebp), %eax movl %eax, (%esp) call _gfortran_st_write_done movl $-1, (%esp) call _gfortran_stop_numeric .size MAIN__, .-MAIN__ .ident "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-46)" .section .note.GNU-stack,"",@progbits実行形式である fsampleは長いので実行形式の16 進数表記のリンクをはっておきます。
Microsoft の初期の製品が MS BASIC で、その後 MS-DOS, Windows, ... とど んどん製品も会社も発展していった、というのは有名な話です。その後lisp 等いろいろなものが発明されています。近年ではperl, php, ruby, python のようなスクリプト言語 (あるいは 軽量言語 (lightweight language) ) と呼ばれるものがインタープリタで動いてい ます。Javascript もブラウザ内のエンジン と呼ばれるものが実はイ ンタープリタとして働き、処理しているわけです。
インタプリタ方式はなにがメリットか、ということなのですが;
昔は UCSD (University of California at San Diego) pascal での p-code と いうものが有名でした。最近は emacs 上のe-lisp bytecode もありますが、な んといってもJava のバイトコードが今では代表例だとおもわれます。上で述べ た、機種に依存しないという特徴により、Windows でも Mac でも Linux でも 原則として同じ Java のコードが走るわけです。アプレットの場合、VM は (IE や NN などの) ブラウザに組み込まれています。
Java の当初よく言われていたスローガンが "Write once, run anywhere" で、コンパイルは一回だけ でどこでも動くよ、というものでした。最近では、実際には微妙なバージョン の差等で、全くそのままでは動かないことのほうが多いようです。さらに .NET Framework も (Windows 環境でしか動かないとはいえ) 中間コー ドを採用しています。これは機種間の差異を吸収するというより、言語間 (C++/VB/C#/...) の差異を吸収するためのもののようです。
その中でもよく言われたのが、 「GOTO 文の害」 です。 GOTO 文 とは 機械語レベルの jump (branch という場合もあります) に対 応して、プログラムの流れを制御 するものなのですが、これを不用意 に使うと、手続きの流れがめちゃくちゃになり、全体が見通せなくなってしま います。プログラムの行に名前(あるいは番号)を振るというのも分かりにく い原因かもしれません。例えば以下の FORTRAN の例をみてみてください。 結果がすぐにわかりますか?
ちなみに、このような制御がぐちゃぐちゃに飛びまくって理解しずらいコード のことをスパゲティ・コードと呼んだりします。
program test02 integer i,cnt,sum sum=0 cnt=1 write(*,*)'Input integer:' read(*,*)i 10 sum=sum+cnt 20 goto 40 30 if (cnt <= i) goto 10 goto 50 40 cnt=cnt+1 goto 30 50 write(*,60)i,sum 60 format('Sum from 0 to ',i0,' is ',i0) stop end program test02そこで、GOTO 排除、言い替えると GOTO を使わなくてもちゃんとプログラムは 書けるための仕掛が考えられました。それがすなわち新しい考え方である 「構造化プログラミング」 で、それにそったプログラミング言語がいろい ろ提唱されました。
そのうちの代表的なものが、構造化プログラミングを提唱したダイクストラ (Dijkstra, Edsger) 等によって設計・開発された ALGOL で、その後Pascal, PL/1 などに繋がっていきます。ちなみに開発された当初の FORTRAN はさてお き、現在の FORTRAN はfor による繰り返しによる構造化は勿論サポートされて います。構造化プログラミングでは、プログラムの構造、つまり、手続きは小さな手続 きのあつまりで、それらの手続きはさらに小さな操作のあつまりで…というトッ プダウン的にプログラムを書くことを推奨しました。さらに、プログラムの流 れの制御は
時代(前後関係)でいうと、ダイクストラの提唱("Go to statement considered harmful", 1968)よりこちら(構造化定理, 1966)のほうが先です。そしてさらに、手続きのまとまりを "procedure" "function"などとモジュー ル化 し、変数の有効範囲 (scope) という考え方もとりいれて、 プログラムに構造をとりいれることに成功しました。ちなみに GOTO は機械語の jump にほぼ対応する ということで、処 理としてはif や for より軽い(というかfor 等も結局機械語レベルではjump で実現されている)ので、処理効率という意味では GOTO のほうがいいのは確 かです。しかし、以下で述べるように、多少スピードは落ちてもバグのはいり にくいプログラミングのほうが重要という考え方が主流になってきて、特に昨 今では計算機能力が非常にあがったので、細かい処理効率の向上は微々たるも の、それよりバグの無いプログラムのほうが大切、という感覚です。それがス クリプト言語の興隆にも繋がっています。
ちなみにプログラミング言語Cも、この構造化プログラミングの流れをうけて、 かつ出来るだけ効率的な実行を可能とし、その上で移植性をできるだけ考慮す るように設計されました。もちろん Visual Basic も(.NET は後述するオブジェクト指向にかなり寄って いますが)構造化プログラミング言語のひとつといっていいかもしれません。そもそもC以前はOS自体はアセンブリ言語で書くのがあたりまえ(ハードウェ アに近いところなので他に書きようがない)だったのですが、それではよろし くないということで、AT&Tの Kerninghan と Richie がCを発明し、それ で書いたものが元祖 UNIX (というか、UNIX を書くためにプログラミング言語 Cを作った)で、その流れが現在の Linux 等に受け継がれてきている(現在進 行形)わけです。
もちろん Linux は現在も(最初の boot のところ等の例外を除き)Cで記述さ れています。おそらく Windows もそうだと推察します。Java 等の中間コード 型の言語ではOSは 原理的に書けない です(そのコードが動く VM は いつ誰が用意するの? ということ)。
さらにちなみにCの場合、 ポインタ と 構造体 というデー タ型を導入したことがそれまでの言語とは決定的に違うところで、これらによっ てOSの記述が可能になったのですが、それはまた別の話なのでここでは割愛 します。