80d414f4a80a2f12db30dca167535d348cdf5fc9
[deliverable/binutils-gdb.git] / opcodes / i386-gen.c
1 /* Copyright 2007 Free Software Foundation, Inc.
2
3 This file is part of GAS, the GNU Assembler, and GDB, the GNU Debugger.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <errno.h>
23 #include "getopt.h"
24 #include "libiberty.h"
25 #include "safe-ctype.h"
26
27 #include "i386-opc.h"
28
29 #include <libintl.h>
30 #define _(String) gettext (String)
31
32 static const char *program_name = NULL;
33 static int debug = 0;
34
35 static void
36 fail (const char *message, ...)
37 {
38 va_list args;
39
40 va_start (args, message);
41 fprintf (stderr, _("%s: Error: "), program_name);
42 vfprintf (stderr, message, args);
43 va_end (args);
44 xexit (1);
45 }
46
47 /* Remove leading white spaces. */
48
49 static char *
50 remove_leading_whitespaces (char *str)
51 {
52 while (ISSPACE (*str))
53 str++;
54 return str;
55 }
56
57 /* Remove trailing white spaces. */
58
59 static void
60 remove_trailing_whitespaces (char *str)
61 {
62 size_t last = strlen (str);
63
64 if (last == 0)
65 return;
66
67 do
68 {
69 last--;
70 if (ISSPACE (str [last]))
71 str[last] = '\0';
72 else
73 break;
74 }
75 while (last != 0);
76 }
77
78 /* Find next field separated by '.' and terminate it. Return a
79 pointer to the one after it. */
80
81 static char *
82 next_field (char *str, char **next)
83 {
84 char *p;
85
86 p = remove_leading_whitespaces (str);
87 for (str = p; *str != ',' && *str != '\0'; str++);
88
89 *str = '\0';
90 remove_trailing_whitespaces (p);
91
92 *next = str + 1;
93
94 return p;
95 }
96
97 static void
98 process_i386_opcodes (void)
99 {
100 FILE *fp = fopen ("i386-opc.tbl", "r");
101 char buf[2048];
102 unsigned int i;
103 char *str, *p, *last;
104 char *name, *operands, *base_opcode, *extension_opcode;
105 char *cpu_flags, *opcode_modifier, *operand_types [MAX_OPERANDS];
106
107 if (fp == NULL)
108 fail (_("can't find i386-opc.tbl for reading\n"));
109
110 printf ("\n/* i386 opcode table. */\n\n");
111 printf ("const template i386_optab[] =\n{\n");
112
113 while (!feof (fp))
114 {
115 if (fgets (buf, sizeof (buf), fp) == NULL)
116 break;
117
118 p = remove_leading_whitespaces (buf);
119
120 /* Skip comments. */
121 str = strstr (p, "//");
122 if (str != NULL)
123 str[0] = '\0';
124
125 /* Remove trailing white spaces. */
126 remove_trailing_whitespaces (p);
127
128 switch (p[0])
129 {
130 case '#':
131 printf ("%s\n", p);
132 case '\0':
133 continue;
134 break;
135 default:
136 break;
137 }
138
139 last = p + strlen (p);
140
141 /* Find name. */
142 name = next_field (p, &str);
143
144 if (str >= last)
145 abort ();
146
147 /* Find number of operands. */
148 operands = next_field (str, &str);
149
150 if (str >= last)
151 abort ();
152
153 /* Find base_opcode. */
154 base_opcode = next_field (str, &str);
155
156 if (str >= last)
157 abort ();
158
159 /* Find extension_opcode. */
160 extension_opcode = next_field (str, &str);
161
162 if (str >= last)
163 abort ();
164
165 /* Find cpu_flags. */
166 cpu_flags = next_field (str, &str);
167
168 if (str >= last)
169 abort ();
170
171 /* Find opcode_modifier. */
172 opcode_modifier = next_field (str, &str);
173
174 if (str >= last)
175 abort ();
176
177 /* Remove the first {. */
178 str = remove_leading_whitespaces (str);
179 if (*str != '{')
180 abort ();
181 str = remove_leading_whitespaces (str + 1);
182
183 i = strlen (str);
184
185 /* There are at least "X}". */
186 if (i < 2)
187 abort ();
188
189 /* Remove trailing white spaces and }. */
190 do
191 {
192 i--;
193 if (ISSPACE (str[i]) || str[i] == '}')
194 str[i] = '\0';
195 else
196 break;
197 }
198 while (i != 0);
199
200 last = str + i;
201
202 /* Find operand_types. */
203 for (i = 0; i < ARRAY_SIZE (operand_types); i++)
204 {
205 if (str >= last)
206 {
207 operand_types [i] = NULL;
208 break;
209 }
210
211 operand_types [i] = next_field (str, &str);
212 if (*operand_types[i] == '0')
213 {
214 if (i != 0)
215 operand_types[i] = NULL;
216 break;
217 }
218 }
219
220 printf (" { \"%s\", %s, %s, %s, %s,\n",
221 name, operands, base_opcode, extension_opcode,
222 cpu_flags);
223
224 printf (" %s,\n", opcode_modifier);
225
226 printf (" { ");
227
228 for (i = 0; i < ARRAY_SIZE (operand_types); i++)
229 {
230 if (operand_types[i] == NULL
231 || *operand_types[i] == '0')
232 {
233 if (i == 0)
234 printf ("0");
235 break;
236 }
237
238 if (i != 0)
239 printf (",\n ");
240
241 printf ("%s", operand_types[i]);
242 }
243 printf (" } },\n");
244 }
245
246 printf (" { NULL, 0, 0, 0, 0, 0, { 0 } }\n");
247 printf ("};\n");
248 }
249
250 static void
251 process_i386_registers (void)
252 {
253 FILE *fp = fopen ("i386-reg.tbl", "r");
254 char buf[2048];
255 char *str, *p, *last;
256 char *reg_name, *reg_type, *reg_flags, *reg_num;
257
258 if (fp == NULL)
259 fail (_("can't find i386-reg.tbl for reading\n"));
260
261 printf ("\n/* i386 register table. */\n\n");
262 printf ("const reg_entry i386_regtab[] =\n{\n");
263
264 while (!feof (fp))
265 {
266 if (fgets (buf, sizeof (buf), fp) == NULL)
267 break;
268
269 p = remove_leading_whitespaces (buf);
270
271 /* Skip comments. */
272 str = strstr (p, "//");
273 if (str != NULL)
274 str[0] = '\0';
275
276 /* Remove trailing white spaces. */
277 remove_trailing_whitespaces (p);
278
279 switch (p[0])
280 {
281 case '#':
282 printf ("%s\n", p);
283 case '\0':
284 continue;
285 break;
286 default:
287 break;
288 }
289
290 last = p + strlen (p);
291
292 /* Find reg_name. */
293 reg_name = next_field (p, &str);
294
295 if (str >= last)
296 abort ();
297
298 /* Find reg_type. */
299 reg_type = next_field (str, &str);
300
301 if (str >= last)
302 abort ();
303
304 /* Find reg_flags. */
305 reg_flags = next_field (str, &str);
306
307 if (str >= last)
308 abort ();
309
310 /* Find reg_num. */
311 reg_num = next_field (str, &str);
312
313 printf (" { \"%s\", %s, %s, %s },\n",
314 reg_name, reg_type, reg_flags, reg_num);
315 }
316
317 printf ("};\n");
318
319 printf ("\nconst unsigned int i386_regtab_size = ARRAY_SIZE (i386_regtab);\n");
320 }
321
322 /* Program options. */
323 #define OPTION_SRCDIR 200
324
325 struct option long_options[] =
326 {
327 {"srcdir", required_argument, NULL, OPTION_SRCDIR},
328 {"debug", no_argument, NULL, 'd'},
329 {"version", no_argument, NULL, 'V'},
330 {"help", no_argument, NULL, 'h'},
331 {0, no_argument, NULL, 0}
332 };
333
334 static void
335 print_version (void)
336 {
337 printf ("%s: version 1.0\n", program_name);
338 xexit (0);
339 }
340
341 static void
342 usage (FILE * stream, int status)
343 {
344 fprintf (stream, "Usage: %s [-V | --version] [-d | --debug] [--srcdir=dirname] [--help]\n",
345 program_name);
346 xexit (status);
347 }
348
349 int
350 main (int argc, char **argv)
351 {
352 extern int chdir (char *);
353 char *srcdir = NULL;
354 int c;
355
356 program_name = *argv;
357 xmalloc_set_program_name (program_name);
358
359 while ((c = getopt_long (argc, argv, "vVdh", long_options, 0)) != EOF)
360 switch (c)
361 {
362 case OPTION_SRCDIR:
363 srcdir = optarg;
364 break;
365 case 'V':
366 case 'v':
367 print_version ();
368 break;
369 case 'd':
370 debug = 1;
371 break;
372 case 'h':
373 case '?':
374 usage (stderr, 0);
375 default:
376 case 0:
377 break;
378 }
379
380 if (optind != argc)
381 usage (stdout, 1);
382
383 if (srcdir != NULL)
384 if (chdir (srcdir) != 0)
385 fail (_("unable to change directory to \"%s\", errno = %s\n"),
386 srcdir, strerror (errno));
387
388 printf ("/* This file is automatically generated by i386-gen. Do not edit! */\n");
389
390 process_i386_opcodes ();
391 process_i386_registers ();
392
393 exit (0);
394 }
This page took 0.0513 seconds and 3 git commands to generate.