start work on asm->c translation
[ia32rtools.git] / tools / translate.c
CommitLineData
c36e914d 1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5#include "my_assert.h"
6#include "my_str.h"
7
8#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
9#define IS(w, y) !strcmp(w, y)
10
11#include "protoparse.h"
12
13const char *asmfn;
14static int asmln;
15
16#define awarn(fmt, ...) \
17 printf("warning:%s:%d: " fmt, asmfn, asmln, ##__VA_ARGS__)
18#define aerr(fmt, ...) do { \
19 printf("error:%s:%d: " fmt, asmfn, asmln, ##__VA_ARGS__); \
20 exit(1); \
21} while (0)
22
23enum op_class {
24 OPC_UNSPEC,
25 OPC_RMD, /* removed or optimized out */
26 OPC_DATA, /* data processing */
27 OPC_DATA_FLAGS, /* data processing + sets flags */
28 OPC_JMP, /* .. and call */
29 OPC_JCC,
30};
31
32enum op_op {
33 OP_INVAL,
34 OP_PUSH,
35 OP_POP,
36 OP_MOV,
37 OP_RET,
38 OP_ADD,
39 OP_TEST,
40 OP_CMP,
41 OP_CALL,
42 OP_JMP,
43 OP_JO,
44 OP_JNO,
45 OP_JC,
46 OP_JNC,
47 OP_JZ,
48 OP_JNZ,
49 OP_JBE,
50 OP_JA,
51 OP_JS,
52 OP_JNS,
53 OP_JP,
54 OP_JNP,
55 OP_JL,
56 OP_JGE,
57 OP_JLE,
58 OP_JG,
59};
60
61enum opr_type {
62 OPT_UNSPEC,
63 OPT_REG,
64 OPT_REGMEM,
65 OPT_LABEL,
66 OPT_CONST,
67};
68
69enum opr_lenmod {
70 OPRM_UNSPEC,
71 OPRM_BYTE,
72 OPRM_WORD,
73 OPRM_DWORD,
74};
75
76#define MAX_OPERANDS 2
77
78struct parsed_opr {
79 enum opr_type type;
80 enum opr_lenmod lmod;
81 unsigned int val;
82 char name[256];
83};
84
85struct parsed_op {
86 enum op_class cls;
87 enum op_op op;
88 struct parsed_opr operand[MAX_OPERANDS];
89 int operand_cnt;
90};
91
92#define MAX_OPS 1024
93
94static struct parsed_op ops[MAX_OPS];
95static char labels[MAX_OPS][32];
96
97const char *main_regs[] = { "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp" };
98
99static int parse_operand(struct parsed_opr *opr,
100 char words[16][256], int wordc, int w, enum op_class cls)
101{
102 char *endp = NULL;
103 int ret, len;
104 int i;
105
106 if (w >= wordc)
107 aerr("parse_operand w %d, wordc %d\n", w, wordc);
108
109 for (i = w; i < wordc; i++) {
110 len = strlen(words[i]);
111 if (words[i][len - 1] == ',') {
112 words[i][len - 1] = 0;
113 wordc = i + 1;
114 break;
115 }
116 }
117
118 if (cls == OPC_JMP || cls == OPC_JCC) {
119 const char *label;
120
121 if (wordc - w == 3 && IS(words[w + 1], "ptr"))
122 label = words[w + 2];
123 else if (wordc - w == 2 && IS(words[w], "short"))
124 label = words[w + 1];
125 else if (wordc - w == 1)
126 label = words[w];
127 else
128 aerr("jump parse error");
129
130 opr->type = OPT_LABEL;
131 strcpy(opr->name, label);
132 return wordc;
133 }
134
135 if (wordc - w >= 3) {
136 if (IS(words[w + 1], "ptr")) {
137 if (IS(words[w], "dword"))
138 opr->lmod = OPRM_DWORD;
139 else if (IS(words[w], "word"))
140 opr->lmod = OPRM_WORD;
141 else if (IS(words[w], "byte"))
142 opr->lmod = OPRM_BYTE;
143 else
144 aerr("type parsing failed\n");
145 w += 2;
146 }
147 }
148
149 if (wordc - w == 2 && IS(words[w], "offset")) {
150 opr->type = OPT_LABEL;
151 strcpy(opr->name, words[w + 1]);
152 return wordc;
153 }
154
155 if (wordc - w != 1)
156 aerr("parse_operand 1 word expected\n");
157
158 len = strlen(words[w]);
159
160 if (words[w][0] == '[') {
161 opr->type = OPT_REGMEM;
162 ret = sscanf(words[w], "[%256s]", opr->name);
163 if (ret != 1)
164 aerr("[] parse failure\n");
165 return wordc;
166 }
167 else if (('0' <= words[w][0] && words[w][0] <= '9')
168 || words[w][0] == '-')
169 {
170 opr->type = OPT_CONST;
171 i = 0;
172 if (len > 1 && words[w][0] == '0')
173 i = 1;
174 if (words[w][len - 1] == 'h') {
175 words[w][len - 1] = 0;
176 opr->val = strtoul(&words[w][i], &endp, 16);
177 }
178 else {
179 opr->val = strtoul(&words[w][i], &endp, 10);
180 }
181 if (*endp != 0)
182 aerr("const parse failed\n");
183 return wordc;
184 }
185
186 strcpy(opr->name, words[w]);
187 opr->type = OPT_REG;
188 return wordc;
189}
190
191static const struct {
192 const char *name;
193 enum op_op op;
194 enum op_class cls;
195 int minopr;
196 int maxopr;
197} op_table[] = {
198 { "push", OP_PUSH, OPC_DATA, 1, 1 },
199 { "pop", OP_POP, OPC_DATA, 1, 1 },
200 { "mov" , OP_MOV, OPC_DATA, 2, 2 },
201 { "add", OP_ADD, OPC_DATA_FLAGS, 2, 2 },
202 { "test", OP_TEST, OPC_DATA_FLAGS, 2, 2 },
203 { "cmp", OP_CMP, OPC_DATA_FLAGS, 2, 2 },
204 { "retn", OP_RET, OPC_JMP, 0, 1 },
205 { "call", OP_CALL, OPC_JMP, 1, 1 },
206 { "jmp", OP_JMP, OPC_JMP, 1, 1 },
207 { "jo", OP_JO, OPC_JCC, 1, 1 }, // 70 OF=1
208 { "jno", OP_JNO, OPC_JCC, 1, 1 }, // 71 OF=0
209 { "jc", OP_JC, OPC_JCC, 1, 1 }, // 72 CF=1
210 { "jb", OP_JC, OPC_JCC, 1, 1 }, // 72
211 { "jnc", OP_JNC, OPC_JCC, 1, 1 }, // 73 CF=0
212 { "jae", OP_JNC, OPC_JCC, 1, 1 }, // 73
213 { "jz", OP_JZ, OPC_JCC, 1, 1 }, // 74 ZF=1
214 { "je", OP_JZ, OPC_JCC, 1, 1 }, // 74
215 { "jnz", OP_JNZ, OPC_JCC, 1, 1 }, // 75 ZF=0
216 { "jne", OP_JNZ, OPC_JCC, 1, 1 }, // 75
217 { "jbe", OP_JBE, OPC_JCC, 1, 1 }, // 76 CF=1 || ZF=1
218 { "jna", OP_JBE, OPC_JCC, 1, 1 }, // 76
219 { "ja", OP_JA, OPC_JCC, 1, 1 }, // 77 CF=0 && ZF=0
220 { "jnbe", OP_JA, OPC_JCC, 1, 1 }, // 77
221 { "js", OP_JS, OPC_JCC, 1, 1 }, // 78 SF=1
222 { "jns", OP_JNS, OPC_JCC, 1, 1 }, // 79 SF=0
223 { "jp", OP_JP, OPC_JCC, 1, 1 }, // 7a PF=1
224 { "jpe", OP_JP, OPC_JCC, 1, 1 }, // 7a
225 { "jnp", OP_JNP, OPC_JCC, 1, 1 }, // 7b PF=0
226 { "jpo", OP_JNP, OPC_JCC, 1, 1 }, // 7b
227 { "jl", OP_JL, OPC_JCC, 1, 1 }, // 7c SF!=OF
228 { "jnge", OP_JL, OPC_JCC, 1, 1 }, // 7c
229 { "jge", OP_JGE, OPC_JCC, 1, 1 }, // 7d SF=OF
230 { "jnl", OP_JGE, OPC_JCC, 1, 1 }, // 7d
231 { "jle", OP_JLE, OPC_JCC, 1, 1 }, // 7e ZF=1 || SF!=OF
232 { "jng", OP_JLE, OPC_JCC, 1, 1 }, // 7e
233 { "jg", OP_JG, OPC_JCC, 1, 1 }, // 7f ZF=0 && SF=OF
234 { "jnle", OP_JG, OPC_JCC, 1, 1 }, // 7f
235};
236
237static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
238{
239 int w = 1;
240 int opr;
241 int i;
242
243 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
244 if (!IS(words[0], op_table[i].name))
245 continue;
246
247 for (opr = 0; opr < op_table[i].minopr; opr++) {
248 w = parse_operand(&op->operand[opr],
249 words, wordc, w, op_table[i].cls);
250 }
251
252 for (; w < wordc && opr < op_table[i].maxopr; opr++) {
253 w = parse_operand(&op->operand[opr],
254 words, wordc, w, op_table[i].cls);
255 }
256
257 goto done;
258 }
259
260 aerr("unhandled op: '%s'\n", words[0]);
261
262done:
263 if (w < wordc)
264 aerr("parse_op %s incomplete: %d/%d\n",
265 words[0], w, wordc);
266
267 op->cls = op_table[i].cls;
268 op->op = op_table[i].op;
269 return;
270}
271
272int gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
273{
274 struct parsed_proto pp;
275 int ret;
276 int i;
277
278 ret = proto_parse(fhdr, funcn, &pp);
279 if (ret)
280 return ret;
281
282 fprintf(fout, "%s %s(", pp.ret_type, funcn);
283 for (i = 0; i < pp.argc; i++) {
284 if (i > 0)
285 fprintf(fout, ", ");
286 fprintf(fout, "%s a%d", pp.arg[i].type, i);
287 }
288 fprintf(fout, ")\n{\n");
289
290
291
292 fprintf(fout, "}\n\n");
293 proto_release(&pp);
294 return 0;
295}
296
297int main(int argc, char *argv[])
298{
299 FILE *fout, *fasm, *fhdr;
300 char line[256];
301 char words[16][256];
302 char func[256];
303 int in_func = 0;
304 int pi = 0;
305 int len;
306 char *p;
307 int wordc;
308
309 if (argc != 4) {
310 printf("usage:\n%s <.c> <.asm> <hdrf>\n",
311 argv[0]);
312 return 1;
313 }
314
315 hdrfn = argv[3];
316 fhdr = fopen(hdrfn, "r");
317 my_assert_not(fhdr, NULL);
318
319 asmfn = argv[2];
320 fasm = fopen(asmfn, "r");
321 my_assert_not(fasm, NULL);
322
323 fout = fopen(argv[1], "w");
324 my_assert_not(fout, NULL);
325
326
327 while (fgets(line, sizeof(line), fasm))
328 {
329 asmln++;
330
331 p = sskip(line);
332 if (*p == 0 || *p == ';')
333 continue;
334
335 memset(words, 0, sizeof(words));
336 for (wordc = 0; wordc < 16; wordc++) {
337 p = sskip(next_word(words[wordc], sizeof(words[0]), p));
338 if (*p == 0 || *p == ';') {
339 wordc++;
340 break;
341 }
342 }
343
344 if (wordc == 0) {
345 // shouldn't happen
346 awarn("wordc == 0?\n");
347 continue;
348 }
349
350 // don't care about this:
351 if (words[0][0] == '.'
352 || IS(words[0], "include")
353 || IS(words[0], "assume") || IS(words[1], "segment")
354 || IS(words[0], "align"))
355 {
356 continue;
357 }
358
359 if (IS(words[1], "proc")) {
360 if (in_func)
361 aerr("proc '%s' while in_func '%s'?\n",
362 words[0], func);
363 strcpy(func, words[0]);
364 in_func = 1;
365 continue;
366 }
367
368 if (IS(words[1], "endp")) {
369 if (!in_func)
370 aerr("endp '%s' while not in_func?\n", words[0]);
371 if (!IS(func, words[0]))
372 aerr("endp '%s' while in_func '%s'?\n",
373 words[0], func);
374 gen_func(fout, fhdr, func, pi);
375 in_func = 0;
376 func[0] = 0;
377 if (pi != 0) {
378 memset(&ops, 0, pi * sizeof(ops[0]));
379 memset(labels, 0, pi * sizeof(labels[0]));
380 pi = 0;
381 }
382 exit(1);
383 continue;
384 }
385
386 if (IS(words[1], "="))
387 // lots of work will be have to be done here, but for now..
388 continue;
389
390 if (pi >= ARRAY_SIZE(ops))
391 aerr("too many ops\n");
392
393 p = strchr(words[0], ':');
394 if (p != NULL) {
395 len = p - words[0];
396 if (len > sizeof(labels[0]) - 1)
397 aerr("label too long: %d\n", len);
398 if (labels[pi][0] != 0)
399 aerr("dupe label?\n");
400 memcpy(labels[pi], words[0], len);
401 labels[pi][len] = 0;
402 continue;
403 }
404
405 parse_op(&ops[pi], words, wordc);
406 pi++;
407
408 (void)proto_parse;
409 }
410
411 fclose(fout);
412 fclose(fasm);
413 fclose(fhdr);
414
415 return 0;
416}