yacc/Doc/prog1.txt (1997, 4/11, 4/17) kan/k0 の内部構造とプログラミングに関する注意. kan/k0 におけるクラスの取扱は C++ や Java に一見して似ているが, 実は全く違う. むしろ, SmallTalk の方が近い. ☆ クラスのインスタンス変数は class 宣言のすぐ後, 次のように宣言する. class クラス名 extends スーパークラス名 { local インスタンス変数名1, インスタンス変数名2, ... インスタンス変数名n; メンバー関数定義 } 上の local 宣言を二つ以上書くとエラーになる. インスタンス変数名がないときは, local ; と宣言すること. ☆ インスタンス変数名は, そのクラス内での 局所変数名, メンバー関数引数名と して使えない. たとえば, class abc extends Object { local a,b; def foo(a) { は インスタンス変数名 a を引数として用いているのでエラーである. 現在のところ エラーメッセージを表示しないのでもっとたちがわるい. ☆ インスタンス変数名にたいする ピリオド . を用いた参照, 代入はできない. たとえば, this.a といった参照はできない. (将来的には, できるようにしたい. ) 参照, 代入はかならず, メンバー関数を用いて行なう. ☆ 生成子の書き方は, 次の形式に従うこと. (yacc/debug/graph.kk より) def new0(引数) { 生成子名はなんでもいい. this = new(); かならず, this = new(....) を書く. クラスの実体が PrimitiveObject の array として生成される. インスタンス変数の初期化 return(this); かならず、this を戻す. } new() は, 上のように, new() とよんでもいいし, this = new(super.スーパークラスの生成子) と書いてもいい. ==> 現在この書き方は正しく機能しない. 2001, 1/13 BUG: super は正しく動かないので使用しない方がよい. 現在のクラスが class Hoge extends Foo なら this = new( Foo.スーパークラスの生成子 ) と生成すべし. d0 で生成された sm1 のコードを参照. 生成法: cat object.kk ファイル | d0 ☆ class インスタンスの内部形式. class インスタンス は PrimitiveObject としては, array であり, その最初の要素は class タグである. インスタンス変数は, その array の要素である. 例えば, class Circle extends Object { local x, /* 中心 */ y, r; /* 半径 */ ; } class GraphicCircle extends Circle { local outline, fill; ; } なる宣言をすると, Circle インスタンスは, [Circle, xの値, yの値, rの値] なる array, GraphicCircle インスタンスは, [GraphicCircle, xの値, yの値, rの値, outlineの値, fillの値] なる array となる. kan/k0 インタプリタは, たとえば, x という変数があらわれると, kan/sm1 の, this 1 get なるコマンドを生成している. インスタンス変数名と, その位置インデックス の対応は, yacc/dic.c の関数で管理されている. ☆ extends により, 名前空間が, PrimitiveObject --- Object を頂点とする木構造に なっている. メソッドの検索は次のようにおこなわれる. 関数呼び出しは, 次のように翻訳される. aaa.foo(b,c) aaa [b c] {foo} sendmsg2 foo(b,c) this [b c] {foo} sendmsg2 すべての関数は二つの引数がスタックにあることを仮定している. sendmsg2 は, 第一引数が, クラスのインスタンス であるばあい, 名前空間 (コンテキスト) をその クラス のものに変更して, 関数呼び出しをおこなう. 例えば, 上の例で, aaa が Graphic の インスタンスであると, foo の実行は, Graphic の名前空間で実行される. operator +,-,*,/ については次のように翻訳される. a + b a b {add} sendmsg2 sendmsg2 は, 第一引数または第2引数が, クラスのインスタンス であるばあい, 名前空間 (コンテキスト) をその クラス のものに変更して, 関数呼び出しをおこなう. 例: class Integer extends Object { local ival; def new0(i) { this = new(); if (IsInteger(i)) ival = i; else { k00_error("new0","Argument must be integer."); sm1(" error "); } return(this); } def value() { return( ival ); } def operator add(b) { local r; r = Integer.new0(ival+b.value()); return(r); } } a = Integer.new0(3); a + a : なお, 上の4つ以外の, <,>, = , == などの operator に関しては, override はできないことに注意. ☆ kan/k0 のエンジン部分は初期状態で, 4本のスタックと 一つのコンテキスト をもっている. Operand Stack (標準のスタック, Kan/stackmachine.c では StandardStack) db.VariableStack db.ErrorStack db.DebugStack これらは var.sm1 で定義され, debug/db.k で活用される. db.VariableStack は, 関数呼び出しのときの, 引数や 関数の局所変数を 一次的に格納する stack である. db.DebugStack は, 関数呼び出しのとき, 現在実行中の関数を格納する stack である. --- engine error or interrupt : in function xxxxx という表示は, このスタックの情報をもとにしている. db.ErrorStack は, engine エラーが積まれるスタックである. コンテキストは, PrimitiveContextp (StandardContextp) が初期状態である. incmac.sm1 を参照せよ. なお PrimitiveObject = [PrimitiveContextp] である. SmallTalk のバイトコードマシンでは, コンテキストは, 名前辞書とスタック を合わせたものであるが, kan/k0 の場合, コンテキストとは, 名前辞書のことを さす. 名前辞書は名前とその値よりなる対応表である. 辞書はハッシュ法で 検索され, その辞書で値が見つからないと, その super 辞書へ検索が移行する. このような木構造での名前空間の実現については, Kan/stackmachine.c の *userDictionary* なる名前の関数を参照されたい. ☆ コンテキストスイッチについての注意. 上で説明したような, 名前空間の動的な変更はエラー処理に関して混乱をひきお こす. したがって, kan/k0 では, 次のような単純な, 解決法をとった. エンジンエラー, ctrl-C の入力があった場合, 必ず CurrentContext を, PrimitiveContext へ戻す. この方針は別の問題を引き起こす. たとえば, エラーが起きた時点の変数の 値の検査が一般にできない. いまのところ, kan/sm1 のコマンドをつかうしか ない. たとえば, class Abc でエラーが起きたとすると, sm1("Abc 0 get setcontext "); で, class Abc の名前空間に移行できる. sm1(" show_user_dictionary ") で現在の辞書に登録されている名前を みることができる. また, Println(変数名); でその変数の値を検査できる. 以上のような仕組みの問題点としては, Cleards(); による, 変数の値の回復ができないことをあげておく. (つまり現在の変数スタックは, どの名前空間かの情報をもっていないので、 変数の値の正しい回復ができない, また, context ごとに別のスタックを 用意している訳でない.) したがって, class を用いたプログラムは, エラーが起きたら, 再スタートするの が賢明である. ☆ Object については, 必ず概要, および, 実例を記述しておくこと. class を用いて書かれたプログラムは一般に読みにくい場合が多々ある. Object が中心にありプログラムをしているにもかかわらず, その Obeject の 概要を理解するのがソースからはむづかしいことが多いのが, その理由であると思われる. 例えば, ?????????????? (考えること)