blob: 2451d0e96480a6add5cd32d50eceb383f5a8b7ff [file] [log] [blame]
/* Copyright 2007 Free Software Foundation, Inc.
This file is part of the GNU opcodes library.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
It is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "getopt.h"
#include "libiberty.h"
#include "safe-ctype.h"
#include "i386-opc.h"
#include <libintl.h>
#define _(String) gettext (String)
static const char *program_name = NULL;
static int debug = 0;
static void
fail (const char *message, ...)
{
va_list args;
va_start (args, message);
fprintf (stderr, _("%s: Error: "), program_name);
vfprintf (stderr, message, args);
va_end (args);
xexit (1);
}
static void
process_copyright (FILE *fp)
{
fprintf (fp, "/* This file is automatically generated by i386-gen. Do not edit! */\n\
/* Copyright 2007 Free Software Foundation, Inc.\n\
\n\
This file is part of the GNU opcodes library.\n\
\n\
This library is free software; you can redistribute it and/or modify\n\
it under the terms of the GNU General Public License as published by\n\
the Free Software Foundation; either version 3, or (at your option)\n\
any later version.\n\
\n\
It is distributed in the hope that it will be useful, but WITHOUT\n\
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n\
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\n\
License for more details.\n\
\n\
You should have received a copy of the GNU General Public License\n\
along with this program; if not, write to the Free Software\n\
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,\n\
MA 02110-1301, USA. */\n");
}
/* Remove leading white spaces. */
static char *
remove_leading_whitespaces (char *str)
{
while (ISSPACE (*str))
str++;
return str;
}
/* Remove trailing white spaces. */
static void
remove_trailing_whitespaces (char *str)
{
size_t last = strlen (str);
if (last == 0)
return;
do
{
last--;
if (ISSPACE (str [last]))
str[last] = '\0';
else
break;
}
while (last != 0);
}
/* Find next field separated by SEP and terminate it. Return a
pointer to the one after it. */
static char *
next_field (char *str, char sep, char **next)
{
char *p;
p = remove_leading_whitespaces (str);
for (str = p; *str != sep && *str != '\0'; str++);
*str = '\0';
remove_trailing_whitespaces (p);
*next = str + 1;
return p;
}
static void
process_i386_opcodes (FILE *table)
{
FILE *fp = fopen ("i386-opc.tbl", "r");
char buf[2048];
unsigned int i;
char *str, *p, *last;
char *name, *operands, *base_opcode, *extension_opcode;
char *cpu_flags, *opcode_modifier, *operand_types [MAX_OPERANDS];
if (fp == NULL)
fail (_("can't find i386-opc.tbl for reading, errno = %s\n"),
strerror (errno));
fprintf (table, "\n/* i386 opcode table. */\n\n");
fprintf (table, "const template i386_optab[] =\n{\n");
while (!feof (fp))
{
if (fgets (buf, sizeof (buf), fp) == NULL)
break;
p = remove_leading_whitespaces (buf);
/* Skip comments. */
str = strstr (p, "//");
if (str != NULL)
str[0] = '\0';
/* Remove trailing white spaces. */
remove_trailing_whitespaces (p);
switch (p[0])
{
case '#':
fprintf (table, "%s\n", p);
case '\0':
continue;
break;
default:
break;
}
last = p + strlen (p);
/* Find name. */
name = next_field (p, ',', &str);
if (str >= last)
abort ();
/* Find number of operands. */
operands = next_field (str, ',', &str);
if (str >= last)
abort ();
/* Find base_opcode. */
base_opcode = next_field (str, ',', &str);
if (str >= last)
abort ();
/* Find extension_opcode. */
extension_opcode = next_field (str, ',', &str);
if (str >= last)
abort ();
/* Find cpu_flags. */
cpu_flags = next_field (str, ',', &str);
if (str >= last)
abort ();
/* Find opcode_modifier. */
opcode_modifier = next_field (str, ',', &str);
if (str >= last)
abort ();
/* Remove the first {. */
str = remove_leading_whitespaces (str);
if (*str != '{')
abort ();
str = remove_leading_whitespaces (str + 1);
i = strlen (str);
/* There are at least "X}". */
if (i < 2)
abort ();
/* Remove trailing white spaces and }. */
do
{
i--;
if (ISSPACE (str[i]) || str[i] == '}')
str[i] = '\0';
else
break;
}
while (i != 0);
last = str + i;
/* Find operand_types. */
for (i = 0; i < ARRAY_SIZE (operand_types); i++)
{
if (str >= last)
{
operand_types [i] = NULL;
break;
}
operand_types [i] = next_field (str, ',', &str);
if (*operand_types[i] == '0')
{
if (i != 0)
operand_types[i] = NULL;
break;
}
}
fprintf (table, " { \"%s\", %s, %s, %s, %s,\n",
name, operands, base_opcode, extension_opcode,
cpu_flags);
fprintf (table, " %s,\n", opcode_modifier);
fprintf (table, " { ");
for (i = 0; i < ARRAY_SIZE (operand_types); i++)
{
if (operand_types[i] == NULL
|| *operand_types[i] == '0')
{
if (i == 0)
fprintf (table, "0");
break;
}
if (i != 0)
fprintf (table, ",\n ");
fprintf (table, "%s", operand_types[i]);
}
fprintf (table, " } },\n");
}
fclose (fp);
fprintf (table, " { NULL, 0, 0, 0, 0, 0, { 0 } }\n");
fprintf (table, "};\n");
}
static void
process_i386_registers (FILE *table)
{
FILE *fp = fopen ("i386-reg.tbl", "r");
char buf[2048];
char *str, *p, *last;
char *reg_name, *reg_type, *reg_flags, *reg_num;
if (fp == NULL)
fail (_("can't find i386-reg.tbl for reading, errno = %s\n"),
strerror (errno));
fprintf (table, "\n/* i386 register table. */\n\n");
fprintf (table, "const reg_entry i386_regtab[] =\n{\n");
while (!feof (fp))
{
if (fgets (buf, sizeof (buf), fp) == NULL)
break;
p = remove_leading_whitespaces (buf);
/* Skip comments. */
str = strstr (p, "//");
if (str != NULL)
str[0] = '\0';
/* Remove trailing white spaces. */
remove_trailing_whitespaces (p);
switch (p[0])
{
case '#':
fprintf (table, "%s\n", p);
case '\0':
continue;
break;
default:
break;
}
last = p + strlen (p);
/* Find reg_name. */
reg_name = next_field (p, ',', &str);
if (str >= last)
abort ();
/* Find reg_type. */
reg_type = next_field (str, ',', &str);
if (str >= last)
abort ();
/* Find reg_flags. */
reg_flags = next_field (str, ',', &str);
if (str >= last)
abort ();
/* Find reg_num. */
reg_num = next_field (str, ',', &str);
fprintf (table, " { \"%s\", %s, %s, %s },\n",
reg_name, reg_type, reg_flags, reg_num);
}
fclose (fp);
fprintf (table, "};\n");
fprintf (table, "\nconst unsigned int i386_regtab_size = ARRAY_SIZE (i386_regtab);\n");
}
/* Program options. */
#define OPTION_SRCDIR 200
struct option long_options[] =
{
{"srcdir", required_argument, NULL, OPTION_SRCDIR},
{"debug", no_argument, NULL, 'd'},
{"version", no_argument, NULL, 'V'},
{"help", no_argument, NULL, 'h'},
{0, no_argument, NULL, 0}
};
static void
print_version (void)
{
printf ("%s: version 1.0\n", program_name);
xexit (0);
}
static void
usage (FILE * stream, int status)
{
fprintf (stream, "Usage: %s [-V | --version] [-d | --debug] [--srcdir=dirname] [--help]\n",
program_name);
xexit (status);
}
int
main (int argc, char **argv)
{
extern int chdir (char *);
char *srcdir = NULL;
int c;
FILE *table;
program_name = *argv;
xmalloc_set_program_name (program_name);
while ((c = getopt_long (argc, argv, "vVdh", long_options, 0)) != EOF)
switch (c)
{
case OPTION_SRCDIR:
srcdir = optarg;
break;
case 'V':
case 'v':
print_version ();
break;
case 'd':
debug = 1;
break;
case 'h':
case '?':
usage (stderr, 0);
default:
case 0:
break;
}
if (optind != argc)
usage (stdout, 1);
if (srcdir != NULL)
if (chdir (srcdir) != 0)
fail (_("unable to change directory to \"%s\", errno = %s\n"),
srcdir, strerror (errno));
table = fopen ("i386-tbl.h", "w");
if (table == NULL)
fail (_("can't create i386-tbl.h, errno = %s\n"), strerror (errno));
process_copyright (table);
process_i386_opcodes (table);
process_i386_registers (table);
fclose (table);
exit (0);
}