start work on asm->c translation
[ia32rtools.git] / tools / protoparse.h
1
2 struct parsed_proto {
3         struct {
4                 char *reg;
5                 const char *type;
6         } arg[16];
7         const char *ret_type;
8         int is_stdcall;
9         int argc;
10         int argc_stack;
11         int argc_reg;
12 };
13
14 static const char *hdrfn;
15 static int hdrfline = 0;
16
17 static int find_protostr(char *dst, size_t dlen, FILE *fhdr, const char *sym)
18 {
19         int line = 0;
20         char *p;
21
22         rewind(fhdr);
23
24         while (fgets(dst, dlen, fhdr))
25         {
26                 line++;
27                 if (strstr(dst, sym) != NULL)
28                         break;
29         }
30         hdrfline = line;
31
32         if (feof(fhdr))
33                 return -1;
34
35         p = dst + strlen(dst);
36         for (p--; p > dst && my_isblank(*p); --p)
37                 *p = 0;
38
39         return 0;
40 }
41
42 static int get_regparm(char *dst, size_t dlen, char *p)
43 {
44         int i, o;
45
46         if (*p != '<')
47                 return 0;
48
49         for (o = 0, i = 1; o < dlen; i++) {
50                 if (p[i] == 0)
51                         return 0;
52                 if (p[i] == '>')
53                         break;
54                 dst[o++] = p[i];
55         }
56         dst[o] = 0;
57         return i + 1;
58 }
59
60 // hmh..
61 static const char *known_types[] = {
62         "const void *",
63         "void *",
64         "char *",
65         "FILE *",
66         "unsigned __int8",
67         "unsigned __int16",
68         "unsigned int",
69         "signed int",
70         "char",
71         "__int8",
72         "__int16",
73         "int",
74         "bool",
75         "void",
76         "BYTE",
77         "WORD",
78         "DWORD",
79         "HMODULE",
80         "HANDLE",
81         "HWND",
82         "LPCSTR",
83         "size_t",
84 };
85
86 static const char *check_type(const char *name)
87 {
88         int i, l;
89
90         for (i = 0; i < ARRAY_SIZE(known_types); i++) {
91                 l = strlen(known_types[i]);
92                 if (strncmp(known_types[i], name, l) == 0)
93                         return known_types[i];
94         }
95
96         return NULL;
97 }
98
99 /* args are always expanded to 32bit */
100 static const char *map_reg(const char *reg)
101 {
102         const char *regs_f[] = { "eax", "ebx", "ecx", "edx", "esi", "edi" };
103         const char *regs_w[] = { "ax",  "bx",  "cx",  "dx",  "si",  "di" };
104         const char *regs_b[] = { "al",  "bl",  "cl",  "dl" };
105         int i;
106
107         for (i = 0; i < ARRAY_SIZE(regs_w); i++)
108                 if (IS(reg, regs_w[i]))
109                         return regs_f[i];
110
111         for (i = 0; i < ARRAY_SIZE(regs_b); i++)
112                 if (IS(reg, regs_b[i]))
113                         return regs_f[i];
114
115         return reg;
116 }
117
118 static int parse_protostr(char *protostr, struct parsed_proto *pp)
119 {
120         char regparm[16];
121         char buf[256];
122         char cconv[32];
123         const char *kt;
124         int xarg = 0;
125         int ret;
126         char *p;
127         int i;
128
129         p = protostr;
130         if (p[0] == '/' && p[1] == '/') {
131                 //printf("warning: decl for sym '%s' is commented out\n", sym);
132                 p = sskip(p + 2);
133         }
134
135         kt = check_type(p);
136         if (kt == NULL) {
137                 printf("%s:%d:%ld: unhandled return in '%s'\n",
138                         hdrfn, hdrfline, (p - protostr) + 1, protostr);
139                 return 1;
140         }
141         pp->ret_type = kt;
142         p += strlen(kt);
143         p = sskip(p);
144
145         p = next_word(cconv, sizeof(cconv), p);
146         p = sskip(p);
147         if (cconv[0] == 0) {
148                 printf("%s:%d:%ld: cconv missing\n",
149                         hdrfn, hdrfline, (p - protostr) + 1);
150                 return 1;
151         }
152         if      (IS(cconv, "__cdecl"))
153                 pp->is_stdcall = 0;
154         else if (IS(cconv, "__stdcall"))
155                 pp->is_stdcall = 1;
156         else if (IS(cconv, "__fastcall"))
157                 pp->is_stdcall = 1;
158         else if (IS(cconv, "__thiscall"))
159                 pp->is_stdcall = 1;
160         else if (IS(cconv, "__userpurge"))
161                 pp->is_stdcall = 1; // in all cases seen..
162         else if (IS(cconv, "__usercall"))
163                 pp->is_stdcall = 0; // ..or is it?
164         else {
165                 printf("%s:%d:%ld: unhandled cconv: '%s'\n",
166                         hdrfn, hdrfline, (p - protostr) + 1, cconv);
167                 return 1;
168         }
169
170         p = next_idt(buf, sizeof(buf), p);
171         p = sskip(p);
172         if (buf[0] == 0) {
173                 printf("%s:%d:%ld: func name missing\n",
174                                 hdrfn, hdrfline, (p - protostr) + 1);
175                 return 1;
176         }
177
178         ret = get_regparm(regparm, sizeof(regparm), p);
179         if (ret > 0) {
180                 if (!IS(regparm, "eax") && !IS(regparm, "ax")
181                  && !IS(regparm, "al"))
182                 {
183                         printf("%s:%d:%ld: bad regparm: %s\n",
184                                 hdrfn, hdrfline, (p - protostr) + 1, regparm);
185                         return 1;
186                 }
187                 p += ret;
188                 p = sskip(p);
189         }
190
191         if (*p != '(') {
192                 printf("%s:%d:%ld: '(' expected, got '%c'\n",
193                                 hdrfn, hdrfline, (p - protostr) + 1, *p);
194                 return 1;
195         }
196         p++;
197
198         while (1) {
199                 p = sskip(p);
200                 if (*p == ')')
201                         break;
202                 if (*p == ',')
203                         p = sskip(p + 1);
204
205                 xarg++;
206
207                 kt = check_type(p);
208                 if (kt == NULL) {
209                         printf("%s:%d:%ld: unhandled type for arg%d\n",
210                                 hdrfn, hdrfline, (p - protostr) + 1, xarg);
211                         return 1;
212                 }
213                 pp->arg[xarg - 1].type = kt;
214                 p += strlen(kt);
215                 p = sskip(p);
216
217                 p = next_idt(buf, sizeof(buf), p);
218                 p = sskip(p);
219 #if 0
220                 if (buf[0] == 0) {
221                         printf("%s:%d:%ld: idt missing for arg%d\n",
222                                 hdrfn, hdrfline, (p - protostr) + 1, xarg);
223                         return 1;
224                 }
225 #endif
226                 pp->arg[xarg - 1].reg = NULL;
227
228                 ret = get_regparm(regparm, sizeof(regparm), p);
229                 if (ret > 0) {
230                         p += ret;
231                         p = sskip(p);
232
233                         pp->arg[xarg - 1].reg = strdup(map_reg(regparm));
234                 }
235         }
236
237         if (xarg > 0 && (IS(cconv, "__fastcall") || IS(cconv, "__thiscall"))) {
238                 if (pp->arg[0].reg != NULL) {
239                         printf("%s:%d: %s with arg1 spec %s?\n",
240                                 hdrfn, hdrfline, cconv, pp->arg[0].reg);
241                 }
242                 pp->arg[0].reg = strdup("ecx");
243         }
244
245         if (xarg > 1 && IS(cconv, "__fastcall")) {
246                 if (pp->arg[1].reg != NULL) {
247                         printf("%s:%d: %s with arg2 spec %s?\n",
248                                 hdrfn, hdrfline, cconv, pp->arg[1].reg);
249                 }
250                 pp->arg[1].reg = strdup("edx");
251         }
252
253         pp->argc = xarg;
254
255         for (i = 0; i < pp->argc; i++) {
256                 if (pp->arg[i].reg == NULL)
257                         pp->argc_stack++;
258                 else
259                         pp->argc_reg++;
260         }
261
262         return 0;
263 }
264
265 static int proto_parse(FILE *fhdr, const char *sym, struct parsed_proto *pp)
266 {
267         char protostr[256];
268         int ret;
269
270         memset(pp, 0, sizeof(*pp));
271
272         ret = find_protostr(protostr, sizeof(protostr), fhdr, sym);
273         if (ret != 0) {
274                 printf("%s: sym '%s' is missing\n", hdrfn, sym);
275                 return ret;
276         }
277
278         return parse_protostr(protostr, pp);
279 }
280
281 static void proto_release(struct parsed_proto *pp)
282 {
283         int i;
284
285         for (i = 0; i < pp->argc; i++) {
286                 if (pp->arg[i].reg == NULL)
287                         free(pp->arg[i].reg);
288         }
289 }