BlitzMax/Modules/Axe/Lua
Lua指令碼通常在VM(虛擬機器)中執行。因此,我們首先啟動一個VM,然後載入基本的Lua庫
Local LuaState:byte ptr = luaL_newstate() luaL_openlibs(LuaState)
luaL_newstate() 返回的位元組指標在每次Lua函式呼叫時都需要。現在你已經完成了初始化,可以開始執行指令碼了。
之後關閉Lua VM可以透過一個函式完成
lua_close(LuaState)
Lua指令碼可以直接從Blitzmax字串中執行。
Local Script:String = "print(~qHello World!~q)" luaL_loadString(LuaState,Script)
這段程式碼載入並編譯了指令碼。如果出現問題,luaL_loadString() 會返回一個 <> 0 的值。
lua_getfield(LuaState, LUA_GLOBALSINDEX, "debug")' get global "debug" lua_getfield(LuaState, -1, "traceback") ' get "debug.traceback" lua_remove (LuaState, -2) ' remove "debug" table from stack
這些命令現在不重要,它們只是為了獲得正確的錯誤資訊。
lua_pcall(LuaState,1,-1,-1)' use "debug.traceback" as err.hdlr
這行程式碼實際上執行了指令碼。同樣,如果它的返回值是 <> 0,則發生了錯誤。如果一切都正常,程式將按照預期顯示一個“Hello World!”。
你可能已經注意到,僅僅能夠執行指令碼而不能與BlitzMax互動並沒有什麼用。因此,下一步就是學習如何從Lua指令碼呼叫BlitzMax函式。不幸的是,我們不能直接使用任意函式,因為函式必須遵循特定的佈局
Function BMXName:int (LuaState:Byte Ptr)
... ' handling of parameters passed from Lua (if required)
... ' actual function body
... ' passing results back to Lua (if required)
return 0 ' number of values returned to Lua function
End Function
顯然,在Lua指令碼中使用函式提交的引數不會直接傳輸到BlitzMax函式。我們必須手動處理它們,但不要急於求成。首先,我們需要將函式註冊到Lua
lua_register(LuaState, "luaname", BMXName)
現在可以在Lua(全域性)中以luaname() 的形式呼叫BMXName()。你可能選擇將函式命名與BlitzMax中相同,但你沒有必要這樣做。
假設我們嘗試從Lua呼叫
luaname(810, "Hallo!")
使用上面的示例函式。Lua沒有抱怨額外的引數,但我們也無法從函式內部訪問它們。它們到哪裡去了?Lua將它們放置在引數堆疊上。每個引數都被分配了一個索引,可以透過該索引識別。索引按順序編號,從1開始。因此,810 可以在索引1處找到,“Hallo!”可以在索引2處找到。現在我們只需要知道從引數堆疊讀取值的相應命令,我們就完成了
Function BMXName:Int (LuaState:Byte Ptr) Local int_value:Int = luaL_checkinteger(LuaState, 1) Local str_value:String = luaL_checkstring(LuaState, 2) Print int_value Print str_value Return 0 ' number of values returned to Lua function End Function
返回一個或多個值到Lua指令碼的操作類似,但你不必指定索引,因為值會自動追加到堆疊。以下是一個示例
Function BMXName:Int (LuaState:Byte Ptr) lua_pushnumber(LuaState, 810) lua_pushstring(LuaState, "Hallo!") Return 2 ' number of values returned to Lua function End Function
在大多數情況下,你只會返回一個值或根本不返回值,但如你所見,也可以返回更多值。
我們知道如何執行完整的Lua指令碼,但如果我們只需要一個函式呢?在這種情況下,你首先必須將要呼叫的函式放在堆疊上,然後是引數。以下是一個示例。Lua指令碼
function luafunc(para, str) print(para, str) end
BlitzMax程式碼
lua_getfield(LuaState, LUA_GLOBALSINDEX, "luafunc") 'Puts the function onto the stack lua_pushinteger(LuaState, 810) 'First Argument lua_pushstring(LuaState, "Hallo!") 'Second Argument lua_call(LuaState, 2, 0) 'Call the function with 2 arguments and no result
如果有返回值,它們會在函式執行後被放置到堆疊上。
lua_pushstring(LuaState, "Hallo!") lua_setglobal (LuaState, "luaglobal")
第一個命令將“Hallo!”寫入堆疊,第二個命令將它放入全域性luaglobal。
lua_getglobal(LuaState, "luaglobal") Local str:String = lua_tostring(LuaState, -1)
第一個命令將值放入堆疊,第二個命令將它放入BlitzMax變數。
如果你想儲存當前Lua VM的狀態,你需要找到一種方法來獲取所有全域性變數。一種方法是使用lua_next函式
lua_pushnil(LuaState) ' first key While (lua_next(LuaState, LUA_GLOBALSINDEX) <> 0) ' iterate through all values of the global environment table ' uses 'key' (at index -2) and 'value' (at index -1) Print(lua_typename(LuaState,lua_type(LuaState , - 1))+" - "+lua_tostring(LuaState,-2)+"-"+lua_tostring(LuaState,-1)) ' removes 'value'; keeps 'key' for next iteration lua_pop(LuaState, 1); Wend
請注意,這種方法不僅返回全域性變數,還返回函式、表等,你需要使用lua_type命令來進行分類。