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