リファレンス 1.0
このページでは「へたれBASIC」(1.0)の詳細な仕様、いわゆるリファレンスというのを載せてみようと思います。しかし簡単なプログラムといっても、仕様を書き出してみると以外と書く事が多いのに気が付きました。そんなわけで、プログラムの骨格となるような重要な仕様だけを最初に書いて、その他の細々とした部分は随時更新しながら書くことにしました。
こうして文章で書いてみると、各インターフェイスがいかに整合性が取れていないのかが良く分ります(爆)。ソースコードだけを追ってると、以前に作ったまま放ってあるインターフェイス(爆!)にも意味があるものと思っちゃうので、文書化はやっぱり重要です!!っていうか、もっと記憶力良くなれよ自分!(泣)

目次
型クラスの仕様
CInterpreterの実装
抽象演算子の種類
CMachineメンバと制御用OP_HANDLER


型クラスの仕様
CDataType
型を扱うためのクラス(型クラスと呼ぶことにします)の共通のインターフェイスと実装を持たせた抽象クラスです。

CDataType()
virtual ~CDataType()

virtual OP_HANDLER* GetOperator(ABS_OPERATION kind_op) = 0
戻り値
OP_HANDLER(演算処理用関数)のアドレス。ない場合は0を返す。
引数
kind_op ... 演算子のID。
機能
kind_opで指定された演算を行う関数のアドレスを返します。ここで返される関数は、実行時環境のデータ領域などとやり取りをして、演算処理を行います。対応する関数がない場合は、内部的にエラー値が設定されます。この値はGetLastErr()で取得することができます。
演算の種類については抽象演算子の種類をご覧下さい。

virtual OP_HANDLER* GetTypeChange(CDataType* pType) = 0
戻り値
OP_HANDLER(演算処理用関数・ jのアドレス。ない場合は0を返す。
引数
pType ... 変換対象となる型
機能
実行時にデータ領域のトップにある値を、pTypeで示される型の値に変換する関数のアドレスを返します。
しかし!!この機能はまだ実装してなかったりします。(泣)

bool IsEquel(const CDataType& type) const
戻り値
自オブジェクトがtypeと等価ならtrue、そうでないならfalse。
引数
type ... 判定対象の型変数
機能
typeで示される型変数と自オブジェクトで、型等価判定を行います。

bool IsEquel(int id) const
戻り値
自オブジェクトがidで示される型ならtrue、そうでないならfalse。
引数
id ... 型クラスのID
機能
idで示される型クラスと自オブジェクトで、型等価判定を行います。関数の引数の型など、型クラスのインスタンス毎の違いについては無視されます。

virtual bool IsArray()
戻り値
型クラスが配列ならtrue、それ以外はfalse
機能
型クラスが配列かどうか調べます。

virtual CDataType* CreateSameType(void) const = 0
戻り値
型変数と、同じクラスのインスタンス。
機能
型変数と、同じクラスのインスタンスを生成します。型変数内部の属性はコピーされません。デフォルトの値となります。

int GetId(void) const
戻り値
型クラスのID
機能
型クラスに割当てられたIDを返します。

void SetClass(STORAGE_CLASS cls)
引数
cls ... 記憶クラス
機能
記憶クラスを設定します。記憶クラスは翻訳の後処理に影響を及ぼします。

enum STORAGE_CLASS
{
NONE = 0, //未定
INDIRECT _OPERAND,//コード領域に即値として格納される
VARIABLE, //変数としてデータ領域に格納される
};

翻訳の後処理の時呼ばれる関数群
virtual ERR_CODE ChangeCode(CCode* pCode)
戻り値
発生したエラーコード。エラーがない場合は、ERR_NOTHING。
引数
pCode ... コード領域へのポインタ
機能
コード領域に実現値やアドレスを埋め込みます。

virtual ERR_CODE Push(void)
戻り値
発生したエラーコード。エラーがない場合は、ERR_NOTHING。
機能
データ領域に実現値を埋め込みます。この関数はCInterpreter::Interpret()が翻訳処理を終えた後、コード領域の走査を行い、その過程で型変数(実際には記号表)への参照が見つかった際に呼び出されます。

エラー処理用関数
static const char* GetOpName(ABS_OPERATION idop)
戻り値
演算子の文字列
引数
idop ... 演算子のID
機能
抽象演算子のIDに対応した演算子の文字列を返します。

ERR_CODE GetLastErr(void)
戻り値
最後に発生したエラーID
機能
最後に発生したエラーIDを返します。

CArrayType
CArrayTypeは配列型を扱うための型クラスです。任意の型を配列化できるようにするために、このクラスには別の方クラスを登録するインターフェイスも持っています。実行時、配列にアクセスするためには、添字の値を予めプッシュしておくなどの処理を行っておく必要がありますが、そのためのコマンドはCInterpreterによって構成されます。

ERR_CODE SuspendType(const CDataType* type)
戻り値
発生したエラー値。なければERR_NOTHING。
引数
type ... 登録する型変数のポインタ
機能
配列化する型を登録します。typeで示される型が登録されます・ ェ、内部で新しく型変数が生成されますので、一度型を登録した後はtypeとは独立に管理されます。またtype内の属性はコピーされません。(「へたれBASIC」では型クラスの種類だけ分れば十分ですのでこうしてますが、この仕様はもっと複雑な型システムを導入するようになった時に変えるかもしれません。)

CDataType* DeArray(void)
戻り値
登録されている型。未登録の場合は0。
機能
登録されている型変数へのポインタを返します。


int GetArrayNo(void)
戻り値
配列が登録された回数。
機能
CArrayTypeクラスのインスタンス全体で、SuspendType()が呼び出された回数を返します。この値は実行時に配列を分類するために使います。詳しくはAOP_ARRAY_PUSHをご覧下さい。

CFuncType
CFuncTypeは関数についての情報を保持する型クラスです。CFuncTypeは関数名と、引数の型のリスト、関数としての働きを提供するOP_HANDLERのアドレスなどの、設定と参照を行うためのインターフェイスを持っています。実行時に関数を呼び出すためには、引数をスタック上に積み重ねておく必要がありますが、この処理はCInterpreterのメンバ関数が、CFuncTypeのインスタンスを参照しながら作り出します。

CFuncTypeのインスタンスがCInterpreterへ登録される仕組み
CFuncTypeのインスタンスは、翻訳を開始する前に、関数名をキーにしてCInterpreter内の記号表に登録されるようになっています。具体的には、CInterpreter::LoadFunction()という関数に、下記のCFuncTableというクラス(構造体)のインスタンスへのポインタが渡され、それを読み取って、CFuncTypeのインスタンスを生成し、記号表に登録する処理が行われます。
CFuncTableのインスタンスはCFuncTypeのインプリメントファイルで、定数の配列として、その実現値が直に書かれてます。

struct CFuncTable
{
const char* pstr; //関数名
OP_HANDLER* pFunc; //関数の動作を司るOP_HANDLERのアドレス
const CDataType* pArgType[4];//引数と戻り値の型情報のバッファ
s tatic const CFuncTable* GetFuncTable(void);//インスタンス取得のための静的メソッド
};


int CntArguments()
戻り値
設定されている引数の個数。
機能
自オブジェクトに設定されている引数の個数を返します。


const CDataType* GetRetType()
戻り値
設定されている戻り値の型。
機能
自オブジェクトに設定されている、戻り値の型を返します。


void SetRetType(const CDataType* type)
引数
type ... 設定する戻り値の型。
機能
戻り値の型を登録します。


ERR_CODE AddArguments(const CDataType* type)
戻り値
発生したエラーのID。
引数
type ... 設定する引数の型。
機能
引数の型を登録します。この関数を最初に呼び出した時は第1引数の型が登録され、呼び出す度に第2引数、第3引数の型が登録されます。


ERR_CODE CheckArguments(int index, const CDataType* type)
戻り値
発生したエラーのID。
引数
index ... 登録されている引数の番号
type ... 比較する対象となる型変数。
機能
登録されている引数の型が、typeで示される型と同じかどうかを判定します。型が一致する場合は、ERR_NOTHINGを一致しない場合や、indexが範囲外の場合は対応するエラーIDを返します。


void SetFuncAddress(OP_HANDLER* pFunc)
引数
設定する関数のアドレス。
機能
関数としての機能を提供するOP_HANDLER関数を登録します。この関数はCFuncTypeのインプリメントファイルと同じファイルに書かれていて、実行時にはデータ領域の操作を行ったり、それ以外にも色々な動作を行います。



static void SetMachine(CMachine* machine)
戻り値
引数の個数
引数
machine ... 実行時環境(CMachineのインスタンス)へのポインタ
機能
実行時環境の参照を、CFuncTypeのファイルスコープに設定します。このスコープには「へたれBASIC」で呼び出した関数の実際の処理を行う関数が定義されてます。これらの関数は、実行時に設定されたポインタを介して、データ領域などの操作を行います。


CVoidType
CVoidTypeは、値を持たない型を表します。値を持たないので、この型の変数を作ることも出来ませんし、いかなる型の変数に代入することも出来ません。戻り値が定義されていない関数の戻り値を参照してしまうと、意味の無い値を参照することになってしまいます。これを防ぐために、戻り値が無い事を表す、このクラスを導入しました。


CIntegerType
CIntegerTypeは整数型を表す型クラスです。仮想関数GetOperator()は、データ領域の値を整数値として解釈して、四則演算や、Push/Popなど操作を行うOP_HANDLERを提供します。また、「へたれBASIC」のソースコード中に書かれた、定数値を保持するメンバ変数もあります。

CStringType
CIntegerTypeは文字列型を表す型クラスです。仮想関数GetOperator()は、データ領域の値を文字列を表すCStrクラスのインスタンスのポインタとして解釈して、文字連結や、Push/Popなど操作を行うOP_HANDLERを提供します。また、「へたれBASIC」のソースコード中に書かれた、文字列リテラルを保持するメンバ変数もあります。

OP_HANDLER対応表
各型クラスの仮想関数GetOperator()は渡された演算子のIDに基づいて、自クラスの型に見合った処理を行うOP_HANDLERを返します。しかし、各々の型が全ての演算に対応している訳ではありませんので、型と、演算子IDの組み合わせによってはOP_HANDLERを返さない場合もあります。
そこで、型クラスがOP_HANDLERを返すか、返さないかの組み合わせを表にしてみました。「●」が返す、「×」が返さないを表します。
 CArrayTypeCFuncTypeCVoidTypeCStringTypeCIntegerType
AOP_AND××××
AOP_OR××××
AOP_EQ×××
AOP_LE×××
AOP_GE×××
AOP_LT×××
AOP_GT×××
AOP_NQ×××
AOP_ADD×××
AOP_SUB××××
AOP_MUL××××
AOP_DIV××××
AOP_UMINUS××××
AOP_PUSHI×××
AOP_PUSHAT×××
AOP_POPAT×××
AOP_REMOVE××
AOP_FCALL××××
AOP_ARRAY_PUSH×××
AOP_ARRAY_POP×××
AOP_COMBINE×××××
AOP_PRINT×××
AOP_INPUT×××




CInterpreterの実装
CInterpreterは翻訳に関わる処理を統括しているクラスです。記号表や、構文木といったデータ構造を用いて、翻訳の過程で必要となる情報を記憶しています。

構文木について
構文木は式の構造を表すために導入しました。CDag型を使ったデータ構造で、4つのint値の組み合わせで一つのノードとなっています。構文木はCInterpreterの一連のMake〜()の内部で生成され、それぞれのint値はノードの種類毎に適宜キャスティングして使用されるため、ノードの種類毎に値の意味は異なります。ある種のノードは、別のノードの番号をint値として記憶する形で、子のノードへの参照を持つものがあり、これによって木構造の参照関係を作り出しています。全ての種類のノードに共通する構成は次のようになっています。

{ノードの種類,任意,任意,ノードが表す部分式の型}

ノードの種類には抽象演算子のIDが流用されています。これは計算式の構文の種類と、演算処理の種類にはあまり違いがないと思ったのでそうしました。これによって構文木から実行コードを生成するGenExpression()の実装を簡素化しています。
「任意」と書かれている箇所は個々のノード毎に異なる意味を持ちます。子ノードへの参照や、記号表への参照、その他の付加的な情報などが、Make〜()によって設定されます。
「ノードが表す部分式の型」は、そのノードによって作られた実行コードが、実行時、スタックトップへと積む値の
型を表します。「へたれBASIC」では全ての部分式の演算結果の型は静的に決まります。


メンバ関数
CInterpreterのメンバ関数は大別すると、yyparse()から呼び出される関数、main()から呼び出される関数、そしてCInterpreterの別のメンバ関数から呼び出される関数(ヘルパ関数)があります。
ヘルパ関数などは、privateで宣言しても、yyparse()やyyerror()などのフレンド指定された外部関数から呼び出されてしまう可能性もあります。せめて関数名から分かりやすくするため、内部的に呼び出される関数(ヘルパ関数)は、小文字とアンダーラインの組み合わせで書き、クラスの外側から呼び出される関数(インターフェイス関数)は、大文字と小文字の組み合わせで書くようにしました。

void SetSource(FILE *fp)
引数
fp ... ソースコードが格納されているファイルのポインタ。
機能
翻訳対象となるソースコードが格納されているファイルをCInterpreterのインスタンスへ設定します。

void SetMachine(CMachine* machine)
引数
machine ... 実行時環境のポインタ
機能
生成の対象となる実行時環境(CMachineのインスタンス)をCInterpreterのインスタンスへ設定します。

ERR_CODE Interpret(void)
戻り値
発生したエラーのID。
機能
ソースコードを翻訳して、実行時環境を構築します。

ERR_CODE LoadFunction(const CFuncTable* pFuncTbl)
戻り値
発生したエラーのID。
引数
pFuncTbl ... 関数の情報が入ったテーブルへのポインタ
機能
「へたれBASIC」のソースコードから呼び出される組込み関数を登録します。

ERR_CODE CreateDataRegion(void)
戻り値
発生したエラーのID。
機能
定数や変数が格納される領域を実行時環境のデータ領域に設定します。この関数はソースコードが全て解析された後に呼ばれます。

ERR_CODE WashCodeRegion(void)
戻り値
発生したエラーのID。
機能
コード領域の中で未解決の参照やジャンプ先に値を埋め込みます。この関数はソースコードが全て解析された後に呼ばれます。

CIdentifer* make_label_id(int strid)
CIdentifer* make_label_id(const char* pstr)
戻り値
ラベルが設定された記号表エントリへのポインタ。記号表エントリが不正の場合は0を返す。
引数
pstr ... ・ 宴xルの文字列へのポインタ。
strid ... ラベルの文字列を参照するためのID。
機能
記号表から指定された文字列で記号表エントリを検索し、そのエントリがラベル情報を保持しているかどうか調べます。もしエントリがラベルのものではない場合はFireError()し、0を返します。もしエントリが見つからなければ、新しいエントリを作り、ジャンプ先未定のラベルを設定して、記号表に登録します。

CIdentifer* gen_jumps_code(CIdentifer* pid, CMachine::COMMAND_HANDLER cmd)
戻り値
pidと同じ値。
引数
pid ... ラベルが登録されている記号表エントリへのポインタ。
cmd ... ジャンプ系のコマンドID(Jump, Jump_by_0, Callのどれか)。
機能
GenJump(), GenJumpBy_0(), GenCall()から共通して呼び出される、ジャンプ系コマンド生成用の関数です。ジャンプ先としてpidの値がコード領域に埋め込まれます。この値は構文解析終了後にジャンプ先のアドレスへと変換されます。

CIdentifer* GenJump(void)
CIdentifer* GenJump(int strid)
戻り値
検索/生成されたラベル用の記号表エントリのポインタ。
引数
strid ... ラベルの文字列を参照するためのID。
機能
stridで示される名前のラベルへの無条件ジャンプコマンド(Jump)を生成します。stridで示される名前が記号表にない場合は、新しくエントリを生成し登録します。stridが渡されていない場合は、他と重複しない名前が自動的に生成され、記号表に登録されます。

CIdentifer* GenJumpBy_0(void)
CIdentifer* GenJumpBy_0(int strid)
戻り値
検索/生成されたラベル用の記号表エントリのポインタ。
引数
strid ... ラベルの文字列を参照するためのID。
機能
stridで示される名前のラベルへの条件ジャンプコマンド(Jump_by_0)を生成します。stridで示される名前が記号表にない場合は、新しくエントリを生成 し登録します。stridが渡されていない場合は、他と重複しない名前が自動的に生成され、記号表に登録されます。

CIdentifer* GenCall(int strid)
戻り値
生成されたラベル用の記号表エントリのポインタ。
引数
strid ... ラベルの文字列を参照するためのID。
機能
stridで示される名前のラベルへのサブルーチンコールコマンド(Call)を生成します。stridで示される名前が記号表にない場合は、新しくエントリを生成し登録します。

ERR_CODE GenReturn(void)
戻り値
エラーが発生した場合は、エラー値を返す。発生しなかったら、ERR_NOTHINGを返す。
機能
Return文に対応するOP_HANDLERのアドレスを、コード領域に書き込みます。

ERR_CODE GenEnd(void)
戻り値
エラーが発生した場合は、エラー値を返す。発生しなかったら、ERR_NOTHINGを返す。
機能
Return文に対応するOP_HANDLERのアドレスを、コード領域に書き込みます。

ERR_CODE GenLabel(int strid)
ERR_CODE GenLabel(CIdentifer* pid)
戻り値
エラーが発生した場合はエラー値を返します。それ以外はERR_NOTHINGを返します。
引数
strid ... ラベルの文字列を参照するためのID。記号表エントリの検索に使います。
pid  ... ラベルが設定された記号表エントリへのポインタ。
機能
stridが渡された場合は、記号表エントリを検索します。記号表エントリが見つからない場合はFireError()を呼び出し、エラーを返します。
エントリに設定されているラベル情報に、現在生成されているコード領域の最後尾のアドレスを設定します。すでに別のアドレスが設定されていた場合は、FireError()しエラーを返します。

ERR_CODE GenFor(int strid, int iniTree, int dstTree, int stpTree)
戻り値
エラーが発生・ オた場合はエラー値を返します。それ以外はERR_NOTHINGを返します。
引数
strid ... ループカウンタ用変数の名前を参照するためのID。
iniTree ... ループの初期値を計算する式を表す構文木。
dstTree ... ループの終了値を計算する式を表す構文木。
stpTree ... ループの増分を計算する式を表す構文木。
機能
For文に対応する実行コードを生成します。実行コードの構成についてはCMachineメンバと制御用OP_HANDLERをご参照下さい。

ERR_CODE GenNext(int strid)
ERR_CODE GenNext(void)
戻り値
エラーが発生した場合はエラー値を返します。それ以外はERR_NOTHINGを返します。
引数
strid ... ループカウンタ用変数の名前を参照するためのID。
機能
Next文に対応する実行コードを生成します。実行コードの構成についてはCMachineメンバと制御用OP_HANDLERをご参照下さい。

ERR_CODE gen_next(const char* pstr)
戻り値
エラーが発生した場合はエラー値を返します。それ以外はERR_NOTHINGを返します。
引数
strid ... ループカウンタ用変数の名前を参照するためのID。
機能
2つのGenNext()関数の共通の機能を提供するヘルパ関数です。

ERR_CODE GenInput(int strid)
戻り値
エラーが発生した場合はエラー値を返します。それ以外はERR_NOTHINGを返します。
引数
strid ... 代入対象の変数名を参照するためのID。
機能
Input文に対応した実行コードを生成します。実行コードの構成については抽象演算子の種類をご参照下さい。


ERR_CODE GenPrint(int index)
戻り値
エラーが発生した場合はエラー値を返します。それ以外はERR_NOTHINGを返します。
引数
index ... 表示する値を生成する式を表す 構文木のノード番号。
機能
Print文に対応した実行コードを生成します。実行コードの構成については抽象演算子の種類をご参照下さい。

ERR_CODE GenRemove(int rtree)
戻り値
エラーが発生した場合はエラー値を返します。それ以外はERR_NOTHINGを返します。
引数
rtree ... 右辺式を表す構文木のノード番号。
機能
代入のない、右辺式のみの式文に対応する実行コードを生成します。右辺式の実行コードを生成のため、内部ではGenExpression()が呼び出されます。右辺式のコードによって計算された右辺値を削除するための実行コードが挿入されます。

ERR_CODE GenVarAssign(int strid, int rtree)
戻り値
エラーが発生した場合はエラー値を返します。それ以外はERR_NOTHINGを返します。
引数
strid ... 代入対象の変数名を参照するためのID。
rtree ... 右辺式を表す構文木のノード番号。
機能
変数に対して代入を行う式文に対応する実行コードを生成します。変数名が始めて出てくるものであった場合は、この変数に対応する記号表エントリを生成します。右辺式の実行コードを生成のため、内部ではGenExpression()が呼び出されます。現バージョンでは右辺値の型と、変数の型が一致しなければ代入を行うことはできません。
右辺値を変数に代入する実行コードが挿入されます。

ERR_CODE GenArrayAssign(int strid, int arg_node, int rtree)
戻り値
エラーが発生した場合はエラー値を返します。それ以外はERR_NOTHINGを返します。
引数
strid ... 代入対象の配列変数名を参照するためのID。
arg_node ... 添字の式を表す構文木のノード番号。
rtree ... 右辺式を表す構文木のノード番号。
機能
配列変数に対して代入を行う式文に対応する実行コードを生成します。変数名が始めて出てくるものであった場合は、この変数に対応する記号表エントリを生成します。右辺式の実行コードを生成のため、また配列の添字スタックに積むコードを生成するために、内部でGenEx pression()が呼び出されます。配列の要素へ右辺値を代入する実行コードが生成されます。詳しくはAOP_ARRAY_POPをご参照下さい。現バージョンでは右辺値の型と、配列変数の型が一致しなければ代入を行うことはできません。




ERR_CODE GenExpression(int index)
戻り値
エラーが発生した場合はエラー値を返します。それ以外はERR_NOTHINGを返します。
引数
index ... 構文木のノード番号。
機能
indexで示された構文木に対応する部分式の実行コードを生成します。この関数は構文木のノードの種類によって次のように別々の処理を行っています。
AOP_AND, AOP_OR, AOP_EQ, AOP_LE, AOP_GE, AOP_LT,
AOP_GT, AOP_NQ, AOP_ADD, AOP_SUB, AOP_MUL, AOP_DIVの場合:
ノードは左辺と右辺の子ノードを持っているので、その子ノードの番号を引数にして、GenExpression()を再帰的によびだし部分式の左辺と右辺の値をスタックトップに積むための実行コードを生成します。
次にノードの種類として設定されている抽象演算子のIDと、ノードが表す部分式の型から、対応する実行コード(OP_HANDLER)を生成します。
AOP_COMBINEの場合:
AOP_COMBINEはカンマ式に対応する構文木です。GenExpression()を再帰的によびだしカンマの左側と右側の値をスタックトップに積むための実行コードを生成します。
これらの値に対して何らかの演算処理を行うコードは生成しないため、これらのはスタックトップに残ったままになります。カンマ式は、配列の添字や、関数の引数をスタック上に積み上げるために使われます。カンマ式が連続している場合は、次のようにカンマ式の一番右側の部分式が、スタックトップになります。
ソースコード”式A , 式B , 式C”
構文木の構成
実行コード…|式Aの実行コード|式Bの実行コード|式Cの実行コード
計算後のスタック状態…|式Aの計算結果|式Bの計算結果|式Cの計算結果

AOP_UMINUSの場合:
AOP_UMINUSは単項マイナス式に対応する構文木です。対象となる部分式に対応した実行コードを再起呼び出しによって生成した後、単項マイナス演算を行う実行コードを書き込みます。
AOP_FCALLの場合:
AOP_FCALLは関数式に対応した構文木です。関数に引数がある場合は、引数に対応した部分式を書き出し、次に関数を呼び出す実行コード(といっても関数のアドレスそのものですが…)を書き出します。
AOP_PUSHIの場合:
AOP_PUSHIは定数式に対応した構文木です。定数値はAOP_PUSHIに対応するOP_HANDLERのオペランドとして取り込む形式となっています。詳しくはAOP_PUSHIをご覧下さい。
AOP_PUSHATの場合:
AOP_PUSHATは変数参照に対応した構文木です。AOP_PUSHATに対応するOP_HANDLERに続いて、変数の格納場所を示す整数値が、コード領域に書きこまれます。
AOP_ARRAY_PUSHの場合:
この構文木に対応する処理はヘルパ関数gen_array_push()が行っています。


ERR_CODE gen_array_push(int index)
戻り値
エラーが発生した場合はエラー値を返します。それ以外はERR_NOTHINGを返します。
引数
index ... 配列参照を表す構文木のノード番号。
機能
配列参照に対応した構文木から実行コードを生成します。この関数が構成する実行コードについてはAOP_ARRAY_PUSHをご参照下さい。また構文木の値の定義についてはmake_array()をご参照下さい。

int MakeExpr(int type, int ltree , int rtree)
戻り値
生成した構文木のノード番号を返します。エラーが発生するとCDag::NULL_NODEを返します。
引数
type ... 構文木に設定する演算の種類。
ltree ... 演算子の左辺を表す構文木のノード番号。
rtree ... 演算子の右辺を表す構文木のノード番号。
機能
以下の演算に対応する構文木を作ります。
AOP_AND, AOP_OR, AOP_EQ, AOP_LE, AOP_GE, AOP_LT, AOP_GT,
AOP_NQ, AOP_ADD,AOP_SUB,AOP_MUL,AOP_DIV
こららの演算の場合は、右辺と左辺との間での型・ フ互換性を検証した後に、{演算の種類,左辺のノード番号,右辺のノード番号,この演算の結果の型}という構成で構文木を生成します。型の互換性については、現バージョンでは左辺と右辺が同じ型でないと演算できない、という単純な規則を適用しています。
AOP_UMINUS
{AOP_UMINUS, 右辺のノード番号,0(ゼロ), この演算の結果の型}という構成で構文木を生成します。
AOP_COMBINE
{AOP_COMBINE, 左辺のノード番号, 右辺のノード番号,この演算の結果の型}という構成で構文木を生成します。

int MakeVar(int strid)
戻り値
生成した構文木のノード番号を返します。エラーが発生するとCDag::NULL_NODEを返します。
引数
strid ... 変数名の文字列を参照するためのID。
機能
指定された文字列で記号表を検索し、それが変数であるかどうかを確認して、変数の参照に対応する構文木を作ります。構文木の構成は次のようになります。
{AOP_PUSHAT, 変数の記号表エントリのポインタ, 0, この演算(変数)の型}

int MakeConstance(int strid, int id)
戻り値
生成した構文木のノード番号を返します。エラーが発生するとCDag::NULL_NODEを返します。
引数
strid ... 定数値の文字列を参照するためのID。
id ... 定数値の型の種類を表す番号。
機能
stridで示された文字列をidで示される型(STRING or NUMBER)を持つ値へと変換します。その型に対応した型変数を生成し、型変数に値を設定します。その型変数を、他と重複しない名前を付け記号表に登録します。そしてその記号表エントリのポインタと共に以下の構成の記号表を生成します。
{AOP_PUSHI, 定数の記号表エントリのポインタ, 0, この演算(定数)の型}

int MakeFuncOrArray(int strid, int arg_node)
戻り値
生成した構文木のノード番号を返します。エラーが発生するとCDag::NULL_NODEを返します。
引数
strid ... 定数値の文字列を参照するためのID。
id ... 定数値の型の種類を表す番号。< br>機能
関数や配列参照に対応した構文木を作ります。関数と配列は、構文としては変わらないので、識別子で記号表を検索し、型に合わせて、関数の構文木を作るmake_function()か、配列参照の構文木を作るmake_array()を呼び出します。どちらの型でもない場合は、エラーを報告します。

int make_function(CIdentifer* pid, int arg_node)
戻り値
生成した構文木のノード番号を返します。エラーが発生するとCDag::NULL_NODEを返します。
引数
pid ... 関数が登録されている記号表エントリへのポインタ。
arg_node ... 関数の引数を表す構文木のノード番号。
機能
関数呼び出しに対応する構文木を作ります。arg_ndoeで渡された(「へたれBASIC」の文法としての)引数の型の組み合わせが、正しいかどうかを、pidに登録されているCFuncTypeのインスタンスに問い合わせて確認します。次の形式で構文木を作ります。
{AOP_FCALL, pid, arg_node, この演算の結果(関数の戻り値)の型}

int make_array(CIdentifer* pid, int arg_node)
戻り値
生成した構文木のノード番号を返します。エラーが発生するとCDag::NULL_NODEを返します。
引数
pid ... 配列変数が登録されている記号表エントリへのポインタ。
arg_node ... 配列の添字を表す構文木のノード番号。
機能
配列参照に対応する構文木を生成します。arg_nodeには1つ以上の整数型か、文字列型の添字がなくてはならないので、これを確認します。そして次の構成の構文木を生成します。
{AOP_ARRAY_PUSH, pid, arg_node + (添字の個数 16), この演算(=pidに設定されている配列要素)の型}

ERR_CODE FireError(ERR_CODE err, const char* pstr=0)
戻り値
errで渡されたエラー値。
引数
err ... 報告対象となるエラー値。
pstr ... エラーが発生した単語。
機能
エラーを報告する際に呼び出される関数です。この関数はput_error()でエラーを標準エラー出力へ出力した後、致命的なエラーで あれば、構文解析を終了する処理を行います。また以下のメンバ変数に値を設定します。
m_bErrorHasFired ... 一度でもエラーが発生すると、trueになります。翻訳終了後、このフラグが立っていると、プログラムの実行は行われません。
m_lastError ... 直前に起こったエラーを保持します。CInterpeterの他のメンバ関数は、この値を参照することで、エラーが既に発生しているかどうか知ることが出来ます。この値はyyparse()によって翻訳単位の一文毎に初期化しています。

ERR_CODE put_error(ERR_CODE err = ERR_NOTHING, const char* pstr=0, int lineno = 0)
戻り値
生成した構文木のノード番号を返します。エラーが発生するとCDag::NULL_NODEを返します。
引数
err ... 表示するエラー番号。
pstr ... エラーメッセージと共に出力する文字列。
lineno ... エラーの発生した行番号。
機能
標準エラー出力にエラーを書き出します。

void VoidError(void)
機能
m_lastErrorの値を初期化します。この関数は、yyparse()によって、一つの文の解析が終わる度に呼び出されます。


抽象演算子の種類
抽象演算子は、各型クラスのGetOperator()関数によって実際の演算処理を行うOP_HANDLERに変換されます。これらのOP_HANDLERが、実行時にデータ領域に及ぼす作用や、コード領域でのオペランド(コード領域中に埋め込まれていて、OP_HANDLERに取り込まれる値)の形式は、どんな型であっても変わりありません。

各抽象演算子の作用
凡例;
抽象演算子のID
スタック状態の変化
“→”を境にして、左側は処理前のスタック状態、右側が処理後のスタック状態を表します。“,”で一つ一つのデータが区切られます。一番右側に書いた項目は、スタックトップの要素を表します。一番左側に“…”と書かれている部分は、その処理によって作用が及ぼされることのない要素が、スタックの底側にあるかもしれないことを表しています。また、データの名前の後に“…”が書かれ・ トいる場合は、同じ意味のデータが複数続くことを表し、“[”と“]”で囲まれている場合は、そのデータが省略される場合があることを表します。

オペランド
オペランドを持つ処理の場合はその意味を書きます。
処理
その処理の具体的な内容を書きます。

AOP_AND
スタック状態の変化
…,左辺,右辺 → …,計算結果
処理
左辺と右辺の論理積(AND)を計算します。

AOP_OR
スタック状態の変化
…,左辺,右辺 → …,計算結果
処理
左辺と右辺の論理和(OR)を計算します。

AOP_EQ
スタック状態の変化
…,左辺,右辺 → …,計算結果
処理
左辺と右辺の等価判定を行います。計算結果は等価なら1、それ以外は0になります。

AOP_LE
スタック状態の変化
…,左辺,右辺 → …,計算結果
処理
計算結果は左辺が右辺より同じか小さい場合は1、それ以外は0。

AOP_GE
スタック状態の変化
…,左辺,右辺 → …,計算結果
処理
計算結果は左辺が右辺より同じか大きい場合は1、それ以外は0。

AOP_LT
スタック状態の変化
…,左辺,右辺 → …,計算結果
処理
計算結果は左辺が右辺より小さい場合は1、それ以外は0。

AOP_GT
スタック状態の変化
…,左辺,右辺 → …,計算結果
処理
計算結果は左辺が右辺より大きい場合は1、それ以外は0。

AOP_NQ
スタック状態の変化
…,左辺,右辺 → …,計算結果
処理
左辺と右辺の値が異なれば1、等価なら0。

AOP_ADD
スタック状態の変化
…,左辺,右辺 → …,計算結果
処理
左辺の値に右辺の値を加算します。

AOP_SUB
スタック状態の変化
…,左辺,右辺 → …,計算結果
処理
左辺の値から右辺の値を減算します。

A OP_MUL
スタック状態の変化
…,左辺,右辺 → …,計算結果
処理
左辺の値に右辺の値を乗算します。

AOP_DIV
スタック状態の変化
…,左辺,右辺 → …,計算結果
処理
左辺の値を右辺で除算します。右辺が0ならばエラーを発生します。

AOP_UMINUS - (単項)
スタック状態の変化
…,右辺 → …,計算結果
処理
右辺の値の正負を反転します。

AOP_PUSHI
スタック状態の変化
… → …,オペランドの値のコピー
オペランド
即値
処理
オペランドの値をコピーして、スタックにPush(スタックトップに積む)します。

AOP_PUSHAT
スタック状態の変化
… → …,オペランドが示す場所の値のコピー
オペランド
アドレス
処理
オペランドの値によって示されたアドレス(データ領域の添字)に存在するデータをコピーして、スタックにPush(スタックトップに積む)します。

AOP_POPAT
スタック状態の変化
…,データ → … /* オペランドで示される位置へコピーされます。 */
オペランド
[アドレス]
処理
スタックトップのデータをPopして、オペランドの値によって示されたアドレス(データ領域の添字)に存在するデータヘコピーします。

AOP_REMOVE
スタック状態の変化
…,データ → … /* データは消去されます。 */
処理
スタックトップのデータをPopして、消去します。

AOP_FCALL 関数呼び出し
スタック状態の変化
…,[引数…] → [戻り値]
処理
関数呼び出しを行います。引数や戻り値の型や個数は各OP_HANDLER毎に異なります。(現バージョンでは戻り値は1個以下です。)

AOP_ARRAY_PUSH
スタック状態の変化
…,配列を個別に識別するID,配列の添字… → …,配列からコピーされたデータ
cIペランド
添字 の個数+1
処理
配列の内容をコピーして、スタックにPushします。配列の実装には、CMachine::m_DArray(ハッシュ表)が使われています。配列を個別に識別するIDや、配列の添字をキーにして、このオブジェクト内部を検索して、対応する要素を得ています。

AOP_ARRAY_POP ポップして配列の内部にコピー
スタック状態の変化
…,配列へコピーするデータ,配列を個別に識別するID,配列の添字… → … /* データは配列内にコピーされます。*/
オペランド
添字の個数+1
処理
データを配列内部へコピーします。

AOP_COMBINE
スタック状態の変化
…,左辺,右辺 → …,左辺,右辺 /* この演算に対応するOP_HANDLERはありません。*/
処理
何もしません。スタックに積み上げられた値は、後ほど関数の引数や、配列の添字として使われます。

AOP_PRINT
スタック状態の変化
…,表示するデータ → … /* データは標準出力へ出力されます。*/
処理
スタックからデータをPopし、標準出力へ書き出します。

AOP_INPUT
スタック状態の変化
… → …,入力されたデータ
処理
標準入力からデータを入力して、スタックにPushします。


CMachineメンバと制御用OP_HANDLER
CMachineは実行時環境を保持する他にも、プログラムの流れを制御するためのOP_HANDLERを返す機能もあります。これらのOP_HANDLERはCMachineのインプリメントファイルと同じファイルスコープの中で定義されています。

メンバ関数
static CMachine* GetInstance(void)
戻り値
唯一のCMachineインスタンス。
機能
CMachineのインスタンスを得ます。CMachineのコンストラクタは隠蔽されているため、CMachineのインスタンスを生成できるのは、この関数だけです。この関数は、CMachineのインスタンスが1つしか生成されないことを保証します。

void Go()
機能
翻訳が終わったプログラムを実行します。この関数は、CInterpreter::Interpret()によって既に翻訳が終了していることを前提として機能します。OP_HANDLERのエラーをチェックして、エラーがあれば、PutError()を呼び出した後、処理を終了します。

CCode::ELEMENT Fetch(void)
戻り値
コード領域上の値。
機能
現在解釈中のコード領域を1つ読み進めて、そこにある値を返します。各OP_HANDLERがその処理に必要とする値をコード領域から得る場合に呼び出されます。


void PutError(ERR_CODE err)
引数
err ... 表示するエラー値。
機能
各OP_HANDLERから返されるエラー値を標準エラー出力に書き出します。

OP_HANDLER* GetCtrlHandler(COMMAND_HANDLER id)
戻り値
制御用OP_HANDLERのアドレス。
引数
制御用コマンドのID。
機能
idで渡されたコマンドに対応するOP_HANDLERのアドレスを返します。

ReleaseData(void)
機能
プログラム終了後に、データ領域や配列領域の後始末を行います。


制御用OP_HANDLER
ここでは制御用OP_HANDLERが行う処理について詳解します。スタック状態などの表記法については、抽象演算子の種類をご参照下さい。


Jump
オペランド
ジャンプ先の一つ前のアドレス。
機能
無条件ジャンプを行います。

Jump_by_0
オペランド
ジャンプ先の一つ前のアドレス。
スタック状態の変化
…,条件値 → … 
機能
スタックトップからPopした値が0の時のみジャンプを行います。

Call
オペランド
コール先の一つ前のアドレス。
機能
サブルーチンコールを行います。コール先の文脈で、Returnコマンドが実行され ると、コール元の直後の命令から処理が開始されます。

Return
機能
直前に実行されたCallコマンドが存在する場所の1つ次の実行コードへジャンプします。

For
オペランド
ループカウンタに使用する変数のアドレス。
スタック状態の変化
…,目標値,増分 → …
機能
ループカウント変数のアドレスと、目標値、増分、この命令の場所を記憶します。この情報はNextコマンドを実行する際に、解釈されます。ループカウント変数の準備と初期化を行う実行コードは、CInterpreter::GenFor()で生成されています。

Next
オペランド
ループカウンタに使用する変数のアドレス。
機能
ループカウンタ変数に、Forコマンドで設定された増分を加算し、目標値を超えない場合は、対応するFor文の直後へジャンプします。Forコマンドにより設定されたループカウンタ変数のアドレスと、オペランドによって示されるアドレスが異なる場合は、エラーを返します。

End
機能
プログラムの実行を停止します。


 
前のページへ  次のページへ
言語処理系の制作に戻る
もくじに戻る