1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
|
/* MIX simulator, copyright 1994 by Darius Bacon */
#include "mix.h"
#include "asm.h"
#include "driver.h"
#include "parse.h"
#include "symbol.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* --- Attributes of the current instruction or directive --- */
static char label[max_identifier_length+1];
static Byte the_C, default_F;
static Flag F_must_be_default;
/* --- Handlers for each type of directive --- */
/* Each must parse the operand field; see assemble_line(). */
static void do_opcode(void)
{
assemble(set_byte(the_C, 5, parse_operand(F_must_be_default, default_F)));
}
static void do_con(void)
{
assemble(parse_W());
}
static void do_alf(void)
{
error("Use CON instead of ALF");
}
static void do_end(void)
{
set_entry_point(cell_to_address(parse_W()));
}
static void do_equ(void)
{
define_symbol(string_to_symbol(label), parse_W());
if (VERBOSE) {
print_cell(symbol_value(string_to_symbol(label)));
printf("\n");
}
}
static void do_orig(void)
{
here = cell_to_address(parse_W());
}
/* --- The opcode/directive table --- */
typedef const struct OpDef {
const char *name;
void (*handler)(void);
Byte C, F;
Flag is_extended;
} OpDef;
#define extended true
#define def_opcode(name, C, F, is_ext) { name, do_opcode, C, F, is_ext }
#define def_directive(name, handler) { name, handler, 0, 0, 0 }
static OpDef op_table[] = {
#include "ops.inc"
};
/* --- The main driver --- */
static int delta_C;
/* Compare strings a la strcmp, ignoring case, and allowing a `-' in
pattern to stand for any general register.
Pre: pattern is all lowercase and contains at most one `-'.
Post: if they match, delta_C is set to the register number of the
register. (delta_C unspecified if there was no `-'.) */
static int compare_mnemonics(const char *datum, const char *pattern)
{
unsigned my_delta_C = 0;
for (; *pattern; ++pattern, ++datum) {
char d = tolower(*datum);
if (*pattern == '-') {
static const char legals[] = "a123456x";
const char *temp = strchr(legals, d);
if (temp)
my_delta_C = temp - legals;
else
break;
} else if (*pattern == d)
;
else
break;
}
{
int result = tolower(*datum) - *pattern;
if (result == 0)
delta_C = my_delta_C;
return result;
}
}
typedef void (*Handler)(void);
/* I'd prefer something faster than a linear search here. Maybe have
op2c.awk expand out the `-' characters so we only need look for a
string equal to mnemonic. */
static Handler lookup_mnemonic(const char *mnemonic)
{
unsigned i;
delta_C = 0;
for (i = 0; i < sizeof op_table / sizeof op_table[0]; ++i) {
if (compare_mnemonics(mnemonic, op_table[i].name) == 0) {
the_C = op_table[i].C + delta_C;
default_F = op_table[i].F;
F_must_be_default = op_table[i].is_extended;
return op_table[i].handler;
}
}
return NULL;
}
static const char *skip_blanks(const char *s)
{
return s + strspn(s, " \t");
}
typedef const char *const_char_ptr;
static void eat_identifier(char *buffer, const_char_ptr *s)
{
const char *scan = buffer;
size_t size, truncated_size;
for (scan = *s; !isspace (*scan) && *scan != '\0'; ++scan)
;
size = scan - *s;
{ /* ensure it's a legal identifier */
Flag alpha = false, non_alphanum = false;
for (scan = *s; scan < *s + size; ++scan) {
if (isalpha(*scan))
alpha = true;
else if (!isalnum (*scan))
non_alphanum = true;
}
if ((!alpha && size != 0) || non_alphanum) {
error ("Ill-formed label or mnemonic: %*.*s", size, size, *s);
buffer[0] = '\0';
*s += size;
return;
}
}
if (max_identifier_length < size) {
warn ("Truncated long label or mnemonic: %*.*s", size, size, *s);
truncated_size = max_identifier_length;
} else
truncated_size = size;
memcpy(buffer, *s, truncated_size);
buffer[truncated_size] = '\0';
*s += size;
}
void assemble_line(const char *line)
{
char mnemonic[max_identifier_length+1];
const char *scan = line;
if (*skip_blanks(scan) == '*') /* the comment character */
return;
eat_identifier(label, &scan); /* eat label if any */
scan = skip_blanks(scan);
eat_identifier(mnemonic, &scan); /* eat mnemonic */
scan = skip_blanks(scan);
setup_scanner(scan); /* prepare to parse operand field */
{
Handler handler = lookup_mnemonic(mnemonic);
if (handler != do_equ && label[0] != '\0')
define_symbol(string_to_symbol(label), address_to_cell(here));
if (handler) {
handler();
done_parsing(); /* this goes here since *all* handlers parse an operand field */
} else if (mnemonic[0] != '\0')
error("Unknown instruction: %s", mnemonic);
else
;
}
}
|