summaryrefslogtreecommitdiffhomepage
path: root/mixlib
diff options
context:
space:
mode:
Diffstat (limited to 'mixlib')
-rw-r--r--mixlib/Makefile.am42
-rw-r--r--mixlib/gettext.h69
-rw-r--r--mixlib/mix.c99
-rw-r--r--mixlib/mix.h78
-rw-r--r--mixlib/mix_code_file.c330
-rw-r--r--mixlib/mix_code_file.h106
-rw-r--r--mixlib/mix_config.c298
-rw-r--r--mixlib/mix_config.h100
-rw-r--r--mixlib/mix_device.c164
-rw-r--r--mixlib/mix_device.h160
-rw-r--r--mixlib/mix_eval.c191
-rw-r--r--mixlib/mix_eval.h110
-rw-r--r--mixlib/mix_eval_scanner.l276
-rw-r--r--mixlib/mix_file.c159
-rw-r--r--mixlib/mix_file.h65
-rw-r--r--mixlib/mix_ins.c269
-rw-r--r--mixlib/mix_ins.h195
-rw-r--r--mixlib/mix_io.c208
-rw-r--r--mixlib/mix_io.h119
-rw-r--r--mixlib/mix_parser.c605
-rw-r--r--mixlib/mix_parser.h111
-rw-r--r--mixlib/mix_predicate.c215
-rw-r--r--mixlib/mix_predicate.h80
-rw-r--r--mixlib/mix_predicate_list.c117
-rw-r--r--mixlib/mix_predicate_list.h64
-rw-r--r--mixlib/mix_scanner.l581
-rw-r--r--mixlib/mix_src_file.c157
-rw-r--r--mixlib/mix_src_file.h57
-rw-r--r--mixlib/mix_symbol_table.c198
-rw-r--r--mixlib/mix_symbol_table.h109
-rw-r--r--mixlib/mix_types.c569
-rw-r--r--mixlib/mix_types.h293
-rw-r--r--mixlib/mix_vm.c706
-rw-r--r--mixlib/mix_vm.h255
-rw-r--r--mixlib/mix_vm_clock.c70
-rw-r--r--mixlib/mix_vm_clock.h55
-rw-r--r--mixlib/mix_vm_command.c641
-rw-r--r--mixlib/mix_vm_command.h256
-rw-r--r--mixlib/mix_vm_dump.c147
-rw-r--r--mixlib/mix_vm_dump.h91
-rw-r--r--mixlib/testsuite/Makefile.am32
-rw-r--r--mixlib/testsuite/mix_device_t.c76
-rw-r--r--mixlib/testsuite/mix_eval_t.c119
-rw-r--r--mixlib/testsuite/mix_ins_t.c79
-rw-r--r--mixlib/testsuite/mix_parser_t.c85
-rw-r--r--mixlib/testsuite/mix_types_t.c369
-rw-r--r--mixlib/testsuite/mix_vm_ins_t.c505
-rw-r--r--mixlib/testsuite/test.h44
-rw-r--r--mixlib/xmix_device.c199
-rw-r--r--mixlib/xmix_device.h96
-rw-r--r--mixlib/xmix_eval.h55
-rw-r--r--mixlib/xmix_io.c57
-rw-r--r--mixlib/xmix_io.h64
-rw-r--r--mixlib/xmix_parser.h111
-rw-r--r--mixlib/xmix_vm.c598
-rw-r--r--mixlib/xmix_vm.h139
-rw-r--r--mixlib/xmix_vm_command.c64
-rw-r--r--mixlib/xmix_vm_command.h102
-rw-r--r--mixlib/xmix_vm_handlers.c1387
-rw-r--r--mixlib/xmix_vm_handlers.h87
60 files changed, 12683 insertions, 0 deletions
diff --git a/mixlib/Makefile.am b/mixlib/Makefile.am
new file mode 100644
index 0000000..b925ff5
--- /dev/null
+++ b/mixlib/Makefile.am
@@ -0,0 +1,42 @@
+## Process this file with automake to produce Makefile.in
+
+# Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# $Id: Makefile.am,v 1.6 2002/12/08 01:36:49 jao Exp $
+
+SUBDIRS = testsuite
+INCLUDES = -I$(includedir) -I$(top_srcdir) -DG_LOG_DOMAIN=\"libmix\"
+
+noinst_LIBRARIES = libmix.a
+libmix_a_SOURCES = gettext.h mix.h mix.c \
+ mix_types.h mix_types.c \
+ mix_ins.h mix_ins.c \
+ mix_vm.h mix_vm.c xmix_vm.h xmix_vm.c \
+ mix_vm_dump.h mix_vm_dump.c \
+ mix_io.h mix_io.c xmix_io.h xmix_io.c \
+ mix_symbol_table.h mix_symbol_table.c \
+ mix_file.h mix_file.c \
+ mix_code_file.h mix_code_file.c \
+ mix_parser.h xmix_parser.h mix_parser.c mix_scanner.l \
+ mix_device.h mix_device.c xmix_device.h xmix_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_command.c mix_vm_command.h \
+ xmix_vm_command.c xmix_vm_command.h \
+ xmix_vm_handlers.h xmix_vm_handlers.c \
+ mix_config.c mix_config.h \
+ mix_predicate.c mix_predicate.h \
+ mix_predicate_list.c mix_predicate_list.h
+
+
+
+
diff --git a/mixlib/gettext.h b/mixlib/gettext.h
new file mode 100644
index 0000000..fa3622f
--- /dev/null
+++ b/mixlib/gettext.h
@@ -0,0 +1,69 @@
+/* Convenience header for conditional use of GNU <libintl.h>.
+ Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published
+ by the Free Software Foundation; either version 2, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifndef _LIBGETTEXT_H
+#define _LIBGETTEXT_H 1
+
+/* NLS can be disabled through the configure --disable-nls option. */
+#if ENABLE_NLS
+
+/* Get declarations of GNU message catalog functions. */
+# include <libintl.h>
+
+#else
+
+/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
+ chokes if dcgettext is defined as a macro. So include it now, to make
+ later inclusions of <locale.h> a NOP. We don't include <libintl.h>
+ as well because people using "gettext.h" will not include <libintl.h>,
+ and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
+ is OK. */
+#if defined(__sun)
+# include <locale.h>
+#endif
+
+/* Disabled NLS.
+ The casts to 'const char *' serve the purpose of producing warnings
+ for invalid uses of the value returned from these functions.
+ On pre-ANSI systems without 'const', the config.h file is supposed to
+ contain "#define const". */
+# define gettext(Msgid) ((const char *) (Msgid))
+# define dgettext(Domainname, Msgid) ((const char *) (Msgid))
+# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid))
+# define ngettext(Msgid1, Msgid2, N) \
+ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define dngettext(Domainname, Msgid1, Msgid2, N) \
+ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
+ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define textdomain(Domainname) ((const char *) (Domainname))
+# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
+# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset))
+
+#endif
+
+/* A pseudo function call that serves as a marker for the automated
+ extraction of messages, but does not call gettext(). The run-time
+ translation is done at a different place in the code.
+ The argument, String, should be a literal string. Concatenated strings
+ and other string expressions won't work.
+ The macro's expansion is not parenthesized, so that it is suitable as
+ initializer for static 'char[]' or 'const char[]' variables. */
+#define gettext_noop(String) String
+
+#endif /* _LIBGETTEXT_H */
diff --git a/mixlib/mix.c b/mixlib/mix.c
new file mode 100644
index 0000000..3578a57
--- /dev/null
+++ b/mixlib/mix.c
@@ -0,0 +1,99 @@
+/* -*-c-*- -------------- mix.c :
+ * Implementation of the functions declared in mix.h
+ * ------------------------------------------------------------------
+ * $Id: mix.c,v 1.6 2005/09/20 19:43:13 jao Exp $
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000, 2001, 2002 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+
+
+#include "mix_types.h"
+#include "mix_ins.h"
+#include "mix_code_file.h"
+#include "mix.h"
+
+
+/* This function must be called before using the library */
+void
+mix_init_lib(void)
+{
+ mix_init_types ();
+ mix_init_ins ();
+ mix_code_file_set_defext (MIX_CODE_DEFEXT);
+}
+
+
+/* This function must be called for deallocating the lib resources
+ when it is no longer in use
+*/
+void
+mix_release_lib (void)
+{
+ /* clean the user defined code file extension (if any) */
+ mix_code_file_set_defext (NULL);
+ mix_release_ins ();
+}
+
+const char *MIX_GPL_LICENSE =
+"Copyright (C) 2001 Free Software Foundation, Inc.\n"
+"There is NO warranty. You may redistribute this software\n"
+"under the terms of the GNU General Public License.\n"
+"For more information about these matters, see the files named COPYING.\n";
+
+void
+mix_print_license (const gchar *program)
+{
+ fprintf (stderr, _("%s (GNU MDK %s)\n\n"),
+ program, VERSION);
+ fprintf (stderr, MIX_GPL_LICENSE);
+}
+
+/* check dir, and create it if it doesn't exist */
+gboolean
+mix_stat_dir (const gchar *dirname, const gchar *alias)
+{
+ struct stat statbuf;
+
+ g_return_val_if_fail (dirname != NULL, FALSE);
+ if (alias == NULL) alias = "";
+
+ if (stat (dirname, &statbuf) == -1)
+ {
+ if (errno != ENOENT || mkdir (dirname, S_IRWXU | S_IRWXG | S_IRWXO))
+ {
+ g_warning (_("Error creating %s dir %s: %s"),
+ alias, dirname, strerror (errno));
+ return FALSE;
+ }
+ stat (dirname, &statbuf);
+ }
+
+ if (!(statbuf.st_mode & S_IFDIR))
+ {
+ g_warning (_("Error setting %s dir: %s is not a directory"),
+ alias, dirname);
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/mixlib/mix.h b/mixlib/mix.h
new file mode 100644
index 0000000..6a3fd1d
--- /dev/null
+++ b/mixlib/mix.h
@@ -0,0 +1,78 @@
+/* -*-c-*- ---------------- mix.h :
+ * Initialisation of the mix library
+ * ------------------------------------------------------------------
+ * $Id: mix.h,v 1.7 2005/09/20 19:43:13 jao Exp $
+ * ------------------------------------------------------------------
+ * 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
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef MIX_H
+#define MIX_H
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#else
+# warning "config.h not found, package misconfigured."
+# define PACKAGE "mdk"
+# define VERSION "0.0"
+#endif
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+/*
+#ifdef HAVE_GETTEXT
+# include <libintl.h>
+# define gettext_noop(String) (String)
+#else
+# include <intl/libgettext.h>
+#endif
+*/
+#include "gettext.h"
+
+#define _(String) gettext (String)
+#define N_(String) gettext_noop (String)
+
+#include <glib.h>
+
+/* This function must be called before using the library */
+extern void
+mix_init_lib (void);
+
+/* This function must be called for deallocating the lib resources
+ when it is no longer in use
+*/
+extern void
+mix_release_lib (void);
+
+
+extern const char *MIX_GPL_LICENSE;
+
+extern void
+mix_print_license (const gchar *program);
+
+
+/* check dir, and create it if it doesn't exist */
+extern gboolean
+mix_stat_dir (const gchar *dirname, const gchar *alias);
+
+
+#endif /* MIX_H */
+
diff --git a/mixlib/mix_code_file.c b/mixlib/mix_code_file.c
new file mode 100644
index 0000000..ab67812
--- /dev/null
+++ b/mixlib/mix_code_file.c
@@ -0,0 +1,330 @@
+/* -*-c-*- -------------- mix_code_file.c :
+ * Implementation of the functions declared in mix_code_file.h
+ * ------------------------------------------------------------------
+ * $Id: mix_code_file.c,v 1.6 2005/09/20 19:43:13 jao Exp $
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000, 2002, 2003 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <string.h>
+
+#include "mix.h"
+#include "xmix_io.h"
+#include "mix_code_file.h"
+
+/* mix_code_file_t type */
+static const gint32 SIGNATURE_ = 0xDEADBEEF; /* release files */
+static const gint32 SIGNATURE_D_ = 0xBEEFDEAD; /* debug files */
+
+#define IS_DEBUG_(file) ((file)->header.signature == SIGNATURE_D_)
+#define IS_RELEASE_(file) ((file)->header.signature == SIGNATURE_)
+
+
+typedef struct mix_cfheader_t mix_cfheader_t;
+struct mix_cfheader_t
+{
+ gint32 signature;
+ gint mj_ver;
+ gint mn_ver;
+ gint16 start;
+ size_t path_len;
+};
+
+struct mix_code_file_t
+{
+ mix_file_t *file; /* the underlying disk file */
+ mix_address_t address; /* current address while reading */
+ mix_cfheader_t header; /* file header */
+ gchar *source_path; /* variable length part of the header*/
+ mix_symbol_table_t *symbol_table; /* code files with debug info fill it*/
+};
+
+#define to_io_(cf) MIX_IOCHANNEL (cf->file)
+
+/* Code files are lists of tagged words. A MIX_INS_TAG_ denotes
+ * that the word is an instruction, whose address is the next to
+ * the previous instruction's one, while a MIX_ADDR_TAG_ indicates
+ * that the word is a new address origin for the next instructions.
+ * The tags are stored as bit patterns in bit 31 of the mix word.
+ */
+#define MIX_ADDR_TAG_ (MIX_WORD_SIGN_BIT<<1)
+
+#define is_ins_(word) (((word)&MIX_ADDR_TAG_) == MIX_WORD_ZERO)
+#define is_addr_(word) (((word)&MIX_ADDR_TAG_) == MIX_ADDR_TAG_)
+#define tag_ins_(word) (word)
+#define tag_addr_(word) ((word)|MIX_ADDR_TAG_)
+#define extract_ins_(tagged) (tagged)
+#define extract_addr_(tagged) ((tagged)&MIX_SHORT_MAX)
+
+/* mix code files have a default extension (.mix) which is customizable */
+static const gchar *DEFEXT_ = NULL;
+
+const gchar *
+mix_code_file_get_defext (void)
+{
+ return DEFEXT_;
+}
+
+gboolean
+mix_code_file_set_defext (const gchar *ext)
+{
+ if (DEFEXT_ != NULL) g_free ((void *)DEFEXT_);
+ DEFEXT_ = (ext != NULL)? g_strdup (ext):NULL;
+ return (DEFEXT_ != NULL || ext == NULL);
+}
+
+/* create/destroy code files for read or write */
+static mix_code_file_t *
+mix_code_file_new_ (const gchar *name, mix_fmode_t mode)
+{
+ mix_code_file_t *result = g_new (mix_code_file_t, 1);
+ if ( result != NULL )
+ {
+ result->file = mix_file_new_with_def_ext (name, mode, DEFEXT_);
+ result->address = MIX_SHORT_ZERO;
+ result->source_path = NULL;
+ result->symbol_table = NULL;
+ }
+ if ( result != NULL && result->file == NULL )
+ {
+ g_free (result);
+ result = NULL;
+ }
+ return result;
+}
+
+mix_code_file_t *
+mix_code_file_new_read (const gchar *name)
+{
+ mix_code_file_t *result = mix_code_file_new_ (name, mix_io_READ);
+ mix_cfheader_t *header;
+ FILE *file;
+ gboolean check;
+
+ if ( result == NULL )
+ return NULL;
+
+ file = mix_file_to_FILE (result->file);
+ header = &(result->header);
+ check = fread (header, sizeof (mix_cfheader_t), 1, file)
+ && (IS_RELEASE_ (result) || IS_DEBUG_ (result));
+
+ if ( check )
+ {
+ gint major, minor;
+ sscanf (VERSION, "%d.%d", &major, &minor);
+ check = header->mj_ver == major && header->mn_ver <= minor;
+ }
+
+ if ( check )
+ {/* get source path */
+ result->source_path = g_strnfill (1 + header->path_len, '\0');
+ check = result->source_path != NULL
+ && fgets (result->source_path, 1 + header->path_len, file) != NULL;
+ }
+
+ if ( check && IS_DEBUG_ (result) )
+ {/* read symbol table */
+ result->symbol_table = mix_symbol_table_new_from_file (file);
+ check = result->symbol_table != NULL;
+ }
+
+ if ( !check )
+ {
+ mix_code_file_delete (result);
+ return NULL;
+ }
+
+ return result;
+}
+
+mix_code_file_t *
+mix_code_file_new_write(const gchar *name, mix_address_t addr,
+ const gchar *source_path, gboolean debug,
+ const mix_symbol_table_t *table)
+{
+ mix_code_file_t *result;
+ FILE *file;
+ gboolean check;
+
+ result = mix_code_file_new_ (name, mix_io_WRITE);
+ if ( result == NULL || ( file = mix_file_to_FILE (result->file) ) == NULL )
+ return NULL;
+ else if ( source_path != NULL )
+ {
+ result->source_path = g_strdup (source_path/*, MAX_PATH_LEN_*/);
+ if ( result->source_path == NULL )
+ {
+ mix_code_file_delete (result);
+ return NULL;
+ }
+ }
+ else
+ result->source_path = NULL;
+
+ result->header.signature = debug? SIGNATURE_D_:SIGNATURE_;
+ sscanf (VERSION, "%d.%d", &result->header.mj_ver, &result->header.mn_ver);
+ result->header.start = (gint16) addr;
+ result->header.path_len = strlen (result->source_path);
+ check = write_data_ (to_io_ (result), &result->header, 1);
+ if ( check && result->source_path != NULL )
+ check = fputs (result->source_path, file) != EOF;
+ if ( check && debug )
+ mix_symbol_table_print (table, MIX_SYM_LINE, file, TRUE);
+ if ( !check )
+ {
+ mix_code_file_delete (result);
+ return NULL;
+ }
+ return result;
+}
+
+void
+mix_code_file_delete (mix_code_file_t *file)
+{
+ g_return_if_fail (file != NULL);
+ mix_file_delete (file->file);
+ if (file->source_path) g_free (file->source_path);
+ g_free (file);
+}
+
+/* get general parameters from a code file */
+gboolean
+mix_code_file_is_debug (const mix_code_file_t *file)
+{
+ return (file != NULL) && IS_DEBUG_ (file);
+}
+
+gint
+mix_code_file_major_version (const mix_code_file_t *file)
+{
+ g_return_val_if_fail (file != NULL, 0);
+ return file->header.mj_ver;
+}
+
+gint
+mix_code_file_minor_version (const mix_code_file_t *file)
+{
+ g_return_val_if_fail (file != NULL, 0);
+ return file->header.mn_ver;
+}
+
+mix_address_t
+mix_code_file_get_start_addr (const mix_code_file_t *file)
+{
+ g_return_val_if_fail (file != NULL, MIX_SHORT_ZERO);
+ return mix_short_new (file->header.start);
+}
+
+mix_symbol_table_t *
+mix_code_file_get_symbol_table(mix_code_file_t *file)
+{
+ mix_symbol_table_t *result = NULL;
+ g_return_val_if_fail (file != NULL, NULL);
+ result = file->symbol_table;
+ file->symbol_table = NULL;
+ return result;
+}
+
+/* read instructions from a code file */
+gboolean
+mix_code_file_is_eof (mix_code_file_t *file)
+{
+ return is_eof_ (to_io_ (file));
+}
+
+gboolean
+mix_code_file_get_ins (mix_code_file_t *file, mix_ins_desc_t *desc)
+{
+ mix_word_t next;
+ g_return_val_if_fail (file != NULL, FALSE);
+ g_return_val_if_fail (desc != NULL, FALSE);
+ while (TRUE)
+ {
+ if ( ! mix_io_read_word_array (to_io_ (file), &next, 1) ) return FALSE;
+ if ( is_addr_ (next) )
+ file->address = extract_addr_ (next);
+ else if ( is_ins_ (next) )
+ {
+ desc->ins = extract_ins_ (next);
+ desc->address = (file->address)++;
+ if ( IS_DEBUG_ (file) )
+ {
+ mix_short_t lineno;
+ if ( !mix_io_read_short_array (to_io_ (file), &lineno, 1) )
+ return FALSE;
+ desc->lineno = mix_short_magnitude (lineno);
+ }
+ else
+ desc->lineno = 0;
+ return TRUE;
+ }
+ else
+ {
+ g_assert_not_reached ();
+ return FALSE;
+ }
+ };
+}
+
+/* Write instructions to a code file */
+gboolean
+mix_code_file_write_ins (mix_code_file_t *file, const mix_ins_desc_t *desc)
+{
+ g_return_val_if_fail (desc != NULL, FALSE);
+ return ( mix_code_file_set_address (file, desc->address) &&
+ mix_code_file_write_next_ins (file, desc->ins, desc->lineno) );
+}
+
+gboolean
+mix_code_file_write_next_ins (mix_code_file_t *file, mix_word_t ins,
+ guint lineno)
+{
+ g_return_val_if_fail (file != NULL, FALSE);
+ if ( mix_io_write_word (to_io_ (file), tag_ins_ (ins))
+ && ( IS_RELEASE_ (file)
+ || mix_io_write_short (to_io_ (file), mix_short_new (lineno)) )
+ )
+ {
+ ++(file->address);
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+gboolean
+mix_code_file_set_address (mix_code_file_t *file, mix_address_t address)
+{
+ g_return_val_if_fail(file != NULL, FALSE);
+ if ( file->address != address ) {
+ if ( !mix_io_write_word (to_io_ (file),
+ tag_addr_ (mix_short_to_word_fast (address))) )
+ return FALSE;
+ file->address = address;
+ }
+ return TRUE;
+}
+
+/* get details about the source file */
+const gchar *
+mix_code_file_get_source_path (const mix_code_file_t *file)
+{
+ g_return_val_if_fail (file != NULL, NULL);
+ return file->source_path;
+}
diff --git a/mixlib/mix_code_file.h b/mixlib/mix_code_file.h
new file mode 100644
index 0000000..84b89fb
--- /dev/null
+++ b/mixlib/mix_code_file.h
@@ -0,0 +1,106 @@
+/* -*-c-*- ---------------- mix_code_file.h :
+ * Declaration of mix_code_file_t, a file containing compiled mix
+ * instructions.
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef MIX_CODE_FILE_H
+#define MIX_CODE_FILE_H
+
+#include "mix_file.h"
+#include "mix_ins.h"
+#include "mix_symbol_table.h"
+
+/* mix_code_file_t type */
+typedef struct mix_code_file_t mix_code_file_t;
+
+/* instructions are loaded at specific memory addresses and related to
+ source line numbers
+*/
+typedef struct mix_ins_desc_t mix_ins_desc_t;
+struct mix_ins_desc_t
+{
+ mix_word_t ins; /* a mix instruction coded into a word */
+ mix_address_t address; /* the address of this instruction */
+ guint lineno; /* source file line no. */
+};
+
+/* mix code files have a default extension (.mix) which is customizable */
+extern const gchar *
+mix_code_file_get_defext(void);
+
+extern gboolean
+mix_code_file_set_defext(const gchar *ext);
+
+/* create/destroy code files for read or write */
+/* if -name- does not end with defext, it is automatically appended */
+extern mix_code_file_t *
+mix_code_file_new_read(const gchar *name);
+
+/* open a code file for write with/out debug information */
+extern mix_code_file_t *
+mix_code_file_new_write(const gchar *name, mix_address_t start,
+ const gchar *source_path, gboolean debug,
+ const mix_symbol_table_t *table);
+
+extern void
+mix_code_file_delete(mix_code_file_t *file);
+
+/* get general parameters from a code file */
+extern gboolean
+mix_code_file_is_debug(const mix_code_file_t *file);
+
+extern gint
+mix_code_file_major_version(const mix_code_file_t *file);
+
+extern gint
+mix_code_file_minor_version(const mix_code_file_t *file);
+
+extern mix_address_t
+mix_code_file_get_start_addr(const mix_code_file_t *file);
+
+extern mix_symbol_table_t *
+mix_code_file_get_symbol_table(mix_code_file_t *file);
+
+/* read instructions from a code file */
+extern gboolean
+mix_code_file_is_eof(mix_code_file_t *file);
+
+extern gboolean
+mix_code_file_get_ins(mix_code_file_t *file, mix_ins_desc_t *desc);
+
+/* write instructions to a code file */
+extern gboolean
+mix_code_file_write_ins(mix_code_file_t *file, const mix_ins_desc_t *desc);
+
+extern gboolean
+mix_code_file_write_next_ins(mix_code_file_t *file, mix_word_t ins,
+ guint lineno);
+
+extern gboolean
+mix_code_file_set_address(mix_code_file_t *file, mix_address_t address);
+
+/* get details about the source file */
+extern const gchar *
+mix_code_file_get_source_path (const mix_code_file_t *file);
+
+
+#endif /* MIX_CODE_FILE_H */
+
diff --git a/mixlib/mix_config.c b/mixlib/mix_config.c
new file mode 100644
index 0000000..694b18b
--- /dev/null
+++ b/mixlib/mix_config.c
@@ -0,0 +1,298 @@
+/* -*-c-*- -------------- mix_config.c :
+ * Implementation of the functions declared in mix_config.h
+ * ------------------------------------------------------------------
+ * $Id: mix_config.c,v 1.12 2005/09/20 19:43:13 jao Exp $
+ * ------------------------------------------------------------------
+ * Copyright (C) 2001, 2002, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include "mix_config.h"
+
+const gchar *MIX_CONFIG_DIR = ".mdk";
+
+static const gchar COMMENT_PREFIX_ = '#';
+static const gchar *AUTOSAVE_KEY_ = "Autosave";
+static const gchar *AUTOSAVE_YES_ = "True";
+static const gchar *AUTOSAVE_NO_ = "False";
+static const gchar *DEVICES_KEY_ = "Devices.dir";
+static const gchar *HISTORY_KEY_ = "History.file";
+static const gchar *HISTORY_SIZE_KEY_ = "History.size";
+
+/* the config type */
+struct mix_config_t
+{
+ gchar *filename; /* full path to configuration file */
+ gboolean autosave; /* whether save on destroy */
+ GHashTable *items; /* configuration items */
+};
+
+/* create a new config handler, giving the dir and name of the config file */
+mix_config_t *
+mix_config_new (const gchar *dirname, const gchar *filename)
+{
+ static const gchar *DEF_DIRNAME_ = NULL;
+ static const gchar *DEF_FILENAME_ = "config";
+
+ const gchar *autosave;
+ FILE *f;
+ mix_config_t *result = NULL;
+
+ if (DEF_DIRNAME_ == NULL)
+ DEF_DIRNAME_ = g_strconcat (g_get_home_dir (), G_DIR_SEPARATOR_S,
+ MIX_CONFIG_DIR, NULL);
+
+ if (dirname == NULL) dirname = DEF_DIRNAME_;
+ if (filename == NULL) filename = DEF_FILENAME_;
+
+ if (!mix_stat_dir (dirname, "configuration")) return NULL;
+
+ result = g_new (mix_config_t, 1);
+ result->filename = g_strdup_printf ("%s/%s", dirname, filename);
+ result->items = g_hash_table_new (g_str_hash, g_str_equal);
+
+ f = fopen (result->filename, "r");
+ if (f != NULL)
+ {
+ enum {LEN = 256};
+ gchar buffer[LEN];
+ gchar *line = buffer;
+ while (!feof (f))
+ {
+ line = fgets (line, LEN, f);
+ if (line) line = g_strstrip (line);
+ if (line && line[0] != COMMENT_PREFIX_)
+ {
+ gchar **vals = g_strsplit (line, "=", 2);
+ g_hash_table_insert (result->items,
+ (gpointer) g_strstrip (vals[0]),
+ (gpointer) g_strstrip (vals[1]));
+ }
+ }
+ fclose (f);
+ }
+
+ autosave = mix_config_get (result, AUTOSAVE_KEY_);
+ result->autosave = autosave && !g_ascii_strcasecmp (autosave, AUTOSAVE_YES_);
+
+ return result;
+}
+
+/* delete a config handler, saving the configuration if needed */
+void
+mix_config_delete (mix_config_t *config)
+{
+ g_return_if_fail (config != NULL);
+ if (mix_config_is_autosave (config)) mix_config_save (config);
+ g_free (config->filename);
+ g_hash_table_destroy (config->items);
+ g_free (config);
+}
+
+/* get the config filename */
+const gchar *
+mix_config_get_filename (const mix_config_t *config)
+{
+ g_return_val_if_fail (config != NULL, NULL);
+ return config->filename;
+}
+
+/* get a config item's value from its key */
+const gchar *
+mix_config_get (const mix_config_t *config, const gchar *key)
+{
+ g_return_val_if_fail (config != NULL, NULL);
+ g_return_val_if_fail (key != NULL, NULL);
+
+ return (const gchar*)g_hash_table_lookup (config->items, key);
+}
+
+gint
+mix_config_get_integer (const mix_config_t *config, const gchar *key)
+{
+ const gchar *val;
+ g_return_val_if_fail (config != NULL, 0);
+ g_return_val_if_fail (key != NULL, 0);
+ val = mix_config_get (config, key);
+ if (!val) return 0;
+ return atoi (val);
+}
+
+/* update (or create if it does not exist) a new config item */
+void
+mix_config_update (mix_config_t *config, const gchar *key, const gchar *value)
+{
+ gpointer okey = NULL;
+ gpointer oval = NULL;
+
+ g_return_if_fail (config != NULL);
+ g_return_if_fail (key != NULL);
+ g_return_if_fail (value != NULL);
+
+ if (g_hash_table_lookup_extended (config->items, key, &okey, &oval))
+ {
+ if (oval != value)
+ {
+ g_free (oval);
+ oval = (gpointer)g_strdup (value);
+ }
+ }
+ else
+ {
+ okey = (gpointer)g_strdup (key);
+ oval = (gpointer)g_strdup (value);
+ }
+
+ g_hash_table_insert (config->items, okey, oval);
+}
+
+void
+mix_config_update_integer (mix_config_t *config, const gchar *key, gint value)
+{
+ gchar *val;
+
+ g_return_if_fail (config != NULL);
+ g_return_if_fail (key != NULL);
+
+ val = g_strdup_printf ("%d", value);
+ mix_config_update (config, key, val);
+ g_free (val);
+}
+
+void
+mix_config_remove (mix_config_t *config, const gchar *key)
+{
+ gchar *val;
+
+ g_return_if_fail (config != NULL);
+ g_return_if_fail (key != NULL);
+
+ val = g_hash_table_lookup (config->items, key);
+ if (val != NULL)
+ {
+ g_hash_table_remove (config->items, key);
+ g_free (val);
+ }
+}
+
+/* save the current configuration */
+static void
+save_ (gpointer key, gpointer value, gpointer file)
+{
+ fprintf ((FILE *)file, "%s=%s\n", (char *)key, (char *)value);
+}
+
+void
+mix_config_save (const mix_config_t *config)
+{
+ FILE *f;
+
+ g_return_if_fail (config != NULL);
+
+ f = fopen (config->filename, "w");
+ if (!f)
+ {
+ g_warning (_("Unable to open config file %s (%s)"),
+ config->filename, g_strerror (errno));
+ return;
+ }
+ g_hash_table_foreach (config->items, save_, (gpointer)f);
+ fclose (f);
+}
+
+/* set autosave on delete flag */
+void
+mix_config_set_autosave (mix_config_t *config, gboolean autosave)
+{
+ mix_config_update (config, AUTOSAVE_KEY_,
+ autosave? AUTOSAVE_YES_ : AUTOSAVE_NO_);
+ config->autosave = autosave;
+}
+
+
+gboolean
+mix_config_is_autosave (const mix_config_t *config)
+{
+ g_return_val_if_fail (config != NULL, FALSE);
+ return config->autosave;
+}
+
+/* devices dir*/
+void
+mix_config_set_devices_dir (mix_config_t *config, const gchar *dirname)
+{
+ g_return_if_fail (config != NULL);
+ g_return_if_fail (dirname != NULL);
+ if (mix_stat_dir (dirname, "devices"))
+ mix_config_update (config, DEVICES_KEY_, dirname);
+}
+
+extern const gchar *
+mix_config_get_devices_dir (const mix_config_t *config)
+{
+ g_return_val_if_fail (config != NULL, NULL);
+ return mix_config_get (config, DEVICES_KEY_);
+}
+
+/* history file. if relative path, config dir taken as root */
+void
+mix_config_set_history_file (mix_config_t *config, const gchar *path)
+{
+ g_return_if_fail (config != NULL);
+ g_return_if_fail (path != NULL);
+ if (g_path_is_absolute (path))
+ {
+ mix_config_update (config, HISTORY_KEY_, path);
+ }
+ else
+ {
+ gchar *base = g_path_get_dirname (config->filename);
+ gchar *hf = g_strconcat (base, G_DIR_SEPARATOR_S, path, NULL);
+ mix_config_update (config, HISTORY_KEY_, hf);
+ g_free (hf);
+ g_free (base);
+ }
+}
+
+const gchar *
+mix_config_get_history_file (const mix_config_t *config)
+{
+ g_return_val_if_fail (config != NULL, NULL);
+ return mix_config_get (config, HISTORY_KEY_);
+}
+
+void
+mix_config_set_history_size (mix_config_t *config, gint s)
+{
+ g_return_if_fail (config != NULL);
+ g_return_if_fail (s >= 0);
+ mix_config_update_integer (config, HISTORY_SIZE_KEY_, s);
+}
+
+gint
+mix_config_get_history_size (const mix_config_t *config)
+{
+ g_return_val_if_fail (config != NULL, 0);
+ return mix_config_get_integer (config, HISTORY_SIZE_KEY_);
+}
diff --git a/mixlib/mix_config.h b/mixlib/mix_config.h
new file mode 100644
index 0000000..9d2af32
--- /dev/null
+++ b/mixlib/mix_config.h
@@ -0,0 +1,100 @@
+/* -*-c-*- ---------------- mix_config.h :
+ * Basic config storage utility.
+ * ------------------------------------------------------------------
+ * $Id: mix_config.h,v 1.6 2005/09/20 19:43:13 jao Exp $
+ * ------------------------------------------------------------------
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef MIX_CONFIG_H
+#define MIX_CONFIG_H
+
+#include "mix.h"
+
+/* default config dir */
+extern const gchar *MIX_CONFIG_DIR;
+
+/* the config type */
+typedef struct mix_config_t mix_config_t;
+
+/* create a new config handler, giving the dir and name of the config file */
+extern mix_config_t *
+mix_config_new (const gchar *dirname, const gchar *filename);
+
+/* delete a config handler, saving the configuration if needed */
+extern void
+mix_config_delete (mix_config_t *config);
+
+/* get the config filename (fully qualified) */
+extern const gchar *
+mix_config_get_filename (const mix_config_t *config);
+
+/* get a config item's value from its key */
+extern const gchar *
+mix_config_get (const mix_config_t *config, const gchar *key);
+
+extern gint
+mix_config_get_integer (const mix_config_t *config, const gchar *key);
+
+/* update (or create if it does not exist) a new config item */
+extern void
+mix_config_update (mix_config_t *config, const gchar *key, const gchar *value);
+
+extern void
+mix_config_update_integer (mix_config_t *config, const gchar *key, gint value);
+
+extern void
+mix_config_remove (mix_config_t *config, const gchar *key);
+
+/* save the current configuration */
+extern void
+mix_config_save (const mix_config_t *config);
+
+/** shared config params **/
+
+/* set autosave on delete flag */
+extern void
+mix_config_set_autosave (mix_config_t *config, gboolean autosave);
+
+extern gboolean
+mix_config_is_autosave (const mix_config_t *config);
+
+/* devices dir*/
+extern void
+mix_config_set_devices_dir (mix_config_t *config, const gchar *dirname);
+
+extern const gchar *
+mix_config_get_devices_dir (const mix_config_t *config);
+
+/* history file. if relative path, config dir taken as root */
+extern void
+mix_config_set_history_file (mix_config_t *config, const gchar *path);
+
+extern const gchar *
+mix_config_get_history_file (const mix_config_t *config);
+
+extern void
+mix_config_set_history_size (mix_config_t *config, gint s);
+
+extern gint
+mix_config_get_history_size (const mix_config_t *config);
+
+
+#endif /* MIX_CONFIG_H */
+
diff --git a/mixlib/mix_device.c b/mixlib/mix_device.c
new file mode 100644
index 0000000..6a99e8a
--- /dev/null
+++ b/mixlib/mix_device.c
@@ -0,0 +1,164 @@
+/* -*-c-*- -------------- mix_device.c :
+ * Implementation of the functions declared in mix_device.h
+ * ------------------------------------------------------------------
+ * 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
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "mix_file.h"
+#include "xmix_device.h"
+
+/*
+ Set the directory for mix device files (by default, it's ".")
+ If the dir does not exist, it is created.
+*/
+gboolean
+mix_device_set_dir (const gchar *dirname)
+{
+ if (mix_stat_dir (dirname, "devices"))
+ {
+ if (DEV_DIR_) g_free (DEV_DIR_);
+ DEV_DIR_ = g_strdup (dirname);
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+const gchar *
+mix_device_get_dir (void)
+{
+ return DEV_DIR_;
+}
+
+mix_device_t *
+mix_device_new (mix_device_type_t type)
+{
+ mix_device_t *result = NULL;
+ g_return_val_if_fail (type < mix_dev_INVALID, NULL);
+ result = g_new (mix_device_t, 1);
+ construct_device_ (result, type);
+ return result;
+}
+
+
+
+mix_device_t *
+mix_device_new_with_name (mix_device_type_t type, const gchar *name)
+{
+ mix_device_t *result = NULL;
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (type < mix_dev_INVALID, NULL);
+ result = g_new (mix_device_t, 1);
+ construct_device_with_name_ (result, type, name);
+ return result;
+}
+
+/*
+ Create a new device with a given type and stream
+*/
+mix_device_t *
+mix_device_new_with_file (mix_device_type_t type, FILE *file)
+{
+ mix_device_t *result = NULL;
+ g_return_val_if_fail (file != NULL, NULL);
+ g_return_val_if_fail (type < mix_dev_INVALID, NULL);
+ result = g_new (mix_device_t, 1);
+ construct_device_with_file_ (result, type, file);
+ return result;
+}
+
+void
+mix_device_delete (mix_device_t *dev)
+{
+ if (dev != NULL)
+ {
+ (dev->vtable->destroy) (dev);
+ g_free (dev);
+ }
+}
+
+mix_device_type_t
+mix_device_type (const mix_device_t *dev)
+{
+ g_return_val_if_fail (dev != NULL, mix_dev_INVALID);
+ return dev->type;
+}
+
+const char *
+mix_device_get_name (const mix_device_t *dev)
+{
+ g_return_val_if_fail (dev != NULL, NULL);
+ return mix_file_base_name(GET_FILE_(dev));
+}
+
+/*
+ Get the device block size
+*/
+size_t
+mix_device_block_size (const mix_device_t *dev)
+{
+ g_return_val_if_fail (dev != NULL, 0);
+ return SIZES_[dev->type];
+}
+
+/*
+ Get the device io mode
+*/
+mix_device_mode_t
+mix_device_mode (const mix_device_t *dev)
+{
+ g_return_val_if_fail (dev != NULL, 0);
+ return MODES_[dev->type];
+}
+
+/*
+ Write a block to the device.
+*/
+gboolean
+mix_device_write (mix_device_t *dev, const mix_word_t *block)
+{
+ g_return_val_if_fail (dev != NULL, FALSE);
+ g_return_val_if_fail (block != NULL, FALSE);
+ g_assert (dev->vtable != NULL);
+ return (dev->vtable->write) (dev, block);
+}
+
+gboolean
+mix_device_read (mix_device_t *dev, mix_word_t *block)
+{
+ g_return_val_if_fail (dev != NULL, FALSE);
+ g_return_val_if_fail (block != NULL, FALSE);
+ g_assert (dev->vtable != NULL);
+ return (dev->vtable->read) (dev, block);
+}
+
+gboolean
+mix_device_ioc (mix_device_t *dev, mix_short_t arg)
+{
+ g_return_val_if_fail (dev != NULL, FALSE);
+ g_assert (dev->vtable != NULL);
+ return (dev->vtable->ioc) (dev, arg);
+}
+
+gboolean
+mix_device_busy (const mix_device_t *dev)
+{
+ g_return_val_if_fail (dev != NULL, FALSE);
+ return (dev->vtable->busy) (dev);
+
+}
diff --git a/mixlib/mix_device.h b/mixlib/mix_device.h
new file mode 100644
index 0000000..7830dfe
--- /dev/null
+++ b/mixlib/mix_device.h
@@ -0,0 +1,160 @@
+/* -*-c-*- ---------------- mix_device.h :
+ * Declaration of mix_device_t and associated methods.
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000, 2001, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef MIX_DEVICE_H
+#define MIX_DEVICE_H
+
+#include <stddef.h>
+#include <stdio.h>
+#include "mix.h"
+#include "mix_types.h"
+
+/*
+ A mix device, which derives from mix_io_channel_t
+*/
+typedef struct mix_device_t mix_device_t;
+
+/*
+ The device type
+*/
+typedef enum {
+ mix_dev_TAPE_0,
+ mix_dev_TAPE_1,
+ mix_dev_TAPE_2,
+ mix_dev_TAPE_3,
+ mix_dev_TAPE_4,
+ mix_dev_TAPE_5,
+ mix_dev_TAPE_6,
+ mix_dev_TAPE_7,
+ mix_dev_DISK_0,
+ mix_dev_DISK_1,
+ mix_dev_DISK_2,
+ mix_dev_DISK_3,
+ mix_dev_DISK_4,
+ mix_dev_DISK_5,
+ mix_dev_DISK_6,
+ mix_dev_DISK_7,
+ mix_dev_CARD_RD,
+ mix_dev_CARD_WR,
+ mix_dev_PRINTER,
+ mix_dev_CONSOLE,
+ mix_dev_PAPER_TAPE,
+ mix_dev_INVALID
+} mix_device_type_t;
+
+/*
+ The device io mode
+*/
+typedef enum {
+ mix_dev_BIN,
+ mix_dev_CHAR
+} mix_device_mode_t;
+
+/*
+ Set the directory for mix device files (by default, it's ".")
+ If the dir does not exist, it is created.
+*/
+extern gboolean
+mix_device_set_dir (const gchar *dirname);
+
+extern const gchar *
+mix_device_get_dir (void);
+
+/*
+ Create a new device with default name and given type.
+*/
+extern mix_device_t *
+mix_device_new (mix_device_type_t type);
+
+/*
+ Create a new device with a given type and name.
+*/
+extern mix_device_t *
+mix_device_new_with_name (mix_device_type_t type, const gchar *name);
+
+/*
+ Create a new device with a given type and stream
+*/
+extern mix_device_t *
+mix_device_new_with_file (mix_device_type_t type, FILE *file);
+
+/*
+ Delete a device.
+*/
+extern void
+mix_device_delete (mix_device_t *dev);
+
+/*
+ Get a device type
+*/
+extern mix_device_type_t
+mix_device_type (const mix_device_t *dev);
+
+
+/*
+ Get a device name
+*/
+extern const char *
+mix_device_get_name (const mix_device_t *dev);
+
+/*
+ Get the device block size
+*/
+extern size_t
+mix_device_block_size (const mix_device_t *dev);
+
+/*
+ Get the device io mode
+*/
+extern mix_device_mode_t
+mix_device_mode (const mix_device_t *dev);
+
+/*
+ Write a block to the device.
+*/
+extern gboolean
+mix_device_write (mix_device_t *dev, const mix_word_t *block);
+
+/*
+ Read a block from the device.
+*/
+extern gboolean
+mix_device_read (mix_device_t *dev, mix_word_t *block);
+
+/*
+ Perform an io control operation on the device.
+ The parameter _arg_ is the operation's argument:
+ 0- rewind to beginning
+ <0 - rewind the given number of blocks
+ >0 - skip forward the given number of blocks
+*/
+extern gboolean
+mix_device_ioc (mix_device_t *dev, mix_short_t arg);
+
+/*
+ Check if a device is busy
+*/
+extern gboolean
+mix_device_busy (const mix_device_t *dev);
+
+#endif /* MIX_DEVICE_H */
+
diff --git a/mixlib/mix_eval.c b/mixlib/mix_eval.c
new file mode 100644
index 0000000..f6f816a
--- /dev/null
+++ b/mixlib/mix_eval.c
@@ -0,0 +1,191 @@
+/* -*-c-*- -------------- mix_eval.c :
+ * Implementation of the functions declared in mix_eval.h
+ * ------------------------------------------------------------------
+ * Last change: Time-stamp: "01/02/20 00:23:58 jose"
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#include "xmix_eval.h"
+
+
+static const gchar *errors_[] = {
+ N_("Successful evaluation"),
+ N_("Syntax error in expression"),
+ N_("Out of range F-specification"),
+ N_("Mismatched parenthesis"),
+ N_("Undefined symbol"),
+ N_("Internal error")
+};
+
+
+/* create a new evaluator */
+mix_eval_t *
+mix_eval_new (void)
+{
+ mix_eval_t *result = g_new (mix_eval_t, 1);
+ result->table = mix_symbol_table_new ();
+ if (result->table == NULL) {
+ g_free (result);
+ return NULL;
+ }
+ result->towner = TRUE;
+ result->value = MIX_WORD_ZERO;
+ result->errpos = 0;
+ return result;
+}
+
+/* create a new evaluator with an external symbol table */
+mix_eval_t *
+mix_eval_new_with_table (mix_symbol_table_t *table)
+{
+ mix_eval_t *result = g_new (mix_eval_t, 1);
+ result->table = table;
+ result->towner = FALSE;
+ result->value = MIX_WORD_ZERO;
+ result->errpos = 0;
+ return result;
+}
+
+/* delete */
+void
+mix_eval_delete (mix_eval_t *eval)
+{
+ g_return_if_fail (eval);
+ if (eval->table && eval->towner) {
+ mix_symbol_table_delete (eval->table);
+ }
+ g_free (eval);
+}
+
+/* eval an expression */
+mix_eval_result_t
+mix_eval_expression_with_loc (mix_eval_t *eval, const gchar *expr,
+ mix_short_t loc)
+{
+ mix_eval_data_ data;
+
+ if (expr == NULL || eval == NULL)
+ return MIX_EVAL_INTERN;
+ data.expr = g_strdup_printf ("%s\n", expr);
+ data.table = eval->table;
+ data.errpos = eval->errpos;
+ data.value = eval->value;
+ data.loc = loc;
+ eval->result = mix_eval_expr (&data);
+ if (eval->result == MIX_EVAL_OK) {
+ eval->value = data.value;
+ eval->errpos = -1;
+ } else {
+ eval->errpos = data.errpos;
+ }
+ g_free (data.expr);
+
+ return eval->result;
+}
+
+/* get the result of the last evaluation */
+mix_word_t
+mix_eval_value (const mix_eval_t *eval)
+{
+ g_return_val_if_fail (eval != NULL, MIX_WORD_ZERO);
+ return eval->value;
+}
+
+/* get the last eval result code */
+mix_eval_result_t
+mix_eval_last_error (const mix_eval_t *eval)
+{
+ g_return_val_if_fail (eval != NULL, MIX_EVAL_INTERN);
+ return eval->result;
+}
+
+/* get the last error string */
+const gchar*
+mix_eval_last_error_string (const mix_eval_t *eval)
+{
+ g_return_val_if_fail (eval != NULL, errors_[MIX_EVAL_INTERN]);
+ return errors_[eval->result];
+}
+
+/* get the position of last error */
+guint
+mix_eval_last_error_pos (const mix_eval_t *eval)
+{
+ g_return_val_if_fail (eval != NULL, 0);
+ return eval->errpos;
+}
+
+/* add, or redefine, a symbol. see mix_symbol_table.h for
+ possible outcomes. */
+gint
+mix_eval_set_symbol (mix_eval_t *eval, const gchar *symbol,
+ mix_word_t value)
+{
+ g_return_val_if_fail (eval != NULL && eval->table != NULL,
+ MIX_SYM_FAIL);
+ return mix_symbol_table_insert (eval->table, symbol, value);
+}
+
+void
+mix_eval_remove_symbol (mix_eval_t *eval, const gchar *symbol)
+{
+ g_return_if_fail (eval != NULL && eval->table != NULL);
+ mix_symbol_table_remove (eval->table, symbol);
+}
+
+void
+mix_eval_use_symbol_table (mix_eval_t *eval,
+ mix_symbol_table_t *table)
+{
+ g_return_if_fail (eval != NULL);
+ if (eval->table != NULL && eval->towner)
+ mix_symbol_table_delete (eval->table);
+ eval->table = table;
+ eval->towner = FALSE;
+}
+
+const mix_symbol_table_t *
+mix_eval_symbol_table (const mix_eval_t *eval)
+{
+ g_return_val_if_fail (eval != NULL, NULL);
+ return eval->table;
+}
+
+gboolean
+mix_eval_set_symbols_from_table (mix_eval_t *eval,
+ const mix_symbol_table_t *table)
+{
+ g_return_val_if_fail (eval != NULL, FALSE);
+ if (eval->table != NULL)
+ return mix_symbol_table_merge_table (eval->table, table);
+ else
+ return FALSE;
+}
+
+gboolean
+mix_eval_remove_symbols_from_table (mix_eval_t *eval,
+ const mix_symbol_table_t *table)
+{
+ g_return_val_if_fail (eval != NULL, FALSE);
+ if (eval->table != NULL)
+ return mix_symbol_table_substract_table (eval->table, table);
+ else
+ return FALSE;
+}
diff --git a/mixlib/mix_eval.h b/mixlib/mix_eval.h
new file mode 100644
index 0000000..c1c1243
--- /dev/null
+++ b/mixlib/mix_eval.h
@@ -0,0 +1,110 @@
+/* -*-c-*- ---------------- mix_eval.h :
+ * mix_eval_t is an evaluator of MIX W-expressions
+ * ------------------------------------------------------------------
+ * Last change: Time-stamp: <01/02/20 00:23:58 jose>
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef MIX_EVAL_H
+#define MIX_EVAL_H
+
+#include "mix.h"
+#include "mix_types.h"
+#include "mix_symbol_table.h"
+
+/* the evaluator type */
+typedef struct mix_eval_t mix_eval_t;
+
+/* possible evaluation outcomes*/
+typedef enum {
+ MIX_EVAL_OK, /* sucess*/
+ MIX_EVAL_SYNTAX, /* syntax error */
+ MIX_EVAL_INV_FSPEC, /* out of range fspec */
+ MIX_EVAL_MIS_PAREN, /* mismatched parenthesis */
+ MIX_EVAL_UNDEF_SYM, /* undefined symbol */
+ MIX_EVAL_INTERN /* internal error */
+} mix_eval_result_t;
+
+/* create a new evaluator */
+extern mix_eval_t *
+mix_eval_new (void);
+
+/* create a new evaluator with an external symbol table */
+extern mix_eval_t *
+mix_eval_new_with_table (mix_symbol_table_t *table);
+
+/* delete */
+extern void
+mix_eval_delete (mix_eval_t *eval);
+
+/* provide a new symbol table to be used */
+extern void
+mix_eval_use_symbol_table (mix_eval_t *eval,
+ mix_symbol_table_t *table);
+
+extern const mix_symbol_table_t *
+mix_eval_symbol_table (const mix_eval_t *eval);
+
+/* eval an expression providing a value for loc counter */
+extern mix_eval_result_t
+mix_eval_expression_with_loc (mix_eval_t *eval, const gchar *expr,
+ mix_short_t loc);
+/* eval an expression with null loc*/
+#define mix_eval_expression (eval,expr) \
+ mix_eval_expression_with_loc (eval, expr, MIX_SHORT_ZERO)
+
+
+/* get the result of the last evaluation */
+extern mix_word_t
+mix_eval_value (const mix_eval_t *eval);
+
+/* get the last eval result code */
+extern mix_eval_result_t
+mix_eval_last_error (const mix_eval_t *eval);
+
+/* get the last error string */
+extern const gchar*
+mix_eval_last_error_string (const mix_eval_t *eval);
+
+/* get the position of last error */
+extern guint
+mix_eval_last_error_pos (const mix_eval_t *eval);
+
+/* add, or redefine, a symbol. see mix_symbol_table.h for
+ possible outcomes. */
+extern gint
+mix_eval_set_symbol (mix_eval_t *eval, const gchar *symbol,
+ mix_word_t value);
+
+extern gboolean
+mix_eval_set_symbols_from_table (mix_eval_t *eval,
+ const mix_symbol_table_t *table);
+
+extern void
+mix_eval_remove_symbol (mix_eval_t *eval, const gchar *symbol);
+
+extern gboolean
+mix_eval_remove_symbols_from_table (mix_eval_t *eval,
+ const mix_symbol_table_t *table);
+
+
+
+#endif /* MIX_EVAL_H */
+
diff --git a/mixlib/mix_eval_scanner.l b/mixlib/mix_eval_scanner.l
new file mode 100644
index 0000000..8d0d3bd
--- /dev/null
+++ b/mixlib/mix_eval_scanner.l
@@ -0,0 +1,276 @@
+/* -*-c-*- ------------------ mix_eval_scanner.l :
+ * scanner used by mix_eval_t
+ * ------------------------------------------------------------------
+ * $Id: mix_eval_scanner.l,v 1.4 2005/09/20 19:43:13 jao Exp $
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+%{
+#include <string.h>
+#include "mix.h"
+#include "xmix_eval.h"
+
+#define YY_DECL \
+ mix_eval_result_t mix_eval_expr (mix_eval_data_ *data)
+
+/* keep track of current position in buffer */
+#define YY_USER_ACTION yypos += yyleng;
+
+#define RETURN_STATE(err) \
+ do { \
+ done = TRUE; \
+ state = err; \
+ BEGIN (INITIAL); \
+ } while (FALSE)
+
+#define CLEAN_UP() \
+ do { \
+ yy_delete_buffer (buffer); \
+ g_free (expr_cp); \
+ } while (FALSE)
+
+static mix_word_t eval_binop_ (const gchar *op, mix_word_t x, mix_word_t y);
+
+static int unput_word_ (mix_word_t word);
+
+/* { */
+/* gchar *value; */
+/* gint k, result; */
+/* value = g_strdup_printf ("%s%ld", */
+/* mix_word_is_negative (word)? "-":"+", */
+/* mix_word_magnitude (word)); */
+/* result = strlen (value); */
+/* for (k = result - 1; k >= 0; --k) */
+/* unput (value[k]); */
+/* g_free (value); */
+/* return result; */
+/* } */
+
+%}
+
+%option nomain
+%option caseless
+%option array
+%option stack
+%option noyywrap
+%option noyy_top_state
+%option noreject
+%option outfile="lex.yy.c"
+
+%s EVAL
+%s WEVAL
+
+ws [ \t]+
+digit [0-9]
+letter [A-Z]
+number [+-]?{digit}+
+mixchar [0-9A-Z .,'')(+*/=$<>@;:\-]
+locsymbol {digit}H
+flocsymbol {digit}F
+blocsymbol {digit}B
+symbol {digit}*{letter}+[A-Z0-9]*
+binops "+"|"-"|"/"|"//"|":"
+binop {binops}|"*"
+atexpr {digit}+|{symbol}|\*
+expr [+-]?{atexpr}({binop}{1}{atexpr})*
+fpart \({expr}\)
+wexpr {expr}({fpart})?(,{expr}({fpart})?)*
+
+
+%%
+
+%{
+ YY_BUFFER_STATE buffer;
+ mix_word_t expr_val = MIX_WORD_ZERO, wexpr_val = MIX_WORD_ZERO;
+ mix_word_t wexpr_val_tmp = MIX_WORD_ZERO;
+ mix_eval_result_t state = MIX_EVAL_OK;
+ gchar *expr_cp;
+ gint yypos = -22; /* to account for padding */
+ gboolean is_fp = FALSE, done = FALSE;
+ g_assert (data != NULL && data->expr != NULL);
+ /* make room enough to unput computed values */
+ expr_cp = g_strdup_printf ("%-20s%s"," ", data->expr);
+ buffer = yy_scan_string (expr_cp);
+ data->errpos = -1;
+%}
+
+
+<*><<EOF>> {
+ CLEAN_UP ();
+ return MIX_EVAL_INTERN;
+}
+
+<INITIAL>{
+ {ws} /* eat whitespace */
+ . {
+ if (!done && state == MIX_EVAL_OK) {
+ yypos -= yyleng; yyless (0);
+ yy_push_state (WEVAL);
+ } else {
+ CLEAN_UP ();
+ if (state == MIX_EVAL_OK) return (MIX_EVAL_SYNTAX);
+ data->errpos = yypos;
+ return state;
+ }
+ }
+ "\n" {
+ CLEAN_UP();
+ if (state == MIX_EVAL_OK)
+ data->value = wexpr_val;
+ else
+ data->errpos = yypos;
+ return state;
+ }
+}
+
+<WEVAL>{
+ {number}"(" {
+ is_fp = TRUE;
+ wexpr_val_tmp = mix_word_new (atol (yytext));
+ }
+ {number}")" {
+ glong val = atol (yytext);
+ if ( !is_fp ) {
+ RETURN_STATE (MIX_EVAL_MIS_PAREN);
+ } else if ( val < 0 || val > MIX_BYTE_MAX
+ || !mix_fspec_is_valid (mix_byte_new (val)) ) {
+ RETURN_STATE (MIX_EVAL_INV_FSPEC);
+ } else {
+ is_fp = FALSE;
+ wexpr_val = mix_word_store_field (mix_byte_new (val),
+ wexpr_val_tmp,
+ wexpr_val);
+ }
+ }
+ {number}/({ws}*\n)|[,()] {
+ wexpr_val = mix_word_new (atol (yytext));
+ }
+ {expr}/({ws}*\n)|[,()] {
+ if (yytext[0] != '*')
+ {
+ yypos -= yyleng;
+ yyless (0);
+ }
+ else
+ {
+ yypos -= yyleng - 1;
+ expr_val = mix_short_to_word_fast (data->loc);
+ yyless (1);
+ }
+ yy_push_state (EVAL);
+ }
+ ,/{expr} /* eat comma if followed by expression */
+ [\t\n ] { /* ok if not inside an f-part */
+ if ( is_fp ) {
+ RETURN_STATE (MIX_EVAL_MIS_PAREN);
+ }
+ unput (yytext[yyleng-1]); --yypos;
+ done = TRUE;
+ yy_pop_state ();
+ }
+ . RETURN_STATE (MIX_EVAL_SYNTAX);
+}
+
+<EVAL>{
+ {binop}{digit}+ {
+ const gchar *s = ( yytext[1] == '/' ) ? yytext+2 : yytext+1;
+ mix_word_t value = mix_word_new (atol (s));
+ expr_val = eval_binop_ (yytext, expr_val, value);
+ }
+ {binop}{symbol} {
+ const gchar *s = ( yytext[1] == '/' ) ? yytext+2 : yytext+1;
+ if ( !mix_symbol_table_is_defined (data->table, s) ) {
+ RETURN_STATE (MIX_EVAL_UNDEF_SYM);
+ }
+ expr_val = eval_binop_ (yytext, expr_val,
+ mix_symbol_table_value (data->table, s));
+ }
+ {binop}"*" {
+ expr_val = eval_binop_ (yytext, expr_val,
+ mix_short_to_word_fast (data->loc));
+ }
+ "*" yypos -= unput_word_ (mix_short_to_word_fast (data->loc));
+ {number} expr_val = mix_word_new (atol (yytext));
+ {symbol} {
+ if ( !mix_symbol_table_is_defined (data->table, yytext) ) {
+ RETURN_STATE (MIX_EVAL_UNDEF_SYM);
+ }
+ expr_val = mix_symbol_table_value (data->table, yytext);
+ }
+ [,)(\n\t ] {
+ unput (yytext[0]); --yypos;
+ yypos -= unput_word_ (expr_val);
+ yy_pop_state ();
+ }
+
+ . RETURN_STATE (MIX_EVAL_SYNTAX);
+}
+
+
+%%
+
+static mix_word_t
+eval_binop_ (const gchar *op, mix_word_t x, mix_word_t y)
+{
+ mix_word_t result = MIX_WORD_ZERO;
+ switch (op[0])
+ {
+ case '+':
+ result = mix_word_add (x,y);
+ break;
+ case '-':
+ result = mix_word_sub (x,y);
+ break;
+ case '*':
+ mix_word_mul (x, y, NULL, &result);
+ break;
+ case ':':
+ {
+ mix_word_t a;
+ mix_word_mul (x, 8, NULL, &a);
+ result = mix_word_add (a, y);
+ break;
+ }
+ case '/':
+ if ( strlen (op) > 1 && op[1] == '/' ) {
+ mix_word_div (x,MIX_WORD_ZERO,y, &result, NULL);
+ } else {
+ mix_word_div (MIX_WORD_ZERO, x, y, &result, NULL);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ return result;
+}
+
+static int
+unput_word_ (mix_word_t word)
+{
+ gchar *value;
+ gint k, result;
+ value = g_strdup_printf ("%s%ld",
+ mix_word_is_negative (word)? "-":"+",
+ mix_word_magnitude (word));
+ result = strlen (value);
+ for (k = result - 1; k >= 0; --k)
+ unput (value[k]);
+ g_free (value);
+ return result;
+}
diff --git a/mixlib/mix_file.c b/mixlib/mix_file.c
new file mode 100644
index 0000000..383d3b4
--- /dev/null
+++ b/mixlib/mix_file.c
@@ -0,0 +1,159 @@
+/* -*-c-*- -------------- mix_file.c :
+ * Implementation of the functions declared in mix_file.h
+ * ------------------------------------------------------------------
+ * 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
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <string.h>
+
+#include "xmix_io.h"
+#include "mix_file.h"
+
+const gchar *MIX_SRC_DEFEXT = ".mixal",
+ *MIX_LIST_DEFEXT = ".mls", *MIX_CODE_DEFEXT = ".mix";
+
+/* file names completions */
+#define needs_completion_(name,defext) \
+ ( strcmp(name + strlen(name) - strlen(defext), defext) != 0 )
+
+#define add_completion_(name, defext) \
+ g_strconcat(name, defext, NULL)
+
+/* The actual definition of mix_file_t */
+struct mix_file_t
+{
+ mix_iochannel_t parent;
+ gchar *base_name;
+ gchar *ext;
+};
+
+/* Creation/destruction of files */
+static mix_file_t *
+open_file_(const gchar *name, mix_fmode_t mode)
+{
+ mix_file_t *result;
+ FILE *file;
+ const gchar *fmode = fmode_to_type_ (mode);
+
+ /* if the read/write file already exists, open in r+ mode */
+ if (mode == mix_io_RDWRT && (file = fopen (name, "r")))
+ {
+ fmode = "r+";
+ fclose (file);
+ }
+
+ result = g_new(mix_file_t, 1);
+ file = fopen(name, fmode);
+ if ( file == NULL ) {
+ g_free (result);
+ return NULL;
+ }
+ io_init_from_file_(MIX_IOCHANNEL(result), file);
+ return result;
+}
+
+mix_file_t *
+mix_file_new(const gchar *name, mix_fmode_t mode)
+{
+ mix_file_t *result;
+ gchar *bname;
+
+ if ( name == NULL ) return NULL;
+ bname = g_strdup(name);
+ if ( bname == NULL ) return NULL;
+ result = open_file_(name, mode);
+ if ( result == NULL )
+ {
+ g_free(bname);
+ return NULL;
+ }
+ result->base_name = bname;
+ result->ext = NULL;
+ return result;
+}
+
+/* creates a file adding to its name the defext if missing */
+mix_file_t *
+mix_file_new_with_def_ext(const gchar *name, mix_fmode_t mode,
+ const gchar *defext)
+{
+ const gchar *real_name;
+ mix_file_t *result;
+
+ if ( name == NULL ) return NULL;
+ if ( defext == NULL ) return mix_file_new(name, mode);
+ real_name = needs_completion_(name, defext) ?
+ add_completion_(name, defext) : name;
+ result = open_file_(real_name, mode);
+ if ( real_name != name ) g_free((void *)real_name);
+ if ( result == NULL ) return NULL;
+ result->ext = g_strdup(defext);
+ if ( needs_completion_(name, defext) )
+ result->base_name = g_strdup(name);
+ else
+ result->base_name = g_strndup(name, strlen(name) - strlen(defext));
+ if ( result->ext == NULL || result->base_name == NULL )
+ {
+ mix_file_delete(result);
+ return NULL;
+ }
+ return result;
+}
+
+void
+mix_file_delete(mix_file_t *file)
+{
+ g_return_if_fail(file != NULL);
+ io_close_(MIX_IOCHANNEL(file));
+ if (file->base_name) g_free(file->base_name);
+ if (file->ext) g_free(file->ext);
+ g_free(file);
+}
+
+/* convert to a standard FILE */
+extern FILE *
+mix_file_to_FILE(const mix_file_t *file)
+{
+ if ( file == NULL ) return NULL;
+ return io_get_FILE_(file);
+}
+
+/* complete a name with an extension, if needed */
+gchar *
+mix_file_complete_name (const gchar *name, const gchar *extension)
+{
+ if (!name) return NULL;
+ if (!extension || !needs_completion_ (name, extension))
+ return g_strdup (name);
+ return add_completion_ (name, extension);
+}
+
+/* Get the base name and extension of file */
+const gchar *
+mix_file_base_name(const mix_file_t *file)
+{
+ g_return_val_if_fail(file != NULL, NULL);
+ return file->base_name;
+}
+
+const gchar *
+mix_file_extension(const mix_file_t *file)
+{
+ g_return_val_if_fail(file != NULL, NULL);
+ return file->ext;
+}
diff --git a/mixlib/mix_file.h b/mixlib/mix_file.h
new file mode 100644
index 0000000..059eebb
--- /dev/null
+++ b/mixlib/mix_file.h
@@ -0,0 +1,65 @@
+/* -*-c-*- ---------------- mix_file.h :
+ * Declarations for the mix_file_t type.
+ * ------------------------------------------------------------------
+ * 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
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef MIX_FILE_H
+#define MIX_FILE_H
+
+#include "mix_io.h"
+
+/* The mix_file_t type, deriving from mix_iochannel_t and
+ representing a disk file
+*/
+typedef struct mix_file_t mix_file_t;
+
+/* Creation/destruction of files */
+extern mix_file_t *
+mix_file_new(const gchar *name, mix_fmode_t mode);
+
+/* creates a file adding to its name the defext if missing */
+extern mix_file_t *
+mix_file_new_with_def_ext(const gchar *name, mix_fmode_t mode,
+ const gchar *defext);
+
+extern void
+mix_file_delete(mix_file_t *file);
+
+/* convert to a standard FILE */
+extern FILE *
+mix_file_to_FILE(const mix_file_t *file);
+
+/* standard default extensions */
+extern const gchar *MIX_SRC_DEFEXT, *MIX_LIST_DEFEXT, *MIX_CODE_DEFEXT;
+
+/* complete a name with an extension, if needed */
+extern gchar *
+mix_file_complete_name (const gchar *name, const gchar *extension);
+
+/* Get the base name and extension of file */
+extern const gchar *
+mix_file_base_name(const mix_file_t *file);
+
+extern const gchar *
+mix_file_extension(const mix_file_t *file);
+
+
+#endif /* MIX_FILE_H */
+
diff --git a/mixlib/mix_ins.c b/mixlib/mix_ins.c
new file mode 100644
index 0000000..1aa3f70
--- /dev/null
+++ b/mixlib/mix_ins.c
@@ -0,0 +1,269 @@
+/* -*-c-*- ------------------ mix_ins.c :
+ * Implementation of the functions declared in mix_ins.h
+ * ------------------------------------------------------------------
+ * Copyright (C) 1999, 2003 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "mix_ins.h"
+
+
+struct mix_ins_desc_
+{
+ mix_opcode_t opcode;
+ mix_fspec_t def_fspec;
+ const gchar *string_rep;
+ gboolean is_ext;
+};
+
+#define IDES_(c,f,s) {c,f,#s,FALSE}
+#define IDESX_(c,f,s) {c,f,#s,TRUE}
+
+static const struct mix_ins_desc_ id_to_desc_[] = {
+ IDES_(0,0,NOP), IDES_(1,5,ADD), IDES_(2,5,SUB), IDES_(3,5,MUL),
+ IDES_(4,5,DIV),
+ IDESX_(5,0,NUM), IDESX_(5,1,CHAR), IDESX_(5,2,HLT),
+ IDESX_(6,0,SLA), IDESX_(6,1,SRA), IDESX_(6,2,SLAX), IDESX_(6,3,SRAX),
+ IDESX_(6,4,SLC), IDESX_(6,5,SRC),
+ IDES_(7,1,MOVE), IDES_(8,5,LDA), IDES_(9,5,LD1), IDES_(10,5,LD2),
+ IDES_(11,5,LD3), IDES_(12,5,LD4), IDES_(13,5,LD5),
+ IDES_(14,5,LD6), IDES_(15,5,LDX), IDES_(16,5,LDAN), IDES_(17,5,LD1N),
+ IDES_(18,5,LD2N), IDES_(19,5,LD3N), IDES_(20,5,LD4N),
+ IDES_(21,5,LD5N), IDES_(22,5,LD6N), IDES_(23,5,LDXN),
+ IDES_(24,5,STA), IDES_(25,5,ST1), IDES_(26,5,ST2), IDES_(27,5,ST3),
+ IDES_(28,5,ST4), IDES_(29,5,ST5), IDES_(30,5,ST6), IDES_(31,5,STX),
+ IDES_(32,2,STJ), IDES_(33,5,STZ), IDES_(34,0,JBUS), IDES_(35,0,IOC),
+ IDES_(36,0,IN), IDES_(37,0,OUT), IDES_(38,0,JRED),
+ IDESX_(39,0,JMP), IDESX_(39,1,JSJ), IDESX_(39,2,JOV), IDESX_(39,3,JNOV),
+ IDESX_(39,4,JL), IDESX_(39,5,JE), IDESX_(39,6,JG), IDESX_(39,7,JGE),
+ IDESX_(39,8,JNE), IDESX_(39,9,JLE),
+ IDESX_(40,0,JAN), IDESX_(40,1,JAZ), IDESX_(40,2,JAP), IDESX_(40,3,JANN),
+ IDESX_(40,4,JANZ), IDESX_(40,5,JANP),
+ IDESX_(41,0,J1N), IDESX_(41,1,J1Z), IDESX_(41,2,J1P), IDESX_(41,3,J1NN),
+ IDESX_(41,4,J1NZ), IDESX_(41,5,J1NP),
+ IDESX_(42,0,J2N), IDESX_(42,1,J2Z), IDESX_(42,2,J2P), IDESX_(42,3,J2NN),
+ IDESX_(42,4,J2NZ), IDESX_(42,5,J2NP),
+ IDESX_(43,0,J3N), IDESX_(43,1,J3Z), IDESX_(43,2,J3P), IDESX_(43,3,J3NN),
+ IDESX_(43,4,J3NZ), IDESX_(43,5,J3NP),
+ IDESX_(44,0,J4N), IDESX_(44,1,J4Z), IDESX_(44,2,J4P), IDESX_(44,3,J4NN),
+ IDESX_(44,4,J4NZ), IDESX_(44,5,J4NP),
+ IDESX_(45,0,J5N), IDESX_(45,1,J5Z), IDESX_(45,2,J5P), IDESX_(45,3,J5NN),
+ IDESX_(45,4,J5NZ), IDESX_(45,5,J5NP),
+ IDESX_(46,0,J6N), IDESX_(46,1,J6Z), IDESX_(46,2,J6P), IDESX_(46,3,J6NN),
+ IDESX_(46,4,J6NZ), IDESX_(46,5,J6NP),
+ IDESX_(47,0,JXN), IDESX_(47,1,JXZ), IDESX_(47,2,JXP), IDESX_(47,3,JXNN),
+ IDESX_(47,4,JXNZ), IDESX_(47,5,JXNP),
+ IDESX_(48,0,INCA), IDESX_(48,1,DECA), IDESX_(48,2,ENTA), IDESX_(48,3,ENNA),
+ IDESX_(49,0,INC1), IDESX_(49,1,DEC1), IDESX_(49,2,ENT1), IDESX_(49,3,ENN1),
+ IDESX_(50,0,INC2), IDESX_(50,1,DEC2), IDESX_(50,2,ENT2), IDESX_(50,3,ENN2),
+ IDESX_(51,0,INC3), IDESX_(51,1,DEC3), IDESX_(51,2,ENT3), IDESX_(51,3,ENN3),
+ IDESX_(52,0,INC4), IDESX_(52,1,DEC4), IDESX_(52,2,ENT4), IDESX_(52,3,ENN4),
+ IDESX_(53,0,INC5), IDESX_(53,1,DEC5), IDESX_(53,2,ENT5), IDESX_(53,3,ENN5),
+ IDESX_(54,0,INC6), IDESX_(54,1,DEC6), IDESX_(54,2,ENT6), IDESX_(54,3,ENN6),
+ IDESX_(55,0,INCX), IDESX_(55,1,DECX), IDESX_(55,2,ENTX), IDESX_(55,3,ENNX),
+ IDES_(56,5,CMPA), IDES_(57,5,CMP1), IDES_(58,5,CMP2), IDES_(59,5,CMP3),
+ IDES_(60,5,CMP4), IDES_(61,5,CMP5), IDES_(62,5,CMP6), IDES_(63,5,CMPX)
+};
+
+static const gsize ID_TO_DESC_SIZE_=
+sizeof(id_to_desc_)/sizeof(id_to_desc_[0]);
+
+/* To look for the mix_ins_id corresponding to a pair (fspec,opcode)
+ we use an array indexed by opcode with values
+ (initial_ins, final_ins - initial_ins)
+*/
+struct mix_opcode_desc_
+{
+ mix_ins_id_t init_id;
+ guchar inc; /* when inc == 0, the id does not depend on fspec */
+};
+
+static struct mix_opcode_desc_ opcode_to_id_[MIX_BYTE_MAX + 1];
+
+/* a hash table mapping strings to mix_ins_id's */
+static GHashTable *string_to_id_ = NULL;
+
+void
+mix_init_ins (void)
+{
+ guint k;
+ g_assert (ID_TO_DESC_SIZE_ == mix_INVALID_INS);
+
+ for ( k = 0; k < MIX_BYTE_MAX + 1; ++k )
+ {
+ opcode_to_id_[k].init_id = mix_INVALID_INS;
+ opcode_to_id_[k].inc = 0;
+ }
+
+ for ( k = 0; k < ID_TO_DESC_SIZE_; ++k )
+ {
+ if ( opcode_to_id_[id_to_desc_[k].opcode].init_id == mix_INVALID_INS )
+ opcode_to_id_[id_to_desc_[k].opcode].init_id = k;
+ else
+ ++opcode_to_id_[id_to_desc_[k].opcode].inc;
+ }
+
+ if ( string_to_id_ == NULL )
+ {
+ string_to_id_ = g_hash_table_new (g_str_hash, g_str_equal);
+ for ( k = 0; k < ID_TO_DESC_SIZE_; ++k)
+ g_hash_table_insert (string_to_id_, (gpointer)id_to_desc_[k].string_rep,
+ GUINT_TO_POINTER (k));
+ }
+
+}
+
+void
+mix_release_ins (void)
+{
+ g_hash_table_destroy (string_to_id_);
+}
+
+/* Conversions between words and ins */
+mix_word_t
+mix_ins_to_word (const mix_ins_t *ins)
+{
+ g_return_val_if_fail (ins != NULL, MIX_WORD_ZERO);
+ return (mix_word_t)((ins->address<<18)|
+ ((ins->index&7)<<12)|(ins->fspec<<6)|(ins->opcode));
+}
+
+mix_ins_id_t
+mix_word_to_ins (mix_word_t word, mix_ins_t *ins)
+{
+ mix_ins_id_t result = mix_get_ins_id (mix_get_ins_opcode (word),
+ mix_get_ins_fspec (word));
+
+ g_return_val_if_fail (ins != NULL, result);
+ mix_word_to_ins_uncheck (word,*ins);
+ return result;
+}
+
+/* Getting ins parameters */
+mix_opcode_t
+mix_get_opcode_from_id (mix_ins_id_t id)
+{
+ g_return_val_if_fail (id < ID_TO_DESC_SIZE_, MIX_BYTE_ZERO);
+ return id_to_desc_[id].opcode;
+}
+
+gboolean
+mix_ins_id_is_extended (mix_ins_id_t id)
+{
+ g_return_val_if_fail (id < ID_TO_DESC_SIZE_, FALSE);
+ return id_to_desc_[id].is_ext;
+}
+
+
+mix_fspec_t
+mix_get_fspec_from_id (mix_ins_id_t id)
+{
+ g_return_val_if_fail (id < ID_TO_DESC_SIZE_, MIX_BYTE_ZERO);
+ return id_to_desc_[id].def_fspec;
+}
+
+
+const gchar *
+mix_get_string_from_id (mix_ins_id_t id)
+{
+ g_return_val_if_fail (id < ID_TO_DESC_SIZE_, NULL);
+ return id_to_desc_[id].string_rep;
+}
+
+mix_ins_id_t
+mix_get_id_from_string (const gchar *name)
+{
+ gpointer key, value;
+ if ( !g_hash_table_lookup_extended (string_to_id_, (gpointer)name,
+ &key, &value) )
+ return mix_INVALID_INS;
+ return (mix_ins_id_t)GPOINTER_TO_UINT (value);
+}
+
+
+mix_ins_id_t
+mix_get_ins_id (mix_opcode_t code, mix_fspec_t fspec)
+{
+ if ( opcode_to_id_[code].inc == 0 )
+ return opcode_to_id_[code].init_id;
+ else if ( opcode_to_id_[code].inc < fspec )
+ return mix_INVALID_INS;
+ else
+ return (opcode_to_id_[code].init_id + fspec);
+}
+
+/* Printable representation */
+extern gchar * /* this pointer must be freed by caller */
+mix_ins_to_string (const mix_ins_t *ins)
+{
+ gboolean needs_f;
+ gchar *result;
+ mix_ins_id_t id;
+
+ g_return_val_if_fail (ins != NULL, NULL);
+ id = mix_ins_id_from_ins (*ins);
+ needs_f = ins->fspec != id_to_desc_[id].def_fspec;
+ if ( needs_f )
+ result = g_strdup_printf ("%s\t%s%d,%d(%d:%d)",
+ mix_get_string_from_id (id),
+ mix_short_is_negative (ins->address) ? "-" : "",
+ mix_short_magnitude (ins->address), ins->index,
+ mix_fspec_left (ins->fspec),
+ mix_fspec_right (ins->fspec));
+ else
+ result = g_strdup_printf ("%s\t%s%d,%d", mix_get_string_from_id (id),
+ mix_short_is_negative (ins->address) ? "-" : "",
+ mix_short_magnitude (ins->address), ins->index);
+ return result;
+}
+
+extern void
+mix_ins_to_string_in_buffer (const mix_ins_t *ins, gchar *buf, guint len)
+{
+ gboolean needs_f;
+ mix_ins_id_t id;
+
+ g_return_if_fail (ins != NULL);
+ g_return_if_fail (buf != NULL);
+ id = mix_ins_id_from_ins (*ins);
+ needs_f = ins->fspec != id_to_desc_[id].def_fspec;
+ if ( needs_f )
+ g_snprintf (buf, len, "%s\t%s%d,%d(%d:%d)",
+ mix_get_string_from_id (id),
+ mix_short_is_negative (ins->address) ? "-" : "",
+ mix_short_magnitude (ins->address), ins->index,
+ mix_fspec_left (ins->fspec),
+ mix_fspec_right (ins->fspec));
+ else
+ g_snprintf (buf, len, "%s\t%s%d,%d",
+ mix_get_string_from_id (id),
+ mix_short_is_negative (ins->address) ? "-" : "",
+ mix_short_magnitude (ins->address), ins->index);
+}
+
+
+
+void
+mix_ins_print (const mix_ins_t *ins)
+{
+ g_return_if_fail (ins != NULL);
+ g_print (mix_get_string_from_id (mix_ins_id_from_ins (*ins)));
+ g_print (" %s%d,%d(%d:%d)", mix_short_is_negative (ins->address) ? "-" : "+",
+ mix_short_magnitude (ins->address), ins->index,
+ mix_fspec_left (ins->fspec), mix_fspec_right (ins->fspec));
+}
+
diff --git a/mixlib/mix_ins.h b/mixlib/mix_ins.h
new file mode 100644
index 0000000..07d8e38
--- /dev/null
+++ b/mixlib/mix_ins.h
@@ -0,0 +1,195 @@
+/* -*-c-*- -------------------- mix_ins.h:
+ * This file declares types and functions for manipulating MIX
+ * instructions
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef MIX_INS_H
+#define MIX_INS_H
+
+#include "mix_types.h"
+
+
+/* Initialise and free mix_ins data */
+extern void
+mix_init_ins(void);
+
+extern void
+mix_release_ins(void);
+
+/* A MIX instruction is made up of address, index, fspec and op_code */
+
+/*-- Address field: contains two bytes */
+typedef mix_short_t mix_address_t;
+
+/*-- Index field: a value between 0 and 6 */
+typedef enum {
+ mix_I0, mix_I1, mix_I2, mix_I3, mix_I4, mix_I5, mix_I6 } mix_index_t;
+
+/*-- Instruction id: enumeration of MIX instruction set */
+typedef enum {
+ mix_NOP, mix_ADD, mix_SUB, mix_MUL, mix_DIV,
+ mix_NUM, mix_CHAR, mix_HLT,
+ mix_SLA, mix_SRA, mix_SLAX, mix_SRAX, mix_SLC, mix_SRC,
+ mix_MOVE, mix_LDA, mix_LD1, mix_LD2, mix_LD3, mix_LD4, mix_LD5,
+ mix_LD6, mix_LDX, mix_LDAN, mix_LD1N, mix_LD2N, mix_LD3N, mix_LD4N,
+ mix_LD5N, mix_LD6N, mix_LDXN, mix_STA, mix_ST1, mix_ST2, mix_ST3, mix_ST4,
+ mix_ST5, mix_ST6, mix_STX, mix_STJ, mix_STZ, mix_JBUS, mix_IOC, mix_IN,
+ mix_OUT, mix_JRED,
+ mix_JMP, mix_JSJ, mix_JOV, mix_JNOV, mix_JL, mix_JE, mix_JG, mix_JGE,
+ mix_JNE, mix_JLE,
+ mix_JAN, mix_JAZ, mix_JAP, mix_JANN, mix_JANZ, mix_JANP,
+ mix_J1N, mix_J1Z, mix_J1P, mix_J1NN, mix_J1NZ, mix_J1NP,
+ mix_J2N, mix_J2Z, mix_J2P, mix_J2NN, mix_J2NZ, mix_J2NP,
+ mix_J3N, mix_J3Z, mix_J3P, mix_J3NN, mix_J3NZ, mix_J3NP,
+ mix_J4N, mix_J4Z, mix_J4P, mix_J4NN, mix_J4NZ, mix_J4NP,
+ mix_J5N, mix_J5Z, mix_J5P, mix_J5NN, mix_J5NZ, mix_J5NP,
+ mix_J6N, mix_J6Z, mix_J6P, mix_J6NN, mix_J6NZ, mix_J6NP,
+ mix_JXN, mix_JXZ, mix_JXP, mix_JXNN, mix_JXNZ, mix_JXNP,
+ mix_INCA, mix_DECA, mix_ENTA, mix_ENNA,
+ mix_INC1, mix_DEC1, mix_ENT1, mix_ENN1,
+ mix_INC2, mix_DEC2, mix_ENT2, mix_ENN2,
+ mix_INC3, mix_DEC3, mix_ENT3, mix_ENN3,
+ mix_INC4, mix_DEC4, mix_ENT4, mix_ENN4,
+ mix_INC5, mix_DEC5, mix_ENT5, mix_ENN5,
+ mix_INC6, mix_DEC6, mix_ENT6, mix_ENN6,
+ mix_INCX, mix_DECX, mix_ENTX, mix_ENNX,
+ mix_CMPA, mix_CMP1, mix_CMP2, mix_CMP3, mix_CMP4,
+ mix_CMP5, mix_CMP6, mix_CMPX, mix_INVALID_INS
+} mix_ins_id_t;
+
+/* each one of the above id's has associated an opcode, a default
+ fspec and a string representation */
+/* the opcode fits in a byte */
+typedef mix_byte_t mix_opcode_t;
+
+/* labels for each opcode */
+enum {
+ mix_opNOP = 0, mix_opADD, mix_opSUB, mix_opMUL, mix_opDIV,
+ mix_opSPC, mix_opSLx, mix_opMOVE,
+ mix_opLDA, mix_opLD1, mix_opLD2, mix_opLD3, mix_opLD4, mix_opLD5,
+ mix_opLD6, mix_opLDX, mix_opLDAN, mix_opLD1N, mix_opLD2N, mix_opLD3N,
+ mix_opLD4N, mix_opLD5N, mix_opLD6N, mix_opLDXN,
+ mix_opSTA, mix_opST1, mix_opST2, mix_opST3, mix_opST4,
+ mix_opST5, mix_opST6, mix_opSTX, mix_opSTJ, mix_opSTZ,
+ mix_opJBUS, mix_opIOC, mix_opIN, mix_opOUT, mix_opJRED,
+ mix_opJMP, mix_opJAx, mix_opJ1x, mix_opJ2x, mix_opJ3x,
+ mix_opJ4x, mix_opJ5x, mix_opJ6x, mix_opJXx,
+ mix_opINCA, mix_opINC1, mix_opINC2, mix_opINC3,
+ mix_opINC4, mix_opINC5, mix_opINC6, mix_opINCX,
+ mix_opCMPA, mix_opCMP1, mix_opCMP2, mix_opCMP3, mix_opCMP4,
+ mix_opCMP5, mix_opCMP6, mix_opCMPX
+};
+
+extern mix_opcode_t
+mix_get_opcode_from_id(mix_ins_id_t id);
+
+extern mix_fspec_t
+mix_get_fspec_from_id(mix_ins_id_t id);
+
+/* For extended instructions, both the opcode and fspec determine
+ the id (i.e., an explicit fspec cannot be used)
+*/
+extern gboolean
+mix_ins_id_is_extended(mix_ins_id_t id);
+
+extern const gchar *
+mix_get_string_from_id(mix_ins_id_t id);
+
+extern mix_ins_id_t
+mix_get_id_from_string(const gchar *name);
+
+extern mix_ins_id_t
+mix_get_ins_id(mix_opcode_t code, mix_fspec_t fspec);
+
+
+/*-- MIX instruction type */
+typedef struct mix_ins_t mix_ins_t;
+struct mix_ins_t
+{
+ mix_address_t address;
+ mix_index_t index;
+ mix_fspec_t fspec;
+ mix_opcode_t opcode;
+};
+
+#define mix_ins_fill_from_id(ins,id) \
+ do { \
+ (ins).opcode = mix_get_opcode_from_id(id); \
+ (ins).fspec = mix_get_fspec_from_id(id); \
+ } while(FALSE)
+
+
+/* A mix ins can be codified into a word */
+extern mix_word_t
+mix_ins_to_word(const mix_ins_t *ins);
+
+extern mix_ins_id_t
+mix_word_to_ins(mix_word_t w, mix_ins_t *ins);
+
+#define mix_word_add_address(word,addr) (word) |= ((addr)<<18)
+
+/* decompose an instruction codified in a word into its parts */
+#define mix_get_ins_address(word) ((mix_address_t)((word)>>18))
+#define mix_get_ins_index(word) ((mix_index_t)(((word)>>12)&7))
+#define mix_get_ins_fspec(word) ((mix_fspec_t)(mix_byte_new((word)>>6)))
+#define mix_get_ins_opcode(word) ((mix_opcode_t)(mix_byte_new(word)))
+
+/* unchecked versions for speed */
+#define mix_ins_to_word_uncheck(ins) \
+ (mix_word_t)(((ins).address<<18)| \
+ (((ins).index&7)<<12)|((ins).fspec<<6)|((ins).opcode))
+
+#define mix_word_to_ins_uncheck(word,ins) \
+ do { \
+ (ins).address = mix_get_ins_address(word); \
+ (ins).index = mix_get_ins_index(word); \
+ (ins).fspec = mix_get_ins_fspec(word); \
+ (ins).opcode = mix_get_ins_opcode(word); \
+ } while(FALSE)
+
+#define mix_ins_id_from_ins(ins) mix_get_ins_id((ins).opcode,(ins).fspec)
+
+
+/* Printable representation */
+extern gchar * /* this pointer must be freed by caller */
+mix_ins_to_string(const mix_ins_t *ins);
+
+extern void
+mix_ins_to_string_in_buffer (const mix_ins_t *ins, gchar *buf, guint len);
+
+extern void
+mix_ins_print(const mix_ins_t *ins);
+
+
+
+/* A MIX ins has an associated execution time */
+/* Initialise mix_ins data providing an interlock time for I/O devices */
+/* --------------------------------------> MOVE to VM
+typedef guint mix_time_t;
+
+extern void
+mix_init_ins_with_interlock_time(mix_time_t t);
+
+extern mix_time_t
+mix_ins_exec_time(const mix_ins_t *ins);
+*/
+
+#endif /* MIX_INS_H */
diff --git a/mixlib/mix_io.c b/mixlib/mix_io.c
new file mode 100644
index 0000000..31e43df
--- /dev/null
+++ b/mixlib/mix_io.c
@@ -0,0 +1,208 @@
+/* -*-c-*- --------------- mix_io.c :
+ * Implementation of the functions declared in mix_io.h
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#include "xmix_io.h"
+
+mix_iochannel_t *
+mix_io_new (FILE *file)
+{
+ mix_iochannel_t *result;
+ g_return_val_if_fail (file != NULL, NULL);
+ result = g_new (mix_iochannel_t, 1);
+ result->file = file;
+ return result;
+}
+
+void
+mix_io_delete (mix_iochannel_t *ch)
+{
+ if (ch != NULL)
+ {
+ fclose (ch->file);
+ g_free (ch);
+ }
+}
+
+FILE *
+mix_io_to_FILE (mix_iochannel_t *ioc)
+{
+ if (ioc == NULL) return NULL;
+ return ioc->file;
+}
+
+gboolean
+mix_io_eof (mix_iochannel_t *ioc)
+{
+ if (ioc == NULL) return TRUE;
+ return is_eof_ (ioc);
+}
+
+gboolean
+mix_io_is_ready (mix_iochannel_t *ioc)
+{
+ if (ioc == NULL) return FALSE;
+ return is_ready_ (ioc);
+}
+
+gboolean
+mix_io_write_byte (mix_iochannel_t *ioc, mix_byte_t b)
+{
+ if (ioc == NULL) return FALSE;
+ return write_data_ (ioc, &b, 1);
+}
+
+gboolean
+mix_io_write_byte_array (mix_iochannel_t *ioc, const mix_byte_t *b,
+ size_t s)
+{
+ if (ioc == NULL || b == NULL) return FALSE;
+ return write_data_ (ioc, b, s);
+}
+
+mix_byte_t
+mix_io_read_byte (mix_iochannel_t *ioc)
+{
+ mix_byte_t result = MIX_BYTE_ZERO;
+ if (ioc != NULL) read_data_ (ioc, &result, 1);
+ return result;
+}
+
+gboolean
+mix_io_read_byte_array (mix_iochannel_t *ioc, mix_byte_t *b, size_t s)
+{
+ return (ioc != NULL) && (b != NULL) && read_data_ (ioc, b, s);
+}
+
+gboolean
+mix_io_write_word (mix_iochannel_t *ioc, mix_word_t w)
+{
+ return (ioc != NULL) && write_data_ (ioc, &w, 1);
+}
+
+gboolean
+mix_io_write_word_array (mix_iochannel_t *ioc, const mix_word_t *w,
+ size_t s)
+{
+ return (ioc != NULL) && (w != NULL) && write_data_ (ioc, w, s);
+}
+
+mix_word_t
+mix_io_read_word (mix_iochannel_t *ioc)
+{
+ mix_word_t result = MIX_WORD_ZERO;
+ if (ioc != NULL) read_data_ (ioc, &result, 1);
+ return result;
+}
+
+gboolean
+mix_io_read_word_array (mix_iochannel_t *ioc, mix_word_t *w, size_t s)
+{
+ return (ioc != NULL) && (w != NULL) && read_data_ (ioc, w, s);
+}
+
+gboolean
+mix_io_write_short (mix_iochannel_t *ioc, mix_short_t w)
+{
+ return (ioc != NULL) && write_data_ (ioc, &w, 1);
+}
+
+gboolean
+mix_io_write_short_array (mix_iochannel_t *ioc, const mix_short_t *w,
+ size_t s)
+{
+ return (ioc != NULL) && (w != NULL) && write_data_ (ioc, w, s);
+}
+
+mix_short_t
+mix_io_read_short (mix_iochannel_t *ioc)
+{
+ mix_short_t result = MIX_SHORT_ZERO;
+ if (ioc != NULL) read_data_ (ioc, &result, 1);
+ return result;
+}
+
+gboolean
+mix_io_read_short_array (mix_iochannel_t *ioc, mix_short_t *w, size_t s)
+{
+ return (ioc != NULL) && (w != NULL) && read_data_ (ioc, w, s);
+}
+
+gboolean
+mix_io_write_char (mix_iochannel_t *ioc, mix_char_t c)
+{
+ guchar value = mix_char_to_ascii (c);
+ return (ioc != NULL) && write_data_ (ioc, &value, 1);
+}
+
+mix_char_t
+mix_io_read_char (mix_iochannel_t *ioc)
+{
+ guchar value = MIX_CHAR_MAX;
+ if (ioc != NULL) read_data_ (ioc, &value, 1);
+ return mix_ascii_to_char (value);
+}
+
+gboolean
+mix_io_write_word_array_as_char (mix_iochannel_t *ioc,
+ const mix_word_t *w, size_t s)
+{
+ guint k, j;
+ guchar value;
+
+ if ((ioc == NULL) || (w == NULL)) return FALSE;
+
+ for (k = 0; k < s; k++)
+ for (j = 1; j < 6; j++)
+ {
+ mix_char_t ch = mix_byte_to_char (mix_word_get_byte (w[k], j));
+ value = mix_char_to_ascii (ch);
+ if (!write_data_ (ioc, &value, 1)) return FALSE;
+ }
+ value = '\n';
+ return write_data_ (ioc, &value, 1);
+}
+
+gboolean
+mix_io_read_word_array_as_char (mix_iochannel_t *ioc,
+ mix_word_t *w, size_t s)
+{
+ guint k, j;
+ guchar value;
+ gboolean eol = FALSE;
+ mix_char_t spc = mix_ascii_to_char (' ');
+
+ if ((ioc == NULL) || (w == NULL)) return FALSE;
+
+ for (k = 0; k < s && !eol; k++)
+ for (j = 1; j < 6; j++)
+ {
+ if (!eol && !read_data_ (ioc, &value, 1)) return FALSE;
+ eol = eol || (value == '\n') || is_eof_ (ioc);
+ mix_word_set_byte (&w[k], j, eol? spc : mix_ascii_to_char (value));
+ }
+ for (; k < s; ++k) w[k] = MIX_WORD_ZERO;
+
+ while (!eol && !is_eof_ (ioc) && value != '\n')
+ if (!read_data_ (ioc, &value, 1)) return FALSE;
+
+ return TRUE;
+}
diff --git a/mixlib/mix_io.h b/mixlib/mix_io.h
new file mode 100644
index 0000000..0e79d67
--- /dev/null
+++ b/mixlib/mix_io.h
@@ -0,0 +1,119 @@
+/* -*-c-*- ------------------ mix_io.h :
+ * Declarations for mix_iochannel_t and mix_file_t
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef MIX_IOCHANNEL_H
+#define MIX_IOCHANNEL_H
+
+#include <stdio.h>
+#include "mix_types.h"
+
+/* mix_iochannel_t: an object for input/output of mix types */
+typedef struct mix_iochannel_t mix_iochannel_t;
+
+/* Cast to mix_iochannel_t */
+#define MIX_IOCHANNEL(file) (mix_iochannel_t *)(file)
+
+/* I/O channels can be created in different modes: */
+typedef enum {
+ mix_io_READ, /* read existing file */
+ mix_io_WRITE, /* write new file */
+ mix_io_RDWRT, /* read/write existing from beginning */
+ mix_io_APPEND, /* append to existing or new file */
+ mix_io_RAPPEND /* read from beginning, append to end */
+} mix_fmode_t;
+
+/* Create from a file handle */
+extern mix_iochannel_t *
+mix_io_new (FILE *file);
+
+/* Delete */
+extern void
+mix_io_delete (mix_iochannel_t *ch);
+
+/* Convert to a FILE * */
+extern FILE *
+mix_io_to_FILE (mix_iochannel_t *ioc);
+
+/* Read/write from/to an iochannel */
+extern gboolean
+mix_io_eof (mix_iochannel_t *ioc);
+
+extern gboolean
+mix_io_is_ready (mix_iochannel_t *ioc);
+
+extern gboolean
+mix_io_write_byte (mix_iochannel_t *ioc, mix_byte_t b);
+
+extern gboolean
+mix_io_write_byte_array (mix_iochannel_t *ioc, const mix_byte_t *b, size_t s);
+
+
+extern mix_byte_t
+mix_io_read_byte (mix_iochannel_t *ioc);
+
+extern gboolean
+mix_io_read_byte_array (mix_iochannel_t *ioc, mix_byte_t *b, size_t s);
+
+
+extern gboolean
+mix_io_write_word (mix_iochannel_t *ioc, mix_word_t w);
+
+
+extern gboolean
+mix_io_write_word_array (mix_iochannel_t *ioc, const mix_word_t *w, size_t s);
+
+extern mix_word_t
+mix_io_read_word (mix_iochannel_t *ioc);
+
+extern gboolean
+mix_io_read_word_array (mix_iochannel_t *ioc, mix_word_t *w, size_t s);
+
+extern gboolean
+mix_io_write_short (mix_iochannel_t *ioc, mix_short_t w);
+
+
+extern gboolean
+mix_io_write_short_array (mix_iochannel_t *ioc, const mix_short_t *w, size_t s);
+
+extern mix_short_t
+mix_io_read_short (mix_iochannel_t *ioc);
+
+extern gboolean
+mix_io_read_short_array (mix_iochannel_t *ioc, mix_short_t *w, size_t s);
+
+extern gboolean
+mix_io_write_char (mix_iochannel_t *ioc, mix_char_t c);
+
+extern mix_char_t
+mix_io_read_char (mix_iochannel_t *ioc);
+
+extern gboolean
+mix_io_write_word_array_as_char (mix_iochannel_t *ioc,
+ const mix_word_t *w, size_t s);
+
+extern gboolean
+mix_io_read_word_array_as_char (mix_iochannel_t *ioc,
+ mix_word_t *w, size_t s);
+
+
+#endif /* MIX_IOCHANNEL_H */
+
diff --git a/mixlib/mix_parser.c b/mixlib/mix_parser.c
new file mode 100644
index 0000000..0dfcf81
--- /dev/null
+++ b/mixlib/mix_parser.c
@@ -0,0 +1,605 @@
+/* -*-c-*- -------------- mix_parser.c :
+ * Implementation of the functions declared in mix_parser.h and
+ * xmix_parser.h
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000, 2001, 2003, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <string.h>
+
+#include "mix.h"
+#include "mix_code_file.h"
+#include "xmix_parser.h"
+
+/* The flex-generated scanner, according to file mix_scanner.l */
+extern mix_parser_err_t
+mix_flex_scan (mix_parser_t *parser);
+
+/*------------ mixparser.h functions -------------------------------------*/
+
+/* error messages */
+static const gchar * const ERR_MESSAGE_[] = {
+ N_("successful compilation"),
+ N_("file not yet compiled"),
+ N_("internal error"),
+ N_("unable to open MIX source file"),
+ N_("unable to open MIX output file"),
+ N_("unexpected end of file"),
+ N_("invalid location field"),
+ N_("duplicated symbol"),
+ N_("symbol too long"),
+ N_("missing operator field"),
+ N_("unexpected location symbol"),
+ N_("invalid address field"),
+ N_("invalid index field"),
+ N_("invalid f-specification"),
+ N_("invalid operation field"),
+ N_("invalid expression"),
+ N_("undefined symbol"),
+ N_("mismatched parenthesis"),
+ N_("unexpected f-specfication"),
+ N_("missing symbol name"),
+ N_("symbol is an instruction name"),
+ N_("failed write access to code file"),
+ N_("operand of ALF pseudo instruction has less than 5 chars"),
+ N_("operand of ALF pseudo instruction has more than 5 chars"),
+ N_("operand of ALF pseudo instruction must be quoted")
+};
+
+static const guint NO_OF_MESSAGES_ = sizeof(ERR_MESSAGE_)/sizeof (gchar*);
+
+const gchar *
+mix_parser_err_string (mix_parser_err_t error)
+{
+ return (error < NO_OF_MESSAGES_) ? _(ERR_MESSAGE_[error]) : NULL;
+}
+
+guint
+mix_parser_err_count (const mix_parser_t *parser)
+{
+ return (parser) ? parser->err_count : 0;
+}
+
+guint
+mix_parser_warning_count (const mix_parser_t *parser)
+{
+ return (parser) ? parser->warn_count : 0;
+}
+
+const gchar *
+mix_parser_src_file_base_name (const mix_parser_t *parser)
+{
+ return (parser) ? mix_file_base_name (parser->in_file) : NULL;
+}
+
+const gchar *
+mix_parser_src_file_extension (const mix_parser_t *parser)
+{
+ return (parser) ? mix_file_extension (parser->in_file) : NULL;
+}
+
+
+/* Create/destroy a mix_parser */
+/* compare function for the table of ins */
+static gint
+compare_shorts_ (gconstpointer s1, gconstpointer s2)
+{
+ mix_short_t a = (mix_short_t)GPOINTER_TO_UINT (s1);
+ mix_short_t b = (mix_short_t)GPOINTER_TO_UINT (s2);
+ if ( mix_short_sign (a) == mix_short_sign (b) )
+ return mix_short_magnitude (a) - mix_short_magnitude (b);
+ else if ( mix_short_magnitude (a) == 0 && mix_short_magnitude (b) == 0 )
+ return 0;
+ else if ( mix_short_is_positive (a) )
+ return 1;
+ return -1;
+}
+
+mix_parser_t *
+mix_parser_new (const gchar *in_file)
+{
+ mix_parser_t *result;
+ mix_file_t *f = mix_file_new_with_def_ext (in_file, mix_io_READ,
+ MIX_SRC_DEFEXT);
+
+ if ( f == NULL ) return NULL;
+ result = g_new (mix_parser_t, 1);
+ result->symbol_table = mix_symbol_table_new ();
+ result->ls_table = mix_symbol_table_new ();
+ result->cur_ls = 0;
+ result->future_refs = g_hash_table_new (g_str_hash, g_str_equal);
+ result->ins_table = g_tree_new (compare_shorts_);
+ if ( result->symbol_table == NULL || result->future_refs == NULL
+ || result->ins_table == NULL || result->ls_table == NULL )
+ {
+ mix_symbol_table_delete (result->symbol_table);
+ mix_symbol_table_delete (result->ls_table);
+ g_hash_table_destroy (result->future_refs);
+ g_tree_destroy (result->ins_table);
+ mix_file_delete (f);
+ g_free (result);
+ g_warning (_("No system resources"));
+ return NULL;
+ }
+ result->con_list = NULL;
+ result->alf_list = NULL;
+ result->in_file = f;
+ result->loc_count = MIX_SHORT_ZERO;
+ result->start = MIX_SHORT_ZERO;
+ result->end = MIX_SHORT_ZERO;
+ result->status = MIX_PERR_NOCOMP;
+ result->err_line = 0;
+ result->err_count = 0;
+ result->warn_count = 0;
+ return result;
+}
+
+static void
+delete_list_vals_ (gpointer key, gpointer value, gpointer data)
+{
+ g_free (key);
+ g_slist_free ((GSList*)value);
+}
+
+static int
+delete_tree_vals_ (gpointer key, gpointer value, gpointer data)
+{
+ g_free (value);
+ return FALSE;
+}
+
+void
+mix_parser_delete (mix_parser_t *parser)
+{
+ g_return_if_fail (parser != NULL);
+ /* clear the GSList values of future_refs and its keys */
+ g_hash_table_foreach (parser->future_refs, delete_list_vals_, NULL);
+ /* clear the ins_node_'s of the ins tree */
+ g_tree_foreach (parser->ins_table, delete_tree_vals_, NULL);
+ /* destroy the tree and hash tables */
+ g_tree_destroy (parser->ins_table);
+ mix_symbol_table_delete (parser->symbol_table);
+ mix_symbol_table_delete (parser->ls_table);
+ g_hash_table_destroy (parser->future_refs);
+ g_slist_free (parser->con_list);
+ g_slist_free (parser->alf_list);
+ mix_file_delete (parser->in_file);
+ g_free (parser);
+}
+
+/* Compile a mix source file */
+static void
+update_future_refs_value_ (mix_parser_t *parser, const gchar *name,
+ mix_short_t value, gboolean remove)
+{
+ GSList *list = NULL;
+ gpointer *plist = (gpointer *)(&list);
+ gpointer key;
+
+ g_assert (parser != NULL && name != NULL);
+ if ( g_hash_table_lookup_extended (parser->future_refs, name, &key, plist) )
+ {
+ GSList *tmp = list;
+ ins_node_ *node;
+ while ( tmp != NULL )
+ {
+ node =
+ (ins_node_ *)g_tree_lookup (parser->ins_table, tmp->data);
+ g_assert (node);
+ if (mix_get_ins_address (node->ins) == 1) {
+ value = mix_short_negative (value);
+ node->ins = mix_word_set_field (node->ins,
+ MIX_WORD_ZERO,
+ mix_fspec_new (1,2));
+ }
+ mix_word_add_address (node->ins, value);
+ g_tree_insert (parser->ins_table, tmp->data, (gpointer)node);
+ tmp = g_slist_next (tmp);
+ }
+ if (remove) {
+ g_hash_table_remove (parser->future_refs, name);
+ g_free (key);
+ }
+ g_slist_free (list);
+ }
+}
+
+#define update_future_refs_(parser,name,rem) \
+ update_future_refs_value_(parser, name, (parser)->loc_count, rem)
+
+static void
+update_ls_ (gpointer symbol, gpointer value, gpointer parser)
+{ /* add an instruction on current location and update refs to it */
+ mix_ins_t ins;
+ mix_word_t w = (mix_word_t) GPOINTER_TO_UINT (value);
+ mix_parser_t *par = (mix_parser_t *) parser;
+
+ mix_word_to_ins_uncheck (w, ins);
+ update_future_refs_ (par, (const gchar *)symbol, TRUE);
+ mix_parser_add_ins (par, &ins, 0);
+ par->loc_count++;
+}
+
+static gboolean
+undef_warning_ (gpointer symbol, gpointer value, gpointer data)
+{
+ mix_parser_t *parser = (mix_parser_t *)data;
+ const gchar *name = (const gchar *)symbol;
+ mix_ins_t ins;
+
+ mix_parser_log_error (parser, MIX_PERR_UNDEF_SYM, 0, name, TRUE);
+
+ mix_word_to_ins_uncheck (MIX_WORD_ZERO, ins);
+ update_future_refs_ (parser, name, FALSE);
+ mix_parser_add_ins (parser, &ins, 0);
+ mix_symbol_table_insert (parser->symbol_table, name,
+ mix_short_to_word_fast (parser->loc_count));
+
+ parser->loc_count++;
+ return TRUE;
+}
+
+mix_parser_err_t
+mix_parser_compile (mix_parser_t *parser)
+{
+ g_return_val_if_fail (parser != NULL, MIX_PERR_INTERNAL);
+ g_return_val_if_fail (parser->in_file != NULL, MIX_PERR_NOIN);
+ g_return_val_if_fail (parser->symbol_table != NULL, MIX_PERR_INTERNAL);
+ g_return_val_if_fail (parser->future_refs != NULL, MIX_PERR_INTERNAL);
+ g_return_val_if_fail (parser->ins_table != NULL, MIX_PERR_INTERNAL);
+
+ parser->status = mix_flex_scan (parser);
+
+ if ( parser->status == MIX_PERR_OK )
+ {
+ parser->loc_count = parser->end;
+ mix_symbol_table_foreach (parser->ls_table, update_ls_, (gpointer)parser);
+ if ( g_hash_table_size (parser->future_refs) > 0)
+ {
+ g_hash_table_foreach_remove (parser->future_refs,
+ undef_warning_, (gpointer)parser);
+ }
+ }
+
+ return parser->status;
+}
+
+/* Write a compiled source to a code file */
+struct write_code_context_
+{
+ mix_code_file_t *file;
+ mix_parser_t *parser;
+};
+
+static gint
+write_code_ (gpointer address, gpointer ins_node, gpointer context)
+{
+ mix_ins_desc_t desc;
+ struct write_code_context_ *cntx = (struct write_code_context_ *)context;
+ desc.ins = ((ins_node_ *)ins_node)->ins;
+ desc.lineno = ((ins_node_ *)ins_node)->lineno;
+ desc.address = (mix_address_t)GPOINTER_TO_UINT (address);
+ if ( mix_code_file_write_ins (cntx->file, &desc) )
+ return FALSE;
+ else
+ {
+ cntx->parser->status = MIX_PERR_NOWRITE;
+ return TRUE;
+ }
+}
+
+mix_parser_err_t
+mix_parser_write_code (mix_parser_t *parser, const gchar *code_file,
+ gboolean debug)
+{
+ struct write_code_context_ context;
+ const gchar *cfname = (code_file) ?
+ code_file : mix_file_base_name (parser->in_file);
+ gchar *source_path;
+
+ g_return_val_if_fail (parser != NULL, MIX_PERR_INTERNAL);
+ if (parser->status != MIX_PERR_OK ) return parser->status;
+ context.parser = parser;
+ if (!g_path_is_absolute (mix_file_base_name (parser->in_file)))
+ {
+ gchar *dir = g_get_current_dir ();
+ source_path = g_strconcat (dir, G_DIR_SEPARATOR_S,
+ mix_file_base_name (parser->in_file), NULL);
+ g_free (dir);
+ }
+ else
+ source_path = g_strdup (mix_file_base_name (parser->in_file));
+
+ context.file = mix_code_file_new_write (cfname, parser->start, source_path,
+ debug, parser->symbol_table);
+ g_free (source_path);
+
+ if (context.file == NULL) return MIX_PERR_NOOUT;
+ g_tree_foreach (parser->ins_table, write_code_, (gpointer)&context);
+ mix_code_file_delete (context.file);
+ return parser->status;
+}
+
+/* Produce a listing file summarising the compilation */
+typedef struct
+{
+ FILE *file;
+ mix_parser_t *parser;
+} listing_context_t;
+
+static gint
+write_listing_ (gpointer address, gpointer ins, gpointer context)
+{
+ guint k;
+ FILE *file = ((listing_context_t *)context)->file;
+ mix_parser_t *parser = ((listing_context_t *)context)->parser;
+ guint end = parser->end;
+ ins_node_ *ins_node = (ins_node_ *)ins;
+ mix_ins_t instruct;
+
+ fprintf (file, "%03d %05d %s ",
+ ins_node->lineno,
+ GPOINTER_TO_INT (address),
+ mix_word_is_negative (ins_node->ins)? "-":"+");
+ for ( k = 1; k < 6; ++k )
+ fprintf (file, "%02d ", mix_word_get_byte (ins_node->ins, k));
+
+ if (g_slist_find (parser->con_list, GUINT_TO_POINTER (ins_node->lineno))
+ || GPOINTER_TO_UINT (address) >= end)
+ fprintf (file, "\tCON\t%04d\n", (int)(ins_node->ins));
+ else if (g_slist_find (parser->alf_list, GUINT_TO_POINTER (ins_node->lineno)))
+ {
+ size_t i;
+ fprintf (file, "\tALF\t\"");
+ for (i = 1; i < 6; ++i)
+ fprintf (file, "%c",
+ mix_char_to_ascii (mix_byte_to_char
+ (mix_word_get_byte (ins_node->ins, i))));
+ fprintf (file, "\"\n");
+ }
+ else if (GPOINTER_TO_UINT (address) < end)
+ {
+ gchar *instext = NULL;
+ mix_ins_id_t id = mix_word_to_ins (ins_node->ins, &instruct);
+ if (id != mix_INVALID_INS)
+ instext = mix_ins_to_string (&instruct);
+ fprintf (file, _("\t%s\n"), instext? instext : _("UNKNOWN"));
+ if (instext) g_free (instext);
+ }
+ else
+ g_assert_not_reached ();
+
+ return FALSE;
+}
+
+mix_parser_err_t
+mix_parser_write_listing (mix_parser_t *parser, const gchar *list_file)
+{
+ mix_file_t *mfile;
+ const gchar *name;
+ listing_context_t context;
+ static const char *sep =
+ "-----------------------------------------------------------------\n";
+
+ g_return_val_if_fail (parser != NULL, MIX_PERR_INTERNAL);
+ if (parser->status != MIX_PERR_OK ) return parser->status;
+ name = (list_file) ? list_file : mix_file_base_name (parser->in_file);
+ mfile = mix_file_new_with_def_ext (name, mix_io_WRITE, MIX_LIST_DEFEXT);
+ if ( mfile == NULL ) return MIX_PERR_NOOUT;
+ context.file = mix_file_to_FILE (mfile);
+ context.parser = parser;
+ fprintf (context.file, _("*** %s%s: compilation summary ***\n\n"),
+ mix_file_base_name (parser->in_file),
+ mix_file_extension (parser->in_file));
+ fputs (sep, context.file);
+ fputs ( _("Src Address Compiled word Symbolic rep\n"),
+ context.file);
+ fputs (sep, context.file);
+ g_tree_foreach (parser->ins_table, write_listing_, (gpointer)(&context));
+ fputs (sep, context.file);
+ fprintf (context.file, _("\n*** Start address:\t%d\n*** End address:\t%d\n"),
+ mix_short_magnitude (parser->start),
+ mix_short_magnitude (parser->end));
+ fprintf (context.file, _("\n*** Symbol table\n"));
+ mix_symbol_table_print (parser->symbol_table, MIX_SYM_ROWS,
+ context.file, TRUE);
+ fprintf (context.file, _("\n*** End of summary ***\n"));
+ mix_file_delete (mfile);
+ return parser->status;
+}
+
+/* load a virtual machine's memory with the contents of a compiled file */
+static gint
+load_vm_ (gpointer address, gpointer ins, gpointer vm)
+{
+ mix_vm_set_addr_contents ((mix_vm_t*)vm,
+ (mix_address_t)GPOINTER_TO_UINT (address),
+ ((ins_node_ *)ins)->ins);
+ return FALSE;
+}
+
+mix_parser_err_t
+mix_parser_load_vm (const mix_parser_t *parser, mix_vm_t *vm)
+{
+ g_return_val_if_fail (parser != NULL, MIX_PERR_INTERNAL);
+ g_return_val_if_fail (vm != NULL, MIX_PERR_INTERNAL);
+ g_return_val_if_fail (parser->status == MIX_PERR_OK, parser->status);
+ mix_vm_reset (vm);
+ g_tree_foreach (parser->ins_table, load_vm_, (gpointer)vm);
+ mix_vm_set_start_addr (vm, parser->start);
+ return parser->status;
+}
+
+
+
+/*------------ xmiparser.h functions -------------------------------------*/
+/* functions to manipulate mix_parser_t during compilation */
+
+
+/* symbol table */
+/* Define a new symbol with value equal to the current loc_count
+ * and update future refs to this symbol
+ */
+mix_parser_err_t
+mix_parser_define_symbol_here (mix_parser_t *parser, const gchar *name)
+{
+ mix_word_t value = mix_short_to_word_fast (parser->loc_count);
+ return mix_parser_define_symbol_value (parser, name, value);
+}
+
+mix_parser_err_t
+mix_parser_define_symbol_value (mix_parser_t *parser, const gchar *name,
+ mix_word_t value)
+{
+ g_assert (parser != NULL && name != NULL);
+
+ switch (mix_symbol_table_add (parser->symbol_table, name, value))
+ {
+ case MIX_SYM_OK:
+ if ( parser->status == MIX_PERR_NOCOMP )
+ update_future_refs_value_ (parser, name, value, TRUE);
+ return MIX_PERR_OK;
+ case MIX_SYM_LONG: return MIX_PERR_LONG_SYMBOL;
+ case MIX_SYM_DUP: return MIX_PERR_DUP_SYMBOL;
+ default: return MIX_PERR_INTERNAL;
+ }
+}
+
+/* Obtain the value of a symbol */
+void
+mix_parser_set_future_ref (mix_parser_t *parser, const gchar *name)
+{
+ const gchar *nname = name;
+ GSList *list;
+
+ g_assert (parser != NULL && name != NULL);
+
+ if ( parser->status == MIX_PERR_NOCOMP )
+ {
+ list = g_hash_table_lookup (parser->future_refs, name);
+ if ( list == NULL ) nname = g_strdup (name);
+ list = g_slist_prepend (list, (gpointer)((guint)parser->loc_count));
+ g_hash_table_insert (parser->future_refs, (gpointer)nname, list);
+ }
+}
+
+/* Redefine the value of a local symbol as the current loc_count */
+void
+mix_parser_manage_local_symbol (mix_parser_t *parser, const gchar *name,
+ mix_short_t value)
+{
+ gchar ref[3];
+ ref[2] = 0;
+
+ g_assert (parser != NULL && name != NULL);
+ g_assert (strlen(name) == 2);
+
+ switch (name[1])
+ {
+ case 'f': case 'F':
+ mix_parser_set_future_ref (parser, name);
+ break;
+ case 'h': case 'H':
+ ref[0] = name[0];
+ ref[1] = 'F';
+ if ( parser->status == MIX_PERR_NOCOMP )
+ update_future_refs_value_ (parser, ref, value, TRUE);
+ ref[1] = 'B';
+ mix_symbol_table_insert (parser->symbol_table, ref,
+ mix_short_to_word_fast (value));
+ break;
+ default:
+ return;
+ }
+}
+
+/* Literal strings symbols */
+void
+mix_parser_define_ls (mix_parser_t *parser, mix_word_t value)
+{
+ gchar *name = g_strdup_printf ("%05d", parser->cur_ls++);
+ mix_symbol_table_add (parser->ls_table, name, value);
+ mix_parser_set_future_ref (parser, name);
+ g_free (name);
+}
+
+/* Compilation */
+static void
+add_raw_ (mix_parser_t *parser, mix_word_t word, guint lineno)
+{
+ if ( parser->status == MIX_PERR_NOCOMP || parser->status == MIX_PERR_OK )
+ {
+ ins_node_ *node = g_new (ins_node_, 1);
+ node->ins = word;
+ node->lineno = lineno;
+ g_tree_insert (parser->ins_table, (gpointer)((guint)parser->loc_count),
+ (gpointer)node);
+ }
+}
+
+void
+mix_parser_add_ins (mix_parser_t *parser, const mix_ins_t *new_ins,
+ guint lineno)
+{
+ g_assert (parser != NULL && new_ins != NULL);
+ add_raw_ (parser, mix_ins_to_word_uncheck (*new_ins), lineno);
+}
+
+void
+mix_parser_add_raw (mix_parser_t *parser, mix_word_t word, guint lineno,
+ gboolean is_con)
+{
+ g_assert (parser != NULL);
+ add_raw_ (parser, word, lineno);
+ if ( parser->status == MIX_PERR_NOCOMP || parser->status == MIX_PERR_OK )
+ {
+ if (is_con)
+ parser->con_list = g_slist_append (parser->con_list,
+ GUINT_TO_POINTER (lineno));
+ else
+ parser->alf_list = g_slist_append (parser->alf_list,
+ GUINT_TO_POINTER (lineno));
+ }
+}
+
+/* Error handling */
+void
+mix_parser_log_error (mix_parser_t *parser, mix_parser_err_t error,
+ gint lineno, const gchar *comment, gboolean warn)
+{
+ g_assert (parser != NULL);
+ if ( warn )
+ parser->warn_count += 1;
+ else
+ {
+ parser->err_count += 1;
+ parser->err_line = lineno;
+ parser->status = error;
+ }
+
+ fprintf (stderr, "%s%s:%d: %s: %s",
+ mix_file_base_name (parser->in_file),
+ mix_file_extension (parser->in_file),
+ lineno, warn ? _("warning"):_("error"), _(ERR_MESSAGE_[error]));
+
+ if (comment != NULL)
+ fprintf (stderr, ": %s\n", comment);
+ else
+ fputs ("\n", stderr);
+}
+
diff --git a/mixlib/mix_parser.h b/mixlib/mix_parser.h
new file mode 100644
index 0000000..2335fb1
--- /dev/null
+++ b/mixlib/mix_parser.h
@@ -0,0 +1,111 @@
+/* -*-c-*- ---------------- mix_parser.h :
+ * Declarations for mix_parser_t, which compiles a source file into
+ * a mix code file.
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000, 2003, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef MIX_PARSER_H
+#define MIX_PARSER_H
+
+#include <glib.h>
+#include "mix_vm.h"
+
+/* The parser type */
+typedef struct mix_parser_t mix_parser_t;
+
+/* Create/destroy a mix_parser */
+extern mix_parser_t *
+mix_parser_new (const gchar *in_file);
+
+extern void
+mix_parser_delete (mix_parser_t *parser);
+
+/* Access source file name */
+extern const gchar *
+mix_parser_src_file_base_name (const mix_parser_t *parser);
+
+extern const gchar *
+mix_parser_src_file_extension (const mix_parser_t *parser);
+
+/* Compile a mix source file */
+/* compilation errors */
+typedef enum {
+ MIX_PERR_OK, /* no error */
+ MIX_PERR_NOCOMP, /* file not yet compiled */
+ MIX_PERR_INTERNAL, /* internal error */
+ MIX_PERR_NOIN, /* unable to open input file */
+ MIX_PERR_NOOUT, /* unable to open output file */
+ MIX_PERR_UNEX_EOF, /* unexpected end of file */
+ MIX_PERR_INV_LOC, /* invalid loc field */
+ MIX_PERR_DUP_SYMBOL, /* duplicated symbol */
+ MIX_PERR_LONG_SYMBOL, /* symbol name too long */
+ MIX_PERR_NOOP, /* missing op field */
+ MIX_PERR_UNEX_LOC, /* unexpected location symbol */
+ MIX_PERR_INV_ADDRESS, /* invalid address field */
+ MIX_PERR_INV_IDX, /* invalid index field */
+ MIX_PERR_INV_FSPEC, /* invalid fspec */
+ MIX_PERR_INV_OP, /* invalid operation */
+ MIX_PERR_INV_EXPR, /* invalid expression */
+ MIX_PERR_UNDEF_SYM, /* undefined symbol */
+ MIX_PERR_MIS_PAREN, /* mismatched parenthesis */
+ MIX_PERR_UNEX_FSPEC, /* unexpected f-spec */
+ MIX_PERR_MIS_SYM, /* missing symbol name */
+ MIX_PERR_SYM_INS, /* symbol has the same name as instruction */
+ MIX_PERR_NOWRITE, /* failed code write */
+ MIX_PERR_SHORT_ALF, /* short ALF operand */
+ MIX_PERR_LONG_ALF, /* too long ALF operand */
+ MIX_PERR_UNQUOTED_ALF /* unquoted ALF operand */
+} mix_parser_err_t;
+
+extern const gchar *
+mix_parser_err_string (mix_parser_err_t error);
+
+extern mix_parser_err_t
+mix_parser_compile (mix_parser_t *parser);
+
+extern guint
+mix_parser_warning_count (const mix_parser_t *parser);
+
+extern guint
+mix_parser_err_count (const mix_parser_t *parser);
+
+/* Write the compilation result to a code file with the given name.
+ code_file is completed, if required, with the requisite extension;
+ if code_file == NULL [source_file_name].[extension] is used.
+ If debug == TRUE, debug information is written.
+*/
+extern mix_parser_err_t
+mix_parser_write_code (mix_parser_t *parser, const gchar *code_file,
+ gboolean debug);
+
+/* Write a "canonical" listing of a compiled source, i.e. a source
+ file with all symbols substituted by their actual values after
+ compilation.
+*/
+extern mix_parser_err_t
+mix_parser_write_listing (mix_parser_t *parser, const gchar *list_file);
+
+/* load a virtual machine's memory with the contents of a compiled file */
+extern mix_parser_err_t
+mix_parser_load_vm (const mix_parser_t *parser, mix_vm_t *vm);
+
+
+#endif /* MIX_PARSER_H */
+
diff --git a/mixlib/mix_predicate.c b/mixlib/mix_predicate.c
new file mode 100644
index 0000000..2143757
--- /dev/null
+++ b/mixlib/mix_predicate.c
@@ -0,0 +1,215 @@
+/* -*-c-*- -------------- mix_predicate.c :
+ * Implementation of the functions declared in mix_predicate.h
+ * ------------------------------------------------------------------
+ * $Id: mix_predicate.c,v 1.6 2005/09/20 19:43:13 jao Exp $
+ * ------------------------------------------------------------------
+ * Copyright (C) 2001, 2002 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "mix_vm.h"
+#include "mix_predicate.h"
+
+/* predicate data */
+typedef union pred_data_t
+{
+ mix_word_t regA;
+ mix_word_t regX;
+ mix_short_t regI;
+ mix_cmpflag_t cmp;
+ gboolean over;
+ mix_word_t mem;
+} pred_data_t;
+
+/* the predicate function type */
+typedef gboolean (*mix_predicate_fun_t) (mix_predicate_t *pred,
+ const mix_vm_t *vm);
+
+/* the predicate type */
+struct mix_predicate_t
+{
+ mix_predicate_type_t type;
+ pred_data_t data;
+ guint control;
+};
+
+/* predicate funcs */
+static gboolean
+pred_func_rA (mix_predicate_t *pred, const mix_vm_t *vm)
+{
+ mix_word_t val = mix_vm_get_rA (vm);
+ if (pred->data.regA == val) return FALSE;
+ pred->data.regA = val;
+ return TRUE;
+}
+
+static gboolean
+pred_func_rX (mix_predicate_t *pred, const mix_vm_t *vm)
+{
+ mix_word_t val = mix_vm_get_rX (vm);
+ if (pred->data.regX == val) return FALSE;
+ pred->data.regX = val;
+ return TRUE;
+}
+
+static gboolean
+pred_func_rI (mix_predicate_t *pred, const mix_vm_t *vm)
+{
+ mix_short_t val = (pred->control == 0) ? mix_vm_get_rJ (vm)
+ : mix_vm_get_rI (vm, pred->control);
+ if (pred->data.regI == val) return FALSE;
+ pred->data.regI = val;
+ return TRUE;
+}
+
+static gboolean
+pred_func_mem (mix_predicate_t *pred, const mix_vm_t *vm)
+{
+ mix_word_t val =
+ mix_vm_get_addr_contents (vm, (mix_address_t)pred->control);
+ if (pred->data.mem == val) return FALSE;
+ pred->data.mem = val;
+ return TRUE;
+}
+
+static gboolean
+pred_func_cmp (mix_predicate_t *pred, const mix_vm_t *vm)
+{
+ mix_cmpflag_t val = mix_vm_get_cmpflag (vm);
+ if (pred->data.cmp == val) return FALSE;
+ pred->data.cmp = val;
+ return TRUE;
+}
+
+static gboolean
+pred_func_over (mix_predicate_t *pred, const mix_vm_t *vm)
+{
+ gboolean val = mix_vm_get_overflow (vm);
+ if (pred->data.over == val) return FALSE;
+ pred->data.over = val;
+ return TRUE;
+}
+
+static mix_predicate_fun_t PRED_FUNCS_[] = {
+ pred_func_rA, pred_func_rX, pred_func_rI, pred_func_rI, pred_func_rI,
+ pred_func_rI, pred_func_rI, pred_func_rI, pred_func_rI,
+ pred_func_over, pred_func_cmp, pred_func_mem
+};
+
+/* create predicates based on vm status */
+mix_predicate_t *
+mix_predicate_new (mix_predicate_type_t type)
+{
+ mix_predicate_t *result;
+ g_return_val_if_fail (type <= MIX_PRED_MEM, NULL);
+ result = g_new (mix_predicate_t, 1);
+ result->type = type;
+ result->data.regA = MIX_WORD_ZERO;
+ if (type >= MIX_PRED_REG_I1 && type <= MIX_PRED_REG_I6)
+ result->control = 1 + type - MIX_PRED_REG_I1;
+ else
+ result->control = 0;
+ return result;
+}
+
+/* delete a predicate */
+void
+mix_predicate_delete (mix_predicate_t *predicate)
+{
+ g_return_if_fail (predicate != NULL);
+ g_free (predicate);
+}
+
+/* return the predicate's type */
+mix_predicate_type_t
+mix_predicate_get_type (const mix_predicate_t *pred)
+{
+ g_return_val_if_fail (pred != NULL, MIX_PRED_INVALID);
+ return pred->type;
+}
+
+/* test a predicate */
+gboolean
+mix_predicate_eval(mix_predicate_t *pred, const mix_vm_t *vm)
+{
+ g_return_val_if_fail (pred != NULL, FALSE);
+ g_return_val_if_fail (vm != NULL, FALSE);
+ return PRED_FUNCS_[pred->type] (pred, vm);
+}
+
+/* change mem address of a MIX_PRED_MEM predicate */
+void
+mix_predicate_set_mem_address (mix_predicate_t *predicate,
+ mix_address_t address)
+{
+ g_return_if_fail (predicate != NULL);
+ predicate->control = address;
+}
+
+/* get message about predicate evaluation */
+const gchar *
+mix_predicate_get_message (const mix_predicate_t *predicate)
+{
+ enum {SIZE = 256};
+ static gchar BUFFER[SIZE];
+ static const gchar *CMP_STRINGS[] = { "L", "E", "G"};
+
+ g_return_val_if_fail (predicate != NULL, NULL);
+
+ switch (predicate->type)
+ {
+ case MIX_PRED_REG_A:
+ g_snprintf (BUFFER, SIZE, _("Register A changed to %s%ld"),
+ mix_word_is_negative (predicate->data.regA)? "-" : "+",
+ mix_word_magnitude (predicate->data.regA));
+ break;
+ case MIX_PRED_REG_X:
+ g_snprintf (BUFFER, SIZE, _("Register X changed to %s%ld"),
+ mix_word_is_negative (predicate->data.regX)? "-" : "+",
+ mix_word_magnitude (predicate->data.regX));
+ break;
+ case MIX_PRED_REG_J:
+ g_snprintf (BUFFER, SIZE, _("Register J changed to %d"),
+ mix_short_magnitude (predicate->data.regI));
+ break;
+ case MIX_PRED_REG_I1: case MIX_PRED_REG_I2: case MIX_PRED_REG_I3:
+ case MIX_PRED_REG_I4: case MIX_PRED_REG_I5: case MIX_PRED_REG_I6:
+ g_snprintf (BUFFER, SIZE, _("Register I%d changed to %s%d"),
+ predicate->control,
+ mix_short_is_negative (predicate->data.regI)? "-" : "+",
+ mix_short_magnitude (predicate->data.regI));
+ break;
+ case MIX_PRED_CMP:
+ g_snprintf (BUFFER, SIZE, _("Comparison flag changed to %s"),
+ CMP_STRINGS[predicate->data.cmp]);
+ break;
+ case MIX_PRED_OVER:
+ g_snprintf (BUFFER, SIZE, _("Overflow toggled %s"),
+ predicate->data.over ? "ON" : "OFF");
+ break;
+ case MIX_PRED_MEM:
+ g_snprintf (BUFFER, SIZE, _("Memory address %d changed to %s%ld"),
+ predicate->control,
+ mix_word_is_negative (predicate->data.mem)? "-" : "+",
+ mix_word_magnitude (predicate->data.mem));
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ return BUFFER;
+}
+
diff --git a/mixlib/mix_predicate.h b/mixlib/mix_predicate.h
new file mode 100644
index 0000000..903de57
--- /dev/null
+++ b/mixlib/mix_predicate.h
@@ -0,0 +1,80 @@
+/* -*-c-*- ---------------- mix_predicate.h :
+ * Predicates and lists of predicates testing vm status.
+ * ------------------------------------------------------------------
+ * Last change: Time-stamp: <2001-07-13 22:32:42 jao>
+ * ------------------------------------------------------------------
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef MIX_PREDICATE_H
+#define MIX_PREDICATE_H
+
+#include "mix.h"
+#include "mix_types.h"
+#include "mix_ins.h"
+
+/* the predicate type */
+typedef struct mix_predicate_t mix_predicate_t;
+
+/* predicate types */
+typedef enum {
+ MIX_PRED_REG_A,
+ MIX_PRED_REG_X,
+ MIX_PRED_REG_J,
+ MIX_PRED_REG_I1,
+ MIX_PRED_REG_I2,
+ MIX_PRED_REG_I3,
+ MIX_PRED_REG_I4,
+ MIX_PRED_REG_I5,
+ MIX_PRED_REG_I6,
+ MIX_PRED_OVER,
+ MIX_PRED_CMP,
+ MIX_PRED_MEM,
+ MIX_PRED_INVALID
+} mix_predicate_type_t;
+
+/* create predicates based on vm status */
+extern mix_predicate_t *
+mix_predicate_new (mix_predicate_type_t type);
+
+/* delete a predicate */
+extern void
+mix_predicate_delete (mix_predicate_t *predicate);
+
+/* return the predicate's type */
+extern mix_predicate_type_t
+mix_predicate_get_type (const mix_predicate_t *pred);
+
+/* change mem address of a MIX_PRED_MEM predicate */
+extern void
+mix_predicate_set_mem_address (mix_predicate_t *predicate,
+ mix_address_t address);
+
+/* get message about predicate evaluation */
+extern const gchar *
+mix_predicate_get_message (const mix_predicate_t *predicate);
+
+/* test a predicate */
+#include "mix_vm.h"
+
+extern gboolean
+mix_predicate_eval(mix_predicate_t *pred, const mix_vm_t *vm);
+
+#endif /* MIX_PREDICATE_H */
+
diff --git a/mixlib/mix_predicate_list.c b/mixlib/mix_predicate_list.c
new file mode 100644
index 0000000..1b68d35
--- /dev/null
+++ b/mixlib/mix_predicate_list.c
@@ -0,0 +1,117 @@
+/* -*-c-*- -------------- mix_predicate_list.c :
+ * Implementation of the functions declared in mix_predicate_list.h
+ * ------------------------------------------------------------------
+ * Last change: Time-stamp: "01/07/18 23:02:26 jao"
+ * ------------------------------------------------------------------
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#include "mix_predicate_list.h"
+
+/* the predicate list type */
+struct mix_predicate_list_t
+{
+ GSList *predicates;
+ const mix_vm_t *vm;
+ const mix_predicate_t *last;
+};
+
+/* a list of predicates */
+mix_predicate_list_t *
+mix_predicate_list_new (const mix_vm_t *vm)
+{
+ mix_predicate_list_t *result;
+ g_return_val_if_fail (vm != NULL, NULL);
+ result = g_new (mix_predicate_list_t, 1);
+ result->predicates = NULL;
+ result->vm = vm;
+ result->last = NULL;
+ return result;
+}
+
+void
+mix_predicate_list_delete (mix_predicate_list_t *list)
+{
+ g_return_if_fail (list != NULL);
+ g_slist_free (list->predicates);
+ g_free (list);
+}
+
+/* evaluate the predicate list */
+gboolean
+mix_predicate_list_eval (mix_predicate_list_t *list)
+{
+ GSList *node;
+
+ g_return_val_if_fail (list != NULL, FALSE);
+ node = list->predicates;
+ while (node) {
+ mix_predicate_t *pred = (mix_predicate_t *)(node->data);
+ if (mix_predicate_eval (pred, list->vm))
+ {
+ list->last = pred;
+ return TRUE;
+ }
+ node = node->next;
+ }
+ list->last = NULL;
+ return FALSE;
+}
+
+/* add/remove predicates to the list */
+void
+mix_predicate_list_add (mix_predicate_list_t *list, mix_predicate_t *predicate)
+{
+ g_return_if_fail (list != NULL);
+ g_return_if_fail (predicate != NULL);
+ if (!g_slist_find (list->predicates, predicate))
+ list->predicates = g_slist_append (list->predicates, (gpointer)predicate);
+ (void)mix_predicate_eval (predicate, list->vm);
+}
+
+gboolean
+mix_predicate_list_remove (mix_predicate_list_t *list,
+ mix_predicate_t *predicate)
+{
+ g_return_val_if_fail (list != NULL, FALSE);
+ g_return_val_if_fail (predicate != NULL, FALSE);
+ if (g_slist_find (list->predicates, predicate))
+ {
+ list->predicates = g_slist_remove (list->predicates, predicate);
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+void
+mix_predicate_list_clear (mix_predicate_list_t *list)
+{
+ g_return_if_fail (list != NULL);
+ g_slist_free (list->predicates);
+ list->predicates = NULL;
+ list->last = NULL;
+}
+
+const mix_predicate_t *
+mix_predicate_list_last_true_eval (const mix_predicate_list_t *list)
+{
+ g_return_val_if_fail (list != NULL, NULL);
+ return list->last;
+}
diff --git a/mixlib/mix_predicate_list.h b/mixlib/mix_predicate_list.h
new file mode 100644
index 0000000..d651df7
--- /dev/null
+++ b/mixlib/mix_predicate_list.h
@@ -0,0 +1,64 @@
+/* -*-c-*- ---------------- mix_predicate_list.h :
+ * A list of predicates.
+ * ------------------------------------------------------------------
+ * Last change: Time-stamp: <01/07/18 23:02:40 jao>
+ * ------------------------------------------------------------------
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef MIX_PREDICATE_LIST_H
+#define MIX_PREDICATE_LIST_H
+
+#include "mix.h"
+#include "mix_vm.h"
+#include "mix_predicate.h"
+
+/* the predicate list type */
+typedef struct mix_predicate_list_t mix_predicate_list_t;
+
+/* create/destroy a list of predicates */
+extern mix_predicate_list_t *
+mix_predicate_list_new (const mix_vm_t *vm);
+
+extern void
+mix_predicate_list_delete (mix_predicate_list_t *list);
+
+/* evaluate the predicate list */
+extern gboolean
+mix_predicate_list_eval (mix_predicate_list_t *list);
+
+extern const mix_predicate_t *
+mix_predicate_list_last_true_eval (const mix_predicate_list_t *list);
+
+#define mix_predicate_list_last_true_eval_type(list) \
+ mix_predicate_get_type (mix_predicate_list_last_true_eval (list))
+
+/* add/remove predicates to the list */
+extern void
+mix_predicate_list_add (mix_predicate_list_t *list, mix_predicate_t *predicate);
+
+extern gboolean
+mix_predicate_list_remove (mix_predicate_list_t *list,
+ mix_predicate_t *predicate);
+
+extern void
+mix_predicate_list_clear (mix_predicate_list_t *list);
+
+#endif /* MIX_PREDICATE_LIST_H */
+
diff --git a/mixlib/mix_scanner.l b/mixlib/mix_scanner.l
new file mode 100644
index 0000000..6150007
--- /dev/null
+++ b/mixlib/mix_scanner.l
@@ -0,0 +1,581 @@
+/* -*-c-*- -------------- mix_scanner.l :
+ * Lexical scanner used by mix_parser_t
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000, 2003, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+%{
+#include <ctype.h>
+#include <string.h>
+
+#include "mix.h"
+#include "xmix_parser.h"
+
+#define YY_DECL mix_parser_err_t mix_flex_scan (mix_parser_t *parser)
+
+#define RESET() \
+ do { \
+ mix_ins_fill_from_id (ins, mix_NOP); \
+ ins.address = 0; \
+ ins.index = 0; \
+ nof = FALSE; \
+ lsf = FALSE; \
+ if (symbol != NULL ) \
+ { \
+ g_free (symbol); \
+ symbol = NULL; \
+ } \
+ if (lsymbol != NULL) \
+ { \
+ g_free (lsymbol); \
+ lsymbol = NULL; \
+ } \
+ } while (FALSE)
+
+#define NEXT() \
+ do { \
+ if (lsymbol != NULL) \
+ mix_parser_manage_local_symbol (parser,lsymbol, \
+ loc); \
+ parser->loc_count++; \
+ RESET (); \
+ ++lineno; \
+ BEGIN (INITIAL); \
+ } while (FALSE)
+
+#define ADD_INS() \
+ do { \
+ mix_parser_add_ins (parser, &ins, lineno); \
+ NEXT (); \
+ } while (FALSE)
+
+#define ADD_RAW(value,is_con) \
+ do { \
+ mix_parser_add_raw (parser, value, lineno, is_con); \
+ NEXT (); \
+ } while (FALSE)
+
+
+#define ENTER_EVAL() \
+ do { \
+ if (yytext[0] != '*') \
+ { \
+ expr_val = MIX_WORD_ZERO; \
+ yyless (0); \
+ } \
+ else \
+ { \
+ expr_val = mix_short_to_word_fast (parser->loc_count); \
+ yyless (1); \
+ } \
+ yy_push_state (EVAL); \
+ } while (FALSE)
+
+#define ENTER_WEVAL(s) \
+ do { \
+ wexpr_val = MIX_WORD_ZERO; \
+ wexpr_val_tmp = MIX_WORD_ZERO; \
+ is_fp = FALSE; \
+ yyless (s); \
+ yy_push_state (WEVAL); \
+ } while (FALSE)
+
+#define RETURN_ERROR(error, comment) \
+ do { \
+ char c; \
+ mix_parser_log_error (parser,error,lineno,comment,FALSE); \
+ while ( (c = input ()) != '\n' && c != EOF ) ; \
+ if ( c == EOF ) return error; else ++lineno; \
+ RESET (); \
+ BEGIN (INITIAL); \
+ } while (FALSE)
+
+
+static mix_word_t eval_binop_ (const gchar *op, mix_word_t x, mix_word_t y);
+
+static void unput_word_ (mix_word_t word);
+
+%}
+
+%option nomain
+%option caseless
+%option array
+%option stack
+%option noyywrap
+%option noyy_top_state
+%option noreject
+%option outfile="lex.yy.c"
+
+%s LOC
+%s OP
+%s ADDRESS
+%s INDEX
+%s FSPEC
+%s EVAL
+%s WEVAL
+%s ORIG
+%s CON
+%s EQU
+%s END
+
+ws [ \t]
+digit [0-9]
+letter [A-Z]
+number [+-]?{digit}+
+mixchar [0-9A-Z .,'')(+*/=$<>@;:\-]
+locsymbol {digit}H
+flocsymbol {digit}F
+blocsymbol {digit}B
+symbol {digit}*{letter}+[A-Z0-9]*
+binop "+"|"-"|"*"|"/"|"//"|":"
+atexpr {digit}+|{symbol}|\*
+expr [+-]?{atexpr}({binop}{1}{atexpr})*
+fpart \({expr}\)
+wexpr {expr}({fpart})?(,{expr}({fpart})?)*
+
+
+%%
+
+%{
+
+ mix_ins_t ins;
+ gboolean nof = FALSE, is_fp = FALSE, end = FALSE, lsf = FALSE;
+ mix_word_t expr_val = MIX_WORD_ZERO, wexpr_val = MIX_WORD_ZERO,
+ wexpr_val_tmp = MIX_WORD_ZERO;
+ gchar *symbol = NULL, *lsymbol = NULL;
+ mix_address_t loc = MIX_SHORT_ZERO;
+ guint lineno = 1;
+ mix_ins_fill_from_id (ins, mix_NOP);
+ ins.address = 0;
+ ins.index = 0;
+ parser->err_line = 0;
+#ifdef FLEX_DEBUG
+ yy_flex_debug = getenv("FLEX_DEBUG");
+#endif
+ yyin = mix_file_to_FILE (parser->in_file);
+
+%}
+
+
+<*><<EOF>> {
+ mix_parser_log_error (parser, MIX_PERR_UNEX_EOF, lineno, NULL, FALSE);
+ return MIX_PERR_UNEX_EOF;
+}
+
+<INITIAL>{
+ ^\*.* /* eat comments */
+ . {
+ if ( end ) return parser->status;
+ yyless (0);
+ BEGIN (LOC);
+ }
+ \n {
+ ++lineno;
+ if ( end ) return parser->status;
+ }
+}
+
+<LOC>{
+ {ws}+ BEGIN (OP); /* LOC field is empty */
+ {locsymbol} { /* manage local symbol */
+ loc = get_ploc_ (parser);
+ lsymbol = g_strdup (yytext);
+ if ( lsymbol == NULL ) {
+ mix_parser_log_error (parser, MIX_PERR_INTERNAL, lineno, NULL, FALSE);
+ return MIX_PERR_INTERNAL;
+ }
+ BEGIN (OP);
+ }
+ {locsymbol}/({ws}+EQU) {/* local symbol with value */
+ loc = get_ploc_ (parser);
+ symbol = g_strdup (yytext);
+ lsymbol = g_strdup (yytext);
+ if ( symbol == NULL || lsymbol == NULL) {
+ mix_parser_log_error (parser, MIX_PERR_INTERNAL, lineno, NULL, FALSE);
+ return MIX_PERR_INTERNAL;
+ }
+ symbol[1] = 'B'; /* this will be referred as nB afterwards */
+ BEGIN (OP);
+ }
+ {flocsymbol}|{blocsymbol} RETURN_ERROR (MIX_PERR_UNEX_LOC, yytext);
+ {symbol}/({ws}+EQU) { /* store symbol name for future definition */
+ symbol = g_strdup (yytext);
+ if ( symbol == NULL ) {
+ mix_parser_log_error (parser, MIX_PERR_INTERNAL, lineno, NULL, FALSE);
+ return MIX_PERR_INTERNAL;
+ }
+ BEGIN (OP);
+ }
+ {symbol} { /* define a new symbol */
+ mix_parser_err_t err;
+ if ( mix_get_id_from_string (yytext) != mix_INVALID_INS )
+ mix_parser_log_error (parser, MIX_PERR_SYM_INS, lineno, yytext, TRUE);
+ if ( (err = mix_parser_define_symbol_here (parser,yytext)) != MIX_PERR_OK )
+ mix_parser_log_error (parser, err, lineno, yytext, FALSE);
+ BEGIN (OP);
+ }
+ . RETURN_ERROR (MIX_PERR_INV_LOC, yytext);
+ \n ++lineno; /* empty line */
+}
+
+<OP>{
+ {ws}+ /* eat leading whitespace */
+ \n RETURN_ERROR (MIX_PERR_NOOP, NULL);
+ ORIG{ws}+ BEGIN (ORIG);
+ CON{ws}+ BEGIN (CON);
+ EQU{ws}+ BEGIN (EQU);
+ END{ws}+ BEGIN (END);
+ ALF{ws}+\"{mixchar}{0,5}\"{ws}+.*\n |
+ ALF{ws}+\"{mixchar}{0,5}\"{ws}*\n {
+ mix_byte_t bytes[5];
+ mix_word_t value;
+ guint k, j = 4;
+
+ while ( yytext[j++] != '\"' ) ;
+ for ( k = j; k < 5+j && yytext[k] != '\"'; ++k )
+ bytes[k-j] = mix_ascii_to_char (yytext[k]);
+ if ( k-j < 5 )
+ {
+ mix_parser_log_error (parser, MIX_PERR_SHORT_ALF, lineno, NULL, TRUE);
+ /* Fill with spaces */
+ for (; k < 5+j; k++)
+ bytes[k-j] = mix_ascii_to_char (' ');
+ }
+ else if ( yytext[k] != '\"' )
+ mix_parser_log_error (parser, MIX_PERR_LONG_ALF, lineno, NULL, TRUE);
+
+ value = mix_bytes_to_word (bytes, 5);
+ ADD_RAW (value, FALSE);
+ }
+ ALF{ws}*\n {
+ mix_byte_t bytes[5];
+ memset (bytes, mix_ascii_to_char (' '), 5);
+ mix_word_t value = mix_bytes_to_word (bytes, 5);
+ ADD_RAW (value, FALSE);
+ }
+ ALF{ws}+({mixchar}{1,5}) {
+ mix_byte_t bytes[5];
+ mix_word_t value;
+ int i, n;
+ for (n = 3; n < yyleng; n++)
+ if (!isspace (yytext[n]))
+ break;
+
+ for (i = 0; i < 5 && n < yyleng; i++, n++)
+ bytes[i] = mix_ascii_to_char (yytext[n]);
+
+ for (; i < 5; i++)
+ bytes[i] = mix_ascii_to_char (' ');
+
+ value = mix_bytes_to_word (bytes, 5);
+ ADD_RAW (value, FALSE);
+ }
+ /* ALF " " */
+ [A-Z0-9]+{ws}*/\n |
+ [A-Z0-9]+{ws}+ {
+ mix_ins_id_t id = mix_get_id_from_string (g_strchomp (yytext));
+ if ( id == mix_INVALID_INS )
+ mix_parser_log_error (parser, MIX_PERR_INV_OP, lineno, yytext, FALSE);
+ else {
+ mix_ins_fill_from_id (ins, id);
+ nof = mix_ins_id_is_extended (id);
+ }
+ BEGIN (ADDRESS);
+ }
+ {expr} RETURN_ERROR (MIX_PERR_INV_OP, yytext);
+ . RETURN_ERROR (MIX_PERR_INV_OP, yytext);
+}
+
+
+<ORIG>{
+ {number}{ws}*\n |
+ {number}{ws}+.*\n {
+ mix_word_t value = mix_word_new (atol (yytext));
+ parser->loc_count = mix_word_to_short_fast (value);
+ ++lineno;
+ BEGIN (INITIAL);
+ }
+}
+
+<CON>{
+ {number}{ws}*\n |
+ {number}{ws}+.*\n {
+ mix_word_t value = mix_word_new (atol (yytext));
+ ADD_RAW (value, TRUE);
+ }
+}
+
+<EQU>{
+ {number}{ws}*\n |
+ {number}{ws}+.*\n {
+ mix_word_t value;
+ gint def;
+ if ( symbol == NULL ) RETURN_ERROR (MIX_PERR_MIS_SYM, NULL);
+ value = mix_word_new (atol (yytext));
+ def = mix_parser_define_symbol_value (parser, symbol, value);
+ if ( def == MIX_SYM_DUP ) RETURN_ERROR (MIX_PERR_DUP_SYMBOL, symbol);
+ if ( def == MIX_SYM_LONG ) RETURN_ERROR (MIX_PERR_LONG_SYMBOL, symbol);
+ ++lineno;
+ BEGIN (INITIAL);
+ }
+}
+
+<END>{
+ {number}{ws}*\n |
+ {number}{ws}+.*\n {
+ parser->start = mix_short_new (atol (yytext));
+ parser->end = parser->loc_count;
+ end = TRUE;
+ if ( parser->status == MIX_PERR_NOCOMP ) parser->status = MIX_PERR_OK;
+ return parser->status;
+ }
+}
+
+<ORIG,CON,EQU,END>{
+ {wexpr} ENTER_WEVAL (0);
+ . RETURN_ERROR (MIX_PERR_INV_OP, yytext);
+}
+
+
+<ADDRESS,INDEX,FSPEC>{locsymbol} RETURN_ERROR (MIX_PERR_UNEX_LOC, yytext);
+
+<ADDRESS>{
+ =/[+-]?{number}= lsf = TRUE;
+ =/{expr}= lsf = TRUE;
+ ={wexpr}= { lsf = TRUE; ENTER_WEVAL (1); }
+ [+-]?{number}={ws}*\n |
+ [+-]?{number}={ws}+.*\n {
+ if (!lsf) RETURN_ERROR (MIX_PERR_INV_ADDRESS, yytext);
+ mix_parser_define_ls (parser, mix_word_new (atol (yytext)));
+ lsf = FALSE;
+ ADD_INS ();
+ }
+ [+-]?{number}=[(,] {
+ int pos = yyleng - 3;
+ if (!lsf) RETURN_ERROR (MIX_PERR_INV_ADDRESS, yytext);
+ unput (yytext[yyleng - 1]);
+ while (pos >= 0) {
+ unput (yytext[pos]);
+ --pos;
+ }
+ }
+ [+-]?{number}{ws}+.*\n |
+ [+-]?{number}[(,\n] {
+ ins.address = mix_short_new (atol (yytext));
+ switch ( yytext[yyleng-1] ) {
+ case '(' : BEGIN (FSPEC); break;
+ case ',' : BEGIN (INDEX); break;
+ case '\n' : ADD_INS (); break;
+ default: g_assert_not_reached ();
+ }
+ }
+ ([+-]?{symbol})/[(,\n\t ] {
+ gboolean neg = (yytext[0] == '-');
+ const gchar *s = (neg || yytext[0] == '+')? yytext+1 : yytext;
+ if ( !mix_symbol_table_is_defined (parser->symbol_table, s) )
+ {
+ mix_parser_set_future_ref (parser, s);
+ if (neg)
+ mix_parser_log_error (parser, MIX_PERR_UNDEF_SYM, lineno, s, TRUE);
+ unput (neg? '1':'0');
+ }
+ else
+ {
+ mix_word_t v = mix_symbol_table_value (parser->symbol_table, s);
+ if ( neg ) mix_word_reverse_sign (v);
+ unput_word_ (v);
+ }
+ }
+ {expr}/[(,=\n\t ] ENTER_EVAL ();
+ \n ADD_INS ();
+ . RETURN_ERROR (MIX_PERR_INV_ADDRESS, yytext);
+}
+
+
+<INDEX>{
+ {number}[\n(\t ] {
+ int end = yytext[yyleng-1];
+ ins.index = mix_byte_new (atol (yytext));
+ if ( end == '\n' )
+ ADD_INS ();
+ else if ( end == '(' )
+ BEGIN (FSPEC);
+ else
+ { /* eat rest of line (comment) */
+ while ( (end = input()) != '\n' && end != EOF ) ;
+ if ( end == '\n' ) ADD_INS ();
+ else RETURN_ERROR (MIX_PERR_UNEX_EOF, NULL);
+ }
+ }
+ {expr}/[\n(\t ] ENTER_EVAL ();
+ \n {
+ mix_parser_log_error (parser, MIX_PERR_INV_IDX, lineno++, NULL, FALSE);
+ RESET ();
+ BEGIN (INITIAL);
+ }
+ . RETURN_ERROR (MIX_PERR_INV_IDX, yytext);
+}
+
+<FSPEC>{
+ {number}")"(({ws}+.*\n)|\n) {
+ glong val = atol (yytext);
+ if ( val < 0 || val > MIX_BYTE_MAX )
+ RETURN_ERROR (MIX_PERR_INV_FSPEC, NULL);
+ if ( ins.opcode != mix_opMOVE
+ && ( ins.opcode < mix_opJBUS || ins.opcode > mix_opJXx )
+ && !mix_fspec_is_valid (mix_byte_new (val)) )
+ RETURN_ERROR (MIX_PERR_INV_FSPEC, NULL);
+ if ( nof )
+ mix_parser_log_error (parser, MIX_PERR_INV_FSPEC,
+ lineno, _("ignored"), TRUE);
+ else
+ {
+ ins.fspec = mix_byte_new (val);
+ if (lsf)
+ {
+ mix_parser_define_ls (parser,
+ mix_short_to_word_fast (ins.address));
+ ins.address = MIX_WORD_ZERO;
+ lsf = FALSE;
+ }
+ ADD_INS ();
+ }
+ }
+ {expr}/")" {
+ ENTER_EVAL ();
+ }
+ . RETURN_ERROR (MIX_PERR_INV_FSPEC, yytext);
+}
+
+
+<EVAL>{
+ {binop}{digit}+ {
+ const gchar *s = ( yytext[1] == '/' ) ? yytext+2 : yytext+1;
+ mix_word_t value = mix_word_new (atol (s));
+ expr_val = eval_binop_ (yytext, expr_val, value);
+ }
+ {binop}{symbol} {
+ const gchar *s = ( yytext[1] == '/' ) ? yytext+2 : yytext+1;
+ if ( !mix_symbol_table_is_defined (parser->symbol_table, s) ) {
+ mix_parser_log_error (parser, MIX_PERR_UNDEF_SYM, lineno, s, FALSE);
+ yy_pop_state ();
+ }
+ expr_val = eval_binop_ (yytext, expr_val,
+ mix_symbol_table_value (parser->symbol_table, s));
+ }
+ {binop}"*" {
+ expr_val = eval_binop_ (yytext, expr_val,
+ mix_short_to_word_fast (parser->loc_count));
+ }
+ "*" unput_word_ (mix_short_to_word_fast (parser->loc_count));
+ {number} expr_val = mix_word_new (atol (yytext));
+ {symbol} {
+ if ( !mix_symbol_table_is_defined (parser->symbol_table, yytext) ) {
+ mix_parser_log_error (parser, MIX_PERR_UNDEF_SYM, lineno, yytext, FALSE);
+ yy_pop_state ();
+ }
+ expr_val = mix_symbol_table_value (parser->symbol_table, yytext);
+ }
+ [,)(=\n\t ] unput (yytext[0]); unput_word_ (expr_val); yy_pop_state ();
+ . RETURN_ERROR (MIX_PERR_INV_EXPR, yytext);
+}
+
+<WEVAL>{
+ {number}"(" {
+ is_fp = TRUE;
+ wexpr_val_tmp = mix_word_new (atol (yytext));
+ }
+ {number}")" {
+ glong val = atol (yytext);
+ if ( !is_fp ) {
+ mix_parser_log_error (parser, MIX_PERR_MIS_PAREN, lineno, NULL, FALSE);
+ yy_pop_state ();
+ }
+ if ( val < 0 || val > MIX_BYTE_MAX
+ || !mix_fspec_is_valid (mix_byte_new (val)) ) {
+ mix_parser_log_error (parser, MIX_PERR_INV_FSPEC, lineno, NULL, FALSE);
+ yy_pop_state ();
+ }
+ is_fp = FALSE;
+ wexpr_val = mix_word_store_field (mix_byte_new (val), wexpr_val_tmp,
+ wexpr_val);
+ }
+ {number}/[,()\n\t ] wexpr_val = mix_word_new (atol (yytext));
+ {expr}/[,()\n\t ] ENTER_EVAL ();
+ ,/{expr} /* eat comma if followed by expression */
+ [=\n\t ] { /* ok if not inside an f-part */
+ if ( is_fp ) {
+ mix_parser_log_error (parser, MIX_PERR_MIS_PAREN, lineno, NULL, FALSE);
+ yy_pop_state ();
+ }
+ unput (yytext[yyleng-1]);
+ unput_word_ (wexpr_val);
+ yy_pop_state ();
+ }
+ . RETURN_ERROR (MIX_PERR_INV_EXPR, NULL);
+}
+
+%%
+
+static mix_word_t
+eval_binop_ (const gchar *op, mix_word_t x, mix_word_t y)
+{
+ mix_word_t result = MIX_WORD_ZERO;
+ switch (op[0])
+ {
+ case '+':
+ result = mix_word_add (x,y);
+ break;
+ case '-':
+ result = mix_word_sub (x,y);
+ break;
+ case '*':
+ mix_word_mul (x, y, NULL, &result);
+ break;
+ case ':':
+ {
+ mix_word_t a;
+ mix_word_mul (x, 8, NULL, &a);
+ result = mix_word_add (a, y);
+ break;
+ }
+ case '/':
+ if ( strlen (op) > 1 && op[1] == '/' ) {
+ mix_word_div (x,MIX_WORD_ZERO,y, &result, NULL);
+ } else {
+ mix_word_div (MIX_WORD_ZERO, x, y, &result, NULL);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ return result;
+}
+
+static void
+unput_word_ (mix_word_t word)
+{
+ gchar *value;
+ gint k;
+ value = g_strdup_printf ("%s%ld",
+ mix_word_is_negative (word)? "-":"+",
+ mix_word_magnitude (word));
+ for (k = strlen (value) - 1; k >= 0; --k)
+ unput (value[k]);
+ g_free (value);
+}
diff --git a/mixlib/mix_src_file.c b/mixlib/mix_src_file.c
new file mode 100644
index 0000000..b376643
--- /dev/null
+++ b/mixlib/mix_src_file.c
@@ -0,0 +1,157 @@
+/* -*-c-*- -------------- mix_src_file.c :
+ * Implementation of the functions declared in mix_src_file.h
+ * ------------------------------------------------------------------
+ * Last change: Time-stamp: "01/03/10 15:23:46 jose"
+ * ------------------------------------------------------------------
+ * 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
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "mix_src_file.h"
+
+/* the MIXAL source file type */
+struct mix_src_file_t
+{
+ gchar *path; /* the path to the disk file */
+ GPtrArray *lines; /* an array of the file lines */
+ guint lineno; /* the number of lines */
+};
+
+/* format a source line */
+static gchar *
+format_line_ (gchar *line)
+{
+ const gchar *label, *op, *rest;
+ gint k = 0;
+
+ if (!line) return line;
+ if (line[0] == '*' || strlen(line) == 0)
+ return g_strdup (line);
+
+ if (isspace (line[0]))
+ {
+ label = " ";
+ while (line[k] && isspace (line[k])) ++k;
+ }
+ else
+ {
+ label = line;
+ while (line[k] && !isspace (line[k])) ++k;
+ while (line[k] && isspace (line[k])) ++k;
+ }
+
+ if (line[k])
+ {
+ line[k - 1] = 0;
+ op = line + k;
+ while (line[k] && !isspace (line[k])) ++k;
+ while (line[k] && isspace (line[k])) ++k;
+ line[k - 1] = 0;
+ rest = (line[k]) ? line + k: "";
+ }
+ else
+ {
+ op = rest = "";
+ }
+
+
+ return g_strdup_printf ("%-11s %-5s %s", label, op, rest);
+}
+
+/* load the source file lines into memory */
+static gboolean
+load_file_ (mix_src_file_t *file)
+{
+ mix_file_t *mf = mix_file_new_with_def_ext (file->path,
+ mix_io_READ,
+ MIX_SRC_DEFEXT);
+ if (mf != NULL)
+ {
+ enum {BUFFER_SIZE = 256};
+ static gchar BUFFER[BUFFER_SIZE];
+
+ FILE *f = mix_file_to_FILE (mf);
+ file->lines = g_ptr_array_new ();
+ file->lineno = 0;
+
+ while (fgets (BUFFER, BUFFER_SIZE, f) == BUFFER)
+ {
+ g_ptr_array_add (file->lines, (gpointer) format_line_ (BUFFER));
+ file->lineno++;
+ }
+
+ mix_file_delete (mf);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* create a new src file from an existing disk file */
+mix_src_file_t *
+mix_src_file_new_for_read (const gchar *path)
+{
+ mix_src_file_t *result = g_new (mix_src_file_t, 1);
+ result->lines = NULL;
+ result->path = g_strdup (path);
+ result->lineno = 0;
+ return result;
+}
+
+/* destroy a src file object */
+void
+mix_src_file_delete (mix_src_file_t *src)
+{
+ g_return_if_fail (src != NULL);
+ if (src->lines) g_ptr_array_free (src->lines, TRUE);
+ g_free (src->path);
+ g_free (src);
+}
+
+/* get the source file path */
+const gchar *
+mix_src_file_get_path (const mix_src_file_t *src)
+{
+ g_return_val_if_fail (src != NULL, NULL);
+ return src->path;
+}
+
+/* get a given line of the source file */
+const gchar *
+mix_src_file_get_line (const mix_src_file_t *src, guint lineno)
+{
+ g_return_val_if_fail (src != NULL, NULL);
+ if (src->lines == NULL && !load_file_ ((mix_src_file_t*)src))
+ return NULL;
+ if (lineno > src->lineno || lineno == 0)
+ return NULL;
+ return (gchar *)g_ptr_array_index (src->lines, lineno - 1);
+}
+
+/* get the total no. of lines in the file */
+guint
+mix_src_file_get_line_no (const mix_src_file_t *src)
+{
+ g_return_val_if_fail (src != NULL, 0);
+ if (src->lines == NULL && !load_file_ ((mix_src_file_t*)src))
+ return 0;
+ return src->lineno;
+}
+
diff --git a/mixlib/mix_src_file.h b/mixlib/mix_src_file.h
new file mode 100644
index 0000000..d3a7461
--- /dev/null
+++ b/mixlib/mix_src_file.h
@@ -0,0 +1,57 @@
+/* -*-c-*- ---------------- mix_src_file.h :
+ * Declaration of mix_src_file_t, a type representing a MIXAL source
+ * file.
+ * ------------------------------------------------------------------
+ * Last change: Time-stamp: <01/02/20 00:23:58 jose>
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef MIX_SRC_FILE_H
+#define MIX_SRC_FILE_H
+
+#include "mix_file.h"
+
+/* the MIXAL source file type */
+typedef struct mix_src_file_t mix_src_file_t;
+
+/* create a new src file from an existing disk file */
+extern mix_src_file_t *
+mix_src_file_new_for_read (const gchar *path);
+
+/* destroy a src file object */
+extern void
+mix_src_file_delete (mix_src_file_t *src);
+
+/* get the source file path */
+extern const gchar *
+mix_src_file_get_path (const mix_src_file_t *src);
+
+/* get a given line of the source file */
+extern const gchar *
+mix_src_file_get_line (const mix_src_file_t *src, guint lineno);
+
+/* get the total no. of lines in the file */
+extern guint
+mix_src_file_get_line_no (const mix_src_file_t *src);
+
+
+
+#endif /* MIX_SRC_FILE_H */
+
diff --git a/mixlib/mix_symbol_table.c b/mixlib/mix_symbol_table.c
new file mode 100644
index 0000000..dc56b7a
--- /dev/null
+++ b/mixlib/mix_symbol_table.c
@@ -0,0 +1,198 @@
+/* -*-c-*- -------------- mix_symbol_table.c :
+ * Implementation of the functions declared in mix_symbol_table.h
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000, 2001, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <ctype.h> /* isdigit */
+#include <string.h>
+
+#include "mix_symbol_table.h"
+
+/* Create an empty table */
+mix_symbol_table_t *
+mix_symbol_table_new (void)
+{
+ return g_hash_table_new (g_str_hash, g_str_equal);
+}
+
+/* Create a table and populate it with the contents of a table stored
+ in -file- using mix_symbol_table_print (table, MIX_SYM_LINE, file)
+*/
+mix_symbol_table_t *
+mix_symbol_table_new_from_file (FILE *file)
+{
+ mix_symbol_table_t *result = mix_symbol_table_new ();
+ if ( result != NULL )
+ {
+ gchar sym[MIX_SYM_MAX_LEN + 1];
+ glong val;
+
+ while ( getc (file) == ',' )
+ {
+ if ( fscanf (file, "%s =%ld", sym, &val) != EOF )
+ mix_symbol_table_add (result, sym, mix_word_new (val));
+ }
+ }
+ return result;
+}
+
+/* Delete a table */
+static void
+delete_hash_keys_ (gpointer key, gpointer value, gpointer data)
+{
+ g_free (key);
+}
+
+void
+mix_symbol_table_delete (mix_symbol_table_t *table)
+{
+ g_hash_table_foreach (table, delete_hash_keys_, NULL);
+ g_hash_table_destroy (table);
+}
+
+/* add/remove symbols from other table */
+static void
+add_symbol_ (gpointer symbol, gpointer value, gpointer target)
+{
+ mix_symbol_table_t *t = (mix_symbol_table_t *)target;
+ gchar *s = (gchar *)symbol;
+ mix_word_t v = (mix_word_t)GPOINTER_TO_UINT (value);
+ mix_symbol_table_insert (t, s, v);
+}
+
+static void
+remove_symbol_ (gpointer symbol, gpointer value, gpointer target)
+{
+ mix_symbol_table_t *t = (mix_symbol_table_t *)target;
+ gchar *s = (gchar *)symbol;
+ mix_symbol_table_remove (t, s);
+}
+
+gboolean
+mix_symbol_table_merge_table (mix_symbol_table_t *table,
+ const mix_symbol_table_t *from)
+{
+ g_return_val_if_fail (table != NULL, FALSE);
+ if (from != NULL)
+ {
+ mix_symbol_table_foreach ((gpointer)from, add_symbol_, table);
+ }
+ return TRUE;
+}
+
+gboolean
+mix_symbol_table_substract_table (mix_symbol_table_t *table,
+ const mix_symbol_table_t *other)
+{
+ g_return_val_if_fail (table != NULL, FALSE);
+ if (other != NULL)
+ {
+ mix_symbol_table_foreach ((gpointer)other, remove_symbol_, table);
+ }
+ return TRUE;
+}
+
+
+/* Add/remove symbols one by one */
+gint
+mix_symbol_table_add (mix_symbol_table_t *table,
+ const gchar *sym, mix_word_t value)
+{
+ gpointer key, val;
+
+ if ( table == NULL || sym == NULL ) return MIX_SYM_FAIL;
+ if ( strlen (sym) > MIX_SYM_MAX_LEN ) return MIX_SYM_LONG;
+
+ if ( !g_hash_table_lookup_extended (table, sym, &key, &val) )
+ {
+ key = g_strdup (sym);
+ g_hash_table_insert (table, key, (gpointer)value);
+ return MIX_SYM_OK;
+ }
+ else
+ return MIX_SYM_DUP;
+}
+
+/* Add or modify symbol if it exists */
+gint
+mix_symbol_table_insert (mix_symbol_table_t *table,
+ const gchar *sym, mix_word_t new_value)
+{
+ gpointer key, val;
+
+ if ( table == NULL || sym == NULL ) return MIX_SYM_FAIL;
+ if ( strlen (sym) > MIX_SYM_MAX_LEN ) return MIX_SYM_LONG;
+
+ if ( !g_hash_table_lookup_extended (table, sym, &key, &val) )
+ key = g_strdup (sym);
+ g_hash_table_insert (table, key, (gpointer)new_value);
+ return MIX_SYM_OK;
+}
+
+
+/* Symbols lookup */
+gboolean
+mix_symbol_table_is_defined (const mix_symbol_table_t *table, const gchar *sym)
+{
+ gpointer key, val;
+ return g_hash_table_lookup_extended((GHashTable *)table, sym, &key, &val);
+}
+
+/* Print table */
+#define is_local_sym_(sym) \
+ ((sym) && (strlen (sym)==2) && (sym[1] == 'B') && isdigit (sym[0]))
+
+static gboolean skip_ = FALSE;
+
+static void
+print_sym_rows_ (gpointer symbol, gpointer value, gpointer file)
+{
+ char *s = (char *)symbol;
+ if (skip_ && !is_local_sym_ (s)) {
+ mix_word_t word = (mix_word_t)GPOINTER_TO_UINT (value);
+ fprintf((FILE *)file, "%-20s: %s%ld\n", s,
+ mix_word_is_negative (word)? "-":"",
+ mix_word_magnitude (word));
+ }
+}
+
+static void
+print_sym_line_ (gpointer symbol, gpointer value, gpointer file)
+{
+ char *s = (char *)symbol;
+ if (skip_ && !is_local_sym_ (s)) {
+ mix_word_t word = (mix_word_t)GPOINTER_TO_UINT (value);
+ fprintf((FILE *)file, ",%s =%s%ld", s,
+ mix_word_is_negative (word)? "-":"",
+ mix_word_magnitude (word));
+ }
+}
+
+void
+mix_symbol_table_print (const mix_symbol_table_t *table, gint mode,
+ FILE *file, gboolean skiplocal)
+{
+ GHFunc func = (mode == MIX_SYM_LINE)? print_sym_line_ : print_sym_rows_;
+ skip_ = skiplocal;
+ if ( table != NULL )
+ g_hash_table_foreach ((GHashTable *)table, func, (gpointer)file);
+ if ( mode == MIX_SYM_LINE ) putc (';', file); /* to mark end-of-table */
+}
+
+
diff --git a/mixlib/mix_symbol_table.h b/mixlib/mix_symbol_table.h
new file mode 100644
index 0000000..c54c3f8
--- /dev/null
+++ b/mixlib/mix_symbol_table.h
@@ -0,0 +1,109 @@
+/* -*-c-*- ---------------- mix_symbol_table.h :
+ * Type mix_symbol_table_t and functions to manipulate it.
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef MIX_SYMBOL_TABLE_H
+#define MIX_SYMBOL_TABLE_H
+
+#include <stdio.h>
+#include "mix_types.h"
+
+/* A symbol table shall be implemented as a hash table */
+typedef GHashTable mix_symbol_table_t ;
+
+/* Maximum length of stored symbols */
+#define MIX_SYM_MAX_LEN 10
+
+/* Create an empty table */
+extern mix_symbol_table_t *
+mix_symbol_table_new (void);
+
+/* Create a table and populate it with the contents of a table stored
+ in -file- using mix_symbol_table_print (table, MIX_SYM_LINE, file)
+*/
+extern mix_symbol_table_t *
+mix_symbol_table_new_from_file (FILE *file);
+
+
+/* Delete a table */
+extern void
+mix_symbol_table_delete (mix_symbol_table_t *table);
+
+/* add/remove symbols from other table */
+extern gboolean
+mix_symbol_table_merge_table (mix_symbol_table_t *table,
+ const mix_symbol_table_t *from);
+
+extern gboolean
+mix_symbol_table_substract_table (mix_symbol_table_t *table,
+ const mix_symbol_table_t *other);
+
+/* Add/remove symbols one by one */
+/* possible outcomes: */
+enum {
+ MIX_SYM_FAIL, /* attempt failed */
+ MIX_SYM_OK,
+ MIX_SYM_DUP, /* duplicated symbol */
+ MIX_SYM_LONG /* symbol too long: only MIX_SYM_MAX_LEN chars used */
+};
+
+extern gint
+mix_symbol_table_add (mix_symbol_table_t *table,
+ const gchar *sym, mix_word_t value);
+
+#define mix_symbol_table_remove(table, sym) \
+ g_hash_table_remove (table, sym)
+
+
+/* Add or modify symbol if it exists */
+extern gint
+mix_symbol_table_insert (mix_symbol_table_t *table,
+ const gchar *sym, mix_word_t new_value);
+
+/* Add or modify symbol if it exists, without copying sym */
+#define mix_symbol_table_insert_static(table,sym,value)\
+ g_hash_table_insert (table,(gpointer)sym,GUINT_TO_POINTER (value))
+
+/* Symbols lookup */
+extern gboolean
+mix_symbol_table_is_defined (const mix_symbol_table_t *table, const gchar *sym);
+
+#define mix_symbol_table_value(table,sym) \
+ (mix_word_t)GPOINTER_TO_UINT (g_hash_table_lookup ((GHashTable *)table, \
+ (gpointer)sym))
+
+/* Traverse the table */
+#define mix_symbol_table_foreach(table,func,data) \
+ g_hash_table_foreach (table,func,data)
+
+/* Print the table */
+enum {
+ MIX_SYM_ROWS, /* each symbol/value in a row */
+ MIX_SYM_LINE /* {,symbol =value}*; in a single row */
+};
+
+extern void
+mix_symbol_table_print (const mix_symbol_table_t *table, gint mode,
+ FILE *file, gboolean skiplocal);
+
+
+#endif /* MIX_SYMBOL_TABLE_H */
+
diff --git a/mixlib/mix_types.c b/mixlib/mix_types.c
new file mode 100644
index 0000000..f87247a
--- /dev/null
+++ b/mixlib/mix_types.c
@@ -0,0 +1,569 @@
+/* -*-c-*- ------------------ mix_types.c :
+ * Implementation file for mix_types.h declarations.
+ * ------------------------------------------------------------------
+ * $Id: mix_types.c,v 1.5 2005/09/20 19:43:13 jao Exp $
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000, 2001, 2002, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "mix.h"
+#include <limits.h>
+#include <ctype.h>
+#include "mix_types.h"
+
+
+/*------------------------ initialisation stuff ------------------------*/
+/* flag telling whether a field spec is valid */
+static gboolean is_bad_field_[MIX_BYTE_MAX + 1];
+/* shift associated with a fspec */
+static guint shift_[MIX_BYTE_MAX + 1];
+/* mask associated with a fspec */
+static glong mask_[MIX_BYTE_MAX + 1];
+
+/* maps from gchar's to mix_char_t */
+#define NONP_ (guchar)('?')
+static mix_char_t ascii_to_mix_char_[UCHAR_MAX + 1];
+static guchar mix_char_to_ascii_[MIX_CHAR_MAX + 1] = {
+ ' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', '~', 'J',
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', '[', '#', 'S', 'T',
+ 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '.', ',', '(', ')', '+', '-', '*', '/', '=', '$',
+ '<', '>', '@', ';', ':', '\''
+};
+
+
+/* initialise the above arrays */
+void
+mix_init_types (void)
+{
+ guint lt, rt;
+ for (lt = 0; lt < 8; ++lt)
+ for (rt = 0; rt < 8; ++rt)
+ {
+ guint F = 8 * lt + rt;
+ is_bad_field_[F] = rt < lt || 5 < rt;
+ if ( is_bad_field_[F] )
+ shift_[F] = 0, mask_[F] = 0;
+ else
+ {
+ guint width = rt - (lt == 0 ? 1 : lt) + 1;
+ shift_[F] = 6 * (5 - rt);
+ mask_[F] = ((1L << (6 * width)) - 1) << shift_[F];
+ }
+ }
+
+ for ( lt = 0; lt < UCHAR_MAX + 1; ++lt )
+ ascii_to_mix_char_[lt] = NONP_;
+ for ( lt = 0; lt < MIX_CHAR_MAX + 1; ++lt )
+ ascii_to_mix_char_[mix_char_to_ascii_[lt]] = (guchar)lt;
+}
+
+mix_char_t
+mix_ascii_to_char (guchar c)
+{
+ return ascii_to_mix_char_[toupper (c)];
+}
+
+
+guchar
+mix_char_to_ascii (mix_char_t c)
+{
+ return c > MIX_CHAR_MAX ? NONP_ : mix_char_to_ascii_[c];
+}
+
+
+/*---------------------------- m_word_t --------------------------------- */
+
+/* Create mix_word_t from an array of mix_byte_t */
+mix_word_t
+mix_bytes_to_word (mix_byte_t *bytes, guint byteno)
+{
+ mix_word_t result = 0;
+ guint k;
+
+ g_return_val_if_fail (bytes != NULL, MIX_WORD_ZERO);
+ g_return_val_if_fail (byteno != 0, MIX_WORD_ZERO);
+
+ if ( byteno > 5 ) byteno = 5;
+ for ( k = 0; k < byteno; k++ )
+ result |= ((gulong)bytes[k]) << (6*(byteno-k-1));
+
+ return result;
+}
+
+
+/* Field operations */
+mix_word_t /* the specified field or 0 if f is not valid */
+mix_word_get_field (mix_fspec_t f, mix_word_t word)
+{
+ mix_word_t result;
+
+ g_return_val_if_fail (!is_bad_field_[f],MIX_WORD_ZERO);
+
+ result = ( (word & mask_[f]) >> shift_[f] );
+ if (f < 8) /* if f is of the form (0:R), retain the sign of word */
+ result |= mix_word_sign (word);
+
+ return result;
+}
+
+
+mix_word_t
+mix_word_set_field (mix_fspec_t f, mix_word_t from, mix_word_t to)
+{
+ mix_word_t result;
+ glong m = mask_[f];
+
+ g_return_val_if_fail (!is_bad_field_[f],to);
+
+ if (f < 8) /* if F is of the form (0:R), use the sign of -from- */
+ result = (to & ~m & ~MIX_WORD_SIGN_BIT)
+ | ((from /*<< shift_[f]*/) & m) | mix_word_sign (from);
+ else
+ result = (to & ~m) | ((from /*<< shift_[f]*/) & m);
+
+ return result;
+}
+
+mix_word_t
+mix_word_store_field (mix_fspec_t f, mix_word_t from, mix_word_t to)
+{
+ mix_word_t result;
+ glong m = mask_[f];
+
+ g_return_val_if_fail (!is_bad_field_[f],to);
+
+ if (f < 8) /* if F is of the form (0:R), use the sign of -from- */
+ result = (to & ~m & ~MIX_WORD_SIGN_BIT)
+ | ((from << shift_[f]) & m) | mix_word_sign (from);
+ else
+ result = (to & ~m) | ((from << shift_[f]) & m);
+
+ return result;
+}
+
+
+
+gboolean
+mix_fspec_is_valid (mix_fspec_t f)
+{
+ return !(is_bad_field_[f]);
+}
+
+mix_byte_t
+mix_word_get_byte (mix_word_t word, /* word parsed */
+ guint idx /* byte: 1 to 5 */ )
+{
+ mix_byte_t fspec = mix_fspec_new (idx,idx);
+
+ g_return_val_if_fail ((idx > 0 && idx < 6), MIX_BYTE_ZERO);
+
+ return mix_byte_new (mix_word_get_field (fspec,word));
+}
+
+
+extern void
+mix_word_set_byte (mix_word_t *into, guint idx, mix_byte_t value)
+{
+ mix_word_t from = value;
+ mix_byte_t fspec = mix_fspec_new (idx,idx);
+
+ g_return_if_fail (into != NULL);
+ g_return_if_fail (idx > 0 && idx < 6);
+
+ from <<= shift_[fspec];
+ *into = mix_word_set_field (fspec,from,*into);
+}
+
+/* Arithmetic operations */
+mix_word_t
+mix_word_add (mix_word_t x, mix_word_t y)
+{
+ static const gulong MIX_WORD_MAX_SIM = 2*MIX_WORD_MAX + 1;
+
+ gint32 result;
+ if ( mix_word_sign (x) == mix_word_sign (y) )
+ {
+ result = (mix_word_magnitude (x) + mix_word_magnitude (y));
+ if ( result > MIX_WORD_MAX ) {
+ /* for instance MIX_WORD_MAX + 1 = - MIX_WORD_MAX */
+ result = MIX_WORD_MAX_SIM - result;
+ result |= mix_word_sign (mix_word_negative (x));
+ } else if ( result != 0 )
+ result |= mix_word_sign (x);
+ /* keep positive sign for 0 so that w - w == -w + w */
+ }
+ else
+ {
+ result = mix_word_magnitude (x) - mix_word_magnitude (y);
+ if (result < 0)
+ result = -result|mix_word_sign (y);
+ else if (result > 0)
+ result = result|mix_word_sign (x);
+ /* keep positive sign for 0 so that w - w == -w + w */
+ }
+
+ g_assert ( result >= 0 );
+
+ return (mix_word_t)result;
+}
+
+gboolean /* TRUE if overflow */
+mix_word_add_and_carry (mix_word_t x, mix_word_t y,
+ mix_word_t *h, mix_word_t *l)
+{
+ gboolean result;
+
+ if ( mix_word_sign (x) == mix_word_sign (y) )
+ {
+ guint32 sum = (mix_word_magnitude (x) + mix_word_magnitude (y));
+ if ( sum > MIX_WORD_MAX )
+ {
+ result = TRUE;
+ if ( l != NULL )
+ {
+ *l = sum - MIX_WORD_MAX -1;
+ *l |= mix_word_sign (x);
+ }
+ if ( h != NULL )
+ {
+ *h = sum >> 30;
+ *h |= mix_word_sign (x);
+ }
+ }
+ else /* sum <= MIX_WORD_MAX */
+ {
+ result = FALSE;
+ if ( h != NULL ) *h = 0;
+ if ( l != NULL )
+ {
+ *l = sum;
+ if ( sum != 0 )
+ *l |= mix_word_sign (x);
+ /* keep positive sign for 0 so that w - w == -w + w */
+ }
+ }
+ }
+ else /* mix_word_sign (x) != mix_word_sign (y) */
+ {
+ result = FALSE;
+ if ( h != NULL ) *h = 0;
+ if ( l != NULL )
+ {
+ gint32 dif = mix_word_magnitude (x) - mix_word_magnitude (y);
+ if ( dif < 0)
+ *l = (-dif)|mix_word_sign (y);
+ else if ( dif > 0)
+ *l = dif|mix_word_sign (x);
+ else /* keep positive sign for 0 so that w - w == -w + w */
+ *l = MIX_WORD_ZERO;
+ }
+ }
+
+ return result;
+}
+
+
+void
+mix_word_mul (mix_word_t x, mix_word_t y,
+ mix_word_t *high_word, mix_word_t *low_word)
+{
+ guint32 sign = mix_word_sign (x) ^ mix_word_sign (y);
+
+ /*
+ x = x0 + x1 * 2 ^ 10 + x2 * 2 ^ 20
+ y = y0 + y1 * 2 ^ 10 + y2 * 2 ^ 20
+ x0, x1, x2, y0, y1, y2 are < 2 ^ 10
+ */
+ guint32 x0 = (x & 0x000003FF);
+ guint32 x1 = (x & 0x000FFC00) >> 10;
+ guint32 x2 = (x & 0x3FF00000) >> 20;
+ guint32 y0 = (y & 0x000003FF);
+ guint32 y1 = (y & 0x000FFC00) >> 10;
+ guint32 y2 = (y & 0x3FF00000) >> 20;
+
+ /*
+ x * y = partial0 +
+ partial1 * 2 ^ 10 +
+ partial2 * 2 ^ 20 +
+ partial3 * 2 ^ 30 +
+ partial4 * 2 ^ 40
+ partial0 and partial4 are < 2 ^ 20
+ partial1 and partial3 are < 2 ^ 21
+ partial2 is < 3 * 2 ^ 20
+ */
+ guint32 partial0 = x0 * y0;
+ guint32 partial1 = x0 * y1 + x1 * y0;
+ guint32 partial2 = x0 * y2 + x1 * y1 + x2 * y0;
+ guint32 partial3 = x1 * y2 + x2 * y1;
+ guint32 partial4 = x2 * y2;
+
+ /* sum1 has a place value of 1 and is < 2 ^ 32 */
+ guint32 sum1 = partial0 + (partial1 << 10);
+ guint32 carry1 = (sum1 & 0xFFF00000) >> 20;
+
+ /* sum2 has a place value of 2 ^ 20 and is < 2 ^ 32 */
+ guint32 sum2 = partial2 + (partial3 << 10) + carry1;
+ guint32 carry2 = (sum2 & 0xFFF00000) >> 20;
+
+ /* sum3 has a place value of 2 ^ 40 and is < 2 ^ 20 */
+ guint32 sum3 = partial4 + carry2;
+
+ sum1 &= ~0xFFF00000;
+ sum2 &= ~0xFFF00000;
+
+ /*
+ Now paste the three values back into two.
+ */
+ if ( low_word != NULL ) {
+ *low_word = sum1 | ((sum2 & 0x000003FF) << 20);
+ *low_word |= sign;
+ }
+ if ( high_word != NULL ) {
+ *high_word = ((sum2 & 0x000FFC00) >> 10) | (sum3 << 10);
+ *high_word |= sign;
+ }
+}
+
+
+gboolean
+mix_word_div (mix_word_t n1, mix_word_t n0, mix_word_t d,
+ mix_word_t *quotient, mix_word_t *remainder)
+{
+ gboolean overflow = FALSE;
+ long magn1 = mix_word_magnitude (n1);
+ long magd = mix_word_magnitude (d);
+
+ if (magd == 0)
+ {
+ overflow = TRUE;
+ /* just so they have -some- valid value */
+ if ( quotient != NULL ) *quotient = 0;
+ if ( remainder != NULL ) *remainder = 0;
+ }
+ else if (magn1 == 0)
+ { /* special-cased for speed */
+ if ( quotient != NULL )
+ *quotient = (mix_word_sign (n1) ^ mix_word_sign (d))
+ | (mix_word_magnitude (n0) / magd);
+ if ( remainder != NULL )
+ *remainder = mix_word_sign (n1) | (mix_word_magnitude (n0) % magd);
+ }
+ else if (magd <= magn1)
+ {
+ overflow = TRUE;
+ if ( quotient != NULL ) *quotient = 0;
+ if ( remainder != NULL ) *remainder = 0;
+ }
+ else
+ {
+ long q = mix_word_magnitude (n0);
+ long r = magn1;
+ unsigned i;
+ for (i = 30; i != 0; --i) {
+ r <<= 1;
+ if ( (q & (1L << 29)) != 0 )
+ ++r;
+ q = (q << 1) & ((1L << 30) - 1);
+ if (magd <= r)
+ ++q, r -= magd;
+ }
+ if ( quotient != NULL )
+ *quotient = (mix_word_sign (n1) ^ mix_word_sign (d)) | q;
+ if ( remainder != NULL )
+ *remainder = mix_word_sign(n1) | r;
+ }
+ return overflow;
+}
+
+void
+mix_word_shift_right (mix_word_t A, mix_word_t X, gulong count,
+ mix_word_t *pA, mix_word_t *pX)
+{
+ if ( pX != NULL ) *pX = mix_word_sign (X);
+ if ( pA != NULL ) *pA = mix_word_sign (A);
+ if (count < 5) {
+ if ( pA != NULL )
+ *pA |= mix_word_magnitude (A) >> (6 * count);
+ if ( pX != NULL )
+ *pX |= MIX_WORD_MAX & ( (mix_word_magnitude (X) >> (6 * count))
+ | (A << (30 - 6 * count)) );
+ } else if (count < 10 && pX != NULL)
+ *pX |= mix_word_magnitude (A) >> (6 * count - 30);
+ else
+ ;
+}
+
+
+void
+mix_word_shift_left (mix_word_t A, mix_word_t X, gulong count,
+ mix_word_t *pA, mix_word_t *pX)
+{
+ if ( pX != NULL ) *pX = mix_word_sign (X);
+ if ( pA != NULL ) *pA = mix_word_sign (A);
+ if (count < 5) {
+ if ( pX != NULL ) *pX |= MIX_WORD_MAX & (X << (6 * count));
+ if ( pA != NULL )
+ *pA |= MIX_WORD_MAX & ( (A << (6 * count)) |
+ (mix_word_magnitude (X) >> (30 - 6 * count)) );
+ } else if (count < 10 && pA != NULL)
+ *pA |= MIX_WORD_MAX & (X << (6 * count - 30));
+ else
+ ;
+}
+
+void
+mix_word_shift_left_circular (mix_word_t A, mix_word_t X, gulong count,
+ mix_word_t *pA, mix_word_t *pX)
+{
+ mix_word_t A1, X1;
+ guint c;
+
+ count %= 10;
+ A1 = count < 5 ? A : X;
+ X1 = count < 5 ? X : A;
+ c = 6 * (count < 5 ? count : count - 5);
+ if ( pX != NULL )
+ *pX = mix_word_sign (X)
+ | ( MIX_WORD_MAX & (X1 << c) ) | ( mix_word_magnitude (A1) >> (30 - c) );
+ if ( pA != NULL )
+ *pA = mix_word_sign (A)
+ | ( MIX_WORD_MAX & (A1 << c) ) | ( mix_word_magnitude (X1) >> (30 - c) );
+}
+
+void
+mix_word_shift_right_circular (mix_word_t A, mix_word_t X, gulong count,
+ mix_word_t *pA, mix_word_t *pX)
+{
+ mix_word_t A1, X1;
+ guint c;
+
+ count %= 10;
+ A1 = count < 5 ? A : X;
+ X1 = count < 5 ? X : A;
+ c = 6 * (count < 5 ? count : count - 5);
+ if ( pX != NULL )
+ *pX = mix_word_sign (X)
+ | ( mix_word_magnitude (X1) >> c ) | ( MIX_WORD_MAX & (A1 << (30 - c)) );
+ if ( pA != NULL )
+ *pA = mix_word_sign (A)
+ | ( mix_word_magnitude (A1) >> c ) | ( MIX_WORD_MAX & (X1 << (30 - c)) );
+}
+
+
+/* Printable representation */
+void
+mix_word_print_to_file (mix_word_t word, const char *message, FILE *f)
+{
+ guint k;
+ if ( message ) fprintf (f, "%s ", message);
+ fprintf (f, "%s ", mix_word_sign (word) == 0 ? "+" : "-");
+ for ( k = 1; k < 6; ++k ) {
+ fprintf (f, "%02d ", mix_word_get_byte (word,k));
+ }
+ fprintf (f, "(%010ld)", mix_word_magnitude (word));
+}
+
+void
+mix_word_print_to_buffer (mix_word_t word, gchar *buf)
+{
+ g_return_if_fail (buf != NULL);
+ sprintf (buf, "%s %02d %02d %02d %02d %02d",
+ mix_word_sign (word) == 0 ? "+" : "-",
+ mix_word_get_byte (word, 1),
+ mix_word_get_byte (word, 2),
+ mix_word_get_byte (word, 3),
+ mix_word_get_byte (word, 4),
+ mix_word_get_byte (word, 5));
+}
+
+/* Conversions between words and shorts */
+mix_short_t
+mix_word_to_short (mix_word_t word)
+{
+ if ( mix_word_is_negative (word) )
+ return ( (word & MIX_SHORT_MAX) | MIX_SHORT_SIGN_BIT );
+ else
+ return (word & MIX_SHORT_MAX);
+}
+
+mix_word_t
+mix_short_to_word (mix_short_t s)
+{
+ if ( mix_short_is_negative (s) )
+ return ((mix_word_t) (mix_short_magnitude (s) | MIX_WORD_SIGN_BIT));
+ else
+ return ((mix_word_t)s);
+}
+
+mix_short_t
+mix_short_add (mix_short_t x, mix_short_t y)
+{
+ static const guint16 MIX_SHORT_MAX_SIM = 2*MIX_SHORT_MAX + 1;
+
+ gint16 result;
+ if ( mix_short_sign (x) == mix_short_sign (y) )
+ {
+ result = (mix_short_magnitude (x) + mix_short_magnitude (y));
+ if ( result > MIX_SHORT_MAX ) {
+ /* for instance MIX_SHORT_MAX + 1 = - MIX_SHORT_MAX */
+ result = MIX_SHORT_MAX_SIM - result;
+ result |= mix_short_sign (mix_short_negative (x));
+ } else if ( result != 0 )
+ result |= mix_short_sign (x);
+ /* keep positive sign for 0 so that w - w == -w + w */
+ }
+ else
+ {
+ result = mix_short_magnitude (x) - mix_short_magnitude (y);
+ if (result < 0)
+ result = -result|mix_short_sign (y);
+ else if (result > 0)
+ result = result|mix_short_sign (x);
+ /* keep positive sign for 0 so that w - w == -w + w */
+ }
+
+ g_assert ( result >= 0 );
+
+ return (mix_short_t)result;
+}
+
+
+/* Printable representation */
+void
+mix_short_print (mix_short_t s, const gchar *message)
+{
+ if ( message ) g_print ("%s ", message);
+ g_print ("%s ", mix_short_sign (s) == 0 ? "+" : "-");
+ g_print ("%02d %02d ", mix_byte_new (s>>6), mix_byte_new (s));
+ g_print ("(%04d)", mix_short_magnitude (s));
+}
+
+void
+mix_short_print_to_buffer (mix_short_t s, gchar *buf)
+{
+ g_return_if_fail (buf != NULL);
+ sprintf (buf, "%s %02d %02d",
+ mix_short_sign (s) == 0 ? "+" : "-",
+ mix_byte_new (s>>6), mix_byte_new (s));
+ /* g_print ("(%04d)", mix_short_magnitude (s));*/
+}
+
+
+
+
diff --git a/mixlib/mix_types.h b/mixlib/mix_types.h
new file mode 100644
index 0000000..c628e05
--- /dev/null
+++ b/mixlib/mix_types.h
@@ -0,0 +1,293 @@
+/* -*-c-*- --------------- mix_types.h:
+ * 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, 2001, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef MIX_TYPES_H
+#define MIX_TYPES_H
+
+#include <stdio.h>
+#include "mix.h"
+
+/* Initialisation function to be called before using the other
+ * functions in this file
+ */
+extern void
+mix_init_types(void);
+
+
+/*----------------- m_byte_t --------------------------------------------*/
+/* MIX byte type */
+typedef guint8 mix_byte_t;
+
+/* Maximum value stored in an mix_byte_t */
+#define MIX_BYTE_MAX ((1L << 6) - 1)
+
+/* Zero mix byte */
+#define MIX_BYTE_ZERO ((mix_byte_t)0)
+
+/* Create a mix_byte_t from any native type */
+#define mix_byte_new(x) ((mix_byte_t)((x) & MIX_BYTE_MAX ))
+
+/* Operations */
+/* Addition */
+#define mix_byte_add(x,y) mix_byte_new((x) + (y))
+/* Substraction */
+#define mix_byte_sub(x,y) mix_byte_new((x) - (y))
+/* Product */
+#define mix_byte_mul(x,y) mix_byte_new((x) * (y))
+/* Quotient */
+#define mix_byte_div(x,y) mix_byte_new((x) / (y))
+
+
+/*----------------- mix_char_t --------------------------------------------*/
+/* MIX char type: chars are coded in MIX from 0 to MIX_CHAR_MAX */
+typedef guint8 mix_char_t;
+
+#define MIX_CHAR_MAX 55
+
+/* Conversions for mix_char_t's */
+#define mix_char_new(l) (((l) < MIX_CHAR_MAX )? (l) : MIX_CHAR_MAX)
+#define mix_char_to_byte(mchar) mix_byte_new (mchar)
+#define mix_byte_to_char(byte) mix_char_new (byte)
+
+extern mix_char_t
+mix_ascii_to_char(guchar c);
+
+extern guchar
+mix_char_to_ascii(mix_char_t c);
+
+
+/*----------------- mix_word_t --------------------------------------------*/
+/*
+ * Represented as a gint32 (glib ensures that this type has 32
+ * bits). Bit 30 is the sign, higher bits are 0,
+ * and bits 0-29 are the magnitude.
+ * Each MIX 'byte' is a 6-bit substring of the magnitude.
+ */
+typedef guint32 mix_word_t;
+
+/* Maximum value stored in an mix_word_t */
+#define MIX_WORD_MAX ((1L << 30) - 1)
+/* Sign bit in a word */
+#define MIX_WORD_SIGN_BIT (1L << 30)
+/* Zero mix word */
+#define MIX_WORD_ZERO ((mix_word_t)0)
+/* Negative zero mix word */
+#define MIX_WORD_MINUS_ZERO (MIX_WORD_ZERO | MIX_WORD_SIGN_BIT)
+
+
+/* Create a mix_word_t from any native type */
+#define mix_word_new(x) \
+( (x) < 0 \
+ ? ( MIX_WORD_SIGN_BIT | ((mix_word_t)(-(x)) & MIX_WORD_MAX) ) \
+ : ( (mix_word_t)(x) & MIX_WORD_MAX ) \
+)
+
+/* Create a mix_word_t from individual bytes */
+#define mix_word_new_b(b1,b2,b3,b4,b5) \
+((mix_word_t)(mix_byte_new(b5) + (mix_byte_new(b4)<<6) + \
+ (mix_byte_new(b3)<<12) + (mix_byte_new(b2)<<18) + \
+ (mix_byte_new(b1)<<24)))
+
+/* Create a negative mix_word_t from individual bytes */
+#define mix_word_new_bn(b1,b2,b3,b4,b5) \
+ mix_word_negative(mix_word_new_b(b1,b2,b3,b4,b5))
+
+/* Create mix_word_t from an array of mix_byte_t */
+extern mix_word_t
+mix_bytes_to_word(mix_byte_t *bytes, guint byteno);
+
+/* Access byte within a word */
+extern mix_byte_t /* byte -idx- or MIX_BYTE_ZERO if -idx- out of range */
+mix_word_get_byte(mix_word_t word, /* word parsed */
+ guint idx /* byte: 1 to 5 */);
+
+/* Set a byte within a mix_word_t */
+extern void
+mix_word_set_byte(mix_word_t *into, /* word to be modified */
+ guint idx, /* byte: 1 to 5 */
+ mix_byte_t value /* byte's value */);
+
+
+/* Operations */
+/* Sign-related definitions */
+#define mix_word_negative(word) ( (word) ^ MIX_WORD_SIGN_BIT )
+#define mix_word_reverse_sign(word) ( word ^= MIX_WORD_SIGN_BIT )
+#define mix_word_sign(word) ( (word) & MIX_WORD_SIGN_BIT )
+#define mix_word_magnitude(word) ( (word) & (MIX_WORD_SIGN_BIT - 1) )
+#define mix_word_is_positive(word) ( mix_word_sign(word) == 0 )
+#define mix_word_is_negative(word) ( mix_word_sign(word) != 0 )
+
+
+/* Arithmetic operations */
+extern mix_word_t
+mix_word_add(mix_word_t x, mix_word_t y);
+
+#define mix_word_sub(x,y) ( mix_word_add((x),mix_word_negative(y)) )
+
+/* Add two words filling a high word if needed.
+ -high_word- and/or -low_word- can be NULL.
+*/
+extern gboolean /* TRUE if overflow */
+mix_word_add_and_carry(mix_word_t x, mix_word_t y,
+ mix_word_t *high_word, mix_word_t *low_word);
+
+/* Product, stored in -high_word- and -low_word-, which
+ can be NULL.
+*/
+extern void
+mix_word_mul(mix_word_t x, mix_word_t y,
+ mix_word_t *high_word, mix_word_t *low_word);
+
+/* Division. -quotient- and/or -remainder- can be NULL. */
+extern gboolean /* TRUE if overflow */
+mix_word_div(mix_word_t n1, mix_word_t n0, mix_word_t d,
+ mix_word_t *quotient, mix_word_t *remainder);
+
+/* Shift operations */
+extern void
+mix_word_shift_left(mix_word_t A, mix_word_t X, gulong count,
+ mix_word_t *pA, mix_word_t *pX);
+extern void
+mix_word_shift_right(mix_word_t A, mix_word_t X, gulong count,
+ mix_word_t *pA, mix_word_t *pX);
+extern void
+mix_word_shift_left_circular(mix_word_t A, mix_word_t X, gulong count,
+ mix_word_t *pA, mix_word_t *pX);
+extern void
+mix_word_shift_right_circular(mix_word_t A, mix_word_t X, gulong count,
+ mix_word_t *pA, mix_word_t *pX);
+
+
+
+
+/*
+ * Fields within a word: a word containing the (L:R)
+ * bytes of the original one. L and R (with 0 <= L <= R < 6)
+ * are specified by a mix_fspec_t F = 8*L + R.
+ */
+typedef guint8 mix_fspec_t;
+
+#define mix_fspec_left(f) ( ((f)>>3) & 7 )
+#define mix_fspec_right(f) ( (f) & 7 )
+#define mix_fspec_new(L,R) ( mix_byte_new(8*(L) + (R)) )
+
+extern gboolean
+mix_fspec_is_valid(mix_fspec_t f);
+
+extern mix_word_t /* the specified field or 0 if f is not valid */
+mix_word_get_field(mix_fspec_t f, mix_word_t word);
+
+extern mix_word_t /* -to- with the field -f- from -from- or -to-
+ if -f- is not a valid fspec */
+mix_word_set_field(mix_fspec_t f, mix_word_t from, mix_word_t to);
+
+/* set field into a zero word */
+#define mix_word_extract_field(fspec,from_word) \
+ mix_word_set_field(fspec,from_word,MIX_WORD_ZERO)
+
+/* Store operation: the no. of bytes determined by -f- is taken
+ * from the right of -from- and stored into -to- in the location
+ * specified by -f-
+ */
+extern mix_word_t
+mix_word_store_field(mix_fspec_t f, mix_word_t from, mix_word_t to);
+
+
+/* Printable representation */
+#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);
+
+extern void
+mix_word_print_to_buffer (mix_word_t word, gchar *buf);
+
+
+/*----------------- mix_short_t ------------------------------------------*/
+typedef guint16 mix_short_t;
+
+#define MIX_SHORT_MAX ((1L << 12) - 1)
+#define MIX_SHORT_SIGN_BIT ((mix_short_t)(1L << 12))
+#define MIX_SHORT_ZERO ((mix_short_t)0)
+#define MIX_SHORT_MINUS_ZERO (MIX_SHORT_ZERO | MIX_SHORT_SIGN_BIT)
+
+/* Sign-related definitions */
+#define mix_short_negative(s) ( (s) ^ MIX_SHORT_SIGN_BIT )
+#define mix_short_sign(s) ( (s) & MIX_SHORT_SIGN_BIT )
+#define mix_short_magnitude(s) \
+ ( (s) & (MIX_SHORT_SIGN_BIT - 1) )
+#define mix_short_is_positive(s) ( mix_short_sign(s) == 0 )
+#define mix_short_is_negative(s) ( mix_short_sign(s) != 0 )
+#define mix_short_reverse_sign(s) ( (s) ^= MIX_SHORT_SIGN_BIT )
+
+/* create short from a long */
+#define mix_short_new(val) \
+ ((val)>= 0 ? (val)&MIX_SHORT_MAX : mix_short_negative(-(val)))
+
+/* Create shorts from individual bytes */
+#define mix_short_new_b(b1,b2) \
+((mix_short_t)((mix_byte_new(b1)<<6) + mix_byte_new(b2)))
+
+#define mix_short_new_bn(b1,b2) mix_short_negative(mix_short_new_b(b1,b2))
+
+/* Conversions between words and shorts. Arithmetic operations
+ on shorts are not provided but for addition: use words instead.
+*/
+/* Make a short taking word's sign and its two least significant
+ bytes (bytes no. 4 and 5)
+*/
+extern mix_short_t
+mix_word_to_short(mix_word_t word);
+
+extern mix_word_t
+mix_short_to_word(mix_short_t s);
+
+/* fast conversion (these macros' argument are evaluated twice */
+#define mix_word_to_short_fast(w) \
+( mix_word_is_negative(w) ? \
+ ((w) & MIX_SHORT_MAX)|MIX_SHORT_SIGN_BIT : (w)&MIX_SHORT_MAX )
+
+#define mix_short_to_word_fast(s) \
+( mix_short_is_negative(s) ? \
+(mix_word_t) (mix_short_magnitude(s)|MIX_WORD_SIGN_BIT): (mix_word_t)(s) )
+
+
+extern mix_short_t
+mix_short_add(mix_short_t x, mix_short_t y);
+
+
+/* printable representation */
+extern void
+mix_short_print(mix_short_t s, const gchar *message);
+
+extern void
+mix_short_print_to_buffer (mix_short_t s, gchar *buf);
+
+
+
+#endif /* MIX_TYPES_H */
+
+
+
+
diff --git a/mixlib/mix_vm.c b/mixlib/mix_vm.c
new file mode 100644
index 0000000..71c8bae
--- /dev/null
+++ b/mixlib/mix_vm.c
@@ -0,0 +1,706 @@
+/* -*-c-*- ------------------ mix_vm.c :
+ * Implementation of the functions declared in mix_vm.h
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000, 2001, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "mix.h"
+#include "xmix_vm.h"
+
+#define vm_reset_(vm) vm_reset_reload_ (vm, FALSE);
+
+static void
+vm_reset_reload_ (mix_vm_t *vm, gboolean is_reload)
+{
+ guint k;
+ set_status_ (vm, MIX_VM_EMPTY);
+ set_rA_ (vm, MIX_WORD_ZERO);
+ set_rX_ (vm, MIX_WORD_ZERO);
+ set_rJ_ (vm, MIX_WORD_ZERO);
+ for ( k = 1; k < IREG_NO_+1; ++k ) set_rI_ (vm, k, MIX_WORD_ZERO);
+ set_over_ (vm, FALSE);
+ set_cmp_ (vm, mix_EQ);
+ set_loc_ (vm, MIX_WORD_ZERO);
+ set_last_error_ (vm, MIX_VM_ERROR_NONE);
+ for ( k = 0; k < MEM_CELLS_NO_; ++k) set_cell_ (vm, k, MIX_WORD_ZERO);
+
+ if (vm->symbol_table != NULL )
+ {
+ mix_symbol_table_delete (vm->symbol_table);
+ vm->symbol_table = NULL;
+ }
+
+ if (vm->line_table != NULL)
+ {
+ g_tree_destroy (vm->line_table);
+ vm->line_table = NULL;
+ }
+
+ if (vm->address_table != NULL)
+ {
+ g_tree_destroy (vm->address_table);
+ vm->address_table = NULL;
+ }
+
+ if (vm->src_file != NULL)
+ {
+ mix_src_file_delete (vm->src_file);
+ vm->src_file = NULL;
+ }
+
+ for (k = 0; k < BD_NO_; ++k)
+ if (vm->devices[k] != NULL)
+ {
+ mix_device_type_t type = mix_device_type (vm->devices[k]);
+ if (!is_reload || (type != mix_dev_CONSOLE
+ && type != mix_dev_PRINTER
+ && type != mix_dev_CARD_WR))
+ {
+ mix_device_delete (vm->devices[k]);
+ vm->devices[k] = NULL;
+ }
+ }
+
+ if (!is_reload)
+ mix_vm_clear_all_breakpoints (vm);
+
+ if (vm->address_list)
+ {
+ g_slist_free (vm->address_list);
+ vm->address_list = NULL;
+ }
+}
+
+
+/* Create/destroy a mix vm */
+mix_vm_t *
+mix_vm_new (void)
+{
+ int i;
+
+ mix_vm_t *vm = g_new (struct mix_vm_t,1);
+ vm->line_table = NULL;
+ vm->address_table = NULL;
+ vm->symbol_table = NULL;
+ vm->src_file = NULL;
+ vm->pred_list = mix_predicate_list_new (vm);
+ vm->address_list = NULL;
+ vm->last_error = MIX_VM_ERROR_NONE;
+
+ for (i = 0; i < BD_NO_; ++i)
+ vm->devices[i] = NULL;
+
+ vm->clock = mix_vm_clock_new ();
+ vm->factory = mix_device_new;
+
+ vm_reset_ (vm);
+
+ return vm;
+}
+
+
+void
+mix_vm_delete (mix_vm_t * vm)
+{
+ int i;
+
+ g_return_if_fail (vm != NULL);
+
+ if (vm->line_table != NULL) g_tree_destroy (vm->line_table);
+ if (vm->address_table != NULL) g_tree_destroy (vm->address_table);
+ if (vm->symbol_table != NULL) mix_symbol_table_delete (vm->symbol_table);
+ if (vm->src_file != NULL) mix_src_file_delete (vm->src_file);
+ if (vm->pred_list != NULL) mix_predicate_list_delete (vm->pred_list);
+ if (vm->address_list != NULL) g_slist_free (vm->address_list);
+ for (i = 0; i < BD_NO_; ++i)
+ mix_device_delete (vm->devices[i]);
+ mix_vm_clock_delete (vm->clock);
+ g_free (vm);
+}
+
+/* connect devices to a virtual machine */
+mix_device_t *
+mix_vm_connect_device (mix_vm_t *vm, mix_device_t *device)
+{
+ mix_device_t *old;
+ mix_device_type_t type;
+
+ g_return_val_if_fail (vm != NULL, NULL);
+ g_return_val_if_fail (device != NULL, NULL);
+
+ type = mix_device_type (device);
+ old = vm->devices[type];
+ vm->devices[type] = device;
+
+ return old;
+}
+
+/* get device */
+mix_device_t *
+mix_vm_get_device (const mix_vm_t *vm, mix_device_type_t dev)
+{
+ g_return_val_if_fail (vm != NULL, NULL);
+ g_return_val_if_fail (dev < mix_dev_INVALID, NULL);
+ return vm->devices[dev];
+}
+
+/* install a device factory for automatic connection */
+void
+mix_vm_set_device_factory (mix_vm_t *vm, mix_device_factory_t factory)
+{
+ g_return_if_fail (vm != NULL);
+ g_return_if_fail (factory != NULL);
+ vm->factory = factory;
+}
+
+/* Reset a vm (set state as of a newly created one) */
+void
+mix_vm_reset (mix_vm_t * vm)
+{
+ g_return_if_fail (vm != NULL);
+ vm_reset_ (vm);
+}
+
+/* Set start address for execution */
+void
+mix_vm_set_start_addr (mix_vm_t *vm, mix_address_t addr)
+{
+ g_return_if_fail (vm != NULL);
+ set_loc_ (vm, addr);
+}
+
+/* Access to the vm's registers */
+mix_word_t
+mix_vm_get_rA (const mix_vm_t *vm)
+{
+ g_return_val_if_fail (vm != NULL, MIX_WORD_ZERO);
+ return get_rA_ (vm);
+}
+
+mix_word_t
+mix_vm_get_rX (const mix_vm_t *vm)
+{
+ g_return_val_if_fail (vm != NULL, MIX_WORD_ZERO);
+ return get_rX_ (vm);
+}
+
+mix_short_t
+mix_vm_get_rJ (const mix_vm_t *vm)
+{
+ g_return_val_if_fail (vm != NULL, MIX_SHORT_ZERO);
+ return mix_word_to_short_fast (get_rJ_ (vm));
+}
+
+mix_short_t
+mix_vm_get_rI (const mix_vm_t *vm, guint idx)
+{
+ g_return_val_if_fail (vm != NULL, MIX_SHORT_ZERO);
+ g_return_val_if_fail (IOK_ (idx), MIX_SHORT_ZERO);
+ return mix_word_to_short_fast (get_rI_ (vm, idx));
+}
+
+void
+mix_vm_set_rA (mix_vm_t *vm, mix_word_t value)
+{
+ g_return_if_fail (vm != NULL);
+ set_rA_ (vm, value);
+}
+
+void
+mix_vm_set_rX (mix_vm_t *vm, mix_word_t value)
+{
+ g_return_if_fail (vm != NULL);
+ set_rX_ (vm, value);
+}
+
+void
+mix_vm_set_rJ (mix_vm_t *vm, mix_short_t value)
+{
+ g_return_if_fail (vm != NULL);
+ g_return_if_fail (mix_short_is_positive (value));
+ set_rJ_ (vm, mix_short_to_word_fast (value));
+}
+
+void
+mix_vm_set_rI (mix_vm_t *vm, guint idx, mix_short_t value)
+{
+ g_return_if_fail (vm != NULL);
+ g_return_if_fail (IOK_ (idx));
+ set_rI_ (vm, idx, mix_short_to_word_fast (value));
+}
+
+/* Access to the comparison flag and overflow toggle */
+mix_cmpflag_t
+mix_vm_get_cmpflag (const mix_vm_t *vm)
+{
+ g_return_val_if_fail (vm != NULL, mix_EQ);
+ return get_cmp_ (vm);
+}
+
+void
+mix_vm_set_cmpflag (mix_vm_t *vm, mix_cmpflag_t value)
+{
+ g_return_if_fail (vm != NULL);
+ set_cmp_ (vm, value);
+}
+
+gboolean
+mix_vm_get_overflow (const mix_vm_t *vm)
+{
+ g_return_val_if_fail (vm != NULL, TRUE);
+ return get_over_ (vm);
+}
+
+void
+mix_vm_set_overflow (mix_vm_t *vm, gboolean value)
+{
+ g_return_if_fail (vm != NULL);
+ set_over_ (vm, value);
+}
+
+void
+mix_vm_toggle_overflow (mix_vm_t *vm)
+{
+ g_return_if_fail (vm != NULL);
+ set_over_ (vm, !get_over_ (vm));
+}
+
+/* Access to memory cells */
+mix_word_t
+mix_vm_get_addr_contents (const mix_vm_t *vm, mix_address_t addr)
+{
+ g_return_val_if_fail (vm != NULL, MIX_WORD_ZERO);
+ return (MEMOK_ (addr))? get_cell_ (vm, addr) : MIX_WORD_ZERO;
+}
+
+void
+mix_vm_set_addr_contents (mix_vm_t *vm, mix_address_t addr, mix_word_t value)
+{
+ g_return_if_fail (vm != NULL);
+ if (MEMOK_ (addr)) set_cell_ (vm, addr, value);
+}
+
+gboolean
+mix_vm_is_halted (const mix_vm_t *vm)
+{
+ return is_halted_ (vm);
+}
+
+/* Execution of instructions */
+gboolean /* TRUE if success */
+mix_vm_exec_ins (mix_vm_t *vm, const mix_ins_t *ins)
+{
+ g_return_val_if_fail (vm != NULL, FALSE);
+ g_return_val_if_fail (ins != NULL, FALSE);
+ return (*ins_handlers_[ins->opcode]) (vm,ins);
+}
+
+/* comparison function for the line and address tables tree */
+static gint
+cmp_uint_ (gconstpointer a, gconstpointer b)
+{
+ return GPOINTER_TO_UINT (a) - GPOINTER_TO_UINT (b);
+}
+
+gboolean
+mix_vm_load_file (mix_vm_t *vm, const gchar *name)
+{
+ mix_code_file_t *file;
+ mix_src_file_t *sfile = NULL;
+ mix_ins_desc_t ins;
+ const gchar *sp;
+ gboolean reload = FALSE;
+
+ g_return_val_if_fail (vm != NULL, FALSE);
+ file = mix_code_file_new_read (name);
+ if (file == NULL)
+ {
+ set_status_ (vm, MIX_VM_ERROR);
+ return FALSE;
+ }
+ sp = mix_code_file_get_source_path (file);
+
+ if (sp != NULL)
+ {
+ sfile = mix_src_file_new_for_read (sp);
+ reload = (vm->src_file
+ && !strcmp (mix_src_file_get_path (vm->src_file),
+ mix_src_file_get_path (sfile)));
+ }
+
+ vm_reset_reload_ (vm, reload);
+
+ if ( mix_code_file_is_debug (file) )
+ {
+ vm->symbol_table = mix_code_file_get_symbol_table (file);
+ vm->line_table = g_tree_new (cmp_uint_);
+ vm->address_table = g_tree_new (cmp_uint_);
+ }
+
+ vm->src_file = sfile;
+
+ while ( mix_code_file_get_ins (file, &ins) )
+ {
+ set_cell_ (vm, ins.address, ins.ins);
+ if ( vm->line_table != NULL )
+ {
+ g_tree_insert (vm->line_table,
+ GUINT_TO_POINTER (ins.lineno),
+ GUINT_TO_POINTER ((guint)ins.address));
+ g_tree_insert (vm->address_table,
+ GUINT_TO_POINTER ((guint)ins.address),
+ GUINT_TO_POINTER (ins.lineno));
+ }
+ }
+ set_loc_ (vm, mix_code_file_get_start_addr (file));
+ set_start_ (vm, get_loc_ (vm));
+ mix_code_file_delete (file);
+
+ set_status_ (vm, MIX_VM_LOADED);
+ return TRUE;
+}
+
+const mix_src_file_t *
+mix_vm_get_src_file (const mix_vm_t *vm)
+{
+ g_return_val_if_fail (vm != NULL, NULL);
+ return vm->src_file;
+}
+
+const mix_symbol_table_t *
+mix_vm_get_symbol_table (const mix_vm_t *vm)
+{
+ g_return_val_if_fail (vm != NULL, NULL);
+ return vm->symbol_table;
+}
+
+mix_address_t
+mix_vm_get_prog_count (const mix_vm_t *vm)
+{
+ g_return_val_if_fail (vm != NULL, MIX_SHORT_ZERO);
+ return get_loc_ (vm);
+}
+
+/* Get the source line number for a given address */
+guint
+mix_vm_get_address_lineno (const mix_vm_t *vm, mix_address_t addr)
+{
+ gpointer gp_addr = GUINT_TO_POINTER ((guint)addr);
+ guint lineno;
+
+ g_return_val_if_fail (vm != NULL, 0);
+ if (!(MEMOK_ (addr))) return 0;
+ lineno = GPOINTER_TO_UINT (g_tree_lookup (vm->address_table, gp_addr));
+ return lineno;
+}
+
+/* Get the address for a given source line number */
+typedef struct
+{
+ guint lineno;
+ mix_address_t result;
+} addr_traverse_t;
+
+static gint
+get_address_ (gpointer key, gpointer value, gpointer data)
+{
+ addr_traverse_t *tr = (addr_traverse_t *)data;
+ if (GPOINTER_TO_UINT (key) == tr->lineno)
+ {
+ tr->result = mix_short_new (GPOINTER_TO_UINT (value));
+ return TRUE;
+ }
+ return (GPOINTER_TO_UINT (key) < tr->lineno)? FALSE:TRUE;
+}
+
+mix_address_t
+mix_vm_get_lineno_address (const mix_vm_t *vm, guint lineno)
+{
+ addr_traverse_t tr;
+
+ g_return_val_if_fail (vm != NULL, MIX_VM_CELL_NO);
+ if (!vm->line_table) return MIX_VM_CELL_NO;
+ tr.lineno = lineno;
+ tr.result = MIX_VM_CELL_NO;
+ g_tree_foreach (vm->line_table, get_address_, (gpointer)&tr);
+ return tr.result;
+}
+
+
+/* continue execution of instructions in memory */
+mix_vm_status_t
+mix_vm_run (mix_vm_t *vm)
+{
+ mix_ins_t ins;
+ g_return_val_if_fail (vm != NULL, MIX_VM_ERROR);
+
+ while ( !is_halted_ (vm) )
+ {
+ mix_word_to_ins_uncheck (get_cell_ (vm, get_loc_ (vm)), ins);
+ vm->address_list =
+ g_slist_prepend (vm->address_list,
+ GINT_TO_POINTER ((gint)get_loc_ (vm)));
+ if ( !(*ins_handlers_[ins.opcode]) (vm,&ins) )
+ return set_status_ (vm, MIX_VM_ERROR);
+ else
+ update_time_ (vm, &ins);
+ if (bp_is_set_ (vm, get_loc_ (vm)))
+ return set_status_ (vm, MIX_VM_BREAK);
+ if (mix_predicate_list_eval (get_pred_list_ (vm)))
+ return set_status_ (vm, MIX_VM_COND_BREAK);
+ if (get_loc_ (vm) >= MIX_VM_CELL_NO) halt_ (vm, TRUE);
+ }
+ return set_status_ (vm, MIX_VM_HALT);
+}
+
+/* execute next memory instruction */
+mix_vm_status_t
+mix_vm_exec_next (mix_vm_t *vm)
+{
+ mix_ins_t ins;
+ g_return_val_if_fail (vm != NULL, MIX_VM_ERROR);
+ if (get_loc_ (vm) >= MIX_VM_CELL_NO) halt_ (vm, TRUE);
+ if (is_halted_ (vm)) return set_status_ (vm, MIX_VM_HALT);
+ vm->address_list =
+ g_slist_prepend (vm->address_list,
+ GINT_TO_POINTER ((gint)get_loc_ (vm)));
+ mix_word_to_ins_uncheck (get_cell_ (vm, get_loc_ (vm)), ins);
+ if (!(*ins_handlers_[ins.opcode]) (vm, &ins))
+ return set_status_ (vm, MIX_VM_ERROR);
+ else
+ update_time_ (vm, &ins);
+ if (is_halted_ (vm)) return set_status_ (vm, MIX_VM_HALT);
+ if (bp_is_set_ (vm, get_loc_ (vm))) return set_status_ (vm, MIX_VM_BREAK);
+ if (mix_predicate_list_eval (get_pred_list_ (vm)))
+ return set_status_ (vm, MIX_VM_COND_BREAK);
+ return set_status_ (vm, MIX_VM_RUNNING);
+}
+
+/* get the current execution status */
+mix_vm_status_t
+mix_vm_get_run_status (const mix_vm_t *vm)
+{
+ g_return_val_if_fail (vm != NULL, MIX_VM_ERROR);
+ return get_status_ (vm);
+}
+
+mix_vm_error_t
+mix_vm_get_last_error (const mix_vm_t *vm)
+{
+ g_return_val_if_fail (vm != NULL, MIX_VM_ERROR_UNEXPECTED);
+ return get_last_error_ (vm);
+}
+
+const gchar *
+mix_vm_get_last_error_string (const mix_vm_t *vm)
+{
+ return mix_vm_get_error_string (mix_vm_get_last_error (vm));
+}
+
+const gchar *
+mix_vm_get_error_string (mix_vm_error_t code)
+{
+ static const gchar *errors[] = {
+ N_("No error"),
+ N_("Invalid memory address"),
+ N_("Invalid device number"),
+ N_("Invalid fspec"),
+ N_("Invalid M-value"),
+ N_("Cannot access device"),
+ N_("Cannot access device for reading"),
+ N_("Cannot access device for writing"),
+ N_("Unexpected error"),
+ N_("Unknow error code")
+ };
+
+ return errors[(code < 0 || code > MIX_VM_ERROR_UNEXPECTED)
+ ? MIX_VM_ERROR_UNEXPECTED + 1 : code];
+}
+
+/* Breakpoints */
+gulong
+mix_vm_get_break_lineno (const mix_vm_t *vm)
+{
+ g_return_val_if_fail (vm != NULL, 0);
+ if (vm->address_table == NULL)
+ return 0;
+ else
+ {
+ gpointer loc = GUINT_TO_POINTER ((guint)get_loc_ (vm));
+ return GPOINTER_TO_UINT (g_tree_lookup (vm->address_table,loc));
+ }
+}
+
+typedef struct
+{
+ mix_vm_t *vm;
+ guint lineno;
+ gint result;
+} bp_traverse_t;
+
+static gint
+set_break_ (gpointer key, gpointer value, gpointer data)
+{
+ bp_traverse_t *tr = (bp_traverse_t *)data;
+ if (GPOINTER_TO_UINT (key) >= tr->lineno)
+ {
+ bp_set_ (tr->vm, mix_short_new (GPOINTER_TO_UINT (value)));
+ tr->lineno = GPOINTER_TO_UINT (key);
+ tr->result = MIX_VM_BP_OK;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+gint /* if >0 the line no. of the break point */
+mix_vm_set_breakpoint (mix_vm_t *vm, guint lineno)
+{
+ bp_traverse_t tr;
+
+ g_return_val_if_fail (vm != NULL, MIX_VM_BP_ERROR);
+ if (!vm->line_table) return MIX_VM_BP_NDEBUG;
+ tr.lineno = lineno;
+ tr.vm = vm;
+ tr.result = MIX_VM_BP_INV_LINE;
+ g_tree_foreach (vm->line_table, set_break_, (gpointer)&tr);
+ if (tr.result == MIX_VM_BP_OK)
+ return tr.lineno;
+ else
+ return tr.result;
+}
+
+gint
+mix_vm_set_breakpoint_address (mix_vm_t *vm, guint address)
+{
+ g_return_val_if_fail (vm != NULL, MIX_VM_BP_ERROR);
+ if (address >= MIX_VM_CELL_NO)
+ return MIX_VM_BP_INV_ADDRESS;
+ else
+ bp_set_ (vm, mix_short_new (address));
+ return MIX_VM_BP_OK;
+}
+
+gboolean
+mix_vm_has_breakpoint_at_address (const mix_vm_t *vm, guint address)
+{
+ g_return_val_if_fail (vm != NULL, FALSE);
+ if (address >= MIX_VM_CELL_NO) return FALSE;
+ return (bp_is_set_ (vm, address));
+}
+
+static gint
+clear_break_ (gpointer key, gpointer value, gpointer data)
+{
+ bp_traverse_t *tr = (bp_traverse_t *)data;
+ if (GPOINTER_TO_UINT (key) == tr->lineno)
+ {
+ bp_clear_ (tr->vm, mix_short_new (GPOINTER_TO_UINT (value)));
+ tr->result = MIX_VM_BP_OK;
+ return TRUE;
+ }
+ else if (GPOINTER_TO_UINT (key) > tr->lineno)
+ return TRUE;
+
+ return FALSE;
+}
+
+gint /* one of MIX_VM_BP_ */
+mix_vm_clear_breakpoint (mix_vm_t *vm, guint lineno)
+{
+ bp_traverse_t tr;
+
+ g_return_val_if_fail (vm != NULL, MIX_VM_BP_ERROR);
+ if (!vm->line_table) return MIX_VM_BP_NDEBUG;
+ tr.lineno = lineno;
+ tr.vm = vm;
+ tr.result = MIX_VM_BP_INV_LINE;
+ g_tree_foreach (vm->line_table, clear_break_, (gpointer)&tr);
+ return tr.result;
+}
+
+gint
+mix_vm_clear_breakpoint_address (mix_vm_t *vm, guint address)
+{
+ g_return_val_if_fail (vm != NULL, MIX_VM_BP_ERROR);
+ if (address >= MIX_VM_CELL_NO)
+ return MIX_VM_BP_INV_ADDRESS;
+ else
+ bp_clear_ (vm, mix_short_new (address));
+ return MIX_VM_BP_OK;
+}
+
+void
+mix_vm_clear_all_breakpoints (mix_vm_t *vm)
+{
+ g_return_if_fail (vm != NULL);
+ bp_clear_all_ (vm);
+ mix_predicate_list_clear (get_pred_list_ (vm));
+}
+
+
+gboolean
+mix_vm_set_conditional_breakpoint (mix_vm_t *vm, mix_predicate_t *pred)
+{
+ g_return_val_if_fail (vm != NULL, FALSE);
+ g_return_val_if_fail (pred != NULL, FALSE);
+ mix_predicate_list_add (get_pred_list_ (vm), pred);
+ return TRUE;
+}
+
+gboolean
+mix_vm_clear_conditional_breakpoint (mix_vm_t *vm, mix_predicate_t *pred)
+{
+ g_return_val_if_fail (vm != NULL, FALSE);
+ g_return_val_if_fail (pred != NULL, FALSE);
+ return mix_predicate_list_remove (get_pred_list_ (vm), pred);
+}
+
+const gchar *
+mix_vm_get_last_breakpoint_message (const mix_vm_t *vm)
+{
+ const mix_predicate_t *last = NULL;
+ g_return_val_if_fail (vm != NULL, NULL);
+ if ((last = mix_predicate_list_last_true_eval (get_pred_list_ (vm))) != NULL)
+ return mix_predicate_get_message (last);
+ return NULL;
+}
+
+mix_predicate_type_t
+mix_vm_get_last_conditional_breakpoint_type (const mix_vm_t *vm)
+{
+ const mix_predicate_t *last = NULL;
+ g_return_val_if_fail (vm != NULL, MIX_PRED_INVALID);
+ last = mix_predicate_list_last_true_eval (get_pred_list_ (vm));
+ return last? mix_predicate_get_type (last) : MIX_PRED_INVALID;
+}
+
+/* Get the vm uptime, defined as the time spent executing instructions */
+mix_time_t
+mix_vm_get_uptime (const mix_vm_t *vm)
+{
+ g_return_val_if_fail (vm != NULL, 0);
+ return mix_vm_clock_get_time (get_clock_ (vm));
+}
+
+/* Get the list of addresses for executed instructions */
+const GSList *
+mix_vm_get_backtrace (const mix_vm_t *vm)
+{
+ g_return_val_if_fail (vm != NULL, NULL);
+ return get_address_list_ (vm);
+}
diff --git a/mixlib/mix_vm.h b/mixlib/mix_vm.h
new file mode 100644
index 0000000..12b082a
--- /dev/null
+++ b/mixlib/mix_vm.h
@@ -0,0 +1,255 @@
+/* ---------------------- mix_vm.h :
+ * Types and functions implementing the MIX virtual machine
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000, 2001, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef MIX_VM_H
+#define MIX_VM_H
+
+#include "mix_types.h"
+#include "mix_ins.h"
+#include "mix_device.h"
+#include "mix_code_file.h"
+#include "mix_src_file.h"
+#include "mix_symbol_table.h"
+#include "mix_vm_clock.h"
+
+/* Comparison flag */
+typedef enum { mix_LESS, mix_EQ, mix_GREAT } mix_cmpflag_t;
+
+/* Number of memory cells in the virtual machine */
+enum { MIX_VM_CELL_NO = 4000 };
+
+/* Opaque type for the mix virtual machine */
+typedef struct mix_vm_t mix_vm_t;
+
+/* Create/destroy a mix vm */
+extern mix_vm_t *
+mix_vm_new(void);
+
+extern void
+mix_vm_delete(mix_vm_t * vm);
+
+/* connect devices to a virtual machine */
+extern mix_device_t * /* previously connected device */
+mix_vm_connect_device (mix_vm_t *vm, mix_device_t *device);
+
+/* get device */
+extern mix_device_t *
+mix_vm_get_device (const mix_vm_t *vm, mix_device_type_t dev);
+
+/* install a device factory for automatic connection */
+typedef mix_device_t * (* mix_device_factory_t) (mix_device_type_t device);
+extern void
+mix_vm_set_device_factory (mix_vm_t *vm, mix_device_factory_t factory);
+
+/* Reset a vm (set state as of a newly created one) */
+extern void
+mix_vm_reset(mix_vm_t * vm);
+
+/* Set start address for execution */
+extern void
+mix_vm_set_start_addr(mix_vm_t *vm, mix_address_t addr);
+
+/* Access to the vm's registers */
+extern mix_word_t
+mix_vm_get_rA(const mix_vm_t *vm);
+
+extern mix_word_t
+mix_vm_get_rX(const mix_vm_t *vm);
+
+extern mix_short_t
+mix_vm_get_rJ(const mix_vm_t *vm);
+
+extern mix_short_t
+mix_vm_get_rI(const mix_vm_t *vm, guint idx);
+
+extern void
+mix_vm_set_rA(mix_vm_t *vm, mix_word_t value);
+
+extern void
+mix_vm_set_rX(mix_vm_t *vm, mix_word_t value);
+
+extern void
+mix_vm_set_rJ(mix_vm_t *vm, mix_short_t value);
+
+extern void
+mix_vm_set_rI(mix_vm_t *vm, guint idx, mix_short_t value);
+
+/* Access to the comparison flag and overflow toggle */
+extern mix_cmpflag_t
+mix_vm_get_cmpflag(const mix_vm_t *vm);
+
+extern void
+mix_vm_set_cmpflag(mix_vm_t *vm, mix_cmpflag_t value);
+
+extern gboolean
+mix_vm_get_overflow(const mix_vm_t *vm);
+
+extern void
+mix_vm_set_overflow(mix_vm_t *vm, gboolean value);
+
+extern void
+mix_vm_toggle_overflow(mix_vm_t *vm);
+
+extern gboolean
+mix_vm_is_halted(const mix_vm_t *vm);
+
+/* Access to memory cells */
+extern mix_word_t
+mix_vm_get_addr_contents(const mix_vm_t *vm, mix_address_t addr);
+
+extern void
+mix_vm_set_addr_contents(mix_vm_t *vm, mix_address_t addr, mix_word_t value);
+
+/* Execution of instructions and programs */
+extern gboolean /* TRUE if success */
+mix_vm_exec_ins(mix_vm_t *vm, const mix_ins_t *ins);
+
+/* Load a code file into memory (-name- does not need the default extension)
+ * resetting the vm's state
+ */
+extern gboolean
+mix_vm_load_file(mix_vm_t *vm, const gchar *name);
+
+/* Get the source file object corresponding to the last loaded code file */
+extern const mix_src_file_t *
+mix_vm_get_src_file (const mix_vm_t *vm);
+
+/* Get symbol table of loaded file */
+extern const mix_symbol_table_t *
+mix_vm_get_symbol_table (const mix_vm_t *vm);
+
+/* Get current program counter */
+extern mix_address_t
+mix_vm_get_prog_count (const mix_vm_t *vm);
+
+/* Get the source line number for a given address */
+extern guint
+mix_vm_get_address_lineno (const mix_vm_t *vm, mix_address_t addr);
+
+/* Get the address for a given source line number */
+extern mix_address_t
+mix_vm_get_lineno_address (const mix_vm_t *vm, guint lineno);
+
+/* continue execution of instructions in memory */
+/* Possible outcomes */
+typedef enum {
+ MIX_VM_ERROR, /* error executing instructions */
+ MIX_VM_BREAK, /* breakpoint found */
+ MIX_VM_COND_BREAK, /* conditional breakpoint found */
+ MIX_VM_HALT, /* end of execution */
+ MIX_VM_RUNNING, /* successful instruction execution */
+ MIX_VM_LOADED, /* program loaded */
+ MIX_VM_EMPTY /* no program loaded */
+} mix_vm_status_t;
+
+/* execution errors */
+typedef enum {
+ MIX_VM_ERROR_NONE, /* no error */
+ MIX_VM_ERROR_BAD_ACCESS, /* bad memory address */
+ MIX_VM_ERROR_BAD_DEVICE_NO, /* bad device number */
+ MIX_VM_ERROR_BAD_FSPEC, /* invalid fspec */
+ MIX_VM_ERROR_BAD_M, /* invalid M-value */
+ MIX_VM_ERROR_DEV_CTL, /* error accessing device for ioctl */
+ MIX_VM_ERROR_DEV_READ, /* error accessing device for reading */
+ MIX_VM_ERROR_DEV_WRITE, /* error accessing device for writing */
+ MIX_VM_ERROR_UNEXPECTED /* unexpected error */
+} mix_vm_error_t;
+
+extern mix_vm_error_t
+mix_vm_get_last_error (const mix_vm_t *vm);
+
+extern const gchar *
+mix_vm_get_last_error_string (const mix_vm_t *vm);
+
+extern const gchar *
+mix_vm_get_error_string (mix_vm_error_t code);
+
+/* run until next breakpoint or end of execution */
+extern mix_vm_status_t
+mix_vm_run (mix_vm_t *vm);
+
+/* execute next memory instruction */
+extern mix_vm_status_t
+mix_vm_exec_next (mix_vm_t *vm);
+
+/* get the current execution status */
+extern mix_vm_status_t
+mix_vm_get_run_status (const mix_vm_t *vm);
+
+/* get the line no. of the last break or 0 if not found */
+extern gulong
+mix_vm_get_break_lineno (const mix_vm_t *vm);
+
+
+/* Breakpoints */
+/* possible error outcomes */
+enum {
+ MIX_VM_BP_ERROR = -4, /* internal error */
+ MIX_VM_BP_NDEBUG = -3, /* no debug info */
+ MIX_VM_BP_INV_ADDRESS = -2, /* address out of range */
+ MIX_VM_BP_INV_LINE = -1, /* invalid line no. */
+ MIX_VM_BP_OK = 0 /* success */
+};
+
+
+extern gint /* if >0 the line no. of the break point */
+mix_vm_set_breakpoint (mix_vm_t *vm, guint lineno);
+
+extern gint /* one of MIX_VM_BP_ */
+mix_vm_set_breakpoint_address (mix_vm_t *vm, guint address);
+
+extern gint /* one of MIX_VM_BP_ */
+mix_vm_clear_breakpoint (mix_vm_t *vm, guint lineno);
+
+extern gint /* one of MIX_VM_BP_ */
+mix_vm_clear_breakpoint_address (mix_vm_t *vm, guint address) ;
+
+extern gboolean
+mix_vm_has_breakpoint_at_address (const mix_vm_t *vm, guint address);
+
+extern void
+mix_vm_clear_all_breakpoints (mix_vm_t *vm);
+
+#include "mix_predicate.h"
+extern gboolean
+mix_vm_set_conditional_breakpoint (mix_vm_t *vm, mix_predicate_t *pred);
+
+extern gboolean
+mix_vm_clear_conditional_breakpoint (mix_vm_t *vm, mix_predicate_t *pred);
+
+extern const gchar *
+mix_vm_get_last_breakpoint_message (const mix_vm_t *vm);
+
+extern mix_predicate_type_t
+mix_vm_get_last_conditional_breakpoint_type (const mix_vm_t *vm);
+
+/* Get the vm uptime, defined as the time spent executing instructions */
+extern mix_time_t
+mix_vm_get_uptime (const mix_vm_t *vm);
+
+/* Get the list of addresses for executed instructions */
+extern const GSList *
+mix_vm_get_backtrace (const mix_vm_t *vm);
+
+
+#endif /* MIX_VM_H */
+
diff --git a/mixlib/mix_vm_clock.c b/mixlib/mix_vm_clock.c
new file mode 100644
index 0000000..cc39992
--- /dev/null
+++ b/mixlib/mix_vm_clock.c
@@ -0,0 +1,70 @@
+/* -*-c-*- -------------- mix_vm_clock.c :
+ * Implementation of the functions declared in mix_vm_clock.h
+ * ------------------------------------------------------------------
+ * $Id: mix_vm_clock.c,v 1.3 2005/09/20 19:43:13 jao Exp $
+ * ------------------------------------------------------------------
+ * 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
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#include "mix_vm_clock.h"
+
+static const mix_time_t exec_times_[] = {
+ 1, 2, 2, 10, 12, 10, 2, 1,
+ 2, 2, 2, 2 , 2, 2, 2, 2,
+ 2, 2, 2, 2 , 2, 2, 2, 2,
+ 2, 2, 2, 2 , 2, 2, 2, 2,
+ 2, 2, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2 , 2, 2, 2, 2
+};
+
+
+/* Create/delete a clock */
+mix_vm_clock_t *
+mix_vm_clock_new ()
+{
+ mix_vm_clock_t *result = g_new (mix_vm_clock_t, 1);
+ result->time = 0;
+ return result;
+}
+
+void
+mix_vm_clock_delete (mix_vm_clock_t *clock)
+{
+ g_return_if_fail (clock != NULL);
+}
+
+/* Increase time with the units needed to execute ins */
+mix_time_t
+mix_vm_clock_add_lapse (mix_vm_clock_t *clock, const mix_ins_t *ins)
+{
+ mix_time_t t = 0;
+ g_return_val_if_fail (clock != NULL, 0);
+ if (ins != NULL)
+ {
+ t = exec_times_[ins->opcode];
+ if (ins->opcode == mix_opMOVE) {
+ t += 2 * (ins->fspec);
+ }
+ }
+ clock->time += t;
+ return t;
+}
+
diff --git a/mixlib/mix_vm_clock.h b/mixlib/mix_vm_clock.h
new file mode 100644
index 0000000..3c19973
--- /dev/null
+++ b/mixlib/mix_vm_clock.h
@@ -0,0 +1,55 @@
+/* -*-c-*- ---------------- mix_vm_clock.h :
+ * Declaration of mix_vm_clock_t, a clock for the MIX virtual machine.
+ * ------------------------------------------------------------------
+ * Last change: Time-stamp: <01/02/20 00:23:58 jose>
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef MIX_VM_CLOCK_H
+#define MIX_VM_CLOCK_H
+
+#include "mix.h"
+#include "mix_ins.h"
+
+/* the type of time unit */
+typedef gulong mix_time_t;
+
+/* the clock type */
+typedef struct mix_vm_clock_t
+{
+ mix_time_t time;
+} mix_vm_clock_t;
+
+/* Create/delete a clock */
+extern mix_vm_clock_t *
+mix_vm_clock_new ();
+
+extern void
+mix_vm_clock_delete (mix_vm_clock_t *clock);
+
+/* Increase time with the units needed to execute ins */
+extern mix_time_t /* the added lapse */
+mix_vm_clock_add_lapse (mix_vm_clock_t *clock, const mix_ins_t *ins);
+
+/* Get the time since creation */
+#define mix_vm_clock_get_time(clock) (clock? clock->time:0)
+
+#endif /* MIX_VM_CLOCK_H */
+
diff --git a/mixlib/mix_vm_command.c b/mixlib/mix_vm_command.c
new file mode 100644
index 0000000..350dae5
--- /dev/null
+++ b/mixlib/mix_vm_command.c
@@ -0,0 +1,641 @@
+/* -*-c-*- -------------- mix_vm_command.c :
+ * Implementation of the functions declared in mix_vm_command.h
+ * ------------------------------------------------------------------
+ * $Id: mix_vm_command.c,v 1.30 2005/09/20 19:43:13 jao Exp $
+ * ------------------------------------------------------------------
+ * Copyright (C) 2001, 2002, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#include "xmix_vm_command.h"
+#include "xmix_vm_handlers.h"
+
+#ifdef HAVE_LIBHISTORY
+# include <readline/history.h>
+#endif
+
+#ifdef HAVE_LIBREADLINE
+# include <readline/readline.h>
+#endif
+
+/* hook execution */
+static void
+exec_hook_list_ (GSList *list, mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ while (list)
+ {
+ hook_ *hook = (hook_ *)list->data;
+ if (hook)
+ (hook->func)(dis, arg, hook->data);
+ list = list->next;
+ }
+}
+
+static void
+exec_global_hook_list_ (GSList *list,
+ mix_vm_cmd_dispatcher_t *dis,
+ mix_vm_command_t cmd, const gchar *arg)
+{
+ while (list)
+ {
+ global_hook_ *hook = (global_hook_ *)list->data;
+ if (hook)
+ (hook->func)(dis, cmd, arg, hook->data);
+ list = list->next;
+ }
+}
+
+/* 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)
+{
+ 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 */
+static GCompletion *
+make_completions_ (void)
+{
+ GList *cmds = NULL;
+ gint k;
+
+ GCompletion *completions = g_completion_new (NULL);
+ for (k = 0; k < MIX_CMD_INVALID; ++k)
+ cmds = g_list_append (cmds, (gpointer) mix_vm_command_to_string (k));
+ g_completion_add_items (completions, cmds);
+ return completions;
+}
+
+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->result = TRUE;
+ result->out = out_fd;
+ result->err = err_fd;
+ result->log_msg = TRUE;
+ result->uptime = result->laptime = result->progtime = 0;
+ result->printtime = TRUE;
+ result->trace = FALSE;
+ result->program = NULL;
+ result->editor = NULL;
+ result->assembler = NULL;
+ 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 = result->global_post = NULL;
+
+ for (k =0; k < MIX_CMD_INVALID; ++k)
+ result->pre_hooks[k] = result->post_hooks[k] = NULL;
+
+ result->config = NULL;
+
+ for (k = 0; k < PRNO_; ++k)
+ result->preds[k] = mix_predicate_new (k);
+
+ result->mem_preds = g_hash_table_new (NULL, NULL);
+ result->commands = g_hash_table_new (g_str_hash, g_str_equal);
+ result->completions = make_completions_ ();
+
+ return result;
+}
+
+mix_vm_cmd_dispatcher_t *
+mix_vm_cmd_dispatcher_new_with_config (FILE *out, FILE *err,
+ mix_config_t *config)
+{
+ mix_vm_cmd_dispatcher_t *result = mix_vm_cmd_dispatcher_new (out, err);
+ if (result != NULL && (result->config = config) != NULL)
+ {
+ gint hsize = 0;
+ const gchar *val = mix_config_get (result->config, TRACING_KEY_);
+ if (val) cmd_strace_ (result, val);
+ val = mix_config_get (result->config, EDITOR_KEY_);
+ if (val) mix_vm_cmd_dispatcher_set_editor (result, val);
+ val = mix_config_get (result->config, ASM_KEY_);
+ if (val) mix_vm_cmd_dispatcher_set_assembler (result, val);
+ val = mix_config_get (result->config, TIMING_KEY_);
+ if (val) cmd_stime_ (result, val);
+ val = mix_config_get_devices_dir (result->config);
+ if (!val || !mix_stat_dir (val, "devices"))
+ {
+ gchar *dirname =
+ g_path_get_dirname (mix_config_get_filename (config));
+ cmd_sddir_ (result, dirname);
+ g_free (dirname);
+ }
+ else
+ mix_device_set_dir (val);
+ val = mix_config_get (result->config, LOGGING_KEY_);
+ if (val) cmd_slog_ (result, val);
+#ifdef HAVE_LIBHISTORY
+ val = mix_config_get_history_file (result->config);
+ hsize = mix_config_get_history_size (result->config);
+ using_history ();
+ stifle_history (hsize);
+ if (val)
+ {
+ read_history ((char *)val);
+ history_set_pos (history_base + history_length - 1);
+ }
+#endif
+ }
+ return result;
+}
+
+
+/* delete (does not close the fds in the constructor) */
+static gboolean
+del_pred_ (gpointer key, gpointer val, gpointer data)
+{
+ if (val) mix_predicate_delete ((mix_predicate_t *)val);
+ return TRUE;
+}
+
+static void
+del_hook_ (gpointer data, gpointer ignored)
+{
+ if (data) g_free (data);
+}
+
+static void
+del_hook_list_ (GSList *s)
+{
+ if (s)
+ {
+ g_slist_foreach (s, del_hook_, NULL);
+ g_slist_free (s);
+ }
+}
+
+void
+mix_vm_cmd_dispatcher_delete (mix_vm_cmd_dispatcher_t *dis)
+{
+ const gchar *hfile = NULL;
+ gint k;
+
+ g_return_if_fail (dis != NULL);
+ mix_eval_delete (dis->eval);
+ mix_dump_context_delete (dis->dump);
+ mix_vm_delete (dis->vm);
+ if (dis->editor) g_free (dis->editor);
+ if (dis->editor) g_free (dis->assembler);
+#ifdef HAVE_LIBHISTORY
+ if (dis->config && (hfile = mix_config_get_history_file
+ (dis->config)))
+ write_history ((char *)hfile);
+#endif
+ for (k = 0; k < PRNO_; ++k) mix_predicate_delete (dis->preds[k]);
+ g_hash_table_foreach_remove (dis->mem_preds, del_pred_, NULL);
+ g_hash_table_destroy (dis->mem_preds);
+ g_hash_table_destroy (dis->commands);
+ g_completion_free (dis->completions);
+ for (k = 0; k < MIX_CMD_INVALID; ++k)
+ {
+ del_hook_list_ (dis->pre_hooks[k]);
+ del_hook_list_ (dis->post_hooks[k]);
+ }
+ del_hook_list_ (dis->global_pre);
+ del_hook_list_ (dis->global_post);
+ g_free (dis);
+}
+
+/* register new commands for a dispatcher */
+void
+mix_vm_cmd_dispatcher_register_new (mix_vm_cmd_dispatcher_t *dis,
+ mix_vm_command_info_t *cmd)
+{
+ GList *list = NULL;
+ g_return_if_fail (dis != NULL);
+ g_return_if_fail (cmd != NULL);
+ g_hash_table_insert (dis->commands, (gpointer)cmd->name, (gpointer)cmd);
+ list = g_list_append (list, (gpointer)cmd->name);
+ g_completion_add_items (dis->completions, list);
+}
+
+const GList *
+mix_vm_cmd_dispatcher_complete (const mix_vm_cmd_dispatcher_t *dis,
+ const gchar *cmd, gchar **prefix)
+{
+ char *cp;
+ GList *result;
+
+ g_return_val_if_fail (dis != NULL, NULL);
+ g_return_val_if_fail (cmd != NULL, NULL);
+
+ cp = g_strdup (cmd);
+ result = g_completion_complete (dis->completions, cp, prefix);
+ g_free (cp);
+ return result;
+}
+
+/* set/get out/error streams */
+FILE *
+mix_vm_cmd_dispatcher_get_out_stream (const mix_vm_cmd_dispatcher_t *dis)
+{
+ g_return_val_if_fail (dis, NULL);
+ return dis->out;
+}
+
+FILE *
+mix_vm_cmd_dispatcher_get_err_stream (const mix_vm_cmd_dispatcher_t *dis)
+{
+ g_return_val_if_fail (dis, NULL);
+ return dis->err;
+}
+
+FILE * /* old output stream */
+mix_vm_cmd_dispatcher_set_out_stream (mix_vm_cmd_dispatcher_t *dis, FILE *out)
+{
+ FILE *old = NULL;
+ g_return_val_if_fail (dis != NULL, old);
+ old = dis->out;
+ dis->out = out;
+ dis->dump->channel = out;
+ return old;
+}
+
+FILE * /* old error stream */
+mix_vm_cmd_dispatcher_set_error_stream (mix_vm_cmd_dispatcher_t *dis,
+ FILE *err)
+{
+ FILE *old = NULL;
+ g_return_val_if_fail (dis != NULL, old);
+ old = dis->err;
+ dis->err = err;
+ return old;
+}
+
+
+/* set editor and compiler templates */
+void
+mix_vm_cmd_dispatcher_set_editor (mix_vm_cmd_dispatcher_t *dis,
+ const gchar *edit_tplt)
+{
+ g_return_if_fail (dis != NULL);
+ if (dis->editor) g_free (dis->editor);
+ dis->editor = (edit_tplt) ? g_strdup (edit_tplt) : NULL;
+ if (dis->config && dis->editor)
+ mix_config_update (dis->config, EDITOR_KEY_, dis->editor);
+}
+
+void
+mix_vm_cmd_dispatcher_set_assembler (mix_vm_cmd_dispatcher_t *dis,
+ const gchar *asm_tplt)
+{
+ g_return_if_fail (dis != NULL);
+ if (dis->assembler) g_free (dis->assembler);
+ dis->assembler = (asm_tplt) ? g_strdup (asm_tplt) : NULL;
+ if (dis->config && dis->assembler)
+ mix_config_update (dis->config, ASM_KEY_, dis->assembler);
+}
+
+const gchar *
+mix_vm_cmd_dispatcher_get_editor (const mix_vm_cmd_dispatcher_t *dis)
+{
+ g_return_val_if_fail (dis != NULL, NULL);
+ return dis->editor;
+}
+
+const gchar *
+mix_vm_cmd_dispatcher_get_assembler (const mix_vm_cmd_dispatcher_t *dis)
+{
+ g_return_val_if_fail (dis != NULL, NULL);
+ return dis->assembler;
+}
+
+const gchar *
+mix_vm_cmd_dispatcher_get_src_file_path (const mix_vm_cmd_dispatcher_t *dis)
+{
+ static gchar *PATH = NULL;
+
+ const mix_vm_t *vm = mix_vm_cmd_dispatcher_get_vm (dis);
+ const mix_src_file_t *f = mix_vm_get_src_file (vm);
+
+ if (PATH)
+ {
+ g_free (PATH);
+ PATH = NULL;
+ }
+
+ if (f)
+ PATH = mix_file_complete_name (mix_src_file_get_path (f), MIX_SRC_DEFEXT);
+
+ return PATH;
+}
+
+const gchar *
+mix_vm_cmd_dispatcher_get_program_path (const mix_vm_cmd_dispatcher_t *dis)
+{
+ g_return_val_if_fail (dis != NULL, NULL);
+ return dis->program;
+}
+
+/* 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)
+{
+ hook_ *phook;
+
+ g_return_if_fail (dis != NULL);
+ g_return_if_fail (cmd < MIX_CMD_INVALID);
+
+ phook = g_new (hook_, 1);
+ phook->func = hook;
+ phook->data = data;
+
+ dis->pre_hooks[cmd] = g_slist_append (dis->pre_hooks[cmd], phook);
+}
+
+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)
+{
+ hook_ *phook;
+
+ g_return_if_fail (dis != NULL);
+ g_return_if_fail (cmd < MIX_CMD_INVALID);
+
+ phook = g_new (hook_, 1);
+ phook->func = hook;
+ phook->data = data;
+
+ dis->post_hooks[cmd] = g_slist_append (dis->post_hooks[cmd], phook);
+}
+
+void
+mix_vm_cmd_dispatcher_global_pre_hook (mix_vm_cmd_dispatcher_t *dis,
+ mix_vm_cmd_global_hook_t hook,
+ gpointer data)
+{
+ global_hook_ *phook;
+
+ g_return_if_fail (dis != NULL);
+
+ phook = g_new (global_hook_, 1);
+ phook->func = hook;
+ phook->data = data;
+
+ dis->global_pre = g_slist_append (dis->global_pre, phook);
+}
+
+void
+mix_vm_cmd_dispatcher_global_post_hook (mix_vm_cmd_dispatcher_t *dis,
+ mix_vm_cmd_global_hook_t hook,
+ gpointer data)
+{
+ global_hook_ *phook;
+
+ g_return_if_fail (dis != NULL);
+
+ phook = g_new (global_hook_, 1);
+ phook->func = hook;
+ phook->data = data;
+
+ dis->global_post = g_slist_append (dis->global_post, phook);
+}
+
+/* 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)
+{
+ g_return_val_if_fail (dis != NULL, FALSE);
+
+ if (dis->global_pre)
+ exec_global_hook_list_ (dis->global_pre, dis, cmd, arg);
+
+ if (cmd < MIX_CMD_INVALID)
+ {
+ if (dis->pre_hooks[cmd])
+ exec_hook_list_ (dis->pre_hooks[cmd], dis, arg);
+
+ fflush (dis->out);
+ fflush (dis->err);
+
+ dis->result = (commands_[cmd].func)(dis, arg);
+
+ fflush (dis->out);
+ fflush (dis->err);
+
+ if (dis->post_hooks[cmd])
+ exec_hook_list_ (dis->post_hooks[cmd], dis, arg);
+
+ fflush (dis->out);
+ fflush (dis->err);
+ }
+ else
+ {
+ fprintf (dis->err, _("Unknown command. Try: help\n"));
+ }
+
+ if (dis->global_post)
+ exec_global_hook_list_ (dis->global_post, dis, cmd, arg);
+
+ fflush (dis->out);
+ fflush (dis->err);
+ return dis->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;
+
+ 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;
+ }
+
+ (void) mix_vm_cmd_dispatcher_dispatch_split_text (dis, cp, arg);
+
+ g_free (cp);
+
+ return dis->result;
+}
+
+/* dispatch a command in text format, with command and arg split */
+gboolean
+mix_vm_cmd_dispatcher_dispatch_split_text (mix_vm_cmd_dispatcher_t *dis,
+ const gchar *command,
+ const gchar *arg)
+{
+ mix_vm_command_info_t *info;
+
+ g_return_val_if_fail (dis, FALSE);
+
+ if (!command) return FALSE;
+ if (!arg) arg = "";
+
+ info = (mix_vm_command_info_t *)g_hash_table_lookup (dis->commands, command);
+
+ if (info)
+ {
+ if (dis->global_pre)
+ exec_global_hook_list_ (dis->global_pre, dis, MIX_CMD_LOCAL, arg);
+
+ fflush (dis->out);
+ fflush (dis->err);
+
+ dis->result = info->func (dis, arg);
+
+ fflush (dis->out);
+ fflush (dis->err);
+
+ if (dis->global_post)
+ exec_global_hook_list_ (dis->global_post, dis, MIX_CMD_LOCAL, arg);
+
+ fflush (dis->out);
+ fflush (dis->err);
+ }
+ else
+ dis->result =
+ mix_vm_cmd_dispatcher_dispatch (dis,
+ mix_vm_command_from_string (command),
+ arg);
+ return dis->result;
+}
+
+
+/* get the last dispatch's result */
+gboolean
+mix_vm_cmd_dispatcher_get_last_result (const mix_vm_cmd_dispatcher_t *dis)
+{
+ g_return_val_if_fail (dis != NULL, FALSE);
+ return dis->result;
+}
+
+/* get total uptime */
+mix_time_t
+mix_vm_cmd_dispatcher_get_uptime (const mix_vm_cmd_dispatcher_t *dis)
+{
+ g_return_val_if_fail (dis != NULL, 0);
+ return dis->uptime;
+}
+
+/* get program total time */
+mix_time_t
+mix_vm_cmd_dispatcher_get_progtime (const mix_vm_cmd_dispatcher_t *dis)
+{
+ g_return_val_if_fail (dis != NULL, 0);
+ return dis->progtime;
+}
+
+/* get time lapse */
+mix_time_t
+mix_vm_cmd_dispatcher_get_laptime (const mix_vm_cmd_dispatcher_t *dis)
+{
+ g_return_val_if_fail (dis != NULL, 0);
+ return dis->laptime;
+}
+
+/* toggle time printing */
+void
+mix_vm_cmd_dispatcher_print_time (mix_vm_cmd_dispatcher_t * dis, gboolean print)
+{
+ g_return_if_fail (dis != NULL);
+ dis->printtime = print;
+}
+
+/* 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;
+}
+
+/* src file info */
+gulong
+mix_vm_cmd_dispatcher_get_src_file_lineno (const mix_vm_cmd_dispatcher_t *dis)
+{
+ g_return_val_if_fail (dis != NULL, 0);
+ return mix_vm_get_break_lineno (dis->vm);
+}
+
+const gchar *
+mix_vm_cmd_dispatcher_get_src_file_line (const mix_vm_cmd_dispatcher_t *dis,
+ gulong line, gboolean cr)
+{
+ const mix_src_file_t *file;
+ g_return_val_if_fail (dis != NULL, NULL);
+
+ file = mix_vm_get_src_file (dis->vm);
+
+ if (line == 0 || file == NULL) return cr? "" : "\n";
+
+ if (cr)
+ return mix_src_file_get_line (file, line);
+ else
+ {
+ enum {BUFF_SIZE = 256};
+ static gchar BUFFER[BUFF_SIZE];
+ int len =
+ g_snprintf (BUFFER, BUFF_SIZE, "%s", mix_src_file_get_line (file, line));
+ if (len > 0 && BUFFER[len - 1] == '\n') BUFFER[len - 1] = '\0';
+ return BUFFER;
+ }
+}
+
+
diff --git a/mixlib/mix_vm_command.h b/mixlib/mix_vm_command.h
new file mode 100644
index 0000000..1ff561f
--- /dev/null
+++ b/mixlib/mix_vm_command.h
@@ -0,0 +1,256 @@
+/* -*-c-*- ---------------- mix_vm_command.h :
+ * declarations for mix_vm_command_t, describing commands issued to a vm
+ * ------------------------------------------------------------------
+ * $Id: mix_vm_command.h,v 1.15 2005/09/20 19:43:13 jao Exp $
+ * ------------------------------------------------------------------
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef MIX_VM_COMMAND_H
+#define MIX_VM_COMMAND_H
+
+#include <stdio.h>
+#include "mix.h"
+#include "mix_vm.h"
+#include "mix_config.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_EDIT, /* edit mixal source */
+ MIX_CMD_PEDIT, /* print editor command */
+ MIX_CMD_SEDIT, /* set editor command*/
+ MIX_CMD_COMPILE, /* compile mixal source */
+ MIX_CMD_PASM, /* print compiler command */
+ MIX_CMD_SASM, /* set assembler command */
+ MIX_CMD_RUN, /* run a loaded program */
+ MIX_CMD_NEXT, /* run next instruction */
+ MIX_CMD_PSTAT, /* print current vm status */
+ 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_SBPR, /* set breakpoint on register changed */
+ MIX_CMD_CBPR, /* clear breakpoint on register changed */
+ MIX_CMD_SBPM, /* set breakpoint on mem cell changed */
+ MIX_CMD_CBPM, /* clear breakpoint on mem cell changed */
+ MIX_CMD_SBPC, /* set breakpoint on comp flag changed */
+ MIX_CMD_CBPC, /* clear breakpoint on comp flag changed */
+ MIX_CMD_SBPO, /* set breakpoint on overflow toggled */
+ MIX_CMD_CBPO, /* clear breakpoint on overflow toggled */
+ MIX_CMD_CABP, /* clear all breakpoints */
+ MIX_CMD_WEVAL, /* evaluate a w-expression */
+ MIX_CMD_W2D, /* print word in decimal notation */
+ MIX_CMD_STRACE, /* enable/disable instruction traces */
+ MIX_CMD_PBT, /* print backtrace */
+ MIX_CMD_STIME, /* enable/disable timing statistics */
+ MIX_CMD_PTIME, /* print current time statistics */
+ MIX_CMD_SDDIR, /* set device directory */
+ MIX_CMD_PDDIR, /* print current device directory */
+ MIX_CMD_SLOG, /* set on/off message logging */
+ MIX_CMD_PPROG, /* print the current program path */
+ MIX_CMD_PSRC, /* print the current program source path */
+ MIx_CMD_PLINE, /* print the current line no */
+ MIX_CMD_INVALID, /* invalid command identifier */
+ MIX_CMD_LOCAL /* locally defined command */
+} mix_vm_command_t;
+
+/* new commands definition */
+typedef gboolean (*mix_vm_cmd_function_t) (mix_vm_cmd_dispatcher_t *,
+ const gchar *);
+typedef struct {
+ const gchar *name; /* User printable name of the function. */
+ mix_vm_cmd_function_t func; /* Function to call to do the job. */
+ const char *doc; /* Documentation for this function. */
+ const char *usage; /* Usage */
+} mix_vm_command_info_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, /* output messages file */
+ FILE *err /* error messages file */);
+
+extern mix_vm_cmd_dispatcher_t *
+mix_vm_cmd_dispatcher_new_with_config (FILE *out, FILE *err,
+ mix_config_t *config);
+
+/* delete (does not close the fds in the constructor) */
+extern void
+mix_vm_cmd_dispatcher_delete (mix_vm_cmd_dispatcher_t *dis);
+
+/* register new commands for a dispatcher */
+extern void
+mix_vm_cmd_dispatcher_register_new (mix_vm_cmd_dispatcher_t *dis,
+ mix_vm_command_info_t *cmd);
+
+/* get command completion list */
+const GList *
+mix_vm_cmd_dispatcher_complete (const mix_vm_cmd_dispatcher_t *dis,
+ const gchar *cmd, gchar **prefix);
+
+/* set/get out/error streams */
+extern FILE *
+mix_vm_cmd_dispatcher_get_out_stream (const mix_vm_cmd_dispatcher_t *dis);
+
+extern FILE *
+mix_vm_cmd_dispatcher_get_err_stream (const mix_vm_cmd_dispatcher_t *dis);
+
+extern FILE * /* old output stream */
+mix_vm_cmd_dispatcher_set_out_stream (mix_vm_cmd_dispatcher_t *dis,
+ FILE *out);
+
+extern FILE * /* old error stream */
+mix_vm_cmd_dispatcher_set_error_stream (mix_vm_cmd_dispatcher_t *dis,
+ FILE *err);
+
+/* set editor and compiler templates */
+extern void
+mix_vm_cmd_dispatcher_set_editor (mix_vm_cmd_dispatcher_t *dis,
+ const gchar *edit_tplt);
+
+extern void
+mix_vm_cmd_dispatcher_set_assembler (mix_vm_cmd_dispatcher_t *dis,
+ const gchar *asm_tplt);
+
+extern const gchar *
+mix_vm_cmd_dispatcher_get_src_file_path (const mix_vm_cmd_dispatcher_t *dis);
+
+extern const gchar *
+mix_vm_cmd_dispatcher_get_program_path (const mix_vm_cmd_dispatcher_t *dis);
+
+extern const gchar *
+mix_vm_cmd_dispatcher_get_editor (const mix_vm_cmd_dispatcher_t *dis);
+
+extern const gchar *
+mix_vm_cmd_dispatcher_get_assembler (const 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);
+
+/* dispatch a command in text format, with command and arg split */
+extern gboolean
+mix_vm_cmd_dispatcher_dispatch_split_text (mix_vm_cmd_dispatcher_t *dis,
+ const gchar *command,
+ const gchar *arg);
+
+/* get the last dispatch's result */
+extern gboolean
+mix_vm_cmd_dispatcher_get_last_result (const mix_vm_cmd_dispatcher_t *dis);
+
+/* get total uptime */
+extern mix_time_t
+mix_vm_cmd_dispatcher_get_uptime (const mix_vm_cmd_dispatcher_t *dis);
+
+/* get program total time */
+extern mix_time_t
+mix_vm_cmd_dispatcher_get_progtime (const mix_vm_cmd_dispatcher_t *dis);
+
+/* get time lapse */
+extern mix_time_t
+mix_vm_cmd_dispatcher_get_laptime (const mix_vm_cmd_dispatcher_t *dis);
+
+/* src file info */
+extern gulong
+mix_vm_cmd_dispatcher_get_src_file_lineno (const mix_vm_cmd_dispatcher_t *dis);
+
+extern const gchar *
+mix_vm_cmd_dispatcher_get_src_file_line (const mix_vm_cmd_dispatcher_t *dis,
+ gulong line, gboolean cr);
+
+/* toggle time printing */
+extern void
+mix_vm_cmd_dispatcher_print_time (mix_vm_cmd_dispatcher_t * dis,
+ gboolean print);
+
+/* 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
new file mode 100644
index 0000000..5c0bc32
--- /dev/null
+++ b/mixlib/mix_vm_dump.c
@@ -0,0 +1,147 @@
+/* ---------------------- mix_vm_dump.c :
+ * Implementation of the functions declared in mix_vm_dump.h
+ * ------------------------------------------------------------------
+** Copyright (C) 2000 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**
+*/
+
+#include "mix.h"
+#include <unistd.h>
+#include "xmix_vm.h"
+#include "mix_vm_dump.h"
+
+/* Create/destroy a dump context */
+mix_dump_context_t *
+mix_dump_context_new(FILE *fd, mix_address_t begin, mix_address_t end,
+ guint32 options)
+{
+ mix_dump_context_t *result = NULL;
+
+ g_return_val_if_fail (fd != NULL, NULL);
+
+ if ( begin > end ) begin = end;
+ if ( end >= MEM_CELLS_NO_ ) end = MEM_CELLS_NO_;
+
+ result = g_new (mix_dump_context_t,1);
+ result->options = options;
+ result->begin = begin;
+ result->end = end;
+ result->channel = fd;
+
+ return result;
+}
+
+void
+mix_dump_context_delete (mix_dump_context_t *dc)
+{
+ g_return_if_fail (dc != NULL);
+ g_free (dc);
+}
+
+/* Use the dump context */
+#define WORD_FMT_ "%s %02d %02d %02d %02d %02d (%010ld)"
+#define SHORT_FMT_ "%s %02d %02d (%04d)"
+#define WORD_SIGN_(w) mix_word_is_negative (w)? "-":"+"
+#define SHORT_SIGN_(s) mix_short_is_negative (s)? "-":"+"
+#define WORD_ABS_(w) mix_word_magnitude (w)
+#define SHORT_ABS_(s) mix_short_magnitude (s)
+#define WORD_BYTE_(w,i) mix_byte_new (mix_word_magnitude (w)>>(6*(5-i)))
+#define SHORT_BYTE_(s,i) mix_byte_new (mix_short_magnitude (s)>>(6*(2-i)))
+#define WORD_ARGS_(w) WORD_SIGN_ (w), WORD_BYTE_ (w,1), WORD_BYTE_ (w,2), \
+ WORD_BYTE_ (w,3), WORD_BYTE_ (w,4), WORD_BYTE_ (w,5), WORD_ABS_ (w)
+#define SHORT_ARGS_(s) SHORT_SIGN_ (s), SHORT_BYTE_ (s,1), SHORT_BYTE_ (s,2), \
+ SHORT_ABS_ (s)
+
+void
+mix_vm_dump (const mix_vm_t *vm, const mix_dump_context_t *dc)
+{
+ 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);
+ 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);
+ 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);
+ fprintf (f, "rJ: " SHORT_FMT_ "\n", SHORT_ARGS_ (rJ));
+ }
+
+ for (j = 0, i = 0; j < IREG_NO_; ++j)
+ {
+ 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));
+ fprintf (f, "rI%d: " SHORT_FMT_ "\t", j+1, SHORT_ARGS_ (rI));
+ i++;
+ }
+ if ( i%2 == 0 && i != 0 ) fprintf (f, "\n");
+ }
+
+ if ( i%2 == 1 ) fprintf (f, "\n");
+
+ if ( (dc->options & MIX_DUMP_OVER) == MIX_DUMP_OVER )
+ {
+ fprintf (f, _("Overflow: %s\n"), get_over_ (vm)? "T":"F");
+ }
+
+ if ( (dc->options & MIX_DUMP_CMP) == MIX_DUMP_CMP )
+ {
+ const gchar *val = "?";
+ switch (get_cmp_ (vm))
+ {
+ case mix_LESS:
+ val = "L";
+ break;
+ case mix_GREAT:
+ val = "G";
+ break;
+ case mix_EQ:
+ val = "E";
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ fprintf (f, _("Cmp: %s\n"), val);
+ }
+
+ if ( (dc->options & MIX_DUMP_CELLS) == MIX_DUMP_CELLS )
+ {
+ for (j = dc->begin; j < dc->end; ++j)
+ {
+ mix_word_t cell = get_cell_ (vm,j);
+ 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
new file mode 100644
index 0000000..7f8b0c3
--- /dev/null
+++ b/mixlib/mix_vm_dump.h
@@ -0,0 +1,91 @@
+/* ---------------------- mix_vm_dump.h :
+ * This file declares types and functions for dumping the contents
+ * of a mix virtual machine.
+ * ------------------------------------------------------------------
+** 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
+** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**
+*/
+
+
+#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 */
+typedef struct mix_dump_context_t mix_dump_context_t;
+struct mix_dump_context_t
+{
+ /* flags activating dumps (see enum below) */
+ guint32 options;
+ /* range of addresses dumped: [begin,end) */
+ mix_address_t begin;
+ mix_address_t end;
+ /* IO channel for dumping */
+ FILE *channel;
+};
+
+/* Flags for activating dumps */
+#define MIX_DUMP_NONE 0
+#define MIX_DUMP_rA 1
+#define MIX_DUMP_rX (1<<1)
+#define MIX_DUMP_rJ (1<<2)
+#define MIX_DUMP_rI1 (1<<3)
+#define MIX_DUMP_rI2 (1<<4)
+#define MIX_DUMP_rI3 (1<<5)
+#define MIX_DUMP_rI4 (1<<6)
+#define MIX_DUMP_rI5 (1<<7)
+#define MIX_DUMP_rI6 (1<<8)
+#define MIX_DUMP_rIa MIX_DUMP_rI1|MIX_DUMP_rI2|MIX_DUMP_rI3 \
+ |MIX_DUMP_rI4|MIX_DUMP_rI5|MIX_DUMP_rI6
+#define MIX_DUMP_rALL MIX_DUMP_rA|MIX_DUMP_rX|MIX_DUMP_rJ|MIX_DUMP_rIa
+#define MIX_DUMP_OVER (1<<9)
+#define MIX_DUMP_CMP (1<<10)
+#define MIX_DUMP_CELLS (1<<11)
+#define MIX_DUMP_ALL MIX_DUMP_rALL|MIX_DUMP_OVER|MIX_DUMP_CMP|MIX_DUMP_CELLS
+#define MIX_DUMP_ALL_NOMEM MIX_DUMP_rALL|MIX_DUMP_OVER|MIX_DUMP_CMP
+
+/* Default output channel (stdout) */
+#define MIX_DUMP_DEF_CHANNEL (stdout)
+
+/* Create/destroy a dump context */
+extern mix_dump_context_t *
+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);
+
+/* Modify an existing dump context */
+#define mix_dump_context_add_opt(dc,opt) ((dc)->options |= (opt))
+#define mix_dump_context_del_opt(dc,opt) ((dc)->options &= ~(opt))
+#define mix_dump_context_set_opt(dc,opt) ((dc)->options = (opt))
+#define mix_dump_context_range(dc,first,last) \
+do { \
+ (dc)->begin = first; \
+ (dc)->end = last; \
+} while (FALSE)
+
+
+/* Use the dump context */
+extern void
+mix_vm_dump(const mix_vm_t *vm, const mix_dump_context_t *dc);
+
+
+#endif /* MIX_VM_DUMP_H */
+
diff --git a/mixlib/testsuite/Makefile.am b/mixlib/testsuite/Makefile.am
new file mode 100644
index 0000000..834f833
--- /dev/null
+++ b/mixlib/testsuite/Makefile.am
@@ -0,0 +1,32 @@
+## Process this file with automake to produce Makefile.in
+
+# Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# $Id: Makefile.am,v 1.2 2001/09/29 01:53:51 jao Exp $
+
+INCLUDES = -I$(includedir) -I$(top_srcdir) -I$(top_srcdir)/mixlib
+LDADD = $(top_builddir)/mixlib/libmix.a
+
+check_PROGRAMS = mixtypest mixinstest mixvminstest mixparsertest mixdevtest mixevaltest
+TESTS = $(check_PROGRAMS)
+
+mixtypest_SOURCES = test.h mix_types_t.c
+mixinstest_SOURCES = test.h mix_ins_t.c
+mixvminstest_SOURCES = test.h mix_vm_ins_t.c
+mixparsertest_SOURCES = test.h mix_parser_t.c
+mixdevtest_SOURCES = test.h mix_device_t.c
+mixevaltest_SOURCES = test.h mix_eval_t.c
+
+
+
+
+
+
diff --git a/mixlib/testsuite/mix_device_t.c b/mixlib/testsuite/mix_device_t.c
new file mode 100644
index 0000000..8638d2f
--- /dev/null
+++ b/mixlib/testsuite/mix_device_t.c
@@ -0,0 +1,76 @@
+/* -*-c-*- -------------- mix_device_t.c :
+ * Implementation of the functions declared in mix_device_t.h
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <stdlib.h>
+#include <mix_device.h>
+
+/* Define VERBOSE_TEST if you want to get prints of the test */
+/* #define VERBOSE_TEST */
+#include "test.h"
+
+static int S_ = MIX_CHAR_MAX +1;
+
+int
+main (int argc, char **argv)
+{
+ mix_device_t *console;
+ size_t s;
+ mix_word_t **block;
+ mix_char_t mchars[S_];
+ gchar chars[S_];
+ int i, j;
+ int bno;
+
+
+ INIT_TEST;
+
+ console = mix_device_new (mix_dev_CONSOLE);
+ s = mix_device_block_size (console);
+ bno = S_/(s*5);
+ if (bno == 0) bno = 1;
+
+ block = g_new (mix_word_t *, bno);
+ for (i = 0; i < bno; ++i)
+ block[i] = g_new (mix_word_t, s);
+
+ for (i = 0; i < S_; ++i) {
+ chars[i] = mix_char_to_ascii (i);
+ mchars[i] = mix_ascii_to_char (chars[i]);
+ g_assert (mchars[i] == i);
+ }
+
+ for (i = 0; i < bno; ++i) {
+ for (j = 0; j < s; ++j) {
+ int n = i*s + 5*j;
+ if (n < S_)
+ block[i][j] = mix_bytes_to_word (mchars + n, 5);
+ else
+ block[i][j] = 0;
+ }
+ }
+
+ for (i = 0; i < bno; ++i) {
+ mix_device_write (console, block[i]);
+ }
+
+
+ return EXIT_SUCCESS;
+}
diff --git a/mixlib/testsuite/mix_eval_t.c b/mixlib/testsuite/mix_eval_t.c
new file mode 100644
index 0000000..9b62fd6
--- /dev/null
+++ b/mixlib/testsuite/mix_eval_t.c
@@ -0,0 +1,119 @@
+/* -*-c-*- -------------- mix_eval_t.c :
+ * Test of mix_eval_t
+ * ------------------------------------------------------------------
+ * Last change: Time-stamp: "01/02/20 00:26:15 jose"
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#include <stdlib.h>
+#include <mix_eval.h>
+/* Define VERBOSE_TEST if you want to get prints of the test */
+/* #define VERBOSE_TEST */
+#include "test.h"
+
+typedef struct test_case_t
+{
+ const gchar *expr;
+ gint value;
+ mix_eval_result_t result;
+} test_case_t;
+
+#define ok_case(exp,val) {exp, val, MIX_EVAL_OK}
+#define err_case(exp,err) {exp, 0, err}
+
+typedef struct sym_val_t
+{
+ const gchar *sym;
+ mix_word_t value;
+} sym_val_t;
+
+#define new_symbol(sym,val) {sym, mix_word_new (val)}
+
+int
+main(int argc, char **argv)
+{
+ size_t k;
+ mix_eval_t *eval;
+ mix_short_t loc = mix_short_new (30);
+ sym_val_t symbols[] = {
+ new_symbol ("s0", 43),
+ new_symbol ("s1", -1234),
+ new_symbol ("s2", 0),
+ new_symbol ("s3", -20),
+ new_symbol (NULL, 0)
+ };
+
+ test_case_t cases[] = {
+ ok_case ("2343", 2343),
+ ok_case ("-890", -890),
+ ok_case ("15+1015", 1030),
+ ok_case ("1-481", -480),
+ ok_case ("2300/10", 230),
+ ok_case ("24*3", 72),
+ ok_case ("2:5", 21),
+ ok_case ("1//3", 357913941),
+ ok_case ("12+*", 42),
+ ok_case ("***", 900),
+ ok_case ("1:3*2-4", 18),
+ ok_case ("-1+5*20/6", 13),
+ ok_case ("-1000(0,2),1", 1),
+ ok_case ("s0-s2*3", 129),
+ ok_case ("s3**", -600),
+ ok_case ("s3(3:5)", 20),
+ ok_case ("-s1", 1234),
+ ok_case ("s1/10+s0", 166),
+ err_case ("foo", MIX_EVAL_UNDEF_SYM),
+ err_case ("11--2", MIX_EVAL_SYNTAX),
+ err_case ("s2*foo*3", MIX_EVAL_UNDEF_SYM),
+ err_case ("12/32),1", MIX_EVAL_MIS_PAREN),
+ err_case ("2000(88)", MIX_EVAL_INV_FSPEC),
+ ok_case (NULL, 0)
+ };
+
+ INIT_TEST;
+ g_print ("Entering mix_eval test...");
+ eval = mix_eval_new ();
+
+ for (k = 0; symbols[k].sym; ++k)
+ mix_eval_set_symbol (eval, symbols[k].sym, symbols[k].value);
+
+ for (k = 0; cases[k].expr; ++k) {
+ mix_eval_result_t r = cases[k].result, s;
+ g_print ("Evaluating \"%s\" = %d ...",
+ cases[k].expr, cases[k].value);
+
+ s = mix_eval_expression_with_loc (eval, cases[k].expr, loc);
+ g_assert (s == r);
+ if ( s == MIX_EVAL_OK ) {
+ mix_word_print (mix_eval_value (eval), "... ");
+ g_print ("\n");
+ g_assert (mix_eval_value (eval) == mix_word_new(cases[k].value));
+ } else {
+ g_print ("\n------->%s, at pos %d\n",
+ mix_eval_last_error_string (eval),
+ mix_eval_last_error_pos (eval));
+ }
+ }
+ mix_eval_delete (eval);
+
+ return EXIT_SUCCESS;
+}
+
+
diff --git a/mixlib/testsuite/mix_ins_t.c b/mixlib/testsuite/mix_ins_t.c
new file mode 100644
index 0000000..8dcc619
--- /dev/null
+++ b/mixlib/testsuite/mix_ins_t.c
@@ -0,0 +1,79 @@
+/*----------------------- mix_ins_t.c -------------------------------
+ * Tests for mix_ins.h
+ *-------------------------------------------------------------------
+** Copyright (C) 1999 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**
+*/
+
+#include <stdlib.h>
+#include <mix_ins.h>
+
+/* Define VERBOSE_TEST if you want to get prints of the test */
+/* #define VERBOSE_TEST */
+#include "test.h"
+
+
+int
+main(int argc, const char**argv)
+{
+ mix_word_t words[6];
+ mix_ins_t ins[3];
+ guint k;
+
+ INIT_TEST;
+
+ g_print("\n...ok.\nTesting mix_ins_id_t properties...\n");
+ for ( k = 0; k < mix_INVALID_INS; ++k )
+ {
+ mix_opcode_t c = mix_get_opcode_from_id(k);
+ mix_fspec_t f = mix_get_fspec_from_id(k);
+ mix_ins_id_t id = mix_get_ins_id(c,f);
+
+ g_print("%02d:%s (%1d:%1d), ",
+ c, mix_get_string_from_id(k),
+ mix_fspec_left(f), mix_fspec_right(f));
+ if ( (k+1)%3 == 0 ) g_print("\n");
+
+ g_assert(id==k);
+ }
+
+ g_print("\n...ok.\nTesting mix_ins_t properties...\n");
+ for ( k = 1; k < mix_INVALID_INS; ++k )
+ {
+ g_print("%d ",k);
+ mix_ins_fill_from_id(ins[0], k);
+ g_assert(mix_ins_id_from_ins(ins[0]) == k);
+ ins[0].address = 0x0123;
+ ins[0].index = mix_I2;
+ words[2] = mix_ins_to_word(ins);
+ g_assert(ins[0].address == mix_get_ins_address(words[2]));
+ g_assert(ins[0].index == mix_get_ins_index(words[2]));
+ g_assert(ins[0].fspec == mix_get_ins_fspec(words[2]));
+ g_assert(ins[0].opcode == mix_get_ins_opcode(words[2]));
+ g_assert(mix_word_to_ins(words[2],ins+1) == k);
+ g_assert(ins[0].address == ins[1].address);
+ g_assert(ins[0].index == ins[1].index);
+ g_assert(ins[0].fspec == ins[1].fspec);
+ g_assert(ins[0].opcode == ins[1].opcode);
+ }
+
+ g_print("\n...ok.\n");
+
+
+
+ return EXIT_SUCCESS;
+}
diff --git a/mixlib/testsuite/mix_parser_t.c b/mixlib/testsuite/mix_parser_t.c
new file mode 100644
index 0000000..215fc70
--- /dev/null
+++ b/mixlib/testsuite/mix_parser_t.c
@@ -0,0 +1,85 @@
+/* -*-c-*- -------------- mix_parser_t.c :
+ * Test of mix_parser_t
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#include <stdlib.h>
+#include <mix_parser.h>
+
+/* Define VERBOSE_TEST if you want to get prints of the test */
+/* #define VERBOSE_TEST */
+#include "test.h"
+
+static const gchar * const FILES_[] = { "test1" , "taocp145"
+};
+
+static const size_t FILE_NO_ = sizeof(FILES_)/sizeof(FILES_[0]);
+
+static void
+test_code_(const gchar *name)
+{
+ mix_parser_t *parser = mix_parser_new(name);
+ mix_parser_err_t err;
+ mix_code_file_t *code;
+ mix_ins_desc_t ins;
+
+ g_assert(parser);
+ err = mix_parser_compile(parser);
+ if ( err != MIX_PERR_OK ) {
+ g_print(mix_parser_err_string(err));
+ g_print("\n");
+ }
+ g_assert(err == MIX_PERR_OK);
+ err = mix_parser_write_code(parser, name, FALSE);
+ code = mix_code_file_new_read(name);
+ g_assert(code);
+ g_message("%s: Version: %d.%d", name, mix_code_file_major_version(code),
+ mix_code_file_minor_version(code));
+ mix_short_print(mix_code_file_get_start_addr(code), "Start address: ");
+ g_print("\n");
+ while ( mix_code_file_get_ins(code, &ins) ) {
+ mix_ins_t i;
+ mix_word_to_ins_uncheck(ins.ins, i);
+ mix_short_print(ins.address, "addr: ");
+ g_print(" : ");
+ mix_ins_print(&i);
+ g_print("\n");
+ }
+
+ mix_parser_delete(parser);
+ mix_code_file_delete(code);
+}
+
+int
+main(int argc, char **argv)
+{
+ size_t k;
+
+ INIT_TEST;
+
+ for (k = 0; k < FILE_NO_; ++k)
+ // test_code_(FILES_[k]);
+ ;
+
+
+ return EXIT_SUCCESS;
+}
+
diff --git a/mixlib/testsuite/mix_types_t.c b/mixlib/testsuite/mix_types_t.c
new file mode 100644
index 0000000..ababead
--- /dev/null
+++ b/mixlib/testsuite/mix_types_t.c
@@ -0,0 +1,369 @@
+/*----------------------- mix_types_t.c -----------------------------
+ * Tests for mix_types.h
+ * ------------------------------------------------------------------
+*
+** Copyright (C) 1999, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**
+*/
+
+
+#include <stdlib.h>
+#include <mix_types.h>
+
+/* Define VERBOSE_TEST if you want to get prints of the test */
+/* #define VERBOSE_TEST */
+#include "test.h"
+
+/* compare two words */
+static gboolean
+word_compare_(mix_word_t w1, mix_word_t w2)
+{
+ if ( mix_word_magnitude(w1) == 0 )
+ return ( mix_word_magnitude(w2) == 0 );
+ else
+ return ( w1 == w2 );
+}
+
+
+/* create a word from an array of bytes and check the result */
+static void
+test_word_from_bytes_(mix_word_t *word,
+ mix_byte_t *bytes,
+ unsigned byteno,
+ const char *message)
+{
+ mix_byte_t r;
+ unsigned int k;
+
+ *word = mix_bytes_to_word(bytes,byteno);
+ mix_word_print(*word,message);
+ g_print("\n");
+ for ( k = 5-byteno; k < 5; ++k ) {
+ PRINT_BYTE(r = mix_word_get_byte(*word,k+1));
+ g_print(" (k = %d)\n",k);
+ g_assert( r == bytes[k-5+byteno] );
+ }
+}
+
+
+/* test field access */
+static void
+test_field_access_(mix_fspec_t l, mix_fspec_t r,
+ mix_word_t from, mix_word_t to)
+{
+ mix_fspec_t f = mix_fspec_new(l,r);
+ mix_word_t result;
+
+ PRINT_BYTE(l); g_print(", ");
+ PRINT_BYTE(r); g_print(", ");
+ PRINT_BYTE(f); g_print("\n ");
+ mix_word_print(from, "from: ");
+ mix_word_print(to, " to: ");
+ g_assert( mix_fspec_left(f) == l );
+ g_assert( mix_fspec_right(f) == r );
+ result = mix_word_set_field(f,from,to);
+ mix_word_print(result,"\n\tresult: ");
+ g_assert( mix_word_get_field(f,from) == mix_word_get_field(f,result) );
+ g_print("\n");
+}
+
+/* test word addition */
+static void
+test_word_add_(mix_word_t w1, mix_word_t w2)
+{
+ mix_word_t r;
+
+ r = mix_word_add(w1,w2);
+ mix_word_print(w1,"\n");
+ mix_word_print(w2,NULL);
+ mix_word_print(r," = ");
+ g_assert( word_compare_(mix_word_sub(r,w1), w2) );
+ g_assert( word_compare_(mix_word_sub(r,w2), w1) );
+ /* while asserting the following, take into account that 0 != -0
+ for mix words, although they are logically equivalent
+ */
+ g_assert( word_compare_(mix_word_sub(w1,r), mix_word_negative(w2)) );
+ g_assert( word_compare_(mix_word_sub(w2,r), mix_word_negative(w1)) );
+ g_assert( word_compare_(mix_word_add(w2,w1), r) );
+}
+
+/* test word multiplication */
+static void
+test_word_mul_(mix_word_t w1, mix_word_t w2)
+{
+ mix_word_t h, l, q, r = 0;
+ mix_word_mul(w1,w2,&h,&l);
+ mix_word_print(w1,"\n");
+ mix_word_print(w2,"*");
+ mix_word_print(h,"\n =");
+ mix_word_print(l,NULL);
+ if ( w1 != 0 ) {
+ g_assert( mix_word_div(h,l,w1,&q,&r) == FALSE );
+ g_assert( mix_word_magnitude(r) == 0 );
+ g_assert( q == w2 );
+ } else {
+ g_assert( mix_word_magnitude(l) == 0 && mix_word_magnitude(h) == 0 );
+ }
+ if ( w2 != 0 ) {
+ g_assert( mix_word_div(h,l,w2,&q,&r) == FALSE );
+ g_assert( mix_word_magnitude(r) == 0 );
+ g_assert( q == w1 );
+ } else {
+ g_assert( mix_word_magnitude(l) == 0 && mix_word_magnitude(h) == 0 );
+ }
+
+}
+
+/* test word division */
+static void
+test_word_div_(mix_word_t h, mix_word_t l, mix_word_t by)
+{
+ mix_word_t q,r;
+ gboolean overflow;
+
+ overflow = mix_word_div(h,l,by,&q,&r);
+
+ mix_word_print(h,"\n\n");
+ mix_word_print(l,NULL);
+ mix_word_print(by,"\n div by ");
+
+ if ( !overflow ) {
+ mix_word_t h1, l1, h2;
+ mix_word_print(q,"\n q = ");
+ mix_word_print(r," r = ");
+ mix_word_mul(by,q,&h1,&l1);
+ mix_word_add_and_carry(l1,r,&h2,&l1);
+ h1 = mix_word_add(h1,h2);
+ g_assert( mix_word_magnitude(r) < mix_word_magnitude(by) );
+ g_assert( word_compare_(h1,h) );
+ g_assert( mix_word_magnitude(l1) == mix_word_magnitude(l) );
+ } else
+ g_print("\n\t = overflow");
+
+}
+
+static void
+test_mix_char_(void)
+{
+ mix_char_t mchar;
+ guchar achar;
+ guint k;
+ g_print("\nTesting mix_char_t. Table of mix_chars:\n");
+
+ for (k = 0; k < MIX_CHAR_MAX + 1; ++k) {
+ mchar = k;
+ achar = mix_char_to_ascii(mchar);
+ g_print("%02d: %c, ", k, achar);
+ if ( (k+1)%5 == 0 ) g_print("\n");
+ g_assert( mchar == mix_ascii_to_char(achar) );
+ }
+
+ g_print("\nchar <-> byte conversions...\n");
+
+ for (k = 0; k < MIX_CHAR_MAX + 1; ++k) {
+ mix_byte_t c = mix_byte_new (k);
+ g_assert (c == mix_byte_to_char (mix_char_to_byte (c)));
+ }
+
+ g_print("\n");
+}
+
+
+/* main test driver for mix_types.h/c */
+
+int main(int argc, char **argv)
+{
+ unsigned int j,k;
+ mix_byte_t bytes[5] = { 0, 3, 20, 30, 40 };
+ mix_byte_t r;
+ mix_short_t ss[6];
+ mix_word_t words[6];
+
+ INIT_TEST;
+
+ g_print("Testing mix_byte_t arithmetics...\n");
+ PRINT_BYTE(bytes[0]); g_print(", ");
+ PRINT_BYTE(bytes[1]); g_print(", ");
+ PRINT_BYTE(bytes[2]); g_print(", ");
+ PRINT_BYTE(bytes[3]); g_print(", ");
+ PRINT_BYTE(bytes[4]); g_print("\n");
+ PRINT_BYTE(r = mix_byte_add(bytes[1],bytes[2]));
+ g_print("\n"); g_assert(r == 23);
+ PRINT_BYTE(r = mix_byte_add(bytes[3],bytes[4]));
+ g_print("\n"); g_assert(r == 6);
+ PRINT_BYTE(r = mix_byte_sub(bytes[0],bytes[1]));
+ g_print("\n"); g_assert(r == 61);
+ PRINT_BYTE(r = mix_byte_sub(bytes[4],bytes[3]));
+ g_print("\n"); g_assert(r == 10);
+ PRINT_BYTE(r = mix_byte_sub(bytes[1],bytes[4]));
+ g_print("\n"); g_assert(r == 27);
+ PRINT_BYTE(r = mix_byte_mul(bytes[0],bytes[1]));
+ g_print("\n"); g_assert(r == 0);
+ PRINT_BYTE(r = mix_byte_mul(bytes[1],bytes[2]));
+ g_print("\n"); g_assert(r == 60);
+ PRINT_BYTE(r = mix_byte_mul(bytes[1],bytes[4]));
+ g_print("\n"); g_assert(r == 56);
+ PRINT_BYTE(r = mix_byte_mul(bytes[4],bytes[1]));
+ g_print("\n"); g_assert(r == 56);
+ PRINT_BYTE(r = mix_byte_div(bytes[4],bytes[2]));
+ g_print("\n"); g_assert(r == 2);
+ PRINT_BYTE(r = mix_byte_div(bytes[3],bytes[2]));
+ g_print("\n"); g_assert(r == 1);
+
+ test_mix_char_();
+
+ g_print("\nTesting word<->short conversions...");
+ words[0] = mix_bytes_to_word(bytes+1,5);
+ words[1] = mix_word_negative(words[0]);
+ ss[0] = mix_word_to_short(words[0]);
+ ss[1] = mix_word_to_short(words[1]);
+ mix_word_print(words[0],"\nwords[0]=");
+ mix_word_print(words[1],"\nwords[1]=");
+ mix_short_print(ss[0],"\nss[0]=");
+ mix_short_print(ss[1],"\nss[1]=");
+ g_assert(mix_short_is_positive(ss[0]));
+ g_assert(mix_short_is_negative(ss[1]));
+ words[2] = mix_short_to_word(ss[0]);
+ words[3] = mix_short_to_word(ss[1]);
+ mix_word_print(words[2],"\nwords[2]=");
+ mix_word_print(words[3],"\nwords[3]=");
+ g_assert(mix_word_sign(words[0]) == mix_word_sign(words[2]));
+ g_assert(mix_word_sign(words[1]) == mix_word_sign(words[3]));
+ g_assert(mix_short_magnitude(ss[0]) == mix_word_magnitude(words[2]));
+ g_assert(mix_short_magnitude(ss[1]) == mix_word_magnitude(words[3]));
+ g_assert(mix_word_get_byte(words[0],4) == mix_word_get_byte(words[2],4));
+ g_assert(mix_word_get_byte(words[0],5) == mix_word_get_byte(words[2],5));
+ g_assert(mix_word_get_byte(words[1],4) == mix_word_get_byte(words[3],4));
+ g_assert(mix_word_get_byte(words[1],5) == mix_word_get_byte(words[3],5));
+ words[4] = mix_word_extract_field(mix_fspec_new(4,5),words[0]);
+ words[5] = mix_word_extract_field(mix_fspec_new(4,5),words[1]);
+ mix_word_reverse_sign(words[5]);
+ g_assert(words[4] == words[2]);
+ g_assert(words[5] == words[3]);
+
+ g_print("Testing mix_word_t creation and byte access...\n");
+ test_word_from_bytes_(words,bytes,5,"word[0] created from bytes[0-4]");
+ test_word_from_bytes_(words+1,bytes,4,"\nword[1] created from bytes[0-3]");
+ test_word_from_bytes_(words+2,bytes,3,"\nword[2] created from bytes[0-2]");
+ words[3] = mix_word_negative(words[2]);
+ g_assert( mix_word_negative(words[3]) == words[2] );
+ g_assert( mix_word_is_negative(words[3]) && !mix_word_is_negative(words[2]));
+ mix_word_print(words[3],"\nword[3] created from -word[2]");
+ test_word_from_bytes_(words+4,bytes+2,2,"\nword[2] created from bytes[2-3]");
+
+ g_print("\nTesting mix_word_t field access...\n");
+ mix_word_set_byte(words+3,1,12);
+ mix_word_set_byte(words+3,2,58);
+ g_assert( mix_word_get_byte(words[3],1) == 12 );
+ g_assert( mix_word_get_byte(words[3],2) == 58 );
+ test_field_access_(0,5,words[3],words[4]);
+ test_field_access_(1,5,words[3],words[4]);
+ test_field_access_(2,5,words[3],words[4]);
+ test_field_access_(3,5,words[3],words[4]);
+ test_field_access_(4,5,words[3],words[4]);
+ test_field_access_(5,5,words[3],words[4]);
+ test_field_access_(0,0,words[3],words[4]);
+
+ g_print("\n\nTesting mix_word_t arithmetics...\n");
+ words[0] = MIX_WORD_MAX;
+ words[1] = mix_word_negative(words[0]);
+ for ( k = 1; k < 6; ++k ) {
+ mix_word_set_byte(words+2,k,5*k);
+ mix_word_set_byte(words+4,k,10*(5-k));
+ mix_word_set_byte(words+3,k,21 + 3*k);
+ }
+ words[5] = 0;
+
+ g_print("\n***addition***");
+ for ( k = 0; k < 6; ++k )
+ for ( j = 0; j <= k; ++j ) {
+ test_word_add_(words[k],mix_word_negative(words[j]));
+ test_word_add_(words[k],words[j]);
+ }
+ g_print("\n***product***");
+ for ( k = 0; k < 6; ++k )
+ for ( j = 0; j <= k; ++j ) {
+ test_word_mul_(words[k],words[j]);
+ }
+ g_print("\n***division***");
+ for ( k = 0; k < 6; ++k ) {
+ test_word_div_(words[k],0,words[0]);
+ for ( j = 0; j <= k; ++j ) {
+ test_word_div_(k,words[j],words[j]);
+ test_word_div_(0,mix_word_add(mix_word_magnitude(words[j]),j),words[j]);
+ test_word_div_(mix_word_negative(k),words[j],words[j]);
+ }
+ }
+
+ g_print("\nTesting shift operations...\n");
+ for ( k = 0; k < 10; ++k )
+ mix_word_set_byte(words+(k/5),1+(k%5),k+1);
+
+ mix_word_print(words[0],"A = ");
+ mix_word_print(words[1],"X = ");
+ for ( k = 0; k < 11; ++k ) {
+ mix_word_t A, X;
+ unsigned int m;
+
+ mix_word_shift_left(words[0],words[1],k,&A,&X);
+ g_print("\nShift left %d:\n",k);
+ mix_word_print(A,"A ");
+ mix_word_print(X,"X ");
+ for ( m = 0; m < 10 - k; ++m )
+ g_assert( mix_word_get_byte( m < 5 ? A:X, (m%5)+1 ) ==
+ mix_word_get_byte(words[(m+k)/5], ((m+k)%5)+1) );
+ for ( ; m < 10; ++m )
+ g_assert( mix_word_get_byte( m < 5 ? A:X, (m%5)+1 ) == 0 );
+
+ mix_word_shift_right(words[0],words[1],k,&A,&X);
+ g_print("\nShift right %d:\n",k);
+ mix_word_print(A,"A ");
+ mix_word_print(X,"X ");
+ for ( m = 0; m < k; ++m )
+ g_assert( mix_word_get_byte( m < 5 ? A:X, (m%5)+1 ) == 0 );
+ for ( ; m < 10; ++m )
+ g_assert( mix_word_get_byte( m < 5 ? A:X, (m%5)+1 ) ==
+ mix_word_get_byte(words[(m-k)/5], ((m-k)%5)+1) );
+
+ mix_word_shift_left_circular(words[0],words[1],k,&A,&X);
+ g_print("\nShift left circular %d:\n",k);
+ mix_word_print(A,"A ");
+ mix_word_print(X,"X ");
+ for ( m = 0; m < 10 - k; ++m )
+ g_assert( mix_word_get_byte( m < 5 ? A:X, (m%5)+1 ) ==
+ mix_word_get_byte(words[(m+k)/5], ((m+k)%5)+1) );
+ for ( ; m < 10; ++m )
+ g_assert( mix_word_get_byte( m < 5 ? A:X, (m%5)+1 ) ==
+ mix_word_get_byte(words[(m-10+k)/5], 1+((m-10+k)%5)) );
+ mix_word_shift_right_circular(A, X, k, &A, &X);
+ g_print("\nRe-shiftting right...\n");
+ mix_word_print(A, "A ");
+ mix_word_print(X, "X ");
+ g_assert(A == words[0]);
+ g_assert(X == words[1]);
+ }
+
+
+ g_print("\n");
+ return EXIT_SUCCESS;
+}
+
+
+
+
+
+
diff --git a/mixlib/testsuite/mix_vm_ins_t.c b/mixlib/testsuite/mix_vm_ins_t.c
new file mode 100644
index 0000000..458cbba
--- /dev/null
+++ b/mixlib/testsuite/mix_vm_ins_t.c
@@ -0,0 +1,505 @@
+/* ---------------------- mix_vm_ins_t.c :
+ * Tests for the virtual machine instruction handlers.
+ * ------------------------------------------------------------------
+** Copyright (C) 2000, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**
+*/
+
+
+#include <stdlib.h>
+/* #define VERBOSE_TEST */
+#include "test.h"
+#include "mix_vm.h"
+#include "mix_vm_dump.h"
+
+typedef struct
+{
+ mix_word_t rA_b, rA_a;
+ mix_word_t rX_b, rX_a;
+ mix_short_t rJ_b, rJ_a;
+ mix_short_t rI_b[6], rI_a[6];
+ gboolean over_b, over_a;
+ mix_cmpflag_t cmp_b, cmp_a;
+ mix_address_t begin, end;
+ mix_word_t *cells_b, *cells_a;
+ const mix_ins_t *ins;
+} test_desc_t;
+
+static void
+set_cells_(test_desc_t *t, mix_address_t begin, mix_address_t end)
+{
+ g_assert(begin <= end);
+ t->begin = begin;
+ t->end = end;
+ t->cells_b = g_new(mix_word_t,end-begin);
+ t->cells_a = g_new(mix_word_t,end-begin);
+}
+
+static void
+free_cells_(test_desc_t *t)
+{
+ g_assert(t);
+ g_free(t->cells_a);
+ g_free(t->cells_b);
+ t->cells_a = t->cells_b = NULL;
+ t->begin = t->end = 0;
+}
+
+
+static void
+fill_test_desc_(test_desc_t *t, const mix_vm_t *vm, const mix_ins_t *ins)
+{
+ guint k;
+ g_assert(t);
+ g_assert(vm);
+
+ t->rA_b = t->rA_a = mix_vm_get_rA(vm);
+ t->rX_b = t->rX_a = mix_vm_get_rX(vm);
+ t->rJ_b = t->rJ_a = mix_vm_get_rJ(vm);
+ for ( k = 0; k < 6; ++k )
+ t->rI_b[k] = t->rI_a[k] = mix_vm_get_rI(vm,k+1);
+ t->cmp_b = t->cmp_a = mix_vm_get_cmpflag(vm);
+ t->over_b = t->over_a = mix_vm_get_overflow(vm);
+
+ for (k = 0; k < t->end-t->begin; ++k)
+ t->cells_a[k] = t->cells_b[k] =
+ mix_vm_get_addr_contents(vm,t->begin+k);
+ t->ins = ins;
+}
+
+
+static void
+run_test_(test_desc_t *t, mix_vm_t *vm, mix_dump_context_t *dc)
+{
+ guint k;
+ g_assert(t);
+ g_assert(vm);
+
+ mix_vm_set_rA(vm, t->rA_b);
+ mix_vm_set_rX(vm, t->rX_b);
+ mix_vm_set_rJ(vm, t->rJ_b);
+ for (k = 0; k < 6; ++k) mix_vm_set_rI(vm, k+1, t->rI_b[k]);
+ for (k = t->begin; k < t->end; ++k)
+ mix_vm_set_addr_contents(vm, k, t->cells_b[k-t->begin]);
+ mix_vm_set_cmpflag(vm, t->cmp_b);
+ mix_vm_set_overflow(vm, t->over_b);
+
+ mix_ins_print(t->ins);
+ if (dc) {
+ mix_dump_context_range(dc, t->begin, t->end);
+ mix_vm_dump(vm,dc);
+ }
+ k = mix_vm_exec_ins(vm, t->ins);
+ if (dc) mix_vm_dump(vm, dc);
+ g_assert(k == TRUE);
+ g_assert(mix_vm_get_rA(vm) == t->rA_a);
+ g_assert(mix_vm_get_rX(vm) == t->rX_a);
+ for (k = 0; k < 6; ++k) g_assert(mix_vm_get_rI(vm, k+1) == t->rI_a[k]);
+ g_assert(mix_vm_get_cmpflag(vm) == t->cmp_a);
+ g_assert(mix_vm_get_overflow(vm) == t->over_a);
+ for (k = t->begin; k < t->end; ++k)
+ g_assert(mix_vm_get_addr_contents(vm, k) == t->cells_a[k-t->begin]);
+}
+
+
+
+static void
+test_arithmetics_(mix_vm_t *vm, mix_dump_context_t *dc)
+{
+ test_desc_t test;
+ mix_ins_t ins;
+
+ g_print("\nTesting arithmetic instructions...\n");
+ mix_vm_reset(vm);
+ mix_ins_fill_from_id(ins,mix_ADD);
+ ins.index = 0;
+ ins.address = 1000;
+ mix_vm_set_rA(vm,mix_word_new_b(19,18,1,2,22));
+ mix_vm_set_addr_contents(vm,1000,mix_word_new_b(1,36,5,0,50));
+ set_cells_(&test,1000,1001);
+ fill_test_desc_(&test,vm,&ins);
+ test.rA_a = mix_word_new_b(20,54,6,3,8);
+ run_test_(&test, vm, dc);
+
+ mix_ins_fill_from_id(ins,mix_SUB);
+ mix_vm_set_rA(vm,mix_word_new_bn(19,18,0,0,9));
+ mix_vm_set_addr_contents(vm,1000,mix_word_new_bn(31,16,2,22,0));
+ fill_test_desc_(&test,vm,&ins);
+ test.rA_a = mix_word_new_b(11,62,2,21,55);
+ run_test_(&test, vm, dc);
+
+ mix_ins_fill_from_id(ins,mix_MUL);
+ mix_vm_set_rA(vm,mix_word_new_b(1,1,1,1,1));
+ mix_vm_set_addr_contents(vm,1000, mix_word_new_b(1,1,1,1,1));
+ fill_test_desc_(&test,vm,&ins);
+ test.rA_a = mix_word_new_b(0,1,2,3,4);
+ test.rX_a = mix_word_new_b(5,4,3,2,1);
+ run_test_(&test, vm, dc);
+
+ ins.fspec = mix_fspec_new(1,1);
+ mix_vm_set_rA(vm,mix_word_new_bn(0,0,0,1,48));
+ mix_vm_set_addr_contents(vm,1000,mix_word_new_bn(2,16,2,22,0));
+ fill_test_desc_(&test,vm,&ins);
+ test.rA_a = MIX_WORD_MINUS_ZERO;
+ test.rX_a = mix_word_new_bn(0,0,0,3,32);
+ run_test_(&test, vm, dc);
+
+ mix_vm_set_rA(vm,mix_word_new_bn(0,0,0,1,48));
+ mix_vm_set_addr_contents(vm,1000,mix_word_new_b(2,0,34,33,1));
+ fill_test_desc_(&test,vm,&ins);
+ test.rA_a = MIX_WORD_MINUS_ZERO;
+ test.rX_a = mix_word_new_bn(0,0,0,3,32);
+ run_test_(&test, vm, dc);
+
+ ins.fspec = mix_fspec_new(0,5);
+ mix_vm_set_rA(vm,mix_word_new_bn(50,0,1,48,4));
+ mix_vm_set_addr_contents(vm,1000,mix_word_new_bn(2,0,0,0,0));
+ fill_test_desc_(&test,vm,&ins);
+ test.rA_a = mix_word_new_b(1,36,0,3,32);
+ test.rX_a = mix_word_new_b(8,0,0,0,0);
+ run_test_(&test, vm, dc);
+
+ mix_ins_fill_from_id(ins,mix_DIV);
+ mix_vm_set_rA(vm,MIX_WORD_ZERO);
+ mix_vm_set_rX(vm,mix_word_new_b(0,0,0,0,17));
+ mix_vm_set_addr_contents(vm,1000, mix_word_new_b(0,0,0,0,3));
+ fill_test_desc_(&test,vm,&ins);
+ test.rA_a = mix_word_new_b(0,0,0,0,5);
+ test.rX_a = mix_word_new_b(0,0,0,0,2);
+ run_test_(&test, vm, dc);
+
+ mix_vm_set_rA(vm,MIX_WORD_ZERO);
+ mix_vm_set_rX(vm,mix_word_new_bn(0,0,0,0,17));
+ mix_vm_set_addr_contents(vm,1000, mix_word_new_b(0,0,0,0,3));
+ fill_test_desc_(&test,vm,&ins);
+ test.rA_a = mix_word_new_b(0,0,0,0,5);
+ test.rX_a = mix_word_new_b(0,0,0,0,2);
+ run_test_(&test, vm, dc);
+
+ mix_vm_set_rA(vm, MIX_WORD_MINUS_ZERO);
+ mix_vm_set_rX(vm, mix_word_new_b(19,19,0,3,1));
+ mix_vm_set_addr_contents(vm,1000, mix_word_new_bn(0,0,0,2,0));
+ fill_test_desc_(&test,vm,&ins);
+ test.rA_a = mix_word_new_b(0,9,41,32,1);
+ test.rX_a = mix_word_new_bn(0,0,0,1,1);
+ run_test_(&test, vm, dc);
+
+ free_cells_(&test);
+}
+
+static void
+test_shift_(mix_vm_t *vm, mix_dump_context_t *dc)
+{
+ test_desc_t test;
+ mix_ins_t ins;
+
+ g_print("Testing shift instructions...\n");
+ mix_vm_reset(vm);
+ set_cells_(&test,0,0);
+ fill_test_desc_(&test,vm,&ins);
+ mix_ins_fill_from_id(ins,mix_SRAX);
+ ins.index = 0;
+ ins.address = 1;
+ test.rA_b = mix_word_new_b(1,2,3,4,5);
+ test.rX_b = mix_word_new_bn(6,7,8,9,10);
+ test.rA_a = mix_word_new_b(0,1,2,3,4);
+ test.rX_a = mix_word_new_bn(5,6,7,8,9);
+ run_test_(&test, vm, dc);
+
+ mix_ins_fill_from_id(ins, mix_SLA);
+ ins.address = 2;
+ fill_test_desc_(&test, vm, &ins);
+ test.rA_a = mix_word_new_b(2,3,4,0,0);
+ run_test_(&test, vm, dc);
+
+ mix_ins_fill_from_id(ins, mix_SRC);
+ ins.address = 4;
+ fill_test_desc_(&test, vm, &ins);
+ test.rA_a = mix_word_new_b(6,7,8,9,2);
+ test.rX_a = mix_word_new_bn(3,4,0,0,5);
+ run_test_(&test, vm, dc);
+
+ mix_ins_fill_from_id(ins, mix_SRA);
+ ins.address = 2;
+ fill_test_desc_(&test, vm, &ins);
+ test.rA_a = mix_word_new_b(0,0,6,7,8);
+ run_test_(&test, vm, dc);
+
+ mix_ins_fill_from_id(ins, mix_SLC);
+ ins.address = 501;
+ fill_test_desc_(&test, vm, &ins);
+ test.rA_a = mix_word_new_b(0,6,7,8,3);
+ test.rX_a = mix_word_new_bn(4,0,0,5,0);
+ run_test_(&test, vm, dc);
+}
+
+static void
+test_spc_(mix_vm_t *vm, mix_dump_context_t *dc)
+{
+ test_desc_t test;
+ mix_ins_t ins;
+
+ g_print("Testing special instructions...\n");
+ mix_vm_reset(vm);
+ set_cells_(&test,0,0);
+ fill_test_desc_(&test,vm,&ins);
+ mix_ins_fill_from_id(ins,mix_NUM);
+ ins.index = 0;
+ ins.address = 0;
+ test.rA_b = mix_word_new_bn(0,0,31,32,39);
+ test.rX_b = mix_word_new_b(37,57,47,30,30);
+ test.rA_a = mix_word_negative(12977700);
+ test.rX_a = test.rX_b;
+ run_test_(&test, vm, dc);
+
+ mix_ins_fill_from_id(ins, mix_INCA);
+ ins.address = 1;
+ fill_test_desc_(&test, vm, &ins);
+ test.rA_a = mix_word_negative(12977699);
+ run_test_(&test, vm, dc);
+
+ mix_ins_fill_from_id(ins, mix_CHAR);
+ fill_test_desc_(&test, vm, &ins);
+ test.rA_a = mix_word_new_bn(30,30,31,32,39);
+ test.rX_a = mix_word_new_b(37,37,36,39,39);
+ run_test_(&test, vm, dc);
+
+ mix_ins_fill_from_id(ins, mix_HLT);
+ fill_test_desc_(&test, vm, &ins);
+ run_test_(&test, vm, dc);
+ g_assert(mix_vm_is_halted(vm));
+
+}
+
+static void
+test_move_(mix_vm_t *vm, mix_dump_context_t *dc)
+{
+ test_desc_t test;
+ mix_ins_t ins;
+ guint k;
+
+ g_print("Testing move instruction...\n");
+ mix_vm_reset(vm);
+ set_cells_(&test,0,10);
+ fill_test_desc_(&test,vm,&ins);
+ mix_ins_fill_from_id(ins,mix_MOVE);
+
+ ins.index = 0;
+ ins.address = 0;
+ ins.fspec = 5;
+ for ( k = 0; k < 5; ++k )
+ test.cells_b[k] = test.cells_a[k+5] = test.cells_a[k] =mix_word_new(100*k);
+
+ test.rI_b[0] = 5;
+ test.rI_a[0] = 10;
+ run_test_(&test,vm,dc);
+
+ free_cells_(&test);
+}
+
+
+
+static void
+test_load_(mix_vm_t *vm, mix_dump_context_t *dc)
+{
+ test_desc_t test;
+ mix_ins_t ins;
+ mix_ins_id_t ids[4] = {mix_LDA, mix_LDX, mix_LDAN, mix_LDXN};
+ mix_word_t r_a[14] = {
+ mix_word_new_bn(1,16,3,5,4),
+ mix_word_new_b(1,16,3,5,4),
+ mix_word_new_b(0,0,3,5,4),
+ mix_word_new_bn(0,0,1,16,3),
+ mix_word_new_b(0,0,0,0,5),
+ mix_word_new_b(0,0,0,0,1),
+ MIX_WORD_MINUS_ZERO,
+ mix_word_new_b(1,16,3,5,4),
+ mix_word_new_bn(1,16,3,5,4),
+ mix_word_new_bn(0,0,3,5,4),
+ mix_word_new_b(0,0,1,16,3),
+ mix_word_new_bn(0,0,0,0,5),
+ mix_word_new_bn(0,0,0,0,1),
+ MIX_WORD_ZERO
+ };
+ mix_fspec_t fs[11] = {5,13,29,3,36,9,0,0,0,0,0};
+ mix_address_t a_a[11] = {
+ MIX_SHORT_MINUS_ZERO,
+ mix_short_new_bn(0,1),
+ mix_short_new_bn(1,16),
+ mix_short_new_bn(16,3),
+ mix_short_new_bn(3,5),
+ mix_short_new_bn(5,4),
+ mix_short_new_b(1,16),
+ mix_short_new_b(16,3),
+ mix_short_new_b(5,4),
+ mix_short_new_b(5,4),
+ mix_short_new_b(3,5)
+ };
+ mix_word_t val = mix_word_new_bn(1,16,3,5,4);
+ gint j;
+
+ g_print("Testing load instructions...\n");
+ set_cells_(&test,2000,2001);
+ ins.index = 1;
+ ins.address = mix_short_negative(50);
+
+ mix_vm_reset(vm);
+ mix_vm_set_addr_contents(vm, 2000, val);
+
+ for (j = 0; j < 4; ++j)
+ {
+ gint k;
+ mix_ins_fill_from_id(ins,ids[j]);
+ for ( k = 0; k < 7; ++k ) {
+ fill_test_desc_(&test,vm,&ins);
+ ins.fspec = fs[k];
+ switch (ids[j])
+ {
+ case mix_LDA: test.rA_a = r_a[k]; break;
+ case mix_LDX: test.rX_a = r_a[k]; break;
+ case mix_LDAN: test.rA_a = r_a[k + 7]; break;
+ case mix_LDXN: test.rX_a = r_a[k + 7]; break;
+ default: g_assert_not_reached();
+ }
+ test.rI_b[0] = test.rI_a[0] = 2050;
+ run_test_(&test, vm, dc);
+ }
+ }
+
+ ins.index = 0;
+ ins.address = 2000;
+ fs[0] = 0; fs[1] = 1; fs[2] = 2; fs[3] = 3; fs[4] = 4; fs[5] = 5;
+ fs[6] = 10; fs[7] = 11; fs[8] = 37; fs[9] = 29; fs[10] = 12;
+
+ mix_vm_reset(vm);
+ mix_vm_set_addr_contents(vm, 2000, val);
+ for ( j = 0; j < 14; j++ )
+ {
+ guint k;
+ if (j == 6 || j == 7 ) continue; /* mix_LDX, mix_LDAN */
+ mix_ins_fill_from_id(ins, mix_LD1 + j);
+ for (k = 0; k < 11; ++k)
+ {
+ fill_test_desc_(&test, vm, &ins);
+ ins.fspec = fs[k];
+ if ( j < 6 )
+ test.rI_a[j] = a_a[k];
+ else /* mix_LDiN */
+ test.rI_a[j-8] = mix_short_negative (a_a[k]);
+ run_test_(&test, vm, dc);
+ }
+ }
+
+ free_cells_(&test);
+}
+
+
+static void
+test_store_(mix_vm_t *vm, mix_dump_context_t *dc)
+{
+ test_desc_t test;
+ mix_ins_t ins;
+ mix_word_t reg = mix_word_new_b(6,7,8,9,0);
+ mix_word_t add = mix_word_new_bn(1,2,3,4,5);
+ mix_word_t addr[6] = { mix_word_new_b(6,7,8,9,0),
+ mix_word_new_bn(6,7,8,9,0),
+ mix_word_new_bn(1,2,3,4,0),
+ mix_word_new_bn(1,0,3,4,5),
+ mix_word_new_bn(1,9,0,4,5),
+ mix_word_new_b(0,2,3,4,5)};
+ mix_word_t addri[6] = { mix_word_new_b(0,0,0,9,0),
+ mix_word_new_bn(0,0,0,9,0),
+ mix_word_new_bn(1,2,3,4,0),
+ mix_word_new_bn(1,0,3,4,5),
+ mix_word_new_bn(1,9,0,4,5),
+ mix_word_new_b(0,2,3,4,5)};
+ mix_word_t addrz[6] = { mix_word_new_b(0,0,0,0,0),
+ mix_word_new_bn(0,0,0,0,0),
+ mix_word_new_bn(1,2,3,4,0),
+ mix_word_new_bn(1,0,3,4,5),
+ mix_word_new_bn(1,0,0,4,5),
+ mix_word_new_b(0,2,3,4,5)};
+ mix_fspec_t fs[6] = {5,13,45,18,19,1};
+ gint i,j;
+
+ g_print("Testing store instructions...\n");
+
+ set_cells_(&test,2000,2001);
+ ins.index = 0;
+ ins.address = 2000;
+
+ mix_vm_reset(vm);
+ fill_test_desc_(&test,vm,&ins);
+ test.rA_a = test.rA_b = test.rX_a = test.rX_b = reg;
+ test.rJ_a = test.rJ_b = mix_word_to_short(reg);
+ for (j = 0; j < 6; ++j)
+ test.rI_a[j] = test.rI_b[j] = test.rJ_a;
+ test.cells_b[0] = add;
+
+ for (i = 0; i < 10; ++i)
+ {
+ mix_ins_fill_from_id(ins,mix_STA+i);
+ for (j = 0; j < 6; ++j)
+ {
+ ins.fspec = fs[j];
+ if (i == 0 || i == 7 ) /* mix_STA, mix_STX */
+ test.cells_a[0] = addr[j];
+ else if ( i < 9 ) /* mix_STi, mix_STJ */
+ test.cells_a[0] = addri[j];
+ else /* mix_STZ */
+ test.cells_a[0] = addrz[j];
+ run_test_(&test,vm,dc);
+ }
+ }
+
+ free_cells_(&test);
+}
+
+
+
+int
+main(int argc, const char **argv)
+{
+ mix_vm_t *vm;
+ mix_dump_context_t *dc;
+
+ INIT_TEST;
+
+ vm = mix_vm_new();
+
+#ifdef VERBOSE_TEST
+ dc = mix_dump_context_new(MIX_DUMP_DEF_CHANNEL, 0, 0, MIX_DUMP_ALL);
+#else
+ dc = NULL;
+#endif
+
+ test_arithmetics_(vm, dc);
+ test_shift_(vm, dc);
+ test_spc_(vm,dc);
+ test_move_(vm,dc);
+ test_load_(vm,dc);
+ test_store_(vm,dc);
+
+ mix_vm_delete(vm);
+
+#ifdef VERBOSE_TEST
+ mix_dump_context_delete(dc);
+#endif
+
+ return EXIT_SUCCESS;
+}
+
diff --git a/mixlib/testsuite/test.h b/mixlib/testsuite/test.h
new file mode 100644
index 0000000..7f8eb0c
--- /dev/null
+++ b/mixlib/testsuite/test.h
@@ -0,0 +1,44 @@
+/*
+** Copyright (C) 1999 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**
+*/
+
+/* Common definitions for test programs */
+
+#ifndef TEST_H
+#define TEST_H
+
+#include <glib.h>
+#include <mix.h>
+
+#define PRINT_BYTE(byte) g_print("%s = %02d",#byte,byte)
+
+#ifdef VERBOSE_TEST /* get printed information */
+#define INIT_TEST \
+ do { g_set_print_handler(NULL); mix_init_lib(); } while(FALSE);
+#else /* no printed information */
+static void
+dummy_print_f_(const gchar *m)
+{
+ /* no output */
+}
+#define INIT_TEST \
+do { g_set_print_handler(dummy_print_f_); mix_init_lib(); } while(FALSE);
+#endif /* VERBOSE_TEST */
+
+
+#endif /* TEST_H */
diff --git a/mixlib/xmix_device.c b/mixlib/xmix_device.c
new file mode 100644
index 0000000..c61ab55
--- /dev/null
+++ b/mixlib/xmix_device.c
@@ -0,0 +1,199 @@
+/* -*-c-*- -------------- xmix_device.c :
+ * Implementation of the functions declared in xmix_device.h
+ * ------------------------------------------------------------------
+ * Last change: Time-stamp: "2001-05-10 01:10:25 jao"
+ * ------------------------------------------------------------------
+ * Copyright (C) 2001, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#include "xmix_device.h"
+#include "mix_types.h"
+
+gchar *DEV_DIR_ = NULL;
+
+const char *DEV_EXT_ = ".dev";
+
+const char *DEF_NAMES_[] = {
+ "tape0", "tape1", "tape2", "tape3", "tape4", "tape5", "tape6", "tape7",
+ "disk0", "disk1", "disk2", "disk3", "disk4", "disk5", "disk6", "disk7",
+ "cardrd", "cardwr", "printer", "console", "paper"
+};
+
+const size_t SIZES_[] = {
+ 100, 100, 100, 100, 100, 100, 100, 100,
+ 100, 100, 100, 100, 100, 100, 100, 100,
+ 16, 16, 24, 14, 14
+};
+
+const mix_device_mode_t MODES_[] = {
+ mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, mix_dev_BIN,
+ mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, mix_dev_BIN,
+ mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, mix_dev_BIN,
+ mix_dev_BIN, mix_dev_CHAR, mix_dev_CHAR, mix_dev_CHAR, mix_dev_CHAR,
+ mix_dev_CHAR
+};
+
+const mix_fmode_t FMODES_[] = {
+ mix_io_RDWRT, mix_io_RDWRT, mix_io_RDWRT, mix_io_RDWRT,
+ mix_io_RDWRT, mix_io_RDWRT, mix_io_RDWRT, mix_io_RDWRT,
+ mix_io_RDWRT, mix_io_RDWRT, mix_io_RDWRT, mix_io_RDWRT,
+ mix_io_RDWRT, mix_io_RDWRT, mix_io_RDWRT, mix_io_RDWRT,
+ mix_io_READ, mix_io_WRITE, mix_io_WRITE, mix_io_RDWRT, mix_io_READ
+};
+
+/* constructors */
+void
+construct_device_ (mix_device_t *result, mix_device_type_t type)
+{
+ gchar *name;
+ name = DEV_DIR_ ? g_strdup_printf ("%s/%s", DEV_DIR_, DEF_NAMES_[type])
+ : g_strdup (DEF_NAMES_[type]);
+ construct_device_with_name_ (result, type, name);
+ g_free (name);
+}
+
+
+void
+construct_device_with_name_ (mix_device_t *result,
+ mix_device_type_t type, const gchar *name)
+{
+ result->type = type;
+ if (type != mix_dev_CONSOLE)
+ {
+ result->file = MIX_IOCHANNEL(mix_file_new_with_def_ext (name,
+ FMODES_[type],
+ DEV_EXT_));
+ result->vtable = DEF_DEV_VTABLE_;
+ }
+ else
+ {
+ result->file = mix_io_new (stdout);
+ result->vtable = CONSOLE_DEV_VTABLE_;
+ }
+}
+
+
+void
+construct_device_with_file_ (mix_device_t *result,
+ mix_device_type_t type, FILE *file)
+{
+ result->type = type;
+ result->file = mix_io_new (file);
+ result->vtable = DEF_DEV_VTABLE_;
+}
+
+
+/*
+ Write a block to the device.
+*/
+static gboolean
+write_ (mix_device_t *dev, const mix_word_t *block)
+{
+ gboolean result;
+
+ if (FMODES_[dev->type] == mix_io_READ) return FALSE;
+ if (MODES_[dev->type] == mix_dev_CHAR)
+ result = mix_io_write_word_array_as_char (GET_CHANNEL_ (dev),
+ block, SIZES_[dev->type]);
+ else
+ result = mix_io_write_word_array (GET_CHANNEL_ (dev),
+ block, SIZES_[dev->type]);
+ fflush (mix_io_to_FILE (GET_CHANNEL_ (dev)));
+
+ return result;
+}
+
+static gboolean
+read_cons_ (mix_device_t *dev, mix_word_t *block)
+{
+ return mix_io_read_word_array_as_char (mix_io_new (stdin), block,
+ SIZES_[mix_dev_CONSOLE]);
+}
+
+static gboolean
+read_ (mix_device_t *dev, mix_word_t *block)
+{
+ gboolean result;
+
+ if (FMODES_[dev->type] == mix_io_WRITE) return FALSE;
+ if (MODES_[dev->type] == mix_dev_CHAR)
+ {
+ result = mix_io_read_word_array_as_char (GET_CHANNEL_ (dev),
+ block, SIZES_[dev->type]);
+ }
+ else
+ result = mix_io_read_word_array (GET_CHANNEL_ (dev),
+ block, SIZES_[dev->type]);
+
+ return result;
+}
+
+static gboolean
+ioc_ (mix_device_t *dev, mix_short_t arg)
+{
+ int m;
+ FILE *file;
+
+ m = mix_short_magnitude(arg);
+ if (mix_short_is_negative(arg)) m = -m;
+ m *= sizeof (mix_word_t) * SIZES_[dev->type];
+ file = mix_io_to_FILE (GET_CHANNEL_(dev));
+
+ if (dev->type >= mix_dev_TAPE_0 && dev->type <= mix_dev_TAPE_7)
+ {
+ if (m == 0) rewind (file);
+ else fseek (file, m, SEEK_CUR);
+ }
+ if (dev->type >= mix_dev_DISK_0 && dev->type <= mix_dev_DISK_7)
+ {
+ if (m == 0) return FALSE;
+ // position disk
+ }
+ if (dev->type == mix_dev_PAPER_TAPE)
+ {
+ if (m == 0) return FALSE;
+ rewind (file);
+ }
+ return TRUE;
+}
+
+static gboolean
+busy_ (const mix_device_t *dev)
+{
+ return (!mix_io_is_ready (GET_CHANNEL_(dev)));
+}
+
+static void
+destroy_ (mix_device_t *dev)
+{
+ if (dev->type != mix_dev_CONSOLE && GET_FILE_(dev) != NULL)
+ mix_file_delete (GET_FILE_(dev));
+}
+
+static mix_device_vtable_t VTABLE_ = {
+ write_, read_, ioc_, busy_, destroy_
+};
+
+const mix_device_vtable_t * DEF_DEV_VTABLE_ = &VTABLE_;
+
+static mix_device_vtable_t CVTABLE_ = {
+ write_, read_cons_, ioc_, busy_, destroy_
+};
+
+const mix_device_vtable_t * CONSOLE_DEV_VTABLE_ = &CVTABLE_;
diff --git a/mixlib/xmix_device.h b/mixlib/xmix_device.h
new file mode 100644
index 0000000..0eb3fa8
--- /dev/null
+++ b/mixlib/xmix_device.h
@@ -0,0 +1,96 @@
+/* -*-c-*- ---------------- xmix_device.h :
+ * Protected declarations for mix_device_t
+ * ------------------------------------------------------------------
+ * Last change: Time-stamp: <2001-05-07 23:59:35 jao>
+ * ------------------------------------------------------------------
+ * Copyright (C) 2001, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef XMIX_DEVICE_H
+#define XMIX_DEVICE_H
+
+#include "mix_file.h"
+#include "mix_device.h"
+
+/* device file directory */
+extern gchar *DEV_DIR_;
+
+/* table of overridable device operations */
+typedef gboolean (*mix_dev_write_func_t) (mix_device_t *, const mix_word_t *);
+typedef gboolean (*mix_dev_read_func_t) (mix_device_t *, mix_word_t *);
+typedef gboolean (*mix_dev_ioc_func_t) (mix_device_t *, mix_short_t);
+typedef gboolean (*mix_dev_busy_func_t) (const mix_device_t *);
+typedef void (*mix_dev_destroy_t) (mix_device_t *);
+
+typedef struct mix_device_vtable_t
+{
+ mix_dev_write_func_t write;
+ mix_dev_read_func_t read;
+ mix_dev_ioc_func_t ioc;
+ mix_dev_busy_func_t busy;
+ mix_dev_destroy_t destroy;
+} mix_device_vtable_t;
+
+/* default vtables */
+extern const mix_device_vtable_t *DEF_DEV_VTABLE_;
+extern const mix_device_vtable_t *CONSOLE_DEV_VTABLE_;
+
+/*
+ Actual definition of a mix device, which can be cast to
+ a mix file.
+*/
+struct mix_device_t
+{
+ mix_iochannel_t *file;
+ mix_device_type_t type;
+ const mix_device_vtable_t *vtable;
+};
+
+/* constructors */
+extern void
+construct_device_ (mix_device_t *dev, mix_device_type_t type);
+
+extern void
+construct_device_with_name_ (mix_device_t *dev,
+ mix_device_type_t type, const gchar *name);
+
+extern void
+construct_device_with_file_ (mix_device_t *dev,
+ mix_device_type_t type, FILE *file);
+
+
+#define GET_CHANNEL_(dev) (dev->file)
+#define GET_FILE_(dev) ((mix_file_t *)(dev->file))
+
+/* default extension for device files */
+extern const char *DEV_EXT_;
+/* default names for device files */
+extern const char *DEF_NAMES_[];
+/* block sizes for devices */
+extern const size_t SIZES_[];
+/* io modes for devices */
+extern const mix_device_mode_t MODES_[];
+/* files modes for devices */
+extern const mix_fmode_t FMODES_[];
+
+
+
+
+#endif /* XMIX_DEVICE_H */
+
diff --git a/mixlib/xmix_eval.h b/mixlib/xmix_eval.h
new file mode 100644
index 0000000..7516ed3
--- /dev/null
+++ b/mixlib/xmix_eval.h
@@ -0,0 +1,55 @@
+/* -*-c-*- ---------------- xmix_eval.h :
+ * Definition of opaque types in mix_eval.h
+ * ------------------------------------------------------------------
+ * Last change: Time-stamp: <01/02/20 00:25:14 jose>
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef XMIX_EVAL_H
+#define XMIX_EVAL_H
+
+#include "mix_eval.h"
+
+/* the evaluator type */
+struct mix_eval_t
+{
+ mix_symbol_table_t *table; /* symbol table */
+ gboolean towner; /* true if owns the table */
+ mix_eval_result_t result; /* last evaluation result */
+ gint errpos; /* location of last error */
+ mix_word_t value; /* last computed value */
+};
+
+/* flex scanner data/result struct */
+typedef struct mix_eval_data_
+{
+ gchar *expr;
+ const mix_symbol_table_t *table;
+ mix_word_t value;
+ mix_short_t loc;
+ gint errpos;
+} mix_eval_data_;
+
+/* flex scanner prototype */
+extern
+mix_eval_result_t mix_eval_expr (mix_eval_data_ *data);
+
+#endif /* XMIX_EVAL_H */
+
diff --git a/mixlib/xmix_io.c b/mixlib/xmix_io.c
new file mode 100644
index 0000000..a43d284
--- /dev/null
+++ b/mixlib/xmix_io.c
@@ -0,0 +1,57 @@
+/* -*-c-*- ------------------ xmix_io.c :
+ * Implementation of the functions declared in xmix_io.h
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "xmix_io.h"
+
+const char *io_OPENTYPE_[5] = { "r", "w", "w+", "a", "a+" };
+
+
+/* initialise a mix_iochannel from a file descriptor */
+gboolean
+io_init_from_fdesc_(mix_iochannel_t *ioc, int fdesc)
+{
+ FILE *file;
+ mix_fmode_t mode;
+ int flags = fcntl(fdesc, F_GETFL);
+
+ if ( (flags&O_RDONLY) == O_RDONLY )
+ mode = mix_io_READ;
+ else if ( (flags&O_WRONLY) == O_WRONLY )
+ mode = mix_io_WRITE;
+ else if ( (flags&O_RDWR) == O_RDWR )
+ mode = mix_io_RDWRT;
+ else
+ return FALSE;
+
+ file = fdopen(fdesc, fmode_to_type_(mode));
+ g_return_val_if_fail(file != NULL, FALSE);
+ if (mode == mix_io_RDWRT) rewind (file);
+ io_init_from_file_(ioc, file);
+
+ return TRUE;
+}
+
+
+
diff --git a/mixlib/xmix_io.h b/mixlib/xmix_io.h
new file mode 100644
index 0000000..1346559
--- /dev/null
+++ b/mixlib/xmix_io.h
@@ -0,0 +1,64 @@
+/* -*-c-*- ------------------ xmix_io.h :
+ * Implementation of mix_iochannel_t and mix_file_t
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef XMIX_IOCHANNEL_H
+#define XMIX_IOCHANNEL_H
+
+#include <stdio.h>
+#include "mix_io.h"
+
+/* the actual definition of mix_iochannel_t */
+struct mix_iochannel_t
+{
+ FILE *file;
+};
+
+
+extern const char * io_OPENTYPE_[5];
+
+#define fmode_to_type_(mode) ( (mode) < 6 ? io_OPENTYPE_[(mode)]:NULL )
+
+/* initialisation */
+extern gboolean
+io_init_from_fdesc_(mix_iochannel_t *ioc, int fdesc);
+
+#define io_init_from_file_(ioc,f) (ioc)->file = f
+
+#define io_close_(ioc) fclose((ioc)->file)
+
+/* write/read data */
+#define write_data_(ioc,data,no) \
+ ( (no) == fwrite((const void*)(data), sizeof(*(data)), (no), (ioc)->file) )
+
+#define read_data_(ioc,data,no) \
+ ( (no) == fread((void*)(data), sizeof(*(data)), (no), (ioc)->file) )
+
+/* state */
+#define is_eof_(ioc) ( feof((ioc)->file) != 0 )
+#define is_ready_(ioc) ( ferror((ioc)->file) == 0 )
+
+/* conversions */
+#define io_get_FILE_(ioc) (MIX_IOCHANNEL(ioc))->file
+
+
+#endif /* XMIX_IOCHANNEL_H */
+
diff --git a/mixlib/xmix_parser.h b/mixlib/xmix_parser.h
new file mode 100644
index 0000000..51f1560
--- /dev/null
+++ b/mixlib/xmix_parser.h
@@ -0,0 +1,111 @@
+/* -*-c-*- ---------------- xmix_parser.h :
+ * Declarations for the implementation of mix_parser_t
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef XMIX_PARSER_H
+#define XMIX_PARSER_H
+
+#include "mix_ins.h"
+#include "mix_file.h"
+#include "mix_symbol_table.h"
+#include "mix_parser.h"
+
+/* mix_parser_t definition */
+struct mix_parser_t
+{
+ mix_file_t *in_file; /* the source file to be compiled */
+ mix_symbol_table_t *symbol_table;
+ mix_symbol_table_t *ls_table; /* literal strings symbols */
+ guint cur_ls; /* current literal string symbol */
+ GHashTable *future_refs; /* a map from symbol name to list of addresses */
+ GTree *ins_table; /* a table of compiled instructions */
+ GSList *con_list; /* CON instructions */
+ GSList *alf_list; /* ALF instructions */
+ mix_address_t loc_count; /* current memory location during compilation */
+ mix_parser_err_t status; /* outcome of compilation */
+ guint err_line; /* line of the last error */
+ guint err_count; /* no. of errors during compilation */
+ guint warn_count; /* no. of warnings during compilation */
+ mix_address_t start; /* start address of the compiled code */
+ mix_address_t end; /* end address of the compiled code */
+};
+
+/* each node of the ins_table stores a mix_word_t with the instruction
+ and a source code line (for debugging and listing)
+*/
+typedef struct ins_node_
+{
+ mix_word_t ins;
+ guint lineno;
+} ins_node_;
+
+
+/* functions to manipulate mix_parser_t during compilation */
+
+/* access loc counter */
+#define get_ploc_(parser) ((parser)->loc_count)
+
+/* symbol table */
+/* Define a new symbol with given value
+ * and update previously set refs to this symbol
+ */
+extern mix_parser_err_t
+mix_parser_define_symbol_value (mix_parser_t *parser, const gchar *name,
+ mix_word_t value);
+
+/* Define a new symbol with value equal to the current loc_count
+ * and update previously set refs to this symbol
+ */
+extern mix_parser_err_t
+mix_parser_define_symbol_here (mix_parser_t *parser, const gchar *name);
+
+/* Set a reference to future symbol here */
+extern void
+mix_parser_set_future_ref (mix_parser_t *parser, const gchar *name);
+
+/* Redefine the value of a local symbol as the current loc_count */
+extern void
+mix_parser_manage_local_symbol (mix_parser_t *parser, const gchar *name,
+ mix_short_t value);
+
+/* Literal strings symbols */
+extern void
+mix_parser_define_ls (mix_parser_t *parser, mix_word_t value);
+
+/* Compilation */
+/* Add instruction with address the current loc_count */
+extern void
+mix_parser_add_ins (mix_parser_t *parser, const mix_ins_t *new_ins,
+ guint lineno);
+extern void
+mix_parser_add_raw (mix_parser_t *parser, mix_word_t word, guint lineno,
+ gboolean is_con);
+
+/* Error handling */
+extern void
+mix_parser_log_error (mix_parser_t *parser, mix_parser_err_t error,
+ gint lineno, const gchar *comment, gboolean warn);
+
+
+
+
+#endif /* XMIX_PARSER_H */
+
diff --git a/mixlib/xmix_vm.c b/mixlib/xmix_vm.c
new file mode 100644
index 0000000..d5b4e4b
--- /dev/null
+++ b/mixlib/xmix_vm.c
@@ -0,0 +1,598 @@
+/* ---------------------- xmix_vm.c :
+ * Implementation of the functions declared in xmix_vm.h
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000, 2003, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#include "xmix_vm.h"
+
+/* auxiliar functions */
+G_INLINE_FUNC mix_address_t
+get_M_ (const mix_vm_t *vm, const mix_ins_t *ins);
+G_INLINE_FUNC mix_word_t
+get_V_ (const mix_vm_t *vm, const mix_ins_t *ins);
+G_INLINE_FUNC mix_device_t *
+get_dev_ (mix_vm_t *vm, mix_fspec_t type);
+
+G_INLINE_FUNC mix_address_t
+get_M_ (const mix_vm_t *vm, const mix_ins_t *ins)
+{
+ if ( ins->index == 0 )
+ return ins->address;
+ else
+ return mix_short_add (ins->address,
+ mix_word_to_short_fast (get_rI_ (vm, ins->index)));
+}
+
+G_INLINE_FUNC mix_word_t
+get_V_ (const mix_vm_t *vm, const mix_ins_t *ins)
+{
+ return mix_word_get_field (ins->fspec, get_cell_ (vm, get_M_ (vm,ins)));
+}
+
+G_INLINE_FUNC mix_device_t *
+get_dev_ (mix_vm_t *vm, mix_fspec_t type)
+{
+ if (type >= BD_NO_) return NULL;
+ if (vm->devices[type] == NULL)
+ vm->devices[type] = vm->factory (type);
+ return vm->devices[type];
+}
+
+/* error macro */
+#define fail_if_not_(vm,cond,error) \
+do { \
+ if (!(cond)) \
+ { \
+ set_last_error_ (vm, error); \
+ return FALSE; \
+ } \
+} while (FALSE)
+
+#define fail_(vm,error) fail_if_not_ (vm, FALSE, error)
+
+#define fail_unexpected_(vm) fail_ (vm, MIX_VM_ERROR_UNEXPECTED)
+
+/* Instruction handlers */
+
+static gboolean
+nop_handler_ (mix_vm_t *vm, const mix_ins_t *ins)
+{
+ g_assert (ins->opcode == mix_opNOP);
+ inc_loc_ (vm);
+ return TRUE;
+}
+
+static gboolean
+add_handler_ (mix_vm_t *vm, const mix_ins_t *ins)
+{
+ mix_word_t val = get_V_ (vm, ins);
+ g_assert (ins->opcode == mix_opADD || ins->opcode == mix_opSUB);
+ if ( ins->opcode == mix_opSUB ) mix_word_reverse_sign (val);
+ if ( mix_word_add_and_carry (get_rA_ (vm), val, NULL, &get_rA_ (vm)) )
+ set_over_ (vm,TRUE);
+ inc_loc_ (vm);
+ return TRUE;
+}
+
+
+static gboolean
+mul_handler_ (mix_vm_t *vm, const mix_ins_t *ins)
+{
+ g_assert (ins->opcode == mix_opMUL);
+ mix_word_mul (get_rA_ (vm), get_V_ (vm,ins), &get_rA_ (vm), &get_rX_ (vm));
+ inc_loc_ (vm);
+ return TRUE;
+}
+
+static gboolean
+div_handler_ (mix_vm_t *vm, const mix_ins_t *ins)
+{
+ g_assert (ins->opcode == mix_opDIV);
+ if ( mix_word_div (get_rA_ (vm), get_rX_ (vm), get_V_ (vm,ins),
+ &get_rA_ (vm), &get_rX_ (vm)) )
+ set_over_ (vm,TRUE);
+ inc_loc_ (vm);
+ return TRUE;
+}
+
+static gboolean
+spc_handler_ (mix_vm_t *vm, const mix_ins_t *ins)
+{
+ g_assert (ins->opcode == mix_opSPC);
+
+ switch (mix_ins_id_from_ins (*ins)) {
+ case mix_HLT: halt_ (vm, TRUE); break;
+ case mix_CHAR:
+ {
+ guint32 num = mix_word_magnitude (get_rA_ (vm));
+ mix_char_t z = mix_ascii_to_char ('0');
+ guint i;
+ for (i = 5; 0 < i; --i, num /= 10)
+ mix_word_set_byte (&get_rX_ (vm), i, z + num % 10);
+ for (i = 5; 0 < i; --i, num /= 10)
+ mix_word_set_byte (&get_rA_ (vm), i, z + num % 10);
+ break;
+ }
+ case mix_NUM:
+ {
+ guint i;
+ mix_word_t num = MIX_WORD_ZERO;
+ mix_word_t ten = 10;
+ for (i = 1; i <= 5; ++i) {
+ mix_word_mul (ten, num, NULL, &num);
+ mix_word_add_and_carry (num, mix_word_get_byte (get_rA_ (vm),i)%10,
+ NULL, &num);
+ }
+ for (i = 1; i <= 5; ++i) {
+ mix_word_mul (ten, num, NULL, &num);
+ mix_word_add_and_carry (num, mix_word_get_byte (get_rX_ (vm),i)%10,
+ NULL, &num);
+ }
+ set_rA_ (vm, mix_word_is_negative (get_rA_ (vm)) ?
+ mix_word_negative (num) : num);
+ break;
+ }
+ default: fail_ (vm, MIX_VM_ERROR_BAD_FSPEC);
+ }
+ inc_loc_ (vm);
+ return TRUE;
+}
+
+static gboolean
+sla_handler_ (mix_vm_t *vm, const mix_ins_t *ins)
+{
+ mix_short_t n = get_M_ (vm,ins);
+
+ g_assert (ins->opcode == mix_opSLx);
+
+ fail_if_not_ (vm, mix_short_is_positive (n), MIX_VM_ERROR_BAD_M);
+
+ switch ( mix_ins_id_from_ins (*ins) ) {
+ case mix_SLA:
+ mix_word_shift_left (get_rA_ (vm), MIX_WORD_ZERO, n, &get_rA_ (vm), NULL);
+ break;
+ case mix_SRA:
+ mix_word_shift_right (get_rA_ (vm), MIX_WORD_ZERO, n, &get_rA_ (vm), NULL);
+ break;
+ case mix_SLAX:
+ mix_word_shift_left (get_rA_ (vm), get_rX_ (vm), n,
+ &get_rA_ (vm), &get_rX_ (vm));
+ break;
+ case mix_SRAX:
+ mix_word_shift_right (get_rA_ (vm), get_rX_ (vm), n,
+ &get_rA_ (vm), &get_rX_ (vm));
+ break;
+ case mix_SLC:
+ mix_word_shift_left_circular (get_rA_ (vm), get_rX_ (vm), n,
+ &get_rA_ (vm), &get_rX_ (vm));
+ break;
+ case mix_SRC:
+ mix_word_shift_right_circular (get_rA_ (vm), get_rX_ (vm), n,
+ &get_rA_ (vm), &get_rX_ (vm));
+ break;
+ default:
+ fail_unexpected_ (vm);
+ }
+
+ inc_loc_ (vm);
+ return TRUE;
+}
+
+static gboolean
+mov_handler_ (mix_vm_t *vm, const mix_ins_t *ins)
+{
+ mix_short_t from = get_M_ (vm,ins),
+ to = mix_word_to_short_fast (get_rI_ (vm,1));
+ guint k, delta = ins->fspec;
+
+ g_assert (ins->opcode == mix_opMOVE);
+ if (mix_short_is_positive (from)
+ && mix_short_is_positive (to)
+ && MEMOK_ (from + delta -1)
+ && MEMOK_ (to + delta - 1))
+ {
+ for (k = 0; k < delta; ++k)
+ set_cell_ (vm, to+k, get_cell_ (vm, from+k));
+ set_rI_ (vm, 1, to+delta);
+ inc_loc_ (vm);
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+static gboolean
+lda_handler_ (mix_vm_t *vm, const mix_ins_t *ins)
+{
+ gint r = 0;
+ mix_word_t val;
+ mix_ins_id_t id = mix_ins_id_from_ins (*ins);
+
+ g_assert (id >= mix_LDA && id <= mix_LDXN);
+
+ val = get_V_ (vm, ins);
+ if (id > mix_LDX) mix_word_reverse_sign (val);
+ if ( (id > mix_LDA && id < mix_LDX) || (id > mix_LDAN && id < mix_LDXN) )
+ /* Bytes 1-3 of I regs are always null */
+ val = mix_word_set_field (mix_fspec_new (1,3),MIX_WORD_ZERO,val);
+
+ switch (id) {
+ case mix_LDA: case mix_LDAN: r = A_; break;
+ case mix_LDX: case mix_LDXN: r = X_; break;
+ case mix_LD1: case mix_LD1N: r = I1_; break;
+ case mix_LD2: case mix_LD2N: r = I2_; break;
+ case mix_LD3: case mix_LD3N: r = I3_; break;
+ case mix_LD4: case mix_LD4N: r = I4_; break;
+ case mix_LD5: case mix_LD5N: r = I5_; break;
+ case mix_LD6: case mix_LD6N: r = I6_; break;
+ default: g_assert_not_reached ();
+ }
+ set_reg_ (vm, r, val);
+ inc_loc_ (vm);
+ return TRUE;
+}
+
+
+static gboolean
+sta_handler_ (mix_vm_t *vm, const mix_ins_t *ins)
+{
+ mix_address_t addr = get_M_ (vm, ins);
+ mix_ins_id_t id = mix_ins_id_from_ins (*ins);
+ mix_word_t from;
+
+ g_assert (id >= mix_STA && id <= mix_STZ);
+ switch (id) {
+ case mix_STA: from = get_rA_ (vm); break;
+ case mix_STX: from = get_rX_ (vm); break;
+ case mix_STJ: from = get_rJ_ (vm); break;
+ case mix_STZ: from = MIX_WORD_ZERO; break;
+ default: from = get_rI_ (vm, id - mix_ST1 + 1); break;
+ }
+ set_cell_ (vm, addr,
+ mix_word_store_field (ins->fspec, from, get_cell_ (vm, addr)));
+ inc_loc_ (vm);
+ return TRUE;
+}
+
+static gboolean
+jbs_handler_ (mix_vm_t *vm, const mix_ins_t *ins)
+{
+ g_assert (ins->opcode == mix_opJBUS);
+ fail_if_not_ (vm, ins->fspec < BD_NO_, MIX_VM_ERROR_BAD_DEVICE_NO);
+ fail_if_not_ (vm, get_dev_ (vm, ins->fspec) != NULL,
+ MIX_VM_ERROR_BAD_DEVICE_NO);
+
+ if ( mix_device_busy (get_dev_ (vm, ins->fspec)) ) {
+ set_rJ_ (vm, get_loc_ (vm));
+ set_loc_ (vm, get_M_ (vm, ins));
+ } else inc_loc_ (vm);
+ return TRUE;
+}
+
+static gboolean
+ioc_handler_ (mix_vm_t *vm, const mix_ins_t *ins)
+{
+ mix_address_t addr;
+ mix_device_t *dev;
+
+ g_assert (ins->opcode == mix_opIOC);
+
+ addr = get_M_ (vm, ins);
+ fail_if_not_ (vm, ins->fspec < BD_NO_, MIX_VM_ERROR_BAD_DEVICE_NO);
+
+ dev = get_dev_ (vm, ins->fspec);
+ fail_if_not_ (vm, dev != NULL, MIX_VM_ERROR_BAD_DEVICE_NO);
+
+ fail_if_not_ (vm, mix_device_ioc (dev, addr), MIX_VM_ERROR_DEV_CTL);
+
+ inc_loc_ (vm);
+ return TRUE;
+}
+
+static gboolean
+inp_handler_ (mix_vm_t *vm, const mix_ins_t *ins)
+{
+ mix_address_t addr;
+ mix_device_t *dev;
+
+ g_assert (ins->opcode == mix_opIN);
+ fail_if_not_ (vm, ins->fspec < BD_NO_, MIX_VM_ERROR_BAD_DEVICE_NO);
+
+ addr = get_M_ (vm, ins);
+ fail_if_not_ (vm, MEMOK_ (addr), MIX_VM_ERROR_BAD_ACCESS);
+
+ dev = get_dev_ (vm, ins->fspec);
+ fail_if_not_ (vm, dev != NULL, MIX_VM_ERROR_BAD_DEVICE_NO);
+
+ fail_if_not_ (vm, MEM_CELLS_NO_ - addr > mix_device_block_size (dev),
+ MIX_VM_ERROR_BAD_ACCESS);
+
+ fail_if_not_ (vm, mix_device_read (dev, get_cell_ptr_ (vm, addr)),
+ MIX_VM_ERROR_DEV_READ);
+
+ inc_loc_ (vm);
+ return TRUE;
+}
+
+static gboolean
+out_handler_ (mix_vm_t *vm, const mix_ins_t *ins)
+{
+ mix_address_t addr;
+ mix_device_t *dev;
+
+ g_assert (ins->opcode == mix_opOUT);
+
+ fail_if_not_ (vm, ins->fspec < BD_NO_, MIX_VM_ERROR_BAD_DEVICE_NO);
+
+ addr = get_M_ (vm, ins);
+ fail_if_not_ (vm, MEMOK_ (addr), MIX_VM_ERROR_BAD_ACCESS);
+
+ dev = get_dev_ (vm, ins->fspec);
+ fail_if_not_ (vm, dev != NULL, MIX_VM_ERROR_BAD_DEVICE_NO);
+
+ fail_if_not_ (vm, MEM_CELLS_NO_ - addr > mix_device_block_size (dev),
+ MIX_VM_ERROR_BAD_ACCESS);
+
+ fail_if_not_ (vm, mix_device_write (dev, get_cell_ptr_ (vm, addr)),
+ MIX_VM_ERROR_DEV_WRITE);
+
+ inc_loc_ (vm);
+ return TRUE;
+}
+
+static gboolean
+jrd_handler_ (mix_vm_t *vm, const mix_ins_t *ins)
+{
+ g_assert (ins->opcode == mix_opJRED);
+ fail_if_not_ (vm, ins->fspec < BD_NO_, MIX_VM_ERROR_BAD_DEVICE_NO);
+ fail_if_not_ (vm, get_dev_ (vm, ins->fspec) != NULL,
+ MIX_VM_ERROR_BAD_DEVICE_NO);
+
+ inc_loc_ (vm);
+ if ( !mix_device_busy (get_dev_ (vm, ins->fspec)) )
+ {
+ set_rJ_ (vm, get_loc_ (vm));
+ set_loc_ (vm, get_M_ (vm, ins));
+ }
+ return TRUE;
+}
+
+static gboolean
+jmp_handler_ (mix_vm_t *vm, const mix_ins_t *ins)
+{
+ gboolean jump = FALSE;
+ mix_address_t addr = get_M_ (vm, ins);
+ mix_ins_id_t id = mix_ins_id_from_ins (*ins);
+
+ g_assert (ins->opcode == mix_opJMP);
+ fail_if_not_ (vm, MEMOK_ (addr), MIX_VM_ERROR_BAD_ACCESS);
+
+ switch ( id ) {
+ case mix_JMP:
+ case mix_JSJ:
+ jump = TRUE;
+ break;
+ case mix_JOV:
+ jump = get_over_ (vm);
+ if (jump) set_over_ (vm, FALSE);
+ break;
+ case mix_JNOV:
+ jump = !get_over_ (vm);
+ set_over_ (vm, FALSE);
+ break;
+ case mix_JL:
+ jump = ( get_cmp_ (vm) == mix_LESS );
+ break;
+ case mix_JE:
+ jump = ( get_cmp_ (vm) == mix_EQ );
+ break;
+ case mix_JG:
+ jump = ( get_cmp_ (vm) == mix_GREAT );
+ break;
+ case mix_JGE:
+ jump = ( get_cmp_ (vm) != mix_LESS );
+ break;
+ case mix_JNE:
+ jump = ( get_cmp_ (vm) != mix_EQ );
+ break;
+ case mix_JLE:
+ jump = ( get_cmp_ (vm) != mix_GREAT );
+ break;
+ default:
+ fail_unexpected_ (vm);
+ }
+
+ inc_loc_ (vm);
+ if ( jump ) {
+ if ( id != mix_JSJ ) set_rJ_ (vm, get_loc_ (vm));
+ set_loc_ (vm, addr);
+ }
+ return TRUE;
+}
+
+static gboolean
+jpx_handler_ (mix_vm_t *vm, const mix_ins_t *ins)
+{
+ gboolean jump = FALSE;
+ mix_address_t addr = get_M_ (vm, ins);
+ mix_ins_id_t id = mix_ins_id_from_ins (*ins);
+ mix_word_t val;
+
+ g_assert (ins->opcode >= mix_opJAx || ins->opcode <= mix_opJXx);
+ fail_if_not_ (vm, MEMOK_ (addr), MIX_VM_ERROR_BAD_ACCESS);
+
+ switch (ins->opcode) {
+ case mix_opJAx: val = get_rA_ (vm); break;
+ case mix_opJXx: val = get_rX_ (vm); break;
+ default: val = get_rI_ (vm, ins->opcode - mix_opJAx);
+ }
+
+ switch (id) {
+ case mix_JAN: case mix_JXN:
+ case mix_J1N: case mix_J2N: case mix_J3N:
+ case mix_J4N: case mix_J5N: case mix_J6N:
+ jump = mix_word_is_negative (val) && val != MIX_WORD_MINUS_ZERO;
+ break;
+ case mix_JAZ: case mix_JXZ:
+ case mix_J1Z: case mix_J2Z: case mix_J3Z:
+ case mix_J4Z: case mix_J5Z: case mix_J6Z:
+ jump = mix_word_magnitude (val) == MIX_WORD_ZERO;
+ break;
+ case mix_JAP: case mix_JXP:
+ case mix_J1P: case mix_J2P: case mix_J3P:
+ case mix_J4P: case mix_J5P: case mix_J6P:
+ jump = mix_word_is_positive (val) && val != MIX_WORD_ZERO;
+ break;
+ case mix_JANN: case mix_JXNN:
+ case mix_J1NN: case mix_J2NN: case mix_J3NN:
+ case mix_J4NN: case mix_J5NN: case mix_J6NN:
+ jump = mix_word_magnitude (val) == MIX_WORD_ZERO
+ || mix_word_is_positive (val);
+ break;
+ case mix_JANZ: case mix_JXNZ:
+ case mix_J1NZ: case mix_J2NZ: case mix_J3NZ:
+ case mix_J4NZ: case mix_J5NZ: case mix_J6NZ:
+ jump = mix_word_magnitude (val) != MIX_WORD_ZERO;
+ break;
+ case mix_JANP: case mix_JXNP:
+ case mix_J1NP: case mix_J2NP: case mix_J3NP:
+ case mix_J4NP: case mix_J5NP: case mix_J6NP:
+ jump = mix_word_magnitude (val) == MIX_WORD_ZERO
+ || mix_word_is_negative (val);
+ break;
+ default:
+ fail_unexpected_ (vm);
+ }
+
+ inc_loc_ (vm);
+ if ( jump ) {
+ set_rJ_ (vm, get_loc_ (vm));
+ set_loc_ (vm, addr);
+ }
+ return TRUE;
+}
+
+static gboolean
+ina_handler_ (mix_vm_t *vm, const mix_ins_t *ins)
+{
+ mix_word_t val = mix_short_to_word_fast (get_M_ (vm, ins));
+ mix_ins_id_t id = mix_ins_id_from_ins (*ins);
+ gint r;
+
+ g_assert (id >= mix_INCA && id <= mix_ENNX);
+
+ switch (ins->opcode) {
+ case mix_opINCA: r = A_; break;
+ case mix_opINCX: r = X_; break;
+ default: r = I1_ + ins->opcode - mix_opINC1;
+ }
+
+ switch (id) {
+ case mix_ENTA: case mix_ENTX:
+ break;
+ case mix_ENT1: case mix_ENT2: case mix_ENT3:
+ case mix_ENT4: case mix_ENT5: case mix_ENT6:
+ val = mix_word_set_field (mix_fspec_new (1,3), MIX_WORD_ZERO, val);
+ break;
+ case mix_INCA: case mix_INCX:
+ if ( mix_word_add_and_carry (val, get_reg_ (vm, r), NULL, &val) )
+ set_over_ (vm, TRUE);
+ break;
+ case mix_INC1: case mix_INC2: case mix_INC3:
+ case mix_INC4: case mix_INC5: case mix_INC6:
+ mix_word_add_and_carry (val, get_reg_ (vm,r), NULL, &val);
+ val = mix_word_set_field (mix_fspec_new (1,3), MIX_WORD_ZERO, val);
+ break;
+ case mix_DECA: case mix_DECX:
+ if ( mix_word_add_and_carry (mix_word_negative (val), get_reg_ (vm, r),
+ NULL, &val) )
+ set_over_ (vm, TRUE);
+ break;
+ case mix_DEC1: case mix_DEC2: case mix_DEC3:
+ case mix_DEC4: case mix_DEC5: case mix_DEC6:
+ mix_word_add_and_carry (mix_word_negative (val), get_reg_ (vm,r),
+ NULL, &val);
+ val = mix_word_set_field (mix_fspec_new (1,3), MIX_WORD_ZERO, val);
+ break;
+ case mix_ENN1: case mix_ENN2: case mix_ENN3:
+ case mix_ENN4: case mix_ENN5: case mix_ENN6:
+ val = mix_word_set_field (mix_fspec_new (1,3), MIX_WORD_ZERO, val);
+ /* fallthrough */
+ case mix_ENNA: case mix_ENNX:
+ mix_word_reverse_sign (val);
+ break;
+ default:
+ fail_unexpected_ (vm);
+ }
+ set_reg_ (vm, r, val);
+ inc_loc_ (vm);
+ return TRUE;
+}
+
+static gboolean
+cmp_handler_ (mix_vm_t *vm, const mix_ins_t *ins)
+{
+ g_assert (ins->opcode >= mix_opCMPA && ins->opcode <= mix_opCMPX);
+
+ if ( ins->fspec == 0 ) { /* shortcut: +0 == -0 */
+ set_cmp_ (vm, mix_EQ);
+ } else {
+ mix_word_t v = get_V_ (vm, ins);
+ mix_word_t reg;
+ mix_cmpflag_t flag;
+
+ switch (ins->opcode) {
+ case mix_opCMPA:
+ reg = get_rA_ (vm);
+ break;
+ case mix_opCMPX:
+ reg = get_rX_ (vm);
+ break;
+ default:
+ reg = get_rI_ (vm, ins->opcode - mix_opCMPA);
+ break;
+ }
+ reg = mix_word_get_field (ins->fspec, reg);
+ mix_word_add_and_carry (reg, mix_word_negative (v), NULL, &reg);
+ if ( mix_word_magnitude (reg) == MIX_WORD_ZERO ) flag = mix_EQ;
+ else if ( mix_word_is_positive (reg) ) flag = mix_GREAT;
+ else flag = mix_LESS;
+ set_cmp_ (vm, flag);
+ }
+ inc_loc_ (vm);
+ return TRUE;
+}
+
+ins_handler_t_ ins_handlers_[MIX_BYTE_MAX + 1] = {
+ nop_handler_, add_handler_, add_handler_, mul_handler_, div_handler_,
+ spc_handler_, sla_handler_, mov_handler_, lda_handler_, lda_handler_,
+ lda_handler_, lda_handler_, lda_handler_, lda_handler_, lda_handler_,
+ lda_handler_, lda_handler_, lda_handler_, lda_handler_, lda_handler_,
+ lda_handler_, lda_handler_, lda_handler_, lda_handler_, sta_handler_,
+ sta_handler_, sta_handler_, sta_handler_, sta_handler_, sta_handler_,
+ sta_handler_, sta_handler_, sta_handler_, sta_handler_, jbs_handler_,
+ ioc_handler_, inp_handler_, out_handler_, jrd_handler_, jmp_handler_,
+ jpx_handler_, jpx_handler_, jpx_handler_, jpx_handler_, jpx_handler_,
+ jpx_handler_, jpx_handler_, jpx_handler_, ina_handler_, ina_handler_,
+ ina_handler_, ina_handler_, ina_handler_, ina_handler_, ina_handler_,
+ ina_handler_, cmp_handler_, cmp_handler_, cmp_handler_, cmp_handler_,
+ cmp_handler_, cmp_handler_, cmp_handler_, cmp_handler_,
+};
diff --git a/mixlib/xmix_vm.h b/mixlib/xmix_vm.h
new file mode 100644
index 0000000..7a634d4
--- /dev/null
+++ b/mixlib/xmix_vm.h
@@ -0,0 +1,139 @@
+/* ---------------------- xmix_vm.h :
+ * This file contains internal declarations used in the implementation
+ * of the mix_vm_t type.
+ * ------------------------------------------------------------------
+ * $Id: xmix_vm.h,v 1.10 2005/09/20 19:43:13 jao Exp $
+ * ------------------------------------------------------------------
+ * Copyright (C) 2000, 2002, 2003, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef XMIX_VM_H
+#define XMIX_VM_H
+
+#include <string.h>
+
+#include "mix_symbol_table.h"
+#include "mix_device.h"
+#include "mix_src_file.h"
+#include "mix_predicate_list.h"
+#include "mix_vm.h"
+
+/* The mix_vm_t type */
+enum {
+ IREG_NO_ = 6,
+ BD_NO_ = 21,
+ MEM_CELLS_NO_ = MIX_VM_CELL_NO,
+ MEM_CELLS_MAX_ = MIX_VM_CELL_NO - 1
+};
+
+struct mix_vm_t
+{
+ mix_word_t reg[IREG_NO_+3];
+ mix_word_t cell[MEM_CELLS_NO_];
+ gboolean overflow;
+ mix_cmpflag_t cmpflag;
+ mix_short_t loc_count;
+ mix_vm_status_t status;
+ mix_vm_error_t last_error;
+ mix_device_t * devices[BD_NO_];
+ mix_address_t start_addr; /* start address of loaded file */
+ GTree *line_table; /* source line no -> address */
+ GTree *address_table; /* adress -> source line no */
+ gint8 bp[MEM_CELLS_NO_/8]; /* each bit signals a break point */
+ mix_vm_clock_t *clock; /* the vm clock */
+ mix_symbol_table_t *symbol_table;
+ mix_src_file_t *src_file; /* source of last loaded code file */
+ mix_device_factory_t factory; /* the factory for new devices */
+ mix_predicate_list_t *pred_list; /* predicates for conditional bps */
+ GSList *address_list; /* list of executed addresses */
+};
+
+/* Macros for accessing/modifying the above structure.
+ * Warning: the arguments of these macros must not have side-effects.
+ */
+#define IOK_(idx) ( (idx) > 0 && (idx) < IREG_NO_+1 )
+#define MEMOK_(addr) ( mix_short_is_positive(addr) && (addr) < MEM_CELLS_NO_ )
+#define REGOK_(r) ( (r) >= 0 && (r) < IREG_NO_ + 3 )
+
+enum { A_ = 0, X_, J_, I1_, I2_, I3_, I4_, I5_, I6_ };
+
+#define get_reg_(vm, r) ((vm)->reg[r])
+#define get_rA_(vm) get_reg_(vm, A_)
+#define get_rX_(vm) get_reg_(vm, X_)
+#define get_rJ_(vm) get_reg_(vm, J_)
+#define get_rI_(vm,idx) get_reg_(vm, I1_ + (idx) - 1)
+#define get_cell_(vm,addr) ( MEMOK_(addr) ? vm->cell[addr] : MIX_WORD_ZERO )
+#define get_cell_ptr_(vm,addr) ( MEMOK_(addr) ? (vm->cell) + addr : NULL )
+#define get_cmp_(vm) (vm->cmpflag)
+#define get_over_(vm) (vm->overflow)
+#define get_loc_(vm) (vm->loc_count)
+#define get_clock_(vm) (vm->clock)
+#define get_pred_list_(vm) (vm->pred_list)
+#define get_address_list_(vm) (vm->address_list)
+#define get_status_(vm) (vm->status)
+#define get_last_error_(vm) (vm->last_error)
+#define set_last_error_(vm,error) ((vm)->last_error = (error))
+
+#define set_reg_(vm,r,x) \
+do { \
+ if ( REGOK_(r) ) vm->reg[r] = (x); \
+} while (FALSE)
+
+#define set_rA_(vm,x) set_reg_(vm,A_,x)
+#define set_rX_(vm,x) set_reg_(vm,X_,x)
+#define set_rJ_(vm,x) set_reg_(vm,J_,(x)&MIX_SHORT_MAX)
+#define set_rI_(vm,idx,x) set_reg_(vm,(idx) + I1_ - 1,x)
+
+#define set_cell_(vm,addr,x) \
+do { \
+ if ( MEMOK_(addr) ) (vm)->cell[addr] = (x); \
+} while (FALSE)
+
+#define set_cmp_(vm,x) (vm)->cmpflag = (x)
+#define set_over_(vm,x) (vm)->overflow = (x)
+#define set_loc_(vm,x) (vm)->loc_count = (MEMOK_(x)? (x) : MIX_SHORT_ZERO)
+
+#define set_status_(vm,s) ((vm)->status = (s))
+#define is_halted_(vm) ((vm)->status == MIX_VM_HALT)
+#define halt_(vm,val) ((vm)->status = (val)? MIX_VM_HALT : MIX_VM_RUNNING)
+
+#define inc_loc_(vm) \
+do { \
+ if (++(vm->loc_count) == MEM_CELLS_NO_) \
+ { vm->loc_count--; halt_(vm, TRUE); } \
+} while(FALSE)
+
+#define set_start_(vm,val) ((vm)->start_addr = (val))
+#define reset_loc_(vm) set_loc_ (vm, vm->start_addr)
+#define update_time_(vm,ins) mix_vm_clock_add_lapse (get_clock_(vm), ins)
+
+/* Breakpoints handling */
+#define bp_clear_all_(vm) memset (vm->bp, 0, MEM_CELLS_NO_/8)
+#define bp_set_(vm,addr) vm->bp[(addr)>>3] |= 1 << ((addr)&7)
+#define bp_clear_(vm,addr) vm->bp[(addr)>>3] &= ~(1 << ((addr)&7))
+#define bp_is_set_(vm,addr) vm->bp[(addr)>>3] & (1 << ((addr)&7))
+
+/* Instruction handlers */
+typedef gboolean (*ins_handler_t_)(mix_vm_t *,const mix_ins_t *);
+
+extern ins_handler_t_ ins_handlers_[MIX_BYTE_MAX + 1];
+
+
+#endif /* XMIX_VM_H */
+
diff --git a/mixlib/xmix_vm_command.c b/mixlib/xmix_vm_command.c
new file mode 100644
index 0000000..370ffb7
--- /dev/null
+++ b/mixlib/xmix_vm_command.c
@@ -0,0 +1,64 @@
+/* -*-c-*- -------------- xmix_vm_command.c :
+ * Implementation of the functions declared in xmix_vm_command.h
+ * ------------------------------------------------------------------
+ * $Id: xmix_vm_command.c,v 1.4 2005/09/20 19:43:13 jao Exp $
+ * ------------------------------------------------------------------
+ * Copyright (C) 2001, 2002 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "xmix_vm_command.h"
+
+/* configuration keys */
+const gchar *TRACING_KEY_ = "Tracing";
+const gchar *TIMING_KEY_ = "Timing";
+const gchar *EDITOR_KEY_ = "Editor";
+const gchar *ASM_KEY_ = "Assembler";
+const gchar *LOGGING_KEY_ = "Logs";
+
+void
+log_message_ (mix_vm_cmd_dispatcher_t *dis, const gchar *fmt, ...)
+{
+ if (dis && fmt && dis->log_msg && dis->out)
+ {
+ va_list args;
+ va_start (args, fmt);
+ vfprintf (dis->out, fmt, args);
+ fprintf (dis->out, "\n");
+ va_end (args);
+ }
+}
+
+
+extern void
+log_error_ (mix_vm_cmd_dispatcher_t *dis, const gchar *fmt, ...)
+{
+ enum {BUFF_SIZE = 256};
+ static gchar BUFFER[256];
+
+ if (dis && fmt && dis->err)
+ {
+ va_list args;
+ va_start (args, fmt);
+ g_snprintf (BUFFER, BUFF_SIZE, "ERROR: %s\n", fmt);
+ vfprintf (dis->err, BUFFER, args);
+ va_end (args);
+ }
+}
diff --git a/mixlib/xmix_vm_command.h b/mixlib/xmix_vm_command.h
new file mode 100644
index 0000000..ae2c2e7
--- /dev/null
+++ b/mixlib/xmix_vm_command.h
@@ -0,0 +1,102 @@
+/* -*-c-*- ---------------- xmix_vm_command.h :
+ * Private type declarations form mix_vm_command
+ * ------------------------------------------------------------------
+ * $Id: xmix_vm_command.h,v 1.5 2005/09/20 19:43:13 jao Exp $
+ * ------------------------------------------------------------------
+ * Copyright (C) 2001, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef XMIX_VM_COMMAND_H
+#define XMIX_VM_COMMAND_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "mix.h"
+#include "mix_device.h"
+#include "mix_vm.h"
+#include "mix_vm_dump.h"
+#include "mix_eval.h"
+#include "mix_predicate.h"
+#include "mix_vm_command.h"
+
+
+/* configuration keys */
+extern const gchar *TRACING_KEY_;
+extern const gchar *TIMING_KEY_;
+extern const gchar *EDITOR_KEY_;
+extern const gchar *ASM_KEY_;
+extern const gchar *LOGGING_KEY_;
+
+/* 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_;
+
+enum {PRNO_ = MIX_PRED_MEM, HOOKNO_ = MIX_CMD_INVALID};
+
+struct mix_vm_cmd_dispatcher_t
+{
+ mix_vm_t *vm; /* the virtual machine */
+ gboolean result; /* last command's outcome */
+ gchar *program; /* the name of the last loaded program */
+ gchar *editor; /* edit command line template */
+ gchar *assembler; /* compile command line template */
+ 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 */
+ gboolean printtime; /* printing times flag */
+ mix_time_t uptime; /* total running time */
+ mix_time_t laptime; /* last run time */
+ mix_time_t progtime; /* current program running time */
+ GHashTable *commands; /* local commands */
+ GCompletion *completions; /* command completion list */
+ GSList *pre_hooks[HOOKNO_]; /* Pre-command hooks */
+ GSList *post_hooks[HOOKNO_]; /* Post-command hooks */
+ GSList *global_pre; /* global pre-command hook */
+ GSList *global_post; /* global post-command hook */
+ mix_config_t *config; /* externally provided configuration */
+ mix_predicate_t *preds[PRNO_]; /* predicates for conditional breakpoints */
+ GHashTable *mem_preds; /* predicates for memory conditional bps */
+ gboolean log_msg; /* message logging activation flag*/
+};
+
+extern void
+log_message_ (mix_vm_cmd_dispatcher_t *dis, const gchar *fmt, ...);
+
+extern void
+log_error_ (mix_vm_cmd_dispatcher_t *dis, const gchar *fmt, ...);
+
+#define wants_logs_(dis) (dis)->log_msg
+
+#endif /* XMIX_VM_COMMAND_H */
+
diff --git a/mixlib/xmix_vm_handlers.c b/mixlib/xmix_vm_handlers.c
new file mode 100644
index 0000000..ba7052b
--- /dev/null
+++ b/mixlib/xmix_vm_handlers.c
@@ -0,0 +1,1387 @@
+/* -*-c-*- -------------- xmix_vm_handlers.c :
+ * Implementation of the functions declared in xmix_vm_handlers.h
+ * ------------------------------------------------------------------
+ * $Id: xmix_vm_handlers.c,v 1.10 2005/09/20 19:43:13 jao Exp $
+ * ------------------------------------------------------------------
+ * Copyright (C) 2001, 2002, 2003, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#include "xmix_vm_handlers.h"
+
+/* available commands (in the same order as the type enum) */
+mix_vm_command_info_t commands_[] = {
+ { "help", cmd_help_, N_("Display this text"), "help [COMMAND]"},
+ { "load", cmd_load_, N_("Load a MIX code file"), "load FILENAME"},
+ { "edit", cmd_edit_, N_("Edit a MIXAL source file"), "edit [FILENAME]"},
+ { "pedit", cmd_pedit_, N_("Print the external editor command"), "pedit"},
+ { "sedit", cmd_sedit_, N_("Set the external editor command"),
+ "sedit COMMAND (e.g. emacs %s)"},
+ { "compile", cmd_compile_, N_("Compile a MIXAL source file"),
+ "compile [FILENAME]"},
+ { "pasm", cmd_pasm_, N_("Print the compile command"), "pasm"},
+ { "sasm", cmd_sasm_, N_("Set the compile command"),
+ "sasm COMMAND (e.g. mixasm -g -l %s)"},
+ { "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]"},
+ { "pstat", cmd_pstat_, N_("Print current vm status"), "pstat"},
+ { "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"),
+ "sreg 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"},
+ { "sbpr", cmd_sbpr_, N_("Set conditional breakpoint on register change"),
+ "sbpr A | X | J | I[1-6]"},
+ { "cbpr", cmd_cbpr_, N_("Clear conditional breakpoint on register change"),
+ "sbpr A | X | J | I[1-6]"},
+ { "sbpm", cmd_sbpm_, N_("Set conditional breakpoint on mem cell change"),
+ "sbpm ADDRESS"},
+ { "cbpm", cmd_cbpm_, N_("Clear conditional breakpoint on mem cell change"),
+ "cbpm ADDRESS"},
+ { "sbpc", cmd_sbpc_,
+ N_("Set conditional breakpoint on comparison flag change"), "sbpc"},
+ { "cbpc", cmd_cbpc_,
+ N_("Clear conditional breakpoint on comparison flag change"), "cbpc"},
+ { "sbpo", cmd_sbpo_,
+ N_("Set conditional breakpoint on overflow toggled"), "sbpo"},
+ { "cbpo", cmd_cbpo_,
+ N_("Set conditional breakpoint on overflow toggled"), "cbpo"},
+ { "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"},
+ { "strace", cmd_strace_, N_("Turn on/off instruction tracing"),
+ "strace on|off"},
+ { "pbt", cmd_pbt_, N_("Print backtrace of executed instructions"),
+ "pbt [INS_NO] (e.g pbt 5)"},
+ { "stime", cmd_stime_, N_("Turn on/off timing statistics"),
+ "stime on|off"},
+ { "ptime", cmd_ptime_, N_("Print current time statistics"), "ptime"},
+ { "sddir", cmd_sddir_, N_("Set devices directory"),"sddir NEWDIR"},
+ { "pddir", cmd_pddir_, N_("Print current devices directory"),"pddir"},
+ { "slog", cmd_slog_, N_("Turn on/off message logging"), "slog on|off"},
+ { "pprog", cmd_pprog_, N_("Print the current program path"), "pprog"},
+ { "psrc", cmd_psrc_, N_("Print the current program source path"), "psrc"},
+ { "pline", cmd_pline_,
+ N_("Print the current (or a given) program source line"), "pline [LINENO]"},
+ { NULL, NULL, NULL, NULL},
+};
+
+/* trace current instruction */
+static void
+do_trace_ (mix_vm_cmd_dispatcher_t *dis, gboolean error)
+{
+ 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);
+ }
+
+ if (!error)
+ log_message_ (dis, "%d: [%-15s]\t%s", (gint)loc, STRINS, line);
+ else
+ log_error_ (dis, "%d: [%-15s]\t%s", (gint)loc, STRINS, line);
+}
+
+static void
+trace_ (mix_vm_cmd_dispatcher_t *dis)
+{
+ if (wants_logs_ (dis))
+ {
+ do_trace_ (dis, FALSE);
+ }
+}
+
+#define trace_error_(dis) do_trace_ (dis, TRUE)
+
+/* run a program tracing executed instructions */
+static int
+run_and_trace_ (mix_vm_cmd_dispatcher_t *dis)
+{
+ int k = MIX_VM_RUNNING;
+ if (!dis->trace)
+ return mix_vm_run (dis->vm);
+ else while (k == MIX_VM_RUNNING)
+ {
+ trace_ (dis);
+ k = mix_vm_exec_next (dis->vm);
+ }
+ return k;
+}
+
+/* print time statistics */
+static void
+print_time_ (mix_vm_cmd_dispatcher_t *dis)
+{
+ dis->laptime = mix_vm_get_uptime (dis->vm) - dis->uptime;
+ dis->uptime += dis->laptime;
+ dis->progtime += dis->laptime;
+ if (dis->printtime)
+ fprintf
+ (dis->out,
+ _("Elapsed time: %ld /Total program time: %ld (Total uptime: %ld)\n"),
+ dis->laptime, dis->progtime, dis->uptime);
+}
+
+
+/* commands */
+static void
+print_help_ (gpointer key, gpointer val, gpointer data)
+{
+ mix_vm_command_info_t *info = (mix_vm_command_info_t *)val;
+ if (info)
+ fprintf ((FILE *)data, "%-15s%s\n", info->name, info->doc);
+}
+
+gboolean
+cmd_help_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ if (arg && strlen (arg) > 0)
+ {
+ int i;
+ mix_vm_command_info_t *info =
+ (mix_vm_command_info_t *)g_hash_table_lookup
+ (dis->commands, (gpointer)arg);
+ for (i = 0; info == NULL && commands_[i].name; i++)
+ if (!strcmp (commands_[i].name, arg)) info = commands_ + i;
+ if (info)
+ {
+ fprintf (dis->out , _("%-15s%s.\n%-15sUsage: %s\n"),
+ info->name, info->doc, "", info->usage);
+ return TRUE;
+ }
+ fprintf (dis->out, _("No commands match `%s'\n"), arg);
+ return FALSE;
+ }
+ else
+ {
+ int i = 0;
+ fprintf (dis->out, _("Possible commands are:\n"));
+ for (i = 0; commands_[i].name; ++i)
+ fprintf (dis->out, "%-15s%s\n", commands_[i].name, commands_[i].doc);
+ g_hash_table_foreach (dis->commands, print_help_, (gpointer)dis->out);
+ return TRUE;
+ }
+}
+
+gboolean
+cmd_load_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ errno = 0;
+ if (arg == NULL || *arg == '\0')
+ {
+ log_error_ (dis, _("Missing file name"));
+ return FALSE;
+ }
+ mix_eval_remove_symbols_from_table (dis->eval,
+ mix_vm_get_symbol_table (dis->vm));
+ if (!mix_vm_load_file (dis->vm, arg) )
+ {
+ log_error_ (dis, _("Cannot load %s: "), arg);
+ if ( errno == 0 )
+ log_error_ (dis, _("Wrong file format"));
+ else
+ log_error_ (dis, "%s", strerror (errno));
+ return FALSE;
+ }
+
+ if (dis->program != arg)
+ {
+ if (dis->program) g_free (dis->program);
+ dis->program = mix_file_complete_name (arg, MIX_CODE_DEFEXT);
+ }
+
+ mix_eval_set_symbols_from_table (dis->eval,
+ mix_vm_get_symbol_table (dis->vm));
+ if (wants_logs_ (dis))
+ log_message_ (dis, _("Program loaded. Start address: %d"),
+ mix_vm_get_prog_count (dis->vm));
+
+ dis->laptime = dis->progtime = 0;
+ return TRUE;
+}
+
+gboolean
+cmd_edit_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ if (dis->editor == NULL)
+ {
+ log_error_ (dis, _("Editor not specified (use sedit)"));
+ return FALSE;
+ }
+ if (!arg || *arg == '\0') arg = mix_vm_cmd_dispatcher_get_src_file_path (dis);
+ if (!arg)
+ {
+ log_error_ (dis, _("MIXAL source file path not found"));
+ return FALSE;
+ }
+ else
+ {
+ gchar *cmd = g_strdup_printf (dis->editor, arg);
+ if (wants_logs_ (dis)) log_message_ (dis, cmd);
+ system (cmd);
+ if (wants_logs_ (dis)) log_message_ (dis, _(" ...done"));
+ g_free (cmd);
+ return TRUE;
+ }
+}
+
+gboolean
+cmd_compile_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ if (dis->assembler == NULL)
+ {
+ log_error_ (dis, _("MIX assembler not specified (use sasm)"));
+ return FALSE;
+ }
+ if (!arg || *arg == '\0') arg = mix_vm_cmd_dispatcher_get_src_file_path (dis);
+ if (!arg)
+ {
+ log_error_ (dis, _("MIXAL source file path not found"));
+ return FALSE;
+ }
+ else
+ {
+ gchar *cmd = g_strdup_printf (dis->assembler, arg);
+ if (wants_logs_ (dis)) log_message_ (dis, cmd);
+ if (system (cmd) == EXIT_SUCCESS && wants_logs_ (dis))
+ log_message_ (dis, _("Successful compilation"));
+ g_free (cmd);
+ return TRUE;
+ }
+}
+
+gboolean
+cmd_run_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ if (arg != NULL && *arg != '\0' && cmd_load_ (dis, arg) != TRUE)
+ return FALSE;
+
+ if (mix_vm_is_halted (dis->vm)) cmd_load_ (dis, dis->program);
+
+ if (wants_logs_ (dis)) log_message_ (dis, _("Running ..."));
+
+ switch (run_and_trace_ (dis))
+ {
+ case MIX_VM_HALT:
+ if (wants_logs_ (dis)) log_message_ (dis, _("... done"));
+ break;
+ case MIX_VM_BREAK:
+ if (wants_logs_ (dis))
+ {
+ gulong line = mix_vm_get_break_lineno (dis->vm);
+ if (line != 0)
+ log_message_
+ (dis, _("... stopped: breakpoint at line %ld (address %d)"),
+ line, mix_vm_get_prog_count (dis->vm));
+ else
+ log_message_ (dis, _("... stopped: breakpoint at address %d"),
+ mix_vm_get_prog_count (dis->vm));
+ }
+ break;
+ case MIX_VM_COND_BREAK:
+ if (wants_logs_ (dis))
+ {
+ gulong line = mix_vm_get_break_lineno (dis->vm);
+ if (line != 0)
+ log_message_ (dis, _("... stopped: %s (line %ld, address %d)"),
+ mix_vm_get_last_breakpoint_message (dis->vm),
+ line, mix_vm_get_prog_count (dis->vm));
+ else
+ log_message_ (dis, _("... stopped: %s (address %d)"),
+ mix_vm_get_last_breakpoint_message (dis->vm),
+ mix_vm_get_prog_count (dis->vm));
+ }
+ break;
+ case MIX_VM_ERROR:
+ log_error_ (dis, _("%s:"), mix_vm_get_last_error_string (dis->vm));
+ trace_error_ (dis);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ if (wants_logs_ (dis)) print_time_ (dis);
+
+ return TRUE;
+}
+
+gboolean
+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')
+ {
+ log_error_ (dis, _("Invalid argument: %s"), arg);
+ return FALSE;
+ }
+ ins_no = atoi (arg);
+ }
+
+ if (mix_vm_is_halted (dis->vm)) cmd_load_ (dis, dis->program);
+
+ while ( ins_no-- > 0 )
+ {
+ if (dis->trace) trace_ (dis);
+ k = mix_vm_exec_next (dis->vm);
+ if (k == MIX_VM_HALT)
+ {
+ if (wants_logs_ (dis))
+ log_message_(dis, _("End of program reached at address %d"),
+ mix_vm_get_prog_count (dis->vm));
+ break;
+ }
+ else if (k == MIX_VM_ERROR)
+ {
+ log_error_ (dis, _("%s:"), mix_vm_get_last_error_string (dis->vm));
+ trace_error_ (dis);
+ break;
+ }
+ }
+ if (wants_logs_ (dis)) print_time_ (dis);
+
+ return TRUE;
+}
+
+gboolean
+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;
+}
+
+gboolean
+cmd_psym_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ gboolean result = FALSE;
+ const mix_symbol_table_t *table = mix_eval_symbol_table (dis->eval);
+ if ( table == NULL )
+ log_error_ (dis, _("Symbol table not available"));
+ else if (arg != NULL && *arg != '\0')
+ {
+ if ( mix_symbol_table_is_defined (table, arg) )
+ {
+ mix_word_print_to_file (mix_symbol_table_value (table, arg),
+ NULL, dis->out);
+ putc ('\n', dis->out);
+ result = TRUE;
+ }
+ else
+ fprintf (dis->out, _("%s: symbol not defined\n"), arg);
+ }
+ else
+ {
+ mix_symbol_table_print (table, MIX_SYM_ROWS, dis->out, TRUE);
+ result = TRUE;
+ }
+
+ return result;
+}
+
+gboolean
+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 )
+ {
+ log_error_ (dis, _("Invalid I index: %d"), i);
+ return FALSE;
+ }
+ mix_dump_context_add_opt (dis->dump, opt[i]);
+ }
+ }
+ break;
+ default:
+ log_error_ (dis, _("Invalid argument: %s"), arg);
+ return FALSE;
+ }
+ mix_vm_dump (dis->vm, dis->dump);
+ return TRUE;
+}
+
+gboolean
+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;
+}
+
+gboolean
+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;
+}
+
+gboolean
+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 )
+ {
+ log_error_ (dis, _("Missing memory address"));
+ return FALSE;
+ }
+ 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] == '-')
+ {
+ gchar *narg;
+ arg[i++] = '\0';
+ begin = atol (arg);
+ narg = arg + i;
+ i = 0;
+ while (isdigit (narg[i]))
+ i++;
+ while (isspace (narg[i]))
+ i++;
+ if (narg[i] != '\0')
+ error = TRUE;
+ else
+ end = atol (narg);
+ }
+ else
+ error = TRUE;
+
+ if (error)
+ {
+ log_error_ (dis, _("Invalid argument: %s"), arg);
+ }
+ else if ( end < begin || end > MIX_VM_CELL_NO - 1 )
+ {
+ log_error_ (dis, _("Invalid range: %ld-%ld"), begin, end);
+ error = TRUE;
+ }
+ 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 !error;
+}
+
+gboolean
+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)
+ {
+ log_error_ (dis, _("Invalid argument: %s"), arg);
+ }
+
+ return ok;
+}
+
+gboolean
+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)
+ {
+ log_error_ (dis, _("Invalid argument: %s"), arg);
+ }
+
+ return ok;
+}
+
+gboolean
+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)
+ {
+ log_error_ (dis, _("Invalid argument: %s"), arg);
+ }
+
+ return ok;
+}
+
+gboolean
+cmd_smem_ (mix_vm_cmd_dispatcher_t *dis, const gchar *carg)
+{
+ gboolean ok = (strlen (carg) > 2 && isdigit (carg[0]));
+ glong addr = -1;
+ glong value = 0;
+ 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
+ {
+ log_error_ (dis, _("Invalid argument: %s"), arg);
+ }
+ if (arg) g_free (arg);
+
+ return ok;
+}
+
+gboolean
+cmd_ssym_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ gboolean result = FALSE;
+ if (arg == NULL || strlen(arg) == 0)
+ {
+ log_error_ (dis, _("Missing arguments"));
+ }
+ 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));
+ result = TRUE;
+ }
+ }
+ else
+ {
+ log_error_ (dis, _("Wrong argument number"));
+ }
+ g_free (a);
+ }
+ return result;
+}
+
+gboolean
+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')
+ {
+ log_error_ (dis, _("Invalid argument: %s"), arg);
+ return FALSE;
+ }
+ lineno = atol (arg);
+ switch (k = mix_vm_set_breakpoint (dis->vm, lineno))
+ {
+ case MIX_VM_BP_INV_LINE:
+ log_error_ (dis, _("Line number %ld too high"), lineno);
+ break;
+ case MIX_VM_BP_ERROR:
+ log_error_ (dis, _("Could not set breakpoint: internal error"));
+ break;
+ case MIX_VM_BP_NDEBUG:
+ log_error_ (dis, _("Could not set breakpoint: no debug info available"),
+ dis->err);
+ break;
+ default:
+ if (wants_logs_ (dis))
+ log_message_ (dis, _("Breakpoint set at line %ld"), k);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+gboolean
+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')
+ {
+ log_error_ (dis, _("Invalid argument: %s"), arg);
+ return FALSE;
+ }
+ address = atol (arg);
+ switch (mix_vm_set_breakpoint_address (dis->vm, address))
+ {
+ case MIX_VM_BP_INV_ADDRESS:
+ log_error_ (dis, _("Invalid address %ld"), address);
+ break;
+ case MIX_VM_BP_ERROR:
+ log_error_ (dis, _("Could not set breakpoint: internal error"));
+ break;
+ default:
+ if (wants_logs_ (dis))
+ log_message_ (dis, _("Breakpoint set at address %ld"), address);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+gboolean
+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')
+ {
+ log_error_ (dis, _("Invalid argument: %s"), arg);
+ return FALSE;
+ }
+ lineno = atol (arg);
+ switch (mix_vm_clear_breakpoint (dis->vm, lineno))
+ {
+ case MIX_VM_BP_INV_LINE:
+ log_error_ (dis, _("No breakpoint set at line %ld"), lineno);
+ break;
+ case MIX_VM_BP_ERROR:
+ log_error_ (dis, _("Could not set breakpoint: internal error"));
+ break;
+ case MIX_VM_BP_NDEBUG:
+ log_error_ (dis, _("No debug info available"));
+ break;
+ case MIX_VM_BP_OK:
+ if (wants_logs_ (dis))
+ log_message_ (dis, _("Breakpoint cleared at line %ld"), lineno);
+ return TRUE;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ return FALSE;
+}
+
+gboolean
+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')
+ {
+ log_error_ (dis, _("Invalid argument: %s"), arg);
+ return FALSE;
+ }
+ address = atol (arg);
+ switch (mix_vm_clear_breakpoint_address (dis->vm, address))
+ {
+ case MIX_VM_BP_INV_ADDRESS:
+ log_error_ (dis, _("Invalid address %ld"), address);
+ break;
+ case MIX_VM_BP_ERROR:
+ log_error_ (dis, _("Could not clear breakpoint: internal error"));
+ break;
+ default:
+ if (wants_logs_ (dis))
+ log_message_ (dis, _("Breakpoint cleared at address %ld"), address);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+gboolean
+cmd_cabp_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ if (strlen (arg) != 0)
+ {
+ log_error_ (dis, _("Unexpected argument: %s"), arg);
+ return FALSE;
+ }
+ mix_vm_clear_all_breakpoints (dis->vm);
+ return TRUE;
+}
+
+gboolean
+cmd_weval_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ if ( strlen (arg) == 0 )
+ {
+ log_error_ (dis, _("Missing expression"));
+ return FALSE;
+ }
+
+ 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);
+ return TRUE;
+ }
+ 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 FALSE;
+ }
+}
+
+gboolean
+cmd_w2d_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ if ( strlen (arg) == 0 )
+ {
+ log_error_ (dis, _("Missing expression"));
+ return FALSE;
+ }
+ 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]))
+ {
+ log_error_ (dis, _("Incorrect byte specification: %s"), b);
+ success = FALSE;
+ b = NULL;
+ }
+ else
+ {
+ bytes[k++] = mix_byte_new (atoi (b));
+ b = strtok (NULL, " \t");
+ }
+ }
+ if (success)
+ {
+ if (strtok (NULL, "\t") != NULL)
+ {
+ log_error_ (dis,
+ _("The expression %s does not fit in a word"), arg);
+ success = FALSE;
+ }
+ 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 success;
+ }
+}
+
+gboolean
+cmd_strace_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ static const gchar *ON = "on";
+ static const gchar *OFF = "off";
+ if (!arg || !strlen (arg))
+ {
+ log_error_ (dis, _("Missing argument"));
+ }
+ else if (!strcmp (arg, ON))
+ {
+ dis->trace = TRUE;
+ if (dis->config) mix_config_update (dis->config, TRACING_KEY_, ON);
+ }
+ else if (!strcmp (arg, OFF))
+ {
+ dis->trace = FALSE;
+ if (dis->config) mix_config_update (dis->config, TRACING_KEY_, OFF);
+ }
+ else
+ log_error_ (dis, _("Wrong argument: "), arg);
+ return TRUE;
+}
+
+gboolean
+cmd_stime_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ static const gchar *ON = "on";
+ static const gchar *OFF = "off";
+ if (!arg || !strlen (arg))
+ {
+ log_error_ (dis, _("Missing argument"));
+ }
+ else if (!strcmp (arg, ON))
+ {
+ dis->printtime = TRUE;
+ if (dis->config) mix_config_update (dis->config, TIMING_KEY_, ON);
+ }
+ else if (!strcmp (arg, OFF))
+ {
+ dis->printtime = FALSE;
+ if (dis->config) mix_config_update (dis->config, TIMING_KEY_, OFF);
+ }
+ else
+ log_error_ (dis, _("Wrong argument: "), arg);
+ return TRUE;
+}
+
+gboolean
+cmd_ptime_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ print_time_ (dis);
+ return TRUE;
+}
+
+gboolean
+cmd_pedit_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ const gchar *ed = mix_vm_cmd_dispatcher_get_editor (dis);
+ if (dis)
+ fprintf (dis->out, _("Edit command: %s\n"), ed);
+ else
+ fprintf (dis->out, _("Edit command not set (use sedit)\n"));
+ return TRUE;
+}
+
+gboolean
+cmd_sedit_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ if (!arg || !strlen (arg))
+ {
+ log_error_ (dis, _("Missing argument"));
+ return FALSE;
+ }
+ mix_vm_cmd_dispatcher_set_editor (dis, arg);
+ return TRUE;
+}
+
+gboolean
+cmd_pasm_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ const gchar *ed = mix_vm_cmd_dispatcher_get_assembler (dis);
+ if (dis)
+ fprintf (dis->out, _("Compile command: %s\n"), ed);
+ else
+ fprintf (dis->out, _("Compile command not set (use sasm)\n"));
+ return TRUE;
+}
+
+gboolean
+cmd_sasm_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ if (!arg || !strlen (arg))
+ {
+ log_error_ (dis, _("Missing argument"));
+ return FALSE;
+ }
+ mix_vm_cmd_dispatcher_set_assembler (dis, arg);
+ return TRUE;
+}
+
+gboolean
+cmd_sddir_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ if (!arg || !strlen (arg)) log_error_ (dis, _("Missing argument"));
+ else if (mix_device_set_dir (arg) && dis->config)
+ mix_config_set_devices_dir (dis->config, arg);
+ return TRUE;
+}
+
+gboolean
+cmd_pddir_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ fprintf (dis->out, _("Device directory: %s\n"), mix_device_get_dir ());
+ return TRUE;
+}
+
+static const gint INVALID_REG_ = -2;
+
+static mix_predicate_type_t
+get_reg_pred_ (const gchar *arg)
+{
+ mix_predicate_type_t pred = INVALID_REG_;
+
+ switch (*arg)
+ {
+ case 'A':
+ pred = MIX_PRED_REG_A;
+ break;
+ case 'X':
+ pred = MIX_PRED_REG_X;
+ break;
+ case 'J':
+ pred = MIX_PRED_REG_J;
+ break;
+ case 'I':
+ {
+ if ( strlen (arg) == 2 )
+ {
+ int i = arg[1] - '1';
+ if (i >= 0 && i < 6)
+ pred = MIX_PRED_REG_I1 - 1 + i;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return pred;
+}
+
+gboolean
+cmd_sbpr_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ mix_predicate_type_t pred = get_reg_pred_ (arg);
+ if (pred != INVALID_REG_)
+ {
+ mix_vm_set_conditional_breakpoint (dis->vm, dis->preds[pred]);
+ if (wants_logs_ (dis))
+ log_message_ (dis,
+ _("Conditional breakpoint on r%s change set"), arg);
+ return TRUE;
+ }
+ else
+ {
+ log_error_ (dis, _("Invalid argument %s"), arg);
+ return FALSE;
+ }
+}
+
+gboolean
+cmd_cbpr_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ mix_predicate_type_t pred = get_reg_pred_ (arg);
+ if (pred != INVALID_REG_)
+ {
+ if (mix_vm_clear_conditional_breakpoint (dis->vm, dis->preds[pred]))
+ {
+ if (wants_logs_(dis))
+ log_message_ (dis,
+ _("Conditional breakpoint on r%s change removed"),
+ arg);
+ }
+ else
+ log_error_ (dis, _("No breakpoint set on r%s change"), arg);
+ return TRUE;
+ }
+ else
+ {
+ log_error_ (dis, _("Invalid argument %s"), arg);
+ return FALSE;
+ }
+}
+
+gboolean
+cmd_sbpm_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ gint add = atoi (arg);
+ gpointer key, value;
+ if (add < 0 || add > MIX_VM_CELL_NO)
+ {
+ log_error_ (dis, _("Invalid memory address: %s"), arg);
+ return FALSE;
+ }
+ if (!g_hash_table_lookup_extended (dis->mem_preds, GINT_TO_POINTER (add),
+ &key, &value))
+ {
+ mix_predicate_t *new_pred = mix_predicate_new (MIX_PRED_MEM);
+ mix_predicate_set_mem_address (new_pred, add);
+ g_hash_table_insert (dis->mem_preds,
+ GINT_TO_POINTER (add), (gpointer)new_pred);
+ mix_vm_set_conditional_breakpoint (dis->vm, new_pred);
+ }
+ if (wants_logs_ (dis))
+ log_message_ (dis, _("Conditional breakpoint on mem cell no. %d set"),
+ add);
+ return TRUE;
+}
+
+gboolean
+cmd_cbpm_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ gint add = atoi (arg);
+ gpointer key, value;
+ if (add < 0 || add > MIX_VM_CELL_NO)
+ {
+ log_error_ (dis, _("Invalid memory address: %s"), arg);
+ return FALSE;
+ }
+ if (g_hash_table_lookup_extended (dis->mem_preds, GINT_TO_POINTER (add),
+ &key, &value))
+ {
+ g_hash_table_remove (dis->mem_preds, key);
+ mix_vm_clear_conditional_breakpoint (dis->vm, (mix_predicate_t *)value);
+ mix_predicate_delete ((mix_predicate_t *)value);
+ if (wants_logs_ (dis))
+ log_message_ (dis,
+ _("Conditional breakpoint on mem cell no. %d removed"),
+ add);
+ }
+ else
+ {
+ log_error_ (dis, _("No conditional breakpoint set at address %d"),
+ add);
+ }
+ return TRUE;
+}
+
+gboolean
+cmd_sbpo_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ if (arg && strlen (arg))
+ log_error_ (dis, _("Unexpected argument: %s"), arg);
+ else
+ {
+ mix_vm_set_conditional_breakpoint (dis->vm, dis->preds[MIX_PRED_OVER]);
+ if (wants_logs_ (dis))
+ log_message_ (dis,
+ _("Conditional breakpoint on overflow toggled set"));
+ }
+ return TRUE;
+}
+
+gboolean
+cmd_cbpo_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ if (arg && strlen (arg))
+ log_error_ (dis, _("Unexpected argument: %s"), arg);
+ else
+ {
+ if (mix_vm_clear_conditional_breakpoint
+ (dis->vm, dis->preds[MIX_PRED_OVER]))
+ {
+ if (wants_logs_ (dis))
+ log_message_
+ (dis, _("Conditional breakpoint on overflow toggled removed."));
+ }
+ else
+ log_error_ (dis, _("No breakpoint set on overflow toggle"));
+ }
+ return TRUE;
+}
+
+gboolean
+cmd_sbpc_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ if (arg && strlen (arg))
+ log_error_ (dis, _("Unexpected argument: %s"), arg);
+ else
+ {
+ mix_vm_set_conditional_breakpoint (dis->vm, dis->preds[MIX_PRED_CMP]);
+ if (wants_logs_ (dis))
+ log_message_
+ (dis, _("Conditional breakpoint on comparison flag changed set"));
+ }
+ return TRUE;
+}
+
+gboolean
+cmd_cbpc_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ if (arg && strlen (arg))
+ log_error_ (dis, _("Unexpected argument: %s"), arg);
+ else
+ {
+ if (mix_vm_clear_conditional_breakpoint
+ (dis->vm, dis->preds[MIX_PRED_CMP]))
+ {
+ if (wants_logs_ (dis))
+ log_message_
+ (dis,
+ _("Conditional breakpoint on comparison flag changed removed."));
+ }
+ else
+ log_error_ (dis, _("No breakpoint set on comparison flag change"));
+ }
+ return TRUE;
+}
+
+gboolean
+cmd_pbt_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ enum {SIZE = 256};
+ static gchar BUFFER[SIZE];
+ gint no = atoi (arg);
+ gint k = 0, address;
+ guint line;
+ const mix_src_file_t *file = mix_vm_get_src_file (dis->vm);
+ char *name =
+ file ? g_path_get_basename (mix_src_file_get_path (file)) : NULL;
+
+ const GSList *add = mix_vm_get_backtrace (dis->vm);
+ while (add && (no == 0 || k < no))
+ {
+ BUFFER[0] = '\0';
+ address = GPOINTER_TO_INT (add->data);
+ line = mix_vm_get_address_lineno (dis->vm, address);
+ if (line && file)
+ {
+ int j = 0;
+ g_snprintf (BUFFER, SIZE, "%s", mix_src_file_get_line (file, line));
+ while (!isspace (BUFFER[j])) j++;
+ BUFFER[j] = '\0';
+ }
+ if (strlen (BUFFER) == 0) g_snprintf (BUFFER, SIZE, "%d", address);
+ fprintf (dis->out, "#%d\t%s\tin %s%s:%d\n", k, BUFFER, name,
+ MIX_SRC_DEFEXT, line);
+ ++k;
+ add = add->next;
+ }
+ return TRUE;
+}
+
+gboolean
+cmd_slog_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ static const gchar *ON = "on";
+ static const gchar *OFF = "off";
+ if (arg && !strcmp (arg, ON))
+ {
+ dis->log_msg = TRUE;
+ if (dis->config) mix_config_update (dis->config, LOGGING_KEY_, ON);
+ }
+ else if (arg && !strcmp (arg, OFF))
+ {
+ dis->log_msg = FALSE;
+ if (dis->config) mix_config_update (dis->config, LOGGING_KEY_, OFF);
+ }
+ else
+ log_error_ (dis, _("Wrong argument: "), arg);
+ return TRUE;
+}
+
+gboolean
+cmd_pprog_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ const gchar *path = mix_vm_cmd_dispatcher_get_program_path (dis);
+ fprintf (dis->out, path? path : _("No program currently loaded"));
+ fprintf (dis->out, "\n");
+ return (path != NULL);
+}
+
+gboolean
+cmd_psrc_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ const gchar *path = mix_vm_cmd_dispatcher_get_src_file_path (dis);
+ fprintf (dis->out, path? path : _("No program currently loaded\n"));
+ fprintf (dis->out, "\n");
+ return (path != NULL);
+}
+
+gboolean
+cmd_pline_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ gulong line = 0;
+ const gchar *txt;
+
+ if (arg && strlen (arg)) line = atoi (arg);
+
+ if (line < 0)
+ {
+ log_error_ (dis, _("Invalid argument"));
+ return FALSE;
+ }
+
+ if (line == 0)
+ line = mix_vm_cmd_dispatcher_get_src_file_lineno (dis);
+
+ if (line == 0)
+ txt = "No such line (debug info not available)\n";
+ else
+ txt = mix_vm_cmd_dispatcher_get_src_file_line (dis, line, FALSE);
+
+ if (txt == NULL || strlen (txt) == 0) txt = "No such line\n";
+
+ fprintf (dis->out, "Line %ld: %s\n", line, txt);
+
+ return TRUE;
+}
+
+gboolean
+cmd_pstat_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ static const gchar *MSGS[MIX_VM_EMPTY + 1] = {
+ N_("Error loading or executing file"),
+ N_("Execution stopped: breakpoint encountered"),
+ N_("Execution stopped: conditional breakpoint encountered"),
+ N_("Program successfully terminated"),
+ N_("Execution stopped"),
+ N_("Program successfully loaded"),
+ N_("No program loaded")
+ };
+ mix_vm_status_t status =
+ mix_vm_get_run_status (mix_vm_cmd_dispatcher_get_vm (dis));
+ fprintf (dis->out, "VM status: %s\n", MSGS[status]);
+ return TRUE;
+}
diff --git a/mixlib/xmix_vm_handlers.h b/mixlib/xmix_vm_handlers.h
new file mode 100644
index 0000000..b3258f9
--- /dev/null
+++ b/mixlib/xmix_vm_handlers.h
@@ -0,0 +1,87 @@
+/* -*-c-*- ---------------- xmix_vm_handlers.h :
+ * mix_vm_cmd_dispatcher command handlers
+ * ------------------------------------------------------------------
+ * $Id: xmix_vm_handlers.h,v 1.4 2005/09/20 19:43:13 jao Exp $
+ * ------------------------------------------------------------------
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef XMIX_VM_HANDLERS_H
+#define XMIX_VM_HANDLERS_H
+
+#include "xmix_vm_command.h"
+
+/* command handlers */
+#define DEC_FUN(name) \
+ extern gboolean 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 (strace_);
+DEC_FUN (stime_);
+DEC_FUN (ptime_);
+DEC_FUN (edit_);
+DEC_FUN (compile_);
+DEC_FUN (pedit_);
+DEC_FUN (sedit_);
+DEC_FUN (pasm_);
+DEC_FUN (sasm_);
+DEC_FUN (pddir_);
+DEC_FUN (sddir_);
+DEC_FUN (sbpr_);
+DEC_FUN (sbpm_);
+DEC_FUN (sbpc_);
+DEC_FUN (sbpo_);
+DEC_FUN (cbpr_);
+DEC_FUN (cbpm_);
+DEC_FUN (cbpc_);
+DEC_FUN (cbpo_);
+DEC_FUN (pbt_);
+DEC_FUN (slog_);
+DEC_FUN (pprog_);
+DEC_FUN (psrc_);
+DEC_FUN (pline_);
+DEC_FUN (pstat_);
+
+/* default command structure */
+extern mix_vm_command_info_t commands_[];
+
+
+#endif /* XMIX_VM_HANDLERS_H */
+