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.testclean:
rm lua_conf.test
1.lua
a=4
b=[[good girl]]
say(“hello”)
结果
i say hello
a=4
b=good girl