summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--mixlib/Makefile.am4
-rw-r--r--mixlib/mix_types.c12
-rw-r--r--mixlib/mix_types.h10
-rw-r--r--mixlib/mix_vm_command.c1096
-rw-r--r--mixlib/mix_vm_command.h139
-rw-r--r--mixlib/mix_vm_dump.c77
-rw-r--r--mixlib/mix_vm_dump.h13
-rw-r--r--mixutils/mixvm_command.c945
8 files changed, 1343 insertions, 953 deletions
diff --git a/mixlib/Makefile.am b/mixlib/Makefile.am
index 25269bb..38c475a 100644
--- a/mixlib/Makefile.am
+++ b/mixlib/Makefile.am
@@ -27,5 +27,7 @@ libmix_a_SOURCES = mix.h mix.c \
mix_device.h mix_device.c \
mix_eval.h mix_eval.c xmix_eval.h mix_eval_scanner.l \
mix_src_file.c mix_src_file.h \
- mix_vm_clock.c mix_vm_clock.h
+ mix_vm_clock.c mix_vm_clock.h \
+ mix_vm_command.c mix_vm_command.h
+
diff --git a/mixlib/mix_types.c b/mixlib/mix_types.c
index 06f926f..4baa4f0 100644
--- a/mixlib/mix_types.c
+++ b/mixlib/mix_types.c
@@ -1,7 +1,7 @@
/* -*-c-*- ------------------ mix_types.c :
* Implementation file for mix_types.h declarations.
* ------------------------------------------------------------------
- * Copyright (C) 2000 Free Software Foundation, Inc.
+ * Copyright (C) 2000, 2001 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -465,15 +465,15 @@ mix_word_shift_right_circular (mix_word_t A, mix_word_t X, gulong count,
/* Printable representation */
void
-mix_word_print (mix_word_t word, const char *message)
+mix_word_print_to_file (mix_word_t word, const char *message, FILE *f)
{
guint k;
- if ( message ) g_print ("%s ", message);
- g_print ("%s ", mix_word_sign (word) == 0 ? "+" : "-");
+ if ( message ) fprintf (f, "%s ", message);
+ fprintf (f, "%s ", mix_word_sign (word) == 0 ? "+" : "-");
for ( k = 1; k < 6; ++k ) {
- g_print ("%02d ", mix_word_get_byte (word,k));
+ fprintf (f, "%02d ", mix_word_get_byte (word,k));
}
- g_print ("(%010ld)", mix_word_magnitude (word));
+ fprintf (f, "(%010ld)", mix_word_magnitude (word));
}
/* Conversions between words and shorts */
diff --git a/mixlib/mix_types.h b/mixlib/mix_types.h
index d706de1..dae6ff8 100644
--- a/mixlib/mix_types.h
+++ b/mixlib/mix_types.h
@@ -2,7 +2,7 @@
* This file contains declarations for the basic types used in MIX:
* mix_byte_t, mix_char_t, mix_short_t and mix_word_t.
* ------------------------------------------------------------------
- * Copyright (C) 2000 Free Software Foundation, Inc.
+ * Copyright (C) 2000, 2001 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,6 +24,7 @@
#ifndef MIX_TYPES_H
#define MIX_TYPES_H
+#include <stdio.h>
#include <glib.h>
/* Initialisation function to be called before using the other
@@ -212,8 +213,11 @@ mix_word_store_field(mix_fspec_t f, mix_word_t from, mix_word_t to);
/* Printable representation */
-extern void
-mix_word_print(mix_word_t word, const char *message);
+#define mix_word_print(word,message) \
+ mix_word_print_to_file (word, message, stdout)
+
+extern void
+mix_word_print_to_file (mix_word_t word, const char *message, FILE *f);
/*----------------- mix_short_t ------------------------------------------*/
diff --git a/mixlib/mix_vm_command.c b/mixlib/mix_vm_command.c
new file mode 100644
index 0000000..49f7d1d
--- /dev/null
+++ b/mixlib/mix_vm_command.c
@@ -0,0 +1,1096 @@
+/* -*-c-*- -------------- mix_vm_command.c :
+ * Implementation of the functions declared in mix_vm_command.h
+ * ------------------------------------------------------------------
+ * Last change: Time-stamp: "01/02/26 03:29:19 jose"
+ * ------------------------------------------------------------------
+ * Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "mix_vm_command.h"
+#include "mix_vm.h"
+#include "mix_vm_dump.h"
+#include "mix_eval.h"
+
+/* hooks */
+typedef struct
+{
+ mix_vm_cmd_hook_t func;
+ gpointer data;
+} hook_;
+
+typedef struct
+{
+ mix_vm_cmd_global_hook_t func;
+ gpointer data;
+} global_hook_;
+
+struct mix_vm_cmd_dispatcher_t
+{
+ mix_vm_t *vm; /* the virtual machine */
+ FILE *out; /* message output file */
+ FILE *err; /* error output file */
+ mix_dump_context_t *dump; /* dump context for output */
+ mix_eval_t *eval; /* evaluator for w-expressions */
+ gboolean trace; /* tracing flag */
+ mix_time_t uptime; /* total running time */
+ mix_time_t laptime; /* current program running time */
+ hook_ pre_hooks[MIX_CMD_INVALID]; /* Pre-command hooks */
+ hook_ post_hooks[MIX_CMD_INVALID]; /* Post-command hooks */
+ global_hook_ global_pre; /* global pre-command hook */
+ global_hook_ global_post; /* global post-command hook */
+};
+
+/* command handlers */
+typedef int (*Function_)(mix_vm_cmd_dispatcher_t *, const gchar *);
+#define DEC_FUN(name) \
+ static int cmd_##name (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+
+DEC_FUN (help_);
+DEC_FUN (load_);
+DEC_FUN (run_);
+DEC_FUN (next_);
+DEC_FUN (pc_);
+DEC_FUN (psym_);
+DEC_FUN (preg_);
+DEC_FUN (pflags_);
+DEC_FUN (pall_);
+DEC_FUN (pmem_);
+DEC_FUN (sreg_);
+DEC_FUN (scmp_);
+DEC_FUN (sover_);
+DEC_FUN (smem_);
+DEC_FUN (ssym_);
+DEC_FUN (sbp_);
+DEC_FUN (sbpa_);
+DEC_FUN (cbp_);
+DEC_FUN (cbpa_);
+DEC_FUN (cabp_);
+DEC_FUN (weval_);
+DEC_FUN (w2d_);
+DEC_FUN (tron_);
+DEC_FUN (troff_);
+
+/* internal command info struct */
+typedef struct {
+ const char *name; /* User printable name of the function. */
+ Function_ func; /* Function to call to do the job. */
+ const char *doc; /* Documentation for this function. */
+ const char *usage; /* Usage */
+} command_;
+
+/* available commands (in the same order as the type enum) */
+
+command_ commands_[] = {
+ { "help", cmd_help_, N_("Display this text"), "help [COMMAND]"},
+ { "load", cmd_load_, N_("Load a MIX code file"), "load FILENAME"},
+ { "run", cmd_run_, N_("Run loaded or given MIX code file"),
+ "run [FILENAME]"},
+ { "next", cmd_next_, N_("Execute next instruction(s)"),
+ "next [NO_OF_INS]"},
+ { "pc", cmd_pc_, N_("Print program counter value"), "pc" },
+ { "psym", cmd_psym_, N_("Print symbol value"), "psym [SYMBOLNAME]"},
+ { "preg", cmd_preg_, N_("Print register value"),
+ "preg [A | X | J | I[1-6]]"},
+ { "pflags", cmd_pflags_, N_("Print comparison and overflow flags"),
+ "pflags"},
+ { "pall", cmd_pall_, N_("Print all registers and flags"), "pall"},
+ { "pmem", cmd_pmem_, N_("Print memory contents in address range"),
+ "pmem FROM[-TO]"},
+ { "sreg", cmd_sreg_, N_("Set register value"),
+ "preg A | X | J | I[1-6] VALUE"},
+ { "scmp", cmd_scmp_, N_("Set comparison flag value"), "scmp L | E | G"},
+ { "sover", cmd_sover_, N_("Set overflow flag value"), "sover T | F" },
+ { "smem", cmd_smem_, N_("Set memory contents in given address"),
+ "smem ADDRESS VALUE"},
+ { "ssym", cmd_ssym_, N_("Set a symbol\'s value"), "ssym SYMBOL WEXPR"},
+ { "sbp", cmd_sbp_, N_("Set break point at given line"), "sbp LINENO"},
+ { "cbp", cmd_cbp_, N_("Clear break point at given line"), "cbp LINENO"},
+ { "sbpa", cmd_sbpa_, N_("Set break point at given address"),
+ "sbpa ADDRESS"},
+ { "cbpa", cmd_cbpa_, N_("Clear break point at given address"),
+ "cbpa ADDRESS"},
+ { "cabp", cmd_cabp_, N_("Clear all breakpoints"), "cabp"},
+ { "weval", cmd_weval_, N_("Evaluate a given W-expression"), "weval WEXPR"},
+ { "w2d", cmd_w2d_, N_("Convert a MIX word to its decimal value"),
+ "w2d WORD"},
+ { "tron", cmd_tron_, N_("Turn on instruction tracing."), "tron"},
+ { "troff", cmd_troff_, N_("Turn off instruction tracing."), "troff"},
+ { NULL, NULL, NULL, NULL},
+};
+
+
+/* external interface */
+
+/* conversion from/to commands to strings */
+const gchar *
+mix_vm_command_to_string (mix_vm_command_t cmd)
+{
+ if (cmd < MIX_CMD_INVALID) return commands_[cmd].name;
+ else return NULL;
+}
+
+mix_vm_command_t
+mix_vm_command_from_string (const gchar *name)
+{
+ /* inefficient linear search, i know */
+ gint cmd = 0;
+ while (cmd < MIX_CMD_INVALID && strcmp (name, commands_[cmd].name))
+ ++cmd;
+ return cmd;
+}
+
+/* get help string about a command */
+const gchar *
+mix_vm_command_help (mix_vm_command_t cmd)
+{
+ if (cmd < MIX_CMD_INVALID) return commands_[cmd].doc;
+ else return NULL;
+}
+
+const gchar *
+mix_vm_command_usage (mix_vm_command_t cmd)
+{
+ if (cmd < MIX_CMD_INVALID) return commands_[cmd].usage;
+ else return NULL;
+}
+
+/* create a new command dispatcher */
+mix_vm_cmd_dispatcher_t *
+mix_vm_cmd_dispatcher_new (FILE *out_fd, /* output messages file */
+ FILE *err_fd /* error messages file */)
+{
+ mix_vm_cmd_dispatcher_t *result = NULL;
+ int k;
+
+ g_return_val_if_fail (out_fd && err_fd, NULL);
+
+ result = g_new (mix_vm_cmd_dispatcher_t, 1);
+ result->out = out_fd;
+ result->err = err_fd;
+ result->uptime = result->laptime = 0;
+ result->trace = FALSE;
+ result->eval = mix_eval_new ();
+ result->dump = mix_dump_context_new (out_fd,
+ MIX_SHORT_ZERO, MIX_SHORT_ZERO,
+ MIX_DUMP_ALL);
+ result->vm = mix_vm_new ();
+ result->global_pre.func = result->global_post.func = NULL;
+ result->global_pre.data = result->global_post.data = NULL;
+ for (k =0; k < MIX_CMD_INVALID; ++k)
+ {
+ result->pre_hooks[k].func = result->post_hooks[k].func = NULL;
+ result->pre_hooks[k].data = result->post_hooks[k].data = NULL;
+ }
+
+ return result;
+}
+
+/* delete (does not close the fds in the constructor) */
+extern void
+mix_vm_cmd_dispatcher_delete (mix_vm_cmd_dispatcher_t *dis)
+{
+ g_return_if_fail (dis != NULL);
+ mix_eval_delete (dis->eval);
+ mix_dump_context_delete (dis->dump);
+ mix_vm_delete (dis->vm);
+ g_free (dis);
+}
+
+/* install hooks */
+void
+mix_vm_cmd_dispatcher_pre_hook (mix_vm_cmd_dispatcher_t *dis,
+ mix_vm_command_t cmd,
+ mix_vm_cmd_hook_t hook, gpointer data)
+{
+ g_return_if_fail (dis != NULL);
+ g_return_if_fail (cmd < MIX_CMD_INVALID);
+ dis->pre_hooks[cmd].func = hook;
+ dis->pre_hooks[cmd].data = data;
+}
+
+void
+mix_vm_cmd_dispatcher_post_hook (mix_vm_cmd_dispatcher_t *dis,
+ mix_vm_command_t cmd,
+ mix_vm_cmd_hook_t hook, gpointer data)
+{
+ g_return_if_fail (dis != NULL);
+ g_return_if_fail (cmd < MIX_CMD_INVALID);
+ dis->post_hooks[cmd].func = hook;
+ dis->post_hooks[cmd].data = data;
+}
+
+void
+mix_vm_cmd_dispatcher_global_pre_hook (mix_vm_cmd_dispatcher_t *dis,
+ mix_vm_cmd_global_hook_t hook,
+ gpointer data)
+{
+ g_return_if_fail (dis != NULL);
+ dis->global_pre.func = hook;
+ dis->global_pre.data = data;
+}
+
+void
+mix_vm_cmd_dispatcher_global_post_hook (mix_vm_cmd_dispatcher_t *dis,
+ mix_vm_cmd_global_hook_t hook,
+ gpointer data)
+{
+ g_return_if_fail (dis != NULL);
+ dis->global_post.func = hook;
+ dis->global_post.data = data;
+}
+
+/* dispatch a command */
+gboolean /* TRUE if success, FALSE otherwise */
+mix_vm_cmd_dispatcher_dispatch (mix_vm_cmd_dispatcher_t *dis,
+ mix_vm_command_t cmd, const gchar *arg)
+{
+ gboolean result = FALSE;
+ g_return_val_if_fail (dis != NULL, FALSE);
+
+ if (dis->global_pre.func)
+ (dis->global_pre.func)(dis, cmd, arg, dis->global_pre.data);
+
+ if (cmd < MIX_CMD_INVALID)
+ {
+ if (dis->pre_hooks[cmd].func)
+ (dis->pre_hooks[cmd].func)(dis, arg, dis->pre_hooks[cmd].data);
+ result = (commands_[cmd].func)(dis, arg);
+ if (dis->post_hooks[cmd].func)
+ (dis->post_hooks[cmd].func)(dis, arg, dis->post_hooks[cmd].data);
+ }
+ else
+ {
+ fprintf (dis->err, "Unknown command. Try: help");
+ }
+
+ if (dis->global_post.func)
+ (dis->global_post.func)(dis, cmd, arg, dis->global_post.data);
+
+ fflush (dis->out);
+ fflush (dis->err);
+ return result;
+}
+
+/* dispatch a command in text format */
+gboolean
+mix_vm_cmd_dispatcher_dispatch_text (mix_vm_cmd_dispatcher_t *dis,
+ const gchar *text)
+{
+ gchar *cp, *arg = "";
+ int k = 0;
+ gboolean result;
+
+ g_return_val_if_fail (dis != NULL, FALSE);
+ g_return_val_if_fail (text != NULL, FALSE);
+
+ cp = g_strdup (text);
+ while (cp[k] && !isspace (cp[k])) ++k;
+ if (cp[k])
+ {
+ cp[k] = '\0'; ++k;
+ while (cp[k] && isspace (cp[k])) ++k;
+ arg = cp + k;
+ }
+
+ result = mix_vm_cmd_dispatcher_dispatch (dis,
+ mix_vm_command_from_string (cp),
+ arg);
+ g_free (cp);
+ return result;
+}
+
+/* get the mix vm */
+const mix_vm_t *
+mix_vm_cmd_dispatcher_get_vm (const mix_vm_cmd_dispatcher_t *dis)
+{
+ g_return_val_if_fail (dis != NULL, NULL);
+ return dis->vm;
+}
+
+
+/* trace current instruction */
+static void
+trace_ (mix_vm_cmd_dispatcher_t *dis)
+{
+ enum {BUFFER_LEN = 128};
+ static gchar STRINS[BUFFER_LEN];
+
+ const mix_src_file_t *file = mix_vm_get_src_file (dis->vm);
+ const gchar *line = "\n";
+ mix_address_t loc = mix_vm_get_prog_count (dis->vm);
+ mix_word_t ins = mix_vm_get_addr_contents (dis->vm, loc);
+ mix_ins_t fins;
+ mix_word_to_ins_uncheck (ins, fins);
+ mix_ins_to_string_in_buffer (&fins, STRINS, BUFFER_LEN);
+
+ if (file != NULL)
+ {
+ gulong b = mix_vm_get_break_lineno (dis->vm);
+ if (b > 0) line = mix_src_file_get_line (file, b);
+ }
+
+ fprintf (dis->out, "%d: [%s]\t%s", (gint)loc, STRINS, line);
+}
+
+/* run a program tracing executed instructions */
+static int
+run_and_trace_ (mix_vm_cmd_dispatcher_t *dis)
+{
+ int k = MIX_VM_OK;
+ if (!dis->trace)
+ return mix_vm_run (dis->vm);
+ else while (k == MIX_VM_OK)
+ {
+ trace_ (dis);
+ k = mix_vm_exec_next (dis->vm);
+ }
+ return k;
+}
+
+/* print time statistics */
+static void
+print_time_ (mix_vm_cmd_dispatcher_t *dis)
+{
+ mix_time_t lapse = mix_vm_get_uptime(dis->vm) - dis->uptime;
+ dis->uptime += lapse;
+ dis->laptime += lapse;
+ fprintf( dis->out,
+ _("Elapsed time: %ld /Total program time: %ld (Total uptime: %ld)\n"),
+ lapse, dis->laptime, dis->uptime);
+}
+
+
+/* commands */
+
+static int
+cmd_help_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ static const int NO_OF_COLS = 6;
+
+ int i;
+ int printed = 0;
+
+ for (i = 0; commands_[i].name; i++)
+ {
+ if (!*arg || (strcmp (arg, commands_[i].name) == 0))
+ {
+ fprintf (dis->out ,_("%s\t\t%s. Usage: %s\n"), commands_[i].name,
+ _(commands_[i].doc), commands_[i].usage);
+ printed++;
+ }
+ }
+
+ if (!printed)
+ {
+ fprintf (dis->out,
+ _("No commands match `%s'. Possibilities are:\n"), arg);
+
+ for (i = 0; commands_[i].name; i++)
+ {
+ if (printed == NO_OF_COLS)
+ {
+ printed = 0;
+ fprintf (dis->out, "\n");
+ }
+
+ fprintf (dis->out, "%s\t", commands_[i].name);
+ printed++;
+ }
+
+ if (printed)
+ fprintf (dis->out, "\n");
+ }
+ return TRUE;
+}
+
+static int
+cmd_load_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ errno = 0;
+ if (arg == NULL || *arg == '\0')
+ {
+ fputs (_("Missing file name\n"), dis->err);
+ return TRUE;
+ }
+ mix_eval_remove_symbols_from_table (dis->eval,
+ mix_vm_get_symbol_table (dis->vm));
+ if (!mix_vm_load_file (dis->vm, arg) )
+ {
+ fprintf (dis->err, _("Cannot load %s: "), arg);
+ if ( errno == 0 )
+ fputs (_("Wrong file format\n"), dis->err);
+ else
+ perror (NULL);
+ return TRUE + 1;
+ }
+ mix_eval_set_symbols_from_table (dis->eval,
+ mix_vm_get_symbol_table (dis->vm));
+
+ fprintf (dis->out, _("Program loaded. Start address: %d\n"),
+ mix_vm_get_prog_count (dis->vm));
+
+ dis->laptime = 0;
+ return TRUE;
+}
+
+
+static int
+cmd_run_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ if (arg != NULL && *arg != '\0' && cmd_load_ (dis, arg) != TRUE)
+ return TRUE;
+ fputs (_("Running ...\n"), dis->out);
+
+ if (mix_vm_is_halted (dis->vm))
+ {
+ mix_vm_reset_program (dis->vm);
+ dis->laptime = 0;
+ }
+
+ switch (run_and_trace_ (dis))
+ {
+ case MIX_VM_HALT:
+ fputs (_("... done\n"), dis->out);
+ break;
+ case MIX_VM_BREAK:
+ {
+ gulong line = mix_vm_get_break_lineno (dis->vm);
+ if (line != 0)
+ fprintf (dis->out,
+ _("... stopped: breakpoint at line %ld (address %d)\n"),
+ line, mix_vm_get_prog_count (dis->vm));
+ else
+ fprintf (dis->out, _("... stopped: breakpoint at address %d\n"),
+ mix_vm_get_prog_count (dis->vm));
+ }
+ break;
+ case MIX_VM_ERROR:
+ fputs (_("... error executing loaded file"), dis->err);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ print_time_ (dis);
+
+ return TRUE;
+}
+
+static int
+cmd_next_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ int ins_no = 1;
+ int k;
+
+ if ( strlen (arg) != 0 )
+ {
+ int k = 0;
+ while (isdigit (arg[k]))
+ k++;
+ if (arg[k] != '\0')
+ {
+ fprintf (dis->err, _("Invalid argument: %s\n"), arg);
+ return cmd_help_ (dis, "next");
+ }
+ ins_no = atoi (arg);
+ }
+
+ if (mix_vm_is_halted (dis->vm))
+ {
+ mix_vm_reset_program (dis->vm);
+ dis->laptime = 0;
+ }
+
+ while ( ins_no-- > 0 )
+ {
+ if (dis->trace) trace_ (dis);
+ k = mix_vm_exec_next (dis->vm);
+ if (k == MIX_VM_HALT)
+ {
+ fprintf (dis->err, _("End of program reached at address %d\n"),
+ mix_vm_get_prog_count (dis->vm));
+ break;
+ }
+ else if (k == MIX_VM_ERROR)
+ {
+ fprintf (dis->err, _("Error at address %d\n"),
+ mix_vm_get_prog_count (dis->vm));
+ break;
+ }
+ }
+ print_time_ (dis);
+
+ return TRUE;
+}
+
+static int
+cmd_pc_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ fprintf (dis->out, "Current address: %d\n", mix_vm_get_prog_count (dis->vm));
+ return TRUE;
+}
+
+static int
+cmd_psym_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ const mix_symbol_table_t *table = mix_eval_symbol_table (dis->eval);
+ if ( table == NULL )
+ fputs (_("Symbol table not available\n"), dis->err);
+ else if (arg != NULL && *arg != '\0')
+ {
+ if ( mix_symbol_table_is_defined (table, arg) )
+ {
+ mix_word_print (mix_symbol_table_value (table, arg), NULL);
+ putc ('\n', dis->out);
+ }
+ else
+ fprintf (dis->out, _("%s: symbol not defined\n"), arg);
+ }
+ else
+ mix_symbol_table_print (table, MIX_SYM_ROWS, stdout, TRUE);
+
+ return TRUE;
+}
+
+static int
+cmd_preg_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ mix_dump_context_set_opt (dis->dump, MIX_DUMP_NONE);
+ if ( strlen (arg) == 0 )
+ mix_dump_context_add_opt (dis->dump, MIX_DUMP_rALL);
+ else switch (*arg)
+ {
+ case 'A':
+ mix_dump_context_add_opt (dis->dump, MIX_DUMP_rA);
+ break;
+ case 'X':
+ mix_dump_context_add_opt (dis->dump, MIX_DUMP_rX);
+ break;
+ case 'J':
+ mix_dump_context_add_opt (dis->dump, MIX_DUMP_rJ);
+ break;
+ case 'I':
+ {
+ if ( strlen (arg) == 1 )
+ mix_dump_context_add_opt (dis->dump, MIX_DUMP_rIa);
+ else
+ {
+ static gint32 opt[] = { MIX_DUMP_rI1, MIX_DUMP_rI2,
+ MIX_DUMP_rI3, MIX_DUMP_rI4,
+ MIX_DUMP_rI5, MIX_DUMP_rI6
+ };
+ int i = arg[1] - '1';
+ if ( i < 0 || i > 5 )
+ {
+ fprintf (dis->err, _("Invalid I index: %d"), i);
+ return TRUE;
+ }
+ mix_dump_context_add_opt (dis->dump, opt[i]);
+ }
+ }
+ break;
+ default:
+ fprintf (dis->err, _("Invalid argument: %s\n"), arg);
+ return TRUE;
+ }
+ mix_vm_dump (dis->vm, dis->dump);
+ return TRUE;
+}
+
+static int
+cmd_pflags_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ mix_dump_context_set_opt (dis->dump, MIX_DUMP_CMP | MIX_DUMP_OVER);
+ mix_vm_dump (dis->vm, dis->dump);
+ return TRUE;
+}
+
+static int
+cmd_pall_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ mix_dump_context_set_opt (dis->dump, MIX_DUMP_ALL_NOMEM);
+ mix_vm_dump (dis->vm, dis->dump);
+ return TRUE;
+}
+
+static int
+cmd_pmem_ (mix_vm_cmd_dispatcher_t *dis, const gchar *carg)
+{
+ glong begin = MIX_SHORT_ZERO, end = MIX_SHORT_ZERO;
+ int i = 0;
+ gboolean error = FALSE;
+ gchar *arg = NULL;
+
+ if ( strlen (carg) == 0 )
+ {
+ fputs (_("Missing memory address\n"), dis->err);
+ return TRUE;
+ }
+ arg = g_strdup (carg);
+ while (isdigit (arg[i]))
+ i++;
+ while (isspace (arg[i]))
+ i++;
+ if (arg[i] == '\0')
+ begin = end = atol (arg);
+ else if (arg[i] == '-')
+ {
+ arg[i++] = '\0';
+ begin = atol (arg);
+ arg = arg + i;
+ i = 0;
+ while (isdigit (arg[i]))
+ i++;
+ while (isspace (arg[i]))
+ i++;
+ if (arg[i] != '\0')
+ error = TRUE;
+ else
+ end = atol (arg);
+ }
+ else
+ error = TRUE;
+
+ if (error)
+ {
+ fprintf (dis->err, _("Invalid argument: %s\n"), arg);
+ cmd_help_ (dis, "pmem");
+ }
+ else if ( end < begin || end > MIX_VM_CELL_NO - 1 )
+ {
+ fprintf (dis->err, _("Invalid range: %ld-%ld\n"), begin, end);
+ }
+ else
+ {
+ mix_dump_context_set_opt (dis->dump, MIX_DUMP_CELLS);
+ mix_dump_context_range (dis->dump, mix_short_new (begin),
+ mix_short_new (end + 1));
+ mix_vm_dump (dis->vm, dis->dump);
+ }
+ g_free (arg);
+ return TRUE;
+}
+
+static int
+cmd_sreg_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ int i = 0;
+ char reg = arg[0];
+ gboolean ok = TRUE;
+ long value;
+
+ i = (reg == 'I') ? 2 : 1;
+ ok = strlen (arg) > 2 && isspace (arg[i]);
+ if (ok)
+ {
+ while (isspace (arg[i])) i++;
+ ok = isdigit (arg[i]) || arg[i] == '+' || arg[i] == '-';
+ if (ok)
+ {
+ value = atol (arg + i);
+ if (arg[i] == '+' || arg[i] == '-') i++;
+ while (isdigit (arg[i])) i++;
+ ok = (arg[i] == '\0');
+ if (ok)
+ switch (reg)
+ {
+ case 'A':
+ mix_vm_set_rA (dis->vm, mix_word_new (value));
+ break;
+ case 'X':
+ mix_vm_set_rX (dis->vm, mix_word_new (value));
+ break;
+ case 'J':
+ if ( value >= 0 )
+ mix_vm_set_rJ (dis->vm, mix_short_new (value));
+ else
+ ok = FALSE;
+ break;
+ case 'I':
+ {
+ guint k = arg[1] - '0';
+ if ( k < 7 )
+ mix_vm_set_rI (dis->vm, k, mix_short_new (value));
+ else
+ ok = FALSE;
+ }
+ break;
+ default:
+ ok = FALSE;
+ }
+ }
+ }
+ if (!ok)
+ {
+ fprintf (dis->err, _("Invalid argument: %s\n"), arg);
+ cmd_help_ (dis, "sreg");
+ }
+
+ return TRUE;
+}
+
+static int
+cmd_scmp_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ gboolean ok = (strlen (arg) == 1);
+ if (ok) switch (arg[0])
+ {
+ case 'L':
+ mix_vm_set_cmpflag (dis->vm, mix_LESS);
+ break;
+ case 'E':
+ mix_vm_set_cmpflag (dis->vm, mix_EQ);
+ break;
+ case 'G':
+ mix_vm_set_cmpflag (dis->vm, mix_GREAT);
+ break;
+ default:
+ ok = FALSE;
+ }
+ if (!ok)
+ {
+ fprintf (dis->err, _("Invalid argument: %s\n"), arg);
+ cmd_help_ (dis, "scmp");
+ }
+
+ return TRUE;
+}
+
+static int
+cmd_sover_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ gboolean ok = (strlen (arg) == 1);
+ if (ok) switch (arg[0])
+ {
+ case 'T':
+ mix_vm_set_overflow (dis->vm, TRUE);
+ break;
+ case 'F':
+ mix_vm_set_overflow (dis->vm, FALSE);
+ break;
+ default:
+ ok = FALSE;
+ }
+ if (!ok)
+ {
+ fprintf (dis->err, _("Invalid argument: %s\n"), arg);
+ cmd_help_ (dis, "sover");
+ }
+
+ return TRUE;
+}
+
+static int
+cmd_smem_ (mix_vm_cmd_dispatcher_t *dis, const gchar *carg)
+{
+ gboolean ok = (strlen (carg) > 2 && isdigit (carg[0]));
+ gulong addr;
+ glong value;
+ int k = 0;
+ gchar *arg = NULL;
+
+ if (ok)
+ {
+ arg = g_strdup (carg);
+ while (isdigit (arg[k])) k++;
+ ok = isspace (arg[k]);
+ if (ok)
+ {
+ arg[k++] = '\0';
+ addr = atol (arg);
+ ok = addr < MIX_VM_CELL_NO;
+ }
+ if (ok)
+ {
+ while (isspace (arg[k])) k++;
+ value = atol (arg + k);
+ if ( arg[k] == '+' || arg[k] == '-' ) k++;
+ while (isdigit (arg[k])) k++;
+ ok = arg[k] == '\0';
+ }
+ }
+
+ if (ok)
+ mix_vm_set_addr_contents (dis->vm, mix_short_new (addr),
+ mix_word_new (value));
+ else
+ {
+ fprintf (dis->err, _("Invalid argument: %s\n"), arg);
+ cmd_help_ (dis, "smem");
+ }
+ g_free (arg);
+
+ return TRUE;
+}
+
+static int
+cmd_ssym_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ if (arg == NULL || strlen(arg) == 0)
+ {
+ fprintf (dis->err, _("Missing arguments\n"));
+ return cmd_help_ (dis, "ssym");
+ }
+ else
+ {
+ gchar *a = g_strdup (arg);
+ gchar *s = strtok (a, " \t");
+ gchar *w = strtok (NULL, " \t");
+ if (w != NULL && strtok (NULL, " \t") == NULL)
+ {
+ cmd_weval_ (dis, w);
+ if (mix_eval_last_error (dis->eval) == MIX_EVAL_OK)
+ mix_eval_set_symbol (dis->eval, s, mix_eval_value (dis->eval));
+ }
+ else
+ {
+ fprintf (dis->err, _("Wrong argument number\n"));
+ cmd_help_ (dis, "ssym");
+ }
+ g_free (a);
+ return TRUE;
+ }
+}
+
+static int
+cmd_sbp_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ glong lineno;
+ glong k = 0;
+ while (isdigit (arg[k])) k++;
+ if (arg[k] != '\0')
+ {
+ fprintf (dis->err, _("Invalid argument: %s\n"), arg);
+ return cmd_help_ (dis, "sbp");
+ }
+ lineno = atol (arg);
+ switch (k = mix_vm_set_breakpoint (dis->vm, lineno))
+ {
+ case MIX_VM_BP_INV_LINE:
+ fprintf (dis->err, _("Line number %ld too high\n"), lineno);
+ break;
+ case MIX_VM_BP_ERROR:
+ fputs (_("Could not set breakpoint. Internal error\n"), dis->err);
+ break;
+ case MIX_VM_BP_NDEBUG:
+ fputs (_("Could not set breakpoint. No debug info available\n"),
+ dis->err);
+ break;
+ default:
+ fprintf (dis->err, _("Breakpoint set at line %ld\n"), k);
+ break;
+ }
+ return TRUE;
+}
+
+static int
+cmd_sbpa_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ glong address;
+ glong k = 0;
+ while (isdigit (arg[k])) k++;
+ if (arg[k] != '\0')
+ {
+ fprintf (dis->err, _("Invalid argument: %s\n"), arg);
+ return cmd_help_ (dis, "sbpa");
+ }
+ address = atol (arg);
+ switch (mix_vm_set_breakpoint_address (dis->vm, address))
+ {
+ case MIX_VM_BP_INV_ADDRESS:
+ fprintf (dis->err, _("Invalid address %ld\n"), address);
+ break;
+ case MIX_VM_BP_ERROR:
+ fputs (_("Could not set breakpoint. Internal error\n"), dis->err);
+ break;
+ default:
+ fprintf (dis->err, _("Breakpoint set at address %ld\n"), address);
+ break;
+ }
+ return TRUE;
+}
+
+static int
+cmd_cbp_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ glong lineno;
+ int k = 0;
+ while (isdigit (arg[k])) k++;
+ if (arg[k] != '\0')
+ {
+ fprintf (dis->err, _("Invalid argument: %s\n"), arg);
+ return cmd_help_ (dis, "cbp");
+ }
+ lineno = atol (arg);
+ switch (mix_vm_clear_breakpoint (dis->vm, lineno))
+ {
+ case MIX_VM_BP_INV_LINE:
+ fprintf (dis->err, _("No breakpoint set at line %ld\n"), lineno);
+ break;
+ case MIX_VM_BP_ERROR:
+ fputs (_("Could not set breakpoint. Internal error\n"), dis->err);
+ break;
+ case MIX_VM_BP_NDEBUG:
+ fputs (_("No debug info available\n"), dis->err);
+ break;
+ case MIX_VM_BP_OK:
+ fprintf (dis->err, _("Breakpoint cleared at line %ld\n"), lineno);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ return TRUE;
+}
+
+static int
+cmd_cbpa_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ glong address;
+ glong k = 0;
+ while (isdigit (arg[k])) k++;
+ if (arg[k] != '\0')
+ {
+ fprintf (dis->err, _("Invalid argument: %s\n"), arg);
+ return cmd_help_ (dis, "cbpa");
+ }
+ address = atol (arg);
+ switch (mix_vm_clear_breakpoint_address (dis->vm, address))
+ {
+ case MIX_VM_BP_INV_ADDRESS:
+ fprintf (dis->err, _("Invalid address %ld\n"), address);
+ break;
+ case MIX_VM_BP_ERROR:
+ fputs (_("Could not clear breakpoint. Internal error\n"), dis->err);
+ break;
+ default:
+ fprintf (dis->err, _("Breakpoint cleared at address %ld\n"), address);
+ break;
+ }
+ return TRUE;
+}
+
+
+static int
+cmd_cabp_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ if (strlen (arg) != 0)
+ {
+ fprintf (dis->err, _("Invalid argument: %s\n"), arg);
+ return cmd_help_ (dis, "cabp");
+ }
+ mix_vm_clear_all_breakpoints (dis->vm);
+ return TRUE;
+}
+
+static int
+cmd_weval_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ if ( strlen (arg) == 0 )
+ return cmd_help_ (dis, "weval");
+
+ if (mix_eval_expression_with_loc (dis->eval, arg,
+ mix_vm_get_prog_count (dis->vm)) ==
+ MIX_EVAL_OK)
+ {
+ mix_word_print_to_file (mix_eval_value (dis->eval), NULL, dis->out);
+ putc ('\n', dis->out);
+ }
+ else
+ {
+ gint pos = mix_eval_last_error_pos (dis->eval);
+ gint k, len = strlen (arg);
+ g_assert(pos > -1 && pos <= len);
+ for (k = 0; k<pos; ++k) fputc (arg[k], dis->err);
+ fputc ('\n', dis->err);
+ for (k = 0; k<pos; ++k) fputc (' ', dis->err);
+ for (k = pos; k < len; ++k) fputc (arg[k], dis->err);
+ fprintf (dis->err, _("\nEvaluation error: %s\n"),
+ mix_eval_last_error_string (dis->eval));
+ }
+
+ return TRUE;
+}
+
+static int
+cmd_w2d_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ if ( strlen (arg) == 0 )
+ return cmd_help_ (dis, "w2d");
+ else
+ {
+ gchar *cp = g_strdup (arg), *a = cp;
+ mix_byte_t bytes[5] = {0, 0, 0, 0, 0};
+ gchar *b;
+ guint k = 0;
+ gboolean is_n = (a[0] == '-'), success = TRUE;
+ if (a[0] == '+' || a[0] == '-') ++a;
+ b = strtok (a, " \t");
+ while (b != NULL && k < 5)
+ {
+ if (strlen (b) != 2 || !isdigit(b[0]) || !isdigit(b[1]))
+ {
+ fprintf (dis->err, _("Incorrect byte specification: %s\n"), b);
+ success = FALSE;
+ b = NULL;
+ }
+ else
+ {
+ bytes[k++] = mix_byte_new (atoi (b));
+ b = strtok (NULL, " \t");
+ }
+ }
+ if (success)
+ {
+ if (strtok (NULL, "\t") != NULL)
+ fprintf (dis->err, _("The expression %s does not fit in a word\n"),
+ arg);
+ else
+ {
+ mix_word_t w = mix_bytes_to_word (bytes, k);
+ fprintf (dis->out, "%s%ld\n", is_n? "-":"+",
+ mix_word_magnitude (w));
+ }
+ }
+ g_free (cp);
+ }
+
+ return TRUE;
+}
+
+static int
+cmd_tron_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ dis->trace = TRUE;
+ fprintf (dis->out, _("Instruction tracing has been turned ON.\n"));
+ return TRUE;
+}
+
+static int
+cmd_troff_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ dis->trace = FALSE;
+ fprintf (dis->out, _("Instruction tracing has been turned OFF.\n"));
+ return TRUE;
+}
diff --git a/mixlib/mix_vm_command.h b/mixlib/mix_vm_command.h
new file mode 100644
index 0000000..89a2c2b
--- /dev/null
+++ b/mixlib/mix_vm_command.h
@@ -0,0 +1,139 @@
+/* -*-c-*- ---------------- mix_vm_command.h :
+ * declarations for mix_vm_command_t, describing commands issued to a vm
+ * ------------------------------------------------------------------
+ * Last change: Time-stamp: <01/02/26 02:41:26 jose>
+ * ------------------------------------------------------------------
+ * Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifndef MIX_VM_COMMAND_H
+#define MIX_VM_COMMAND_H
+
+#include <stdio.h>
+#include "mix.h"
+#include "mix_vm.h"
+
+/* mix_vm_cmd_dispatcher encapsulates a virtual machine and helper
+ objects, providing a command driven interface with output to
+ provided files (in the posix sense).
+*/
+typedef struct mix_vm_cmd_dispatcher_t mix_vm_cmd_dispatcher_t;
+
+/* mix_vm_cmd_dispatcher understands the commands of this type */
+typedef enum {
+ MIX_CMD_HELP = 0, /* echo help message */
+ MIX_CMD_LOAD, /* load a mix program */
+ MIX_CMD_RUN, /* run a loaded program */
+ MIX_CMD_NEXT, /* run next instruction */
+ MIX_CMD_LOC, /* print location pointer */
+ MIX_CMD_PSYM, /* print symbol */
+ MIX_CMD_PREG, /* print registry */
+ MIX_CMD_PFLAGS, /* print comp and overf flags */
+ MIX_CMD_PALL, /* print all registers and flags */
+ MIX_CMD_PMEM, /* print memory cells */
+ MIX_CMD_SREG, /* set register value */
+ MIX_CMD_SCMP, /* set comparison flag value */
+ MIX_CMD_SOVER, /* set overflow toggle value */
+ MIX_CMD_SMEM, /* set memory cell value */
+ MIX_CMD_SSYM, /* set symbol value */
+ MIX_CMD_SBP, /* set breakpoint at lineno */
+ MIX_CMD_CBP, /* clear breakpoint at lineno */
+ MIX_CMD_SBPA, /* set breakpoint at address */
+ MIX_CMD_CBPA, /* clear breakpoint at address */
+ MIX_CMD_CABP, /* clear all breakpoints */
+ MIX_CMD_WEVAL, /* evaluate a w-expression */
+ MIX_CMD_W2D, /* print word in decimal notation */
+ MIX_CMD_TRON, /* enable instruction traces */
+ MIX_CMD_TROFF, /* disble instruction traces */
+ MIX_CMD_INVALID, /* invalid command identifier */
+} mix_vm_command_t;
+
+/* hook functions, to be invoked before and/or after command execution */
+typedef void (*mix_vm_cmd_hook_t)(mix_vm_cmd_dispatcher_t *dis,
+ const gchar *arg, gpointer data);
+
+/* global hook functions */
+typedef void (*mix_vm_cmd_global_hook_t)(mix_vm_cmd_dispatcher_t *dis,
+ mix_vm_command_t cmd,
+ const gchar *arg, gpointer data);
+
+/* conversion from/to commands to strings */
+extern const gchar *
+mix_vm_command_to_string (mix_vm_command_t cmd);
+
+extern mix_vm_command_t
+mix_vm_command_from_string (const gchar *name);
+
+/* get help string about a command */
+extern const gchar *
+mix_vm_command_help (mix_vm_command_t cmd);
+
+extern const gchar *
+mix_vm_command_usage (mix_vm_command_t cmd);
+
+
+/* create a new command dispatcher */
+extern mix_vm_cmd_dispatcher_t *
+mix_vm_cmd_dispatcher_new (FILE *out_fd, /* output messages file */
+ FILE *err_fd /* error messages file */);
+
+/* delete (does not close the fds in the constructor) */
+extern void
+mix_vm_cmd_dispatcher_delete (mix_vm_cmd_dispatcher_t *dis);
+
+/* dispatch a command */
+extern gboolean /* TRUE if success, FALSE otherwise */
+mix_vm_cmd_dispatcher_dispatch (mix_vm_cmd_dispatcher_t *dis,
+ mix_vm_command_t cmd, const gchar *arg);
+
+/* dispatch a command in text format */
+extern gboolean
+mix_vm_cmd_dispatcher_dispatch_text (mix_vm_cmd_dispatcher_t *dis,
+ const gchar *text);
+
+/* install hooks */
+extern void
+mix_vm_cmd_dispatcher_pre_hook (mix_vm_cmd_dispatcher_t *dis,
+ mix_vm_command_t cmd,
+ mix_vm_cmd_hook_t hook, gpointer data);
+
+extern void
+mix_vm_cmd_dispatcher_post_hook (mix_vm_cmd_dispatcher_t *dis,
+ mix_vm_command_t cmd,
+ mix_vm_cmd_hook_t hook, gpointer data);
+
+extern void
+mix_vm_cmd_dispatcher_global_pre_hook (mix_vm_cmd_dispatcher_t *dis,
+ mix_vm_cmd_global_hook_t hook,
+ gpointer data);
+
+extern void
+mix_vm_cmd_dispatcher_global_post_hook (mix_vm_cmd_dispatcher_t *dis,
+ mix_vm_cmd_global_hook_t hook,
+ gpointer data);
+
+
+
+/* get the mix vm */
+extern const mix_vm_t *
+mix_vm_cmd_dispatcher_get_vm (const mix_vm_cmd_dispatcher_t *dis);
+
+
+#endif /* MIX_VM_COMMAND_H */
+
diff --git a/mixlib/mix_vm_dump.c b/mixlib/mix_vm_dump.c
index 2d773fc..91953fd 100644
--- a/mixlib/mix_vm_dump.c
+++ b/mixlib/mix_vm_dump.c
@@ -26,15 +26,12 @@
/* Create/destroy a dump context */
mix_dump_context_t *
-mix_dump_context_new(gint fd, mix_address_t begin, mix_address_t end,
+mix_dump_context_new(FILE *fd, mix_address_t begin, mix_address_t end,
guint32 options)
{
mix_dump_context_t *result = NULL;
- GIOChannel *channel = NULL;
- if ( fd == MIX_DUMP_DEF_CHANNEL ) fd = STDIN_FILENO;
- channel = g_io_channel_unix_new (fd);
- g_return_val_if_fail (channel != NULL, NULL);
+ g_return_val_if_fail (fd != NULL, NULL);
if ( begin > end ) begin = end;
if ( end >= MEM_CELLS_NO_ ) end = MEM_CELLS_NO_;
@@ -43,7 +40,7 @@ mix_dump_context_new(gint fd, mix_address_t begin, mix_address_t end,
result->options = options;
result->begin = begin;
result->end = end;
- result->channel = channel;
+ result->channel = fd;
return result;
}
@@ -52,20 +49,9 @@ void
mix_dump_context_delete (mix_dump_context_t *dc)
{
g_return_if_fail (dc != NULL);
- g_io_channel_close (dc->channel);
g_free (dc);
}
-gboolean /* TRUE if success */
-mix_dump_context_set_channel (mix_dump_context_t *dc, gint fd)
-{
- g_return_val_if_fail (dc != NULL, FALSE);
- g_io_channel_close (dc->channel);
- dc->channel = g_io_channel_unix_new (fd == MIX_DUMP_DEF_CHANNEL?
- STDERR_FILENO : fd);
- return ( dc->channel != NULL );
-}
-
/* Use the dump context */
#define WORD_FMT_ "%s %02d %02d %02d %02d %02d (%010ld)"
#define SHORT_FMT_ "%s %02d %02d (%04d)"
@@ -80,55 +66,33 @@ mix_dump_context_set_channel (mix_dump_context_t *dc, gint fd)
#define SHORT_ARGS_(s) SHORT_SIGN_ (s), SHORT_BYTE_ (s,1), SHORT_BYTE_ (s,2), \
SHORT_ABS_ (s)
-static gboolean
-write_buffer_ (const gchar *buf, guint len, GIOChannel *io)
-{
- guint k, err;
-
- while ( len > 0 ) {
- err = g_io_channel_write (io, (gchar *) buf, len, &k);
- g_return_val_if_fail (err == G_IO_ERROR_NONE ||
- err == G_IO_ERROR_AGAIN, FALSE);
- len -= k;
- }
- return TRUE;
-}
-
-
-
void
mix_vm_dump (const mix_vm_t *vm, const mix_dump_context_t *dc)
{
- static const guint BUF_LEN = 40;
- gchar buf[BUF_LEN];
guint j, i;
+ FILE *f;
g_return_if_fail (vm != NULL);
g_return_if_fail (dc != NULL);
-
+ f = dc->channel;
+
if ( (dc->options & MIX_DUMP_rA) == MIX_DUMP_rA )
{
mix_word_t rA = get_rA_ (vm);
- guint k = g_snprintf (buf, BUF_LEN, "rA: " WORD_FMT_ "\n",
- WORD_ARGS_ (rA));
- g_return_if_fail (write_buffer_ (buf, k, dc->channel));
+ fprintf (f, "rA: " WORD_FMT_ "\n", WORD_ARGS_ (rA));
}
if ( (dc->options & MIX_DUMP_rX) == MIX_DUMP_rX )
{
mix_word_t rX = get_rX_ (vm);
- guint k = g_snprintf (buf, BUF_LEN, "rX: " WORD_FMT_ "\n",
- WORD_ARGS_ (rX));
- g_return_if_fail (write_buffer_ (buf, k, dc->channel));
+ fprintf (f, "rX: " WORD_FMT_ "\n", WORD_ARGS_ (rX));
}
if ( (dc->options & MIX_DUMP_rJ) == MIX_DUMP_rJ )
{
mix_short_t rJ = get_rJ_ (vm);
- guint k = g_snprintf (buf, BUF_LEN, "rJ: " SHORT_FMT_ "\n",
- SHORT_ARGS_ (rJ));
- g_return_if_fail (write_buffer_ (buf, k, dc->channel));
+ fprintf (f, "rJ: " SHORT_FMT_ "\n", SHORT_ARGS_ (rJ));
}
for (j = 0, i = 0; j < IREG_NO_; ++j)
@@ -136,28 +100,21 @@ mix_vm_dump (const mix_vm_t *vm, const mix_dump_context_t *dc)
if ( (dc->options & (MIX_DUMP_rI1<<j)) == (MIX_DUMP_rI1<<j) )
{
mix_short_t rI = mix_word_to_short_fast (get_rI_ (vm, j+1));
- guint k = g_snprintf (buf, BUF_LEN, "rI%d: " SHORT_FMT_ "\t",
- j+1, SHORT_ARGS_ (rI));
- g_return_if_fail (write_buffer_ (buf, k, dc->channel));
+ fprintf (f, "rI%d: " SHORT_FMT_ "\t", j+1, SHORT_ARGS_ (rI));
i++;
}
- if ( i%2 == 0 && i != 0 )
- g_return_if_fail (write_buffer_ ("\n", 1, dc->channel));
+ if ( i%2 == 0 && i != 0 ) fprintf (f, "\n");
}
- if ( i%2 == 1 )
- g_return_if_fail (write_buffer_ ("\n", 1, dc->channel));
+ if ( i%2 == 1 ) fprintf (f, "\n");
if ( (dc->options & MIX_DUMP_OVER) == MIX_DUMP_OVER )
{
- guint k = g_snprintf (buf, BUF_LEN, _("Overflow: %s\n"),
- get_over_ (vm)? "T":"F");
- g_return_if_fail (write_buffer_ (buf, k, dc->channel));
+ fprintf (f, _("Overflow: %s\n"), get_over_ (vm)? "T":"F");
}
if ( (dc->options & MIX_DUMP_CMP) == MIX_DUMP_CMP )
{
- guint k;
const gchar *val = "?";
switch (get_cmp_ (vm))
{
@@ -174,8 +131,7 @@ mix_vm_dump (const mix_vm_t *vm, const mix_dump_context_t *dc)
g_assert_not_reached ();
break;
}
- k = g_snprintf (buf, BUF_LEN, _("Cmp: %s\n"), val);
- g_return_if_fail (write_buffer_ (buf, k, dc->channel));
+ fprintf (f, _("Cmp: %s\n"), val);
}
if ( (dc->options & MIX_DUMP_CELLS) == MIX_DUMP_CELLS )
@@ -183,10 +139,9 @@ mix_vm_dump (const mix_vm_t *vm, const mix_dump_context_t *dc)
for (j = dc->begin; j < dc->end; ++j)
{
mix_word_t cell = get_cell_ (vm,j);
- guint k = g_snprintf (buf, BUF_LEN, "%04d: " WORD_FMT_ "\n", j,
- WORD_ARGS_ (cell));
- g_return_if_fail (write_buffer_ (buf, k, dc->channel));
+ fprintf (f, "%04d: " WORD_FMT_ "\n", j, WORD_ARGS_ (cell));
}
}
+ fflush (f);
}
diff --git a/mixlib/mix_vm_dump.h b/mixlib/mix_vm_dump.h
index 265a747..8c5e1bd 100644
--- a/mixlib/mix_vm_dump.h
+++ b/mixlib/mix_vm_dump.h
@@ -2,7 +2,7 @@
* This file declares types and functions for dumping the contents
* of a mix virtual machine.
* ------------------------------------------------------------------
-** Copyright (C) 2000 Free Software Foundation, Inc.
+** Copyright (C) 2000, 2001 Free Software Foundation, Inc.
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
@@ -24,6 +24,7 @@
#ifndef MIX_VM_DUMP_H
#define MIX_VM_DUMP_H
+#include <stdio.h>
#include "mix_vm.h"
/* Dump context: a structure defining the properties of dumping */
@@ -36,7 +37,7 @@ struct mix_dump_context_t
mix_address_t begin;
mix_address_t end;
/* IO channel for dumping */
- GIOChannel *channel;
+ FILE *channel;
};
/* Flags for activating dumps */
@@ -60,12 +61,12 @@ struct mix_dump_context_t
#define MIX_DUMP_ALL_NOMEM MIX_DUMP_rALL|MIX_DUMP_OVER|MIX_DUMP_CMP
/* Default output channel (stdout) */
-#define MIX_DUMP_DEF_CHANNEL (-1)
+#define MIX_DUMP_DEF_CHANNEL (stdout)
/* Create/destroy a dump context */
extern mix_dump_context_t *
-mix_dump_context_new(gint fd, mix_address_t begin, mix_address_t end,
- guint32 options);
+mix_dump_context_new (FILE *fd, mix_address_t begin, mix_address_t end,
+ guint32 options);
extern void
mix_dump_context_delete(mix_dump_context_t *dc);
@@ -80,8 +81,6 @@ do { \
(dc)->end = last; \
} while (FALSE)
-extern gboolean /* TRUE if success */
-mix_dump_context_set_channel(mix_dump_context_t *dc, gint fd);
/* Use the dump context */
extern void
diff --git a/mixutils/mixvm_command.c b/mixutils/mixvm_command.c
index c585363..516bd68 100644
--- a/mixutils/mixvm_command.c
+++ b/mixutils/mixvm_command.c
@@ -24,7 +24,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
-#include <errno.h>
#include <readline/readline.h>
#include <readline/history.h>
@@ -32,6 +31,7 @@
#include <mixlib/mix_vm_dump.h>
#include <mixlib/mix_eval.h>
#include <mixlib/mix_src_file.h>
+#include <mixlib/mix_vm_command.h>
#include "mixvm_command.h"
/* The names of functions that actually do the manipulation. */
@@ -40,31 +40,8 @@ static int cmd_##name (char *arg)
DEC_FUN (help_);
DEC_FUN (shell_);
-DEC_FUN (load_);
-DEC_FUN (run_);
-DEC_FUN (next_);
-DEC_FUN (pc_);
-DEC_FUN (psym_);
-DEC_FUN (preg_);
-DEC_FUN (pflags_);
-DEC_FUN (pall_);
-DEC_FUN (pmem_);
-DEC_FUN (sreg_);
-DEC_FUN (scmp_);
-DEC_FUN (sover_);
-DEC_FUN (smem_);
-DEC_FUN (ssym_);
-DEC_FUN (sbp_);
-DEC_FUN (sbpa_);
-DEC_FUN (cbp_);
-DEC_FUN (cbpa_);
-DEC_FUN (cabp_);
DEC_FUN (compile_);
DEC_FUN (edit_);
-DEC_FUN (weval_);
-DEC_FUN (w2d_);
-DEC_FUN (tron_);
-DEC_FUN (troff_);
DEC_FUN (quit_);
/* A structure which contains information on the commands this program
@@ -78,47 +55,20 @@ typedef struct {
COMMAND commands[] = {
{ "help", cmd_help_, N_("Display this text"), "help [COMMAND]" },
- { "?", cmd_help_, N_("Synonym for `help'"), "? [COMMAND]" },
- { "!", cmd_shell_, N_("Execute shell command"), "! COMMAND" },
- { "load", cmd_load_, N_("Load a MIX code file"), "load FILENAME" },
- { "run", cmd_run_, N_("Run loaded or given MIX code file"),
- "run [FILENAME]" },
- { "next", cmd_next_, N_("Execute next instruction(s)"),
- "next [NO_OF_INS]"},
- { "pc", cmd_pc_, N_("Print program counter value"), "pc" },
- { "psym", cmd_psym_, N_("Print symbol value"), "psym [SYMBOLNAME]" },
- { "preg", cmd_preg_, N_("Print register value"),
- "preg [A | X | J | I[1-6]]" },
- { "pflags", cmd_pflags_, N_("Print comparison and overflow flags"),
- "pflags" },
- { "pall", cmd_pall_, N_("Print all registers and flags"), "pall" },
- { "pmem", cmd_pmem_, N_("Print memory contents in address range"),
- "pmem FROM[-TO]" },
- { "sreg", cmd_sreg_, N_("Set register value"),
- "preg A | X | J | I[1-6] VALUE" },
- { "scmp", cmd_scmp_, N_("Set comparison flag value"), "scmp L | E | G" },
- { "sover", cmd_sover_, N_("Set overflow flag value"), "sover T | F" },
- { "smem", cmd_smem_, N_("Set memory contents in given address"),
- "smem ADDRESS VALUE" },
- { "ssym", cmd_ssym_, N_("Set a symbol\'s value"), "ssym SYMBOL WEXPR" },
- { "sbp", cmd_sbp_, N_("Set break point at given line"), "sbp LINENO" },
- { "cbp", cmd_cbp_, N_("Clear break point at given line"), "cbp LINENO" },
- { "sbpa", cmd_sbpa_, N_("Set break point at given address"),
- "sbpa ADDRESS" },
- { "cbpa", cmd_cbpa_, N_("Clear break point at given address"),
- "cbpa ADDRESS" },
- { "cabp", cmd_cabp_, N_("Clear all breakpoints"), "cabp" },
+ { "shell", cmd_shell_, N_("Execute shell command"), "shell COMMAND" },
{ "compile", cmd_compile_, N_("Compile a source file"), "compile FILENAME"},
{ "edit", cmd_edit_, N_("Edit a source file"), "edit FILENAME"},
- { "weval", cmd_weval_, N_("Evaluate a given W-expres sion"), "weval WEXPR"},
- { "w2d", cmd_w2d_, N_("Convert a MIX word to its decimal value"),
- "w2d WORD" },
- { "tron", cmd_tron_, N_("Turn on instruction tracing."), "tron" },
- { "troff", cmd_troff_, N_("Turn off instruction tracing."), "troff" },
{ "quit", cmd_quit_, N_("Quit the program"), "quit" },
{ (char *)NULL, (Function *)NULL, (char *)NULL }
};
+#define LOCAL_COMANDS_NO_ ((sizeof (commands) / sizeof (commands[0])) - 1)
+#define MIX_COMMANDS_NO_ MIX_CMD_INVALID+1
+#define ALL_COMMANDS_NO_ LOCAL_COMANDS_NO_+MIX_COMMANDS_NO_
+
+static const char *mix_commands_[ALL_COMMANDS_NO_] = {NULL};
+
+
/* readline functions */
static char *
@@ -165,14 +115,13 @@ mixvm_cmd_generator_ (char *text, int state)
}
/* Return the next name which partially matches from the command list. */
- while ( (name = commands[list_index].name) != NULL)
+ while ((name = mix_commands_[list_index]) != NULL)
{
list_index++;
-
if (strncmp (name, text, len) == 0)
return (g_strdup (name));
}
-
+
/* If no names matched, then return NULL. */
return ((char *)NULL);
}
@@ -191,113 +140,31 @@ find_command_ (const char *name)
}
-/* the virtual machine and dump context */
-static mix_vm_t *vm_ = NULL;
-static mix_dump_context_t *dc_ = NULL;
-/* the w-expression evaluator */
-static mix_eval_t *eval_ = NULL;
-/* trace status */
-static gboolean is_tracing_ = FALSE;
-/* uptime */
-static mix_time_t uptime_ = 0;
-static mix_time_t prog_time_ = 0;
-/* emacs interface */
-static gboolean emacs_ = FALSE;
+/* mixvm dispatcher */
+static mix_vm_cmd_dispatcher_t *dis_ = NULL;
-
-/* auxiliar methods */
/* emacs interface */
static void
-emacs_output_ (void);
-
-/* trace current instruction */
-static void
-trace_ (void);
-
-/* run a program tracing executed instructions */
-static int
-run_and_trace_ (void);
-
-/* print time statistics */
-static void
-print_time_ (void);
-
-
-static void
-emacs_output_ (void)
+emacs_output_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg, gpointer data)
{
/* pek: probably bad that we snag the src w/every emacs_output_,
however when multiple files are supported then this will
have to be done each time (but the info will be snagged
from elsewhere...) */
- const mix_src_file_t *src = mix_vm_get_src_file (vm_);
+ const mix_vm_t *vm = mix_vm_cmd_dispatcher_get_vm (dis);
+ const mix_src_file_t *src = mix_vm_get_src_file (vm);
const gchar *path = mix_src_file_get_path (src);
- mix_address_t loc = mix_vm_get_prog_count (vm_);
- guint lineno = mix_vm_get_address_lineno (vm_, loc);
+ mix_address_t loc = mix_vm_get_prog_count (vm);
+ guint lineno = mix_vm_get_address_lineno (vm, loc);
printf ("\032\032mixvm:%s%s:%d\n", path, MIX_SRC_DEFEXT, lineno);
return;
}
-/* trace current instruction */
-static void
-trace_ (void)
-{
- enum {BUFFER_LEN = 128};
- static gchar STRINS[BUFFER_LEN];
-
- const mix_src_file_t *file = mix_vm_get_src_file (vm_);
- const gchar *line = "\n";
- mix_address_t loc = mix_vm_get_prog_count (vm_);
- mix_word_t ins = mix_vm_get_addr_contents (vm_, loc);
- mix_ins_t fins;
- mix_word_to_ins_uncheck (ins, fins);
- mix_ins_to_string_in_buffer (&fins, STRINS, BUFFER_LEN);
-
- if (file != NULL)
- {
- gulong b = mix_vm_get_break_lineno (vm_);
- if (b > 0) line = mix_src_file_get_line (file, b);
- }
-
- printf ("%d: [%s]\t%s", (gint)loc, STRINS, line);
-}
-
-/* run a program tracing executed instructions */
-static int
-run_and_trace_ (void)
-{
- int k = MIX_VM_OK;
- if (!is_tracing_)
- return mix_vm_run (vm_);
- else while (k == MIX_VM_OK)
- {
- trace_ ();
- k = mix_vm_exec_next (vm_);
- }
- return k;
-}
-
-/* print time statistics */
-static void
-print_time_ (void)
-{
- mix_time_t lapse = mix_vm_get_uptime(vm_) - uptime_;
- uptime_ += lapse;
- prog_time_ += lapse;
- printf(_("Elapsed time: %ld /Total program time: %ld (Total uptime: %ld)\n"),
- lapse, prog_time_, uptime_);
-}
-
-
-/* commands */
-
static int
cmd_help_ (char *arg)
{
- static const int NO_OF_COLS = 6;
-
int i;
int printed = 0;
@@ -310,625 +177,36 @@ cmd_help_ (char *arg)
printed++;
}
}
-
- if (!printed)
+
+ if (printed > 1) printf ("\n");
+
+ for (i = LOCAL_COMANDS_NO_ + 1 /* skip help cmd */; mix_commands_[i]; i++)
{
- printf (_("No commands match `%s'. Possibilities are:\n"), arg);
-
- for (i = 0; commands[i].name; i++)
+ if (!*arg || (strcmp (arg, mix_commands_[i]) == 0))
{
- if (printed == NO_OF_COLS)
- {
- printed = 0;
- printf ("\n");
- }
-
- printf ("%s\t", commands[i].name);
+ printf (_("%s\t\t%s. Usage: %s\n"), mix_commands_[i],
+ mix_vm_command_help (i - LOCAL_COMANDS_NO_),
+ mix_vm_command_usage (i - LOCAL_COMANDS_NO_));
printed++;
}
-
- if (printed)
- printf ("\n");
- }
- return TRUE;
-}
-
-static int
-cmd_load_ (char *arg)
-{
- errno = 0;
- if (arg == NULL || *arg == '\0')
- {
- fputs (_("Missing file name\n"), stderr);
- return TRUE;
- }
- mix_eval_remove_symbols_from_table (eval_,
- mix_vm_get_symbol_table (vm_));
- if (!mix_vm_load_file (vm_, arg) )
- {
- fprintf (stderr, _("Cannot load %s: "), arg);
- if ( errno == 0 )
- fputs (_("Wrong file format\n"), stderr);
- else
- perror (NULL);
- return TRUE + 1;
- }
- mix_eval_set_symbols_from_table (eval_,
- mix_vm_get_symbol_table (vm_));
-
- fprintf (stderr, _("Program loaded. Start address: %d\n"),
- mix_vm_get_prog_count (vm_));
-
- prog_time_ = 0;
-
- if (emacs_)
- {
- emacs_output_();
}
-
- return TRUE;
-}
-
-
-static int
-cmd_run_ (char *arg)
-{
- if (arg != NULL && *arg != '\0' && cmd_load_ (arg) != TRUE)
- return TRUE;
- puts (_("Running ..."));
- if (mix_vm_is_halted (vm_))
- {
- mix_vm_reset_program (vm_);
- prog_time_ = 0;
- }
+ if (!printed) printf ("Command \'%s\' not found\n", arg);
- switch (run_and_trace_ ())
- {
- case MIX_VM_HALT:
- puts (_("... done"));
- break;
- case MIX_VM_BREAK:
- {
- gulong line = mix_vm_get_break_lineno (vm_);
- if (line != 0)
- printf (_("... stopped: breakpoint at line %ld (address %d)\n"),
- line, mix_vm_get_prog_count (vm_));
- else
- printf (_("... stopped: breakpoint at address %d\n"),
- mix_vm_get_prog_count (vm_));
- }
- break;
- case MIX_VM_ERROR:
- puts (_("... error executing loaded file"));
- break;
- default:
- g_assert_not_reached ();
- break;
- }
- print_time_ ();
-
- if (emacs_)
- {
- emacs_output_();
- }
-
return TRUE;
-}
-
-static int
-cmd_next_ (char *arg)
-{
- int ins_no = 1;
- int k;
-
- if ( strlen (arg) != 0 )
- {
- int k = 0;
- while (isdigit (arg[k]))
- k++;
- if (arg[k] != '\0')
- {
- fprintf (stderr, _("Invalid argument: %s\n"), arg);
- return cmd_help_ ("next");
- }
- ins_no = atoi (arg);
- }
-
- if (mix_vm_is_halted (vm_))
- {
- mix_vm_reset_program (vm_);
- prog_time_ = 0;
- }
- while ( ins_no-- > 0 )
- {
- if (is_tracing_) trace_ ();
- k = mix_vm_exec_next (vm_);
- if (k == MIX_VM_HALT)
- {
- fprintf (stderr, _("End of program reached at address %d\n"),
- mix_vm_get_prog_count (vm_));
- break;
- }
- else if (k == MIX_VM_ERROR)
- {
- fprintf (stderr, _("Error at address %d\n"),
- mix_vm_get_prog_count (vm_));
- break;
- }
- }
- print_time_ ();
-
- if (emacs_)
- {
- emacs_output_();
- }
-
- return TRUE;
}
static int
cmd_quit_ (char *arg)
{
puts ("Quitting ...");
- if ( vm_ ) mix_vm_delete (vm_);
- if ( dc_ ) mix_dump_context_delete (dc_);
+ if ( dis_ ) mix_vm_cmd_dispatcher_delete (dis_);
/* pek: anything needed here to make the marker disappear??? */
return FALSE;
}
-static int
-cmd_pc_ (char *arg)
-{
- printf ("Current address: %d\n", mix_vm_get_prog_count (vm_));
- return TRUE;
-}
-
-static int
-cmd_psym_ (char *arg)
-{
- const mix_symbol_table_t *table = mix_eval_symbol_table (eval_);
- if ( table == NULL )
- fputs (_("Symbol table not available\n"), stderr);
- else if (arg != NULL && *arg != '\0')
- {
- if ( mix_symbol_table_is_defined (table, arg) )
- {
- mix_word_print (mix_symbol_table_value (table, arg), NULL);
- putc ('\n', stdout);
- }
- else
- printf (_("%s: symbol not defined\n"), arg);
- }
- else
- mix_symbol_table_print (table, MIX_SYM_ROWS, stdout, TRUE);
-
- return TRUE;
-}
-
-static int
-cmd_preg_ (char *arg)
-{
- mix_dump_context_set_opt (dc_, MIX_DUMP_NONE);
- if ( strlen (arg) == 0 )
- mix_dump_context_add_opt (dc_, MIX_DUMP_rALL);
- else switch (*arg)
- {
- case 'A':
- mix_dump_context_add_opt (dc_, MIX_DUMP_rA);
- break;
- case 'X':
- mix_dump_context_add_opt (dc_, MIX_DUMP_rX);
- break;
- case 'J':
- mix_dump_context_add_opt (dc_, MIX_DUMP_rJ);
- break;
- case 'I':
- {
- if ( strlen (arg) == 1 )
- mix_dump_context_add_opt (dc_, MIX_DUMP_rIa);
- else
- {
- static gint32 opt[] = { MIX_DUMP_rI1, MIX_DUMP_rI2,
- MIX_DUMP_rI3, MIX_DUMP_rI4,
- MIX_DUMP_rI5, MIX_DUMP_rI6
- };
- int i = arg[1] - '1';
- if ( i < 0 || i > 5 )
- {
- fprintf (stderr, _("Invalid I index: %d"), i);
- return TRUE;
- }
- mix_dump_context_add_opt (dc_, opt[i]);
- }
- }
- break;
- default:
- fprintf (stderr, _("Invalid argument: %s\n"), arg);
- return TRUE;
- }
- mix_vm_dump (vm_, dc_);
- return TRUE;
-}
-
-static int
-cmd_pflags_ (char *arg)
-{
- mix_dump_context_set_opt (dc_, MIX_DUMP_CMP | MIX_DUMP_OVER);
- mix_vm_dump (vm_, dc_);
- return TRUE;
-}
-
-static int
-cmd_pall_ (char *arg)
-{
- mix_dump_context_set_opt (dc_, MIX_DUMP_ALL_NOMEM);
- mix_vm_dump (vm_, dc_);
- return TRUE;
-}
-
-static int
-cmd_pmem_ (char *arg)
-{
- glong begin = MIX_SHORT_ZERO, end = MIX_SHORT_ZERO;
- int i = 0;
- gboolean error = FALSE;
-
- if ( strlen (arg) == 0 )
- {
- fputs (_("Missing memory address\n"), stderr);
- return TRUE;
- }
- while (isdigit (arg[i]))
- i++;
- while (isspace (arg[i]))
- i++;
- if (arg[i] == '\0')
- begin = end = atol (arg);
- else if (arg[i] == '-')
- {
- arg[i++] = '\0';
- begin = atol (arg);
- arg = arg + i;
- i = 0;
- while (isdigit (arg[i]))
- i++;
- while (isspace (arg[i]))
- i++;
- if (arg[i] != '\0')
- error = TRUE;
- else
- end = atol (arg);
- }
- else
- error = TRUE;
-
- if (error)
- {
- fprintf (stderr, _("Invalid argument: %s\n"), arg);
- return cmd_help_("pmem");
- }
- if ( end < begin || end > MIX_VM_CELL_NO - 1 )
- {
- fprintf (stderr, _("Invalid range: %ld-%ld\n"), begin, end);
- return TRUE;
- }
-
- mix_dump_context_set_opt (dc_, MIX_DUMP_CELLS);
- mix_dump_context_range (dc_, mix_short_new (begin), mix_short_new (end + 1));
- mix_vm_dump (vm_, dc_);
-
- return TRUE;
-}
-
-static int
-cmd_sreg_ (char *arg)
-{
- int i = 0;
- char reg = arg[0];
- gboolean ok = TRUE;
- long value;
-
- i = (reg == 'I') ? 2 : 1;
- ok = strlen (arg) > 2 && isspace (arg[i]);
- if (ok)
- {
- while (isspace (arg[i])) i++;
- ok = isdigit (arg[i]) || arg[i] == '+' || arg[i] == '-';
- if (ok)
- {
- value = atol (arg + i);
- if (arg[i] == '+' || arg[i] == '-') i++;
- while (isdigit (arg[i])) i++;
- ok = (arg[i] == '\0');
- if (ok)
- switch (reg)
- {
- case 'A':
- mix_vm_set_rA (vm_, mix_word_new (value));
- break;
- case 'X':
- mix_vm_set_rX (vm_, mix_word_new (value));
- break;
- case 'J':
- if ( value >= 0 )
- mix_vm_set_rJ (vm_, mix_short_new (value));
- else
- ok = FALSE;
- break;
- case 'I':
- {
- guint k = arg[1] - '0';
- if ( k < 7 )
- mix_vm_set_rI (vm_, k, mix_short_new (value));
- else
- ok = FALSE;
- }
- break;
- default:
- ok = FALSE;
- }
- }
- }
- if (!ok)
- {
- fprintf (stderr, _("Invalid argument: %s\n"), arg);
- cmd_help_ ("sreg");
- }
-
- return TRUE;
-}
-
-static int
-cmd_scmp_ (char *arg)
-{
- gboolean ok = (strlen (arg) == 1);
- if (ok) switch (arg[0])
- {
- case 'L':
- mix_vm_set_cmpflag (vm_, mix_LESS);
- break;
- case 'E':
- mix_vm_set_cmpflag (vm_, mix_EQ);
- break;
- case 'G':
- mix_vm_set_cmpflag (vm_, mix_GREAT);
- break;
- default:
- ok = FALSE;
- }
- if (!ok)
- {
- fprintf (stderr, _("Invalid argument: %s\n"), arg);
- cmd_help_ ("scmp");
- }
-
- return TRUE;
-}
-
-static int
-cmd_sover_ (char *arg)
-{
- gboolean ok = (strlen (arg) == 1);
- if (ok) switch (arg[0])
- {
- case 'T':
- mix_vm_set_overflow (vm_, TRUE);
- break;
- case 'F':
- mix_vm_set_overflow (vm_, FALSE);
- break;
- default:
- ok = FALSE;
- }
- if (!ok)
- {
- fprintf (stderr, _("Invalid argument: %s\n"), arg);
- cmd_help_ ("sover");
- }
-
- return TRUE;
-}
-
-static int
-cmd_smem_ (char *arg)
-{
- gboolean ok = (strlen (arg) > 2 && isdigit (arg[0]));
- gulong addr;
- glong value;
- int k = 0;
-
- if (ok)
- {
- while (isdigit (arg[k])) k++;
- ok = isspace (arg[k]);
- if (ok)
- {
- arg[k++] = '\0';
- addr = atol (arg);
- ok = addr < MIX_VM_CELL_NO;
- }
- if (ok)
- {
- while (isspace (arg[k])) k++;
- value = atol (arg + k);
- if ( arg[k] == '+' || arg[k] == '-' ) k++;
- while (isdigit (arg[k])) k++;
- ok = arg[k] == '\0';
- }
- }
-
- if (ok)
- mix_vm_set_addr_contents (vm_, mix_short_new (addr), mix_word_new (value));
- else
- {
- fprintf (stderr, "Invalid argument: %s\n", arg);
- cmd_help_ ("smem");
- }
-
- return TRUE;
-}
-
-static int
-cmd_ssym_ (char *arg)
-{
- if (arg == NULL || strlen(arg) == 0)
- {
- fprintf (stderr, _("Missing arguments\n"));
- return cmd_help_ ("ssym");
- }
- else
- {
- gchar *a = g_strdup (arg);
- gchar *s = strtok (a, " \t");
- gchar *w = strtok (NULL, " \t");
- if (w != NULL && strtok (NULL, " \t") == NULL)
- {
- cmd_weval_ (w);
- if (mix_eval_last_error (eval_) == MIX_EVAL_OK)
- mix_eval_set_symbol (eval_, s, mix_eval_value (eval_));
- }
- else
- {
- fprintf (stderr, _("Wrong argument number\n"));
- cmd_help_ ("ssym");
- }
- g_free (a);
- return TRUE;
- }
-}
-
-static int
-cmd_sbp_ (char *arg)
-{
- glong lineno;
- glong k = 0;
- while (isdigit (arg[k])) k++;
- if (arg[k] != '\0')
- {
- fprintf (stderr, _("Invalid argument: %s\n"), arg);
- return cmd_help_ ("sbp");
- }
- lineno = atol (arg);
- switch (k = mix_vm_set_breakpoint (vm_, lineno))
- {
- case MIX_VM_BP_INV_LINE:
- fprintf (stderr, _("Line number %ld too high\n"), lineno);
- break;
- case MIX_VM_BP_ERROR:
- fputs (_("Could not set breakpoint. Internal error\n"), stderr);
- break;
- case MIX_VM_BP_NDEBUG:
- fputs (_("Could not set breakpoint. No debug info available\n"), stderr);
- break;
- default:
- fprintf (stderr, _("Breakpoint set at line %ld\n"), k);
- break;
- }
- return TRUE;
-}
-
-static int
-cmd_sbpa_ (char *arg)
-{
- glong address;
- glong k = 0;
- while (isdigit (arg[k])) k++;
- if (arg[k] != '\0')
- {
- fprintf (stderr, _("Invalid argument: %s\n"), arg);
- return cmd_help_ ("sbpa");
- }
- address = atol (arg);
- switch (mix_vm_set_breakpoint_address (vm_, address))
- {
- case MIX_VM_BP_INV_ADDRESS:
- fprintf (stderr, _("Invalid address %ld\n"), address);
- break;
- case MIX_VM_BP_ERROR:
- fputs (_("Could not set breakpoint. Internal error\n"), stderr);
- break;
- default:
- fprintf (stderr, _("Breakpoint set at address %ld\n"), address);
- break;
- }
- return TRUE;
-}
-
-static int
-cmd_cbp_ (char *arg)
-{
- glong lineno;
- int k = 0;
- while (isdigit (arg[k])) k++;
- if (arg[k] != '\0')
- {
- fprintf (stderr, _("Invalid argument: %s\n"), arg);
- return cmd_help_ ("cbp");
- }
- lineno = atol (arg);
- switch (mix_vm_clear_breakpoint (vm_, lineno))
- {
- case MIX_VM_BP_INV_LINE:
- fprintf (stderr, _("No breakpoint set at line %ld\n"), lineno);
- break;
- case MIX_VM_BP_ERROR:
- fputs (_("Could not set breakpoint. Internal error\n"), stderr);
- break;
- case MIX_VM_BP_NDEBUG:
- fputs (_("No debug info available\n"), stderr);
- break;
- case MIX_VM_BP_OK:
- fprintf (stderr, _("Breakpoint cleared at line %ld\n"), lineno);
- break;
- default:
- g_assert_not_reached ();
- break;
- }
- return TRUE;
-}
-
-static int
-cmd_cbpa_ (char *arg)
-{
- glong address;
- glong k = 0;
- while (isdigit (arg[k])) k++;
- if (arg[k] != '\0')
- {
- fprintf (stderr, _("Invalid argument: %s\n"), arg);
- return cmd_help_ ("cbpa");
- }
- address = atol (arg);
- switch (mix_vm_clear_breakpoint_address (vm_, address))
- {
- case MIX_VM_BP_INV_ADDRESS:
- fprintf (stderr, _("Invalid address %ld\n"), address);
- break;
- case MIX_VM_BP_ERROR:
- fputs (_("Could not clear breakpoint. Internal error\n"), stderr);
- break;
- default:
- fprintf (stderr, _("Breakpoint cleared at address %ld\n"), address);
- break;
- }
- return TRUE;
-}
-
-
-static int
-cmd_cabp_ (char *arg)
-{
- if (strlen (arg) != 0)
- {
- fprintf (stderr, _("Invalid argument: %s\n"), arg);
- return cmd_help_ ("cabp");
- }
- mix_vm_clear_all_breakpoints (vm_);
- return TRUE;
-}
static int
cmd_shell_ (char *arg)
@@ -957,8 +235,8 @@ static int
cmd_edit_ (char *arg)
{
static const gchar * envars[] = { "MDK_EDITOR", "X_EDITOR", "EDITOR",
- "VISUAL"
- };
+ "VISUAL" };
+
static const guint s = sizeof (envars) / sizeof (envars[0]);
static const gchar *editor = NULL;
@@ -989,117 +267,38 @@ cmd_edit_ (char *arg)
return TRUE;
}
-static int
-cmd_weval_ (char *arg)
-{
- if ( strlen (arg) == 0 )
- return cmd_help_ ("weval");
-
- if (mix_eval_expression_with_loc (eval_, arg,
- mix_vm_get_prog_count (vm_)) ==
- MIX_EVAL_OK)
- {
- mix_word_print (mix_eval_value (eval_), NULL);
- putc ('\n', stdout);
- }
- else
- {
- gint pos = mix_eval_last_error_pos (eval_);
- gint k, len = strlen (arg);
- g_assert(pos > -1 && pos <= len);
- for (k = 0; k<pos; ++k) fputc (arg[k], stderr);
- fputc ('\n', stderr);
- for (k = 0; k<pos; ++k) fputc (' ', stderr);
- for (k = pos; k < len; ++k) fputc (arg[k], stderr);
- fprintf (stderr, _("\nEvaluation error: %s\n"),
- mix_eval_last_error_string (eval_));
- }
-
- return TRUE;
-}
-
-static int
-cmd_w2d_ (char *arg)
-{
- if ( strlen (arg) == 0 )
- return cmd_help_ ("w2d");
- else
- {
- gchar *cp = g_strdup (arg), *a = cp;
- mix_byte_t bytes[5] = {0, 0, 0, 0, 0};
- gchar *b;
- guint k = 0;
- gboolean is_n = (a[0] == '-'), success = TRUE;
- if (a[0] == '+' || a[0] == '-') ++a;
- b = strtok (a, " \t");
- while (b != NULL && k < 5)
- {
- if (strlen (b) != 2 || !isdigit(b[0]) || !isdigit(b[1]))
- {
- fprintf (stderr, _("Incorrect byte specification: %s\n"), b);
- success = FALSE;
- b = NULL;
- }
- else
- {
- bytes[k++] = mix_byte_new (atoi (b));
- b = strtok (NULL, " \t");
- }
- }
- if (success)
- {
- if (strtok (NULL, "\t") != NULL)
- fprintf (stderr, _("The expression %s does not fit in a word\n"),
- arg);
- else
- {
- mix_word_t w = mix_bytes_to_word (bytes, k);
- fprintf (stdout, "%s%ld\n", is_n? "-":"+",
- mix_word_magnitude (w));
- }
- }
- g_free (cp);
- }
-
- return TRUE;
-}
-
-static int
-cmd_tron_ (char *arg)
-{
- is_tracing_ = TRUE;
- printf (_("Instruction tracing has been turned ON.\n"));
- return TRUE;
-}
-
-static int
-cmd_troff_ (char *arg)
-{
- is_tracing_ = FALSE;
- printf (_("Instruction tracing has been turned OFF.\n"));
- return TRUE;
-}
/* external interface */
void
mixvm_cmd_init (char *arg, gboolean use_emacs)
{
+ int k;
+ /* get local command names */
+ for (k = 0; k < LOCAL_COMANDS_NO_; ++k)
+ mix_commands_[k] = commands[k].name;
+ /* get external command names */
+ for (k = 0; k < MIX_CMD_INVALID; ++k)
+ mix_commands_[k + LOCAL_COMANDS_NO_] = mix_vm_command_to_string (k);
+ mix_commands_[ALL_COMMANDS_NO_ - 1] = NULL;
/* Tell the completer that we want a crack first. */
rl_attempted_completion_function = (CPPFunction *)mixvm_cmd_completion_;
- /* set the emacs flag */
- emacs_ = use_emacs;
- /* initialise the vm */
- vm_ = mix_vm_new ();
- dc_ = mix_dump_context_new (MIX_DUMP_DEF_CHANNEL,
- MIX_SHORT_ZERO, MIX_SHORT_ZERO,
- MIX_DUMP_ALL);
- eval_ = mix_eval_new ();
-
- if ( vm_ == NULL || dc_ == NULL || eval_ == NULL)
+ /* initialise the dispatcher */
+ dis_ = mix_vm_cmd_dispatcher_new (stdout, stderr);
+
+ if ( dis_ == NULL)
g_error (_("Failed initialisation (no memory resources)"));
+
+ /* install post hook for emacs interaction */
+ if (use_emacs)
+ {
+ mix_vm_cmd_dispatcher_post_hook (dis_, MIX_CMD_LOAD, emacs_output_, NULL);
+ mix_vm_cmd_dispatcher_post_hook (dis_, MIX_CMD_RUN, emacs_output_, NULL);
+ mix_vm_cmd_dispatcher_post_hook (dis_, MIX_CMD_NEXT, emacs_output_, NULL);
+ }
+
if (arg)
- cmd_load_ (arg);
+ mix_vm_cmd_dispatcher_dispatch (dis_, MIX_CMD_LOAD, arg);
}
gboolean
@@ -1107,7 +306,8 @@ mixvm_cmd_exec (char *line)
{
int i;
COMMAND *command;
- char *word;
+ char *cmd, *arg;
+ mix_vm_command_t mix_cmd;
if (!line) return cmd_quit_(NULL);
@@ -1118,7 +318,7 @@ mixvm_cmd_exec (char *line)
i = 0;
while (line[i] && isspace (line[i]))
i++;
- word = line + i;
+ cmd = line + i;
while (line[i] && !isspace (line[i]))
i++;
@@ -1126,34 +326,29 @@ mixvm_cmd_exec (char *line)
if (line[i])
line[i++] = '\0';
- if (word == NULL || strlen (word) == 0)
+ if (cmd == NULL || strlen (cmd) == 0)
return TRUE;
- command = find_command_ (word);
-
- if (!command)
- {
- fprintf (stderr, _("%s: No such command. Try \'help\'\n"), word);
- return TRUE;
- }
-
/* Get argument to command, if any. */
while (isspace (line[i]))
i++;
- word = line + i;
+ arg = line + i;
- /* pek note: as far as I know, only load, run,
- next, and quit can affect where gud will
- displays the "marker". I am toying with the
- idea of adding some logic before and after
- the *(command->func) that determines if
- either the source file or line number have
- changed. If another command is added later,
- then the logic won't have to be inserted... */
+ /* try to find local command */
+ command = find_command_ (cmd);
+ if (command)
+ return ((*(command->func)) (arg));
- /* Call the function. */
- return ((*(command->func)) (word));
+ /* try to find mix command */
+ mix_cmd = mix_vm_command_from_string (cmd);
+
+ if (mix_cmd == MIX_CMD_INVALID)
+ fprintf (stderr, _("%s: No such command. Try \'help\'\n"), cmd);
+ else
+ mix_vm_cmd_dispatcher_dispatch (dis_, mix_cmd, arg);
+
+ return TRUE;
}