File: [local] / OpenXM / src / k097 / Doc / prog1.txt (download)
Revision 1.1.1.1 (vendor branch), Fri Oct 8 02:12:16 1999 UTC (24 years, 11 months ago) by maekawa
Branch: OpenXM
CVS Tags: maekawa-ipv6, RELEASE_20000124, RELEASE_1_1_3, RELEASE_1_1_2, ALPHA Changes since 1.1: +0 -0
lines
o import OpenXM sources
|
yacc/Doc/prog1.txt (1997, 4/11, 4/17)
kan/k0 の内部構造とプログラミングに関する注意.
kan/k0 におけるクラスの取扱は C++ や Java に一見して似ているが,
実は全く違う. むしろ, SmallTalk の方が近い.
☆ クラスのインスタンス変数は class 宣言のすぐ後, 次のように宣言する.
class クラス名 extends スーパークラス名 {
local インスタンス変数名1,
インスタンス変数名2,
...
インスタンス変数名n;
メンバー関数定義
}
上の 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.スーパークラスの生成子)
と書いてもいい.
☆ 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 の
概要を理解するのがソースからはむづかしいことが多いのが,
その理由であると思われる.
例えば, ?????????????? (考えること)