実数型コンパイラ言語 REAL

大貫伸昭
 
 実数型コンパイラREALをひと言でいうと,「SLANGを実数対応にして,再帰をできなくしたもの」ということになります。SLANGと共通の特徴を簡単に説明しますと,ディスク上のASCIIファイルまたはメモリ上のソースプログラム(テープの場合はいったんメモリに読み込んでから)をコンパイルして,オプジェクトをメモリ上に出力する1パスのコンパイラで,ランタイムルーチンはオブジェクトの先頭にリロケートして出力されます。C言語のようにすべての処理は関数の形で記述し,変数や配列は大域的なものと局所的なものの2種類使えます。間接変数を使って「ポインタもどき」くらいは可能ですし.もちろんメモリやI/O,特殊ワークエリアを配列の形で直接アクセスしたり,マシン語やデータを直接オブジェクトに落とすこともできます。その他,関数名や変数名などにシフトJISの漢字を使用可能,ディスク使用時には#INCLUDEによるファイルの取り込みが可能,などとなっています。SLANGと異なるのは,おおよそ以下のようなことです。その他,細かいことについてはマニュアルを参照してください。
●実数が使える
 SLANGで扱えたのは整数型のみでしたが,REALではINT型(整数型)とREAL型(実数型)の2種類を扱えます。REAL型はプログラムの先頭で,アドレス宣言のSINGLE宣言かDOUBLE宣言によって,単精度か倍精度のどちらか一方を選びます。プログラム中で単精度実数と倍精度実数を同時に扱うことはできません。デフォルトは倍精度になっていますので,なにも宣言しないと倍精度になります。
 INT型はSLANG同様符号なし整数値を扱いますが,自動的にREAL型に変換したり,REAL型からINT型に変換する場合は,符号付き整数値として処理しています。言語としては「美しくない」ものになってしまい,最後の最後まで迷ったのですが,実用性を考えてあえてこうしました。もちろん,符号なし整数値としてREAL型との変換を行う演算子も用意しでありますが,その一方でメモリ不足のため,整数型のデータを符号付きで演算するピリオド演算子をカットしてしまい,片手落ちとなっています。なんとかうまく使いこなしてやってください。
●SOROBANが必要
 コンパイル時と実行時のどちらも,浮動小数点演算パッケージSOROBANが必要です(実数を全然使っていないときでも必要)。コンパイル時にもSOROBANを利用していますので,オブジェクトがSOROBANと重なってはいけません(「OUT OF MEMORY!」のエラーになります)。SOROBANは1989年4月号の新型ローダ(配布ディスクに収録:LOADER)を使って読み込んでください。コンパイルと実行を続けて行う場合は,実行時に改めてSOROBANを読み込む必要はないでしょう。また,コンパイル時と実行時でSOROBANが同じアドレスにないといけません。実行時はランタイムルーチンでSOROBANのアドレスをチェックし,コンパイル時のアドレスと異なっていたらなにもしないで終了してしまいます。
●DECLARE宣言
 C言語でいうプロトタイプ宣言が導入されました(というより必要になったのですが)。その時点で未定義の(後ろのほうで定義してある)関数を呼び出す場合1パスのコンパイラにはその関数や引数の型がわかりません。SLANGでは関数や引数の型はすべて整数型と決まっていましたから処理を続けることができましたが,REALではINT型とREAL型の2種類の型がありますからそういうわけにはいきません。そこでプログラムの頭のほうで,関数の型や引数の型と数を宣言しておこうというのがプロトタイプ宣言です。REALではDECLARE宣言(宣言宣言?意味不明ですね)といいます。コンパイラはこれを参照して関数の型を知り,引数の型や数のチェックをします。もちろん,関数呼び出し時にすでに定義しである関数は,宣言をする必要はありません。
●再帰ができない
 SLANGでは引数や局所変数を動的にメモリ上に取りますから再帰が可能でしたが,REALでは引数や変数などをすべて静的にメモリ上に割り当てますので,再帰ができなくなっています。再帰は,その関数自身を直接または間接的に呼び出す機能ですが,呼び出すたびに局所的な変数などが保存されなくてはなりません。あれば便利な機能ですが,これを削ったおかげでREALが完成したようなものですから,勘弁してください。
 その代わり,変数の値をスタックに一時的に保存する関数としてPUSH()とPOP()を追加しました。配列などは保存できませんが,これを利用すればなんとか再帰を実現できると思います。ただし,スタックはプログラムで使用しているスタックですので,使い方を間違えるといとも簡単に暴走するはずです。注意してください。
●実行速度はSLANGより遅い
 残念ながら整数型のデータを扱う場合,REALの実行速度はSLANGに比べるとやや遅くなっています。一例を挙げますと,100回ループの「エラトステネスのふるい」で,SLANGの137秒に対して,REALは158秒となっています。整数型のデータを扱う処理ではSLANGとまるで同じ処理をしていますので,SLANGとまったく同じ実行速度を得ることが可能だったのですが,メモリ不足のため最適化の処理部が入りきらず実現できませんでした。
 実数型のデータを扱う処理では,一切最適化を考えていません。「実数を手経に扱える」ことだけを考えて設計しました(実行速度は二の次)。もっともREALの実数の実行速度が遅いとしたら,8割方はSOROBANの責任でしょう(結局みんな私の責任だったりする)。おそらく実行速度はSLANGで実数演算ライブラリを使用したときとたいして変わりがないと思います。
●その他
 配列の宣言(ARRAY宣言)で要素数の指定がC言語に準じたものになりました。例を挙げると,
  ARRAY A[3];
 とすると,SLANGではA[0]からA[3]までの4個の配列が用意されましたが,REALではA[0]からA[2]までの3個が用意されます。注意してください。
 IF文などの条件式にはカッコが必要になりました。また,MACHINE関数ではスタックを利用した方法がなくなりました。すべてレジスタを使って引数を渡します。
 

◆使用方法

 配布ディスクに収録されているオブジェクトはディスク版ですから,テープやQDを使用する場合は$3005の内容を$00に書き換えてください。ソースプログラムは別のエディタで作成し,デバイス上に保存してください。次に,REAL起動前に,ローダを使ってSOROBANを読み込んでおきます。起動の際は,コールドスタートアドレス(3000H)をコールします。ホットスタートアドレス(3003H)なら大域表の内容が保存されています(REALがメモリ上にあった場合)。起動するとコマンドモードになりますので,Cコマンドを使ってデバイス上やメモリ上のソースプログラムをコンパイルしてください。
 
表1 コマンド
●C ファイル名
 ソースファイルをコンパイルする。ファイル名を省略した場合はメモリ上のソースをコンパイルする。Cの後ろに/を加えると,ソースリストを表示しながらコンパイルする。
●S ファイル名:nn1:nn2 [:nn3:[nn4]]
 オブジェクトをセーブする。[ ]内は省略可を表わす。nn1~nn4はそれぞれ先頭,最終,実行,格納アドレスを表し,オフセットをつけない場合はnn4を省略する。
●X nn
 ソースを格納するアドレスをnnに変更する。メモリ上にあるソーステキストをコンパイルする場合はこのコマンドでアドレスを指定する。
●O
 定義された大域的な名前と,その値を出力する。
●D デバイス名:
 ディレクトリを表示する。
●DV デバイス名:
 デフォルトデバイスを変更する。
●Jnn
 アドレスnnをコールする。
●!
 S-OSのモニタにジャンプする。
●M
 各機種のモニタにジャンプする。
 
図 メモリマップ
  ●オンメモリ版  
 0000H
 3000H
 
7000H
 

 
B000H


 
#MEMAX
S-OS
REAL
ソース
プログラム
 
オブジェクト
コード
 SOROBAN 
 
 
 
*1
 
 
 
*2
 
*3
 
 
  ●ディスク版  
 3000H

 
7000H
 
8000H
 
 
 
B000H


 
#MEMAX
 
REAL
 
クラスタBUFF
 
 
 
 
オブジェクト
コード
 SOROBAN 

 
*4

 
 
 
 
*5

 
*6
 
●S-OS特殊ワークエリア
0000H
 
 
 0100H



 0300H
  
 
0400H


 
 0800H

定数表
 

関数表
 

局所表
 

 ハッシュ表 
 

大域表
 

定数表:文字列定数やREAL型の定数値をバッファリングする。
関数表:関数の引数の型や数を記録する。
局所表:局所的な名前の表。ブロックごとに初期化される。
ハッシュ表:大域表のためのハッシュ表
大域表:大域的な名前の表。他の4つの表の残りが表の大きさとなる。
*1 TEXT_TOPの初期値。変更可。
*2 OBJ初期値の初期値。変更可。
*3 SOROBANはソースやオブジェクトと重ならなければどこでもよい。
*4 クラスタBUFFの初期値。変更可。
*5 OBJ初期値の初期値。変更可。8000Hにするとよい。
*6 SOROBANはオブジェクトと重ならなければどこでもよい。
 
表2 変更可能な値
 起動前に以下の値を書き換えておくことにより,作成するプログラムに合わせてワークエリア等を設定することが可能。
●$3005 (1バイト) [DISK] 初期値:01
 00:オンメモリ版
 01:ディスク版
●3006H (2バイト) [OBJ初期値] 初期値:B000H
 オブジェクトコードを生成する先頭アドレス。 ORG宣言を省略した場合に使用される(ディスク版の場合8000Hに)。
●3008H (2バイト) [ランタイム最終ADR]
 ランタイムルーチンの最終アドレス。ランタイムルーチンを追加した場合変更する。
●300AH (2バイト) [クラスタBUFF] 初期値:7000H
 ディスク版でソーステキストを読み込むための4Kバイトのバッファの先頭アドレス。
●300CH (2バイト) [TEXT_TOP] 初期値:7000H
 オンメモリ版でソーステキストを格納する先頭アドレス。
●300EH (2バイト) [定数表SIZE] 初期値:0100H
 S-OS特殊ワークエリア上に取られる定数表のサイズ。
●3010H (2バイト) [関数WKSIZE] 初期値:0200H
 S-OS特殊ワークエリア上に取られる関数表のサイズ。
●3012H (2バイト) [局所表SIZE] 初期値:0100H
 S-OS特殊ワークエリア上に取られる局所表のサイズ。
●3014H (2バイト) [ハッシュ表SIZE] 初 期 値:0400H
 S-OS特殊ワークエリア上に取られるハッシュ表のサイズ。
●3016H (1バイト) [BAT対応] 初期値:01
 00:S-OSがバッチ処浬に対応していない。
 01:S-OSがバッチ処理に対応している。
 

REALリファレンスマニュアル

■書式に関する規定

●名前
 英文字(アルファベット,漢字,@,^)で始まり,英文字か数字からなる文字列。アルファベットの大文字と小文字の区別はしない。関数名,変数名,配列名,記号定数名,ラベルはすべてこの文字列からなる。
●フリーフォーマット
 基本的にはC言語のようにフリーフォーマットで行の概念はなく,名前の途中以外どこで区切ってもよいが,例外がある。
・//コメント //以降はコメントとみなされ,その行の終わリまで無視される。
・“文字列” 2行にまたがることはできない。
・配列 配列名と[の間を空白などで区切ることはできない。
・関数 関数名と(の間を空白などで区切ることはできない。
●空白
 空白は名前の途中と配列の[および関数の(の前以外ならどこに置いてもよい 。改行,コメント,#コマンドは空白と同等である。
●コメント
 注釈文。空白が置けるところなら,どこに置いてもよい。
  //コメント //から行の終わりまで。
  /*コメント*/ /*から */まで。ネスティング不可。
  (*コメント*)  (*から*)まで。ネスティング不可。
●#コマンド
 コンパイラに対する命令。空白が置けるところなら,どこに置いてもよい。
・#INCLUDE ファイルネーム
 別のソースをその場所に取り込む。ネスティング不可。ファイルネーム以降は行の終わりまで無視される。オンメモリ版では使用できない。
・#CHAIN ファイルネーム
 続きのソースを読み込む。ファイルネーム以降はすべて無視される。オンメモリ版の場合,準備がよいかどうか聞いてくるので,なにかキーを押すと読み込みを始める。BREAKキーを仰すとコンパイルを中止する。
・#IF INT型定数式
  #ELSE
  #ENDIF
 条件付コンパイルを行う。#IFの後ろの式が真(0以外)ならば#IFから#ELSEまでを,偽(0)ならば#ELSEから#ENDIFまでをコンパイルする。ただし,必ず行の先頭になければならない。#ELSEはなくてもよい。ネスティング不可。
 

■型

●型の種類
 型は基本的にはINT型とREAL型の2種類のみである。ただし,配列にはCHAR型とINT型とREAL型の3種類,関数にはVOID型とINT型とREAL型の3種類がある。
●REAL型
 データは5バイト(単精度)または8バイト(倍精度)で表される実数値。SINGLE宣言がされれば単精度で,DOUBLE宣言がされれば倍精度で処理される。
●INT型
 データは2バイトで0から65535までの符号なし整数値。
●CHAR型
 配列のみにある型。データは1バイトで表される0から255までの整数値。
●VOID型
 関数のみにある型。値を返さない型。
 

■型変換と型チェック

●CHAR型は自動的にINT型に変換してから演算を行う。
●INT型とREAL型との演算では自動的にINT型の値をREAL型に変換してから演算を行う。
●INT型は符号なし整数型だがREAL型に変換する場合は,符号付き整数値とみなして実数値に変換する。また,逆にREAL型からINT型に変換する場合は,実数値を符号付き整数値に変換する。
●関数の引数では,自動的な型変換は行わず型チェックのみ行う。
●MACHINE関数とPRINT関数の引数では,自動的な型変換も型チェックも行わない。
●RETURN文で値を返す場合は,自動的な型変換は行わず,その関数の型とのチェックのみ行う。
●VOID関数以外の型で値を返さなくてもエラーにはならない。
 

■プログラム

  アドレス宣言
  大域宣言
  ブロック
   :
  大域宣言
  ブロック
 アドレス宣言,大域宣言とブロック(関数定義)からなる。必ず,
   MAIN( )
という関数が必要で,プログラムを実行させることは関数MAIN( )を実行することである。関数MAIN( )の定義はプログラムのどこにあってもよい。MAIN()はINT型の関数として宣言されている。
 

■名前の有効範囲

●大域的な名前
 関数名や大域宣言で宣言された名前は大域的な名前となり,プログラム全体で使用できる。関数名以外は,宣言以後有効となる。
●局所的な名前
 局所宣言で宣言された名前や仮引数,ラベル名は,局所的な名前となり,その関数(ブロック)内でのみ使用できる。大域的な名前に向じ名前があった場合,局所的な名前を優先する。
 

■アドレス宣言

 オブジェクトコードやワークエリアの先頭アドレスの指定や,REAL型の精度の指定(単精度か,倍精度か)を行う。宣言を省略した場合はデフォルト値が使われる。デフォルトは
  ORG $B000;
  OFFSET 0;
  DOUBLE;
ただし,ORG宣言の初期値は変更可。
●ORG INT型定数式;
 オブジェクトコードの先頭アドレスを指定する。実際には,先頭にランタイムルーチンがリロケートされ,その後ろにオブジェクトコードが続く。
●WORK INT型定数式;
 変数や配列のワークエリアの先頭アドレスを指定する。宣言を省略した場合は,ワークエリアはオブジェクトコード中に含まれる。初期値を持つ変数や配列は宣言の有無にかかわらず,オブジェクトコード中に含まれる。
●OFFSET INT型定数式;
 オブジェクトを実行するアドレスと異なるアドレスに生成する際のオフセットを指定する。
●STACK INT型定数式;
 実行時のスタックを指定する。ただし,プログラム呼び出し時のスタックは保存されなければならない。宣言を省略した場合は呼び出し時のスタックが使用される。
●DOUBLE;
 REAL型の実数を倍精度(8バイト)で扱う。
●SINGLE;
 REAL型の実数を単精度(5バイト)で扱う。
●大域宣言
 大域的な名前を宣言する。それらの名前は宣言以後すべての場所で使用できる。
●VAR宣言 大域的な変数を宣言する。
●ARRAY宣言 大域的な配列を宣言する。
●CONST宣言 大域的な記号定数を宣言する。
●MACHINE宣言 MACHINE関数を宣言する。
●DECLARE宣言 関数のプロトタイプ宣言をする。
 

■ブロック

  関数頭書き
  局所宣言
  BEGIN
    文
  END;
 局所的なまとまりで,この中で宣言された名前はこの中でのみ有効となる。BEGINからEND;までで,関数を定義する。BEGINとEND;は[ ]でもよい。たとえば,
  INT FUNC1 (INT X,Y)
  VAR INT I;
  BEGIN
   I=X+Y;
   RETURN (I);
  END;
(* 関数頭書き *)
(* 局所宣言 *)
(* 関数定義 *)
のようになる。
●関数頭書き
 定義する関数名を宣言する。ブロックの最初に,
   型 関数名 (仮引数,仮引数,…)
の形で書く。型を省略すると,INT型とみなされる。仮引数を持たない場合は,
   型 関数名 ()
と書く。
 仮引数の書式はVAR宣言の書式と同じだが,格納アドレス指定と初期化はできない。複数個ある場合は,カンマで区切る。仮引数は関数呼び出し時の実引数の値を持ち(値渡し),自動的に静的な局所変数として宣言される。たとえば,
   INT FUNC (REAL A, B, INT C)
とするとA,BはREAL型の局所変数,CはINT型の局所変数となる。
 MACHINE関数は,
   型 関数名 (引数の数)
の形で書く。
●局所宣言
 局所的な名前を宣言する(ブロック内でのみ使用できる)。
●VAR宣言 局所的な変数を宣言する。
●ARRAY宣言 局所的な配列を宣言する。
●CONST宣言 局所的な記号定数を宣言する。
 

■変数

 単純変数と間接変数があり,必ずVAR宣言か仮引数で宣言しないと使用できない。
 単純変数は,変数としてのみ使用でき,配列としては扱えない。INT型とREAL型がある。
 間接変数は,変数としても配列としても扱える。配列として扱う場合は間接変数の値を配列の先頭アドレスとみなして,配列と同じようにメモリをアクセスする。配列同様2次元まで扱える。間接変数自体はINT型の単純変数だが,宣言時には配列としての型を宣言する。型を省略した場合はINT型とみなされる。
 たとえば,POINTがINT型の間接変数として宣言されていたとすると,
  POINT=$C000;
  I=POINT[3];
では,C006Hの内容を下位バイト,C007Hの内容を上位バイトとして,変数Iに代入される。2次元の間接変数は,主に2次元配列を受け取る仮引数として使用する。
●VAR宣言
   VAR 型 変数名 ;  (* 単純変数 *)
   VAR 型 変数名 [ ] ;  (* 1次元間接変数 *)
   VAR 型 変数名 [ ][n] ;   (* 2次元間接変数 *)
 変数を宣言する。カンマで区切っていくつでも宣言でき,最後はセミコロンで終わる。型はINT型とREAL型のみ。ただし,間接変数にはCHAR型もある。型を省略した場合は,ひとつ前の型と同じとみなされる。デフォルトの型はINT型。間接変数は配列として使用する際の型を宣言する。たとえば,
  VAR
     INT A, B,
     REAL C, D[],
     CHAR E[];
とすると,A,BはINT型の単純変数,CはREAL型の単純変数,DはREAL型の間接変数,EはCHAR型の間接変数となる。
 2次元の間接変数を宣言する場合には,
  VAR INT F[2][3];
のようにする。ただし,第一の添字の2は意味をもたないので,
  VAR INT F[][3];
のように宣言する。添字はINT型の定数でなければならない。
●格納アドレスの指定
 : INT型定数式とすることにより,変数の格納アドレスを指定することができる。
  VAR XY:$C000, BYTE Z[ ]: $D000;
と書くと,C000HとC001HをINT型単純変数XYの格納アドレス,D000HとD001HをCHAR型間接変数Zの格納アドレスとすることができる(間接変数自体はINT型の変数なので,2バイト必要)。
●初期化
 =定数式とすることにより,変数の初期化をすることができる。この場合,WORK宣言がなされていても,その変数はプログラム中に埋め込まれる。
  VAR A=0, B=3, C[ ]=$C000;
  VAR REAL R=12.3456;
 この初期化はコンパイル時にのみ行われ.実行時には行われない。
 

■定数

 INT型とREAL型の2種類ある。
●10進数
 小数点を含む表現か,Eを用いた指数表現の10進数は無条件でREAL型になる。小数点を含む表現でも指数表現でもない場合,-32768~65536の整数はINT型になり,その他はREAL型になる。
 例)  1234, -5     (* INT型 *)
    1.0,3E5,1.2E-2  (* REAL型 *)
●16進数
 '$'で始まり16進文字からなる文字列。INT型になる。
 例) $ABCD,$FFFF
●2進数
 '0'と'1'からなり'B'で終わる文字列。INT型になる。
 例) 1111000011001010B
●文字定数
 '(シングルクォーテーション)でくくった1文字で,文字のASCIIコードを値とする。エスケープ文字が使用可。INT型になる。
 例) 'A','\N','\''
●文字列定数
 "(ダブルクォーテーション)でくくった文字列で,文字列が格納されているアドレスを値とする。文字列はオブジェクトコード中に埋め込まれ,自動的に最後に$00がつけられる。エスケープ文字が使用可。INT型になる。ただし,2行にまたがることはできず,定数式にも使用できない。
 例) "メッセージ¥n"
●記号定数
 定数値に名前をつけて定数値と同等に扱える。CONST宣言で定義する。ただし,REAL型の記号定数は定数式に使用できない。
 例) CONST REAL PAI=3.14159265359;
●$
 次に生成するオブジェクトコードのアドレスを値とする。INT型になる。
●CONST [INT型定数式]
 コンパイル時の定数式のアドレスのメモリの内容を値とする。1バイト単位でアクセスする。INT型。
 例) CONST INT @WIDTH=CONST [$1F5C];
●CONSTW [INT型定数式]
 CONST [INT型定数式]と同様。2バイト単位でアクセスする。INT型。
 例) CONST @@=CONSTW [CONSTW [$1F82]+2];
●エスケープ文字
 文字定数や文字列定数中に使われ,2バイトで1文字として扱われる。\の後ろに1文字を付けた形で使用されるが,該当する文字がない場合は\だけで1文字となる。大文字と小文字の区別はしない。
  \\ … \
  \" … "
  \' … '
  \N … $0D
  \/ … $0D
  \C … $0C
  \R … $1C
  \L … $1D
  \U … $1E
  \D … $1F
  \0 … $00
●定数式
 定数からなる式だが,文字列定数とREAL型の記号定数,カンマ演算子は使用できない。定数には,オブジェクトを生成せずコンパイル時に値が確定している式も含まれる。つまり,
  &変数名
  配列名
  &配列名[INT型定数式]
  &定義済みのラベル名
 なども定義できる。
 また,INT型の定数式では,途中にREAL型の定数などが表れても,最終的にINT型の定数値になればよい。
●CONST宣言
   CONST 型 記号定数名=定数式;
 記号定数を定義する。カンマで区切っていくつでも宣言でき,最後はセミコロンで終わる。型にはINT型とREAL型がある。型を省略した場合についてはVAR宣言と同様。たとえば,
  CONST INT PC=9801,
     REAL PAI=3.14;
とすると,PCはINT型の9801,PAIはREAL型の3.14という定数値を持つ名前となる。
 

■配列

 配列は2次元まで可能で,配列の表現はC言語と同じ。型には,CHAR型,INT型,REAL型の3種類がある。CHAR型は1バイト単位で,INT型は2バイト単位で,REAL型は5または8バイト単位で,配列要紫をアクセスする。添字のチェックはしない。必ずARRAY宣言で宣言してから使用する。2次元配列は,
  配列名 [行] [列]
の形で書く。
 配列名は配列のワークの先頭のアドレスを指す定数である。
●ARRAY宣言
  ARRAY 型 配列名 [n1];    (* 1次元配列 *)
  ARRAY 型 配列名 [n1] [n2]; (* 2次元配列 *)
  (* ただし,n1,n2はINT型定数式 *)
 配列を宣言する。カンマで区切っていくつでも宣言でき,最後はセミコロンで終わる。型には,CHAR型,INT型,REAL型の3種類があり,型を省略した場合についてはVAR宣言と同様。たとえば,
  ARRAY REAL A[10];
と宣言すると,REAL型の配列がA[0]からA[9]までの10個分確保される。
●格納アドレスの指定
 :INT型定数式とすることにより,配列の格納アドレスを指定することができる。たとえば,
  ARRAY ABC[10]: $C000;
とすると,C000H以降を配列ABCのワークエリアとし,ABC[0]の格納アドレスはC000HとC001H,ABC[1]はC002HとC003H,……となる。この場合,添字は意味を持たないので,
  ARRAY ABC[ ]: $C000;
としてもよい。
●初期化
 ={定数式,定数式,…}とすることにより,配列の初期化をすることができる(ただし,{}は文括弧)。この場合,WORK宣言がなされていても,その配列はプログラム中に埋め込まれる。
  ARRAY BYTE DT[4]={0, 1, 2, 3};
 初期値が足りない場合は,残りは0で埋められる。多すぎる場合は,エラーとなる。添字が省略された場合はチェックしない。型がCHAR型の場合のみ,CODE関数と同じ書式を使って初期化できる。
  ARRAY CHAR STR1[ ]=["ガマちゃん" ,$0D ,0];
この初期化はコンパイル時にのみ行われ,実行時には行われない。
 

■関数

 通常の関数とMACHINE関数がある。型はVOID型とINT型とREAL型の3種類がある。再帰はできない。引数の数は,通常の関数では8個まで,MACHINE関数では5個までである。
●関数コール
 値渡しである。
  関数名(実引数,実引数,…)
の形で関数を呼び出す。実引数と仮引数の型や数が合わないと,エラーになる。
  RETURN (式);
によって返される値が関数の値となる。
 MACHINE関数の場合は,引数の数のチェックは行われない。
●DECLARE宣言
 関数のプロトタイプ宣言をする。関数の定義より前に関数を呼び出す場合,関数の型や,引数の型がコンパイラにわからないため,プログラムの頭のほうで(通常アドレス宣言の次の大域宣言で),関数の型や,引数の裂を宣言しておく。コンパイラはこれをたよりに,型のチェックや,引数の数のチェックを行う。宣言は,
  DECLARE 型 関数名 (引数の型,引数の型,……);
の形で行う。複数の関数を宣言する場合は,カンマで区切る。DECLARE宣言がされずに,未定義の関数を呼び出した場合は,関数も引数もすべてINT型として処理される。
  例) DECLARE REAL SUB1(REAL, INT),
        INT SUB2(),
        VOID SUB3(INT);
 仮引数に間接変数を使用する場合は,DECLARE宣言ではINT型として宣言する。たとえば関数が,
  REAL SUB4(CHAR P[ ], REAL R1[3]);
となっていたとすると,DECLARE宣言では以下のようになる。
  DECLARE REAL SUB4(INT, INT);
●MACHINE関数
 MACHINE関数はMACHINE宣言した関数で,レジスタを使って引数を渡す。MACHINE関数呼び出し時には.引数の数のチェックは行われるが,引数の型のチェックは行われない。主に,外部のマシン語ルーチンをMACHINE関数として宣言するが,プログラム中でCODE関数を使って定義したマシン語関数もMACHINE関数とすることができる。ただし必ず使用,定義する前にMACHINE宣言しなければならないので,通常,アドレス宣言の次の大域宣言で宣言する。引数は最大5個までで,レジスタを使った呼び出し方は,次のようになる。
  0個…CALLのみ。
  1個…HLに代入してCALL。
  2個…順にHL,DEに代入してCALL。
  3個…順にHL,DE,BCに代入してCALL。
  4個…順にHL,DE,BC,IXに代入してCALL。
  5個…順にHL,DE,BC,IX,IYに代入してCALL。
関数の値は,INT型の場合,関数から戻ってきたときのHLレジスタの値となる。REAL型の場合は,HLレジスタが指しているアドレスのREAL型データが値となる。
●MACHINE宣言
 MACHINE関数を宣言する。
  MACHINE 型 関数名 (引数の数);
の形で宣言。復数のMACHINE関数を宣言する場合は,カンマで区切る。
  MACHINE MSUB(2): $C000;
そして,後ろに:INT型定数式をつけると,外部にあるマシン語サブルーチンを関数として利用できる。上の場合,MSUBはC000Hにあり引数を2個持ちHLジスタの値を返すINT型の関数となる。
 

■演算子

 特に断りがないかぎリ,INT型の演算結果はINT型,REAL型の演算結果はREAL型となる。
●代入演算子
=
代入。
●算術演算子
  +
  -
  +
  -
  *
  /
  %
正符号。単項演算子。
負符号。単項演算子。
加算。
減算。
乗算。
除算。
剰余算。
●カンマ演算子
,
左から右へ計算され,最も右の論理項を値とする。
●論理演算子
 真のとき1,偽のとき0。結果はINT型。
&&
!!
NOT
!
論理積。
論理和。
論理否定 (単項演算子)。
 〃  (  〃  )。
●ビット演算子
 オペランドはINT型のみ。REAL型は不可。
AND
OR
XOR
CPL
<<
>>
論理積。
論理和。
排他的論理和。
ビット反転 (単項演算子)。
左シフト。空いたビットには0が入る。C言語参照。
右シフト。空いたビットには0が入る。C言語参照。
●関係演算子
 真のとき1,偽のとき0。結果はINT型。
==
<>
!=
<=
>=
<
>
等しい。
等しくない。

小さいか等しい。
大きいか等しい。
小さい。
大きい。
●型変換演算子
 すべて単項演算子。
CVITR
CVUTR
CVRTI
CVRTU
符号付き整数(INT型)をREAL型に変換。
符号なし整数(INT型)をREAL型に変換。
REAL型を符号付き整数(INT型)に変換。
REAL型を符号なし整数(INT型)に変換。
符号は無視される。
●その他
++
--
&
ABS
SGN
インクリメント演算子。C言語参照のこと。
デクリメント演算子。C言語参照のこと。
アドレス演算子。C言語参照のこと。結果はINT型。
絶対値。単項演算子。
正の数なら1,0なら0,負の数なら-1となる。単項演算子。
●演算の優先順位
  1. [ ]
  2. ( ) ++ -- &
  3. + - ! NOT CPL ABS SGN CVITR CVUTR CVRTI CVRTU
  4. * / %
  5. + -
  6. << >>
  7. == <> != <= >= <> .<=. .>=. .<. .>.
  8. OR AND XOR
  9. &&
  10. !!
  11. =
  12. , (カンマ)
 

■文

 { }は文括弧を表す。文括弧として[ ],( ),「」,BEGIN END; が使用できる。[ ]は省略可を表す。
●ラベル
 ラベル名:
 GOTO文やEXIT TO文のジャンプ先を指定する。ラベル名は局所的な名前となる。
●式文
 式;
 式の文。
●復合文
 {文 [, 文, …, 文] }
 複数の文を文括弧でくくり,ひとつの文として扱う。
●空文
 ;
 なにもしない文。
●IF文
 IF 文 {THEN} 文1 [ELSE 文2]
 式の値が真ならば文1,偽ならば文2を実行する。
●FOR文
 FOR INT型単純変数名= 式1 TO   式2 文
 FOR INT型単純変数名= 式1 DOWNTO 式2 文
 単純変数の値を式lから式2になるまで1ずつ増やし,文を繰り返す。DOWNTOの場合は1ずつ減らす。まず文を実行してから,終値の判定を行う 。 ただし,式1と式2が間に0をはさむ場合は,期待される繰り返しは行われず,1回で繰り返しを終了する。
 FOR ( 式 ; 条件式 ; 式 ) 文
 C言語のFOR文と同じ。上記のPASCAL型FOR文よりもオブジエクト効率が劣るが,REAL型の変数など,より複雑な条件が使用できる。
●WHILE文
 WHILE (条件式) 文
 条件式の値が真の間,文を繰り返す。
●REPEAT文
 REPEAT 文 UNTIL (条件式) ;
 条件式の値が真になるまで,文を繰り返す。
●EXIT文
 EXIT;
 FOR文,WHILE文,REPEAT文から脱出する。C言語のbreak文と同じ。
●RETURN文
 RETURN;
 RETURN(式);
 その関数を終了して,呼び出した関数に戻る。(式) ; をつけた場合は,式の値を関数の値とする。
●GOTO文
 GOTO ラベル名;
 ラベルにジャンプする(必ずラベルは同じ関数内に)。
●CASE文
 CASE (INT型式0) {
   INT型定数式1 : 文1
   INT型定数式2 : 文2
   … … …
   [OTHERS [:] 文]
 }
 式0の値が定数式nと等しければ,文nを実行し,CASE文を脱出する。上から順に比較していき,いずれの定数式とも等しくなかった場合は,OTHERSの後ろの文を実行する。
  INT型定数式1 TO INT型定数式2 : 文1
とすると,式0の値が定数式1以上,定数式2以下の場合,文1を実行する。
  INT型定数式1, [INT型定数式2, …,] INT型定数式n : 文
とすると,式0の値が定数式1から定数式nまでのいずれかに等しい場合,文を実行する。
 

■登録済みの名前

 システム配列やシステム関数,登録済みの名前はすべて大域的な名前である。これらは宣言せずに使用できる。
●登録済みの記号定数
・int FALSE = 0;
・int TRUE = 1;
 

■登録済みの変数

●int ^A
 CALL関数. GETREG関数で使用。CALL関数では値をAレジスタに代入してからマシン語ルーチンをコールし,終了後Aレジスタの値が代入される。
●int ^BC
 int ^DE
 int ^HL
 int ^IX
 int ^IY
 以上は^Aと同様。
●int ^AF
 ^Aと同様。^AFの上位バイトと^Aの下位バイトは同じ値を持つ。
●int ^SP
 CALL関数 .GETREG関数で使用。現在のSPの値が代入される。
●int ^CY
 CALL関数,GETREG関数で使用。CYフラグが立っていれば1,立っていなければ0が代入される。
●int ^ZERO
 CALL関数,GETREG関数で使用。Zフラグ。^CYと同様。
●システム配列
 [ ]内の式はすべて,INT型の式。
●char MEM[式]
 式の値のアドレスの内容を1バイト単位でアクセスする。
●char MEMW[式]
 式の値のアドレスの内容を2バイト単位でアクセスする。式のアドレスが下位バイト,式+1のアドレスが上位バイトに対応する。
●real MEMR[式]
 式のアドレスに実数値が格納されているものとして5バイト単位(単精度),または8バイト単位(倍精度)でアクセスする。
●char PORT[式]
 式の値のI/Oポートを1バイト単位でアクセスする。
●int PORTW[式]
 式の値のI/Oポートを2バイト単位でアクセスする。式のI/Oポートが下位バイト,式+1のI/Oポートが上位バイトに対応する。下位バイト,上位バイトの順にアクセスされる。
●char SOS[式]
 式の値のS-OS特殊ワークエリアを1バイト単位でアクセス。
●char SOSW[式]
 式の値のS-OS特殊ワークエリアを2バイト単位でアクセスする。式の特殊ワークエリアが下位バイト,式+1の特殊ワークエリアが上位バイトに対応する。
 

■登録済みの関数

●void BEEP( )
 BEEP音を鳴らす。S-OSの#BELL。
●void STOP( )
 プログラムの実行を終了する。
●int LOCATE(int x, y)
 カーソルをx,y座標に移動する。
●int INKEY(int n)
 入力されたキーの値を返す。
   n=0のときS-OSの#GETKYと同じ
   n=1のときS-OSの#FLGETと同じ
   その他のときS-OSの#INKEYと同じ
●int INPUT( )
 キーボードから入力された整数値を返す。先頭に$を付けると,16進数とみなす。コールした時点のカーソル以降を読み込み,正常な入力が行われた場合は^CY=0,BREAKキーが押されたり誤入力があった場合は^CY=1となる。
●real INPUTR( )
 キーボードから入力された実数値を返す。コールした時点のカーソル以降を読み込み,正常な入力が行われた場合は^CY=0,BREAKキーが押されたり誤入力があった場合は^CY=1となる。変数^DEが10進文字列の終了アドレス+1を指している。
●int GETL(int addr)
 キーボードから1行入力し,アドレスaddrに格納して,行の長さを返す。BREAKキーが押されると-1を返す。行の最後は00H。
●int GETLlN (int addr, len)
 1行の長さlenを指定できるほかは,GETL関数と同じ。オーバーした分は無視される。
●int LlNPUT(int addr, len)
 コールし た時点のカーソル以降を続み込むほかはGETLlN関数と同じ。
●void WIDTH(int n)
 画面モード(40キャラ,80キャラ)を切り替える。nが40以下だと40キャラ,40より大きいと80キャラとなる。S-OSの#WIDCH。
●int SCREEN(int x, y)
 画面のx,y座標のキャラクターコードを返す。S-OSの#SCRN。
●int PRMODE(int n)
 PRINT関数の出力を切り替える。
   n=0のとき,画面にのみ出力
   n=1のとき,画面とプリンタに出力
   その他のとき,プリンタのみに出力
●int BIT(int val, n)
 値valの第nビットを調べ,0か1かを返す。
●void SET(int val, n)
 値valの第nビットを1にする。
●void RESET(int val, n)
 値valの第nビットを0にする。
●int SEX(int val)
 値valを符号付き1バイトとし,符号付き2バイト値にして返す。
●int RND(int n)
 0からn-1までの乱数を返す。
●void GETREG( )
 各レジスタの値を,それぞれ変数,^AF,^BC,^DE,^HL,^IX,^IY,^CARRY,^ZERO,^SPに代入する。^SPに正しい値を代入したい場合は単独で用いること。
●int CALL(int addr)
 各レジスタに変数^A,^BC,^DE,^HL,^IX,^IYの値を代入して,addrをコールする。コールが終了すると,GETREG( )と同様の処理をし,HLレジスタの値を返す。
●int CVITS(int val, buff)
 値valを10進数の文字列に直してbuffに格納し,文字列の先頭アドレスを返す。buffは6バイト必要。
●int CVRTS(real val, int buff)
 値valを10進数の文字列に直してbuffに格納し,文字列の先頭アドレスを返す。buffは単精度で18バイト,倍精度で34バイト必要。
●real CVSTR(int buff)
 buffの10進数の文字列をREAL型に変換する。変数^DEが10進文字列の終了アドレス+1を指している。
●real INT(real data)
 dataを越えない最大の整数にする。
●real FIX(real data)
 dataの小数点以下を切り捨てた値を返す。
●real FRAC(real data)
 dataの小数部を返す。
●real CINT(real data)
 dataの小数第1位を四捨五入した値を返す。
●real SQR(real data)
 dataの平方根を返す。
●real SIN(real data)
 関数SIN。
●real COS(real data)
 三角関数COS。
●real TAN(real data)
 三角関数TAN。
●real ATN(real data)
 三角関数アークタンジェント(逆正接)。
●real EXP(real data)
 指数関数。
●real LOG(real data)
 自然対数。
●real POW(real a,b)
 aのb乗を返す。
●real RAD(real data)
 度単位からラジアン単位に変換する。
●PUSH関数とPOP関数
 変数の値を一時スタックに保存するためのシステム関数。
   PUSH(式,式,…);
      ;
      ;
   POP(変数名,変数名,…);
の形で使用する。関数ではあるが式中では使用せず,必ず単独で使用すること(演算や代入の式に使ってはいけない)。動作はZ80のマシン語のPUSH,POPと同様で,PUSHする順番と逆の順番でPOPしなければならないし,型も合っていなければならない(自動的な型変換は行われない)。値を保存するスタックはプログラムのスタックそのものなので,PUSH,POPする場所については注意が必要である。また,PUSHしたら必ずその関数内でPOPしなければならない。
 例)
   PUSH(I,J,K);
   SUB();
   POP(K,J,I);
●PUSH(式,式,…)
 式の値をスタックに積む。
●POP(変数名,変数名,…)
 スタックから取り出した値を変数に代入する。
●CODE関数
 直接データをオブジェクトにするためのシステム関数。
   CODE(CODE項,CODE項,…)
の形で使用する。式中では,マシン語データを実行後,HLレジスタの値をINT型の値として返す。CODE項には以下のものがある。
●INT型定数式
 定数式の値の下位バイトを1バイトのオブジェクトにする。
●%INT型定数式
 定数式の値を下位バイト,上位バイトの順で2バイトのオブジェクトにする。
●"文字列"
 文字列をそのまま,オブジェクトにする。最後に$00はつかない。
●[式]
 式がINT型の場合は式の値をHLレジスタに代入するオブジェクトを,式がREAL型の場合は,式の値が格納されているアドレスをHLレジスタに代入するオブジェクトを作る。
●(実数定数式)
 実数値を5バイト(単精度),または8バイト(倍精度)のオブジェクトにする。
●<ラベル名>
 ラベルのアドレスを,下位バイト,上位バイトの順で2バイトのオブジェクトにする
●PRINT関数
 文字や数値を画面やプリンタに出力するシステム関数。
   PRINT(書式項,書式項,…)
の形で使用する。PRMODE関数で出力先を変えることができる。書式項には以下のものがある。
●"文字列"
 文字列をそのまま出力。
●/(スラッシュ)
 改行する。
●INT値
 INT値を10進左詰め出力。
●PN$(INT値)
 INT値を符号付き10進左詰め出力。
●FORM$(INT値a, INT値n)
 aを10進n桁右詰め出力。
●DECI$(INT値a)
 aを10進5桁右詰め出力。
●HEX2$(INT値a)
 aを16進2桁出力。
●HEX4$(INT値a)
 aを16進4桁出力。
●MSG$(INT値a)
 aのアドレスから$0Dの直前までをASCII出力。
●MSX$(INT値a)
 aのアドレスから$00の直前までをASCII出力。
●STR$(INT値a, INT値n)
 aのキャラクタをn個出力。
●CHR$(INT値a)
 aを上位バイト,下位バイトの順にASCII出力。
●REAL$(REAL値a)
 実数値を出力。
 
■エラーメッセージ
●CAN'T INCLUDE!
 INCLUDEの入れ子が深すぎる。オンメモリ版ではINCLUDEできない。入れ子は4レベルまで。
●CAN'T JUMP
 ジャンプできない。
●CONST STACK O.F.!
 定数スタックがあふれた。実数定数演算が複雑すぎる。
●CONST TBL O.F.!
 定数表がいっぱいになった。300EHの値を大きくするとよい。
●DIV BY 0
 0で割っている。
●FUNC TBL O.F.!
 関数表がいっぱいになった。3010Hの値を大きくするとよい。
●GLOBAL TBL O.F.!
 大域表がいっぱいになった。
●HASH TBL O.F.!
 ハッシュ表があふれた。3014Hの値を大きくするとよい。
●ILLEGAL ADDRESS!
 アドレス宣言のアドレスの指定が正しくない。
●ILLEGAL BRACE
 カッコのエラー。あるべきカッコがない。または開きと閉じのカッコが合わない。
●ILLEGAL CONST
 正しい定数式ではない。
●ILLEGAL STRING
 文字列エラー。20H未満のコードがある。
●ILLEGAL TYPE
 型が間違っている。
●ILLEGAL USE OF REAL!
 REAL型は使用できない。
●ILLEGAL USE OF NAME
 名前を誤使用している。
●LOCAL TBL O.F.!
 局所表がいっぱいになった。3012Hの値を大きくするとよい。
●MISMATCHED NUMBER OF ARG
 引数の数が合わない。
●MISMATCHED TYPE OF ARG
 引数の型が合わない。
●MISSING UNTIL
 UNTILがない。
●MISSING TO/DOWNTO
 TO/DOWNTOがない。
●MISSING [文字]
 あるべき文字がない。
●MISSING #IF
 $IFがない。
●NESTING O.F.!
 ループの入れ子が深すぎる。入れ子は16レベルまで。
●OUT OF MEMORY!
 メモリオーバー。もしくはオブジェクトがSOROBANと重なった。
●OUT OF RANGE
 値が大きすぎる。
●REDEF OF NAME!
 2重に宣言している。
●SYNTAX ERROR!
 文法エラー。
●TEMP TBL O.F.!
 TEMP表がいっぱいになった。実数演算が複雑すぎる。
●TOO COMPLEX!
 式が複雑すぎる。
●TOO LONG LINE!
 1行が長すぎる。1行は128文字以内。
●TOO LONG NAME!
 名前が長すぎる。名前は32文字以内。
●TOO LONG STRING
 文字列が長すぎる。
●TOO MANY ARG!
 引数が多すぎる。引数は8個まで。
●TOO MANY DATA
 データが多すぎる。
●UNDEF ARRAY
 未宣言配列。
●UNDEF FUNC
 未宣言関数。
●UNDEF LABEL
 未宣言ラベル。
●UNDEF VAR
 未宣言変数。
●#IF NESTING
 #IFは入れ子にできない。
 
(C)1991 Nobuaki Onuki(original)
(C)1997 Junji Okazaki(edited)
(C)2024 Oh!Ishi,Nibbles Lab.(formatted)