SLANG

Tweet

作:大貫 信昭
Oh!X 1988年3月号掲載/1990年1月号再掲載/1993年9月号再掲載


★ダウンロード

18バイトヘッダ付き


★プログラム情報

プログラム 3000~730Ch
スタート 3000h


★解説

 SLANGはC言語風のスタイルを持つ、S-OSオリジナルのプログラミング言語(コンパイラ)です。1パスでオブジェクトを出力するためコンパイルも高速で、最適化にも力を入れているので高速に動作するオブジェクトが出来上がります。文法は、基本的にはAlgol系を踏襲しているものの、BASICやWICSの雰囲気も感じられる、ちょっと変わった雰囲気をまとっています。

 今や8bit PICでさえもCで開発する時代、似て非なるオリジナル言語の必要性など感じにくいと思いますが、当時はC言語は16bit以上のマイコンならともかく8bitマイコンには効率が悪いと考えられ、身の丈に合ったCっぽいプログラミング言語が求められていました。

 そこに現れたSLANGは、記述性と拡張性の高さから人気を集め、たちまちのうちにS-OSにおける主要なプログラミング言語の地位を獲得しました。アセンブリ言語を除けば、おそらくFuzzyBASICと双璧を成すユーザー数を誇ると思われます。

●使い方

 SLANGはコンパイラ言語なので、まずソースを作成し、コンパイルします。エディタを内蔵していませんので、ZEDAやE-MATEなどのエディタを使う必要があります。

 SLANGをロードし、3000h番地にジャンプするとモニタが起動します(コマンドラインからソースを与えることはできません)。モニタコマンドは以下の通りです。

C filename ソースファイルをコンパイルする
ファイル名を省略した場合メモリ上のソースがコンパイルされる
C/とすることでリスト付きコンパイルとなる
X nn ソースを格納するアドレスをnnに変更
メモリ上にあるソースをコンパイルする場合はこのコマンドでアドレスを指定する
S nn1 nn2 nn3 nn4:filename オブジェクトをセーブする
nn1~nn4はそれぞれ先頭・最終・実行・格納アドレスを表す
オフセットをつけない場合はnn4を省略する
D デバイス名 ディレクトリを表示する
DV デバイス名 デフォルトデバイスを変更する
# プリンタのON/OFFを切り替える
Jnn
Gnn
アドレスnnをコールする
! S-OSのモニタにジャンプする
M 各機種のモニタにジャンプする

 コンパイル後出力されたオブジェクトはメモリ上に展開されていますのでSコマンドで保存します(自動的に保存してはくれない)。メモリにはSLANG本体がありますのでその領域に展開されるオブジェクトが作れません。その場合はオフセットを指定して空き領域に展開させ、オフセット付きでセーブするようにしてください。

●メモリマップ

◆コンパイル時
DISK版 ONメモリ版 特殊ワークエリア
0000H
 
 
 3000H
 
 
7400H
 
8000H
 
 
B000H
 
#MEMAX

S-OS
 

SLANG
 
クラスタBUFF
 
 
 
 
オブジェクト
コード
 
 
 
 
 
 
*1
 
 
 
 
*2
 
 
0000H
 
 
 3000H
 
 
7400H
 
 
 
 
B000H
 
#MEMAX

S-OS
 

SLANG
 
ソース
プログラム
 
 
 
オブジェクト
コード
 
 
 
 
 
 
*3
 
 
 
 
*2
 
 
0000H
 
 
 
 0200H
 
 
0300H
 
 
 
 

局所表
 
 

ハッシュ表
 
大域表
 
 
 
*4
 
 
 
*5
 
 
*6
 
 
 
 
     
*1 クラスタBUFFの初期値
*2 OBJ初期値の初期値。DISK版の場合8000Hにするとよい
*3 TEXT TOPの初期値
*4 局所表TOPの初期値
*5 ハッシュ表TOPの初期値
*6 大域表TOPの初期値
◆実行時 (スタックはコールされた時点のスタックを使う)
ORG宣言・WORK宣言を
省略した場合
ORG宣言を省略し、
WORK $8000とした場合
0000H
 
 
 3000H
 
 
8000H
 
 
 
 
 
 
 

S-OS
 
 
 
 
RUN TIME
 
オブジェクト
&静的ワーク
動的ワーク

 
0000H
 
 
 3000H
 
 
8000H
 
B000H
 
 
 
 
  
 
 
  

S-OS
 
 
 
 
静的ワーク
 
動的ワーク

 
RUN TIME
 
オブジェクト
&静的ワーク
の一部

●初期値およびスイッチ

 3006~3015h番地までの領域は初期値とコンパイルの動作に関するスイッチが収められています。ソースの都合に応じて適宜変更してください。

アドレス 機能 初期値 説明
3006H DISK 1 0:オンメモリ版
1:ディスク版
3007H セミコロンチェック 1 0:チェックしない
1:チェックする
3008H OBJ初期値(下位) B000H オブジェクトコードを生成する先頭アドレス。ORG宣言を省略した場合使用される。ディスク版の場合8000Hにするとよい
3009H OBJ初期値(上位)
300AH ランタイム最終ADR(下位)   ランタイムルーチンの最終アドレス。ランタイムルーチンを追加する場合変更する
300BH ランタイム最終ADR(上位)
300CH クラスタBUFF(下位) 7400H ディスク版で,ソースを読み込むための4Kバイトのワークの先頭アドレス
300DH クラスタBUFF(上位)
300EH TEXT.TOP(下位) 7400H オンメモリ版で、ソースを格納する先頭アドレスの初期値。 Xコマンドで変更することができる
300FH TEXT.TOP(上位)
3010H 局所表TOP(下位) 0000H S-OS特殊ワークエリア上に取られる局所表の先頭アドレス。通常は変更しない
3011H 局所表TOP(上位)
3012H ハッシュ表TOP(下位) 0200H S-OS特殊ワーク上に取られる大域表のためのハッシュ表のアドレス。同時に局所表の上限でもある
3013H ハッシュ表TOP(上位)
3014H 大域表TOP(下位) 0300H S-OS特殊ワーク上に取られる大域表の先頭アドレス。同時にハッシュ表の上限でもある
3015H 大域表TOP(上位)

★ライブラリ

 SLANGはMACHINE関数を使ったりランタイムルーチンを拡張することで外部で作ったマシン語ルーチンを追加関数として使用することができます。この仕組みを用いていくつかライブラリが発表されました。

ファイル入出力ライブラリ (1988年10月号)
 一般的な1文字単位でのファイル入出力関数。
実数演算ライブラリ (SOROBAN.LIB、1989年4月号)
 SOROBANを使用するためのライブラリ。
リダイレクションライブラリ (DIO.LIB、1989年12月号)
 他のOSで言う標準入出力からデータをやり取りする機能を使えるようにする。ファイル入出力ライブラリが必要。
グラフィックライブラリ (GRAPHICS.LIB、1990年9月号)
 MAGICをSLANGから扱えるようにするライブラリ。投稿作品であるBILLIARDSの制作の副産物で、必要な機能のみの実装。
NEWファイル入出力ライブラリ (1991年9月号)
 ファイル入出力ライブラリに問題が多数あったので改良したもの。DIO.LIBには対応していない。
グラフィックライブラリ (GRAPH.LIB、1992年8月号)
 MAGICの機能をフルサポートするライブラリ。ポリゴンも描画できる。SOROBAN/SOROBAN.LIBが必要。

 上記リンクからダウンロードできるバイナリには、NEWファイル入出力ライブラリが既に組み込まれています。


★SLANGリファレンスマニュアル

(※)は掲載記事にて記載されていなかった情報です。

●書式に関する規定

フリーフォーマット

 基本的にはC言語のようにフリーフォーマットで、行の概念はなく、名前などの途中以外ではどこで区切ってもよいがいくつか例外がある 。

//コメント   //以降はコメントとみなされ、その行の終わリまで無視される
“文字列”   2行にまたがることはできない 
配列   配列名と[の問を空白などで区切ることはできない 
関数   関数名と(の問を空白などで区切ることはできない 

空白

 空白は名前などの途中と配列の[および関数の(の前以外ならどこに置いてもよい 。以下のものは空白と同等である。

改行
コメント
#コマンド

コメント

注釈文。空白が置けるところなら、どこに置いてもよい。

//コメン卜   //から行の終わりまで
/*コメント*/   /*から */まで。ネスティング不可
(*コメント*)   (*から*)まで。ネスティング不可

#コマンド

 コンパイラに対する命令。空白が置けるところなら、どこに置いてもよい。

#INCLUDE ファイルネーム
 別のソースをその場所に取り込む。ネスティング不可。ファイルネーム以降は行の終わりまで無視される。オンメモリ版では使用できない
#CHAIN ファイルネーム
 続きのソースを読み込む。ファイルネーム以降はすべて無視される。オンメモリ版の場合、準備がよいかどうか聞いてくるので、なにかキーを押すと読み込みを始める。プレイクキーを仰すとコンパイルを中止する
#IF 式
#ELSE
#ENDIF
 条件付きコンパイルを行う。#IFの後ろの式が真ならば#ELSEまでを、偽ならば#ELSEから#ENDIFまてをコンパイルする

アドレス宣言

 オブジェクトコードやワークエリアの先頭アドレスを指定する。宣言を省略することもできる。

ORG宣言
 オブジェク卜コードの先頭アドレスを指定する。宣言を省略した場合はデフォルト値が使われる。実際には、先頭にランタイムルーチンがリロケー卜され、その後ろにオブジェクトコードが続く
WORK宣言
 変数や配列のワークエリアの先頭アドレスを指定する。まず静的なワークエリアが取られ、その後ろから$FFFFに向かって、動的なワークエリアが伸びていく
 宣言を省略した場合は、静的なワークエリアはオブジェクトコード中に埋め込まれ、動的なワークエリアはオブジェクトコードの後ろから$FFFFに向かって伸びていく。ただし、初期値を持つ静的なワークエリアの場合は、宣言の有無にかかわらず、オブジェクトコード中に埋め込まれる
OFFSET宣言
 コードを生成する際のオフセッ卜を指定する。ZEDAやFuzzyBASICコンパイラのOFFSETと同じ。
 宣言を省略した場合はオフセットは0となる

プログラム

 アドレス茸言、大域宣言とブロック(関数定義)からなる。必ず、

MAIN( )

という関数が必要で、プログラムを実行させることは関数MAIN( )を実行させることである。関数MAIN( )の定義はプログラムのどこにあってもよい。

ブロック

 関数頭書き、局所的宣言(静的宣言と局所宣言)と関数定義からなる。

SUB (X,Y)
 VAR I;
 BEGIN
  I=X+Y;
  RETURN (I);
 END;
    (* 関数頭書き *)
(* 静的宣言 *)
(* 関数定義 *)

 局所的なまとまりで、この中で宣言された名前はこの中でのみ有効となる。

名前の有効範囲

局所的な名前

 静的宣言や局所宣言で宣言された名前や仮引数、ラベル名は局所的な名前となり、その関数内でのみ使用できる。大域的な名前に向じ名前があった場合、局所的な名前を優先する

大域的な名前

 関数名や大域宣言で宣言された名前は大域的な名前となり、プログラム全体で使用できる。関数名以外は、宣言された以後有効となる

大域宣言

 大域的な名前を宣言する。変数や配列は静的にメモリに割り付ける。

静的宣言

 局所的な名前を宣言する。変数や配列は静的にメモリに割り付ける。

局所宣言

 局所的な名前を宣言する。変数や配列は動的に取る。ただし、そのワークエリアの合計は1関数240バイト以内でなければならない。

BYTE, ! … 1バイト型
WORD, % … 2バイト型

●データ形式

変数

 符号なし16ピット長整数を扱い、型はない。単純変数と間接変数があり、必ずVAR宣言が仮引数で宣言してから使用する。
 間接変数は、変数としても、配列としても扱える。FuzzyBASICの変数.メモリ配列の扱いと同じ。間接変数自体に型はないが、配列と して使用するため1バイト型か2バイト型かを宣言しなければならない。省略した場合は、2バイト型とみなされる。
 たとえば、POINTが2バイト型の間接変数として宣言されていたとすると、

POINT=$C000;
I=POINT[3];

では、$C006の内容を下位バイト、$C007の内容を上位バイトとして、変数Iに代入される。
 単純変数は変数としてのみ使用でき、配列としては扱えない。

VAR宣言

 変数を宣言する。仮引数リストも書式は同じ。複数の変数を宣言する場合には","(カンマ)でつなぐ。
 単純変数は

VAR HENSUU, ABC;

のように変数名を響けばよい。
 間接変数は配列として使用する際の型を宣言し、変数名に[ ]を付けた形で茸言する。

VAR BYTE POINT[ ], %KANSETU[ ];

型を省略した場合は2バイト型とみなされる。
 後ろに:定数式とすることにより、変数の格納アドレスを指定することができる。

VAR XY:$C000, BYTE Z[ ]: $D000;

と書くと、$C000と$C001を変数XYの格納アドレス、$D000と$D001を変数Zの格納アドレスとすることができる。
 二次元の間接変数も宣言可能。(※)

VAR F[][15];

 また、=定数式とすることにより、変数の初期化をすることができる。この場合、WORK宣言がなされていても、その変数のワークはプログラム中に埋め込まれる。

VAR A=0, B=3, C[ ]=$C000;

 この初期化はコンパイル時にのみ行われ.実行時には行われない。
 ただし、変数の格納アドレス指定と初期化は大域宣言と静的宣言のみ使用でき、局所宣言や仮引数リストでは使用できない。

定数

 基本的には、16ピット長の符号なし整数で0から65535までの値を取るが、2の補数表現の符号付きの整数と見ることができる。

10進数
 数字からなる文字列
例) 1234, -5
16進数
 $で始まり16進数からなる文字列か数字で始まり、かつ16進数からなり最後にHが付く文字列
例) $ABCD, 12ABH, 0FFFFH
2進数
 0と1からなる文字列で、最後にBが付く
例) 111011001010B
文字定数
 '(シングルクォーテーション)でくくった1文字で、文字のASCIIコードを値とする。エスケープ文字が使用可
例) 'A', '\N', '\'
文字列定数
 "(ダブルクォーテーション)でくくった文字列で、文字列が格納されているアドレスを値とする文字列は、オブジェク卜コード中に埋め込まれ、自動的に最後に$00が付けられる。エスケープ文字が使用可。
 ただし、2行にまたがることはできず、定数式にも使用できない
例)"メッセージ¥n"
記号定数
 CONST宣言で定義された値を持つ
$
 次に生成するオブジェクトコードのアドレスを値とする

エスケープ文字

 文字定数や文字列定数中に使われ、2文字で1文字として扱われる。\の後ろに1文字を付けた形で使用されるが、該当する文字がない場合は\だけで1文字となる。大文字と小文字の区別はしない。
(編注:この項のみ、バックスラッシュを全角文字で表記している。ブラウザや環境によっては半角¥記号がバックスラッシュとして表示されるが、誌面掲載時としてはその方が正しい表記となる。実際の使用時は当然ながら半角文字で表記すること)

\\
\" "
\' '
\N $0D
\/ $0D
\C $0C
\R $1C
\L $1D
\U $1E
\D $1F
\0 $00 (MZ以外では\は¥)

CONST宣言

 記号定数を定義する。複数の記号定数を定義する場合は"," (カンマ)でつなぐ。

CONST PC=$8001, MZ=2000;

とすると、以後PCは $8001、MZは2000という定数値を持つ。
 CONST宣言は静的宣言と局所宣言の差異はなく、どちらも局所的な記号定数の宣言となる 。

配列

 1バイト型と2バイト型がある。単純配列と間接配列とシステム配列があり、単純配列はARRAY宣言で、間接配列はVAR宣言か仮引数で間接変数として宣言してから使用する。システム配列は宣言しない。
 1バイト型は1バイト単位で、2バイト型は2バイト単位で、配列要素をアクセスする。
 アクセス時に添字のチェックはしない。システム配列はメモリやI/O、S-OS特殊ワークエリアを配列の形で直接アクセスする。
 単純配列はARRAY宣言で宣言する。たとえば、

ARRAY BYTE BUFF[10];

と宣言すると、 1バイト数の配列がBUFF[0]からBUFF[10] ま で の11個確保される。単純配列名は配列のワークの先頭のアドレスを指す定数として扱われるが、動的な(局所宣言で宣言された)配列名は定数式には使用できない。
 間接配列は間接変数を配列として使用する。 間接変数の値をインデックスとしてメモリをアクセスする。FuzzyBASICのメモリ配列と同じ。型は間接変数を宣言する際に指定する。省略した場合は2バイト型と見なされる。また、間接配列名は変数である。

ARRAY宣言

 単純配列を宣言する。複数の配列を宣言する場合は","(カンマ)でつなぐ。

ARRAY BYTE ABUF[5], WORD C[3];

のように型配列名[定数式]の形で宣言すると、定数式+1個分の配列が確保される。添字を省略すると0とみなされ、1個分の配列が確保される。型を省略すると、2バイト型とみなされる。
 二次元までの配列変数を宣言可能。

ARRAY BYTE ABC[5][3];

 後ろに:定数式とすると、配列の格納アドレスを指定することができる。

ARRAY ABC[10]: $C000;

とすると、$C000以降を配列ABCのワークエリアとし、ABC[0]の格納アドレスは$C000と$C001、ABC[1]は$C002と$C003、ABC[2]は$C004と$C005、……となる(配列ABCは2バイト型のため)。
 この場合、添字は意味を持たないので、

ARRAY ABC[ ]: $C000;

としてもよい。
また={CODEリスト}とすると、配列を初期化することができる。ただし、{ }は文括狐。この場合、WORK宣言がなされていても、その配列のワークエリアは.プログラム中に埋め込まれる。

ARRAY BYTE DT[4]={0, 1, 2, 3, 4};

 初期値が足りない場合は、残りは0で埋められる。多すぎる場合は、エラーとなる。添字が省略された場合はチェックしない。
 ただし、配列の格納アドレス指定と.初期化は、大域宣言と静的宣言のみで使用でき、局所宣言では使用できない。

●関数

関数頭書き

 定義する関数名を宣言する。ブロックの最初に書き、以後、静的宣言や局所宣言、関数定義が続く。

関数名(仮引数リスト)

の型で書く。
 仮引数リストの書式は、局所宣言のVAR宣言の書式と同じ。
仮引数を持たない場合は、

関数名( )

と書く。
 仮引数は関数コール時の実引数の値を持ち(値渡し)、自動的に動的な局所変数として宣言される。
MACHINE宣言されたマシン語関数は、

関数名(引数の数)

と書く。ただし、引数の数が0個の場合と、引数の数を省略して宣言する場合は、

関数名( )

と書く 。

関数定義

 関数を定義する。

BEGIN
  局所宣言;
  文;
  …
  文;
END;

の形で書く。

END(式);

とすると、式の値を関数の値として返すことができる。

関数

 ユーザー関数とシステム関数とMACHINE関数がある。
 ユーザー関数はプログラム中で定義した関数。引数を渡すのにIYレジスタをポインタとして使用する。
 システム関数には、CODE関数とPRINT関数がある。
 MACHINE関数はMACHINE宣言した関数で、ユーザ一関数と異なり、レジスタやスタックを使って引数を渡す。主に、外部のマシン語サブルーチンをMACHINE関数として宣言するが、プログラム中でCODE関数を使って定義したマシン話関数もMACHINE関数とすることができる。

関数コール

 値渡しである。

関数名(実引数リスト)

の形で関数を呼び出す。
 実引数と仮引数の数が合わないと、エラーになる。

RETURN (式);

や、

END (式);

によって返される値が関数の値となる。
 MACHINE関数で引数の数を省略して宣言した場合のみ、引数の数のチェックを行わない。

MACHINE宣言

 マシン語関数を宣言する。複数のマシン語関数を宣言する場合は"," (カンマ)でつなぐ。

関数名(引数の数)

の形で宣言する。ただし、その関数を使用、定義する前に宣言しなければならず、また、大域宣言でのみ宣言できるので、通常、アドレス宣言の次の大域宣言で宣言する 。

MACHINE MSUB(2): $C000;

のように後ろに:定数式を付けると、外部にあるマシン語サブルーチンを関数として利用できる。上の場合MSUBは$C000にあり、引数を2個持つ関数となる。
 引数の数が0個の場合は、マシン語関数ではなく、引数を持たないふつうの関数として扱われるので、 プログラム内の関数の宣言は無意味である。外部の関数の宣言に使う。

MACHINE MON(0): $1F8E;

 引数の数が1個から3個までの場合は、レジスタを使って引数を渡す。
 引数の数が4個以上の場合は、スタックを使って引数を渡す。
 引数の数を省略した場合は、スタックを使って引数を渡し、HLレジスタに引数の数が代入される。この場合に限り、引数の数のチェックは行わない。

MACHINE PRINTF( );

関数コールの実際

 引数や、動的な変数や配列のポインタとしてIYレジスタを使用している。
 実引数の場合、

SUB (A, B)

とすると、

LD   HL, (VARA)
LD   (IY+$70), L
LD   (IY+$71), H
LD   HL, (VARB)
LD   (IY+$72), L
LD   (IY+$73), H
CALL   SUB

というコードが生成される。一方、関数側では、たとえば、

SUB(I, J)
 VAR K;
 BEGIN
   VAR L;
   〜
 END;
    (* 仮引数 *)
(* 静的宣言 *)

(*局所宣言*)

となっていたとすると、動的な変数は3個(I, J, L)となり、関数の最初と最後に、

PUSH
LD
ADD

POP
  IY
BC, 6 ; 3個×2バイト
IY, BC

IY

というコードが生成される。
 ただし、動的な変数や配列がない場合は、なにも生成されない。
 この関数内での動的な変数のアドレスは次のようになる。

I …… (IY+$6A) 下位
(IY+$6B) 上位
J …… (IY+$6C) 下位
(IY+$6D) 上位
L …… (IY+$6E) 下位
(IY+$6F) 上位

 つまり、Iの初期値は実引数Aの値、Jの初期値は実引数Bの値、Lの初期値は不定となる。
 実引数用のワークは(IY+$70)から(IY+$7F)までであるため、引数の数は最大8佃までとなる。実引数に関数を使用する場合、引数が8個以下でもワークがあふれてしまいエラーになる場合があるので注意すること 。
 動的な変数や配列のワークは(IY+$80)から(IY+$6F)までの240バイトしかないので. 大きな動的配列を宣言する場合は、注意すること。
 関数の値は、関数から戻ってきたときのHLレジスタの値となる 。
 MACHINE関数の場合は、宣言した引数の数によって呼び出し方が異なる。

0個 ……CALLのみ
1個 ……HLレジスタに引数を代入してCALL
2個 ……順にHL,DEに代入してCALL
3個 ……順にHL,DE,BCに代入してCALL
4個以上 ……スタックに積んでCALL
省略 ……スタックに積み、HLに引数の数を代入してCALL

例)スタックに積んだ様子 SUB(A,B,C);

アドレス大
 
  
 
 
SP
アドレス小
 
A
B
C
リターンアドレス
 

 MACHINE関数で、動的な変数や配列を使用する場合も、ユーザー関数と同様のIYレジスタの退避が行われるので注意すること。
 関数の値は、関数から戻ってきたときのHLレジスタの値となる。

●演算子

式はすべて16ビット長で演算を行う。
真は1、偽は0。

ビット演算子

AND   論理積
OR   論理和
XOR   排他的論理和
CPL   ビット反転
<<   左シフト
>>   右シフト
HIGH   上位8ビットを値とする
LOW   下位8ビットを値とする

論理演算子(真のとき1、偽のとき0を値とする)

NOT         論理否定

関係演算子 (真のとき1、偽のとき0を値とする)

==   等しい
<>   等しくない
!=  
>   大きい
>=   大きいか等しい
<   小さい
<=   小さいか等しい

代入演算子

=            代入

カンマ演算子

,            左から右へ計算され、最も右の論理項を値とする

算術演算子

+ (単項)   正符号
- (単項)   負符号
+   加算
-   減算
*   乗算
/   除算
MOD   剰余算

ピリオド演算子(符号付きで演算を行う)

.*. ./. .MOD. .<<. .>>. .<=. .>=. .<. .>.

その他

++    インクリメント演算
 変数や配列の値に1を加える。変数や配列の前に置いた場合は、+1してから値が参照され、後ろに置いた場合は、値が参照されてから+1する
--    デクリメン卜演算子
 変数や配列の値から1を引く。前置き、後ろ置きの規則は++と同じ
&    アドレス演算子
 変数や配列が格納されているアドレスを値とする。ただし、システム配列には使用できない
?:   C言語の条件演算子と同じ。三項演算子

演算の優先順位

  1. ( ) [ ]
  2. ++ -- &
  3. + - HIGH LOW NOT CPL(すべて単項演算子)
  4. * / MOD << >> .*. ./. .MOD. .<<. .>>.
  5. + -
  6. == <> != <= >= <> .<=. .>=. .<. .>.
  7. AND OR XOR
  8. ? : (三項演算子)
  9. =
  10. , (カンマ)

●システム構成

 { }は文括弧を表す。文括弧として[ ]、( )、「」、BEGIN END; が使用できる。[ ]は省略可を表す。

ラベル

ラベル名:
 GOTO文やEXIT TO文のジャンプ先を指定する。ラベル名は局所的な名前となる。

式文

式;
 式の文。

復合文

{文 [, 文, …, 文]}
 複数の文を文括弧でくくり、ひとつの文として扱う。

空文

;
 なにもしない文。

IF文

IF 文 {THEN} 文1 [ELSE 文2] [ENDIF;]
 式の値が真ならば文1、偽ならば文2を実行する。
 文2がIF文の場合、ELSE IFをELSEIFまたはEFと書くことができる。

FOR文

FOR  単純変数名= 式1  TO  式2  [DO] 文  [NEXT;]
DOWNTO
 単純変数の値を式lから式2になるまで1ずつ増やし、文を繰り返す。DOWNTOの場合は1ずつ減らす。
 まず文を実行してから、終値の判定を行う 。 ただし、式1と式2が問に0をはさむ場合は、期待される繰り返しは行われず、1回で繰り返しを終了する。

WHILE文

WHILE 式 [DO] 文 [WEND;]
 式の値が真のあいだ、文を繰り返す。

REPEAT文

REPEAT 文 UNTIL 式 ;
 式の値が真になるまで、文を繰り返す。

LOOP文(※)

LOOP 文 ;
 永久ループ。WHILE文の式の値が常に真/REPEAT文の式の値が常に偽であるのと同等。

EXIT文

EXIT;
 FOR文、WHILE文、REPEAT文から脱出する。C言語のbreak文と同じ。
EXIT TO ラベル名;
 ラベルにジャンプする。ただし、あと戻りはできない。
EXIT(式);(※)
 式の値の数だけループを抜ける。

RETURN文

RETURN;
 その関数を終了して、呼び出した関数に戻る。
RETURN(式);
 式をその関数の値として、呼び出した関数に戻る。

GOTO文

GOTO ラベル名;
 ラベルにジャンプする。EXIT TOラベル名;と違って、ジャンプ先に制限はない。

CASE文

CASE 式0 [OF] {
  定数式1[:]文1
  [定数式2[:]文2]
  … … …
  [OTHERS[:]文]
}

 式0の値が定数nと等しければ、文nを実行し、CASE文を脱出する。上から順に比較していき、いずれの定数式とも等しくなかった場合は、OTHERSの後ろの文を実行する。

定数式1 TO 定数式2[:]文1

とすると、式0の値が定数式1以上、定数式2以下の場合、文1を実行する。

定数式1, [定数式2, …,] 定数式n [:]文1

とすると、式0の値が定数式lから定数式nまでのいずれかに等しい場合、文1を実行する。

登録済みの名前

 システム関数やシステム配列など、登録済みの名前は、すべて大域的な名前である。

登録済みの記号定数

FALSE 値は0
TRUE 値は1

システム配列

MEM[式] 式の値のアドレスの内容を1パイト単位でアクセスする
MEMW[式] 式の値のアドレスの内容を2パイト単位でアクセスする。式のアドレスが下位バイト、式+1のアドレスが上位バイトに対応する
PORT[式] 式の値のI/Oポートをlバイト単位でアクセスする
PORTW[式] 式の値のI/Oポートを2バイト単位でアクセスする。式のI/Oポートが下位バイト、式+1のI/Oポートが上位バイトに対応する。下位バイト、上位バイトの順にアクセスされる
SOS[式] 式の値のS-O5特殊ワークエリアをlバイト単位でアクセスする
SOSW[式] 式の値のS-OS特殊ワークエリアを2バイト単位でアクセスする。式の特殊ワークエリアが下位バイト、式+1の特殊ワークエリアが上位バイトに対応する

登録済みの変数

^A   CALL関数. GETREG関数で使用。CALL関数では値をAレジスタに代入してからマシン語ルーチンをコールし、終了後Aレジスタの値が代入される。^は↑でも可
^BC   Aと問様
^DE   Aと同様
^HL   Aと問様
^IX   Aと問様
^IY   Aと問様 
^AF   Aと問様。^AFの上位バイトと^Aの下位パイ卜は同じ値を持つ
^SP   CALL関数 .GETREG関数で使用。現在のSPの値が代入される
^CARRY   CALL関数、GETREG関数で使用。CYフラグが立っていればい1、立っていなければ0が代入される
^CY  
^ZERO   Zフラグ。^CARRYと問様
@KBUFF   キ一入力用パッファのアドレスを値として持つ。代入すると、S-OSの#KBFADの値が変わってしまうので注意すること

登録済みの基本関数

BEEP( )
 BEEP音を鳴らす。S-OSの#BELL
STOP( )
 プログラムの実行を終了する
LOCATE(X座標, Y座標)
 カーソルを移動する
INKEY(n)
入力されたキーの値を返す
n=0のときS-OSの#GETKYと同じ
n=1のときS-OSの#FLGETと同じ
その他のときS-OSの#INKEYと同じ
INPUT( )
 キーボードから入力された数値を返す。先頭に$を付けると、16進数とみなす。コールした時点のカーソル以降を読み込み、正常な入力が行われた場合は^CARRY=0、ブレイクキーが押されたり誤入力があった場合は^CARRY=1となる
GETL(格納アドレス)
 キーボードから1行入力し、格納アドレスに格納し、行の長さを返す
 ブレイクキーが押された場合は-1を返す。行の最後は0となる
GETLlN (格納アドレス, 長さ)
 l行の最大長を指定できるほかは、GETL関数と同じ。オーバーした分は無視される
LlNPUT(格納アドレス, 長さ)
 コールし た時点のカーソル以降は続み込むほかはGETLlN関数と同じ
WIDTH(n)
 画面モード(40キャラ、80キャラ)を切り替える。nが40以下だと、40キャラ、40より大きいと80キャラとなる。S-OSの#WIDCH
SCREEN(X座標, Y座標)
 画面のキャラクタを読み出し、キャラクタコードを返す。S-OSの#SCRN
PRMODE(n)
 PRINT関数の出力を切り替える
n=0のとき、画面にのみ出力
n=1のとき、画面とプリンタに出力
その他のとき、プリンタのみに出力
BIT(値, n)
 値の第nビットを調べ、0かlを返す
 nの値は0から15まで
SET(値, n)
 値の第nピットを1にする
RESET(値, n)
 値の第nビットを0にする
ABS(n)
 nを2の補数表現の符号付きの値とみなし、その絶対値を返す
SEX(n)
 nを符号付き1バイトの値とみなし、符号付き2バイトの値にして返す
SGN(n)
 nを符号付きの値とみなし、正なら1、0なら0、負なら-1を返す
RND(n)
 0からn-1までの乱数を返す
VTOS(値, BUFF)
 値を10進数の文字列に直してBUFFに格納する。文字列の最後は$00になる。BUFFは6バイト必要
GETREG( )
 各レジスタなどの値、それぞれ変数、^AF, ^BC, ^DE, ^HL, ^IX, ^IY, ^CARRY, ^ZERO, ^5Pに代入する。単独で用いること
CALL(アドレス)
 各レジスタに、変数^A, ^BC, ^DE, ^HL, ^IX, ^IYの値を代入して、アドレスをコールする。コールが終了すると、GETREG( )と問機の処理をし、HLレジスタの値を返す

システム関数

 CODE関数とPRINT関数がある。

CODE関数

 直接データをオブジェクトに落とすための関数。式中で使われる場合は、マシン語データを実行後、HLレジスタの値を値とする.

CODEリスト

 CODE関数や配列の初期化など、データを直接オブジェクトに落とすための書式。CODE項を","(カンマ)でつなぐ。

CODE項

"文字列"
 文字列をそのまま、オブジェクトに落とす。文字列定数のように、自動的に最後に$00を付けることはしない
[式]
 式の値をHLレジスタに代入するようなオブジェクトを作る。その他のレジスタの値は保証されない
<ラベル名>
 ラベルのアドレスを、下位バイ卜、上位バイトの順で2バイトのオブジェクトにする
型, 定数式
 1バイト型なら、定数式の値の下位バイトを1バイトのオブジェクトにし、2バイト型なら、下位バイト、上位バイトの順で2バイトのオブジェクトにする。型を省略した場合は1バイト型とみなされる

PRINT関数

 文字や数値を画面やプリンタに出力する。PRMODE関数で出力先を変えることができる。

書式リスト

 PRINT関数の書式。書式項を","(カンマ)でつなぐ。

書式項

"文字列"   文字列をそのまま出力
/(スラッシュ)   改行する
  値を10進左詰め出力
FORM$(値, n)   値を10進n桁右詰め出力
DECI$(値)   値を10進5桁右詰め出力
%(値)   
PN$(値)   値を符号付き10進左詰め出力
HEX2$(値)   値を16進2桁出力
HEX4$(値)   値を16進4桁出力
MSG$(値)   値のアドレスから$0Dの直前までをASCII出力
MSX$(値)   値のアドレスから$00の直前までをASCII出力
!(値)  
STR$(値, n)   値のキャラクタをn個出力
CHR$(n)   値を上位バイト、下位バイトの順にASCII出力
SPC$(n)   空白をn個出力
CR$(n)   改行をn個出力
TAB$(n)   力一ソルをn回右へ移動

●エラーメッセージ

Missing   "文字" あるべき文字がない
Syntax error   文法エラー
Illegal constant   正しい定数式ではない
Illegal brace   文括弧エラー。あるべき文括弧がない。また開きと閉じの括弧が合わない
Bad string   文字列エラー。$20以下のコードがある
Illegal name   名前を誤使用している
Dup def name   二重に宣言している
Undef array   未宣言配列
Undef var   未宣言変数
Illegal address   アドレス宣言のアドレス指定が正しくない
Too many arguments   引数が多すぎる。引数のワークは8個分しかない
Too many data   データが多すぎる
Out of range   値が大きすぎる
Local area overflow   局所域がいっぱいになった。動的局所域は240バイトしかない
Unmatched arguments   引数の数が合わない
Dev by 0   0で割っている
Missing UNTIL   UNTILがない
Missing TO/DOWNTO   TO/DOWNTOがない
Can't jump   ジャンプできない
Nesting overflow   ループの入れ子が深すぎる。16レベルまで
Global table overflow   大域表がいっぱいになった
Local table overflow   局所表がいっぱいになった
Too long line   1行が長すぎる。1行は255文字以内に収める
Too long name   名前が長すぎる。名前は32文字以内に収める
Can't include   INCLUDEできない。オンメモリ版ではINCLUDEできない。入れ子は8レベルまで
Undef func   未宣言関数
Undef label   未宣言ラベル
Memory over   メモリがオーパーした

★ファイル入出力ライブラリ

●追加関数

 アドレスはライブラリ先頭アドレスからのオフセットである。

•FOPEN(FNO, FNAME, MODE)

機能:ファイルをオープンする
アドレス:0048H
 FNO(HL):ファイルナンパー
 FNAME(DE):ファイル名が格納されている先頭アドレス
 MODE(BC):オープンモード
      0:読み込み専用
      1:書き込み専用
      2:読み書き両用
      3:新規オープン
戻り値
正常終了:Cy=0, A=0
    H=0, L=0
エラー :CY=1, A=エラーナンバー
    H=FFH, L=エラーナンバー

•FSEEK(FNO, OS, MODE)

機能:ファイルポインタを移動する
アドレス:01C5H
 FNO(HL):ファイルナンバー
 OS(DE):ファイルポインタの移動位置のオフセット
 MODE(BC):移動位置の基準
      0:ファイルの先頭 (OSの値は 0~65535 とみなされる)
      1:現在のファイルポインタの位置 (OSの値は-32768~32767とみなされる)
      2:ファイルの終端(OSの値は-65535~0とみなされる)
戻り値
正常終了:Cy=0, A=0
    HL=移動後のファイルポインタの位置
エラー :Cy=1, A=エラーナンバー
    HL=FFFH

•FPUTC(FNO, CHR)

機能:ファイルに1バイトデータを書き込む
アドレス:0216H
 FNO(HL):ファイルナンバー
 CHR(DE):書き込む1バイトデータ
戻り値
正常終了:Cy=0、A=0
    H=0, L=0
エラー :Cy=1, A=エラーナンバー
    H=FFH, L=エラーナンバー

•FGETC(FNO)

機能:ファイルから1バイトデータを読み込む
アドレス:0225H
 FNO(HL):ファイルナンバー
戻り値
正常終了:Cy=0, A=0
    H=0, L=読み込んだデータ
エラー :Cy=1, A=エラーナンバー
    H=FFH, L=エラーナンバー

•FCLOSE(FNO)

機能:ファイルをクローズする
アドレス:030FH
 FNO(HL):ファイルナンバー
戻り値
正常終了:Cy=0, A=0
    H=0, L=0
エラー :Cy=1, A=エラーナンバー
    H=FFh, L=エラーナンバー

●エラーナンバー

 関数でエラーが発生したときにエラーナンバーを返すが、S-OSで決められているエラー番号1~14のほかに15~20の番号を返す場合がある 。それらの意味は以下のとおり。

15 Bad Device

 デパイスがディスクではない

16 Open Mode Error

 読み込みモードでオープンしたファイルに書き込みを行おうとした。あるいは害き込みモードでオープンしたファイルから読み込みを行おうとした

17 Out of File

 ファイルポインタがファイル外になった

18 Already Open

 オープンしようとしたファイルナンバーがすでにオープン中のファイルに存在する

19 Double Open

 オープンしようとしたファイルがすでにほかのファイルナンバーでオープンされている

20 Too Long Flie

 ファイルサイズが長すぎる (65535パイ卜を超えている)

●ワークエリア

 これらのワークエリアはファイルオープン中に書き換えてはならない。

0000H : ディスクアクセスをセクタ単位で行うかクラスタ単位で行うかの指定(初期値は1)
0:セクタ単位(ランダムっぽいアクセス向き)
1:クラスタ単位(シーケンシャルっぽいアクセス向き)
0001H : FATバッファの先頭アドレス(下位)
0002H : FATバッファの先頭アドレス(上位)

 このアドレスから400HバイトをFATバッファとして使用。ただし、使用するデバイスが3つ以下の場合には 、デバイスの数x100Hバイトを使用する。

0003H : ファイルアクセス用のデータバッファの先頭アドレス(下位)
0004H : ファイルアクセス用のデータバッファの先頭アドレス(上位)

 ディスクアクセスをセクタ単位で行う場合は、このアドレスから400Hバイトを使用。 クラスタ単位の場合は4000Hバイトを使用する。
 なお、FATバッファの初期値はC800H、データバッファの初期値はCC00Hになっている。