further work to handle more things..
[ia32rtools.git] / tools / translate.c
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
13 const char *asmfn;
14 static 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
23 enum op_flags {
24   OPF_RMD    = (1 << 0), /* removed or optimized out */
25   OPF_DATA   = (1 << 1), /* data processing - writes to dst opr */
26   OPF_FLAGS  = (1 << 2), /* sets flags */
27   OPF_JMP    = (1 << 3), /* branches, ret and call */
28   OPF_CC     = (1 << 4), /* uses flags */
29   OPF_TAIL   = (1 << 5), /* ret or tail call */
30 };
31
32 enum op_op {
33         OP_INVAL,
34         OP_PUSH,
35         OP_POP,
36         OP_MOV,
37         OP_LEA,
38         OP_MOVZX,
39         OP_MOVSX,
40         OP_NOT,
41         OP_CDQ,
42         OP_RET,
43         OP_ADD,
44         OP_SUB,
45         OP_AND,
46         OP_OR,
47         OP_XOR,
48         OP_SHL,
49         OP_SHR,
50         OP_SAR,
51         OP_ADC,
52         OP_SBB,
53         OP_INC,
54         OP_DEC,
55         OP_NEG,
56         OP_MUL,
57         OP_IMUL,
58         OP_DIV,
59         OP_IDIV,
60         OP_TEST,
61         OP_CMP,
62         OP_CALL,
63         OP_JMP,
64         OP_JO,
65         OP_JNO,
66         OP_JC,
67         OP_JNC,
68         OP_JZ,
69         OP_JNZ,
70         OP_JBE,
71         OP_JA,
72         OP_JS,
73         OP_JNS,
74         OP_JP,
75         OP_JNP,
76         OP_JL,
77         OP_JGE,
78         OP_JLE,
79         OP_JG,
80 };
81
82 enum opr_type {
83   OPT_UNSPEC,
84   OPT_REG,
85   OPT_REGMEM,
86   OPT_LABEL,
87   OPT_OFFSET,
88   OPT_CONST,
89 };
90
91 enum opr_lenmod {
92         OPLM_UNSPEC,
93         OPLM_BYTE,
94         OPLM_WORD,
95         OPLM_DWORD,
96 };
97
98 #define MAX_OPERANDS 3
99
100 struct parsed_opr {
101   enum opr_type type;
102   enum opr_lenmod lmod;
103   int reg;
104   unsigned int val;
105   char name[256];
106 };
107
108 struct parsed_op {
109   enum op_op op;
110   struct parsed_opr operand[MAX_OPERANDS];
111   unsigned int flags;
112   int operand_cnt;
113   int regmask_src;        // all referensed regs
114   int regmask_dst;
115   int pfomask;            // parsed_flag_op that can't be delayed
116   int cc_scratch;         // for storage during analysis
117   int bt_i;               // branch target (for branches)
118   void *datap;
119 };
120
121 // datap:
122 // OP_PUSH - arg number if arg is altered before call
123 // OP_CALL - ptr to parsed_proto
124 // (OPF_CC) - point to corresponding (OPF_FLAGS)
125
126 struct parsed_equ {
127   char name[64];
128   enum opr_lenmod lmod;
129   int offset;
130 };
131
132 #define MAX_OPS 1024
133
134 static struct parsed_op ops[MAX_OPS];
135 static struct parsed_equ *g_eqs;
136 static int g_eqcnt;
137 static char g_labels[MAX_OPS][32];
138 static struct parsed_proto g_func_pp;
139 static char g_func[256];
140 static char g_comment[256];
141 static int g_bp_frame;
142 static int g_bp_stack;
143 #define ferr(op_, fmt, ...) do { \
144   printf("error:%s:#%ld: '%s': " fmt, g_func, (op_) - ops, \
145     dump_op(op_), ##__VA_ARGS__); \
146   exit(1); \
147 } while (0)
148
149 #define MAX_REGS 8
150
151 const char *regs_r32[] = { "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp" };
152 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
153 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
154 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
155
156 enum x86_regs { xUNSPEC = -1, xAX, xBX, xCX, xDX, xSI, xDI, xBP, xSP };
157
158 // possible basic comparison types (without inversion)
159 enum parsed_flag_op {
160   PFO_O,  // 0 OF=1
161   PFO_C,  // 2 CF=1
162   PFO_Z,  // 4 ZF=1
163   PFO_BE, // 6 CF=1||ZF=1
164   PFO_S,  // 8 SF=1
165   PFO_P,  // a PF=1
166   PFO_L,  // c SF!=OF
167   PFO_LE, // e ZF=1||SF!=OF
168 };
169
170 static const char *parsed_flag_op_names[] = {
171   "o", "c", "z", "be", "s", "p", "l", "le"
172 };
173
174 static int char_array_i(const char *array[], size_t len, const char *s)
175 {
176   int i;
177
178   for (i = 0; i < len; i++)
179     if (IS(s, array[i]))
180       return i;
181
182   return -1;
183 }
184
185 static void printf_number(char *buf, size_t buf_size, long number)
186 {
187   // output in C-friendly form
188   snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
189 }
190
191 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
192 {
193   int reg;
194
195   reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
196   if (reg >= 0) {
197     *reg_lmod = OPLM_DWORD;
198     return reg;
199   }
200   reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
201   if (reg >= 0) {
202     *reg_lmod = OPLM_WORD;
203     return reg;
204   }
205   reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
206   if (reg >= 0) {
207     *reg_lmod = OPLM_BYTE;
208     return reg;
209   }
210   reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
211   if (reg >= 0) {
212     *reg_lmod = OPLM_BYTE;
213     return reg;
214   }
215
216   return -1;
217 }
218
219 static long parse_number(const char *number)
220 {
221   int len = strlen(number);
222   const char *p = number;
223   char *endp = NULL;
224   int neg = 0;
225   int bad;
226   long ret;
227
228   if (*p == '-') {
229     neg = 1;
230     p++;
231   }
232   if (len > 1 && *p == '0')
233     p++;
234   if (number[len - 1] == 'h') {
235     ret = strtol(p, &endp, 16);
236     bad = (*endp != 'h');
237   }
238   else {
239     ret = strtol(p, &endp, 10);
240     bad = (*endp != 0);
241   }
242   if (bad)
243     aerr("number parsing failed\n");
244   if (neg)
245     ret = -ret;
246   return ret;
247 }
248
249 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
250 {
251   enum opr_lenmod lmod;
252   char cvtbuf[256];
253   char *d = cvtbuf;
254   char *s = name;
255   char w[64];
256   long number;
257   int reg;
258   int c = 0;
259
260   *d = 0;
261
262   while (*s != 0) {
263     d += strlen(d);
264     while (my_isblank(*s))
265       s++;
266     for (; my_issep(*s); d++, s++)
267       *d = *s;
268     while (my_isblank(*s))
269       s++;
270     *d = 0;
271
272     // skip 'ds:' prefix
273     if (!strncmp(s, "ds:", 3))
274       s += 3;
275
276     s = next_idt(w, sizeof(w), s);
277     if (w[0] == 0)
278       break;
279     c++;
280
281     reg = parse_reg(&lmod, w);
282     if (reg >= 0) {
283       *regmask |= 1 << reg;
284       goto pass;
285     }
286
287     if ('0' <= w[0] && w[0] <= '9') {
288       number = parse_number(w);
289       printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
290       continue;
291     }
292
293     // probably some label/identifier - pass
294
295 pass:
296     snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
297   }
298
299   if (need_c_cvt)
300     strcpy(name, cvtbuf);
301
302   return c;
303 }
304
305 static int guess_lmod_from_name(struct parsed_opr *opr)
306 {
307   if (!strncmp(opr->name, "dword_", 6)) {
308     opr->lmod = OPLM_DWORD;
309     return 1;
310   }
311   if (!strncmp(opr->name, "word_", 5)) {
312     opr->lmod = OPLM_WORD;
313     return 1;
314   }
315   if (!strncmp(opr->name, "byte_", 5)) {
316     opr->lmod = OPLM_BYTE;
317     return 1;
318   }
319   return 0;
320 }
321
322 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
323   int *regmask)
324 {
325   opr->type = OPT_REG;
326   opr->reg = reg;
327   opr->lmod = lmod;
328   *regmask |= 1 << reg;
329 }
330
331 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name);
332
333 static int parse_operand(struct parsed_opr *opr,
334   int *regmask, int *regmask_indirect,
335         char words[16][256], int wordc, int w, unsigned int op_flags)
336 {
337   enum opr_lenmod tmplmod;
338   int ret, len;
339   long number;
340   int i;
341
342         if (w >= wordc)
343                 aerr("parse_operand w %d, wordc %d\n", w, wordc);
344
345         opr->reg = xUNSPEC;
346
347         for (i = w; i < wordc; i++) {
348                 len = strlen(words[i]);
349                 if (words[i][len - 1] == ',') {
350                         words[i][len - 1] = 0;
351                         wordc = i + 1;
352                         break;
353                 }
354         }
355
356         if (op_flags & OPF_JMP) {
357                 const char *label;
358
359                 if (wordc - w == 3 && IS(words[w + 1], "ptr"))
360                         label = words[w + 2];
361                 else if (wordc - w == 2 && IS(words[w], "short"))
362                         label = words[w + 1];
363                 else if (wordc - w == 1)
364                         label = words[w];
365                 else
366                         aerr("jump parse error");
367
368                 opr->type = OPT_LABEL;
369                 strcpy(opr->name, label);
370                 return wordc;
371         }
372
373         if (wordc - w >= 3) {
374                 if (IS(words[w + 1], "ptr")) {
375                         if (IS(words[w], "dword"))
376                                 opr->lmod = OPLM_DWORD;
377                         else if (IS(words[w], "word"))
378                                 opr->lmod = OPLM_WORD;
379                         else if (IS(words[w], "byte"))
380                                 opr->lmod = OPLM_BYTE;
381                         else
382                                 aerr("type parsing failed\n");
383                         w += 2;
384                 }
385         }
386
387         if (wordc - w == 2 && IS(words[w], "offset")) {
388                 opr->type = OPT_OFFSET;
389                 strcpy(opr->name, words[w + 1]);
390                 return wordc;
391         }
392
393   if (wordc - w != 1)
394     aerr("parse_operand 1 word expected\n");
395
396   strcpy(opr->name, words[w]);
397
398   if (words[w][0] == '[') {
399     opr->type = OPT_REGMEM;
400     ret = sscanf(words[w], "[%[^]]]", opr->name);
401     if (ret != 1)
402       aerr("[] parse failure\n");
403
404     parse_indmode(opr->name, regmask_indirect, 1);
405     if (opr->lmod == OPLM_UNSPEC && !strncmp(opr->name, "ebp+", 4)) {
406       // might be an equ
407       struct parsed_equ *eq = equ_find(NULL, opr->name + 4);
408       if (eq)
409         opr->lmod = eq->lmod;
410     }
411     return wordc;
412   }
413   else if (strchr(words[w], '[')) {
414     // label[reg] form
415     opr->type = OPT_REGMEM;
416     if (opr->lmod == OPLM_UNSPEC)
417       guess_lmod_from_name(opr);
418     parse_indmode(strchr(words[w], '['), regmask_indirect, 0);
419     return wordc;
420   }
421   else if (('0' <= words[w][0] && words[w][0] <= '9')
422     || words[w][0] == '-')
423   {
424     number = parse_number(words[w]);
425     opr->type = OPT_CONST;
426     opr->val = number;
427     printf_number(opr->name, sizeof(opr->name), number);
428     return wordc;
429   }
430
431   ret = parse_reg(&tmplmod, opr->name);
432   if (ret >= 0) {
433     setup_reg_opr(opr, ret, tmplmod, regmask);
434     return wordc;
435   }
436
437   // most likely var in data segment
438   opr->type = OPT_LABEL;
439   if (opr->lmod == OPLM_UNSPEC)
440     guess_lmod_from_name(opr);
441   if (opr->lmod != OPLM_UNSPEC)
442     return wordc;
443
444   // TODO: scan data seg to determine type?
445   return wordc;
446 }
447
448 static const struct {
449   const char *name;
450   enum op_op op;
451   unsigned int minopr;
452   unsigned int maxopr;
453   unsigned int flags;
454 } op_table[] = {
455   { "push", OP_PUSH,   1, 1, 0 },
456   { "pop",  OP_POP,    1, 1, OPF_DATA },
457   { "mov" , OP_MOV,    2, 2, OPF_DATA },
458   { "lea",  OP_LEA,    2, 2, OPF_DATA },
459   { "movzx",OP_MOVZX,  2, 2, OPF_DATA },
460   { "movsx",OP_MOVSX,  2, 2, OPF_DATA },
461   { "not",  OP_NOT,    1, 1, OPF_DATA },
462   { "cdq",  OP_CDQ,    0, 0, OPF_DATA },
463   { "add",  OP_ADD,    2, 2, OPF_DATA|OPF_FLAGS },
464   { "sub",  OP_SUB,    2, 2, OPF_DATA|OPF_FLAGS },
465   { "and",  OP_AND,    2, 2, OPF_DATA|OPF_FLAGS },
466   { "or",   OP_OR,     2, 2, OPF_DATA|OPF_FLAGS },
467   { "xor",  OP_XOR,    2, 2, OPF_DATA|OPF_FLAGS },
468   { "shl",  OP_SHL,    2, 2, OPF_DATA|OPF_FLAGS },
469   { "shr",  OP_SHR,    2, 2, OPF_DATA|OPF_FLAGS },
470   { "sal",  OP_SHL,    2, 2, OPF_DATA|OPF_FLAGS },
471   { "sar",  OP_SAR,    2, 2, OPF_DATA|OPF_FLAGS },
472   { "adc",  OP_ADC,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
473   { "sbb",  OP_SBB,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
474   { "inc",  OP_INC,    1, 1, OPF_DATA|OPF_FLAGS },
475   { "dec",  OP_DEC,    1, 1, OPF_DATA|OPF_FLAGS },
476   { "neg",  OP_NEG,    1, 1, OPF_DATA|OPF_FLAGS },
477   { "mul",  OP_MUL,    1, 1, OPF_DATA|OPF_FLAGS },
478   { "imul", OP_IMUL,   1, 3, OPF_DATA|OPF_FLAGS },
479   { "div",  OP_DIV,    1, 1, OPF_DATA|OPF_FLAGS },
480   { "idiv", OP_IDIV,   1, 1, OPF_DATA|OPF_FLAGS },
481   { "test", OP_TEST,   2, 2, OPF_FLAGS },
482   { "cmp",  OP_CMP,    2, 2, OPF_FLAGS },
483   { "retn", OP_RET,    0, 1, OPF_JMP|OPF_TAIL },
484   { "call", OP_CALL,   1, 1, OPF_JMP|OPF_FLAGS },
485   { "jmp",  OP_JMP,    1, 1, OPF_JMP },
486   { "jo",   OP_JO,     1, 1, OPF_JMP|OPF_CC }, // 70 OF=1
487   { "jno",  OP_JNO,    1, 1, OPF_JMP|OPF_CC }, // 71 OF=0
488   { "jc",   OP_JC,     1, 1, OPF_JMP|OPF_CC }, // 72 CF=1
489   { "jb",   OP_JC,     1, 1, OPF_JMP|OPF_CC }, // 72
490   { "jnc",  OP_JNC,    1, 1, OPF_JMP|OPF_CC }, // 73 CF=0
491   { "jae",  OP_JNC,    1, 1, OPF_JMP|OPF_CC }, // 73
492   { "jz",   OP_JZ,     1, 1, OPF_JMP|OPF_CC }, // 74 ZF=1
493   { "je",   OP_JZ,     1, 1, OPF_JMP|OPF_CC }, // 74
494   { "jnz",  OP_JNZ,    1, 1, OPF_JMP|OPF_CC }, // 75 ZF=0
495   { "jne",  OP_JNZ,    1, 1, OPF_JMP|OPF_CC }, // 75
496   { "jbe",  OP_JBE,    1, 1, OPF_JMP|OPF_CC }, // 76 CF=1 || ZF=1
497   { "jna",  OP_JBE,    1, 1, OPF_JMP|OPF_CC }, // 76
498   { "ja",   OP_JA,     1, 1, OPF_JMP|OPF_CC }, // 77 CF=0 && ZF=0
499   { "jnbe", OP_JA,     1, 1, OPF_JMP|OPF_CC }, // 77
500   { "js",   OP_JS,     1, 1, OPF_JMP|OPF_CC }, // 78 SF=1
501   { "jns",  OP_JNS,    1, 1, OPF_JMP|OPF_CC }, // 79 SF=0
502   { "jp",   OP_JP,     1, 1, OPF_JMP|OPF_CC }, // 7a PF=1
503   { "jpe",  OP_JP,     1, 1, OPF_JMP|OPF_CC }, // 7a
504   { "jnp",  OP_JNP,    1, 1, OPF_JMP|OPF_CC }, // 7b PF=0
505   { "jpo",  OP_JNP,    1, 1, OPF_JMP|OPF_CC }, // 7b
506   { "jl",   OP_JL,     1, 1, OPF_JMP|OPF_CC }, // 7c SF!=OF
507   { "jnge", OP_JL,     1, 1, OPF_JMP|OPF_CC }, // 7c
508   { "jge",  OP_JGE,    1, 1, OPF_JMP|OPF_CC }, // 7d SF=OF
509   { "jnl",  OP_JGE,    1, 1, OPF_JMP|OPF_CC }, // 7d
510   { "jle",  OP_JLE,    1, 1, OPF_JMP|OPF_CC }, // 7e ZF=1 || SF!=OF
511   { "jng",  OP_JLE,    1, 1, OPF_JMP|OPF_CC }, // 7e
512   { "jg",   OP_JG,     1, 1, OPF_JMP|OPF_CC }, // 7f ZF=0 && SF=OF
513   { "jnle", OP_JG,     1, 1, OPF_JMP|OPF_CC }, // 7f
514   { "seto",   OP_JO,   1, 1, OPF_DATA|OPF_CC },
515   { "setno",  OP_JNO,  1, 1, OPF_DATA|OPF_CC },
516   { "setc",   OP_JC,   1, 1, OPF_DATA|OPF_CC },
517   { "setb",   OP_JC,   1, 1, OPF_DATA|OPF_CC },
518   { "setnc",  OP_JNC,  1, 1, OPF_DATA|OPF_CC },
519   { "setae",  OP_JNC,  1, 1, OPF_DATA|OPF_CC },
520   { "setz",   OP_JZ,   1, 1, OPF_DATA|OPF_CC },
521   { "sete",   OP_JZ,   1, 1, OPF_DATA|OPF_CC },
522   { "setnz",  OP_JNZ,  1, 1, OPF_DATA|OPF_CC },
523   { "setne",  OP_JNZ,  1, 1, OPF_DATA|OPF_CC },
524   { "setbe",  OP_JBE,  1, 1, OPF_DATA|OPF_CC },
525   { "setna",  OP_JBE,  1, 1, OPF_DATA|OPF_CC },
526   { "seta",   OP_JA,   1, 1, OPF_DATA|OPF_CC },
527   { "setnbe", OP_JA,   1, 1, OPF_DATA|OPF_CC },
528   { "sets",   OP_JS,   1, 1, OPF_DATA|OPF_CC },
529   { "setns",  OP_JNS,  1, 1, OPF_DATA|OPF_CC },
530   { "setp",   OP_JP,   1, 1, OPF_DATA|OPF_CC },
531   { "setpe",  OP_JP,   1, 1, OPF_DATA|OPF_CC },
532   { "setnp",  OP_JNP,  1, 1, OPF_DATA|OPF_CC },
533   { "setpo",  OP_JNP,  1, 1, OPF_DATA|OPF_CC },
534   { "setl",   OP_JL,   1, 1, OPF_DATA|OPF_CC },
535   { "setnge", OP_JL,   1, 1, OPF_DATA|OPF_CC },
536   { "setge",  OP_JGE,  1, 1, OPF_DATA|OPF_CC },
537   { "setnl",  OP_JGE,  1, 1, OPF_DATA|OPF_CC },
538   { "setle",  OP_JLE,  1, 1, OPF_DATA|OPF_CC },
539   { "setng",  OP_JLE,  1, 1, OPF_DATA|OPF_CC },
540   { "setg",   OP_JG,   1, 1, OPF_DATA|OPF_CC },
541   { "setnle", OP_JG,   1, 1, OPF_DATA|OPF_CC },
542 };
543
544 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
545 {
546   int regmask_ind;
547   int regmask;
548   int opr = 0;
549   int w = 1;
550   int i;
551
552   for (i = 0; i < ARRAY_SIZE(op_table); i++) {
553     if (IS(words[0], op_table[i].name))
554       break;
555   }
556
557   if (i == ARRAY_SIZE(op_table))
558     aerr("unhandled op: '%s'\n", words[0]);
559
560   op->op = op_table[i].op;
561   op->flags = op_table[i].flags;
562   op->regmask_src = op->regmask_dst = 0;
563
564   for (opr = 0; opr < op_table[i].minopr; opr++) {
565     regmask = regmask_ind = 0;
566     w = parse_operand(&op->operand[opr], &regmask, &regmask_ind,
567       words, wordc, w, op->flags);
568
569     if (opr == 0 && (op->flags & OPF_DATA))
570       op->regmask_dst = regmask;
571     // for now, mark dst as src too
572     op->regmask_src |= regmask | regmask_ind;
573   }
574
575   for (; w < wordc && opr < op_table[i].maxopr; opr++) {
576     w = parse_operand(&op->operand[opr],
577       &op->regmask_src, &op->regmask_src,
578       words, wordc, w, op->flags);
579   }
580
581   if (w < wordc)
582     aerr("parse_op %s incomplete: %d/%d\n",
583       words[0], w, wordc);
584
585   // special cases
586   op->operand_cnt = opr;
587   if (!strncmp(op_table[i].name, "set", 3))
588     op->operand[0].lmod = OPLM_BYTE;
589
590   // ops with implicit argumets
591   switch (op->op) {
592   case OP_CDQ:
593     op->operand_cnt = 2;
594     setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
595     setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
596     break;
597
598   case OP_IMUL:
599     if (op->operand_cnt != 1)
600       break;
601     // fallthrough
602   case OP_MUL:
603     // singleop mul
604     op->regmask_dst = (1 << xDX) | (1 << xAX);
605     op->regmask_src |= (1 << xAX);
606     if (op->operand[0].lmod == OPLM_UNSPEC)
607       op->operand[0].lmod = OPLM_DWORD;
608     break;
609
610   case OP_DIV:
611   case OP_IDIV:
612     // we could set up operands for edx:eax, but there is no real need to
613     // (see is_opr_modified())
614     regmask = (1 << xDX) | (1 << xAX);
615     op->regmask_dst = regmask;
616     op->regmask_src |= regmask;
617     if (op->operand[0].lmod == OPLM_UNSPEC)
618       op->operand[0].lmod = OPLM_DWORD;
619     break;
620
621   case OP_SHL:
622   case OP_SHR:
623   case OP_SAR:
624     if (op->operand[1].lmod == OPLM_UNSPEC)
625       op->operand[1].lmod = OPLM_BYTE;
626     break;
627
628   default:
629     break;
630   }
631 }
632
633 static const char *op_name(enum op_op op)
634 {
635   int i;
636
637   for (i = 0; i < ARRAY_SIZE(op_table); i++)
638     if (op_table[i].op == op)
639       return op_table[i].name;
640
641   return "???";
642 }
643
644 // debug
645 static const char *dump_op(struct parsed_op *po)
646 {
647   static char out[128];
648   char *p = out;
649   int i;
650
651   snprintf(out, sizeof(out), "%s", op_name(po->op));
652   for (i = 0; i < po->operand_cnt; i++) {
653     p += strlen(p);
654     if (i > 0)
655       *p++ = ',';
656     snprintf(p, sizeof(out) - (p - out),
657       po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
658       po->operand[i].name);
659   }
660
661   return out;
662 }
663
664 static const char *opr_name(struct parsed_op *po, int opr_num)
665 {
666   if (opr_num >= po->operand_cnt)
667     ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
668   return po->operand[opr_num].name;
669 }
670
671 static unsigned int opr_const(struct parsed_op *po, int opr_num)
672 {
673   if (opr_num >= po->operand_cnt)
674     ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
675   if (po->operand[opr_num].type != OPT_CONST)
676     ferr(po, "opr %d: const expected\n", opr_num);
677   return po->operand[opr_num].val;
678 }
679
680 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
681 {
682   if ((unsigned int)popr->reg >= MAX_REGS)
683     ferr(po, "invalid reg: %d\n", popr->reg);
684   return regs_r32[popr->reg];
685 }
686
687 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name)
688 {
689   int i;
690
691   for (i = 0; i < g_eqcnt; i++)
692     if (IS(g_eqs[i].name, name))
693       break;
694   if (i >= g_eqcnt) {
695     if (po != NULL)
696       ferr(po, "unresolved equ name: '%s'\n", name);
697     return NULL;
698   }
699
700   return &g_eqs[i];
701 }
702
703 static void bg_frame_access(struct parsed_op *po, enum opr_lenmod lmod,
704   char *buf, size_t buf_size, const char *bp_arg,
705   int is_src, int is_lea)
706 {
707   const char *prefix = "";
708   struct parsed_equ *eq;
709   int i, arg_i, arg_s;
710   int sf_ofs;
711
712   snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
713
714   eq = equ_find(po, bp_arg);
715
716   if (eq->offset >= 0) {
717     arg_i = eq->offset / 4 - 2;
718     if (arg_i < 0 || arg_i >= g_func_pp.argc_stack)
719       ferr(po, "offset %d doesn't map to any arg\n", eq->offset);
720
721     for (i = arg_s = 0; i < g_func_pp.argc; i++) {
722       if (g_func_pp.arg[i].reg != NULL)
723         continue;
724       if (arg_s == arg_i)
725         break;
726       arg_s++;
727     }
728     if (i == g_func_pp.argc)
729       ferr(po, "arg %d not in prototype?\n", arg_i);
730     if (is_lea)
731       ferr(po, "lea to arg?\n");
732
733     snprintf(buf, buf_size, "%sa%d", is_src ? "(u32)" : "", i + 1);
734   }
735   else {
736     if (g_bp_stack == 0)
737       ferr(po, "bp_stack access after it was not detected\n");
738
739     sf_ofs = g_bp_stack + eq->offset;
740     if (sf_ofs < 0)
741       ferr(po, "bp_stack offset %d/%d\n", eq->offset, g_bp_stack);
742
743     if (is_lea)
744       prefix = "&";
745
746     switch (lmod)
747     {
748     case OPLM_BYTE:
749       snprintf(buf, buf_size, "%ssf.b[%d]", prefix, sf_ofs);
750       break;
751     case OPLM_WORD:
752       snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
753       break;
754     case OPLM_DWORD:
755       snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
756       break;
757     default:
758       ferr(po, "bp_stack bad lmod: %d\n", lmod);
759     }
760   }
761 }
762
763 static char *out_src_opr(char *buf, size_t buf_size,
764         struct parsed_op *po, struct parsed_opr *popr, int is_lea)
765 {
766   const char *cast = "";
767   char tmp1[256], tmp2[256];
768   char expr[256];
769   int ret;
770
771   switch (popr->type) {
772   case OPT_REG:
773     if (is_lea)
774       ferr(po, "lea from reg?\n");
775
776     switch (popr->lmod) {
777     case OPLM_DWORD:
778       snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
779       break;
780     case OPLM_WORD:
781       snprintf(buf, buf_size, "(u16)%s", opr_reg_p(po, popr));
782       break;
783     case OPLM_BYTE:
784       if (popr->name[1] == 'h') // XXX..
785         snprintf(buf, buf_size, "(u8)(%s >> 8)", opr_reg_p(po, popr));
786       else
787         snprintf(buf, buf_size, "(u8)%s", opr_reg_p(po, popr));
788       break;
789     default:
790       ferr(po, "invalid src lmod: %d\n", popr->lmod);
791     }
792     break;
793
794   case OPT_REGMEM:
795     if (g_bp_frame && !strncmp(popr->name, "ebp+", 4)) {
796       bg_frame_access(po, popr->lmod, buf, buf_size,
797         popr->name + 4, 1, is_lea);
798       break;
799     }
800
801     strcpy(expr, popr->name);
802     if (strchr(expr, '[')) {
803       // special case: '[' can only be left for label[reg] form
804       ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
805       if (ret != 2)
806         ferr(po, "parse failure for '%s'\n", expr);
807       snprintf(expr, sizeof(expr), "(u32)%s + %s", tmp1, tmp2);
808     }
809
810     // XXX: do we need more parsing?
811     if (is_lea) {
812       snprintf(buf, buf_size, "%s", expr);
813       break;
814     }
815
816     switch (popr->lmod) {
817     case OPLM_DWORD:
818       cast = "*(u32 *)";
819       break;
820     case OPLM_WORD:
821       cast = "*(u16 *)";
822       break;
823     case OPLM_BYTE:
824       cast = "*(u8 *)";
825       break;
826     default:
827       ferr(po, "invalid lmod: %d\n", popr->lmod);
828     }
829     snprintf(buf, buf_size, "%s(%s)", cast, expr);
830     break;
831
832   case OPT_LABEL:
833     if (is_lea)
834       snprintf(buf, buf_size, "(u32)&%s", popr->name);
835     else
836       snprintf(buf, buf_size, "(u32)%s", popr->name);
837     break;
838
839   case OPT_OFFSET:
840     if (is_lea)
841       ferr(po, "lea an offset?\n");
842     snprintf(buf, buf_size, "(u32)&%s", popr->name);
843     break;
844
845   case OPT_CONST:
846     if (is_lea)
847       ferr(po, "lea from const?\n");
848
849     printf_number(buf, buf_size, popr->val);
850     break;
851
852   default:
853     ferr(po, "invalid src type: %d\n", popr->type);
854   }
855
856   return buf;
857 }
858
859 static char *out_dst_opr(char *buf, size_t buf_size,
860         struct parsed_op *po, struct parsed_opr *popr)
861 {
862   switch (popr->type) {
863   case OPT_REG:
864     switch (popr->lmod) {
865     case OPLM_DWORD:
866       snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
867       break;
868     case OPLM_WORD:
869       // ugh..
870       snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
871       break;
872     case OPLM_BYTE:
873       // ugh..
874       if (popr->name[1] == 'h') // XXX..
875         snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
876       else
877         snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
878       break;
879     default:
880       ferr(po, "invalid dst lmod: %d\n", popr->lmod);
881     }
882     break;
883
884   case OPT_REGMEM:
885     if (g_bp_frame && !strncmp(popr->name, "ebp+", 4)) {
886       bg_frame_access(po, popr->lmod, buf, buf_size,
887         popr->name + 4, 0, 0);
888       break;
889     }
890
891     return out_src_opr(buf, buf_size, po, popr, 0);
892
893   default:
894     ferr(po, "invalid dst type: %d\n", popr->type);
895   }
896
897   return buf;
898 }
899
900 static const char *lmod_cast_u(struct parsed_op *po,
901   enum opr_lenmod lmod)
902 {
903   switch (lmod) {
904   case OPLM_DWORD:
905     return "";
906   case OPLM_WORD:
907     return "(u16)";
908   case OPLM_BYTE:
909     return "(u8)";
910   default:
911     ferr(po, "invalid lmod: %d\n", lmod);
912     return "(_invalid_)";
913   }
914 }
915
916 static const char *lmod_cast_s(struct parsed_op *po,
917   enum opr_lenmod lmod)
918 {
919   switch (lmod) {
920   case OPLM_DWORD:
921     return "(s32)";
922   case OPLM_WORD:
923     return "(s16)";
924   case OPLM_BYTE:
925     return "(s8)";
926   default:
927     ferr(po, "invalid lmod: %d\n", lmod);
928     return "(_invalid_)";
929   }
930 }
931
932 static const char *lmod_cast(struct parsed_op *po,
933   enum opr_lenmod lmod, int is_signed)
934 {
935   return is_signed ?
936     lmod_cast_s(po, lmod) :
937     lmod_cast_u(po, lmod);
938 }
939
940 static enum parsed_flag_op split_cond(struct parsed_op *po,
941   enum op_op op, int *is_neg)
942 {
943   *is_neg = 0;
944
945   switch (op) {
946   case OP_JO:
947     return PFO_O;
948   case OP_JC:
949     return PFO_C;
950   case OP_JZ:
951     return PFO_Z;
952   case OP_JBE:
953     return PFO_BE;
954   case OP_JS:
955     return PFO_S;
956   case OP_JP:
957     return PFO_P;
958   case OP_JL:
959     return PFO_L;
960   case OP_JLE:
961     return PFO_LE;
962
963   case OP_JNO:
964     *is_neg = 1;
965     return PFO_O;
966   case OP_JNC:
967     *is_neg = 1;
968     return PFO_C;
969   case OP_JNZ:
970     *is_neg = 1;
971     return PFO_Z;
972   case OP_JA:
973     *is_neg = 1;
974     return PFO_BE;
975   case OP_JNS:
976     *is_neg = 1;
977     return PFO_S;
978   case OP_JNP:
979     *is_neg = 1;
980     return PFO_P;
981   case OP_JGE:
982     *is_neg = 1;
983     return PFO_L;
984   case OP_JG:
985     *is_neg = 1;
986     return PFO_LE;
987
988   case OP_ADC:
989   case OP_SBB:
990     return PFO_C;
991
992   default:
993     ferr(po, "split_cond: bad op %d\n", op);
994     return -1;
995   }
996 }
997
998 static void out_test_for_cc(char *buf, size_t buf_size,
999   struct parsed_op *po, enum parsed_flag_op pfo, int is_neg,
1000   enum opr_lenmod lmod, const char *expr)
1001 {
1002   const char *cast, *scast;
1003
1004   cast = lmod_cast_u(po, lmod);
1005   scast = lmod_cast_s(po, lmod);
1006
1007   switch (pfo) {
1008   case PFO_Z:
1009   case PFO_BE: // CF=1||ZF=1; CF=0
1010     snprintf(buf, buf_size, "(%s%s %s 0)",
1011       cast, expr, is_neg ? "!=" : "==");
1012     break;
1013
1014   case PFO_S:
1015   case PFO_L: // SF!=OF; OF=0
1016     snprintf(buf, buf_size, "(%s%s %s 0)",
1017       scast, expr, is_neg ? ">=" : "<");
1018     break;
1019
1020   case PFO_LE: // ZF=1||SF!=OF; OF=0
1021     snprintf(buf, buf_size, "(%s%s %s 0)",
1022       scast, expr, is_neg ? ">" : "<=");
1023     break;
1024
1025   default:
1026     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
1027   }
1028 }
1029
1030 static void out_cmp_for_cc(char *buf, size_t buf_size,
1031   struct parsed_op *po, enum parsed_flag_op pfo, int is_neg,
1032   enum opr_lenmod lmod, const char *expr1, const char *expr2)
1033 {
1034   const char *cast, *scast;
1035
1036   cast = lmod_cast_u(po, lmod);
1037   scast = lmod_cast_s(po, lmod);
1038
1039   switch (pfo) {
1040   case PFO_C:
1041     // note: must be unsigned compare
1042     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1043       cast, expr1, is_neg ? ">=" : "<", cast, expr2);
1044     break;
1045
1046   case PFO_Z:
1047     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1048       cast, expr1, is_neg ? "!=" : "==", cast, expr2);
1049     break;
1050
1051   case PFO_BE: // !a
1052     // note: must be unsigned compare
1053     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1054       cast, expr1, is_neg ? ">" : "<=", cast, expr2);
1055     break;
1056
1057   // note: must be signed compare
1058   case PFO_S:
1059     snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
1060       scast, expr1, expr2, is_neg ? ">=" : "<");
1061     break;
1062
1063   case PFO_L: // !ge
1064     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1065       scast, expr1, is_neg ? ">=" : "<", scast, expr2);
1066     break;
1067
1068   case PFO_LE:
1069     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1070       scast, expr1, is_neg ? ">" : "<=", scast, expr2);
1071     break;
1072
1073   default:
1074     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
1075   }
1076 }
1077
1078 static void out_cmp_test(char *buf, size_t buf_size,
1079   struct parsed_op *po, enum parsed_flag_op pfo, int is_neg)
1080 {
1081   char buf1[256], buf2[256], buf3[256];
1082
1083   if (po->op == OP_TEST) {
1084     if (IS(opr_name(po, 0), opr_name(po, 1))) {
1085       out_src_opr(buf3, sizeof(buf3), po, &po->operand[0], 0);
1086     }
1087     else {
1088       out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
1089       out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0);
1090       snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
1091     }
1092     out_test_for_cc(buf, buf_size, po, pfo, is_neg,
1093       po->operand[0].lmod, buf3);
1094   }
1095   else if (po->op == OP_CMP) {
1096     out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], 0);
1097     out_src_opr(buf3, sizeof(buf3), po, &po->operand[1], 0);
1098     out_cmp_for_cc(buf, buf_size, po, pfo, is_neg,
1099       po->operand[0].lmod, buf2, buf3);
1100   }
1101   else
1102     ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
1103 }
1104
1105 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
1106         struct parsed_opr *popr2)
1107 {
1108   if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
1109     ferr(po, "missing lmod for both operands\n");
1110
1111   if (popr1->lmod == OPLM_UNSPEC)
1112     popr1->lmod = popr2->lmod;
1113   else if (popr2->lmod == OPLM_UNSPEC)
1114     popr2->lmod = popr1->lmod;
1115   else if (popr1->lmod != popr2->lmod)
1116     ferr(po, "conflicting lmods: %d vs %d\n", popr1->lmod, popr2->lmod);
1117 }
1118
1119 static const char *op_to_c(struct parsed_op *po)
1120 {
1121   switch (po->op)
1122   {
1123     case OP_ADD:
1124     case OP_ADC:
1125       return "+";
1126     case OP_SUB:
1127     case OP_SBB:
1128       return "-";
1129     case OP_AND:
1130       return "&";
1131     case OP_OR:
1132       return "|";
1133     case OP_XOR:
1134       return "^";
1135     case OP_SHL:
1136       return "<<";
1137     case OP_SHR:
1138       return ">>";
1139     case OP_MUL:
1140     case OP_IMUL:
1141       return "*";
1142     default:
1143       ferr(po, "op_to_c was supplied with %d\n", po->op);
1144   }
1145 }
1146
1147 static int scan_for_pop(int i, int opcnt, const char *reg,
1148   int magic, int do_patch)
1149 {
1150   struct parsed_op *po;
1151   int ret = 0;
1152
1153   for (; i < opcnt; i++) {
1154     po = &ops[i];
1155     if (po->cc_scratch == magic)
1156       break; // already checked
1157     po->cc_scratch = magic;
1158
1159     if (po->flags & OPF_TAIL)
1160       return -1; // deadend
1161
1162     if (po->flags & OPF_RMD)
1163       continue;
1164
1165     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
1166       if (po->bt_i < 0) {
1167         ferr(po, "dead branch\n");
1168         return -1;
1169       }
1170
1171       if (po->flags & OPF_CC) {
1172         ret |= scan_for_pop(po->bt_i, opcnt, reg, magic, do_patch);
1173         if (ret < 0)
1174           return ret; // dead end
1175       }
1176       else {
1177         i = po->bt_i - 1;
1178       }
1179       continue;
1180     }
1181
1182     if (po->op == OP_POP && po->operand[0].type == OPT_REG
1183         && IS(po->operand[0].name, reg))
1184     {
1185       if (do_patch)
1186         po->flags |= OPF_RMD;
1187       return 1;
1188     }
1189   }
1190
1191   return ret;
1192 }
1193
1194 // scan for pop starting from 'ret' op (all paths)
1195 static int scan_for_pop_ret(int i, int opcnt, const char *reg, int do_patch)
1196 {
1197   int found = 0;
1198   int j;
1199
1200   for (; i < opcnt; i++) {
1201     if (!(ops[i].flags & OPF_TAIL))
1202       continue;
1203
1204     for (j = i - 1; j >= 0; j--) {
1205       if (ops[j].flags & OPF_RMD)
1206         continue;
1207       if (ops[j].flags & OPF_JMP)
1208         return -1;
1209
1210       if (ops[j].op == OP_POP && ops[j].operand[0].type == OPT_REG
1211           && IS(ops[j].operand[0].name, reg))
1212       {
1213         found = 1;
1214         if (do_patch)
1215           ops[j].flags |= OPF_RMD;
1216         break;
1217       }
1218
1219       if (g_labels[j][0] != 0)
1220         return -1;
1221     }
1222   }
1223
1224   return found ? 0 : -1;
1225 }
1226
1227 // is operand 'opr modified' by parsed_op 'po'?
1228 static int is_opr_modified(const struct parsed_opr *opr,
1229   const struct parsed_op *po)
1230 {
1231   if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
1232     return 0;
1233
1234   if (opr->type == OPT_REG && po->operand[0].type == OPT_REG) {
1235     if (po->regmask_dst & (1 << opr->reg))
1236       return 1;
1237     else
1238       return 0;
1239   }
1240
1241   return IS(po->operand[0].name, opr->name);
1242 }
1243
1244 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
1245 static int is_any_opr_modified(const struct parsed_op *po_test,
1246   const struct parsed_op *po)
1247 {
1248   int i;
1249
1250   if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
1251     return 0;
1252
1253   if (po_test->regmask_src & po->regmask_dst)
1254     return 1;
1255
1256   for (i = 0; i < po_test->operand_cnt; i++)
1257     if (IS(po_test->operand[i].name, po->operand[0].name))
1258       return 1;
1259
1260   return 0;
1261 }
1262
1263 // scan for po_test operand modification in range given
1264 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt)
1265 {
1266   for (; i < opcnt; i++) {
1267     if (is_any_opr_modified(po_test, &ops[i]))
1268       return i;
1269   }
1270
1271   return -1;
1272 }
1273
1274 static int scan_for_flag_set(int i)
1275 {
1276   for (; i >= 0; i--) {
1277     if (ops[i].flags & OPF_FLAGS)
1278       return i;
1279
1280     if ((ops[i].flags & OPF_JMP) && !(ops[i].flags & OPF_CC))
1281       return -1;
1282     if (g_labels[i][0] != 0)
1283       return -1;
1284   }
1285
1286   return -1;
1287 }
1288
1289 // scan back for cdq, if anything modifies edx, fail
1290 static int scan_for_cdq_edx(int i)
1291 {
1292   for (; i >= 0; i--) {
1293     if (ops[i].op == OP_CDQ)
1294       return i;
1295
1296     if (ops[i].regmask_dst & (1 << xDX))
1297       return -1;
1298     if (g_labels[i][0] != 0)
1299       return -1;
1300   }
1301
1302   return -1;
1303 }
1304
1305 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
1306 {
1307   struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
1308   struct parsed_opr *last_arith_dst = NULL;
1309   char buf1[256], buf2[256], buf3[256];
1310   struct parsed_proto *pp;
1311   const char *tmpname;
1312   int save_arg_vars = 0;
1313   int cmp_result_vars = 0;
1314   int need_mul_var = 0;
1315   int had_decl = 0;
1316   int regmask_arg = 0;
1317   int regmask = 0;
1318   int no_output;
1319   int dummy;
1320   int arg;
1321   int i, j;
1322   int reg;
1323   int ret;
1324
1325   g_bp_frame = g_bp_stack = 0;
1326
1327   ret = proto_parse(fhdr, funcn, &g_func_pp);
1328   if (ret)
1329     ferr(ops, "proto_parse failed for '%s'\n", funcn);
1330
1331   fprintf(fout, "%s %s(", g_func_pp.ret_type, funcn);
1332   for (i = 0; i < g_func_pp.argc; i++) {
1333     if (i > 0)
1334       fprintf(fout, ", ");
1335     fprintf(fout, "%s a%d", g_func_pp.arg[i].type, i + 1);
1336   }
1337   fprintf(fout, ")\n{\n");
1338
1339   // pass1:
1340   // - handle ebp frame, remove ops related to it
1341   if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
1342       && ops[1].op == OP_MOV
1343       && IS(opr_name(&ops[1], 0), "ebp")
1344       && IS(opr_name(&ops[1], 1), "esp"))
1345   {
1346     int ecx_push = 0;
1347
1348     g_bp_frame = 1;
1349     ops[0].flags |= OPF_RMD;
1350     ops[1].flags |= OPF_RMD;
1351
1352     if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
1353       g_bp_stack = opr_const(&ops[2], 1);
1354       ops[2].flags |= OPF_RMD;
1355     }
1356     else {
1357       // another way msvc builds stack frame..
1358       i = 2;
1359       while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
1360         g_bp_stack += 4;
1361         ops[i].flags |= OPF_RMD;
1362         ecx_push++;
1363         i++;
1364       }
1365     }
1366
1367     i = 2;
1368     do {
1369       for (; i < opcnt; i++)
1370         if (ops[i].op == OP_RET)
1371           break;
1372       if (ops[i - 1].op != OP_POP || !IS(opr_name(&ops[i - 1], 0), "ebp"))
1373         ferr(&ops[i - 1], "'pop ebp' expected\n");
1374       ops[i - 1].flags |= OPF_RMD;
1375
1376       if (g_bp_stack != 0) {
1377         if (ops[i - 2].op != OP_MOV
1378             || !IS(opr_name(&ops[i - 2], 0), "esp")
1379             || !IS(opr_name(&ops[i - 2], 1), "ebp"))
1380         {
1381           ferr(&ops[i - 2], "esp restore expected\n");
1382         }
1383         ops[i - 2].flags |= OPF_RMD;
1384
1385         if (ecx_push && ops[i - 3].op == OP_POP
1386           && IS(opr_name(&ops[i - 3], 0), "ecx"))
1387         {
1388           ferr(&ops[i - 3], "unexpected ecx pop\n");
1389         }
1390       }
1391
1392       i++;
1393     } while (i < opcnt);
1394   }
1395
1396   // pass2:
1397   // - resolve all branches
1398   for (i = 0; i < opcnt; i++) {
1399     po = &ops[i];
1400     po->bt_i = -1;
1401
1402     if ((po->flags & OPF_RMD) || !(po->flags & OPF_JMP)
1403         || po->op == OP_CALL || po->op == OP_RET)
1404       continue;
1405
1406     for (j = 0; j < opcnt; j++) {
1407       if (g_labels[j][0] && IS(po->operand[0].name, g_labels[j])) {
1408         po->bt_i = j;
1409         break;
1410       }
1411     }
1412
1413     if (po->bt_i == -1) {
1414       // assume tail call
1415       po->op = OP_CALL;
1416       po->flags |= OPF_TAIL;
1417     }
1418   }
1419
1420   // pass3:
1421   // - find POPs for PUSHes, rm both
1422   // - scan for all used registers
1423   // - find flag set ops for their users
1424   // - process calls
1425   for (i = 0; i < opcnt; i++) {
1426     po = &ops[i];
1427     if (po->flags & OPF_RMD)
1428       continue;
1429
1430     if (po->op == OP_PUSH && po->operand[0].type == OPT_REG) {
1431       if (po->operand[0].reg < 0)
1432         ferr(po, "reg not set for push?\n");
1433       if (!(regmask & (1 << po->operand[0].reg))) { // reg save
1434         ret = scan_for_pop(i + 1, opcnt, po->operand[0].name, i + 1, 0);
1435         if (ret == 1) {
1436           po->flags |= OPF_RMD;
1437           scan_for_pop(i + 1, opcnt, po->operand[0].name, i + 2, 1);
1438           continue;
1439         }
1440         ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, 0);
1441         if (ret == 0) {
1442           po->flags |= OPF_RMD;
1443           scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, 1);
1444           continue;
1445         }
1446       }
1447     }
1448
1449     regmask |= po->regmask_src | po->regmask_dst;
1450
1451     if (po->flags & OPF_CC)
1452     {
1453       ret = scan_for_flag_set(i - 1);
1454       if (ret < 0)
1455         ferr(po, "unable to trace flag setter\n");
1456
1457       tmp_op = &ops[ret]; // flag setter
1458       ret = scan_for_mod(tmp_op, ret + 1, i);
1459       if (ret >= 0) {
1460         ret = 1 << split_cond(po, po->op, &dummy);
1461         tmp_op->pfomask |= ret;
1462         cmp_result_vars |= ret;
1463         po->datap = tmp_op;
1464       }
1465
1466       if (po->op == OP_ADC || po->op == OP_SBB)
1467         cmp_result_vars |= 1 << PFO_C;
1468     }
1469     else if (po->op == OP_CALL)
1470     {
1471       pp = malloc(sizeof(*pp));
1472       my_assert_not(pp, NULL);
1473       tmpname = opr_name(&ops[i], 0);
1474       ret = proto_parse(fhdr, tmpname, pp);
1475       if (ret)
1476         ferr(po, "proto_parse failed for '%s'\n", tmpname);
1477
1478       for (arg = 0; arg < pp->argc; arg++)
1479         if (pp->arg[arg].reg == NULL)
1480           break;
1481
1482       for (j = i - 1; j >= 0 && arg < pp->argc; j--) {
1483         if (ops[j].flags & OPF_RMD)
1484           continue;
1485         if (ops[j].op != OP_PUSH)
1486           continue;
1487         if (g_labels[j + 1][0] != 0)
1488           ferr(po, "arg search interrupted by '%s'\n", g_labels[j + 1]);
1489
1490         pp->arg[arg].datap = &ops[j];
1491         ret = scan_for_mod(&ops[j], j + 1, i);
1492         if (ret >= 0) {
1493           // mark this push as one that needs operand saving
1494           ops[j].datap = (void *)(long)(arg + 1);
1495           save_arg_vars |= 1 << arg;
1496         }
1497         else
1498           ops[j].flags |= OPF_RMD;
1499
1500         // next arg
1501         for (arg++; arg < pp->argc; arg++)
1502           if (pp->arg[arg].reg == NULL)
1503             break;
1504       }
1505       if (arg < pp->argc)
1506         ferr(po, "arg collect failed for '%s'\n", tmpname);
1507       po->datap = pp;
1508     }
1509     else if (po->op == OP_MUL
1510       || (po->op == OP_IMUL && po->operand_cnt == 1))
1511     {
1512       need_mul_var = 1;
1513     }
1514   }
1515
1516   // declare stack frame
1517   if (g_bp_stack)
1518     fprintf(fout, "  union { u32 d[%d]; u16 w[%d]; u8 b[%d]; } sf;\n",
1519       (g_bp_stack + 3) / 4, (g_bp_stack + 1) / 2, g_bp_stack);
1520
1521   // instantiate arg-registers
1522   for (i = 0; i < g_func_pp.argc; i++) {
1523     if (g_func_pp.arg[i].reg != NULL) {
1524       reg = char_array_i(regs_r32,
1525               ARRAY_SIZE(regs_r32), g_func_pp.arg[i].reg);
1526       if (reg < 0)
1527         ferr(ops, "arg '%s' is not a reg?\n", g_func_pp.arg[i].reg);
1528
1529       regmask_arg |= 1 << reg;
1530       fprintf(fout, "  u32 %s = (u32)a%d;\n",
1531         g_func_pp.arg[i].reg, i + 1);
1532       had_decl = 1;
1533     }
1534   }
1535
1536   // instantiate other regs - special case for eax
1537   if (!((regmask | regmask_arg) & 1) && !IS(g_func_pp.ret_type, "void")) {
1538     fprintf(fout, "  u32 eax = 0;\n");
1539     had_decl = 1;
1540   }
1541
1542   regmask &= ~regmask_arg;
1543   if (g_bp_frame)
1544     regmask &= ~(1 << xBP);
1545   if (regmask) {
1546     for (reg = 0; reg < 8; reg++) {
1547       if (regmask & (1 << reg)) {
1548         fprintf(fout, "  u32 %s;\n", regs_r32[reg]);
1549         had_decl = 1;
1550       }
1551     }
1552   }
1553
1554   if (save_arg_vars) {
1555     for (reg = 0; reg < 32; reg++) {
1556       if (save_arg_vars & (1 << reg)) {
1557         fprintf(fout, "  u32 s_a%d;\n", reg + 1);
1558         had_decl = 1;
1559       }
1560     }
1561   }
1562
1563   if (cmp_result_vars) {
1564     for (i = 0; i < 8; i++) {
1565       if (cmp_result_vars & (1 << i)) {
1566         fprintf(fout, "  u32 cond_%s;\n", parsed_flag_op_names[i]);
1567         had_decl = 1;
1568       }
1569     }
1570   }
1571
1572   if (need_mul_var) {
1573     fprintf(fout, "  u64 mul_tmp;\n");
1574     had_decl = 1;
1575   }
1576
1577   if (had_decl)
1578     fprintf(fout, "\n");
1579
1580   // output ops
1581   for (i = 0; i < opcnt; i++)
1582   {
1583     if (g_labels[i][0] != 0)
1584       fprintf(fout, "\n%s:\n", g_labels[i]);
1585
1586     po = &ops[i];
1587     if (po->flags & OPF_RMD)
1588       continue;
1589
1590     no_output = 0;
1591
1592     #define assert_operand_cnt(n_) \
1593       if (po->operand_cnt != n_) \
1594         ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
1595
1596     // conditional/flag using op?
1597     if (po->flags & OPF_CC)
1598     {
1599       enum parsed_flag_op pfo;
1600       int is_neg = 0;
1601
1602       pfo = split_cond(po, po->op, &is_neg);
1603
1604       // we go through all this trouble to avoid using parsed_flag_op,
1605       // which makes generated code much nicer
1606       if (delayed_flag_op != NULL)
1607       {
1608         out_cmp_test(buf1, sizeof(buf1), delayed_flag_op, pfo, is_neg);
1609       }
1610       else if (last_arith_dst != NULL
1611         && (pfo == PFO_Z || pfo == PFO_S || pfo == PFO_P))
1612       {
1613         out_src_opr(buf3, sizeof(buf3), po, last_arith_dst, 0);
1614         out_test_for_cc(buf1, sizeof(buf1), po, pfo, is_neg,
1615           last_arith_dst->lmod, buf3);
1616       }
1617       else if (po->datap != NULL) {
1618         // use preprocessed results
1619         tmp_op = po->datap;
1620         if (!tmp_op || !(tmp_op->pfomask & (1 << pfo)))
1621           ferr(po, "not prepared for pfo %d\n", pfo);
1622
1623         // note: is_neg was not yet applied
1624         snprintf(buf1, sizeof(buf1), "(%scond_%s)",
1625           is_neg ? "!" : "", parsed_flag_op_names[pfo]);
1626       }
1627       else {
1628         ferr(po, "all methods of finding comparison failed\n");
1629       }
1630  
1631       if (po->flags & OPF_JMP) {
1632         fprintf(fout, "  if %s\n", buf1);
1633       }
1634       else if (po->op == OP_ADC || po->op == OP_SBB) {
1635         fprintf(fout, "  cond_%s = %s;\n", parsed_flag_op_names[pfo], buf1);
1636       }
1637       else if (po->flags & OPF_DATA) { // SETcc
1638         out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
1639         fprintf(fout, "  %s = %s;", buf2, buf1);
1640       }
1641       else {
1642         ferr(po, "unhandled conditional op\n");
1643       }
1644     }
1645
1646     switch (po->op)
1647     {
1648       case OP_MOV:
1649         assert_operand_cnt(2);
1650         propagate_lmod(po, &po->operand[0], &po->operand[1]);
1651         fprintf(fout, "  %s = %s;",
1652             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1653             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1654         break;
1655
1656       case OP_LEA:
1657         assert_operand_cnt(2);
1658         po->operand[1].lmod = OPLM_DWORD; // always
1659         fprintf(fout, "  %s = %s;",
1660             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1661             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 1));
1662         break;
1663
1664       case OP_MOVZX:
1665         assert_operand_cnt(2);
1666         fprintf(fout, "  %s = %s;",
1667             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1668             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1669         break;
1670
1671       case OP_MOVSX:
1672         assert_operand_cnt(2);
1673         switch (po->operand[1].lmod) {
1674         case OPLM_BYTE:
1675           strcpy(buf3, "(s8)");
1676           break;
1677         case OPLM_WORD:
1678           strcpy(buf3, "(s16)");
1679           break;
1680         default:
1681           ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
1682         }
1683         fprintf(fout, "  %s = %s%s;",
1684             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1685             buf3,
1686             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1687         break;
1688
1689       case OP_NOT:
1690         assert_operand_cnt(1);
1691         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
1692         fprintf(fout, "  %s = ~%s;", buf1, buf1);
1693         break;
1694
1695       case OP_CDQ:
1696         assert_operand_cnt(2);
1697         fprintf(fout, "  %s = (s32)%s >> 31;",
1698             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1699             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1700         strcpy(g_comment, "cdq");
1701         break;
1702
1703       // arithmetic w/flags
1704       case OP_ADD:
1705       case OP_SUB:
1706       case OP_AND:
1707       case OP_OR:
1708         propagate_lmod(po, &po->operand[0], &po->operand[1]);
1709         // fallthrough
1710       case OP_SHL:
1711       case OP_SHR:
1712       dualop_arith:
1713         assert_operand_cnt(2);
1714         fprintf(fout, "  %s %s= %s;",
1715             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1716             op_to_c(po),
1717             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1718         last_arith_dst = &po->operand[0];
1719         delayed_flag_op = NULL;
1720         break;
1721
1722       case OP_XOR:
1723         assert_operand_cnt(2);
1724         propagate_lmod(po, &po->operand[0], &po->operand[1]);
1725         if (IS(opr_name(po, 0), opr_name(po, 1))) {
1726           // special case for XOR
1727           fprintf(fout, "  %s = 0;",
1728             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
1729           last_arith_dst = &po->operand[0];
1730           delayed_flag_op = NULL;
1731           break;
1732         }
1733         goto dualop_arith;
1734
1735       case OP_SAR:
1736         assert_operand_cnt(2);
1737         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
1738         fprintf(fout, "  %s = %s%s >> %s;", buf1,
1739           lmod_cast_s(po, po->operand[0].lmod), buf1,
1740           out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1741         last_arith_dst = &po->operand[0];
1742         delayed_flag_op = NULL;
1743         break;
1744
1745       case OP_ADC:
1746       case OP_SBB:
1747         assert_operand_cnt(2);
1748         propagate_lmod(po, &po->operand[0], &po->operand[1]);
1749         fprintf(fout, "  %s %s= %s + cond_c;",
1750             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1751             op_to_c(po),
1752             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1753         last_arith_dst = &po->operand[0];
1754         delayed_flag_op = NULL;
1755         break;
1756
1757       case OP_INC:
1758       case OP_DEC:
1759         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
1760         strcpy(buf2, po->op == OP_INC ? "++" : "--");
1761         fprintf(fout, "  %s%s;", buf1, buf2);
1762         last_arith_dst = &po->operand[0];
1763         delayed_flag_op = NULL;
1764         break;
1765
1766       case OP_NEG:
1767         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
1768         out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], 0);
1769         fprintf(fout, "  %s = -%s%s;", buf1,
1770           lmod_cast_s(po, po->operand[0].lmod), buf2);
1771         last_arith_dst = &po->operand[0];
1772         delayed_flag_op = NULL;
1773         break;
1774
1775       case OP_IMUL:
1776         if (po->operand_cnt == 2)
1777           goto dualop_arith;
1778         if (po->operand_cnt == 3)
1779           ferr(po, "TODO imul3\n");
1780         // fallthrough
1781       case OP_MUL:
1782         assert_operand_cnt(1);
1783         strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
1784         fprintf(fout, "  mul_tmp = %seax * %s%s;\n", buf1, buf1,
1785           out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], 0));
1786         fprintf(fout, "  edx = mul_tmp >> 32;\n");
1787         fprintf(fout, "  eax = mul_tmp;");
1788         last_arith_dst = NULL;
1789         delayed_flag_op = NULL;
1790         break;
1791
1792       case OP_DIV:
1793       case OP_IDIV:
1794         assert_operand_cnt(1);
1795         if (po->operand[0].lmod != OPLM_DWORD)
1796           ferr(po, "unhandled lmod %d\n", po->operand[0].lmod);
1797
1798         // 32bit division is common, look for it
1799         if (scan_for_cdq_edx(i - 1) >= 0) {
1800           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
1801           strcpy(buf2, lmod_cast(po, po->operand[0].lmod,
1802             po->op == OP_IDIV));
1803           fprintf(fout, "  edx = %seax %% %s%s;\n", buf2, buf2, buf1);
1804           fprintf(fout, "  eax = %seax / %s%s;", buf2, buf2, buf1);
1805         }
1806         else
1807           ferr(po, "TODO 64bit divident\n");
1808         last_arith_dst = NULL;
1809         delayed_flag_op = NULL;
1810         break;
1811
1812       case OP_TEST:
1813       case OP_CMP:
1814         propagate_lmod(po, &po->operand[0], &po->operand[1]);
1815         if (po->pfomask != 0) {
1816           for (j = 0; j < 8; j++) {
1817             if (po->pfomask & (1 << j)) {
1818               out_cmp_test(buf1, sizeof(buf1), po, j, 0);
1819               fprintf(fout, "  cond_%s = %s;",
1820                 parsed_flag_op_names[j], buf1);
1821             }
1822           }
1823         }
1824         else
1825           no_output = 1;
1826         delayed_flag_op = po;
1827         break;
1828
1829       // note: we reuse OP_Jcc for SETcc, only flags differ
1830       case OP_JO ... OP_JG:
1831         if (po->flags & OPF_JMP)
1832           fprintf(fout, "    goto %s;", po->operand[0].name);
1833         // else SETcc - should already be handled
1834         break;
1835
1836       case OP_JMP:
1837         assert_operand_cnt(1);
1838         if (po->operand[0].type != OPT_LABEL)
1839           ferr(po, "unhandled call type\n");
1840
1841         fprintf(fout, "  goto %s;", po->operand[0].name);
1842         break;
1843
1844       case OP_CALL:
1845         assert_operand_cnt(1);
1846         if (po->operand[0].type != OPT_LABEL)
1847           ferr(po, "unhandled call type\n");
1848
1849         pp = po->datap;
1850         if (pp == NULL)
1851           ferr(po, "NULL pp\n");
1852
1853         fprintf(fout, "  ");
1854         if (!IS(pp->ret_type, "void")) {
1855           if (po->flags & OPF_TAIL)
1856             fprintf(fout, "return ");
1857           else
1858             fprintf(fout, "eax = ");
1859           if (strchr(pp->ret_type, '*'))
1860             fprintf(fout, "(u32)");
1861         }
1862
1863         fprintf(fout, "%s(", opr_name(po, 0));
1864         for (arg = 0; arg < pp->argc; arg++) {
1865           if (arg > 0)
1866             fprintf(fout, ", ");
1867
1868           if (strchr(pp->arg[arg].type, '*'))
1869             fprintf(fout, "(%s)", pp->arg[arg].type);
1870
1871           if (pp->arg[arg].reg != NULL) {
1872             fprintf(fout, "%s", pp->arg[arg].reg);
1873             continue;
1874           }
1875
1876           // stack arg
1877           tmp_op = pp->arg[arg].datap;
1878           if (tmp_op == NULL)
1879             ferr(po, "parsed_op missing for arg%d\n", arg);
1880           if (tmp_op->datap) {
1881             fprintf(fout, "s_a%ld", (long)tmp_op->datap);
1882           }
1883           else {
1884             fprintf(fout, "%s",
1885               out_src_opr(buf1, sizeof(buf1),
1886                 tmp_op, &tmp_op->operand[0], 0));
1887           }
1888         }
1889         fprintf(fout, ");");
1890
1891         if (po->flags & OPF_TAIL) {
1892           strcpy(g_comment, "tailcall");
1893           if (IS(pp->ret_type, "void"))
1894             fprintf(fout, "\n  return;");
1895         }
1896         delayed_flag_op = NULL;
1897         last_arith_dst = NULL;
1898         break;
1899
1900       case OP_RET:
1901         if (IS(g_func_pp.ret_type, "void"))
1902           fprintf(fout, "  return;");
1903         else
1904           fprintf(fout, "  return eax;");
1905         break;
1906
1907       case OP_PUSH:
1908         if (po->datap) {
1909           // special case - saved func arg
1910           fprintf(fout, "  s_a%ld = %s;", (long)po->datap,
1911             out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0));
1912           break;
1913         }
1914         ferr(po, "push encountered\n");
1915         break;
1916
1917       case OP_POP:
1918         ferr(po, "pop encountered\n");
1919         break;
1920
1921       default:
1922         no_output = 1;
1923         ferr(po, "unhandled op type %d, flags %x\n",
1924           po->op, po->flags);
1925         break;
1926     }
1927
1928     if (g_comment[0] != 0) {
1929       fprintf(fout, "  // %s", g_comment);
1930       g_comment[0] = 0;
1931       no_output = 0;
1932     }
1933     if (!no_output)
1934       fprintf(fout, "\n");
1935
1936     // see is delayed flag stuff is still valid
1937     if (delayed_flag_op != NULL && delayed_flag_op != po) {
1938       if (is_any_opr_modified(delayed_flag_op, po))
1939         delayed_flag_op = NULL;
1940     }
1941
1942     if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
1943       if (is_opr_modified(last_arith_dst, po))
1944         last_arith_dst = NULL;
1945     }
1946   }
1947
1948   fprintf(fout, "}\n\n");
1949
1950   // cleanup
1951   for (i = 0; i < opcnt; i++) {
1952     if (ops[i].op == OP_CALL) {
1953       pp = ops[i].datap;
1954       if (pp) {
1955         proto_release(pp);
1956         free(pp);
1957       }
1958     }
1959   }
1960   proto_release(&g_func_pp);
1961 }
1962
1963 int main(int argc, char *argv[])
1964 {
1965   FILE *fout, *fasm, *fhdr;
1966   char line[256];
1967   char words[16][256];
1968   int in_func = 0;
1969   int eq_alloc;
1970   int pi = 0;
1971   int len;
1972   char *p;
1973   int wordc;
1974
1975   if (argc != 4) {
1976     printf("usage:\n%s <.c> <.asm> <hdrf>\n",
1977       argv[0]);
1978     return 1;
1979   }
1980
1981   hdrfn = argv[3];
1982   fhdr = fopen(hdrfn, "r");
1983   my_assert_not(fhdr, NULL);
1984
1985   asmfn = argv[2];
1986   fasm = fopen(asmfn, "r");
1987   my_assert_not(fasm, NULL);
1988
1989   fout = fopen(argv[1], "w");
1990   my_assert_not(fout, NULL);
1991
1992   eq_alloc = 128;
1993   g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
1994   my_assert_not(g_eqs, NULL);
1995
1996   while (fgets(line, sizeof(line), fasm))
1997   {
1998     asmln++;
1999
2000     p = sskip(line);
2001     if (*p == 0 || *p == ';')
2002       continue;
2003
2004     memset(words, 0, sizeof(words));
2005     for (wordc = 0; wordc < 16; wordc++) {
2006       p = sskip(next_word(words[wordc], sizeof(words[0]), p));
2007       if (*p == 0 || *p == ';') {
2008         wordc++;
2009         break;
2010       }
2011     }
2012
2013     if (wordc == 0) {
2014       // shouldn't happen
2015       awarn("wordc == 0?\n");
2016       continue;
2017     }
2018
2019     // don't care about this:
2020     if (words[0][0] == '.'
2021         || IS(words[0], "include")
2022         || IS(words[0], "assume") || IS(words[1], "segment")
2023         || IS(words[0], "align"))
2024     {
2025       continue;
2026     }
2027
2028     if (IS(words[1], "proc")) {
2029       if (in_func)
2030         aerr("proc '%s' while in_func '%s'?\n",
2031           words[0], g_func);
2032       strcpy(g_func, words[0]);
2033       in_func = 1;
2034       continue;
2035     }
2036
2037     if (IS(words[1], "endp")) {
2038       if (!in_func)
2039         aerr("endp '%s' while not in_func?\n", words[0]);
2040       if (!IS(g_func, words[0]))
2041         aerr("endp '%s' while in_func '%s'?\n",
2042           words[0], g_func);
2043       gen_func(fout, fhdr, g_func, pi);
2044       in_func = 0;
2045       g_func[0] = 0;
2046       if (pi != 0) {
2047         memset(&ops, 0, pi * sizeof(ops[0]));
2048         memset(g_labels, 0, pi * sizeof(g_labels[0]));
2049         pi = 0;
2050       }
2051       g_eqcnt = 0;
2052       continue;
2053     }
2054
2055     if (IS(words[1], "=")) {
2056       if (wordc != 5)
2057         aerr("unhandled equ, wc=%d\n", wordc);
2058       if (g_eqcnt >= eq_alloc) {
2059         eq_alloc *= 2;
2060         g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
2061         my_assert_not(g_eqs, NULL);
2062       }
2063
2064       len = strlen(words[0]);
2065       if (len > sizeof(g_eqs[0].name) - 1)
2066         aerr("equ name too long: %d\n", len);
2067       strcpy(g_eqs[g_eqcnt].name, words[0]);
2068
2069       if (!IS(words[3], "ptr"))
2070         aerr("unhandled equ\n");
2071       if (IS(words[2], "dword"))
2072         g_eqs[g_eqcnt].lmod = OPLM_DWORD;
2073       else if (IS(words[2], "word"))
2074         g_eqs[g_eqcnt].lmod = OPLM_WORD;
2075       else if (IS(words[2], "byte"))
2076         g_eqs[g_eqcnt].lmod = OPLM_BYTE;
2077       else
2078         aerr("bad lmod: '%s'\n", words[2]);
2079
2080       g_eqs[g_eqcnt].offset = parse_number(words[4]);
2081       g_eqcnt++;
2082       continue;
2083     }
2084
2085     if (pi >= ARRAY_SIZE(ops))
2086       aerr("too many ops\n");
2087
2088     p = strchr(words[0], ':');
2089     if (p != NULL) {
2090       len = p - words[0];
2091       if (len > sizeof(g_labels[0]) - 1)
2092         aerr("label too long: %d\n", len);
2093       if (g_labels[pi][0] != 0)
2094         aerr("dupe label?\n");
2095       memcpy(g_labels[pi], words[0], len);
2096       g_labels[pi][len] = 0;
2097       continue;
2098     }
2099
2100     parse_op(&ops[pi], words, wordc);
2101     pi++;
2102
2103     (void)proto_parse;
2104   }
2105
2106   fclose(fout);
2107   fclose(fasm);
2108   fclose(fhdr);
2109
2110   return 0;
2111 }
2112
2113 // vim:ts=2:shiftwidth=2:expandtab