![]() |
![]() |
トップページへ | [ 一覧 | 検索 | 最終更新 ] [ 差分 | 履歴 | 凍結 ] |
![]() |
AYA Version5 マニュアル†このマニュアルは、HTML形式で配布されているものを、すぐに見られるようにWiki上に転記・一部わかりやすいよう加筆したものです。 AYA Version5 システム関数も参照してください。 概要†「あや」と読みます。文字列処理を行なうためのDLLです。 C言語に似た文法を使用して、
といった処理を行なうことが出来ます。 文はWindows DLLですので、直接利用するためには、プログラミングに関する知識がある程度必要です。 環境†Windows用です。
開発のごく初期に98SE、2000、xpで動作確認しましたが、最終版はxpでしか確認を取っていません。 利用規定†
主な変更点†version 4系列の文をお使いの方は、この項を読むことでversion 5の性能のあらましを簡単に理解できます。 新機能/改善された機能†
変更された機能†version 5の開発においては、version 4が抱える不具合や仕様の不整合を矯正することが重視されました。
エクスポートしている関数†文は以下の公開された関数を持っています。 文を利用するプログラムは、文をLoadLibraryした後にこれらの関数を実行して所望の処理を行ないます。 extern "C" __declspec(dllexport) BOOL __cdecl load(HGLOBAL h, long len) 文に初期化を指示します。 extern "C" __declspec(dllexport) BOOL __cdecl unload() 文に終了を指示します。 extern "C" __declspec(dllexport) HGLOBAL __cdecl request(HGLOBAL h, long *len) 文に処理を指示し、結果を得ます。 なお、これはデスクトップマスコットソフトウェア「伺か」で使用される擬似AI用DLL「SHIORI」 のインタフェース規格と完全に同一のものです。 基礎設定†文 ver.5のデフォルトのDLLファイル名は「aya5.dll」です。 // dics dic, basis.dic dic, control./*doc*/ayc // option parameters charset, UTF-8 msglang, english log, executelog.txt iolog, off fncdepth, 16 設定はコマンドとパラメータをカンマで区切って指定します。 charset, name†標準の文字コードを設定します。
dic, filename†辞書ファイルfilenameをロードします。 msglang, language†ログに記録されるエラーメッセージ類の言語を選択します。
log, logfilename†実行ログをファイルlogfilenameに記録します。 iolog, [on|off]†load、unload、request実行時の入出力文字列と処理時間をログに記録するかを設定します。 fncdepth, depth†関数呼び出しの深さ上限を数値で指定します。 文スクリプトリファレンス†文スクリプトの書式はC言語のそれを踏襲しています。 関数†基礎†request実行時に"Hello World"という文字列を返すプログラムコードの全体を以下に示します。 request { "Hello World" } 文をロードしたモジュールがHGLOBAL request(HGLOBAL h, long *len)を実行すると、このスクリプトが実行され、"Hello World"が
返されます。
loadとunloadも同様です。 loadとrequestはひとつの引数を持っています。これは変数で取り出せます。 _argc†引数の数。loadとrequestでは引数はひとつの文字列ですから1となります。unloadは引数を持たないので、この値は0となります。 _argv†引数の実体が格納されています。これは_argc個の要素を持つ配列です。各要素へのアクセスは演算子[i]で行います。 基礎編のまとめとして、loadでは変数strに"Hello"を格納し、requestで引数として渡された文字列とstrを結合して返すプログラムコードを 示します。~これまでの説明を踏まえて読んでみてください。 load { str = "Hello" } request { str + " " + _argv[0] + "!" } 処理対象文字列を"World"としてrequestを実行すると、結果として"Hello World!"が得られます。 書式†以下の則があります。
つまり先に挙げたHello Worldコードは以下のように1行に詰めて書くことが出来ます。 request{"Hello World"} では以下のように書いてもいいのか? もちろん。問題なく動作します。(ただしこんな風に書くのは感心できない!) req/ uest { "/ Hello World" } /の次の行(新たに結合される行)先頭にある空白文字はインデント文字と見なされ、消されます。 "ABCD EFG" 第4項を説明します。 request { answer = 1 + 2 "答えは" + answer + "です。" } セミコロンを使用して以下のように書けます。 request { answer = 1 + 2; "答えは" + answer + "です。" } セミコロンは過剰に書いても問題ありません。それらは無視され、動作に影響は与えません。 ユーザー関数の定義と実行†load、unload、request以外に好きな名前の関数を作成できます。 request { hello } hello { "Hello World" } 上に示したのはもっとも単純な例です。requestは結果として"Hello World"を返します。 同じ結果が得られるもう少し複雑な例を、以下に示します。 request { combine("Hello", "World") } combine { _argv[0] + " " + _argv[1] } 関数名の後ろに( )をつけて、その中にカンマで値を並べて書くと、これらは該関数に渡される引数として扱われます。
すなわち変数_argvと_argcに値が格納されて、該関数内で参照できるようになります。
関数は再帰呼び出しが可能です。 request { factorial(5) } factorial { if !_argv[0] 1 else factorial(_argv[0] - 1)*_argv[0] } requestは120を返します。 択一†request { "Hello World" "こんにちは世界" "Hallo Welt" } このように列挙すると、これらは平等な「出力候補」として扱われ、出力はこれらのうちのいずれかひとつになります。 5種類の選択方法が用意されており、いずれかを選ぶことができます。~ただし、voidとarrayは特殊な用途のみで使用します。 なにもなし†デフォルトでは無作為に選択します。 nonoverlap†すべての候補が出力されるまでは、同じ候補を選択しなくなります。 request : nonoverlap { "Hello World" "こんにちは世界" "Hallo Welt" } 上のように、関数名の後ろに": nonoverlap"を付け加えます。 sequential†記述された順に出力します。最後まで出力したらまた先頭に戻ります。 request : sequential { "Hello World" "こんにちは世界" "Hallo Welt" } 上のように、関数名の後ろに": sequential"を付け加えます。 void†何も出力しなくなります。 request : void { "Hello World" "こんにちは世界" "Hallo Welt" } 「何も実行しない」ではなく、「何も出力しない」であることに注意してください。 increment_i : void { i++ i } 上の関数increment_iはiに1を加算します。voidが無い場合、この関数は加算結果を返しますが、voidを指定すると値を返さず、 ただ加算を行うのみとなります。 array†出力候補をすべて結合した汎用配列を関数の返値とします。 request : array { "This is a pen." ("A","B","C") 3.14 } 出力は汎用配列 ("This is a pen.", "A", "B", "C", 3.14) となります。 nonoverlapとsequentialは、出力確定子が存在する場合でも取り得るすべての組み合わせに対して正常に機能します。 request : sequential { "1" "2" "3" -- "A" "B" } requestは以下の順序で出力を発生します。 "1A" "2A" "3A" "1B" "2B" "3B" "1A" "2A" … 関数によっては実行毎に出力候補の数が変動します。~たとえば以下の関数は、変数iの値によって候補数は2個もしくは4個に変化します。 request : sequential { if i { "1" "2" } "3" "4" } 候補数が変化した場合、nonoverlapとsequentialの巡回順序は初期化され、最初からやり直しになります。この時に限って、前回と同じ値が重複して 出力されることはあり得ます。 入れ子†request { { "Hello World" "こんにちは世界" } "Hallo Welt" } { } は階層的にいくつでも重ねて書くことが出来ます。動きは最上層の{ }と同じです。すなわち、包含される候補からひとつを選択して出力します。 出力確定子†request { "Hello" "Perfect" "Peaceful" -- " Wor" -- "ld" "th" }
nonoverlap、sequentialと組み合わせて使用した場合、(グループ単位ではなく)関数が取り得る全ての組み合わせに対して動作します。 出力確定子はどこでも問題なく使用できます。{ }入れ子の深い位置でも使えます。 文は文字列のほかに数値なども扱えますが、出力確定子は結合する際にそれらをすべて文字列に変換し、文字列として結合します。 値と変数†即値†文が扱える値は整数、実数、文字列の3種類です。 整数†符号付き32bit整数です。
10進数値はそのまま記述します。 int10 { 10 0b1010 0xa } 実数†符号付き64bit浮動小数点数です。小数点以下の桁がある場合や、精度が落ちてもいいので非常に巨大な数値を扱いたい場合はこれを使用します。 整数との区別は小数点の有無です。文は数値に小数点を見つけると、これを実数として取り扱います。 文字列†ダブルクォート(")で囲まれた値は文字列です。 文字列の中にダブルクォートが含まれてはいけません。 文字列(展開なし)†シングルクォート(')で囲まれた値は、展開されない単純な文字列です。 変数†変数は値を格納するための領域です。
を格納することができます。 名前は以下の禁止条項に抵触しない限りは自由につけることができます。
値の格納(代入)は代入演算子 = で行ないます。内容を出力するには、関数と同様にその名前を書きます。 request { str = "こんにちは" str } 上は単純な例で、変数strに文字列を格納し、そのまま出力しています。 まだ値が代入されていない変数は、空の文字列を出力します。~「何も出力しない」ではないことに注意してください。 request { "Hello World" i } i は存在しません。これは空の文字列になりますから、結局上の例は下のコードと等価であり、"Hello World"もしくは空の文字列を1/2の確率で出力することになります。 request { "Hello World" "" } 変数のスコープと寿命†変数はスコープ(有効範囲)の違いによって2種類存在します。
両者を区別するのは変数の名前です。変数名の先頭がアンダースコア("_")の変数は、ローカル変数として扱われます。 「必要な範囲だけで有効な変数」であるローカル変数をうまく利用することで、プログラムの見通しが良くなります。 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 } このプログラムは期待通りには動作しません。 演算†基本†C言語と同様の書式で四則演算、比較演算、代入、その他が可能です。 演算子 意味 優先度 ( ) [ ] ブラケット 高い ! 否定 ++ -- ポストインクリ/デクリ * / % 乗除算、剰余 + - 加減算 & フィードバック == != >= <= > < _in_ !_in_ 比較 && 論理積 || 論理和 = := 代入 += -= *= /= %= +:= -:= *:= /:= %:= ,= 演算して代入 , 汎用配列要素の列挙 低い コロン(":")付きの代入演算子は過去互換性を保持するために残されているもので、機能的にはコロン無しのものと同等です。 *は単項演算子です。 ブラケット( )については次項で詳説します。 foo { "or" _in_ "World" } _in_は左辺の文字列が右辺の文字列に含まれていれば1、含まれていなければ0を返します。!_in_はその逆です。 比較演算子は結果が真であれば整数1を、偽であれば0を返します。 代入でない演算は結果がそのまま出力となります。 foo { (3+2)*4 } この関数fooは20を出力します。 同じ優先度の演算子が連続している場合は、常に左から結合されます。 1+2-3 たとえば上の式は
の順に計算されます。 i = j = 10 これはどうなるでしょう。C言語では代入演算子は右から結合されますから、iとjには10が代入されます。
の順に計算されます。したがって、iには10は入らないのです。 i = (j = 10) これで i にも10が入るようになります。 演算対象の項の型が一致していない場合、結果の型は以下のようになります。
ひとつの演算式内で型が混在していても構いません。 "10+2は" + (10+2) + "です。" 最初に10+2が整数として計算され、結果12が得られます。残りはすべて文字列との加算ですから、12は文字列に変換され、文字列として結合されます。 ブラケット( )による演算順序制御†ブラケット( )で囲んだ部分は演算順序が最優先扱いになります。 answer = (_i = 10) + (2*(_i + 10)) 文の演算則をよく理解している人でないと、answerに何が代入されるかを正確に答えることは出来ないでしょう。 answer = (((_i = 10))) + (2*(_i + 10)) これで代入部分の優先度が一気に引き上げられました。今度は正しい結果が入るはずです。 なお、代入部分を囲むブラケットは2段で十分ではないかと思われるかも知れませんが、それも誤りです。ブラケット2段は_i + 10と同じ深さとなりますが、=と+では優先度が+のほうが高いのです。 フィードバック演算子&†フィードバック演算子&は、他の演算子とは使い方がまったく異なる独特の演算子です。 request { _i = 1 foo(&_i) } foo { _argv[0] = 100 } 関数呼び出しの際に引数として変数を与える場合、その先頭に&を書くことができます。
先頭に&を付けられた変数は、呼び出し先関数の_argvの対応する要素へ関連付けられます。すなわち、_argvを書き換えると、対応する呼び出し元の変数の値も書き換わるようになります。 request { foo(1, 2, &_value, "Hello", &_value2) _value + _value2 } foo { _argv[2] = _argv[0] + _argv[1] _argv[4] = _argv[3] + " World" } 関数requestは "3Hello World" を出力します。 当然のことですが、フィードバック演算子は変数にしか付けられません。 配列†演算子[ ]は配列要素にアクセスするための演算子です。 配列には文字列スプリットを擬似的に配列と見なす「簡易配列」と、カンマ区切りで列挙された要素を扱う「汎用配列」の2種類があります。 簡易配列†文字列に含まれるカンマをデリミタ(区切り文字)と解釈して、配列のように扱う機能です。 request { _a = "this,is,a,pen" _a[1] } requestは"is"を出力します。
[ ]演算子が処理する対象は変数である必要はありません。即値でも関数の返値でもいいです。 request { "this,is,a,pen"[1] } 序数の後ろにカンマ区切りでデリミタを指定することにより、カンマでなく他の文字列で簡易配列要素を区切ることができます。 request { "This is a island."[2,"is"] } "is"で区切るわけですから、文字列は以下のように分解されます。 [0] "Th"~ [1] " "~ [2] " a "~ [3] "land."~ したがってrequestは" a "を返します。 デリミタ指定をうまく使うと、多次元配列風に値を取り出すことが出来ます。 request { _ar = "taro|male,ayame|female,hotaru|female" _ar[2][1,"|"] } _ar[2]は"hotaru|female"です。さらに"|"を区切り文字として解釈して[1]を取り出しますので、結果は"female"となります。 このように、階層毎にユニークなデリミタを適用することによって、任意の位置の値を簡単に抜き出すことができるようになります。 範囲外の序数を指定した場合の出力は、存在しない変数の値を取り出そうとした場合と同様、空の文字列となります。 ここからは変数限定の機能を解説します。 要素に代入が可能です。 request { _a = "this,is,a,pen" _a[3] = "eraser" _a } "pen"を"eraser"に書き換えています。requestの実行結果は"this,is,a,eraser"となります。 デリミタ指定しても正しく機能します。 request { _s = "This is a island." _s[2,"is"] = " beautiful " _s } requestは"This is beautiful island."を出力します。 多次元配列風に[ ]演算子を連結して使用している場合、代入はできません。 request { _ar = "taro|male,ayame|female,hotaru|female" _ar[1][1,"|"] = "male" } ayameの性別をmaleに書き換えようとしていますが、この操作はエラーとなります。代入が可能なのは一次元の場合のみです。 現在の要素数を越える位置へも問題なく代入できます。デリミタが自動的に追加され、要素数が拡張されます。 request { _m = "fuji/asama/tanigawa" _m[5,"/"] = "daisen" _m } requestは"fuji/asama/tanigawa///daisen"を出力します。
SETDELIMという関数を使用すると、「デフォルトのデリミタ」をカンマから別の文字列へ変更できます。 request { _m = "fuji/asama/tanigawa" SETDELIM(_m, "/") _m[5] = "daisen" _m } SETDELIMすることにより、単純に_m[5]と書くことができるようになります。 多次元配列風に[ ]演算子を連結して使用している場合、SETDELIMは最初の(一次元目の)[ ]のみで有効です。 汎用配列†汎用配列はさまざまな型の値を混在して格納できる配列構造です。 初期化†i = (100,"test",-1.5) 要素をカンマで列挙して記述します。 (i = 100),"test",-1.5 このように解釈されてしまいます。 配列を空の状態で初期化するには、IARRAYという関数を使用します。IARRAYは「空の汎用配列」を返す関数です。 i = IARRAY 初期化時に要素をひとつだけ代入したい場合は工夫が要ります。たとえば単に i = 100 としたのでは、配列ではなくただの数値の代入になってしまうからです。 i = (IARRAY,100) 要素追加†i = (i,"add") とすると配列の後端に"add"が追加されます。
配列を追加することもできます。 i = (i,("add",123,0.0)) a = a + 1 を a += 1と略せるように、上の例は下のようにも書くことができます。 i ,= ("add",123,0.0) 先頭への挿入も同じ書式で可能です。 i = ("first",i) 中途への挿入もできます。 i = (100,200,300,400,500,600) i[2] ,= "insertion" iは(100,200,300,"insertion",400,500,600)となります。 i[2] = ("insertion",i[2]) とします。 要素削除†削除したい要素へIARRAYを代入します。 i = (100,200,300,400,500,600) i[2] = IARRAY 300が削除され、iは(100,200,400,500,600)となります。 値の更新†単純に要素へ代入できます。 現在の要素数を越える位置へも問題なく代入できます。必要な数だけ要素数が拡張されます。 値の取り出し†通常の変数と同様、序数を指定して記述すればそのまま出力されます。 範囲外の序数を指定した場合の出力は、存在しない変数の値を取り出そうとした場合と同様、空の文字列となります。 i = (100,200,300,400,500,600) i[4] 500が出力されます。
[ ]演算子が処理する対象は変数である必要はありません。即値でも関数の返値でもいいです。 (100,200,300,400,500,600)[4] 500が出力されます。 汎用配列をそのまま関数の出力にできます。 request { river[2] } river { "tenryu","bandou-tarou","ishikari","shimanto" } requestは"ishikari"を出力します。 多次元化はできない†汎用配列は多次元配列を構成できません。 (100,200,(300,400),500,600) このように書いても、内包されたブラケット部分が副次的な配列と認識されることはありません。 (100,200,300,400,500,600) 演算†要素単位の演算は通常に行うことが出来ます。 汎用配列と単項値との演算は、「全要素へ単項値が演算される」という独特の動作となります。 pref = "gunnma","ohsaka","hokkaido" pref += "-ken" answer = (2*(1,2,3))[1] prefは "gunnma-ken","ohsaka-ken","hokkaido-ken" となります。
answerには4が代入されます。 関数の引数†文において関数の引数は汎用配列です。_argvの内容は、呼び出し側引数がそのまま代入された汎用配列となっています。 つまり func(1, 2, "test") という関数の呼び出しは、 _i = (1,2,"test") func(_i) とも書けます。非常にトリッキーな表記ですが、これで意図どおりに動作します。 request { total(1,2,3,4,5,6) } total { calc_total(_argv) } calc_total { _answer = 0; foreach _argv; _val { _answer += _val } _answer } totalは自分では何もせず、すべての引数をそのままcalc_totalへ引き渡しています。 _i = (1,2,"test") func("sky", _i, "sun") 上の呼び出しは以下と等価です。汎用配列は多次元化できないことを思い出してください。 func("sky", 1, 2, "test", "sun") デリミタ/取得数指定†_i = (2,"is") "This is a island."[_i] 簡易配列のデリミタ指定の部分も汎用配列です。したがって上のようなことも出来ます。これは下の記述と等価です。 "This is a island."[2,"is"] 範囲指定†簡易配列/汎用配列とも、序数を範囲で指定できます。取得、代入とも可能です。 範囲は汎用配列で指定します。たとえば i[a,b] は「iの要素a~b」を表します。 name = ("さくら","せりこ","奈留","まゆら","毒子","美耳") i = name[1,3] name[3,4] = "奎子" j = name name[0,2] = IARRAY k = name iには ("せりこ","奈留","まゆら") が格納されます。 範囲外は無視されます。 n = (1,2,3,4) n[-2,1] *= 5 nは (5,10,3,4) です。 対象が簡易配列の場合でも書式は同じです。 name = "さくら,せりこ,奈留,まゆら,毒子,美耳" i = name[1,3] name[3,4] = "奎子" j = name iは "せりこ,奈留,まゆら" 、jは "さくら,せりこ,奈留,奎子,美耳" です。 デリミタ指定も可能です。範囲指定のすぐ後ろに続けて指定します。 animal = "くま!うさぎ!ねこ!いぬ!わに" i = animal[0,2,"!"] animal[2,4,"!"] = "ぶた" j = animal iは "くま!うさぎ!ねこ" 、jは "くま!うさぎ!ぶた" です。 汎用配列のパラレル出力†すべての式/値の前に「parallel」を書くことができます。 foo0 { ("A","B","C") "地球" } foo1 { parallel ("A","B","C") "地球" } foo0の出力は、("A", "B", "C") もしくは "地球"。 parallel STRLEN("earth") STRLEN("earth") 択一メソッドarrayとparallelを利用することにより、関数の出力候補と汎用配列を相互に変換することができます。 cyclic : sequential { parallel _argv } 文字列内埋め込み要素の展開†文字列の中に変数や関数を埋め込んで、これらの実行結果を当該位置へ挿入することができます。 範囲付き展開†要素を%( )で囲んで埋め込みます。 request { _i = "pen" "This is a %(_i)." } requestを実行すると、"This is a pen."が出力されます。 %( )はいわゆるeval(文字列をスクリプトコードと解釈して実行する)のような動作を行います。 単一の関数や変数だけでなく、数式を埋め込むことができます。 request { "1+2+3は%(1+2+3)です。" } requestは"1+2+3は6です。"を出力します。 文の文字列は内部にダブルクォートを含むことが出来ない点に注意してください。したがって、文字列を含む数式を埋め込むことは出来ません。以下はエラーです。 request { "This is a %(_i = "pen")." } このような場合は、埋め込みを使用せず通常の数式として結合します。 request { "This is a " + (_i = "pen") + "." } ブラケット( )による演算順序制御は範囲付き展開でも同様に働きます。~以下の例を見てください。 request { "遊星「%(_i = planet)」は遠い。この遊星は%(color(_i))色をしている。" } planet { "mars" "saturn" "pluto" } color { case _argv[0] { when "mars"; "red" when "saturn"; "yerrow" when "pluto"; "blue" others; "unknown" } } 最も( )が深いのはcolor(_i)の引数ですので、_i = planetの前にcolorが呼び出されてしまいます。 "遊星「%((_i = planet))」は遠い。この遊星は%(color(_i))色をしている。" これで矛盾の無い文字列が得られるようになります。 名称最長一致展開†( )を付与せず、単に%のみでも埋め込み展開は機能します。 request { o = "pen" obj = "eraser" object = "world" "This is a %object." } obje { "television" } 展開対象は%以降の文字列に一致する最も長い名前を持った変数/関数となります。上の例の場合、もっともよく一致するのは変数objectですから、これが採用されます。
結果は"This is a world."となります。
変数は刻々と作成されたり消えたりしますから、展開対象が状況によって変化することになります。 request { val = "red" trans -- value = "blue" trans } trans { "%value" } transは二度実行されますが、最初と二度目では"%value"の動きが変わります。すなわち、最初は変数val+"ue"、二度目は変数valueと解釈されます。 request { "「%planet」は遠い。「%city」も遠い。もっとも%[1]になら行けなくもない。" } planet { "mars" "saturn" "pluto" } city { "newyork" "moscow" "madrid" } %[i]は0オリジンでi番目の展開結果を得ます。 名称最長一致による展開は実行する度に展開対象を検索しなおしますので、範囲付き展開と比べて動作速度が劇的に遅いです。 フロー制御†ifによる分岐†式の結果が真であれば以降に続く{ }内を処理します。 request { if !i { "iは0である。" } } すぐ後にelseif節を付加することができます。これはifの判定が偽であった場合のみ処理されます。 request { if !i { "iは0である。" } elseif i == 5 { "iは5である。" } elseif "A" _in_ TOUPPER(i) { "iは文字列で、aもしくはAを含んでいる。" } else { "iは0でも5でもaを含む文字列でもない何物かである。" } } if、elseif、elseが処理する{ }内にスクリプトが1つしか存在しない場合は、{ }を略せます。したがって上の例は 下のように書きなおすことが出来ます。 request { if !i "iは0である。" elseif i == 5 "iは5である。" elseif "A" _in_ TOUPPER(i) "iは文字列で、aもしくはAを含んでいる。" else "iは0でも5でもaを含む文字列でもない何物かである。" } ただしifが重なっている場合は{ }の省略は出来ません。以下はC言語では正しいですが、文では誤りです。 if i == 0 if j == 0 "iとjはともに0である。" 以下のように{ }が必要です。 if i == 0 { if j == 0 "iとjはともに0である。" } C言語と同様に、ifの判定式は全体をブラケット( )で囲むことができます。 caseによる分岐†caseはラベル分岐構造を実現します。 request { case i { when 0 { "iは0である。" } when "A" "iは文字列Aである。" others { "iは0でもAでもない。" } } } caseに与えられた判定式の結果に一致するラベル値を持ったwhen節が実行されます。 request { case name+(i+1) { when "Pentium3","Pentium4" "Pen!!!は1999年、Pen4は2000年発売発売。" when "Pentium5"-"PentiumX" { "まだ無い。" } others "分からない。" } } whenに記述するラベル値は必ず即値でなければなりません。変数や関数、演算子を含む数式は記述できません。 when、othersが処理する{ }内にスクリプトが1つしか存在しない場合は、ifと同様に{ }を省略できます。 switchによる分岐†{ }内の出力候補から出力は無作為に選ばれますが、switchを使用すると選択する候補をを位置で指定できます。 request { switch id { "idは0である。" "idは1である。" { "idは2である。" "idはtwoである。" } "idは"3である。" } } 変数idの値によって出力される文字列が指定されます。指定は0オリジンです。 request { switch 1 { "かわいい" "天才" "サル" -- "とは言い難い" -- "ですね。" "かもしれません。" } } requestの出力は"天才かもしれません。"となります。 ループ†while、for、foreachの3種類のループ構造があります。 while†whileが評価する式が真である間は{ }内を繰り返し処理します。 request { _i = 1 _j = 0 while _i < 11 { _j += _i _i++ } "1から10をすべて足すと%(_j)である。" } 上の例はwhileの機能を簡単に説明しています。 下の例では異なる10個の文字列を発生しています。requestの出力は、1~10のうちいずれかの平方根を報告する文字列です。 request { _i = 1 while _i < 11 { "%(_i)の平方根は%(SQRT(_i))である。" _i++ } } for†forはwhileと同様の先判定ループ構造ですが、初期化式、脱出判定式、ループ毎に実行する式を一箇所にまとめて書ける点が優れています。 以下は、whileで挙げた平方根を報告する例をforで書き直したものです。 request { for _i = 1; _i < 11; _i++ { "%(_i)の平方根は%(SQRT(_i))である。" } } _i = 1はループを始める直前に実行されます。_i < 11はループ判定式で、これが真である間はループが続きます。_i++はループの一単位が完了して先頭へ
戻る際に実行される式です。
C言語では for ( ; ; ) とすることで無限ループとできますが、文では各式を省略できません。 for 1;1;1 などとしてください。ただ、whileなら while 1 で済むため、文で無限ループを作る際は、可読性の点からも、動作速度の点からも、whileを使用すべきであると言えます。 foreach†簡易配列、もしくは汎用配列の各要素値を順番に取り出します。 以下では簡易配列の要素値を取り出して数値へ変換し、すべての合計を計算しています。 request { _str = "1,3,5,7,9" _t = 0 foreach _str; _i { _t += TOINT(_i) } _t } foreachに続いて処理対象を記述します。上の例では簡易配列_strを指定しています。次に書かれた_iは取り出された要素値を格納する変数で、これは 必ず変数でなければなりません。 処理対象の変数のデリミタがSETDELIMによって変更されていても、foreachはそのデリミタを認識して正常に動作します。 foreachは汎用配列も処理できます。 request { _sent = ("I", "am", 31, "years", "old.") _t = "" foreach _sent; _i { _t += (_i + " ") } _t } requestは"I am 31 years old. "を出力します。 foreachループ内において要素取り出し対象の簡易配列、汎用配列を書き換えてもかまいません。 break†ループ中にbreakが現れると、現在実行中の最も深いループから脱出します。 request { _j = 0 for _i = 0; _i < 100; _i++ { _j = _i*_i if _j >= 100 break } _i - 1 } 上の例では、forは初期値0の_iが100に達するまでループを実行しようとします。しかし、ループ内には「_i を二乗した結果が 100 を越えたらループから抜ける」ようにbreakが仕込まれています。したがって、実際には _i = 10 の時点でループが終了します。
requestは_iから1を減じた価を返しています。つまりrequestは、二乗した結果が100を越えない最大の整数を求める関数です。 continue†ループ中にcontinueが現れると、その位置からすぐにループ先頭へ戻ります。 request { _j = "" for _i = 0; _i < 3; _i++ { _j += "go " if _i > 0 continue _j += "ahead " } _j } _iは0、1、2と変化しますが、1、2ではcontinueが働くので、_jに"ahead"を追加する式が実行されません。 return†returnが現れると、その関数の実行はそこで終わります。 to_rad { if GETTYPE(_argv[0]) == 3 { -1 return } _argv[0]*2.0*3.14/360.0 } 関数to_radはdegreeをradianへ変換します。 プリプロセス†プリプロセスは辞書ファイルを読み込んでいる段階で実行される命令です。 #define†辞書ファイルから読み込んだ(パース前の)生の文字列に対して、直接文字列置換を実行します。 #define before after とすると、これを記述した行より後ろにbeforeが見つかるたびに、それがafterへ置きかえられます。 #define の有効範囲は、宣言した次の行から、そのファイルの終端までです。
置換は記述順に行われますので、先に変換しておきたいものを先に書いてください。 #globaldefine†#globaldefine before after 機能は #define ディレクティブと同じです。ただし、有効範囲が異なります。 #globaldefine を宣言すると、次の行以降の全ての範囲(その後に読み込まれる辞書ファイルも含む)で有効になります。 たとえば最初に読み込む辞書ファイルの先頭に #globaldefine を記述すると、その効果はすべての辞書ファイルに及ぶことになります。 #defineが先に処理されます。。#globaldefine は、#define 置換のあとで実行されます。 #globaldefine tea green #define tea milk "teacup" 置換結果は"milkcup"となります。 予約語†以下の単語はシステム関数名、及び制御命令名です。 システム関数†../システム関数で記述されている関数は全て利用できません。 制御構造キーワード†
演算子†以下の単語/文字は演算子です。
謝辞†以下のライブラリを利用もしくは参考にさせていただきました。感謝致します。
|
最終更新日: 2008-03-07 (金) 22:08:04
|