2007-09-06 H.J. Lu <hongjiu.lu@intel.com>
[binutils.git] / opcodes / i386-gen.c
blobc610a75702407e1dde0cb8f664e82db0bb41775a
1 /* Copyright 2007 Free Software Foundation, Inc.
3 This file is part of the GNU opcodes library.
5 This library 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 3, or (at your option)
8 any later version.
10 It is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
13 License for more details.
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,
18 MA 02110-1301, USA. */
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24 #include "getopt.h"
25 #include "libiberty.h"
26 #include "safe-ctype.h"
28 #include "i386-opc.h"
30 #include <libintl.h>
31 #define _(String) gettext (String)
33 static const char *program_name = NULL;
34 static int debug = 0;
36 static void
37 fail (const char *message, ...)
39 va_list args;
41 va_start (args, message);
42 fprintf (stderr, _("%s: Error: "), program_name);
43 vfprintf (stderr, message, args);
44 va_end (args);
45 xexit (1);
48 static void
49 process_copyright (FILE *fp)
51 fprintf (fp, "/* This file is automatically generated by i386-gen. Do not edit! */\n\
52 /* Copyright 2007 Free Software Foundation, Inc.\n\
53 \n\
54 This file is part of the GNU opcodes library.\n\
55 \n\
56 This library is free software; you can redistribute it and/or modify\n\
57 it under the terms of the GNU General Public License as published by\n\
58 the Free Software Foundation; either version 3, or (at your option)\n\
59 any later version.\n\
60 \n\
61 It is distributed in the hope that it will be useful, but WITHOUT\n\
62 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n\
63 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\n\
64 License for more details.\n\
65 \n\
66 You should have received a copy of the GNU General Public License\n\
67 along with this program; if not, write to the Free Software\n\
68 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,\n\
69 MA 02110-1301, USA. */\n");
72 /* Remove leading white spaces. */
74 static char *
75 remove_leading_whitespaces (char *str)
77 while (ISSPACE (*str))
78 str++;
79 return str;
82 /* Remove trailing white spaces. */
84 static void
85 remove_trailing_whitespaces (char *str)
87 size_t last = strlen (str);
89 if (last == 0)
90 return;
94 last--;
95 if (ISSPACE (str [last]))
96 str[last] = '\0';
97 else
98 break;
100 while (last != 0);
103 /* Find next field separated by '.' and terminate it. Return a
104 pointer to the one after it. */
106 static char *
107 next_field (char *str, char **next)
109 char *p;
111 p = remove_leading_whitespaces (str);
112 for (str = p; *str != ',' && *str != '\0'; str++);
114 *str = '\0';
115 remove_trailing_whitespaces (p);
117 *next = str + 1;
119 return p;
122 static void
123 process_i386_opcodes (FILE *table)
125 FILE *fp = fopen ("i386-opc.tbl", "r");
126 char buf[2048];
127 unsigned int i;
128 char *str, *p, *last;
129 char *name, *operands, *base_opcode, *extension_opcode;
130 char *cpu_flags, *opcode_modifier, *operand_types [MAX_OPERANDS];
132 if (fp == NULL)
133 fail (_("can't find i386-opc.tbl for reading, errno = %s\n"),
134 strerror (errno));
136 fprintf (table, "\n/* i386 opcode table. */\n\n");
137 fprintf (table, "const template i386_optab[] =\n{\n");
139 while (!feof (fp))
141 if (fgets (buf, sizeof (buf), fp) == NULL)
142 break;
144 p = remove_leading_whitespaces (buf);
146 /* Skip comments. */
147 str = strstr (p, "//");
148 if (str != NULL)
149 str[0] = '\0';
151 /* Remove trailing white spaces. */
152 remove_trailing_whitespaces (p);
154 switch (p[0])
156 case '#':
157 fprintf (table, "%s\n", p);
158 case '\0':
159 continue;
160 break;
161 default:
162 break;
165 last = p + strlen (p);
167 /* Find name. */
168 name = next_field (p, &str);
170 if (str >= last)
171 abort ();
173 /* Find number of operands. */
174 operands = next_field (str, &str);
176 if (str >= last)
177 abort ();
179 /* Find base_opcode. */
180 base_opcode = next_field (str, &str);
182 if (str >= last)
183 abort ();
185 /* Find extension_opcode. */
186 extension_opcode = next_field (str, &str);
188 if (str >= last)
189 abort ();
191 /* Find cpu_flags. */
192 cpu_flags = next_field (str, &str);
194 if (str >= last)
195 abort ();
197 /* Find opcode_modifier. */
198 opcode_modifier = next_field (str, &str);
200 if (str >= last)
201 abort ();
203 /* Remove the first {. */
204 str = remove_leading_whitespaces (str);
205 if (*str != '{')
206 abort ();
207 str = remove_leading_whitespaces (str + 1);
209 i = strlen (str);
211 /* There are at least "X}". */
212 if (i < 2)
213 abort ();
215 /* Remove trailing white spaces and }. */
218 i--;
219 if (ISSPACE (str[i]) || str[i] == '}')
220 str[i] = '\0';
221 else
222 break;
224 while (i != 0);
226 last = str + i;
228 /* Find operand_types. */
229 for (i = 0; i < ARRAY_SIZE (operand_types); i++)
231 if (str >= last)
233 operand_types [i] = NULL;
234 break;
237 operand_types [i] = next_field (str, &str);
238 if (*operand_types[i] == '0')
240 if (i != 0)
241 operand_types[i] = NULL;
242 break;
246 fprintf (table, " { \"%s\", %s, %s, %s, %s,\n",
247 name, operands, base_opcode, extension_opcode,
248 cpu_flags);
250 fprintf (table, " %s,\n", opcode_modifier);
252 fprintf (table, " { ");
254 for (i = 0; i < ARRAY_SIZE (operand_types); i++)
256 if (operand_types[i] == NULL
257 || *operand_types[i] == '0')
259 if (i == 0)
260 fprintf (table, "0");
261 break;
264 if (i != 0)
265 fprintf (table, ",\n ");
267 fprintf (table, "%s", operand_types[i]);
269 fprintf (table, " } },\n");
272 fclose (fp);
274 fprintf (table, " { NULL, 0, 0, 0, 0, 0, { 0 } }\n");
275 fprintf (table, "};\n");
278 static void
279 process_i386_registers (FILE *table)
281 FILE *fp = fopen ("i386-reg.tbl", "r");
282 char buf[2048];
283 char *str, *p, *last;
284 char *reg_name, *reg_type, *reg_flags, *reg_num;
286 if (fp == NULL)
287 fail (_("can't find i386-reg.tbl for reading, errno = %s\n"),
288 strerror (errno));
290 fprintf (table, "\n/* i386 register table. */\n\n");
291 fprintf (table, "const reg_entry i386_regtab[] =\n{\n");
293 while (!feof (fp))
295 if (fgets (buf, sizeof (buf), fp) == NULL)
296 break;
298 p = remove_leading_whitespaces (buf);
300 /* Skip comments. */
301 str = strstr (p, "//");
302 if (str != NULL)
303 str[0] = '\0';
305 /* Remove trailing white spaces. */
306 remove_trailing_whitespaces (p);
308 switch (p[0])
310 case '#':
311 fprintf (table, "%s\n", p);
312 case '\0':
313 continue;
314 break;
315 default:
316 break;
319 last = p + strlen (p);
321 /* Find reg_name. */
322 reg_name = next_field (p, &str);
324 if (str >= last)
325 abort ();
327 /* Find reg_type. */
328 reg_type = next_field (str, &str);
330 if (str >= last)
331 abort ();
333 /* Find reg_flags. */
334 reg_flags = next_field (str, &str);
336 if (str >= last)
337 abort ();
339 /* Find reg_num. */
340 reg_num = next_field (str, &str);
342 fprintf (table, " { \"%s\", %s, %s, %s },\n",
343 reg_name, reg_type, reg_flags, reg_num);
346 fclose (fp);
348 fprintf (table, "};\n");
350 fprintf (table, "\nconst unsigned int i386_regtab_size = ARRAY_SIZE (i386_regtab);\n");
353 /* Program options. */
354 #define OPTION_SRCDIR 200
356 struct option long_options[] =
358 {"srcdir", required_argument, NULL, OPTION_SRCDIR},
359 {"debug", no_argument, NULL, 'd'},
360 {"version", no_argument, NULL, 'V'},
361 {"help", no_argument, NULL, 'h'},
362 {0, no_argument, NULL, 0}
365 static void
366 print_version (void)
368 printf ("%s: version 1.0\n", program_name);
369 xexit (0);
372 static void
373 usage (FILE * stream, int status)
375 fprintf (stream, "Usage: %s [-V | --version] [-d | --debug] [--srcdir=dirname] [--help]\n",
376 program_name);
377 xexit (status);
381 main (int argc, char **argv)
383 extern int chdir (char *);
384 char *srcdir = NULL;
385 int c;
386 FILE *table;
388 program_name = *argv;
389 xmalloc_set_program_name (program_name);
391 while ((c = getopt_long (argc, argv, "vVdh", long_options, 0)) != EOF)
392 switch (c)
394 case OPTION_SRCDIR:
395 srcdir = optarg;
396 break;
397 case 'V':
398 case 'v':
399 print_version ();
400 break;
401 case 'd':
402 debug = 1;
403 break;
404 case 'h':
405 case '?':
406 usage (stderr, 0);
407 default:
408 case 0:
409 break;
412 if (optind != argc)
413 usage (stdout, 1);
415 if (srcdir != NULL)
416 if (chdir (srcdir) != 0)
417 fail (_("unable to change directory to \"%s\", errno = %s\n"),
418 srcdir, strerror (errno));
420 table = fopen ("i386-tbl.h", "w");
421 if (table == NULL)
422 fail (_("can't create i386-tbl.h, errno = %s\n"), strerror (errno));
424 process_copyright (table);
426 process_i386_opcodes (table);
427 process_i386_registers (table);
429 fclose (table);
431 exit (0);