instruction handling. Use the GNU gperf file format, but continue to use our custom minimal perfect hash generator. svn path=/trunk/yasm/; revision=19290.6.2
parent
32921a0d12
commit
00e958bcf6
14 changed files with 1325 additions and 1321 deletions
@ -0,0 +1,240 @@ |
||||
# |
||||
# x86 CPU recognition |
||||
# |
||||
# Copyright (C) 2002-2007 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 <util.h> |
||||
RCSID("$Id$"); |
||||
|
||||
#include <libyasm.h> |
||||
#include <libyasm/phash.h> |
||||
|
||||
#include "modules/arch/x86/x86arch.h" |
||||
|
||||
enum cpu_mode { |
||||
CPU_MODE_VERBATIM = 1, |
||||
CPU_MODE_SET, |
||||
CPU_MODE_CLEAR |
||||
}; |
||||
|
||||
#define PROC_186 CPU_186|CPU_Priv |
||||
#define PROC_286 CPU_186|CPU_286|CPU_Priv |
||||
#define PROC_386 CPU_186|CPU_286|CPU_386|CPU_SMM|CPU_Prot|CPU_Priv |
||||
#define PROC_486 CPU_186|CPU_286|CPU_386|CPU_486|CPU_FPU|CPU_SMM|\ |
||||
CPU_Prot|CPU_Priv |
||||
#define PROC_586 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_FPU|\ |
||||
CPU_SMM|CPU_Prot|CPU_Priv |
||||
#define PROC_686 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\ |
||||
CPU_FPU|CPU_SMM|CPU_Prot|CPU_Priv |
||||
#define PROC_p2 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\ |
||||
CPU_FPU|CPU_MMX|CPU_SMM|CPU_Prot|CPU_Priv |
||||
#define PROC_p3 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\ |
||||
CPU_P3|CPU_FPU|CPU_MMX|CPU_SSE|CPU_SMM|CPU_Prot|\ |
||||
CPU_Priv |
||||
#define PROC_p4 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\ |
||||
CPU_P3|CPU_P4|CPU_FPU|CPU_MMX|CPU_SSE|CPU_SSE2|\ |
||||
CPU_SMM|CPU_Prot|CPU_Priv |
||||
#define PROC_ia64 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\ |
||||
CPU_P3|CPU_P4|CPU_IA64|CPU_FPU|CPU_MMX|CPU_SSE|\ |
||||
CPU_SSE2|CPU_SMM|CPU_Prot|CPU_Priv |
||||
#define PROC_k6 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\ |
||||
CPU_K6|CPU_FPU|CPU_MMX|CPU_3DNow|CPU_SMM|CPU_Prot|\ |
||||
CPU_Priv |
||||
#define PROC_k7 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\ |
||||
CPU_K6|CPU_Athlon|CPU_FPU|CPU_MMX|CPU_SSE|CPU_3DNow|\ |
||||
CPU_SMM|CPU_Prot|CPU_Priv |
||||
#define PROC_hammer CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\ |
||||
CPU_K6|CPU_Athlon|CPU_Hammer|CPU_FPU|CPU_MMX|\ |
||||
CPU_SSE|CPU_SSE2|CPU_3DNow|CPU_SMM|CPU_Prot|\ |
||||
CPU_Priv |
||||
#define PROC_prescott CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\ |
||||
CPU_Hammer|CPU_EM64T|CPU_FPU|CPU_MMX|\ |
||||
CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_SMM|\ |
||||
CPU_Prot|CPU_Priv |
||||
#define PROC_conroe CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\ |
||||
CPU_Hammer|CPU_EM64T|CPU_FPU|CPU_MMX|\ |
||||
CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_SSSE3|CPU_SMM|\ |
||||
CPU_Prot|CPU_Priv |
||||
#define PROC_penryn CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\ |
||||
CPU_Hammer|CPU_EM64T|CPU_FPU|CPU_MMX|\ |
||||
CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_SSSE3|CPU_SSE41|CPU_SMM|\ |
||||
CPU_Prot|CPU_Priv |
||||
#define PROC_nehalem CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\ |
||||
CPU_Hammer|CPU_EM64T|CPU_FPU|CPU_MMX|\ |
||||
CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_SSSE3|CPU_SSE41|\ |
||||
CPU_SSE42|CPU_SMM|CPU_Prot|CPU_Priv |
||||
|
||||
%} |
||||
%ignore-case |
||||
%language=ANSI-C |
||||
%compare-strncmp |
||||
%readonly-tables |
||||
%enum |
||||
%struct-type |
||||
%define hash-function-name cpu_hash |
||||
%define lookup-function-name cpu_find |
||||
struct cpu_parse_data { |
||||
const char *name; |
||||
enum cpu_mode mode; |
||||
unsigned long cpu; |
||||
}; |
||||
%% |
||||
8086, CPU_MODE_VERBATIM, CPU_Priv |
||||
186, CPU_MODE_VERBATIM, PROC_186 |
||||
80186, CPU_MODE_VERBATIM, PROC_186 |
||||
i186, CPU_MODE_VERBATIM, PROC_186 |
||||
286, CPU_MODE_VERBATIM, PROC_286 |
||||
80286, CPU_MODE_VERBATIM, PROC_286 |
||||
i286, CPU_MODE_VERBATIM, PROC_286 |
||||
386, CPU_MODE_VERBATIM, PROC_386 |
||||
80386, CPU_MODE_VERBATIM, PROC_386 |
||||
i386, CPU_MODE_VERBATIM, PROC_386 |
||||
486, CPU_MODE_VERBATIM, PROC_486 |
||||
80486, CPU_MODE_VERBATIM, PROC_486 |
||||
i486, CPU_MODE_VERBATIM, PROC_486 |
||||
586, CPU_MODE_VERBATIM, PROC_586 |
||||
i586, CPU_MODE_VERBATIM, PROC_586 |
||||
pentium, CPU_MODE_VERBATIM, PROC_586 |
||||
p5, CPU_MODE_VERBATIM, PROC_586 |
||||
686, CPU_MODE_VERBATIM, PROC_686 |
||||
i686, CPU_MODE_VERBATIM, PROC_686 |
||||
p6, CPU_MODE_VERBATIM, PROC_686 |
||||
ppro, CPU_MODE_VERBATIM, PROC_686 |
||||
pentiumpro, CPU_MODE_VERBATIM, PROC_686 |
||||
p2, CPU_MODE_VERBATIM, PROC_p2 |
||||
pentium2, CPU_MODE_VERBATIM, PROC_p2 |
||||
pentium-2, CPU_MODE_VERBATIM, PROC_p2 |
||||
pentiumii, CPU_MODE_VERBATIM, PROC_p2 |
||||
pentium-ii, CPU_MODE_VERBATIM, PROC_p2 |
||||
p3, CPU_MODE_VERBATIM, PROC_p3 |
||||
pentium3, CPU_MODE_VERBATIM, PROC_p3 |
||||
pentium-3, CPU_MODE_VERBATIM, PROC_p3 |
||||
pentiumiii, CPU_MODE_VERBATIM, PROC_p3 |
||||
pentium-iii, CPU_MODE_VERBATIM, PROC_p3 |
||||
katmai, CPU_MODE_VERBATIM, PROC_p3 |
||||
p4, CPU_MODE_VERBATIM, PROC_p4 |
||||
pentium4, CPU_MODE_VERBATIM, PROC_p4 |
||||
pentium-4, CPU_MODE_VERBATIM, PROC_p4 |
||||
pentiumiv, CPU_MODE_VERBATIM, PROC_p4 |
||||
pentium-iv, CPU_MODE_VERBATIM, PROC_p4 |
||||
williamette, CPU_MODE_VERBATIM, PROC_p4 |
||||
ia64, CPU_MODE_VERBATIM, PROC_ia64 |
||||
ia-64, CPU_MODE_VERBATIM, PROC_ia64 |
||||
itanium, CPU_MODE_VERBATIM, PROC_ia64 |
||||
k6, CPU_MODE_VERBATIM, PROC_k6 |
||||
k7, CPU_MODE_VERBATIM, PROC_k7 |
||||
athlon, CPU_MODE_VERBATIM, PROC_k7 |
||||
hammer, CPU_MODE_VERBATIM, PROC_hammer |
||||
sledgehammer, CPU_MODE_VERBATIM, PROC_hammer |
||||
opteron, CPU_MODE_VERBATIM, PROC_hammer |
||||
athlon64, CPU_MODE_VERBATIM, PROC_hammer |
||||
athlon-64, CPU_MODE_VERBATIM, PROC_hammer |
||||
prescott, CPU_MODE_VERBATIM, PROC_prescott |
||||
conroe, CPU_MODE_VERBATIM, PROC_conroe |
||||
penryn, CPU_MODE_VERBATIM, PROC_penryn |
||||
nehalem, CPU_MODE_VERBATIM, PROC_nehalem |
||||
# |
||||
# Features have "no" versions to disable them, and only set/reset the |
||||
# specific feature being changed. All other bits are left alone. |
||||
# |
||||
fpu, CPU_MODE_SET, CPU_FPU |
||||
nofpu, CPU_MODE_CLEAR, CPU_FPU |
||||
mmx, CPU_MODE_SET, CPU_MMX |
||||
nommx, CPU_MODE_CLEAR, CPU_MMX |
||||
sse, CPU_MODE_SET, CPU_SSE |
||||
nosse, CPU_MODE_CLEAR, CPU_SSE |
||||
sse2, CPU_MODE_SET, CPU_SSE2 |
||||
nosse2, CPU_MODE_CLEAR, CPU_SSE2 |
||||
sse3, CPU_MODE_SET, CPU_SSE3 |
||||
nosse3, CPU_MODE_CLEAR, CPU_SSE3 |
||||
#pni, CPU_MODE_SET, CPU_PNI |
||||
#nopni, CPU_MODE_CLEAR, CPU_PNI |
||||
3dnow, CPU_MODE_SET, CPU_3DNow |
||||
no3dnow, CPU_MODE_CLEAR, CPU_3DNow |
||||
cyrix, CPU_MODE_SET, CPU_Cyrix |
||||
nocyrix, CPU_MODE_CLEAR, CPU_Cyrix |
||||
amd, CPU_MODE_SET, CPU_AMD |
||||
noamd, CPU_MODE_CLEAR, CPU_AMD |
||||
smm, CPU_MODE_SET, CPU_SMM |
||||
nosmm, CPU_MODE_CLEAR, CPU_SMM |
||||
prot, CPU_MODE_SET, CPU_Prot |
||||
noprot, CPU_MODE_CLEAR, CPU_Prot |
||||
protected, CPU_MODE_SET, CPU_Prot |
||||
noprotected, CPU_MODE_CLEAR, CPU_Prot |
||||
undoc, CPU_MODE_SET, CPU_Undoc |
||||
noundoc, CPU_MODE_CLEAR, CPU_Undoc |
||||
undocumented, CPU_MODE_SET, CPU_Undoc |
||||
noundocumented, CPU_MODE_CLEAR, CPU_Undoc |
||||
obs, CPU_MODE_SET, CPU_Obs |
||||
noobs, CPU_MODE_CLEAR, CPU_Obs |
||||
obsolete, CPU_MODE_SET, CPU_Obs |
||||
noobsolete, CPU_MODE_CLEAR, CPU_Obs |
||||
priv, CPU_MODE_SET, CPU_Priv |
||||
nopriv, CPU_MODE_CLEAR, CPU_Priv |
||||
privileged, CPU_MODE_SET, CPU_Priv |
||||
noprivileged, CPU_MODE_CLEAR, CPU_Priv |
||||
svm, CPU_MODE_SET, CPU_SVM |
||||
nosvm, CPU_MODE_CLEAR, CPU_SVM |
||||
padlock, CPU_MODE_SET, CPU_PadLock |
||||
nopadlock, CPU_MODE_CLEAR, CPU_PadLock |
||||
em64t, CPU_MODE_SET, CPU_EM64T |
||||
noem64t, CPU_MODE_CLEAR, CPU_EM64T |
||||
ssse3, CPU_MODE_SET, CPU_SSSE3 |
||||
nossse3, CPU_MODE_CLEAR, CPU_SSSE3 |
||||
sse4.1, CPU_MODE_SET, CPU_SSE41 |
||||
nosse4.1, CPU_MODE_CLEAR, CPU_SSE41 |
||||
sse4.2, CPU_MODE_SET, CPU_SSE42 |
||||
nosse4.2, CPU_MODE_CLEAR, CPU_SSE42 |
||||
sse4, CPU_MODE_SET, CPU_SSE4 |
||||
nosse4, CPU_MODE_CLEAR, CPU_SSE4 |
||||
%% |
||||
|
||||
void |
||||
yasm_x86__parse_cpu(yasm_arch_x86 *arch_x86, const char *cpuid, |
||||
size_t cpuid_len) |
||||
{ |
||||
/*@null@*/ const struct cpu_parse_data *pdata; |
||||
|
||||
if (cpuid_len > 15) |
||||
return; |
||||
|
||||
pdata = cpu_find(cpuid, cpuid_len); |
||||
if (!pdata) { |
||||
yasm_warn_set(YASM_WARN_GENERAL, |
||||
N_("unrecognized CPU identifier `%s'"), cpuid); |
||||
return; |
||||
} |
||||
|
||||
switch (pdata->mode) { |
||||
case CPU_MODE_VERBATIM: |
||||
arch_x86->cpu_enabled = pdata->cpu; |
||||
break; |
||||
case CPU_MODE_SET: |
||||
arch_x86->cpu_enabled |= pdata->cpu; |
||||
break; |
||||
case CPU_MODE_CLEAR: |
||||
arch_x86->cpu_enabled &= ~pdata->cpu; |
||||
break; |
||||
} |
||||
} |
@ -0,0 +1,197 @@ |
||||
/* $Id$
|
||||
* |
||||
* Generate x86 instructions gperf files |
||||
* |
||||
* Copyright (C) 2006-2007 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 <stdlib.h> |
||||
|
||||
static char line[1024]; |
||||
static unsigned int cur_line = 1; |
||||
unsigned int num_errors = 0; |
||||
|
||||
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); |
||||
num_errors++; |
||||
} |
||||
|
||||
static void |
||||
parse_insn(FILE *out_nasm, FILE *out_gas) |
||||
{ |
||||
char *parser = strtok(NULL, " \t\n"); |
||||
char *bname = strtok(NULL, " \t\n"); |
||||
char *suffix = strtok(NULL, " \t\n"); |
||||
char *group = strtok(NULL, " \t\n"); |
||||
char *mod = strtok(NULL, " \t\n"); |
||||
char *cpu = strtok(NULL, " \t\n"); |
||||
|
||||
if (!suffix) { |
||||
report_error("INSN requires suffix"); |
||||
return; |
||||
} |
||||
|
||||
if (suffix[0] != '"') { |
||||
/* Just one instruction to generate */ |
||||
if (parser[0] == '-' || strcmp(parser, "gas") == 0) |
||||
fprintf(out_gas, |
||||
"%s,\t%s_insn,\t(%sUL<<8)|NELEMS(%s_insn),\t%s,\t%s\n", |
||||
bname, group, mod, group, cpu, suffix); |
||||
if (parser[0] == '-' || strcmp(parser, "nasm") == 0) |
||||
fprintf(out_nasm, |
||||
"%s,\t%s_insn,\t(%sUL<<8)|NELEMS(%s_insn),\t%s,\t%s\n", |
||||
bname, group, mod, group, cpu, suffix); |
||||
} else { |
||||
/* Need to generate with suffixes for gas */ |
||||
char *p; |
||||
char sufstr[6]; |
||||
size_t bnamelen = strlen(bname); |
||||
char *name = malloc(bnamelen+2); |
||||
|
||||
strcpy(name, bname); |
||||
strcpy(sufstr, "SUF_X"); |
||||
|
||||
for (p = &suffix[1]; *p != '"'; p++) { |
||||
sufstr[4] = toupper(*p); |
||||
|
||||
name[bnamelen] = tolower(*p); |
||||
name[bnamelen+1] = '\0'; |
||||
|
||||
fprintf(out_gas, |
||||
"%s,\t%s_insn,\t(%sUL<<8)|NELEMS(%s_insn),\t%s,\t%s\n", |
||||
name, group, mod, group, cpu, sufstr); |
||||
} |
||||
free(name); |
||||
|
||||
/* And finally the version sans suffix */ |
||||
if (parser[0] == '-' || strcmp(parser, "gas") == 0) |
||||
fprintf(out_gas, |
||||
"%s,\t%s_insn,\t(%sUL<<8)|NELEMS(%s_insn),\t%s,\t%s\n", |
||||
bname, group, mod, group, cpu, "NONE"); |
||||
if (parser[0] == '-' || strcmp(parser, "nasm") == 0) |
||||
fprintf(out_nasm, |
||||
"%s,\t%s_insn,\t(%sUL<<8)|NELEMS(%s_insn),\t%s,\t%s\n", |
||||
bname, group, mod, group, cpu, "NONE"); |
||||
} |
||||
} |
||||
|
||||
static void |
||||
parse_prefix(FILE *out_nasm, FILE *out_gas) |
||||
{ |
||||
char *parser = strtok(NULL, " \t\n"); |
||||
char *name = strtok(NULL, " \t\n"); |
||||
char *type = strtok(NULL, " \t\n"); |
||||
char *value = strtok(NULL, " \t\n"); |
||||
|
||||
if (parser[0] == '-' || strcmp(parser, "gas") == 0) |
||||
fprintf(out_gas, "%s,\tNULL,\t%s,\t%s,\tNONE\n", name, type, value); |
||||
if (parser[0] == '-' || strcmp(parser, "nasm") == 0) |
||||
fprintf(out_nasm, "%s,\tNULL,\t%s,\t%s,\tNONE\n", name, type, value); |
||||
} |
||||
|
||||
void |
||||
output_base(FILE *out, const char *parser) |
||||
{ |
||||
fputs("%ignore-case\n", out); |
||||
fputs("%language=ANSI-C\n", out); |
||||
fputs("%compare-strncmp\n", out); |
||||
fputs("%readonly-tables\n", out); |
||||
fputs("%enum\n", out); |
||||
fputs("%struct-type\n", out); |
||||
fprintf(out, "%%define hash-function-name insnprefix_%s_hash\n", parser); |
||||
fprintf(out, "%%define lookup-function-name insnprefix_%s_find\n", parser); |
||||
fputs("struct insnprefix_parse_data;\n", out); |
||||
fputs("%%\n", out); |
||||
} |
||||
|
||||
int |
||||
main(int argc, char *argv[]) |
||||
{ |
||||
FILE *in, *out_nasm, *out_gas; |
||||
size_t i; |
||||
char *tok; |
||||
|
||||
if (argc != 4) { |
||||
fprintf(stderr, "Usage: x86geninsn <in> <out_nasm> <out_gas>\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; |
||||
} |
||||
|
||||
out_nasm = fopen(argv[2], "wt"); |
||||
if (!out_nasm) { |
||||
fprintf(stderr, "Could not open `%s' for writing\n", argv[2]); |
||||
return EXIT_FAILURE; |
||||
} |
||||
out_gas = fopen(argv[3], "wt"); |
||||
if (!out_gas) { |
||||
fprintf(stderr, "Could not open `%s' for writing\n", argv[2]); |
||||
return EXIT_FAILURE; |
||||
} |
||||
|
||||
output_base(out_nasm, "nasm"); |
||||
output_base(out_gas, "gas"); |
||||
|
||||
/* Parse input file */ |
||||
while (fgets(line, 1024, 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; |
||||
|
||||
if (strcmp(tok, "INSN") == 0) |
||||
parse_insn(out_nasm, out_gas); |
||||
else if (strcmp(tok, "PREFIX") == 0) |
||||
parse_prefix(out_nasm, out_gas); |
||||
else |
||||
report_error("unknown directive `%s'\n", tok); |
||||
cur_line++; |
||||
} |
||||
|
||||
if (num_errors > 0) |
||||
return EXIT_FAILURE; |
||||
|
||||
return EXIT_SUCCESS; |
||||
} |
||||
|
@ -0,0 +1,274 @@ |
||||
# |
||||
# x86 register and target modifier recognition |
||||
# |
||||
# Copyright (C) 2002-2007 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 <util.h> |
||||
RCSID("$Id$"); |
||||
|
||||
#include <libyasm.h> |
||||
#include <libyasm/phash.h> |
||||
|
||||
#include "modules/arch/x86/x86arch.h" |
||||
|
||||
enum regtmod_type { |
||||
REG = 1, |
||||
REGGROUP, |
||||
SEGREG, |
||||
TARGETMOD |
||||
}; |
||||
%} |
||||
%ignore-case |
||||
%language=ANSI-C |
||||
%compare-strncmp |
||||
%readonly-tables |
||||
%enum |
||||
%struct-type |
||||
%define hash-function-name regtmod_hash |
||||
%define lookup-function-name regtmod_find |
||||
struct regtmod_parse_data { |
||||
const char *name; |
||||
unsigned int type:8; /* regtmod_type */ |
||||
|
||||
/* REG: register size |
||||
* SEGREG: prefix encoding |
||||
* Others: 0 |
||||
*/ |
||||
unsigned int size_prefix:8; |
||||
|
||||
/* REG: register index |
||||
* REGGROUP: register group type |
||||
* SEGREG: register encoding |
||||
* TARGETMOD: target modifier |
||||
*/ |
||||
unsigned int data:8; |
||||
|
||||
/* REG: required bits setting |
||||
* SEGREG: BITS in which the segment is ignored |
||||
* Others: 0 |
||||
*/ |
||||
unsigned int bits:8; |
||||
}; |
||||
%% |
||||
# |
||||
# control, debug, and test registers |
||||
# |
||||
cr0, REG, X86_CRREG, 0, 0 |
||||
cr2, REG, X86_CRREG, 2, 0 |
||||
cr3, REG, X86_CRREG, 3, 0 |
||||
cr4, REG, X86_CRREG, 4, 0 |
||||
cr8, REG, X86_CRREG, 8, 64 |
||||
# |
||||
dr0, REG, X86_DRREG, 0, 0 |
||||
dr1, REG, X86_DRREG, 1, 0 |
||||
dr2, REG, X86_DRREG, 2, 0 |
||||
dr3, REG, X86_DRREG, 3, 0 |
||||
dr4, REG, X86_DRREG, 4, 0 |
||||
dr5, REG, X86_DRREG, 5, 0 |
||||
dr6, REG, X86_DRREG, 6, 0 |
||||
dr7, REG, X86_DRREG, 7, 0 |
||||
# |
||||
tr0, REG, X86_TRREG, 0, 0 |
||||
tr1, REG, X86_TRREG, 1, 0 |
||||
tr2, REG, X86_TRREG, 2, 0 |
||||
tr3, REG, X86_TRREG, 3, 0 |
||||
tr4, REG, X86_TRREG, 4, 0 |
||||
tr5, REG, X86_TRREG, 5, 0 |
||||
tr6, REG, X86_TRREG, 6, 0 |
||||
tr7, REG, X86_TRREG, 7, 0 |
||||
# |
||||
# floating point, MMX, and SSE/SSE2 registers |
||||
# |
||||
st0, REG, X86_FPUREG, 0, 0 |
||||
st1, REG, X86_FPUREG, 1, 0 |
||||
st2, REG, X86_FPUREG, 2, 0 |
||||
st3, REG, X86_FPUREG, 3, 0 |
||||
st4, REG, X86_FPUREG, 4, 0 |
||||
st5, REG, X86_FPUREG, 5, 0 |
||||
st6, REG, X86_FPUREG, 6, 0 |
||||
st7, REG, X86_FPUREG, 7, 0 |
||||
# |
||||
mm0, REG, X86_MMXREG, 0, 0 |
||||
mm1, REG, X86_MMXREG, 1, 0 |
||||
mm2, REG, X86_MMXREG, 2, 0 |
||||
mm3, REG, X86_MMXREG, 3, 0 |
||||
mm4, REG, X86_MMXREG, 4, 0 |
||||
mm5, REG, X86_MMXREG, 5, 0 |
||||
mm6, REG, X86_MMXREG, 6, 0 |
||||
mm7, REG, X86_MMXREG, 7, 0 |
||||
# |
||||
xmm0, REG, X86_XMMREG, 0, 0 |
||||
xmm1, REG, X86_XMMREG, 1, 0 |
||||
xmm2, REG, X86_XMMREG, 2, 0 |
||||
xmm3, REG, X86_XMMREG, 3, 0 |
||||
xmm4, REG, X86_XMMREG, 4, 0 |
||||
xmm5, REG, X86_XMMREG, 5, 0 |
||||
xmm6, REG, X86_XMMREG, 6, 0 |
||||
xmm7, REG, X86_XMMREG, 7, 0 |
||||
xmm8, REG, X86_XMMREG, 8, 64 |
||||
xmm9, REG, X86_XMMREG, 9, 64 |
||||
xmm10, REG, X86_XMMREG, 10, 64 |
||||
xmm11, REG, X86_XMMREG, 11, 64 |
||||
xmm12, REG, X86_XMMREG, 12, 64 |
||||
xmm13, REG, X86_XMMREG, 13, 64 |
||||
xmm14, REG, X86_XMMREG, 14, 64 |
||||
xmm15, REG, X86_XMMREG, 15, 64 |
||||
# |
||||
# integer registers |
||||
# |
||||
rax, REG, X86_REG64, 0, 64 |
||||
rcx, REG, X86_REG64, 1, 64 |
||||
rdx, REG, X86_REG64, 2, 64 |
||||
rbx, REG, X86_REG64, 3, 64 |
||||
rsp, REG, X86_REG64, 4, 64 |
||||
rbp, REG, X86_REG64, 5, 64 |
||||
rsi, REG, X86_REG64, 6, 64 |
||||
rdi, REG, X86_REG64, 7, 64 |
||||
r8, REG, X86_REG64, 8, 64 |
||||
r9, REG, X86_REG64, 9, 64 |
||||
r10, REG, X86_REG64, 10, 64 |
||||
r11, REG, X86_REG64, 11, 64 |
||||
r12, REG, X86_REG64, 12, 64 |
||||
r13, REG, X86_REG64, 13, 64 |
||||
r14, REG, X86_REG64, 14, 64 |
||||
r15, REG, X86_REG64, 15, 64 |
||||
# |
||||
eax, REG, X86_REG32, 0, 0 |
||||
ecx, REG, X86_REG32, 1, 0 |
||||
edx, REG, X86_REG32, 2, 0 |
||||
ebx, REG, X86_REG32, 3, 0 |
||||
esp, REG, X86_REG32, 4, 0 |
||||
ebp, REG, X86_REG32, 5, 0 |
||||
esi, REG, X86_REG32, 6, 0 |
||||
edi, REG, X86_REG32, 7, 0 |
||||
r8d, REG, X86_REG32, 8, 64 |
||||
r9d, REG, X86_REG32, 9, 64 |
||||
r10d, REG, X86_REG32, 10, 64 |
||||
r11d, REG, X86_REG32, 11, 64 |
||||
r12d, REG, X86_REG32, 12, 64 |
||||
r13d, REG, X86_REG32, 13, 64 |
||||
r14d, REG, X86_REG32, 14, 64 |
||||
r15d, REG, X86_REG32, 15, 64 |
||||
# |
||||
ax, REG, X86_REG16, 0, 0 |
||||
cx, REG, X86_REG16, 1, 0 |
||||
dx, REG, X86_REG16, 2, 0 |
||||
bx, REG, X86_REG16, 3, 0 |
||||
sp, REG, X86_REG16, 4, 0 |
||||
bp, REG, X86_REG16, 5, 0 |
||||
si, REG, X86_REG16, 6, 0 |
||||
di, REG, X86_REG16, 7, 0 |
||||
r8w, REG, X86_REG16, 8, 64 |
||||
r9w, REG, X86_REG16, 9, 64 |
||||
r10w, REG, X86_REG16, 10, 64 |
||||
r11w, REG, X86_REG16, 11, 64 |
||||
r12w, REG, X86_REG16, 12, 64 |
||||
r13w, REG, X86_REG16, 13, 64 |
||||
r14w, REG, X86_REG16, 14, 64 |
||||
r15w, REG, X86_REG16, 15, 64 |
||||
# |
||||
al, REG, X86_REG8, 0, 0 |
||||
cl, REG, X86_REG8, 1, 0 |
||||
dl, REG, X86_REG8, 2, 0 |
||||
bl, REG, X86_REG8, 3, 0 |
||||
ah, REG, X86_REG8, 4, 0 |
||||
ch, REG, X86_REG8, 5, 0 |
||||
dh, REG, X86_REG8, 6, 0 |
||||
bh, REG, X86_REG8, 7, 0 |
||||
r8b, REG, X86_REG8, 8, 64 |
||||
r9b, REG, X86_REG8, 9, 64 |
||||
r10b, REG, X86_REG8, 10, 64 |
||||
r11b, REG, X86_REG8, 11, 64 |
||||
r12b, REG, X86_REG8, 12, 64 |
||||
r13b, REG, X86_REG8, 13, 64 |
||||
r14b, REG, X86_REG8, 14, 64 |
||||
r15b, REG, X86_REG8, 15, 64 |
||||
# |
||||
spl, REG, X86_REG8X, 4, 64 |
||||
bpl, REG, X86_REG8X, 5, 64 |
||||
sil, REG, X86_REG8X, 6, 64 |
||||
dil, REG, X86_REG8X, 7, 64 |
||||
# |
||||
rip, REG, X86_RIP, 0, 64 |
||||
# |
||||
# floating point, MMX, and SSE/SSE2 registers |
||||
# |
||||
st, REGGROUP, 0, X86_FPUREG, 0 |
||||
mm, REGGROUP, 0, X86_MMXREG, 0 |
||||
xmm, REGGROUP, 0, X86_XMMREG, 0 |
||||
# |
||||
# segment registers |
||||
# |
||||
es, SEGREG, 0x26, 0x00, 64 |
||||
cs, SEGREG, 0x2e, 0x01, 0 |
||||
ss, SEGREG, 0x36, 0x02, 64 |
||||
ds, SEGREG, 0x3e, 0x03, 64 |
||||
fs, SEGREG, 0x64, 0x04, 0 |
||||
gs, SEGREG, 0x65, 0x05, 0 |
||||
# |
||||
# target modifiers |
||||
# |
||||
near, TARGETMOD, 0, X86_NEAR, 0 |
||||
short, TARGETMOD, 0, X86_SHORT, 0 |
||||
far, TARGETMOD, 0, X86_FAR, 0 |
||||
to, TARGETMOD, 0, X86_TO, 0 |
||||
%% |
||||
|
||||
yasm_arch_regtmod |
||||
yasm_x86__parse_check_regtmod(yasm_arch *arch, const char *id, size_t id_len, |
||||
uintptr_t *data) |
||||
{ |
||||
yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch; |
||||
/*@null@*/ const struct regtmod_parse_data *pdata; |
||||
unsigned int bits; |
||||
yasm_arch_regtmod type; |
||||
|
||||
if (id_len > 7) |
||||
return YASM_ARCH_NOTREGTMOD; |
||||
|
||||
pdata = regtmod_find(id, id_len); |
||||
if (!pdata) |
||||
return YASM_ARCH_NOTREGTMOD; |
||||
|
||||
type = (yasm_arch_regtmod)pdata->type; |
||||
bits = pdata->bits; |
||||
|
||||
if (type == YASM_ARCH_REG && bits != 0 && arch_x86->mode_bits != bits) { |
||||
yasm_warn_set(YASM_WARN_GENERAL, |
||||
N_("`%s' is a register in %u-bit mode"), id, bits); |
||||
return YASM_ARCH_NOTREGTMOD; |
||||
} |
||||
|
||||
if (type == YASM_ARCH_SEGREG && bits != 0 && arch_x86->mode_bits == bits) { |
||||
yasm_warn_set(YASM_WARN_GENERAL, |
||||
N_("`%s' segment register ignored in %u-bit mode"), id, |
||||
bits); |
||||
} |
||||
|
||||
if (type == YASM_ARCH_SEGREG) |
||||
*data = (pdata->size_prefix<<8) | pdata->data; |
||||
else |
||||
*data = pdata->size_prefix | pdata->data; |
||||
return type; |
||||
} |
@ -1,9 +1,9 @@ |
||||
# $Id$ |
||||
|
||||
EXTRA_DIST += tools/re2c/Makefile.inc |
||||
EXTRA_DIST += tools/gap/Makefile.inc |
||||
EXTRA_DIST += tools/genperf/Makefile.inc |
||||
EXTRA_DIST += tools/python-yasm/Makefile.inc |
||||
|
||||
include tools/re2c/Makefile.inc |
||||
include tools/gap/Makefile.inc |
||||
include tools/genperf/Makefile.inc |
||||
include tools/python-yasm/Makefile.inc |
||||
|
@ -1,34 +0,0 @@ |
||||
# $Id$ |
||||
|
||||
# These utility programs have to be built for BUILD host in cross-build. |
||||
# This makes things rather non-standard automake |
||||
|
||||
noinst_PROGRAMS += gap |
||||
|
||||
gap_SOURCES = |
||||
EXTRA_DIST += tools/gap/gap.c |
||||
EXTRA_DIST += tools/gap/perfect.c |
||||
EXTRA_DIST += tools/gap/perfect.h |
||||
EXTRA_DIST += tools/gap/standard.h |
||||
gap_LDADD = gap.$(OBJEXT) |
||||
gap_LDADD += gap-perfect.$(OBJEXT) |
||||
gap_LDADD += gap-phash.$(OBJEXT) |
||||
gap_LDADD += gap-xmalloc.$(OBJEXT) |
||||
gap_LDADD += gap-xstrdup.$(OBJEXT) |
||||
gap_LINK = $(CCLD_FOR_BUILD) -o $@ |
||||
|
||||
gap.$(OBJEXT): tools/gap/gap.c |
||||
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f tools/gap/gap.c || echo '$(srcdir)/'`tools/gap/gap.c |
||||
|
||||
gap-perfect.$(OBJEXT): tools/gap/perfect.c |
||||
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f tools/gap/perfect.c || echo '$(srcdir)/'`tools/gap/perfect.c |
||||
|
||||
gap-phash.$(OBJEXT): libyasm/phash.c |
||||
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f libyasm/phash.c || echo '$(srcdir)/'`libyasm/phash.c |
||||
|
||||
gap-xmalloc.$(OBJEXT): libyasm/xmalloc.c |
||||
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f libyasm/xmalloc.c || echo '$(srcdir)/'`libyasm/xmalloc.c |
||||
|
||||
gap-xstrdup.$(OBJEXT): libyasm/xstrdup.c |
||||
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f libyasm/xstrdup.c || echo '$(srcdir)/'`libyasm/xstrdup.c |
||||
|
@ -1,854 +0,0 @@ |
||||
/* $Id$
|
||||
* |
||||
* Generate Arch Parser (GAP): generates ARCHparse.c from ARCHparse.gap. |
||||
* |
||||
* Copyright (C) 2006-2007 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(®tmod_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(®tmod_byp)) { |
||||
db = yasm_xmalloc(sizeof(dir_byp)); |
||||
db->parser = NULL; |
||||
STAILQ_INIT(&db->dirs); |
||||
|
||||
STAILQ_INSERT_TAIL(®tmod_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", ®tmod_byp); |
||||
} |
||||
|
||||
static void |
||||
parse_prefix(void) |
||||
{ |
||||
parse_generic(PREFIX, "PREFIX", &insnprefix_byp); |
||||
} |
||||
|
||||
static void |
||||
parse_reg(void) |
||||
{ |
||||
parse_generic(REG, "REG", ®tmod_byp); |
||||
} |
||||
|
||||
static void |
||||
parse_reggroup(void) |
||||
{ |
||||
parse_generic(REGGROUP, "REGGROUP", ®tmod_byp); |
||||
} |
||||
|
||||
static void |
||||
parse_segreg(void) |
||||
{ |
||||
parse_generic(SEGREG, "SEGREG", ®tmod_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 = (ub4)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(®tmod_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, ®tmod_byp, link) |
||||
perfect_dir(out, "regtmod", db->parser, &db->dirs); |
||||
|
||||
if (errors > 0) |
||||
return EXIT_FAILURE; |
||||
|
||||
return EXIT_SUCCESS; |
||||
} |
||||
|
@ -0,0 +1,34 @@ |
||||
# $Id$ |
||||
|
||||
# These utility programs have to be built for BUILD host in cross-build. |
||||
# This makes things rather non-standard automake |
||||
|
||||
noinst_PROGRAMS += genperf |
||||
|
||||
genperf_SOURCES = |
||||
EXTRA_DIST += tools/genperf/genperf.c |
||||
EXTRA_DIST += tools/genperf/perfect.c |
||||
EXTRA_DIST += tools/genperf/perfect.h |
||||
EXTRA_DIST += tools/genperf/standard.h |
||||
genperf_LDADD = genperf.$(OBJEXT) |
||||
genperf_LDADD += gp-perfect.$(OBJEXT) |
||||
genperf_LDADD += gp-phash.$(OBJEXT) |
||||
genperf_LDADD += gp-xmalloc.$(OBJEXT) |
||||
genperf_LDADD += gp-xstrdup.$(OBJEXT) |
||||
genperf_LINK = $(CCLD_FOR_BUILD) -o $@ |
||||
|
||||
genperf.$(OBJEXT): tools/genperf/genperf.c |
||||
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f tools/genperf/genperf.c || echo '$(srcdir)/'`tools/genperf/genperf.c |
||||
|
||||
gp-perfect.$(OBJEXT): tools/genperf/perfect.c |
||||
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f tools/genperf/perfect.c || echo '$(srcdir)/'`tools/genperf/perfect.c |
||||
|
||||
gp-phash.$(OBJEXT): libyasm/phash.c |
||||
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f libyasm/phash.c || echo '$(srcdir)/'`libyasm/phash.c |
||||
|
||||
gp-xmalloc.$(OBJEXT): libyasm/xmalloc.c |
||||
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f libyasm/xmalloc.c || echo '$(srcdir)/'`libyasm/xmalloc.c |
||||
|
||||
gp-xstrdup.$(OBJEXT): libyasm/xstrdup.c |
||||
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f libyasm/xstrdup.c || echo '$(srcdir)/'`libyasm/xstrdup.c |
||||
|
@ -0,0 +1,519 @@ |
||||
/* $Id$
|
||||
* |
||||
* Generate Minimal Perfect Hash (genperf) |
||||
* |
||||
* Copyright (C) 2006-2007 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/genperf/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(keyword_list, keyword) keyword_list; |
||||
typedef struct keyword { |
||||
STAILQ_ENTRY(keyword) link; |
||||
char *name; |
||||
char *args; |
||||
unsigned int line; |
||||
} keyword; |
||||
|
||||
static unsigned int cur_line = 1; |
||||
static int errors = 0; |
||||
|
||||
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(); |
||||
} |
||||
|
||||
/* make the c output for the perfect hash tab array */ |
||||
static void |
||||
make_c_tab( |
||||
FILE *f, |
||||
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 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 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 "); |
||||
else |
||||
fprintf(f, " static const unsigned short "); |
||||
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_gen(FILE *out, const char *lookup_function_name, |
||||
const char *struct_name, keyword_list *kws, |
||||
const char *filename) |
||||
{ |
||||
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 */ |
||||
keyword *kw; |
||||
|
||||
/* 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(kw, kws, link) { |
||||
key *k = yasm_xmalloc(sizeof(key)); |
||||
|
||||
k->name_k = yasm__xstrdup(kw->name); |
||||
k->len_k = (ub4)strlen(kw->name); |
||||
k->next_k = keys; |
||||
keys = k; |
||||
nkeys++; |
||||
} |
||||
|
||||
/* find the hash */ |
||||
findhash(&tab, &tabh, &alen, &blen, &salt, &final,
|
||||
scramble, &smax, keys, nkeys, &form); |
||||
|
||||
/* The hash function beginning */ |
||||
fprintf(out, "static const struct %s *\n", struct_name); |
||||
fprintf(out, "%s(const char *key, size_t len)\n", lookup_function_name); |
||||
fprintf(out, "{\n"); |
||||
|
||||
/* 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 struct %s pd[%lu] = {\n", struct_name, nkeys); |
||||
for (i=0; i<nkeys; i++) { |
||||
if (tabh[i].key_h) { |
||||
sval *sv; |
||||
STAILQ_FOREACH(kw, kws, link) { |
||||
if (strcmp(kw->name, tabh[i].key_h->name_k) == 0) |
||||
break; |
||||
} |
||||
if (!kw) { |
||||
report_error("internal error: could not find `%s'", |
||||
tabh[i].key_h->name_k); |
||||
break; |
||||
} |
||||
fprintf(out, "#line %u \"%s\"\n", kw->line, filename); |
||||
fprintf(out, " {\"%s\"%s}", kw->name, kw->args); |
||||
} 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, tab, smax, blen, scramble); |
||||
|
||||
/* The hash function body */ |
||||
fprintf(out, " const struct %s *ret;\n", struct_name); |
||||
for (i=0; i<final.used; ++i) |
||||
fprintf(out, final.line[i]); |
||||
fprintf(out, " if (rsl >= %lu) return NULL;\n", nkeys); |
||||
fprintf(out, " ret = &pd[rsl];\n"); |
||||
fprintf(out, " if (strcmp(key, ret->name) != 0) return NULL;\n"); |
||||
fprintf(out, " return ret;\n"); |
||||
fprintf(out, "}\n"); |
||||
fprintf(out, "\n"); |
||||
|
||||
free(tab); |
||||
free(tabh); |
||||
} |
||||
|
||||
int |
||||
main(int argc, char *argv[]) |
||||
{ |
||||
FILE *in; |
||||
size_t i; |
||||
char *ch; |
||||
static char line[1024], tmp[1024]; |
||||
static char struct_name[128] = ""; |
||||
static char lookup_function_name[128] = "in_word_set"; |
||||
static char language[16] = ""; |
||||
static char delimiters[16] = ",\r\n"; |
||||
static char name[128]; |
||||
int need_struct = 0; |
||||
int have_struct = 0; |
||||
int go_keywords = 0; |
||||
int ignore_case = 0; |
||||
int compare_strncmp = 0; |
||||
int readonly_tables = 0; |
||||
slist usercode, usercode2; |
||||
keyword_list keywords; |
||||
sval *sv; |
||||
keyword *kw; |
||||
|
||||
if (argc != 2) { |
||||
fprintf(stderr, "Usage: genperf <in>\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(&usercode); |
||||
STAILQ_INIT(&usercode2); |
||||
STAILQ_INIT(&keywords); |
||||
|
||||
/* Parse declarations section */ |
||||
while (fgets(line, 1024, in)) { |
||||
/* Comments start with # as the first thing on a line */ |
||||
if (line[0] == '#') { |
||||
cur_line++; |
||||
continue; |
||||
} |
||||
|
||||
/* Handle structure declaration */ |
||||
if (strncmp(line, "struct", 6) == 0) { |
||||
int braces; |
||||
|
||||
if (!need_struct) { |
||||
report_error("struct without %%struct-type declaration"); |
||||
return EXIT_FAILURE; |
||||
} |
||||
if (have_struct) { |
||||
report_error("more than one struct declaration"); |
||||
return EXIT_FAILURE; |
||||
} |
||||
have_struct = 1; |
||||
|
||||
/* copy struct name */ |
||||
ch = &line[6]; |
||||
while (isspace(*ch)) |
||||
ch++; |
||||
i = 0; |
||||
while ((isalnum(*ch) || *ch == '_') && i < 127) |
||||
struct_name[i++] = *ch++; |
||||
if (i == 127) { |
||||
report_error("struct name too long"); |
||||
return EXIT_FAILURE; |
||||
} |
||||
struct_name[i] = '\0'; |
||||
|
||||
sv = yasm_xmalloc(sizeof(sval)); |
||||
snprintf(tmp, 1024, "#line %u \"%s\"\n", cur_line, argv[1]); |
||||
sv->str = yasm__xstrdup(tmp); |
||||
STAILQ_INSERT_TAIL(&usercode, sv, link); |
||||
|
||||
braces = 0; |
||||
do { |
||||
/* count braces to determine when we're done */ |
||||
ch = line; |
||||
while (*ch != '\0') { |
||||
if (*ch == '{') |
||||
braces++; |
||||
if (*ch == '}') |
||||
braces--; |
||||
ch++; |
||||
} |
||||
sv = yasm_xmalloc(sizeof(sval)); |
||||
sv->str = yasm__xstrdup(line); |
||||
STAILQ_INSERT_TAIL(&usercode, sv, link); |
||||
cur_line++; |
||||
if (braces <= 0) |
||||
break; |
||||
} while (fgets(line, 1024, in)); |
||||
cur_line++; |
||||
continue; |
||||
} |
||||
|
||||
/* Ignore non-declaration lines */ |
||||
if (line[0] != '%') { |
||||
cur_line++; |
||||
continue; |
||||
} |
||||
|
||||
/* %% terminates declarations section */ |
||||
if (line[1] == '%') { |
||||
if (need_struct && !have_struct) { |
||||
report_error("%%struct-type declaration, but no struct found"); |
||||
return EXIT_FAILURE; |
||||
} |
||||
go_keywords = 1; |
||||
break; /* move on to keywords section */ |
||||
} |
||||
|
||||
/* %{ begins a verbatim code section that ends with %} */ |
||||
if (line[1] == '{') { |
||||
sv = yasm_xmalloc(sizeof(sval)); |
||||
snprintf(tmp, 1024, "#line %u \"%s\"\n\n", cur_line, argv[1]); |
||||
sv->str = yasm__xstrdup(tmp); |
||||
STAILQ_INSERT_TAIL(&usercode, sv, link); |
||||
|
||||
while (fgets(line, 1024, in)) { |
||||
cur_line++; |
||||
if (line[0] == '%' && line[1] == '}') |
||||
break; |
||||
sv = yasm_xmalloc(sizeof(sval)); |
||||
sv->str = yasm__xstrdup(line); |
||||
STAILQ_INSERT_TAIL(&usercode, sv, link); |
||||
} |
||||
cur_line++; |
||||
continue; |
||||
} |
||||
|
||||
if (strncmp(&line[1], "ignore-case", 11) == 0) { |
||||
ignore_case = 1; |
||||
} else if (strncmp(&line[1], "compare-strncmp", 15) == 0) { |
||||
compare_strncmp = 1; |
||||
} else if (strncmp(&line[1], "readonly-tables", 15) == 0) { |
||||
readonly_tables = 1; |
||||
} else if (strncmp(&line[1], "language=", 9) == 0) { |
||||
ch = &line[10]; |
||||
i = 0; |
||||
while (*ch != '\n' && i<15) |
||||
language[i++] = *ch++; |
||||
language[i] = '\0'; |
||||
} else if (strncmp(&line[1], "delimiters=", 11) == 0) { |
||||
ch = &line[12]; |
||||
i = 0; |
||||
while (i<15) |
||||
delimiters[i++] = *ch++; |
||||
delimiters[i] = '\0'; |
||||
} else if (strncmp(&line[1], "enum", 4) == 0) { |
||||
/* unused */ |
||||
} else if (strncmp(&line[1], "struct-type", 11) == 0) { |
||||
need_struct = 1; |
||||
} else if (strncmp(&line[1], "define", 6) == 0) { |
||||
/* Several different defines we need to handle */ |
||||
ch = &line[7]; |
||||
while (isspace(*ch)) |
||||
ch++; |
||||
|
||||
if (strncmp(ch, "hash-function-name", 18) == 0) { |
||||
/* unused */ |
||||
} else if (strncmp(ch, "lookup-function-name", 20) == 0) { |
||||
ch = &line[7+20+1]; |
||||
while (isspace(*ch)) |
||||
ch++; |
||||
i = 0; |
||||
while ((isalnum(*ch) || *ch == '_') && i < 127) |
||||
lookup_function_name[i++] = *ch++; |
||||
if (i == 127) { |
||||
report_error("struct name too long"); |
||||
return EXIT_FAILURE; |
||||
} |
||||
lookup_function_name[i] = '\0'; |
||||
} else { |
||||
fprintf(stderr, "%u: unrecognized define `%s'\n", cur_line, |
||||
line); |
||||
} |
||||
} else { |
||||
fprintf(stderr, "%u: unrecognized declaration `%s'\n", cur_line, |
||||
line); |
||||
} |
||||
|
||||
cur_line++; |
||||
} |
||||
|
||||
if (!go_keywords) { |
||||
report_error("no keywords section found"); |
||||
return EXIT_FAILURE; |
||||
} |
||||
|
||||
/* Parse keywords section */ |
||||
while (fgets(line, 1024, in)) { |
||||
char *d; |
||||
|
||||
/* Comments start with # as the first thing on a line */ |
||||
if (line[0] == '#') { |
||||
cur_line++; |
||||
continue; |
||||
} |
||||
|
||||
/* Keywords section terminated with %% */ |
||||
if (line[0] == '%' && line[1] == '%') |
||||
break; |
||||
|
||||
/* Look for name */ |
||||
ch = &line[0]; |
||||
i = 0; |
||||
while (strchr(delimiters, *ch) == NULL && i < 127) |
||||
name[i++] = *ch++; |
||||
if (i == 127) { |
||||
report_error("keyword name too long"); |
||||
return EXIT_FAILURE; |
||||
} |
||||
name[i] = '\0'; |
||||
|
||||
/* Strip EOL */ |
||||
d = strrchr(ch, '\n'); |
||||
if (d) |
||||
*d = '\0'; |
||||
d = strrchr(ch, '\r'); |
||||
if (d) |
||||
*d = '\0'; |
||||
kw = yasm_xmalloc(sizeof(keyword)); |
||||
kw->name = yasm__xstrdup(name); |
||||
kw->args = yasm__xstrdup(ch); |
||||
kw->line = cur_line; |
||||
STAILQ_INSERT_TAIL(&keywords, kw, link); |
||||
cur_line++; |
||||
} |
||||
|
||||
if (errors > 0) |
||||
return EXIT_FAILURE; |
||||
|
||||
/* Pull in any end code */ |
||||
if (!feof(in)) { |
||||
sv = yasm_xmalloc(sizeof(sval)); |
||||
snprintf(tmp, 1024, "#line %u \"%s\"\n\n", cur_line, argv[1]); |
||||
sv->str = yasm__xstrdup(tmp); |
||||
STAILQ_INSERT_TAIL(&usercode2, sv, link); |
||||
|
||||
while (fgets(line, 1024, in)) { |
||||
sv = yasm_xmalloc(sizeof(sval)); |
||||
sv->str = yasm__xstrdup(line); |
||||
STAILQ_INSERT_TAIL(&usercode2, sv, link); |
||||
} |
||||
} |
||||
|
||||
/* output code */ |
||||
printf("/* %s code produced by genperf */\n", language); |
||||
printf("/* Command-line: genperf %s */\n", argv[1]); |
||||
|
||||
STAILQ_FOREACH(sv, &usercode, link) |
||||
printf("%s", sv->str); |
||||
|
||||
/* Get perfect hash */ |
||||
perfect_gen(stdout, lookup_function_name, struct_name, &keywords, argv[1]); |
||||
|
||||
STAILQ_FOREACH(sv, &usercode2, link) |
||||
printf("%s", sv->str); |
||||
|
||||
if (errors > 0) |
||||
return EXIT_FAILURE; |
||||
|
||||
return EXIT_SUCCESS; |
||||
} |
||||
|
Loading…
Reference in new issue