■補講 1980年代前半のBASICを使っていた人向け
1980年代前半にコンピューターを使ってプログラムを作っていた人向け、つまりBASIC言語を少しやったことがある人向けにBASICをJavaScriptで書いたらどうなるのかを説明します。HTML5+JavaScriptをちょっとやってみようかなと思ったマイコン少年(死語ですね・・・)だった方々、少し思い出してBASIC→JavaScriptにトライしてみましょう。
------------------------------------------------------------
■BASICを動かす
まず、現在でも古き良き時代のBASICを動かすことができます。ここではChimunk Basicを使って動作するBASICプログラムを載せておきます。なお、PC, MZ, FM, Basic Masterなど特定の機種に依存するような制御コードはなるべく避けています。
●Chipmunk Basic
http://www.nicholson.com/rhn/basic/
------------------------------------------------------------
■コメントと文字の表示
まず、コメントと画面に文字を表示するプログラムを見てみましょう。BASICだと以下のようになります。
----------------------------------------------
●BASIC
10 REM ここは注釈です
20 PRINT "Sample"
----------------------------------------------
BASICでは最初に行番号があって、その次に実際のプログラムが書かれます。行番号10ではREMとあります。これはREMARK、つまりコメントです。機種によっては'(シングルクオート)でも代用できました。コメントなので何も処理されません。
行番号20を見てみましょう。なつかしい(?)PRINT文があります。PRINTは画面に文字を表示するものです。"で囲むと文字列として画面に表示されます。つまり、このBASICプログラムを実行すると画面に
Sample
とだけ表示されることになります。
それでは、これがHTML5+JavaScriptになると、どうなるか説明しましょう。まず、BASICの時と違ってHTMLファイルが必要になります。index.htmlといったファイル名で作成し中身を書きます。中身は本書にあるようにHTML5のタグでマークアップします。
ただ、今回の場合は画面に表示するためだけのHTMLなので以下のように書いておきます。これは以後のサンプルでも共通です。これだけ書いておけばOKです。
ここで注目する点は
です。ここにPRINT文で指定された文字を表示するためにID名を割り当ててあります。
昔の8bitマシンでは画面を何枚も重ねることは難しいか、できない機種も多くありましたがHTML5+JavaScriptであれば何枚でも画面を重ね合わせることができます。前面を文字、背面をCanvasを使ってグラフィック画面にすることもできます。
----------------------------------------------
●HTML
----------------------------------------------
BASICからJavaScriptへ
----------------------------------------------
これでHTMLファイルの用意ができたのでJavaScriptを使って画面に文字を表示してみましょう。まず、先ほど作成したindex.htmlファイルと同じフォルダにbasic.jsというファイルを作成します。このbasic.jsファイルの中身を以下のようにします。
----------------------------------------------
●JavaScript (basic.js)
----------------------------------------------
// ここは注釈です
document.getElementById("screen1").innerHTML = "Sample";
----------------------------------------------
JavaScriptもBASICと同様に2行しかありません。BASIC言語とは異なりJavaScriptでは行番号はありません。このため、GOTOやGOSUBはありません。後ほど説明する関数/サブルーチンをうまく使って書くことになります。
まず、最初の行はBASICと同じ注釈です。BASICではREMでしたがJavaScriptの場合は//です。REMを//にするだけですから難しくはないでしょう。
次が画面に文字を表示するプログラムです。これはBASICのPRINT文と比べて長いですね。先ほどHTMLでとしました。ここに文字を表示するには「document.getElementById("screen1").innerHTML」に代入します。つまり上記のサンプルのようにすると画面に文字が表示されます。長いのですが、こういうものだと覚えてしまいましょう。ちなみに関数を使ったりして短く書くこともできます。
------------------------------------------------------------
■計算してみよう
それでは次に計算してみましょう。ここでは変数A, Bに数値を入れて加算した結果を変数Cに入れます。この変数Cの結果を画面に表示します。
まず、BASICですが以下のようになります。BASICの場合、LET A = 10のようにLETを使って代入する場合もあります。ただ、このLETは省略できるので、ほとんどの場合書かれることはありません。
以下のプログラムを実行すると計算した結果の15が表示されます。
----------------------------------------------
●BASIC
----------------------------------------------
10 A = 10
20 B = 5
30 C = A + B
40 PRINT "A + B = ";C
----------------------------------------------
それでは、同じ処理をJavaScriptで書いてみましょう。BASICでは変数名の大文字小文字は関係ありませんでしたが、JavaScriptは大文字と小文字は区別されます。つまりAとaでは別の変数と見なされます。
先ほどのBASICプログラムをJavaScriptで書くと以下のようになります。行番号がないことを除けば、ほとんど同じです。異なるのは先ほども説明した画面に文字(計算結果)を表示する部分です。
BASICではPRINTに;(セミコロン)をつけて変数名を書くと改行せずに文字や変数値を表示できます。同じ事をJavaScriptで行う場合は以下のように+を使って書きます。;が+になっただけです。
ちなみにJavaScriptで;(セミコロン)を書くと行末とみなされてしまうので注意しましょう。
----------------------------------------------
●JavaScript (basic.js)
----------------------------------------------
A = 10
B = 5
C = A + B
document.getElementById("screen1").innerHTML = "A + B = "+C;
----------------------------------------------
------------------------------------------------------------
■繰り返してみよう
それでは次に繰り返し処理を行ってみましょう。BASICで繰り返し処理を行うにはFOR〜NEXTを使います。以下のプログラムは1から10までの数値を画面に表示するものです。
変数Iに1が入り、その後TOで示される値になるまで繰り返されます。この時、何も指定しなければ変数Iは1つずつ値が加算されていきます(STEPを指定すると値の増減が指定できます)。値が自動的に加算されていくので画面には1から10までの数値が表示されます。
----------------------------------------------
●BASIC
----------------------------------------------
10 FOR I=1 TO 10
20 PRINT I
30 NEXT
----------------------------------------------
それでは次にJavaScriptで同じ処理を書いてみましょう。JavaScriptでもBASICと同じforを使います。ただし、大文字ではなく小文字です。JavaScriptの命令は全部小文字になっています。
forの後は()の中にどのように変数値を変えるかなどを指定します。基本的にはBASICと同じですが、TOはありません。TOで指定する値が「I<=10」の部分です。これは終了値ではなく繰り返し条件です。つまり変数Iの値が10以下であれば繰り返すという事になります。
その後にはBASICのSTEPにあたる変数値の増減方法を書きます。変数Iに1つずつ足していくので「I=I+1」と書きます。ただ、JavaScriptでは「I=I+1」でなく「I++」のように++を使って書かれることがほとんどです。この++は変数の値に1を足すという意味です。また、ここではBASICの移植ということで変数名が大文字になっていますが、基本的にはJavaScriptでは変数名は小文字が使われます。
さて、繰り返しの設定ができましたので、変数値を表示する部分を説明しましょう。BASICではFOR〜NEXTでしたが、JavaScriptではNEXTがありません。その代わり{と}で繰り返したい部分を囲みます。
文字を表示する部分ですが、これまでとは異なり「document.getElementById("screen1").innerHTML +=」のように+=となっています。これはすでに表示されている内容に追加していく場合にこのように書きます。=にしてしまうと、書き込むたびに内容が消されてしまい最後の値である10だけが表示されてしまいます。
また、BASICのPRINT文は最後に;(セミコロン)を書かなければ自動的に改行してくれます。しかし、JavaScriptでは自動的に改行が行われません。そこで、「I+"
"」として強制的に改行するようにしています。
はHTMLでは改行を示します。
----------------------------------------------
●JavaScript (basic.js)
----------------------------------------------
for(I=1; I<=10; I=I+1)
{
document.getElementById("screen1").innerHTML += I+"
"
}
----------------------------------------------
------------------------------
【コラム】ループ変数
------------------------------
BASIC言語ではFOR〜NEXTで使われる繰り返し変数(ループ変数)にI,J,Kが多く使われます。JavaScriptでもGoogleで検索してみるとループ変数にI,J,Kが多く使われます。
これは、もとはFORTRANというプログラミング言語があり、ここでの制約がそのままBASICに引き継がれています。古いFORTRANでは変数名の長さにはあまり制限がない代わりに先頭の1文字で、どのような変数かを判別していました。FORTRANではIから始まる変数は「整数型」であり整数しか計算できません。そのかわり高速に計算ができます。特に宣言しない限りI,J,K,L,M,Nは「暗黙の型宣言」によって整数と見なされます。
となるとI,J,Kがループ変数に、M,Nが計算結果を入れるための変数に使われる事になります。ちなみに他の変数は浮動小数値計算に使われます。
変数名が最初の1文字でしか判別されないのと、昔は紙テープ(キーボードを押すとテープに穴をあけるヤツがあるんです。紙がちぎれた時はオレンジ色の紙で補修)やマークシートのカード(□を鉛筆で塗り潰します。1枚のカードがプログラムの1行です。1行の文字数制限もあります)でしたので、変数名は短くせざるを得ない事情がありました。
ということで、1文字だけのI,J,Kが繰り返し用としてFORTRANでは多く使われました。では、どうしてBASICでもそうなってしまったのかというと、元々BASICはFORTRAN同様に計算のために作られたためです。FORTRANでは計算するまでにコンパイル作業がありましたがBASICでは、コンパイルはしません。計算結果はすぐに出てきます(インタプリタ型)。
初期のBASICの命令セットは以下のようになっていてPC-8001/MZ-80K/FM-7などに搭載されたBASICとは、かなり異なっています。行列計算などが手軽にできるようになっていました。
http://www.openspc2.org/BASIC/HTML/Dartmas%5BBASIC%5D.html
BASICはFORTRANの代わりとして使うわけですが、暗黙の型宣言などはありません。が、既存のプログラムか慣例をそのまま引き継いだため繰り返し変数にI,J,Kが多く使われるようになったと思われます。C言語が普及してから数年後には、そういうiとかjとか分からない変数名は使うな、使ってはならないという会社もありました。
------------------------------
------------------------------
【コラム】変数名が大文字だけど
------------------------------
BASICから学んだ人ならともかく、JavaやJavaScriptなどを知っている人が、この補修講義で使われている変数を見ると「なんだこりゃ!おかしいぞ、駄目じゃないか」と思うかもしれません。これはBASICの変数名をそのまま使っているからです。
今は英語の小文字が表示できるのが当たり前ですが、1980年代には英語の小文字を表示できないマシンもありました。つまり英語の大文字しか使えないわけです。ですから、必然的に変数名は全部大文字になるわけです。
さらにメモリの制約が多く変数名に2文字使えるというのは贅沢な場合もありました。ですから変数名が一文字になってしまう事も多々ありました。このため、昔のマイコン誌(今の言葉ならパソコン誌)には、変数表という変数が何を示しているかを示す表が掲載されていることがありました。マイコンBASICマガジンなどには、よく掲載されていました。
------------------------------
------------------------------------------------------------
■配列を使ってみよう
それでは次に配列を使ってみましょう。BASICでは配列を使う時にはDIMで使う量の配列数を指定します。DIM A(10)とすれば配列変数Aが用意され1〜10まで、合計10個の箱が用意されることになります。
以下のプログラムは配列変数Aに11〜20までの数値を入れ、その内容を画面に表示するものです。BASICではA(2)とすると配列の内容にアクセスすることができます。A(2)だと配列の2番目の中身にアクセスできることになります。
----------------------------------------------
●BASIC
----------------------------------------------
10 DIM A(10)
20 FOR I=1 TO 10
30 A(I) = I + 10
40 PRINT A(I)
50 NEXT
----------------------------------------------
それでは同じプログラムをJavaScriptにしてみましょう。JavaScriptにすると以下のようになります。最初の行がBASICとは違ってますね。BASICではDIM A(10)だったのがA = new Array()となっています。BASICでは使う配列の要素数を明示しなければいけませんでした。これは使用するメモリサイズを明確にし確保しておくためです。
これに対してJavaScriptでは使用する要素数を明示する必要はありません。一応できることはできますが、あまり意味がありません。BASICはDIMで配列要素数を決めてしまうと、そのままサイズが固定されてしまい変更できませんが、JavaScriptでは状況に応じて自動的に処理してくれます。つまり、配列であることを示せばよいのです。
次に配列へのアクセスですが、BASICではA(番号)でしたがJavaScriptではA[番号]です。単純に( )を[ ]にすればよいので難しくはないでしょう。
実際のプログラムは以下のようになります。実行すると画面には11〜20までの数値が表示されます。
----------------------------------------------
●JavaScript (basic.js)
----------------------------------------------
A = new Array()
for(I=1; I<=10; I=I+1)
{
A[I] = I + 10
document.getElementById("screen1").innerHTML += A[I]+"
"
}
----------------------------------------------
------------------------------
【コラム】添え字の下限値
------------------------------
DIMで配列を宣言すると最初の要素はA(1)のように1から始まります。これに対してJavaScriptではA = new Array()とした場合、A[0]のように0から始まります。
言語によって配列の最初の番号が0の場合と1の場合があります。BASIC言語やLua言語では1から始まり、C言語やJavaScriptなどでは0から始まります。
幸いBASICにはoption baseという命令があり、0から始めるようにするか1から始まるようにするかを指定することができます。
------------------------------
------------------------------------------------------------
■サブルーチンを使ってみよう
BASICを習った人なら、しばらくすると学習したと思われるのが、このサブルーチンです。これは呼び出し側であるメイン(ルーチン)に対して子側(サブ)の処理であるためサブルーチンと呼ばれます。
BASICでサブルーチンを呼び出すにはGOSUB 行番号とします。呼び出されたサブルーチンから呼び出し元に戻るにはRETURNを使います。以下のBASICプログラムは変数Aの値を表示し、その後1を足すというシンプルなものです。GOSUB 1000としてサブルーチンを呼び出すと変数Aの値が画面に表示されます。さらにGOSUB 1000とすると変数Aの値が1つずつ増えていきます。
----------------------------------------------
●BASIC
----------------------------------------------
10 A = 10
20 GOSUB 1000
30 GOSUB 1000
40 A = 100
50 GOSUB 1000
60 GOSUB 1000
90 END
1000 REM -- Subroutine --
1010 PRINT "A = ";A
1020 A = A + 1
1030 RETURN
----------------------------------------------
それでは、これをJavaScriptにしてみましょう。BASICしか分からない人向けになるべく、そのまま移植してあります。JavaScriptには行番号がないため、代わりに「関数名」を指定し呼び出します。ここでは関数名はGOSUB1000です。この関数を呼び出すにはJavaScriptでは後ろに()を付けます。つまりGOSUB1000()とするとGOSUB1000という名前の関数が呼び出されるのです。
それでは実際に呼び出されるサブルーチン側、つまりJavaScriptの関数を見てみましょう。JavaScriptでは関数を作る時にはfunctionと書いて、その続きに関数名を書きます。今回はGOSUB1000ですからfunction GOSUB1000とします。その続きには()を書きます。ここでの()は呼び出しの意味の()ではありません。行頭がfunctionの場合には以後に定義されている関数は、この段階では呼び出されず何も処理されません。()の続きには{があります。これは関数の中身を書きますよ、というものです。ですから、最後には}を書いておきます。この{〜}内に処理を書くわけです。
変数Aの内容を表示する部分は、これまでと変わりません。また、変数Aに1を足す場合もこれまでの説明でわかるでしょう。というかBASICと全く同じですから説明がいりませんね。
関数の最後にはBASICのRETURNと同じようにreturnがあります。JavaScriptでもreturnと書けば関数からの処理を終えて呼び出し元に処理を戻します。BASICと異なりreturnは全部小文字で各必要があります。
----------------------------------------------
●JavaScript (basic.js)
----------------------------------------------
A = 10
GOSUB1000()
GOSUB1000()
A = 100
GOSUB1000()
GOSUB1000()
// GOSUB1000という名前のサブルーチン(関数)
function GOSUB1000(){
document.getElementById("screen1").innerHTML += "A = "+A+"
"
A = A + 1
return
}
----------------------------------------------
とりあえず、簡単なBASICユーザー向けにJavaScriptでは、どう書くのかを説明してみました。本書内でのコードと、かなり違うと思った人もいるでしょう。これはBASICのコードをJavaScriptに置き換えているためです。
それでも、動きますから手始めにやってみて、面白いなと思ったらJavaScriptの勉強をしてみるとよいでしょう。
あと、他の補修講義ではZ80マシン語のエミュレータを作成しています。同様にBASICのプログラムをJavaScriptで動かすようにすれば、昔作ったBASICのプログラムを動かすこともできるでしょう。
都合のよい事に1980年代のプログラムはマイコンBASICマガジンなどの「紙」に印刷されているため、エミュレーターさえ作ることができれば、ゲームなどを入力して楽しむこともできます。結局フロッピーディスクなど便利なメディアは消滅していきますが、紙に残された8ビットマシンのプログラムは、まだ数十年は持つでしょう。
------------------------------
【コラム】グラフィック画面とテキスト画面がある機種は
------------------------------
PC-8801やX1などのようにテキスト画面とグラフィック画面が独立して表示できる機種の場合は以下のようにして画面を重ね合わせて表示することができます。
----------------------------------------------
●HTML
----------------------------------------------
背面がグラフィック画面で手前が文字画面
----------------------------------------------
●JavaScript (basic.js)
----------------------------------------------
// テキスト画面に文字を表示
document.getElementById("screen1").innerHTML = "Basic Sample";
// グラフィック画面にランダムに四角形を描画
function randomLine(){
var canvasObj = document.getElementById("screen2");
var context = canvasObj.getContext("2d");
context.globalAlpha = 0.25;
var col = ["red", "green", "yellow", "blue"];
context.fillStyle = ["red", "green", "yellow", "blue"][Math.floor(Math.random()* 4)];
var x1 = Math.random()* 320;
var y1 = Math.random()* 200;
var w = Math.random()* 320;
var h = Math.random()* 200;
context.fillRect(x1, y1, w, h);
}
setInterval("randomLine()", 100);
----------------------------------------------
FM-7のようにテキスト画面がグラフィック画面と同じものになっている場合には、直接Canvasに文字を書くことになります。この場合はCanvasだけ用意して、そこにfillText()を使って文字を書きます。グラフィック面と共用することになるため、文字の上に四角形が描かれると文字が消えてしまったり色が変わってしまいます。
----------------------------------------------
●HTML
----------------------------------------------
グラフィック画面だけのマシン(FM-7)
----------------------------------------------
●JavaScript (basic.js)
----------------------------------------------
// グラフィック画面にランダムに四角形を描画
function randomLine(){
var canvasObj = document.getElementById("screen2");
var context = canvasObj.getContext("2d");
context.globalAlpha = 0.25;
var col = ["red", "green", "yellow", "blue"];
context.fillStyle = ["red", "green", "yellow", "blue"][Math.floor(Math.random()* 4)];
var x1 = Math.random()* 320;
var y1 = Math.random()* 200;
var w = Math.random()* 320;
var h = Math.random()* 200;
context.fillRect(x1, y1, w, h);
}
// テキスト画面に文字を表示
function drawText(){
var canvasObj = document.getElementById("screen2");
var context = canvasObj.getContext("2d");
context.fillStyle = "white";
context.fillText("Basic Sample", 0, 20);
}
drawText();
setInterval("randomLine()", 100);
----------------------------------------------