Files correlati : ba8 ve1 Ricompilazione Demo : [ ] Commento : Corretta gestione MESSAGE APPEND nel caso di campi vuoti git-svn-id: svn://10.65.10.50/trunk@13680 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			1311 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1311 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| #include <ctype.h>
 | |
| #include <stdlib.h>
 | |
| 
 | |
| #include <alex.h>
 | |
| #include <automask.h>
 | |
| #include <colors.h>
 | |
| #include <defmask.h>
 | |
| #include <dongle.h>
 | |
| #include <prefix.h>
 | |
| #include <recarray.h>
 | |
| #include <statbar.h>
 | |
| #include <urldefid.h>
 | |
| #include <utility.h>
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TAVM_op
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| enum AVM_opcode 
 | |
| { 
 | |
|   avm_nop, 
 | |
|   avm_add, avm_and, 
 | |
|   avm_begin,
 | |
|   avm_call_word, avm_ceil, avm_cold, avm_cr,
 | |
|   avm_cmp_eq, avm_cmp_gt, avm_cmp_gteq, avm_cmp_lt, avm_cmp_lteq, avm_cmp_noteq, 
 | |
|   avm_cmp_emptyeq, avm_cmp_nulleq, avm_cmp_zeroeq,
 | |
|   avm_div, avm_divide, avm_do, avm_dot, avm_drop, avm_dup, 
 | |
|   avm_else,
 | |
|   avm_fetch, avm_forget,
 | |
|   avm_i, avm_if, avm_include, 
 | |
|   avm_j,
 | |
|   avm_loop,
 | |
|   avm_mod, avm_mon, avm_mul,
 | |
|   avm_negate, avm_null,
 | |
|   avm_or, avm_over, 
 | |
|   avm_perform, avm_pick, avm_plus_loop, avm_plus_store, avm_push, 
 | |
|   avm_repeat, avm_rdrop, avm_rpeek, avm_rpush, avm_roll, avm_rot, avm_round,
 | |
|   avm_strlen, avm_strmid, avm_strtok_fetch, avm_strtok_add, 
 | |
|   avm_store, avm_sp, avm_sub, avm_swap, 
 | |
|   avm_then, avm_trunc,
 | |
|   avm_until, avm_usrword, 
 | |
|   avm_warm, avm_while,
 | |
|   avm_zzz
 | |
| };
 | |
| 
 | |
| const char* AVM_TOKENS[avm_zzz+1] = 
 | |
| {
 | |
|   "$NOP$",
 | |
|   "+", "AND",
 | |
|   "BEGIN",
 | |
|   "$CALL_WORD$", "CEIL", "COLD", "CR",
 | |
|   "=", ">", ">=", "<", "<=", "<>", 
 | |
|   "EMPTY=", "NULL=", "0=", 
 | |
|   "DIV", "/", "DO", ".", "DROP", "DUP",
 | |
|   "ELSE",
 | |
|   "@", "FORGET",
 | |
|   "I", "IF", "INCLUDE",
 | |
|   "J",
 | |
|   "LOOP",
 | |
|   "MOD", "MON", "*",
 | |
|   "NEGATE", "NULL",
 | |
|   "OR", "OVER",
 | |
|   "PERFORM", "PICK", "+LOOP", "+!", "$PUSH$",
 | |
|   "REPEAT", "R>", "R@", ">R", "ROLL", "ROT", "ROUND",
 | |
|   "STRLEN", "STRMID", "STRTOK@", "STRTOK+", 
 | |
|   "!", "SP", "-", "SWAP",
 | |
|   "THEN", "TRUNC",
 | |
|   "UNTIL", "$USR$",
 | |
|   "WARM", "WHILE"
 | |
| };
 | |
| 
 | |
| enum TBreakpointType { brk_none = 0x0, brk_user = 0x1, brk_auto = 0x2 };
 | |
| 
 | |
| class TAVM_op : public TObject
 | |
| {
 | |
|   AVM_opcode _op;
 | |
|   TVariant _var;
 | |
|   int _break_pointer;
 | |
| 
 | |
| public:
 | |
|   const TVariant& var() const { return _var; }
 | |
|   TVariant& var() { return _var; }
 | |
|   AVM_opcode op() const { return _op; }
 | |
|   bool has_break() const { return _break_pointer != brk_none; }
 | |
|   bool has_auto_break() const { return (_break_pointer & brk_auto) != 0; }
 | |
|   void set_user_break(bool on);
 | |
|   void set_auto_break(bool on);
 | |
| 
 | |
|   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(const TAVM_op& op);
 | |
|   TAVM_op(AVM_opcode o);
 | |
| };
 | |
| 
 | |
| void TAVM_op::set_user_break(bool on)
 | |
| {
 | |
|   _break_pointer = on ? brk_user : brk_none;
 | |
| }
 | |
| 
 | |
| void TAVM_op::set_auto_break(bool on)
 | |
| {
 | |
|   if (on)
 | |
|     _break_pointer |= brk_auto;
 | |
|   else
 | |
|     _break_pointer &= ~brk_auto;
 | |
| }
 | |
| 
 | |
| 
 | |
| TAVM_op::TAVM_op(AVM_opcode o, const TString& str)
 | |
|        : _op(o), _var(str), _break_pointer(0)
 | |
| { }
 | |
| 
 | |
| TAVM_op::TAVM_op(AVM_opcode o, const real& num)
 | |
|        : _op(o), _var(num), _break_pointer(0)
 | |
| { }
 | |
| 
 | |
| TAVM_op::TAVM_op(AVM_opcode o, const long num)
 | |
|        : _op(o), _var(num), _break_pointer(0)
 | |
| { }
 | |
| 
 | |
| TAVM_op::TAVM_op(AVM_opcode o)
 | |
|        : _op(o), _break_pointer(0)
 | |
| { }
 | |
| 
 | |
| TAVM_op::TAVM_op(const TAVM_op& op) : _op(op._op), _var(op._var), _break_pointer(0)
 | |
| {
 | |
| }
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TAVM_monitor
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| class TAVM_list_window : public TField_window
 | |
| {
 | |
|   TBytecode* _bc;
 | |
|   int _ip;
 | |
|   const TString_array* _user_words;
 | |
| 
 | |
| protected:
 | |
|   virtual void update();
 | |
|   virtual void handler(WINDOW win, EVENT* ep);
 | |
| 
 | |
| public:
 | |
|   void set_bytecode(const TBytecode* bc, int ip, const TString_array& uw);
 | |
|   TAVM_list_window(int x, int y, int dx, int dy, WINDOW parent, TWindowed_field* owner);
 | |
| };
 | |
| 
 | |
| void TAVM_list_window::handler(WINDOW win, EVENT* ep)
 | |
| {
 | |
|   if (ep->type == E_MOUSE_DOWN)
 | |
|   {
 | |
|     const TPoint pt = dev2log(ep->v.mouse.where);
 | |
|     if (pt.x <= 5)
 | |
|     {
 | |
|       TAVM_op& op = *(TAVM_op*)_bc->objptr(pt.y-1);
 | |
|       op.set_user_break(ep->v.mouse.button == 0);
 | |
|       force_update();
 | |
|     }
 | |
|   }
 | |
|   TField_window::handler(win, ep);
 | |
| }
 | |
| 
 | |
| void TAVM_list_window::update()
 | |
| {
 | |
|   clear(NORMAL_BACK_COLOR);
 | |
|   if (_bc != NULL)
 | |
|   {
 | |
|     autoscroll(false);
 | |
|     set_brush(DISABLED_BACK_COLOR);
 | |
|     bar(0, 0, columns()+1, 1); 
 | |
|     bar(0, 0, 5, rows()+1); 
 | |
|     set_brush(NORMAL_BACK_COLOR);
 | |
|     printat(0, 0, _bc->name());
 | |
|     autoscroll(true);
 | |
| 
 | |
|     TString str;
 | |
|     int tab = 6;
 | |
| 
 | |
|     const int last = min(_bc->items(), rows());
 | |
|     for (int i = 0; i < last; i++)
 | |
|     {
 | |
| 
 | |
|       const int y = i+1;
 | |
|       if (_ip == i)
 | |
|       {
 | |
|         set_brush(FOCUS_BACK_COLOR);
 | |
|         bar(0, y, 80, y+1); 
 | |
|         set_brush(NORMAL_BACK_COLOR);
 | |
|       }
 | |
|       printat(0, y, "%04d", i);
 | |
|       const TAVM_op& op = *(const TAVM_op*)_bc->objptr(i);
 | |
|       const AVM_opcode co = op.op();
 | |
|       const TVariant& var = op.var();
 | |
| 
 | |
|       if (op.has_break())
 | |
|         printat(4, y, "<");
 | |
| 
 | |
|       if (co == avm_else || co == avm_then || 
 | |
|           co == avm_loop || co == avm_plus_loop || 
 | |
|           co == avm_repeat || co == avm_until || co == avm_while)
 | |
|         tab -= 2;
 | |
|       if (co == avm_push)
 | |
|       {
 | |
|         if (var.is_string() && var.as_string()[0] != '#')   
 | |
|           str.cut(0) << '"' << var.as_string() << '"';
 | |
|         else
 | |
|         {
 | |
|           if (var.is_null())
 | |
|             str = "NULL";
 | |
|           else
 | |
|             str = var.as_string();
 | |
|         }
 | |
|       } else
 | |
|       if (co == avm_call_word)
 | |
|       {
 | |
|         str = var.as_string();
 | |
|       } else
 | |
|       if (co == avm_usrword)
 | |
|       {
 | |
|         str = _user_words->row(var.as_int());
 | |
|         str << " (#" << var.as_int() << ')';
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         str = AVM_TOKENS[co];
 | |
|         if (!var.is_null())
 | |
|           str << " (" << var.as_string() << ')';
 | |
|       }
 | |
|       printat(tab, y, str);
 | |
|       if (co == avm_if || co == avm_else || 
 | |
|         co == avm_do || co == avm_begin || co == avm_while)
 | |
|         tab += 2;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void TAVM_list_window::set_bytecode(const TBytecode* bc, int ip, const TString_array& uw) 
 | |
| { 
 | |
|   _bc = (TBytecode*)bc; 
 | |
|   _ip = ip;
 | |
|   _user_words = &uw;
 | |
|   set_scroll_max(80, _bc->items() - rows());
 | |
| }
 | |
| 
 | |
| TAVM_list_window::TAVM_list_window(int x, int y, int dx, int dy, WINDOW parent, TWindowed_field* owner)
 | |
|            : TField_window(x, y, dx, dy, parent, owner), _bc(NULL)
 | |
| {
 | |
|   autoscroll(true);
 | |
| }
 | |
| 
 | |
| class TAVM_stack_window : public TField_window
 | |
| {
 | |
|   TVariant_stack* _stack;
 | |
| 
 | |
| protected:
 | |
|   virtual void update();
 | |
| 
 | |
| public:
 | |
|   void set_stack(TVariant_stack& s);
 | |
|   TAVM_stack_window(int x, int y, int dx, int dy, WINDOW parent, TWindowed_field* owner);
 | |
| };
 | |
| 
 | |
| void TAVM_stack_window::update()
 | |
| {
 | |
|   clear(NORMAL_BACK_COLOR);
 | |
|   if (_stack != NULL)
 | |
|   {
 | |
|     for (int i = 0; i < _stack->items(); i++)
 | |
|     {
 | |
|       const TVariant& var = _stack->peek(i);
 | |
|       if (var.is_null())
 | |
|         printat(0, i, "NULL");
 | |
|       else
 | |
|         printat(0, i, var.as_string());
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void TAVM_stack_window::set_stack(TVariant_stack& s)
 | |
| {
 | |
|   _stack = &s;
 | |
|   set_scroll_max(80, s.items() - rows());
 | |
| }
 | |
| 
 | |
| TAVM_stack_window::TAVM_stack_window(int x, int y, int dx, int dy, WINDOW parent, TWindowed_field* owner)
 | |
|            : TField_window(x, y, dx, dy, parent, owner), _stack(NULL)
 | |
| {
 | |
|   autoscroll(true);
 | |
| }
 | |
| 
 | |
| class TAVM_list_field : public TWindowed_field
 | |
| {
 | |
| protected:
 | |
|   virtual TField_window* create_window(int x, int y, int dx, int dy, WINDOW parent);
 | |
| 
 | |
| public:
 | |
|   TAVM_list_field(TMask* m) : TWindowed_field(m) { }
 | |
|   virtual ~TAVM_list_field() { }
 | |
| };
 | |
| 
 | |
| TField_window* TAVM_list_field::create_window(int x, int y, int dx, int dy, WINDOW parent)
 | |
| {
 | |
|   return new TAVM_list_window(x, y, dx, dy, parent, this);
 | |
| }
 | |
| 
 | |
| class TAVM_stack_field : public TWindowed_field
 | |
| {
 | |
| protected:
 | |
|   virtual TField_window* create_window(int x, int y, int dx, int dy, WINDOW parent);
 | |
| 
 | |
| public:
 | |
|   TAVM_stack_field(TMask* m) : TWindowed_field(m) { }
 | |
|   virtual ~TAVM_stack_field() { }
 | |
| };
 | |
| 
 | |
| TField_window* TAVM_stack_field::create_window(int x, int y, int dx, int dy, WINDOW parent)
 | |
| {
 | |
|   return new TAVM_stack_window(x, y, dx, dy, parent, this);
 | |
| }
 | |
| 
 | |
| class TAVM_monitor : public TAutomask
 | |
| {
 | |
|   TAVM_list_window *_lw;
 | |
|   TAVM_stack_window *_sw, *_rw;
 | |
|   bool _ignore_mon;
 | |
| 
 | |
| protected:
 | |
|   virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
 | |
|   virtual bool on_key(KEY k);
 | |
| 
 | |
| public:
 | |
|   void set_ignore_mon(bool im) { _ignore_mon = im; }
 | |
|   bool ignore_mon() const { return _ignore_mon; }
 | |
|   TAVM_list_window& monitor() const { return *_lw; }
 | |
|   TAVM_stack_window& stacker() const { return *_sw; }
 | |
|   TAVM_stack_window& rstacker() const { return *_rw; }
 | |
|   TAVM_monitor();
 | |
| };
 | |
| 
 | |
| 
 | |
| bool TAVM_monitor::on_field_event(TOperable_field& o, TField_event e, long jolly)
 | |
| {
 | |
|   switch (o.dlg())
 | |
|   {
 | |
|   case 104:
 | |
|     if (e == fe_init)
 | |
|       o.set(ignore_mon() ? "X" : "");
 | |
|     if (e == fe_modify)
 | |
|       set_ignore_mon(!o.get().blank());
 | |
|     break;
 | |
|   default:
 | |
|     break;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool TAVM_monitor::on_key(KEY k)
 | |
| {
 | |
|   switch (k)
 | |
|   {
 | |
|   case K_F10:
 | |
|   case K_F11: 
 | |
|     stop_run(k); 
 | |
|     return true;
 | |
|   default: break;
 | |
|   }
 | |
|   return TAutomask::on_key(k);
 | |
| }
 | |
| 
 | |
| TAVM_monitor::TAVM_monitor() : TAutomask("Monitor", 1, 50, 20), _ignore_mon(false)
 | |
| {
 | |
|   TWindowed_field* wf = new TAVM_list_field(this);
 | |
|   wf->create(101, 0, 0, 24, -4); add_field(wf);
 | |
|   _lw = (TAVM_list_window*)&wf->win();
 | |
| 
 | |
|   TWindowed_field* sf = new TAVM_stack_field(this);
 | |
|   sf->create(102, 27, 0, -3, 9); add_field(sf);
 | |
|   _sw = (TAVM_stack_window*)&sf->win();
 | |
| 
 | |
|   TWindowed_field* rf = new TAVM_stack_field(this);
 | |
|   rf->create(103, 27, 10, -3, -4); add_field(rf);
 | |
|   _rw = (TAVM_stack_window*)&rf->win();
 | |
| 
 | |
|   add_boolean(104, 0, "Ignora MON d'ora in poi", 1, -3);
 | |
| 
 | |
|   add_button(DLG_NEXTREC, 0, "", -14, -1, 10, 2, "", 124).set_exit_key(K_F11);
 | |
|   add_button(DLG_LASTREC, 0, "", -24, -1, 10, 2, "", 1671).set_exit_key(K_F10);
 | |
|   add_button(DLG_ELABORA, 0, "", -34, -1, 10, 2, "", BMP_LASTREC).set_exit_key(K_F5);
 | |
|   add_button(DLG_QUIT,    0, "", -44, -1, 10, 2).set_exit_key(K_QUIT);
 | |
| 
 | |
|   set_handlers();
 | |
| }
 | |
| 
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TAVM
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| class TAVM
 | |
| {
 | |
|   TAlex_virtual_machine* _vm;
 | |
|   bool _interactive;
 | |
|   TString _last_error;
 | |
|   TVariant_stack _stack, _rstack;
 | |
|   const TBytecode* _bc; // Current word (or command line)
 | |
|   int _ip;              // Current instruction pointer
 | |
|   ostream* _outstr;
 | |
| 
 | |
|   TAssoc_array _words;
 | |
|   TAssoc_array _vars;
 | |
|   TString_array _user_words;
 | |
|   TAVM_monitor _mon;
 | |
| 
 | |
| protected:
 | |
|   bool get_token(istream& instr, TString& str) const;
 | |
|   AVM_opcode token2opcode(const TString& str) const;
 | |
|   int compare_tos_nos();
 | |
|   int find_matching(const TBytecode& bytecode, AVM_opcode op1, AVM_opcode op2 = avm_nop) const;
 | |
|   void execute(const TAVM_op& op);
 | |
|   void do_call(const TString& func);
 | |
| 
 | |
|   const TString_array& get_user_words();
 | |
|   int compile_user_word(const char* n);
 | |
| 
 | |
| public:
 | |
|   void log_error(const char* str);
 | |
|   const TString& get_last_error() const { return _last_error; }
 | |
| 
 | |
|   bool compile(istream& instr, TBytecode& bc);
 | |
|   bool execute(const TBytecode& bc);
 | |
|   void do_restart(bool cold);
 | |
|   bool do_include(const char* fname);
 | |
|   void do_fetch(const TString& name);
 | |
|   void do_add();
 | |
|   void do_store(const TString& name);
 | |
|   void set_interactive(bool inter) { _interactive = inter; }
 | |
|   bool defined(const char* w);
 | |
| 
 | |
|   TAVM(TAlex_virtual_machine* vm);
 | |
|   virtual ~TAVM();
 | |
| };
 | |
| 
 | |
| void TAVM::log_error(const char* str)
 | |
| {
 | |
|   _last_error = str;
 | |
|   if (_interactive)
 | |
|     error_box(str);
 | |
| #ifdef DBG
 | |
|   else
 | |
|     statbar_set_title(TASK_WIN, str);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| bool TAVM::get_token(istream& instr, TString& str) const
 | |
| {
 | |
|   str.cut(0);
 | |
|   eatwhite(instr);
 | |
|   if (instr.eof())
 | |
|     return false;
 | |
|   char c;
 | |
|   instr.get(c);
 | |
|   str << c;
 | |
|   if (c == '"')
 | |
|   {
 | |
|     char* buf = str.get_buffer()+1;
 | |
|     const int bufsize = str.size()-1;
 | |
|     instr.getline(buf, bufsize, '"');
 | |
|     str << '"';
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     instr.get(c);
 | |
|     while (!isspace(c) && c != EOF)
 | |
|     {
 | |
|       str << c;
 | |
|       instr.get(c);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return *str > ' ';
 | |
| }
 | |
| 
 | |
| #define ALEX_TOKENS 24
 | |
| 
 | |
| 
 | |
| AVM_opcode TAVM::token2opcode(const TString& str) const
 | |
| {
 | |
|   for (int i = 0; AVM_TOKENS[i] != NULL; i++)
 | |
|   {
 | |
|     if (str == AVM_TOKENS[i])
 | |
|       return AVM_opcode(i);
 | |
|   }
 | |
| 
 | |
|   const TBytecode* bc =(const TBytecode*)_words.objptr(str);
 | |
|   if (bc != NULL)
 | |
|     return avm_call_word;
 | |
| 
 | |
|   return avm_nop;
 | |
| }
 | |
| 
 | |
| int TAVM::find_matching(const TBytecode& bytecode, AVM_opcode op1, AVM_opcode op2) const
 | |
| {
 | |
|   int i;
 | |
|   for (i = bytecode.last(); i >= 0; i--)
 | |
|   {
 | |
|     TAVM_op& theop = (TAVM_op&)bytecode[i];
 | |
|     if ((theop.op() == op1 || theop.op() == op2) && theop.var().is_null())
 | |
|     {
 | |
|       theop.var() = long(bytecode.items());
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
|   return i;
 | |
| }
 | |
| 
 | |
| const TString_array& TAVM::get_user_words()
 | |
| {
 | |
|   if (_user_words.items() == 0)
 | |
|   {
 | |
|     _user_words.add("***");
 | |
|     _vm->get_usr_words(_user_words);
 | |
|   }
 | |
|   return _user_words;
 | |
| }
 | |
| 
 | |
| int TAVM::compile_user_word(const char* w)
 | |
| {
 | |
|   const TString_array& uw = get_user_words();
 | |
|   const int i = uw.find(w);
 | |
|   return i > 0 ? i : 0;
 | |
| }
 | |
| 
 | |
| bool TAVM::compile(istream& instr, TBytecode& bytecode)
 | |
| {
 | |
|   TString str(256);
 | |
|   bytecode.destroy();
 | |
|   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 ((isdigit(str[0]) || (str[0]=='-')) && isdigit(str[str.len()-1]))
 | |
|     {
 | |
|       const real r(str);
 | |
|       op = new TAVM_op(avm_push, r);
 | |
|     } else
 | |
|     if (str[0] == '#') // User variable
 | |
|     {
 | |
|       op = new TAVM_op(avm_push, str);
 | |
|     } else
 | |
|     if (str == ":") // User word
 | |
|     {
 | |
|       if (get_token(instr, str))
 | |
|       {
 | |
|         TBytecode* bc = new TBytecode;
 | |
|         bc->set_name(str);
 | |
|         _words.add(str, bc, true);
 | |
|         compile(instr, *bc);
 | |
|         op = new TAVM_op(avm_nop);
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         _last_error = "Missing word after :";
 | |
|         log_error(_last_error);
 | |
|         return false;
 | |
|       }
 | |
|     } else
 | |
|     if (str == "VARIABLE")
 | |
|     {
 | |
|       if (get_token(instr, str))
 | |
|       {
 | |
|         _vars.add(str, NULL_VARIANT);
 | |
|         op = new TAVM_op(avm_nop);
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         _last_error = "Missing VARIABLE name";
 | |
|         log_error(_last_error);
 | |
|         return false;
 | |
|       }
 | |
|     } else
 | |
|     if (str == ";")
 | |
|     {
 | |
|       return true;
 | |
|     } else
 | |
|     if (str == "(")
 | |
|     {
 | |
|       TString256 str;
 | |
|       instr.getline(str.get_buffer(), str.size(), ')');
 | |
|       op = new TAVM_op(avm_nop);
 | |
|     } else
 | |
|     if (str == "\\")
 | |
|     {
 | |
|       TString256 str;
 | |
|       instr.getline(str.get_buffer(), str.size());
 | |
|       op = new TAVM_op(avm_nop);
 | |
|     } else
 | |
|     if (_vars.objptr(str) != NULL)
 | |
|     {
 | |
|       op = new TAVM_op(avm_push, str);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       const int oc = compile_user_word(str);
 | |
|       if (oc > 0)
 | |
|         op = new TAVM_op(avm_usrword, oc);
 | |
|       else
 | |
|       {
 | |
|         const AVM_opcode oc = token2opcode(str);
 | |
|         if (oc != avm_nop)
 | |
|         {
 | |
|           switch (oc)
 | |
|           {
 | |
|           case avm_else:
 | |
|             if (find_matching(bytecode, avm_if) < 0)
 | |
|             {
 | |
|               _last_error = "ELSE without matching IF";
 | |
|               log_error(_last_error);
 | |
|               return false;
 | |
|             }
 | |
|             op = new TAVM_op(oc);
 | |
|             break;
 | |
|           case avm_then:
 | |
|             if (find_matching(bytecode, avm_if, avm_else) < 0)
 | |
|             {
 | |
|               _last_error = "THEN without matching IF";
 | |
|               log_error(_last_error);
 | |
|               return false;
 | |
|             }
 | |
|             op = new TAVM_op(oc);
 | |
|             break;
 | |
|           case avm_loop:
 | |
|           case avm_plus_loop:
 | |
|             {
 | |
|               const int do_pos = find_matching(bytecode, avm_do);
 | |
|               if (do_pos < 0)
 | |
|               {
 | |
|                 _last_error.cut(0) << str << " without matching DO";
 | |
|                 log_error(_last_error);
 | |
|                 return false;
 | |
|               }
 | |
|               op = new TAVM_op(oc, do_pos);
 | |
|             }
 | |
|             break;
 | |
|           case avm_repeat:
 | |
|           case avm_until:
 | |
|             {
 | |
|               const int begin_pos = find_matching(bytecode, avm_begin);
 | |
|               if (begin_pos < 0)
 | |
|               {
 | |
|                 _last_error.cut(0) << str << " without matching BEGIN";
 | |
|                 log_error(_last_error);
 | |
|                 return false;
 | |
|               }
 | |
|               find_matching(bytecode, avm_while);
 | |
|               op = new TAVM_op(oc, begin_pos);
 | |
|             }
 | |
|             break;
 | |
|           case avm_call_word:
 | |
|             {
 | |
|               const TBytecode* bc = (const TBytecode*)_words.objptr(str);
 | |
|               if (bc != NULL && bc->items() == 1)
 | |
|               {
 | |
|                 const TAVM_op* inline_op = (const TAVM_op*)bc->objptr(0);
 | |
|                 op = new TAVM_op(*inline_op);
 | |
|               }
 | |
|               else
 | |
|                 op = new TAVM_op(oc, str);
 | |
|             }
 | |
|             break;
 | |
|           default:
 | |
|             op = new TAVM_op(oc);
 | |
|             break;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     if (op != NULL)
 | |
|     {
 | |
|       if (op->op() != avm_nop)
 | |
|         bytecode.add(op);
 | |
|       else
 | |
|         delete op;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       _last_error.cut(0) << "Unknown WORD: " << str;
 | |
|       log_error(_last_error);
 | |
|       // return false;  // Non e' un errore gravissimo!
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| int TAVM::compare_tos_nos()
 | |
| {
 | |
|   const TVariant& tos = _stack.pop();
 | |
|   const TVariant& nos = _stack.pop();
 | |
|   return nos.compare(tos);
 | |
| }
 | |
| 
 | |
| void TAVM::do_call(const TString& func)
 | |
| {
 | |
|   if (_stack.overflow())
 | |
|   {
 | |
|     log_error("Stack overflow");
 | |
|     _bc = NULL;
 | |
|     return;
 | |
|   }
 | |
|   TBytecode* bc = (TBytecode*)_words.objptr(func);
 | |
|   if (bc != NULL)
 | |
|   {
 | |
|     _rstack.push(_bc->name());
 | |
|     _rstack.push(_ip+1);
 | |
|     _ip = -1; // will be incremented!
 | |
|     _bc = bc;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     _last_error = func; _last_error << " ?";
 | |
|     log_error(_last_error);
 | |
|     _bc = NULL;
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool TAVM::do_include(const char* fname)
 | |
| {
 | |
|   TFilename name = fname;
 | |
|   bool ok = name.custom_path();
 | |
|   if (ok)
 | |
|   {
 | |
|     TBytecode bc;
 | |
|     ifstream inf(name); 
 | |
|     ok = compile(inf, bc);
 | |
|     if (ok)
 | |
|       execute(bc);
 | |
|   }
 | |
|   return ok;
 | |
| }
 | |
| 
 | |
| // Mette sullo stack il valore della variabile name
 | |
| void TAVM::do_fetch(const TString& name)
 | |
| {
 | |
|   const TVariant* var = name[0] != '#' ? (const TVariant*)_vars.objptr(name) : NULL;
 | |
|   if (var != NULL)
 | |
|     _stack.push(*var);
 | |
|   else
 | |
|   {
 | |
|     TVariant var;
 | |
|     _vm->get_usr_val(name, var);
 | |
|     _stack.push(var);
 | |
|   } 
 | |
| }
 | |
| 
 | |
| void TAVM::do_add()
 | |
| {
 | |
|   const TVariant& v1 = _stack.pop();
 | |
|   TVariant& v0 = (TVariant&)_stack.peek();
 | |
|   v0.add(v1);
 | |
| }
 | |
| 
 | |
| // Legge dallo stack il valore da asseganre alla variabile name
 | |
| void TAVM::do_store(const TString& name)
 | |
| {
 | |
|   const TVariant& var = _stack.pop();
 | |
|   TVariant* v = name[0] != '#' ? (TVariant*)_vars.objptr(name) : NULL;
 | |
|   if (v != NULL)
 | |
|     *v = var;
 | |
|   else
 | |
|     _vm->set_usr_val(name, var);
 | |
| }
 | |
| 
 | |
| bool TAVM::defined(const char* name)
 | |
| {
 | |
|   if (_words.objptr(name) != NULL)
 | |
|     return true;
 | |
| 
 | |
|   return compile_user_word(name) > 0;
 | |
| }
 | |
| 
 | |
| void TAVM::execute(const TAVM_op& op)
 | |
| {
 | |
|   switch(op.op())
 | |
|   {
 | |
|   case avm_add: do_add(); break;
 | |
|   case avm_and: 
 | |
|     {
 | |
|       const TVariant& v1 = _stack.pop();
 | |
|       TVariant& v0 = (TVariant&)_stack.peek();
 | |
|       const long r = v0.as_int() & v1.as_int();
 | |
|       v0.set(r);
 | |
|     }
 | |
|     break;
 | |
|   case avm_begin: break;
 | |
|   case avm_call_word: do_call(op.var().as_string()); break;
 | |
|   case avm_ceil: 
 | |
|     {
 | |
|       const long dec = _stack.pop().as_int();
 | |
|       TVariant& v0 = (TVariant&)_stack.peek();
 | |
|       real k = v0.as_real(); k.ceil(dec);
 | |
|       v0 = k;
 | |
|     }
 | |
|     break;
 | |
|   case avm_cold: do_restart(true); _bc = NULL; break;
 | |
|   case avm_cr: _stack.push("\n"); break;
 | |
|   case avm_cmp_eq   : _stack.push(compare_tos_nos() == 0); break;
 | |
|   case avm_cmp_gt   : _stack.push(compare_tos_nos() > 0);  break;
 | |
|   case avm_cmp_gteq : _stack.push(compare_tos_nos() >= 0); break;
 | |
|   case avm_cmp_lt   : _stack.push(compare_tos_nos() < 0);  break;
 | |
|   case avm_cmp_lteq : _stack.push(compare_tos_nos() <= 0); break;
 | |
|   case avm_cmp_noteq: _stack.push(compare_tos_nos() != 0); break;
 | |
|   case avm_cmp_emptyeq: _stack.push(_stack.pop().is_empty()); break;
 | |
|   case avm_cmp_nulleq:_stack.push(_stack.pop().is_null()); break;
 | |
|   case avm_cmp_zeroeq:_stack.push(_stack.pop().is_zero()); break;
 | |
|   case avm_div:
 | |
|     {
 | |
|       const long r0 = _stack.pop().as_int();
 | |
|       const long r1 = _stack.pop().as_int();
 | |
|       if (r0 != 0)
 | |
|       {
 | |
|         const long n = r1 / r0;
 | |
|         _stack.push(n);
 | |
|       }
 | |
|       else
 | |
|         _stack.push(NULL_VARIANT);
 | |
|     }
 | |
| 
 | |
|     break;
 | |
|   case avm_divide: 
 | |
|     {
 | |
|       const real& r0 = _stack.pop().as_real();
 | |
|       const real& r1 = _stack.pop().as_real();
 | |
|       if (!r0.is_zero())
 | |
|       {
 | |
|         const real n = r1 / r0;
 | |
|         _stack.push(n);
 | |
|       }
 | |
|       else
 | |
|         _stack.push(NULL_VARIANT);
 | |
|     }
 | |
|     break;
 | |
|   case avm_do: 
 | |
|     {
 | |
|       const TVariant& start = _stack.pop();
 | |
|       const TVariant& limit = _stack.pop();
 | |
|       if (start.compare(limit) < 0)
 | |
|       {
 | |
|         _rstack.push(limit);
 | |
|         _rstack.push(start);
 | |
|       }
 | |
|       else
 | |
|         _ip = op.var().as_int();
 | |
|     }
 | |
|     break;
 | |
|   case avm_dot: 
 | |
|     if (_outstr != NULL)
 | |
|       *_outstr << _stack.pop().as_string(); 
 | |
|     break;
 | |
|   case avm_drop: 
 | |
|     if (!_stack.drop())
 | |
|     {
 | |
|       log_error("Stack underflow");
 | |
|       _bc = NULL;
 | |
|     }
 | |
|     break;
 | |
|   case avm_dup: _stack.push(_stack.peek()); break;
 | |
|   case avm_else:
 | |
|     _ip = op.var().as_int();
 | |
|     break;
 | |
|   case avm_fetch: do_fetch(_stack.pop().as_string()); break;
 | |
|   case avm_forget:
 | |
|     {
 | |
|       const TString& name = _stack.pop().as_string();
 | |
|       _vars.remove(name);
 | |
|       _words.remove(name);
 | |
|     }
 | |
|     break;
 | |
|   case avm_i: _stack.push(_rstack.peek()); break;
 | |
|   case avm_if:
 | |
|     if (_stack.pop().is_zero())
 | |
|       _ip = op.var().as_int();
 | |
|     break;
 | |
|   case avm_include: do_include(_stack.pop().as_string()); break;
 | |
|   case avm_j: _stack.push(_rstack.peek(2)); break;
 | |
|   case avm_loop: 
 | |
|     {
 | |
|       TVariant& start = _rstack.pop();
 | |
|       const TVariant& limit = _rstack.pop();
 | |
|       start.add(TVariant(UNO));
 | |
|       _stack.push(limit);
 | |
|       _stack.push(start);
 | |
|       _ip = op.var().as_int()-1;
 | |
|     }
 | |
|     break;
 | |
|   case avm_mod: 
 | |
|     {
 | |
|       const long i0 = _stack.pop().as_int();
 | |
|       const long i1 = _stack.pop().as_int();
 | |
|       _stack.push(i1 % i0);
 | |
|     }
 | |
|     break;
 | |
|   case avm_mon: 
 | |
|     if (!_mon.is_open() && !_mon.ignore_mon())
 | |
|       _mon.open_modal();
 | |
|     break;
 | |
|   case avm_mul: 
 | |
|     {
 | |
|       const TVariant& v1 = _stack.pop();
 | |
|       TVariant& v0 = (TVariant&)_stack.peek();
 | |
|       const real m = v0.as_real() * v1.as_real();
 | |
|       v0.set(m);
 | |
|     }
 | |
|     break;
 | |
|   case avm_negate:
 | |
|     {
 | |
|       TVariant& tos = _stack.peek();
 | |
|       tos.set(tos.as_bool() ? false : true);
 | |
|     }
 | |
|     break;
 | |
|   case avm_null: _stack.push(NULL_VARIANT); break;
 | |
|   case avm_or:
 | |
|     {
 | |
|       const TVariant& tos = _stack.pop();
 | |
|       TVariant& nos = (TVariant&)_stack.peek();
 | |
|       const long r = nos.as_int() | tos.as_int();
 | |
|       nos.set(r);
 | |
|     }
 | |
|     break;
 | |
|   case avm_over: _stack.push(_stack.peek(1)); break;
 | |
|   case avm_perform: do_call(_stack.pop().as_string()); break;
 | |
|   case avm_pick: _stack.push(_stack.peek(_stack.pop().as_int())); break;
 | |
|   case avm_plus_loop: 
 | |
|     {
 | |
|       TVariant& start = _rstack.pop();
 | |
|       const TVariant& limit = _rstack.pop();
 | |
|       start.add(_stack.pop());
 | |
|       _stack.push(limit);
 | |
|       _stack.push(start);
 | |
|       _ip = op.var().as_int()-1;
 | |
|     }
 | |
|     break;
 | |
|   case avm_plus_store:
 | |
|     {
 | |
|       const TString name = _stack.pop().as_string();
 | |
|       do_fetch(name);
 | |
|       _stack.roll(1);
 | |
|       do_add();
 | |
|       do_store(name);
 | |
|     }
 | |
|     break;
 | |
|   case avm_push: _stack.push(op.var()); break;
 | |
|   case avm_repeat: _ip = op.var().as_int(); break;
 | |
|   case avm_rdrop: _stack.push(_rstack.pop()); break;
 | |
|   case avm_rpeek: _stack.push(_rstack.peek()); break;
 | |
|   case avm_rpush: _rstack.push(_stack.pop()); break;
 | |
|   case avm_roll: _stack.roll(_stack.pop().as_int()); break;
 | |
|   case avm_rot: _stack.roll(2); break;
 | |
|   case avm_round: 
 | |
|     {
 | |
|       const long dec = _stack.pop().as_int();
 | |
|       TVariant& v0 = (TVariant&)_stack.peek();
 | |
|       real k = v0.as_real(); k.round(dec);
 | |
|       v0 = k;
 | |
|     }
 | |
|     break;
 | |
|   case avm_store: do_store(_stack.pop().as_string()); break;
 | |
|   case avm_strlen: _stack.push(_stack.pop().as_string().len()); break;
 | |
|   case avm_strmid: 
 | |
|     {
 | |
|       const int len = _stack.pop().as_int();
 | |
|       const int frm = _stack.pop().as_int();
 | |
|       const TString& str = _stack.pop().as_string();
 | |
|       _stack.push(str.mid(frm, len)); break;
 | |
|     }
 | |
|     break;
 | |
|   case avm_strtok_fetch: 
 | |
|     {
 | |
|       const int pos = _stack.pop().as_int();
 | |
|       TToken_string str(_stack.pop().as_string());
 | |
|       const char* tok = str.get(pos);
 | |
|       _stack.push(tok);
 | |
|     }
 | |
|     break;
 | |
|   case avm_strtok_add: 
 | |
|     {
 | |
|       const TString& tok = _stack.pop().as_string();
 | |
|       TToken_string str(_stack.pop().as_string());
 | |
|       str.add(tok);
 | |
|       _stack.push(str);
 | |
|     }
 | |
|     break;
 | |
|   case avm_sp: _stack.push(_stack.items()); break;
 | |
|   case avm_sub : 
 | |
|     {
 | |
|       const TVariant& v1 = _stack.pop();
 | |
|       TVariant& v0 = (TVariant&)_stack.peek();
 | |
|       v0.sub(v1);
 | |
|     }
 | |
|     break;
 | |
|   case avm_swap: _stack.roll(1); break;
 | |
|   case avm_then: break;
 | |
|   case avm_trunc: 
 | |
|     {
 | |
|       const long dec = _stack.pop().as_int();
 | |
|       TVariant& v0 = (TVariant&)_stack.peek();
 | |
|       real k = v0.as_real(); k.trunc(dec);
 | |
|       v0 = k;
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   case avm_until: 
 | |
|     if (_stack.pop().is_zero())
 | |
|       _ip = op.var().as_int(); 
 | |
|     break;
 | |
|   case avm_usrword: 
 | |
|     {
 | |
|       const long usrword = op.var().as_int();
 | |
|       _vm->execute_usr_word(usrword, _stack); 
 | |
|     }
 | |
|     break;
 | |
|   case avm_warm: do_restart(false); _bc = NULL; break;
 | |
|   case avm_while: 
 | |
|     if (_stack.pop().is_zero())
 | |
|       _ip = op.var().as_int();  // Exit loop
 | |
|     break; 
 | |
|   default:
 | |
|     _last_error << "Unimplemented op code: " << op.op() << '\n';
 | |
|     log_error(_last_error);
 | |
|     _bc = NULL; // force exit
 | |
|     break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool TAVM::execute(const TBytecode& cmdline)
 | |
| {
 | |
|   const TBytecode* old_bc = _bc;
 | |
|   const int old_ip = _ip;
 | |
|   bool aborted = false;
 | |
|   
 | |
|   _stack.reset();
 | |
|   _rstack.reset();
 | |
|   _bc = &cmdline;
 | |
|   _ip = 0;
 | |
|  
 | |
|   while (_bc != NULL)
 | |
|   {
 | |
|     while (_ip >= _bc->items()) // Fine funzione
 | |
|     {
 | |
|       if (_rstack.items() >= 2) // Controllo il return stack
 | |
|       {
 | |
|         _ip = _rstack.pop().as_int();
 | |
|         const TString& str = _rstack.pop().as_string();
 | |
|         if (str == cmdline.name())
 | |
|           _bc = &cmdline;
 | |
|         else
 | |
|         {
 | |
|           _bc = (const TBytecode*)_words.objptr(str);
 | |
|           if (_bc == NULL)
 | |
|             break;
 | |
|         }
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         _bc = NULL;
 | |
|         break; // Fine esecuzione
 | |
|       }
 | |
|     }
 | |
|     if (_bc == NULL || _ip > _bc->items())
 | |
|       break;
 | |
| 
 | |
|     TAVM_op& op = *(TAVM_op*)_bc->objptr(_ip);
 | |
|     if (op.has_break() && !_mon.is_open())
 | |
|     {
 | |
|       if (op.has_auto_break())
 | |
|         op.set_auto_break(false);
 | |
|       _mon.open_modal();
 | |
|     }
 | |
| 
 | |
|     if (_mon.is_open())  // Gestione debugger
 | |
|     {
 | |
|       TAVM_list_window& monitor = _mon.monitor();
 | |
|       monitor.set_bytecode(_bc, _ip, _user_words);
 | |
|       TAVM_stack_window& stacker = _mon.stacker();
 | |
|       stacker.set_stack(_stack);
 | |
|       TAVM_stack_window& rstacker = _mon.rstacker();
 | |
|       rstacker.set_stack(_rstack);
 | |
|       const KEY k = _mon.run();
 | |
|       switch (k)
 | |
|       {
 | |
|       case K_F11: monitor.force_update(); stacker.force_update(); rstacker.force_update(); break;
 | |
|       case K_F10: 
 | |
|         if (_ip < _bc->items()-1)
 | |
|         {
 | |
|           _mon.close_modal(); 
 | |
|           TAVM_op& op = *(TAVM_op*)_bc->objptr(_ip+1);
 | |
|           op.set_auto_break(true);
 | |
|         }
 | |
|         break;
 | |
|       case K_QUIT: aborted = true;
 | |
|       case K_F5  : _mon.close_modal(); break;
 | |
|       default: break;
 | |
|       }  
 | |
|     }
 | |
| 
 | |
|     execute(op);
 | |
| 
 | |
|     _ip++;
 | |
|   }
 | |
| 
 | |
|   if (_mon.is_open()) // Chiudi debugger
 | |
|     _mon.close_modal();
 | |
| 
 | |
|   //const bool ok = _bc != NULL;  // Not aborted
 | |
|   _bc = old_bc;
 | |
|   _ip = old_ip;
 | |
|   
 | |
|   return !aborted;
 | |
| }
 | |
| 
 | |
| void TAVM::do_restart(bool cold)
 | |
| {
 | |
|   _stack.reset();
 | |
|   _rstack.reset();
 | |
|   if (cold)
 | |
|   {
 | |
|     _words.destroy();
 | |
|     _vars.destroy();
 | |
|     do_include("alex.alx");
 | |
|   }
 | |
|   _mon.set_ignore_mon(false);
 | |
| }
 | |
| 
 | |
| TAVM::TAVM(TAlex_virtual_machine* vm) 
 | |
|     : _vm(vm), _interactive(false), _outstr(NULL)
 | |
| { 
 | |
|   do_restart(true);
 | |
| }
 | |
| 
 | |
| TAVM::~TAVM()
 | |
| {
 | |
| }
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TAlex_virtual_machine
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| TAVM& TAlex_virtual_machine::avm()
 | |
| {
 | |
|   if (_avm == NULL)
 | |
|     _avm = new TAVM(this);
 | |
|   return *_avm;
 | |
| }
 | |
| 
 | |
| void TAlex_virtual_machine::log_error(const char* str)
 | |
| {
 | |
|   if (_avm != NULL)
 | |
|     _avm->log_error(str);
 | |
| }
 | |
| 
 | |
| 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)
 | |
| {
 | |
|   return avm().compile(instr, bc);
 | |
| }
 | |
| 
 | |
| bool TAlex_virtual_machine::execute(const TBytecode& bc)
 | |
| {
 | |
|   return avm().execute(bc);
 | |
| }
 | |
| 
 | |
| bool TAlex_virtual_machine::compile(const char* cmd, TBytecode& bc)
 | |
| {
 | |
| #ifdef LINUX
 | |
| 	string s(cmd);
 | |
|   istringstream instr(s);
 | |
| #else
 | |
|   istrstream instr((char*)cmd, (size_t)strlen(cmd));
 | |
| #endif
 | |
|   return compile(instr, bc);
 | |
| }
 | |
| 
 | |
| void TAlex_virtual_machine::warm_restart() // Ripartenza a caldo
 | |
| {
 | |
|   avm().do_restart(false);
 | |
| }
 | |
| 
 | |
| void TAlex_virtual_machine::cold_restart() // Ripartenza a freddo
 | |
| {
 | |
|   avm().do_restart(true);
 | |
| }
 | |
| 
 | |
| bool TAlex_virtual_machine::get_usr_val(const TString& name, TVariant& var) const
 | |
| {
 | |
|   if (name.starts_with("#SYSTEM."))
 | |
|   {
 | |
|     const TFixed_string n((const char*)name+8);
 | |
|     if (n == "ADMINISTATOR")
 | |
|     {
 | |
|       var.set(dongle().administrator());
 | |
|       return true;
 | |
|     }
 | |
|     if (n == "CLOCK")
 | |
|     {
 | |
|       const long msec = clock() / (CLOCKS_PER_SEC / 1000);
 | |
|       var.set(msec);
 | |
|       return true;
 | |
|     }
 | |
|     if (n == "FIRM")
 | |
|     {
 | |
|       var.set(prefix().get_codditta());
 | |
|       return true;
 | |
|     }
 | |
|     if (n == "RAGSOC")
 | |
|     {
 | |
|       const long code = prefix().get_codditta();
 | |
|       const TString& ragsoc = cache().get(LF_NDITTE, code, n);
 | |
|       var.set(ragsoc);
 | |
|       return true;
 | |
|     }
 | |
|     if (n == "STUDY")
 | |
|     {
 | |
|       var.set(firm2dir(-1));
 | |
|       return true;
 | |
|     }
 | |
|     if (n == "DATE")
 | |
|     {
 | |
|       const TDate oggi(TODAY);
 | |
|       var.set(oggi);
 | |
|       return true;
 | |
|     }
 | |
|     if (n == "TIME")
 | |
|     {
 | |
|       time_t lt; time(<);
 | |
|       struct tm* t = localtime(<);
 | |
|       TString16 str; 
 | |
|       str.format("%02d:%02d:%02d", t->tm_hour, t->tm_min, t->tm_sec);
 | |
|       var.set(str);
 | |
|       return true;
 | |
|     }
 | |
|     if (n == "USER")
 | |
|     {
 | |
|       var.set(user());
 | |
|       return true;
 | |
|     }
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| bool TAlex_virtual_machine::set_usr_val(const TString& name, const TVariant& var)
 | |
| {
 | |
|   if (name.starts_with("#SYSTEM."))
 | |
|   {
 | |
|     const TFixed_string n((const char*)name+8);
 | |
|     if (n == "FIRM")
 | |
|     {
 | |
|       return prefix().set_codditta(var.as_int());
 | |
|     }
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| unsigned int TAlex_virtual_machine::get_usr_words(TString_array&) const
 | |
| {
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| bool TAlex_virtual_machine::execute_usr_word(unsigned int opcode, TVariant_stack& stack)
 | |
| {
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| bool TAlex_virtual_machine::include(const char* fname)
 | |
| {
 | |
|   return avm().do_include(fname);
 | |
| }
 | |
| 
 | |
| void TAlex_virtual_machine::include_libraries(bool reload)
 | |
| {
 | |
|   if (reload || !defined("2DUP"))
 | |
|     include("alex.alx");
 | |
| }
 | |
| 
 | |
| void TAlex_virtual_machine::set_interactive(bool inter) 
 | |
| { avm().set_interactive(inter); }
 | |
| 
 | |
| bool TAlex_virtual_machine::defined(const char* name) 
 | |
| {
 | |
|   return avm().defined(name);
 | |
| }
 | |
| 
 | |
| TAlex_virtual_machine::TAlex_virtual_machine() : _avm(NULL)
 | |
| {
 | |
| }
 | |
| 
 | |
| TAlex_virtual_machine::~TAlex_virtual_machine()
 | |
| {
 | |
|   if (_avm != NULL)
 | |
|     delete _avm;
 | |
| }
 | |
| 
 |