File: driver.c

package info (click to toggle)
mixal 1.08-5
  • links: PTS
  • area: main
  • in suites: potato
  • size: 208 kB
  • ctags: 296
  • sloc: ansic: 1,597; makefile: 87; sh: 12; awk: 10
file content (200 lines) | stat: -rw-r--r-- 4,848 bytes parent folder | download | duplicates (5)
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
	    ;
    }
}