式と演算子

式とは

1 + 2 のような演算子と被演算子によって記述されるものです。

+ などの演算を行う記号を演算子といい、その目的(材料)となる 1 や 2 を被演算子といいます。1 + 2 は「整数 1 および整数 2 において加算という演算を行い、その結果を返す」式ということになります。

とりあえず記号を演算子と呼ぶ、くらいに思っておいてください。また数同士の足し算だけでなく、文字列の連結なども行われるため、計算ではなく演算と呼びます。

被演算子には、1 や 2.23 といった数値や "kirikiri" といったような文字列(文字の並び)などが利用できます。また、変数関数などの識別子も用いられます。

識別子とは

文字通り、識別できるものです。

たとえばクラスメイトに渡辺くんが4人いたら、その苗字は識別子としての条件をみたしていません。その代わり、班分けをしたときにその班に渡辺くんが1人しかいなければ、その班内であれば「渡辺」は識別子になりえます。

この識別子は、変数や関数を表すときに用いられます。

識別子には先頭に数字がきてはいけなかったり、catch は使えなかったりとルールが決められています。詳しくは(tjs2doc) トークンを参照してください。

演算子

主なものを優先順位の高いものから紹介していきます。

( )

カッコ(いわゆる小カッコ)には大きくわけて2つの用途で使われます。

3 * (1 - 2) のように、カッコがある方を優先的に演算させるため。

そして、kag.process('', '*next') のように関数(メソッド)の後ろにつけて実行させるためです。後者の方法は、カッコの中に引数(その関数・メソッドの材料となる値)を記述することもできます。

.

ピリオド(ドット)は、後述する配列と辞書配列オブジェクト指向で触れますが、直接メンバ選択演算子といいます。

ここでは、A.Bとあれば「AのB」といったくらいで捉えてください。sf.foo なんかそうですね。システム変数の foo という意味です。

 [ ]

大カッコは、主に配列と辞書配列で使われる間接メンバ選択演算子です。

関数(メソッド)の小カッコ、辞書配列はオブジェクトのドット、配列の大カッコは演算子の中でも優先順位が高いものですので、(たとえば sf.foo で)ひとかたまりにしてとらえた方がわかりやすいかもしれません。

++, --

[eval exp="sf.clear += 1"]

上のような、1追加する際には += 演算子が利用できました。ここで、1増やすもしくは1減らす際のみ更に簡単に書ける、特別な演算子が用意されています。それが ++ 演算子と -- 演算子です。それぞれインクリメント(増加)演算子、デクリメント(減少)演算子と呼ばれます。

[iscript]
var sum = 50;
for(var i = 0; i < 10; i++){
  sum--;
}
// sum => 40;
[endscript]

+, -

演算子によっては、状況により異なるはたらきをするものがあります。そのうち、+ 演算子と - 演算子は単項(被演算子が1つ)の演算子としてもはたらきます。

まず - 演算子は、数値を正負逆転させる演算子です。ですので、-1 のように数値につけるだけでなく、-sf.foo のような使い方もできます。それどころか次のようなことも可能です。

[iscript]
sf.foo = -1;
sf.foo = -(-(-sf.foo));
// sf.foo => 1;
[endscript]

次に、+ 演算子は、右にある値が数値ならば何もしませんが、文字列ならばそれを数値にできるだけ変換しようとします。また、変換できなかった場合は 0 を返します。

KAGシステムのソース内では、しばしば文字列から数値に変換、もしくは元々数値なら何もしないので念のため数値を保証しておきたい場面に使われています。

[eval exp="sf.foo = +"12人の妹"]
; sf.foo => 12

*, /

次に優先されるのは、四則計算の掛け算と割り算です。

TJSは日本語も使えますが、基本的にプログラミングは(半角)英数で行われていました。そのため「×」「÷」という記号に代わり「*」「/」という記号が用いられています。

[eval exp="sf.foo = 1 + 2 * 3 - 4 / 5 + 6"]
; f.foo = 1 + 6 - 0.8 + 6
; sf.foo => 12.2

C言語などを習得されている方へ。

TJSでは整数 / 整数でも結果は実数となります。(内部では)整数と実数は型として異なりますが、表面上は数値としてまとめて同じものと扱われます。(多分)

+, -

今度は単項ではなく二項演算子(被演算子が2つ)の + 演算子と - 演算子です。いわゆる四則計算における和と差を求める演算子です。

ただし、 + 演算子のみちょっと特殊で、2つある被演算子のうち一方もしくは両方が文字列のときは、加算演算子ではなく文字列連結演算子としてはたらきます。つまり少しでも文字列が混ざったら、数値は文字列に自動的に変換されます。

[eval exp="sf.foo = 1 + 2 * 3 - 4 / 5 + "6"]
; 1 + 6 - 0.8 + "6"
; 6.2 + "6"
; "6.2" + "6"
; sf.foo => "6.26"

<, >, <=, >=

比較を行う演算子です。< 演算子は左の項より右の項が大きければ真、<= 演算子は左の項より右の項が大きいか等しければ真。>, >= はその反対です。

代入演算子の = もそうですが、プログラミング言語の演算子と数学の演算子は役割が異なります。これらの比較演算子でいうならば、数学の場合は大なりなどの条件が前提として式を展開していきますが、プログラミングの場合は、大なりならば真、違えば偽と大小関係をチェックするだけの記号にすぎません。

[iscript]
function less(arg1, arg2){
  if(arg1 - arg2 < 0){
    return true;
  } else{
    return false;
  }
}
// sf.foo = 1 < 3;
sf.foo = less(1, 3);
// sf.foo => false
[endscript]

(上記の関数内で結局 < 演算子を使っていますが)演算子は関数と同じく特定の演算を行い結果を返す関数に似たものです。別のプログラミング言語のRubyなどは、今まで演算子として扱ってきた記号も、名前が特殊なだけのメソッド(関数)として扱っています。

被演算子の二項が両方とも数値ならば、それぞれ大きさを比較しますが、両方とも文字列ならばUnicode文字セットにおける辞書順に比較されます。すなわち "a" より "b" の方が後とみなされます。これに関してはUnicodeという文字と数値の対応表における数値をもとにしています。("a" は97番、"b" は98番)

なお、数値と文字列との比較の場合、文字列が + 演算子のルールで数値化された上で比較されるようです。

==, !=, ===, !==

比較ではなく、実際に等しいか確認する同値演算子です。= 演算子は代入に使われるため、等しいかどうか確かめる演算子は == となっています。対して、等しくないかどうかは != 演算子で確かめます。

== 演算子と != 演算子は、両項の型が異なる場合、自動で変換したうえで演算します。すわなち 1 == "1" は型をあわせたのち、真を返します。

型のチェックまで行うもの(型の変換を自動で行わないもの)に === 演算子と !== 演算子があります。状況によって使い分けますが、void との比較などではこの === 演算子などを使用します。(void == false を真にしたい場合などは == 演算子を使えばよいが、通常は void は互換性のある false や 0 とも区別して使われる。)

&&, ||

&& 演算子と || 演算子は論理(真か偽か)を列挙する際に使われる。

&& 演算子は論理積――すなわち二項のうち両方とも真(1)でなければ真とならない。どちらか一方でも偽(0)であれば偽(0)となってしまう。一方 || 演算子は論理和――すわなり二項のうちどちらかが真(1)でなければ真とならない。どちらとも偽(0)であれば偽(0)となってしまう。

一般的には、論理積(&&)演算子は「かつ」の条件に。論理和(||)演算子は「または」の条件に用いられる。

[iscript]
sf.foo = false;
// 1 == "1" かつ 1 < "3" のとき
if(1 == "1" && 1 < "3"){
  // 1 == "0" または 1 == "1" が真ならば true(真; 1)が代入される
  // もし偽であれば何も代入されない; もとの false(偽; 0)のまま 
  sf.foo = (1 == "0" || 1 == "1");
}
// sf.foo => 1
[endscript]

その他

その他にもいろいろ演算子はありますが、今回は主なもののみ紹介しました。これ以外を使用する際には別途説明していきたいと思います。

 
tjs/expression.txt · 最終更新: 2008/09/14 22:24 by tohka