Lua ,语法简单(极像javascript), 移植性好(纯C实现), 启动速度快,空间占用小, 真不愧是潜入式脚本语言之王。 本人想拿它来做 配置文件(conf),也想加一点IoC, 就是配置脚本可以调用主程序的函数。 实现如下: repeat_macro.h #ifndef __REPEAT_MACRO_H__ #define __REPEAT_MACRO_H__ // concatenation #define CAT(a, b) PRIMITIVE_CAT(a, b) #define PRIMITIVE_CAT(a, b) a ## b // binary intermediate split #define SPLIT(i, im) PRIMITIVE_CAT(SPLIT_, i)(im) #define SPLIT_0(a, b) a #define SPLIT_1(a, b) b // saturating increment and decrement #define DEC(x) SPLIT(0, PRIMITIVE_CAT(DEC_, x)) #define INC(x) SPLIT(1, PRIMITIVE_CAT(DEC_, x)) #define DEC_0 0, 1 #define DEC_1 0, 2 #define DEC_2 1, 3 #define DEC_3 2, 4 #define DEC_4 3, 5 #define DEC_5 4, 6 #define DEC_6 5, 7 #define DEC_7 6, 8 #define DEC_8 7, 9 #define DEC_9 8, 10 #define DEC_10 9, 11 #define DEC_11 10, 12 #define DEC_12 11, 13 #define DEC_13 12, 14 #define DEC_14 13, 15 #define DEC_15 14, 15 // bit complement #define COMPL(bit) PRIMITIVE_CAT(COMPL_, bit) #define COMPL_0 1 #define COMPL_1 0 // nullary parentheses detection #define IS_NULLARY(x) SPLIT(0, CAT(IS_NULLARY_R_, IS_NULLARY_C x)) #define IS_NULLARY_C() 1 #define IS_NULLARY_R_1 1, ~ #define IS_NULLARY_R_IS_NULLARY_C 0, ~ // boolean conversion #define BOOL(x) COMPL(IS_NULLARY(PRIMITIVE_CAT(BOOL_, x))) #define BOOL_0 () // recursion backend #define EXPR(s) PRIMITIVE_CAT(EXPR_, s) #define EXPR_0(x) x #define EXPR_1(x) x #define EXPR_2(x) x #define EXPR_3(x) x #define EXPR_4(x) x #define EXPR_5(x) x #define EXPR_6(x) x #define EXPR_7(x) x #define EXPR_8(x) x #define EXPR_9(x) x #define EXPR_10(x) x #define EXPR_11(x) x #define EXPR_12(x) x #define EXPR_13(x) x #define EXPR_14(x) x #define EXPR_15(x) x // bit-oriented if control structure #define IIF(bit) PRIMITIVE_CAT(IIF_, bit) #define IIF_0(t, f) f #define IIF_1(t, f) t // number-oriented if control structure #define IF(cond) IIF(BOOL(cond)) // emptiness abstraction #define EMPTY() // 1x and 2x deferral macros #define DEFER(macro) macro EMPTY() #define OBSTRUCT() DEFER(EMPTY)() // argument list eater #define EAT(size) PRIMITIVE_CAT(EAT_, size) #define EAT_0() #define EAT_1(a) #define EAT_2(a, b) #define EAT_3(a, b, c) #define EAT_4(a, b, c, d) #define EAT_5(a, b, c, d, e) #define EAT_6(a, b, c, d, e, f) #define EAT_7(a, b, c, d, e, f, g) #define EAT_8(a, b, c, d, e, f, g, h) #define EAT_9(a, b, c, d, e, f, g, h, i) #define EAT_10(a, b, c, d, e, f, g, h, i, j) #define EAT_11(a, b, c, d, e, f, g, h, i, j, k) // comma abstractions #define COMMA() , #define COMMA_IF(n) IF(n)(COMMA, EMPTY)() // repetition construct #define REPEAT(s, count, macro, data) \ EXPR(s)(REPEAT_I(INC(s), INC(s), count, macro, data)) \ /**/ #define REPEAT_INDIRECT() REPEAT_I #define REPEAT_I(s, o, count, macro, data) \ IF(count)(REPEAT_II, EAT(6))(OBSTRUCT(), s, o, DEC(count), macro, data) \ /**/ #define REPEAT_II(_, s, o, count, macro, data) \ EXPR(s) _(REPEAT_INDIRECT _()( \ INC(s), o, count, macro, data \ )) \ EXPR OBSTRUCT()(o)(macro OBSTRUCT()(o, count, data)) \ /**/ #endif //__REPEAT_MACRO_H__
lua_bind.h #ifndef __LUA_BIND_H__ #define __LUA_BIND_H__ extern "C" { #include <lua.h> } #include <string> #ifndef LOG #define ENABLE_LUA_BIND_H_LOG #include <stdio.h> #define LOG(level, format, ...) \ fprintf(stderr, "[%s][%s][%d]: " format "\n", #level, __FILE__, int(__LINE__), ##__VA_ARGS__) #endif //LOG template<typename T> T lua_get_param(lua_State *state, int index) { LOG(ERROR, "parement type unsupport type"); return T(); } template <> int lua_get_param<int>(lua_State *state, int index) { if (!lua_isnumber(state, index)) { LOG(ERROR, "lua argument should be a number\n"); return 0; } return (int)lua_tonumber(state, index); } template <> bool lua_get_param<bool>(lua_State *state, int index) { if (!lua_isboolean(state, index)){ LOG(ERROR, "lua argument should be a boolean\n"); return 0; } return (bool)lua_toboolean(state, index); } template <> double lua_get_param<double>(lua_State *state, int index) { if (!lua_isnumber(state, index)) { LOG(ERROR, "lua argument should be a number\n"); return 0; } return lua_tonumber(state, index); } template <> char const * lua_get_param<char const*>(lua_State *state, int index) { if (!lua_isstring(state, index)){ LOG(ERROR, "lua argument should be a string\n"); return ""; } return lua_tostring(state, index); } template <> std::string lua_get_param<std::string >(lua_State *state, int index) { if (!lua_isstring(state, index)){ LOG(ERROR, "lua argument should be a string\n"); return std::string(); } return std::string(lua_tostring(state, index)); } template<typename T> int lua_set_result(lua_State *state, T value) { LOG(ERROR, "parement type unsupport type"); return 0; } template <> int lua_set_result<int>(lua_State *state, int value) { lua_pushnumber(state, double(value)); return 1; } template <> int lua_set_result<bool>(lua_State *state, bool value) { lua_pushboolean(state, value); return 1; } template <> int lua_set_result<double>(lua_State *state, double value) { lua_pushnumber(state, value); return 1; } template <> int lua_set_result<char const *>(lua_State *state, char const * value) { if(value) { lua_pushstring(state, value); } else { lua_pushstring(state, ""); } return 1; } template <> int lua_set_result<std::string>(lua_State *state, std::string value) { lua_pushstring(state, value.c_str()); return 1; } #include "repeat_macro.h" template<typename T> class function_type_info { public: typedef T result_type; }; #define TEMPLATE_PARAM_TYPE(s, v, arg) COMMA_IF(v) typename CAT(arg, v) #define TEMPLATE_PARAM_TYPE_LIST(num) EXPR(0)(REPEAT(0, num, TEMPLATE_PARAM_TYPE, arg)) #define DEF_FUN_PARAM_TYPE(s, v, arg) typedef CAT(arg, v) CAT(CAT(arg, v), _type) ; #define ALL_DEF_FUN_PARAM_TYPE(num) EXPR(0)(REPEAT(0, num, DEF_FUN_PARAM_TYPE, arg)) #define GET_FUN_PARAM_TYPE(s, v, arg) COMMA_IF(v) CAT(arg, INC(v)) #define GET_FUN_PARAM_TYPE_LIST(num) EXPR(0) (REPEAT(0, num, GET_FUN_PARAM_TYPE, arg)) #define DEF_FUNCTION_TYPE_INFO(_, num, arg) \ template< TEMPLATE_PARAM_TYPE_LIST(INC(num)) > \ class function_type_info< arg0 (*)( GET_FUN_PARAM_TYPE_LIST(num) ) > \ {\ public:\ ALL_DEF_FUN_PARAM_TYPE(INC(num))\ typedef arg0 result_type;\ }; DEF_FUNCTION_TYPE_INFO(_, 0, arg) DEF_FUNCTION_TYPE_INFO(_, 1, arg) DEF_FUNCTION_TYPE_INFO(_, 2, arg) DEF_FUNCTION_TYPE_INFO(_, 3, arg) DEF_FUNCTION_TYPE_INFO(_, 4, arg) DEF_FUNCTION_TYPE_INFO(_, 5, arg) DEF_FUNCTION_TYPE_INFO(_, 6, arg) DEF_FUNCTION_TYPE_INFO(_, 7, arg) DEF_FUNCTION_TYPE_INFO(_, 8, arg) DEF_FUNCTION_TYPE_INFO(_, 9, arg) DEF_FUNCTION_TYPE_INFO(_, 10, arg) DEF_FUNCTION_TYPE_INFO(_, 11, arg) DEF_FUNCTION_TYPE_INFO(_, 12, arg) DEF_FUNCTION_TYPE_INFO(_, 13, arg) DEF_FUNCTION_TYPE_INFO(_, 14, arg) #define LUA_PARAM_TYPE(functor,n) CAT(CAT(functor::arg, n),_type) #define GET_PARAM_IN(s, v, functor) LUA_PARAM_TYPE(functor, v) CAT(arg, v) = lua_get_param< LUA_PARAM_TYPE(functor, v) >(state, v); #define GET_PARAM_FUN(n, functor) EXPR(0)(REPEAT(1, INC(n), GET_PARAM_IN, functor)) #define LUA_CALL_ARG_IN(s, v, arg) COMMA_IF(v) CAT(arg, INC(v)) #define LUA_CALL_FUN_ARG(n, arg) EXPR(0)(REPEAT(0, n, LUA_CALL_ARG_IN, arg)) #define LUA_BIND_NAME(fun, num) CAT(CAT(__lua_bind_, fun), num) #define DEF_LUA_BIND(fun, num)\ int LUA_BIND_NAME(fun, num) (lua_State *state){ \ typedef function_type_info<typeof(&fun)> functor_info_type; \ GET_PARAM_FUN(num, functor_info_type) \ typeof(fun(LUA_CALL_FUN_ARG(num, arg))) result = fun(LUA_CALL_FUN_ARG(num, arg));\ int ret = lua_set_result(state, result); \ return ret;\ } #define DEF_LUA_BIND_VOID(fun, num)\ int LUA_BIND_NAME(fun, num) (lua_State *state){ \ typedef function_type_info<typeof(&fun)> functor_info_type; \ GET_PARAM_FUN(num, functor_info_type) \ fun(LUA_CALL_FUN_ARG(num, arg));\ return 0;\ } #ifdef ENABLE_LUA_BIND_H_LOG #undef LOG #undef ENABLE_LUA_BIND_H_LOG #endif //ENABLE_LUA_BIND_H_LOG #endif //__LUA_BIND_H__
lua_conf.hpp #ifndef __LUA_CONF_H__ #define __LUA_CONF_H__ extern "C" { #include <lua.h> #include <lauxlib.h> #include <lualib.h> } #include "lua_bind.h" #include <sstream> #include <string> #include <assert.h> #ifndef LOG #define ENABLE_LUA_CONF_H_LOG #include <stdio.h> #define LOG(level, format, ...) \ fprintf(stderr, "[%s][%s][%d]: " format "\n", #level, __FILE__, int(__LINE__), ##__VA_ARGS__) #endif //LOG namespace lua { class LuaBase { public: bool open(char const *filename) { if(NULL == filename) return false; file_name_ = filename; state_ = lua_open(); luaopen_base(state_); //luaopen_io(state_); //luaopen_string(state_); //luaopen_math(state_); if (luaL_loadfile(state_, file_name_.c_str())) { LOG(ERROR, "cannot load configuration file: %s", file_name_.c_str()); close(); return false; } return true; } typedef int bind_type(lua_State *); bool registry(char const *name, bind_type fun) { if(NULL==name || NULL == state_) return false; lua_pushcfunction(state_, fun); lua_setglobal(state_, name); return true; } bool load() { if(NULL == state_) return false; if(lua_pcall(state_, 0, 0, 0)){ LOG(ERROR, "cannot run configuration file: %s", file_name_.c_str()); close(); return false; } return true; } void close() { if(state_) lua_close(state_); state_ = NULL; } lua_State *state_; std::string file_name_; }; class LuaConf: public LuaBase { public: template <typename T> T get(char const* name){ if(NULL==name || NULL == state_) return T(); lua_getglobal(state_, name); if (!lua_isstring(state_, -1)){ LOG(ERROR, "should be a string\n"); return T(); } std::string value = lua_tostring(state_, -1); lua_pop(state_, -1); std::istringstream in(value, std::istringstream::in); T ret; in>>ret; return ret; } }; template <> int LuaConf::get<int>(char const* name){ if(NULL==name || NULL == state_) return 0; lua_getglobal(state_, name); if (!lua_isnumber(state_, -1)) { LOG(ERROR, "should be a number\n"); return 0; } int result = (int)lua_tonumber(state_, -1); lua_pop(state_, -1); return result; } template <> double LuaConf::get<double>(char const* name) { if(NULL==name || NULL == state_) return 0; lua_getglobal(state_, name); if (!lua_isnumber(state_, -1)) { LOG(ERROR, "should be a number\n"); return 0; } double result = lua_tonumber(state_, -1); lua_pop(state_, -1); return result; } template <> std::string LuaConf::get<std::string>(char const* name) { if(NULL==name || NULL == state_) return std::string(); lua_getglobal(state_, name); if (!lua_isstring(state_, -1)) { LOG(ERROR, "should be a string\n"); return std::string(); } std::string result = lua_tostring(state_, -1); lua_pop(state_, -1); return result; } }; #ifdef ENABLE_LUA_CONF_H_LOG #undef LOG #undef ENABLE_LUA_CONF_H_LOG #endif //ENABLE_LUA_CONF_H_LOG #endif //__LUA_CONF_H__
lua_conf.test.cpp #include "lua_conf.hpp" #include <stdio.h> #include <string> int say(char const *name) { printf("i say %s", name); return 1; } DEF_LUA_BIND(say, 1) int main() { lua::LuaConf conf; conf.open("1.lua"); conf.registry("say", LUA_BIND_NAME(say, 1)); conf.load(); int a = conf.get<int>("a"); printf("a=%d\n", a); std::string b = conf.get<std::string>("b"); printf("b=%s\n", b.c_str()); return 0; }
makefile lua_conf.test: lua_conf.test.cpp g++ -g -I./ lua_conf.test.cpp -L./ -llua -o lua_conf.test clean: rm lua_conf.test
1.lua a=4 b=[[good girl]] say(“hello”)
结果 i say hello a=4 b=good girl
|
请发表评论