1
0
mirror of https://git.savannah.gnu.org/git/gperf.git synced 2025-12-02 21:19:24 +00:00

Move the input routines to class Input.

This commit is contained in:
Bruno Haible
2002-11-15 13:01:01 +00:00
parent 276e2fd949
commit ef7645289d
7 changed files with 504 additions and 401 deletions

View File

@@ -1,3 +1,21 @@
2002-10-15 Bruno Haible <bruno@clisp.org>
* src/input.h: New file.
* src/input.cc: New file, extracted from key-list.cc.
* src/key-list.h (Key_List): Don't inherit from Read_Line.
(Key_List::get_special_input,
Key_List::save_include_src, Key_List::get_array_type,
Key_List::strcspn, Key_List::set_output_types): Remove methods.
* src/key-list.cc (Key_List::get_special_input,
Key_List::save_include_src, Key_List::get_array_type,
Key_List::strcspn, Key_List::set_output_types, parse_line): Move to
src/input.cc.
(Key_List::read_keys): Use Input::read_keys.
(Key_List::Key_List): Update.
* src/gen-perf.cc: Update.
* src/Makefile.in (OBJECTS): Add input.o.
(input.o): New rule.
2002-10-14 Bruno Haible <bruno@clisp.org> 2002-10-14 Bruno Haible <bruno@clisp.org>
* src/options.cc: Don't include "vector.h". * src/options.cc: Don't include "vector.h".

View File

@@ -61,7 +61,7 @@ VPATH = $(srcdir)
OBJECTS = options.o main.o gen-perf.o key-list.o \ OBJECTS = options.o main.o gen-perf.o key-list.o \
hash-table.o bool-array.o read-line.o vectors.o version.o \ hash-table.o bool-array.o read-line.o vectors.o version.o \
keyword.o keyword-list.o output.o keyword.o keyword-list.o output.o input.o
LIBS = ../lib/libgp.a @GPERF_LIBM@ LIBS = ../lib/libgp.a @GPERF_LIBM@
CPPFLAGS = -I. -I$(srcdir)/../lib CPPFLAGS = -I. -I$(srcdir)/../lib
@@ -116,6 +116,8 @@ keyword-list.o : keyword-list.cc keyword-list.h
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/keyword-list.cc $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/keyword-list.cc
output.o : output.cc output.h output.o : output.cc output.h
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/output.cc $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/output.cc
input.o : input.cc input.h
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/input.cc
install : all force install : all force
$(MKINSTALLDIRS) $(DESTDIR)$(bindir) $(MKINSTALLDIRS) $(DESTDIR)$(bindir)

View File

@@ -41,7 +41,7 @@ Gen_Perf::Gen_Perf ()
int non_linked_length; int non_linked_length;
Vectors::ALPHA_SIZE = (option[SEVENBIT] ? 128 : 256); Vectors::ALPHA_SIZE = (option[SEVENBIT] ? 128 : 256);
Key_List::read_keys (); read_keys ();
if (option[ORDER]) if (option[ORDER])
reorder (); reorder ();
_num_done = 1; _num_done = 1;

347
src/input.cc Normal file
View File

@@ -0,0 +1,347 @@
/* Input routines.
Copyright (C) 1989-1998, 2002 Free Software Foundation, Inc.
Written by Douglas C. Schmidt <schmidt@ics.uci.edu>
and Bruno Haible <bruno@clisp.org>.
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 exit() */
#include <string.h> /* declares strncpy(), strchr() */
#include <limits.h> /* defines UCHAR_MAX etc. */
#include "options.h"
#include "input.h"
/* Gathers the input stream into a buffer until one of two things occur:
1. We read a '%' followed by a '%'
2. We read a '%' followed by a '}'
The first symbolizes the beginning of the keyword list proper,
The second symbolizes the end of the C source code to be generated
verbatim in the output file.
I assume that the keys are separated from the optional preceding struct
declaration by a consecutive % followed by either % or } starting in
the first column. The code below uses an expandible buffer to scan off
and return a pointer to all the code (if any) appearing before the delimiter. */
const char *
Input::get_special_input (char delimiter)
{
int size = 80;
char *buf = new char[size];
int c, i;
for (i = 0; (c = getchar ()) != EOF; i++)
{
if (c == '%')
{
if ((c = getchar ()) == delimiter)
{
while ((c = getchar ()) != '\n')
; /* discard newline */
if (i == 0)
return "";
else
{
buf[delimiter == '%' && buf[i - 2] == ';' ? i - 2 : i - 1] = '\0';
return buf;
}
}
else
buf[i++] = '%';
}
else if (i >= size) /* Yikes, time to grow the buffer! */
{
char *temp = new char[size *= 2];
int j;
for (j = 0; j < i; j++)
temp[j] = buf[j];
buf = temp;
}
buf[i] = c;
}
return 0; /* Problem here. */
}
/* Stores any C text that must be included verbatim into the
generated code output. */
const char *
Input::save_include_src ()
{
int c;
if ((c = getchar ()) != '%')
ungetc (c, stdin);
else if ((c = getchar ()) != '{')
{
fprintf (stderr, "internal error, %c != '{' on line %d in file %s", c, __LINE__, __FILE__);
exit (1);
}
else
return get_special_input ('}');
return "";
}
/* Determines from the input file whether the user wants to build a table
from a user-defined struct, or whether the user is content to simply
use the default array of keys. */
const char *
Input::get_array_type ()
{
return get_special_input ('%');
}
/* strcspn - find length of initial segment of S consisting entirely
of characters not from REJECT (borrowed from Henry Spencer's
ANSI string package, when GNU libc comes out I'll replace this...). */
#ifndef strcspn
inline int
Input::strcspn (const char *s, const char *reject)
{
const char *scan;
const char *rej_scan;
int count = 0;
for (scan = s; *scan; scan++)
{
for (rej_scan = reject; *rej_scan; rej_scan++)
if (*scan == *rej_scan)
return count;
count++;
}
return count;
}
#endif
/* Sets up the Return_Type, the Struct_Tag type and the Array_Type
based upon various user Options. */
void
Input::set_output_types ()
{
if (option[TYPE])
{
_array_type = get_array_type ();
if (!_array_type)
/* Something's wrong, but we'll catch it later on, in read_keys()... */
return;
/* Yow, we've got a user-defined type... */
int i = strcspn (_array_type, "{\n\0");
/* Remove trailing whitespace. */
while (i > 0 && strchr (" \t", _array_type[i-1]))
i--;
int struct_tag_length = i;
/* Set `struct_tag' to a naked "struct something". */
char *structtag = new char[struct_tag_length + 1];
strncpy (structtag, _array_type, struct_tag_length);
structtag[struct_tag_length] = '\0';
_struct_tag = structtag;
/* The return type of the lookup function is "struct something *".
No "const" here, because if !option[CONST], some user code might want
to modify the structure. */
char *rettype = new char[struct_tag_length + 3];
strncpy (rettype, _array_type, struct_tag_length);
rettype[struct_tag_length] = ' ';
rettype[struct_tag_length + 1] = '*';
rettype[struct_tag_length + 2] = '\0';
_return_type = rettype;
}
}
/* Extracts a key from an input line and creates a new KeywordExt_List for
it. */
static KeywordExt_List *
parse_line (const char *line, const char *delimiters)
{
if (*line == '"')
{
/* Parse a string in ANSI C syntax. */
char *key = new char[strlen(line)];
char *kp = key;
const char *lp = line + 1;
for (; *lp;)
{
char c = *lp;
if (c == '\0')
{
fprintf (stderr, "unterminated string: %s\n", line);
exit (1);
}
else if (c == '\\')
{
c = *++lp;
switch (c)
{
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
{
int code = 0;
int count = 0;
while (count < 3 && *lp >= '0' && *lp <= '7')
{
code = (code << 3) + (*lp - '0');
lp++;
count++;
}
if (code > UCHAR_MAX)
fprintf (stderr, "octal escape out of range: %s\n", line);
*kp = (char) code;
break;
}
case 'x':
{
int code = 0;
int count = 0;
lp++;
while ((*lp >= '0' && *lp <= '9')
|| (*lp >= 'A' && *lp <= 'F')
|| (*lp >= 'a' && *lp <= 'f'))
{
code = (code << 4)
+ (*lp >= 'A' && *lp <= 'F' ? *lp - 'A' + 10 :
*lp >= 'a' && *lp <= 'f' ? *lp - 'a' + 10 :
*lp - '0');
lp++;
count++;
}
if (count == 0)
fprintf (stderr, "hexadecimal escape without any hex digits: %s\n", line);
if (code > UCHAR_MAX)
fprintf (stderr, "hexadecimal escape out of range: %s\n", line);
*kp = (char) code;
break;
}
case '\\': case '\'': case '"':
*kp = c;
lp++;
break;
case 'n':
*kp = '\n';
lp++;
break;
case 't':
*kp = '\t';
lp++;
break;
case 'r':
*kp = '\r';
lp++;
break;
case 'f':
*kp = '\f';
lp++;
break;
case 'b':
*kp = '\b';
lp++;
break;
case 'a':
*kp = '\a';
lp++;
break;
case 'v':
*kp = '\v';
lp++;
break;
default:
fprintf (stderr, "invalid escape sequence in string: %s\n", line);
exit (1);
}
}
else if (c == '"')
break;
else
{
*kp = c;
lp++;
}
kp++;
}
lp++;
if (*lp != '\0')
{
if (strchr (delimiters, *lp) == NULL)
{
fprintf (stderr, "string not followed by delimiter: %s\n", line);
exit (1);
}
lp++;
}
return new KeywordExt_List (key, kp - key, option[TYPE] ? lp : "");
}
else
{
/* Not a string. Look for the delimiter. */
int len = strcspn (line, delimiters);
const char *rest;
if (line[len] == '\0')
rest = "";
else
/* Skip the first delimiter. */
rest = &line[len + 1];
return new KeywordExt_List (line, len, option[TYPE] ? rest : "");
}
}
void
Input::read_keys ()
{
char *ptr;
_include_src = save_include_src ();
set_output_types ();
/* Oops, problem with the input file. */
if (! (ptr = Read_Line::read_next_line ()))
{
fprintf (stderr, "No words in input file, did you forget to prepend %s or use -t accidentally?\n", "%%");
exit (1);
}
/* Read in all the keywords from the input file. */
const char *delimiter = option.get_delimiter ();
_head = parse_line (ptr, delimiter);
for (KeywordExt_List *temp = _head;
(ptr = Read_Line::read_next_line ()) && strcmp (ptr, "%%");
temp = temp->rest())
temp->rest() = parse_line (ptr, delimiter);
/* See if any additional C code is included at end of this file. */
if (ptr)
_additional_code = 1;
}

52
src/input.h Normal file
View File

@@ -0,0 +1,52 @@
/* This may look like C code, but it is really -*- C++ -*- */
/* Input routines.
Copyright (C) 1989-1998, 2002 Free Software Foundation, Inc.
Written by Douglas C. Schmidt <schmidt@ics.uci.edu>
and Bruno Haible <bruno@clisp.org>.
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 input_h
#define input_h 1
#include "read-line.h"
#include "keyword-list.h"
class Input : private Read_Line
{
public:
void read_keys ();
private:
#ifndef strcspn
static int strcspn (const char *s, const char *reject);
#endif
void set_output_types ();
const char *get_array_type ();
const char *save_include_src ();
const char *get_special_input (char delimiter);
public:
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 _additional_code; /* True if any additional C code is included. */
KeywordExt_List *_head; /* Points to the head of the linked list. */
};
#endif

View File

@@ -19,13 +19,12 @@ 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. */ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <stdio.h> #include <stdio.h>
#include <string.h> /* declares strncpy(), strchr() */ #include <stdlib.h> /* declares exit() */
#include <stdlib.h> /* declares malloc(), free(), abs(), exit(), abort() */ #include <limits.h> /* defines INT_MIN, INT_MAX */
#include <limits.h> /* defines UCHAR_MAX etc. */
#include "options.h" #include "options.h"
#include "read-line.h"
#include "hash-table.h"
#include "key-list.h" #include "key-list.h"
#include "input.h"
#include "hash-table.h"
/* Make the hash table 8 times larger than the number of keyword entries. */ /* Make the hash table 8 times larger than the number of keyword entries. */
static const int TABLE_MULTIPLE = 10; static const int TABLE_MULTIPLE = 10;
@@ -49,338 +48,31 @@ Key_List::~Key_List ()
} }
} }
/* Gathers the input stream into a buffer until one of two things occur:
1. We read a '%' followed by a '%'
2. We read a '%' followed by a '}'
The first symbolizes the beginning of the keyword list proper,
The second symbolizes the end of the C source code to be generated
verbatim in the output file.
I assume that the keys are separated from the optional preceding struct
declaration by a consecutive % followed by either % or } starting in
the first column. The code below uses an expandible buffer to scan off
and return a pointer to all the code (if any) appearing before the delimiter. */
const char *
Key_List::get_special_input (char delimiter)
{
int size = 80;
char *buf = new char[size];
int c, i;
for (i = 0; (c = getchar ()) != EOF; i++)
{
if (c == '%')
{
if ((c = getchar ()) == delimiter)
{
while ((c = getchar ()) != '\n')
; /* discard newline */
if (i == 0)
return "";
else
{
buf[delimiter == '%' && buf[i - 2] == ';' ? i - 2 : i - 1] = '\0';
return buf;
}
}
else
buf[i++] = '%';
}
else if (i >= size) /* Yikes, time to grow the buffer! */
{
char *temp = new char[size *= 2];
int j;
for (j = 0; j < i; j++)
temp[j] = buf[j];
buf = temp;
}
buf[i] = c;
}
return 0; /* Problem here. */
}
/* Stores any C text that must be included verbatim into the
generated code output. */
const char *
Key_List::save_include_src ()
{
int c;
if ((c = getchar ()) != '%')
ungetc (c, stdin);
else if ((c = getchar ()) != '{')
{
fprintf (stderr, "internal error, %c != '{' on line %d in file %s", c, __LINE__, __FILE__);
exit (1);
}
else
return get_special_input ('}');
return "";
}
/* Determines from the input file whether the user wants to build a table
from a user-defined struct, or whether the user is content to simply
use the default array of keys. */
const char *
Key_List::get_array_type ()
{
return get_special_input ('%');
}
/* strcspn - find length of initial segment of S consisting entirely
of characters not from REJECT (borrowed from Henry Spencer's
ANSI string package, when GNU libc comes out I'll replace this...). */
#ifndef strcspn
inline int
Key_List::strcspn (const char *s, const char *reject)
{
const char *scan;
const char *rej_scan;
int count = 0;
for (scan = s; *scan; scan++)
{
for (rej_scan = reject; *rej_scan; rej_scan++)
if (*scan == *rej_scan)
return count;
count++;
}
return count;
}
#endif
/* Sets up the Return_Type, the Struct_Tag type and the Array_Type
based upon various user Options. */
void
Key_List::set_output_types ()
{
if (option[TYPE])
{
_array_type = get_array_type ();
if (!_array_type)
/* Something's wrong, but we'll catch it later on, in read_keys()... */
return;
/* Yow, we've got a user-defined type... */
int i = strcspn (_array_type, "{\n\0");
/* Remove trailing whitespace. */
while (i > 0 && strchr (" \t", _array_type[i-1]))
i--;
int struct_tag_length = i;
/* Set `struct_tag' to a naked "struct something". */
char *structtag = new char[struct_tag_length + 1];
strncpy (structtag, _array_type, struct_tag_length);
structtag[struct_tag_length] = '\0';
_struct_tag = structtag;
/* The return type of the lookup function is "struct something *".
No "const" here, because if !option[CONST], some user code might want
to modify the structure. */
char *rettype = new char[struct_tag_length + 3];
strncpy (rettype, _array_type, struct_tag_length);
rettype[struct_tag_length] = ' ';
rettype[struct_tag_length + 1] = '*';
rettype[struct_tag_length + 2] = '\0';
_return_type = rettype;
}
}
/* Extracts a key from an input line and creates a new KeywordExt_List for
it. */
static KeywordExt_List *
parse_line (const char *line, const char *delimiters)
{
if (*line == '"')
{
/* Parse a string in ANSI C syntax. */
char *key = new char[strlen(line)];
char *kp = key;
const char *lp = line + 1;
for (; *lp;)
{
char c = *lp;
if (c == '\0')
{
fprintf (stderr, "unterminated string: %s\n", line);
exit (1);
}
else if (c == '\\')
{
c = *++lp;
switch (c)
{
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
{
int code = 0;
int count = 0;
while (count < 3 && *lp >= '0' && *lp <= '7')
{
code = (code << 3) + (*lp - '0');
lp++;
count++;
}
if (code > UCHAR_MAX)
fprintf (stderr, "octal escape out of range: %s\n", line);
*kp = (char) code;
break;
}
case 'x':
{
int code = 0;
int count = 0;
lp++;
while ((*lp >= '0' && *lp <= '9')
|| (*lp >= 'A' && *lp <= 'F')
|| (*lp >= 'a' && *lp <= 'f'))
{
code = (code << 4)
+ (*lp >= 'A' && *lp <= 'F' ? *lp - 'A' + 10 :
*lp >= 'a' && *lp <= 'f' ? *lp - 'a' + 10 :
*lp - '0');
lp++;
count++;
}
if (count == 0)
fprintf (stderr, "hexadecimal escape without any hex digits: %s\n", line);
if (code > UCHAR_MAX)
fprintf (stderr, "hexadecimal escape out of range: %s\n", line);
*kp = (char) code;
break;
}
case '\\': case '\'': case '"':
*kp = c;
lp++;
break;
case 'n':
*kp = '\n';
lp++;
break;
case 't':
*kp = '\t';
lp++;
break;
case 'r':
*kp = '\r';
lp++;
break;
case 'f':
*kp = '\f';
lp++;
break;
case 'b':
*kp = '\b';
lp++;
break;
case 'a':
*kp = '\a';
lp++;
break;
case 'v':
*kp = '\v';
lp++;
break;
default:
fprintf (stderr, "invalid escape sequence in string: %s\n", line);
exit (1);
}
}
else if (c == '"')
break;
else
{
*kp = c;
lp++;
}
kp++;
}
lp++;
if (*lp != '\0')
{
if (strchr (delimiters, *lp) == NULL)
{
fprintf (stderr, "string not followed by delimiter: %s\n", line);
exit (1);
}
lp++;
}
return new KeywordExt_List (key, kp - key, option[TYPE] ? lp : "");
}
else
{
/* Not a string. Look for the delimiter. */
int len = strcspn (line, delimiters);
const char *rest;
if (line[len] == '\0')
rest = "";
else
/* Skip the first delimiter. */
rest = &line[len + 1];
return new KeywordExt_List (line, len, option[TYPE] ? rest : "");
}
}
/* Reads in all keys from standard input and creates a linked list pointed /* Reads in all keys from standard input and creates a linked list pointed
to by Head. This list is then quickly checked for ``links,'' i.e., to by _head. This list is then quickly checked for "links", i.e.,
unhashable elements possessing identical key sets and lengths. */ unhashable elements possessing identical key sets and lengths. */
void void
Key_List::read_keys () Key_List::read_keys ()
{ {
char *ptr; Input inputter;
inputter.read_keys ();
_array_type = inputter._array_type;
_return_type = inputter._return_type;
_struct_tag = inputter._struct_tag;
_include_src = inputter._include_src;
_additional_code = inputter._additional_code;
_head = inputter._head;
_include_src = save_include_src ();
set_output_types ();
/* Oops, problem with the input file. */
if (! (ptr = Read_Line::read_next_line ()))
{
fprintf (stderr, "No words in input file, did you forget to prepend %s or use -t accidentally?\n", "%%");
exit (1);
}
/* Read in all the keywords from the input file. */
else
{
const char *delimiter = option.get_delimiter ();
KeywordExt_List *temp; KeywordExt_List *temp;
KeywordExt_List *trail = NULL; KeywordExt_List *trail = NULL;
_head = parse_line (ptr, delimiter); for (temp = _head; temp; temp = temp->rest())
_head->first()->init_selchars(this);
for (temp = _head;
(ptr = Read_Line::read_next_line ()) && strcmp (ptr, "%%");
temp = temp->rest())
{ {
temp->rest() = parse_line (ptr, delimiter); temp->first()->init_selchars(this);
temp->rest()->first()->init_selchars(this);
_total_keys++; _total_keys++;
} }
/* See if any additional C code is included at end of this file. */
if (ptr)
_additional_code = 1;
/* Hash table this number of times larger than keyword number. */ /* Hash table this number of times larger than keyword number. */
int table_size = (_list_len = _total_keys) * TABLE_MULTIPLE; int table_size = (_list_len = _total_keys) * TABLE_MULTIPLE;
/* Table must be a power of 2 for the hash function scheme to work. */ /* Table must be a power of 2 for the hash function scheme to work. */
@@ -450,7 +142,6 @@ Key_List::read_keys ()
exit (1); exit (1);
} }
} }
}
/* Recursively merges two sorted lists together to form one sorted list. The /* Recursively merges two sorted lists together to form one sorted list. The
ordering criteria is by frequency of occurrence of elements in the key set ordering criteria is by frequency of occurrence of elements in the key set
@@ -638,7 +329,7 @@ Key_List::dump ()
Key_List::Key_List () Key_List::Key_List ()
{ {
_total_keys = 1; _total_keys = 0;
_max_key_len = INT_MIN; _max_key_len = INT_MIN;
_min_key_len = INT_MAX; _min_key_len = INT_MAX;
_array_type = 0; _array_type = 0;

View File

@@ -33,7 +33,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include "vectors.h" #include "vectors.h"
#include "read-line.h" #include "read-line.h"
class Key_List : private Read_Line, public Vectors class Key_List : public Vectors
{ {
protected: protected:
const char *_array_type; /* Pointer to the type for word list. */ const char *_array_type; /* Pointer to the type for word list. */
@@ -55,16 +55,9 @@ protected:
private: private:
static int _determined[MAX_ALPHA_SIZE]; /* Used in function reorder, below. */ static int _determined[MAX_ALPHA_SIZE]; /* Used in function reorder, below. */
static int get_occurrence (KeywordExt *ptr); static int get_occurrence (KeywordExt *ptr);
#ifndef strcspn
static int strcspn (const char *s, const char *reject);
#endif
static int already_determined (KeywordExt *ptr); static int already_determined (KeywordExt *ptr);
static void set_determined (KeywordExt *ptr); static void set_determined (KeywordExt *ptr);
void set_output_types ();
void dump (); void dump ();
const char *get_array_type ();
const char *save_include_src ();
const char *get_special_input (char delimiter);
KeywordExt_List *merge (KeywordExt_List *list1, KeywordExt_List *list2); KeywordExt_List *merge (KeywordExt_List *list1, KeywordExt_List *list2);
KeywordExt_List *merge_sort (KeywordExt_List *head); KeywordExt_List *merge_sort (KeywordExt_List *head);