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