1
0
mirror of https://git.savannah.gnu.org/git/gperf.git synced 2025-12-02 13:09:22 +00:00

Initial revision

This commit is contained in:
Bruno Haible
2000-08-19 06:20:11 +00:00
commit 501ee3e640
107 changed files with 30411 additions and 0 deletions

143
src/Makefile.in Normal file
View File

@@ -0,0 +1,143 @@
# Makefile for gperf/src
# Copyright (C) 1989, 1992, 1993, 1998 Free Software Foundation, Inc.
# written by Douglas C. Schmidt (schmidt@ics.uci.edu)
#
# This file is part of GNU GPERF.
#
# GNU GPERF 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 1, or (at your option)
# any later version.
#
# GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
# Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA.
#### Start of system configuration section. ####
# Directories used by "make":
srcdir = @srcdir@
# Directories used by "make install":
prefix = @prefix@
local_prefix = /usr/local
exec_prefix = @exec_prefix@
bindir = @bindir@
# Programs used by "make":
# C compiler
CC = @CC@
CFLAGS = @CFLAGS@
CPP = @CPP@
# C++ compiler
CXX = @CXX@
CXXFLAGS = @CXXFLAGS@
CXXCPP = @CXXCPP@
# Other
MV = mv
LN = ln
RM = rm -f
@SET_MAKE@
# Programs used by "make install":
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
#### End of system configuration section. ####
SHELL = /bin/sh
VPATH = $(srcdir)
OBJECTS = new.o options.o iterator.o main.o gen-perf.o key-list.o list-node.o \
hash-table.o bool-array.o read-line.o trace.o vectors.o version.o
LIBS = ../lib/libgp.a -lm
CPPFLAGS = -I. -I$(srcdir)/../lib
TARGETPROG = gperf
all : $(TARGETPROG)
$(TARGETPROG): $(OBJECTS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBS)
# Don't use implicit rules, since AIX "make" and OSF/1 "make" don't always
# expand $< correctly in this context.
#
#%.o : %.c
# $(CC) $(CFLAGS) $(CPPFLAGS) -c $<
#
#%.o : %.cc
# $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $<
# Dependencies.
CONFIG_H = config.h
VERSION_H = version.h
VECTORS_H = vectors.h
TRACE_H = trace.h
READ_LINE_H = read-line.h read-line.icc $(TRACE_H)
OPTIONS_H = options.h options.icc $(TRACE_H)
LIST_NODE_H = list-node.h $(VECTORS_H)
KEY_LIST_H = key-list.h $(LIST_NODE_H) $(VECTORS_H) $(READ_LINE_H)
ITERATOR_H = iterator.h
HASH_TABLE_H = hash-table.h $(LIST_NODE_H)
BOOL_ARRAY_H = bool-array.h bool-array.icc $(TRACE_H) $(OPTIONS_H)
GEN_PERF_H = gen-perf.h $(KEY_LIST_H) $(BOOL_ARRAY_H)
bool-array.o : bool-array.cc $(BOOL_ARRAY_H) $(OPTIONS_H) $(TRACE_H)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/bool-array.cc
gen-perf.o : gen-perf.cc $(GEN_PERF_H) $(OPTIONS_H) $(TRACE_H)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/gen-perf.cc
hash-table.o : hash-table.cc $(HASH_TABLE_H) $(OPTIONS_H) $(TRACE_H)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/hash-table.cc
iterator.o : iterator.cc $(ITERATOR_H) $(TRACE_H)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/iterator.cc
key-list.o : key-list.cc $(KEY_LIST_H) $(OPTIONS_H) $(READ_LINE_H) $(HASH_TABLE_H) $(TRACE_H) $(VERSION_H)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/key-list.cc
list-node.o : list-node.cc $(LIST_NODE_H) $(OPTIONS_H) $(TRACE_H)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/list-node.cc
main.o : main.cc $(OPTIONS_H) $(GEN_PERF_H) $(TRACE_H) $(CONFIG_H)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/main.cc
new.o : new.cc $(TRACE_H) $(CONFIG_H)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/new.cc
options.o : options.cc $(OPTIONS_H) $(ITERATOR_H) $(TRACE_H) $(VECTORS_H) $(VERSION_H)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/options.cc
read-line.o : read-line.cc $(READ_LINE_H) $(OPTIONS_H) $(TRACE_H)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/read-line.cc
trace.o : trace.cc $(TRACE_H)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/trace.cc
vectors.o : vectors.cc $(VECTORS_H)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/vectors.cc
version.o : version.cc $(VERSION_H)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/version.cc
install : all force
if [ ! -d $(bindir) ] ; then mkdir $(bindir) ; fi
$(INSTALL_PROGRAM) $(TARGETPROG) $(bindir)/$(TARGETPROG)
installdirs : force
if [ ! -d $(bindir) ] ; then mkdir $(bindir) ; fi
uninstall : force
$(RM) $(bindir)/$(TARGETPROG)
check : all
mostlyclean : clean
clean : force
$(RM) *~ *.s *.o *.a $(TARGETPROG) core
distclean : clean
$(RM) config.status config.log config.cache Makefile config.h
maintainer-clean : distclean
force :

49
src/bool-array.cc Normal file
View File

@@ -0,0 +1,49 @@
/* Fast lookup table abstraction implemented as an Iteration Number Array
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include "bool-array.h"
#include <stdio.h>
#include <string.h>
#include "options.h"
#include "trace.h"
STORAGE_TYPE * Bool_Array::storage_array;
STORAGE_TYPE Bool_Array::iteration_number;
unsigned int Bool_Array::size;
/* Prints out debugging diagnostics. */
Bool_Array::~Bool_Array (void)
{
T (Trace t ("Bool_Array::~Bool_Array");)
if (option[DEBUG])
fprintf (stderr, "\ndumping boolean array information\n"
"size = %d\niteration number = %d\nend of array dump\n",
size, iteration_number);
}
#ifndef __OPTIMIZE__
#define INLINE /* not inline */
#include "bool-array.icc"
#undef INLINE
#endif /* not defined __OPTIMIZE__ */

66
src/bool-array.h Normal file
View File

@@ -0,0 +1,66 @@
/* This may look like C code, but it is really -*- C++ -*- */
/* Simple lookup table abstraction implemented as an Iteration Number Array.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* Define and implement a simple boolean array abstraction,
uses an Iteration Numbering implementation to save on initialization time. */
#ifndef bool_array_h
#define bool_array_h 1
#include "trace.h"
#ifdef LO_CAL
/* If we are on a memory diet then we'll only make these use a limited
amount of storage space. */
typedef unsigned short STORAGE_TYPE;
#else
typedef unsigned int STORAGE_TYPE;
#endif
class Bool_Array
{
private:
static STORAGE_TYPE *storage_array; /* Initialization of the index space. */
static STORAGE_TYPE iteration_number; /* Keep track of the current iteration. */
static unsigned int size; /* Keep track of array size. */
public:
Bool_Array (void);
~Bool_Array (void);
static void init (STORAGE_TYPE *buffer, unsigned int s);
static int find (int hash_value);
static void reset (void);
};
#ifdef __OPTIMIZE__ /* efficiency hack! */
#include <stdio.h>
#include <string.h>
#include "options.h"
#define INLINE inline
#include "bool-array.icc"
#undef INLINE
#endif
#endif

85
src/bool-array.icc Normal file
View File

@@ -0,0 +1,85 @@
/* Inline Functions for bool-array.{h,cc}.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
// This needs:
//#include <stdio.h>
//#include <string.h>
//#include "options.h"
//#include "trace.h"
INLINE
Bool_Array::Bool_Array (void)
{
T (Trace t ("Bool_Array::Bool_Array");)
storage_array = 0;
iteration_number = size = 0;
}
INLINE void
Bool_Array::init (STORAGE_TYPE *buffer, unsigned int s)
{
T (Trace t ("Bool_Array::init");)
size = s;
iteration_number = 1;
storage_array = buffer;
memset (storage_array, 0, s * sizeof (*storage_array));
if (option[DEBUG])
fprintf (stderr, "\nbool array size = %d, total bytes = %d\n",
size, (unsigned int) (size * sizeof (*storage_array)));
}
INLINE int
Bool_Array::find (int index)
{
T (Trace t ("Bool_Array::find");)
if (storage_array[index] == iteration_number)
return 1;
else
{
storage_array[index] = iteration_number;
return 0;
}
}
INLINE void
Bool_Array::reset (void)
{
T (Trace t ("Bool_Array::reset");)
/* If we wrap around it's time to zero things out again! However, this only
occurs once about every 2^31 or 2^15 iterations, so it should probably
never happen! */
if (++iteration_number == 0)
{
if (option[DEBUG])
{
fprintf (stderr, "(re-initializing bool_array)...");
fflush (stderr);
}
iteration_number = 1;
memset (storage_array, 0, size * sizeof (*storage_array));
if (option[DEBUG])
{
fprintf (stderr, "done\n");
fflush (stderr);
}
}
}

19
src/config.h.in Normal file
View File

@@ -0,0 +1,19 @@
/* config.h.in. Generated automatically from configure.in by autoheader. */
/* Define if the C++ compiler supports "throw ()" declarations. */
#undef HAVE_THROW_DECL
/* Define if you have the getrlimit function. */
#undef HAVE_GETRLIMIT
/* Define if you have the setrlimit function. */
#undef HAVE_SETRLIMIT
/* Define if you have the <sys/resource.h> header file. */
#undef HAVE_SYS_RESOURCE_H
/* Define if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H

1573
src/configure vendored Executable file

File diff suppressed because it is too large Load Diff

71
src/configure.in Normal file
View File

@@ -0,0 +1,71 @@
dnl autoconf configuration for gperf/src
dnl Copyright (C) 1998 Free Software Foundation, Inc.
dnl written by Douglas C. Schmidt (schmidt@ics.uci.edu)
dnl
dnl This file is part of GNU GPERF.
dnl
dnl GNU GPERF is free software; you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
dnl the Free Software Foundation; either version 1, or (at your option)
dnl any later version.
dnl
dnl GNU GPERF is distributed in the hope that it will be useful,
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
dnl GNU General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License
dnl along with GNU GPERF; see the file COPYING. If not, write to the
dnl Free Software Foundation, 59 Temple Place - Suite 330, Boston,
dnl MA 02111-1307, USA.
AC_INIT(gen-perf.cc)
AC_CONFIG_HEADER(config.h)
AC_PROG_MAKE_SET
dnl
dnl checks for programs
dnl
AC_PROG_CC
dnl sets variable CC
AC_PROG_CPP
dnl sets variable CPP
AC_PROG_CXX
dnl sets variable CXX
AC_PROG_CXXCPP
dnl sets variable CXXCPP
CL_PROG_INSTALL
dnl sets variables INSTALL, INSTALL_DATA, INSTALL_PROGRAM
dnl
dnl checks for compiler characteristics
dnl
AC_MSG_CHECKING([for working throw()])
AC_CACHE_VAL(gp_cxx_throw_decl,[
AC_LANG_SAVE()
AC_LANG_CPLUSPLUS()
AC_TRY_COMPILE([#include <stdlib.h>
void operator delete (void* ptr) throw() {}], [],
gp_cxx_throw_decl=yes, gp_cxx_throw_decl=no)
AC_LANG_RESTORE()
])
AC_MSG_RESULT([$]gp_cxx_throw_decl)
if test [$]gp_cxx_throw_decl = yes; then
AC_DEFINE(HAVE_THROW_DECL)
fi
dnl
dnl checks for functions and declarations
dnl
AC_CHECK_HEADERS(unistd.h sys/time.h sys/resource.h)
dnl DEFs HAVE_UNISTD_H, HAVE_SYS_TIME_H, HAVE_SYS_RESOURCE_H
if test $ac_cv_header_sys_resource_h = yes; then
AC_CHECK_FUNCS(getrlimit)
dnl DEFS HAVE_GETRLIMIT
if test $ac_cv_func_getrlimit = yes; then
AC_CHECK_FUNCS(setrlimit)
dnl DEFS HAVE_SETRLIMIT
fi
fi
dnl
dnl That's it.
dnl
AC_OUTPUT(Makefile)

342
src/gen-perf.cc Normal file
View File

@@ -0,0 +1,342 @@
/* Provides high-level routines to manipulate the keywork list
structures the code generation output.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <stdio.h>
#include <stdlib.h> /* declares rand(), srand() */
#include <time.h> /* declares time() */
#include "options.h"
#include "gen-perf.h"
#include "trace.h"
/* Efficiently returns the least power of two greater than or equal to X! */
#define POW(X) ((!X)?1:(X-=1,X|=X>>1,X|=X>>2,X|=X>>4,X|=X>>8,X|=X>>16,(++X)))
/* Reads input keys, possibly applies the reordering heuristic, sets the
maximum associated value size (rounded up to the nearest power of 2),
may initialize the associated values array, and determines the maximum
hash table size. Note: using the random numbers is often helpful,
though not as deterministic, of course! */
Gen_Perf::Gen_Perf (void)
{
T (Trace t ("Gen_Perf::Gen_Perf");)
int asso_value_max;
int non_linked_length;
Key_List::read_keys ();
if (option[ORDER])
reorder ();
asso_value_max = option.get_asso_max ();
non_linked_length = Key_List::keyword_list_length ();
num_done = 1;
fewest_collisions = 0;
if (asso_value_max == 0)
asso_value_max = non_linked_length;
else if (asso_value_max > 0)
asso_value_max *= non_linked_length;
else /* if (asso_value_max < 0) */
asso_value_max = non_linked_length / -asso_value_max;
option.set_asso_max (POW (asso_value_max));
if (option[RANDOM])
{
srand ((long) time (0));
for (int i = 0; i < ALPHA_SIZE; i++)
asso_values[i] = (rand () & asso_value_max - 1);
}
else
{
int asso_value = option.initial_value ();
if (asso_value) /* Initialize array if user requests non-zero default. */
for (int i = ALPHA_SIZE - 1; i >= 0; i--)
asso_values[i] = asso_value & option.get_asso_max () - 1;
}
max_hash_value = Key_List::max_key_length () + option.get_asso_max () *
option.get_max_keysig_size ();
if (option[DEBUG])
fprintf (stderr, "total non-linked keys = %d\nmaximum associated value is %d"
"\nmaximum size of generated hash table is %d\n",
non_linked_length, asso_value_max, max_hash_value);
}
/* Merge two disjoint hash key multisets to form the ordered disjoint union of the sets.
(In a multiset, an element can occur multiple times).
Precondition: both set_1 and set_2 must be ordered. Returns the length
of the combined set. */
inline int
Gen_Perf::compute_disjoint_union (const char *set_1, const char *set_2, char *set_3)
{
T (Trace t ("Gen_Perf::compute_disjoint_union");)
char *base = set_3;
while (*set_1 && *set_2)
if (*set_1 == *set_2)
set_1++, set_2++;
else
{
*set_3 = *set_1 < *set_2 ? *set_1++ : *set_2++;
if (set_3 == base || *set_3 != *(set_3-1)) set_3++;
}
while (*set_1)
{
*set_3 = *set_1++;
if (set_3 == base || *set_3 != *(set_3-1)) set_3++;
}
while (*set_2)
{
*set_3 = *set_2++;
if (set_3 == base || *set_3 != *(set_3-1)) set_3++;
}
*set_3 = '\0';
return set_3 - base;
}
/* Sort the UNION_SET in increasing frequency of occurrence.
This speeds up later processing since we may assume the resulting
set (Set_3, in this case), is ordered. Uses insertion sort, since
the UNION_SET is typically short. */
inline void
Gen_Perf::sort_set (char *union_set, int len)
{
T (Trace t ("Gen_Perf::sort_set");)
int i, j;
for (i = 0, j = len - 1; i < j; i++)
{
int curr;
char tmp;
for (curr = i + 1, tmp = union_set[curr];
curr > 0 && occurrences[(unsigned char)tmp] < occurrences[(unsigned char)(union_set[curr-1])];
curr--)
union_set[curr] = union_set[curr - 1];
union_set[curr] = tmp;
}
}
/* Generate a key set's hash value. */
inline int
Gen_Perf::hash (List_Node *key_node)
{
T (Trace t ("Gen_Perf::hash");)
int sum = option[NOLENGTH] ? 0 : key_node->length;
for (const char *ptr = key_node->char_set; *ptr; ptr++)
sum += asso_values[(unsigned char)(*ptr)];
return key_node->hash_value = sum;
}
/* Find out how character value change affects successfully hashed items.
Returns FALSE if no other hash values are affected, else returns TRUE.
Note that because Option.Get_Asso_Max is a power of two we can guarantee
that all legal Asso_Values are visited without repetition since
Option.Get_Jump was forced to be an odd value! */
inline int
Gen_Perf::affects_prev (char c, List_Node *curr)
{
T (Trace t ("Gen_Perf::affects_prev");)
int original_char = asso_values[(unsigned char)c];
int total_iterations = !option[FAST]
? option.get_asso_max () : option.get_iterations () ? option.get_iterations () : keyword_list_length ();
/* Try all legal associated values. */
for (int i = total_iterations - 1; i >= 0; i--)
{
int collisions = 0;
asso_values[(unsigned char)c] =
(asso_values[(unsigned char)c] + (option.get_jump () ? option.get_jump () : rand ()))
& (option.get_asso_max () - 1);
/* Iteration Number array is a win, O(1) intialization time! */
reset ();
/* See how this asso_value change affects previous keywords. If
it does better than before we'll take it! */
for (List_Node *ptr = head;
!Bool_Array::find (hash (ptr)) || ++collisions < fewest_collisions;
ptr = ptr->next)
if (ptr == curr)
{
fewest_collisions = collisions;
if (option[DEBUG])
fprintf (stderr, "- resolved after %d iterations", total_iterations - i);
return 0;
}
}
/* Restore original values, no more tries. */
asso_values[(unsigned char)c] = original_char;
/* If we're this far it's time to try the next character.... */
return 1;
}
/* Change a character value, try least-used characters first. */
void
Gen_Perf::change (List_Node *prior, List_Node *curr)
{
T (Trace t ("Gen_Perf::change");)
static char *union_set;
if (!union_set)
union_set = new char [2 * option.get_max_keysig_size () + 1];
if (option[DEBUG])
{
fprintf (stderr, "collision on keyword #%d, prior = \"%s\", curr = \"%s\" hash = %d\n",
num_done, prior->key, curr->key, curr->hash_value);
fflush (stderr);
}
sort_set (union_set, compute_disjoint_union (prior->char_set, curr->char_set, union_set));
/* Try changing some values, if change doesn't alter other values continue normal action. */
fewest_collisions++;
for (char *temp = union_set; *temp; temp++)
if (!affects_prev (*temp, curr))
{
if (option[DEBUG])
{
fprintf (stderr, " by changing asso_value['%c'] (char #%d) to %d\n",
*temp, temp - union_set + 1, asso_values[(unsigned char)(*temp)]);
fflush (stderr);
}
return; /* Good, doesn't affect previous hash values, we'll take it. */
}
for (List_Node *ptr = head; ptr != curr; ptr = ptr->next)
hash (ptr);
hash (curr);
if (option[DEBUG])
{
fprintf (stderr, "** collision not resolved after %d iterations, %d duplicates remain, continuing...\n",
!option[FAST] ? option.get_asso_max () : option.get_iterations () ? option.get_iterations () : keyword_list_length (),
fewest_collisions + total_duplicates);
fflush (stderr);
}
}
/* Does the hard stuff....
Initializes the Iteration Number array, and attempts to find a perfect
function that will hash all the key words without getting any
duplications. This is made much easier since we aren't attempting
to generate *minimum* functions, only perfect ones.
If we can't generate a perfect function in one pass *and* the user
hasn't enabled the DUP option, we'll inform the user to try the
randomization option, use -D, or choose alternative key positions.
The alternatives (e.g., back-tracking) are too time-consuming, i.e,
exponential in the number of keys. */
int
Gen_Perf::operator() (void)
{
T (Trace t ("Gen_Perf::operator()");)
#if LARGE_STACK_ARRAYS
STORAGE_TYPE buffer[max_hash_value + 1];
#else
// Note: we don't use new, because that invokes a custom operator new.
STORAGE_TYPE *buffer
= (STORAGE_TYPE*) malloc (sizeof(STORAGE_TYPE) * (max_hash_value + 1));
if (buffer == NULL)
abort ();
#endif
Bool_Array::init (buffer, max_hash_value + 1);
List_Node *curr;
for (curr = head; curr; curr = curr->next)
{
hash (curr);
for (List_Node *ptr = head; ptr != curr; ptr = ptr->next)
if (ptr->hash_value == curr->hash_value)
{
change (ptr, curr);
break;
}
num_done++;
}
/* Make one final check, just to make sure nothing weird happened.... */
Bool_Array::reset ();
for (curr = head; curr; curr = curr->next)
if (Bool_Array::find (hash (curr)))
if (option[DUP]) /* Keep track of this number... */
total_duplicates++;
else /* Yow, big problems. we're outta here! */
{
fprintf (stderr, "\nInternal error, duplicate value %d:\n"
"try options -D or -r, or use new key positions.\n\n", hash (curr));
#if !LARGE_STACK_ARRAYS
free ((char *) buffer);
#endif
return 1;
}
/* Sorts the key word list by hash value, and then outputs the list.
The generated hash table code is only output if the early stage of
processing turned out O.K. */
sort ();
output ();
#if !LARGE_STACK_ARRAYS
free ((char *) buffer);
#endif
return 0;
}
/* Prints out some diagnostics upon completion. */
Gen_Perf::~Gen_Perf (void)
{
T (Trace t ("Gen_Perf::~Gen_Perf");)
if (option[DEBUG])
{
fprintf (stderr, "\ndumping occurrence and associated values tables\n");
for (int i = 0; i < ALPHA_SIZE; i++)
if (occurrences[i])
fprintf (stderr, "asso_values[%c] = %6d, occurrences[%c] = %6d\n",
i, asso_values[i], i, occurrences[i]);
fprintf (stderr, "end table dumping\n");
}
}

50
src/gen-perf.h Normal file
View File

@@ -0,0 +1,50 @@
/* This may look like C code, but it is really -*- C++ -*- */
/* Provides high-level routines to manipulate the keyword list
structures the code generation output.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#ifndef gen_perf_h
#define gen_perf_h 1
#include "key-list.h"
#include "bool-array.h"
class Gen_Perf : private Key_List, private Bool_Array
{
private:
int max_hash_value; /* Maximum possible hash value. */
int fewest_collisions; /* Records fewest # of collisions for asso value. */
int num_done; /* Number of keywords processed without a collision. */
void change (List_Node *prior, List_Node *curr);
int affects_prev (char c, List_Node *curr);
static int hash (List_Node *key_node);
static int compute_disjoint_union (const char *set_1, const char *set_2, char *set_3);
static void sort_set (char *union_set, int len);
public:
Gen_Perf (void);
~Gen_Perf (void);
int operator () (void);
};
#endif

91
src/hash-table.cc Normal file
View File

@@ -0,0 +1,91 @@
/* Hash table for checking keyword links. Implemented using double hashing.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include "hash-table.h"
#include <stdio.h>
#include <string.h> /* declares memset(), strcmp() */
#include <hash.h>
#include "options.h"
#include "trace.h"
#define NIL(TYPE) (TYPE *)0
/* The size of the hash table is always the smallest power of 2 >= the size
indicated by the user. This allows several optimizations, including
the use of double hashing and elimination of the mod instruction.
Note that the size had better be larger than the number of items
in the hash table, else there's trouble!!! Note that the memory
for the hash table is allocated *outside* the intialization routine.
This compromises information hiding somewhat, but greatly reduces
memory fragmentation, since we can now use alloca! */
Hash_Table::Hash_Table (List_Node **table_ptr, int s):
table (table_ptr), size (s), collisions (0)
{
T (Trace t ("Hash_Table::Hash_Table");)
memset ((char *) table, 0, size * sizeof (*table));
}
Hash_Table::~Hash_Table (void)
{
T (Trace t ("Hash_Table::~Hash_Table");)
if (option[DEBUG])
{
int field_width = option.get_max_keysig_size ();
fprintf (stderr,
"\ndumping the hash table\n"
"total available table slots = %d, total bytes = %d, total collisions = %d\n"
"location, %*s, keyword\n",
size, size * (int) sizeof (*table), collisions,
field_width, "keysig");
for (int i = size - 1; i >= 0; i--)
if (table[i])
fprintf (stderr, "%8d, %*s, %s\n",
i, field_width, table[i]->char_set, table[i]->key);
fprintf (stderr, "\nend dumping hash table\n\n");
}
}
/* If the ITEM is already in the hash table return the item found
in the table. Otherwise inserts the ITEM, and returns FALSE.
Uses double hashing. */
List_Node *
Hash_Table::operator() (List_Node *item, int ignore_length)
{
T (Trace t ("Hash_Table::operator()");)
unsigned hash_val = hashpjw (item->char_set);
int probe = hash_val & size - 1;
int increment = (hash_val ^ item->length | 1) & size - 1;
while (table[probe]
&& (strcmp (table[probe]->char_set, item->char_set)
|| (!ignore_length && table[probe]->length != item->length)))
{
collisions++;
probe = probe + increment & size - 1;
}
return table[probe] ? table[probe] : (table[probe] = item, NIL (List_Node));
}

42
src/hash-table.h Normal file
View File

@@ -0,0 +1,42 @@
/* This may look like C code, but it is really -*- C++ -*- */
/* Hash table used to check for duplicate keyword entries.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#ifndef hash_table_h
#define hash_table_h 1
#include "list-node.h"
class Hash_Table
{
private:
List_Node **table; /* Vector of pointers to linked lists of List_Node's. */
int size; /* Size of the vector. */
int collisions; /* Find out how well our double hashing is working! */
public:
Hash_Table (List_Node **t, int s);
~Hash_Table (void);
List_Node *operator () (List_Node *item, int ignore_length);
};
#endif

88
src/iterator.cc Normal file
View File

@@ -0,0 +1,88 @@
/* Provides an Iterator for keyword characters.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include "iterator.h"
#include <stream.h>
#include <ctype.h>
#include "trace.h"
/* Constructor for Iterator. */
Iterator::Iterator (const char *s, int lo, int hi, int word_end, int bad_val, int key_end)
{
T (Trace t ("Iterator::Iterator");)
end = key_end;
error_value = bad_val;
end_word = word_end;
str = s;
hi_bound = hi;
lo_bound = lo;
}
/* Provide an Iterator, returning the ``next'' value from
the list of valid values given in the constructor. */
int
Iterator::operator() (void)
{
T (Trace t ("Iterator::operator()");)
/* Variables to record the Iterator's status when handling ranges, e.g., 3-12. */
static int size;
static int curr_value;
static int upper_bound;
if (size)
{
if (++curr_value >= upper_bound)
size = 0;
return curr_value;
}
else
{
while (*str)
switch (*str)
{
default: return error_value;
case ',': str++; break;
case '$': str++; return end_word;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
for (curr_value = 0; isdigit ((unsigned char)(*str)); str++)
curr_value = curr_value * 10 + (*str - '0');
if (*str == '-')
{
for (size = 1, upper_bound = 0;
isdigit ((unsigned char)(*++str));
upper_bound = upper_bound * 10 + (*str - '0'));
if (upper_bound <= curr_value || upper_bound > hi_bound)
return error_value;
}
return curr_value >= lo_bound && curr_value <= hi_bound
? curr_value : error_value;
}
return end;
}
}

51
src/iterator.h Normal file
View File

@@ -0,0 +1,51 @@
/* This may look like C code, but it is really -*- C++ -*- */
/* Provides an Iterator for keyword characters.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* Provides an Iterator that expands and decodes a control string containing digits
and ranges, returning an integer every time the generator function is called.
This is used to decode the user's key position requests. For example:
"-k 1,2,5-10,$" will return 1, 2, 5, 6, 7, 8, 9, 10, and 0 ( representing
the abstract ``last character of the key'' on successive calls to the
member function operator ().
No errors are handled in these routines, they are passed back to the
calling routines via a user-supplied Error_Value */
#ifndef iterator_h
#define iterator_h 1
class Iterator
{
private:
const char *str; /* A pointer to the string provided by the user. */
int end; /* Value returned after last key is processed. */
int end_word; /* A value marking the abstract ``end of word'' ( usually '$'). */
int error_value; /* Error value returned when input is syntactically erroneous. */
int hi_bound; /* Greatest possible value, inclusive. */
int lo_bound; /* Smallest possible value, inclusive. */
public:
Iterator (const char *s, int lo, int hi, int word_end, int bad_val, int key_end);
int operator () (void);
};
#endif

1957
src/key-list.cc Normal file

File diff suppressed because it is too large Load Diff

96
src/key-list.h Normal file
View File

@@ -0,0 +1,96 @@
/* This may look like C code, but it is really -*- C++ -*- */
/* Data and function member declarations for the keyword list class.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
/* The key word list is a useful abstraction that keeps track of
various pieces of information that enable that fast generation
of the Gen_Perf.hash function. A Key_List is a singly-linked
list of List_Nodes. */
#ifndef key_list_h
#define key_list_h 1
#include "list-node.h"
#include "vectors.h"
#include "read-line.h"
/* OSF/1 cxx needs these forward declarations. */
struct Output_Constants;
struct Output_Compare;
class Key_List : private Read_Line, public Vectors
{
private:
const char *array_type; /* Pointer to the type for word list. */
const char *return_type; /* Pointer to return type for lookup function. */
const char *struct_tag; /* Shorthand for user-defined struct tag type. */
const char *include_src; /* C source code to be included verbatim. */
int max_key_len; /* Maximum length of the longest keyword. */
int min_key_len; /* Minimum length of the shortest keyword. */
int min_hash_value; /* Minimum hash value for all keywords. */
int max_hash_value; /* Maximum hash value for all keywords. */
int occurrence_sort; /* True if sorting by occurrence. */
int hash_sort; /* True if sorting by hash value. */
int additional_code; /* True if any additional C code is included. */
int list_len; /* Length of head's Key_List, not counting duplicates. */
int total_keys; /* Total number of keys, counting duplicates. */
static int determined[MAX_ALPHA_SIZE]; /* Used in function reorder, below. */
static int get_occurrence (List_Node *ptr);
#ifndef strcspn
static int strcspn (const char *s, const char *reject);
#endif
static int already_determined (List_Node *ptr);
static void set_determined (List_Node *ptr);
void compute_min_max (void);
int num_hash_values (void);
void output_constants (struct Output_Constants&);
void output_hash_function (void);
void output_keylength_table (void);
void output_keyword_table (void);
void output_lookup_array (void);
void output_lookup_tables (void);
void output_lookup_function_body (const struct Output_Compare&);
void output_lookup_function (void);
void set_output_types (void);
void dump (void);
const char *get_array_type (void);
const char *save_include_src (void);
const char *get_special_input (char delimiter);
List_Node *merge (List_Node *list1, List_Node *list2);
List_Node *merge_sort (List_Node *head);
protected:
List_Node *head; /* Points to the head of the linked list. */
int total_duplicates; /* Total number of duplicate hash values. */
public:
Key_List (void);
~Key_List (void);
int keyword_list_length (void);
int max_key_length (void);
void reorder (void);
void sort (void);
void read_keys (void);
void output (void);
};
#endif

101
src/list-node.cc Normal file
View File

@@ -0,0 +1,101 @@
/* Creates and initializes a new list node.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include "list-node.h"
#include <stdio.h>
#include <stdlib.h> /* declares exit() */
#include "options.h"
#include "trace.h"
/* Sorts the key set alphabetically to speed up subsequent operations.
Uses insertion sort since the set is probably quite small. */
inline void
List_Node::set_sort (char *base, int len)
{
T (Trace t ("List_Node::set_sort");)
int i, j;
for (i = 0, j = len - 1; i < j; i++)
{
char curr, tmp;
for (curr = i + 1, tmp = base[curr]; curr > 0 && tmp < base[curr-1]; curr--)
base[curr] = base[curr - 1];
base[curr] = tmp;
}
}
/* Initializes a List_Node. This requires obtaining memory for the CHAR_SET
initializing them using the information stored in the KEY_POSITIONS array in Options,
and checking for simple errors. It's important to note that KEY and REST are
both pointers to the different offsets into the same block of dynamic memory pointed
to by parameter K. The data member REST is used to store any additional fields
of the input file (it is set to the "" string if Option[TYPE] is not enabled).
This is useful if the user wishes to incorporate a lookup structure,
rather than just an array of keys. Finally, KEY_NUMBER contains a count
of the total number of keys seen so far. This is used to initialize
the INDEX field to some useful value. */
List_Node::List_Node (char *k, int len): link (0), next (0),
key (k), rest (option[TYPE] ? k + len + 1 : ""), length (len), index (0)
{
T (Trace t ("List_Node::List_Node");)
char *ptr = new char[(option[ALLCHARS] ? len : option.get_max_keysig_size ()) + 1];
char *key_set = ptr;
k[len] = '\0'; /* Null terminate KEY to separate it from REST. */
if (option[ALLCHARS]) /* Use all the character position in the KEY. */
for (; *k; k++, ptr++)
++occurrences[(unsigned char)(*ptr = *k)];
else /* Only use those character positions specified by the user. */
{
int i;
/* Iterate thru the list of key_positions, initializing occurrences table
and char_set (via char * pointer ptr). */
for (option.reset (); (i = option.get ()) != EOS; )
{
if (i == WORD_END) /* Special notation for last KEY position, i.e. '$'. */
*ptr = key[len - 1];
else if (i <= len) /* Within range of KEY length, so we'll keep it. */
*ptr = key[i - 1];
else /* Out of range of KEY length, so we'll just skip it. */
continue;
++occurrences[(unsigned char)(*ptr++)];
}
/* Didn't get any hits and user doesn't want to consider the
keylength, so there are essentially no usable hash positions! */
if (ptr == char_set && option[NOLENGTH])
{
fprintf (stderr, "Can't hash keyword %s with chosen key positions.\n", key);
exit (1);
}
}
*ptr = '\0'; /* Terminate this bastard.... */
/* Sort the KEY_SET items alphabetically. */
set_sort (key_set, ptr - key_set);
char_set = key_set;
}

45
src/list-node.h Normal file
View File

@@ -0,0 +1,45 @@
/* This may look like C code, but it is really -*- C++ -*- */
/* Data and function members for defining values and operations of a list node.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#ifndef list_node_h
#define list_node_h 1
#include "vectors.h"
struct List_Node : private Vectors
{
List_Node *link; /* TRUE if key has an identical KEY_SET as another key. */
List_Node *next; /* Points to next element on the list. */
const char *key; /* Each keyword string stored here. */
const char *rest; /* Additional information for building hash function. */
const char *char_set; /* Set of characters to hash, specified by user. */
int length; /* Length of the key. */
int hash_value; /* Hash value for the key. */
int occurrence; /* A metric for frequency of key set occurrences. */
int index; /* Position of this node relative to other nodes. */
List_Node (char *key, int len);
static void set_sort (char *base, int len);
};
#endif

72
src/main.cc Normal file
View File

@@ -0,0 +1,72 @@
/* Driver program for the Gen_Perf hash function generator
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
/* Simple driver program for the Gen_Perf.hash function generator.
Most of the hard work is done in class Gen_Perf and its class methods. */
#include "config.h"
#include <sys/types.h>
#if LARGE_STACK_ARRAYS && defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#endif
#include <stdio.h>
#include "options.h"
#include "gen-perf.h"
#include "trace.h"
int
main (int argc, char *argv[])
{
T (Trace t ("main");)
#if LARGE_STACK_ARRAYS && defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) && defined(RLIMIT_STACK)
/* Get rid of any avoidable limit on stack size. */
{
struct rlimit rlim;
if (getrlimit (RLIMIT_STACK, &rlim) == 0)
if (rlim.rlim_cur < rlim.rlim_max)
{
rlim.rlim_cur = rlim.rlim_max;
setrlimit (RLIMIT_STACK, &rlim);
}
}
#endif /* RLIMIT_STACK */
/* Sets the Options. */
option (argc, argv);
/* Initializes the key word list. */
Gen_Perf generate_table;
/* Generates and prints the Gen_Perf hash table. */
int status = generate_table ();
/* Don't use exit() here, it skips the destructors. */
return status;
}

87
src/new.cc Normal file
View File

@@ -0,0 +1,87 @@
/* Defines a buffered memory allocation abstraction that reduces calls to
malloc.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include "config.h"
#include <stdio.h>
#include <stdlib.h> /* declares malloc(), exit() */
#include "trace.h"
/* Determine default alignment. If your C++ compiler does not
like this then try something like #define DEFAULT_ALIGNMENT 8. */
struct fooalign {char x; double d;};
const int ALIGNMENT = ((char *)&((struct fooalign *) 0)->d - (char *)0);
/* Provide an abstraction that cuts down on the number of
calls to NEW by buffering the memory pool from which
strings are allocated. */
void *
operator new (size_t size)
{
T (Trace t ("operator new");)
static char *buf_start = 0; /* Large array used to reduce calls to NEW. */
static char *buf_end = 0; /* Indicates end of BUF_START. */
static size_t buf_size = 4096; /* Size of buffer pointed to by BUF_START. */
char *temp;
/* Align this on correct boundaries, just to be safe... */
size = ((size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
/* If we are about to overflow our buffer we'll just grab another
chunk of memory. Since we never free the original memory it
doesn't matter that no one points to the beginning of that
chunk. Note we use a heuristic that grows the buffer either by
size of the request or by twice the previous size, whichever is
larger. */
if (buf_start + size >= buf_end)
{
buf_size *= 2;
if (buf_size < size)
buf_size = size;
if ((buf_start = (char *)malloc (buf_size)) != (char *)0)
buf_end = buf_start + buf_size;
else
{
fprintf (stderr, "Virtual memory exhausted in `operator new'\n");
exit (1);
}
}
temp = buf_start;
buf_start += size;
return temp;
}
/* We need this deletion operator in order to make the linker happy.
Because `operator new' and `operator delete' always come together. */
void
operator delete (void *ptr)
#ifdef HAVE_THROW_DECL
throw()
#endif
{
T (Trace t ("operator delete");)
// We cannot call free here, as it doesn't match the mallocs.
// free ((char *) ptr);
(void) ptr;
}

668
src/options.cc Normal file
View File

@@ -0,0 +1,668 @@
/* Handles parsing the Options provided to the user.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <stdio.h>
#include <stdlib.h> /* declares atoi(), abs(), exit() */
#include <string.h> /* declares strcmp() */
#include "getopt.h"
#include "options.h"
#include "iterator.h"
#include "trace.h"
#include "vectors.h"
#include "version.h"
/* Global option coordinator for the entire program. */
Options option;
/* Records the program name. */
const char *program_name;
/* Size to jump on a collision. */
static const int DEFAULT_JUMP_VALUE = 5;
/* Default name for generated lookup function. */
static const char *const DEFAULT_NAME = "in_word_set";
/* Default name for the key component. */
static const char *const DEFAULT_KEY = "name";
/* Default name for the generated class. */
static const char *const DEFAULT_CLASS_NAME = "Perfect_Hash";
/* Default name for generated hash function. */
static const char *const DEFAULT_HASH_NAME = "hash";
/* Default name for generated hash table array. */
static const char *const DEFAULT_WORDLIST_NAME = "wordlist";
/* Default delimiters that separate keywords from their attributes. */
static const char *const DEFAULT_DELIMITERS = ",\n";
int Options::option_word;
int Options::total_switches;
int Options::total_keysig_size;
int Options::size;
int Options::key_pos;
int Options::jump;
int Options::initial_asso_value;
int Options::argument_count;
int Options::iterations;
char **Options::argument_vector;
const char *Options::function_name;
const char *Options::key_name;
const char *Options::class_name;
const char *Options::hash_name;
const char *Options::wordlist_name;
const char *Options::delimiters;
char Options::key_positions[MAX_KEY_POS];
/* Prints program usage to given stream. */
void
Options::short_usage (FILE * strm)
{
T (Trace t ("Options::short_usage");)
fprintf (strm, "Usage: %s [-cCdDef[num]GhH<hashname>i<init>Ijk<keys>K<keyname>lL<language>nN<function name>ors<size>S<switches>tTvW<wordlistname>Z<class name>7] [input-file]\n"
"Try `%s --help' for more information.\n",
program_name, program_name);
}
void
Options::long_usage (FILE * strm)
{
T (Trace t ("Options::long_usage");)
fprintf (strm,
"GNU `gperf' generates perfect hash functions.\n"
"\n"
"Usage: %s [OPTION]... [INPUT-FILE]\n"
"\n"
"If a long option shows an argument as mandatory, then it is mandatory\n"
"for the equivalent short option also.\n"
"\n"
"Input file interpretation:\n"
" -e, --delimiters=DELIMITER-LIST\n"
" Allow user to provide a string containing delimiters\n"
" used to separate keywords from their attributes.\n"
" Default is \",\\n\".\n"
" -t, --struct-type Allows the user to include a structured type\n"
" declaration for generated code. Any text before %%%%\n"
" is considered part of the type declaration. Key\n"
" words and additional fields may follow this, one\n"
" group of fields per line.\n"
"\n"
"Language for the output code:\n"
" -L, --language=LANGUAGE-NAME\n"
" Generates code in the specified language. Languages\n"
" handled are currently C++, ANSI-C, C, and KR-C. The\n"
" default is C.\n"
"\n"
"Details in the output code:\n"
" -K, --slot-name=NAME Select name of the keyword component in the keyword\n"
" structure.\n"
" -H, --hash-fn-name=NAME\n"
" Specify name of generated hash function. Default is\n"
" `hash'.\n"
" -N, --lookup-fn-name=NAME\n"
" Specify name of generated lookup function. Default\n"
" name is `in_word_set'.\n"
" -Z, --class-name=NAME Specify name of generated C++ class. Default name is\n"
" `Perfect_Hash'.\n"
" -7, --seven-bit Assume 7-bit characters.\n"
" -c, --compare-strncmp Generate comparison code using strncmp rather than\n"
" strcmp.\n"
" -C, --readonly-tables Make the contents of generated lookup tables\n"
" constant, i.e., readonly.\n"
" -E, --enum Define constant values using an enum local to the\n"
" lookup function rather than with defines.\n"
" -I, --includes Include the necessary system include file <string.h>\n"
" at the beginning of the code.\n"
" -G, --global Generate the static table of keywords as a static\n"
" global variable, rather than hiding it inside of the\n"
" lookup function (which is the default behavior).\n"
" -W, --word-array-name=NAME\n"
" Specify name of word list array. Default name is\n"
" `wordlist'.\n"
" -S, --switch=COUNT Causes the generated C code to use a switch\n"
" statement scheme, rather than an array lookup table.\n"
" This can lead to a reduction in both time and space\n"
" requirements for some keyfiles. The COUNT argument\n"
" determines how many switch statements are generated.\n"
" A value of 1 generates 1 switch containing all the\n"
" elements, a value of 2 generates 2 tables with 1/2\n"
" the elements in each table, etc. If COUNT is very\n"
" large, say 1000000, the generated C code does a\n"
" binary search.\n"
" -T, --omit-struct-type\n"
" Prevents the transfer of the type declaration to the\n"
" output file. Use this option if the type is already\n"
" defined elsewhere.\n"
"\n"
"Algorithm employed by gperf:\n"
" -k, --key-positions=KEYS\n"
" Select the key positions used in the hash function.\n"
" The allowable choices range between 1-%d, inclusive.\n"
" The positions are separated by commas, ranges may be\n"
" used, and key positions may occur in any order.\n"
" Also, the meta-character '*' causes the generated\n"
" hash function to consider ALL key positions, and $\n"
" indicates the ``final character'' of a key, e.g.,\n"
" $,1,2,4,6-10.\n"
" -l, --compare-strlen Compare key lengths before trying a string\n"
" comparison. This helps cut down on the number of\n"
" string comparisons made during the lookup.\n"
" -D, --duplicates Handle keywords that hash to duplicate values. This\n"
" is useful for certain highly redundant keyword sets.\n"
" -f, --fast=ITERATIONS Generate the gen-perf.hash function ``fast''. This\n"
" decreases gperf's running time at the cost of\n"
" minimizing generated table size. The numeric\n"
" argument represents the number of times to iterate\n"
" when resolving a collision. `0' means ``iterate by\n"
" the number of keywords''.\n"
" -i, --initial-asso=N Provide an initial value for the associate values\n"
" array. Default is 0. Setting this value larger helps\n"
" inflate the size of the final table.\n"
" -j, --jump=JUMP-VALUE Affects the ``jump value'', i.e., how far to advance\n"
" the associated character value upon collisions. Must\n"
" be an odd number, default is %d.\n"
" -n, --no-strlen Do not include the length of the keyword when\n"
" computing the hash function.\n"
" -o, --occurrence-sort Reorders input keys by frequency of occurrence of\n"
" the key sets. This should decrease the search time\n"
" dramatically.\n"
" -r, --random Utilizes randomness to initialize the associated\n"
" values table.\n"
" -s, --size-multiple=N Affects the size of the generated hash table. The\n"
" numeric argument N indicates ``how many times larger\n"
" or smaller'' the associated value range should be,\n"
" in relationship to the number of keys, e.g. a value\n"
" of 3 means ``allow the maximum associated value to\n"
" be about 3 times larger than the number of input\n"
" keys.'' Conversely, a value of -3 means ``make the\n"
" maximum associated value about 3 times smaller than\n"
" the number of input keys. A larger table should\n"
" decrease the time required for an unsuccessful\n"
" search, at the expense of extra table space. Default\n"
" value is 1.\n"
"\n"
"Informative output:\n"
" -h, --help Print this message.\n"
" -v, --version Print the gperf version number.\n"
" -d, --debug Enables the debugging option (produces verbose\n"
" output to the standard error).\n"
"\n"
"Report bugs to <bug-gnu-utils@gnu.org>.\n"
, program_name, MAX_KEY_POS - 1, DEFAULT_JUMP_VALUE);
}
/* Output command-line Options. */
void
Options::print_options (void)
{
T (Trace t ("Options::print_options");)
int i;
printf ("/* Command-line: ");
for (i = 0; i < argument_count; i++)
printf ("%s ", argument_vector[i]);
printf (" */");
}
/* Sorts the key positions *IN REVERSE ORDER!!*
This makes further routines more efficient. Especially when generating code.
Uses a simple Insertion Sort since the set is probably ordered.
Returns 1 if there are no duplicates, 0 otherwise. */
inline int
Options::key_sort (char *base, int len)
{
T (Trace t ("Options::key_sort");)
int i, j;
for (i = 0, j = len - 1; i < j; i++)
{
int curr, tmp;
for (curr = i + 1,tmp = base[curr]; curr > 0 && tmp >= base[curr - 1]; curr--)
if ((base[curr] = base[curr - 1]) == tmp) /* oh no, a duplicate!!! */
return 0;
base[curr] = tmp;
}
return 1;
}
/* Sets the default Options. */
Options::Options (void)
{
T (Trace t ("Options::Options");)
key_positions[0] = WORD_START;
key_positions[1] = WORD_END;
key_positions[2] = EOS;
total_keysig_size = 2;
delimiters = DEFAULT_DELIMITERS;
jump = DEFAULT_JUMP_VALUE;
option_word = DEFAULTCHARS | C;
function_name = DEFAULT_NAME;
key_name = DEFAULT_KEY;
hash_name = DEFAULT_HASH_NAME;
wordlist_name = DEFAULT_WORDLIST_NAME;
class_name = DEFAULT_CLASS_NAME;
total_switches = size = 1;
initial_asso_value = iterations = 0;
}
/* Dumps option status when debug is set. */
Options::~Options (void)
{
T (Trace t ("Options::~Options");)
if (option_word & DEBUG)
{
char *ptr;
fprintf (stderr, "\ndumping Options:"
"\nDEBUG is.......: %s"
"\nORDER is.......: %s"
"\nTYPE is........: %s"
"\nRANDOM is......: %s"
"\nDEFAULTCHARS is: %s"
"\nSWITCH is......: %s"
"\nNOLENGTH is....: %s"
"\nLENTABLE is....: %s"
"\nDUP is.........: %s"
"\nFAST is........: %s"
"\nCOMP is........: %s"
"\nNOTYPE is......: %s"
"\nGLOBAL is......: %s"
"\nCONST is.......: %s"
"\nKRC is.........: %s"
"\nC is...........: %s"
"\nANSIC is.......: %s"
"\nCPLUSPLUS is...: %s"
"\nENUM is........: %s"
"\nINCLUDE is.....: %s"
"\nSEVENBIT is....: %s"
"\niterations = %d"
"\nlookup function name = %s"
"\nhash function name = %s"
"\nword list name = %s"
"\nkey name = %s"
"\njump value = %d"
"\nmax associated value = %d"
"\ninitial associated value = %d"
"\ndelimiters = %s"
"\nnumber of switch statements = %d\n",
option_word & DEBUG ? "enabled" : "disabled",
option_word & ORDER ? "enabled" : "disabled",
option_word & TYPE ? "enabled" : "disabled",
option_word & RANDOM ? "enabled" : "disabled",
option_word & DEFAULTCHARS ? "enabled" : "disabled",
option_word & SWITCH ? "enabled" : "disabled",
option_word & NOLENGTH ? "enabled" : "disabled",
option_word & LENTABLE ? "enabled" : "disabled",
option_word & DUP ? "enabled" : "disabled",
option_word & FAST ? "enabled" : "disabled",
option_word & COMP ? "enabled" : "disabled",
option_word & NOTYPE ? "enabled" : "disabled",
option_word & GLOBAL ? "enabled" : "disabled",
option_word & CONST ? "enabled" : "disabled",
option_word & KRC ? "enabled" : "disabled",
option_word & C ? "enabled" : "disabled",
option_word & ANSIC ? "enabled" : "disabled",
option_word & CPLUSPLUS ? "enabled" : "disabled",
option_word & ENUM ? "enabled" : "disabled",
option_word & INCLUDE ? "enabled" : "disabled",
option_word & SEVENBIT ? "enabled" : "disabled",
iterations,
function_name, hash_name, wordlist_name, key_name,
jump, size - 1, initial_asso_value, delimiters, total_switches);
if (option_word & ALLCHARS)
fprintf (stderr, "all characters are used in the hash function\n");
fprintf (stderr, "maximum keysig size = %d\nkey positions are: \n",
total_keysig_size);
for (ptr = key_positions; *ptr != EOS; ptr++)
if (*ptr == WORD_END)
fprintf (stderr, "$\n");
else
fprintf (stderr, "%d\n", *ptr);
fprintf (stderr, "finished dumping Options\n");
}
}
/* Parses the command line Options and sets appropriate flags in option_word. */
static const struct option long_options[] =
{
{ "delimiters", required_argument, 0, 'e' },
{ "struct-type", no_argument, 0, 't' },
{ "language", required_argument, 0, 'L' },
{ "slot-name", required_argument, 0, 'K' },
{ "hash-fn-name", required_argument, 0, 'H' },
{ "lookup-fn-name", required_argument, 0, 'N' },
{ "class-name", required_argument, 0, 'Z' },
{ "seven-bit", no_argument, 0, '7' },
{ "compare-strncmp", no_argument, 0, 'c' },
{ "readonly-tables", no_argument, 0, 'C' },
{ "enum", no_argument, 0, 'E' },
{ "includes", no_argument, 0, 'I' },
{ "global", no_argument, 0, 'G' },
{ "word-array-name", required_argument, 0, 'W' },
{ "switch", required_argument, 0, 'S' },
{ "omit-struct-type", no_argument, 0, 'T' },
{ "key-positions", required_argument, 0, 'k' },
{ "compare-strlen", no_argument, 0, 'l' },
{ "duplicates", no_argument, 0, 'D' },
{ "fast", required_argument, 0, 'f' },
{ "initial-asso", required_argument, 0, 'i' },
{ "jump", required_argument, 0, 'j' },
{ "no-strlen", no_argument, 0, 'n' },
{ "occurrence-sort", no_argument, 0, 'o' },
{ "random", no_argument, 0, 'r' },
{ "size-multiple", required_argument, 0, 's' },
{ "help", no_argument, 0, 'h' },
{ "version", no_argument, 0, 'v' },
{ "debug", no_argument, 0, 'd' },
{ 0, no_argument, 0, 0 }
};
void
Options::operator() (int argc, char *argv[])
{
T (Trace t ("Options::operator()");)
int option_char;
program_name = argv[0];
argument_count = argc;
argument_vector = argv;
while ((option_char =
getopt_long (argument_count, argument_vector,
"adcCDe:Ef:gGhH:i:Ij:k:K:lL:nN:oprs:S:tTvW:Z:7",
long_options, (int *)0))
!= -1)
{
switch (option_char)
{
case 'a': /* Generated code uses the ANSI prototype format. */
break; /* This is now the default. */
case 'c': /* Generate strncmp rather than strcmp. */
{
option_word |= COMP;
break;
}
case 'C': /* Make the generated tables readonly (const). */
{
option_word |= CONST;
break;
}
case 'd': /* Enable debugging option. */
{
option_word |= DEBUG;
fprintf (stderr, "Starting program %s, version %s, with debugging on.\n",
program_name, version_string);
break;
}
case 'D': /* Enable duplicate option. */
{
option_word |= DUP;
break;
}
case 'e': /* Allows user to provide keyword/attribute separator */
{
option.delimiters = /*getopt*/optarg;
break;
}
case 'E':
{
option_word |= ENUM;
break;
}
case 'f': /* Generate the hash table ``fast.'' */
{
option_word |= FAST;
if ((iterations = atoi (/*getopt*/optarg)) < 0)
{
fprintf (stderr, "iterations value must not be negative, assuming 0\n");
iterations = 0;
}
break;
}
case 'g': /* Use the ``inline'' keyword for generated sub-routines, ifdef __GNUC__. */
break; /* This is now the default. */
case 'G': /* Make the keyword table a global variable. */
{
option_word |= GLOBAL;
break;
}
case 'h': /* Displays a list of helpful Options to the user. */
{
long_usage (stdout);
exit (0);
}
case 'H': /* Sets the name for the hash function */
{
hash_name = /*getopt*/optarg;
break;
}
case 'i': /* Sets the initial value for the associated values array. */
{
if ((initial_asso_value = atoi (/*getopt*/optarg)) < 0)
fprintf (stderr, "Initial value %d should be non-zero, ignoring and continuing.\n", initial_asso_value);
if (option[RANDOM])
fprintf (stderr, "warning, -r option superceeds -i, ignoring -i option and continuing\n");
break;
}
case 'I': /* Enable #include statements. */
{
option_word |= INCLUDE;
break;
}
case 'j': /* Sets the jump value, must be odd for later algorithms. */
{
if ((jump = atoi (/*getopt*/optarg)) < 0)
{
fprintf (stderr, "Jump value %d must be a positive number.\n", jump);
short_usage (stderr);
exit (1);
}
else if (jump && ((jump % 2) == 0))
fprintf (stderr, "Jump value %d should be odd, adding 1 and continuing...\n", jump++);
break;
}
case 'k': /* Sets key positions used for hash function. */
{
const int BAD_VALUE = -1;
int value;
Iterator expand (/*getopt*/optarg, 1, MAX_KEY_POS - 1, WORD_END, BAD_VALUE, EOS);
if (/*getopt*/optarg [0] == '*') /* Use all the characters for hashing!!!! */
option_word = (option_word & ~DEFAULTCHARS) | ALLCHARS;
else
{
char *key_pos;
for (key_pos = key_positions; (value = expand ()) != EOS; key_pos++)
if (value == BAD_VALUE)
{
fprintf (stderr, "Illegal key value or range, use 1,2,3-%d,'$' or '*'.\n",
MAX_KEY_POS - 1);
short_usage (stderr);
exit (1);
}
else
*key_pos = value;;
*key_pos = EOS;
if (! (total_keysig_size = (key_pos - key_positions)))
{
fprintf (stderr, "No keys selected.\n");
short_usage (stderr);
exit (1);
}
else if (! key_sort (key_positions, total_keysig_size))
{
fprintf (stderr, "Duplicate keys selected\n");
short_usage (stderr);
exit (1);
}
if (total_keysig_size != 2
|| (key_positions[0] != 1 || key_positions[1] != WORD_END))
option_word &= ~DEFAULTCHARS;
}
break;
}
case 'K': /* Make this the keyname for the keyword component field. */
{
key_name = /*getopt*/optarg;
break;
}
case 'l': /* Create length table to avoid extra string compares. */
{
option_word |= LENTABLE;
break;
}
case 'L': /* Deal with different generated languages. */
{
option_word &= ~(KRC | C | ANSIC | CPLUSPLUS);
if (!strcmp (/*getopt*/optarg, "KR-C"))
option_word |= KRC;
else if (!strcmp (/*getopt*/optarg, "C"))
option_word |= C;
else if (!strcmp (/*getopt*/optarg, "ANSI-C"))
option_word |= ANSIC;
else if (!strcmp (/*getopt*/optarg, "C++"))
option_word |= CPLUSPLUS;
else
{
fprintf (stderr, "unsupported language option %s, defaulting to C\n", /*getopt*/optarg);
option_word |= C;
}
break;
}
case 'n': /* Don't include the length when computing hash function. */
{
option_word |= NOLENGTH;
break;
}
case 'N': /* Make generated lookup function name be optarg */
{
function_name = /*getopt*/optarg;
break;
}
case 'o': /* Order input by frequency of key set occurrence. */
{
option_word |= ORDER;
break;
}
case 'p': /* Generated lookup function a pointer instead of int. */
break; /* This is now the default. */
case 'r': /* Utilize randomness to initialize the associated values table. */
{
option_word |= RANDOM;
if (option.initial_asso_value != 0)
fprintf (stderr, "warning, -r option superceeds -i, disabling -i option and continuing\n");
break;
}
case 's': /* Range of associated values, determines size of final table. */
{
if (abs (size = atoi (/*getopt*/optarg)) > 50)
fprintf (stderr, "%d is excessive, did you really mean this?! (try `%s --help' for help)\n", size, program_name);
break;
}
case 'S': /* Generate switch statement output, rather than lookup table. */
{
option_word |= SWITCH;
if ((option.total_switches = atoi (/*getopt*/optarg)) <= 0)
{
fprintf (stderr, "number of switches %s must be a positive number\n", /*getopt*/optarg);
short_usage (stderr);
exit (1);
}
break;
}
case 't': /* Enable the TYPE mode, allowing arbitrary user structures. */
{
option_word |= TYPE;
break;
}
case 'T': /* Don't print structure definition. */
{
option_word |= NOTYPE;
break;
}
case 'v': /* Print out the version and quit. */
fprintf (stdout, "GNU gperf %s\n", version_string);
exit (0);
case 'W': /* Sets the name for the hash table array */
{
wordlist_name = /*getopt*/optarg;
break;
}
case 'Z': /* Set the class name. */
{
class_name = /*getopt*/optarg;
break;
}
case '7': /* Assume 7-bit characters. */
{
option_word |= SEVENBIT;
Vectors::ALPHA_SIZE = 128;
break;
}
default:
short_usage (stderr);
exit (1);
}
}
if (argv[/*getopt*/optind] && ! freopen (argv[/*getopt*/optind], "r", stdin))
{
fprintf (stderr, "Cannot open keyword file `%s'\n", argv[/*getopt*/optind]);
short_usage (stderr);
exit (1);
}
if (++/*getopt*/optind < argc)
{
fprintf (stderr, "Extra trailing arguments to %s.\n", program_name);
short_usage (stderr);
exit (1);
}
}
#ifndef __OPTIMIZE__
#define INLINE /* not inline */
#include "options.icc"
#undef INLINE
#endif /* not defined __OPTIMIZE__ */

157
src/options.h Normal file
View File

@@ -0,0 +1,157 @@
/* This may look like C code, but it is really -*- C++ -*- */
/* Handles parsing the Options provided to the user.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
/* This module provides a uniform interface to the various options available
to a user of the gperf hash function generator. In addition to the
run-time options, found in the Option_Type below, there is also the
hash table Size and the Keys to be used in the hashing.
The overall design of this module was an experiment in using C++
classes as a mechanism to enhance centralization of option and
and error handling, which tend to get out of hand in a C program. */
#ifndef options_h
#define options_h 1
#include <stdio.h>
/* Enumerate the potential debugging Options. */
enum Option_Type
{
DEBUG = 01, /* Enable debugging (prints diagnostics to stderr). */
ORDER = 02, /* Apply ordering heuristic to speed-up search time. */
ALLCHARS = 04, /* Use all characters in hash function. */
TYPE = 010, /* Handle user-defined type structured keyword input. */
RANDOM = 020, /* Randomly initialize the associated values table. */
DEFAULTCHARS = 040, /* Make default char positions be 1,$ (end of keyword). */
SWITCH = 0100, /* Generate switch output to save space. */
NOLENGTH = 0200, /* Don't include keyword length in hash computations. */
LENTABLE = 0400, /* Generate a length table for string comparison. */
DUP = 01000, /* Handle duplicate hash values for keywords. */
FAST = 02000, /* Generate the hash function ``fast.'' */
NOTYPE = 04000, /* Don't include user-defined type definition in output -- it's already defined elsewhere. */
COMP = 010000, /* Generate strncmp rather than strcmp. */
GLOBAL = 020000, /* Make the keyword table a global variable. */
CONST = 040000, /* Make the generated tables readonly (const). */
KRC = 0100000, /* Generate K&R C code: no prototypes, no const. */
C = 0200000, /* Generate C code: no prototypes, but const (user can #define it away). */
ANSIC = 0400000, /* Generate ISO/ANSI C code: prototypes and const, but no class. */
CPLUSPLUS = 01000000, /* Generate C++ code: prototypes, const, class, inline, enum. */
ENUM = 02000000, /* Use enum for constants. */
INCLUDE = 04000000, /* Generate #include statements. */
SEVENBIT = 010000000 /* Assume 7-bit, not 8-bit, characters. */
};
/* Define some useful constants (these don't really belong here, but I'm
not sure where else to put them!). These should be consts, but g++
doesn't seem to do the right thing with them at the moment... ;-( */
enum
{
MAX_KEY_POS = 128 - 1, /* Max size of each word's key set. */
WORD_START = 1, /* Signals the start of a word. */
WORD_END = 0, /* Signals the end of a word. */
EOS = MAX_KEY_POS /* Signals end of the key list. */
};
/* Class manager for gperf program Options. */
class Options
{
public:
Options (void);
~Options (void);
int operator[] (Option_Type option);
void operator() (int argc, char *argv[]);
void operator= (enum Option_Type);
void operator!= (enum Option_Type);
static void print_options (void);
static void set_asso_max (int r);
static int get_asso_max (void);
static void reset (void);
static int get (void);
static int get_iterations (void);
static int get_max_keysig_size (void);
static void set_keysig_size (int);
static int get_jump (void);
static int initial_value (void);
static int get_total_switches (void);
static const char *get_function_name (void);
static const char *get_key_name (void);
static const char *get_class_name (void);
static const char *get_hash_name (void);
static const char *get_wordlist_name (void);
static const char *get_delimiter (void);
private:
static int option_word; /* Holds the user-specified Options. */
static int total_switches; /* Number of switch statements to generate. */
static int total_keysig_size; /* Total number of distinct key_positions. */
static int size; /* Range of the hash table. */
static int key_pos; /* Tracks current key position for Iterator. */
static int jump; /* Jump length when trying alternative values. */
static int initial_asso_value; /* Initial value for asso_values table. */
static int argument_count; /* Records count of command-line arguments. */
static int iterations; /* Amount to iterate when a collision occurs. */
static char **argument_vector; /* Stores a pointer to command-line vector. */
static const char *function_name; /* Names used for generated lookup function. */
static const char *key_name; /* Name used for keyword key. */
static const char *class_name; /* Name used for generated C++ class. */
static const char *hash_name; /* Name used for generated hash function. */
static const char *wordlist_name; /* Name used for hash table array. */
static const char *delimiters; /* Separates keywords from other attributes. */
static char key_positions[MAX_KEY_POS]; /* Contains user-specified key choices. */
static int key_sort (char *base, int len); /* Sorts key positions in REVERSE order. */
static void short_usage (FILE * strm); /* Prints proper program usage. */
static void long_usage (FILE * strm); /* Prints proper program usage. */
};
/* Global option coordinator for the entire program. */
extern Options option;
/* Set to 1 if your want to stack-allocate some large arrays.
This requires compiler support for variable-size arrays on the stack
(not ANSI). */
#ifndef LARGE_STACK_ARRAYS
#if defined(__GNUG__) && !defined(__STRICT_ANSI__)
#define LARGE_STACK_ARRAYS 1
#else
#define LARGE_STACK_ARRAYS 0
#endif
#endif
/* Set to 1 if the stack is large enough for holding a text line. */
#ifndef LARGE_STACK
#define LARGE_STACK 1
#endif
#ifdef __OPTIMIZE__
#include "trace.h"
#define INLINE inline
#include "options.icc"
#undef INLINE
#endif
#endif

175
src/options.icc Normal file
View File

@@ -0,0 +1,175 @@
/* Inline Functions for options.{h,cc}.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
// This needs:
//#include "trace.h"
/* TRUE if option enable, else FALSE. */
INLINE int
Options::operator[] (Option_Type option)
{
T (Trace t ("Options::operator[]");)
return option_word & option;
}
/* Enables option OPT. */
INLINE void
Options::operator = (enum Option_Type opt)
{
T (Trace t ("Options::operator=");)
option_word |= opt;
}
/* Disables option OPT. */
INLINE void
Options::operator != (enum Option_Type opt)
{
T (Trace t ("Options::operator!=");)
option_word &= ~opt;
}
/* Initializes the key Iterator. */
INLINE void
Options::reset (void)
{
T (Trace t ("Options::reset");)
key_pos = 0;
}
/* Returns current key_position and advance index. */
INLINE int
Options::get (void)
{
T (Trace t ("Options::get");)
return key_positions[key_pos++];
}
/* Sets the size of the table size. */
INLINE void
Options::set_asso_max (int r)
{
T (Trace t ("Options::set_asso_max");)
size = r;
}
/* Returns the size of the table size. */
INLINE int
Options::get_asso_max (void)
{
T (Trace t ("Options::get_asso_max");)
return size;
}
/* Returns total distinct key positions. */
INLINE int
Options::get_max_keysig_size (void)
{
T (Trace t ("Options::get_max_keysig_size");)
return total_keysig_size;
}
/* Sets total distinct key positions. */
INLINE void
Options::set_keysig_size (int size)
{
T (Trace t ("Options::set_keysig_size");)
total_keysig_size = size;
}
/* Returns the jump value. */
INLINE int
Options::get_jump (void)
{
T (Trace t ("Options::get_jump");)
return jump;
}
/* Returns the generated function name. */
INLINE const char *
Options::get_function_name (void)
{
T (Trace t ("Options::get_function_name");)
return function_name;
}
/* Returns the keyword key name. */
INLINE const char *
Options::get_key_name (void)
{
T (Trace t ("Options::get_key_name");)
return key_name;
}
/* Returns the hash function name. */
INLINE const char *
Options::get_hash_name (void)
{
T (Trace t ("Options::get_hash_name");)
return hash_name;
}
/* Returns the hash table array name. */
INLINE const char *
Options::get_wordlist_name (void)
{
T (Trace t ("Options::get_wordlist_name");)
return wordlist_name;
}
/* Returns the generated class name. */
INLINE const char *
Options::get_class_name (void)
{
T (Trace t ("Options::get_class_name");)
return class_name;
}
/* Returns the initial associated character value. */
INLINE int
Options::initial_value (void)
{
T (Trace t ("Options::initial_value");)
return initial_asso_value;
}
/* Returns the iterations value. */
INLINE int
Options::get_iterations (void)
{
T (Trace t ("Options::get_iterations");)
return iterations;
}
/* Returns the string used to delimit keywords from other attributes. */
INLINE const char *
Options::get_delimiter ()
{
T (Trace t ("Options::get_delimiter");)
return delimiters;
}
/* Gets the total number of switch statements to generate. */
INLINE int
Options::get_total_switches ()
{
T (Trace t ("Options::get_total_switches");)
return total_switches;
}

97
src/read-line.cc Normal file
View File

@@ -0,0 +1,97 @@
/* Correctly reads an arbitrarily size string.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include "read-line.h"
#include <stdlib.h>
#include <string.h> /* declares memcpy() */
#include "options.h"
#include "trace.h"
/* Recursively fills up the buffer. */
#define CHUNK_SIZE 4096
/* CHUNKS is the number of chunks (each of size CHUNK_SIZE) which have
already been read and which are temporarily stored on the stack.
This function reads the remainder of the line, allocates a buffer
for the entire line, fills the part beyond &buffer[chunks*CHUNK_SIZE],
and returns &buffer[chunks*CHUNK_SIZE]. */
char *
Read_Line::readln_aux (int chunks)
{
T (Trace t ("Read_Line::readln_aux");)
#if LARGE_STACK
char buf[CHUNK_SIZE];
#else
// Note: we don't use new, because that invokes a custom operator new.
char *buf = (char*)malloc(CHUNK_SIZE);
if (buf == NULL)
abort ();
#endif
char *bufptr = buf;
char *ptr;
int c;
while (c = getc (fp), c != EOF && c != '\n') /* fill the current buffer */
{
*bufptr++ = c;
if (bufptr - buf == CHUNK_SIZE)
{
if ((ptr = readln_aux (chunks + 1)) != NULL)
/* prepend remainder to ptr buffer */
{
ptr -= CHUNK_SIZE;
memcpy (ptr, buf, CHUNK_SIZE);
}
goto done;
}
}
if (c == EOF && bufptr == buf && chunks == 0)
ptr = NULL;
else
{
size_t s1 = chunks * CHUNK_SIZE;
size_t s2 = bufptr - buf;
ptr = new char[s1+s2+1];
ptr += s1;
ptr[s2] = '\0';
memcpy (ptr, buf, s2);
}
done:
#if !LARGE_STACK
free (buf);
#endif
return ptr;
}
#ifndef __OPTIMIZE__
#define INLINE /* not inline */
#include "read-line.icc"
#undef INLINE
#endif /* not defined __OPTIMIZE__ */

53
src/read-line.h Normal file
View File

@@ -0,0 +1,53 @@
/* This may look like C code, but it is really -*- C++ -*- */
/* Reads arbitrarily long string from input file, returning it as a
dynamically allocated buffer.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
/* Returns a pointer to an arbitrary length string. Returns NULL on error or EOF
The storage for the string is dynamically allocated by new. */
#ifndef read_line_h
#define read_line_h 1
#include <stdio.h>
class Read_Line
{
private:
char *readln_aux (int chunks);
FILE *fp; /* FILE pointer to the input stream. */
public:
Read_Line (FILE *stream = stdin) : fp (stream) {}
char *get_line (void);
};
#ifdef __OPTIMIZE__
#include "trace.h"
#define INLINE inline
#include "read-line.icc"
#undef INLINE
#endif
#endif

47
src/read-line.icc Normal file
View File

@@ -0,0 +1,47 @@
/* Inline Functions for read-line.{h,cc}.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
// This needs:
//#include <stdio.h>
//#include "trace.h"
/* Returns the ``next'' line, ignoring comments beginning with '#'. */
INLINE char *
Read_Line::get_line (void)
{
T (Trace t ("Read_Line::get_line");)
int c;
while ((c = getc (fp)) == '#')
{
while (c = getc (fp), c != EOF && c != '\n')
;
if (c == EOF)
return (char *)0;
}
if (c == EOF)
return (char *)0;
ungetc (c, stdin);
return readln_aux (0);
}

35
src/trace.cc Normal file
View File

@@ -0,0 +1,35 @@
/* Tracing function calls.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include "trace.h"
#include <stdio.h>
int Trace::nesting = 0;
Trace::Trace (const char *n)
{
fprintf (stderr, "%*scalling %s\n", 3 * nesting++, "", name = n);
}
Trace::~Trace (void)
{
fprintf (stderr, "%*sleaving %s\n", 3 * --nesting, "", name);
}

40
src/trace.h Normal file
View File

@@ -0,0 +1,40 @@
/* Tracing function calls.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#ifndef trace_h
#define trace_h 1
#ifdef TRACE
#define T(X) X
#else
#define T(X)
#endif
class Trace
{
private:
static int nesting;
const char *name;
public:
Trace (const char *n);
~Trace (void);
};
#endif

25
src/vectors.cc Normal file
View File

@@ -0,0 +1,25 @@
/* Static class data members that are shared between several classes.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include "vectors.h"
int Vectors::ALPHA_SIZE = MAX_ALPHA_SIZE;
int Vectors::occurrences[MAX_ALPHA_SIZE];
int Vectors::asso_values[MAX_ALPHA_SIZE];

37
src/vectors.h Normal file
View File

@@ -0,0 +1,37 @@
/* This may look like C code, but it is really -*- C++ -*- */
/* Static class data members that are shared between several classes via
inheritance.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#ifndef vectors_h
#define vectors_h 1
static const int MAX_ALPHA_SIZE = 256;
struct Vectors
{
static int ALPHA_SIZE; /* Size of alphabet. */
static int occurrences[MAX_ALPHA_SIZE]; /* Counts occurrences of each key set character. */
static int asso_values[MAX_ALPHA_SIZE]; /* Value associated with each character. */
};
#endif

22
src/version.cc Normal file
View File

@@ -0,0 +1,22 @@
/* Current program version number.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
const char *version_string = "2.7";

23
src/version.h Normal file
View File

@@ -0,0 +1,23 @@
/* Current program version number.
Copyright (C) 1989-1998 Free Software Foundation, Inc.
written by Douglas C. Schmidt (schmidt@ics.uci.edu)
This file is part of GNU GPERF.
GNU GPERF 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 1, or (at your option)
any later version.
GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
/* Current release version. */
extern const char *version_string;