Annotation of OpenXM/src/k097/Doc/prog1.txt, Revision 1.1
1.1 ! maekawa 1:
! 2:
! 3: yacc/Doc/prog1.txt (1997, 4/11, 4/17)
! 4: kan/k0 の内部構造とプログラミングに関する注意.
! 5:
! 6: kan/k0 におけるクラスの取扱は C++ や Java に一見して似ているが,
! 7: 実は全く違う. むしろ, SmallTalk の方が近い.
! 8:
! 9: ☆ クラスのインスタンス変数は class 宣言のすぐ後, 次のように宣言する.
! 10:
! 11: class クラス名 extends スーパークラス名 {
! 12: local インスタンス変数名1,
! 13: インスタンス変数名2,
! 14: ...
! 15: インスタンス変数名n;
! 16:
! 17: メンバー関数定義
! 18: }
! 19:
! 20: 上の local 宣言を二つ以上書くとエラーになる.
! 21:
! 22: ☆ インスタンス変数名は, そのクラス内での 局所変数名, メンバー関数引数名と
! 23: して使えない.
! 24:
! 25: たとえば,
! 26: class abc extends Object {
! 27: local a,b;
! 28: def foo(a) {
! 29:
! 30: は インスタンス変数名 a を引数として用いているのでエラーである.
! 31: 現在のところ エラーメッセージを表示しないのでもっとたちがわるい.
! 32:
! 33: ☆ インスタンス変数名にたいする ピリオド . を用いた参照, 代入はできない.
! 34: たとえば,
! 35: this.a
! 36: といった参照はできない. (将来的には, できるようにしたい. )
! 37: 参照, 代入はかならず, メンバー関数を用いて行なう.
! 38:
! 39: ☆ 生成子の書き方は, 次の形式に従うこと. (yacc/debug/graph.kk より)
! 40:
! 41: def new0(引数) { 生成子名はなんでもいい.
! 42: this = new(); かならず, this = new(....) を書く.
! 43: クラスの実体が PrimitiveObject の
! 44: array として生成される.
! 45: インスタンス変数の初期化
! 46: return(this); かならず、this を戻す.
! 47: }
! 48:
! 49:
! 50: new() は, 上のように, new() とよんでもいいし,
! 51: this = new(super.スーパークラスの生成子)
! 52: と書いてもいい.
! 53:
! 54: ☆ class インスタンスの内部形式.
! 55:
! 56: class インスタンス は PrimitiveObject としては, array であり,
! 57: その最初の要素は class タグである.
! 58: インスタンス変数は, その array の要素である.
! 59:
! 60: 例えば,
! 61: class Circle extends Object {
! 62: local x, /* 中心 */
! 63: y,
! 64: r; /* 半径 */
! 65: ;
! 66: }
! 67:
! 68: class GraphicCircle extends Circle {
! 69: local outline, fill;
! 70: ;
! 71: }
! 72:
! 73: なる宣言をすると, Circle インスタンスは,
! 74: [Circle, xの値, yの値, rの値]
! 75: なる array, GraphicCircle インスタンスは,
! 76: [GraphicCircle, xの値, yの値, rの値, outlineの値, fillの値]
! 77: なる array となる.
! 78: kan/k0 インタプリタは, たとえば, x という変数があらわれると,
! 79: kan/sm1 の,
! 80: this 1 get
! 81: なるコマンドを生成している. インスタンス変数名と, その位置インデックス
! 82: の対応は, yacc/dic.c の関数で管理されている.
! 83:
! 84: ☆ extends により, 名前空間が, PrimitiveObject --- Object を頂点とする木構造に
! 85: なっている. メソッドの検索は次のようにおこなわれる.
! 86:
! 87: 関数呼び出しは, 次のように翻訳される.
! 88: aaa.foo(b,c) aaa [b c] {foo} sendmsg2
! 89: foo(b,c) this [b c] {foo} sendmsg2
! 90:
! 91: すべての関数は二つの引数がスタックにあることを仮定している.
! 92: sendmsg2 は, 第一引数が, クラスのインスタンス であるばあい,
! 93: 名前空間 (コンテキスト)
! 94: をその クラス のものに変更して, 関数呼び出しをおこなう.
! 95: 例えば, 上の例で, aaa が Graphic の インスタンスであると,
! 96: foo の実行は, Graphic の名前空間で実行される.
! 97:
! 98:
! 99: operator +,-,*,/ については次のように翻訳される.
! 100: a + b a b {add} sendmsg2
! 101: sendmsg2 は, 第一引数または第2引数が, クラスのインスタンス であるばあい,
! 102: 名前空間 (コンテキスト)
! 103: をその クラス のものに変更して, 関数呼び出しをおこなう.
! 104: 例:
! 105: class Integer extends Object {
! 106: local ival;
! 107: def new0(i) {
! 108: this = new();
! 109: if (IsInteger(i)) ival = i;
! 110: else {
! 111: k00_error("new0","Argument must be integer."); sm1(" error ");
! 112: }
! 113: return(this);
! 114: }
! 115: def value() { return( ival ); }
! 116: def operator add(b) {
! 117: local r;
! 118: r = Integer.new0(ival+b.value());
! 119: return(r);
! 120: }
! 121: }
! 122:
! 123: a = Integer.new0(3);
! 124: a + a :
! 125:
! 126:
! 127:
! 128:
! 129:
! 130: なお, 上の4つ以外の,
! 131: <,>, = , == などの operator に関しては, override はできないことに注意.
! 132:
! 133:
! 134:
! 135: ☆ kan/k0 のエンジン部分は初期状態で, 4本のスタックと 一つのコンテキスト
! 136: をもっている.
! 137:
! 138: Operand Stack (標準のスタック, Kan/stackmachine.c では StandardStack)
! 139: db.VariableStack
! 140: db.ErrorStack
! 141: db.DebugStack
! 142: これらは var.sm1 で定義され, debug/db.k で活用される.
! 143:
! 144: db.VariableStack は, 関数呼び出しのときの, 引数や 関数の局所変数を
! 145: 一次的に格納する stack である.
! 146:
! 147: db.DebugStack は, 関数呼び出しのとき, 現在実行中の関数を格納する
! 148: stack である. --- engine error or interrupt : in function xxxxx
! 149: という表示は, このスタックの情報をもとにしている.
! 150:
! 151: db.ErrorStack は, engine エラーが積まれるスタックである.
! 152:
! 153:
! 154: コンテキストは,
! 155: PrimitiveContextp (StandardContextp)
! 156: が初期状態である. incmac.sm1 を参照せよ.
! 157: なお PrimitiveObject = [PrimitiveContextp] である.
! 158:
! 159:
! 160: SmallTalk のバイトコードマシンでは, コンテキストは, 名前辞書とスタック
! 161: を合わせたものであるが, kan/k0 の場合, コンテキストとは, 名前辞書のことを
! 162: さす. 名前辞書は名前とその値よりなる対応表である. 辞書はハッシュ法で
! 163: 検索され, その辞書で値が見つからないと, その super 辞書へ検索が移行する.
! 164: このような木構造での名前空間の実現については, Kan/stackmachine.c
! 165: の *userDictionary* なる名前の関数を参照されたい.
! 166:
! 167: ☆ コンテキストスイッチについての注意.
! 168:
! 169: 上で説明したような, 名前空間の動的な変更はエラー処理に関して混乱をひきお
! 170: こす. したがって, kan/k0 では, 次のような単純な, 解決法をとった.
! 171:
! 172: エンジンエラー, ctrl-C の入力があった場合, 必ず CurrentContext を,
! 173: PrimitiveContext へ戻す.
! 174:
! 175: この方針は別の問題を引き起こす. たとえば, エラーが起きた時点の変数の
! 176: 値の検査が一般にできない. いまのところ, kan/sm1 のコマンドをつかうしか
! 177: ない.
! 178: たとえば, class Abc でエラーが起きたとすると,
! 179: sm1("Abc 0 get setcontext ");
! 180: で, class Abc の名前空間に移行できる.
! 181: sm1(" show_user_dictionary ") で現在の辞書に登録されている名前を
! 182: みることができる. また,
! 183: Println(変数名);
! 184: でその変数の値を検査できる.
! 185:
! 186: 以上のような仕組みの問題点としては,
! 187: Cleards(); による, 変数の値の回復ができないことをあげておく.
! 188: (つまり現在の変数スタックは, どの名前空間かの情報をもっていないので、
! 189: 変数の値の正しい回復ができない, また, context ごとに別のスタックを
! 190: 用意している訳でない.)
! 191: したがって, class を用いたプログラムは, エラーが起きたら, 再スタートするの
! 192: が賢明である.
! 193:
! 194:
! 195: ☆ Object については, 必ず概要, および, 実例を記述しておくこと.
! 196:
! 197: class を用いて書かれたプログラムは一般に読みにくい場合が多々ある.
! 198: Object が中心にありプログラムをしているにもかかわらず, その Obeject の
! 199: 概要を理解するのがソースからはむづかしいことが多いのが,
! 200: その理由であると思われる.
! 201: 例えば, ?????????????? (考えること)
! 202:
! 203:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>