コンテンツにスキップ

値と変数

即値

YAYA が扱える値は整数、実数、文字列の 3 種類。

整数 (int)

符号付き 64bit 整数(Tc566-1で拡張。それ以前は 32bit)。10 進数値はそのまま記述する。先頭に 0b を付加すると 2 進数値、先頭に 0x を付加すると 16 進数値を記述できる。

次の関数 int10 は整数 10 を返す。3 つの記述はいずれも 10 進数では 10 だから。

int10
{
    10
    0b1010
    0xa
}

実数 (double)

符号付き 64bit 浮動小数点数。小数点以下の桁がある場合や、精度が落ちてもいいので非常に巨大な数値を扱いたい場合に使う。

整数との区別は小数点の有無で、YAYA は数値に小数点を見つけると、これを実数として取り扱う。たとえば

Test
{
    3/4*100
}

とすると、結果は 75 ではなく 0 になる。これは 3/4 を評価したときに int として解釈し、小数点以下が切り捨てられるため(演算子は左から順に評価される)。意図した動作にするには

Test
{
    3.0/4*100
}

とする必要がある。3.0 を評価した時点で double 型として解釈するため、結果は実数の 75.0 になる。実数を文字列にすると小数点以下 6 桁になり、75.000000 と出力される。整数にしたい場合は TOINT 関数を使う。

変数の演算でこれを行いたいときは、宣言時に実数を代入するか、TOREAL 関数を用いる必要がある。

Test
{
    _A = 3
    _B = 4
    TOREAL(_A)/_B*100
}

小数点は OS のロケールによらず常に . で、文字列から実数への変換や辞書に書いた実数も . で読む(ドイツ語などの , が小数点のロケールでも同じ)。

文字列

ダブルクォート(")で囲まれた値は文字列で、変数や関数の展開(文字列内埋め込み要素の展開)が行われる。

行末に / を書くと、改行を含む文字列を記述できる。

"こん\n/
なかんじに\n/
書いてもOK\n/"

後述するヒアドキュメントを用いても、改行を含む文字列を書ける。さくらスクリプトは文字列として記述しないと動作しない。

Tc569-8 以前のバージョンでは、文字列の中にダブルクォートを含められない。Tc569-8 以降のバージョンでは、ダブルクォートを 2 回続けて書くことで、文字列内にダブルクォートを追加できる。

"1""2"

と書くと、1"2 という文字列を定義したことになる。

文字列(展開なし)

シングルクォート(')で囲まれた値は、展開されない単純な文字列。YAYA では文字列中に変数や関数を埋め込めるが、これが展開されるのはダブルクォートで囲まれた文字列のみ。

Tc569-8 以前のバージョンでは、文字列の中にシングルクォートを含められない。Tc569-8 以降のバージョンでは、シングルクォートを 2 回続けて書くことで、文字列内にシングルクォートを追加できる。

'1''2'

と書くと、1'2 という文字列を定義したことになる。

あまり複雑な使い方をすると後で見にくくなるのでおすすめしないが、同時に使う例として、

'1''2"3'
"1'2""3"

はいずれも、1'2"3 という文字列を定義したのと同じになる。

ヒアドキュメント

複数行書ける文字列即値。Tc535-1 から使用できる。

<<"
行1
行2
">>

で展開あり文字列、

<<'
行1
行2
'>>

で展開なし文字列になる。ヒアドキュメントの前や後にいろいろな式を書けるが、辞書ファイル内のみのサポートで、EVAL してもエラーになる。

配列とハッシュ

即値のほかに、値をまとめて扱う型として汎用配列(配列)がある。Tc600-3以降ではハッシュ(連想配列、ハッシュ)も使える。

Tc600-3以降では、配列やハッシュの要素に配列やハッシュを入れる(入れ子にする)こともできる(値の入れ子と多次元代入)。

変数

変数は値を格納するための領域。ひとつの変数には、

  • 整数、実数、文字列
  • 要素ごとに上記のいずれかを格納できる汎用配列
  • ハッシュ(Tc600-3以降)

を格納できる。名前は次の禁止条項に抵触しない限り自由につけられる。

  • 数字 0〜9 で始まる
  • 次の文字を含む: 空白 ! " # $ % & ( ) * + , - / : ; < = > ? @ [ ] ` { | } ~
  • 予約語と完全に一致する
  • 関数名と完全に一致する

値の格納(代入)は代入演算子 = で行う。内容を出力するには、関数と同様にその名前を書く。

request
{
    str = "こんにちは"

    str
}

上は単純な例で、変数 str に文字列を格納し、そのまま出力している。

まだ値が代入されていない変数は、「未定義型」という特殊な型になる。「何も出力しない」ではないことに注意。

request
{
    "Hello World"
    i
}

この場合、i は存在しないため「未定義型」になる。「未定義型」は、数値との演算では 0、文字列との演算では ''(空っぽの文字列)として扱われる。上記の例では、この「未定義型」と "Hello World" という文字列のどちらかが 1/2 の確率で返される。

スコープとライフタイム

変数はスコープ(有効範囲)の違いによって 2 種類ある。

  • グローバル変数: すべての関数で共通に使用できる変数。寿命は(ERASEVAR で消去されない限り)永遠
  • ローカル変数: 現在の { } 内、およびそれより深い入れ子階層のみで使用できる変数。寿命は該当する { } を抜けるところまで

両者を区別するのは変数の名前で、変数名の先頭がアンダースコア(_)の変数はローカル変数として扱われる。「必要な範囲だけで有効な変数」であるローカル変数をうまく利用することで、プログラムの見通しが良くなる。

request
{
    _i = "3*2は"

    _j = multi(3)

    _i + _j + "です"
}

multi
{
    _i = _argv[0]
    _i * 2
}

request と multi が同じ名前の変数 _i を使っているが、それらはまったく別物として扱われ、お互いの値を破壊することはない。関数の引数を扱う変数 _argc と _argv も実はローカル変数で、関数ごとに別の値を格納するためローカル変数になっている。

ローカル変数が「現在の関数内で使用可能な変数」ではなく、「現在の { } 内、およびそれより深い入れ子階層のみで使用できる変数」であることには注意。

request
{
    {
        _str = "Hello World"
    }

    _str
}

このプログラムは期待どおりには動作しない。_str は { } 内のみで有効なので、出力を取り出そうとしている位置では消えてしまっている。したがって、この関数 request は空の文字列を出力する。

グローバル変数とローカル変数の違いはもうひとつ、寿命である。ローカル変数は上で見たとおり、変数を使用している { } から外れると消えてしまう。対してグローバル変数はどこでも使用でき、さらに unload でその値がファイルへ自動的に保存され、load で復元される。

グローバル変数を削除するには ERASEVAR 関数を使う必要がある。また、その性質上、グローバル変数の初期化は起動時に最初に実行される関数(OnBoot など)で行うことを推奨する。