]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/binutils/opcodes/i386-gen.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / binutils / 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 }