前回lua_interpreterを実行してみて、バックスペースなどの操作が出来なかったのだが、これはlibreadlineを使っていなかったからだった。 コンパイルするときに、-DLUA_USE_READLINEを追加することでBSやAltなどが使用可能になる。
gcc -o lua_interpreter lua_interpreter.c -llua5.2 -lreadline -DLUA_USE_READLINE
とりあえずは、luaモードになったときは、os.exit()が呼ばれない限りはシミュレーション終了後にインタプリタモードに入ることにした。 そのためみ、Luaの実行関数から抜けても、インタプリタを出すようにする。luaのソースから引っ張ってくるならば、dotty()を実行することでこれが可能になる。
if (!FLAGS_script.empty()) { - ExecuteFromFile (FLAGS_script); - + lua_State *lua_state = SetupLuaEnv (); + ExecuteFromFile (lua_state, FLAGS_script); + dotty (lua_state); + } else if (!is_cmd_binfile && !is_cmd_srecfile && !is_cmd_imgfile) { + lua_State *lua_state = SetupLuaEnv (); + dotty (lua_state);
という訳で、ExecuteFromFile() がLuaのスクリプトを実行する関数で、この関数を抜けてもdotty()が実行されるようになる。
それ以外にも、特に実行ファイルが指定されなければ、Luaスクリプトが呼ばれるようにした。 LuaをC++の中で使う場合は、まずはlua_state構造体をインスタンスして、それに対して処理を実行しなければならない。例えば、lua_stateにC++の関数を登録するためには、以下のようにする。
lua_State* SetupLuaEnv (void) { lua_State *lua_state = luaL_newstate (); luaL_openlibs (lua_state); // Register Functions lua_register (lua_state, "make_core", Lua_MakeCore); lua_register (lua_state, "run", Lua_Run); lua_register (lua_state, "set_pc", Lua_SetPC); lua_register (lua_state, "set_max_cycle", Lua_SetMaxCycle); lua_register (lua_state, "load", Lua_LoadBin); lua_register (lua_state, "debug", Lua_SetDebug); lua_register (lua_state, "get_step", Lua_GetStep); lua_register (lua_state, "get_addr", Lua_GetAddr); lua_register (lua_state, "set_pcbreak", Lua_SetPCBreak); lua_register (lua_state, "get_reg", Lua_GetReg); lua_register (lua_state, "get_mem", Lua_GetMem); lua_register (lua_state, "dump_regs", Lua_DumpRegs); lua_register (lua_state, "skip_hier", Lua_SkipHier); return lua_state; }
Luaを処理する各関数には、殆どの場合このlua_stateを殆どの場合追加する。そのあたりは、複数のLuaインタプリタを立ち上げたりするときの構造が非常にしっかりしている印象だ。 一方で、Pythonの場合はそのあたりが暗黙的になっているというか、構造体などを指定しなくても一つの環境にいろいろ追加されていくから、ちょっと厳密ではないが、取っ付きやすくはある。
Py_Main(argc, argv); // 環境構造体を指定する必要がない