MikoScript3 言語仕様
入出力形式
ファイルやバッファの入出力では、様々な形態のデータが対象になります。
これらの個々のケースごとに多種類の入出力関数を設けるのは、あまり得策
ではありません。本言語では、入出力関数を、.Read と .Write に統一し、
データ側に、入出力形式を設定するようになっています。
以下に、本言語での入出力形式の一覧を示します。
ASCIIコード列(固定長)の入出力形式:
'C(n) ASCII n 桁の一般文字列
'I(n) ASCII n 桁の整数(10進)表記文字列
'X(n) ASCII n 桁の整数(16進)表記文字列
'F(n) ASCII n 桁の実数(f型)表記文字列
文字列(任意符号化方式)の入出力形式:
'T(n) 一般文字列(固定長)
'LINE 改行終端文字列(可変長)
'LN (同上)
'CSZ 0終端文字列(可変長)
バイナリーデータ(固定長)の入出力形式:
'BYTE 8 ビット整数(符号有り)
'UBYTE 8 ビット整数(符号無し)
'SHORT 16 ビット整数(符号有り)
'USHORT 16 ビット整数(符号無し)
'LONG 32 ビット整数(符号有り)
'ULONG 32 ビット整数(符号無し)
'FLOAT 32 ビット実数
'DOUBLE 64 ビット実数
ビットフィールド(固定長)の入出力形式:
'BIT_FIELD(n) n バイトのビットフィールド
'BIT(n) or 'UBIT(n) n ビット整数値(符号無し)
'SBIT(n) n ビット整数値(符号有り)
構造体の入出力形式
'STRUCT
これらの入出力形式は、所定のリレー型関数(詳細後述)で、入出力対象の変数や定数
に設定します。それを、入出力関数(ファイル/バッファの .Read, と .Write 関数)に
渡すと、それに応じて入出力動作が行なわれます。
このように、入出力形式とは、入出力対象のデータと、実際に入出力されるデータとの
変換仕様を規定するものです。
変数や定数に入出力形式を設定しても、入出力以外の殆どの動作には影響しません。
例えば、ある変数に 'BYTE の入出力形式を設定しても、通常通り、その箱に整数や実数、
あるいは、文字列等を代入することができます。また、この箱を、演算式に使っても、
それが、BYTE の精度になるわけではありません。
ところで、本言語の入出力形式の仕様は、他のスクリプト言語には、あまり見られない
かもしれません。本仕様の一部は、COBOL を参考にしていますが、大部分は、本言語独自
のものです。
特定の符号化方式の文字コード列(固定長)を出力する場合
内部形式の文字列( UTF-16(LE) )や、数値(整数/実数)を、特定の符号化方式の
n 個の文字コード列に変換して出力する場合、次の4形式があります。
(*1) 文字列 → n 個の文字コード列
内部形式の文字列を(特定の符号化方式の)文字コード列に変換し、そのコード数が、
n と同じならそのまま、n 未満なら不足分に 0 値を補充し、n を超えれば余った分を
カットして、出力します。なお、この変換で変換不能なコードは、特別なコードに変換
します。( ⇒ 参照 )
(*2) 整数値 → 10進表記の n 個の文字コード列
内部形式の整数値を 'd 変換した文字列を(特定の符号化方式の)文字コード列に
変換し、そのコード数が、n と同じならそのまま、n 未満なら不足分に 0 値を補充し、
n を超えれば次のようにして出力します。その整数値が正なら、その末尾から n 桁部分
を出力し、負なら、マイナス符号(-)と末尾からの n - 1 桁部分を出力します。
(*3) 整数値 → 16進表記の n 個の文字コード列
内部形式の整数値を 'x 変換した文字列を(特定の符号化方式の)文字コード列に
変換し、そのコード数が、n と同じならそのまま、n 未満なら不足分に 0 値を補充し、
n を超えればその末尾から n 桁のコード部分を出力します。
(*4) 実数値 → f型表記の n 個の文字コード列
内部形式の実数値を 'f 変換した文字列を(特定の符号化方式の)文字コード列に
変換し、そのコード数が、n と同じならそのまま、n 未満なら不足分に 0 値を補充し、
n を超えれば次のようにして出力します。まず、小数点以下の下位の方の桁からカット
します。それでも超過する場合、整数部の上位の方の桁からカットします。このような
対処で、丁度 n 桁になるようにして、出力します。
特定の符号化方式の文字コード列(固定長)を入力する場合
特定の符号化方式の n 個の 文字コード列を、内部形式の文字列( UTF-16(LE) )や
数値(整数/実数)に変換して入力する場合、次の4形式があります。
なお、この形式の入力では、入力データが足りない場合、例外が発生します。また、
この変換で変換不能なコードは、特別なコードに変換されます。( ⇒ 参照 )
(*5) n 個の文字コード列 → 文字列
入力文字コード列の先頭から順に走査して、0 終端( 0 値のコード)があればそこ
まで、なければ n 個まで取り込んで、内部形式( UTF-16(LE) )に変換した文字列が
本入力値になります。
(*6) 10進表記の n 個の文字コード列 → 整数値
(*5) のように入力した文字列を 'int(10) 変換した整数値が、本入力値になります。
(*7) 16進表記の n 個の文字コード列 → 整数値
(*5) のように入力した文字列を 'int(16) 変換した整数値が、本入力値になります。
(*8) 実数表記の n 個の文字コード列 → 実数値
(*5) のように入力した文字列を 'float 変換した実数値が、本入力値になります。
●ASCIIコード列(固定長)の入出力形式
変数や定数の値を、そのまま入出力するのではなく、ASCIIコード列に変換して入出力
する場合に、この形式を使います。ちなみに、既存の外部ファイルに、この形式で格納
されている場合はよくあります。また、外部プログラムと文字列データをやり取りする
場合にも、この形式はよく使われます。
以下に、この関連のリレー型関数について説明します。なお、1 個の ASCIIコードは、
1 バイトになります。
T'C(n) ASCII n 桁の一般文字列
機能: 対象 T に「ASCII n 桁の一般文字列」を示す入出力形式を設定します。
説明: この入出力形式は、次の対象に設定可能です。
・定文字列、または、文字列変数
・数値(整数、実数)の定数、または、変数
・空箱(この箱は本形式設定後、空文字列の箱に変わります)
対象の箱が不在の場合、空文字列の箱として新規に生成します。
n の有効範囲は、0 〜 1000 です。
n が省略時、n = 1 として扱います。
返値: 対象が箱の時にはその箱への参照を返し、実値の時にはその値自身を返します。
対象が不正な時、null を返します。
出力: 本形式が設定された変数/定数が、出力関数の引数に指定された場合、
各データ型に応じて、次のように、n 個の ASCIIコード列が出力されます。
・(*1) 文字列 → n 個の ASCIIコード列
・(*2) 整数値 → 10進表記の n 個の ASCIIコード列
・(*4) 実数値 → f型表記の n 個の ASCIIコード列
入力: 本形式が設定された変数が、入力関数の引数に指定された場合、この変数には、
・(*5) n 個の ASCIIコード列 → 文字列
のように入力された文字列が代入されます。
T'I(n) ASCII n 桁の整数(10進)表記文字列
機能: 対象 T に「ASCII n 桁の整数(10進)表記文字列」を示す入出力形式を設定
します。
説明: この入出力形式は、次の対象に設定可能です。
・数値(整数、実数)の定数、または、変数
・定文字列、または、文字列変数
・空箱(この箱は本形式設定後、空文字列の箱に変わります)
対象の箱が不在の場合、空文字列の箱として新規に生成します。
n の有効範囲は、0 〜 120 です。
n が省略時、n = 6 として扱います。
返値: 対象が箱の時にはその箱への参照を返し、実値の時にはその値自身を返します。
対象が不正な時、null を返します。
出力: 本形式が設定された変数/定数が、出力関数の引数に指定された場合、
各データ型に応じて、次のように、n 桁 ASCIIコード列が出力されます。
・(*2) 整数値 → 10進表記 n 桁 ASCIIコード列
・実数値 → (*2) 整数値 → 10進表記 n 桁 ASCIIコード列
・文字列 → (*2) 整数値 → 10進表記 n 桁 ASCIIコード列
入力: 本形式が設定された変数が、入力関数の引数に指定された場合、この変数には、
・(*6) 10進表記 n 桁 ASCIIコード列 → 整数値
のようにして入力された整数値が代入されます。
T'X(n) ASCII n 桁の整数(16進)表記文字列
機能: 対象 T に「ASCII n 桁の整数(16進)表記文字列」を示す入出力形式を設定
します。
説明: この入出力形式は、次の対象に設定可能です。
・数値(整数、実数)の定数、または、変数
・定文字列、または、文字列変数
・空箱(この箱は本形式設定後、空文字列の箱に変わります)
対象の箱が不在の場合、空文字列の箱として新規に生成します。
n の有効範囲は、0 〜 120 です。
n が省略時、n = 6 として扱います。
返値: 対象が箱の時にはその箱への参照を返し、実値の時にはその値自身を返します。
対象が不正な時、null を返します。
出力: 本形式が設定された変数/定数が、出力関数の引数に指定された場合、
各データ型に応じて、次のように、n 桁 ASCIIコード列が出力されます。
・(*3) 整数値 → 16進表記 n 桁 ASCIIコード列
・実数値 → (*3) 整数値 → 16進表記 n 桁 ASCIIコード列
・文字列 → (*3) 整数値 → 16進表記 n 桁 ASCIIコード列
入力: 本形式が設定された変数が、入力関数の引数に指定された場合、この変数には、
・(*7) 16進表記 n 桁 ASCIIコード列 → 整数値
のようにして入力された整数値が代入されます。
T'F(n) ASCII n 桁の実数(f型)表記文字列
機能: 対象 T に「ASCII n 桁の実数(f型)表記文字列」を示す入出力形式を設定
します。
説明: この入出力形式は、次の対象に設定可能です。
・数値(整数、実数)の定数、または、変数
・定文字列、または、文字列変数
・空箱(この箱は本形式設定後、空文字列の箱に変わります)
対象の箱が不在の場合、空文字列の箱として新規に生成します。
n の有効範囲は、0 〜 120 です。
n が省略時、n = 6 として扱います。
返値: 対象が箱の時にはその箱への参照を返し、実値の時にはその値自身を返します。
対象が不正な時、null を返します。
出力: 本形式が設定された変数/定数が、出力関数の引数に指定された場合、
各データ型に応じて、次のように、n 桁 ASCIIコード列が出力されます。
・(*4) 実数値 → f型表記 n 桁 ASCIIコード列
・整数値 → (*4) 実数値 → f型表記 n 桁 ASCIIコード列
・文字列 → (*4) 実数値 → f型表記 n 桁 ASCIIコード列
入力: 本形式が設定された変数が、入力関数の引数に指定された場合、この変数には、
・(*8) 実数表記 n 桁 ASCIIコード列 → 実数値
のようにして入力された実数値が代入されます。
●文字列(任意符号化方式)の入出力形式
文字列のデータは、各種のファイルに格納されているだけでなく、外部プログラムとの
やり取りなどでも、よく使われます。また、文字列の文字コードには、いろいろな符号化
方式があります。
以下のリレー型関数を使えば、所定の形式で入出力する際に、文字コードの符号化方式
が自動的に変換されます。
T'T(n) 一般文字列(固定長)
機能: 対象 T に「一般文字列(固定長)」を示す入出力形式を設定します。
説明: この入出力形式は、次の対象に設定可能です。
・定文字列、または、文字列変数
・数値(整数、実数)の定数、または、変数
・空箱(この箱は本形式設定後、空文字列の箱に変わります)
対象の箱が不在の場合、空文字列の箱として新規に生成します。
n の有効範囲は、0 〜 1000 です。
n が省略時、n = 1 として扱います。
返値: 対象が箱の時にはその箱への参照を返し、実値の時にはその値自身を返します。
対象が不正な時、null を返します。
出力: 本形式が設定された変数/定数が、出力関数の引数に指定された場合、
各データ型に応じて、次のように、n 個の文字コード列が出力されます。
・(*1) 文字列 → n 個の文字コード列
・(*2) 整数値 → 10進表記の n 個の文字コード列
・(*4) 実数値 → f型表記の n 個の文字コード列
いずれの場合でも、出力される文字列は、'CharEnc で指定された符号化方式に
変換された文字コードになります。
入力: 本形式が設定された変数が、入力関数の引数に指定された場合、この変数には、
・(*5) n 個の文字コード列 → 文字列
のように入力された文字列が代入されます。
なお、読み込まれるデータの文字コードは、'CharEnc で指定された符号化方式
から、内部形式の符号化方式( UTF-16(LE) )へ変換されます。
T'LINE or T'LN 改行終端文字列
機能: 対象 T に「改行終端文字列」を示す入出力形式を設定します。
説明: 'LN は、'LINE の簡略形です。どちらを使っても機能は同じです。
この入出力形式は、次の対象に設定可能です。
・定文字列、または、文字列変数
・数値(整数、実数)の定数、または、変数
・空箱(この箱は本形式設定後、空文字列の箱に変わります)
対象の箱が不在の場合、空文字列の箱として新規に生成します。
対象が無い場合、空文字列として扱われます。
返値: 対象が箱の時、その箱への参照、実値の時、その値自身を返します。
対象が不正な時、null を返します。
出力: 本形式が設定された変数/定数が、出力関数の引数に指定された場合、次の
各データ型に対応した文字列と、その後に改行コードを付加した文字列が、
出力されます。
・文字列 → それ自身
・整数値 → 10進整数表記文字列
・実数値 → g型実数表記文字列
いずれの場合でも、出力される文字列は、'CharEnc で指定された符号化方式に
変換された文字コードになります。また、付加される改行コードも、'CharEnc
で指定された改行コードになります。なお、'CharEnc での指定がない場合は、
内部形式の符号化方式( UTF-16(LE) )で出力されます。また、改行コードは、
内部形式の CR+LF になります。
入力: 本形式が設定された変数が、入力関数の引数に指定された場合、その入力データ
から読み込まれた1行分の文字列が、その変数に、設定されます。この文字列
には、その行末の改行コードが含まれます。この1行分の文字列というのは、
その入力データの今回の入力開始位置から改行コード直後までになります。その
途中に改行コードがなければ、入力データの終端までになります。
なお、読み込まれるデータの文字コードは、'CharEnc で指定された符号化方式
から、内部形式の符号化方式( UTF-16(LE) )へ変換されます。
用例: 次のスクリプトは、Shift-JIS コードで保存されている "File.txt" という
テキストファイルの内容を1行ずつ読み出して、それに行番号を付けて、
プリントします。
'CharEnc( "Shift-JIS" );
file = ::File.Open( "File.txt", "in" );
if( file == null )
'Error!( "Failed to open file!\n" );
line'LN;
n = 0;
while( file.Read( line ) > 0 && line != null )
print "%3d: %s"'fmt( ++n, line ) : -;
file.Close();
T'CSZ 0終端文字列
機能: 対象 T に「0終端文字列」を示す入出力形式を設定します。
説明: この入出力形式は、次の対象に設定可能です。
・定文字列、または、文字列変数
・数値(整数、実数)の定数、または、変数
・空箱(この箱は本形式設定後、空文字列の箱に変わります)
対象の箱が不在の場合、空文字列の箱として新規に生成します。
対象が無い場合、空文字列として扱われます。
返値: 対象が箱の時、その箱への参照、実値の時、その値自身を返します。
対象が不正な時、null を返します。
出力: 本形式が設定された変数/定数が、出力関数の引数に指定された場合、次の
各データ型に対応した文字列と、その後に0終端コードを付加した文字列が、
出力されます。
・文字列 → それ自身
・整数値 → 10進整数表記文字列
・実数値 → g型実数表記文字列
いずれの場合でも、出力される文字列は、'CharEnc で指定された符号化方式に
変換された文字コードになります。また、付加される0終端コードも、それに
対応するコードになります。なお、'CharEnc での指定がない場合は、内部形式
の符号化方式( UTF-16(LE) )で出力されます。また、0終端コードは U+0000
になります。
入力: 本形式が設定された変数が、入力関数の引数に指定された場合、その入力データ
から読み込まれた0終端までの文字列が、その変数に設定されます。なお、途中
に0終端がなければ、データの終端までになります。
なお、読み込まれるデータの文字コードは、'CharEnc で指定された符号化方式
から、内部形式の符号化方式( UTF-16(LE) )へ変換されます。
用例:
●バイナリーデータ(固定長)の入出力形式
数値を表わす固定長のバイナリーデータの形式には、いろいろありますが、
次の各リレー型関数は、そのデータ型の入出力形式を設定します。
関数名 | データ型 | バイト数 |
'BYTE | 8 ビット整数(符号有り) | 1 バイト |
'UBYTE | 8 ビット整数(符号無し) | 1 バイト |
'SHORT | 16 ビット整数(符号有り) | 2 バイト |
'USHORT | 16 ビット整数(符号無し) | 2 バイト |
'LONG | 32 ビット整数(符号有り) | 4 バイト |
'ULONG | 32 ビット整数(符号無し) | 4 バイト |
'FLOAT | 32 ビット実数 | 4 バイト |
'DOUBLE | 64 ビット実数 | 8 バイト |
これらのリレー型関数が、この用途に使われる場合、その対象は必須ですが、
引数は無しにしないといけません。ちなみに、引数があると、純粋配列の生成
になってしまいます。⇒ 注意事項
これらのバイナリーデータの入出力形式は、次の対象に設定可能です。
・数値(整数、実数)の定数または変数
・定文字列、または、文字列変数
・空箱(この箱は、本形式の設定によって、次のように変わります。
整数型の形式を設定すると、0 値の整数箱に変わります。
実数型の形式を設定すると、0 値の実数箱に変わります。)
対象の箱が不在の場合、
整数型の形式では、0 値の整数箱として新規に生成します。
実数型の形式では、0 値の実数箱として新規に生成します。
これらのリレー型関数の返値は、次のようになります。
・対象が箱の時、その箱への参照
・対象が実値の時、その値自身
・対象が不正な時、null
これらのバイナリーデータ形式が設定された変数/定数が、出力関数の引数に
指定された場合、次のバイト列が出力されます。
整数型の形式の場合:
・整数値 → 各データ型の整数値
・実数値 → 各データ型の整数値
・文字列 → 'int(10) 変換した整数値 → 各データ型の整数値
実数型の形式の場合:
・実数値 → 各データ型の実数値
・整数値 → 各データ型の実数値
・文字列 → 'float 変換した実数値 → 各データ型の実数値
これらのバイナリーデータ形式が設定された変数が、入力関数の引数に指定
された場合、この変数には、入力バイト列から、次のようにして読み込まれた
数値が設定されます。
・整数型の形式の場合、入力バイト列から、そのデータ型のバイト分を
読み込んで、そのバイト列に対応する整数値を、本言語の整数形式に
変換して、その箱に代入します。
・実数型の形式の場合、入力バイト列から、そのデータ型のバイト分を
読み込んで、そのバイト列に対応する実数値を、本言語の実数形式に
変換して、その箱に代入します。
・入力バイト列から、各データ型のバイト分を読み込めない場合、つまり、
入力終端までの残りが、そのバイト数に満たない場合、その箱には、
null を代入します。
●ビットフィールド(固定長)の入出力形式
ビット構成を意識した入出力を行なうには、ビットフィールドの入出力形式を
使うと便利です。
例えば、16-bit (2-byte) のバイナリーデータ内に、色の RGB を各 5-bit ずつ
割り当てて使用する場合、次のようになります。
Color'BIT_FIELD(2); // 2-byte のビットフィールド箱を生成
Color.Blue 'BIT(5); // 最初の 5-bit を「青」に割り当て
Color.Green'BIT(5); // 次 の 5-bit を「緑」に割り当て
Color.Red 'BIT(5); // 最後の 5-bit を「赤」に割り当て
これで、Color 箱を入出力する時には、2-byte のバイト列になり、その中の
ビット構成は、RGB 各 5-bit ずつになります。なお、'BIT_FIELD と 'BIT の
リレー型関数については、後程説明します。
ビットフィールド内では、下位ビットから上位ビットの方向へ、各ビット列が
割り当てられていきます。上例の場合、16-bit 内の LSB(最下位ビット)を
Bit-0、以降順に、Bit-1, Bit2, ... として、MSB(最上位ビット)を、Bit-15
とすると、
Bit-0〜4: 青, Bit-5〜9: 緑, Bit-10〜14: 赤, Bit-15: 未使用
のように割り当てられています。
ビットフィールドの箱は、それを示す入出力形式が設定されている複合箱に
なります。また、その中の各ビットの箱(上例では、Blue, Green, Red )も、
通常の箱ですが、それを示す入出力形式が設定されています。そのため、
各ビットの箱は、それに値を代入したり、演算式で使用することができます。
例えば、上例の各ビット箱に、値を代入するには、次のようになります。
Color.Blue = 24; // = 0b11000
Color.Green = 14; // = 0b01110
Color.Red = 21; // = 0b10101
ちなみに、これは、次のようにしても構いません。
Color = { 24, 14, 21 };
ビットフィールドを出力する場合、通常通り行なえます。例えば、上例の
Color を、バッファに出力する場合、次のようになります。
bf = ::Buffer();
bf.Write( Color );
ちなみに、これを、USHORT の入出力形式で読み出して、プリントする場合、
次のようになります。
bf.Seek(0);
bf.Read( U'USHORT );
print U'b(16);
これを実行すると、次の通りプリントされます。
0101010111011000
ビットフィールドを入力する場合も、通常通り行なえます。
例えば、先程のバッファに、USHORT の形式で値を書き込んで、Color に
読み出す場合、次のようになります。
bf.Seek(0);
bf.Write( 0b0`11111`00000`10101'USHORT );
bf.Seek(0);
bf.Read( Color );
print Color.Red'b(5), Color.Green'b(5), Color.Blue'b(5);
ちなみに、これを実行すると、次の通りプリントされます。
11111, 00000, 10101
次に、ビットフィールドに関連するリレー型関数について、説明します。
T'BIT_FIELD(n) n バイトのビットフィールド
機能: 対象 T に「 n バイトのビットフィールド」を示す入出力形式を
設定します。
説明: この入出力形式は、基本的に、複合箱にのみ設定可能です。
この入出力形式の設定時に、その対象が複合箱でない場合、
次のようになります。
対象の箱が不在の場合、空の複合箱として新規に生成します。
対象の箱が単一箱の場合、その箱を空の複合箱に変えます。
但し、数値/文字列/空以外の単一箱には、設定できません。
なお、対象の箱が複合箱の場合、その中身は変わりません。
但し、ファイル/バッファの箱には、設定できません。
バイト数 n の有効範囲は、1 〜 1000 です。
n が省略時、n = 1 として扱います。
返値: 対象が箱の時、その箱への参照を返します。
対象が不正な時、null を返します。
補説: この入出力形式が設定された箱(ビットフィールド箱)が、
入出力関数の引数に指定された場合、実際にその入出力の対象になる
のは、この箱自身ではなく、この箱内の直下にある「ビット規定箱」
になります。このビット規定箱というのは、'BIT, 'SBIT, 'UBIT の
どれかの入出力形式が設定された箱のことです。この箱のデータ型は、
通常、整数ですが、実数でも構いません。実数の場合は、整数に変換
されて使用されます。それ以外のデータ型は、不可です。
なお、ビットフィールド箱内に、ビット規定箱以外の箱があっても
構いませんが、入出力の対象にはなりません。
出力: ビットフィールド箱が、出力関数の引数に指定された場合、
この箱内にある各「ビット規定箱」のビット列が、次のようにして、
n バイトに合成されて、出力されます。
・ビット規定箱のビット列は、その箱の整数値の 32 ビットのうち、
下位部分の規定数分のビット列になります。つまり、その箱で
規定されているビット数を k とすると、Bit(k-1) 〜 Bit0 の
部分のビット列になります。
・各「ビット規定箱」のビット列は、n バイト内の下位ビットから
上位ビットの方向に、順に埋められていきます。
・n バイト内で余ったビットには、0 が埋められます。
・n バイトを超過したビットは、無視されます。
入力: ビットフィールド箱が、入力関数の引数に指定された場合、
入力バイト列から n バイト分が読み込まれて、
各「ビット規定箱」に、次のようにして、分配されます。
・各「ビット規定箱」で規定されているビット数分のビットは、
入力された n バイト内の下位ビットから上位ビットの方向に、
順に取得されていきます。
・このように取得された各ビット列は、整数値に変換されて、
各ビット規定箱に代入されます。
・このビット列から整数値(32-bit)への変換では、
そのビット規定箱で規定されている符号の有無に依存します。
符号無しの場合、そのビット列は、整数値の 32-bit のうちの
下位のビット部分になり、残りの上位のビット部分は、すべて
0 になります。
符号有りの場合、そのビット列は、整数値の 32-bit のうちの
下位のビット部分になり、残りの上位のビット部分は、すべて、
そのビット列の最上位ビットと同じになります。
・n バイトのビットでは、ビットフィールド箱内のすべての
「ビット規定箱」のビットを賄いきれなかった場合、
不足分のビットはすべて 0 になります。
なお、もし、入力バイト列から n バイト分を読み込めなければ、
その入力関数は、エラーになりますが、ビットフィールド箱は、
現状が維持されます。
T'BIT(n) or T'UBIT(n) n ビット整数値(符号無し)
機能: 対象 T に「 n ビット整数値(符号無し)」を示す入出力形式を
設定します。
説明: 'BIT と 'UBIT は、名前が違うだけで、機能は同じです。ちなみに、
'UBIT の U は、unsigned の意味です。'UBIT は、'SBIT との対比で、
符号無しを明示したい場合に使います。
この入出力形式は、通常、ビットフィールド箱( 'BIT_FIELD の
入出力形式が設定された箱)内の箱に設定します。この場合、
その箱のデータ型は、通常、整数にします。実数でも構いませんが、
入出力時に有効なのはそれが整数に変換された値です。なお、
数値以外のデータ型は、この場合には使えません。
ビットフィールド箱内でない場合、次の対象に設定可能です。
・数値(整数、実数)の変数または定数
・文字列の変数または定数
・空箱(この箱は本形式設定後、0 値の整数箱に変わります)
いずれの場合でも、対象の箱が不在なら、その箱を 0 値の整数箱
として新規に生成します。
ビット数 n の有効範囲は、1 〜 32 です。
n が省略時、n = 1 として扱います。
返値: 対象が箱の時、その箱への参照、実値の時、その値自身を返します。
対象が不正な時、null を返します。
補説: ビットフィールドの入出力を行なう場合、入出力関数の引数には、
本形式が設定された変数/定数を直接指定するのではなく、通常は、
ビットフィールド箱を指定します。この場合の動作については、
'BIT_FIELD で説明しています。
以下では、入出力関数の引数自身に直接、本形式が設定されている
(比較的特殊な)場合について、説明します。
出力: 本形式が設定された変数/定数が、出力関数の引数に指定された場合、
その値が整数なら、その下位 n ビットを保持するのに必要な最少の
バイト列が、下位バイトから上位バイトの順に出力されます。その際、
バイト列のビット数が n よりも多い場合、余ったビットは全て 0 に
なります。一方、その引数の箱の値が整数でなければ、それを整数に
変換した値が同様に出力されます。
入力: 本形式が設定された変数が、入力関数の引数に指定された場合、この
変数には、次のような整数値が代入されます。まず、n ビットを確保
するのに必要な最少のバイト列が読み込まれます。このバイト列の
下位 n ビットが、その整数値の下位 n ビットになります。その整数
値の残りの上位ビットは、全て 0 になります。
T'SBIT(n) n ビット整数値(符号有り)
機能: 対象 T に「 n ビット整数値(符号有り)」を示す入出力形式を
設定します。
説明: 'SBIT の S は、signed の意味です。
この入出力形式は、通常、ビットフィールド箱( 'BIT_FIELD の
入出力形式が設定された箱)内の箱に設定します。この場合、
その箱のデータ型は、通常、整数にします。実数でも構いませんが、
入出力時に有効なのはそれが整数に変換された値です。なお、
数値以外のデータ型は、この場合には使えません。
ビットフィールド箱内でない場合、次の対象に設定可能です。
・数値(整数、実数)の変数または定数
・文字列の変数または定数
・空箱(この箱は本形式設定後、0 値の整数箱に変わります)
いずれの場合でも、対象の箱が不在なら、その箱を 0 値の整数箱
として新規に生成します。
ビット数 n の有効範囲は、1 〜 32 です。
n が省略時、n = 1 として扱います。
返値: 対象が箱の時、その箱への参照、実値の時、その値自身を返します。
対象が不正な時、null を返します。
補説: ビットフィールドの入出力を行なう場合、入出力関数の引数には、
本形式が設定された変数/定数を直接指定するのではなく、通常は、
ビットフィールド箱を指定します。この場合の動作については、
'BIT_FIELD で説明しています。
以下では、入出力関数の引数自身に直接、本形式が設定されている
(比較的特殊な)場合について、説明します。
出力: 本形式が設定された変数/定数が、出力関数の引数に指定された場合、
その値が整数なら、その下位 n ビットを保持するのに必要な最少の
バイト列が、下位バイトから上位バイトの順に出力されます。その際、
バイト列のビット数が n よりも多い場合、余ったビットは全て 0 に
なります。一方、その引数の箱の値が整数でなければ、それを整数に
変換した値が同様に出力されます。
入力: 本形式が設定された変数が、入力関数の引数に指定された場合、この
変数には、次のような整数値が代入されます。まず、n ビットを確保
するのに必要な最少のバイト列が読み込まれます。このバイト列の
下位 n ビットが、その整数値の下位 n ビットになります。その整数
値の残りのビットは全て、n ビットのうちの最上位ビットと同じ値に
なります。
●構造体の入出力形式
構造体は、通常、「構造体設定文」の実行によって、設定します。
'STRUCT というリレー型関数を使えば、これと同様のことが行なえます。
例えば、構造体設定文で、
POINT ::= { .X 'LONG; .Y 'LONG; }
として、設定した構造体は、'STRUCT を使って、次のように設定できます。
POINT 'STRUCT;
POINT.X 'LONG;
POINT.Y 'LONG;
この場合、どちらの方法で、構造体を設定しても、結果は同じです。
構造体の入出力に関しては、「構造体」の章の「入出力時のバイナリー構成」
で説明しています。
●入出力形式の設定解除/変更
箱に設定した入出力形式は、'attr というリレー型関数を使って、任意に
解除することができます。例えば、
A 'STRUCT;
を実行すると、箱 A は、構造体の箱になりますが、その後で、
A 'attr(0);
を実行すると、箱 A は、通常の「箱を入れる箱」になります。
箱に設定した入出力形式は、再設定すれば、任意に変更することができます。
例えば、
X 'SHORT;
を実行すると、箱 X には、「 16 ビット整数(符号有り)」の形式が設定
されますが、その後で、
X 'UBYTE;
を実行すると、箱 X は、「 8 ビット整数(符号無し)」の形式の設定に
更新されます。
●ファイル/バッファ相互間の入出力
今までの説明では、ファイルやバッファの入出力対象が、数値や文字列の
変数/定数、あるいは、構造体やビットフィールドでしたが、
ファイルやバッファを入出力対象にすることもできます。例えば、ファイル
からバッファへデータを読み出すとか、ファイルAに別のファイルBのデータ
を書き込むとかも、直接できます。
ファイルやバッファを入出力対象にする場合、そのファイルやバッファの
インスタンスに、入出力形式を設定します。ちなみに、ファイルやバッファ
のクラスには、入出力形式を設定することはできません。
ファイルやバッファのインスタンスに入出力形式を設定した場合、その動作
は、各形式に応じて、次のようになります。なお、その動作は、入出力形式を
変数/定数に設定した場合とは、かなり違っているところもあります。
'C(n), 'I(n), 'X(n), 'F(n), 'BIT_FIELD(n) の場合、各形式の意味とは
無関係に、n バイト分のデータを入出力します。この場合、n は、整数値の
上限まで指定できます。
'T(n) の場合、現在の符号化方式での1文字コードのサイズ × n バイトを
入出力します。例えば、UTF-16(LE) では、2 x n バイト、Shift-JIS では、
n バイトを入出力します。ちなみに、現在の符号化方式は、'CharEnc で指定
します。
'SBYTE(n), 'UBYTE(n), 'SHORT(n), 'USHORT(n), 'LONG(n), 'ULONG(n),
'SGLFLT(n), 'DBLFLT(n) の場合、その形式のサイズ × n バイト分のデータを
入出力します。例えば、'LONG(10) では、4 x 10 = 40 バイトを入出力します。
このバイト数は、整数値の上限まで有効です。
なお、この形式では、純粋配列と同様に、引数を、( n, m, ... ) のように
多次元で指定しても構いません。その場合、その形式のサイズ × 全要素数 の
バイトを入出力します。例えば、'SHORT(5,10) では、2 x 5 x 10 = 100 バイト
を入出力します。
'BIT(n), 'UBIT(n), 'SBIT(n) の場合、n ビットに必要な最小限のバイト数
を入出力します。例えば、'BIT(10) では、2 バイトを入出力します。
このビット数は、整数値の上限まで有効です。
上記以外の入出力形式の設定は、無効です。エラーにはなりません。
デフォールトでは、ファイルやバッファのインスタンスには、入出力形式は、
設定されていません。また、'attr(0) で、それらの入出力形式の設定を解除
することができます。
入出力形式が設定されていない場合、入力側のファイル/バッファの現時点での
入力開始位置から入力終端までの全データが読み込まれて、出力側のファイル/
バッファに書き込まれます。
この関連の例を、以下に示します。
次のスクリプトは、"File.txt" というファイルを開いて、その全内容を、
バッファに読み出して使うところです。
buff = ::Buffer();
file = ::File.Open( "File.txt", "in" );
if( file == null )
'Error!( "Failed to open file!\n" );
file.Read( buff );
file.Close();
buff.Seek(0);
・・・・・
次のスクリプトは、バッファに 0 〜 999 の 16-bit 整数値を 1000 個 書き
込んで、そのうちの最初の 800 個のデータを、"File.bin" というファイルに
書き込みます。ちなみに、このファイルのサイズは、2 x 800 = 1600 バイトに
なります。
bf = ::Buffer();
for( i = 0 ; i < 1000 ; i++ )
bf.Write( i'SHORT );
bf.Seek(0);
fl = ::File.Open( "File.bin", "out" );
if( fl == null )
'Error!( "Failed to open file!\n" );
fl.Write( bf'SHORT( 800 ) );
fl.Close();
●純粋配列の入出力
純粋配列の箱には、入出力形式を設定できません。しかし、
純粋配列自身を、入出力関数の引数に指定することはできます。その場合、
その純粋配列の全データが、入出力の対象になります。
例えば、先程の例で作成した "File.bin" というファイルの後半のデータ
(800 バイト) を、10 x 40 の2次元の USHORT の純粋配列に読み出す場合、
次のようになります。
A'USHORT( 10, 40 );
file = ::File.Open( "File.bin", "in" );
if( file == null )
'Error!( "Failed to open file!\n" );
file.Seek( 800 );
file.Read( A );
print A(0,0), A(0,1), "...", A(9,38), A(9,39);
ちなみに、これを実行すると、次の通りプリントされます。
400, 401, ..., 798, 799
なお、純粋配列の要素は、通常の数値と同様なので、それに入出力形式を
設定して、入出力関数の引数に指定することができます。
●入出力形式なしでの入出力
入力関数の引数の箱(純粋配列以外)に入出力形式が設定されていない場合、
何をどのように入力するのか判断できないので、その入力はエラーになります。
出力関数の引数に入出力形式が設定されていない場合、その引数の内容に応じて、
次のように出力されます。
整数値: 'LONG と同様にして出力されます。
実数値: 'DBLFLT と同様にして出力されます。
文字列: その文字列自身が出力されます。
ファイル、バッファ、純粋配列に関しては、既に説明した通りです。
その他: とりあえず無視されます(現状、エラーにはなりません)。
●メモリーブロックに対する入出力
今まで述べた入出力形式は、通常の大半の用途に対応できますが、直接メモリーの
アドレスとサイズを指定する必要がある入出力には不向きです。このような入出力を
行なう場合は、'MEMBLK というリレー型関数を使います。
この関数を使った例を以下に示します。この例では、"File.bin" というファイル
から、A という純粋配列のインデックスが 24 の要素のアドレスへ、80 バイト分の
データを読み出してきています。
A'UBYTE( 1000 );
file = ::File.Open( "File.bin", "in" );
file.Read( 'MEMBLK( A(24)'addr, 80 ) );
'MEMBLK が返す値は、変数に代入したり、関数の引数や返値に使うこともできます。
例えば、次の例は冗長ですが、前の例と同じことを行ないます。
function F( fname, mblk )
{
file = ::File.Open( fname, "in" );
file.Read( mblk );
}
A'UBYTE( 1000 );
F( "File.bin", 'MEMBLK( A(24)'addr, 80 ) );
余談ですが、上の2例では、ファイルをオープンした後、クローズしていませんが、
File クラスのインスタンス file が破棄される時、つまり、第1例では、スクリプト
の終了直前、第2例では、関数 F を抜ける時に、自動的にクローズされます。
●注意事項
構造体、ビットフィールド、ファイル/バッファのインスタンスに関しては、
既に述べた通りですが、それ以外の複合箱では、基本的に、
'C, 'I, 'X, 'F, 'T, 'LINE, 'LN, 'CSZ
'SBYTE, 'UBYTE, 'SHORT, 'USHORT, 'LONG, 'ULONG, 'SGLFLT, 'DBLFLT
'BIT, 'UBIT, 'SBIT
の入出力形式は、使えません。
単一箱や定数の(複製)代入では、その代入元の入出力形式は、その代入先
にコピーされない仕様になっています。例えば、
A 'LONG;
B = A;
C = 123 'SHORT;
としても、変数 B, C には、入出力形式が設定されていません。このような
仕様になっているのは、この代入では、必ずしも入出力形式のコピーが必要
でないことと、その分の処理を省いて、少しでも実行速度を上げるためです。
複合箱の(複製)代入では、その代入元の入出力形式は、その代入先に全て
コピーされます。例えば、
Point'STRUCT; Point.X'LONG; Point.Y'LONG;
P = Point;
Color'BIT_FIELD(2);
Color.Blue'BIT(5); Color.Green'BIT(5); Color.Red 'BIT(5);
Q = Color;
とすると、箱 P, Q は、それぞれ、Point 構造体、Color ビットフィールドと
同じ構造で同じ入出力形式が設定されています。