#ifndef LIBCUBESCRIPT_CS_VM_HH #define LIBCUBESCRIPT_CS_VM_HH #include "cubescript.hh" #include #include #include namespace cscript { static constexpr int MaxArguments = 25; static constexpr int MaxResults = 7; static constexpr int DummyIdx = MaxArguments; static constexpr int NumargsIdx = MaxArguments + 1; static constexpr int DbgaliasIdx = MaxArguments + 2; enum { ID_UNKNOWN = -1, ID_IVAR, ID_FVAR, ID_SVAR, ID_COMMAND, ID_ALIAS, ID_LOCAL, ID_DO, ID_DOARGS, ID_IF, ID_RESULT, ID_NOT, ID_AND, ID_OR }; enum { VAL_NULL = 0, VAL_INT, VAL_FLOAT, VAL_STR, VAL_ANY, VAL_CODE, VAL_MACRO, VAL_IDENT, VAL_CSTR, VAL_CANY, VAL_WORD, VAL_POP, VAL_COND }; static const int cs_valtypet[] = { VAL_NULL, VAL_INT, VAL_FLOAT, VAL_STR, VAL_CSTR, VAL_CODE, VAL_MACRO, VAL_IDENT }; static inline int cs_vtype_to_int(CsValueType v) { return cs_valtypet[int(v)]; } struct Command: CsIdent { char *cargs; ostd::Uint32 argmask; int numargs; CmdFunc cb_cftv; Command( int type, ostd::ConstCharRange name, ostd::ConstCharRange args, ostd::Uint32 argmask, int numargs, CmdFunc func ); }; enum { CODE_START = 0, CODE_OFFSET, CODE_NULL, CODE_TRUE, CODE_FALSE, CODE_NOT, CODE_POP, CODE_ENTER, CODE_ENTER_RESULT, CODE_EXIT, CODE_RESULT_ARG, CODE_VAL, CODE_VALI, CODE_DUP, CODE_MACRO, CODE_BOOL, CODE_BLOCK, CODE_EMPTY, CODE_COMPILE, CODE_COND, CODE_FORCE, CODE_RESULT, CODE_IDENT, CODE_IDENTU, CODE_IDENTARG, CODE_COM, CODE_COMC, CODE_COMV, CODE_CONC, CODE_CONCW, CODE_CONCM, CODE_DOWN, CODE_SVAR, CODE_SVARM, CODE_SVAR1, CODE_IVAR, CODE_IVAR1, CODE_IVAR2, CODE_IVAR3, CODE_FVAR, CODE_FVAR1, CODE_LOOKUP, CODE_LOOKUPU, CODE_LOOKUPARG, CODE_LOOKUPM, CODE_LOOKUPMU, CODE_LOOKUPMARG, CODE_ALIAS, CODE_ALIASU, CODE_ALIASARG, CODE_CALL, CODE_CALLU, CODE_CALLARG, CODE_PRINT, CODE_LOCAL, CODE_DO, CODE_DOARGS, CODE_JUMP, CODE_JUMP_TRUE, CODE_JUMP_FALSE, CODE_JUMP_RESULT_TRUE, CODE_JUMP_RESULT_FALSE, CODE_OP_MASK = 0x3F, CODE_RET = 6, CODE_RET_MASK = 0xC0, /* return type flags */ RET_NULL = VAL_NULL << CODE_RET, RET_STR = VAL_STR << CODE_RET, RET_INT = VAL_INT << CODE_RET, RET_FLOAT = VAL_FLOAT << CODE_RET, }; struct NullValue: CsValue { NullValue() { set_null(); } } const null_value; template static void cs_do_args(CsState &cs, F body) { CsIdentStack argstack[MaxArguments]; int argmask1 = cs.p_stack->usedargs; for (int i = 0; argmask1; argmask1 >>= 1, ++i) { if (argmask1 & 1) { static_cast(cs.identmap[i])->undo_arg(argstack[i]); } } CsIdentLink *prevstack = cs.p_stack->next; CsIdentLink aliaslink = { cs.p_stack->id, cs.p_stack, prevstack->usedargs, prevstack->argstack }; cs.p_stack = &aliaslink; body(); prevstack->usedargs = aliaslink.usedargs; cs.p_stack = aliaslink.next; int argmask2 = cs.p_stack->usedargs; for (int i = 0; argmask2; argmask2 >>= 1, ++i) { if (argmask2 & 1) { static_cast(cs.identmap[i])->redo_arg(argstack[i]); } } } ostd::ConstCharRange cs_debug_line( ostd::ConstCharRange p, ostd::ConstCharRange fmt, ostd::CharRange buf ); void cs_debug_alias(CsState &cs); template void cs_debug_code(CsState &cs, ostd::ConstCharRange fmt, A &&...args) { if (cs.nodebug) { return; } ostd::err.writefln(fmt, ostd::forward(args)...); cs_debug_alias(cs); } template void cs_debug_code_line( CsState &cs, ostd::ConstCharRange p, ostd::ConstCharRange fmt, A &&...args ) { if (cs.nodebug) { return; } ostd::Array buf; ostd::err.writefln( cs_debug_line(p, fmt, ostd::CharRange(buf.data(), buf.size())), ostd::forward(args)... ); cs_debug_alias(cs); } struct GenState { CsState &cs; CsVector code; char const *source; GenState() = delete; GenState(CsState &csr): cs(csr), code(), source(nullptr) {} void gen_str(ostd::ConstCharRange word, bool macro = false) { if (word.size() <= 3 && !macro) { ostd::Uint32 op = CODE_VALI | RET_STR; for (ostd::Size i = 0; i < word.size(); ++i) { op |= ostd::Uint32(ostd::byte(word[i])) << ((i + 1) * 8); } code.push(op); return; } code.push( (macro ? CODE_MACRO : (CODE_VAL | RET_STR)) | (word.size() << 8) ); code.push_n( reinterpret_cast(word.data()), word.size() / sizeof(ostd::Uint32) ); ostd::Size esz = word.size() % sizeof(ostd::Uint32); union { char c[sizeof(ostd::Uint32)]; ostd::Uint32 u; } end; end.u = 0; memcpy(end.c, word.data() + word.size() - esz, esz); code.push(end.u); } void gen_str() { code.push(CODE_VALI | RET_STR); } void gen_null() { code.push(CODE_VALI | RET_NULL); } void gen_int(CsInt i = 0) { if (i >= -0x800000 && i <= 0x7FFFFF) { code.push(CODE_VALI | RET_INT | (i << 8)); } else { code.push(CODE_VAL | RET_INT); code.push(i); } } void gen_int(ostd::ConstCharRange word); void gen_float(CsFloat f = 0.0f) { if (CsInt(f) == f && f >= -0x800000 && f <= 0x7FFFFF) { code.push(CODE_VALI | RET_FLOAT | (CsInt(f) << 8)); } else { union { CsFloat f; ostd::Uint32 u; } c; c.f = f; code.push(CODE_VAL | RET_FLOAT); code.push(c.u); } } void gen_float(ostd::ConstCharRange word); void gen_ident(CsIdent *id) { code.push( ((id->get_index() < MaxArguments) ? CODE_IDENTARG : CODE_IDENT ) | (id->get_index() << 8) ); } void gen_ident() { gen_ident(cs.identmap[DummyIdx]); } void gen_ident(ostd::ConstCharRange word) { gen_ident(cs.new_ident(word)); } void gen_value( int wordtype, ostd::ConstCharRange word = ostd::ConstCharRange() ); void gen_main(ostd::ConstCharRange s, int ret_type = VAL_ANY); char next_char() { return *source++; } char current() { return *source; } }; CsString intstr(int v); CsString floatstr(CsFloat v); bool cs_check_num(ostd::ConstCharRange s); static inline void bcode_incr(ostd::Uint32 *bc) { *bc += 0x100; } static inline void bcode_decr(ostd::Uint32 *bc) { *bc -= 0x100; if (ostd::Int32(*bc) < 0x100) { delete[] bc; } } } /* namespace cscript */ #endif /* LIBCUBESCRIPT_CS_VM_HH */