Files correlati : Ricompilazione Demo : [ ] Commento : Riportata la versione 2.1 300 git-svn-id: svn://10.65.10.50/trunk@13091 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			1296 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1296 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_variable,
 | 
						|
  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$",
 | 
						|
  "VARIABLE",
 | 
						|
  "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() = 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 == ";")
 | 
						|
    {
 | 
						|
      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
 | 
						|
    {
 | 
						|
      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_int());
 | 
						|
    }
 | 
						|
    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.peek().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.peek().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_variable: _vars.add(_stack.pop().as_string(), NULL_VARIANT); 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;
 | 
						|
}
 | 
						|
 |