// script binding functionality enum { VAL_NULL = 0, VAL_INT, VAL_FLOAT, VAL_STR, VAL_ANY, VAL_CODE, VAL_MACRO, VAL_IDENT }; enum { CODE_START = 0, CODE_OFFSET, CODE_POP, CODE_ENTER, CODE_EXIT, CODE_VAL, CODE_VALI, CODE_MACRO, CODE_BOOL, CODE_BLOCK, CODE_COMPILE, CODE_FORCE, CODE_RESULT, CODE_IDENT, CODE_IDENTU, CODE_IDENTARG, CODE_COM, CODE_COMD, CODE_COMC, CODE_COMV, CODE_CONC, CODE_CONCW, CODE_CONCM, CODE_DOWN, CODE_SVAR, CODE_SVAR1, CODE_IVAR, CODE_IVAR1, CODE_IVAR2, CODE_IVAR3, CODE_FVAR, CODE_FVAR1, CODE_LOOKUP, CODE_LOOKUPU, CODE_LOOKUPARG, CODE_ALIAS, CODE_ALIASU, CODE_ALIASARG, CODE_CALL, CODE_CALLU, CODE_CALLARG, CODE_PRINT, CODE_LOCAL, CODE_OP_MASK = 0x3F, CODE_RET = 6, CODE_RET_MASK = 0xC0, /* return type flags */ RET_NULL = VAL_NULL< x ? IDF_READONLY : 0)), name(n), minval(m), maxval(x), fun((identfun)f) { storage.i = s; } // ID_FVAR ident(int t, const char *n, float m, float x, float *s, void *f = NULL, int flags = 0) : type(t), flags(flags | (m > x ? IDF_READONLY : 0)), name(n), minvalf(m), maxvalf(x), fun((identfun)f) { storage.f = s; } // ID_SVAR ident(int t, const char *n, char **s, void *f = NULL, int flags = 0) : type(t), flags(flags), name(n), fun((identfun)f) { storage.s = s; } // ID_ALIAS ident(int t, const char *n, char *a, int flags) : type(t), valtype(VAL_STR), flags(flags), name(n), code(NULL), stack(NULL) { val.s = a; } ident(int t, const char *n, int a, int flags) : type(t), valtype(VAL_INT), flags(flags), name(n), code(NULL), stack(NULL) { val.i = a; } ident(int t, const char *n, float a, int flags) : type(t), valtype(VAL_FLOAT), flags(flags), name(n), code(NULL), stack(NULL) { val.f = a; } ident(int t, const char *n, int flags) : type(t), valtype(VAL_NULL), flags(flags), name(n), code(NULL), stack(NULL) {} ident(int t, const char *n, const tagval &v, int flags) : type(t), valtype(v.type), flags(flags), name(n), code(NULL), stack(NULL) { val = v; } // ID_COMMAND ident(int t, const char *n, const char *args, uint argmask, int numargs, void *f = NULL, int flags = 0) : type(t), numargs(numargs), flags(flags), name(n), args(args), argmask(argmask), fun((identfun)f) {} void changed() { if(fun) fun(); } void setval(const tagval &v) { valtype = v.type; val = v; } void setval(const identstack &v) { valtype = v.valtype; val = v.val; } void forcenull() { if(valtype==VAL_STR) delete[] val.s; valtype = VAL_NULL; } float getfloat() const; int getint() const; const char *getstr() const; void getval(tagval &v) const; }; extern void addident(ident *id); extern tagval *commandret; extern const char *intstr(int v); extern void intret(int v); extern const char *floatstr(float v); extern void floatret(float v); extern void stringret(char *s); extern void result(tagval &v); extern void result(const char *s); static inline int parseint(const char *s) { return int(strtoul(s, NULL, 0)); } static inline float parsefloat(const char *s) { // not all platforms (windows) can parse hexadecimal integers via strtod char *end; double val = strtod(s, &end); return val || end==s || (*end!='x' && *end!='X') ? float(val) : float(parseint(s)); } static inline void intformat(char *buf, int v, int len = 20) { nformatstring(buf, len, "%d", v); } static inline void floatformat(char *buf, float v, int len = 20) { nformatstring(buf, len, v==int(v) ? "%.1f" : "%.6g", v); } static inline const char *getstr(const identval &v, int type) { switch(type) { case VAL_STR: case VAL_MACRO: return v.s; case VAL_INT: return intstr(v.i); case VAL_FLOAT: return floatstr(v.f); default: return ""; } } inline const char *tagval::getstr() const { return ::getstr(*this, type); } inline const char *ident::getstr() const { return ::getstr(val, valtype); } static inline int getint(const identval &v, int type) { switch(type) { case VAL_INT: return v.i; case VAL_FLOAT: return int(v.f); case VAL_STR: case VAL_MACRO: return parseint(v.s); default: return 0; } } inline int tagval::getint() const { return ::getint(*this, type); } inline int ident::getint() const { return ::getint(val, valtype); } static inline float getfloat(const identval &v, int type) { switch(type) { case VAL_FLOAT: return v.f; case VAL_INT: return float(v.i); case VAL_STR: case VAL_MACRO: return parsefloat(v.s); default: return 0.0f; } } inline float tagval::getfloat() const { return ::getfloat(*this, type); } inline float ident::getfloat() const { return ::getfloat(val, valtype); } inline void ident::getval(tagval &v) const { switch(valtype) { case VAL_STR: case VAL_MACRO: v.setstr(newstring(val.s)); break; case VAL_INT: v.setint(val.i); break; case VAL_FLOAT: v.setfloat(val.f); break; default: v.setnull(); break; } } // nasty macros for registering script functions, abuses globals to avoid excessive infrastructure #define KEYWORD(name, type) UNUSED static bool __dummy_##name = addkeyword(type, #name) #define COMMANDN(name, fun, nargs) UNUSED static bool __dummy_##fun = addcommand(#name, (identfun)fun, nargs) #define COMMAND(name, nargs) COMMANDN(name, name, nargs) #define _VAR(name, global, min, cur, max, persist) int global = variable(#name, min, cur, max, &global, NULL, persist) #define VARN(name, global, min, cur, max) _VAR(name, global, min, cur, max, 0) #define VARNP(name, global, min, cur, max) _VAR(name, global, min, cur, max, IDF_PERSIST) #define VARNR(name, global, min, cur, max) _VAR(name, global, min, cur, max, IDF_OVERRIDE) #define VAR(name, min, cur, max) _VAR(name, name, min, cur, max, 0) #define VARP(name, min, cur, max) _VAR(name, name, min, cur, max, IDF_PERSIST) #define VARR(name, min, cur, max) _VAR(name, name, min, cur, max, IDF_OVERRIDE) #define _VARF(name, global, min, cur, max, body, persist) void var_##name(); int global = variable(#name, min, cur, max, &global, var_##name, persist); void var_##name() { body; } #define VARFN(name, global, min, cur, max, body) _VARF(name, global, min, cur, max, body, 0) #define VARF(name, min, cur, max, body) _VARF(name, name, min, cur, max, body, 0) #define VARFP(name, min, cur, max, body) _VARF(name, name, min, cur, max, body, IDF_PERSIST) #define VARFR(name, min, cur, max, body) _VARF(name, name, min, cur, max, body, IDF_OVERRIDE) #define VARFNP(name, global, min, cur, max, body) _VARF(name, global, min, cur, max, body, IDF_PERSIST) #define _HVAR(name, global, min, cur, max, persist) int global = variable(#name, min, cur, max, &global, NULL, persist | IDF_HEX) #define HVARN(name, global, min, cur, max) _HVAR(name, global, min, cur, max, 0) #define HVARNP(name, global, min, cur, max) _HVAR(name, global, min, cur, max, IDF_PERSIST) #define HVARNR(name, global, min, cur, max) _HVAR(name, global, min, cur, max, IDF_OVERRIDE) #define HVAR(name, min, cur, max) _HVAR(name, name, min, cur, max, 0) #define HVARP(name, min, cur, max) _HVAR(name, name, min, cur, max, IDF_PERSIST) #define HVARR(name, min, cur, max) _HVAR(name, name, min, cur, max, IDF_OVERRIDE) #define _HVARF(name, global, min, cur, max, body, persist) void var_##name(); int global = variable(#name, min, cur, max, &global, var_##name, persist | IDF_HEX); void var_##name() { body; } #define HVARFN(name, global, min, cur, max, body) _HVARF(name, global, min, cur, max, body, 0) #define HVARF(name, min, cur, max, body) _HVARF(name, name, min, cur, max, body, 0) #define HVARFP(name, min, cur, max, body) _HVARF(name, name, min, cur, max, body, IDF_PERSIST) #define HVARFR(name, min, cur, max, body) _HVARF(name, name, min, cur, max, body, IDF_OVERRIDE) #define _FVAR(name, global, min, cur, max, persist) float global = fvariable(#name, min, cur, max, &global, NULL, persist) #define FVARN(name, global, min, cur, max) _FVAR(name, global, min, cur, max, 0) #define FVARNP(name, global, min, cur, max) _FVAR(name, global, min, cur, max, IDF_PERSIST) #define FVARNR(name, global, min, cur, max) _FVAR(name, global, min, cur, max, IDF_OVERRIDE) #define FVAR(name, min, cur, max) _FVAR(name, name, min, cur, max, 0) #define FVARP(name, min, cur, max) _FVAR(name, name, min, cur, max, IDF_PERSIST) #define FVARR(name, min, cur, max) _FVAR(name, name, min, cur, max, IDF_OVERRIDE) #define _FVARF(name, global, min, cur, max, body, persist) void var_##name(); float global = fvariable(#name, min, cur, max, &global, var_##name, persist); void var_##name() { body; } #define FVARFN(name, global, min, cur, max, body) _FVARF(name, global, min, cur, max, body, 0) #define FVARF(name, min, cur, max, body) _FVARF(name, name, min, cur, max, body, 0) #define FVARFP(name, min, cur, max, body) _FVARF(name, name, min, cur, max, body, IDF_PERSIST) #define FVARFR(name, min, cur, max, body) _FVARF(name, name, min, cur, max, body, IDF_OVERRIDE) #define _SVAR(name, global, cur, persist) char *global = svariable(#name, cur, &global, NULL, persist) #define SVARN(name, global, cur) _SVAR(name, global, cur, 0) #define SVARNP(name, global, cur) _SVAR(name, global, cur, IDF_PERSIST) #define SVARNR(name, global, cur) _SVAR(name, global, cur, IDF_OVERRIDE) #define SVAR(name, cur) _SVAR(name, name, cur, 0) #define SVARP(name, cur) _SVAR(name, name, cur, IDF_PERSIST) #define SVARR(name, cur) _SVAR(name, name, cur, IDF_OVERRIDE) #define _SVARF(name, global, cur, body, persist) void var_##name(); char *global = svariable(#name, cur, &global, var_##name, persist); void var_##name() { body; } #define SVARFN(name, global, cur, body) _SVARF(name, global, cur, body, 0) #define SVARF(name, cur, body) _SVARF(name, name, cur, body, 0) #define SVARFP(name, cur, body) _SVARF(name, name, cur, body, IDF_PERSIST) #define SVARFR(name, cur, body) _SVARF(name, name, cur, body, IDF_OVERRIDE) // anonymous inline commands, uses nasty template trick with line numbers to keep names unique #define ICOMMANDNS(name, cmdname, nargs, proto, b) template struct cmdname; template<> struct cmdname<__LINE__> { static bool init; static void run proto; }; bool cmdname<__LINE__>::init = addcommand(name, (identfun)cmdname<__LINE__>::run, nargs); void cmdname<__LINE__>::run proto \ { b; } #define ICOMMANDN(name, cmdname, nargs, proto, b) ICOMMANDNS(#name, cmdname, nargs, proto, b) #define ICOMMANDNAME(name) _icmd_##name #define ICOMMAND(name, nargs, proto, b) ICOMMANDN(name, ICOMMANDNAME(name), nargs, proto, b) #define ICOMMANDSNAME _icmds_ #define ICOMMANDS(name, nargs, proto, b) ICOMMANDNS(name, ICOMMANDSNAME, nargs, proto, b)