13-08.スクリプトの実行
CLangProject側の
main.cppには以下の記述があります。
#include "proc.h"
//中略
int main(int argc, char** argv) {
InputParser input(argc, argv);
const string& filename = input.getCmdOption("-f");
if (filename.empty()) {
cout << "スクリプトファイルが指定されていません。" << endl;
return 1;
}
errno_t err;
FILE* fp;
if ((err = fopen_s(&fp, filename.c_str(), "r")) != 0) {
cout << "スクリプトファイルの読み込みに失敗しました。" << endl;
return 1;
}
auto tntp = clg::StackMachine::get();
if (tntp->compile(fp)) {
return 1;
}
tntp->execute();
tntp->destroy();
return 0;
}
赤くなっているところですが、
tntpポインタに
StackMachineクラスのインスタンスのポインタを代入し、以降はそのポインタ経由で操作しています。
if (tntp->compile(fp)) {
return 1;
}
は、BisonやFlexの字句解析や構文解析を行います。失敗すれば終了します。
前項で説明した内容が処理されます。
は
実行です。この関数は以下のような内容になります。
void StackMachine::execute() {
if (m_pRoot) {
m_pRoot->execute();
}
}
m_pRootというのは
Rootクラスのインスタンスのポインタです。コンパイル時に構築されます。
は以下の内容になります。
Value Root::execute() {
// main関数を探して実行
FunctionCallExp* pFunc = new FunctionCallExp("main");
pFunc->execute();
return Value();
}
ここでは、
main関数を
スクリプトを探して、見つかったら実行します。
関数は
関数の定義リストとして、
DeclarationList* m_pDeclarationList;
という
Rootクラスのメンバ変数として保持しています。
関数は、前項で説明した
clg::StackMachine::get()->createIntFunctionDeclaration関数;
によって定義ずみです。この内容は
//int型関数定義
Declaration* StackMachine::createIntFunctionDeclaration(Expression* pExp, Statement* stm) {
IdentifierExp* pIdent = dynamic_cast<IdentifierExp*>(pExp);
CompoundStatement* pComp = dynamic_cast<CompoundStatement*>(stm);
if (pIdent && stm) {
auto pObj = new IntFunctionDeclaration(pIdent, stm);
m_objPool.push_back(pObj);
return pObj;
}
else {
cout << "関数定義が間違っています" << endl;
exit(1);
}
return nullptr;
}
のようになっています。この中で
IntFunctionDeclarationクラスのインスタンスが構築されますが、そのオブジェクトは
CLangProject.yにて
declaration_list
: declaration
{
$$ = clg::StackMachine::get()->createDeclarationList($1);
}
| declaration_list declaration
{
$$ = clg::StackMachine::get()->createDeclarationList($1,$2);
}
;
と
定義リストに追加されます。その内容は、最終的には
CLangProject.yの
root
: declaration_list
{
$$ = clg::StackMachine::get()->addRootDeclarationList($1);
}
;
と
Rootオブジェクトの
DeclarationList* m_pDeclarationList;
に追加されます。そのコードは
//ルートへのDeclarationListの追加
Root* StackMachine::addRootDeclarationList(DeclarationList* decl) {
if (m_pRoot) {
m_pRoot->setDeclList(decl);
}
return m_pRoot;
}
です。
スクリプトでは
int func() {
dump 30;
}
int main () {
dump 10;
dump 20;
func();
}
のように
main関数も存在します。
さて、
実行の前置きが長くなりました。
いずれにせよ、
Value Root::execute() {
// main関数を探して実行
FunctionCallExp* pFunc = new FunctionCallExp("main");
pFunc->execute();
return Value();
}
のように
main関数を実行します。
関数の実行式は
Value FunctionCallExp::execute() {
bool flg = false;
auto pRoot = StackMachine::get()->getRoot();
auto pos = pRoot->getDeclList();
do {
auto decl = pos->getDecl();
auto tgt = dynamic_cast<IntFunctionDeclaration*>(decl);
if (tgt) {
string str = tgt->getIdentity();
if (str == m_Identity) {
flg = true;
tgt->excute();
break;
}
}
pos = pos->getNext();
} while (pos);
if (!flg) {
cout << "関数が見つかりません。: " << m_Identity << endl;
exit(1);
}
return Value();
}
となります。
実行結果
ここまでの実装で、
int func() {
dump 30;
}
int main () {
dump 10;
dump 20;
func();
}
というスクリプトは
10
20
30
...\Debug\CLangProject.exe (プロセス 18652) は、コード 0 で終了しました。
このウィンドウを閉じるには、任意のキーを押してください...
という実行結果になります。
なーんだ、つまんない、とか思わないでください。
これが
言語の開発です。ゆっくりゆっくり進むのです。
次項からは、いよいよ
変数を実装したいと思います。
ゆっくりお付き合いいただければ幸いです。