summaryrefslogtreecommitdiff
path: root/util.c
blob: e291f901ed865c9896341e8d164780b91ec659d0 (plain)
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
201
202
203
204
205
206
207
208
209
210
211
#include <string.h>
#include <ctype.h>

#include "instruction.h"
#include "lex.h"

/**
 * Keywords
 */
static struct {
	int look;
	const char *str;
} keywords[] = {
	{ .look = 0, .str = "declare" },
	{ .look = 0, .str = "byte"    },
	{ .look = 0, .str = "bytes"   },
	{ .look = 0, .str = "word"    },
	{ .look = 0, .str = "words"   },
	{ .look = 0, .str = "base"    },
	{ .str = NULL },
};

/**
  * Human-readable descriptions for tokens
  */
static struct {
	enum TOKEN_TYPE look;
	const char *str;
} token_to_desc[] = {
	{ .look = TOKEN_REGISTER, .str = "register"            },
	{ .look = TOKEN_NUMERIC , .str = "numeric literal"     },
	{ .look = TOKEN_KEYWORD , .str = "keyword"             },
	{ .look = TOKEN_STRING  , .str = "string literal"      },
	{ .look = TOKEN_COMMA   , .str = "comma"               },
	{ .look = TOKEN_LABEL   , .str = "label"               },
	{ .look = TOKEN_IDENT   , .str = "identifier"          },
	{ .look = TOKEN_DOT     , .str = "assembler directive" },
	{ .look = TOKEN_EOL     , .str = "end of line"         },
	{ .look = TOKEN_EOF     , .str = "end of file"         },
	{ .str = NULL },
};

/**
 * ALU operation to assembly instruction
 */
static struct {
	enum OPER look;
	const char *str;
} oper_to_asm[] = {
	{ .look = OPER_ADD, .str = "add" },
	{ .look = OPER_SUB, .str = "sub" },
	{ .look = OPER_SHL, .str = "shl" },
	{ .look = OPER_SHR, .str = "shr" },
	{ .look = OPER_AND, .str = "and" },
	{ .look = OPER_OR , .str = "or"  },
	{ .look = OPER_XOR, .str = "xor" },
	{ .look = OPER_MUL, .str = "mul" },
	{ .str = NULL },
};

/**
 * Jump condition to jump assembly instruction
 */
static struct {
	enum JCOND look;
	const char *str;
} j_to_asm[] = {
	{ .look = JB_UNCOND , .str = "jmp"  },
	{ .look = JB_NEVER  , .str = "jn"   },
	{ .look = JB_ZERO   , .str = "jz"   },
	{ .look = JB_NZERO  , .str = "jnz"  },
	{ .look = JB_CARRY  , .str = "jc"   },
	{ .look = JB_NCARRY , .str = "jnc"  },
	{ .look = JB_CARRYZ , .str = "jcz"  },
	{ .look = JB_NCARRYZ, .str = "jncz" },
	{ .str = NULL },
};

/**
 * Jump condition to branch assembly instruction
 */
static struct {
	enum JCOND look;
	const char *str;
} b_to_asm[] = {
	{ .look = JB_UNCOND , .str = "bra"  },
	{ .look = JB_NEVER  , .str = "bn"   },
	{ .look = JB_ZERO   , .str = "bz"   },
	{ .look = JB_NZERO  , .str = "bnz"  },
	{ .look = JB_CARRY  , .str = "bc"   },
	{ .look = JB_NCARRY , .str = "bnc"  },
	{ .look = JB_CARRYZ , .str = "bcz"  },
	{ .look = JB_NCARRYZ, .str = "bncz" },
	{ .str = NULL },
};

/**
 * Register number to assembly representation
 */
static struct {
	enum REG look;
	const char *str;
} reg_to_asm[] = {
	{ .look = REG_0, .str = "$0" },
	{ .look = REG_1, .str = "$1" },
	{ .look = REG_2, .str = "$2" },
	{ .look = REG_3, .str = "$3" },
	{ .look = REG_4, .str = "$4" },
	{ .look = REG_5, .str = "$5" },
	{ .look = REG_6, .str = "$6" },
	{ .look = REG_H, .str = "$H" },
	/* non-preferred aliases: */
	{ .look = REG_0, .str = "$z" },
	{ .look = REG_H, .str = "$7" },
	{ .str = NULL },
};

/* Generates a function that takes an enum value from the given type and looks
 * it up in the given lookup table, returning a string that matches it from
 * the table, or NULL if no such string exists */
#define GENERATE_STR_LOOKUP_FUNC(name, lookup, type) \
const char* name(type x) { \
	size_t i = 0; \
	for (i = 0; lookup[i].str; i++) \
		if (lookup[i].look == x) \
			return lookup[i].str; \
	return NULL; \
}

/* Inverse of GENERATE_STR_LOOKUP_FUNC - this generates a function that takes
 * a string and places in *res an enum value matching that string as entered
 * in the given lookup table.
 * Returns zero on match
 * Returns non-zero on no match */
#define GENERATE_NUM_LOOKUP_FUNC(name, lookup, type) \
int name(const char *x, type *res) { \
	size_t i = 0; \
	for (i = 0; lookup[i].str; i++) \
		if (strcmp(lookup[i].str, x) == 0) { \
			if (res) \
				*res = lookup[i].look; \
			return 0; \
		} \
	return 1; \
}

GENERATE_STR_LOOKUP_FUNC(get_asm_from_oper, oper_to_asm, enum OPER)
GENERATE_STR_LOOKUP_FUNC(get_asm_from_j, j_to_asm, enum JCOND)
GENERATE_STR_LOOKUP_FUNC(get_asm_from_b, b_to_asm, enum JCOND)
GENERATE_STR_LOOKUP_FUNC(get_asm_from_reg, reg_to_asm, enum REG)
GENERATE_STR_LOOKUP_FUNC(get_token_description, token_to_desc, enum TOKEN_TYPE)

GENERATE_NUM_LOOKUP_FUNC(get_keyword, keywords, int)
GENERATE_NUM_LOOKUP_FUNC(get_oper_from_asm, oper_to_asm, enum OPER)
GENERATE_NUM_LOOKUP_FUNC(get_j_from_asm, j_to_asm, enum JCOND)
GENERATE_NUM_LOOKUP_FUNC(get_b_from_asm, b_to_asm, enum JCOND)
GENERATE_NUM_LOOKUP_FUNC(get_reg_from_asm, reg_to_asm, enum REG)


void indicate_file_area(FILE* fd, size_t line, size_t column, size_t span)
{
	size_t i = 0;
	const char margin[] = "  ";

	char buf[1024] = { '\0' };
	char *s = buf;
	char c = '\0';

	rewind(fd);
	while (line && !feof(fd) && fgets(buf, sizeof(buf), fd)) {
		s = buf;
		while (*s) {
			if (*(s++) == '\n') {
				line--;
			}
		}
	}

	/* trim leading whitespace */
	s = buf;
	while (*s == '\t' || *s == ' ') {
		s++;
	}

	/* filter non-printables to spaces to keep alignment correct */
	for (i = 0; i < strlen(s); i++) {
		if (!isprint(s[i]) && s[i] != '\n') {
			s[i] = ' ';
		}
	}

	fputs(margin, stderr);
	fputs(s, stderr);

	/* corner case: buf had no return */
	if (s[strlen(s) - 1] != '\n') {
		fputc('\n', stderr);
	}

	fputs(margin, stderr);
	column -= (s - buf);
	for (column--; column; column--) {
		fputc(' ', stderr);
	}

	c = span == 1 ? '^' : '"';
	for (; span; span--) {
		fputc(c, stderr);
	}
	fputc('\n', stderr);
}