diff options
author | jaortega <jaortega> | 2001-02-26 23:21:17 +0000 |
---|---|---|
committer | jaortega <jaortega> | 2001-02-26 23:21:17 +0000 |
commit | f270b847a817582f60f6371293fade65fe9afb9f (patch) | |
tree | fcd080b39e8f811905a7e194949aa1d55cbdffd8 | |
parent | 119a5240f57ded266447b485e5a7c0eec6dd67f8 (diff) | |
download | mdk-f270b847a817582f60f6371293fade65fe9afb9f.tar.gz mdk-f270b847a817582f60f6371293fade65fe9afb9f.tar.bz2 |
mix vm command dispatch refactoring
-rw-r--r-- | mixlib/Makefile.am | 4 | ||||
-rw-r--r-- | mixlib/mix_types.c | 12 | ||||
-rw-r--r-- | mixlib/mix_types.h | 10 | ||||
-rw-r--r-- | mixlib/mix_vm_command.c | 1096 | ||||
-rw-r--r-- | mixlib/mix_vm_command.h | 139 | ||||
-rw-r--r-- | mixlib/mix_vm_dump.c | 77 | ||||
-rw-r--r-- | mixlib/mix_vm_dump.h | 13 | ||||
-rw-r--r-- | mixutils/mixvm_command.c | 945 |
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; } |