ObjectScript API、C ++との統合。 パート1:スタックの操作、C ++からのOS関数の呼び出し

ObjectScriptは、新しいオープンソースのオブジェクト指向プログラミング言語です。 ObjectScriptは、JavaScript、Lua、PHPなどの言語の機能を拡張します。 彼のプレゼンテーションは、 この記事でしばらく前にハブで行われ、読者の間で興味と熱烈な議論を呼び起こしました。 そのため、プレゼンテーションにこだわらず、ObjectScript APIについて説明しないことにしました。 APIの説明をいくつかの部分に分けて、記事をできるだけ短くするようにします。

パート1:スタックの操作、C ++からのOS関数の呼び出し


OS(ObjectScript)を使用した最小限のプログラムは次のとおりです。

#include "objectscript.h" using namespace ObjectScript; int main() { OS * os = OS::create(); // TODO: main code here os->release(); return 0; } 

つまり OSインスタンスを作成し、それを使用して正しくdeleteます。ただし、 deleteオペレーターだけでなく、 releaseメソッドを呼び出します。

OSインスタンスは必要な数だけ同時に作成でき、必要に応じて、互いに完全に独立して動作します。

次に、 TODOの代わりに配置する必要があるコードの例を示しますメインコードはこちらです。

それでは、C ++を使用して次のOSコードをシミュレートしましょう。

 print("10 * (3+2) = ", 10 * (3+2)) 

ここにあるもの:2つのパラメーターを持つグローバル関数の呼び出し。1つ目は定数文字列、2つ目は数学演算の結果です。

最初に行うことは、関数呼び出しを準備することです。 これを行うには、スタックに2つの値を配置する必要があります。1つ目は関数自体で、2つ目はこの関数の値です。 たとえば、静的関数など、関数がこれを使用しない場合、 nullthisとして配置する必要があります。 このようにします:

  os->getGlobal("print"); // #1 -     os->pushNull(); // #2 

次に、関数が呼び出されるパラメーターをスタックに追加します。

  os->pushString("10 * (3+2) = "); // #3 -   

次に、2番目のパラメーターの数学演算をシミュレートします。

  os->pushNumber(10); // #4 os->pushNumber(3); // #5 os->pushNumber(2); // #6 os->runOp(OP_ADD); // #5 - 3+2 os->runOp(OP_MUL); // #4 - 10 * (3+2) 

できた! runOpメソッドは、OSカーネルを使用して、スタック内の値に対して数学、論理、およびビットごとの演算子を実行できます。 つまり、必要に応じて、型変換などが行われます。... OP_ADDは、スタックの最上部の2つの値(つまり、最後に2回スタックに置かれた値)に対して加算演算子を実行します。 この場合、結果はスタック上の値を置き換えます(つまり、2つの値がスタックから削除され、結果が追加されます)。 OP_MUL乗算についても同様です。

現時点では、スタックに4つの値があります: 1-関数、 2 -null、 3-文字列、 4-数値。 いいね! あなたは電話することができます:

  os->call(2); //    2  

それだけです、私たちはコンソールを見ます(コンソールに印刷結果を印刷)、それは次のようになります:

 10 * (3+2) = 50 

この場合、スタックは完全に空になります。 関数を呼び出すときに使用される4つの値は、スタックから削除されます。

例2


OSで次のコードをシミュレートします。

 bar = {firsname="James", lastname="Bond"} bar.profession = "actor" print bar 

スタック上に新しいオブジェクトを作成します。

 os->newObject(); // #1 

最初のプロパティfirsname="James"設定します。

 os->pushStackValue(-1); // #2 

-1は、スタックの最上部への相対ポインターです。 プロパティを設定するスタックにオブジェクトを追加します(オブジェクトは参照によりスタックに追加されます)。

 os->pushString("firsname"); // #3 -   os->pushString("James"); // #4 -    os->setProperty(); // #1 

setPropertyメソッドは、プロパティを設定し、使用されている値をスタックから削除します(この場合、スタックの最上部で3つの値が使用されます:オブジェクト、プロパティ名、および値)。

2番目のプロパティでも同じことを行いますが、より短い方法で行います。

 os->pushString("Bond"); // #2 -  os->setProperty(-2, "lastname"); // #1 

-2はスタックの先頭から2番目の値への相対ポインターであり(これがオブジェクトです)、文字列"Bond"がスタックの先頭になりました。

オブジェクトをグローバル変数barに保存します

 os->setGlobal("bar"); // #0 

現在、スタックには値がありません。 次に、コードbar.profession = "actor"実行します。

 os->getGlobal("bar"); // #1 -      bar os->pushString("actor"); // #2 os->setProperty(-2, "profession"); // #1 os->pop(); // #0 -    bar   

完了、 print bar

 os->getGlobal("print"); // #1 os->pushNull(); // #2 os->getGlobal("bar"); // #3 os->call(1); // #0 

コンソールを見ると、次のようになっているはずです。

 {"firsname":"James","lastname":"Bond","profession":"actor"} 

例3


OSで次のコードをシミュレートします。

 print(concat(5, " big differences")) 

通常どおり開始します。

 os->getGlobal("print"); // #1 -      print os->pushNull(); // #2 -  this   print os->getGlobal("concat"); // #3 -      concat os->pushNull(); // #4 -  this   concat os->pushNumber(5); // #5 -    concat os->pushString(" big differences"); // #6 -    concat os->call(2, 1); // #3 -   concat 

この段階で、2つのパラメーターを使用して関数を呼び出し、出力で1つの結果を要求しました(0の結果を要求した場合、concatは1つのデフォルト結果を返します。関数呼び出しの後、2つ以上の値が必要な場合、最初の結果はconcat関数からのもので、残りはnullで補完されます)。

次にprint呼び出しprint

 os->call(1); // #0 

コンソールでは次のようになります。

 5 big differences 

プログラムの全文:

 #include "objectscript.h" using namespace ObjectScript; int main() { OS * os = OS::create(); /* print("10 * (3+2) = ", 10 * (3+2)) */ os->getGlobal("print"); // #1 - stack values, it's print function from standart library os->pushNull(); // #2 - null, it's function this, each call of function must have this // push the first argument os->pushString("10 * (3+2) = "); // #3 - we have 3 stack values here // prepare second argument os->pushNumber(10); // #4 os->pushNumber(3); // #5 os->pushNumber(2); // #6 os->runOp(OP_ADD); // #5 - 3+2 os->runOp(OP_MUL); // #4 - 10 * (3+2) os->call(2); // call function with 2 arguments /* bar = {firsname="James", lastname="Bond"} bar.profession = "actor" print bar */ os->newObject(); // #1 - new object os->pushStackValue(-1); // #2 - the same object, -1 - is relative pointer to the top stack value os->pushString("firsname"); // #3 - property key os->pushString("James"); // #4 - property value os->setProperty(); // #1 - setProperty uses 3 stack values and pop them // second way of same functionality os->pushString("Bond"); // #2 - property value os->setProperty(-2, "lastname"); // #1 os->setGlobal("bar"); // #0 - assign object value to global bar variable, pop value // let's do bar.profession = "actor" os->getGlobal("bar"); // #1 - our global a variable os->pushString("actor"); // #2 - property value os->setProperty(-2, "profession"); // #1 os->pop(); // #0 // let's do print bar os->getGlobal("print"); // #1 os->pushNull(); // #2 os->getGlobal("bar"); // #3 os->call(1); // #0 /* print(concat(5, " big differences")) */ os->getGlobal("print"); // #1 - print function os->pushNull(); // #2 - this for print os->getGlobal("concat"); // #3 - concat function os->pushNull(); // #4 - this for concat os->pushNumber(5); // #5 os->pushString(" big differences"); // #6 os->call(2, 1); // #3 - result is already at the top of stack os->call(1); // #0 os->release(); return 0; } 

ObjectScriptのソースコードとサンプルは、 このリンクのこの記事からダウンロードでき、 proj.win32 \ examples.slnstack_usageプロジェクトを開きます。

Source: https://habr.com/ru/post/J152797/


All Articles