MikoScript 言語仕様
 スレッド
 スレッドとは、本言語では、スクリプトを独立して実行できる単位のことです。
スクリプトの実行時に、スレッドは、複数同時に存在し得ますが、同時には
1つのスレッドだけしか実行されません。しかし、各スレッドの実行は、適時
切り換われるようになっています。
 本言語のスレッドは、本インタプリタ自身で管理しています。
これは、OSが管理するプリエンプティブなスレッドではありません。
本システムでは、基本的に、ノンプリエンプティブなマルチスレッドになります。
 本言語のスレッドは、コルーチン、あるいは、ファイバー的な形態で
実現されています。このスレッドは、OSが管理するスレッドと比較すると、
オーバーヘッドが少なく、軽量で、切り換えも高速に行なわれます。また、
なによりも、簡易に使うことができます。しかし、各スレッドの実行は、
自動的には切り換わらないので、各スレッド自身で操作する必要があります。
これは、面倒な場合もありますが、自ら任意に制御できるというメリットも
あります。
●スレッドの状態
 このような動作形態になっている本言語の各スレッドは、その生存中、次の
状態のうちのどれかになります。
実行中:
 現在スクリプトを実行しているスレッドが、この状態になります。
 この状態には、1つのスレッドだけしかなれません。
 この状態になるスレッドがない時もあります(全スレッドが睡眠時)。
 この状態のスレッドは、「スクリプトの実行権」を保持しています。
 この実行権は、「実行中」のスレッド自身が操作しない限り、
 他のスレッドに自動的に移譲されることはありません。
 これが、ノンプリエンプティブなマルチスレッドの特性です。
実行待ち:
 これは、実行準備が整っていて実行可能なスレッドの状態です。
 この状態のスレッドは、「スクリプトの実行権」が自分に移譲される
 のを待っています。
 複数のスレッドがこの状態にある時、待ち行列が形成されます。
 この行列は、早い者順に並びます。後から来た者は最後に並びます。
 この並び順が、「スクリプトの実行権」移譲のデフォールトの優先順位に
 なります。この順とは無関係に、特定のスレッドに実行権を移譲すること
 もできます。
睡眠中:
 これは、所定の時間が経過するまで、あるいは、所定のイベントが
 発生するまで、待っているスレッドの状態です。
 この状態のスレッドが複数ある時、待ち行列が形成されます。
 この行列は、待ち時間の短い順に並びます。しかし、必ずしも
 この順に待ち状態が解消されるとは限りません。
 この待ち状態が解消されたスレッドは、いきなり「実行中」になる
 のではなく、一旦「実行待ち」の状態になります。
●スレッドの動作
 まず、スクリプトを最初に実行する時点で、「メインスレッド」が生成
されます。メインスレッドは、「暗黙のメイン関数」をコールします。
その動作中に、メインスレッドは、他のスレッドを任意に生成することが
できます。もし、他のスレッドを生成しなければ、シングルスレッドの動作で
終わります。
 どのスレッドでも、他のスレッドを幾つでも生成できます。スレッドには、
生成した方と生成された方で、その親子関係上の生得的な差異はありません。
どのスレッドも平等に扱われます。
 スレッドが生成されると、そのスレッドが、いきなり「実行中」の状態に
なるわけではなく、まず「実行待ち」の状態になります。その際は,上記の
待ち行列の最後に並ぶことになります。一方、そのスレッドを生成した方の
親スレッドは、その「実行中」の状態を継続します。
 スクリプトの実行権は、現「実行中」のスレッドが、自ら、次のどれかを
行なった時に初めて、切り換わります。
  ・自身の実行を終了する
  ・明示的に実行権を他に移譲する
  ・睡眠に入る
  ・イベント待ち状態になる
 スレッドが生成される時には、通常、最初にコールすべき関数とその引数が
指定されます。つまり、スレッドの実行は、その関数コールで始まります。
一方、その関数を抜けた時(リターンした時)に、そのスレッドの実行が
終了します。
 各スレッドは、それぞれ、固有の「識別番号」が割り当てられています。
この値は、スレッドが生成された時に確定し、生涯変わりません。
特定のスレッドに対する操作を行なう時には、この識別番号で指定します。
 メインスレッドが終了しても、他のスレッドが残っていれば、スクリプトの
実行は継続します。全てのスレッドの実行が終了した時に、スクリプトの実行
が終了します。
●スレッドの協調
 一般に、マルチスレッド環境では、各スレッドの協調動作ができる必要が
あります。例えば、あるスレッドが自分の作業をしながら、他のスレッドに
別の作業を依頼して、それが完了した時点で、その結果を使うというような
場合です。
 このような動作を行なうには、各スレッドの同期が必要で、そのために、
  セマフォ、クリティカルセクション、イベント、ミューテックス等
の機能が、一般的には備わっています。
 本マルチスレッドの環境では、これらの機能は、「イベントキュー」等で
提供しています。これに関しては、後程説明します。
●スレッド操作関数
 スレッド関連の操作は、本言語では、以下のリレー型関数で行ないます。
 'start 関数
機能: 対象の関数をスレッドとして起動します。
書式: <関数名>'start( <引数の並び> )
返値: 起動したスレッドの識別番号( 起動失敗時は、null )
説明: 通常の関数コールの書式では、
      <関数名>( <引数の並び> )
    となりますが、関数をスレッドとして起動する場合は、上記のように、
    <関数名> と ( <引数の並び> ) の間に、'start を入れた書式になります。
    もし、その関数に引数がなければ、'start はリレー型関数なので、
      <関数名>'start
    のように、引数を省略しても構いません。
    'start を実行すると、新規にスレッドが生成されます。
    このスレッドの「識別番号」が、'start 関数の返値になります。
    新規生成されたスレッドは、即時に実行権を獲得するのではなく、
    まず「実行待ち」状態の待ち行列の最後に並びます。
    'start を実行したスレッド自身は、そのまま実行を継続します。
    起動したスレッドに、その場で実行権を移譲したい場合は、
      <関数名>'start( <引数の並び> )'yield;
    とします。'yield に関しては、後で説明しています。
    起動したスレッドを、T [ms] 時間経過するまで休止させる場合は、
      <関数名>'start( <引数の並び> )'sleep( T );
    とします。'sleep に関しては、後で説明しています。
用例:
        print "メインスレッド・スタート!";
        ^IsToStop = #FALSE;   // サブスレッドへの終了要求OFF
      
        // サブスレッドとして、Thread という関数を起動
        Thread'start( "サブスレッド・スタート!" );
      
        // メッセージボックス表示
        ::Inform( "メインスレッドが、このボックスを表示して、\n"
                  "サブスレッドが、裏でプリントしています。\n"
                  "このボックスを閉じると、\n"
                  "メインスレッドは、すぐに終了しますが、\n"
                  "サブスレッドは、しばらくしてから終了します。" );
      
        ^IsToStop = #TRUE;    // サブスレッドへの終了要求ON
        print "メインスレッド終了!";
        return;
      
        function  Thread( msg )     // この関数はサブスレッドで実行
        {
            print msg;    // メインスレッドからのメッセージをプリント
      
            // 0, 1, 2, 3, ... と順に数字をカウントアップしてプリント
            for( i = 0 ; i <= 1000 ; i++ )
            {
                print i;
                'sleep( 100 );
                if( ^IsToStop )   // メインスレッドから終了要求あり?
                    break;
            }
            print "サブスレッドは、もうすぐ終了します...";
            //(注意)メインスレッドが終了しても、サブスレッドは継続
      
            // 10, 9, 8, ... と順に数字をカウントダウンしてプリント
            for( i = 10 ; i >= 0 ; i-- )
            {
                print i;
                'sleep( 100 );
            }
            print "サブスレッド終了!";
        }
 'stop 関数
機能: 対象のスレッドの実行を(強制的に)終了します。
書式: <識別番号>'stop
説明: 'stop 関数を実行すると、その対象の <識別番号> に対応する
    スレッドの実行が(強制的に)終了します。
    <識別番号> が省略された場合、'stop を実行したスレッド自身の
    実行が終了します。
返値: 終了したスレッドの識別番号( 失敗時は、null )
    ( Ver1.24 以下では、成功時 1, 失敗時 0 )
注意: スレッドの実行終了は、通常、そのスレッドが起動された時に、
    最初にコールした関数から抜ける(リターンする)ことによって、
    行ないます。そうすれば、その関数のローカルスコープ内にクラスの
    インスタンスが残っていても、そのデストラクタが、通常通りにコール
    されます。しかし、'stop で、スレッドの実行を強制終了した場合、
    そのスレッドが使用していた全メモリーは正常に解放されますが、
    そのローカルスコープ内にあるインスタンスのデストラクタは、
    コールされません。
用例: 
        // サブスレッドを起動して、3 秒後に強制終了する
        Tid = Func'start;   // サブスレッドを起動
        'sleep( 3000 );     // 3 秒間休止
        Tid'stop;           // サブスレッドを終了
        return;
        function  Func()    // スレッドとして実行される関数
        {
            for( i = 1 ;; i++ )   // プリントを繰り返す
            {
                print i;
                'yield;    // ← 実行権の切り換えに必要!
            }
        }
 'sleep 関数
機能: 対象のスレッドを指定時間だけ睡眠させます。
書式: <識別番号>'sleep( <時間> )
説明: 'sleep は、<識別番号> に対応するスレッドを「睡眠中」の状態に
    移行させます。そのスレッドが既に睡眠中の場合は、その睡眠時間を、
    引数の <時間> に更新します。
    <識別番号> が省略された場合、'sleep を実行したスレッド自身が
    「睡眠中」の状態に移行します。たぶん大半の用途がこの場合でしょう。
    引数の <時間> には、睡眠時間(単位:ミリ秒)を指定します。
    <時間> を省略した場合、永久睡眠になります。
    <時間> の値が 0 以下の場合、睡眠時間が既に経過済みと見なされて、
    即時に起床します。(起床に関しては下記の注意参照)
    'sleep を実行したスレッドは、その睡眠対象が自分以外の場合、
    そのまま実行を継続します。
    'sleep を実行したスレッド自身が睡眠した場合、実行権は、
    「実行待ち」行列の先頭のスレッドに移譲されます。もし、その
    スレッドがなければ、全スレッドが「睡眠中」ということになります。
補説: 「睡眠中」のスレッドは、睡眠時間が経過すると起床します。その際、
    即時に実行権を獲得するのではなく、まず「実行待ち」行列の最後に
    回されます。その時、もし他に「実行待ち」のスレッドも「実行中」の
    スレッドもなければ、起床したスレッドが、実行権を獲得します。
注意: 「DLLのコールバック関数」内で、'sleep は実行できません。
返値: 睡眠したスレッドの識別番号( 失敗時は、null )
    ( Ver1.24 以下では、成功時 1, 失敗時 0 )
用例: 
            function  Func( x )  {  print x ;  }
            print "メイン開始";
            Func'start( "Thread (1)" )'sleep( 3000 );
            Func'start( "Thread (2)" )'sleep( 2000 );
            Func'start( "Thread (3)" )'sleep( 1000 );
            'wait;   // 全サブスレッドの終了を待つ
            'sleep( 1000 );
            print "メイン終了";
    このスクリプトを実行すると、次の各行が1秒経過するごとに
    ぽつぽつとプリントされます。
      メイン開始
      Thread (3)
      Thread (2)
      Thread (1)
      メイン終了
 'wake 関数
機能: 対象の睡眠中のスレッドを強制的に起床させます。
書式: <識別番号>'wake
説明: 'wake 関数を実行すると、その対象の <識別番号> に対応する
    睡眠中のスレッドを(強制的に)起床させます。
    <識別番号> が省略された場合、全ての睡眠中のスレッドを
    (強制的に)起床させます。
    起床させられたスレッドは、「実行待ち」行列の最後に並びます。
    'wake を実行したスレッド自身は、そのまま実行を継続します。
返値: 起床したスレッドの識別番号( 失敗時は、null )
    ( Ver1.24 以下では、成功時 1, 失敗時 0 )
注意: ダイアログ入出力待ち( ::Input, ::Confirm, ::Inform, ::Alert の
    どれかの関数を実行中)のスレッドに対して、'wake はできません。
用例: 
            function  Func( x )
            {
                print x : " 開始";
                'sleep;  // 永久睡眠
                print x : " 終了";
            }
            a = Func'start( "A" )'yield;
            b = Func'start( "B" )'yield;
            a'wake'yield;   // Aを起こして実行権を移譲
            b'wake'yield;   // Bを起こして実行権を移譲
    このスクリプトを実行すると、次のようにプリントされます。
      A 開始
      B 開始
      A 終了
      B 終了
 'wait 関数
機能: 対象のスレッドの実行が終了するまで待ちます。
書式: <識別番号>'wait( <時間> )
説明: 'wait を実行したスレッドは、<識別番号> に対応するスレッドの
    実行が終了するまで、睡眠状態で待機します。
    引数の <時間> は、タイムアウト時間(単位:ミリ秒)を指定します。
    <時間> の値が正の場合、それが待ち時間の限度になります。もし、
    その時間が経過しても、対象のスレッドの実行が終了していなければ、
    つまり、タイムアウトになると、待機中のスレッドは、睡眠状態を
    解除されて、「実行待ち」行列の最後に回されます。
    <時間> を省略した場合、永久に待ち続けます。
    <時間> の値が 0 以下の場合、即時にタイムアウトになります。
    <識別番号> が省略された場合、自分以外の全スレッドの実行が終了
    するまで待機します。但し、これが行なえるのは、メインスレッド
    だけです。
注意: どのスレッドも、メインスレッドの実行終了を待つことはできません。
    また、既に実行終了待ちをしているスレッドの実行終了を待つことは
    できません。また、自分自身の実行終了を待つこともできません。
    「DLLのコールバック関数」内で、'wait は実行できません。
返値: = 1: 対象スレッドの実行終了待ちが完了して、正常に復帰
    = 0: 失敗(対象スレッドの実行終了待ちができなかった場合)
    =-1: タイムアウト(対象スレッドの実行が終了する前に、
       引数の <時間> が経過してしまった場合)
用例: 
        function  A()  {  print "A開始";  'sleep( 3000 );  print "A終了";  }
        function  B()  {  print "B開始";  'sleep( 2000 );  print "B終了";  }
        function  C()  {  print "C開始";  'sleep( 1000 );  print "C終了";  }
        print "メイン開始";
        A'start();  B'start();  C'start();
        'wait();    // 全サブスレッドの終了待ち
        print "メイン終了";
    このスクリプトを実行すると、次のようにプリントされます。
      メイン開始
      A開始
      B開始
      C開始
      C終了
      B終了
      A終了
      メイン終了
 'yield 関数
機能: 対象のスレッドに実行権を移譲します。
書式: <識別番号>'yield
説明: 'yield を実行すると、まず、そのスレッドの実行権がなくなります。
    その際、そのスレッドは、「実行待ち」行列の最後に回されます。
    次に、<識別番号> に対応するスレッドが、「実行待ち」行列内から
    検索されて、もし見つかれば、そのスレッドに実行権が移譲されます。
    見つからないか、または、<識別番号> が省略された場合には、
    「実行待ち」行列の先頭のスレッドに、実行権が移譲されます。
    なお、「睡眠中」のスレッドに、実行権を移譲することはできません。
返値: 移譲先スレッドの識別番号( 失敗時は、null )
    ( Ver1.24 以下では、成功時 1, 失敗時 0 )
注意: 「DLLのコールバック関数」内で、'yield は実行できません。
用例: 
        ^A = A_Thread'start;
        ^B = B_Thread'start;
        return;
        function  A_Thread()
        {
            for( i = 1 ; i <= 3 ; i++ )
            {
                print "A: " : i;
                ^B'yield;
            }
        }
        function  B_Thread()
        {
            for( i = 1 ; i <= 5 ; i++ )
            {
                print "B: " : i;
                ^A'yield;
            }
        }
    ちなみに、これを実行すると、次の通りプリントされます。
     A: 1
     B: 1
     A: 2
     B: 2
     A: 3
     B: 3
     B: 4
     B: 5
 'ticks 関数
機能: 対象のスレッドの現時点までの実行時間の合計を取得します。
書式: <識別番号>'ticks
説明: 'ticks は、<識別番号> に対応するスレッドが、誕生してから
    現時点までに、実行権を獲得していた時間の合計を返します。
    <識別番号> が省略された場合、'ticks を実行したスレッド自身が
    対象になります。
返値: 実行時間の合計(単位がミリ秒の整数値)
    =-1: 失敗(対象スレッドがない場合)
注意: 本スクリプトのスレッドが実行権を獲得していても、実際には
    OSが他のプロセスにCPUを割り当てている場合があります。
    また、そもそも、本システムは、各スレッドの実行時間を厳密に
    管理しているわけではありません。そのため、'ticks の返す
    時間の精度はあまりよくありません。あくまで目安程度です。
    なお、本時間は、ミリ秒以下が切り捨てになります。
用例: 次のスクリプトを実行すると、for ループを百万回実行するのに
    要した時間がプリントされます。
            for( i = 0 ; i < 1`000`000 ; i++ )
                continue;
            print 'ticks;
 'tid 関数
機能: 現スレッドの識別番号を返します。
書式: 'tid
説明: 本関数は、本関数を実行したスレッドの「識別番号」を返します。
    ちなみに、これは整数値です。
●実行制御関数
 スクリプトの実行制御は、以下のリレー型関数で行ないます。
 'Error! 関数
機能: 現スレッドを異常終了します。
書式: 'Error!( <項目>,... )
説明: 本関数は、スクリプトの実行において、現スレッドのみを異常終了
    させます。他のスレッドは、通常通りです。
    'Error! は、自スレッドに対して 'stop を行なうのとほぼ同じですが、
    次の違いがあります。
    まず、'Error! では、スクリプトの実行上、異常があったことに
    なります。本言語が、テキストエディタ等のアプリケーションに
    組み込まれている場合、スクリプトの反復実行モードがありますが、
    'Error! が実行されれば、その反復実行モードは解除されます。
    次に、'Error! では、異常終了時に、引数で指定された各 <項目> を、
    (エラーメッセージとして)プリントします。
    引数は、なし、または、1個以上のプリント対象の <項目> を指定します。
    引数がない場合、'Error! だけで、丸括弧は勿論不要です。
    引数がある場合、各 <項目> のデータ型式は何であっても構いません。
    文字列なら、そのままプリントします。
    数値なら、適当な文字列に変換してプリントします。
    それ以外なら、所定の形態の文字列に変換してプリントします。
    このプリントでは、最後に自動的に改行が付加されることはありません。
注意: 「DLLのコールバック関数」内で、'Error! を実行すると、
    コールバック関数自身の実行が終了します。この場合、他のスレッド
    には影響しません。
返値: 無意味(そもそも本関数を実行したスレッドが終了してしまうため)
用例: 
        if( Result < 0 )
            'Error!( "不正な結果になりました!\n" );
    if(( file = ::File.Open( "ReadMe.txt", "in" )) == null )
            'Error!( ::ErrorMessage( $err_code, $err_info ), "\n" );
 'Pause! 関数
機能: スクリプトの実行を一時停止します。
書式: 'Pause!( <項目>,... )
説明: 本関数は、全スレッドの実行を一時停止することによって、
    スクリプトの実行を一時停止します。
    スクリプトの実行再開は、スクリプト自身では行なえません。
    本言語が、テキストエディタ等のアプリケーションに組み込まれて
    いる場合、実行再開のボタンを押すか、メニュー項目を選択します。
    しかし、本言語が、コンソールアプリケーションとして実装されて
    いる場合、実行再開の操作は通常できません。そのため、'Pause! は、
    スクリプトでは実行しないほうが良いでしょう。
    引数の <項目> があれば、一時停止する前に、プリントされます。
    この引数に関しては、'Pause! の場合と同様です。
返値: 無効( null )
 'Abort! 関数
機能: スクリプトの実行を強制的に中止します。
書式: 'Abort!( <項目>,... )
説明: 本関数は、全スレッドの実行を強制終了することによって、
    スクリプトの実行を強制的に中止します。
    引数の <項目> があれば、強制中断の前に、プリントされます。
    この引数に関しては、'Pause! の場合と同様です。
注意: 本言語が、テキストエディタ等のアプリケーションに組み込まれて
    いる場合、スクリプトの反復実行モードがありますが、
    'Abort! を実行すると、その反復実行モードは解除されます。
返値: 無意味(そもそも本関数を実行したスレッドが終了してしまうため)
用例: 
        if( DoSomethig() != #OK )
            'Abort!( "異常発生!(%d)\n"'fmt( Result ) );
●イベントキュー操作関数
 本スクリプト言語のマルチスレッド環境では、各スレッドの協調動作が
できるように、「イベントキュー」を提供しています。
 イベントキューでは、基本的に、あるスレッドがそこにイベントを
入れて、別のスレッドがそこから取り出すというような形態で使います。
このイベントは、各スレッド間で取り決めるもので、任意のデータが
使えます。ここでは、イベント(事象)と言っていますが、その意味に
限定して使う必要はありません。
 イベントを取り出す側のスレッドは、イベントキューが空の時には、
イベントが入ってくるまで、睡眠状態で待つことができます。
その際には、最大待ち時間を設定することもできます。現実行中の
スレッドが、この待ち状態になると、「実行待ち」行列の先頭の
スレッドに、実行権が移譲されます。
 イベントキューは、FIFO(First-In First-Out:先入れ先出し型
バッファ)としても、スタック(Last-In First-Out:後入れ先出し型
バッファ)としても、使えます。
 イベントキューでは、整数値や文字列だけでなく、任意の構造の複合箱の
出し入れも可能です。また、1つのイベントキュー内に、異なるデータ型、
あるいは構造の箱があっても構いません。
 イベントキューで箱を出し入れする際、箱の中身がコピーされるのではなく、
その箱自身が移動します。これは「移動代入」的な動作になります。
この移動は、コピーよりも、かなり高速で、メモリーの使用量も少なくて
済みます。
 イベントキューを使えば、イベント駆動型のプログラミングができます。
また、イベントキューを、セマフォや、ミューテックスとして、使うことも
できます。
 イベントキューは、マルチスレッド環境で使うように設計されていますが、
シングルスレッドでも、FIFOやスタックとして使うことができます。
また、イベントキュー自身は、複合箱の一種なので、箱としての一般的な
操作が可能です。
 次に、イベントキューを操作するリレー型関数を説明します。
 'queue! 関数
機能: 対象の箱をイベントキュー用の箱に設定します。
書式: <箱名>'queue!
説明: 本関数は、<箱名> で指定された対象の箱をイベントキュー用の箱に
    します。
    対象の箱が存在していない場合、その箱を新規に生成します。
    対象の箱が既存の複合箱の場合、その中身はそのまま引き継ぎます。
    対象の箱が既存の単一箱の場合、その中身は破棄して、その箱を、
    空のイベントキュー用の箱に変更します。
返値: 正常終了時、イベントキュー用に設定した対象の箱への一時参照
    不正終了時、null( <箱名> の指定が不正の場合等 )
用例: グローバルスコープに EventQue というイベントキュー用の箱を
    作成するには、
            ::EventQue'queue!;
    とします。ちなみに、当箱が既存でその中が空でない可能性がある
    時に、初期状態として必ず空を保証するには、
            ::EventQue'new!'queue!;
    とします。
 'push と 'post 関数
機能: 対象の箱内に、指定項目の箱を追加します。
書式: <箱名>'push( <項目>, ... )
    <箱名>'post( <項目>, ... )
説明: 'push は、対象の箱内の先頭に指定項目を追加します。
    'post は、対象の箱内の末尾に指定項目を追加します。
    両関数の違いは、これ以外には特にありません。
    <箱名> で指定された対象の箱が存在していない場合、
      その箱名で、空の複合箱を新規に生成します。
    対象の箱が既存の単一箱の場合、
      その中身を破棄して、その箱を空の複合箱に変更します。
    対象の箱が既存の複合箱の場合、
      そのまま使用します。
    追加する <項目> は、複数個指定しても構いません。
    指定された <項目> が、箱の場合、
      その箱は、対象の箱内に移動します。その結果、元の場所から
      その箱が無くなっているので、注意が必要です。なお、<項目> に
      指定する箱は、移動可能ならどのような箱でも構いません。
    指定された <項目> が、直値(数値/文字列リテラル等)の場合、
      その値を保持する箱が、対象の箱内に追加生成されます。
    いずれの場合でも、対象の箱内に追加された箱の名前は、
      適当な一時名になります。これは通常、気にする必要はありません。
補説: 'push と 'pop を使えば、スタック操作が行なえます。
    'post と 'pop を使えば、FIFO操作が行なえます。
    対象の箱は、必ずしも、イベントキュー用の箱でなくても構いません。
    また、本関数の実行によって、対象の箱がイベントキュー用の箱に
    変わるわけではありません。
    対象の箱がイベントキュー用の箱の場合、本関数の実行の最後で、
    そのイベントキュー待ちのスレッドがあるかどうかが確認されます。
    もしあれば、そのスレッドは、イベント待ちの状態を解除されて、
    「実行待ち」行列の最後に並びます。
    ちなみに、本関数コール時に <項目> の指定がなかった場合、何も
    追加されませんが、その時点でイベントキューが空でなければ、
    上記のイベントキュー関連の処理が行なわれます。
返値: 正常終了時、対象の箱への一時参照
    不正終了時、null( <箱名> の指定が不正の場合等 )
用例: (1) FIFOとして、整数値を出し入れする場合
              Q'post(1), Q'post(2), Q'post(3);
              Q'post(4,5,6);
              while(( v = Q'pop ) != null )
                  print v, -;
              print;
     これを実行すると、次のようにプリントされます。
       1, 2, 3, 4, 5, 6, 
    (2) スタックとして、文字列を出し入れする場合
              Q'push("A");  Q'push("B");  Q'push("C");
              Q'push("F","E","D");
              while(( v = Q'pop ) != null )
                  print v, -;
              print;
     これを実行すると、次のようにプリントされます。
       F, E, D, C, B, A, 
    (3) 注意
              for( i = 1 ; i <= 6 ; i++ )
                  Q'post( i );    // ← ※
      これは、上記(1)の例と同じ 'post 結果になりそうですが、
      ※ の実行時に、変数 i の箱が、Q の箱内に移動されて、
      元の場所には無くなるので、i++ の時に例外が発生します。
      これを避けるには、例えば、
                  Q'post( i'val );
      とします。または、
                  msg = i;
                  Q'post( msg );
      のようにしても構いません。
 'pop 関数
機能: 対象の箱内の先頭の箱を取り出します。
書式: <箱名>'pop( <時間> )
説明: 本関数は、<箱名> で指定された対象の箱内にある先頭の箱を、
    取り出します。この取り出しに関しては、下記の「補説」で
    もう少し詳しく説明しています。
    対象の箱が、複合箱でなければ、この取り出しに失敗します。
    対象の箱が、複合箱であって、その中が空でなければ、通常、
    この取り出しには成功します。
    対象の箱が、イベントキュー用の箱であれば、それが空であっても、
    そこにイベントが入って来るまで待つことができます。
    引数の <時間> は、そのタイムアウト時間(単位:ミリ秒)を指定します。
    <時間> の値が正の場合、その時間が経過しても、イベントが入って
    来なければ、つまり、タイムアウトになると、取り出しは失敗になります。
    その際、そのスレッドは、待機状態を解除されて、「実行待ち」行列の
    最後に並びます。
    <時間> を省略した場合、イベントが入って来るまで、ずっと待ち続けます。
    <時間> の値が 0 以下の場合、即時にタイムアウトになります。
    これは、対象の箱が空か否かを確認する時に使います。
    対象の箱がイベントキュー用の箱でなければ、<時間> の指定は無効です。
    つまり、対象の箱が空なら、即時、取り出しに失敗します。
返値: 取り出しに成功した時、取り出した箱( 下記「補説」参照 )
    取り出しに失敗した時、null
補説: 対象の箱内から取り出された箱は、ひとまず「一時箱」に移動されます。
    この時、その箱は元の場所には無くなっています。本関数の返値は、
    この一時箱を示す値になります。この一時箱は、通常の箱とほとんど
    同様に扱われます。ただ、これが代入式の右辺になる場合、その代入は
    必ず「移動代入」になります。つまり、代入演算子 =  :=  <- が
    どれであっても、一時箱の実体が代入先へ移動されます。これによって、
    その一時箱は消えます。一時箱は、このようにして消えなくても、
    使われなくなった時点で自動的に破棄されます。そのため、一時箱が
    いつまでも残存することはありません。
注意: <時間> 指定がない場合、対象の箱がイベントキュー用の箱か否かで、
    それが空の時の動作が異なるので注意が必要です。例えば、
      Q'pop
    では、Q がイベントキュー用の箱なら、ずっと待ち続けますが、
    Q がイベントキュー用の箱でなければ、即時に失敗して戻ってきます。
用例: 次のスクリプトは、メインスレッドが、イベントキューに、イベントを
    ポストし、サブスレッドがそれを取り出してプリントします。
        ::EventQue'new!'queue!;     // イベントキューを作成
        EventHandler'start();       // イベント受信スレッドを起動
        // イベントキューに、0, 1, ..., 9 の数値を 0.5 秒ごとにポスト
        for( n = 0 ; n < 10 ; n++ )
        {
            ::EventQue'post( n'val );
            'sleep( 500 );
        }
        ::EventQue'post( -1 );      // 終了を示すイベントをポスト
        return;
        function  EventHandler()    // イベント受信処理スレッド関数
        {
            do  // イベントキューからイベントを取り出してプリント
            {
                ev = ::EventQue'pop;    // イベントを受信するまで待つ
                print ev;
            }
            while( ev != -1 );
        }