Annotation of OpenXM/src/k097/Doc/prog1.txt, Revision 1.1.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>