#include #include #include #include #include #include "ba8304.h" TVariant& TVariant_stack::peek(int depth) { const int sp = _sp-depth-1; return sp >= 0 ? (TVariant&)_var[sp] : NULL_VARIANT; } TVariant& TVariant_stack::pop() { TVariant& var = peek(); if (_sp > 0) _sp--; return var; } void TVariant_stack::push(const TVariant& var) { if (_var.objptr(_sp) == NULL) _var.add(var, _sp); else (TVariant&)_var[_sp] = var; _sp++; } /////////////////////////////////////////////////////////// // TAVM_op /////////////////////////////////////////////////////////// enum AVM_opcode { avm_nop, avm_add, avm_dot, avm_dup, avm_push, avm_sub, avm_usrget, avm_usrset, avm_usrword }; class TAVM_op : public TObject { AVM_opcode _op; TVariant _var; public: const TVariant& var() const { return _var; } TVariant& var() { return _var; } AVM_opcode op() const { return _op; } TAVM_op(AVM_opcode o, const TString& str); TAVM_op(AVM_opcode o, const real& num); TAVM_op(AVM_opcode o, const long num); TAVM_op(AVM_opcode o); }; TAVM_op::TAVM_op(AVM_opcode o, const TString& str) : _op(o), _var(str) { } TAVM_op::TAVM_op(AVM_opcode o, const real& num) : _op(o), _var(num) { } TAVM_op::TAVM_op(AVM_opcode o, const long num) : _op(o), _var(num) { } TAVM_op::TAVM_op(AVM_opcode o) : _op(o) { } /////////////////////////////////////////////////////////// // TAVM /////////////////////////////////////////////////////////// class TAVM { TAlex_virtual_machine* _vm; TString _last_error; TVariant_stack _stack; protected: bool get_token(istream& instr, TString& str) const; AVM_opcode token2opcode(const TString& str) const; void log_error(const char* str); public: const TString& get_last_error() const { return _last_error; } bool compile(istream& instr, TBytecode& bc); bool execute(const TBytecode& bc, ostream& outstr); TAVM(TAlex_virtual_machine* vm) : _vm(vm) { } }; void TAVM::log_error(const char* str) { _last_error = str; error_box(str); } bool TAVM::get_token(istream& instr, TString& str) const { str.cut(0); instr.eatwhite(); if (instr.eof()) return false; char c; instr.get(c); str << c; char* buf = str.get_buffer()+1; const int bufsize = str.size()-1; if (c == '"') { instr.getline(buf, bufsize, '"'); str << '"'; } else instr.getline(buf, bufsize, ' '); return *str > ' '; } AVM_opcode TAVM::token2opcode(const TString& str) const { const char* AVM_TOKENS[4] = { "+", "-", ".", NULL }; AVM_opcode AVM_OPCODES[4] = { avm_add, avm_sub, avm_dot, avm_nop }; for (int i = 0; AVM_TOKENS[i] != NULL; i++) { if (str == AVM_TOKENS[i]) return AVM_OPCODES[i]; } return avm_nop; } bool TAVM::compile(istream& instr, TBytecode& bytecode) { TString str(256); bytecode.destroy(); bytecode.set_language("Alex"); while (get_token(instr, str)) { TAVM_op* op = NULL; if (str[0] == '"') { str.rtrim(1); str.ltrim(1); op = new TAVM_op(avm_push, str); } else if (str[0] == '@') // Address of field? { str.ltrim(1); op = new TAVM_op(avm_push, str); } else if (isdigit(str[0])) { const real r(str); op = new TAVM_op(avm_push, r); } else if (str[0] == '#') { op = new TAVM_op(avm_usrget, str); } else { const AVM_opcode oc = token2opcode(str); if (oc != avm_nop) op = new TAVM_op(oc); else { const unsigned int oc = _vm->compile_usr_word(str); if (oc > 0) op = new TAVM_op(avm_usrword, oc); } } if (op != NULL) bytecode.add(op); else { _last_error.cut(0) << "Unknown WORD: " << str; log_error(_last_error); return false; } } return true; } bool TAVM::execute(const TBytecode& bc, ostream& outstr) { int ip = 0; while (ip < bc.items()) { const TAVM_op& op = *(const TAVM_op*)bc.objptr(ip); bool jumped_elsewhere = false; switch(op.op()) { case avm_add : { const TVariant& v1 = _stack.pop(); TVariant& v0 = (TVariant&)_stack.peek(); v0.add(v1); } break; case avm_dot: outstr << _stack.pop().as_string(); break; case avm_dup: _stack.push(_stack.peek()); break; case avm_push: _stack.push(op.var()); break; case avm_sub : { const TVariant& v1 = _stack.pop(); TVariant& v0 = (TVariant&)_stack.peek(); v0.sub(v1); } break; case avm_usrget: { const TString& name = op.var().as_string(); TVariant var; _vm->get_usr_val(name, var); _stack.push(var); } break; case avm_usrword: _vm->execute_usr_word(op.var().as_int(), _stack); break; default: _last_error << "Bad op code: " << op.op() << '\n'; log_error(_last_error); return false; } if (!jumped_elsewhere) ip++; } return true; } /////////////////////////////////////////////////////////// // TAlex_virtual_machine /////////////////////////////////////////////////////////// const TString& TAlex_virtual_machine::get_last_error() const { if (_avm != NULL) return _avm->get_last_error(); return EMPTY_STRING; } bool TAlex_virtual_machine::compile(istream& instr, TBytecode& bc) { if (_avm == NULL) _avm = new TAVM(this); return _avm->compile(instr, bc); } bool TAlex_virtual_machine::execute(const TBytecode& bc, ostream& outstr) { if (_avm == NULL) _avm = new TAVM(this); return _avm->execute(bc, outstr); } bool TAlex_virtual_machine::compile(const char* cmd, TBytecode& bc) { istrstream instr((char*)cmd, strlen(cmd)); return compile(instr, bc); } bool TAlex_virtual_machine::execute(const TBytecode& bc, TString& outs) { char* buf = outs.get_buffer(); memset(buf, 0, outs.size()); ostrstream outstr(buf, outs.size()); return execute(bc, outstr); } bool TAlex_virtual_machine::get_usr_val(const TString& name, TVariant& var) const { return false; } bool TAlex_virtual_machine::set_usr_val(const TString& name, const TVariant& var) { return false; } unsigned int TAlex_virtual_machine::compile_usr_word(const TString& name) const { return 0; } bool TAlex_virtual_machine::execute_usr_word(unsigned int opcode, TVariant_stack& stack) { return false; } TAlex_virtual_machine::TAlex_virtual_machine() : _avm(NULL) { } TAlex_virtual_machine::~TAlex_virtual_machine() { if (_avm != NULL) delete _avm; }