LUA_API lua_arith (1)
8180 ワード
冒頭
このセクションの目標は
解析
1行目、
注記は、Luaプログラムがコア
If you port Lua to another platform, you are "allowed"to overwrite lua_lock with your own definition; and this definition should essentially be a mutex, to disallow cross-thread operations on the same Lua objects. Essentially, when implemented, it should act similarly to Python's Global Interpreter Lock (GIL).
2行目を見てみると、
3行目の
前節では,
私たちは
亲爱なる客官よ、もしあなたが内部のデバッグの需要があれば、自分で
2つ目は
では、二つの場所は何が違うのでしょうか.推測:最初の場所は、ソースコードを修正する必要がある場合に内部デバッグを行う場合に使用されます.2つ目は外部のC APIユーザー向けですが、なぜですか?標準ライブラリのみのためです!
こんなにたくさん見て、やっと
苦労して、山を越えて水を渡って、私たちはついに第5行:
マクロ定義を置換すると、
続いて、
スタックトップインデックスを自己増加させ、
次に、10行目を見てみましょう.なぜこの注釈を特に見るのか.ここには重要なヒントがあります.
以上の準備が万全になった後、現在の状況では、最初の操作数はスタック内の
この節は長すぎるので,筆者も疲れたので,まず筆を置いて,次の節は続けよう.
終了勉強は煩わしくないが、紙面が長すぎて、しばらく休んでから戦うのは煩わしくない. ソースコードを见て本当に多くのものを理解することができて、だから恐れないでください、いつも収获があなたを待っています.
リファレンス
** lua_lock ** Purpose of lua_lock and lua_unlock Threads Tutorial
** lua_assert ** lua_assert macro definition
このセクションの目標は
lua_arith
です.文字通りarith
はarithmetic
の略、つまり算数の意味です.Luaの演算と密接に関係していることがわかり,Luaの算術規則を理解するのに役立つことを理解した.くだらないことは言わないで,馬を放しなさい.解析
lua_arith
はlua.h
で宣言されています.// lua.h 211
LUA_API void (lua_arith) (lua_State *L, int op);
lua_State
はluaのステータスマシンの内容であり、しばらくは関係なく、適切なタイミングで徐々に説明を展開します.これに加えて、lua_arith
はパラメータとして整数データop
を受信し、op
はoperator
の略であり、演算子を意味する.演算子は整数型なので、必ず様々な演算子の定義があり、苦労して探す必要はありません.宣言の上にあります.#define LUA_OPADD 0 // + /* ORDER TM, ORDER OP */
#define LUA_OPSUB 1 // -
#define LUA_OPMUL 2 // *
#define LUA_OPMOD 3 // %
#define LUA_OPPOW 4 // ^
#define LUA_OPDIV 5 // /
#define LUA_OPIDIV 6 // //
#define LUA_OPBAND 7 //
#define LUA_OPBOR 8 //
#define LUA_OPBXOR 9 //
#define LUA_OPSHL 10 //
#define LUA_OPSHR 11 //
#define LUA_OPUNM 12 //
#define LUA_OPBNOT 13 //
lua_arith
の実装を推測すると、想像では演算子に基づいてswicth
を行い、それぞれのcase
で具体的に異なる演算を実現するのが一般的でしょう.まずこのように決めて、それからその実現を見てみましょう.// lua_api.c 302
LUA_API void lua_arith (lua_State *L, int op) {
lua_lock(L);
if (op != LUA_OPUNM && op != LUA_OPBNOT)
api_checknelems(L, 2); /* all other operations expect two operands */
else { /* for unary operations, add fake 2nd operand */
api_checknelems(L, 1);
setobjs2s(L, L->top, L->top - 1);
api_incr_top(L);
}
/* first operand at top - 2, second at top - 1; result go to top - 2 */
luaO_arith(L, op, L->top - 2, L->top - 1, L->top - 2);
L->top--; /* remove second operand */
lua_unlock(L);
}
1行目、
lua_lock(L);
、何の役に立つか分からないので、その定義を見てください.// llimits.h 213
/*
** macros that are executed whenever program enters the Lua core
** ('lua_lock') and leaves the core ('lua_unlock')
*/
#if !defined(lua_lock)
#define lua_lock(L) ((void) 0)
#define lua_unlock(L) ((void) 0)
#endif
注記は、Luaプログラムがコア
core
に入るとlua_lock
が実行され、コアcore
から離れるとlua_unlock
が実行されることを意味する.しかし、私たちが見たのは((void) 0)
です.お母さん、これは何もしていないのではないでしょうか.何の意味があるの?仕方なくGoogleの、そこで1篇のPurpose of luaを探し当てますlock and luc_unlock、以下は節選と翻訳です.If you port Lua to another platform, you are "allowed"to overwrite lua_lock with your own definition; and this definition should essentially be a mutex, to disallow cross-thread operations on the same Lua objects. Essentially, when implemented, it should act similarly to Python's Global Interpreter Lock (GIL).
Lua
を他のプラットフォームに移植する必要がある場合、lua_lock
を書き換えることができる.同じLua
オブジェクトに対するスレッド間の動作を回避するために、lua_lock
の定義は反発しなければならず、その実装においてその動作はPython
のグローバル解釈ロック(GIL)と類似しなければならないことに留意されたい.lua_lock
とlua_unlock
は主にスレッド間通信に用いられる場合であり、一般的には考慮する必要はなく、Lua
は公式にも保持されており、マルチスレッド操作に関わる必要がある場合は、開発者自身が反発行為を実現する必要があるという意味である.もっと知りたいなら、このLua Threads Tutorialを見てみましょう.2行目を見てみると、
if (op != LUA_OPUNM && op != LUA_OPBNOT)
という分岐条件が現れました.LUA_OPUNM
およびLUA_OPBNOT
は単眼演算子であり、その後の注釈も補足し、その下の操作には2つの操作数、すなわち両目演算が必要である.では、else
分岐は明らかに単一演算に対して、単一演算に対して、2番目の擬似オペランドが追加されたという説明がある.どういう意味ですか.私たちは後で説明します.3行目の
api_checknelems(L, 2);
に移動し、定義を見つけました.// lapi.h 20
#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \
"not enough elements in the stack")
前節では,
(L->top - L->ci->func)
を紹介したが,その意味は現在のスタック内の要素の個数を知ることであり,api_checknelems(L, n)
の意図は,現在のスタック内の要素が十分であるかどうかを調べることであり,インデックスnがスタック内の要素より大きい場合,スタック内に存在しない要素にアクセスすることは当然限界であると考えられる.私たちは引き続き見て、そうかどうか見てみましょう.api_check
を探し続けます.// llimits.h 97
/*
** assertion for checking API calls
*/
#if !defined(luai_apicheck)
#define luai_apicheck(l,e) lua_assert(e)
#endif
#define api_check(l,e,msg) luai_apicheck(l,(e) && msg)
api_check
はluai_apicheck
によってバインドされ、luai_apicheck
はlua_assert
によってバインドされることに留意されたい.注記:この方法は、API呼び出しの断言を確認するために使用される.わあ、本当にTM心が疲れて、こんなに長い間探して、結果は断言であることを発見して、lua_assert
の行為は今まだ明らかになっていないで、依然としてぼんやりしていて、更に探すしかありません.luai_apicheck
を探して、他の定義があるかどうか見てみましょう.結果は本当にあって、疲れて、見てみましょう:// luaconf.h 683
/*
@@ LUA_USE_APICHECK turns on several consistency checks on the C API.
** Define it as a help when debugging C code.
*/
#if defined(LUA_USE_APICHECK)
#include
#define luai_apicheck(l,e) assert(e)
#endif
LUA_USE_APICHECK
がオンになっている場合、luai_apicheck
は標準のC assert
を使用します.上記に関連して、LUA_USE_APICHECK
がオンでない場合、luai_apicheck
はLua lua_asser
を使用する.OK、やった!今、私たちは安心してlua_assert
を探すことができます.その結果、ニマ、また2つの定義があることが分かった!まず最初の場所を見てみましょう// llimits.h 84
/* internal assertions for in-house debugging */
#if defined(lua_assert)
#define check_exp(c,e) (lua_assert(c), (e))
/* to avoid problems with conditions too long */
#define lua_longassert(c) ((c) ? (void)0 : lua_assert(0))
#else
#define lua_assert(c) ((void)0)
#define check_exp(c,e) (e)
#define lua_longassert(c) ((void)0)
#endif
私たちは
lua_assert
が定義した状況をスキップして(その下の内容は私たちの理解にとって何の役にも立たないので)、定義されていない時の状況を見ます:#define lua_assert(c) ((void)0)
よ、万歳、また何もしません.注釈がどのように解釈されているかを見てください.これは内部デバッグに使用される内部断言です.ふんふん、どういう意味?冗談で言って、また番頭を振ったんだよ.亲爱なる客官よ、もしあなたが内部のデバッグの需要があれば、自分で
lua_assert
の行为を定义してください.そうしないと、当店は一切特殊な処理をしません.あなたは自分で拡張して、逆さまにしましょう、ハハハ!いらっしゃいませ!ありがとうございます.2つ目は
lualib.h 53
行にあります.// lublib.h 53
#if !defined(lua_assert)
#define lua_assert(x) ((void)0)
#endif
lualib.h
は、Lua
の標準ライブラリを定義する.同じように、まだ処理されていません.断言行為を定義していなかったら、これからも特別な処理はしませんよ.では、二つの場所は何が違うのでしょうか.推測:最初の場所は、ソースコードを修正する必要がある場合に内部デバッグを行う場合に使用されます.2つ目は外部のC APIユーザー向けですが、なぜですか?標準ライブラリのみのためです!
こんなにたくさん見て、やっと
api_checknelems(L, 2);
がスタック内の要素が2つ以上あるかどうかを検査するためであることを知って、もしないならば断言を投げ出します;すなわち,スタック内の要素がオペランドの要求を満たさないとエラーとなる.同様に、単眼演算api_checknelems(L, 1);
についても同様である.苦労して、山を越えて水を渡って、私たちはついに第5行:
setobjs2s(L, L->top, L->top - 1);
に来ました.今回は定義を見つけて、次のようにします.// lobject.h 190
#define checkliveness(L,obj) \
lua_longassert(!iscollectable(obj) || \
(righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj)))))
// lobject.h 259
#define setobj(L,obj1,obj2) \
{ TValue *io1=(obj1); *io1 = *(obj2); \
(void)L; checkliveness(L,io1); }
// lobject.h 269
/* from stack to (same) stack */
#define setobjs2s setobj
マクロ定義を置換すると、
setobjs2s(L, L->top, L->top - 1);
を次のように展開できます.{
TValue *io1=(L->top);
*io1 = *(L->top - 1);
(void)L;
checkliveness(L,io1);// , , Lua
}
続いて、
api_incr_top(L)
が実行される.#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \
"stack overflow");}
スタックトップインデックスを自己増加させ、
L->top <= L->ci->top
を確認します.ここのスタックトップインデックスについて、なぜ自己増加しますか?コンテキストに連絡するには、2番目の擬似オペランドに空間を空ける必要があります.次に、10行目を見てみましょう.なぜこの注釈を特に見るのか.ここには重要なヒントがあります.
/* first operand at top - 2, second at top - 1; result go to top - 2 */
以上の準備が万全になった後、現在の状況では、最初の操作数はスタック内の
top - 2
カ所、2番目の操作数はtop - 1
カ所にあり、その後、演算結果はtop - 2
カ所に置かれます.この節は長すぎるので,筆者も疲れたので,まず筆を置いて,次の節は続けよう.
終了
リファレンス
** lua_lock **
** lua_assert **