blob: eb96d16604ead6c624aaed943c649e922e8108d7 [file] [log] [blame]
/* $Id$
*
* Generate Arch Parser (GAP): generates ARCHparse.c from ARCHparse.gap.
*
* Copyright (C) 2006 Peter Johnson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <ctype.h>
#include <stdarg.h>
#include <string.h>
#include "tools/gap/perfect.h"
#include "libyasm/compat-queue.h"
#include "libyasm/coretype.h"
#include "libyasm/errwarn.h"
typedef STAILQ_HEAD(slist, sval) slist;
typedef struct sval {
STAILQ_ENTRY(sval) link;
char *str;
} sval;
typedef STAILQ_HEAD(dir_list, dir) dir_list;
typedef struct dir {
STAILQ_ENTRY(dir) link;
char *name;
const char *func;
slist args;
} dir;
typedef STAILQ_HEAD(dir_byp_list, dir_byp) dir_byp_list;
typedef struct dir_byp {
STAILQ_ENTRY(dir_byp) link;
/*@null@*/ char *parser;
dir_list dirs;
} dir_byp;
typedef enum {
ARCH = 0,
PARSERS,
INSN,
CPU,
CPU_ALIAS,
CPU_FEATURE,
TARGETMOD,
PREFIX,
REG,
REGGROUP,
SEGREG,
NUM_DIRS
} dir_type;
typedef struct {
void (*parse_insn) (void); /* arch-specific parse_insn */
int multi_parser[NUM_DIRS]; /* whether it has an initial parser field */
} arch_handler;
static void x86_parse_insn(void);
static const arch_handler arch_x86 = {
x86_parse_insn,
{0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0}
};
static struct {
const char *name;
const arch_handler *arch;
} archs[] = {
{"x86", &arch_x86},
};
static char line[1024];
static unsigned int cur_line = 0, next_line = 1;
static int errors = 0;
static const arch_handler *arch = NULL;
/* Lists of directives, keyed by parser name */
static dir_byp_list insnprefix_byp;
static dir_byp_list cpu_byp;
static dir_byp_list regtmod_byp;
static void
report_error(const char *fmt, ...)
{
va_list ap;
fprintf(stderr, "%u: ", cur_line);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputc('\n', stderr);
errors++;
}
void
yasm__fatal(const char *message, ...)
{
abort();
}
static void
dup_slist(slist *out, slist *in)
{
sval *sv;
STAILQ_INIT(out);
STAILQ_FOREACH(sv, in, link) {
sval *nsv = yasm_xmalloc(sizeof(sval));
nsv->str = yasm__xstrdup(sv->str);
STAILQ_INSERT_TAIL(out, nsv, link);
}
}
static dir *
dup_dir(dir *in)
{
dir *out = yasm_xmalloc(sizeof(dir));
out->name = yasm__xstrdup(in->name);
out->func = in->func;
dup_slist(&out->args, &in->args);
return out;
}
static dir_list *
get_dirs(dir_byp_list *byp, /*@null@*/ const char *parser)
{
dir_list *found = NULL;
dir_byp *db;
if (STAILQ_EMPTY(byp)) {
report_error("PARSERS not yet specified");
return NULL;
}
STAILQ_FOREACH(db, byp, link) {
if ((!parser && !db->parser) ||
(parser && db->parser && strcmp(parser, db->parser) == 0)) {
found = &db->dirs;
break;
}
}
return found;
}
/* Add a keyword/data to a slist of slist keyed by parser name.
* Returns nonzero on error.
*/
static int
add_dir(dir_byp_list *byp, /*@null@*/ const char *parser, dir *d)
{
dir_list *found = get_dirs(byp, parser);
if (found) {
STAILQ_INSERT_TAIL(found, d, link);
return 0;
} else if (!parser) {
/* Add separately to all */
dir_byp *db;
int first = 1;
STAILQ_FOREACH(db, byp, link) {
if (!first)
d = dup_dir(d);
first = 0;
STAILQ_INSERT_TAIL(&db->dirs, d, link);
}
return 0;
} else {
report_error("parser not found");
return 1;
}
}
static char *
check_parser(dir_type type)
{
char *parser = NULL;
if (arch->multi_parser[type]) {
parser = strtok(NULL, " \t\n");
if (strcmp(parser, "-") == 0)
parser = NULL;
}
return parser;
}
static void
parse_args(slist *args)
{
char *tok;
sval *sv;
STAILQ_INIT(args);
tok = strtok(NULL, " \t\n");
if (!tok) {
report_error("no args");
return;
}
while (tok) {
sv = yasm_xmalloc(sizeof(sval));
sv->str = yasm__xstrdup(tok);
STAILQ_INSERT_TAIL(args, sv, link);
tok = strtok(NULL, " \t\n");
}
}
static dir *
parse_generic(dir_type type, const char *func, dir_byp_list *byp)
{
char *parser = check_parser(type);
char *name = strtok(NULL, " \t\n");
dir *d = yasm_xmalloc(sizeof(dir));
d->name = yasm__xstrdup(name);
d->func = func;
parse_args(&d->args);
add_dir(byp, parser, d);
return d;
}
static void
parse_arch(void)
{
size_t i;
int found = 0;
char *tok = strtok(NULL, " \t\n");
if (!tok) {
report_error("ARCH requires an operand");
return;
}
for (i=0; i<sizeof(archs)/sizeof(archs[0]); i++) {
if (strcmp(archs[i].name, tok) == 0) {
found = 1;
break;
}
}
if (!found) {
report_error("unrecognized ARCH");
return;
}
arch = archs[i].arch;
}
static void
parse_parsers(void)
{
dir_byp *db;
char *tok;
if (!arch) {
report_error("ARCH not specified before PARSERS");
return;
}
tok = strtok(NULL, " \t\n");
if (!tok) {
report_error("no PARSERS parameter");
return;
}
while (tok) {
/* Insert into each slist of slist if broken out by parser */
if (arch->multi_parser[INSN] || arch->multi_parser[PREFIX]) {
db = yasm_xmalloc(sizeof(dir_byp));
db->parser = yasm__xstrdup(tok);
STAILQ_INIT(&db->dirs);
STAILQ_INSERT_TAIL(&insnprefix_byp, db, link);
}
if (arch->multi_parser[CPU] || arch->multi_parser[CPU_ALIAS] ||
arch->multi_parser[CPU_FEATURE]) {
db = yasm_xmalloc(sizeof(dir_byp));
db->parser = yasm__xstrdup(tok);
STAILQ_INIT(&db->dirs);
STAILQ_INSERT_TAIL(&cpu_byp, db, link);
}
if (arch->multi_parser[TARGETMOD] || arch->multi_parser[REG] ||
arch->multi_parser[REGGROUP] || arch->multi_parser[SEGREG]) {
db = yasm_xmalloc(sizeof(dir_byp));
db->parser = yasm__xstrdup(tok);
STAILQ_INIT(&db->dirs);
STAILQ_INSERT_TAIL(&regtmod_byp, db, link);
}
tok = strtok(NULL, " \t\n");
}
/* Add NULL (global) versions if not already created */
if (STAILQ_EMPTY(&insnprefix_byp)) {
db = yasm_xmalloc(sizeof(dir_byp));
db->parser = NULL;
STAILQ_INIT(&db->dirs);
STAILQ_INSERT_TAIL(&insnprefix_byp, db, link);
}
if (STAILQ_EMPTY(&cpu_byp)) {
db = yasm_xmalloc(sizeof(dir_byp));
db->parser = NULL;
STAILQ_INIT(&db->dirs);
STAILQ_INSERT_TAIL(&cpu_byp, db, link);
}
if (STAILQ_EMPTY(&regtmod_byp)) {
db = yasm_xmalloc(sizeof(dir_byp));
db->parser = NULL;
STAILQ_INIT(&db->dirs);
STAILQ_INSERT_TAIL(&regtmod_byp, db, link);
}
}
static void
x86_parse_insn(void)
{
char *parser = check_parser(INSN);
char *bname = strtok(NULL, " \t\n");
char *suffix = strtok(NULL, " \t\n");
dir *d;
slist args;
sval *sv;
if (!suffix) {
report_error("INSN requires suffix");
return;
}
/* save the remainder of args */
parse_args(&args);
if (suffix[0] != '"') {
/* Just one instruction to generate */
sv = yasm_xmalloc(sizeof(sval));
sv->str = yasm__xstrdup(suffix);
STAILQ_INSERT_HEAD(&args, sv, link);
d = yasm_xmalloc(sizeof(dir));
d->name = yasm__xstrdup(bname);
d->func = "INSN";
d->args = args;
add_dir(&insnprefix_byp, parser, d);
} else {
/* Need to generate with suffixes for gas */
char *p;
char sufstr[6];
size_t bnamelen = strlen(bname);
strcpy(sufstr, "SUF_X");
for (p = &suffix[1]; *p != '"'; p++) {
sufstr[4] = toupper(*p);
d = yasm_xmalloc(sizeof(dir));
d->name = yasm_xmalloc(bnamelen+2);
strcpy(d->name, bname);
d->name[bnamelen] = tolower(*p);
d->name[bnamelen+1] = '\0';
d->func = "INSN";
dup_slist(&d->args, &args);
sv = yasm_xmalloc(sizeof(sval));
sv->str = yasm__xstrdup(sufstr);
STAILQ_INSERT_HEAD(&d->args, sv, link);
add_dir(&insnprefix_byp, "gas", d);
}
/* And finally the version sans suffix */
sv = yasm_xmalloc(sizeof(sval));
sv->str = yasm__xstrdup("NONE");
STAILQ_INSERT_HEAD(&args, sv, link);
d = yasm_xmalloc(sizeof(dir));
d->name = yasm__xstrdup(bname);
d->func = "INSN";
d->args = args;
add_dir(&insnprefix_byp, parser, d);
}
}
static void
parse_insn(void)
{
if (!arch) {
report_error("ARCH not defined prior to INSN");
return;
}
arch->parse_insn();
}
static void
parse_cpu(void)
{
dir *d = parse_generic(CPU, "CPU", &cpu_byp);
sval *sv = yasm_xmalloc(sizeof(sval));
sv->str = yasm__xstrdup("CPU_MODE_VERBATIM");
STAILQ_INSERT_TAIL(&d->args, sv, link);
}
static void
parse_cpu_alias(void)
{
char *parser = check_parser(CPU_ALIAS);
char *name = strtok(NULL, " \t\n");
char *alias = strtok(NULL, " \t\n");
dir_list *dirs = get_dirs(&cpu_byp, parser);
dir *aliasd, *d;
if (!alias) {
report_error("CPU_ALIAS requires an operand");
return;
}
STAILQ_FOREACH(aliasd, dirs, link) {
if (strcmp(aliasd->name, alias) == 0)
break;
}
if (!aliasd) {
report_error("could not find `%s'", alias);
return;
}
d = yasm_xmalloc(sizeof(dir));
d->name = yasm__xstrdup(name);
d->func = "CPU";
dup_slist(&d->args, &aliasd->args);
add_dir(&cpu_byp, parser, d);
}
static void
parse_cpu_feature(void)
{
char *parser = check_parser(CPU_FEATURE);
char *name = strtok(NULL, " \t\n");
dir *name_dir = yasm_xmalloc(sizeof(dir));
dir *noname_dir = yasm_xmalloc(sizeof(dir));
sval *sv;
name_dir->name = yasm__xstrdup(name);
name_dir->func = "CPU_FEATURE";
parse_args(&name_dir->args);
noname_dir->name = yasm_xmalloc(strlen(name)+3);
strcpy(noname_dir->name, "no");
strcat(noname_dir->name, name);
noname_dir->func = name_dir->func;
dup_slist(&noname_dir->args, &name_dir->args);
sv = yasm_xmalloc(sizeof(sval));
sv->str = yasm__xstrdup("CPU_MODE_SET");
STAILQ_INSERT_TAIL(&name_dir->args, sv, link);
sv = yasm_xmalloc(sizeof(sval));
sv->str = yasm__xstrdup("CPU_MODE_CLEAR");
STAILQ_INSERT_TAIL(&noname_dir->args, sv, link);
add_dir(&cpu_byp, parser, name_dir);
add_dir(&cpu_byp, parser, noname_dir);
}
static void
parse_targetmod(void)
{
parse_generic(TARGETMOD, "TARGETMOD", &regtmod_byp);
}
static void
parse_prefix(void)
{
parse_generic(PREFIX, "PREFIX", &insnprefix_byp);
}
static void
parse_reg(void)
{
parse_generic(REG, "REG", &regtmod_byp);
}
static void
parse_reggroup(void)
{
parse_generic(REGGROUP, "REGGROUP", &regtmod_byp);
}
static void
parse_segreg(void)
{
parse_generic(SEGREG, "SEGREG", &regtmod_byp);
}
/* make the c output for the perfect hash tab array */
static void
make_c_tab(
FILE *f,
const char *which,
const char *parser,
bstuff *tab, /* table indexed by b */
ub4 smax, /* range of scramble[] */
ub4 blen, /* b in 0..blen-1, power of 2 */
ub4 *scramble) /* used in final hash */
{
ub4 i;
/* table for the mapping for the perfect hash */
if (blen >= USE_SCRAMBLE) {
/* A way to make the 1-byte values in tab bigger */
if (smax > UB2MAXVAL+1) {
fprintf(f, "static const unsigned long %s_", which);
if (parser)
fprintf(f, "%s_", parser);
fprintf(f, "scramble[] = {\n");
for (i=0; i<=UB1MAXVAL; i+=4)
fprintf(f, "0x%.8lx, 0x%.8lx, 0x%.8lx, 0x%.8lx,\n",
scramble[i+0], scramble[i+1], scramble[i+2], scramble[i+3]);
} else {
fprintf(f, "static const unsigned short %s_", which);
if (parser)
fprintf(f, "%s_", parser);
fprintf(f, "scramble[] = {\n");
for (i=0; i<=UB1MAXVAL; i+=8)
fprintf(f,
"0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx,\n",
scramble[i+0], scramble[i+1], scramble[i+2], scramble[i+3],
scramble[i+4], scramble[i+5], scramble[i+6], scramble[i+7]);
}
fprintf(f, "};\n");
fprintf(f, "\n");
}
if (blen > 0) {
/* small adjustments to _a_ to make values distinct */
if (smax <= UB1MAXVAL+1 || blen >= USE_SCRAMBLE)
fprintf(f, "static const unsigned char %s_", which);
else
fprintf(f, "static const unsigned short %s_", which);
if (parser)
fprintf(f, "%s_", parser);
fprintf(f, "tab[] = {\n");
if (blen < 16) {
for (i=0; i<blen; ++i)
fprintf(f, "%3ld,", scramble[tab[i].val_b]);
} else if (blen <= 1024) {
for (i=0; i<blen; i+=16)
fprintf(f, "%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,\n",
scramble[tab[i+0].val_b], scramble[tab[i+1].val_b],
scramble[tab[i+2].val_b], scramble[tab[i+3].val_b],
scramble[tab[i+4].val_b], scramble[tab[i+5].val_b],
scramble[tab[i+6].val_b], scramble[tab[i+7].val_b],
scramble[tab[i+8].val_b], scramble[tab[i+9].val_b],
scramble[tab[i+10].val_b], scramble[tab[i+11].val_b],
scramble[tab[i+12].val_b], scramble[tab[i+13].val_b],
scramble[tab[i+14].val_b], scramble[tab[i+15].val_b]);
} else if (blen < USE_SCRAMBLE) {
for (i=0; i<blen; i+=8)
fprintf(f, "%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,\n",
scramble[tab[i+0].val_b], scramble[tab[i+1].val_b],
scramble[tab[i+2].val_b], scramble[tab[i+3].val_b],
scramble[tab[i+4].val_b], scramble[tab[i+5].val_b],
scramble[tab[i+6].val_b], scramble[tab[i+7].val_b]);
} else {
for (i=0; i<blen; i+=16)
fprintf(f, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,\n",
tab[i+0].val_b, tab[i+1].val_b,
tab[i+2].val_b, tab[i+3].val_b,
tab[i+4].val_b, tab[i+5].val_b,
tab[i+6].val_b, tab[i+7].val_b,
tab[i+8].val_b, tab[i+9].val_b,
tab[i+10].val_b, tab[i+11].val_b,
tab[i+12].val_b, tab[i+13].val_b,
tab[i+14].val_b, tab[i+15].val_b);
}
fprintf(f, "};\n");
fprintf(f, "\n");
}
}
static void
perfect_dir(FILE *out, const char *which, const char *parser, dir_list *dirs)
{
ub4 nkeys;
key *keys;
hashform form;
bstuff *tab; /* table indexed by b */
hstuff *tabh; /* table indexed by hash value */
ub4 smax; /* scramble[] values in 0..smax-1, a power of 2 */
ub4 alen; /* a in 0..alen-1, a power of 2 */
ub4 blen; /* b in 0..blen-1, a power of 2 */
ub4 salt; /* a parameter to the hash function */
gencode final; /* code for final hash */
ub4 i;
ub4 scramble[SCRAMBLE_LEN]; /* used in final hash function */
char buf[10][80]; /* buffer for generated code */
char *buf2[10]; /* also for generated code */
int cpumode = strcmp(which, "cpu") == 0;
dir *d;
/* perfect hash configuration */
form.mode = NORMAL_HM;
form.hashtype = STRING_HT;
form.perfect = MINIMAL_HP;
form.speed = SLOW_HS;
/* set up code for final hash */
final.line = buf2;
final.used = 0;
final.len = 10;
for (i=0; i<10; i++)
final.line[i] = buf[i];
/* build list of keys */
nkeys = 0;
keys = NULL;
STAILQ_FOREACH(d, dirs, link) {
key *k = yasm_xmalloc(sizeof(key));
k->name_k = yasm__xstrdup(d->name);
k->len_k = strlen(d->name);
k->next_k = keys;
keys = k;
nkeys++;
}
/* find the hash */
findhash(&tab, &tabh, &alen, &blen, &salt, &final,
scramble, &smax, keys, nkeys, &form);
/* output the dir table: this should loop up to smax for NORMAL_HP,
* or up to pakd.nkeys for MINIMAL_HP.
*/
fprintf(out, "static const %s_parse_data %s_", which, which);
if (parser)
fprintf(out, "%s_", parser);
fprintf(out, "pd[%lu] = {\n", nkeys);
for (i=0; i<nkeys; i++) {
if (tabh[i].key_h) {
sval *sv;
STAILQ_FOREACH(d, dirs, link) {
if (strcmp(d->name, tabh[i].key_h->name_k) == 0)
break;
}
if (!d) {
report_error("internal error: could not find `%s'",
tabh[i].key_h->name_k);
break;
}
if (cpumode)
fprintf(out, "{\"%s\",", d->name);
else
fprintf(out, "%s(\"%s\",", d->func, d->name);
STAILQ_FOREACH(sv, &d->args, link) {
fprintf(out, " %s", sv->str);
if (STAILQ_NEXT(sv, link))
fprintf(out, ",");
}
fprintf(out, cpumode ? "}" : ")");
} else
fprintf(out, " { NULL }");
if (i < nkeys-1)
fprintf(out, ",");
fprintf(out, "\n");
}
fprintf(out, "};\n");
/* output the hash tab[] array */
make_c_tab(out, which, parser, tab, smax, blen, scramble);
/* The hash function */
fprintf(out, "#define tab %s_", which);
if (parser)
fprintf(out, "%s_", parser);
fprintf(out, "tab\n");
fprintf(out, "static const %s_parse_data *\n%s_", which, which);
if (parser)
fprintf(out, "%s_", parser);
fprintf(out, "find(const char *key, size_t len)\n");
fprintf(out, "{\n");
fprintf(out, " const %s_parse_data *ret;\n", which);
for (i=0; i<final.used; ++i)
fprintf(out, final.line[i]);
fprintf(out, " if (rsl >= %lu) return NULL;\n", nkeys);
fprintf(out, " ret = &%s_", which);
if (parser)
fprintf(out, "%s_", parser);
fprintf(out, "pd[rsl];\n");
fprintf(out, " if (strcmp(key, ret->name) != 0) return NULL;\n");
fprintf(out, " return ret;\n");
fprintf(out, "}\n");
fprintf(out, "#undef tab\n\n");
free(tab);
free(tabh);
}
/* Get an entire "real" line from the input file by combining any
* \\\n continuations.
*/
static int get_line(FILE *in)
{
char *p = line;
cur_line = next_line;
if (feof(in))
return 0;
while (p < &line[1023-128]) {
if (!fgets(p, 128, in))
return 1;
next_line++;
/* if continuation, strip out leading whitespace */
if (p > line) {
char *p2 = p;
while (isspace(*p2)) p2++;
if (p2 > p)
memmove(p, p2, strlen(p2)+1);
}
while (*p) p++;
if (p[-2] != '\\' || p[-1] != '\n') {
if (p[-1] == '\n')
p[-1] = '\0';
return 1;
}
p -= 2;
}
return 0;
}
static struct {
const char *name;
int indx;
void (*handler) (void);
} directives[] = {
{"ARCH", ARCH, parse_arch},
{"PARSERS", PARSERS, parse_parsers},
{"INSN", INSN, parse_insn},
{"CPU", CPU, parse_cpu},
{"CPU_ALIAS", CPU_ALIAS, parse_cpu_alias},
{"CPU_FEATURE", CPU_FEATURE, parse_cpu_feature},
{"TARGETMOD", TARGETMOD, parse_targetmod},
{"PREFIX", PREFIX, parse_prefix},
{"REG", REG, parse_reg},
{"REGGROUP", REGGROUP, parse_reggroup},
{"SEGREG", SEGREG, parse_segreg},
};
int
main(int argc, char *argv[])
{
FILE *in, *out;
size_t i;
char *tok;
int count[NUM_DIRS];
dir_byp *db;
for (i=0; i<NUM_DIRS; i++)
count[i] = 0;
if (argc != 3) {
fprintf(stderr, "Usage: gap <in> <out>\n");
return EXIT_FAILURE;
}
in = fopen(argv[1], "rt");
if (!in) {
fprintf(stderr, "Could not open `%s' for reading\n", argv[1]);
return EXIT_FAILURE;
}
STAILQ_INIT(&insnprefix_byp);
STAILQ_INIT(&cpu_byp);
STAILQ_INIT(&regtmod_byp);
/* Parse input file */
while (get_line(in)) {
int found;
/*printf("%s\n", line);*/
tok = strtok(line, " \t\n");
if (!tok)
continue;
/* Comments start with # as the first thing on a line */
if (tok[0] == '#')
continue;
/* Look for directive */
found = 0;
for (i=0; i<sizeof(directives)/sizeof(directives[0]); i++) {
if (strcmp(tok, directives[i].name) == 0) {
count[directives[i].indx]++;
directives[i].handler();
found = 1;
break;
}
}
if (!found)
report_error("unknown directive `%s'\n", tok);
}
/* Output some informational statistics */
printf("Directives read:\n");
for (i=0; i<sizeof(directives)/sizeof(directives[0]); i++)
printf("\t%d\t%s\n", count[directives[i].indx], directives[i].name);
if (errors > 0)
return EXIT_FAILURE;
out = fopen(argv[2], "wt");
if (!out) {
fprintf(stderr, "Could not open `%s' for writing\n", argv[2]);
return EXIT_FAILURE;
}
/* Get perfect hashes for the three lists of directives */
STAILQ_FOREACH(db, &insnprefix_byp, link)
perfect_dir(out, "insnprefix", db->parser, &db->dirs);
STAILQ_FOREACH(db, &cpu_byp, link)
perfect_dir(out, "cpu", db->parser, &db->dirs);
STAILQ_FOREACH(db, &regtmod_byp, link)
perfect_dir(out, "regtmod", db->parser, &db->dirs);
if (errors > 0)
return EXIT_FAILURE;
return EXIT_SUCCESS;
}