From: borutr Date: Sun, 31 Dec 2006 16:29:37 +0000 (+0000) Subject: * SDCPP synchronized with GCC CPP release version 4.1.1, X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=42f9b5740a20b531ffefdd4a6271f15c10b8f990;p=fw%2Fsdcc * SDCPP synchronized with GCC CPP release version 4.1.1, currently the latest release: * support/cpp2/libcpp, support/cpp2/libcpp/include, support/cpp2/libcpp/include/cpp-id-data.h support/cpp2/libiberty/fopen_unlocked.c support/cpp2/libiberty/md5.c support/cpp2/md5.h support/cpp2/opt-functions.awk support/cpp2/opt-gather.awk support/cpp2/optc-gen.awk support/cpp2/opth-gen.awk: added * support/cpp2/Makefile.in, support/cpp2/auto-host_vc_in.h, support/cpp2/c-incpath.c, support/cpp2/c-incpath.h, support/cpp2/c-ppoutput.c, support/cpp2/c-pretty-print.c, support/cpp2/c-pretty-print.h, support/cpp2/cppdefault.c, support/cpp2/cppdefault.h, support/cpp2/diagnostic.c, support/cpp2/diagnostic.h, support/cpp2/except.h, support/cpp2/hwint.h, support/cpp2/input.h, support/cpp2/intl.h, support/cpp2/move-if-change, support/cpp2/opts.c, support/cpp2/opts.h, support/cpp2/output.h, support/cpp2/prefix.c, support/cpp2/prefix.h, support/cpp2/pretty-print.c, support/cpp2/pretty-print.h, support/cpp2/sdcpp-opts.c, support/cpp2/sdcpp.c, support/cpp2/sdcpp.dsp, support/cpp2/sdcpp.h, support/cpp2/sdcpp.opt, support/cpp2/sdcppa.dsp, support/cpp2/symcat.h, support/cpp2/version.c: modified * support/cpp2/libcpp/charset.c, support/cpp2/libcpp/directives.c, support/cpp2/libcpp/errors.c, support/cpp2/libcpp/expr.c, support/cpp2/libcpp/files.c, support/cpp2/libcpp/identifiers.c, support/cpp2/libcpp/include/cpplib.h, support/cpp2/libcpp/include/line-map.h, support/cpp2/libcpp/include/mkdeps.h, support/cpp2/libcpp/include/symtab.h, support/cpp2/libcpp/init.c, support/cpp2/libcpp/internal.h, support/cpp2/libcpp/lex.c, support/cpp2/libcpp/line-map.c, support/cpp2/libcpp/macro.c, support/cpp2/libcpp/mkdeps.c, support/cpp2/libcpp/symtab.c, support/cpp2/libcpp/system.h, support/cpp2/libcpp/traditional.c, support/cpp2/libcpp/ucnid.h, support/cpp2/libiberty/hashtab.c, support/cpp2/libiberty/hashtab.h: moved * support/cpp2/cppcharset.c, support/cpp2/cpperror.c, support/cpp2/cppexp.c, support/cpp2/cppfiles.c, support/cpp2/cpphash.c, support/cpp2/cpphash.h, support/cpp2/cppinit.c, support/cpp2/cpplex.c, support/cpp2/cpplib.c, support/cpp2/cpplib.h, support/cpp2/cppmacro.c, support/cpp2/cpptrad.c, support/cpp2/cppucnid.h, support/cpp2/hashtab.c, support/cpp2/hashtab.h, support/cpp2/hashtable.c, support/cpp2/hashtable.h, support/cpp2/line-map.c, support/cpp2/line-map.h, support/cpp2/mkdeps.c, support/cpp2/mkdeps.h, support/cpp2/options_vc_in.c, support/cpp2/options_vc_in.h, support/cpp2/opts.sh, support/cpp2/system.h: deleted / moved git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@4543 4a8a32a2-be11-0410-ad9d-d568d2c75423 --- diff --git a/ChangeLog b/ChangeLog index acb6b0da..73bb2c40 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,61 @@ +2006-12-31 Borut Razem + + * SDCPP synchronized with GCC CPP release version 4.1.1, + currently the latest release: + * support/cpp2/libcpp, support/cpp2/libcpp/include, + support/cpp2/libcpp/include/cpp-id-data.h + support/cpp2/libiberty/fopen_unlocked.c + support/cpp2/libiberty/md5.c + support/cpp2/md5.h + support/cpp2/opt-functions.awk + support/cpp2/opt-gather.awk + support/cpp2/optc-gen.awk + support/cpp2/opth-gen.awk: + added + * support/cpp2/Makefile.in, support/cpp2/auto-host_vc_in.h, + support/cpp2/c-incpath.c, support/cpp2/c-incpath.h, + support/cpp2/c-ppoutput.c, support/cpp2/c-pretty-print.c, + support/cpp2/c-pretty-print.h, support/cpp2/cppdefault.c, + support/cpp2/cppdefault.h, support/cpp2/diagnostic.c, + support/cpp2/diagnostic.h, support/cpp2/except.h, + support/cpp2/hwint.h, support/cpp2/input.h, + support/cpp2/intl.h, support/cpp2/move-if-change, + support/cpp2/opts.c, support/cpp2/opts.h, + support/cpp2/output.h, support/cpp2/prefix.c, + support/cpp2/prefix.h, support/cpp2/pretty-print.c, + support/cpp2/pretty-print.h, support/cpp2/sdcpp-opts.c, + support/cpp2/sdcpp.c, support/cpp2/sdcpp.dsp, + support/cpp2/sdcpp.h, support/cpp2/sdcpp.opt, + support/cpp2/sdcppa.dsp, support/cpp2/symcat.h, + support/cpp2/version.c: + modified + * support/cpp2/libcpp/charset.c, support/cpp2/libcpp/directives.c, + support/cpp2/libcpp/errors.c, support/cpp2/libcpp/expr.c, + support/cpp2/libcpp/files.c, support/cpp2/libcpp/identifiers.c, + support/cpp2/libcpp/include/cpplib.h, support/cpp2/libcpp/include/line-map.h, + support/cpp2/libcpp/include/mkdeps.h, support/cpp2/libcpp/include/symtab.h, + support/cpp2/libcpp/init.c, support/cpp2/libcpp/internal.h, + support/cpp2/libcpp/lex.c, support/cpp2/libcpp/line-map.c, + support/cpp2/libcpp/macro.c, support/cpp2/libcpp/mkdeps.c, + support/cpp2/libcpp/symtab.c, support/cpp2/libcpp/system.h, + support/cpp2/libcpp/traditional.c, support/cpp2/libcpp/ucnid.h, + support/cpp2/libiberty/hashtab.c, support/cpp2/libiberty/hashtab.h: + moved + * support/cpp2/cppcharset.c, support/cpp2/cpperror.c, + support/cpp2/cppexp.c, support/cpp2/cppfiles.c, + support/cpp2/cpphash.c, support/cpp2/cpphash.h, + support/cpp2/cppinit.c, support/cpp2/cpplex.c, + support/cpp2/cpplib.c, support/cpp2/cpplib.h, + support/cpp2/cppmacro.c, support/cpp2/cpptrad.c, + support/cpp2/cppucnid.h, support/cpp2/hashtab.c, + support/cpp2/hashtab.h, support/cpp2/hashtable.c, + support/cpp2/hashtable.h, support/cpp2/line-map.c, + support/cpp2/line-map.h, support/cpp2/mkdeps.c, + support/cpp2/mkdeps.h, support/cpp2/options_vc_in.c, + support/cpp2/options_vc_in.h, support/cpp2/opts.sh, + support/cpp2/system.h: + deleted / moved + 2006-12-31 Borut Razem * configure.in, configure: fixed bug #1538756: configure dies if bison diff --git a/support/cpp2/Makefile.in b/support/cpp2/Makefile.in index 12d10400..46980540 100644 --- a/support/cpp2/Makefile.in +++ b/support/cpp2/Makefile.in @@ -70,6 +70,7 @@ STAMP = echo timestamp > # Where to find some libiberty headers. LIBIBERTY_DIR = $(srcdir)/libiberty +LIBCPP_DIR = $(srcdir)/libcpp OBSTACK_H = $(LIBIBERTY_DIR)/obstack.h SPLAY_TREE_H= $(LIBIBERTY_DIR)/splay-tree.h @@ -95,6 +96,9 @@ exeext = @host_exeext@ transform = @program_transform_name@ lang_opt_files=$(srcdir)/sdcpp.opt +# All option source files +ALL_OPT_FILES=$(lang_opt_files) $(extra_opt_files) + # Top build directory, relative to here. top_builddir = @top_builddir@ @@ -148,7 +152,7 @@ SYSTEM_H = system.h hwint.h #@build_overrides@ # -INCLUDES = -I$(srcdir) -I$(LIBIBERTY_DIR) -I. +INCLUDES = -I$(srcdir) -I$(LIBCPP_DIR) -I$(LIBCPP_DIR)/include -I$(LIBIBERTY_DIR) -I. # Always use -I$(srcdir)/config when compiling. .c.o: @@ -183,19 +187,28 @@ config.status: $(srcdir)/configure version.c LANGUAGES="$(CONFIG_LANGUAGES)" $(SHELL) config.status --recheck; \ fi -options.c: $(lang_opt_files) $(srcdir)/opts.sh options.h intl.h -options.h: $(lang_opt_files) $(srcdir)/opts.sh Makefile - AWK=$(AWK) $(SHELL) $(srcdir)/opts.sh \ - '$(SHELL) $(srcdir)/move-if-change' \ - options.c options.h $(lang_opt_files) +optionlist: s-options ; @true +s-options: $(ALL_OPT_FILES) Makefile $(srcdir)/opt-gather.awk + $(AWK) -f $(srcdir)/opt-gather.awk $(ALL_OPT_FILES) > tmp-optionlist + $(SHELL) $(srcdir)/move-if-change tmp-optionlist optionlist + $(STAMP) s-options + +options.c: optionlist $(srcdir)/opt-functions.awk $(srcdir)/optc-gen.awk + $(AWK) -f $(srcdir)/opt-functions.awk -f $(srcdir)/optc-gen.awk \ + -v header_name="config.h system.h options.h" < $< > $@ + +options.h: s-options-h ; @true +s-options-h: optionlist $(srcdir)/opt-functions.awk $(srcdir)/opth-gen.awk + $(AWK) -f $(srcdir)/opt-functions.awk -f $(srcdir)/opth-gen.awk \ + < $< > tmp-options.h + $(SHELL) $(srcdir)/move-if-change tmp-options.h options.h + $(STAMP) $@ version.o: version.c version.h hashtable.o: hashtable.c hashtable.h $(CONFIG_H) $(SYSTEM_H) $(OBSTACK_H) -hashtab.o: hashtab.c hashtab.h $(CONFIG_H) - cppcharset.o: cppcharset.c $(CONFIG_H) $(SYSTEM_H) prefix.o: prefix.c $(CONFIG_H) $(SYSTEM_H) Makefile prefix.h @@ -215,13 +228,14 @@ PREPROCESSOR_DEFINES = \ -DCROSS_INCLUDE_DIR=\"$(gcc_tooldir)/sys-include\" \ -DTOOL_INCLUDE_DIR=\"$(gcc_tooldir)/include\" -LIBCPP_OBJS = c-ppoutput.o cppinit.o cpplib.o cpplex.o cppmacro.o cppexp.o cppfiles.o \ - cpphash.o cpperror.o cppdefault.o \ - hashtable.o mkdeps.o prefix.o version.o \ - line-map.o cpptrad.o cppcharset.o hashtab.o \ - opts.o options.o diagnostic.o pretty-print.o c-incpath.o +########################## +# Libcpp + +LIBCPP_OBJS = charset.o directives.o errors.o expr.o files.o identifiers.o \ + init.o lex.o line-map.o macro.o mkdeps.o symtab.o traditional.o -LIBCPP_DEPS = cpplib.h cpphash.h hashtable.h intl.h options.h $(OBSTACK_H) $(SYSTEM_H) + +##LIBCPP_DEPS = cpplib.h cpphash.h hashtable.h intl.h options.h $(OBSTACK_H) $(SYSTEM_H) # Most of the other archives built/used by this makefile are for # targets. This one is strictly for the host. @@ -230,53 +244,72 @@ libcpp.a: $(LIBCPP_OBJS) $(AR) $(AR_FLAGS) libcpp.a $(LIBCPP_OBJS) -$(RANLIB) libcpp.a -MY_LIBIBERTY_BITS = concat.o getpwd.o hex.o lbasename.o obstack.o \ - safe-ctype.o splay-tree.o vasprintf.o xexit.o xmalloc.o \ - xmemdup.o xstrdup.o xstrerror.o +charset.o: $(LIBCPP_DIR)/charset.c $(CONFIG_H) $(LIBCPP_DEPS) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) -$(TARGET): sdcpp.o sdcpp-opts.o $(MY_LIBIBERTY_BITS) libcpp.a $(LIBDEPS) - mkdir -p $(dir $@) - $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ sdcpp.o sdcpp-opts.o \ - $(MY_LIBIBERTY_BITS) libcpp.a $(LIBS) +directives.o: $(LIBCPP_DIR)/directives.c $(CONFIG_H) $(LIBCPP_DEPS) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) -sdcpp.o: sdcpp.c $(CONFIG_H) cpplib.h $(SYSTEM_H) options.h -sdcpp-opts.o: sdcpp-opts.c $(CONFIG_H) $(LIBCPP_DEPS) options.h +errors.o: $(LIBCPP_DIR)/errors.c $(CONFIG_H) $(LIBCPP_DEPS) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) -c-ppoutput.o: c-ppoutput.c $(CONFIG_H) cpplib.h intl.h $(SYSTEM_H) -cppinit.o: cppinit.c $(CONFIG_H) $(LIBCPP_DEPS) cppdefault.h \ - mkdeps.h prefix.h output.h version.h -cpperror.o: cpperror.c $(CONFIG_H) $(LIBCPP_DEPS) -cppexp.o: cppexp.c $(CONFIG_H) $(LIBCPP_DEPS) -cpplex.o: cpplex.c $(CONFIG_H) $(LIBCPP_DEPS) -cppmacro.o: cppmacro.c $(CONFIG_H) $(LIBCPP_DEPS) -cpplib.o: cpplib.c $(CONFIG_H) $(LIBCPP_DEPS) -cpphash.o: cpphash.c $(CONFIG_H) $(LIBCPP_DEPS) -cppfiles.o: cppfiles.c $(CONFIG_H) $(LIBCPP_DEPS) $(SPLAY_TREE_H) mkdeps.h -cpptrad.o: cpptrad.c $(CONFIG_H) $(LIBCPP_DEPS) -opts.o: opts.c $(CONFIG_H) $(LIBCPP_DEPS) options.h -diagnostic.o: diagnostic.c $(CONFIG_H) $(LIBCPP_DEPS) diagnostic.h -pretty-print.o: pretty-print.c $(CONFIG_H) $(LIBCPP_DEPS) pretty-print.h -c-incpath.o: $(CONFIG_H) $(LIBCPP_DEPS) c-incpath.h +expr.o: $(LIBCPP_DIR)/expr.c $(CONFIG_H) $(LIBCPP_DEPS) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) -cppdefault.o: cppdefault.c $(CONFIG_H) $(SYSTEM_H) cppdefault.h Makefile - $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ - $(PREPROCESSOR_DEFINES) \ - -c $(srcdir)/cppdefault.c +files.o: $(LIBCPP_DIR)/files.c $(CONFIG_H) $(LIBCPP_DEPS) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) + +identifiers.o: $(LIBCPP_DIR)/identifiers.c $(CONFIG_H) $(LIBCPP_DEPS) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) + +init.o: $(LIBCPP_DIR)/init.c $(CONFIG_H) $(LIBCPP_DEPS) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) + +lex.o: $(LIBCPP_DIR)/lex.c $(CONFIG_H) $(LIBCPP_DEPS) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) + +line-map.o: $(LIBCPP_DIR)/line-map.c $(CONFIG_H) $(LIBCPP_DEPS) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) + +macro.o: $(LIBCPP_DIR)/macro.c $(CONFIG_H) $(LIBCPP_DEPS) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) + +mkdeps.o: $(LIBCPP_DIR)/mkdeps.c $(CONFIG_H) $(LIBCPP_DEPS) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) -mkdeps.o: mkdeps.c $(CONFIG_H) $(SYSTEM_H) mkdeps.h +symtab.o: $(LIBCPP_DIR)/symtab.c $(CONFIG_H) $(LIBCPP_DEPS) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) +traditional.o: $(LIBCPP_DIR)/traditional.c $(CONFIG_H) $(LIBCPP_DEPS) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) + +########################## # Libiberty -concat.o: $(LIBIBERTY_DIR)/concat.c $(CONFIG_H) $(LIBCPP_DEPS) +MY_LIBIBERTY_BITS = concat.o fopen_unlocked.o getpwd.o hashtab.o hex.o \ + lbasename.o md5.o obstack.o safe-ctype.o splay-tree.o \ + vasprintf.o xexit.o xmalloc.o xmemdup.o xstrdup.o \ + xstrerror.o + +concat.o: $(LIBIBERTY_DIR)/concat.c $(CONFIG_H) $(LIBCPP_DEPS) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) + +fopen_unlocked.o: $(LIBIBERTY_DIR)/fopen_unlocked.c $(CONFIG_H) $(LIBCPP_DEPS) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) + +getpwd.o: $(LIBIBERTY_DIR)/getpwd.c $(CONFIG_H) $(LIBCPP_DEPS) $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) -getpwd.o: $(LIBIBERTY_DIR)/getpwd.c $(CONFIG_H) $(LIBCPP_DEPS) +hashtab.o: $(LIBIBERTY_DIR)/hashtab.c $(CONFIG_H) $(LIBCPP_DEPS) $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) -hex.o: $(LIBIBERTY_DIR)/hex.c $(CONFIG_H) $(LIBCPP_DEPS) +hex.o: $(LIBIBERTY_DIR)/hex.c $(CONFIG_H) $(LIBCPP_DEPS) $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) -lbasename.o: $(LIBIBERTY_DIR)/lbasename.c $(CONFIG_H) $(LIBCPP_DEPS) +lbasename.o: $(LIBIBERTY_DIR)/lbasename.c $(CONFIG_H) $(LIBCPP_DEPS) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) + +md5.o: $(LIBIBERTY_DIR)/md5.c $(LIBIBERTY_DIR)/obstack.h $(CONFIG_H) $(LIBCPP_DEPS) $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) obstack.o: $(LIBIBERTY_DIR)/obstack.c $(LIBIBERTY_DIR)/obstack.h $(CONFIG_H) $(LIBCPP_DEPS) @@ -305,3 +338,32 @@ xstrdup.o: $(LIBIBERTY_DIR)/xstrdup.c $(CONFIG_H) $(LIBCPP_DEPS) xstrerror.o: $(LIBIBERTY_DIR)/xstrerror.c $(CONFIG_H) $(LIBCPP_DEPS) $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) + +########################## +# Sdcpp + +SDCC_OBJS = sdcpp.o sdcpp-opts.o c-ppoutput.o cppdefault.o prefix.o version.o opts.o options.o diagnostic.o pretty-print.o c-incpath.o + +$(TARGET): $(SDCC_OBJS) $(MY_LIBIBERTY_BITS) libcpp.a $(LIBDEPS) + mkdir -p $(dir $@) + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(SDCC_OBJS) \ + $(MY_LIBIBERTY_BITS) libcpp.a $(LIBS) + +sdcpp.o: sdcpp.c $(CONFIG_H) $(SYSTEM_H) options.h + +sdcpp-opts.o: sdcpp-opts.c $(CONFIG_H) $(LIBCPP_DEPS) options.h + +c-ppoutput.o: c-ppoutput.c $(CONFIG_H) $(SYSTEM_H) + +opts.o: opts.c $(CONFIG_H) $(LIBCPP_DEPS) options.h + +diagnostic.o: diagnostic.c $(CONFIG_H) $(LIBCPP_DEPS) diagnostic.h + +pretty-print.o: pretty-print.c $(CONFIG_H) $(LIBCPP_DEPS) pretty-print.h + +c-incpath.o: $(CONFIG_H) $(LIBCPP_DEPS) c-incpath.h + +cppdefault.o: cppdefault.c $(CONFIG_H) $(SYSTEM_H) cppdefault.h Makefile + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(PREPROCESSOR_DEFINES) \ + -c $(srcdir)/cppdefault.c diff --git a/support/cpp2/auto-host_vc_in.h b/support/cpp2/auto-host_vc_in.h index a2b61ca7..4e3ddad9 100644 --- a/support/cpp2/auto-host_vc_in.h +++ b/support/cpp2/auto-host_vc_in.h @@ -23,9 +23,10 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/ #include #include #include +#include #define HAVE_STRINGIZE -#define STDC_HEADERS +#define STDC_HEADERS 1 #define PACKAGE "sdcc" #define LOCALEDIR "" #define PREFIX "" diff --git a/support/cpp2/c-incpath.c b/support/cpp2/c-incpath.c index 4b0bf545..8ae9e554 100644 --- a/support/cpp2/c-incpath.c +++ b/support/cpp2/c-incpath.c @@ -1,6 +1,6 @@ /* Set up combined include path chain for the preprocessor. Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. Broken out of cppinit.c and cppfiles.c and rewritten Mar 2003. @@ -16,7 +16,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include "system.h" @@ -33,7 +33,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ # define INO_T_EQ(A, B) (!memcmp (&(A), &(B), sizeof (A))) # define INO_T_COPY(DEST, SRC) memcpy(&(DEST), &(SRC), sizeof (SRC)) #else -# if (defined _WIN32 && ! defined (_UWIN)) || defined __MSDOS__ +# if (defined _WIN32 && !defined (_UWIN)) || defined __MSDOS__ # define INO_T_EQ(A, B) 0 # else # define INO_T_EQ(A, B) ((A) == (B)) @@ -110,7 +110,7 @@ add_env_var_paths (const char *env_var, int chain) path[q - p] = '\0'; } - add_path (path, chain, chain == SYSTEM); + add_path (path, chain, chain == SYSTEM, false); } } @@ -124,7 +124,7 @@ add_standard_paths (const char *sysroot, const char *iprefix, int cxx_stdinc) if (iprefix && (len = cpp_GCC_INCLUDE_DIR_len) != 0) { /* Look for directories that start with the standard prefix. - "Translate" them, ie. replace /usr/local/lib/gcc... with + "Translate" them, i.e. replace /usr/local/lib/gcc... with IPREFIX and search them first. */ for (p = cpp_include_defaults; p->fname; p++) { @@ -138,7 +138,7 @@ add_standard_paths (const char *sysroot, const char *iprefix, int cxx_stdinc) if (!strncmp (p->fname, cpp_GCC_INCLUDE_DIR, len)) { char *str = concat (iprefix, p->fname + len, NULL); - add_path (str, SYSTEM, p->cxx_aware); + add_path (str, SYSTEM, p->cxx_aware, false); } } } @@ -156,7 +156,7 @@ add_standard_paths (const char *sysroot, const char *iprefix, int cxx_stdinc) else str = update_path (p->fname, p->component); - add_path (str, SYSTEM, p->cxx_aware); + add_path (str, SYSTEM, p->cxx_aware, false); } } } @@ -167,6 +167,7 @@ add_standard_paths (const char *sysroot, const char *iprefix, int cxx_stdinc) JOIN, unless it duplicates JOIN in which case the last path is removed. Return the head of the resulting chain. Any of HEAD, JOIN and SYSTEM can be NULL. */ + static struct cpp_dir * remove_duplicates (cpp_reader *pfile, struct cpp_dir *head, struct cpp_dir *system, struct cpp_dir *join, @@ -187,7 +188,13 @@ remove_duplicates (cpp_reader *pfile, struct cpp_dir *head, if (errno != ENOENT) cpp_errno (pfile, CPP_DL_ERROR, cur->name); else - reason = REASON_NOENT; + { + /* If -Wmissing-include-dirs is given, warn. */ + cpp_options *opts = cpp_get_options (pfile); + if (opts->warn_missing_include_dirs && cur->user_supplied_p) + cpp_errno (pfile, CPP_DL_WARNING, cur->name); + reason = REASON_NOENT; + } } else if (!S_ISDIR (st.st_mode)) cpp_error_with_line (pfile, CPP_DL_ERROR, 0, 0, @@ -200,7 +207,8 @@ remove_duplicates (cpp_reader *pfile, struct cpp_dir *head, /* Remove this one if it is in the system chain. */ reason = REASON_DUP_SYS; for (tmp = system; tmp; tmp = tmp->next) - if (INO_T_EQ (tmp->ino, cur->ino) && tmp->dev == cur->dev) + if (INO_T_EQ (tmp->ino, cur->ino) && tmp->dev == cur->dev + && cur->construct == tmp->construct) break; if (!tmp) @@ -208,14 +216,16 @@ remove_duplicates (cpp_reader *pfile, struct cpp_dir *head, /* Duplicate of something earlier in the same chain? */ reason = REASON_DUP; for (tmp = head; tmp != cur; tmp = tmp->next) - if (INO_T_EQ (cur->ino, tmp->ino) && cur->dev == tmp->dev) + if (INO_T_EQ (cur->ino, tmp->ino) && cur->dev == tmp->dev + && cur->construct == tmp->construct) break; if (tmp == cur /* Last in the chain and duplicate of JOIN? */ && !(cur->next == NULL && join && INO_T_EQ (cur->ino, join->ino) - && cur->dev == join->dev)) + && cur->dev == join->dev + && cur->construct == join->construct)) { /* Unique, so keep this directory. */ pcur = &cur->next; @@ -239,9 +249,10 @@ remove_duplicates (cpp_reader *pfile, struct cpp_dir *head, We can't just merge the lists and then uniquify them because then we may lose directories from the <> search path that should be - there; consider -Ifoo -Ibar -I- -Ifoo -Iquux. It is however safe - to treat -Ibar -Ifoo -I- -Ifoo -Iquux as if written -Ibar -I- -Ifoo - -Iquux. */ + there; consider -iquote foo -iquote bar -Ifoo -Iquux. It is + however safe to treat -iquote bar -iquote foo -Ifoo -Iquux as if + written -iquote bar -Ifoo -Iquux. */ + static void merge_include_chains (cpp_reader *pfile, int verbose) { @@ -296,16 +307,28 @@ split_quote_chain (void) quote_ignores_source_dir = true; } +/* Add P to the chain specified by CHAIN. */ + +void +add_cpp_dir_path (cpp_dir *p, int chain) +{ + if (tails[chain]) + tails[chain]->next = p; + else + heads[chain] = p; + tails[chain] = p; +} + /* Add PATH to the include chain CHAIN. PATH must be malloc-ed and NUL-terminated. */ void -add_path (char *path, int chain, int cxx_aware) +add_path (char *path, int chain, int cxx_aware, bool user_supplied_p) { - struct cpp_dir *p; + cpp_dir *p; #if defined (HAVE_DOS_BASED_FILE_SYSTEM) /* Convert all backslashes to slashes. The native CRT stat() - function does not recognise a directory that ends in a backslash + function does not recognize a directory that ends in a backslash (unless it is a drive root dir, such "c:\"). Forward slashes, trailing or otherwise, cause no problems for stat(). */ char* c; @@ -313,19 +336,17 @@ add_path (char *path, int chain, int cxx_aware) if (*c == '\\') *c = '/'; #endif - p = xmalloc (sizeof (struct cpp_dir)); + p = xmalloc (sizeof (cpp_dir)); p->next = NULL; p->name = path; if (chain == SYSTEM || chain == AFTER) p->sysp = 1 + !cxx_aware; else p->sysp = 0; + p->construct = 0; + p->user_supplied_p = user_supplied_p; - if (tails[chain]) - tails[chain]->next = p; - else - heads[chain] = p; - tails[chain] = p; + add_cpp_dir_path (p, chain); } /* Exported function to handle include chain merging, duplicate @@ -351,12 +372,33 @@ register_include_chains (cpp_reader *pfile, const char *sysroot, add_env_var_paths ("CPATH", BRACKET); add_env_var_paths (lang_env_vars[idx], SYSTEM); + target_c_incpath.extra_pre_includes (sysroot, iprefix, stdinc); + /* Finally chain on the standard directories. */ if (stdinc) add_standard_paths (sysroot, iprefix, cxx_stdinc); + target_c_incpath.extra_includes (sysroot, iprefix, stdinc); + merge_include_chains (pfile, verbose); cpp_set_include_chains (pfile, heads[QUOTE], heads[BRACKET], quote_ignores_source_dir); } +#if !(defined TARGET_EXTRA_INCLUDES) || !(defined TARGET_EXTRA_PRE_INCLUDES) +static void hook_void_charptr_charptr_int (const char *sysroot ATTRIBUTE_UNUSED, + const char *iprefix ATTRIBUTE_UNUSED, + int stdinc ATTRIBUTE_UNUSED) +{ +} +#endif + +#ifndef TARGET_EXTRA_INCLUDES +#define TARGET_EXTRA_INCLUDES hook_void_charptr_charptr_int +#endif +#ifndef TARGET_EXTRA_PRE_INCLUDES +#define TARGET_EXTRA_PRE_INCLUDES hook_void_charptr_charptr_int +#endif + +struct target_c_incpath_s target_c_incpath = { TARGET_EXTRA_PRE_INCLUDES, TARGET_EXTRA_INCLUDES }; + diff --git a/support/cpp2/c-incpath.h b/support/cpp2/c-incpath.h index 31ed657d..c309844c 100644 --- a/support/cpp2/c-incpath.h +++ b/support/cpp2/c-incpath.h @@ -1,5 +1,5 @@ /* Set up combined include path for the preprocessor. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -13,11 +13,20 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ extern void split_quote_chain (void); -extern void add_path (char *, int, int); +extern void add_path (char *, int, int, bool); extern void register_include_chains (cpp_reader *, const char *, const char *, int, int, int); +extern void add_cpp_dir_path (struct cpp_dir *, int); + +struct target_c_incpath_s { + /* Do extra includes processing. STDINC is false iff -nostdinc was given. */ + void (*extra_pre_includes) (const char *, const char *, int); + void (*extra_includes) (const char *, const char *, int); +}; + +extern struct target_c_incpath_s target_c_incpath; enum { QUOTE = 0, BRACKET, SYSTEM, AFTER }; diff --git a/support/cpp2/c-ppoutput.c b/support/cpp2/c-ppoutput.c index f564dfe1..9a543431 100644 --- a/support/cpp2/c-ppoutput.c +++ b/support/cpp2/c-ppoutput.c @@ -15,23 +15,23 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include "system.h" #include "cpplib.h" -#include "cpphash.h" +#include "../libcpp/internal.h" /* Encapsulates state used to convert a stream of tokens into a text file. */ static struct { FILE *outf; /* Stream to write to. */ - const struct line_map *map; /* Logical to physical line mappings. */ const cpp_token *prev; /* Previous token. */ const cpp_token *source; /* Source token for spacing. */ - fileline line; /* Line currently being written. */ + int src_line; /* Line number currently being written. */ unsigned char printed; /* Nonzero if something output at line. */ + bool first_time; /* pp_file_change hasn't been called yet. */ } print; /* General output routines. */ @@ -40,18 +40,22 @@ static void scan_translation_unit_trad (cpp_reader *); static void account_for_newlines (const unsigned char *, size_t); static int dump_macro (cpp_reader *, cpp_hashnode *, void *); -static void print_line (const struct line_map *, fileline, const char *); -static void maybe_print_line (const struct line_map *, fileline); +static void print_line (source_location, const char *); +static void maybe_print_line (source_location); /* Callback routines for the parser. Most of these are active only in specific modes. */ static void cb_line_change (cpp_reader *, const cpp_token *, int); -static void cb_define (cpp_reader *, fileline, cpp_hashnode *); -static void cb_undef (cpp_reader *, fileline, cpp_hashnode *); -static void cb_include (cpp_reader *, fileline, const unsigned char *, - const char *, int); -static void cb_ident (cpp_reader *, fileline, const cpp_string *); -static void cb_def_pragma (cpp_reader *, fileline); +static void cb_define (cpp_reader *, source_location, cpp_hashnode *); +static void cb_undef (cpp_reader *, source_location, cpp_hashnode *); +static void cb_include (cpp_reader *, source_location, const unsigned char *, + const char *, int, const cpp_token **); +static void cb_ident (cpp_reader *, source_location, const cpp_string *); +static void cb_def_pragma (cpp_reader *, source_location); +#if 0 +static void cb_read_pch (cpp_reader *pfile, const char *name, + int fd, const char *orig_name); +#endif /* Preprocess and output. */ void @@ -101,20 +105,28 @@ init_pp_output (FILE *out_stream) if (flag_dump_includes) cb->include = cb_include; +#if 0 + if (flag_pch_preprocess) + { + cb->valid_pch = c_common_valid_pch; + cb->read_pch = cb_read_pch; + } +#endif + if (flag_dump_macros == 'N' || flag_dump_macros == 'D') { cb->define = cb_define; cb->undef = cb_undef; } - /* Initialize the print structure. Setting print.line to -1 here is + /* Initialize the print structure. Setting print.src_line to -1 here is a trick to guarantee that the first token of the file will cause a linemarker to be output by maybe_print_line. */ - print.line = (fileline) -1; + print.src_line = -1; print.printed = 0; print.prev = 0; - print.map = 0; print.outf = out_stream; + print.first_time = 1; } /* Writes out the preprocessed file, handling spacing and paste @@ -166,13 +178,13 @@ scan_translation_unit (cpp_reader *pfile) } } -/* Adjust print.line for newlines embedded in output. */ +/* Adjust print.src_line for newlines embedded in output. */ static void account_for_newlines (const unsigned char *str, size_t len) { while (len--) if (*str++ == '\n') - print.line++; + print.src_line++; } /* Writes out a traditionally preprocessed file. */ @@ -182,7 +194,7 @@ scan_translation_unit_trad (cpp_reader *pfile) while (_cpp_read_logical_line_trad (pfile)) { size_t len = pfile->out.cur - pfile->out.base; - maybe_print_line (print.map, pfile->out.first_line); + maybe_print_line (pfile->out.first_line); fwrite (pfile->out.base, 1, len, print.outf); print.printed = 1; if (!CPP_OPTION (pfile, discard_comments)) @@ -194,52 +206,57 @@ scan_translation_unit_trad (cpp_reader *pfile) different line to the current one, output the required newlines or a line marker, and return 1. Otherwise return 0. */ static void -maybe_print_line (const struct line_map *map, fileline line) +maybe_print_line (source_location src_loc) { + const struct line_map *map = linemap_lookup (&line_table, src_loc); + int src_line = SOURCE_LINE (map, src_loc); /* End the previous line of text. */ if (print.printed) { putc ('\n', print.outf); - print.line++; + print.src_line++; print.printed = 0; } - if (line >= print.line && line < print.line + 8) + if (src_line >= print.src_line && src_line < print.src_line + 8) { - while (line > print.line) + while (src_line > print.src_line) { putc ('\n', print.outf); - print.line++; + print.src_line++; } } else - print_line (map, line, ""); + print_line (src_loc, ""); } /* Output a line marker for logical line LINE. Special flags are "1" or "2" indicating entering or leaving a file. */ static void -print_line (const struct line_map *map, fileline line, const char *special_flags) +print_line (source_location src_loc, const char *special_flags) { /* End any previous line of text. */ if (print.printed) putc ('\n', print.outf); print.printed = 0; - print.line = line; if (!flag_no_line_commands) { + const struct line_map *map = linemap_lookup (&line_table, src_loc); + size_t to_file_len = strlen (map->to_file); unsigned char *to_file_quoted = alloca (to_file_len * 4 + 1); unsigned char *p; + print.src_line = SOURCE_LINE (map, src_loc); + /* cpp_quote_string does not nul-terminate, so we have to do it ourselves. */ p = cpp_quote_string (to_file_quoted, - (unsigned char *)map->to_file, to_file_len); + (unsigned char *) map->to_file, to_file_len); *p = '\0'; fprintf (print.outf, "# %u \"%s\"%s", - SOURCE_LINE (map, print.line), + print.src_line == 0 ? 1 : print.src_line, to_file_quoted, special_flags); if (map->sysp == 2) @@ -257,10 +274,12 @@ static void cb_line_change (cpp_reader *pfile, const cpp_token *token, int parsing_args) { + source_location src_loc = token->src_loc; + if (token->type == CPP_EOF || parsing_args) return; - maybe_print_line (print.map, token->line); + maybe_print_line (src_loc); print.prev = 0; print.source = 0; @@ -271,30 +290,28 @@ cb_line_change (cpp_reader *pfile, const cpp_token *token, ought to care. Some things do care; the fault lies with them. */ if (!CPP_OPTION (pfile, traditional)) { + const struct line_map *map = linemap_lookup (&line_table, src_loc); + int spaces = SOURCE_COLUMN (map, src_loc) - 2; print.printed = 1; - if (token->col > 2) - { - unsigned int spaces = token->col - 2; - while (spaces--) - putc (' ', print.outf); - } + while (-- spaces >= 0) + putc (' ', print.outf); } } static void -cb_ident (cpp_reader *pfile ATTRIBUTE_UNUSED, fileline line, +cb_ident (cpp_reader *pfile ATTRIBUTE_UNUSED, source_location line, const cpp_string *str) { - maybe_print_line (print.map, line); + maybe_print_line (line); fprintf (print.outf, "#ident %s\n", str->text); - print.line++; + print.src_line++; } static void -cb_define (cpp_reader *pfile, fileline line, cpp_hashnode *node) +cb_define (cpp_reader *pfile, source_location line, cpp_hashnode *node) { - maybe_print_line (print.map, line); + maybe_print_line (line); fputs ("#define ", print.outf); /* 'D' is whole definition; 'N' is name only. */ @@ -305,32 +322,46 @@ cb_define (cpp_reader *pfile, fileline line, cpp_hashnode *node) fputs ((const char *) NODE_NAME (node), print.outf); putc ('\n', print.outf); - print.line++; + print.src_line++; } static void -cb_undef (cpp_reader *pfile ATTRIBUTE_UNUSED, fileline line, +cb_undef (cpp_reader *pfile ATTRIBUTE_UNUSED, source_location line, cpp_hashnode *node) { - maybe_print_line (print.map, line); + maybe_print_line (line); fprintf (print.outf, "#undef %s\n", NODE_NAME (node)); - print.line++; + print.src_line++; } static void -cb_include (cpp_reader *pfile ATTRIBUTE_UNUSED, fileline line, - const unsigned char *dir, const char *header, int angle_brackets) +cb_include (cpp_reader *pfile ATTRIBUTE_UNUSED, source_location line, + const unsigned char *dir, const char *header, int angle_brackets, + const cpp_token **comments) { - maybe_print_line (print.map, line); + maybe_print_line (line); if (angle_brackets) - fprintf (print.outf, "#%s <%s>\n", dir, header); + fprintf (print.outf, "#%s <%s>", dir, header); else - fprintf (print.outf, "#%s \"%s\"\n", dir, header); - print.line++; + fprintf (print.outf, "#%s \"%s\"", dir, header); + + if (comments != NULL) + { + while (*comments != NULL) + { + if ((*comments)->flags & PREV_WHITE) + putc (' ', print.outf); + cpp_output_token (*comments, print.outf); + ++comments; + } + } + + putc ('\n', print.outf); + print.src_line++; } /* Callback called when -fworking-director and -E to emit working - diretory in cpp output file. */ + directory in cpp output file. */ void pp_dir_change (cpp_reader *pfile ATTRIBUTE_UNUSED, const char *dir) @@ -339,15 +370,14 @@ pp_dir_change (cpp_reader *pfile ATTRIBUTE_UNUSED, const char *dir) unsigned char *to_file_quoted = alloca (to_file_len * 4 + 1); unsigned char *p; - /* cpp_quote_string does not nul-terminate, so we have to do it ourselves. */ + /* cpp_quote_string does not nul-terminate, so we have to do it ourselves. */ p = cpp_quote_string (to_file_quoted, (unsigned char *) dir, to_file_len); *p = '\0'; fprintf (print.outf, "# 1 \"%s//\"\n", to_file_quoted); } /* The file name, line number or system header flags have changed, as - described in MAP. From this point on, the old print.map might be - pointing to freed memory, and so must not be dereferenced. */ + described in MAP. */ void pp_file_change (const struct line_map *map) @@ -359,38 +389,38 @@ pp_file_change (const struct line_map *map) if (map != NULL) { - /* First time? */ - if (print.map == NULL) + if (print.first_time) { /* Avoid printing foo.i when the main file is foo.c. */ if (!cpp_get_options (parse_in)->preprocessed) - print_line (map, map->from_line, flags); + print_line (map->start_location, flags); + print.first_time = 0; } else { /* Bring current file to correct line when entering a new file. */ if (map->reason == LC_ENTER) - maybe_print_line (map - 1, map->from_line - 1); - + { + const struct line_map *from = INCLUDED_FROM (&line_table, map); + maybe_print_line (LAST_SOURCE_LINE_LOCATION (from)); + } if (map->reason == LC_ENTER) flags = " 1"; else if (map->reason == LC_LEAVE) flags = " 2"; - print_line (map, map->from_line, flags); + print_line (map->start_location, flags); } } - - print.map = map; } /* Copy a #pragma directive to the preprocessed output. */ static void -cb_def_pragma (cpp_reader *pfile, fileline line) +cb_def_pragma (cpp_reader *pfile, source_location line) { - maybe_print_line (print.map, line); + maybe_print_line (line); fputs ("#pragma ", print.outf); cpp_output_line (pfile, print.outf); - print.line++; + print.src_line++; } /* Dump out the hash table. */ @@ -403,8 +433,24 @@ dump_macro (cpp_reader *pfile, cpp_hashnode *node, void *v ATTRIBUTE_UNUSED) fputs ((const char *) cpp_macro_definition (pfile, node), print.outf); putc ('\n', print.outf); - print.line++; + print.src_line++; } return 1; } + +#if 0 +/* Load in the PCH file NAME, open on FD. It was originally searched for + by ORIG_NAME. Also, print out a #include command so that the PCH + file can be loaded when the preprocessed output is compiled. */ + +static void +cb_read_pch (cpp_reader *pfile, const char *name, + int fd, const char *orig_name ATTRIBUTE_UNUSED) +{ + c_common_read_pch (pfile, name, fd, orig_name); + + fprintf (print.outf, "#pragma GCC pch_preprocess \"%s\"\n", name); + print.src_line++; +} +#endif \ No newline at end of file diff --git a/support/cpp2/c-pretty-print.c b/support/cpp2/c-pretty-print.c index f4b744e0..45f62ad4 100644 --- a/support/cpp2/c-pretty-print.c +++ b/support/cpp2/c-pretty-print.c @@ -1,5 +1,5 @@ /* Subroutines common to both C and C++ pretty-printers. - Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. Contributed by Gabriel Dos Reis This file is part of GCC. @@ -16,11 +16,12 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ #include "config.h" #include "system.h" +#include "real.h" #include "c-pretty-print.h" /* The pretty-printer code is primarily designed to closely follow @@ -37,24 +38,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA pp_c_whitespace (PP); \ } while (0) -#define pp_c_left_bracket(PP) \ - do { \ - pp_left_bracket (PP); \ - pp_base (PP)->padding = pp_none; \ - } while (0) - -#define pp_c_right_bracket(PP) \ - do { \ - pp_right_bracket (PP); \ - pp_base (PP)->padding = pp_none; \ - } while (0) - -#define pp_c_star(PP) \ - do { \ - pp_star (PP); \ - pp_base (PP)->padding = pp_none; \ - } while (0) - /* literal */ static void pp_c_char (c_pretty_printer *, int); @@ -114,6 +97,20 @@ pp_c_right_brace (c_pretty_printer *pp) pp_base (pp)->padding = pp_none; } +void +pp_c_left_bracket (c_pretty_printer *pp) +{ + pp_left_bracket (pp); + pp_base (pp)->padding = pp_none; +} + +void +pp_c_right_bracket (c_pretty_printer *pp) +{ + pp_right_bracket (pp); + pp_base (pp)->padding = pp_none; +} + void pp_c_dot (c_pretty_printer *pp) { @@ -128,6 +125,13 @@ pp_c_ampersand (c_pretty_printer *pp) pp_base (pp)->padding = pp_none; } +void +pp_c_star (c_pretty_printer *pp) +{ + pp_star (pp); + pp_base (pp)->padding = pp_none; +} + void pp_c_arrow (c_pretty_printer *pp) { @@ -136,17 +140,36 @@ pp_c_arrow (c_pretty_printer *pp) } void -pp_c_semicolon(c_pretty_printer *pp) +pp_c_semicolon (c_pretty_printer *pp) { pp_semicolon (pp); pp_base (pp)->padding = pp_none; } +void +pp_c_complement (c_pretty_printer *pp) +{ + pp_complement (pp); + pp_base (pp)->padding = pp_none; +} + +void +pp_c_exclamation (c_pretty_printer *pp) +{ + pp_exclamation (pp); + pp_base (pp)->padding = pp_none; +} + +/* Print out the external representation of CV-QUALIFIER. */ + static void pp_c_cv_qualifier (c_pretty_printer *pp, const char *cv) { const char *p = pp_last_position_in_text (pp); - if (p != NULL && *p == '*') + /* The C programming language does not have references, but it is much + simpler to handle those here rather than going through the same + logic in the C++ pretty-printer. */ + if (p != NULL && (*p == '*' || *p == '&')) pp_c_whitespace (pp); pp_c_identifier (pp, cv); } @@ -161,6 +184,9 @@ pp_c_type_cast (c_pretty_printer *pp, tree t) pp_c_right_paren (pp); } +/* We're about to pretty-print a pointer type as indicated by T. + Output a whitespace, if needed, preparing for subsequent output. */ + void pp_c_space_for_pointer_operator (c_pretty_printer *pp, tree t) { @@ -194,7 +220,7 @@ void pp_c_type_qualifier_list (c_pretty_printer *pp, tree t) { int qualifiers; - + if (!TYPE_P (t)) t = TREE_TYPE (t); @@ -230,6 +256,13 @@ pp_c_pointer (c_pretty_printer *pp, tree t) pp_c_type_qualifier_list (pp, t); break; + /* ??? This node is now in GENERIC and so shouldn't be here. But + we'll fix that later. */ + case DECL_EXPR: + pp_declaration (pp, DECL_EXPR_DECL (t)); + pp_needs_newline (pp) = true; + break; + default: pp_unsupported_tree (pp, t); } @@ -268,7 +301,7 @@ pp_c_type_specifier (c_pretty_printer *pp, tree t) break; case IDENTIFIER_NODE: - pp_c_tree_identifier (pp, t); + pp_c_tree_decl_identifier (pp, t); break; case VOID_TYPE: @@ -277,10 +310,42 @@ pp_c_type_specifier (c_pretty_printer *pp, tree t) case INTEGER_TYPE: case REAL_TYPE: if (TYPE_NAME (t)) - t = TYPE_NAME (t); + { + t = TYPE_NAME (t); + pp_c_type_specifier (pp, t); + } else - t = c_common_type_for_mode (TYPE_MODE (t), TREE_UNSIGNED (t)); - pp_c_type_specifier (pp, t); + { + int prec = TYPE_PRECISION (t); + t = c_common_type_for_mode (TYPE_MODE (t), TYPE_UNSIGNED (t)); + if (TYPE_NAME (t)) + { + pp_c_type_specifier (pp, t); + if (TYPE_PRECISION (t) != prec) + { + pp_string (pp, ":"); + pp_decimal_int (pp, prec); + } + } + else + { + switch (code) + { + case INTEGER_TYPE: + pp_string (pp, (TYPE_UNSIGNED (t) + ? ""); + } + } break; case TYPE_DECL: @@ -346,6 +411,8 @@ pp_c_specifier_qualifier_list (c_pretty_printer *pp, tree t) pp_c_whitespace (pp); pp_c_left_paren (pp); } + else if (!c_dialect_cxx ()) + pp_c_whitespace (pp); pp_ptr_operator (pp, t); } break; @@ -441,7 +508,7 @@ pp_c_direct_abstract_declarator (c_pretty_printer *pp, tree t) case POINTER_TYPE: pp_abstract_declarator (pp, t); break; - + case FUNCTION_TYPE: pp_c_parameter_type_list (pp, t); pp_direct_abstract_declarator (pp, TREE_TYPE (t)); @@ -449,7 +516,7 @@ pp_c_direct_abstract_declarator (c_pretty_printer *pp, tree t) case ARRAY_TYPE: pp_c_left_bracket (pp); - if (TYPE_DOMAIN (t)) + if (TYPE_DOMAIN (t) && TYPE_MAX_VALUE (TYPE_DOMAIN (t))) pp_expression (pp, TYPE_MAX_VALUE (TYPE_DOMAIN (t))); pp_c_right_bracket (pp); pp_direct_abstract_declarator (pp, TREE_TYPE (t)); @@ -467,7 +534,7 @@ pp_c_direct_abstract_declarator (c_pretty_printer *pp, tree t) case COMPLEX_TYPE: case TYPE_DECL: break; - + default: pp_unsupported_tree (pp, t); break; @@ -536,7 +603,7 @@ pp_c_declaration_specifiers (c_pretty_printer *pp, tree t) direct-declarator [ static type-qualifier-list(opt) assignment-expression(opt)] direct-declarator [ type-qualifier-list static assignment-expression ] direct-declarator [ type-qualifier-list * ] - direct-declaratpr ( parameter-type-list ) + direct-declarator ( parameter-type-list ) direct-declarator ( identifier-list(opt) ) */ void @@ -549,11 +616,10 @@ pp_c_direct_declarator (c_pretty_printer *pp, tree t) case TYPE_DECL: case FIELD_DECL: case LABEL_DECL: - if (DECL_NAME (t)) - { - pp_c_space_for_pointer_operator (pp, TREE_TYPE (t)); - pp_c_tree_identifier (pp, DECL_NAME (t)); - } + pp_c_space_for_pointer_operator (pp, TREE_TYPE (t)); + pp_c_tree_decl_identifier (pp, t); + break; + case ARRAY_TYPE: case POINTER_TYPE: pp_abstract_declarator (pp, TREE_TYPE (t)); @@ -566,7 +632,7 @@ pp_c_direct_declarator (c_pretty_printer *pp, tree t) case FUNCTION_DECL: pp_c_space_for_pointer_operator (pp, TREE_TYPE (TREE_TYPE (t))); - pp_c_tree_identifier (pp, DECL_NAME (t)); + pp_c_tree_decl_identifier (pp, t); if (pp_c_base (pp)->flags & pp_c_flag_abstract) pp_abstract_declarator (pp, TREE_TYPE (t)); else @@ -615,7 +681,7 @@ pp_c_declarator (c_pretty_printer *pp, tree t) pp_direct_declarator (pp, t); break; - + default: pp_unsupported_tree (pp, t); break; @@ -673,50 +739,37 @@ pp_c_function_definition (c_pretty_printer *pp, tree t) /* Expressions. */ -/* Print out a c-char. */ +/* Print out a c-char. This is called solely for characters which are + in the *target* execution character set. We ought to convert them + back to the *host* execution character set before printing, but we + have no way to do this at present. A decent compromise is to print + all characters as if they were in the host execution character set, + and not attempt to recover any named escape characters, but render + all unprintables as octal escapes. If the host and target character + sets are the same, this produces relatively readable output. If they + are not the same, strings may appear as gibberish, but that's okay + (in fact, it may well be what the reader wants, e.g. if they are looking + to see if conversion to the target character set happened correctly). + + A special case: we need to prefix \, ", and ' with backslashes. It is + correct to do so for the *host*'s \, ", and ', because the rest of the + file appears in the host character set. */ static void pp_c_char (c_pretty_printer *pp, int c) { - switch (c) + if (ISPRINT (c)) { - case TARGET_NEWLINE: - pp_string (pp, "\\n"); - break; - case TARGET_TAB: - pp_string (pp, "\\t"); - break; - case TARGET_VT: - pp_string (pp, "\\v"); - break; - case TARGET_BS: - pp_string (pp, "\\b"); - break; - case TARGET_CR: - pp_string (pp, "\\r"); - break; - case TARGET_FF: - pp_string (pp, "\\f"); - break; - case TARGET_BELL: - pp_string (pp, "\\a"); - break; - case '\\': - pp_string (pp, "\\\\"); - break; - case '\'': - pp_string (pp, "\\'"); - break; - case '\"': - pp_string (pp, "\\\""); - break; - default: - if (ISPRINT (c)) - pp_character (pp, c); - else - pp_scalar (pp, "\\%03o", (unsigned) c); - break; + switch (c) + { + case '\\': pp_string (pp, "\\\\"); break; + case '\'': pp_string (pp, "\\\'"); break; + case '\"': pp_string (pp, "\\\""); break; + default: pp_character (pp, c); + } } + else + pp_scalar (pp, "\\%03o", (unsigned) c); } /* Print out a STRING literal. */ @@ -733,6 +786,8 @@ pp_c_string_literal (c_pretty_printer *pp, tree s) pp_doublequote (pp); } +/* Pretty-print an INTEGER literal. */ + static void pp_c_integer_constant (c_pretty_printer *pp, tree i) { @@ -744,16 +799,18 @@ pp_c_integer_constant (c_pretty_printer *pp, tree i) { if (tree_int_cst_sgn (i) < 0) { - pp_c_char (pp, '-'); - i = build_int_2 (-TREE_INT_CST_LOW (i), - ~TREE_INT_CST_HIGH (i) + !TREE_INT_CST_LOW (i)); + pp_character (pp, '-'); + i = build_int_cst_wide (NULL_TREE, + -TREE_INT_CST_LOW (i), + ~TREE_INT_CST_HIGH (i) + + !TREE_INT_CST_LOW (i)); } sprintf (pp_buffer (pp)->digit_buffer, HOST_WIDE_INT_PRINT_DOUBLE_HEX, TREE_INT_CST_HIGH (i), TREE_INT_CST_LOW (i)); pp_string (pp, pp_buffer (pp)->digit_buffer); } - if (TREE_UNSIGNED (type)) + if (TYPE_UNSIGNED (type)) pp_character (pp, 'u'); if (type == long_integer_type_node || type == long_unsigned_type_node) pp_character (pp, 'l'); @@ -769,10 +826,10 @@ pp_c_character_constant (c_pretty_printer *pp, tree c) { tree type = TREE_TYPE (c); if (type == wchar_type_node) - pp_character (pp, 'L'); + pp_character (pp, 'L'); pp_quote (pp); - if (host_integerp (c, TREE_UNSIGNED (type))) - pp_c_char (pp, tree_low_cst (c, TREE_UNSIGNED (type))); + if (host_integerp (c, TYPE_UNSIGNED (type))) + pp_c_char (pp, tree_low_cst (c, TYPE_UNSIGNED (type))); else pp_scalar (pp, "\\x%x", (unsigned) TREE_INT_CST_LOW (c)); pp_quote (pp); @@ -852,12 +909,12 @@ pp_c_floating_constant (c_pretty_printer *pp, tree r) } /* Pretty-print a compound literal expression. GNU extensions include - vector constants. */ + vector constants. */ static void pp_c_compound_literal (c_pretty_printer *pp, tree e) { - tree type = TREE_TYPE (e); + tree type = TREE_TYPE (e); pp_c_type_cast (pp, type); switch (TREE_CODE (type)) @@ -898,8 +955,8 @@ pp_c_constant (c_pretty_printer *pp, tree e) pp_c_character_constant (pp, e); else if (TREE_CODE (type) == ENUMERAL_TYPE && pp_c_enumeration_constant (pp, e)) - ; - else + ; + else pp_c_integer_constant (pp, e); } break; @@ -918,11 +975,13 @@ pp_c_constant (c_pretty_printer *pp, tree e) } } +/* Pretty-print an IDENTIFIER_NODE, preceded by whitespace is necessary. */ + void pp_c_identifier (c_pretty_printer *pp, const char *id) { - pp_c_maybe_whitespace (pp); - pp_identifier (pp, id); + pp_c_maybe_whitespace (pp); + pp_identifier (pp, id); pp_base (pp)->padding = pp_before; } @@ -944,8 +1003,9 @@ pp_c_primary_expression (c_pretty_printer *pp, tree e) case CONST_DECL: case FUNCTION_DECL: case LABEL_DECL: - e = DECL_NAME (e); - /* Fall through. */ + pp_c_tree_decl_identifier (pp, e); + break; + case IDENTIFIER_NODE: pp_c_tree_identifier (pp, e); break; @@ -964,9 +1024,19 @@ pp_c_primary_expression (c_pretty_printer *pp, tree e) pp_c_constant (pp, e); break; - case STMT_EXPR: + case TARGET_EXPR: + pp_c_identifier (pp, "__builtin_memcpy"); pp_c_left_paren (pp); - pp_statement (pp, STMT_EXPR_STMT (e)); + pp_ampersand (pp); + pp_primary_expression (pp, TREE_OPERAND (e, 0)); + pp_separate_with (pp, ','); + pp_ampersand (pp); + pp_initializer (pp, TREE_OPERAND (e, 1)); + if (TREE_OPERAND (e, 2)) + { + pp_separate_with (pp, ','); + pp_c_expression (pp, TREE_OPERAND (e, 2)); + } pp_c_right_paren (pp); break; @@ -989,13 +1059,7 @@ static void pp_c_initializer (c_pretty_printer *pp, tree e) { if (TREE_CODE (e) == CONSTRUCTOR) - { - enum tree_code code = TREE_CODE (TREE_TYPE (e)); - if (code == RECORD_TYPE || code == UNION_TYPE || code == ARRAY_TYPE) - pp_c_brace_enclosed_initializer_list (pp, e); - else - pp_unsupported_tree (pp, TREE_OPERAND (e, 1)); - } + pp_c_brace_enclosed_initializer_list (pp, e); else pp_expression (pp, e); } @@ -1008,7 +1072,9 @@ void pp_c_init_declarator (c_pretty_printer *pp, tree t) { pp_declarator (pp, t); - if (DECL_INITIAL (t)) + /* We don't want to output function definitions here. There are handled + elsewhere (and the syntactic form is bogus anyway). */ + if (TREE_CODE (t) != FUNCTION_DECL && DECL_INITIAL (t)) { tree init = DECL_INITIAL (t); /* This C++ bit is handled here because it is easier to do so. @@ -1081,25 +1147,36 @@ pp_c_initializer_list (c_pretty_printer *pp, tree e) pp_separate_with (pp, ','); } } - break; + return; case VECTOR_TYPE: - pp_c_expression_list (pp, TREE_VECTOR_CST_ELTS (e)); - break; + if (TREE_CODE (e) == VECTOR_CST) + pp_c_expression_list (pp, TREE_VECTOR_CST_ELTS (e)); + else if (TREE_CODE (e) == CONSTRUCTOR) + pp_c_constructor_elts (pp, CONSTRUCTOR_ELTS (e)); + else + break; + return; case COMPLEX_TYPE: - { - const bool cst = TREE_CODE (e) == COMPLEX_CST; - pp_expression (pp, cst ? TREE_REALPART (e) : TREE_OPERAND (e, 0)); - pp_separate_with (pp, ','); - pp_expression (pp, cst ? TREE_IMAGPART (e) : TREE_OPERAND (e, 1)); - } - break; + if (TREE_CODE (e) == CONSTRUCTOR) + pp_c_constructor_elts (pp, CONSTRUCTOR_ELTS (e)); + else if (TREE_CODE (e) == COMPLEX_CST || TREE_CODE (e) == COMPLEX_EXPR) + { + const bool cst = TREE_CODE (e) == COMPLEX_CST; + pp_expression (pp, cst ? TREE_REALPART (e) : TREE_OPERAND (e, 0)); + pp_separate_with (pp, ','); + pp_expression (pp, cst ? TREE_IMAGPART (e) : TREE_OPERAND (e, 1)); + } + else + break; + return; default: - pp_unsupported_tree (pp, type); break; } + + pp_unsupported_tree (pp, type); } /* Pretty-print a brace-enclosed initializer-list. */ @@ -1131,7 +1208,9 @@ pp_c_id_expression (c_pretty_printer *pp, tree t) case FUNCTION_DECL: case FIELD_DECL: case LABEL_DECL: - t = DECL_NAME (t); + pp_c_tree_decl_identifier (pp, t); + break; + case IDENTIFIER_NODE: pp_c_tree_identifier (pp, t); break; @@ -1165,11 +1244,6 @@ pp_c_postfix_expression (c_pretty_printer *pp, tree e) pp_identifier (pp, code == POSTINCREMENT_EXPR ? "++" : "--"); break; - case ARROW_EXPR: - pp_postfix_expression (pp, TREE_OPERAND (e, 0)); - pp_c_arrow (pp); - break; - case ARRAY_REF: pp_postfix_expression (pp, TREE_OPERAND (e, 0)); pp_c_left_bracket (pp); @@ -1182,6 +1256,62 @@ pp_c_postfix_expression (c_pretty_printer *pp, tree e) pp_c_call_argument_list (pp, TREE_OPERAND (e, 1)); break; + case UNORDERED_EXPR: + pp_c_identifier (pp, flag_isoc99 + ? "isunordered" + : "__builtin_isunordered"); + goto two_args_fun; + + case ORDERED_EXPR: + pp_c_identifier (pp, flag_isoc99 + ? "!isunordered" + : "!__builtin_isunordered"); + goto two_args_fun; + + case UNLT_EXPR: + pp_c_identifier (pp, flag_isoc99 + ? "!isgreaterequal" + : "!__builtin_isgreaterequal"); + goto two_args_fun; + + case UNLE_EXPR: + pp_c_identifier (pp, flag_isoc99 + ? "!isgreater" + : "!__builtin_isgreater"); + goto two_args_fun; + + case UNGT_EXPR: + pp_c_identifier (pp, flag_isoc99 + ? "!islessequal" + : "!__builtin_islessequal"); + goto two_args_fun; + + case UNGE_EXPR: + pp_c_identifier (pp, flag_isoc99 + ? "!isless" + : "!__builtin_isless"); + goto two_args_fun; + + case UNEQ_EXPR: + pp_c_identifier (pp, flag_isoc99 + ? "!islessgreater" + : "!__builtin_islessgreater"); + goto two_args_fun; + + case LTGT_EXPR: + pp_c_identifier (pp, flag_isoc99 + ? "islessgreater" + : "__builtin_islessgreater"); + goto two_args_fun; + + two_args_fun: + pp_c_left_paren (pp); + pp_expression (pp, TREE_OPERAND (e, 0)); + pp_separate_with (pp, ','); + pp_expression (pp, TREE_OPERAND (e, 1)); + pp_c_right_paren (pp); + break; + case ABS_EXPR: pp_c_identifier (pp, "__builtin_abs"); pp_c_left_paren (pp); @@ -1255,6 +1385,22 @@ pp_c_expression_list (c_pretty_printer *pp, tree e) } } +/* Print out V, which contains the elements of a constructor. */ + +void +pp_c_constructor_elts (c_pretty_printer *pp, VEC(constructor_elt,gc) *v) +{ + unsigned HOST_WIDE_INT ix; + tree value; + + FOR_EACH_CONSTRUCTOR_VALUE (v, ix, value) + { + pp_expression (pp, value); + if (ix != VEC_length (constructor_elt, v) - 1) + pp_separate_with (pp, ','); + } +} + /* Print out an expression-list in parens, as in a function call. */ void @@ -1276,7 +1422,7 @@ pp_c_call_argument_list (c_pretty_printer *pp, tree t) unary-operator: one of * & + - ! ~ - + GNU extensions. unary-expression: __alignof__ unary-expression @@ -1316,16 +1462,6 @@ pp_c_unary_expression (c_pretty_printer *pp, tree e) pp_c_cast_expression (pp, TREE_OPERAND (e, 0)); break; - case SIZEOF_EXPR: - case ALIGNOF_EXPR: - pp_c_identifier (pp, code == SIZEOF_EXPR ? "sizeof" : "__alignof__"); - pp_c_whitespace (pp); - if (TYPE_P (TREE_OPERAND (e, 0))) - pp_c_type_cast (pp, TREE_OPERAND (e, 0)); - else - pp_unary_expression (pp, TREE_OPERAND (e, 0)); - break; - case REALPART_EXPR: case IMAGPART_EXPR: pp_c_identifier (pp, code == REALPART_EXPR ? "__real__" : "__imag__"); @@ -1413,7 +1549,7 @@ pp_c_additive_expression (c_pretty_printer *pp, tree e) else pp_minus (pp); pp_c_whitespace (pp); - pp_multiplicative_expression (pp, TREE_OPERAND (e, 1)); + pp_multiplicative_expression (pp, TREE_OPERAND (e, 1)); break; default: @@ -1631,7 +1767,7 @@ pp_c_conditional_expression (c_pretty_printer *pp, tree e) /* assignment-expression: conditional-expression - unary-expression assignment-operator assignment-expression + unary-expression assignment-operator assignment-expression assignment-expression: one of = *= /= %= += -= >>= <<= &= ^= |= */ @@ -1687,19 +1823,25 @@ pp_c_expression (c_pretty_printer *pp, tree e) case FIELD_DECL: case LABEL_DECL: case ERROR_MARK: - case STMT_EXPR: pp_primary_expression (pp, e); break; case POSTINCREMENT_EXPR: case POSTDECREMENT_EXPR: - case ARROW_EXPR: case ARRAY_REF: case CALL_EXPR: case COMPONENT_REF: case COMPLEX_CST: case COMPLEX_EXPR: case VECTOR_CST: + case ORDERED_EXPR: + case UNORDERED_EXPR: + case LTGT_EXPR: + case UNEQ_EXPR: + case UNLE_EXPR: + case UNLT_EXPR: + case UNGE_EXPR: + case UNGT_EXPR: case ABS_EXPR: case CONSTRUCTOR: case COMPOUND_LITERAL_EXPR: @@ -1715,8 +1857,6 @@ pp_c_expression (c_pretty_printer *pp, tree e) case TRUTH_NOT_EXPR: case PREINCREMENT_EXPR: case PREDECREMENT_EXPR: - case SIZEOF_EXPR: - case ALIGNOF_EXPR: case REALPART_EXPR: case IMAGPART_EXPR: pp_c_unary_expression (pp, e); @@ -1770,7 +1910,7 @@ pp_c_expression (c_pretty_printer *pp, tree e) case NE_EXPR: pp_c_equality_expression (pp, e); break; - + case COND_EXPR: pp_conditional_expression (pp, e); break; @@ -1796,14 +1936,13 @@ pp_c_expression (c_pretty_printer *pp, tree e) case NOP_EXPR: case NON_LVALUE_EXPR: case SAVE_EXPR: - case UNSAVE_EXPR: pp_expression (pp, TREE_OPERAND (e, 0)); break; case TARGET_EXPR: pp_postfix_expression (pp, TREE_OPERAND (e, 1)); break; - + default: pp_unsupported_tree (pp, e); break; @@ -1814,308 +1953,16 @@ pp_c_expression (c_pretty_printer *pp, tree e) /* Statements. */ -/* statement: - labeled-statement - compound-statement - expression-statement - selection-statement - iteration-statement - jump-statement */ - void pp_c_statement (c_pretty_printer *pp, tree stmt) { - enum tree_code code; - if (stmt == NULL) return; - - code = TREE_CODE (stmt); - switch (code) - { - /* labeled-statement: - identifier : statement - case constant-expression : statement - default : statement */ - case LABEL_STMT: - case CASE_LABEL: - if (pp_needs_newline (pp)) - pp_newline_and_indent (pp, -3); - else - pp_indentation (pp) -= 3; - if (code == LABEL_STMT) - pp_tree_identifier (pp, DECL_NAME (LABEL_STMT_LABEL (stmt))); - else if (code == CASE_LABEL) - { - if (CASE_LOW (stmt) == NULL_TREE) - pp_identifier (pp, "default"); - else - { - pp_c_identifier (pp, "case"); - pp_c_whitespace (pp); - pp_conditional_expression (pp, CASE_LOW (stmt)); - if (CASE_HIGH (stmt)) - { - pp_identifier (pp, "..."); - pp_conditional_expression (pp, CASE_HIGH (stmt)); - } - } - } - pp_colon (pp); - pp_indentation (pp) += 3; - pp_needs_newline (pp) = true; - break; - /* compound-statement: - { block-item-list(opt) } - - block-item-list: - block-item - block-item-list block-item - - block-item: - declaration - statement */ - case COMPOUND_STMT: - if (pp_needs_newline (pp)) - pp_newline_and_indent (pp, 0); - pp_c_left_brace (pp); - pp_newline_and_indent (pp, 3); - for (stmt = COMPOUND_BODY (stmt); stmt; stmt = TREE_CHAIN (stmt)) - pp_statement (pp, stmt); - pp_newline_and_indent (pp, -3); - pp_c_right_brace (pp); - pp_needs_newline (pp) = true; - break; + if (pp_needs_newline (pp)) + pp_newline_and_indent (pp, 0); - /* expression-statement: - expression(opt) ; */ - case EXPR_STMT: - case CLEANUP_STMT: - if (pp_needs_newline (pp)) - pp_newline_and_indent (pp, 0); - { - tree e = code == EXPR_STMT - ? EXPR_STMT_EXPR (stmt) - : CLEANUP_EXPR (stmt); - if (e) - pp_expression (pp, e); - } - pp_c_semicolon (pp); - pp_needs_newline (pp) = true; - break; - - /* selection-statement: - if ( expression ) statement - if ( expression ) statement else statement - switch ( expression ) statement */ - case IF_STMT: - if (pp_needs_newline (pp)) - pp_newline_and_indent (pp, 0); - pp_c_identifier (pp, "if"); - pp_c_whitespace (pp); - pp_c_left_paren (pp); - pp_expression (pp, IF_COND (stmt)); - pp_c_right_paren (pp); - pp_newline_and_indent (pp, 3); - pp_statement (pp, THEN_CLAUSE (stmt)); - pp_newline_and_indent (pp, -3); - if (ELSE_CLAUSE (stmt)) - { - tree else_clause = ELSE_CLAUSE (stmt); - pp_c_identifier (pp, "else"); - if (TREE_CODE (else_clause) == IF_STMT) - pp_c_whitespace (pp); - else - pp_newline_and_indent (pp, 3); - pp_statement (pp, else_clause); - if (TREE_CODE (else_clause) != IF_STMT) - pp_newline_and_indent (pp, -3); - } - break; - - case SWITCH_STMT: - if (pp_needs_newline (pp)) - pp_newline_and_indent (pp, 0); - pp_c_identifier (pp, "switch"); - pp_space (pp); - pp_c_left_paren (pp); - pp_expression (pp, SWITCH_COND (stmt)); - pp_c_right_paren (pp); - pp_indentation (pp) += 3; - pp_needs_newline (pp) = true; - pp_statement (pp, SWITCH_BODY (stmt)); - pp_newline_and_indent (pp, -3); - break; - - /* iteration-statement: - while ( expression ) statement - do statement while ( expression ) ; - for ( expression(opt) ; expression(opt) ; expression(opt) ) statement - for ( declaration expression(opt) ; expression(opt) ) statement */ - case WHILE_STMT: - if (pp_needs_newline (pp)) - pp_newline_and_indent (pp, 0); - pp_c_identifier (pp, "while"); - pp_space (pp); - pp_c_left_paren (pp); - pp_expression (pp, WHILE_COND (stmt)); - pp_c_right_paren (pp); - pp_newline_and_indent (pp, 3); - pp_statement (pp, WHILE_BODY (stmt)); - pp_indentation (pp) -= 3; - pp_needs_newline (pp) = true; - break; - - case DO_STMT: - if (pp_needs_newline (pp)) - pp_newline_and_indent (pp, 0); - pp_c_identifier (pp, "do"); - pp_newline_and_indent (pp, 3); - pp_statement (pp, DO_BODY (stmt)); - pp_newline_and_indent (pp, -3); - pp_c_identifier (pp, "while"); - pp_space (pp); - pp_c_left_paren (pp); - pp_expression (pp, DO_COND (stmt)); - pp_c_right_paren (pp); - pp_c_semicolon (pp); - pp_needs_newline (pp) = true; - break; - - case FOR_STMT: - if (pp_needs_newline (pp)) - pp_newline_and_indent (pp, 0); - pp_c_identifier (pp, "for"); - pp_space (pp); - pp_c_left_paren (pp); - if (FOR_INIT_STMT (stmt)) - pp_statement (pp, FOR_INIT_STMT (stmt)); - else - pp_c_semicolon (pp); - pp_needs_newline (pp) = false; - pp_c_whitespace (pp); - if (FOR_COND (stmt)) - pp_expression (pp, FOR_COND (stmt)); - pp_c_semicolon (pp); - pp_needs_newline (pp) = false; - pp_c_whitespace (pp); - if (FOR_EXPR (stmt)) - pp_expression (pp, FOR_EXPR (stmt)); - pp_c_right_paren (pp); - pp_newline_and_indent (pp, 3); - pp_statement (pp, FOR_BODY (stmt)); - pp_indentation (pp) -= 3; - pp_needs_newline (pp) = true; - break; - - /* jump-statement: - goto identifier; - continue ; - return expression(opt) ; */ - case BREAK_STMT: - case CONTINUE_STMT: - if (pp_needs_newline (pp)) - pp_newline_and_indent (pp, 0); - pp_identifier (pp, code == BREAK_STMT ? "break" : "continue"); - pp_c_semicolon (pp); - pp_needs_newline (pp) = true; - break; - - case RETURN_STMT: - case GOTO_STMT: - { - tree e = code == RETURN_STMT - ? RETURN_STMT_EXPR (stmt) - : GOTO_DESTINATION (stmt); - if (pp_needs_newline (pp)) - pp_newline_and_indent (pp, 0); - pp_c_identifier (pp, code == RETURN_STMT ? "return" : "goto"); - pp_c_whitespace (pp); - if (e) - { - if (TREE_CODE (e) == INIT_EXPR - && TREE_CODE (TREE_OPERAND (e, 0)) == RESULT_DECL) - e = TREE_OPERAND (e, 1); - pp_expression (pp, e); - } - pp_c_semicolon (pp); - pp_needs_newline (pp) = true; - } - break; - - case SCOPE_STMT: - if (!SCOPE_NULLIFIED_P (stmt) && SCOPE_NO_CLEANUPS_P (stmt)) - { - int i = 0; - if (pp_needs_newline (pp)) - pp_newline_and_indent (pp, 0); - if (SCOPE_BEGIN_P (stmt)) - { - pp_left_brace (pp); - i = 3; - } - else if (SCOPE_END_P (stmt)) - { - pp_right_brace (pp); - i = -3; - } - pp_indentation (pp) += i; - pp_needs_newline (pp) = true; - } - break; - - case DECL_STMT: - if (pp_needs_newline (pp)) - pp_newline_and_indent (pp, 0); - pp_declaration (pp, DECL_STMT_DECL (stmt)); - pp_needs_newline (pp) = true; - break; - - case ASM_STMT: - { - bool has_volatile_p = ASM_VOLATILE_P (stmt); - bool is_extended = has_volatile_p || ASM_INPUTS (stmt) - || ASM_OUTPUTS (stmt) || ASM_CLOBBERS (stmt); - pp_c_identifier (pp, is_extended ? "__asm__" : "asm"); - if (has_volatile_p) - pp_c_identifier (pp, "__volatile__"); - pp_space (pp); - pp_c_left_paren (pp); - pp_c_string_literal (pp, ASM_STRING (stmt)); - if (is_extended) - { - pp_space (pp); - pp_separate_with (pp, ':'); - if (ASM_OUTPUTS (stmt)) - pp_expression (pp, ASM_OUTPUTS (stmt)); - pp_space (pp); - pp_separate_with (pp, ':'); - if (ASM_INPUTS (stmt)) - pp_expression (pp, ASM_INPUTS (stmt)); - pp_space (pp); - pp_separate_with (pp, ':'); - if (ASM_CLOBBERS (stmt)) - pp_expression (pp, ASM_CLOBBERS (stmt)); - } - pp_c_right_paren (pp); - pp_newline (pp); - } - break; - - case FILE_STMT: - pp_c_identifier (pp, "__FILE__"); - pp_space (pp); - pp_equal (pp); - pp_c_whitespace (pp); - pp_c_identifier (pp, FILE_STMT_FILENAME (stmt)); - pp_c_semicolon (pp); - pp_needs_newline (pp) = true; - break; - - default: - pp_unsupported_tree (pp, stmt); - } + dump_generic_node (pp_base (pp), stmt, pp_indentation (pp), 0, true); } @@ -2152,3 +1999,59 @@ pp_c_pretty_printer_init (c_pretty_printer *pp) pp->assignment_expression = pp_c_assignment_expression; pp->expression = pp_c_expression; } + + +/* Print the tree T in full, on file FILE. */ + +void +print_c_tree (FILE *file, tree t) +{ + static c_pretty_printer pp_rec; + static bool initialized = 0; + c_pretty_printer *pp = &pp_rec; + + if (!initialized) + { + initialized = 1; + pp_construct (pp_base (pp), NULL, 0); + pp_c_pretty_printer_init (pp); + pp_needs_newline (pp) = true; + } + pp_base (pp)->buffer->stream = file; + + pp_statement (pp, t); + + pp_newline (pp); + pp_flush (pp); +} + +/* Print the tree T in full, on stderr. */ + +void +debug_c_tree (tree t) +{ + print_c_tree (stderr, t); + fputc ('\n', stderr); +} + +/* Output the DECL_NAME of T. If T has no DECL_NAME, output a string made + up of T's memory address. */ + +void +pp_c_tree_decl_identifier (c_pretty_printer *pp, tree t) +{ + const char *name; + + gcc_assert (DECL_P (t)); + + if (DECL_NAME (t)) + name = IDENTIFIER_POINTER (DECL_NAME (t)); + else + { + static char xname[8]; + sprintf (xname, "", ((unsigned)((unsigned long)(t) & 0xffff))); + name = xname; + } + + pp_c_identifier (pp, name); +} diff --git a/support/cpp2/c-pretty-print.h b/support/cpp2/c-pretty-print.h index e9084b3e..2b9add61 100644 --- a/support/cpp2/c-pretty-print.h +++ b/support/cpp2/c-pretty-print.h @@ -1,5 +1,5 @@ /* Various declarations for the C and C++ pretty-printers. - Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. Contributed by Gabriel Dos Reis This file is part of GCC. @@ -16,8 +16,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ #ifndef GCC_C_PRETTY_PRINTER #define GCC_C_PRETTY_PRINTER @@ -28,7 +28,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA typedef enum { pp_c_flag_abstract = 1 << 1, - pp_c_flag_last_bit = 2 + pp_c_flag_last_bit = 2 } pp_c_pretty_print_flags; @@ -58,7 +58,7 @@ struct c_pretty_print_info int *offset_list; pp_flags flags; - + /* These must be overridden by each of the C and C++ front-end to reflect their understanding of syntactic productions when they differ. */ c_pretty_print_fn declaration; @@ -93,7 +93,7 @@ struct c_pretty_print_info #undef pp_base #define pp_base(PP) (&pp_c_base (PP)->base) - + #define pp_c_tree_identifier(PPI, ID) \ pp_c_identifier (PPI, IDENTIFIER_POINTER (ID)) @@ -157,13 +157,19 @@ void pp_c_left_paren (c_pretty_printer *); void pp_c_right_paren (c_pretty_printer *); void pp_c_left_brace (c_pretty_printer *); void pp_c_right_brace (c_pretty_printer *); +void pp_c_left_bracket (c_pretty_printer *); +void pp_c_right_bracket (c_pretty_printer *); void pp_c_dot (c_pretty_printer *); void pp_c_ampersand (c_pretty_printer *); +void pp_c_star (c_pretty_printer *); void pp_c_arrow (c_pretty_printer *); void pp_c_semicolon (c_pretty_printer *); +void pp_c_complement (c_pretty_printer *); +void pp_c_exclamation (c_pretty_printer *); void pp_c_space_for_pointer_operator (c_pretty_printer *, tree); /* Declarations. */ +void pp_c_tree_decl_identifier (c_pretty_printer *, tree); void pp_c_function_definition (c_pretty_printer *, tree); void pp_c_attributes (c_pretty_printer *, tree); void pp_c_type_qualifier_list (c_pretty_printer *, tree); @@ -184,6 +190,7 @@ void pp_c_statement (c_pretty_printer *, tree); void pp_c_expression (c_pretty_printer *, tree); void pp_c_logical_or_expression (c_pretty_printer *, tree); void pp_c_expression_list (c_pretty_printer *, tree); +////void pp_c_constructor_elts (c_pretty_printer *, VEC(constructor_elt,gc) *); void pp_c_call_argument_list (c_pretty_printer *, tree); void pp_c_unary_expression (c_pretty_printer *, tree); void pp_c_cast_expression (c_pretty_printer *, tree); @@ -195,4 +202,6 @@ void pp_c_id_expression (c_pretty_printer *, tree); void pp_c_identifier (c_pretty_printer *, const char *); void pp_c_string_literal (c_pretty_printer *, tree); +void print_c_tree (FILE *file, tree t); + #endif /* GCC_C_PRETTY_PRINTER */ diff --git a/support/cpp2/cppcharset.c b/support/cpp2/cppcharset.c deleted file mode 100644 index a6a65ed7..00000000 --- a/support/cpp2/cppcharset.c +++ /dev/null @@ -1,1411 +0,0 @@ -/* CPP Library - charsets - Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 - Free Software Foundation, Inc. - - Broken out of c-lex.c Apr 2003, adding valid C99 UCN ranges. - -This program 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 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include "config.h" -#include "system.h" -#include "cpplib.h" -#include "cpphash.h" -#include "cppucnid.h" - -/* Character set handling for C-family languages. - - Terminological note: In what follows, "charset" or "character set" - will be taken to mean both an abstract set of characters and an - encoding for that set. - - The C99 standard discusses two character sets: source and execution. - The source character set is used for internal processing in translation - phases 1 through 4; the execution character set is used thereafter. - Both are required by 5.2.1.2p1 to be multibyte encodings, not wide - character encodings (see 3.7.2, 3.7.3 for the standardese meanings - of these terms). Furthermore, the "basic character set" (listed in - 5.2.1p3) is to be encoded in each with values one byte wide, and is - to appear in the initial shift state. - - It is not explicitly mentioned, but there is also a "wide execution - character set" used to encode wide character constants and wide - string literals; this is supposed to be the result of applying the - standard library function mbstowcs() to an equivalent narrow string - (6.4.5p5). However, the behavior of hexadecimal and octal - \-escapes is at odds with this; they are supposed to be translated - directly to wchar_t values (6.4.4.4p5,6). - - The source character set is not necessarily the character set used - to encode physical source files on disk; translation phase 1 converts - from whatever that encoding is to the source character set. - - The presence of universal character names in C99 (6.4.3 et seq.) - forces the source character set to be isomorphic to ISO 10646, - that is, Unicode. There is no such constraint on the execution - character set; note also that the conversion from source to - execution character set does not occur for identifiers (5.1.1.2p1#5). - - For convenience of implementation, the source character set's - encoding of the basic character set should be identical to the - execution character set OF THE HOST SYSTEM's encoding of the basic - character set, and it should not be a state-dependent encoding. - - cpplib uses UTF-8 or UTF-EBCDIC for the source character set, - depending on whether the host is based on ASCII or EBCDIC (see - respectively Unicode section 2.3/ISO10646 Amendment 2, and Unicode - Technical Report #16). With limited exceptions, it relies on the - system library's iconv() primitive to do charset conversion - (specified in SUSv2). */ - -#if !HAVE_ICONV -/* Make certain that the uses of iconv(), iconv_open(), iconv_close() - below, which are guarded only by if statements with compile-time - constant conditions, do not cause link errors. */ -#define iconv_open(x, y) (errno = EINVAL, (iconv_t)-1) -#define iconv(a,b,c,d,e) (errno = EINVAL, (size_t)-1) -#define iconv_close(x) (void)0 -#define ICONV_CONST -#endif - -#if HOST_CHARSET == HOST_CHARSET_ASCII -#define SOURCE_CHARSET "UTF-8" -#elif HOST_CHARSET == HOST_CHARSET_EBCDIC -#define SOURCE_CHARSET "UTF-EBCDIC" -#else -#error "Unrecognized basic host character set" -#endif - -#ifndef EILSEQ -#define EILSEQ EINVAL -#endif - -/* This structure is used for a resizable string buffer throughout. */ -/* Don't call it strbuf, as that conflicts with unistd.h on systems - such as DYNIX/ptx where unistd.h includes stropts.h. */ -struct _cpp_strbuf -{ - uchar *text; - size_t asize; - size_t len; -}; - -/* This is enough to hold any string that fits on a single 80-column - line, even if iconv quadruples its size (e.g. conversion from - ASCII to UTF-32) rounded up to a power of two. */ -#define OUTBUF_BLOCK_SIZE 256 - -/* Conversions between UTF-8 and UTF-16/32 are implemented by custom - logic. This is because a depressing number of systems lack iconv, - or have have iconv libraries that do not do these conversions, so - we need a fallback implementation for them. To ensure the fallback - doesn't break due to neglect, it is used on all systems. - - UTF-32 encoding is nice and simple: a four-byte binary number, - constrained to the range 00000000-7FFFFFFF to avoid questions of - signedness. We do have to cope with big- and little-endian - variants. - - UTF-16 encoding uses two-byte binary numbers, again in big- and - little-endian variants, for all values in the 00000000-0000FFFF - range. Values in the 00010000-0010FFFF range are encoded as pairs - of two-byte numbers, called "surrogate pairs": given a number S in - this range, it is mapped to a pair (H, L) as follows: - - H = (S - 0x10000) / 0x400 + 0xD800 - L = (S - 0x10000) % 0x400 + 0xDC00 - - Two-byte values in the D800...DFFF range are ill-formed except as a - component of a surrogate pair. Even if the encoding within a - two-byte value is little-endian, the H member of the surrogate pair - comes first. - - There is no way to encode values in the 00110000-7FFFFFFF range, - which is not currently a problem as there are no assigned code - points in that range; however, the author expects that it will - eventually become necessary to abandon UTF-16 due to this - limitation. Note also that, because of these pairs, UTF-16 does - not meet the requirements of the C standard for a wide character - encoding (see 3.7.3 and 6.4.4.4p11). - - UTF-8 encoding looks like this: - - value range encoded as - 00000000-0000007F 0xxxxxxx - 00000080-000007FF 110xxxxx 10xxxxxx - 00000800-0000FFFF 1110xxxx 10xxxxxx 10xxxxxx - 00010000-001FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - 00200000-03FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - 04000000-7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - - Values in the 0000D800 ... 0000DFFF range (surrogates) are invalid, - which means that three-byte sequences ED xx yy, with A0 <= xx <= BF, - never occur. Note also that any value that can be encoded by a - given row of the table can also be encoded by all successive rows, - but this is not done; only the shortest possible encoding for any - given value is valid. For instance, the character 07C0 could be - encoded as any of DF 80, E0 9F 80, F0 80 9F 80, F8 80 80 9F 80, or - FC 80 80 80 9F 80. Only the first is valid. - - An implementation note: the transformation from UTF-16 to UTF-8, or - vice versa, is easiest done by using UTF-32 as an intermediary. */ - -/* Internal primitives which go from an UTF-8 byte stream to native-endian - UTF-32 in a cppchar_t, or vice versa; this avoids an extra marshal/unmarshal - operation in several places below. */ -static inline int -one_utf8_to_cppchar (const uchar **inbufp, size_t *inbytesleftp, - cppchar_t *cp) -{ - static const uchar masks[6] = { 0x7F, 0x1F, 0x0F, 0x07, 0x02, 0x01 }; - static const uchar patns[6] = { 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - - cppchar_t c; - const uchar *inbuf = *inbufp; - size_t nbytes, i; - - if (*inbytesleftp < 1) - return EINVAL; - - c = *inbuf; - if (c < 0x80) - { - *cp = c; - *inbytesleftp -= 1; - *inbufp += 1; - return 0; - } - - /* The number of leading 1-bits in the first byte indicates how many - bytes follow. */ - for (nbytes = 2; nbytes < 7; nbytes++) - if ((c & ~masks[nbytes-1]) == patns[nbytes-1]) - goto found; - return EILSEQ; - found: - - if (*inbytesleftp < nbytes) - return EINVAL; - - c = (c & masks[nbytes-1]); - inbuf++; - for (i = 1; i < nbytes; i++) - { - cppchar_t n = *inbuf++; - if ((n & 0xC0) != 0x80) - return EILSEQ; - c = ((c << 6) + (n & 0x3F)); - } - - /* Make sure the shortest possible encoding was used. */ - if (c <= 0x7F && nbytes > 1) return EILSEQ; - if (c <= 0x7FF && nbytes > 2) return EILSEQ; - if (c <= 0xFFFF && nbytes > 3) return EILSEQ; - if (c <= 0x1FFFFF && nbytes > 4) return EILSEQ; - if (c <= 0x3FFFFFF && nbytes > 5) return EILSEQ; - - /* Make sure the character is valid. */ - if (c > 0x7FFFFFFF || (c >= 0xD800 && c <= 0xDFFF)) return EILSEQ; - - *cp = c; - *inbufp = inbuf; - *inbytesleftp -= nbytes; - return 0; -} - -static inline int -one_cppchar_to_utf8 (cppchar_t c, uchar **outbufp, size_t *outbytesleftp) -{ - static const uchar masks[6] = { 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - static const uchar limits[6] = { 0x80, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE }; - size_t nbytes; - uchar buf[6], *p = &buf[6]; - uchar *outbuf = *outbufp; - - nbytes = 1; - if (c < 0x80) - *--p = c; - else - { - do - { - *--p = ((c & 0x3F) | 0x80); - c >>= 6; - nbytes++; - } - while (c >= 0x3F || (c & limits[nbytes-1])); - *--p = (c | masks[nbytes-1]); - } - - if (*outbytesleftp < nbytes) - return E2BIG; - - while (p < &buf[6]) - *outbuf++ = *p++; - *outbytesleftp -= nbytes; - *outbufp = outbuf; - return 0; -} - -/* The following four functions transform one character between the two - encodings named in the function name. All have the signature - int (*)(iconv_t bigend, const uchar **inbufp, size_t *inbytesleftp, - uchar **outbufp, size_t *outbytesleftp) - - BIGEND must have the value 0 or 1, coerced to (iconv_t); it is - interpreted as a boolean indicating whether big-endian or - little-endian encoding is to be used for the member of the pair - that is not UTF-8. - - INBUFP, INBYTESLEFTP, OUTBUFP, OUTBYTESLEFTP work exactly as they - do for iconv. - - The return value is either 0 for success, or an errno value for - failure, which may be E2BIG (need more space), EILSEQ (ill-formed - input sequence), ir EINVAL (incomplete input sequence). */ - -static inline int -one_utf8_to_utf32 (iconv_t bigend, const uchar **inbufp, size_t *inbytesleftp, - uchar **outbufp, size_t *outbytesleftp) -{ - uchar *outbuf; - cppchar_t s = 0; - int rval; - - /* Check for space first, since we know exactly how much we need. */ - if (*outbytesleftp < 4) - return E2BIG; - - rval = one_utf8_to_cppchar (inbufp, inbytesleftp, &s); - if (rval) - return rval; - - outbuf = *outbufp; - outbuf[bigend ? 3 : 0] = (s & 0x000000FF); - outbuf[bigend ? 2 : 1] = (s & 0x0000FF00) >> 8; - outbuf[bigend ? 1 : 2] = (s & 0x00FF0000) >> 16; - outbuf[bigend ? 0 : 3] = (s & 0xFF000000) >> 24; - - *outbufp += 4; - *outbytesleftp -= 4; - return 0; -} - -static inline int -one_utf32_to_utf8 (iconv_t bigend, const uchar **inbufp, size_t *inbytesleftp, - uchar **outbufp, size_t *outbytesleftp) -{ - cppchar_t s; - int rval; - const uchar *inbuf; - - if (*inbytesleftp < 4) - return EINVAL; - - inbuf = *inbufp; - - s = inbuf[bigend ? 0 : 3] << 24; - s += inbuf[bigend ? 1 : 2] << 16; - s += inbuf[bigend ? 2 : 1] << 8; - s += inbuf[bigend ? 3 : 0]; - - if (s >= 0x7FFFFFFF || (s >= 0xD800 && s <= 0xDFFF)) - return EILSEQ; - - rval = one_cppchar_to_utf8 (s, outbufp, outbytesleftp); - if (rval) - return rval; - - *inbufp += 4; - *inbytesleftp -= 4; - return 0; -} - -static inline int -one_utf8_to_utf16 (iconv_t bigend, const uchar **inbufp, size_t *inbytesleftp, - uchar **outbufp, size_t *outbytesleftp) -{ - int rval; - cppchar_t s = 0; - const uchar *save_inbuf = *inbufp; - size_t save_inbytesleft = *inbytesleftp; - uchar *outbuf = *outbufp; - - rval = one_utf8_to_cppchar (inbufp, inbytesleftp, &s); - if (rval) - return rval; - - if (s > 0x0010FFFF) - { - *inbufp = save_inbuf; - *inbytesleftp = save_inbytesleft; - return EILSEQ; - } - - if (s < 0xFFFF) - { - if (*outbytesleftp < 2) - { - *inbufp = save_inbuf; - *inbytesleftp = save_inbytesleft; - return E2BIG; - } - outbuf[bigend ? 1 : 0] = (s & 0x00FF); - outbuf[bigend ? 0 : 1] = (s & 0xFF00) >> 8; - - *outbufp += 2; - *outbytesleftp -= 2; - return 0; - } - else - { - cppchar_t hi, lo; - - if (*outbytesleftp < 4) - { - *inbufp = save_inbuf; - *inbytesleftp = save_inbytesleft; - return E2BIG; - } - - hi = (s - 0x10000) / 0x400 + 0xD800; - lo = (s - 0x10000) % 0x400 + 0xDC00; - - /* Even if we are little-endian, put the high surrogate first. - ??? Matches practice? */ - outbuf[bigend ? 1 : 0] = (hi & 0x00FF); - outbuf[bigend ? 0 : 1] = (hi & 0xFF00) >> 8; - outbuf[bigend ? 3 : 2] = (lo & 0x00FF); - outbuf[bigend ? 2 : 3] = (lo & 0xFF00) >> 8; - - *outbufp += 4; - *outbytesleftp -= 4; - return 0; - } -} - -static inline int -one_utf16_to_utf8 (iconv_t bigend, const uchar **inbufp, size_t *inbytesleftp, - uchar **outbufp, size_t *outbytesleftp) -{ - cppchar_t s; - const uchar *inbuf = *inbufp; - int rval; - - if (*inbytesleftp < 2) - return EINVAL; - s = inbuf[bigend ? 0 : 1] << 8; - s += inbuf[bigend ? 1 : 0]; - - /* Low surrogate without immediately preceding high surrogate is invalid. */ - if (s >= 0xDC00 && s <= 0xDFFF) - return EILSEQ; - /* High surrogate must have a following low surrogate. */ - else if (s >= 0xD800 && s <= 0xDBFF) - { - cppchar_t hi = s, lo; - if (*inbytesleftp < 4) - return EINVAL; - - lo = inbuf[bigend ? 2 : 3] << 8; - lo += inbuf[bigend ? 3 : 2]; - - if (lo < 0xDC00 || lo > 0xDFFF) - return EILSEQ; - - s = (hi - 0xD800) * 0x400 + (lo - 0xDC00) + 0x10000; - } - - rval = one_cppchar_to_utf8 (s, outbufp, outbytesleftp); - if (rval) - return rval; - - /* Success - update the input pointers (one_cppchar_to_utf8 has done - the output pointers for us). */ - if (s <= 0xFFFF) - { - *inbufp += 2; - *inbytesleftp -= 2; - } - else - { - *inbufp += 4; - *inbytesleftp -= 4; - } - return 0; -} - -/* Helper routine for the next few functions. The 'const' on - one_conversion means that we promise not to modify what function is - pointed to, which lets the inliner see through it. */ - -static inline bool -conversion_loop (int (*const one_conversion)(iconv_t, const uchar **, size_t *, - uchar **, size_t *), - iconv_t cd, const uchar *from, size_t flen, struct _cpp_strbuf *to) -{ - const uchar *inbuf; - uchar *outbuf; - size_t inbytesleft, outbytesleft; - int rval; - - inbuf = from; - inbytesleft = flen; - outbuf = to->text + to->len; - outbytesleft = to->asize - to->len; - - for (;;) - { - do - rval = one_conversion (cd, &inbuf, &inbytesleft, - &outbuf, &outbytesleft); - while (inbytesleft && !rval); - - if (__builtin_expect (inbytesleft == 0, 1)) - { - to->len = to->asize - outbytesleft; - return true; - } - if (rval != E2BIG) - { - errno = rval; - return false; - } - - outbytesleft += OUTBUF_BLOCK_SIZE; - to->asize += OUTBUF_BLOCK_SIZE; - to->text = xrealloc (to->text, to->asize); - outbuf = to->text + to->asize - outbytesleft; - } -} - - -/* These functions convert entire strings between character sets. - They all have the signature - - bool (*)(iconv_t cd, const uchar *from, size_t flen, struct _cpp_strbuf *to); - - The input string FROM is converted as specified by the function - name plus the iconv descriptor CD (which may be fake), and the - result appended to TO. On any error, false is returned, otherwise true. */ - -/* These four use the custom conversion code above. */ -static bool -convert_utf8_utf16 (iconv_t cd, const uchar *from, size_t flen, - struct _cpp_strbuf *to) -{ - return conversion_loop (one_utf8_to_utf16, cd, from, flen, to); -} - -static bool -convert_utf8_utf32 (iconv_t cd, const uchar *from, size_t flen, - struct _cpp_strbuf *to) -{ - return conversion_loop (one_utf8_to_utf32, cd, from, flen, to); -} - -static bool -convert_utf16_utf8 (iconv_t cd, const uchar *from, size_t flen, - struct _cpp_strbuf *to) -{ - return conversion_loop (one_utf16_to_utf8, cd, from, flen, to); -} - -static bool -convert_utf32_utf8 (iconv_t cd, const uchar *from, size_t flen, - struct _cpp_strbuf *to) -{ - return conversion_loop (one_utf32_to_utf8, cd, from, flen, to); -} - -/* Identity conversion, used when we have no alternative. */ -static bool -convert_no_conversion (iconv_t cd ATTRIBUTE_UNUSED, - const uchar *from, size_t flen, struct _cpp_strbuf *to) -{ - if (to->len + flen > to->asize) - { - to->asize = to->len + flen; - to->text = xrealloc (to->text, to->asize); - } - memcpy (to->text + to->len, from, flen); - to->len += flen; - return true; -} - -/* And this one uses the system iconv primitive. It's a little - different, since iconv's interface is a little different. */ -#if HAVE_ICONV -static bool -convert_using_iconv (iconv_t cd, const uchar *from, size_t flen, - struct _cpp_strbuf *to) -{ - ICONV_CONST char *inbuf; - char *outbuf; - size_t inbytesleft, outbytesleft; - - /* Reset conversion descriptor and check that it is valid. */ - if (iconv (cd, 0, 0, 0, 0) == (size_t)-1) - return false; - - inbuf = (ICONV_CONST char *)from; - inbytesleft = flen; - outbuf = (char *)to->text + to->len; - outbytesleft = to->asize - to->len; - - for (;;) - { - iconv (cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); - if (__builtin_expect (inbytesleft == 0, 1)) - { - to->len = to->asize - outbytesleft; - return true; - } - if (errno != E2BIG) - return false; - - outbytesleft += OUTBUF_BLOCK_SIZE; - to->asize += OUTBUF_BLOCK_SIZE; - to->text = xrealloc (to->text, to->asize); - outbuf = (char *)to->text + to->asize - outbytesleft; - } -} -#else -#define convert_using_iconv 0 /* prevent undefined symbol error below */ -#endif - -/* Arrange for the above custom conversion logic to be used automatically - when conversion between a suitable pair of character sets is requested. */ - -#define APPLY_CONVERSION(CONVERTER, FROM, FLEN, TO) \ - CONVERTER.func (CONVERTER.cd, FROM, FLEN, TO) - -struct conversion -{ - const char *pair; - convert_f func; - iconv_t fake_cd; -}; -static const struct conversion conversion_tab[] = { - { "UTF-8/UTF-32LE", convert_utf8_utf32, (iconv_t)0 }, - { "UTF-8/UTF-32BE", convert_utf8_utf32, (iconv_t)1 }, - { "UTF-8/UTF-16LE", convert_utf8_utf16, (iconv_t)0 }, - { "UTF-8/UTF-16BE", convert_utf8_utf16, (iconv_t)1 }, - { "UTF-32LE/UTF-8", convert_utf32_utf8, (iconv_t)0 }, - { "UTF-32BE/UTF-8", convert_utf32_utf8, (iconv_t)1 }, - { "UTF-16LE/UTF-8", convert_utf16_utf8, (iconv_t)0 }, - { "UTF-16BE/UTF-8", convert_utf16_utf8, (iconv_t)1 }, -}; - -/* Subroutine of cpp_init_iconv: initialize and return a - cset_converter structure for conversion from FROM to TO. If - iconv_open() fails, issue an error and return an identity - converter. Silently return an identity converter if FROM and TO - are identical. */ -static struct cset_converter -init_iconv_desc (cpp_reader *pfile, const char *to, const char *from) -{ - struct cset_converter ret; - char *pair; - size_t i; - - if (!strcasecmp (to, from)) - { - ret.func = convert_no_conversion; - ret.cd = (iconv_t) -1; - return ret; - } - - pair = alloca(strlen(to) + strlen(from) + 2); - - strcpy(pair, from); - strcat(pair, "/"); - strcat(pair, to); - for (i = 0; i < ARRAY_SIZE (conversion_tab); i++) - if (!strcasecmp (pair, conversion_tab[i].pair)) - { - ret.func = conversion_tab[i].func; - ret.cd = conversion_tab[i].fake_cd; - return ret; - } - - /* No custom converter - try iconv. */ - if (HAVE_ICONV) - { - ret.func = convert_using_iconv; - ret.cd = iconv_open (to, from); - - if (ret.cd == (iconv_t) -1) - { - if (errno == EINVAL) - cpp_error (pfile, CPP_DL_ERROR, /* XXX should be DL_SORRY */ - "conversion from %s to %s not supported by iconv", - from, to); - else - cpp_errno (pfile, CPP_DL_ERROR, "iconv_open"); - - ret.func = convert_no_conversion; - } - } - else - { - cpp_error (pfile, CPP_DL_ERROR, /* XXX should be DL_SORRY */ - "no iconv implementation, cannot convert from %s to %s", - from, to); - ret.func = convert_no_conversion; - ret.cd = (iconv_t) -1; - } - return ret; -} - -/* If charset conversion is requested, initialize iconv(3) descriptors - for conversion from the source character set to the execution - character sets. If iconv is not present in the C library, and - conversion is requested, issue an error. */ - -void -cpp_init_iconv (cpp_reader *pfile) -{ - const char *ncset = CPP_OPTION (pfile, narrow_charset); - const char *wcset = CPP_OPTION (pfile, wide_charset); - const char *default_wcset; - - bool be = CPP_OPTION (pfile, bytes_big_endian); - - if (CPP_OPTION (pfile, wchar_precision) >= 32) - default_wcset = be ? "UTF-32BE" : "UTF-32LE"; - else if (CPP_OPTION (pfile, wchar_precision) >= 16) - default_wcset = be ? "UTF-16BE" : "UTF-16LE"; - else - /* This effectively means that wide strings are not supported, - so don't do any conversion at all. */ - default_wcset = SOURCE_CHARSET; - - if (!ncset) - ncset = SOURCE_CHARSET; - if (!wcset) - wcset = default_wcset; - - pfile->narrow_cset_desc = init_iconv_desc (pfile, ncset, SOURCE_CHARSET); - pfile->wide_cset_desc = init_iconv_desc (pfile, wcset, SOURCE_CHARSET); -} - -void -_cpp_destroy_iconv (cpp_reader *pfile) -{ - if (HAVE_ICONV) - { - if (pfile->narrow_cset_desc.func == convert_using_iconv) - iconv_close (pfile->narrow_cset_desc.cd); - if (pfile->wide_cset_desc.func == convert_using_iconv) - iconv_close (pfile->wide_cset_desc.cd); - } -} - - -/* Utility routine that computes a mask of the form 0000...111... with - WIDTH 1-bits. */ -static inline size_t -width_to_mask (size_t width) -{ - width = MIN (width, BITS_PER_CPPCHAR_T); - if (width >= CHAR_BIT * sizeof (size_t)) - return ~(size_t) 0; - else - return ((size_t) 1 << width) - 1; -} - - - -/* Returns 1 if C is valid in an identifier, 2 if C is valid except at - the start of an identifier, and 0 if C is not valid in an - identifier. We assume C has already gone through the checks of - _cpp_valid_ucn. The algorithm is a simple binary search on the - table defined in cppucnid.h. */ - -static int -ucn_valid_in_identifier (cpp_reader *pfile, cppchar_t c) -{ - int mn, mx, md; - - mn = -1; - mx = ARRAY_SIZE (ucnranges); - while (mx - mn > 1) - { - md = (mn + mx) / 2; - if (c < ucnranges[md].lo) - mx = md; - else if (c > ucnranges[md].hi) - mn = md; - else - goto found; - } - return 0; - - found: - /* When -pedantic, we require the character to have been listed by - the standard for the current language. Otherwise, we accept the - union of the acceptable sets for C++98 and C99. */ - if (CPP_PEDANTIC (pfile) - && ((CPP_OPTION (pfile, c99) && !(ucnranges[md].flags & C99)) - || (CPP_OPTION (pfile, cplusplus) - && !(ucnranges[md].flags & CXX)))) - return 0; - - /* In C99, UCN digits may not begin identifiers. */ - if (CPP_OPTION (pfile, c99) && (ucnranges[md].flags & DIG)) - return 2; - - return 1; -} - -/* [lex.charset]: The character designated by the universal character - name \UNNNNNNNN is that character whose character short name in - ISO/IEC 10646 is NNNNNNNN; the character designated by the - universal character name \uNNNN is that character whose character - short name in ISO/IEC 10646 is 0000NNNN. If the hexadecimal value - for a universal character name is less than 0x20 or in the range - 0x7F-0x9F (inclusive), or if the universal character name - designates a character in the basic source character set, then the - program is ill-formed. - - *PSTR must be preceded by "\u" or "\U"; it is assumed that the - buffer end is delimited by a non-hex digit. Returns zero if UCNs - are not part of the relevant standard, or if the string beginning - at *PSTR doesn't syntactically match the form 'NNNN' or 'NNNNNNNN'. - - Otherwise the nonzero value of the UCN, whether valid or invalid, - is returned. Diagnostics are emitted for invalid values. PSTR - is updated to point one beyond the UCN, or to the syntactically - invalid character. - - IDENTIFIER_POS is 0 when not in an identifier, 1 for the start of - an identifier, or 2 otherwise. -*/ - -cppchar_t -_cpp_valid_ucn (cpp_reader *pfile, const uchar **pstr, - const uchar *limit, int identifier_pos) -{ - cppchar_t result, c; - unsigned int length; - const uchar *str = *pstr; - const uchar *base = str - 2; - - if (!CPP_OPTION (pfile, cplusplus) && !CPP_OPTION (pfile, c99)) - cpp_error (pfile, CPP_DL_WARNING, - "universal character names are only valid in C++ and C99"); - else if (CPP_WTRADITIONAL (pfile) && identifier_pos == 0) - cpp_error (pfile, CPP_DL_WARNING, - "the meaning of '\\%c' is different in traditional C", - (int) str[-1]); - - if (str[-1] == 'u') - length = 4; - else if (str[-1] == 'U') - length = 8; - else - abort(); - - result = 0; - do - { - c = *str; - if (!ISXDIGIT (c)) - break; - str++; - result = (result << 4) + hex_value (c); - } - while (--length && str < limit); - - *pstr = str; - if (length) - { - /* We'll error when we try it out as the start of an identifier. */ - cpp_error (pfile, CPP_DL_ERROR, - "incomplete universal character name %.*s", - (int) (str - base), base); - result = 1; - } - /* The standard permits $, @ and ` to be specified as UCNs. We use - hex escapes so that this also works with EBCDIC hosts. */ - else if ((result < 0xa0 - && (result != 0x24 && result != 0x40 && result != 0x60)) - || (result & 0x80000000) - || (result >= 0xD800 && result <= 0xDFFF)) - { - cpp_error (pfile, CPP_DL_ERROR, - "%.*s is not a valid universal character", - (int) (str - base), base); - result = 1; - } - else if (identifier_pos) - { - int validity = ucn_valid_in_identifier (pfile, result); - - if (validity == 0) - cpp_error (pfile, CPP_DL_ERROR, - "universal character %.*s is not valid in an identifier", - (int) (str - base), base); - else if (validity == 2 && identifier_pos == 1) - cpp_error (pfile, CPP_DL_ERROR, - "universal character %.*s is not valid at the start of an identifier", - (int) (str - base), base); - } - - if (result == 0) - result = 1; - - return result; -} - -/* Convert an UCN, pointed to by FROM, to UTF-8 encoding, then translate - it to the execution character set and write the result into TBUF. - An advanced pointer is returned. Issues all relevant diagnostics. */ - - -static const uchar * -convert_ucn (cpp_reader *pfile, const uchar *from, const uchar *limit, - struct _cpp_strbuf *tbuf, bool wide) -{ - cppchar_t ucn; - uchar buf[6]; - uchar *bufp = buf; - size_t bytesleft = 6; - int rval; - struct cset_converter cvt - = wide ? pfile->wide_cset_desc : pfile->narrow_cset_desc; - - from++; /* Skip u/U. */ - ucn = _cpp_valid_ucn (pfile, &from, limit, 0); - - rval = one_cppchar_to_utf8 (ucn, &bufp, &bytesleft); - if (rval) - { - errno = rval; - cpp_errno (pfile, CPP_DL_ERROR, - "converting UCN to source character set"); - } - else if (!APPLY_CONVERSION (cvt, buf, 6 - bytesleft, tbuf)) - cpp_errno (pfile, CPP_DL_ERROR, - "converting UCN to execution character set"); - - return from; -} - -static void -emit_numeric_escape (cpp_reader *pfile, cppchar_t n, - struct _cpp_strbuf *tbuf, bool wide) -{ - if (wide) - { - /* We have to render this into the target byte order, which may not - be our byte order. */ - bool bigend = CPP_OPTION (pfile, bytes_big_endian); - size_t width = CPP_OPTION (pfile, wchar_precision); - size_t cwidth = CPP_OPTION (pfile, char_precision); - size_t cmask = width_to_mask (cwidth); - size_t nbwc = width / cwidth; - size_t i; - size_t off = tbuf->len; - cppchar_t c; - - if (tbuf->len + nbwc > tbuf->asize) - { - tbuf->asize += OUTBUF_BLOCK_SIZE; - tbuf->text = xrealloc (tbuf->text, tbuf->asize); - } - - for (i = 0; i < nbwc; i++) - { - c = n & cmask; - n >>= cwidth; - tbuf->text[off + (bigend ? nbwc - i - 1 : i)] = c; - } - tbuf->len += nbwc; - } - else - { - if (tbuf->len + 1 > tbuf->asize) - { - tbuf->asize += OUTBUF_BLOCK_SIZE; - tbuf->text = xrealloc (tbuf->text, tbuf->asize); - } - tbuf->text[tbuf->len++] = n; - } -} - -/* Convert a hexadecimal escape, pointed to by FROM, to the execution - character set and write it into the string buffer TBUF. Returns an - advanced pointer, and issues diagnostics as necessary. - No character set translation occurs; this routine always produces the - execution-set character with numeric value equal to the given hex - number. You can, e.g. generate surrogate pairs this way. */ -static const uchar * -convert_hex (cpp_reader *pfile, const uchar *from, const uchar *limit, - struct _cpp_strbuf *tbuf, bool wide) -{ - cppchar_t c, n = 0, overflow = 0; - int digits_found = 0; - size_t width = (wide ? CPP_OPTION (pfile, wchar_precision) - : CPP_OPTION (pfile, char_precision)); - size_t mask = width_to_mask (width); - - if (CPP_WTRADITIONAL (pfile)) - cpp_error (pfile, CPP_DL_WARNING, - "the meaning of '\\x' is different in traditional C"); - - from++; /* Skip 'x'. */ - while (from < limit) - { - c = *from; - if (! hex_p (c)) - break; - from++; - overflow |= n ^ (n << 4 >> 4); - n = (n << 4) + hex_value (c); - digits_found = 1; - } - - if (!digits_found) - { - cpp_error (pfile, CPP_DL_ERROR, - "\\x used with no following hex digits"); - return from; - } - - if (overflow | (n != (n & mask))) - { - cpp_error (pfile, CPP_DL_PEDWARN, - "hex escape sequence out of range"); - n &= mask; - } - - emit_numeric_escape (pfile, n, tbuf, wide); - - return from; -} - -/* Convert an octal escape, pointed to by FROM, to the execution - character set and write it into the string buffer TBUF. Returns an - advanced pointer, and issues diagnostics as necessary. - No character set translation occurs; this routine always produces the - execution-set character with numeric value equal to the given octal - number. */ -static const uchar * -convert_oct (cpp_reader *pfile, const uchar *from, const uchar *limit, - struct _cpp_strbuf *tbuf, bool wide) -{ - size_t count = 0; - cppchar_t c, n = 0; - size_t width = (wide ? CPP_OPTION (pfile, wchar_precision) - : CPP_OPTION (pfile, char_precision)); - size_t mask = width_to_mask (width); - bool overflow = false; - - while (from < limit && count++ < 3) - { - c = *from; - if (c < '0' || c > '7') - break; - from++; - overflow |= n ^ (n << 3 >> 3); - n = (n << 3) + c - '0'; - } - - if (n != (n & mask)) - { - cpp_error (pfile, CPP_DL_PEDWARN, - "octal escape sequence out of range"); - n &= mask; - } - - emit_numeric_escape (pfile, n, tbuf, wide); - - return from; -} - -/* Convert an escape sequence (pointed to by FROM) to its value on - the target, and to the execution character set. Do not scan past - LIMIT. Write the converted value into TBUF. Returns an advanced - pointer. Handles all relevant diagnostics. */ -static const uchar * -convert_escape (cpp_reader *pfile, const uchar *from, const uchar *limit, - struct _cpp_strbuf *tbuf, bool wide) -{ - /* Values of \a \b \e \f \n \r \t \v respectively. */ -#if HOST_CHARSET == HOST_CHARSET_ASCII - static const uchar charconsts[] = { 7, 8, 27, 12, 10, 13, 9, 11 }; -#elif HOST_CHARSET == HOST_CHARSET_EBCDIC - static const uchar charconsts[] = { 47, 22, 39, 12, 21, 13, 5, 11 }; -#else -#error "unknown host character set" -#endif - - uchar c; - struct cset_converter cvt - = wide ? pfile->wide_cset_desc : pfile->narrow_cset_desc; - - c = *from; - switch (c) - { - /* UCNs, hex escapes, and octal escapes are processed separately. */ - case 'u': case 'U': - return convert_ucn (pfile, from, limit, tbuf, wide); - - case 'x': - return convert_hex (pfile, from, limit, tbuf, wide); - break; - - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - return convert_oct (pfile, from, limit, tbuf, wide); - - /* Various letter escapes. Get the appropriate host-charset - value into C. */ - case '\\': case '\'': case '"': case '?': break; - - case '(': case '{': case '[': case '%': - /* '\(', etc, can be used at the beginning of a line in a long - string split onto multiple lines with \-newline, to prevent - Emacs or other text editors from getting confused. '\%' can - be used to prevent SCCS from mangling printf format strings. */ - if (CPP_PEDANTIC (pfile)) - goto unknown; - break; - - case 'b': c = charconsts[1]; break; - case 'f': c = charconsts[3]; break; - case 'n': c = charconsts[4]; break; - case 'r': c = charconsts[5]; break; - case 't': c = charconsts[6]; break; - case 'v': c = charconsts[7]; break; - - case 'a': - if (CPP_WTRADITIONAL (pfile)) - cpp_error (pfile, CPP_DL_WARNING, - "the meaning of '\\a' is different in traditional C"); - c = charconsts[0]; - break; - - case 'e': case 'E': - if (CPP_PEDANTIC (pfile)) - cpp_error (pfile, CPP_DL_PEDWARN, - "non-ISO-standard escape sequence, '\\%c'", (int) c); - c = charconsts[2]; - break; - - default: - unknown: - if (ISGRAPH (c)) - cpp_error (pfile, CPP_DL_PEDWARN, - "unknown escape sequence '\\%c'", (int) c); - else - cpp_error (pfile, CPP_DL_PEDWARN, - "unknown escape sequence: '\\%03o'", (int) c); - } - - /* Now convert what we have to the execution character set. */ - if (!APPLY_CONVERSION (cvt, &c, 1, tbuf)) - cpp_errno (pfile, CPP_DL_ERROR, - "converting escape sequence to execution character set"); - - return from + 1; -} - -/* FROM is an array of cpp_string structures of length COUNT. These - are to be converted from the source to the execution character set, - escape sequences translated, and finally all are to be - concatenated. WIDE indicates whether or not to produce a wide - string. The result is written into TO. Returns true for success, - false for failure. */ -bool -cpp_interpret_string (cpp_reader *pfile, const cpp_string *from, size_t count, - cpp_string *to, bool wide) -{ - struct _cpp_strbuf tbuf; - const uchar *p, *base, *limit; - size_t i; - struct cset_converter cvt - = wide ? pfile->wide_cset_desc : pfile->narrow_cset_desc; - - tbuf.asize = MAX (OUTBUF_BLOCK_SIZE, from->len); - tbuf.text = xmalloc (tbuf.asize); - tbuf.len = 0; - - for (i = 0; i < count; i++) - { - p = from[i].text; - if (*p == 'L') p++; - p++; /* Skip leading quote. */ - limit = from[i].text + from[i].len - 1; /* Skip trailing quote. */ - - for (;;) - { - base = p; - while (p < limit && *p != '\\') - p++; - if (p > base) - { - /* We have a run of normal characters; these can be fed - directly to convert_cset. */ - if (!APPLY_CONVERSION (cvt, base, p - base, &tbuf)) - goto fail; - } - if (p == limit) - break; - - p = convert_escape (pfile, p + 1, limit, &tbuf, wide); - } - } - /* NUL-terminate the 'to' buffer and translate it to a cpp_string - structure. */ - emit_numeric_escape (pfile, 0, &tbuf, wide); - tbuf.text = xrealloc (tbuf.text, tbuf.len); - to->text = tbuf.text; - to->len = tbuf.len; - return true; - - fail: - cpp_errno (pfile, CPP_DL_ERROR, "converting to execution character set"); - free (tbuf.text); - return false; -} - -/* Subroutine of do_line and do_linemarker. Convert escape sequences - in a string, but do not perform character set conversion. */ -bool -_cpp_interpret_string_notranslate (cpp_reader *pfile, const cpp_string *in, - cpp_string *out) -{ - struct cset_converter save_narrow_cset_desc = pfile->narrow_cset_desc; - bool retval; - - pfile->narrow_cset_desc.func = convert_no_conversion; - pfile->narrow_cset_desc.cd = (iconv_t) -1; - - retval = cpp_interpret_string (pfile, in, 1, out, false); - - pfile->narrow_cset_desc = save_narrow_cset_desc; - return retval; -} - - -/* Subroutine of cpp_interpret_charconst which performs the conversion - to a number, for narrow strings. STR is the string structure returned - by cpp_interpret_string. PCHARS_SEEN and UNSIGNEDP are as for - cpp_interpret_charconst. */ -static cppchar_t -narrow_str_to_charconst (cpp_reader *pfile, cpp_string str, - unsigned int *pchars_seen, int *unsignedp) -{ - size_t width = CPP_OPTION (pfile, char_precision); - size_t max_chars = CPP_OPTION (pfile, int_precision) / width; - size_t mask = width_to_mask (width); - size_t i; - cppchar_t result, c; - bool unsigned_p; - - /* The value of a multi-character character constant, or a - single-character character constant whose representation in the - execution character set is more than one byte long, is - implementation defined. This implementation defines it to be the - number formed by interpreting the byte sequence in memory as a - big-endian binary number. If overflow occurs, the high bytes are - lost, and a warning is issued. - - We don't want to process the NUL terminator handed back by - cpp_interpret_string. */ - result = 0; - for (i = 0; i < str.len - 1; i++) - { - c = str.text[i] & mask; - if (width < BITS_PER_CPPCHAR_T) - result = (result << width) | c; - else - result = c; - } - - if (i > max_chars) - { - i = max_chars; - cpp_error (pfile, CPP_DL_WARNING, - "character constant too long for its type"); - } - else if (i > 1 && CPP_OPTION (pfile, warn_multichar)) - cpp_error (pfile, CPP_DL_WARNING, "multi-character character constant"); - - /* Multichar constants are of type int and therefore signed. */ - if (i > 1) - unsigned_p = 0; - else - unsigned_p = CPP_OPTION (pfile, unsigned_char); - - /* Truncate the constant to its natural width, and simultaneously - sign- or zero-extend to the full width of cppchar_t. - For single-character constants, the value is WIDTH bits wide. - For multi-character constants, the value is INT_PRECISION bits wide. */ - if (i > 1) - width = CPP_OPTION (pfile, int_precision); - if (width < BITS_PER_CPPCHAR_T) - { - mask = ((cppchar_t) 1 << width) - 1; - if (unsigned_p || !(result & (1 << (width - 1)))) - result &= mask; - else - result |= ~mask; - } - *pchars_seen = i; - *unsignedp = unsigned_p; - return result; -} - -/* Subroutine of cpp_interpret_charconst which performs the conversion - to a number, for wide strings. STR is the string structure returned - by cpp_interpret_string. PCHARS_SEEN and UNSIGNEDP are as for - cpp_interpret_charconst. */ -static cppchar_t -wide_str_to_charconst (cpp_reader *pfile, cpp_string str, - unsigned int *pchars_seen, int *unsignedp) -{ - bool bigend = CPP_OPTION (pfile, bytes_big_endian); - size_t width = CPP_OPTION (pfile, wchar_precision); - size_t cwidth = CPP_OPTION (pfile, char_precision); - size_t mask = width_to_mask (width); - size_t cmask = width_to_mask (cwidth); - size_t nbwc = width / cwidth; - size_t off, i; - cppchar_t result = 0, c; - - /* This is finicky because the string is in the target's byte order, - which may not be our byte order. Only the last character, ignoring - the NUL terminator, is relevant. */ - off = str.len - (nbwc * 2); - result = 0; - for (i = 0; i < nbwc; i++) - { - c = bigend ? str.text[off + i] : str.text[off + nbwc - i - 1]; - result = (result << cwidth) | (c & cmask); - } - - /* Wide character constants have type wchar_t, and a single - character exactly fills a wchar_t, so a multi-character wide - character constant is guaranteed to overflow. */ - if (off > 0) - cpp_error (pfile, CPP_DL_WARNING, - "character constant too long for its type"); - - /* Truncate the constant to its natural width, and simultaneously - sign- or zero-extend to the full width of cppchar_t. */ - if (width < BITS_PER_CPPCHAR_T) - { - if (CPP_OPTION (pfile, unsigned_wchar) || !(result & (1 << (width - 1)))) - result &= mask; - else - result |= ~mask; - } - - *unsignedp = CPP_OPTION (pfile, unsigned_wchar); - *pchars_seen = 1; - return result; -} - -/* Interpret a (possibly wide) character constant in TOKEN. - PCHARS_SEEN points to a variable that is filled in with the number - of characters seen, and UNSIGNEDP to a variable that indicates - whether the result has signed type. */ -cppchar_t -cpp_interpret_charconst (cpp_reader *pfile, const cpp_token *token, - unsigned int *pchars_seen, int *unsignedp) -{ - cpp_string str = { 0, 0 }; - bool wide = (token->type == CPP_WCHAR); - cppchar_t result; - - /* an empty constant will appear as L'' or '' */ - if (token->val.str.len == (size_t) (2 + wide)) - { - cpp_error (pfile, CPP_DL_ERROR, "empty character constant"); - return 0; - } - else if (!cpp_interpret_string (pfile, &token->val.str, 1, &str, wide)) - return 0; - - if (wide) - result = wide_str_to_charconst (pfile, str, pchars_seen, unsignedp); - else - result = narrow_str_to_charconst (pfile, str, pchars_seen, unsignedp); - - if (str.text != token->val.str.text) - free ((void *)str.text); - - return result; -} - -uchar * -_cpp_convert_input (cpp_reader *pfile, const char *input_charset, - uchar *input, size_t size, size_t len, off_t *st_size) -{ - struct cset_converter input_cset; - struct _cpp_strbuf to; - - input_cset = init_iconv_desc (pfile, SOURCE_CHARSET, input_charset); - if (input_cset.func == convert_no_conversion) - { - to.text = input; - to.asize = size; - to.len = len; - } - else - { - to.asize = MAX (65536, len); - to.text = xmalloc (to.asize); - to.len = 0; - - if (!APPLY_CONVERSION (input_cset, input, len, &to)) - cpp_error (pfile, CPP_DL_ERROR, - "failure to convert %s to %s", - CPP_OPTION (pfile, input_charset), SOURCE_CHARSET); - - free (input); - } - - /* Clean up the mess. */ - if (input_cset.func == convert_using_iconv) - iconv_close (input_cset.cd); - - /* Resize buffer if we allocated substantially too much, or if we - haven't enough space for the \n-terminator. */ - if (to.len + 4096 < to.asize || to.len >= to.asize) - to.text = xrealloc (to.text, to.len + 1); - - to.text[to.len] = '\n'; - *st_size = to.len; - return to.text; -} - -const char * -_cpp_default_encoding (void) -{ - const char *current_encoding = NULL; - -#if defined (HAVE_LOCALE_H) && defined (HAVE_LANGINFO_CODESET) - setlocale (LC_CTYPE, ""); - current_encoding = nl_langinfo (CODESET); -#endif - if (current_encoding == NULL || *current_encoding == '\0') - current_encoding = SOURCE_CHARSET; - - return current_encoding; -} diff --git a/support/cpp2/cppdefault.c b/support/cpp2/cppdefault.c index 60b21537..862ea12e 100644 --- a/support/cpp2/cppdefault.c +++ b/support/cpp2/cppdefault.c @@ -1,6 +1,6 @@ /* CPP Library. Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2003 Free Software Foundation, Inc. + 1999, 2000, 2003, 2004 Free Software Foundation, Inc. Contributed by Per Bothner, 1994-95. Based on CCCP program by Paul Rubin, June 1986 Adapted to ANSI C, Richard Stallman, Jan 1987 @@ -17,7 +17,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include "system.h" @@ -94,9 +94,3 @@ const size_t cpp_GCC_INCLUDE_DIR_len = sizeof GCC_INCLUDE_DIR - 8; const char cpp_GCC_INCLUDE_DIR[] = ""; const size_t cpp_GCC_INCLUDE_DIR_len = 0; #endif - -#ifdef TARGET_SYSTEM_ROOT -const char *cpp_SYSROOT = TARGET_SYSTEM_ROOT; -#else -const char *cpp_SYSROOT = ""; -#endif diff --git a/support/cpp2/cppdefault.h b/support/cpp2/cppdefault.h index 368e082c..f5b38884 100644 --- a/support/cpp2/cppdefault.h +++ b/support/cpp2/cppdefault.h @@ -1,6 +1,6 @@ /* CPP Library. Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2003 Free Software Foundation, Inc. + 1999, 2000, 2003, 2004 Free Software Foundation, Inc. Contributed by Per Bothner, 1994-95. Based on CCCP program by Paul Rubin, June 1986 Adapted to ANSI C, Richard Stallman, Jan 1987 @@ -17,7 +17,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef GCC_CPPDEFAULT_H #define GCC_CPPDEFAULT_H @@ -49,6 +49,4 @@ extern const struct default_include cpp_include_defaults[]; extern const char cpp_GCC_INCLUDE_DIR[]; extern const size_t cpp_GCC_INCLUDE_DIR_len; -extern const char *cpp_SYSROOT; - #endif /* ! GCC_CPPDEFAULT_H */ diff --git a/support/cpp2/cpperror.c b/support/cpp2/cpperror.c deleted file mode 100644 index 61763cc1..00000000 --- a/support/cpp2/cpperror.c +++ /dev/null @@ -1,177 +0,0 @@ -/* Default error handlers for CPP Library. - Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1998, 1999, 2000, - 2001, 2002 Free Software Foundation, Inc. - Written by Per Bothner, 1994. - Based on CCCP program by Paul Rubin, June 1986 - Adapted to ANSI C, Richard Stallman, Jan 1987 - -This program 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 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - In other words, you are welcome to use, share and improve this program. - You are forbidden to forbid anyone else to use, share and improve - what you give them. Help stamp out software-hoarding! */ - -#include "config.h" -#include "system.h" -#include "cpplib.h" -#include "cpphash.h" -#include "intl.h" - -static void print_location (cpp_reader *, fileline, unsigned int); - -/* Print the logical file location (LINE, COL) in preparation for a - diagnostic. Outputs the #include chain if it has changed. A line - of zero suppresses the include stack, and outputs the program name - instead. */ -static void -print_location (cpp_reader *pfile, fileline line, unsigned int col) -{ - if (line == 0) - fprintf (stderr, "%s: ", progname); - else - { - const struct line_map *map; - unsigned int lin; - - map = linemap_lookup (&pfile->line_maps, line); - linemap_print_containing_files (&pfile->line_maps, map); - - lin = SOURCE_LINE (map, line); - if (col == 0) - col = 1; - - if (lin == 0) - fprintf (stderr, "%s:", map->to_file); - else if (CPP_OPTION (pfile, show_column) == 0) - fprintf (stderr, "%s:%u:", map->to_file, lin); - else - fprintf (stderr, "%s:%u:%u:", map->to_file, lin, col); - - fputc (' ', stderr); - } -} - -/* Set up for a diagnostic: print the file and line, bump the error - counter, etc. LINE is the logical line number; zero means to print - at the location of the previously lexed token, which tends to be - the correct place by default. Returns 0 if the error has been - suppressed. */ -int -_cpp_begin_message (cpp_reader *pfile, int code, fileline line, - unsigned int column) -{ - int level = CPP_DL_EXTRACT (code); - - switch (level) - { - case CPP_DL_WARNING: - case CPP_DL_PEDWARN: - if (CPP_IN_SYSTEM_HEADER (pfile) - && ! CPP_OPTION (pfile, warn_system_headers)) - return 0; - /* Fall through. */ - - case CPP_DL_WARNING_SYSHDR: - if (CPP_OPTION (pfile, warnings_are_errors) - || (level == CPP_DL_PEDWARN && CPP_OPTION (pfile, pedantic_errors))) - { - if (CPP_OPTION (pfile, inhibit_errors)) - return 0; - level = CPP_DL_ERROR; - pfile->errors++; - } - else if (CPP_OPTION (pfile, inhibit_warnings)) - return 0; - break; - - case CPP_DL_ERROR: - if (CPP_OPTION (pfile, inhibit_errors)) - return 0; - /* ICEs cannot be inhibited. */ - case CPP_DL_ICE: - pfile->errors++; - break; - } - - print_location (pfile, line, column); - if (CPP_DL_WARNING_P (level)) - fputs (_("warning: "), stderr); - else if (level == CPP_DL_ICE) - fputs (_("internal error: "), stderr); - - return 1; -} - -/* Don't remove the blank before do, as otherwise the exgettext - script will mistake this as a function definition */ -#define v_message(msgid, ap) \ - do { vfprintf (stderr, _(msgid), ap); putc ('\n', stderr); } while (0) - -/* Exported interface. */ - -/* Print an error at the location of the previously lexed token. */ -void -cpp_error (cpp_reader * pfile, int level, const char *msgid, ...) -{ - fileline line; - unsigned int column; - va_list ap; - - va_start (ap, msgid); - - if (CPP_OPTION (pfile, traditional)) - { - if (pfile->state.in_directive) - line = pfile->directive_line; - else - line = pfile->line; - column = 0; - } - else - { - line = pfile->cur_token[-1].line; - column = pfile->cur_token[-1].col; - } - - if (_cpp_begin_message (pfile, level, line, column)) - v_message (msgid, ap); - - va_end (ap); -} - -/* Print an error at a specific location. */ -void -cpp_error_with_line (cpp_reader *pfile, int level, - fileline line, unsigned int column, - const char *msgid, ...) -{ - va_list ap; - - va_start (ap, msgid); - - if (_cpp_begin_message (pfile, level, line, column)) - v_message (msgid, ap); - - va_end (ap); -} - -void -cpp_errno (cpp_reader *pfile, int level, const char *msgid) -{ - if (msgid[0] == '\0') - msgid = _("stdout"); - - cpp_error (pfile, level, "%s: %s", msgid, xstrerror (errno)); -} diff --git a/support/cpp2/cppexp.c b/support/cpp2/cppexp.c deleted file mode 100644 index cb35b6c7..00000000 --- a/support/cpp2/cppexp.c +++ /dev/null @@ -1,1542 +0,0 @@ -/* Parse C expressions for cpplib. - Copyright (C) 1987, 1992, 1994, 1995, 1997, 1998, 1999, 2000, 2001, - 2002 Free Software Foundation. - Contributed by Per Bothner, 1994. - -This program 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 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -#include "config.h" -#include "system.h" -#include "cpplib.h" -#include "cpphash.h" - -#define PART_PRECISION (sizeof (cpp_num_part) * CHAR_BIT) -#define HALF_MASK (~(cpp_num_part) 0 >> (PART_PRECISION / 2)) -#define LOW_PART(num_part) (num_part & HALF_MASK) -#define HIGH_PART(num_part) (num_part >> (PART_PRECISION / 2)) - -struct op -{ - const cpp_token *token; /* The token forming op (for diagnostics). */ - cpp_num value; /* The value logically "right" of op. */ - enum cpp_ttype op; -}; - -/* Some simple utility routines on double integers. */ -#define num_zerop(num) ((num.low | num.high) == 0) -#define num_eq(num1, num2) (num1.low == num2.low && num1.high == num2.high) -static bool num_positive (cpp_num, size_t); -static bool num_greater_eq (cpp_num, cpp_num, size_t); -static cpp_num num_trim (cpp_num, size_t); -static cpp_num num_part_mul (cpp_num_part, cpp_num_part); - -static cpp_num num_unary_op (cpp_reader *, cpp_num, enum cpp_ttype); -static cpp_num num_binary_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype); -static cpp_num num_negate (cpp_num, size_t); -static cpp_num num_bitwise_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype); -static cpp_num num_inequality_op (cpp_reader *, cpp_num, cpp_num, - enum cpp_ttype); -static cpp_num num_equality_op (cpp_reader *, cpp_num, cpp_num, - enum cpp_ttype); -static cpp_num num_mul (cpp_reader *, cpp_num, cpp_num); -static cpp_num num_div_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype); -static cpp_num num_lshift (cpp_num, size_t, size_t); -static cpp_num num_rshift (cpp_num, size_t, size_t); - -static cpp_num append_digit (cpp_num, int, int, size_t); -static cpp_num parse_defined (cpp_reader *); -static cpp_num eval_token (cpp_reader *, const cpp_token *); -static struct op *reduce (cpp_reader *, struct op *, enum cpp_ttype); -static unsigned int interpret_float_suffix (const uchar *, size_t); -static unsigned int interpret_int_suffix (const uchar *, size_t); -static void check_promotion (cpp_reader *, const struct op *); - -/* Token type abuse to create unary plus and minus operators. */ -#define CPP_UPLUS (CPP_LAST_CPP_OP + 1) -#define CPP_UMINUS (CPP_LAST_CPP_OP + 2) - -/* With -O2, gcc appears to produce nice code, moving the error - message load and subsequent jump completely out of the main path. */ -#define SYNTAX_ERROR(msgid) \ - do { cpp_error (pfile, CPP_DL_ERROR, msgid); goto syntax_error; } while(0) -#define SYNTAX_ERROR2(msgid, arg) \ - do { cpp_error (pfile, CPP_DL_ERROR, msgid, arg); goto syntax_error; } \ - while(0) - -/* Subroutine of cpp_classify_number. S points to a float suffix of - length LEN, possibly zero. Returns 0 for an invalid suffix, or a - flag vector describing the suffix. */ -static unsigned int -interpret_float_suffix (const uchar *s, size_t len) -{ - size_t f = 0, l = 0, i = 0; - - while (len--) - switch (s[len]) - { - case 'f': case 'F': f++; break; - case 'l': case 'L': l++; break; - case 'i': case 'I': - case 'j': case 'J': i++; break; - default: - return 0; - } - - if (f + l > 1 || i > 1) - return 0; - - return ((i ? CPP_N_IMAGINARY : 0) - | (f ? CPP_N_SMALL : - l ? CPP_N_LARGE : CPP_N_MEDIUM)); -} - -/* Subroutine of cpp_classify_number. S points to an integer suffix - of length LEN, possibly zero. Returns 0 for an invalid suffix, or a - flag vector describing the suffix. */ -static unsigned int -interpret_int_suffix (const uchar *s, size_t len) -{ - size_t u, l, i; - - u = l = i = 0; - - while (len--) - switch (s[len]) - { - case 'u': case 'U': u++; break; - case 'i': case 'I': - case 'j': case 'J': i++; break; - case 'l': case 'L': l++; - /* If there are two Ls, they must be adjacent and the same case. */ - if (l == 2 && s[len] != s[len + 1]) - return 0; - break; - default: - return 0; - } - - if (l > 2 || u > 1 || i > 1) - return 0; - - return ((i ? CPP_N_IMAGINARY : 0) - | (u ? CPP_N_UNSIGNED : 0) - | ((l == 0) ? CPP_N_SMALL - : (l == 1) ? CPP_N_MEDIUM : CPP_N_LARGE)); -} - -/* Categorize numeric constants according to their field (integer, - floating point, or invalid), radix (decimal, octal, hexadecimal), - and type suffixes. */ -unsigned int -cpp_classify_number (cpp_reader *pfile, const cpp_token *token) -{ - const uchar *str = token->val.str.text; - const uchar *limit; - unsigned int max_digit, result, radix; - enum {NOT_FLOAT = 0, AFTER_POINT, AFTER_EXPON} float_flag; - - /* If the lexer has done its job, length one can only be a single - digit. Fast-path this very common case. */ - if (token->val.str.len == 1) - return CPP_N_INTEGER | CPP_N_SMALL | CPP_N_DECIMAL; - - limit = str + token->val.str.len; - float_flag = NOT_FLOAT; - max_digit = 0; - radix = 10; - - /* First, interpret the radix. */ - if (*str == '0') - { - radix = 8; - str++; - - /* Require at least one hex digit to classify it as hex. */ - if ((*str == 'x' || *str == 'X') - && (str[1] == '.' || ISXDIGIT (str[1]))) - { - radix = 16; - str++; - } - } - - /* Now scan for a well-formed integer or float. */ - for (;;) - { - unsigned int c = *str++; - - if (ISDIGIT (c) || (ISXDIGIT (c) && radix == 16)) - { - c = hex_value (c); - if (c > max_digit) - max_digit = c; - } - else if (c == '.') - { - if (float_flag == NOT_FLOAT) - float_flag = AFTER_POINT; - else - SYNTAX_ERROR ("too many decimal points in number"); - } - else if ((radix <= 10 && (c == 'e' || c == 'E')) - || (radix == 16 && (c == 'p' || c == 'P'))) - { - float_flag = AFTER_EXPON; - break; - } - else - { - /* Start of suffix. */ - str--; - break; - } - } - - if (float_flag != NOT_FLOAT && radix == 8) - radix = 10; - - if (max_digit >= radix) - SYNTAX_ERROR2 ("invalid digit \"%c\" in octal constant", '0' + max_digit); - - if (float_flag != NOT_FLOAT) - { - if (radix == 16 && CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, c99)) - cpp_error (pfile, CPP_DL_PEDWARN, - "use of C99 hexadecimal floating constant"); - - if (float_flag == AFTER_EXPON) - { - if (*str == '+' || *str == '-') - str++; - - /* Exponent is decimal, even if string is a hex float. */ - if (!ISDIGIT (*str)) - SYNTAX_ERROR ("exponent has no digits"); - - do - str++; - while (ISDIGIT (*str)); - } - else if (radix == 16) - SYNTAX_ERROR ("hexadecimal floating constants require an exponent"); - - result = interpret_float_suffix (str, limit - str); - if (result == 0) - { - cpp_error (pfile, CPP_DL_ERROR, - "invalid suffix \"%.*s\" on floating constant", - (int) (limit - str), str); - return CPP_N_INVALID; - } - - /* Traditional C didn't accept any floating suffixes. */ - if (limit != str - && CPP_WTRADITIONAL (pfile) - && ! cpp_sys_macro_p (pfile)) - cpp_error (pfile, CPP_DL_WARNING, - "traditional C rejects the \"%.*s\" suffix", - (int) (limit - str), str); - - result |= CPP_N_FLOATING; - } - else - { - result = interpret_int_suffix (str, limit - str); - if (result == 0) - { - cpp_error (pfile, CPP_DL_ERROR, - "invalid suffix \"%.*s\" on integer constant", - (int) (limit - str), str); - return CPP_N_INVALID; - } - - /* Traditional C only accepted the 'L' suffix. - Suppress warning about 'LL' with -Wno-long-long. */ - if (CPP_WTRADITIONAL (pfile) && ! cpp_sys_macro_p (pfile)) - { - int u_or_i = (result & (CPP_N_UNSIGNED|CPP_N_IMAGINARY)); - int large = (result & CPP_N_WIDTH) == CPP_N_LARGE; - - if (u_or_i || (large && CPP_OPTION (pfile, warn_long_long))) - cpp_error (pfile, CPP_DL_WARNING, - "traditional C rejects the \"%.*s\" suffix", - (int) (limit - str), str); - } - - if ((result & CPP_N_WIDTH) == CPP_N_LARGE - && ! CPP_OPTION (pfile, c99) - && CPP_OPTION (pfile, warn_long_long)) - cpp_error (pfile, CPP_DL_PEDWARN, - "use of C99 long long integer constant"); - - result |= CPP_N_INTEGER; - } - - if ((result & CPP_N_IMAGINARY) && CPP_PEDANTIC (pfile)) - cpp_error (pfile, CPP_DL_PEDWARN, - "imaginary constants are a GCC extension"); - - if (radix == 10) - result |= CPP_N_DECIMAL; - else if (radix == 16) - result |= CPP_N_HEX; - else - result |= CPP_N_OCTAL; - - return result; - - syntax_error: - return CPP_N_INVALID; -} - -/* cpp_interpret_integer converts an integer constant into a cpp_num, - of precision options->precision. - - We do not provide any interface for decimal->float conversion, - because the preprocessor doesn't need it and we don't want to - drag in GCC's floating point emulator. */ -cpp_num -cpp_interpret_integer (cpp_reader *pfile, const cpp_token *token, - unsigned int type) -{ - const uchar *p, *end; - cpp_num result; - - result.low = 0; - result.high = 0; - result.unsignedp = !!(type & CPP_N_UNSIGNED); - result.overflow = false; - - p = token->val.str.text; - end = p + token->val.str.len; - - /* Common case of a single digit. */ - if (token->val.str.len == 1) - result.low = p[0] - '0'; - else - { - cpp_num_part max; - size_t precision = CPP_OPTION (pfile, precision); - unsigned int base = 10, c = 0; - bool overflow = false; - - if ((type & CPP_N_RADIX) == CPP_N_OCTAL) - { - base = 8; - p++; - } - else if ((type & CPP_N_RADIX) == CPP_N_HEX) - { - base = 16; - p += 2; - } - - /* We can add a digit to numbers strictly less than this without - needing the precision and slowness of double integers. */ - max = ~(cpp_num_part) 0; - if (precision < PART_PRECISION) - max >>= PART_PRECISION - precision; - max = (max - base + 1) / base + 1; - - for (; p < end; p++) - { - c = *p; - - if (ISDIGIT (c) || (base == 16 && ISXDIGIT (c))) - c = hex_value (c); - else - break; - - /* Strict inequality for when max is set to zero. */ - if (result.low < max) - result.low = result.low * base + c; - else - { - result = append_digit (result, c, base, precision); - overflow |= result.overflow; - max = 0; - } - } - - if (overflow) - cpp_error (pfile, CPP_DL_PEDWARN, - "integer constant is too large for its type"); - /* If too big to be signed, consider it unsigned. Only warn for - decimal numbers. Traditional numbers were always signed (but - we still honor an explicit U suffix); but we only have - traditional semantics in directives. */ - else if (!result.unsignedp - && !(CPP_OPTION (pfile, traditional) - && pfile->state.in_directive) - && !num_positive (result, precision)) - { - if (base == 10) - cpp_error (pfile, CPP_DL_WARNING, - "integer constant is so large that it is unsigned"); - result.unsignedp = true; - } - } - - return result; -} - -/* Append DIGIT to NUM, a number of PRECISION bits being read in base BASE. */ -static cpp_num -append_digit (cpp_num num, int digit, int base, size_t precision) -{ - cpp_num result; - unsigned int shift = 3 + (base == 16); - bool overflow; - cpp_num_part add_high, add_low; - - /* Multiply by 8 or 16. Catching this overflow here means we don't - need to worry about add_high overflowing. */ - overflow = !!(num.high >> (PART_PRECISION - shift)); - result.high = num.high << shift; - result.low = num.low << shift; - result.high |= num.low >> (PART_PRECISION - shift); - - if (base == 10) - { - add_low = num.low << 1; - add_high = (num.high << 1) + (num.low >> (PART_PRECISION - 1)); - } - else - add_high = add_low = 0; - - if (add_low + digit < add_low) - add_high++; - add_low += digit; - - if (result.low + add_low < result.low) - add_high++; - if (result.high + add_high < result.high) - overflow = true; - - result.low += add_low; - result.high += add_high; - - /* The above code catches overflow of a cpp_num type. This catches - overflow of the (possibly shorter) target precision. */ - num.low = result.low; - num.high = result.high; - result = num_trim (result, precision); - if (!num_eq (result, num)) - overflow = true; - - result.unsignedp = num.unsignedp; - result.overflow = overflow; - return result; -} - -/* Handle meeting "defined" in a preprocessor expression. */ -static cpp_num -parse_defined (cpp_reader *pfile) -{ - cpp_num result; - int paren = 0; - cpp_hashnode *node = 0; - const cpp_token *token; - cpp_context *initial_context = pfile->context; - - /* Don't expand macros. */ - pfile->state.prevent_expansion++; - - token = cpp_get_token (pfile); - if (token->type == CPP_OPEN_PAREN) - { - paren = 1; - token = cpp_get_token (pfile); - } - - if (token->type == CPP_NAME) - { - node = token->val.node; - if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN) - { - cpp_error (pfile, CPP_DL_ERROR, "missing ')' after \"defined\""); - node = 0; - } - } - else - { - cpp_error (pfile, CPP_DL_ERROR, - "operator \"defined\" requires an identifier"); - if (token->flags & NAMED_OP) - { - cpp_token op; - - op.flags = 0; - op.type = token->type; - cpp_error (pfile, CPP_DL_ERROR, - "(\"%s\" is an alternative token for \"%s\" in C++)", - cpp_token_as_text (pfile, token), - cpp_token_as_text (pfile, &op)); - } - } - - if (node) - { - if (pfile->context != initial_context && CPP_PEDANTIC (pfile)) - cpp_error (pfile, CPP_DL_WARNING, - "this use of \"defined\" may not be portable"); - - _cpp_mark_macro_used (node); - - /* A possible controlling macro of the form #if !defined (). - _cpp_parse_expr checks there was no other junk on the line. */ - pfile->mi_ind_cmacro = node; - } - - pfile->state.prevent_expansion--; - - result.unsignedp = false; - result.high = 0; - result.overflow = false; - result.low = node && node->type == NT_MACRO; - return result; -} - -/* Convert a token into a CPP_NUMBER (an interpreted preprocessing - number or character constant, or the result of the "defined" or "#" - operators). */ -static cpp_num -eval_token (cpp_reader *pfile, const cpp_token *token) -{ - cpp_num result; - unsigned int temp; - int unsignedp = 0; - - switch (token->type) - { - case CPP_NUMBER: - temp = cpp_classify_number (pfile, token); - switch (temp & CPP_N_CATEGORY) - { - case CPP_N_FLOATING: - cpp_error (pfile, CPP_DL_ERROR, - "floating constant in preprocessor expression"); - break; - case CPP_N_INTEGER: - if (!(temp & CPP_N_IMAGINARY)) - return cpp_interpret_integer (pfile, token, temp); - cpp_error (pfile, CPP_DL_ERROR, - "imaginary number in preprocessor expression"); - break; - - case CPP_N_INVALID: - /* Error already issued. */ - break; - } - result.high = result.low = 0; - break; - - case CPP_WCHAR: - case CPP_CHAR: - { - cppchar_t cc = cpp_interpret_charconst (pfile, token, - &temp, &unsignedp); - - result.high = 0; - result.low = cc; - /* Sign-extend the result if necessary. */ - if (!unsignedp && (cppchar_signed_t) cc < 0) - { - if (PART_PRECISION > BITS_PER_CPPCHAR_T) - result.low |= ~(~(cpp_num_part) 0 - >> (PART_PRECISION - BITS_PER_CPPCHAR_T)); - result.high = ~(cpp_num_part) 0; - result = num_trim (result, CPP_OPTION (pfile, precision)); - } - } - break; - - case CPP_NAME: - if (token->val.node == pfile->spec_nodes.n_defined) - return parse_defined (pfile); - else if (CPP_OPTION (pfile, cplusplus) - && (token->val.node == pfile->spec_nodes.n_true - || token->val.node == pfile->spec_nodes.n_false)) - { - result.high = 0; - result.low = (token->val.node == pfile->spec_nodes.n_true); - } - else - { - result.high = 0; - result.low = 0; - if (CPP_OPTION (pfile, warn_undef) && !pfile->state.skip_eval) - cpp_error (pfile, CPP_DL_WARNING, "\"%s\" is not defined", - NODE_NAME (token->val.node)); - } - break; - - default: /* CPP_HASH */ - _cpp_test_assertion (pfile, &temp); - result.high = 0; - result.low = temp; - } - - result.unsignedp = !!unsignedp; - result.overflow = false; - return result; -} - -/* Operator precedence and flags table. - -After an operator is returned from the lexer, if it has priority less -than the operator on the top of the stack, we reduce the stack by one -operator and repeat the test. Since equal priorities do not reduce, -this is naturally right-associative. - -We handle left-associative operators by decrementing the priority of -just-lexed operators by one, but retaining the priority of operators -already on the stack. - -The remaining cases are '(' and ')'. We handle '(' by skipping the -reduction phase completely. ')' is given lower priority than -everything else, including '(', effectively forcing a reduction of the -parenthesized expression. If there is a matching '(', the routine -reduce() exits immediately. If the normal exit route sees a ')', then -there cannot have been a matching '(' and an error message is output. - -The parser assumes all shifted operators require a left operand unless -the flag NO_L_OPERAND is set. These semantics are automatic; any -extra semantics need to be handled with operator-specific code. */ - -/* Flags. If CHECK_PROMOTION, we warn if the effective sign of an - operand changes because of integer promotions. */ -#define NO_L_OPERAND (1 << 0) -#define LEFT_ASSOC (1 << 1) -#define CHECK_PROMOTION (1 << 2) - -/* Operator to priority map. Must be in the same order as the first - N entries of enum cpp_ttype. */ -static const struct operator -{ - uchar prio; - uchar flags; -} optab[] = -{ - /* EQ */ {0, 0}, /* Shouldn't happen. */ - /* NOT */ {16, NO_L_OPERAND}, - /* GREATER */ {12, LEFT_ASSOC | CHECK_PROMOTION}, - /* LESS */ {12, LEFT_ASSOC | CHECK_PROMOTION}, - /* PLUS */ {14, LEFT_ASSOC | CHECK_PROMOTION}, - /* MINUS */ {14, LEFT_ASSOC | CHECK_PROMOTION}, - /* MULT */ {15, LEFT_ASSOC | CHECK_PROMOTION}, - /* DIV */ {15, LEFT_ASSOC | CHECK_PROMOTION}, - /* MOD */ {15, LEFT_ASSOC | CHECK_PROMOTION}, - /* AND */ {9, LEFT_ASSOC | CHECK_PROMOTION}, - /* OR */ {7, LEFT_ASSOC | CHECK_PROMOTION}, - /* XOR */ {8, LEFT_ASSOC | CHECK_PROMOTION}, - /* RSHIFT */ {13, LEFT_ASSOC}, - /* LSHIFT */ {13, LEFT_ASSOC}, - - /* MIN */ {10, LEFT_ASSOC | CHECK_PROMOTION}, - /* MAX */ {10, LEFT_ASSOC | CHECK_PROMOTION}, - - /* COMPL */ {16, NO_L_OPERAND}, - /* AND_AND */ {6, LEFT_ASSOC}, - /* OR_OR */ {5, LEFT_ASSOC}, - /* QUERY */ {3, 0}, - /* COLON */ {4, LEFT_ASSOC | CHECK_PROMOTION}, - /* COMMA */ {2, LEFT_ASSOC}, - /* OPEN_PAREN */ {1, NO_L_OPERAND}, - /* CLOSE_PAREN */ {0, 0}, - /* EOF */ {0, 0}, - /* EQ_EQ */ {11, LEFT_ASSOC}, - /* NOT_EQ */ {11, LEFT_ASSOC}, - /* GREATER_EQ */ {12, LEFT_ASSOC | CHECK_PROMOTION}, - /* LESS_EQ */ {12, LEFT_ASSOC | CHECK_PROMOTION}, - /* UPLUS */ {16, NO_L_OPERAND}, - /* UMINUS */ {16, NO_L_OPERAND} -}; - -/* Parse and evaluate a C expression, reading from PFILE. - Returns the truth value of the expression. - - The implementation is an operator precedence parser, i.e. a - bottom-up parser, using a stack for not-yet-reduced tokens. - - The stack base is op_stack, and the current stack pointer is 'top'. - There is a stack element for each operator (only), and the most - recently pushed operator is 'top->op'. An operand (value) is - stored in the 'value' field of the stack element of the operator - that precedes it. */ -bool -_cpp_parse_expr (cpp_reader *pfile) -{ - struct op *top = pfile->op_stack; - unsigned int lex_count; - bool saw_leading_not, want_value = true; - - pfile->state.skip_eval = 0; - - /* Set up detection of #if ! defined(). */ - pfile->mi_ind_cmacro = 0; - saw_leading_not = false; - lex_count = 0; - - /* Lowest priority operator prevents further reductions. */ - top->op = CPP_EOF; - - for (;;) - { - struct op op; - - lex_count++; - op.token = cpp_get_token (pfile); - op.op = op.token->type; - - switch (op.op) - { - /* These tokens convert into values. */ - case CPP_NUMBER: - case CPP_CHAR: - case CPP_WCHAR: - case CPP_NAME: - case CPP_HASH: - if (!want_value) - SYNTAX_ERROR2 ("missing binary operator before token \"%s\"", - cpp_token_as_text (pfile, op.token)); - want_value = false; - top->value = eval_token (pfile, op.token); - continue; - - case CPP_NOT: - saw_leading_not = lex_count == 1; - break; - case CPP_PLUS: - if (want_value) - op.op = CPP_UPLUS; - break; - case CPP_MINUS: - if (want_value) - op.op = CPP_UMINUS; - break; - - default: - if ((int) op.op <= (int) CPP_EQ || (int) op.op >= (int) CPP_PLUS_EQ) - SYNTAX_ERROR2 ("token \"%s\" is not valid in preprocessor expressions", - cpp_token_as_text (pfile, op.token)); - break; - } - - /* Check we have a value or operator as appropriate. */ - if (optab[op.op].flags & NO_L_OPERAND) - { - if (!want_value) - SYNTAX_ERROR2 ("missing binary operator before token \"%s\"", - cpp_token_as_text (pfile, op.token)); - } - else if (want_value) - { - /* We want a number (or expression) and haven't got one. - Try to emit a specific diagnostic. */ - if (op.op == CPP_CLOSE_PAREN && top->op == CPP_OPEN_PAREN) - SYNTAX_ERROR ("missing expression between '(' and ')'"); - - if (op.op == CPP_EOF && top->op == CPP_EOF) - SYNTAX_ERROR ("#if with no expression"); - - if (top->op != CPP_EOF && top->op != CPP_OPEN_PAREN) - SYNTAX_ERROR2 ("operator '%s' has no right operand", - cpp_token_as_text (pfile, top->token)); - else if (op.op == CPP_CLOSE_PAREN || op.op == CPP_EOF) - /* Complain about missing paren during reduction. */; - else - SYNTAX_ERROR2 ("operator '%s' has no left operand", - cpp_token_as_text (pfile, op.token)); - } - - top = reduce (pfile, top, op.op); - if (!top) - goto syntax_error; - - if (op.op == CPP_EOF) - break; - - switch (op.op) - { - case CPP_CLOSE_PAREN: - continue; - case CPP_OR_OR: - if (!num_zerop (top->value)) - pfile->state.skip_eval++; - break; - case CPP_AND_AND: - case CPP_QUERY: - if (num_zerop (top->value)) - pfile->state.skip_eval++; - break; - case CPP_COLON: - if (top->op != CPP_QUERY) - SYNTAX_ERROR (" ':' without preceding '?'"); - if (!num_zerop (top[-1].value)) /* Was '?' condition true? */ - pfile->state.skip_eval++; - else - pfile->state.skip_eval--; - default: - break; - } - - want_value = true; - - /* Check for and handle stack overflow. */ - if (++top == pfile->op_limit) - top = _cpp_expand_op_stack (pfile); - - top->op = op.op; - top->token = op.token; - } - - /* The controlling macro expression is only valid if we called lex 3 - times: and . push_conditional () - checks that we are at top-of-file. */ - if (pfile->mi_ind_cmacro && !(saw_leading_not && lex_count == 3)) - pfile->mi_ind_cmacro = 0; - - if (top != pfile->op_stack) - { - cpp_error (pfile, CPP_DL_ICE, "unbalanced stack in #if"); - syntax_error: - return false; /* Return false on syntax error. */ - } - - return !num_zerop (top->value); -} - -/* Reduce the operator / value stack if possible, in preparation for - pushing operator OP. Returns NULL on error, otherwise the top of - the stack. */ -static struct op * -reduce (cpp_reader *pfile, struct op *top, enum cpp_ttype op) -{ - unsigned int prio; - - if (top->op <= CPP_EQ || top->op > CPP_LAST_CPP_OP + 2) - { - bad_op: - cpp_error (pfile, CPP_DL_ICE, "impossible operator '%u'", top->op); - return 0; - } - - if (op == CPP_OPEN_PAREN) - return top; - - /* Decrement the priority of left-associative operators to force a - reduction with operators of otherwise equal priority. */ - prio = optab[op].prio - ((optab[op].flags & LEFT_ASSOC) != 0); - while (prio < optab[top->op].prio) - { - if (CPP_OPTION (pfile, warn_num_sign_change) - && optab[top->op].flags & CHECK_PROMOTION) - check_promotion (pfile, top); - - switch (top->op) - { - case CPP_UPLUS: - case CPP_UMINUS: - case CPP_NOT: - case CPP_COMPL: - top[-1].value = num_unary_op (pfile, top->value, top->op); - break; - - case CPP_PLUS: - case CPP_MINUS: - case CPP_RSHIFT: - case CPP_LSHIFT: - case CPP_MIN: - case CPP_MAX: - case CPP_COMMA: - top[-1].value = num_binary_op (pfile, top[-1].value, - top->value, top->op); - break; - - case CPP_GREATER: - case CPP_LESS: - case CPP_GREATER_EQ: - case CPP_LESS_EQ: - top[-1].value - = num_inequality_op (pfile, top[-1].value, top->value, top->op); - break; - - case CPP_EQ_EQ: - case CPP_NOT_EQ: - top[-1].value - = num_equality_op (pfile, top[-1].value, top->value, top->op); - break; - - case CPP_AND: - case CPP_OR: - case CPP_XOR: - top[-1].value - = num_bitwise_op (pfile, top[-1].value, top->value, top->op); - break; - - case CPP_MULT: - top[-1].value = num_mul (pfile, top[-1].value, top->value); - break; - - case CPP_DIV: - case CPP_MOD: - top[-1].value = num_div_op (pfile, top[-1].value, - top->value, top->op); - break; - - case CPP_OR_OR: - top--; - if (!num_zerop (top->value)) - pfile->state.skip_eval--; - top->value.low = (!num_zerop (top->value) - || !num_zerop (top[1].value)); - top->value.high = 0; - top->value.unsignedp = false; - top->value.overflow = false; - continue; - - case CPP_AND_AND: - top--; - if (num_zerop (top->value)) - pfile->state.skip_eval--; - top->value.low = (!num_zerop (top->value) - && !num_zerop (top[1].value)); - top->value.high = 0; - top->value.unsignedp = false; - top->value.overflow = false; - continue; - - case CPP_OPEN_PAREN: - if (op != CPP_CLOSE_PAREN) - { - cpp_error (pfile, CPP_DL_ERROR, "missing ')' in expression"); - return 0; - } - top--; - top->value = top[1].value; - return top; - - case CPP_COLON: - top -= 2; - if (!num_zerop (top->value)) - { - pfile->state.skip_eval--; - top->value = top[1].value; - } - else - top->value = top[2].value; - top->value.unsignedp = (top[1].value.unsignedp - || top[2].value.unsignedp); - continue; - - case CPP_QUERY: - cpp_error (pfile, CPP_DL_ERROR, "'?' without following ':'"); - return 0; - - default: - goto bad_op; - } - - top--; - if (top->value.overflow && !pfile->state.skip_eval) - cpp_error (pfile, CPP_DL_PEDWARN, - "integer overflow in preprocessor expression"); - } - - if (op == CPP_CLOSE_PAREN) - { - cpp_error (pfile, CPP_DL_ERROR, "missing '(' in expression"); - return 0; - } - - return top; -} - -/* Returns the position of the old top of stack after expansion. */ -struct op * -_cpp_expand_op_stack (cpp_reader *pfile) -{ - size_t old_size = (size_t) (pfile->op_limit - pfile->op_stack); - size_t new_size = old_size * 2 + 20; - - pfile->op_stack = xrealloc (pfile->op_stack, new_size * sizeof (struct op)); - pfile->op_limit = pfile->op_stack + new_size; - - return pfile->op_stack + old_size; -} - -/* Emits a warning if the effective sign of either operand of OP - changes because of integer promotions. */ -static void -check_promotion (cpp_reader *pfile, const struct op *op) -{ - if (op->value.unsignedp == op[-1].value.unsignedp) - return; - - if (op->value.unsignedp) - { - if (!num_positive (op[-1].value, CPP_OPTION (pfile, precision))) - cpp_error (pfile, CPP_DL_WARNING, - "the left operand of \"%s\" changes sign when promoted", - cpp_token_as_text (pfile, op->token)); - } - else if (!num_positive (op->value, CPP_OPTION (pfile, precision))) - cpp_error (pfile, CPP_DL_WARNING, - "the right operand of \"%s\" changes sign when promoted", - cpp_token_as_text (pfile, op->token)); -} - -/* Clears the unused high order bits of the number pointed to by PNUM. */ -static cpp_num -num_trim (cpp_num num, size_t precision) -{ - if (precision > PART_PRECISION) - { - precision -= PART_PRECISION; - if (precision < PART_PRECISION) - num.high &= ((cpp_num_part) 1 << precision) - 1; - } - else - { - if (precision < PART_PRECISION) - num.low &= ((cpp_num_part) 1 << precision) - 1; - num.high = 0; - } - - return num; -} - -/* True iff A (presumed signed) >= 0. */ -static bool -num_positive (cpp_num num, size_t precision) -{ - if (precision > PART_PRECISION) - { - precision -= PART_PRECISION; - return (num.high & (cpp_num_part) 1 << (precision - 1)) == 0; - } - - return (num.low & (cpp_num_part) 1 << (precision - 1)) == 0; -} - -/* Sign extend a number, with PRECISION significant bits and all - others assumed clear, to fill out a cpp_num structure. */ -cpp_num -cpp_num_sign_extend (cpp_num num, size_t precision) -{ - if (!num.unsignedp) - { - if (precision > PART_PRECISION) - { - precision -= PART_PRECISION; - if (precision < PART_PRECISION - && (num.high & (cpp_num_part) 1 << (precision - 1))) - num.high |= ~(~(cpp_num_part) 0 >> (PART_PRECISION - precision)); - } - else if (num.low & (cpp_num_part) 1 << (precision - 1)) - { - if (precision < PART_PRECISION) - num.low |= ~(~(cpp_num_part) 0 >> (PART_PRECISION - precision)); - num.high = ~(cpp_num_part) 0; - } - } - - return num; -} - -/* Returns the negative of NUM. */ -static cpp_num -num_negate (cpp_num num, size_t precision) -{ - cpp_num copy; - - copy = num; - num.high = ~num.high; - num.low = ~num.low; - if (++num.low == 0) - num.high++; - num = num_trim (num, precision); - num.overflow = (!num.unsignedp && num_eq (num, copy) && !num_zerop (num)); - - return num; -} - -/* Returns true if A >= B. */ -static bool -num_greater_eq (cpp_num pa, cpp_num pb, size_t precision) -{ - bool unsignedp; - - unsignedp = pa.unsignedp || pb.unsignedp; - - if (!unsignedp) - { - /* Both numbers have signed type. If they are of different - sign, the answer is the sign of A. */ - unsignedp = num_positive (pa, precision); - - if (unsignedp != num_positive (pb, precision)) - return unsignedp; - - /* Otherwise we can do an unsigned comparison. */ - } - - return (pa.high > pb.high) || (pa.high == pb.high && pa.low >= pb.low); -} - -/* Returns LHS OP RHS, where OP is a bit-wise operation. */ -static cpp_num -num_bitwise_op (cpp_reader *pfile ATTRIBUTE_UNUSED, - cpp_num lhs, cpp_num rhs, enum cpp_ttype op) -{ - lhs.overflow = false; - lhs.unsignedp = lhs.unsignedp || rhs.unsignedp; - - /* As excess precision is zeroed, there is no need to num_trim () as - these operations cannot introduce a set bit there. */ - if (op == CPP_AND) - { - lhs.low &= rhs.low; - lhs.high &= rhs.high; - } - else if (op == CPP_OR) - { - lhs.low |= rhs.low; - lhs.high |= rhs.high; - } - else - { - lhs.low ^= rhs.low; - lhs.high ^= rhs.high; - } - - return lhs; -} - -/* Returns LHS OP RHS, where OP is an inequality. */ -static cpp_num -num_inequality_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, - enum cpp_ttype op) -{ - bool gte = num_greater_eq (lhs, rhs, CPP_OPTION (pfile, precision)); - - if (op == CPP_GREATER_EQ) - lhs.low = gte; - else if (op == CPP_LESS) - lhs.low = !gte; - else if (op == CPP_GREATER) - lhs.low = gte && !num_eq (lhs, rhs); - else /* CPP_LESS_EQ. */ - lhs.low = !gte || num_eq (lhs, rhs); - - lhs.high = 0; - lhs.overflow = false; - lhs.unsignedp = false; - return lhs; -} - -/* Returns LHS OP RHS, where OP is == or !=. */ -static cpp_num -num_equality_op (cpp_reader *pfile ATTRIBUTE_UNUSED, - cpp_num lhs, cpp_num rhs, enum cpp_ttype op) -{ - /* Work around a 3.0.4 bug; see PR 6950. */ - bool eq = num_eq (lhs, rhs); - if (op == CPP_NOT_EQ) - eq = !eq; - lhs.low = eq; - lhs.high = 0; - lhs.overflow = false; - lhs.unsignedp = false; - return lhs; -} - -/* Shift NUM, of width PRECISION, right by N bits. */ -static cpp_num -num_rshift (cpp_num num, size_t precision, size_t n) -{ - cpp_num_part sign_mask; - - if (num.unsignedp || num_positive (num, precision)) - sign_mask = 0; - else - sign_mask = ~(cpp_num_part) 0; - - if (n >= precision) - num.high = num.low = sign_mask; - else - { - /* Sign-extend. */ - if (precision < PART_PRECISION) - num.high = sign_mask, num.low |= sign_mask << precision; - else if (precision < 2 * PART_PRECISION) - num.high |= sign_mask << (precision - PART_PRECISION); - - if (n >= PART_PRECISION) - { - n -= PART_PRECISION; - num.low = num.high; - num.high = sign_mask; - } - - if (n) - { - num.low = (num.low >> n) | (num.high << (PART_PRECISION - n)); - num.high = (num.high >> n) | (sign_mask << (PART_PRECISION - n)); - } - } - - num = num_trim (num, precision); - num.overflow = false; - return num; -} - -/* Shift NUM, of width PRECISION, left by N bits. */ -static cpp_num -num_lshift (cpp_num num, size_t precision, size_t n) -{ - if (n >= precision) - { - num.overflow = !num.unsignedp && !num_zerop (num); - num.high = num.low = 0; - } - else - { - cpp_num orig, maybe_orig; - size_t m = n; - - orig = num; - if (m >= PART_PRECISION) - { - m -= PART_PRECISION; - num.high = num.low; - num.low = 0; - } - if (m) - { - num.high = (num.high << m) | (num.low >> (PART_PRECISION - m)); - num.low <<= m; - } - num = num_trim (num, precision); - - if (num.unsignedp) - num.overflow = false; - else - { - maybe_orig = num_rshift (num, precision, n); - num.overflow = !num_eq (orig, maybe_orig); - } - } - - return num; -} - -/* The four unary operators: +, -, ! and ~. */ -static cpp_num -num_unary_op (cpp_reader *pfile, cpp_num num, enum cpp_ttype op) -{ - switch (op) - { - case CPP_UPLUS: - if (CPP_WTRADITIONAL (pfile) && !pfile->state.skip_eval) - cpp_error (pfile, CPP_DL_WARNING, - "traditional C rejects the unary plus operator"); - num.overflow = false; - break; - - case CPP_UMINUS: - num = num_negate (num, CPP_OPTION (pfile, precision)); - break; - - case CPP_COMPL: - num.high = ~num.high; - num.low = ~num.low; - num = num_trim (num, CPP_OPTION (pfile, precision)); - num.overflow = false; - break; - - default: /* case CPP_NOT: */ - num.low = num_zerop (num); - num.high = 0; - num.overflow = false; - num.unsignedp = false; - break; - } - - return num; -} - -/* The various binary operators. */ -static cpp_num -num_binary_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op) -{ - cpp_num result; - size_t precision = CPP_OPTION (pfile, precision); - bool gte; - size_t n; - - switch (op) - { - /* Shifts. */ - case CPP_LSHIFT: - case CPP_RSHIFT: - if (!rhs.unsignedp && !num_positive (rhs, precision)) - { - /* A negative shift is a positive shift the other way. */ - if (op == CPP_LSHIFT) - op = CPP_RSHIFT; - else - op = CPP_LSHIFT; - rhs = num_negate (rhs, precision); - } - if (rhs.high) - n = ~0; /* Maximal. */ - else - n = rhs.low; - if (op == CPP_LSHIFT) - lhs = num_lshift (lhs, precision, n); - else - lhs = num_rshift (lhs, precision, n); - break; - - /* Min / Max. */ - case CPP_MIN: - case CPP_MAX: - { - bool unsignedp = lhs.unsignedp || rhs.unsignedp; - - gte = num_greater_eq (lhs, rhs, precision); - if (op == CPP_MIN) - gte = !gte; - if (!gte) - lhs = rhs; - lhs.unsignedp = unsignedp; - } - break; - - /* Arithmetic. */ - case CPP_MINUS: - rhs = num_negate (rhs, precision); - case CPP_PLUS: - result.low = lhs.low + rhs.low; - result.high = lhs.high + rhs.high; - if (result.low < lhs.low) - result.high++; - - result = num_trim (result, precision); - result.unsignedp = lhs.unsignedp || rhs.unsignedp; - if (result.unsignedp) - result.overflow = false; - else - { - bool lhsp = num_positive (lhs, precision); - result.overflow = (lhsp == num_positive (rhs, precision) - && lhsp != num_positive (result, precision)); - } - return result; - - /* Comma. */ - default: /* case CPP_COMMA: */ - if (CPP_PEDANTIC (pfile) && (!CPP_OPTION (pfile, c99) - || !pfile->state.skip_eval)) - cpp_error (pfile, CPP_DL_PEDWARN, - "comma operator in operand of #if"); - lhs = rhs; - break; - } - - return lhs; -} - -/* Multiplies two unsigned cpp_num_parts to give a cpp_num. This - cannot overflow. */ -static cpp_num -num_part_mul (cpp_num_part lhs, cpp_num_part rhs) -{ - cpp_num result; - cpp_num_part middle[2], temp; - - result.low = LOW_PART (lhs) * LOW_PART (rhs); - result.high = HIGH_PART (lhs) * HIGH_PART (rhs); - - middle[0] = LOW_PART (lhs) * HIGH_PART (rhs); - middle[1] = HIGH_PART (lhs) * LOW_PART (rhs); - - temp = result.low; - result.low += LOW_PART (middle[0]) << (PART_PRECISION / 2); - if (result.low < temp) - result.high++; - - temp = result.low; - result.low += LOW_PART (middle[1]) << (PART_PRECISION / 2); - if (result.low < temp) - result.high++; - - result.high += HIGH_PART (middle[0]); - result.high += HIGH_PART (middle[1]); - result.unsignedp = 1; - - return result; -} - -/* Multiply two preprocessing numbers. */ -static cpp_num -num_mul (cpp_reader *pfile, cpp_num lhs, cpp_num rhs) -{ - cpp_num result, temp; - bool unsignedp = lhs.unsignedp || rhs.unsignedp; - bool overflow, negate = false; - size_t precision = CPP_OPTION (pfile, precision); - - /* Prepare for unsigned multiplication. */ - if (!unsignedp) - { - if (!num_positive (lhs, precision)) - negate = !negate, lhs = num_negate (lhs, precision); - if (!num_positive (rhs, precision)) - negate = !negate, rhs = num_negate (rhs, precision); - } - - overflow = lhs.high && rhs.high; - result = num_part_mul (lhs.low, rhs.low); - - temp = num_part_mul (lhs.high, rhs.low); - result.high += temp.low; - if (temp.high) - overflow = true; - - temp = num_part_mul (lhs.low, rhs.high); - result.high += temp.low; - if (temp.high) - overflow = true; - - temp.low = result.low, temp.high = result.high; - result = num_trim (result, precision); - if (!num_eq (result, temp)) - overflow = true; - - if (negate) - result = num_negate (result, precision); - - if (unsignedp) - result.overflow = false; - else - result.overflow = overflow || (num_positive (result, precision) ^ !negate - && !num_zerop (result)); - result.unsignedp = unsignedp; - - return result; -} - -/* Divide two preprocessing numbers, returning the answer or the - remainder depending upon OP. */ -static cpp_num -num_div_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op) -{ - cpp_num result, sub; - cpp_num_part mask; - bool unsignedp = lhs.unsignedp || rhs.unsignedp; - bool negate = false, lhs_neg = false; - size_t i, precision = CPP_OPTION (pfile, precision); - - /* Prepare for unsigned division. */ - if (!unsignedp) - { - if (!num_positive (lhs, precision)) - negate = !negate, lhs_neg = true, lhs = num_negate (lhs, precision); - if (!num_positive (rhs, precision)) - negate = !negate, rhs = num_negate (rhs, precision); - } - - /* Find the high bit. */ - if (rhs.high) - { - i = precision - 1; - mask = (cpp_num_part) 1 << (i - PART_PRECISION); - for (; ; i--, mask >>= 1) - if (rhs.high & mask) - break; - } - else if (rhs.low) - { - if (precision > PART_PRECISION) - i = precision - PART_PRECISION - 1; - else - i = precision - 1; - mask = (cpp_num_part) 1 << i; - for (; ; i--, mask >>= 1) - if (rhs.low & mask) - break; - } - else - { - if (!pfile->state.skip_eval) - cpp_error (pfile, CPP_DL_ERROR, "division by zero in #if"); - return lhs; - } - - /* First nonzero bit of RHS is bit I. Do naive division by - shifting the RHS fully left, and subtracting from LHS if LHS is - at least as big, and then repeating but with one less shift. - This is not very efficient, but is easy to understand. */ - - rhs.unsignedp = true; - lhs.unsignedp = true; - i = precision - i - 1; - sub = num_lshift (rhs, precision, i); - - result.high = result.low = 0; - for (;;) - { - if (num_greater_eq (lhs, sub, precision)) - { - lhs = num_binary_op (pfile, lhs, sub, CPP_MINUS); - if (i >= PART_PRECISION) - result.high |= (cpp_num_part) 1 << (i - PART_PRECISION); - else - result.low |= (cpp_num_part) 1 << i; - } - if (i-- == 0) - break; - sub.low = (sub.low >> 1) | (sub.high << (PART_PRECISION - 1)); - sub.high >>= 1; - } - - /* We divide so that the remainder has the sign of the LHS. */ - if (op == CPP_DIV) - { - result.unsignedp = unsignedp; - if (unsignedp) - result.overflow = false; - else - { - if (negate) - result = num_negate (result, precision); - result.overflow = num_positive (result, precision) ^ !negate; - } - - return result; - } - - /* CPP_MOD. */ - lhs.unsignedp = unsignedp; - lhs.overflow = false; - if (lhs_neg) - lhs = num_negate (lhs, precision); - - return lhs; -} diff --git a/support/cpp2/cppfiles.c b/support/cpp2/cppfiles.c deleted file mode 100644 index e757a40d..00000000 --- a/support/cpp2/cppfiles.c +++ /dev/null @@ -1,1297 +0,0 @@ -/* Part of CPP library. File handling. - Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1998, - 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. - Written by Per Bothner, 1994. - Based on CCCP program by Paul Rubin, June 1986 - Adapted to ANSI C, Richard Stallman, Jan 1987 - Split out of cpplib.c, Zack Weinberg, Oct 1998 - Reimplemented, Neil Booth, Jul 2003 - -This program 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 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include "config.h" -#include "system.h" -#include "cpplib.h" -#include "cpphash.h" -#include "intl.h" -#include "mkdeps.h" -#include "hashtab.h" -#include - -/* Variable length record files on VMS will have a stat size that includes - record control characters that won't be included in the read size. */ -#ifdef VMS -# define FAB_C_VAR 2 /* variable length records (see Starlet fabdef.h) */ -# define STAT_SIZE_RELIABLE(ST) ((ST).st_fab_rfm != FAB_C_VAR) -#else -# define STAT_SIZE_RELIABLE(ST) true -#endif - -#ifdef __DJGPP__ - /* For DJGPP redirected input is opened in text mode. */ -# define set_stdin_to_binary_mode() \ - if (! isatty (0)) setmode (0, O_BINARY) -#else -# define set_stdin_to_binary_mode() /* Nothing */ -#endif - -#ifndef O_BINARY -# define O_BINARY 0 -#endif - -/* This structure represents a file searched for by CPP, whether it - exists or not. An instance may be pointed to by more than one - file_hash_entry; at present no reference count is kept. */ -struct _cpp_file -{ - /* Filename as given to #include or command line switch. */ - const char *name; - - /* The full path used to find the file. */ - const char *path; - - /* The full path of the pch file. */ - const char *pchname; - - /* The file's path with the basename stripped. NULL if it hasn't - been calculated yet. */ - const char *dir_name; - - /* Chain through all files. */ - struct _cpp_file *next_file; - - /* The contents of NAME after calling read_file(). */ - const uchar *buffer; - - /* The macro, if any, preventing re-inclusion. */ - const cpp_hashnode *cmacro; - - /* The directory in the search path where FILE was found. Used for - #include_next and determining whether a header is a system - header. */ - cpp_dir *dir; - - /* As filled in by stat(2) for the file. */ - struct stat st; - - /* File descriptor. Invalid if -1, otherwise open. */ - int fd; - - /* Zero if this file was successfully opened and stat()-ed, - otherwise errno obtained from failure. */ - int err_no; - - /* Number of times the file has been stacked for preprocessing. */ - unsigned short stack_count; - - /* If opened with #import or contains #pragma once. */ - bool once_only; - - /* If read() failed before. */ - bool dont_read; - - /* If this file is the main file. */ - bool main_file; - - /* If BUFFER above contains the true contents of the file. */ - bool buffer_valid; - - /* 0: file not known to be a PCH. - 1: file is a PCH (on return from find_include_file). - 2: file is not and never will be a valid precompiled header. - 3: file is always a valid precompiled header. */ - uchar pch; -}; - -/* A singly-linked list for all searches for a given file name, with - its head pointed to by a slot in FILE_HASH. The file name is what - appeared between the quotes in a #include directive; it can be - determined implicitly from the hash table location or explicitly - from FILE->name. - - FILE is a structure containing details about the file that was - found with that search, or details of how the search failed. - - START_DIR is the starting location of the search in the include - chain. The current directories for "" includes are also hashed in - the hash table and therefore unique. Files that are looked up - without using a search path, such as absolute filenames and file - names from the command line share a special starting directory so - they don't cause cache hits with normal include-chain lookups. - - If START_DIR is NULL then the entry is for a directory, not a file, - and the directory is in DIR. Since the starting point in a file - lookup chain is never NULL, this means that simple pointer - comparisons against START_DIR can be made to determine cache hits - in file lookups. - - If a cache lookup fails because of e.g. an extra "./" in the path, - then nothing will break. It is just less efficient as CPP will - have to do more work re-preprocessing the file, and/or comparing - its contents against earlier once-only files. -*/ -struct file_hash_entry -{ - struct file_hash_entry *next; - cpp_dir *start_dir; - union - { - _cpp_file *file; - cpp_dir *dir; - } u; -}; - -static bool open_file (_cpp_file *file); -static bool pch_open_file (cpp_reader *pfile, _cpp_file *file, - bool *invalid_pch); -static bool find_file_in_dir (cpp_reader *pfile, _cpp_file *file, - bool *invalid_pch); -static bool read_file_guts (cpp_reader *pfile, _cpp_file *file); -static bool read_file (cpp_reader *pfile, _cpp_file *file); -static bool should_stack_file (cpp_reader *, _cpp_file *file, bool import); -static struct cpp_dir *search_path_head (cpp_reader *, const char *fname, - int angle_brackets, enum include_type); -static const char *dir_name_of_file (_cpp_file *file); -static void open_file_failed (cpp_reader *pfile, _cpp_file *file, int); -static struct file_hash_entry *search_cache (struct file_hash_entry *head, - const cpp_dir *start_dir); -static _cpp_file *make_cpp_file (cpp_reader *, cpp_dir *, const char *fname); -static void destroy_cpp_file (_cpp_file *); -static cpp_dir *make_cpp_dir (cpp_reader *, const char *dir_name, int sysp); -static void allocate_file_hash_entries (cpp_reader *pfile); -static struct file_hash_entry *new_file_hash_entry (cpp_reader *pfile); -static int report_missing_guard (void **slot, void *b); -static hashval_t file_hash_hash (const void *p); -static int file_hash_eq (const void *p, const void *q); -static char *read_filename_string (int ch, FILE *f); -static void read_name_map (cpp_dir *dir); -static char *remap_filename (cpp_reader *pfile, _cpp_file *file); -static char *append_file_to_dir (const char *fname, cpp_dir *dir); -static bool validate_pch (cpp_reader *, _cpp_file *file, const char *pchname); -static bool include_pch_p (_cpp_file *file); - -/* Given a filename in FILE->PATH, with the empty string interpreted - as , open it. - - On success FILE contains an open file descriptor and stat - information for the file. On failure the file descriptor is -1 and - the appropriate errno is also stored in FILE. Returns TRUE iff - successful. - - We used to open files in nonblocking mode, but that caused more - problems than it solved. Do take care not to acquire a controlling - terminal by mistake (this can't happen on sane systems, but - paranoia is a virtue). - - Use the three-argument form of open even though we aren't - specifying O_CREAT, to defend against broken system headers. - - O_BINARY tells some runtime libraries (notably DJGPP) not to do - newline translation; we can handle DOS line breaks just fine - ourselves. */ -static bool -open_file (_cpp_file *file) -{ - if (file->path[0] == '\0') - { - file->fd = 0; - set_stdin_to_binary_mode (); - } - else - file->fd = open (file->path, O_RDONLY | O_NOCTTY | O_BINARY, 0666); - - if (file->fd != -1) - { - if (fstat (file->fd, &file->st) == 0) - { - if (!S_ISDIR (file->st.st_mode)) - { - file->err_no = 0; - return true; - } - - /* Ignore a directory and continue the search. The file we're - looking for may be elsewhere in the search path. */ - errno = ENOENT; - } - - close (file->fd); - file->fd = -1; - } - else if (errno == ENOTDIR) - errno = ENOENT; - - file->err_no = errno; - - return false; -} - -/* Temporary PCH intercept of opening a file. Try to find a PCH file - based on FILE->name and FILE->dir, and test those found for - validity using PFILE->cb.valid_pch. Return true iff a valid file is - found. Set *INVALID_PCH if a PCH file is found but wasn't valid. */ - -static bool -pch_open_file (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch) -{ - static const char extension[] = ".gch"; - const char *path = file->path; - size_t len, flen; - char *pchname; - struct stat st; - bool valid = false; - - /* No PCH on or if not requested. */ - if (file->name[0] == '\0' || !pfile->cb.valid_pch) - return false; - - flen = strlen (path); - len = flen + sizeof (extension); - pchname = xmalloc (len); - memcpy (pchname, path, flen); - memcpy (pchname + flen, extension, sizeof (extension)); - - if (stat (pchname, &st) == 0) - { - DIR *pchdir; - struct dirent *d; - size_t dlen, plen = len; - - if (!S_ISDIR (st.st_mode)) - valid = validate_pch (pfile, file, pchname); - else if ((pchdir = opendir (pchname)) != NULL) - { - pchname[plen - 1] = '/'; - while ((d = readdir (pchdir)) != NULL) - { - dlen = strlen (d->d_name) + 1; - if ((strcmp (d->d_name, ".") == 0) - || (strcmp (d->d_name, "..") == 0)) - continue; - if (dlen + plen > len) - { - len += dlen + 64; - pchname = xrealloc (pchname, len); - } - memcpy (pchname + plen, d->d_name, dlen); - valid = validate_pch (pfile, file, pchname); - if (valid) - break; - } - closedir (pchdir); - } - if (valid) - file->pch = true; - else - *invalid_pch = true; - } - - if (valid) - file->pchname = pchname; - else - free (pchname); - - return valid; -} - -/* Try to open the path FILE->name appended to FILE->dir. This is - where remap and PCH intercept the file lookup process. Return true - if the file was found, whether or not the open was successful. - Set *INVALID_PCH to true if a PCH file is found but wasn't valid. */ - -static bool -find_file_in_dir (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch) -{ - char *path; - - if (CPP_OPTION (pfile, remap) && (path = remap_filename (pfile, file))) - ; - else - path = append_file_to_dir (file->name, file->dir); - - file->path = path; - if (pch_open_file (pfile, file, invalid_pch)) - return true; - - if (open_file (file)) - return true; - - if (file->err_no != ENOENT) - { - open_file_failed (pfile, file, 0); - return true; - } - - free (path); - file->path = file->name; - return false; -} - -bool -_cpp_find_failed (_cpp_file *file) -{ - return file->err_no != 0; -} - -/* Given a filename FNAME search for such a file in the include path - starting from START_DIR. If FNAME is the empty string it is - interpreted as STDIN if START_DIR is PFILE->no_seach_path. - - If the file is not found in the file cache fall back to the O/S and - add the result to our cache. - - If the file was not found in the filesystem, or there was an error - opening it, then ERR_NO is nonzero and FD is -1. If the file was - found, then ERR_NO is zero and FD could be -1 or an open file - descriptor. FD can be -1 if the file was found in the cache and - had previously been closed. To open it again pass the return value - to open_file(). -*/ -_cpp_file * -_cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, bool fake, int angle_brackets) -{ - struct file_hash_entry *entry, **hash_slot; - _cpp_file *file; - bool invalid_pch = false; - - /* Ensure we get no confusion between cached files and directories. */ - if (start_dir == NULL) - cpp_error (pfile, CPP_DL_ICE, "NULL directory in find_file"); - - hash_slot = (struct file_hash_entry **) - htab_find_slot_with_hash (pfile->file_hash, fname, - htab_hash_string (fname), - INSERT); - - /* First check the cache before we resort to memory allocation. */ - entry = search_cache (*hash_slot, start_dir); - if (entry) - return entry->u.file; - - file = make_cpp_file (pfile, start_dir, fname); - - /* Try each path in the include chain. */ - for (; !fake ;) - { - if (find_file_in_dir (pfile, file, &invalid_pch)) - break; - - file->dir = file->dir->next; - if (file->dir == NULL) - { - open_file_failed (pfile, file, angle_brackets); - if (invalid_pch) - { - cpp_error (pfile, CPP_DL_ERROR, - "one or more PCH files were found, but they were invalid"); - if (!cpp_get_options (pfile)->warn_invalid_pch) - cpp_error (pfile, CPP_DL_ERROR, - "use -Winvalid-pch for more information"); - } - break; - } - - /* Only check the cache for the starting location (done above) - and the quote and bracket chain heads because there are no - other possible starting points for searches. */ - if (file->dir != pfile->bracket_include - && file->dir != pfile->quote_include) - continue; - - entry = search_cache (*hash_slot, file->dir); - if (entry) - break; - } - - if (entry) - { - /* Cache for START_DIR too, sharing the _cpp_file structure. */ - free ((char *) file->name); - free (file); - file = entry->u.file; - } - else - { - /* This is a new file; put it in the list. */ - file->next_file = pfile->all_files; - pfile->all_files = file; - } - - /* Store this new result in the hash table. */ - entry = new_file_hash_entry (pfile); - entry->next = *hash_slot; - entry->start_dir = start_dir; - entry->u.file = file; - *hash_slot = entry; - - return file; -} - -/* Read a file into FILE->buffer, returning true on success. - - If FILE->fd is something weird, like a block device, we don't want - to read it at all. Don't even try to figure out what something is, - except for plain files and block devices, since there is no - reliable portable way of doing this. - - FIXME: Flush file cache and try again if we run out of memory. */ -static bool -read_file_guts (cpp_reader *pfile, _cpp_file *file) -{ - ssize_t size, total, count; - uchar *buf; - bool regular; - - if (S_ISBLK (file->st.st_mode)) - { - cpp_error (pfile, CPP_DL_ERROR, "%s is a block device", file->path); - return false; - } - - regular = S_ISREG (file->st.st_mode); - if (regular) - { - /* off_t might have a wider range than ssize_t - in other words, - the max size of a file might be bigger than the address - space. We can't handle a file that large. (Anyone with - a single source file bigger than 2GB needs to rethink - their coding style.) Some systems (e.g. AIX 4.1) define - SSIZE_MAX to be much smaller than the actual range of the - type. Use INTTYPE_MAXIMUM unconditionally to ensure this - does not bite us. */ -#ifndef __BORLANDC__ - if (file->st.st_size > INTTYPE_MAXIMUM (ssize_t)) - { - cpp_error (pfile, CPP_DL_ERROR, "%s is too large", file->path); - return false; - } -#endif - - size = file->st.st_size; - } - else - /* 8 kilobytes is a sensible starting size. It ought to be bigger - than the kernel pipe buffer, and it's definitely bigger than - the majority of C source files. */ - size = 8 * 1024; - - buf = xmalloc (size + 1); - total = 0; - while ((count = read (file->fd, buf + total, size - total)) > 0) - { - total += count; - - if (total == size) - { - if (regular) - break; - size *= 2; - buf = xrealloc (buf, size + 1); - } - } - - if (count < 0) - { - cpp_errno (pfile, CPP_DL_ERROR, file->path); - return false; - } - -#ifndef __BORLANDC__ - /* For some reason, even though we opened with O_BINARY, - * Borland C++ seems to insist on doing CR/LF -> LF - * translations for us, which results in the file appearing - * shorter than stat told us it should be. - * - * This sucks, but don't bother throwing a warning. - */ - if (regular && total != size && STAT_SIZE_RELIABLE (file->st)) - cpp_error (pfile, CPP_DL_WARNING, - "%s is shorter than expected", file->path); -#endif - - file->buffer = _cpp_convert_input (pfile, CPP_OPTION (pfile, input_charset), - buf, size, total, &file->st.st_size); - file->buffer_valid = true; - - return true; -} - -/* Convenience wrapper around read_file_guts that opens the file if - necessary and closes the file descriptor after reading. FILE must - have been passed through find_file() at some stage. */ -static bool -read_file (cpp_reader *pfile, _cpp_file *file) -{ - /* If we already have its contents in memory, succeed immediately. */ - if (file->buffer_valid) - return true; - - /* If an earlier read failed for some reason don't try again. */ - if (file->dont_read || file->err_no) - return false; - - if (file->fd == -1 && !open_file (file)) - { - open_file_failed (pfile, file, 0); - return false; - } - - file->dont_read = !read_file_guts (pfile, file); - close (file->fd); - file->fd = -1; - - return !file->dont_read; -} - -/* Returns TRUE if FILE's contents have been successfully placed in - FILE->buffer and the file should be stacked, otherwise false. */ -static bool -should_stack_file (cpp_reader *pfile, _cpp_file *file, bool import) -{ - _cpp_file *f; - - /* Skip once-only files. */ - if (file->once_only) - return false; - - /* We must mark the file once-only if #import now, before header - guard checks. Otherwise, undefining the header guard might - cause the file to be re-stacked. */ - if (import) - { - _cpp_mark_file_once_only (pfile, file); - - /* Don't stack files that have been stacked before. */ - if (file->stack_count) - return false; - } - - /* Skip if the file had a header guard and the macro is defined. - PCH relies on this appearing before the PCH handler below. */ - if (file->cmacro && file->cmacro->type == NT_MACRO) - return false; - - /* Handle PCH files immediately; don't stack them. */ - if (include_pch_p (file)) - { - pfile->cb.read_pch (pfile, file->path, file->fd, file->pchname); - close (file->fd); - file->fd = -1; - return false; - } - - if (!read_file (pfile, file)) - return false; - - /* Now we've read the file's contents, we can stack it if there - are no once-only files. */ - if (!pfile->seen_once_only) - return true; - - /* We may have read the file under a different name. Look - for likely candidates and compare file contents to be sure. */ - for (f = pfile->all_files; f; f = f->next_file) - { - if (f == file) - continue; - - if ((import || f->once_only) - && f->err_no == 0 - && f->st.st_mtime == file->st.st_mtime - && f->st.st_size == file->st.st_size) - { - _cpp_file *ref_file; - bool same_file_p = false; - - if (f->buffer && !f->buffer_valid) - { - /* We already have a buffer but it is not valid, because - the file is still stacked. Make a new one. */ - ref_file = make_cpp_file (pfile, f->dir, f->name); - ref_file->path = f->path; - } - else - /* The file is not stacked anymore. We can reuse it. */ - ref_file = f; - - same_file_p = read_file (pfile, ref_file) - /* Size might have changed in read_file(). */ - && ref_file->st.st_size == file->st.st_size - && !memcmp (ref_file->buffer, - file->buffer, - file->st.st_size); - - if (f->buffer && !f->buffer_valid) - { - ref_file->path = 0; - destroy_cpp_file (ref_file); - } - - if (same_file_p) - break; - } - } - - return f == NULL; -} - -/* Place the file referenced by FILE into a new buffer on the buffer - stack if possible. IMPORT is true if this stacking attempt is - because of a #import directive. Returns true if a buffer is - stacked. */ -bool -_cpp_stack_file (cpp_reader *pfile, _cpp_file *file, bool import) -{ - cpp_buffer *buffer; - int sysp; - - if (!should_stack_file (pfile, file, import)) - return false; - - sysp = MAX ((pfile->map ? pfile->map->sysp : 0), - (file->dir ? file->dir->sysp : 0)); - - /* Add the file to the dependencies on its first inclusion. */ - if (CPP_OPTION (pfile, deps.style) > !!sysp && !file->stack_count) - { - if (!file->main_file || !CPP_OPTION (pfile, deps.ignore_main_file)) - deps_add_dep (pfile->deps, file->path); - } - - /* Clear buffer_valid since _cpp_clean_line messes it up. */ - file->buffer_valid = false; - file->stack_count++; - - /* Stack the buffer. */ - buffer = cpp_push_buffer (pfile, file->buffer, file->st.st_size, - CPP_OPTION (pfile, preprocessed)); - buffer->file = file; - - /* Initialize controlling macro state. */ - pfile->mi_valid = true; - pfile->mi_cmacro = 0; - - /* Generate the call back. */ - _cpp_do_file_change (pfile, LC_ENTER, file->path, 1, sysp); - - return true; -} - -/* Mark FILE to be included once only. */ -void -_cpp_mark_file_once_only (cpp_reader *pfile, _cpp_file *file) -{ - pfile->seen_once_only = true; - file->once_only = true; -} - -/* Return the directory from which searching for FNAME should start, - considering the directive TYPE and ANGLE_BRACKETS. If there is - nothing left in the path, returns NULL. */ -static struct cpp_dir * -search_path_head (cpp_reader *pfile, const char *fname, int angle_brackets, - enum include_type type) -{ - cpp_dir *dir; - _cpp_file *file; - - if (IS_ABSOLUTE_PATH (fname)) - return &pfile->no_search_path; - - /* pfile->buffer is NULL when processing an -include command-line flag. */ - file = pfile->buffer == NULL ? pfile->main_file : pfile->buffer->file; - - /* For #include_next, skip in the search path past the dir in which - the current file was found, but if it was found via an absolute - path use the normal search logic. */ - if (type == IT_INCLUDE_NEXT && file->dir) - dir = file->dir->next; - else if (angle_brackets) - dir = pfile->bracket_include; - else if (type == IT_CMDLINE) - /* -include and -imacros use the #include "" chain with the - preprocessor's cwd prepended. */ - return make_cpp_dir (pfile, "./", false); - else if (pfile->quote_ignores_source_dir) - dir = pfile->quote_include; - else - return make_cpp_dir (pfile, dir_name_of_file (file), pfile->map->sysp); - - if (dir == NULL) - cpp_error (pfile, CPP_DL_ERROR, - "no include path in which to search for %s", fname); - - return dir; -} - -/* Strip the basename from the file's path. It ends with a slash if - of nonzero length. Note that this procedure also works for - , which is represented by the empty string. */ -static const char * -dir_name_of_file (_cpp_file *file) -{ - if (!file->dir_name) - { - size_t len = lbasename (file->path) - file->path; - char *dir_name = xmalloc (len + 1); - - memcpy (dir_name, file->path, len); - dir_name[len] = '\0'; - file->dir_name = dir_name; - } - - return file->dir_name; -} - -/* Handles #include-family directives (distinguished by TYPE), - including HEADER, and the command line -imacros and -include. - Returns true if a buffer was stacked. */ -bool -_cpp_stack_include (cpp_reader *pfile, const char *fname, int angle_brackets, - enum include_type type) -{ - struct cpp_dir *dir; - - dir = search_path_head (pfile, fname, angle_brackets, type); - if (!dir) - return false; - - return _cpp_stack_file (pfile, _cpp_find_file (pfile, fname, dir, false, - angle_brackets), - type == IT_IMPORT); -} - -/* Could not open FILE. The complication is dependency output. */ -static void -open_file_failed (cpp_reader *pfile, _cpp_file *file, int angle_brackets) -{ - int sysp = pfile->map ? pfile->map->sysp: 0; - bool print_dep = CPP_OPTION (pfile, deps.style) > (angle_brackets || !!sysp); - - errno = file->err_no; - if (print_dep && CPP_OPTION (pfile, deps.missing_files) && errno == ENOENT) - deps_add_dep (pfile->deps, file->name); - else - { - /* If we are outputting dependencies but not for this file then - don't error because we can still produce correct output. */ - if (CPP_OPTION (pfile, deps.style) && ! print_dep) - cpp_errno (pfile, CPP_DL_WARNING, file->path); - else - cpp_errno (pfile, CPP_DL_ERROR, file->path); - } -} - -/* Search in the chain beginning at HEAD for a file whose search path - started at START_DIR != NULL. */ -static struct file_hash_entry * -search_cache (struct file_hash_entry *head, const cpp_dir *start_dir) -{ - while (head && head->start_dir != start_dir) - head = head->next; - - return head; -} - -/* Allocate a new _cpp_file structure. */ -static _cpp_file * -make_cpp_file (cpp_reader *pfile, cpp_dir *dir, const char *fname) -{ - _cpp_file *file; - - file = xcalloc (1, sizeof (_cpp_file)); - file->main_file = !pfile->buffer; - file->fd = -1; - file->dir = dir; - file->name = xstrdup (fname); - - return file; -} - -/* Release a _cpp_file structure. */ -static void -destroy_cpp_file (_cpp_file *file) -{ - if (file->buffer) - free ((void *) file->buffer); - free ((void *) file->name); - free (file); -} - -/* A hash of directory names. The directory names are the path names - of files which contain a #include "", the included file name is - appended to this directories. - - To avoid duplicate entries we follow the convention that all - non-empty directory names should end in a '/'. DIR_NAME must be - stored in permanently allocated memory. */ -static cpp_dir * -make_cpp_dir (cpp_reader *pfile, const char *dir_name, int sysp) -{ - struct file_hash_entry *entry, **hash_slot; - cpp_dir *dir; - - hash_slot = (struct file_hash_entry **) - htab_find_slot_with_hash (pfile->dir_hash, dir_name, - htab_hash_string (dir_name), - INSERT); - - /* Have we already hashed this directory? */ - for (entry = *hash_slot; entry; entry = entry->next) - if (entry->start_dir == NULL) - return entry->u.dir; - - dir = xcalloc (1, sizeof (cpp_dir)); - dir->next = pfile->quote_include; - dir->name = (char *) dir_name; - dir->len = strlen (dir_name); - dir->sysp = sysp; - - /* Store this new result in the hash table. */ - entry = new_file_hash_entry (pfile); - entry->next = *hash_slot; - entry->start_dir = NULL; - entry->u.dir = dir; - *hash_slot = entry; - - return dir; -} - -/* Create a new block of memory for file hash entries. */ -static void -allocate_file_hash_entries (cpp_reader *pfile) -{ - pfile->file_hash_entries_used = 0; - pfile->file_hash_entries_allocated = 127; - pfile->file_hash_entries = xmalloc - (pfile->file_hash_entries_allocated * sizeof (struct file_hash_entry)); -} - -/* Return a new file hash entry. */ -static struct file_hash_entry * -new_file_hash_entry (cpp_reader *pfile) -{ - if (pfile->file_hash_entries_used == pfile->file_hash_entries_allocated) - allocate_file_hash_entries (pfile); - - return &pfile->file_hash_entries[pfile->file_hash_entries_used++]; -} - -/* Returns TRUE if a file FNAME has ever been successfully opened. - This routine is not intended to correctly handle filenames aliased - by links or redundant . or .. traversals etc. */ -bool -cpp_included (cpp_reader *pfile, const char *fname) -{ - struct file_hash_entry *entry; - - entry = htab_find_with_hash (pfile->file_hash, fname, - htab_hash_string (fname)); - - while (entry && (entry->start_dir == NULL || entry->u.file->err_no)) - entry = entry->next; - - return entry != NULL; -} - -/* Calculate the hash value of a file hash entry P. */ - -static hashval_t -file_hash_hash (const void *p) -{ - struct file_hash_entry *entry = (struct file_hash_entry *) p; - const char *hname; - if (entry->start_dir) - hname = entry->u.file->name; - else - hname = entry->u.dir->name; - - return htab_hash_string (hname); -} - -/* Compare a string Q against a file hash entry P. */ -static int -file_hash_eq (const void *p, const void *q) -{ - struct file_hash_entry *entry = (struct file_hash_entry *) p; - const char *fname = (const char *) q; - const char *hname; - - if (entry->start_dir) - hname = entry->u.file->name; - else - hname = entry->u.dir->name; - - return strcmp (hname, fname) == 0; -} - -/* Initialize everything in this source file. */ -void -_cpp_init_files (cpp_reader *pfile) -{ - pfile->file_hash = htab_create_alloc (127, file_hash_hash, file_hash_eq, - NULL, xcalloc, free); - pfile->dir_hash = htab_create_alloc (127, file_hash_hash, file_hash_eq, - NULL, xcalloc, free); - allocate_file_hash_entries (pfile); -} - -/* Finalize everything in this source file. */ -void -_cpp_cleanup_files (cpp_reader *pfile) -{ - htab_delete (pfile->file_hash); - htab_delete (pfile->dir_hash); -} - -/* Enter a file name in the hash for the sake of cpp_included. */ -void -_cpp_fake_include (cpp_reader *pfile, const char *fname) -{ - _cpp_find_file (pfile, fname, pfile->buffer->file->dir, true, 0); -} - -/* Not everyone who wants to set system-header-ness on a buffer can - see the details of a buffer. This is an exported interface because - fix-header needs it. */ -void -cpp_make_system_header (cpp_reader *pfile, int syshdr, int externc) -{ - int flags = 0; - - /* 1 = system header, 2 = system header to be treated as C. */ - if (syshdr) - flags = 1 + (externc != 0); - _cpp_do_file_change (pfile, LC_RENAME, pfile->map->to_file, - SOURCE_LINE (pfile->map, pfile->line), flags); -} - -/* Allow the client to change the current file. Used by the front end - to achieve pseudo-file names like . - If REASON is LC_LEAVE, then NEW_NAME must be NULL. */ -void -cpp_change_file (cpp_reader *pfile, enum lc_reason reason, - const char *new_name) -{ - _cpp_do_file_change (pfile, reason, new_name, 1, 0); -} - -/* Callback function for htab_traverse. */ -static int -report_missing_guard (void **slot, void *b) -{ - struct file_hash_entry *entry = (struct file_hash_entry *) *slot; - int *bannerp = (int *) b; - - /* Skip directories. */ - if (entry->start_dir != NULL) - { - _cpp_file *file = entry->u.file; - - /* We don't want MI guard advice for the main file. */ - if (file->cmacro == NULL && file->stack_count == 1 && !file->main_file) - { - if (*bannerp == 0) - { - fputs (_("Multiple include guards may be useful for:\n"), - stderr); - *bannerp = 1; - } - - fputs (entry->u.file->path, stderr); - putc ('\n', stderr); - } - } - - return 0; -} - -/* Report on all files that might benefit from a multiple include guard. - Triggered by -H. */ -void -_cpp_report_missing_guards (cpp_reader *pfile) -{ - int banner = 0; - - htab_traverse (pfile->file_hash, report_missing_guard, &banner); -} - -/* Locate HEADER, and determine whether it is newer than the current - file. If it cannot be located or dated, return -1, if it is - newer, return 1, otherwise 0. */ -int -_cpp_compare_file_date (cpp_reader *pfile, const char *fname, - int angle_brackets) -{ - _cpp_file *file; - struct cpp_dir *dir; - - dir = search_path_head (pfile, fname, angle_brackets, IT_INCLUDE); - if (!dir) - return -1; - - file = _cpp_find_file (pfile, fname, dir, false, angle_brackets); - if (file->err_no) - return -1; - - if (file->fd != -1) - { - close (file->fd); - file->fd = -1; - } - - return file->st.st_mtime > pfile->buffer->file->st.st_mtime; -} - -/* Pushes the given file onto the buffer stack. Returns nonzero if - successful. */ -bool -cpp_push_include (cpp_reader *pfile, const char *fname) -{ - /* Make the command line directive take up a line. */ - pfile->line++; - return _cpp_stack_include (pfile, fname, false, IT_CMDLINE); -} - -/* Do appropriate cleanup when a file INC's buffer is popped off the - input stack. */ -void -_cpp_pop_file_buffer (cpp_reader *pfile, _cpp_file *file) -{ - /* Record the inclusion-preventing macro, which could be NULL - meaning no controlling macro. */ - if (pfile->mi_valid && file->cmacro == NULL) - file->cmacro = pfile->mi_cmacro; - - /* Invalidate control macros in the #including file. */ - pfile->mi_valid = false; - - if (file->buffer) - { - free ((void *) file->buffer); - file->buffer = NULL; - file->buffer_valid = false; - } -} - -/* Set the include chain for "" to QUOTE, for <> to BRACKET. If - QUOTE_IGNORES_SOURCE_DIR, then "" includes do not look in the - directory of the including file. - - If BRACKET does not lie in the QUOTE chain, it is set to QUOTE. */ -void -cpp_set_include_chains (cpp_reader *pfile, cpp_dir *quote, cpp_dir *bracket, - int quote_ignores_source_dir) -{ - pfile->quote_include = quote; - pfile->bracket_include = quote; - pfile->quote_ignores_source_dir = quote_ignores_source_dir; - - for (; quote; quote = quote->next) - { - quote->name_map = NULL; - quote->len = strlen (quote->name); - if (quote == bracket) - pfile->bracket_include = bracket; - } -} - -/* Append the file name to the directory to create the path, but don't - turn / into // or // into ///; // may be a namespace escape. */ -static char * -append_file_to_dir (const char *fname, cpp_dir *dir) -{ - size_t dlen, flen; - char *path; - - dlen = dir->len; - flen = strlen (fname); - path = xmalloc (dlen + 1 + flen + 1); - memcpy (path, dir->name, dlen); - if (dlen && path[dlen - 1] != '/') - path[dlen++] = '/'; - memcpy (&path[dlen], fname, flen + 1); - - return path; -} - -/* Read a space delimited string of unlimited length from a stdio - file F. */ -static char * -read_filename_string (int ch, FILE *f) -{ - char *alloc, *set; - int len; - - len = 20; - set = alloc = xmalloc (len + 1); - if (! is_space (ch)) - { - *set++ = ch; - while ((ch = getc (f)) != EOF && ! is_space (ch)) - { - if (set - alloc == len) - { - len *= 2; - alloc = xrealloc (alloc, len + 1); - set = alloc + len / 2; - } - *set++ = ch; - } - } - *set = '\0'; - ungetc (ch, f); - return alloc; -} - -/* Read the file name map file for DIR. */ -static void -read_name_map (cpp_dir *dir) -{ - static const char FILE_NAME_MAP_FILE[] = "header.gcc"; - char *name; - FILE *f; - size_t len, count = 0, room = 9; - - len = dir->len; - name = alloca (len + sizeof (FILE_NAME_MAP_FILE) + 1); - memcpy (name, dir->name, len); - if (len && name[len - 1] != '/') - name[len++] = '/'; - strcpy (name + len, FILE_NAME_MAP_FILE); - f = fopen (name, "r"); - - dir->name_map = xmalloc (room * sizeof (char *)); - - /* Silently return NULL if we cannot open. */ - if (f) - { - int ch; - - while ((ch = getc (f)) != EOF) - { - char *to; - - if (is_space (ch)) - continue; - - if (count + 2 > room) - { - room += 8; - dir->name_map = xrealloc (dir->name_map, room * sizeof (char *)); - } - - dir->name_map[count] = read_filename_string (ch, f); - while ((ch = getc (f)) != EOF && is_hspace (ch)) - ; - - to = read_filename_string (ch, f); - if (IS_ABSOLUTE_PATH (to)) - dir->name_map[count + 1] = to; - else - { - dir->name_map[count + 1] = append_file_to_dir (to, dir); - free (to); - } - - count += 2; - while ((ch = getc (f)) != '\n') - if (ch == EOF) - break; - } - - fclose (f); - } - - /* Terminate the list of maps. */ - dir->name_map[count] = NULL; -} - -/* Remap a FILE's name based on the file_name_map, if any, for - FILE->dir. If the file name has any directory separators, - recursively check those directories too. */ -static char * -remap_filename (cpp_reader *pfile, _cpp_file *file) -{ - const char *fname, *p; - char *new_dir; - cpp_dir *dir; - size_t index, len; - - dir = file->dir; - fname = file->name; - - for (;;) - { - if (!dir->name_map) - read_name_map (dir); - - for (index = 0; dir->name_map[index]; index += 2) - if (!strcmp (dir->name_map[index], fname)) - return xstrdup (dir->name_map[index + 1]); - - p = strchr (fname, '/'); - if (!p || p == fname) - return NULL; - - len = dir->len + (p - fname + 1); - new_dir = xmalloc (len + 1); - memcpy (new_dir, dir->name, dir->len); - memcpy (new_dir + dir->len, fname, p - fname + 1); - new_dir[len] = '\0'; - - dir = make_cpp_dir (pfile, new_dir, dir->sysp); - fname = p + 1; - } -} - -/* Return true if FILE is usable by PCH. */ -static bool -include_pch_p (_cpp_file *file) -{ - return file->pch & 1; -} - -/* Returns true if PCHNAME is a valid PCH file for FILE. */ -static bool -validate_pch (cpp_reader *pfile, _cpp_file *file, const char *pchname) -{ - const char *saved_path = file->path; - bool valid = false; - - file->path = pchname; - if (open_file (file)) - { - valid = 1 & pfile->cb.valid_pch (pfile, pchname, file->fd); - - if (!valid) - { - close (file->fd); - file->fd = -1; - } - - if (CPP_OPTION (pfile, print_include_names)) - { - unsigned int i; - for (i = 1; i < pfile->line_maps.depth; i++) - putc ('.', stderr); - fprintf (stderr, "%c %s\n", - valid ? '!' : 'x', pchname); - } - } - - file->path = saved_path; - return valid; -} diff --git a/support/cpp2/cpphash.c b/support/cpp2/cpphash.c deleted file mode 100644 index 9d2f51ae..00000000 --- a/support/cpp2/cpphash.c +++ /dev/null @@ -1,121 +0,0 @@ -/* Hash tables for the CPP library. - Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998, - 1999, 2000, 2001, 2002 Free Software Foundation, Inc. - Written by Per Bothner, 1994. - Based on CCCP program by Paul Rubin, June 1986 - Adapted to ANSI C, Richard Stallman, Jan 1987 - -This program 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 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - In other words, you are welcome to use, share and improve this program. - You are forbidden to forbid anyone else to use, share and improve - what you give them. Help stamp out software-hoarding! */ - -#include "config.h" -#include "system.h" -#include "cpplib.h" -#include "cpphash.h" - -static cpp_hashnode *alloc_node (hash_table *); - -/* Return an identifier node for hashtable.c. Used by cpplib except - when integrated with the C front ends. */ -static cpp_hashnode * -alloc_node (hash_table *table) -{ - cpp_hashnode *node; - - node = obstack_alloc (&table->pfile->hash_ob, sizeof (cpp_hashnode)); - memset (node, 0, sizeof (cpp_hashnode)); - return node; -} - -/* Set up the identifier hash table. Use TABLE if non-null, otherwise - create our own. */ -void -_cpp_init_hashtable (cpp_reader *pfile, hash_table *table) -{ - struct spec_nodes *s; - - if (table == NULL) - { - pfile->our_hashtable = 1; - table = ht_create (13); /* 8K (=2^13) entries. */ - table->alloc_node = (hashnode (*) (hash_table *)) alloc_node; - - _obstack_begin (&pfile->hash_ob, 0, 0, - (void *(*) (long)) xmalloc, - (void (*) (void *)) free); - } - - table->pfile = pfile; - pfile->hash_table = table; - - /* Now we can initialize things that use the hash table. */ - _cpp_init_directives (pfile); - _cpp_init_internal_pragmas (pfile); - - s = &pfile->spec_nodes; - s->n_defined = cpp_lookup (pfile, DSC("defined")); - s->n_true = cpp_lookup (pfile, DSC("true")); - s->n_false = cpp_lookup (pfile, DSC("false")); - s->n__VA_ARGS__ = cpp_lookup (pfile, DSC("__VA_ARGS__")); - s->n__VA_ARGS__->flags |= NODE_DIAGNOSTIC; - /* SDCC _asm specific */ - s->n__asm = cpp_lookup (pfile, DSC("_asm")); - -} - -/* Tear down the identifier hash table. */ -void -_cpp_destroy_hashtable (cpp_reader *pfile) -{ - if (pfile->our_hashtable) - { - ht_destroy (pfile->hash_table); - obstack_free (&pfile->hash_ob, 0); - } -} - -/* Returns the hash entry for the STR of length LEN, creating one - if necessary. */ -cpp_hashnode * -cpp_lookup (cpp_reader *pfile, const unsigned char *str, unsigned int len) -{ - /* ht_lookup cannot return NULL. */ - return CPP_HASHNODE (ht_lookup (pfile->hash_table, str, len, HT_ALLOC)); -} - -/* Determine whether the str STR, of length LEN, is a defined macro. */ -int -cpp_defined (cpp_reader *pfile, const unsigned char *str, int len) -{ - cpp_hashnode *node; - - node = CPP_HASHNODE (ht_lookup (pfile->hash_table, str, len, HT_NO_INSERT)); - - /* If it's of type NT_MACRO, it cannot be poisoned. */ - return node && node->type == NT_MACRO; -} - -/* For all nodes in the hashtable, callback CB with parameters PFILE, - the node, and V. */ -void -cpp_forall_identifiers (cpp_reader *pfile, cpp_cb cb, void *v) -{ - /* We don't need a proxy since the hash table's identifier comes - first in cpp_hashnode. */ - ht_forall (pfile->hash_table, (ht_cb) cb, v); -} diff --git a/support/cpp2/cpphash.h b/support/cpp2/cpphash.h deleted file mode 100644 index afe4c832..00000000 --- a/support/cpp2/cpphash.h +++ /dev/null @@ -1,641 +0,0 @@ -/* Part of CPP library. - Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 - Free Software Foundation, Inc. - -This program 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 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* This header defines all the internal data structures and functions - that need to be visible across files. It's called cpphash.h for - historical reasons. */ - -#ifndef GCC_CPPHASH_H -#define GCC_CPPHASH_H - -#include "hashtable.h" - -#if defined HAVE_ICONV_H && defined HAVE_ICONV -#include -#else -#define HAVE_ICONV 0 -typedef int iconv_t; /* dummy */ -#endif - -struct directive; /* Deliberately incomplete. */ -struct pending_option; -struct op; -struct _cpp_strbuf; - -typedef bool (*convert_f) (iconv_t, const unsigned char *, size_t, - struct _cpp_strbuf *); -struct cset_converter -{ - convert_f func; - iconv_t cd; -}; - -#ifndef HAVE_UCHAR -typedef unsigned char uchar; -#endif -#define U (const uchar *) /* Intended use: U"string" */ - -#define BITS_PER_CPPCHAR_T (CHAR_BIT * sizeof (cppchar_t)) - -/* Test if a sign is valid within a preprocessing number. */ -#define VALID_SIGN(c, prevc) \ - (((c) == '+' || (c) == '-') && \ - ((prevc) == 'e' || (prevc) == 'E' \ - || (((prevc) == 'p' || (prevc) == 'P') \ - && CPP_OPTION (pfile, extended_numbers)))) - -#define CPP_OPTION(PFILE, OPTION) ((PFILE)->opts.OPTION) -#define CPP_BUFFER(PFILE) ((PFILE)->buffer) -#define CPP_BUF_COLUMN(BUF, CUR) ((CUR) - (BUF)->line_base) -#define CPP_BUF_COL(BUF) CPP_BUF_COLUMN(BUF, (BUF)->cur) - -/* Maximum nesting of cpp_buffers. We use a static limit, partly for - efficiency, and partly to limit runaway recursion. */ -#define CPP_STACK_MAX 200 - -/* Host alignment handling. */ -struct dummy -{ - char c; - union - { - double d; - int *p; - } u; -}; - -#define DEFAULT_ALIGNMENT offsetof (struct dummy, u) -#define CPP_ALIGN2(size, align) (((size) + ((align) - 1)) & ~((align) - 1)) -#define CPP_ALIGN(size) CPP_ALIGN2 (size, DEFAULT_ALIGNMENT) - -/* Each macro definition is recorded in a cpp_macro structure. - Variadic macros cannot occur with traditional cpp. */ -struct cpp_macro -{ - /* Parameters, if any. */ - cpp_hashnode **params; - - /* Replacement tokens (ISO) or replacement text (traditional). See - comment at top of cpptrad.c for how traditional function-like - macros are encoded. */ - union - { - cpp_token *tokens; - const uchar *text; - } exp; - - /* Definition line number. */ - fileline line; - - /* Number of tokens in expansion, or bytes for traditional macros. */ - unsigned int count; - - /* Number of parameters. */ - unsigned short paramc; - - /* If a function-like macro. */ - unsigned int fun_like : 1; - - /* If a variadic macro. */ - unsigned int variadic : 1; - - /* If macro defined in system header. */ - unsigned int syshdr : 1; - - /* Nonzero if it has been expanded or had its existence tested. */ - unsigned int used : 1; -}; - -#define _cpp_mark_macro_used(NODE) do { \ - if ((NODE)->type == NT_MACRO && !((NODE)->flags & NODE_BUILTIN)) \ - (NODE)->value.macro->used = 1; } while (0) - -/* A generic memory buffer, and operations on it. */ -typedef struct _cpp_buff _cpp_buff; -struct _cpp_buff -{ - struct _cpp_buff *next; - unsigned char *base, *cur, *limit; -}; - -extern _cpp_buff *_cpp_get_buff (cpp_reader *, size_t); -extern void _cpp_release_buff (cpp_reader *, _cpp_buff *); -extern void _cpp_extend_buff (cpp_reader *, _cpp_buff **, size_t); -extern _cpp_buff *_cpp_append_extend_buff (cpp_reader *, _cpp_buff *, size_t); -extern void _cpp_free_buff (_cpp_buff *); -extern unsigned char *_cpp_aligned_alloc (cpp_reader *, size_t); -extern unsigned char *_cpp_unaligned_alloc (cpp_reader *, size_t); - -#define BUFF_ROOM(BUFF) (size_t) ((BUFF)->limit - (BUFF)->cur) -#define BUFF_FRONT(BUFF) ((BUFF)->cur) -#define BUFF_LIMIT(BUFF) ((BUFF)->limit) - -/* #include types. */ -enum include_type {IT_INCLUDE, IT_INCLUDE_NEXT, IT_IMPORT, IT_CMDLINE}; - -union utoken -{ - const cpp_token *token; - const cpp_token **ptoken; -}; - -/* A "run" of tokens; part of a chain of runs. */ -typedef struct tokenrun tokenrun; -struct tokenrun -{ - tokenrun *next, *prev; - cpp_token *base, *limit; -}; - -/* Accessor macros for struct cpp_context. */ -#define FIRST(c) ((c)->u.iso.first) -#define LAST(c) ((c)->u.iso.last) -#define CUR(c) ((c)->u.trad.cur) -#define RLIMIT(c) ((c)->u.trad.rlimit) - -typedef struct cpp_context cpp_context; -struct cpp_context -{ - /* Doubly-linked list. */ - cpp_context *next, *prev; - - union - { - /* For ISO macro expansion. Contexts other than the base context - are contiguous tokens. e.g. macro expansions, expanded - argument tokens. */ - struct - { - union utoken first; - union utoken last; - } iso; - - /* For traditional macro expansion. */ - struct - { - const uchar *cur; - const uchar *rlimit; - } trad; - } u; - - /* If non-NULL, a buffer used for storage related to this context. - When the context is popped, the buffer is released. */ - _cpp_buff *buff; - - /* For a macro context, the macro node, otherwise NULL. */ - cpp_hashnode *macro; - - /* True if utoken element is token, else ptoken. */ - bool direct_p; -}; - -struct lexer_state -{ - /* Nonzero if first token on line is CPP_HASH. */ - unsigned char in_directive; - - /* Nonzero if in a directive that will handle padding tokens itself. - #include needs this to avoid problems with computed include and - spacing between tokens. */ - unsigned char directive_wants_padding; - - /* True if we are skipping a failed conditional group. */ - unsigned char skipping; - - /* Nonzero if in a directive that takes angle-bracketed headers. */ - unsigned char angled_headers; - - /* Nonzero if in a #if or #elif directive. */ - unsigned char in_expression; - - /* Nonzero to save comments. Turned off if discard_comments, and in - all directives apart from #define. */ - unsigned char save_comments; - - /* Nonzero if lexing __VA_ARGS__ is valid. */ - unsigned char va_args_ok; - - /* Nonzero if lexing poisoned identifiers is valid. */ - unsigned char poisoned_ok; - - /* Nonzero to prevent macro expansion. */ - unsigned char prevent_expansion; - - /* Nonzero when parsing arguments to a function-like macro. */ - unsigned char parsing_args; - - /* Nonzero to skip evaluating part of an expression. */ - unsigned int skip_eval; -}; - -/* Special nodes - identifiers with predefined significance. */ -struct spec_nodes -{ - cpp_hashnode *n_defined; /* defined operator */ - cpp_hashnode *n_true; /* C++ keyword true */ - cpp_hashnode *n_false; /* C++ keyword false */ - cpp_hashnode *n__VA_ARGS__; /* C99 vararg macros */ - /* SDCC _asm specific */ - cpp_hashnode *n__asm; /* _asm ... _endasm ; */ -}; - -typedef struct _cpp_line_note _cpp_line_note; -struct _cpp_line_note -{ - /* Location in the clean line the note refers to. */ - const uchar *pos; - - /* Type of note. The 9 'from' trigraph characters represent those - trigraphs, '\\' an escaped newline, ' ' an escaped newline with - intervening space, and anything else is invalid. */ - unsigned int type; -}; - -/* Represents the contents of a file cpplib has read in. */ -struct cpp_buffer -{ - const uchar *cur; /* Current location. */ - const uchar *line_base; /* Start of current physical line. */ - const uchar *next_line; /* Start of to-be-cleaned logical line. */ - - const uchar *buf; /* Entire character buffer. */ - const uchar *rlimit; /* Writable byte at end of file. */ - - _cpp_line_note *notes; /* Array of notes. */ - unsigned int cur_note; /* Next note to process. */ - unsigned int notes_used; /* Number of notes. */ - unsigned int notes_cap; /* Size of allocated array. */ - - struct cpp_buffer *prev; - - /* Pointer into the file table; non-NULL if this is a file buffer. - Used for include_next and to record control macros. */ - struct _cpp_file *file; - - /* Value of if_stack at start of this file. - Used to prohibit unmatched #endif (etc) in an include file. */ - struct if_stack *if_stack; - - /* True if we need to get the next clean line. */ - bool need_line; - - /* True if we have already warned about C++ comments in this file. - The warning happens only for C89 extended mode with -pedantic on, - or for -Wtraditional, and only once per file (otherwise it would - be far too noisy). */ - unsigned char warned_cplusplus_comments; - - /* True if we don't process trigraphs and escaped newlines. True - for preprocessed input, command line directives, and _Pragma - buffers. */ - unsigned char from_stage3; - - /* At EOF, a buffer is automatically popped. If RETURN_AT_EOF is - true, a CPP_EOF token is then returned. Otherwise, the next - token from the enclosing buffer is returned. */ - unsigned int return_at_eof : 1; - - /* The directory of the this buffer's file. Its NAME member is not - allocated, so we don't need to worry about freeing it. */ - struct cpp_dir dir; - - /* Used for buffer overlays by cpptrad.c. */ - const uchar *saved_cur, *saved_rlimit; -}; - -/* A cpp_reader encapsulates the "state" of a pre-processor run. - Applying cpp_get_token repeatedly yields a stream of pre-processor - tokens. Usually, there is only one cpp_reader object active. */ -struct cpp_reader -{ - /* Top of buffer stack. */ - cpp_buffer *buffer; - - /* Overlaid buffer (can be different after processing #include). */ - cpp_buffer *overlaid_buffer; - - /* Lexer state. */ - struct lexer_state state; - - /* Source line tracking. */ - struct line_maps line_maps; - const struct line_map *map; - fileline line; - - /* The line of the '#' of the current directive. */ - fileline directive_line; - - /* Memory buffers. */ - _cpp_buff *a_buff; /* Aligned permanent storage. */ - _cpp_buff *u_buff; /* Unaligned permanent storage. */ - _cpp_buff *free_buffs; /* Free buffer chain. */ - - /* Context stack. */ - struct cpp_context base_context; - struct cpp_context *context; - - /* If in_directive, the directive if known. */ - const struct directive *directive; - - /* Search paths for include files. */ - struct cpp_dir *quote_include; /* "" */ - struct cpp_dir *bracket_include; /* <> */ - struct cpp_dir no_search_path; /* No path. */ - - /* Chain of all hashed _cpp_file instances. */ - struct _cpp_file *all_files; - - struct _cpp_file *main_file; - - /* File and directory hash table. */ - struct htab *file_hash; - struct htab *dir_hash; - struct file_hash_entry *file_hash_entries; - unsigned int file_hash_entries_allocated, file_hash_entries_used; - - /* Nonzero means don't look for #include "foo" the source-file - directory. */ - bool quote_ignores_source_dir; - - /* Nonzero if any file has contained #pragma once or #import has - been used. */ - bool seen_once_only; - - /* Multiple include optimization. */ - const cpp_hashnode *mi_cmacro; - const cpp_hashnode *mi_ind_cmacro; - bool mi_valid; - - /* Lexing. */ - cpp_token *cur_token; - tokenrun base_run, *cur_run; - unsigned int lookaheads; - - /* Nonzero prevents the lexer from re-using the token runs. */ - unsigned int keep_tokens; - - /* Error counter for exit code. */ - unsigned int errors; - - /* Buffer to hold macro definition string. */ - unsigned char *macro_buffer; - unsigned int macro_buffer_len; - - /* Descriptor for converting from the source character set to the - execution character set. */ - struct cset_converter narrow_cset_desc; - - /* Descriptor for converting from the source character set to the - wide execution character set. */ - struct cset_converter wide_cset_desc; - - /* Date and time text. Calculated together if either is requested. */ - const uchar *date; - const uchar *time; - - /* EOF token, and a token forcing paste avoidance. */ - cpp_token avoid_paste; - cpp_token eof; - - /* Opaque handle to the dependencies of mkdeps.c. */ - struct deps *deps; - - /* Obstack holding all macro hash nodes. This never shrinks. - See cpphash.c */ - struct obstack hash_ob; - - /* Obstack holding buffer and conditional structures. This is a - real stack. See cpplib.c. */ - struct obstack buffer_ob; - - /* Pragma table - dynamic, because a library user can add to the - list of recognized pragmas. */ - struct pragma_entry *pragmas; - - /* Call backs to cpplib client. */ - struct cpp_callbacks cb; - - /* Identifier hash table. */ - struct ht *hash_table; - - /* Expression parser stack. */ - struct op *op_stack, *op_limit; - - /* User visible options. */ - struct cpp_options opts; - - /* Special nodes - identifiers with predefined significance to the - preprocessor. */ - struct spec_nodes spec_nodes; - - /* Whether cpplib owns the hashtable. */ - bool our_hashtable; - - /* Traditional preprocessing output buffer (a logical line). */ - struct - { - uchar *base; - uchar *limit; - uchar *cur; - fileline first_line; - } out; - - /* Used to save the original line number during traditional - preprocessing. */ - unsigned int saved_line; - - /* A saved list of the defined macros, for dependency checking - of precompiled headers. */ - struct cpp_savedstate *savedstate; -}; - -/* Character classes. Based on the more primitive macros in safe-ctype.h. - If the definition of `numchar' looks odd to you, please look up the - definition of a pp-number in the C standard [section 6.4.8 of C99]. - - In the unlikely event that characters other than \r and \n enter - the set is_vspace, the macro handle_newline() in cpplex.c must be - updated. */ -#define _dollar_ok(x) ((x) == '$' && CPP_OPTION (pfile, dollars_in_ident)) - -#define is_idchar(x) (ISIDNUM(x) || _dollar_ok(x)) -#define is_numchar(x) ISIDNUM(x) -#define is_idstart(x) (ISIDST(x) || _dollar_ok(x)) -#define is_numstart(x) ISDIGIT(x) -#define is_hspace(x) ISBLANK(x) -#define is_vspace(x) IS_VSPACE(x) -#define is_nvspace(x) IS_NVSPACE(x) -#define is_space(x) IS_SPACE_OR_NUL(x) - -/* This table is constant if it can be initialized at compile time, - which is the case if cpp was compiled with GCC >=2.7, or another - compiler that supports C99. */ -#if HAVE_DESIGNATED_INITIALIZERS -extern const unsigned char _cpp_trigraph_map[UCHAR_MAX + 1]; -#else -extern unsigned char _cpp_trigraph_map[UCHAR_MAX + 1]; -#endif - -/* Macros. */ - -#define CPP_IN_SYSTEM_HEADER(PFILE) ((PFILE)->map && (PFILE)->map->sysp) -#define CPP_PEDANTIC(PF) CPP_OPTION (PF, pedantic) -#define CPP_WTRADITIONAL(PF) CPP_OPTION (PF, warn_traditional) - -/* In cpperror.c */ -extern int _cpp_begin_message (cpp_reader *, int, fileline, unsigned int); - -/* In cppmacro.c */ -extern void _cpp_free_definition (cpp_hashnode *); -extern bool _cpp_create_definition (cpp_reader *, cpp_hashnode *); -extern void _cpp_pop_context (cpp_reader *); -extern void _cpp_push_text_context (cpp_reader *, cpp_hashnode *, - const uchar *, size_t); -extern bool _cpp_save_parameter (cpp_reader *, cpp_macro *, cpp_hashnode *); -extern bool _cpp_arguments_ok (cpp_reader *, cpp_macro *, const cpp_hashnode *, - unsigned int); -extern const uchar *_cpp_builtin_macro_text (cpp_reader *, cpp_hashnode *); -int _cpp_warn_if_unused_macro (cpp_reader *, cpp_hashnode *, void *); -/* In cpphash.c */ -extern void _cpp_init_hashtable (cpp_reader *, hash_table *); -extern void _cpp_destroy_hashtable (cpp_reader *); - -/* In cppfiles.c */ -typedef struct _cpp_file _cpp_file; -extern _cpp_file *_cpp_find_file (cpp_reader *, const char *fname, - cpp_dir *start_dir, bool fake, int); -extern bool _cpp_find_failed (_cpp_file *); -extern void _cpp_mark_file_once_only (cpp_reader *, struct _cpp_file *); -extern void _cpp_fake_include (cpp_reader *, const char *); -extern bool _cpp_stack_file (cpp_reader *, _cpp_file*, bool); -extern bool _cpp_stack_include (cpp_reader *, const char *, int, - enum include_type); -extern int _cpp_compare_file_date (cpp_reader *, const char *, int); -extern void _cpp_report_missing_guards (cpp_reader *); -extern void _cpp_init_files (cpp_reader *); -extern void _cpp_cleanup_files (cpp_reader *); -extern void _cpp_pop_file_buffer (cpp_reader *, struct _cpp_file *); - -/* In cppexp.c */ -extern bool _cpp_parse_expr (cpp_reader *); -extern struct op *_cpp_expand_op_stack (cpp_reader *); - -/* In cpplex.c */ -extern void _cpp_process_line_notes (cpp_reader *, int); -extern void _cpp_clean_line (cpp_reader *); -extern bool _cpp_get_fresh_line (cpp_reader *); -extern bool _cpp_skip_block_comment (cpp_reader *); -extern cpp_token *_cpp_temp_token (cpp_reader *); -extern const cpp_token *_cpp_lex_token (cpp_reader *); -extern cpp_token *_cpp_lex_direct (cpp_reader *); -extern int _cpp_equiv_tokens (const cpp_token *, const cpp_token *); -extern void _cpp_init_tokenrun (tokenrun *, unsigned int); - -/* In cppinit.c. */ -extern void _cpp_maybe_push_include_file (cpp_reader *); - -/* In cpplib.c */ -extern int _cpp_test_assertion (cpp_reader *, unsigned int *); -extern int _cpp_handle_directive (cpp_reader *, int); -extern void _cpp_define_builtin (cpp_reader *, const char *); -extern char ** _cpp_save_pragma_names (cpp_reader *); -extern void _cpp_restore_pragma_names (cpp_reader *, char **); -extern void _cpp_do__Pragma (cpp_reader *); -extern void _cpp_init_directives (cpp_reader *); -extern void _cpp_init_internal_pragmas (cpp_reader *); -extern void _cpp_do_file_change (cpp_reader *, enum lc_reason, const char *, - unsigned int, unsigned int); -extern void _cpp_pop_buffer (cpp_reader *); - -/* In cpptrad.c. */ -extern bool _cpp_scan_out_logical_line (cpp_reader *, cpp_macro *); -extern bool _cpp_read_logical_line_trad (cpp_reader *); -extern void _cpp_overlay_buffer (cpp_reader *pfile, const uchar *, size_t); -extern void _cpp_remove_overlay (cpp_reader *); -extern bool _cpp_create_trad_definition (cpp_reader *, cpp_macro *); -extern bool _cpp_expansions_different_trad (const cpp_macro *, - const cpp_macro *); -extern uchar *_cpp_copy_replacement_text (const cpp_macro *, uchar *); -extern size_t _cpp_replacement_text_len (const cpp_macro *); - -/* In cppcharset.c. */ -extern cppchar_t _cpp_valid_ucn (cpp_reader *, const uchar **, - const uchar *, int); -extern void _cpp_destroy_iconv (cpp_reader *); -extern bool _cpp_interpret_string_notranslate (cpp_reader *, - const cpp_string *, - cpp_string *); -extern uchar *_cpp_convert_input (cpp_reader *, const char *, uchar *, - size_t, size_t, off_t *); -extern const char *_cpp_default_encoding (void); - - -/* Utility routines and macros. */ -#define DSC(str) (const uchar *)str, sizeof str - 1 -#define xnew(T) (T *) xmalloc (sizeof(T)) -#define xcnew(T) (T *) xcalloc (1, sizeof(T)) -#define xnewvec(T, N) (T *) xmalloc (sizeof(T) * (N)) -#define xcnewvec(T, N) (T *) xcalloc (N, sizeof(T)) -#define xobnew(O, T) (T *) obstack_alloc (O, sizeof(T)) - -/* These are inline functions instead of macros so we can get type - checking. */ -static inline int ustrcmp (const uchar *, const uchar *); -static inline int ustrncmp (const uchar *, const uchar *, size_t); -static inline size_t ustrlen (const uchar *); -static inline uchar *uxstrdup (const uchar *); -static inline uchar *ustrchr (const uchar *, int); -static inline int ufputs (const uchar *, FILE *); - -static inline int -ustrcmp (const uchar *s1, const uchar *s2) -{ - return strcmp ((const char *)s1, (const char *)s2); -} - -static inline int -ustrncmp (const uchar *s1, const uchar *s2, size_t n) -{ - return strncmp ((const char *)s1, (const char *)s2, n); -} - -static inline size_t -ustrlen (const uchar *s1) -{ - return strlen ((const char *)s1); -} - -static inline uchar * -uxstrdup (const uchar *s1) -{ - return (uchar *) xstrdup ((const char *)s1); -} - -static inline uchar * -ustrchr (const uchar *s1, int c) -{ - return (uchar *) strchr ((const char *)s1, c); -} - -static inline int -ufputs (const uchar *s, FILE *f) -{ - return fputs ((const char *)s, f); -} - -#endif /* ! GCC_CPPHASH_H */ diff --git a/support/cpp2/cppinit.c b/support/cpp2/cppinit.c deleted file mode 100644 index fab2da2b..00000000 --- a/support/cpp2/cppinit.c +++ /dev/null @@ -1,637 +0,0 @@ -/* CPP Library. - Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. - Contributed by Per Bothner, 1994-95. - Based on CCCP program by Paul Rubin, June 1986 - Adapted to ANSI C, Richard Stallman, Jan 1987 - -This program 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 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include "config.h" -#include "system.h" -#include "cpplib.h" -#include "cpphash.h" -#include "mkdeps.h" - -static void init_library (void); -static void mark_named_operators (cpp_reader *); -static void read_original_filename (cpp_reader *); -static void read_original_directory (cpp_reader *); -static void post_options (cpp_reader *); - -/* If we have designated initializers (GCC >2.7) these tables can be - initialized, constant data. Otherwise, they have to be filled in at - runtime. */ -#if HAVE_DESIGNATED_INITIALIZERS - -#define init_trigraph_map() /* Nothing. */ -#define TRIGRAPH_MAP \ -__extension__ const uchar _cpp_trigraph_map[UCHAR_MAX + 1] = { - -#define END }; -#define s(p, v) [p] = v, - -#else - -#define TRIGRAPH_MAP uchar _cpp_trigraph_map[UCHAR_MAX + 1] = { 0 }; \ - static void init_trigraph_map (void) { \ - unsigned char *x = _cpp_trigraph_map; - -#define END } -#define s(p, v) x[p] = v; - -#endif - -TRIGRAPH_MAP - s('=', '#') s(')', ']') s('!', '|') - s('(', '[') s('\'', '^') s('>', '}') - s('/', '\\') s('<', '{') s('-', '~') -END - -#undef s -#undef END -#undef TRIGRAPH_MAP - -/* A set of booleans indicating what CPP features each source language - requires. */ -struct lang_flags -{ - char c99; - char cplusplus; - char extended_numbers; - char std; - char cplusplus_comments; - char digraphs; -}; - -static const struct lang_flags lang_defaults[] = -{ /* c99 c++ xnum std // digr */ - /* GNUC89 */ { 0, 0, 1, 0, 1, 1 }, - /* GNUC99 */ { 1, 0, 1, 0, 1, 1 }, - /* STDC89 */ { 0, 0, 0, 1, 0, 0 }, - /* STDC94 */ { 0, 0, 0, 1, 0, 1 }, - /* STDC99 */ { 1, 0, 1, 1, 1, 1 }, - /* GNUCXX */ { 0, 1, 1, 0, 1, 1 }, - /* CXX98 */ { 0, 1, 1, 1, 1, 1 }, - /* ASM */ { 0, 0, 1, 0, 1, 0 } -}; - -/* Sets internal flags correctly for a given language. */ -void -cpp_set_lang (cpp_reader *pfile, enum c_lang lang) -{ - const struct lang_flags *l = &lang_defaults[(int) lang]; - - CPP_OPTION (pfile, lang) = lang; - - CPP_OPTION (pfile, c99) = l->c99; - CPP_OPTION (pfile, cplusplus) = l->cplusplus; - CPP_OPTION (pfile, extended_numbers) = l->extended_numbers; - CPP_OPTION (pfile, std) = l->std; - CPP_OPTION (pfile, trigraphs) = l->std; - CPP_OPTION (pfile, cplusplus_comments) = l->cplusplus_comments; - CPP_OPTION (pfile, digraphs) = l->digraphs; -} - -/* Initialize library global state. */ -static void -init_library (void) -{ - static int initialized = 0; - - if (! initialized) - { - initialized = 1; - - /* Set up the trigraph map. This doesn't need to do anything if - we were compiled with a compiler that supports C99 designated - initializers. */ - init_trigraph_map (); - } -} - -/* Initialize a cpp_reader structure. */ -cpp_reader * -cpp_create_reader (enum c_lang lang, hash_table *table) -{ - cpp_reader *pfile; - - /* Initialize this instance of the library if it hasn't been already. */ - init_library (); - - pfile = xcalloc (1, sizeof (cpp_reader)); - - cpp_set_lang (pfile, lang); - CPP_OPTION (pfile, warn_multichar) = 1; - CPP_OPTION (pfile, discard_comments) = 1; - CPP_OPTION (pfile, discard_comments_in_macro_exp) = 1; - CPP_OPTION (pfile, show_column) = 1; - CPP_OPTION (pfile, tabstop) = 8; - CPP_OPTION (pfile, operator_names) = 1; - CPP_OPTION (pfile, warn_trigraphs) = 2; - CPP_OPTION (pfile, warn_endif_labels) = 1; - CPP_OPTION (pfile, warn_deprecated) = 1; - CPP_OPTION (pfile, warn_long_long) = !CPP_OPTION (pfile, c99); - CPP_OPTION (pfile, dollars_in_ident) = 1; - CPP_OPTION (pfile, warn_dollars) = 1; - - /* Default CPP arithmetic to something sensible for the host for the - benefit of dumb users like fix-header. */ - CPP_OPTION (pfile, precision) = CHAR_BIT * sizeof (long); - CPP_OPTION (pfile, char_precision) = CHAR_BIT; - CPP_OPTION (pfile, wchar_precision) = CHAR_BIT * sizeof (int); - CPP_OPTION (pfile, int_precision) = CHAR_BIT * sizeof (int); - CPP_OPTION (pfile, unsigned_char) = 0; - CPP_OPTION (pfile, unsigned_wchar) = 1; - CPP_OPTION (pfile, bytes_big_endian) = 1; /* does not matter */ - - /* Default to locale/UTF-8. */ - CPP_OPTION (pfile, narrow_charset) = _cpp_default_encoding (); - CPP_OPTION (pfile, wide_charset) = 0; - CPP_OPTION (pfile, input_charset) = _cpp_default_encoding (); - - /* SDCC specific */ - CPP_OPTION (pfile, preproc_asm) = 1; - CPP_OPTION (pfile, pedantic_parse_number) = 0; - CPP_OPTION (pfile, obj_ext) = NULL; - - /* A fake empty "directory" used as the starting point for files - looked up without a search path. Name cannot be '/' because we - don't want to prepend anything at all to filenames using it. All - other entries are correct zero-initialized. */ - pfile->no_search_path.name = (char *) ""; - - /* Initialize the line map. Start at logical line 1, so we can use - a line number of zero for special states. */ - linemap_init (&pfile->line_maps); - pfile->line = 1; - - /* Initialize lexer state. */ - pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments); - - /* Set up static tokens. */ - pfile->avoid_paste.type = CPP_PADDING; - pfile->avoid_paste.val.source = NULL; - pfile->eof.type = CPP_EOF; - pfile->eof.flags = 0; - - /* Create a token buffer for the lexer. */ - _cpp_init_tokenrun (&pfile->base_run, 250); - pfile->cur_run = &pfile->base_run; - pfile->cur_token = pfile->base_run.base; - - /* Initialize the base context. */ - pfile->context = &pfile->base_context; - pfile->base_context.macro = 0; - pfile->base_context.prev = pfile->base_context.next = 0; - - /* Aligned and unaligned storage. */ - pfile->a_buff = _cpp_get_buff (pfile, 0); - pfile->u_buff = _cpp_get_buff (pfile, 0); - - /* The expression parser stack. */ - _cpp_expand_op_stack (pfile); - - /* Initialize the buffer obstack. */ - _obstack_begin (&pfile->buffer_ob, 0, 0, - (void *(*) (long)) xmalloc, - (void (*) (void *)) free); - - _cpp_init_files (pfile); - - _cpp_init_hashtable (pfile, table); - - return pfile; -} - -/* Free resources used by PFILE. Accessing PFILE after this function - returns leads to undefined behavior. Returns the error count. */ -void -cpp_destroy (cpp_reader *pfile) -{ - cpp_context *context, *contextn; - tokenrun *run, *runn; - - free (pfile->op_stack); - - while (CPP_BUFFER (pfile) != NULL) - _cpp_pop_buffer (pfile); - - if (pfile->out.base) - free (pfile->out.base); - - if (pfile->macro_buffer) - { - free (pfile->macro_buffer); - pfile->macro_buffer = NULL; - pfile->macro_buffer_len = 0; - } - - if (pfile->deps) - deps_free (pfile->deps); - obstack_free (&pfile->buffer_ob, 0); - - _cpp_destroy_hashtable (pfile); - _cpp_cleanup_files (pfile); - _cpp_destroy_iconv (pfile); - - _cpp_free_buff (pfile->a_buff); - _cpp_free_buff (pfile->u_buff); - _cpp_free_buff (pfile->free_buffs); - - for (run = &pfile->base_run; run; run = runn) - { - runn = run->next; - free (run->base); - if (run != &pfile->base_run) - free (run); - } - - for (context = pfile->base_context.next; context; context = contextn) - { - contextn = context->next; - free (context); - } - - linemap_free (&pfile->line_maps); - free (pfile); -} - -/* This structure defines one built-in identifier. A node will be - entered in the hash table under the name NAME, with value VALUE. - - There are two tables of these. builtin_array holds all the - "builtin" macros: these are handled by builtin_macro() in - cppmacro.c. Builtin is somewhat of a misnomer -- the property of - interest is that these macros require special code to compute their - expansions. The value is a "builtin_type" enumerator. - - operator_array holds the C++ named operators. These are keywords - which act as aliases for punctuators. In C++, they cannot be - altered through #define, and #if recognizes them as operators. In - C, these are not entered into the hash table at all (but see - ). The value is a token-type enumerator. */ -struct builtin -{ - const uchar *name; - unsigned short len; - unsigned short value; -}; - -#define B(n, t) { DSC(n), t } -static const struct builtin builtin_array[] = -{ - B("__TIME__", BT_TIME), - B("__DATE__", BT_DATE), - B("__FILE__", BT_FILE), - B("__BASE_FILE__", BT_BASE_FILE), - B("__LINE__", BT_SPECLINE), - B("__INCLUDE_LEVEL__", BT_INCLUDE_LEVEL), - /* Keep builtins not used for -traditional-cpp at the end, and - update init_builtins() if any more are added. */ - B("_Pragma", BT_PRAGMA), - B("__STDC__", BT_STDC), -}; - -static const struct builtin operator_array[] = -{ - B("and", CPP_AND_AND), - B("and_eq", CPP_AND_EQ), - B("bitand", CPP_AND), - B("bitor", CPP_OR), - B("compl", CPP_COMPL), - B("not", CPP_NOT), - B("not_eq", CPP_NOT_EQ), - B("or", CPP_OR_OR), - B("or_eq", CPP_OR_EQ), - B("xor", CPP_XOR), - B("xor_eq", CPP_XOR_EQ) -}; -#undef B - -/* Mark the C++ named operators in the hash table. */ -static void -mark_named_operators (cpp_reader *pfile) -{ - const struct builtin *b; - - for (b = operator_array; - b < (operator_array + ARRAY_SIZE (operator_array)); - b++) - { - cpp_hashnode *hp = cpp_lookup (pfile, b->name, b->len); - hp->flags |= NODE_OPERATOR; - hp->is_directive = 0; - hp->directive_index = b->value; - } -} - -/* Read the builtins table above and enter them, and language-specific - macros, into the hash table. HOSTED is true if this is a hosted - environment. */ -void -cpp_init_builtins (cpp_reader *pfile, int hosted) -{ - const struct builtin *b; - size_t n = ARRAY_SIZE (builtin_array); - - if (CPP_OPTION (pfile, traditional)) - n -= 2; - - for(b = builtin_array; b < builtin_array + n; b++) - { - cpp_hashnode *hp = cpp_lookup (pfile, b->name, b->len); - hp->type = NT_MACRO; - hp->flags |= NODE_BUILTIN | NODE_WARN; - hp->value.builtin = b->value; - } - - if (CPP_OPTION (pfile, cplusplus)) - _cpp_define_builtin (pfile, "__cplusplus 1"); - else if (CPP_OPTION (pfile, lang) == CLK_ASM) - _cpp_define_builtin (pfile, "__ASSEMBLER__ 1"); - else if (CPP_OPTION (pfile, lang) == CLK_STDC94) - _cpp_define_builtin (pfile, "__STDC_VERSION__ 199409L"); - else if (CPP_OPTION (pfile, c99)) - _cpp_define_builtin (pfile, "__STDC_VERSION__ 199901L"); - - if (hosted) - _cpp_define_builtin (pfile, "__STDC_HOSTED__ 1"); - else - _cpp_define_builtin (pfile, "__STDC_HOSTED__ 0"); - - if (CPP_OPTION (pfile, objc)) - _cpp_define_builtin (pfile, "__OBJC__ 1"); -} - -/* Sanity-checks are dependent on command-line options, so it is - called as a subroutine of cpp_read_main_file (). */ -#if ENABLE_CHECKING -static void sanity_checks (cpp_reader *); -static void sanity_checks (cpp_reader *pfile) -{ - cppchar_t test = 0; - size_t max_precision = 2 * CHAR_BIT * sizeof (cpp_num_part); - - /* Sanity checks for assumptions about CPP arithmetic and target - type precisions made by cpplib. */ - test--; - if (test < 1) - cpp_error (pfile, CPP_DL_ICE, "cppchar_t must be an unsigned type"); - - if (CPP_OPTION (pfile, precision) > max_precision) - cpp_error (pfile, CPP_DL_ICE, - "preprocessor arithmetic has maximum precision of %lu bits;" - " target requires %lu bits", - (unsigned long) max_precision, - (unsigned long) CPP_OPTION (pfile, precision)); - - if (CPP_OPTION (pfile, precision) < CPP_OPTION (pfile, int_precision)) - cpp_error (pfile, CPP_DL_ICE, - "CPP arithmetic must be at least as precise as a target int"); - - if (CPP_OPTION (pfile, char_precision) < 8) - cpp_error (pfile, CPP_DL_ICE, "target char is less than 8 bits wide"); - - if (CPP_OPTION (pfile, wchar_precision) < CPP_OPTION (pfile, char_precision)) - cpp_error (pfile, CPP_DL_ICE, - "target wchar_t is narrower than target char"); - - if (CPP_OPTION (pfile, int_precision) < CPP_OPTION (pfile, char_precision)) - cpp_error (pfile, CPP_DL_ICE, - "target int is narrower than target char"); - - /* This is assumed in eval_token() and could be fixed if necessary. */ - if (sizeof (cppchar_t) > sizeof (cpp_num_part)) - cpp_error (pfile, CPP_DL_ICE, - "CPP half-integer narrower than CPP character"); - - if (CPP_OPTION (pfile, wchar_precision) > BITS_PER_CPPCHAR_T) - cpp_error (pfile, CPP_DL_ICE, - "CPP on this host cannot handle wide character constants over" - " %lu bits, but the target requires %lu bits", - (unsigned long) BITS_PER_CPPCHAR_T, - (unsigned long) CPP_OPTION (pfile, wchar_precision)); -} -#else -# define sanity_checks(PFILE) -#endif - -/* Add a dependency target. Can be called any number of times before - cpp_read_main_file(). If no targets have been added before - cpp_read_main_file(), then the default target is used. */ -void -cpp_add_dependency_target (cpp_reader *pfile, const char *target, int quote) -{ - if (!pfile->deps) - pfile->deps = deps_init (); - - deps_add_target (pfile->deps, target, quote); -} - -/* This is called after options have been parsed, and partially - processed. */ -void -cpp_post_options (cpp_reader *pfile) -{ - sanity_checks (pfile); - - post_options (pfile); - - /* Mark named operators before handling command line macros. */ - if (CPP_OPTION (pfile, cplusplus) && CPP_OPTION (pfile, operator_names)) - mark_named_operators (pfile); - } - -/* Setup for processing input from the file named FNAME, or stdin if - it is the empty string. Return the original filename - on success (e.g. foo.i->foo.c), or NULL on failure. */ -const char * -cpp_read_main_file (cpp_reader *pfile, const char *fname) -{ - if (CPP_OPTION (pfile, deps.style) != DEPS_NONE) - { - if (!pfile->deps) - pfile->deps = deps_init (); - - /* Set the default target (if there is none already). */ - deps_add_default_target (pfile, fname); - } - - pfile->main_file - = _cpp_find_file (pfile, fname, &pfile->no_search_path, false, 0); - if (_cpp_find_failed (pfile->main_file)) - return NULL; - - _cpp_stack_file (pfile, pfile->main_file, false); - - /* For foo.i, read the original filename foo.c now, for the benefit - of the front ends. */ - if (CPP_OPTION (pfile, preprocessed)) - { - read_original_filename (pfile); - if (!pfile->map) - return NULL; - fname = pfile->map->to_file; - } - return fname; -} - -/* For preprocessed files, if the first tokens are of the form # NUM. - handle the directive so we know the original file name. This will - generate file_change callbacks, which the front ends must handle - appropriately given their state of initialization. */ -static void -read_original_filename (cpp_reader *pfile) -{ - const cpp_token *token, *token1; - - /* Lex ahead; if the first tokens are of the form # NUM, then - process the directive, otherwise back up. */ - token = _cpp_lex_direct (pfile); - if (token->type == CPP_HASH) - { - pfile->state.in_directive = 1; - token1 = _cpp_lex_direct (pfile); - _cpp_backup_tokens (pfile, 1); - pfile->state.in_directive = 0; - - /* If it's a #line directive, handle it. */ - if (token1->type == CPP_NUMBER) - { - _cpp_handle_directive (pfile, token->flags & PREV_WHITE); - read_original_directory (pfile); - return; - } - } - - /* Backup as if nothing happened. */ - _cpp_backup_tokens (pfile, 1); -} - -/* For preprocessed files, if the tokens following the first filename - line is of the form # "/path/name//", handle the - directive so we know the original current directory. */ -static void -read_original_directory (cpp_reader *pfile) -{ - const cpp_token *hash, *token; - - /* Lex ahead; if the first tokens are of the form # NUM, then - process the directive, otherwise back up. */ - hash = _cpp_lex_direct (pfile); - if (hash->type != CPP_HASH) - { - _cpp_backup_tokens (pfile, 1); - return; - } - - token = _cpp_lex_direct (pfile); - - if (token->type != CPP_NUMBER) - { - _cpp_backup_tokens (pfile, 2); - return; - } - - token = _cpp_lex_direct (pfile); - - if (token->type != CPP_STRING - || ! (token->val.str.len >= 5 - && token->val.str.text[token->val.str.len-2] == '/' - && token->val.str.text[token->val.str.len-3] == '/')) - { - _cpp_backup_tokens (pfile, 3); - return; - } - - if (pfile->cb.dir_change) - { - char *debugdir = alloca (token->val.str.len - 3); - - memcpy (debugdir, (const char *) token->val.str.text + 1, - token->val.str.len - 4); - debugdir[token->val.str.len - 4] = '\0'; - - pfile->cb.dir_change (pfile, debugdir); - } -} - -/* This is called at the end of preprocessing. It pops the last - buffer and writes dependency output, and returns the number of - errors. - - Maybe it should also reset state, such that you could call - cpp_start_read with a new filename to restart processing. */ -int -cpp_finish (cpp_reader *pfile, FILE *deps_stream) -{ - /* Warn about unused macros before popping the final buffer. */ - if (CPP_OPTION (pfile, warn_unused_macros)) - cpp_forall_identifiers (pfile, _cpp_warn_if_unused_macro, NULL); - - /* cpplex.c leaves the final buffer on the stack. This it so that - it returns an unending stream of CPP_EOFs to the client. If we - popped the buffer, we'd dereference a NULL buffer pointer and - segfault. It's nice to allow the client to do worry-free excess - cpp_get_token calls. */ - while (pfile->buffer) - _cpp_pop_buffer (pfile); - - /* Don't write the deps file if there are errors. */ - if (CPP_OPTION (pfile, deps.style) != DEPS_NONE - && deps_stream && pfile->errors == 0) - { - deps_write (pfile->deps, deps_stream, 72); - - if (CPP_OPTION (pfile, deps.phony_targets)) - deps_phony_targets (pfile->deps, deps_stream); - } - - /* Report on headers that could use multiple include guards. */ - if (CPP_OPTION (pfile, print_include_names)) - _cpp_report_missing_guards (pfile); - - return pfile->errors; -} - -static void -post_options (cpp_reader *pfile) -{ - /* -Wtraditional is not useful in C++ mode. */ - if (CPP_OPTION (pfile, cplusplus)) - CPP_OPTION (pfile, warn_traditional) = 0; - - /* Permanently disable macro expansion if we are rescanning - preprocessed text. Read preprocesed source in ISO mode. */ - if (CPP_OPTION (pfile, preprocessed)) - { - pfile->state.prevent_expansion = 1; - CPP_OPTION (pfile, traditional) = 0; - } - - if (CPP_OPTION (pfile, warn_trigraphs) == 2) - CPP_OPTION (pfile, warn_trigraphs) = !CPP_OPTION (pfile, trigraphs); - - if (CPP_OPTION (pfile, traditional)) - { - CPP_OPTION (pfile, cplusplus_comments) = 0; - - /* Traditional CPP does not accurately track column information. */ - CPP_OPTION (pfile, show_column) = 0; - CPP_OPTION (pfile, trigraphs) = 0; - CPP_OPTION (pfile, warn_trigraphs) = 0; - } -} diff --git a/support/cpp2/cpplex.c b/support/cpp2/cpplex.c deleted file mode 100644 index 610d5b13..00000000 --- a/support/cpp2/cpplex.c +++ /dev/null @@ -1,1896 +0,0 @@ -/* CPP Library - lexical analysis. - Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. - Contributed by Per Bothner, 1994-95. - Based on CCCP program by Paul Rubin, June 1986 - Adapted to ANSI C, Richard Stallman, Jan 1987 - Broken out to separate file, Zack Weinberg, Mar 2000 - -This program 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 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include "config.h" -#include "system.h" -#include "cpplib.h" -#include "cpphash.h" -#include - -enum spell_type -{ - SPELL_OPERATOR = 0, - SPELL_IDENT, - SPELL_LITERAL, - SPELL_NONE -}; - -struct token_spelling -{ - enum spell_type category; - const unsigned char *name; -}; - -static const unsigned char *const digraph_spellings[] = -{ U"%:", U"%:%:", U"<:", U":>", U"<%", U"%>" }; - -#define OP(e, s) { SPELL_OPERATOR, U s }, -#define TK(e, s) { s, U #e }, -static const struct token_spelling token_spellings[N_TTYPES] = { TTYPE_TABLE }; -#undef OP -#undef TK - -#define TOKEN_SPELL(token) (token_spellings[(token)->type].category) -#define TOKEN_NAME(token) (token_spellings[(token)->type].name) - -static void add_line_note (cpp_buffer *, const uchar *, unsigned int); -static int skip_line_comment (cpp_reader *); -static void skip_whitespace (cpp_reader *, cppchar_t); -static cpp_hashnode *lex_identifier (cpp_reader *, const uchar *); -static void lex_number (cpp_reader *, cpp_string *); -static bool forms_identifier_p (cpp_reader *, int); -static void lex_string (cpp_reader *, cpp_token *, const uchar *); -static void save_comment (cpp_reader *, cpp_token *, const uchar *, cppchar_t); -static void create_literal (cpp_reader *, cpp_token *, const uchar *, - unsigned int, enum cpp_ttype); -static bool warn_in_comment (cpp_reader *, _cpp_line_note *); -static int name_p (cpp_reader *, const cpp_string *); -static tokenrun *next_tokenrun (tokenrun *); - -static _cpp_buff *new_buff (size_t); - - -/* Utility routine: - - Compares, the token TOKEN to the NUL-terminated string STRING. - TOKEN must be a CPP_NAME. Returns 1 for equal, 0 for unequal. */ -int -cpp_ideq (const cpp_token *token, const char *string) -{ - if (token->type != CPP_NAME) - return 0; - - return !ustrcmp (NODE_NAME (token->val.node), (const uchar *) string); -} - -/* Record a note TYPE at byte POS into the current cleaned logical - line. */ -static void -add_line_note (cpp_buffer *buffer, const uchar *pos, unsigned int type) -{ - if (buffer->notes_used == buffer->notes_cap) - { - buffer->notes_cap = buffer->notes_cap * 2 + 200; - buffer->notes = xrealloc (buffer->notes, - buffer->notes_cap * sizeof (_cpp_line_note)); - } - - buffer->notes[buffer->notes_used].pos = pos; - buffer->notes[buffer->notes_used].type = type; - buffer->notes_used++; -} - -/* Returns with a logical line that contains no escaped newlines or - trigraphs. This is a time-critical inner loop. */ -void -_cpp_clean_line (cpp_reader *pfile) -{ - cpp_buffer *buffer; - const uchar *s; - uchar c, *d, *p; - - buffer = pfile->buffer; - buffer->cur_note = buffer->notes_used = 0; - buffer->cur = buffer->line_base = buffer->next_line; - buffer->need_line = false; - s = buffer->next_line - 1; - - if (!buffer->from_stage3) - { - /* Short circuit for the common case of an un-escaped line with - no trigraphs. The primary win here is by not writing any - data back to memory until we have to. */ - for (;;) - { - c = *++s; - if (c == '\n' || c == '\r') - { - d = (uchar *) s; - - if (s == buffer->rlimit) - goto done; - - /* DOS line ending? */ - if (c == '\r' && s[1] == '\n') - s++; - - if (s == buffer->rlimit) - goto done; - - /* check for escaped newline */ - p = d; - while (p != buffer->next_line && is_nvspace (p[-1])) - p--; - if (p == buffer->next_line || p[-1] != '\\') - goto done; - - /* Have an escaped newline; process it and proceed to - the slow path. */ - add_line_note (buffer, p - 1, p != d ? ' ' : '\\'); - d = p - 2; - buffer->next_line = p - 1; - break; - } - if (c == '?' && s[1] == '?' && _cpp_trigraph_map[s[2]]) - { - /* Have a trigraph. We may or may not have to convert - it. Add a line note regardless, for -Wtrigraphs. */ - add_line_note (buffer, s, s[2]); - if (CPP_OPTION (pfile, trigraphs)) - { - /* We do, and that means we have to switch to the - slow path. */ - d = (uchar *) s; - *d = _cpp_trigraph_map[s[2]]; - s += 2; - break; - } - } - } - - - for (;;) - { - c = *++s; - *++d = c; - - if (c == '\n' || c == '\r') - { - /* Handle DOS line endings. */ - if (c == '\r' && s != buffer->rlimit && s[1] == '\n') - s++; - if (s == buffer->rlimit) - break; - - /* Escaped? */ - p = d; - while (p != buffer->next_line && is_nvspace (p[-1])) - p--; - if (p == buffer->next_line || p[-1] != '\\') - break; - - add_line_note (buffer, p - 1, p != d ? ' ': '\\'); - d = p - 2; - buffer->next_line = p - 1; - } - else if (c == '?' && s[1] == '?' && _cpp_trigraph_map[s[2]]) - { - /* Add a note regardless, for the benefit of -Wtrigraphs. */ - add_line_note (buffer, d, s[2]); - if (CPP_OPTION (pfile, trigraphs)) - { - *d = _cpp_trigraph_map[s[2]]; - s += 2; - } - } - } - } - else - { - do - s++; - while (*s != '\n' && *s != '\r'); - d = (uchar *) s; - - /* Handle DOS line endings. */ - if (*s == '\r' && s != buffer->rlimit && s[1] == '\n') - s++; - } - - done: - *d = '\n'; - /* A sentinel note that should never be processed. */ - add_line_note (buffer, d + 1, '\n'); - buffer->next_line = s + 1; -} - -/* Return true if the trigraph indicated by NOTE should be warned - about in a comment. */ -static bool -warn_in_comment (cpp_reader *pfile, _cpp_line_note *note) -{ - const uchar *p; - - /* Within comments we don't warn about trigraphs, unless the - trigraph forms an escaped newline, as that may change - behavior. */ - if (note->type != '/') - return false; - - /* If -trigraphs, then this was an escaped newline iff the next note - is coincident. */ - if (CPP_OPTION (pfile, trigraphs)) - return note[1].pos == note->pos; - - /* Otherwise, see if this forms an escaped newline. */ - p = note->pos + 3; - while (is_nvspace (*p)) - p++; - - /* There might have been escaped newlines between the trigraph and the - newline we found. Hence the position test. */ - return (*p == '\n' && p < note[1].pos); -} - -/* Process the notes created by add_line_note as far as the current - location. */ -void -_cpp_process_line_notes (cpp_reader *pfile, int in_comment) -{ - cpp_buffer *buffer = pfile->buffer; - - for (;;) - { - _cpp_line_note *note = &buffer->notes[buffer->cur_note]; - unsigned int col; - - if (note->pos > buffer->cur) - break; - - buffer->cur_note++; - col = CPP_BUF_COLUMN (buffer, note->pos + 1); - - if (note->type == '\\' || note->type == ' ') - { - if (note->type == ' ' && !in_comment) - cpp_error_with_line (pfile, CPP_DL_WARNING, pfile->line, col, - "backslash and newline separated by space"); - - if (buffer->next_line > buffer->rlimit) - { - cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->line, col, - "backslash-newline at end of file"); - /* Prevent "no newline at end of file" warning. */ - buffer->next_line = buffer->rlimit; - } - - buffer->line_base = note->pos; - pfile->line++; - } - else if (_cpp_trigraph_map[note->type]) - { - if (CPP_OPTION (pfile, warn_trigraphs) - && (!in_comment || warn_in_comment (pfile, note))) - { - if (CPP_OPTION (pfile, trigraphs)) - cpp_error_with_line (pfile, CPP_DL_WARNING, pfile->line, col, - "trigraph ??%c converted to %c", - note->type, - (int) _cpp_trigraph_map[note->type]); - else - { - cpp_error_with_line - (pfile, CPP_DL_WARNING, pfile->line, col, - "trigraph ??%c ignored, use -trigraphs to enable", - note->type); - } - } - } - else - abort (); - } -} - -/* SDCC _asm specific */ -/* Skip an _asm ... _endasm block. We find the end of the comment by - seeing _endasm. Returns non-zero if _asm terminated by EOF, zero - otherwise. */ -static int -skip_asm_block (cpp_reader *pfile) -{ -#define _ENDASM_STR "endasm" -#define _ENDASM_LEN ((sizeof _ENDASM_STR) - 1) - - cpp_buffer *buffer = pfile->buffer; - cppchar_t c = EOF; - int prev_space = 0; - int ret = 1; - - while (buffer->cur != buffer->rlimit) - { - prev_space = is_space(c); - c = *buffer->cur++; - - if (prev_space && c == '_') - { - if (buffer->cur + _ENDASM_LEN <= buffer->rlimit && - strncmp(buffer->cur, _ENDASM_STR, _ENDASM_LEN) == 0) - { - buffer->cur += _ENDASM_LEN; - ret = 0; - break; - } - } - else if (c == '\n') - { - --buffer->cur; - _cpp_process_line_notes (pfile, true); - if (buffer->next_line >= buffer->rlimit) - return true; - _cpp_clean_line (pfile); - pfile->line++; - } - } - - _cpp_process_line_notes (pfile, true); - return ret; -} - -/* Skip a C-style block comment. We find the end of the comment by - seeing if an asterisk is before every '/' we encounter. Returns - nonzero if comment terminated by EOF, zero otherwise. - - Buffer->cur points to the initial asterisk of the comment. */ -bool -_cpp_skip_block_comment (cpp_reader *pfile) -{ - cpp_buffer *buffer = pfile->buffer; - const uchar *cur = buffer->cur; - uchar c; - - cur++; - if (*cur == '/') - cur++; - - for (;;) - { - /* People like decorating comments with '*', so check for '/' - instead for efficiency. */ - c = *cur++; - - if (c == '/') - { - if (cur[-2] == '*') - break; - - /* Warn about potential nested comments, but not if the '/' - comes immediately before the true comment delimiter. - Don't bother to get it right across escaped newlines. */ - if (CPP_OPTION (pfile, warn_comments) - && cur[0] == '*' && cur[1] != '/') - { - buffer->cur = cur; - cpp_error_with_line (pfile, CPP_DL_WARNING, - pfile->line, CPP_BUF_COL (buffer), - "\"/*\" within comment"); - } - } - else if (c == '\n') - { - buffer->cur = cur - 1; - _cpp_process_line_notes (pfile, true); - if (buffer->next_line >= buffer->rlimit) - return true; - _cpp_clean_line (pfile); - pfile->line++; - cur = buffer->cur; - } - } - - buffer->cur = cur; - _cpp_process_line_notes (pfile, true); - return false; -} - -/* Skip a C++ line comment, leaving buffer->cur pointing to the - terminating newline. Handles escaped newlines. Returns nonzero - if a multiline comment. */ -static int -skip_line_comment (cpp_reader *pfile) -{ - cpp_buffer *buffer = pfile->buffer; - unsigned int orig_line = pfile->line; - - while (*buffer->cur != '\n') - buffer->cur++; - - _cpp_process_line_notes (pfile, true); - return orig_line != pfile->line; -} - -/* Skips whitespace, saving the next non-whitespace character. */ -static void -skip_whitespace (cpp_reader *pfile, cppchar_t c) -{ - cpp_buffer *buffer = pfile->buffer; - bool saw_NUL = false; - - do - { - /* Horizontal space always OK. */ - if (c == ' ' || c == '\t') - ; - /* Just \f \v or \0 left. */ - else if (c == '\0') - saw_NUL = true; - else if (pfile->state.in_directive && CPP_PEDANTIC (pfile)) - cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->line, - CPP_BUF_COL (buffer), - "%s in preprocessing directive", - c == '\f' ? "form feed" : "vertical tab"); - - c = *buffer->cur++; - } - /* We only want non-vertical space, i.e. ' ' \t \f \v \0. */ - while (is_nvspace (c)); - - if (saw_NUL) - cpp_error (pfile, CPP_DL_WARNING, "null character(s) ignored"); - - buffer->cur--; -} - -/* See if the characters of a number token are valid in a name (no - '.', '+' or '-'). */ -static int -name_p (cpp_reader *pfile, const cpp_string *string) -{ - unsigned int i; - - for (i = 0; i < string->len; i++) - if (!is_idchar (string->text[i])) - return 0; - - return 1; -} - -/* Returns TRUE if the sequence starting at buffer->cur is invalid in - an identifier. FIRST is TRUE if this starts an identifier. */ -static bool -forms_identifier_p (cpp_reader *pfile, int first) -{ - cpp_buffer *buffer = pfile->buffer; - - if (*buffer->cur == '$') - { - if (!CPP_OPTION (pfile, dollars_in_ident)) - return false; - - buffer->cur++; - if (CPP_OPTION (pfile, warn_dollars) && !pfile->state.skipping) - { - CPP_OPTION (pfile, warn_dollars) = 0; - cpp_error (pfile, CPP_DL_PEDWARN, "'$' in identifier or number"); - } - - return true; - } - - /* Is this a syntactically valid UCN? */ - if (0 && *buffer->cur == '\\' - && (buffer->cur[1] == 'u' || buffer->cur[1] == 'U')) - { - buffer->cur += 2; - if (_cpp_valid_ucn (pfile, &buffer->cur, buffer->rlimit, 1 + !first)) - return true; - buffer->cur -= 2; - } - - return false; -} - -/* Lex an identifier starting at BUFFER->CUR - 1. */ -static cpp_hashnode * -lex_identifier (cpp_reader *pfile, const uchar *base) -{ - cpp_hashnode *result; - const uchar *cur; - - do - { - cur = pfile->buffer->cur; - - /* N.B. ISIDNUM does not include $. */ - while (ISIDNUM (*cur)) - cur++; - - pfile->buffer->cur = cur; - } - while (forms_identifier_p (pfile, false)); - - result = (cpp_hashnode *) - ht_lookup (pfile->hash_table, base, cur - base, HT_ALLOC); - - /* Rarely, identifiers require diagnostics when lexed. */ - if (__builtin_expect ((result->flags & NODE_DIAGNOSTIC) - && !pfile->state.skipping, 0)) - { - /* It is allowed to poison the same identifier twice. */ - if ((result->flags & NODE_POISONED) && !pfile->state.poisoned_ok) - cpp_error (pfile, CPP_DL_ERROR, "attempt to use poisoned \"%s\"", - NODE_NAME (result)); - - /* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the - replacement list of a variadic macro. */ - if (result == pfile->spec_nodes.n__VA_ARGS__ - && !pfile->state.va_args_ok) - cpp_error (pfile, CPP_DL_PEDWARN, - "__VA_ARGS__ can only appear in the expansion" - " of a C99 variadic macro"); - } - - return result; -} - -/* SDCC specific */ -/* Pedantic parse a number, beginning with character C, skipping embedded - backslash-newlines. LEADING_PERIOD is nonzero if there was a "." - before C. Place the result in NUMBER. */ -static void -pedantic_lex_number (cpp_reader *pfile, cpp_string *number) -{ -#define get_effective_char(pfile) (*pfile->buffer->cur++) -#define BACKUP() (--pfile->buffer->cur) - - enum num_type_e { NT_DEC, NT_HEX } num_type = NT_DEC; - enum num_part_e { NP_WHOLE, NP_FRACT, NP_EXP, NP_INT_SUFFIX, NP_FLOAT_SUFFIX } num_part = NP_WHOLE; - - uchar c = *(pfile->buffer->cur - 1); - struct obstack *stack = &pfile->hash_table->stack; - cpp_buffer *buffer = pfile->buffer; - int len = 0; - int has_whole = 0; - int has_fract = 0; - - if ('.' == c) - { - num_part = NP_FRACT; - ++len; - obstack_1grow (stack, '.'); - c = get_effective_char(pfile); - } - else - { - if ('0' == c) - { - has_whole = 1; - ++len; - obstack_1grow (stack, c); - c = get_effective_char(pfile); - - switch (c) - { - case 'X': - case 'x': - num_type = NT_HEX; - ++len; - obstack_1grow (stack, c); - c = get_effective_char(pfile); - break; - - case '.': - num_part = NP_FRACT; - ++len; - obstack_1grow (stack, c); - c = get_effective_char(pfile); - break; - } - } - } - - for (; ; ) - { - switch (num_part) - { - case NP_WHOLE: - if (NT_DEC == num_type) - { - while (ISDIGIT (c)) - { - has_whole = 1; - ++len; - obstack_1grow (stack, c); - c = get_effective_char(pfile); - } - - if ('.' == c) - { - num_part = NP_FRACT; - ++len; - obstack_1grow (stack, c); - c = get_effective_char(pfile); - continue; - } - else if ('E' == c || 'e' == c) - { - if (has_whole || has_fract) - { - num_part = NP_EXP; - ++len; - obstack_1grow (stack, c); - c = get_effective_char(pfile); - continue; - } - else - break; - } - } - else - { - while (ISXDIGIT (c)) - { - has_whole = 1; - ++len; - obstack_1grow (stack, c); - c = get_effective_char(pfile); - } - - if ('.' == c) - { - num_part = NP_FRACT; - ++len; - obstack_1grow (stack, c); - c = get_effective_char(pfile); - continue; - } - else if ('P' == c || 'p' == c) - { - if (has_whole || has_fract) - { - num_part = NP_EXP; - ++len; - obstack_1grow (stack, c); - c = get_effective_char(pfile); - continue; - } - else - break; - } - } - num_part = NP_INT_SUFFIX; - continue; - - case NP_FRACT: - if (NT_DEC == num_type) - { - while (ISDIGIT (c)) - { - has_fract = 1; - ++len; - obstack_1grow (stack, c); - c = get_effective_char(pfile); - } - - if ('E' == c || 'e' == c) - { - if (has_whole || has_fract) - { - num_part = NP_EXP; - ++len; - obstack_1grow (stack, c); - c = get_effective_char(pfile); - continue; - } - } - } - else - { - while (ISXDIGIT (c)) - { - has_fract = 1; - ++len; - obstack_1grow (stack, c); - c = get_effective_char(pfile); - } - - if ('P' == c || 'p' == c) - { - if (has_whole || has_fract) - { - num_part = NP_EXP; - ++len; - obstack_1grow (stack, c); - c = get_effective_char(pfile); - continue; - } - } - } - num_part = NP_FLOAT_SUFFIX; - continue; - - case NP_EXP: - if ('+' == c || '-' == c) - { - ++len; - obstack_1grow (stack, c); - c = get_effective_char(pfile); - } - - while (ISDIGIT (c)) - { - ++len; - obstack_1grow (stack, c); - c = get_effective_char(pfile); - } - - num_part = NP_FLOAT_SUFFIX; - continue; - - case NP_INT_SUFFIX: - if ('L' == c || 'l' == c) - { - uchar prevc = c; - - ++len; - obstack_1grow (stack, c); - c = get_effective_char(pfile); - - if (c == prevc) - { - ++len; - obstack_1grow (stack, c); - c = get_effective_char(pfile); - } - } - else if ('U' == c || 'u' == c) - { - ++len; - obstack_1grow (stack, c); - c = get_effective_char(pfile); - } - break; - - case NP_FLOAT_SUFFIX: - if ('F' == c || 'f' == c) - { - ++len; - obstack_1grow (stack, c); - c = get_effective_char(pfile); - } - else if ('L' == c || 'l' == c) - { - ++len; - obstack_1grow (stack, c); - c = get_effective_char(pfile); - } - break; - } - break; - } - - /* Step back over the unwanted char. */ - BACKUP (); - - number->text = obstack_finish (stack); - number->len = len; -} - -/* Lex a number to NUMBER starting at BUFFER->CUR - 1. */ -static void -lex_number (cpp_reader *pfile, cpp_string *number) -{ - const uchar *cur; - const uchar *base; - uchar *dest; - - base = pfile->buffer->cur - 1; - do - { - cur = pfile->buffer->cur; - - /* N.B. ISIDNUM does not include $. */ - while (ISIDNUM (*cur) || *cur == '.' || VALID_SIGN (*cur, cur[-1])) - cur++; - - pfile->buffer->cur = cur; - } - while (forms_identifier_p (pfile, false)); - - number->len = cur - base; - dest = _cpp_unaligned_alloc (pfile, number->len + 1); - memcpy (dest, base, number->len); - dest[number->len] = '\0'; - number->text = dest; -} - -/* Create a token of type TYPE with a literal spelling. */ -static void -create_literal (cpp_reader *pfile, cpp_token *token, const uchar *base, - unsigned int len, enum cpp_ttype type) -{ - uchar *dest = _cpp_unaligned_alloc (pfile, len + 1); - - memcpy (dest, base, len); - dest[len] = '\0'; - token->type = type; - token->val.str.len = len; - token->val.str.text = dest; -} - -/* Lexes a string, character constant, or angle-bracketed header file - name. The stored string contains the spelling, including opening - quote and leading any leading 'L'. It returns the type of the - literal, or CPP_OTHER if it was not properly terminated. - - The spelling is NUL-terminated, but it is not guaranteed that this - is the first NUL since embedded NULs are preserved. */ -static void -lex_string (cpp_reader *pfile, cpp_token *token, const uchar *base) -{ - bool saw_NUL = false; - const uchar *cur; - cppchar_t terminator; - enum cpp_ttype type; - - cur = base; - terminator = *cur++; - if (terminator == 'L') - terminator = *cur++; - if (terminator == '\"') - type = *base == 'L' ? CPP_WSTRING: CPP_STRING; - else if (terminator == '\'') - type = *base == 'L' ? CPP_WCHAR: CPP_CHAR; - else - terminator = '>', type = CPP_HEADER_NAME; - - for (;;) - { - cppchar_t c = *cur++; - - /* In #include-style directives, terminators are not escapable. */ - if (c == '\\' && !pfile->state.angled_headers && *cur != '\n') - cur++; - else if (c == terminator) - break; - else if (c == '\n') - { - cur--; - type = CPP_OTHER; - break; - } - else if (c == '\0') - saw_NUL = true; - } - - if (saw_NUL && !pfile->state.skipping) - cpp_error (pfile, CPP_DL_WARNING, - "null character(s) preserved in literal"); - - pfile->buffer->cur = cur; - create_literal (pfile, token, base, cur - base, type); -} - -/* Fixed _WIN32 problem with CR-CR-LF sequences when outputting - comment blocks (when executed with -C option) and - _asm (SDCPP specific) blocks */ - -/* Count and copy characters from src to dest, excluding CRs: - CRs are automatically generated, because the output is - opened in TEXT mode. If dest == NULL, only count chars */ -static unsigned int -copy_text_chars (char *dest, const char *src, unsigned int len) -{ - unsigned int n = 0; - const char *p; - - for (p = src; p != src + len; ++p) - { - assert(*p != '\0'); - - if (*p != '\r') - { - if (dest != NULL) - *dest++ = *p; - ++n; - } - } - - return n; -} - -/* SDCC _asm specific */ -/* The stored comment includes the comment start and any terminator. */ -static void -save_asm (cpp_reader *pfile, cpp_token *token, const unsigned char *from) -{ -#define _ASM_STR "_asm" -#define _ASM_LEN ((sizeof _ASM_STR) - 1) - - unsigned char *buffer; - unsigned int text_len, len; - - len = pfile->buffer->cur - from; - /* + _ASM_LEN for the initial '_asm'. */ - text_len = copy_text_chars (NULL, from, len) + _ASM_LEN; - buffer = _cpp_unaligned_alloc (pfile, text_len); - - - token->type = CPP_ASM; - token->val.str.len = text_len; - token->val.str.text = buffer; - - memcpy (buffer, _ASM_STR, _ASM_LEN); - copy_text_chars (buffer + _ASM_LEN, from, len); -} - -/* The stored comment includes the comment start and any terminator. */ -static void -save_comment (cpp_reader *pfile, cpp_token *token, const unsigned char *from, - cppchar_t type) -{ - unsigned char *buffer; - unsigned int len, clen; - - len = pfile->buffer->cur - from + 1; /* + 1 for the initial '/'. */ - - /* C++ comments probably (not definitely) have moved past a new - line, which we don't want to save in the comment. */ - if (is_vspace (pfile->buffer->cur[-1])) - len--; - - /* If we are currently in a directive, then we need to store all - C++ comments as C comments internally, and so we need to - allocate a little extra space in that case. - - Note that the only time we encounter a directive here is - when we are saving comments in a "#define". */ - clen = (pfile->state.in_directive && type == '/') ? len + 2 : len; - - buffer = _cpp_unaligned_alloc (pfile, clen); - - token->type = CPP_COMMENT; - token->val.str.len = clen; - token->val.str.text = buffer; - - buffer[0] = '/'; - copy_text_chars (buffer + 1, from, len); - - /* Finish conversion to a C comment, if necessary. */ - if (pfile->state.in_directive && type == '/') - { - buffer[1] = '*'; - buffer[clen - 2] = '*'; - buffer[clen - 1] = '/'; - } -} - -/* Allocate COUNT tokens for RUN. */ -void -_cpp_init_tokenrun (tokenrun *run, unsigned int count) -{ - run->base = xnewvec (cpp_token, count); - run->limit = run->base + count; - run->next = NULL; -} - -/* Returns the next tokenrun, or creates one if there is none. */ -static tokenrun * -next_tokenrun (tokenrun *run) -{ - if (run->next == NULL) - { - run->next = xnew (tokenrun); - run->next->prev = run; - _cpp_init_tokenrun (run->next, 250); - } - - return run->next; -} - -/* Allocate a single token that is invalidated at the same time as the - rest of the tokens on the line. Has its line and col set to the - same as the last lexed token, so that diagnostics appear in the - right place. */ -cpp_token * -_cpp_temp_token (cpp_reader *pfile) -{ - cpp_token *old, *result; - - old = pfile->cur_token - 1; - if (pfile->cur_token == pfile->cur_run->limit) - { - pfile->cur_run = next_tokenrun (pfile->cur_run); - pfile->cur_token = pfile->cur_run->base; - } - - result = pfile->cur_token++; - result->line = old->line; - result->col = old->col; - return result; -} - -/* Lex a token into RESULT (external interface). Takes care of issues - like directive handling, token lookahead, multiple include - optimization and skipping. */ -const cpp_token * -_cpp_lex_token (cpp_reader *pfile) -{ - cpp_token *result; - - for (;;) - { - if (pfile->cur_token == pfile->cur_run->limit) - { - pfile->cur_run = next_tokenrun (pfile->cur_run); - pfile->cur_token = pfile->cur_run->base; - } - - if (pfile->lookaheads) - { - pfile->lookaheads--; - result = pfile->cur_token++; - } - else - result = _cpp_lex_direct (pfile); - - if (result->flags & BOL) - { - /* Is this a directive. If _cpp_handle_directive returns - false, it is an assembler #. */ - if (result->type == CPP_HASH - /* 6.10.3 p 11: Directives in a list of macro arguments - gives undefined behavior. This implementation - handles the directive as normal. */ - && pfile->state.parsing_args != 1 - && _cpp_handle_directive (pfile, result->flags & PREV_WHITE)) - continue; - if (pfile->cb.line_change && !pfile->state.skipping) - pfile->cb.line_change (pfile, result, pfile->state.parsing_args); - } - - /* We don't skip tokens in directives. */ - if (pfile->state.in_directive) - break; - - /* Outside a directive, invalidate controlling macros. At file - EOF, _cpp_lex_direct takes care of popping the buffer, so we never - get here and MI optimization works. */ - pfile->mi_valid = false; - - if (!pfile->state.skipping || result->type == CPP_EOF) - break; - } - - return result; -} - -/* Returns true if a fresh line has been loaded. */ -bool -_cpp_get_fresh_line (cpp_reader *pfile) -{ - int return_at_eof; - - /* We can't get a new line until we leave the current directive. */ - if (pfile->state.in_directive) - return false; - - for (;;) - { - cpp_buffer *buffer = pfile->buffer; - - if (!buffer->need_line) - return true; - - if (buffer->next_line < buffer->rlimit) - { - _cpp_clean_line (pfile); - return true; - } - - /* First, get out of parsing arguments state. */ - if (pfile->state.parsing_args) - return false; - - /* End of buffer. Non-empty files should end in a newline. */ - if (buffer->buf != buffer->rlimit - && buffer->next_line > buffer->rlimit - && !buffer->from_stage3) - { - /* Only warn once. */ - buffer->next_line = buffer->rlimit; - cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->line - 1, - CPP_BUF_COLUMN (buffer, buffer->cur), - "no newline at end of file"); - } - - return_at_eof = buffer->return_at_eof; - _cpp_pop_buffer (pfile); - if (pfile->buffer == NULL || return_at_eof) - return false; - } -} - -#define IF_NEXT_IS(CHAR, THEN_TYPE, ELSE_TYPE) \ - do \ - { \ - result->type = ELSE_TYPE; \ - if (*buffer->cur == CHAR) \ - buffer->cur++, result->type = THEN_TYPE; \ - } \ - while (0) - -/* Lex a token into pfile->cur_token, which is also incremented, to - get diagnostics pointing to the correct location. - - Does not handle issues such as token lookahead, multiple-include - optimization, directives, skipping etc. This function is only - suitable for use by _cpp_lex_token, and in special cases like - lex_expansion_token which doesn't care for any of these issues. - - When meeting a newline, returns CPP_EOF if parsing a directive, - otherwise returns to the start of the token buffer if permissible. - Returns the location of the lexed token. */ -cpp_token * -_cpp_lex_direct (cpp_reader *pfile) -{ - cppchar_t c; - cpp_buffer *buffer; - const unsigned char *comment_start; - cpp_token *result = pfile->cur_token++; - - fresh_line: - result->flags = 0; - buffer = pfile->buffer; - if (buffer->need_line) - { - if (!_cpp_get_fresh_line (pfile)) - { - result->type = CPP_EOF; - if (!pfile->state.in_directive) - { - /* Tell the compiler the line number of the EOF token. */ - result->line = pfile->line; - result->flags = BOL; - } - return result; - } - if (!pfile->keep_tokens) - { - pfile->cur_run = &pfile->base_run; - result = pfile->base_run.base; - pfile->cur_token = result + 1; - } - result->flags = BOL; - if (pfile->state.parsing_args == 2) - result->flags |= PREV_WHITE; - } - buffer = pfile->buffer; - update_tokens_line: - result->line = pfile->line; - - skipped_white: - if (buffer->cur >= buffer->notes[buffer->cur_note].pos - && !pfile->overlaid_buffer) - { - _cpp_process_line_notes (pfile, false); - result->line = pfile->line; - } - c = *buffer->cur++; - result->col = CPP_BUF_COLUMN (buffer, buffer->cur); - - switch (c) - { - case ' ': case '\t': case '\f': case '\v': case '\0': - result->flags |= PREV_WHITE; - skip_whitespace (pfile, c); - goto skipped_white; - - case '\n': - pfile->line++; - buffer->need_line = true; - goto fresh_line; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - result->type = CPP_NUMBER; - if (CPP_OPTION(pfile, pedantic_parse_number)) - pedantic_lex_number (pfile, &result->val.str); - else - lex_number (pfile, &result->val.str); - break; - - case 'L': - /* 'L' may introduce wide characters or strings. */ - if (*buffer->cur == '\'' || *buffer->cur == '"') - { - lex_string (pfile, result, buffer->cur - 1); - break; - } - /* Fall through. */ - - case '_': - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': - case 's': case 't': case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - case 'G': case 'H': case 'I': case 'J': case 'K': - case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': - case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - result->type = CPP_NAME; - result->val.node = lex_identifier (pfile, buffer->cur - 1); - - /* SDCC _asm specific */ - /* handle _asm ... _endasm ; */ - if (CPP_OPTION(pfile, preproc_asm) == 0 && result->val.node == pfile->spec_nodes.n__asm) - { - comment_start = buffer->cur; - result->type = CPP_ASM; - skip_asm_block (pfile); - /* Save the _asm block as a token in its own right. */ - save_asm (pfile, result, comment_start); - } - /* Convert named operators to their proper types. */ - else if (result->val.node->flags & NODE_OPERATOR) - { - result->flags |= NAMED_OP; - result->type = result->val.node->directive_index; - } - break; - - case '\'': - case '"': - lex_string (pfile, result, buffer->cur - 1); - break; - - case '/': - /* A potential block or line comment. */ - comment_start = buffer->cur; - c = *buffer->cur; - - if (c == '*') - { - if (_cpp_skip_block_comment (pfile)) - cpp_error (pfile, CPP_DL_ERROR, "unterminated comment"); - } - else if (c == '/' && (CPP_OPTION (pfile, cplusplus_comments) - || CPP_IN_SYSTEM_HEADER (pfile))) - { - /* Warn about comments only if pedantically GNUC89, and not - in system headers. */ - if (CPP_OPTION (pfile, lang) == CLK_GNUC89 && CPP_PEDANTIC (pfile) - && ! buffer->warned_cplusplus_comments) - { - cpp_error (pfile, CPP_DL_PEDWARN, - "C++ style comments are not allowed in ISO C90"); - cpp_error (pfile, CPP_DL_PEDWARN, - "(this will be reported only once per input file)"); - buffer->warned_cplusplus_comments = 1; - } - - if (skip_line_comment (pfile) && CPP_OPTION (pfile, warn_comments)) - cpp_error (pfile, CPP_DL_WARNING, "multi-line comment"); - } - else if (c == '=') - { - buffer->cur++; - result->type = CPP_DIV_EQ; - break; - } - else - { - result->type = CPP_DIV; - break; - } - - if (!pfile->state.save_comments) - { - result->flags |= PREV_WHITE; - goto update_tokens_line; - } - - /* Save the comment as a token in its own right. */ - save_comment (pfile, result, comment_start, c); - break; - - case '<': - if (pfile->state.angled_headers) - { - lex_string (pfile, result, buffer->cur - 1); - break; - } - - result->type = CPP_LESS; - if (*buffer->cur == '=') - buffer->cur++, result->type = CPP_LESS_EQ; - else if (*buffer->cur == '<') - { - buffer->cur++; - IF_NEXT_IS ('=', CPP_LSHIFT_EQ, CPP_LSHIFT); - } - else if (*buffer->cur == '?' && CPP_OPTION (pfile, cplusplus)) - { - buffer->cur++; - IF_NEXT_IS ('=', CPP_MIN_EQ, CPP_MIN); - } - else if (CPP_OPTION (pfile, digraphs)) - { - if (*buffer->cur == ':') - { - buffer->cur++; - result->flags |= DIGRAPH; - result->type = CPP_OPEN_SQUARE; - } - else if (*buffer->cur == '%') - { - buffer->cur++; - result->flags |= DIGRAPH; - result->type = CPP_OPEN_BRACE; - } - } - break; - - case '>': - result->type = CPP_GREATER; - if (*buffer->cur == '=') - buffer->cur++, result->type = CPP_GREATER_EQ; - else if (*buffer->cur == '>') - { - buffer->cur++; - IF_NEXT_IS ('=', CPP_RSHIFT_EQ, CPP_RSHIFT); - } - else if (*buffer->cur == '?' && CPP_OPTION (pfile, cplusplus)) - { - buffer->cur++; - IF_NEXT_IS ('=', CPP_MAX_EQ, CPP_MAX); - } - break; - - case '%': - result->type = CPP_MOD; - if (*buffer->cur == '=') - buffer->cur++, result->type = CPP_MOD_EQ; - else if (CPP_OPTION (pfile, digraphs)) - { - if (*buffer->cur == ':') - { - buffer->cur++; - result->flags |= DIGRAPH; - result->type = CPP_HASH; - if (*buffer->cur == '%' && buffer->cur[1] == ':') - buffer->cur += 2, result->type = CPP_PASTE; - } - else if (*buffer->cur == '>') - { - buffer->cur++; - result->flags |= DIGRAPH; - result->type = CPP_CLOSE_BRACE; - } - } - break; - - case '.': - result->type = CPP_DOT; - if (ISDIGIT (*buffer->cur)) - { - result->type = CPP_NUMBER; - if (CPP_OPTION(pfile, pedantic_parse_number)) - pedantic_lex_number (pfile, &result->val.str); - else - lex_number (pfile, &result->val.str); - } - else if (*buffer->cur == '.' && buffer->cur[1] == '.') - buffer->cur += 2, result->type = CPP_ELLIPSIS; - else if (*buffer->cur == '*' && CPP_OPTION (pfile, cplusplus)) - buffer->cur++, result->type = CPP_DOT_STAR; - break; - - case '+': - result->type = CPP_PLUS; - if (*buffer->cur == '+') - buffer->cur++, result->type = CPP_PLUS_PLUS; - else if (*buffer->cur == '=') - buffer->cur++, result->type = CPP_PLUS_EQ; - break; - - case '-': - result->type = CPP_MINUS; - if (*buffer->cur == '>') - { - buffer->cur++; - result->type = CPP_DEREF; - if (*buffer->cur == '*' && CPP_OPTION (pfile, cplusplus)) - buffer->cur++, result->type = CPP_DEREF_STAR; - } - else if (*buffer->cur == '-') - buffer->cur++, result->type = CPP_MINUS_MINUS; - else if (*buffer->cur == '=') - buffer->cur++, result->type = CPP_MINUS_EQ; - break; - - case '&': - result->type = CPP_AND; - if (*buffer->cur == '&') - buffer->cur++, result->type = CPP_AND_AND; - else if (*buffer->cur == '=') - buffer->cur++, result->type = CPP_AND_EQ; - break; - - case '|': - result->type = CPP_OR; - if (*buffer->cur == '|') - buffer->cur++, result->type = CPP_OR_OR; - else if (*buffer->cur == '=') - buffer->cur++, result->type = CPP_OR_EQ; - break; - - case ':': - result->type = CPP_COLON; - if (*buffer->cur == ':' && CPP_OPTION (pfile, cplusplus)) - buffer->cur++, result->type = CPP_SCOPE; - else if (*buffer->cur == '>' && CPP_OPTION (pfile, digraphs)) - { - buffer->cur++; - result->flags |= DIGRAPH; - result->type = CPP_CLOSE_SQUARE; - } - break; - - case '*': IF_NEXT_IS ('=', CPP_MULT_EQ, CPP_MULT); break; - case '=': IF_NEXT_IS ('=', CPP_EQ_EQ, CPP_EQ); break; - case '!': IF_NEXT_IS ('=', CPP_NOT_EQ, CPP_NOT); break; - case '^': IF_NEXT_IS ('=', CPP_XOR_EQ, CPP_XOR); break; - case '#': IF_NEXT_IS ('#', CPP_PASTE, CPP_HASH); break; - - case '?': result->type = CPP_QUERY; break; - case '~': result->type = CPP_COMPL; break; - case ',': result->type = CPP_COMMA; break; - case '(': result->type = CPP_OPEN_PAREN; break; - case ')': result->type = CPP_CLOSE_PAREN; break; - case '[': result->type = CPP_OPEN_SQUARE; break; - case ']': result->type = CPP_CLOSE_SQUARE; break; - case '{': result->type = CPP_OPEN_BRACE; break; - case '}': result->type = CPP_CLOSE_BRACE; break; - case ';': result->type = CPP_SEMICOLON; break; - - /* @ is a punctuator in Objective-C. */ - case '@': result->type = CPP_ATSIGN; break; - - case '$': - case '\\': - { - const uchar *base = --buffer->cur; - - if (forms_identifier_p (pfile, true)) - { - result->type = CPP_NAME; - result->val.node = lex_identifier (pfile, base); - break; - } - buffer->cur++; - } - - default: - create_literal (pfile, result, buffer->cur - 1, 1, CPP_OTHER); - break; - } - - return result; -} - -/* An upper bound on the number of bytes needed to spell TOKEN. - Does not include preceding whitespace. */ -unsigned int -cpp_token_len (const cpp_token *token) -{ - unsigned int len; - - switch (TOKEN_SPELL (token)) - { - default: len = 4; break; - case SPELL_LITERAL: len = token->val.str.len; break; - case SPELL_IDENT: len = NODE_LEN (token->val.node); break; - } - - return len; -} - -/* Write the spelling of a token TOKEN to BUFFER. The buffer must - already contain the enough space to hold the token's spelling. - Returns a pointer to the character after the last character written. - FIXME: Would be nice if we didn't need the PFILE argument. */ -unsigned char * -cpp_spell_token (cpp_reader *pfile, const cpp_token *token, - unsigned char *buffer) -{ - switch (TOKEN_SPELL (token)) - { - case SPELL_OPERATOR: - { - const unsigned char *spelling; - unsigned char c; - - if (token->flags & DIGRAPH) - spelling - = digraph_spellings[(int) token->type - (int) CPP_FIRST_DIGRAPH]; - else if (token->flags & NAMED_OP) - goto spell_ident; - else - spelling = TOKEN_NAME (token); - - while ((c = *spelling++) != '\0') - *buffer++ = c; - } - break; - - spell_ident: - case SPELL_IDENT: - memcpy (buffer, NODE_NAME (token->val.node), NODE_LEN (token->val.node)); - buffer += NODE_LEN (token->val.node); - break; - - case SPELL_LITERAL: - memcpy (buffer, token->val.str.text, token->val.str.len); - buffer += token->val.str.len; - break; - - case SPELL_NONE: - cpp_error (pfile, CPP_DL_ICE, - "unspellable token %s", TOKEN_NAME (token)); - break; - } - - return buffer; -} - -/* Returns TOKEN spelt as a null-terminated string. The string is - freed when the reader is destroyed. Useful for diagnostics. */ -unsigned char * -cpp_token_as_text (cpp_reader *pfile, const cpp_token *token) -{ - unsigned int len = cpp_token_len (token) + 1; - unsigned char *start = _cpp_unaligned_alloc (pfile, len), *end; - - end = cpp_spell_token (pfile, token, start); - end[0] = '\0'; - - return start; -} - -/* Used by C front ends, which really should move to using - cpp_token_as_text. */ -const char * -cpp_type2name (enum cpp_ttype type) -{ - return (const char *) token_spellings[type].name; -} - -/* Writes the spelling of token to FP, without any preceding space. - Separated from cpp_spell_token for efficiency - to avoid stdio - double-buffering. */ -void -cpp_output_token (const cpp_token *token, FILE *fp) -{ - switch (TOKEN_SPELL (token)) - { - case SPELL_OPERATOR: - { - const unsigned char *spelling; - int c; - - if (token->flags & DIGRAPH) - spelling - = digraph_spellings[(int) token->type - (int) CPP_FIRST_DIGRAPH]; - else if (token->flags & NAMED_OP) - goto spell_ident; - else - spelling = TOKEN_NAME (token); - - c = *spelling; - do - putc (c, fp); - while ((c = *++spelling) != '\0'); - } - break; - - spell_ident: - case SPELL_IDENT: - fwrite (NODE_NAME (token->val.node), 1, NODE_LEN (token->val.node), fp); - break; - - case SPELL_LITERAL: - fwrite (token->val.str.text, 1, token->val.str.len, fp); - break; - - case SPELL_NONE: - /* An error, most probably. */ - break; - } -} - -/* Compare two tokens. */ -int -_cpp_equiv_tokens (const cpp_token *a, const cpp_token *b) -{ - if (a->type == b->type && a->flags == b->flags) - switch (TOKEN_SPELL (a)) - { - default: /* Keep compiler happy. */ - case SPELL_OPERATOR: - return 1; - case SPELL_NONE: - return (a->type != CPP_MACRO_ARG || a->val.arg_no == b->val.arg_no); - case SPELL_IDENT: - return a->val.node == b->val.node; - case SPELL_LITERAL: - return (a->val.str.len == b->val.str.len - && !memcmp (a->val.str.text, b->val.str.text, - a->val.str.len)); - } - - return 0; -} - -/* Returns nonzero if a space should be inserted to avoid an - accidental token paste for output. For simplicity, it is - conservative, and occasionally advises a space where one is not - needed, e.g. "." and ".2". */ -int -cpp_avoid_paste (cpp_reader *pfile, const cpp_token *token1, - const cpp_token *token2) -{ - enum cpp_ttype a = token1->type, b = token2->type; - cppchar_t c; - - if (token1->flags & NAMED_OP) - a = CPP_NAME; - if (token2->flags & NAMED_OP) - b = CPP_NAME; - - c = EOF; - if (token2->flags & DIGRAPH) - c = digraph_spellings[(int) b - (int) CPP_FIRST_DIGRAPH][0]; - else if (token_spellings[b].category == SPELL_OPERATOR) - c = token_spellings[b].name[0]; - - /* Quickly get everything that can paste with an '='. */ - if ((int) a <= (int) CPP_LAST_EQ && c == '=') - return 1; - - switch (a) - { - case CPP_GREATER: return c == '>' || c == '?'; - case CPP_LESS: return c == '<' || c == '?' || c == '%' || c == ':'; - case CPP_PLUS: return c == '+'; - case CPP_MINUS: return c == '-' || c == '>'; - case CPP_DIV: return c == '/' || c == '*'; /* Comments. */ - case CPP_MOD: return c == ':' || c == '>'; - case CPP_AND: return c == '&'; - case CPP_OR: return c == '|'; - case CPP_COLON: return c == ':' || c == '>'; - case CPP_DEREF: return c == '*'; - case CPP_DOT: return c == '.' || c == '%' || b == CPP_NUMBER; - case CPP_HASH: return c == '#' || c == '%'; /* Digraph form. */ - case CPP_NAME: return ((b == CPP_NUMBER - && name_p (pfile, &token2->val.str)) - || b == CPP_NAME - || b == CPP_CHAR || b == CPP_STRING); /* L */ - case CPP_NUMBER: return (b == CPP_NUMBER || b == CPP_NAME - || c == '.' || c == '+' || c == '-'); - /* UCNs */ - case CPP_OTHER: return ((token1->val.str.text[0] == '\\' - && b == CPP_NAME) - || (CPP_OPTION (pfile, objc) - && token1->val.str.text[0] == '@' - && (b == CPP_NAME || b == CPP_STRING))); - default: break; - } - - return 0; -} - -/* Output all the remaining tokens on the current line, and a newline - character, to FP. Leading whitespace is removed. If there are - macros, special token padding is not performed. */ -void -cpp_output_line (cpp_reader *pfile, FILE *fp) -{ - const cpp_token *token; - - token = cpp_get_token (pfile); - while (token->type != CPP_EOF) - { - cpp_output_token (token, fp); - token = cpp_get_token (pfile); - if (token->flags & PREV_WHITE) - putc (' ', fp); - } - - putc ('\n', fp); -} - -/* Memory buffers. Changing these three constants can have a dramatic - effect on performance. The values here are reasonable defaults, - but might be tuned. If you adjust them, be sure to test across a - range of uses of cpplib, including heavy nested function-like macro - expansion. Also check the change in peak memory usage (NJAMD is a - good tool for this). */ -#define MIN_BUFF_SIZE 8000 -#define BUFF_SIZE_UPPER_BOUND(MIN_SIZE) (MIN_BUFF_SIZE + (MIN_SIZE) * 3 / 2) -#define EXTENDED_BUFF_SIZE(BUFF, MIN_EXTRA) \ - (MIN_EXTRA + ((BUFF)->limit - (BUFF)->cur) * 2) - -#if MIN_BUFF_SIZE > BUFF_SIZE_UPPER_BOUND (0) - #error BUFF_SIZE_UPPER_BOUND must be at least as large as MIN_BUFF_SIZE! -#endif - -/* Create a new allocation buffer. Place the control block at the end - of the buffer, so that buffer overflows will cause immediate chaos. */ -static _cpp_buff * -new_buff (size_t len) -{ - _cpp_buff *result; - unsigned char *base; - - if (len < MIN_BUFF_SIZE) - len = MIN_BUFF_SIZE; - len = CPP_ALIGN (len); - - base = xmalloc (len + sizeof (_cpp_buff)); - result = (_cpp_buff *) (base + len); - result->base = base; - result->cur = base; - result->limit = base + len; - result->next = NULL; - return result; -} - -/* Place a chain of unwanted allocation buffers on the free list. */ -void -_cpp_release_buff (cpp_reader *pfile, _cpp_buff *buff) -{ - _cpp_buff *end = buff; - - while (end->next) - end = end->next; - end->next = pfile->free_buffs; - pfile->free_buffs = buff; -} - -/* Return a free buffer of size at least MIN_SIZE. */ -_cpp_buff * -_cpp_get_buff (cpp_reader *pfile, size_t min_size) -{ - _cpp_buff *result, **p; - - for (p = &pfile->free_buffs;; p = &(*p)->next) - { - size_t size; - - if (*p == NULL) - return new_buff (min_size); - result = *p; - size = result->limit - result->base; - /* Return a buffer that's big enough, but don't waste one that's - way too big. */ - if (size >= min_size && size <= BUFF_SIZE_UPPER_BOUND (min_size)) - break; - } - - *p = result->next; - result->next = NULL; - result->cur = result->base; - return result; -} - -/* Creates a new buffer with enough space to hold the uncommitted - remaining bytes of BUFF, and at least MIN_EXTRA more bytes. Copies - the excess bytes to the new buffer. Chains the new buffer after - BUFF, and returns the new buffer. */ -_cpp_buff * -_cpp_append_extend_buff (cpp_reader *pfile, _cpp_buff *buff, size_t min_extra) -{ - size_t size = EXTENDED_BUFF_SIZE (buff, min_extra); - _cpp_buff *new_buff = _cpp_get_buff (pfile, size); - - buff->next = new_buff; - memcpy (new_buff->base, buff->cur, BUFF_ROOM (buff)); - return new_buff; -} - -/* Creates a new buffer with enough space to hold the uncommitted - remaining bytes of the buffer pointed to by BUFF, and at least - MIN_EXTRA more bytes. Copies the excess bytes to the new buffer. - Chains the new buffer before the buffer pointed to by BUFF, and - updates the pointer to point to the new buffer. */ -void -_cpp_extend_buff (cpp_reader *pfile, _cpp_buff **pbuff, size_t min_extra) -{ - _cpp_buff *new_buff, *old_buff = *pbuff; - size_t size = EXTENDED_BUFF_SIZE (old_buff, min_extra); - - new_buff = _cpp_get_buff (pfile, size); - memcpy (new_buff->base, old_buff->cur, BUFF_ROOM (old_buff)); - new_buff->next = old_buff; - *pbuff = new_buff; -} - -/* Free a chain of buffers starting at BUFF. */ -void -_cpp_free_buff (_cpp_buff *buff) -{ - _cpp_buff *next; - - for (; buff; buff = next) - { - next = buff->next; - free (buff->base); - } -} - -/* Allocate permanent, unaligned storage of length LEN. */ -unsigned char * -_cpp_unaligned_alloc (cpp_reader *pfile, size_t len) -{ - _cpp_buff *buff = pfile->u_buff; - unsigned char *result = buff->cur; - - if (len > (size_t) (buff->limit - result)) - { - buff = _cpp_get_buff (pfile, len); - buff->next = pfile->u_buff; - pfile->u_buff = buff; - result = buff->cur; - } - - buff->cur = result + len; - return result; -} - -/* Allocate permanent, unaligned storage of length LEN from a_buff. - That buffer is used for growing allocations when saving macro - replacement lists in a #define, and when parsing an answer to an - assertion in #assert, #unassert or #if (and therefore possibly - whilst expanding macros). It therefore must not be used by any - code that they might call: specifically the lexer and the guts of - the macro expander. - - All existing other uses clearly fit this restriction: storing - registered pragmas during initialization. */ -unsigned char * -_cpp_aligned_alloc (cpp_reader *pfile, size_t len) -{ - _cpp_buff *buff = pfile->a_buff; - unsigned char *result = buff->cur; - - if (len > (size_t) (buff->limit - result)) - { - buff = _cpp_get_buff (pfile, len); - buff->next = pfile->a_buff; - pfile->a_buff = buff; - result = buff->cur; - } - - buff->cur = result + len; - return result; -} diff --git a/support/cpp2/cpplib.c b/support/cpp2/cpplib.c deleted file mode 100644 index 8a291125..00000000 --- a/support/cpp2/cpplib.c +++ /dev/null @@ -1,2071 +0,0 @@ -/* CPP Library. (Directive handling.) - Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. - Contributed by Per Bothner, 1994-95. - Based on CCCP program by Paul Rubin, June 1986 - Adapted to ANSI C, Richard Stallman, Jan 1987 - -This program 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 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include "config.h" -#include "system.h" -#include "cpplib.h" -#include "cpphash.h" -#include "obstack.h" - -/* Chained list of answers to an assertion. */ -struct answer -{ - struct answer *next; - unsigned int count; - cpp_token first[1]; -}; - -/* Stack of conditionals currently in progress - (including both successful and failing conditionals). */ -struct if_stack -{ - struct if_stack *next; - unsigned int line; /* Line where condition started. */ - const cpp_hashnode *mi_cmacro;/* macro name for #ifndef around entire file */ - bool skip_elses; /* Can future #else / #elif be skipped? */ - bool was_skipping; /* If were skipping on entry. */ - int type; /* Most recent conditional for diagnostics. */ -}; - -/* Contains a registered pragma or pragma namespace. */ -typedef void (*pragma_cb) (cpp_reader *); -struct pragma_entry -{ - struct pragma_entry *next; - const cpp_hashnode *pragma; /* Name and length. */ - int is_nspace; - union { - pragma_cb handler; - struct pragma_entry *space; - } u; -}; - -/* Values for the origin field of struct directive. KANDR directives - come from traditional (K&R) C. STDC89 directives come from the - 1989 C standard. EXTENSION directives are extensions. */ -#define KANDR 0 -#define STDC89 1 -#define EXTENSION 2 - -/* Values for the flags field of struct directive. COND indicates a - conditional; IF_COND an opening conditional. INCL means to treat - "..." and <...> as q-char and h-char sequences respectively. IN_I - means this directive should be handled even if -fpreprocessed is in - effect (these are the directives with callback hooks). - - EXPAND is set on directives that are always macro-expanded. */ -#define COND (1 << 0) -#define IF_COND (1 << 1) -#define INCL (1 << 2) -#define IN_I (1 << 3) -#define EXPAND (1 << 4) - -/* Defines one #-directive, including how to handle it. */ -typedef void (*directive_handler) (cpp_reader *); -typedef struct directive directive; -struct directive -{ - directive_handler handler; /* Function to handle directive. */ - const uchar *name; /* Name of directive. */ - unsigned short length; /* Length of name. */ - unsigned char origin; /* Origin of directive. */ - unsigned char flags; /* Flags describing this directive. */ -}; - -/* Forward declarations. */ - -static void skip_rest_of_line (cpp_reader *); -static void check_eol (cpp_reader *); -static void start_directive (cpp_reader *); -static void prepare_directive_trad (cpp_reader *); -static void end_directive (cpp_reader *, int); -static void directive_diagnostics (cpp_reader *, const directive *, int); -static void run_directive (cpp_reader *, int, const char *, size_t); -static char *glue_header_name (cpp_reader *); -static const char *parse_include (cpp_reader *, int *); -static void push_conditional (cpp_reader *, int, int, const cpp_hashnode *); -static unsigned int read_flag (cpp_reader *, unsigned int); -static int strtoul_for_line (const uchar *, unsigned int, unsigned long *); -static void do_diagnostic (cpp_reader *, int, int); -static cpp_hashnode *lex_macro_node (cpp_reader *); -static int undefine_macros (cpp_reader *, cpp_hashnode *, void *); -static void do_include_common (cpp_reader *, enum include_type); -static struct pragma_entry *lookup_pragma_entry (struct pragma_entry *, - const cpp_hashnode *); -static struct pragma_entry *insert_pragma_entry (cpp_reader *, - struct pragma_entry **, - const cpp_hashnode *, - pragma_cb); -static int count_registered_pragmas (struct pragma_entry *); -static char ** save_registered_pragmas (struct pragma_entry *, char **); -static char ** restore_registered_pragmas (cpp_reader *, struct pragma_entry *, - char **); -static void do_pragma_once (cpp_reader *); -static void do_pragma_poison (cpp_reader *); -static void do_pragma_system_header (cpp_reader *); -static void do_pragma_dependency (cpp_reader *); -static void do_pragma_sdcc_hash (cpp_reader *pfile); -static void do_pragma_preproc_asm (cpp_reader *pfile); -static void do_pragma_pedantic_parse_number (cpp_reader *pfile); -static void do_linemarker (cpp_reader *); -static const cpp_token *get_token_no_padding (cpp_reader *); -static const cpp_token *get__Pragma_string (cpp_reader *); -static void destringize_and_run (cpp_reader *, const cpp_string *); -static int parse_answer (cpp_reader *, struct answer **, int); -static cpp_hashnode *parse_assertion (cpp_reader *, struct answer **, int); -static struct answer ** find_answer (cpp_hashnode *, const struct answer *); -static void handle_assertion (cpp_reader *, const char *, int); - -/* This is the table of directive handlers. It is ordered by - frequency of occurrence; the numbers at the end are directive - counts from all the source code I have lying around (egcs and libc - CVS as of 1999-05-18, plus grub-0.5.91, linux-2.2.9, and - pcmcia-cs-3.0.9). This is no longer important as directive lookup - is now O(1). All extensions other than #warning and #include_next - are deprecated. The name is where the extension appears to have - come from. */ - -#define DIRECTIVE_TABLE \ -D(define, T_DEFINE = 0, KANDR, IN_I) /* 270554 */ \ -D(include, T_INCLUDE, KANDR, INCL | EXPAND) /* 52262 */ \ -D(endif, T_ENDIF, KANDR, COND) /* 45855 */ \ -D(ifdef, T_IFDEF, KANDR, COND | IF_COND) /* 22000 */ \ -D(if, T_IF, KANDR, COND | IF_COND | EXPAND) /* 18162 */ \ -D(else, T_ELSE, KANDR, COND) /* 9863 */ \ -D(ifndef, T_IFNDEF, KANDR, COND | IF_COND) /* 9675 */ \ -D(undef, T_UNDEF, KANDR, IN_I) /* 4837 */ \ -D(line, T_LINE, KANDR, EXPAND) /* 2465 */ \ -D(elif, T_ELIF, STDC89, COND | EXPAND) /* 610 */ \ -D(error, T_ERROR, STDC89, 0) /* 475 */ \ -D(pragma, T_PRAGMA, STDC89, IN_I) /* 195 */ \ -D(warning, T_WARNING, EXTENSION, 0) /* 22 */ \ -D(include_next, T_INCLUDE_NEXT, EXTENSION, INCL | EXPAND) /* 19 */ \ -D(ident, T_IDENT, EXTENSION, IN_I) /* 11 */ \ -D(import, T_IMPORT, EXTENSION, INCL | EXPAND) /* 0 ObjC */ \ -D(assert, T_ASSERT, EXTENSION, 0) /* 0 SVR4 */ \ -D(unassert, T_UNASSERT, EXTENSION, 0) /* 0 SVR4 */ \ -D(sccs, T_SCCS, EXTENSION, 0) /* 0 SVR4? */ - -/* Use the table to generate a series of prototypes, an enum for the - directive names, and an array of directive handlers. */ - -#define D(name, t, o, f) static void do_##name (cpp_reader *); -DIRECTIVE_TABLE -#undef D - -#define D(n, tag, o, f) tag, -enum -{ - DIRECTIVE_TABLE - N_DIRECTIVES -}; -#undef D - -#define D(name, t, origin, flags) \ -{ do_##name, (const uchar *) #name, \ - sizeof #name - 1, origin, flags }, -static const directive dtable[] = -{ -DIRECTIVE_TABLE -}; -#undef D -#undef DIRECTIVE_TABLE - -/* Wrapper struct directive for linemarkers. - The origin is more or less true - the original K+R cpp - did use this notation in its preprocessed output. */ -static const directive linemarker_dir = -{ - do_linemarker, U"#", 1, KANDR, IN_I -}; - -#define SEEN_EOL() (pfile->cur_token[-1].type == CPP_EOF) - -/* Skip any remaining tokens in a directive. */ -static void -skip_rest_of_line (cpp_reader *pfile) -{ - /* Discard all stacked contexts. */ - while (pfile->context->prev) - _cpp_pop_context (pfile); - - /* Sweep up all tokens remaining on the line. */ - if (! SEEN_EOL ()) - while (_cpp_lex_token (pfile)->type != CPP_EOF) - ; -} - -/* Ensure there are no stray tokens at the end of a directive. */ -static void -check_eol (cpp_reader *pfile) -{ - if (! SEEN_EOL () && _cpp_lex_token (pfile)->type != CPP_EOF) - cpp_error (pfile, CPP_DL_PEDWARN, "extra tokens at end of #%s directive", - pfile->directive->name); -} - -/* Called when entering a directive, _Pragma or command-line directive. */ -static void -start_directive (cpp_reader *pfile) -{ - /* Setup in-directive state. */ - pfile->state.in_directive = 1; - pfile->state.save_comments = 0; - - /* Some handlers need the position of the # for diagnostics. */ - pfile->directive_line = pfile->line; -} - -/* Called when leaving a directive, _Pragma or command-line directive. */ -static void -end_directive (cpp_reader *pfile, int skip_line) -{ - if (CPP_OPTION (pfile, traditional)) - { - /* Revert change of prepare_directive_trad. */ - pfile->state.prevent_expansion--; - - if (pfile->directive != &dtable[T_DEFINE]) - _cpp_remove_overlay (pfile); - } - /* We don't skip for an assembler #. */ - else if (skip_line) - { - skip_rest_of_line (pfile); - if (!pfile->keep_tokens) - { - pfile->cur_run = &pfile->base_run; - pfile->cur_token = pfile->base_run.base; - } - } - - /* Restore state. */ - pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments); - pfile->state.in_directive = 0; - pfile->state.in_expression = 0; - pfile->state.angled_headers = 0; - pfile->directive = 0; -} - -/* Prepare to handle the directive in pfile->directive. */ -static void -prepare_directive_trad (cpp_reader *pfile) -{ - if (pfile->directive != &dtable[T_DEFINE]) - { - bool no_expand = (pfile->directive - && ! (pfile->directive->flags & EXPAND)); - bool was_skipping = pfile->state.skipping; - - pfile->state.in_expression = (pfile->directive == &dtable[T_IF] - || pfile->directive == &dtable[T_ELIF]); - if (pfile->state.in_expression) - pfile->state.skipping = false; - - if (no_expand) - pfile->state.prevent_expansion++; - _cpp_scan_out_logical_line (pfile, NULL); - if (no_expand) - pfile->state.prevent_expansion--; - - pfile->state.skipping = was_skipping; - _cpp_overlay_buffer (pfile, pfile->out.base, - pfile->out.cur - pfile->out.base); - } - - /* Stop ISO C from expanding anything. */ - pfile->state.prevent_expansion++; -} - -/* Output diagnostics for a directive DIR. INDENTED is nonzero if - the '#' was indented. */ -static void -directive_diagnostics (cpp_reader *pfile, const directive *dir, int indented) -{ - /* Issue -pedantic warnings for extensions. */ - if (CPP_PEDANTIC (pfile) - && ! pfile->state.skipping - && dir->origin == EXTENSION) - cpp_error (pfile, CPP_DL_PEDWARN, "#%s is a GCC extension", dir->name); - - /* Traditionally, a directive is ignored unless its # is in - column 1. Therefore in code intended to work with K+R - compilers, directives added by C89 must have their # - indented, and directives present in traditional C must not. - This is true even of directives in skipped conditional - blocks. #elif cannot be used at all. */ - if (CPP_WTRADITIONAL (pfile)) - { - if (dir == &dtable[T_ELIF]) - cpp_error (pfile, CPP_DL_WARNING, - "suggest not using #elif in traditional C"); - else if (indented && dir->origin == KANDR) - cpp_error (pfile, CPP_DL_WARNING, - "traditional C ignores #%s with the # indented", - dir->name); - else if (!indented && dir->origin != KANDR) - cpp_error (pfile, CPP_DL_WARNING, - "suggest hiding #%s from traditional C with an indented #", - dir->name); - } -} - -/* Check if we have a known directive. INDENTED is nonzero if the - '#' of the directive was indented. This function is in this file - to save unnecessarily exporting dtable etc. to cpplex.c. Returns - nonzero if the line of tokens has been handled, zero if we should - continue processing the line. */ -int -_cpp_handle_directive (cpp_reader *pfile, int indented) -{ - const directive *dir = 0; - const cpp_token *dname; - bool was_parsing_args = pfile->state.parsing_args; - int skip = 1; - - if (was_parsing_args) - { - if (CPP_OPTION (pfile, pedantic)) - cpp_error (pfile, CPP_DL_PEDWARN, - "embedding a directive within macro arguments is not portable"); - pfile->state.parsing_args = 0; - pfile->state.prevent_expansion = 0; - } - start_directive (pfile); - dname = _cpp_lex_token (pfile); - - if (dname->type == CPP_NAME) - { - if (dname->val.node->is_directive) - dir = &dtable[dname->val.node->directive_index]; - } - /* We do not recognize the # followed by a number extension in - assembler code. */ - else if (dname->type == CPP_NUMBER && CPP_OPTION (pfile, lang) != CLK_ASM) - { - dir = &linemarker_dir; - if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, preprocessed) - && ! pfile->state.skipping) - cpp_error (pfile, CPP_DL_PEDWARN, - "style of line directive is a GCC extension"); - } - - if (dir) - { - /* If we have a directive that is not an opening conditional, - invalidate any control macro. */ - if (! (dir->flags & IF_COND)) - pfile->mi_valid = false; - - /* Kluge alert. In order to be sure that code like this - - #define HASH # - HASH define foo bar - - does not cause '#define foo bar' to get executed when - compiled with -save-temps, we recognize directives in - -fpreprocessed mode only if the # is in column 1. cppmacro.c - puts a space in front of any '#' at the start of a macro. */ - if (CPP_OPTION (pfile, preprocessed) - && (indented || !(dir->flags & IN_I))) - { - skip = 0; - dir = 0; - } - else - { - /* In failed conditional groups, all non-conditional - directives are ignored. Before doing that, whether - skipping or not, we should lex angle-bracketed headers - correctly, and maybe output some diagnostics. */ - pfile->state.angled_headers = dir->flags & INCL; - pfile->state.directive_wants_padding = dir->flags & INCL; - if (! CPP_OPTION (pfile, preprocessed)) - directive_diagnostics (pfile, dir, indented); - if (pfile->state.skipping && !(dir->flags & COND)) - dir = 0; - } - } - else if (dname->type == CPP_EOF) - ; /* CPP_EOF is the "null directive". */ - else - { - /* An unknown directive. Don't complain about it in assembly - source: we don't know where the comments are, and # may - introduce assembler pseudo-ops. Don't complain about invalid - directives in skipped conditional groups (6.10 p4). */ - if (CPP_OPTION (pfile, lang) == CLK_ASM) - skip = 0; - else if (!pfile->state.skipping) - cpp_error (pfile, CPP_DL_ERROR, "invalid preprocessing directive #%s", - cpp_token_as_text (pfile, dname)); - } - - pfile->directive = dir; - if (CPP_OPTION (pfile, traditional)) - prepare_directive_trad (pfile); - - if (dir) - pfile->directive->handler (pfile); - else if (skip == 0) - _cpp_backup_tokens (pfile, 1); - - end_directive (pfile, skip); - if (was_parsing_args) - { - /* Restore state when within macro args. */ - pfile->state.parsing_args = 2; - pfile->state.prevent_expansion = 1; - } - return skip; -} - -/* Directive handler wrapper used by the command line option - processor. BUF is \n terminated. */ -static void -run_directive (cpp_reader *pfile, int dir_no, const char *buf, size_t count) -{ - cpp_push_buffer (pfile, (const uchar *) buf, count, - /* from_stage3 */ true); - /* Disgusting hack. */ - if (dir_no == T_PRAGMA) - pfile->buffer->file = pfile->buffer->prev->file; - start_directive (pfile); - - /* This is a short-term fix to prevent a leading '#' being - interpreted as a directive. */ - _cpp_clean_line (pfile); - - pfile->directive = &dtable[dir_no]; - if (CPP_OPTION (pfile, traditional)) - prepare_directive_trad (pfile); - pfile->directive->handler (pfile); - end_directive (pfile, 1); - if (dir_no == T_PRAGMA) - pfile->buffer->file = NULL; - _cpp_pop_buffer (pfile); -} - -/* Checks for validity the macro name in #define, #undef, #ifdef and - #ifndef directives. */ -static cpp_hashnode * -lex_macro_node (cpp_reader *pfile) -{ - const cpp_token *token = _cpp_lex_token (pfile); - - /* The token immediately after #define must be an identifier. That - identifier may not be "defined", per C99 6.10.8p4. - In C++, it may not be any of the "named operators" either, - per C++98 [lex.digraph], [lex.key]. - Finally, the identifier may not have been poisoned. (In that case - the lexer has issued the error message for us.) */ - - if (token->type == CPP_NAME) - { - cpp_hashnode *node = token->val.node; - - if (node == pfile->spec_nodes.n_defined) - cpp_error (pfile, CPP_DL_ERROR, - "\"defined\" cannot be used as a macro name"); - else if (! (node->flags & NODE_POISONED)) - return node; - } - else if (token->flags & NAMED_OP) - cpp_error (pfile, CPP_DL_ERROR, - "\"%s\" cannot be used as a macro name as it is an operator in C++", - NODE_NAME (token->val.node)); - else if (token->type == CPP_EOF) - cpp_error (pfile, CPP_DL_ERROR, "no macro name given in #%s directive", - pfile->directive->name); - else - cpp_error (pfile, CPP_DL_ERROR, "macro names must be identifiers"); - - return NULL; -} - -/* Process a #define directive. Most work is done in cppmacro.c. */ -static void -do_define (cpp_reader *pfile) -{ - cpp_hashnode *node = lex_macro_node (pfile); - - if (node) - { - /* If we have been requested to expand comments into macros, - then re-enable saving of comments. */ - pfile->state.save_comments = - ! CPP_OPTION (pfile, discard_comments_in_macro_exp); - - if (_cpp_create_definition (pfile, node)) - if (pfile->cb.define) - pfile->cb.define (pfile, pfile->directive_line, node); - } -} - -/* Handle #undef. Mark the identifier NT_VOID in the hash table. */ -static void -do_undef (cpp_reader *pfile) -{ - cpp_hashnode *node = lex_macro_node (pfile); - - if (node) - { - if (pfile->cb.undef) - pfile->cb.undef (pfile, pfile->directive_line, node); - - /* 6.10.3.5 paragraph 2: [#undef] is ignored if the specified - identifier is not currently defined as a macro name. */ - if (node->type == NT_MACRO) - { - if (node->flags & NODE_WARN) - cpp_error (pfile, CPP_DL_WARNING, - "undefining \"%s\"", NODE_NAME (node)); - - if (CPP_OPTION (pfile, warn_unused_macros)) - _cpp_warn_if_unused_macro (pfile, node, NULL); - - _cpp_free_definition (node); - } - } - - check_eol (pfile); -} - -/* Undefine a single macro/assertion/whatever. */ - -static int -undefine_macros (cpp_reader *pfile, cpp_hashnode *h, - void *data_p ATTRIBUTE_UNUSED) -{ - switch (h->type) - { - case NT_VOID: - break; - - case NT_MACRO: - if (pfile->cb.undef) - (*pfile->cb.undef) (pfile, pfile->directive_line, h); - - if (CPP_OPTION (pfile, warn_unused_macros)) - _cpp_warn_if_unused_macro (pfile, h, NULL); - - /* And fall through.... */ - case NT_ASSERTION: - _cpp_free_definition (h); - break; - - default: - abort (); - } - h->flags &= ~NODE_POISONED; - return 1; -} - -/* Undefine all macros and assertions. */ - -void -cpp_undef_all (cpp_reader *pfile) -{ - cpp_forall_identifiers (pfile, undefine_macros, NULL); -} - - -/* Helper routine used by parse_include. Reinterpret the current line - as an h-char-sequence (< ... >); we are looking at the first token - after the <. Returns a malloced filename. */ -static char * -glue_header_name (cpp_reader *pfile) -{ - const cpp_token *token; - char *buffer; - size_t len, total_len = 0, capacity = 1024; - - /* To avoid lexed tokens overwriting our glued name, we can only - allocate from the string pool once we've lexed everything. */ - buffer = xmalloc (capacity); - for (;;) - { - token = get_token_no_padding (pfile); - - if (token->type == CPP_GREATER) - break; - if (token->type == CPP_EOF) - { - cpp_error (pfile, CPP_DL_ERROR, "missing terminating > character"); - break; - } - - len = cpp_token_len (token) + 2; /* Leading space, terminating \0. */ - if (total_len + len > capacity) - { - capacity = (capacity + len) * 2; - buffer = xrealloc (buffer, capacity); - } - - if (token->flags & PREV_WHITE) - buffer[total_len++] = ' '; - - total_len = (cpp_spell_token (pfile, token, (uchar *) &buffer[total_len]) - - (uchar *) buffer); - } - - buffer[total_len] = '\0'; - return buffer; -} - -/* Returns the file name of #include, #include_next, #import and - #pragma dependency. The string is malloced and the caller should - free it. Returns NULL on error. */ -static const char * -parse_include (cpp_reader *pfile, int *pangle_brackets) -{ - char *fname; - const cpp_token *header; - - /* Allow macro expansion. */ - header = get_token_no_padding (pfile); - if (header->type == CPP_STRING || header->type == CPP_HEADER_NAME) - { - fname = xmalloc (header->val.str.len - 1); - memcpy (fname, header->val.str.text + 1, header->val.str.len - 2); - fname[header->val.str.len - 2] = '\0'; - *pangle_brackets = header->type == CPP_HEADER_NAME; - } - else if (header->type == CPP_LESS) - { - fname = glue_header_name (pfile); - *pangle_brackets = 1; - } - else - { - const unsigned char *dir; - - if (pfile->directive == &dtable[T_PRAGMA]) - dir = U"pragma dependency"; - else - dir = pfile->directive->name; - cpp_error (pfile, CPP_DL_ERROR, "#%s expects \"FILENAME\" or ", - dir); - - return NULL; - } - - check_eol (pfile); - return fname; -} - -/* Handle #include, #include_next and #import. */ -static void -do_include_common (cpp_reader *pfile, enum include_type type) -{ - const char *fname; - int angle_brackets; - - fname = parse_include (pfile, &angle_brackets); - if (!fname) - return; - - if (!*fname) - { - cpp_error (pfile, CPP_DL_ERROR, "empty filename in #%s", - pfile->directive->name); - free ((void *) fname); - return; - } - - /* Prevent #include recursion. */ - if (pfile->line_maps.depth >= CPP_STACK_MAX) - cpp_error (pfile, CPP_DL_ERROR, "#include nested too deeply"); - else - { - /* Get out of macro context, if we are. */ - skip_rest_of_line (pfile); - - if (pfile->cb.include) - pfile->cb.include (pfile, pfile->directive_line, - pfile->directive->name, fname, angle_brackets); - - _cpp_stack_include (pfile, fname, angle_brackets, type); - } - - free ((void *) fname); -} - -static void -do_include (cpp_reader *pfile) -{ - do_include_common (pfile, IT_INCLUDE); -} - -static void -do_import (cpp_reader *pfile) -{ - do_include_common (pfile, IT_IMPORT); -} - -static void -do_include_next (cpp_reader *pfile) -{ - enum include_type type = IT_INCLUDE_NEXT; - - /* If this is the primary source file, warn and use the normal - search logic. */ - if (! pfile->buffer->prev) - { - cpp_error (pfile, CPP_DL_WARNING, - "#include_next in primary source file"); - type = IT_INCLUDE; - } - do_include_common (pfile, type); -} - -/* Subroutine of do_linemarker. Read possible flags after file name. - LAST is the last flag seen; 0 if this is the first flag. Return the - flag if it is valid, 0 at the end of the directive. Otherwise - complain. */ -static unsigned int -read_flag (cpp_reader *pfile, unsigned int last) -{ - const cpp_token *token = _cpp_lex_token (pfile); - - if (token->type == CPP_NUMBER && token->val.str.len == 1) - { - unsigned int flag = token->val.str.text[0] - '0'; - - if (flag > last && flag <= 4 - && (flag != 4 || last == 3) - && (flag != 2 || last == 0)) - return flag; - } - - if (token->type != CPP_EOF) - cpp_error (pfile, CPP_DL_ERROR, "invalid flag \"%s\" in line directive", - cpp_token_as_text (pfile, token)); - return 0; -} - -/* Subroutine of do_line and do_linemarker. Convert a number in STR, - of length LEN, to binary; store it in NUMP, and return 0 if the - number was well-formed, 1 if not. Temporary, hopefully. */ -static int -strtoul_for_line (const uchar *str, unsigned int len, long unsigned int *nump) -{ - unsigned long reg = 0; - uchar c; - while (len--) - { - c = *str++; - if (!ISDIGIT (c)) - return 1; - reg *= 10; - reg += c - '0'; - } - *nump = reg; - return 0; -} - -/* Interpret #line command. - Note that the filename string (if any) is a true string constant - (escapes are interpreted), unlike in #line. */ -static void -do_line (cpp_reader *pfile) -{ - const cpp_token *token; - const char *new_file = pfile->map->to_file; - unsigned long new_lineno; - - /* C99 raised the minimum limit on #line numbers. */ - unsigned int cap = CPP_OPTION (pfile, c99) ? 2147483647 : 32767; - - /* #line commands expand macros. */ - token = cpp_get_token (pfile); - if (token->type != CPP_NUMBER - || strtoul_for_line (token->val.str.text, token->val.str.len, - &new_lineno)) - { - cpp_error (pfile, CPP_DL_ERROR, - "\"%s\" after #line is not a positive integer", - cpp_token_as_text (pfile, token)); - return; - } - - if (CPP_PEDANTIC (pfile) && (new_lineno == 0 || new_lineno > cap)) - cpp_error (pfile, CPP_DL_PEDWARN, "line number out of range"); - - token = cpp_get_token (pfile); - if (token->type == CPP_STRING) - { - cpp_string s = { 0, 0 }; - if (_cpp_interpret_string_notranslate (pfile, &token->val.str, &s)) - new_file = (const char *)s.text; - check_eol (pfile); - } - else if (token->type != CPP_EOF) - { - cpp_error (pfile, CPP_DL_ERROR, "\"%s\" is not a valid filename", - cpp_token_as_text (pfile, token)); - return; - } - - skip_rest_of_line (pfile); - _cpp_do_file_change (pfile, LC_RENAME, new_file, new_lineno, - pfile->map->sysp); -} - -/* Interpret the # 44 "file" [flags] notation, which has slightly - different syntax and semantics from #line: Flags are allowed, - and we never complain about the line number being too big. */ -static void -do_linemarker (cpp_reader *pfile) -{ - const cpp_token *token; - const char *new_file = pfile->map->to_file; - unsigned long new_lineno; - unsigned int new_sysp = pfile->map->sysp; - enum lc_reason reason = LC_RENAME; - int flag; - - /* Back up so we can get the number again. Putting this in - _cpp_handle_directive risks two calls to _cpp_backup_tokens in - some circumstances, which can segfault. */ - _cpp_backup_tokens (pfile, 1); - - /* #line commands expand macros. */ - token = cpp_get_token (pfile); - if (token->type != CPP_NUMBER - || strtoul_for_line (token->val.str.text, token->val.str.len, - &new_lineno)) - { - cpp_error (pfile, CPP_DL_ERROR, - "\"%s\" after # is not a positive integer", - cpp_token_as_text (pfile, token)); - return; - } - - token = cpp_get_token (pfile); - if (token->type == CPP_STRING) - { - cpp_string s = { 0, 0 }; - if (_cpp_interpret_string_notranslate (pfile, &token->val.str, &s)) - new_file = (const char *)s.text; - - new_sysp = 0; - flag = read_flag (pfile, 0); - if (flag == 1) - { - reason = LC_ENTER; - /* Fake an include for cpp_included (). */ - _cpp_fake_include (pfile, new_file); - flag = read_flag (pfile, flag); - } - else if (flag == 2) - { - reason = LC_LEAVE; - flag = read_flag (pfile, flag); - } - if (flag == 3) - { - new_sysp = 1; - flag = read_flag (pfile, flag); - if (flag == 4) - new_sysp = 2; - } - - check_eol (pfile); - } - else if (token->type != CPP_EOF) - { - cpp_error (pfile, CPP_DL_ERROR, "\"%s\" is not a valid filename", - cpp_token_as_text (pfile, token)); - return; - } - - skip_rest_of_line (pfile); - _cpp_do_file_change (pfile, reason, new_file, new_lineno, new_sysp); -} - -/* Arrange the file_change callback. pfile->line has changed to - FILE_LINE of TO_FILE, for reason REASON. SYSP is 1 for a system - header, 2 for a system header that needs to be extern "C" protected, - and zero otherwise. */ -void -_cpp_do_file_change (cpp_reader *pfile, enum lc_reason reason, - const char *to_file, unsigned int file_line, - unsigned int sysp) -{ - pfile->map = linemap_add (&pfile->line_maps, reason, sysp, - pfile->line, to_file, file_line); - - if (pfile->cb.file_change) - pfile->cb.file_change (pfile, pfile->map); -} - -/* Report a warning or error detected by the program we are - processing. Use the directive's tokens in the error message. */ -static void -do_diagnostic (cpp_reader *pfile, int code, int print_dir) -{ - if (_cpp_begin_message (pfile, code, - pfile->cur_token[-1].line, - pfile->cur_token[-1].col)) - { - if (print_dir) - fprintf (stderr, "#%s ", pfile->directive->name); - pfile->state.prevent_expansion++; - cpp_output_line (pfile, stderr); - pfile->state.prevent_expansion--; - } -} - -static void -do_error (cpp_reader *pfile) -{ - do_diagnostic (pfile, CPP_DL_ERROR, 1); -} - -static void -do_warning (cpp_reader *pfile) -{ - /* We want #warning diagnostics to be emitted in system headers too. */ - do_diagnostic (pfile, CPP_DL_WARNING_SYSHDR, 1); -} - -/* Report program identification. */ -static void -do_ident (cpp_reader *pfile) -{ - const cpp_token *str = cpp_get_token (pfile); - - if (str->type != CPP_STRING) - cpp_error (pfile, CPP_DL_ERROR, "invalid #ident directive"); - else if (pfile->cb.ident) - pfile->cb.ident (pfile, pfile->directive_line, &str->val.str); - - check_eol (pfile); -} - -/* Lookup a PRAGMA name in a singly-linked CHAIN. Returns the - matching entry, or NULL if none is found. The returned entry could - be the start of a namespace chain, or a pragma. */ -static struct pragma_entry * -lookup_pragma_entry (struct pragma_entry *chain, const cpp_hashnode *pragma) -{ - while (chain && chain->pragma != pragma) - chain = chain->next; - - return chain; -} - -/* Create and insert a pragma entry for NAME at the beginning of a - singly-linked CHAIN. If handler is NULL, it is a namespace, - otherwise it is a pragma and its handler. */ -static struct pragma_entry * -insert_pragma_entry (cpp_reader *pfile, struct pragma_entry **chain, - const cpp_hashnode *pragma, pragma_cb handler) -{ - struct pragma_entry *new; - - new = (struct pragma_entry *) - _cpp_aligned_alloc (pfile, sizeof (struct pragma_entry)); - new->pragma = pragma; - if (handler) - { - new->is_nspace = 0; - new->u.handler = handler; - } - else - { - new->is_nspace = 1; - new->u.space = NULL; - } - - new->next = *chain; - *chain = new; - return new; -} - -/* Register a pragma NAME in namespace SPACE. If SPACE is null, it - goes in the global namespace. HANDLER is the handler it will call, - which must be non-NULL. */ -void -cpp_register_pragma (cpp_reader *pfile, const char *space, const char *name, - pragma_cb handler) -{ - struct pragma_entry **chain = &pfile->pragmas; - struct pragma_entry *entry; - const cpp_hashnode *node; - - if (!handler) - abort (); - - if (space) - { - node = cpp_lookup (pfile, U space, strlen (space)); - entry = lookup_pragma_entry (*chain, node); - if (!entry) - entry = insert_pragma_entry (pfile, chain, node, NULL); - else if (!entry->is_nspace) - goto clash; - chain = &entry->u.space; - } - - /* Check for duplicates. */ - node = cpp_lookup (pfile, U name, strlen (name)); - entry = lookup_pragma_entry (*chain, node); - if (entry) - { - if (entry->is_nspace) - clash: - cpp_error (pfile, CPP_DL_ICE, - "registering \"%s\" as both a pragma and a pragma namespace", - NODE_NAME (node)); - else if (space) - cpp_error (pfile, CPP_DL_ICE, "#pragma %s %s is already registered", - space, name); - else - cpp_error (pfile, CPP_DL_ICE, "#pragma %s is already registered", name); - } - else - insert_pragma_entry (pfile, chain, node, handler); -} - -/* Register the pragmas the preprocessor itself handles. */ -void -_cpp_init_internal_pragmas (cpp_reader *pfile) -{ - /* Pragmas in the global namespace. */ - cpp_register_pragma (pfile, 0, "once", do_pragma_once); - - /* New GCC-specific pragmas should be put in the GCC namespace. */ - cpp_register_pragma (pfile, "GCC", "poison", do_pragma_poison); - cpp_register_pragma (pfile, "GCC", "system_header", do_pragma_system_header); - cpp_register_pragma (pfile, "GCC", "dependency", do_pragma_dependency); - - /* Kevin abuse for SDCC. */ - cpp_register_pragma(pfile, 0, "sdcc_hash", do_pragma_sdcc_hash); - /* SDCC _asm specific */ - cpp_register_pragma(pfile, 0, "preproc_asm", do_pragma_preproc_asm); - /* SDCC specific */ - cpp_register_pragma(pfile, 0, "pedantic_parse_number", do_pragma_pedantic_parse_number); -} - -/* Return the number of registered pragmas in PE. */ - -static int -count_registered_pragmas (struct pragma_entry *pe) -{ - int ct = 0; - for (; pe != NULL; pe = pe->next) - { - if (pe->is_nspace) - ct += count_registered_pragmas (pe->u.space); - ct++; - } - return ct; -} - -/* Save into SD the names of the registered pragmas referenced by PE, - and return a pointer to the next free space in SD. */ - -static char ** -save_registered_pragmas (struct pragma_entry *pe, char **sd) -{ - for (; pe != NULL; pe = pe->next) - { - if (pe->is_nspace) - sd = save_registered_pragmas (pe->u.space, sd); - *sd++ = xmemdup (HT_STR (&pe->pragma->ident), - HT_LEN (&pe->pragma->ident), - HT_LEN (&pe->pragma->ident) + 1); - } - return sd; -} - -/* Return a newly-allocated array which saves the names of the - registered pragmas. */ - -char ** -_cpp_save_pragma_names (cpp_reader *pfile) -{ - int ct = count_registered_pragmas (pfile->pragmas); - char **result = xnewvec (char *, ct); - (void) save_registered_pragmas (pfile->pragmas, result); - return result; -} - -/* Restore from SD the names of the registered pragmas referenced by PE, - and return a pointer to the next unused name in SD. */ - -static char ** -restore_registered_pragmas (cpp_reader *pfile, struct pragma_entry *pe, - char **sd) -{ - for (; pe != NULL; pe = pe->next) - { - if (pe->is_nspace) - sd = restore_registered_pragmas (pfile, pe->u.space, sd); - pe->pragma = cpp_lookup (pfile, U *sd, strlen (*sd)); - free (*sd); - sd++; - } - return sd; -} - -/* Restore the names of the registered pragmas from SAVED. */ - -void -_cpp_restore_pragma_names (cpp_reader *pfile, char **saved) -{ - (void) restore_registered_pragmas (pfile, pfile->pragmas, saved); - free (saved); -} - -/* Pragmata handling. We handle some, and pass the rest on to the - front end. C99 defines three pragmas and says that no macro - expansion is to be performed on them; whether or not macro - expansion happens for other pragmas is implementation defined. - This implementation never macro-expands the text after #pragma. */ -static void -do_pragma (cpp_reader *pfile) -{ - const struct pragma_entry *p = NULL; - const cpp_token *token, *pragma_token = pfile->cur_token; - unsigned int count = 1; - - pfile->state.prevent_expansion++; - - token = cpp_get_token (pfile); - if (token->type == CPP_NAME) - { - p = lookup_pragma_entry (pfile->pragmas, token->val.node); - if (p && p->is_nspace) - { - count = 2; - token = cpp_get_token (pfile); - if (token->type == CPP_NAME) - p = lookup_pragma_entry (p->u.space, token->val.node); - else - p = NULL; - } - } - - if (p) - { - /* Since the handler below doesn't get the line number, that it - might need for diagnostics, make sure it has the right - numbers in place. */ - if (pfile->cb.line_change) - (*pfile->cb.line_change) (pfile, pragma_token, false); - (*p->u.handler) (pfile); - } - else if (pfile->cb.def_pragma) - { - _cpp_backup_tokens (pfile, count); - pfile->cb.def_pragma (pfile, pfile->directive_line); - } - - pfile->state.prevent_expansion--; -} - -/* Handle #pragma once. */ -static void -do_pragma_once (cpp_reader *pfile) -{ - if (pfile->buffer->prev == NULL) - cpp_error (pfile, CPP_DL_WARNING, "#pragma once in main file"); - - check_eol (pfile); - _cpp_mark_file_once_only (pfile, pfile->buffer->file); -} - -/* Handle #pragma GCC poison, to poison one or more identifiers so - that the lexer produces a hard error for each subsequent usage. */ -static void -do_pragma_poison (cpp_reader *pfile) -{ - const cpp_token *tok; - cpp_hashnode *hp; - - pfile->state.poisoned_ok = 1; - for (;;) - { - tok = _cpp_lex_token (pfile); - if (tok->type == CPP_EOF) - break; - if (tok->type != CPP_NAME) - { - cpp_error (pfile, CPP_DL_ERROR, - "invalid #pragma GCC poison directive"); - break; - } - - hp = tok->val.node; - if (hp->flags & NODE_POISONED) - continue; - - if (hp->type == NT_MACRO) - cpp_error (pfile, CPP_DL_WARNING, "poisoning existing macro \"%s\"", - NODE_NAME (hp)); - _cpp_free_definition (hp); - hp->flags |= NODE_POISONED | NODE_DIAGNOSTIC; - } - pfile->state.poisoned_ok = 0; -} - -/* SDCC specific - sdcc_hash pragma */ -static void -do_pragma_sdcc_hash (cpp_reader *pfile) -{ - const cpp_token *tok = _cpp_lex_token (pfile); - - if (tok->type == CPP_PLUS) - { - CPP_OPTION(pfile, allow_naked_hash)++; - } - else if (tok->type == CPP_MINUS) - { - CPP_OPTION(pfile, allow_naked_hash)--; - } - else - { - cpp_error (pfile, CPP_DL_ERROR, - "invalid #pragma sdcc_hash directive, need '+' or '-'"); - } -} - -/* SDCC specific - pedantic_parse_number pragma */ -static void -do_pragma_pedantic_parse_number (cpp_reader *pfile) -{ - const cpp_token *tok = _cpp_lex_token (pfile); - - if (tok->type == CPP_PLUS) - { - CPP_OPTION(pfile, pedantic_parse_number)++; - } - else if (tok->type == CPP_MINUS) - { - CPP_OPTION(pfile, pedantic_parse_number)--; - } - else - { - cpp_error (pfile, CPP_DL_ERROR, - "invalid #pragma pedantic_parse_number directive, need '+' or '-'"); - } -} - -/* SDCC _asm specific - switch _asm block preprocessing on / off */ -static void -do_pragma_preproc_asm (cpp_reader *pfile) -{ - const cpp_token *tok = _cpp_lex_token (pfile); - - if (tok->type == CPP_PLUS) - { - CPP_OPTION(pfile, preproc_asm)++; - } - else if (tok->type == CPP_MINUS) - { - CPP_OPTION(pfile, preproc_asm)--; - } - else - { - cpp_error (pfile, CPP_DL_ERROR, - "invalid #pragma preproc_asm directive, need '+' or '-'"); - } -} - -/* Mark the current header as a system header. This will suppress - some categories of warnings (notably those from -pedantic). It is - intended for use in system libraries that cannot be implemented in - conforming C, but cannot be certain that their headers appear in a - system include directory. To prevent abuse, it is rejected in the - primary source file. */ -static void -do_pragma_system_header (cpp_reader *pfile) -{ - cpp_buffer *buffer = pfile->buffer; - - if (buffer->prev == 0) - cpp_error (pfile, CPP_DL_WARNING, - "#pragma system_header ignored outside include file"); - else - { - check_eol (pfile); - skip_rest_of_line (pfile); - cpp_make_system_header (pfile, 1, 0); - } -} - -/* Check the modified date of the current include file against a specified - file. Issue a diagnostic, if the specified file is newer. We use this to - determine if a fixed header should be refixed. */ -static void -do_pragma_dependency (cpp_reader *pfile) -{ - const char *fname; - int angle_brackets, ordering; - - fname = parse_include (pfile, &angle_brackets); - if (!fname) - return; - - ordering = _cpp_compare_file_date (pfile, fname, angle_brackets); - if (ordering < 0) - cpp_error (pfile, CPP_DL_WARNING, "cannot find source file %s", fname); - else if (ordering > 0) - { - cpp_error (pfile, CPP_DL_WARNING, - "current file is older than %s", fname); - if (cpp_get_token (pfile)->type != CPP_EOF) - { - _cpp_backup_tokens (pfile, 1); - do_diagnostic (pfile, CPP_DL_WARNING, 0); - } - } - - free ((void *) fname); -} - -/* Get a token but skip padding. */ -static const cpp_token * -get_token_no_padding (cpp_reader *pfile) -{ - for (;;) - { - const cpp_token *result = cpp_get_token (pfile); - if (result->type != CPP_PADDING) - return result; - } -} - -/* Check syntax is "(string-literal)". Returns the string on success, - or NULL on failure. */ -static const cpp_token * -get__Pragma_string (cpp_reader *pfile) -{ - const cpp_token *string; - - if (get_token_no_padding (pfile)->type != CPP_OPEN_PAREN) - return NULL; - - string = get_token_no_padding (pfile); - if (string->type != CPP_STRING && string->type != CPP_WSTRING) - return NULL; - - if (get_token_no_padding (pfile)->type != CPP_CLOSE_PAREN) - return NULL; - - return string; -} - -/* Destringize IN into a temporary buffer, by removing the first \ of - \" and \\ sequences, and process the result as a #pragma directive. */ -static void -destringize_and_run (cpp_reader *pfile, const cpp_string *in) -{ - const unsigned char *src, *limit; - char *dest, *result; - - dest = result = alloca (in->len - 1); - src = in->text + 1 + (in->text[0] == 'L'); - limit = in->text + in->len - 1; - while (src < limit) - { - /* We know there is a character following the backslash. */ - if (*src == '\\' && (src[1] == '\\' || src[1] == '"')) - src++; - *dest++ = *src++; - } - *dest = '\n'; - - /* Ugh; an awful kludge. We are really not set up to be lexing - tokens when in the middle of a macro expansion. Use a new - context to force cpp_get_token to lex, and so skip_rest_of_line - doesn't go beyond the end of the text. Also, remember the - current lexing position so we can return to it later. - - Something like line-at-a-time lexing should remove the need for - this. */ - { - cpp_context *saved_context = pfile->context; - cpp_token *saved_cur_token = pfile->cur_token; - tokenrun *saved_cur_run = pfile->cur_run; - - pfile->context = xnew (cpp_context); - pfile->context->macro = 0; - pfile->context->prev = 0; - run_directive (pfile, T_PRAGMA, result, dest - result); - free (pfile->context); - pfile->context = saved_context; - pfile->cur_token = saved_cur_token; - pfile->cur_run = saved_cur_run; - pfile->line--; - } - - /* See above comment. For the moment, we'd like - - token1 _Pragma ("foo") token2 - - to be output as - - token1 - # 7 "file.c" - #pragma foo - # 7 "file.c" - token2 - - Getting the line markers is a little tricky. */ - if (pfile->cb.line_change) - pfile->cb.line_change (pfile, pfile->cur_token, false); -} - -/* Handle the _Pragma operator. */ -void -_cpp_do__Pragma (cpp_reader *pfile) -{ - const cpp_token *string = get__Pragma_string (pfile); - - if (string) - destringize_and_run (pfile, &string->val.str); - else - cpp_error (pfile, CPP_DL_ERROR, - "_Pragma takes a parenthesized string literal"); -} - -/* Ignore #sccs on all systems. */ -static void -do_sccs (cpp_reader *pfile ATTRIBUTE_UNUSED) -{ -} - -/* Handle #ifdef. */ -static void -do_ifdef (cpp_reader *pfile) -{ - int skip = 1; - - if (! pfile->state.skipping) - { - const cpp_hashnode *node = lex_macro_node (pfile); - - if (node) - { - skip = node->type != NT_MACRO; - _cpp_mark_macro_used (node); - check_eol (pfile); - } - } - - push_conditional (pfile, skip, T_IFDEF, 0); -} - -/* Handle #ifndef. */ -static void -do_ifndef (cpp_reader *pfile) -{ - int skip = 1; - const cpp_hashnode *node = 0; - - if (! pfile->state.skipping) - { - node = lex_macro_node (pfile); - - if (node) - { - skip = node->type == NT_MACRO; - _cpp_mark_macro_used (node); - check_eol (pfile); - } - } - - push_conditional (pfile, skip, T_IFNDEF, node); -} - -/* _cpp_parse_expr puts a macro in a "#if !defined ()" expression in - pfile->mi_ind_cmacro so we can handle multiple-include - optimizations. If macro expansion occurs in the expression, we - cannot treat it as a controlling conditional, since the expansion - could change in the future. That is handled by cpp_get_token. */ -static void -do_if (cpp_reader *pfile) -{ - int skip = 1; - - if (! pfile->state.skipping) - skip = _cpp_parse_expr (pfile) == false; - - push_conditional (pfile, skip, T_IF, pfile->mi_ind_cmacro); -} - -/* Flip skipping state if appropriate and continue without changing - if_stack; this is so that the error message for missing #endif's - etc. will point to the original #if. */ -static void -do_else (cpp_reader *pfile) -{ - cpp_buffer *buffer = pfile->buffer; - struct if_stack *ifs = buffer->if_stack; - - if (ifs == NULL) - cpp_error (pfile, CPP_DL_ERROR, "#else without #if"); - else - { - if (ifs->type == T_ELSE) - { - cpp_error (pfile, CPP_DL_ERROR, "#else after #else"); - cpp_error_with_line (pfile, CPP_DL_ERROR, ifs->line, 0, - "the conditional began here"); - } - ifs->type = T_ELSE; - - /* Skip any future (erroneous) #elses or #elifs. */ - pfile->state.skipping = ifs->skip_elses; - ifs->skip_elses = true; - - /* Invalidate any controlling macro. */ - ifs->mi_cmacro = 0; - - /* Only check EOL if was not originally skipping. */ - if (!ifs->was_skipping && CPP_OPTION (pfile, warn_endif_labels)) - check_eol (pfile); - } -} - -/* Handle a #elif directive by not changing if_stack either. See the - comment above do_else. */ -static void -do_elif (cpp_reader *pfile) -{ - cpp_buffer *buffer = pfile->buffer; - struct if_stack *ifs = buffer->if_stack; - - if (ifs == NULL) - cpp_error (pfile, CPP_DL_ERROR, "#elif without #if"); - else - { - if (ifs->type == T_ELSE) - { - cpp_error (pfile, CPP_DL_ERROR, "#elif after #else"); - cpp_error_with_line (pfile, CPP_DL_ERROR, ifs->line, 0, - "the conditional began here"); - } - ifs->type = T_ELIF; - - /* Only evaluate this if we aren't skipping elses. During - evaluation, set skipping to false to get lexer warnings. */ - if (ifs->skip_elses) - pfile->state.skipping = 1; - else - { - pfile->state.skipping = 0; - pfile->state.skipping = ! _cpp_parse_expr (pfile); - ifs->skip_elses = ! pfile->state.skipping; - } - - /* Invalidate any controlling macro. */ - ifs->mi_cmacro = 0; - } -} - -/* #endif pops the if stack and resets pfile->state.skipping. */ -static void -do_endif (cpp_reader *pfile) -{ - cpp_buffer *buffer = pfile->buffer; - struct if_stack *ifs = buffer->if_stack; - - if (ifs == NULL) - cpp_error (pfile, CPP_DL_ERROR, "#endif without #if"); - else - { - /* Only check EOL if was not originally skipping. */ - if (!ifs->was_skipping && CPP_OPTION (pfile, warn_endif_labels)) - check_eol (pfile); - - /* If potential control macro, we go back outside again. */ - if (ifs->next == 0 && ifs->mi_cmacro) - { - pfile->mi_valid = true; - pfile->mi_cmacro = ifs->mi_cmacro; - } - - buffer->if_stack = ifs->next; - pfile->state.skipping = ifs->was_skipping; - obstack_free (&pfile->buffer_ob, ifs); - } -} - -/* Push an if_stack entry for a preprocessor conditional, and set - pfile->state.skipping to SKIP. If TYPE indicates the conditional - is #if or #ifndef, CMACRO is a potentially controlling macro, and - we need to check here that we are at the top of the file. */ -static void -push_conditional (cpp_reader *pfile, int skip, int type, - const cpp_hashnode *cmacro) -{ - struct if_stack *ifs; - cpp_buffer *buffer = pfile->buffer; - - ifs = xobnew (&pfile->buffer_ob, struct if_stack); - ifs->line = pfile->directive_line; - ifs->next = buffer->if_stack; - ifs->skip_elses = pfile->state.skipping || !skip; - ifs->was_skipping = pfile->state.skipping; - ifs->type = type; - /* This condition is effectively a test for top-of-file. */ - if (pfile->mi_valid && pfile->mi_cmacro == 0) - ifs->mi_cmacro = cmacro; - else - ifs->mi_cmacro = 0; - - pfile->state.skipping = skip; - buffer->if_stack = ifs; -} - -/* Read the tokens of the answer into the macro pool, in a directive - of type TYPE. Only commit the memory if we intend it as permanent - storage, i.e. the #assert case. Returns 0 on success, and sets - ANSWERP to point to the answer. */ -static int -parse_answer (cpp_reader *pfile, struct answer **answerp, int type) -{ - const cpp_token *paren; - struct answer *answer; - unsigned int acount; - - /* In a conditional, it is legal to not have an open paren. We - should save the following token in this case. */ - paren = cpp_get_token (pfile); - - /* If not a paren, see if we're OK. */ - if (paren->type != CPP_OPEN_PAREN) - { - /* In a conditional no answer is a test for any answer. It - could be followed by any token. */ - if (type == T_IF) - { - _cpp_backup_tokens (pfile, 1); - return 0; - } - - /* #unassert with no answer is valid - it removes all answers. */ - if (type == T_UNASSERT && paren->type == CPP_EOF) - return 0; - - cpp_error (pfile, CPP_DL_ERROR, "missing '(' after predicate"); - return 1; - } - - for (acount = 0;; acount++) - { - size_t room_needed; - const cpp_token *token = cpp_get_token (pfile); - cpp_token *dest; - - if (token->type == CPP_CLOSE_PAREN) - break; - - if (token->type == CPP_EOF) - { - cpp_error (pfile, CPP_DL_ERROR, "missing ')' to complete answer"); - return 1; - } - - /* struct answer includes the space for one token. */ - room_needed = (sizeof (struct answer) + acount * sizeof (cpp_token)); - - if (BUFF_ROOM (pfile->a_buff) < room_needed) - _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (struct answer)); - - dest = &((struct answer *) BUFF_FRONT (pfile->a_buff))->first[acount]; - *dest = *token; - - /* Drop whitespace at start, for answer equivalence purposes. */ - if (acount == 0) - dest->flags &= ~PREV_WHITE; - } - - if (acount == 0) - { - cpp_error (pfile, CPP_DL_ERROR, "predicate's answer is empty"); - return 1; - } - - answer = (struct answer *) BUFF_FRONT (pfile->a_buff); - answer->count = acount; - answer->next = NULL; - *answerp = answer; - - return 0; -} - -/* Parses an assertion directive of type TYPE, returning a pointer to - the hash node of the predicate, or 0 on error. If an answer was - supplied, it is placed in ANSWERP, otherwise it is set to 0. */ -static cpp_hashnode * -parse_assertion (cpp_reader *pfile, struct answer **answerp, int type) -{ - cpp_hashnode *result = 0; - const cpp_token *predicate; - - /* We don't expand predicates or answers. */ - pfile->state.prevent_expansion++; - - *answerp = 0; - predicate = cpp_get_token (pfile); - if (predicate->type == CPP_EOF) - cpp_error (pfile, CPP_DL_ERROR, "assertion without predicate"); - else if (predicate->type != CPP_NAME) - cpp_error (pfile, CPP_DL_ERROR, "predicate must be an identifier"); - else if (parse_answer (pfile, answerp, type) == 0) - { - unsigned int len = NODE_LEN (predicate->val.node); - unsigned char *sym = alloca (len + 1); - - /* Prefix '#' to get it out of macro namespace. */ - sym[0] = '#'; - memcpy (sym + 1, NODE_NAME (predicate->val.node), len); - result = cpp_lookup (pfile, sym, len + 1); - } - - pfile->state.prevent_expansion--; - return result; -} - -/* Returns a pointer to the pointer to CANDIDATE in the answer chain, - or a pointer to NULL if the answer is not in the chain. */ -static struct answer ** -find_answer (cpp_hashnode *node, const struct answer *candidate) -{ - unsigned int i; - struct answer **result; - - for (result = &node->value.answers; *result; result = &(*result)->next) - { - struct answer *answer = *result; - - if (answer->count == candidate->count) - { - for (i = 0; i < answer->count; i++) - if (! _cpp_equiv_tokens (&answer->first[i], &candidate->first[i])) - break; - - if (i == answer->count) - break; - } - } - - return result; -} - -/* Test an assertion within a preprocessor conditional. Returns - nonzero on failure, zero on success. On success, the result of - the test is written into VALUE, otherwise the value 0. */ -int -_cpp_test_assertion (cpp_reader *pfile, unsigned int *value) -{ - struct answer *answer; - cpp_hashnode *node; - - node = parse_assertion (pfile, &answer, T_IF); - - /* For recovery, an erroneous assertion expression is handled as a - failing assertion. */ - *value = 0; - - if (node) - *value = (node->type == NT_ASSERTION && - (answer == 0 || *find_answer (node, answer) != 0)); - else if (pfile->cur_token[-1].type == CPP_EOF) - _cpp_backup_tokens (pfile, 1); - - /* We don't commit the memory for the answer - it's temporary only. */ - return node == 0; -} - -/* Handle #assert. */ -static void -do_assert (cpp_reader *pfile) -{ - struct answer *new_answer; - cpp_hashnode *node; - - node = parse_assertion (pfile, &new_answer, T_ASSERT); - if (node) - { - /* Place the new answer in the answer list. First check there - is not a duplicate. */ - new_answer->next = 0; - if (node->type == NT_ASSERTION) - { - if (*find_answer (node, new_answer)) - { - cpp_error (pfile, CPP_DL_WARNING, "\"%s\" re-asserted", - NODE_NAME (node) + 1); - return; - } - new_answer->next = node->value.answers; - } - - node->type = NT_ASSERTION; - node->value.answers = new_answer; - BUFF_FRONT (pfile->a_buff) += (sizeof (struct answer) - + (new_answer->count - 1) - * sizeof (cpp_token)); - check_eol (pfile); - } -} - -/* Handle #unassert. */ -static void -do_unassert (cpp_reader *pfile) -{ - cpp_hashnode *node; - struct answer *answer; - - node = parse_assertion (pfile, &answer, T_UNASSERT); - /* It isn't an error to #unassert something that isn't asserted. */ - if (node && node->type == NT_ASSERTION) - { - if (answer) - { - struct answer **p = find_answer (node, answer), *temp; - - /* Remove the answer from the list. */ - temp = *p; - if (temp) - *p = temp->next; - - /* Did we free the last answer? */ - if (node->value.answers == 0) - node->type = NT_VOID; - - check_eol (pfile); - } - else - _cpp_free_definition (node); - } - - /* We don't commit the memory for the answer - it's temporary only. */ -} - -/* These are for -D, -U, -A. */ - -/* Process the string STR as if it appeared as the body of a #define. - If STR is just an identifier, define it with value 1. - If STR has anything after the identifier, then it should - be identifier=definition. */ -void -cpp_define (cpp_reader *pfile, const char *str) -{ - char *buf, *p; - size_t count; - - /* Copy the entire option so we can modify it. - Change the first "=" in the string to a space. If there is none, - tack " 1" on the end. */ - - count = strlen (str); - buf = alloca (count + 3); - memcpy (buf, str, count); - - p = strchr (str, '='); - if (p) - buf[p - str] = ' '; - else - { - buf[count++] = ' '; - buf[count++] = '1'; - } - buf[count] = '\n'; - - run_directive (pfile, T_DEFINE, buf, count); -} - -/* Slight variant of the above for use by initialize_builtins. */ -void -_cpp_define_builtin (cpp_reader *pfile, const char *str) -{ - size_t len = strlen (str); - char *buf = alloca (len + 1); - memcpy (buf, str, len); - buf[len] = '\n'; - run_directive (pfile, T_DEFINE, buf, len); -} - -/* Process MACRO as if it appeared as the body of an #undef. */ -void -cpp_undef (cpp_reader *pfile, const char *macro) -{ - size_t len = strlen (macro); - char *buf = alloca (len + 1); - memcpy (buf, macro, len); - buf[len] = '\n'; - run_directive (pfile, T_UNDEF, buf, len); -} - -/* Process the string STR as if it appeared as the body of a #assert. */ -void -cpp_assert (cpp_reader *pfile, const char *str) -{ - handle_assertion (pfile, str, T_ASSERT); -} - -/* Process STR as if it appeared as the body of an #unassert. */ -void -cpp_unassert (cpp_reader *pfile, const char *str) -{ - handle_assertion (pfile, str, T_UNASSERT); -} - -/* Common code for cpp_assert (-A) and cpp_unassert (-A-). */ -static void -handle_assertion (cpp_reader *pfile, const char *str, int type) -{ - size_t count = strlen (str); - const char *p = strchr (str, '='); - - /* Copy the entire option so we can modify it. Change the first - "=" in the string to a '(', and tack a ')' on the end. */ - char *buf = alloca (count + 2); - - memcpy (buf, str, count); - if (p) - { - buf[p - str] = '('; - buf[count++] = ')'; - } - buf[count] = '\n'; - str = buf; - - run_directive (pfile, type, str, count); -} - -/* The number of errors for a given reader. */ -unsigned int -cpp_errors (cpp_reader *pfile) -{ - return pfile->errors; -} - -/* The options structure. */ -cpp_options * -cpp_get_options (cpp_reader *pfile) -{ - return &pfile->opts; -} - -/* The callbacks structure. */ -cpp_callbacks * -cpp_get_callbacks (cpp_reader *pfile) -{ - return &pfile->cb; -} - -/* The line map set. */ -struct line_maps * -cpp_get_line_maps (cpp_reader *pfile) -{ - return &pfile->line_maps; -} - -/* Copy the given callbacks structure to our own. */ -void -cpp_set_callbacks (cpp_reader *pfile, cpp_callbacks *cb) -{ - pfile->cb = *cb; -} - -/* Push a new buffer on the buffer stack. Returns the new buffer; it - doesn't fail. It does not generate a file change call back; that - is the responsibility of the caller. */ -cpp_buffer * -cpp_push_buffer (cpp_reader *pfile, const uchar *buffer, size_t len, - int from_stage3) -{ - cpp_buffer *new = xobnew (&pfile->buffer_ob, cpp_buffer); - - /* Clears, amongst other things, if_stack and mi_cmacro. */ - memset (new, 0, sizeof (cpp_buffer)); - - new->next_line = new->buf = buffer; - new->rlimit = buffer + len; - new->from_stage3 = from_stage3; - new->prev = pfile->buffer; - new->need_line = true; - - pfile->buffer = new; - return new; -} - -/* Pops a single buffer, with a file change call-back if appropriate. - Then pushes the next -include file, if any remain. */ -void -_cpp_pop_buffer (cpp_reader *pfile) -{ - cpp_buffer *buffer = pfile->buffer; - struct _cpp_file *inc = buffer->file; - struct if_stack *ifs; - - /* Walk back up the conditional stack till we reach its level at - entry to this file, issuing error messages. */ - for (ifs = buffer->if_stack; ifs; ifs = ifs->next) - cpp_error_with_line (pfile, CPP_DL_ERROR, ifs->line, 0, - "unterminated #%s", dtable[ifs->type].name); - - /* In case of a missing #endif. */ - pfile->state.skipping = 0; - - /* _cpp_do_file_change expects pfile->buffer to be the new one. */ - pfile->buffer = buffer->prev; - - free (buffer->notes); - - /* Free the buffer object now; we may want to push a new buffer - in _cpp_push_next_include_file. */ - obstack_free (&pfile->buffer_ob, buffer); - - if (inc) - { - _cpp_pop_file_buffer (pfile, inc); - - _cpp_do_file_change (pfile, LC_LEAVE, 0, 0, 0); - } -} - -/* Enter all recognized directives in the hash table. */ -void -_cpp_init_directives (cpp_reader *pfile) -{ - unsigned int i; - cpp_hashnode *node; - - for (i = 0; i < (unsigned int) N_DIRECTIVES; i++) - { - node = cpp_lookup (pfile, dtable[i].name, dtable[i].length); - node->is_directive = 1; - node->directive_index = i; - } -} diff --git a/support/cpp2/cpplib.h b/support/cpp2/cpplib.h deleted file mode 100644 index 4ce262c4..00000000 --- a/support/cpp2/cpplib.h +++ /dev/null @@ -1,758 +0,0 @@ -/* Definitions for CPP library. - Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 - Free Software Foundation, Inc. - Written by Per Bothner, 1994-95. - -This program 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 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - In other words, you are welcome to use, share and improve this program. - You are forbidden to forbid anyone else to use, share and improve - what you give them. Help stamp out software-hoarding! */ -#ifndef GCC_CPPLIB_H -#define GCC_CPPLIB_H - -#include -#include "hashtable.h" -#include "line-map.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct cpp_reader cpp_reader; -typedef struct cpp_buffer cpp_buffer; -typedef struct cpp_options cpp_options; -typedef struct cpp_token cpp_token; -typedef struct cpp_string cpp_string; -typedef struct cpp_hashnode cpp_hashnode; -typedef struct cpp_macro cpp_macro; -typedef struct cpp_callbacks cpp_callbacks; -typedef struct cpp_dir cpp_dir; - -struct answer; - -/* The first three groups, apart from '=', can appear in preprocessor - expressions (+= and -= are used to indicate unary + and - resp.). - This allows a lookup table to be implemented in _cpp_parse_expr. - - The first group, to CPP_LAST_EQ, can be immediately followed by an - '='. The lexer needs operators ending in '=', like ">>=", to be in - the same order as their counterparts without the '=', like ">>". */ - -/* Positions in the table. */ -#define CPP_LAST_EQ CPP_MAX -#define CPP_FIRST_DIGRAPH CPP_HASH -#define CPP_LAST_PUNCTUATOR CPP_DOT_STAR -#define CPP_LAST_CPP_OP CPP_LESS_EQ - -#define TTYPE_TABLE \ - OP(CPP_EQ = 0, "=") \ - OP(CPP_NOT, "!") \ - OP(CPP_GREATER, ">") /* compare */ \ - OP(CPP_LESS, "<") \ - OP(CPP_PLUS, "+") /* math */ \ - OP(CPP_MINUS, "-") \ - OP(CPP_MULT, "*") \ - OP(CPP_DIV, "/") \ - OP(CPP_MOD, "%") \ - OP(CPP_AND, "&") /* bit ops */ \ - OP(CPP_OR, "|") \ - OP(CPP_XOR, "^") \ - OP(CPP_RSHIFT, ">>") \ - OP(CPP_LSHIFT, "<<") \ - OP(CPP_MIN, "?") \ -\ - OP(CPP_COMPL, "~") \ - OP(CPP_AND_AND, "&&") /* logical */ \ - OP(CPP_OR_OR, "||") \ - OP(CPP_QUERY, "?") \ - OP(CPP_COLON, ":") \ - OP(CPP_COMMA, ",") /* grouping */ \ - OP(CPP_OPEN_PAREN, "(") \ - OP(CPP_CLOSE_PAREN, ")") \ - TK(CPP_EOF, SPELL_NONE) \ - OP(CPP_EQ_EQ, "==") /* compare */ \ - OP(CPP_NOT_EQ, "!=") \ - OP(CPP_GREATER_EQ, ">=") \ - OP(CPP_LESS_EQ, "<=") \ -\ - /* These two are unary + / - in preprocessor expressions. */ \ - OP(CPP_PLUS_EQ, "+=") /* math */ \ - OP(CPP_MINUS_EQ, "-=") \ -\ - OP(CPP_MULT_EQ, "*=") \ - OP(CPP_DIV_EQ, "/=") \ - OP(CPP_MOD_EQ, "%=") \ - OP(CPP_AND_EQ, "&=") /* bit ops */ \ - OP(CPP_OR_EQ, "|=") \ - OP(CPP_XOR_EQ, "^=") \ - OP(CPP_RSHIFT_EQ, ">>=") \ - OP(CPP_LSHIFT_EQ, "<<=") \ - OP(CPP_MIN_EQ, "?=") \ - /* Digraphs together, beginning with CPP_FIRST_DIGRAPH. */ \ - OP(CPP_HASH, "#") /* digraphs */ \ - OP(CPP_PASTE, "##") \ - OP(CPP_OPEN_SQUARE, "[") \ - OP(CPP_CLOSE_SQUARE, "]") \ - OP(CPP_OPEN_BRACE, "{") \ - OP(CPP_CLOSE_BRACE, "}") \ - /* The remainder of the punctuation. Order is not significant. */ \ - OP(CPP_SEMICOLON, ";") /* structure */ \ - OP(CPP_ELLIPSIS, "...") \ - OP(CPP_PLUS_PLUS, "++") /* increment */ \ - OP(CPP_MINUS_MINUS, "--") \ - OP(CPP_DEREF, "->") /* accessors */ \ - OP(CPP_DOT, ".") \ - OP(CPP_SCOPE, "::") \ - OP(CPP_DEREF_STAR, "->*") \ - OP(CPP_DOT_STAR, ".*") \ - OP(CPP_ATSIGN, "@") /* used in Objective-C */ \ -\ - TK(CPP_NAME, SPELL_IDENT) /* word */ \ - TK(CPP_AT_NAME, SPELL_IDENT) /* @word - Objective-C */ \ - TK(CPP_NUMBER, SPELL_LITERAL) /* 34_be+ta */ \ -\ - TK(CPP_CHAR, SPELL_LITERAL) /* 'char' */ \ - TK(CPP_WCHAR, SPELL_LITERAL) /* L'char' */ \ - TK(CPP_OTHER, SPELL_LITERAL) /* stray punctuation */ \ -\ - TK(CPP_STRING, SPELL_LITERAL) /* "string" */ \ - TK(CPP_WSTRING, SPELL_LITERAL) /* L"string" */ \ - TK(CPP_OBJC_STRING, SPELL_LITERAL) /* @"string" - Objective-C */ \ - TK(CPP_HEADER_NAME, SPELL_LITERAL) /* in #include */ \ -\ - TK(CPP_COMMENT, SPELL_LITERAL) /* Only if output comments. */ \ - /* SPELL_LITERAL happens to DTRT. */ \ - TK(CPP_MACRO_ARG, SPELL_NONE) /* Macro argument. */ \ - TK(CPP_PADDING, SPELL_NONE) /* Whitespace for cpp0. */ \ -\ - /* SDCC _asm specific */ \ - TK(CPP_ASM, SPELL_LITERAL) /* _asm ... _endasm ; */ -#define OP(e, s) e, -#define TK(e, s) e, -enum cpp_ttype -{ - TTYPE_TABLE - N_TTYPES -}; -#undef OP -#undef TK - -/* C language kind, used when calling cpp_reader_init. */ -enum c_lang {CLK_GNUC89 = 0, CLK_GNUC99, CLK_STDC89, CLK_STDC94, CLK_STDC99, - CLK_GNUCXX, CLK_CXX98, CLK_ASM}; - -/* Payload of a NUMBER, STRING, CHAR or COMMENT token. */ -struct cpp_string -{ - unsigned int len; - const unsigned char *text; -}; - -/* Flags for the cpp_token structure. */ -#define PREV_WHITE (1 << 0) /* If whitespace before this token. */ -#define DIGRAPH (1 << 1) /* If it was a digraph. */ -#define STRINGIFY_ARG (1 << 2) /* If macro argument to be stringified. */ -#define PASTE_LEFT (1 << 3) /* If on LHS of a ## operator. */ -#define NAMED_OP (1 << 4) /* C++ named operators. */ -#define NO_EXPAND (1 << 5) /* Do not macro-expand this token. */ -#define BOL (1 << 6) /* Token at beginning of line. */ - -/* A preprocessing token. This has been carefully packed and should - occupy 16 bytes on 32-bit hosts and 24 bytes on 64-bit hosts. */ -struct cpp_token -{ - fileline line; /* Logical line of first char of token. */ - unsigned short col; /* Column of first char of token. */ - ENUM_BITFIELD(cpp_ttype) type : CHAR_BIT; /* token type */ - unsigned char flags; /* flags - see above */ - - union - { - cpp_hashnode *node; /* An identifier. */ - const cpp_token *source; /* Inherit padding from this token. */ - struct cpp_string str; /* A string, or number. */ - unsigned int arg_no; /* Argument no. for a CPP_MACRO_ARG. */ - } val; -}; - -/* A type wide enough to hold any multibyte source character. - cpplib's character constant interpreter requires an unsigned type. - Also, a typedef for the signed equivalent. - The width of this type is capped at 32 bits; there do exist targets - where wchar_t is 64 bits, but only in a non-default mode, and there - would be no meaningful interpretation for a wchar_t value greater - than 2^32 anyway -- the widest wide-character encoding around is - ISO 10646, which stops at 2^31. */ -#if CHAR_BIT * SIZEOF_INT >= 32 -# define CPPCHAR_SIGNED_T int -#elif CHAR_BIT * SIZEOF_LONG >= 32 -# define CPPCHAR_SIGNED_T long -#else -# error "Cannot find a least-32-bit signed integer type" -#endif -typedef unsigned CPPCHAR_SIGNED_T cppchar_t; -typedef CPPCHAR_SIGNED_T cppchar_signed_t; - -/* This structure is nested inside struct cpp_reader, and - carries all the options visible to the command line. */ -struct cpp_options -{ - /* Characters between tab stops. */ - unsigned int tabstop; - - /* The language we're preprocessing. */ - enum c_lang lang; - - /* Nonzero means use extra default include directories for C++. */ - unsigned char cplusplus; - - /* Nonzero means handle cplusplus style comments. */ - unsigned char cplusplus_comments; - - /* Nonzero means define __OBJC__, treat @ as a special token, and - use the OBJC[PLUS]_INCLUDE_PATH environment variable. */ - unsigned char objc; - - /* Nonzero means don't copy comments into the output file. */ - unsigned char discard_comments; - - /* Nonzero means don't copy comments into the output file during - macro expansion. */ - unsigned char discard_comments_in_macro_exp; - - /* Nonzero means process the ISO trigraph sequences. */ - unsigned char trigraphs; - - /* Nonzero means process the ISO digraph sequences. */ - unsigned char digraphs; - - /* Nonzero means to allow hexadecimal floats and LL suffixes. */ - unsigned char extended_numbers; - - /* Nonzero means print names of header files (-H). */ - unsigned char print_include_names; - - /* Nonzero means cpp_pedwarn causes a hard error. */ - unsigned char pedantic_errors; - - /* Nonzero means don't print warning messages. */ - unsigned char inhibit_warnings; - - /* Nonzero means complain about deprecated features. */ - unsigned char warn_deprecated; - - /* Nonzero means don't suppress warnings from system headers. */ - unsigned char warn_system_headers; - - /* Nonzero means don't print error messages. Has no option to - select it, but can be set by a user of cpplib (e.g. fix-header). */ - unsigned char inhibit_errors; - - /* Nonzero means warn if slash-star appears in a comment. */ - unsigned char warn_comments; - - /* Nonzero means warn if there are any trigraphs. */ - unsigned char warn_trigraphs; - - /* Nonzero means warn about multicharacter charconsts. */ - unsigned char warn_multichar; - - /* Nonzero means warn about various incompatibilities with - traditional C. */ - unsigned char warn_traditional; - - /* Nonzero means warn about long long numeric constants. */ - unsigned char warn_long_long; - - /* Nonzero means warn about text after an #endif (or #else). */ - unsigned char warn_endif_labels; - - /* Nonzero means warn about implicit sign changes owing to integer - promotions. */ - unsigned char warn_num_sign_change; - - /* Nonzero means turn warnings into errors. */ - unsigned char warnings_are_errors; - - /* Nonzero means we should look for header.gcc files that remap file - names. */ - unsigned char remap; - - /* Zero means dollar signs are punctuation. */ - unsigned char dollars_in_ident; - - /* True if we should warn about dollars in identifiers or numbers - for this translation unit. */ - unsigned char warn_dollars; - - /* Nonzero means warn if undefined identifiers are evaluated in an #if. */ - unsigned char warn_undef; - - /* Nonzero means warn of unused macros from the main file. */ - unsigned char warn_unused_macros; - - /* Nonzero for the 1999 C Standard, including corrigenda and amendments. */ - unsigned char c99; - - /* Nonzero if we are conforming to a specific C or C++ standard. */ - unsigned char std; - - /* Nonzero means give all the error messages the ANSI standard requires. */ - unsigned char pedantic; - - /* Nonzero means we're looking at already preprocessed code, so don't - bother trying to do macro expansion and whatnot. */ - unsigned char preprocessed; - - /* Print column number in error messages. */ - unsigned char show_column; - - /* Nonzero means handle C++ alternate operator names. */ - unsigned char operator_names; - - /* True for traditional preprocessing. */ - unsigned char traditional; - - /* Holds the name of the target (execution) character set. */ - const char *narrow_charset; - - /* Holds the name of the target wide character set. */ - const char *wide_charset; - - /* Holds the name of the input character set. */ - const char *input_charset; - - /* True to warn about precompiled header files we couldn't use. */ - bool warn_invalid_pch; - - /* True if dependencies should be restored from a precompiled header. */ - bool restore_pch_deps; - - /* SDCC abuse by Kevin: allow naked '#' characters in expanded macros - * (see _cpp_create_definition in cppmacro.c) - */ - unsigned char allow_naked_hash; - - /* SDCC _asm specific - switch _asm block preprocessing on / off */ - unsigned char preproc_asm; - - /* SDCC specific - object file exetnsion */ - const char *obj_ext; - - /* SDCC specific - pedantic_parse_number */ - unsigned char pedantic_parse_number; - - /* Dependency generation. */ - struct - { - /* Style of header dependencies to generate. */ - enum {DEPS_NONE = 0, DEPS_USER, DEPS_SYSTEM } style; - - /* Assume missing files are generated files. */ - bool missing_files; - - /* Generate phony targets for each dependency apart from the first - one. */ - bool phony_targets; - - /* If true, no dependency is generated on the main file. */ - bool ignore_main_file; - } deps; - - /* Target-specific features set by the front end or client. */ - - /* Precision for target CPP arithmetic, target characters, target - ints and target wide characters, respectively. */ - size_t precision, char_precision, int_precision, wchar_precision; - - /* True means chars (wide chars) are unsigned. */ - bool unsigned_char, unsigned_wchar; - - /* True if the most significant byte in a word has the lowest - address in memory. */ - bool bytes_big_endian; - - /* Nonzero means __STDC__ should have the value 0 in system headers. */ - unsigned char stdc_0_in_system_headers; -}; - -/* Call backs to cpplib client. */ -struct cpp_callbacks -{ - /* Called when a new line of preprocessed output is started. */ - void (*line_change) (cpp_reader *, const cpp_token *, int); - - /* Called when switching to/from a new file. - The line_map is for the new file. It is NULL if there is no new file. - (In C this happens when done with + and also - when done with a main file.) This can be used for resource cleanup. */ - void (*file_change) (cpp_reader *, const struct line_map *); - - void (*dir_change) (cpp_reader *, const char *); - void (*include) (cpp_reader *, unsigned int, const unsigned char *, - const char *, int); - void (*define) (cpp_reader *, unsigned int, cpp_hashnode *); - void (*undef) (cpp_reader *, unsigned int, cpp_hashnode *); - void (*ident) (cpp_reader *, unsigned int, const cpp_string *); - void (*def_pragma) (cpp_reader *, unsigned int); - int (*valid_pch) (cpp_reader *, const char *, int); - void (*read_pch) (cpp_reader *, const char *, int, const char *); -}; - -/* Chain of directories to look for include files in. */ -struct cpp_dir -{ - /* NULL-terminated singly-linked list. */ - struct cpp_dir *next; - - /* NAME of the directory, NUL-terminated. */ - char *name; - unsigned int len; - - /* One if a system header, two if a system header that has extern - "C" guards for C++. */ - unsigned char sysp; - - /* Mapping of file names for this directory for MS-DOS and related - platforms. A NULL-terminated array of (from, to) pairs. */ - const char **name_map; - - /* The C front end uses these to recognize duplicated - directories in the search path. */ - ino_t ino; - dev_t dev; -}; - -/* Name under which this program was invoked. */ -extern const char *progname; - -/* The structure of a node in the hash table. The hash table has - entries for all identifiers: either macros defined by #define - commands (type NT_MACRO), assertions created with #assert - (NT_ASSERTION), or neither of the above (NT_VOID). Builtin macros - like __LINE__ are flagged NODE_BUILTIN. Poisoned identifiers are - flagged NODE_POISONED. NODE_OPERATOR (C++ only) indicates an - identifier that behaves like an operator such as "xor". - NODE_DIAGNOSTIC is for speed in lex_token: it indicates a - diagnostic may be required for this node. Currently this only - applies to __VA_ARGS__ and poisoned identifiers. */ - -/* Hash node flags. */ -#define NODE_OPERATOR (1 << 0) /* C++ named operator. */ -#define NODE_POISONED (1 << 1) /* Poisoned identifier. */ -#define NODE_BUILTIN (1 << 2) /* Builtin macro. */ -#define NODE_DIAGNOSTIC (1 << 3) /* Possible diagnostic when lexed. */ -#define NODE_WARN (1 << 4) /* Warn if redefined or undefined. */ -#define NODE_DISABLED (1 << 5) /* A disabled macro. */ -#define NODE_MACRO_ARG (1 << 6) /* Used during #define processing. */ - -/* Different flavors of hash node. */ -enum node_type -{ - NT_VOID = 0, /* No definition yet. */ - NT_MACRO, /* A macro of some form. */ - NT_ASSERTION /* Predicate for #assert. */ -}; - -/* Different flavors of builtin macro. _Pragma is an operator, but we - handle it with the builtin code for efficiency reasons. */ -enum builtin_type -{ - BT_SPECLINE = 0, /* `__LINE__' */ - BT_DATE, /* `__DATE__' */ - BT_FILE, /* `__FILE__' */ - BT_BASE_FILE, /* `__BASE_FILE__' */ - BT_INCLUDE_LEVEL, /* `__INCLUDE_LEVEL__' */ - BT_TIME, /* `__TIME__' */ - BT_STDC, /* `__STDC__' */ - BT_PRAGMA /* `_Pragma' operator */ -}; - -#define CPP_HASHNODE(HNODE) ((cpp_hashnode *) (HNODE)) -#define HT_NODE(NODE) ((ht_identifier *) (NODE)) -#define NODE_LEN(NODE) HT_LEN (&(NODE)->ident) -#define NODE_NAME(NODE) HT_STR (&(NODE)->ident) - -/* The common part of an identifier node shared amongst all 3 C front - ends. Also used to store CPP identifiers, which are a superset of - identifiers in the grammatical sense. */ -struct cpp_hashnode GTY(()) -{ - struct ht_identifier ident; - unsigned int is_directive : 1; - unsigned int directive_index : 7; /* If is_directive, - then index into directive table. - Otherwise, a NODE_OPERATOR. */ - unsigned char rid_code; /* Rid code - for front ends. */ - ENUM_BITFIELD(node_type) type : 8; /* CPP node type. */ - unsigned char flags; /* CPP flags. */ - - union _cpp_hashnode_value - { - /* If a macro. */ - cpp_macro * GTY((skip (""))) macro; - /* Answers to an assertion. */ - struct answer * GTY ((skip (""))) answers; - /* Code for a builtin macro. */ - enum builtin_type GTY ((tag ("1"))) builtin; - /* Macro argument index. */ - unsigned short GTY ((tag ("0"))) arg_index; - } GTY ((desc ("0"))) value; -}; - -/* Call this first to get a handle to pass to other functions. - - If you want cpplib to manage its own hashtable, pass in a NULL - pointer. Otherwise you should pass in an initialized hash table - that cpplib will share; this technique is used by the C front - ends. */ -extern cpp_reader *cpp_create_reader (enum c_lang, struct ht *); - -/* Call this to change the selected language standard (e.g. because of - command line options). */ -extern void cpp_set_lang (cpp_reader *, enum c_lang); - -/* Add a dependency TARGET. Quote it for "make" if QUOTE. Can be - called any number of times before cpp_read_main_file(). If no - targets have been added before cpp_read_main_file(), then the - default target is used. */ -extern void cpp_add_dependency_target (cpp_reader *, const char *, int); - -/* Set the include paths. */ -extern void cpp_set_include_chains (cpp_reader *, cpp_dir *, cpp_dir *, int); - -/* Call these to get pointers to the options and callback structures - for a given reader. These pointers are good until you call - cpp_finish on that reader. You can either edit the callbacks - through the pointer returned from cpp_get_callbacks, or set them - with cpp_set_callbacks. */ -extern cpp_options *cpp_get_options (cpp_reader *); -extern struct line_maps *cpp_get_line_maps (cpp_reader *); -extern cpp_callbacks *cpp_get_callbacks (cpp_reader *); -extern void cpp_set_callbacks (cpp_reader *, cpp_callbacks *); - -/* This function reads the file, but does not start preprocessing. It - returns the name of the original file; this is the same as the - input file, except for preprocessed input. This will generate at - least one file change callback, and possibly a line change callback - too. If there was an error opening the file, it returns NULL. */ -extern const char *cpp_read_main_file (cpp_reader *, const char *); - -/* Set up built-ins like __FILE__. */ -extern void cpp_init_builtins (cpp_reader *, int); - -/* This is called after options have been parsed, and partially - processed. */ -extern void cpp_post_options (cpp_reader *); - -/* Set up translation to the target character set. */ -extern void cpp_init_iconv (cpp_reader *); - -/* Call this to finish preprocessing. If you requested dependency - generation, pass an open stream to write the information to, - otherwise NULL. It is your responsibility to close the stream. - - Returns cpp_errors (pfile). */ -extern int cpp_finish (cpp_reader *, FILE *deps_stream); - -/* Call this to release the handle at the end of preprocessing. Any - use of the handle after this function returns is invalid. Returns - cpp_errors (pfile). */ -extern void cpp_destroy (cpp_reader *); - -/* Error count. */ -extern unsigned int cpp_errors (cpp_reader *); - -extern unsigned int cpp_token_len (const cpp_token *); -extern unsigned char *cpp_token_as_text (cpp_reader *, const cpp_token *); -extern unsigned char *cpp_spell_token (cpp_reader *, const cpp_token *, - unsigned char *); -extern void cpp_register_pragma (cpp_reader *, const char *, const char *, - void (*) (cpp_reader *)); -extern int cpp_avoid_paste (cpp_reader *, const cpp_token *, - const cpp_token *); -extern const cpp_token *cpp_get_token (cpp_reader *); -extern const unsigned char *cpp_macro_definition (cpp_reader *, - const cpp_hashnode *); -extern void _cpp_backup_tokens (cpp_reader *, unsigned int); - -/* Evaluate a CPP_CHAR or CPP_WCHAR token. */ -extern cppchar_t cpp_interpret_charconst (cpp_reader *, const cpp_token *, - unsigned int *, int *); -/* Evaluate a vector of CPP_STRING or CPP_WSTRING tokens. */ -extern bool cpp_interpret_string (cpp_reader *, - const cpp_string *, size_t, - cpp_string *, bool); - -/* Used to register macros and assertions, perhaps from the command line. - The text is the same as the command line argument. */ -extern void cpp_define (cpp_reader *, const char *); -extern void cpp_assert (cpp_reader *, const char *); -extern void cpp_undef (cpp_reader *, const char *); -extern void cpp_unassert (cpp_reader *, const char *); - -/* Undefine all macros and assertions. */ -extern void cpp_undef_all (cpp_reader *); - -extern cpp_buffer *cpp_push_buffer (cpp_reader *, const unsigned char *, - size_t, int); -extern int cpp_defined (cpp_reader *, const unsigned char *, int); - -/* A preprocessing number. Code assumes that any unused high bits of - the double integer are set to zero. */ -typedef unsigned HOST_WIDE_INT cpp_num_part; -typedef struct cpp_num cpp_num; -struct cpp_num -{ - cpp_num_part high; - cpp_num_part low; - bool unsignedp; /* True if value should be treated as unsigned. */ - bool overflow; /* True if the most recent calculation overflowed. */ -}; - -/* cpplib provides two interfaces for interpretation of preprocessing - numbers. - - cpp_classify_number categorizes numeric constants according to - their field (integer, floating point, or invalid), radix (decimal, - octal, hexadecimal), and type suffixes. */ - -#define CPP_N_CATEGORY 0x000F -#define CPP_N_INVALID 0x0000 -#define CPP_N_INTEGER 0x0001 -#define CPP_N_FLOATING 0x0002 - -#define CPP_N_WIDTH 0x00F0 -#define CPP_N_SMALL 0x0010 /* int, float. */ -#define CPP_N_MEDIUM 0x0020 /* long, double. */ -#define CPP_N_LARGE 0x0040 /* long long, long double. */ - -#define CPP_N_RADIX 0x0F00 -#define CPP_N_DECIMAL 0x0100 -#define CPP_N_HEX 0x0200 -#define CPP_N_OCTAL 0x0400 - -#define CPP_N_UNSIGNED 0x1000 /* Properties. */ -#define CPP_N_IMAGINARY 0x2000 - -/* Classify a CPP_NUMBER token. The return value is a combination of - the flags from the above sets. */ -extern unsigned cpp_classify_number (cpp_reader *, const cpp_token *); - -/* Evaluate a token classified as category CPP_N_INTEGER. */ -extern cpp_num cpp_interpret_integer (cpp_reader *, const cpp_token *, - unsigned int type); - -/* Sign extend a number, with PRECISION significant bits and all - others assumed clear, to fill out a cpp_num structure. */ -cpp_num cpp_num_sign_extend (cpp_num, size_t); - -/* Diagnostic levels. To get a diagnostic without associating a - position in the translation unit with it, use cpp_error_with_line - with a line number of zero. */ - -/* Warning, an error with -Werror. */ -#define CPP_DL_WARNING 0x00 -/* Same as CPP_DL_WARNING, except it is not suppressed in system headers. */ -#define CPP_DL_WARNING_SYSHDR 0x01 -/* Warning, an error with -pedantic-errors or -Werror. */ -#define CPP_DL_PEDWARN 0x02 -/* An error. */ -#define CPP_DL_ERROR 0x03 -/* An internal consistency check failed. Prints "internal error: ", - otherwise the same as CPP_DL_ERROR. */ -#define CPP_DL_ICE 0x04 -/* Extracts a diagnostic level from an int. */ -#define CPP_DL_EXTRACT(l) (l & 0xf) -/* Nonzero if a diagnostic level is one of the warnings. */ -#define CPP_DL_WARNING_P(l) (CPP_DL_EXTRACT (l) >= CPP_DL_WARNING \ - && CPP_DL_EXTRACT (l) <= CPP_DL_PEDWARN) - -/* N.B. The error-message-printer prototypes have not been nicely - formatted because exgettext needs to see 'msgid' on the same line - as the name of the function in order to work properly. Only the - string argument gets a name in an effort to keep the lines from - getting ridiculously oversized. */ - -/* Output a diagnostic of some kind. */ -extern void cpp_error (cpp_reader *, int, const char *msgid, ...) - ATTRIBUTE_PRINTF_3; - -/* Output a diagnostic with "MSGID: " preceding the - error string of errno. No location is printed. */ -extern void cpp_errno (cpp_reader *, int, const char *msgid); - -/* Same as cpp_error, except additionally specifies a position as a - (translation unit) physical line and physical column. If the line is - zero, then no location is printed. */ -extern void cpp_error_with_line (cpp_reader *, int, fileline, unsigned, - const char *msgid, ...) ATTRIBUTE_PRINTF_5; - -/* In cpplex.c */ -extern int cpp_ideq (const cpp_token *, const char *); -extern void cpp_output_line (cpp_reader *, FILE *); -extern void cpp_output_token (const cpp_token *, FILE *); -extern const char *cpp_type2name (enum cpp_ttype); -/* Returns the value of an escape sequence, truncated to the correct - target precision. PSTR points to the input pointer, which is just - after the backslash. LIMIT is how much text we have. WIDE is true - if the escape sequence is part of a wide character constant or - string literal. Handles all relevant diagnostics. */ -extern cppchar_t cpp_parse_escape (cpp_reader *, const unsigned char ** pstr, - const unsigned char *limit, int wide); - -/* In cpphash.c */ - -/* Lookup an identifier in the hashtable. Puts the identifier in the - table if it is not already there. */ -extern cpp_hashnode *cpp_lookup (cpp_reader *, const unsigned char *, - unsigned int); - -typedef int (*cpp_cb) (cpp_reader *, cpp_hashnode *, void *); -extern void cpp_forall_identifiers (cpp_reader *, cpp_cb, void *); - -/* In cppmacro.c */ -extern void cpp_scan_nooutput (cpp_reader *); -extern int cpp_sys_macro_p (cpp_reader *); -extern unsigned char *cpp_quote_string (unsigned char *, const unsigned char *, - unsigned int); - -/* In cppfiles.c */ -extern bool cpp_included (cpp_reader *, const char *); -extern void cpp_make_system_header (cpp_reader *, int, int); -extern bool cpp_push_include (cpp_reader *, const char *); -extern void cpp_change_file (cpp_reader *, enum lc_reason, const char *); - -/* In cpppch.c */ -struct save_macro_data; -extern int cpp_save_state (cpp_reader *, FILE *); -extern int cpp_write_pch_deps (cpp_reader *, FILE *); -extern int cpp_write_pch_state (cpp_reader *, FILE *); -extern int cpp_valid_state (cpp_reader *, const char *, int); -extern void cpp_prepare_state (cpp_reader *, struct save_macro_data **); -extern int cpp_read_state (cpp_reader *, const char *, FILE *, - struct save_macro_data *); - -#ifdef __cplusplus -} -#endif - -#endif /* ! GCC_CPPLIB_H */ diff --git a/support/cpp2/cppmacro.c b/support/cpp2/cppmacro.c deleted file mode 100644 index 59e3f582..00000000 --- a/support/cpp2/cppmacro.c +++ /dev/null @@ -1,1729 +0,0 @@ -/* Part of CPP library. (Macro and #define handling.) - Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998, - 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. - Written by Per Bothner, 1994. - Based on CCCP program by Paul Rubin, June 1986 - Adapted to ANSI C, Richard Stallman, Jan 1987 - -This program 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 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - In other words, you are welcome to use, share and improve this program. - You are forbidden to forbid anyone else to use, share and improve - what you give them. Help stamp out software-hoarding! */ - -#include "config.h" -#include "system.h" -#include "cpplib.h" -#include "cpphash.h" - -typedef struct macro_arg macro_arg; -struct macro_arg -{ - const cpp_token **first; /* First token in unexpanded argument. */ - const cpp_token **expanded; /* Macro-expanded argument. */ - const cpp_token *stringified; /* Stringified argument. */ - unsigned int count; /* # of tokens in argument. */ - unsigned int expanded_count; /* # of tokens in expanded argument. */ -}; - -/* Macro expansion. */ - -static int enter_macro_context (cpp_reader *, cpp_hashnode *); -static int builtin_macro (cpp_reader *, cpp_hashnode *); -static void push_token_context (cpp_reader *, cpp_hashnode *, - const cpp_token *, unsigned int); -static void push_ptoken_context (cpp_reader *, cpp_hashnode *, _cpp_buff *, - const cpp_token **, unsigned int); -static _cpp_buff *collect_args (cpp_reader *, const cpp_hashnode *); -static cpp_context *next_context (cpp_reader *); -static const cpp_token *padding_token (cpp_reader *, const cpp_token *); -static void expand_arg (cpp_reader *, macro_arg *); -static const cpp_token *new_string_token (cpp_reader *, uchar *, unsigned int); -static const cpp_token *stringify_arg (cpp_reader *, macro_arg *); -static void paste_all_tokens (cpp_reader *, const cpp_token *); -static bool paste_tokens (cpp_reader *, const cpp_token **, const cpp_token *); -static void replace_args (cpp_reader *, cpp_hashnode *, cpp_macro *, - macro_arg *); -static _cpp_buff *funlike_invocation_p (cpp_reader *, cpp_hashnode *); -static bool create_iso_definition (cpp_reader *, cpp_macro *); - -/* #define directive parsing and handling. */ - -static cpp_token *alloc_expansion_token (cpp_reader *, cpp_macro *); -static cpp_token *lex_expansion_token (cpp_reader *, cpp_macro *); -static bool warn_of_redefinition (cpp_reader *, const cpp_hashnode *, - const cpp_macro *); -static bool parse_params (cpp_reader *, cpp_macro *); -static void check_trad_stringification (cpp_reader *, const cpp_macro *, - const cpp_string *); - -/* Emits a warning if NODE is a macro defined in the main file that - has not been used. */ -int -_cpp_warn_if_unused_macro (cpp_reader *pfile, cpp_hashnode *node, - void *v ATTRIBUTE_UNUSED) -{ - if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN)) - { - cpp_macro *macro = node->value.macro; - - if (!macro->used - && MAIN_FILE_P (linemap_lookup (&pfile->line_maps, macro->line))) - cpp_error_with_line (pfile, CPP_DL_WARNING, macro->line, 0, - "macro \"%s\" is not used", NODE_NAME (node)); - } - - return 1; -} - -/* Allocates and returns a CPP_STRING token, containing TEXT of length - LEN, after null-terminating it. TEXT must be in permanent storage. */ -static const cpp_token * -new_string_token (cpp_reader *pfile, unsigned char *text, unsigned int len) -{ - cpp_token *token = _cpp_temp_token (pfile); - - text[len] = '\0'; - token->type = CPP_STRING; - token->val.str.len = len; - token->val.str.text = text; - token->flags = 0; - return token; -} - -static const char * const monthnames[] = -{ - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" -}; - -/* Handle builtin macros like __FILE__, and push the resulting token - on the context stack. Also handles _Pragma, for which no new token - is created. Returns 1 if it generates a new token context, 0 to - return the token to the caller. */ -const uchar * -_cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node) -{ - const uchar *result = NULL; - unsigned int number = 1; - - switch (node->value.builtin) - { - default: - cpp_error (pfile, CPP_DL_ICE, "invalid built-in macro \"%s\"", - NODE_NAME (node)); - break; - - case BT_FILE: - case BT_BASE_FILE: - { - unsigned int len; - const char *name; - uchar *buf; - const struct line_map *map = pfile->map; - - if (node->value.builtin == BT_BASE_FILE) - while (! MAIN_FILE_P (map)) - map = INCLUDED_FROM (&pfile->line_maps, map); - - name = map->to_file; - len = strlen (name); - buf = _cpp_unaligned_alloc (pfile, len * 4 + 3); - result = buf; - *buf = '"'; - buf = cpp_quote_string (buf + 1, (const unsigned char *) name, len); - *buf++ = '"'; - *buf = '\0'; - } - break; - - case BT_INCLUDE_LEVEL: - /* The line map depth counts the primary source as level 1, but - historically __INCLUDE_DEPTH__ has called the primary source - level 0. */ - number = pfile->line_maps.depth - 1; - break; - - case BT_SPECLINE: - /* If __LINE__ is embedded in a macro, it must expand to the - line of the macro's invocation, not its definition. - Otherwise things like assert() will not work properly. */ - if (CPP_OPTION (pfile, traditional)) - number = pfile->line; - else - number = pfile->cur_token[-1].line; - number = SOURCE_LINE (pfile->map, number); - break; - - /* __STDC__ has the value 1 under normal circumstances. - However, if (a) we are in a system header, (b) the option - stdc_0_in_system_headers is true (set by target config), and - (c) we are not in strictly conforming mode, then it has the - value 0. */ - case BT_STDC: - { - if (CPP_IN_SYSTEM_HEADER (pfile) - && CPP_OPTION (pfile, stdc_0_in_system_headers) - && !CPP_OPTION (pfile,std)) - number = 0; - else - number = 1; - } - break; - - case BT_DATE: - case BT_TIME: - if (pfile->date == NULL) - { - /* Allocate __DATE__ and __TIME__ strings from permanent - storage. We only do this once, and don't generate them - at init time, because time() and localtime() are very - slow on some systems. */ - time_t tt; - struct tm *tb = NULL; - - /* (time_t) -1 is a legitimate value for "number of seconds - since the Epoch", so we have to do a little dance to - distinguish that from a genuine error. */ - errno = 0; - tt = time(NULL); - if (tt != (time_t)-1 || errno == 0) - tb = localtime (&tt); - - if (tb) - { - pfile->date = _cpp_unaligned_alloc (pfile, - sizeof ("\"Oct 11 1347\"")); - sprintf ((char *) pfile->date, "\"%s %2d %4d\"", - monthnames[tb->tm_mon], tb->tm_mday, - tb->tm_year + 1900); - - pfile->time = _cpp_unaligned_alloc (pfile, - sizeof ("\"12:34:56\"")); - sprintf ((char *) pfile->time, "\"%02d:%02d:%02d\"", - tb->tm_hour, tb->tm_min, tb->tm_sec); - } - else - { - cpp_errno (pfile, CPP_DL_WARNING, - "could not determine date and time"); - - pfile->date = U"\"??? ?? ????\""; - pfile->time = U"\"??:??:??\""; - } - } - - if (node->value.builtin == BT_DATE) - result = pfile->date; - else - result = pfile->time; - break; - } - - if (result == NULL) - { - /* 21 bytes holds all NUL-terminated unsigned 64-bit numbers. */ - result = _cpp_unaligned_alloc (pfile, 21); - sprintf ((char *) result, "%u", number); - } - - return result; -} - -/* Convert builtin macros like __FILE__ to a token and push it on the - context stack. Also handles _Pragma, for which no new token is - created. Returns 1 if it generates a new token context, 0 to - return the token to the caller. */ -static int -builtin_macro (cpp_reader *pfile, cpp_hashnode *node) -{ - const uchar *buf; - size_t len; - char *nbuf; - - if (node->value.builtin == BT_PRAGMA) - { - /* Don't interpret _Pragma within directives. The standard is - not clear on this, but to me this makes most sense. */ - if (pfile->state.in_directive) - return 0; - - _cpp_do__Pragma (pfile); - return 1; - } - - buf = _cpp_builtin_macro_text (pfile, node); - len = ustrlen (buf); - nbuf = alloca (len + 1); - memcpy (nbuf, buf, len); - nbuf[len]='\n'; - - cpp_push_buffer (pfile, (uchar *) nbuf, len, /* from_stage3 */ true); - _cpp_clean_line (pfile); - - /* Set pfile->cur_token as required by _cpp_lex_direct. */ - pfile->cur_token = _cpp_temp_token (pfile); - push_token_context (pfile, NULL, _cpp_lex_direct (pfile), 1); - if (pfile->buffer->cur != pfile->buffer->rlimit) - cpp_error (pfile, CPP_DL_ICE, "invalid built-in macro \"%s\"", - NODE_NAME (node)); - _cpp_pop_buffer (pfile); - - return 1; -} - -/* Copies SRC, of length LEN, to DEST, adding backslashes before all - backslashes and double quotes. Non-printable characters are - converted to octal. DEST must be of sufficient size. Returns - a pointer to the end of the string. */ -uchar * -cpp_quote_string (uchar *dest, const uchar *src, unsigned int len) -{ - while (len--) - { - uchar c = *src++; - - if (c == '\\' || c == '"') - { - *dest++ = '\\'; - *dest++ = c; - } - else - { - if (ISPRINT (c)) - *dest++ = c; - else - { - sprintf ((char *) dest, "\\%03o", c); - dest += 4; - } - } - } - - return dest; -} - -/* Convert a token sequence ARG to a single string token according to - the rules of the ISO C #-operator. */ -static const cpp_token * -stringify_arg (cpp_reader *pfile, macro_arg *arg) -{ - unsigned char *dest; - unsigned int i, escape_it, backslash_count = 0; - const cpp_token *source = NULL; - size_t len; - - if (BUFF_ROOM (pfile->u_buff) < 3) - _cpp_extend_buff (pfile, &pfile->u_buff, 3); - dest = BUFF_FRONT (pfile->u_buff); - *dest++ = '"'; - - /* Loop, reading in the argument's tokens. */ - for (i = 0; i < arg->count; i++) - { - const cpp_token *token = arg->first[i]; - - if (token->type == CPP_PADDING) - { - if (source == NULL) - source = token->val.source; - continue; - } - - escape_it = (token->type == CPP_STRING || token->type == CPP_WSTRING - || token->type == CPP_CHAR || token->type == CPP_WCHAR); - - /* Room for each char being written in octal, initial space and - final quote and NUL. */ - len = cpp_token_len (token); - if (escape_it) - len *= 4; - len += 3; - - if ((size_t) (BUFF_LIMIT (pfile->u_buff) - dest) < len) - { - size_t len_so_far = dest - BUFF_FRONT (pfile->u_buff); - _cpp_extend_buff (pfile, &pfile->u_buff, len); - dest = BUFF_FRONT (pfile->u_buff) + len_so_far; - } - - /* Leading white space? */ - if (dest - 1 != BUFF_FRONT (pfile->u_buff)) - { - if (source == NULL) - source = token; - if (source->flags & PREV_WHITE) - *dest++ = ' '; - } - source = NULL; - - if (escape_it) - { - _cpp_buff *buff = _cpp_get_buff (pfile, len); - unsigned char *buf = BUFF_FRONT (buff); - len = cpp_spell_token (pfile, token, buf) - buf; - dest = cpp_quote_string (dest, buf, len); - _cpp_release_buff (pfile, buff); - } - else - dest = cpp_spell_token (pfile, token, dest); - - if (token->type == CPP_OTHER && token->val.str.text[0] == '\\') - backslash_count++; - else - backslash_count = 0; - } - - /* Ignore the final \ of invalid string literals. */ - if (backslash_count & 1) - { - cpp_error (pfile, CPP_DL_WARNING, - "invalid string literal, ignoring final '\\'"); - dest--; - } - - /* Commit the memory, including NUL, and return the token. */ - *dest++ = '"'; - len = dest - BUFF_FRONT (pfile->u_buff); - BUFF_FRONT (pfile->u_buff) = dest + 1; - return new_string_token (pfile, dest - len, len); -} - -/* Try to paste two tokens. On success, return nonzero. In any - case, PLHS is updated to point to the pasted token, which is - guaranteed to not have the PASTE_LEFT flag set. */ -static bool -paste_tokens (cpp_reader *pfile, const cpp_token **plhs, const cpp_token *rhs) -{ - unsigned char *buf, *end; - const cpp_token *lhs; - unsigned int len; - bool valid; - - lhs = *plhs; - len = cpp_token_len (lhs) + cpp_token_len (rhs) + 1; - buf = alloca (len); - end = cpp_spell_token (pfile, lhs, buf); - - /* Avoid comment headers, since they are still processed in stage 3. - It is simpler to insert a space here, rather than modifying the - lexer to ignore comments in some circumstances. Simply returning - false doesn't work, since we want to clear the PASTE_LEFT flag. */ - if (lhs->type == CPP_DIV && rhs->type != CPP_EQ) - *end++ = ' '; - end = cpp_spell_token (pfile, rhs, end); - *end = '\n'; - - cpp_push_buffer (pfile, buf, end - buf, /* from_stage3 */ true); - _cpp_clean_line (pfile); - - /* Set pfile->cur_token as required by _cpp_lex_direct. */ - pfile->cur_token = _cpp_temp_token (pfile); - *plhs = _cpp_lex_direct (pfile); - valid = pfile->buffer->cur == pfile->buffer->rlimit; - _cpp_pop_buffer (pfile); - - return valid; -} - -/* Handles an arbitrarily long sequence of ## operators, with initial - operand LHS. This implementation is left-associative, - non-recursive, and finishes a paste before handling succeeding - ones. If a paste fails, we back up to the RHS of the failing ## - operator before pushing the context containing the result of prior - successful pastes, with the effect that the RHS appears in the - output stream after the pasted LHS normally. */ -static void -paste_all_tokens (cpp_reader *pfile, const cpp_token *lhs) -{ - const cpp_token *rhs; - cpp_context *context = pfile->context; - - do - { - /* Take the token directly from the current context. We can do - this, because we are in the replacement list of either an - object-like macro, or a function-like macro with arguments - inserted. In either case, the constraints to #define - guarantee we have at least one more token. */ - if (context->direct_p) - rhs = FIRST (context).token++; - else - rhs = *FIRST (context).ptoken++; - - if (rhs->type == CPP_PADDING) - abort (); - - if (!paste_tokens (pfile, &lhs, rhs)) - { - _cpp_backup_tokens (pfile, 1); - - /* Mandatory error for all apart from assembler. */ - if (CPP_OPTION (pfile, lang) != CLK_ASM) - cpp_error (pfile, CPP_DL_ERROR, - "pasting \"%s\" and \"%s\" does not give a valid preprocessing token", - cpp_token_as_text (pfile, lhs), - cpp_token_as_text (pfile, rhs)); - break; - } - } - while (rhs->flags & PASTE_LEFT); - - /* Put the resulting token in its own context. */ - push_token_context (pfile, NULL, lhs, 1); -} - -/* Returns TRUE if the number of arguments ARGC supplied in an - invocation of the MACRO referenced by NODE is valid. An empty - invocation to a macro with no parameters should pass ARGC as zero. - - Note that MACRO cannot necessarily be deduced from NODE, in case - NODE was redefined whilst collecting arguments. */ -bool -_cpp_arguments_ok (cpp_reader *pfile, cpp_macro *macro, const cpp_hashnode *node, unsigned int argc) -{ - if (argc == macro->paramc) - return true; - - if (argc < macro->paramc) - { - /* As an extension, a rest argument is allowed to not appear in - the invocation at all. - e.g. #define debug(format, args...) something - debug("string"); - - This is exactly the same as if there had been an empty rest - argument - debug("string", ). */ - - if (argc + 1 == macro->paramc && macro->variadic) - { - if (CPP_PEDANTIC (pfile) && ! macro->syshdr) - cpp_error (pfile, CPP_DL_PEDWARN, - "ISO C99 requires rest arguments to be used"); - return true; - } - - cpp_error (pfile, CPP_DL_ERROR, - "macro \"%s\" requires %u arguments, but only %u given", - NODE_NAME (node), macro->paramc, argc); - } - else - cpp_error (pfile, CPP_DL_ERROR, - "macro \"%s\" passed %u arguments, but takes just %u", - NODE_NAME (node), argc, macro->paramc); - - return false; -} - -/* Reads and returns the arguments to a function-like macro - invocation. Assumes the opening parenthesis has been processed. - If there is an error, emits an appropriate diagnostic and returns - NULL. Each argument is terminated by a CPP_EOF token, for the - future benefit of expand_arg(). */ -static _cpp_buff * -collect_args (cpp_reader *pfile, const cpp_hashnode *node) -{ - _cpp_buff *buff, *base_buff; - cpp_macro *macro; - macro_arg *args, *arg; - const cpp_token *token; - unsigned int argc; - - macro = node->value.macro; - if (macro->paramc) - argc = macro->paramc; - else - argc = 1; - buff = _cpp_get_buff (pfile, argc * (50 * sizeof (cpp_token *) - + sizeof (macro_arg))); - base_buff = buff; - args = (macro_arg *) buff->base; - memset (args, 0, argc * sizeof (macro_arg)); - buff->cur = (unsigned char *) &args[argc]; - arg = args, argc = 0; - - /* Collect the tokens making up each argument. We don't yet know - how many arguments have been supplied, whether too many or too - few. Hence the slightly bizarre usage of "argc" and "arg". */ - do - { - unsigned int paren_depth = 0; - unsigned int ntokens = 0; - - argc++; - arg->first = (const cpp_token **) buff->cur; - - for (;;) - { - /* Require space for 2 new tokens (including a CPP_EOF). */ - if ((unsigned char *) &arg->first[ntokens + 2] > buff->limit) - { - buff = _cpp_append_extend_buff (pfile, buff, - 1000 * sizeof (cpp_token *)); - arg->first = (const cpp_token **) buff->cur; - } - - token = cpp_get_token (pfile); - - if (token->type == CPP_PADDING) - { - /* Drop leading padding. */ - if (ntokens == 0) - continue; - } - else if (token->type == CPP_OPEN_PAREN) - paren_depth++; - else if (token->type == CPP_CLOSE_PAREN) - { - if (paren_depth-- == 0) - break; - } - else if (token->type == CPP_COMMA) - { - /* A comma does not terminate an argument within - parentheses or as part of a variable argument. */ - if (paren_depth == 0 - && ! (macro->variadic && argc == macro->paramc)) - break; - } - else if (token->type == CPP_EOF - || (token->type == CPP_HASH && token->flags & BOL)) - break; - - arg->first[ntokens++] = token; - } - - /* Drop trailing padding. */ - while (ntokens > 0 && arg->first[ntokens - 1]->type == CPP_PADDING) - ntokens--; - - arg->count = ntokens; - arg->first[ntokens] = &pfile->eof; - - /* Terminate the argument. Excess arguments loop back and - overwrite the final legitimate argument, before failing. */ - if (argc <= macro->paramc) - { - buff->cur = (unsigned char *) &arg->first[ntokens + 1]; - if (argc != macro->paramc) - arg++; - } - } - while (token->type != CPP_CLOSE_PAREN && token->type != CPP_EOF); - - if (token->type == CPP_EOF) - { - /* We still need the CPP_EOF to end directives, and to end - pre-expansion of a macro argument. Step back is not - unconditional, since we don't want to return a CPP_EOF to our - callers at the end of an -include-d file. */ - if (pfile->context->prev || pfile->state.in_directive) - _cpp_backup_tokens (pfile, 1); - cpp_error (pfile, CPP_DL_ERROR, - "unterminated argument list invoking macro \"%s\"", - NODE_NAME (node)); - } - else - { - /* A single empty argument is counted as no argument. */ - if (argc == 1 && macro->paramc == 0 && args[0].count == 0) - argc = 0; - if (_cpp_arguments_ok (pfile, macro, node, argc)) - { - /* GCC has special semantics for , ## b where b is a varargs - parameter: we remove the comma if b was omitted entirely. - If b was merely an empty argument, the comma is retained. - If the macro takes just one (varargs) parameter, then we - retain the comma only if we are standards conforming. - - If FIRST is NULL replace_args () swallows the comma. */ - if (macro->variadic && (argc < macro->paramc - || (argc == 1 && args[0].count == 0 - && !CPP_OPTION (pfile, std)))) - args[macro->paramc - 1].first = NULL; - return base_buff; - } - } - - /* An error occurred. */ - _cpp_release_buff (pfile, base_buff); - return NULL; -} - -/* Search for an opening parenthesis to the macro of NODE, in such a - way that, if none is found, we don't lose the information in any - intervening padding tokens. If we find the parenthesis, collect - the arguments and return the buffer containing them. */ -static _cpp_buff * -funlike_invocation_p (cpp_reader *pfile, cpp_hashnode *node) -{ - const cpp_token *token, *padding = NULL; - - for (;;) - { - token = cpp_get_token (pfile); - if (token->type != CPP_PADDING) - break; - if (padding == NULL - || (!(padding->flags & PREV_WHITE) && token->val.source == NULL)) - padding = token; - } - - if (token->type == CPP_OPEN_PAREN) - { - pfile->state.parsing_args = 2; - return collect_args (pfile, node); - } - - /* CPP_EOF can be the end of macro arguments, or the end of the - file. We mustn't back up over the latter. Ugh. */ - if (token->type != CPP_EOF || token == &pfile->eof) - { - /* Back up. We may have skipped padding, in which case backing - up more than one token when expanding macros is in general - too difficult. We re-insert it in its own context. */ - _cpp_backup_tokens (pfile, 1); - if (padding) - push_token_context (pfile, NULL, padding, 1); - } - - return NULL; -} - -/* Push the context of a macro with hash entry NODE onto the context - stack. If we can successfully expand the macro, we push a context - containing its yet-to-be-rescanned replacement list and return one. - Otherwise, we don't push a context and return zero. */ -static int -enter_macro_context (cpp_reader *pfile, cpp_hashnode *node) -{ - /* The presence of a macro invalidates a file's controlling macro. */ - pfile->mi_valid = false; - - pfile->state.angled_headers = false; - - /* Handle standard macros. */ - if (! (node->flags & NODE_BUILTIN)) - { - cpp_macro *macro = node->value.macro; - - if (macro->fun_like) - { - _cpp_buff *buff; - - pfile->state.prevent_expansion++; - pfile->keep_tokens++; - pfile->state.parsing_args = 1; - buff = funlike_invocation_p (pfile, node); - pfile->state.parsing_args = 0; - pfile->keep_tokens--; - pfile->state.prevent_expansion--; - - if (buff == NULL) - { - if (CPP_WTRADITIONAL (pfile) && ! node->value.macro->syshdr) - cpp_error (pfile, CPP_DL_WARNING, - "function-like macro \"%s\" must be used with arguments in traditional C", - NODE_NAME (node)); - - return 0; - } - - if (macro->paramc > 0) - replace_args (pfile, node, macro, (macro_arg *) buff->base); - _cpp_release_buff (pfile, buff); - } - - /* Disable the macro within its expansion. */ - node->flags |= NODE_DISABLED; - - macro->used = 1; - - if (macro->paramc == 0) - push_token_context (pfile, node, macro->exp.tokens, macro->count); - - return 1; - } - - /* Handle built-in macros and the _Pragma operator. */ - return builtin_macro (pfile, node); -} - -/* Replace the parameters in a function-like macro of NODE with the - actual ARGS, and place the result in a newly pushed token context. - Expand each argument before replacing, unless it is operated upon - by the # or ## operators. */ -static void -replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro, macro_arg *args) -{ - unsigned int i, total; - const cpp_token *src, *limit; - const cpp_token **dest, **first; - macro_arg *arg; - _cpp_buff *buff; - - /* First, fully macro-expand arguments, calculating the number of - tokens in the final expansion as we go. The ordering of the if - statements below is subtle; we must handle stringification before - pasting. */ - total = macro->count; - limit = macro->exp.tokens + macro->count; - - for (src = macro->exp.tokens; src < limit; src++) - if (src->type == CPP_MACRO_ARG) - { - /* Leading and trailing padding tokens. */ - total += 2; - - /* We have an argument. If it is not being stringified or - pasted it is macro-replaced before insertion. */ - arg = &args[src->val.arg_no - 1]; - - if (src->flags & STRINGIFY_ARG) - { - if (!arg->stringified) - arg->stringified = stringify_arg (pfile, arg); - } - else if ((src->flags & PASTE_LEFT) - || (src > macro->exp.tokens && (src[-1].flags & PASTE_LEFT))) - total += arg->count - 1; - else - { - if (!arg->expanded) - expand_arg (pfile, arg); - total += arg->expanded_count - 1; - } - } - - /* Now allocate space for the expansion, copy the tokens and replace - the arguments. */ - buff = _cpp_get_buff (pfile, total * sizeof (cpp_token *)); - first = (const cpp_token **) buff->base; - dest = first; - - for (src = macro->exp.tokens; src < limit; src++) - { - unsigned int count; - const cpp_token **from, **paste_flag; - - if (src->type != CPP_MACRO_ARG) - { - *dest++ = src; - continue; - } - - paste_flag = 0; - arg = &args[src->val.arg_no - 1]; - if (src->flags & STRINGIFY_ARG) - count = 1, from = &arg->stringified; - else if (src->flags & PASTE_LEFT) - count = arg->count, from = arg->first; - else if (src != macro->exp.tokens && (src[-1].flags & PASTE_LEFT)) - { - count = arg->count, from = arg->first; - if (dest != first) - { - if (dest[-1]->type == CPP_COMMA - && macro->variadic - && src->val.arg_no == macro->paramc) - { - /* Swallow a pasted comma if from == NULL, otherwise - drop the paste flag. */ - if (from == NULL) - dest--; - else - paste_flag = dest - 1; - } - /* Remove the paste flag if the RHS is a placemarker. */ - else if (count == 0) - paste_flag = dest - 1; - } - } - else - count = arg->expanded_count, from = arg->expanded; - - /* Padding on the left of an argument (unless RHS of ##). */ - if ((!pfile->state.in_directive || pfile->state.directive_wants_padding) - && src != macro->exp.tokens && !(src[-1].flags & PASTE_LEFT)) - *dest++ = padding_token (pfile, src); - - if (count) - { - memcpy (dest, from, count * sizeof (cpp_token *)); - dest += count; - - /* With a non-empty argument on the LHS of ##, the last - token should be flagged PASTE_LEFT. */ - if (src->flags & PASTE_LEFT) - paste_flag = dest - 1; - } - - /* Avoid paste on RHS (even case count == 0). */ - if (!pfile->state.in_directive && !(src->flags & PASTE_LEFT)) - *dest++ = &pfile->avoid_paste; - - /* Add a new paste flag, or remove an unwanted one. */ - if (paste_flag) - { - cpp_token *token = _cpp_temp_token (pfile); - token->type = (*paste_flag)->type; - token->val.str = (*paste_flag)->val.str; - if (src->flags & PASTE_LEFT) - token->flags = (*paste_flag)->flags | PASTE_LEFT; - else - token->flags = (*paste_flag)->flags & ~PASTE_LEFT; - *paste_flag = token; - } - } - - /* Free the expanded arguments. */ - for (i = 0; i < macro->paramc; i++) - if (args[i].expanded) - free (args[i].expanded); - - push_ptoken_context (pfile, node, buff, first, dest - first); -} - -/* Return a special padding token, with padding inherited from SOURCE. */ -static const cpp_token * -padding_token (cpp_reader *pfile, const cpp_token *source) -{ - cpp_token *result = _cpp_temp_token (pfile); - - result->type = CPP_PADDING; - result->val.source = source; - result->flags = 0; - return result; -} - -/* Get a new uninitialized context. Create a new one if we cannot - re-use an old one. */ -static cpp_context * -next_context (cpp_reader *pfile) -{ - cpp_context *result = pfile->context->next; - - if (result == 0) - { - result = xnew (cpp_context); - result->prev = pfile->context; - result->next = 0; - pfile->context->next = result; - } - - pfile->context = result; - return result; -} - -/* Push a list of pointers to tokens. */ -static void -push_ptoken_context (cpp_reader *pfile, cpp_hashnode *macro, _cpp_buff *buff, - const cpp_token **first, unsigned int count) -{ - cpp_context *context = next_context (pfile); - - context->direct_p = false; - context->macro = macro; - context->buff = buff; - FIRST (context).ptoken = first; - LAST (context).ptoken = first + count; -} - -/* Push a list of tokens. */ -static void -push_token_context (cpp_reader *pfile, cpp_hashnode *macro, - const cpp_token *first, unsigned int count) -{ - cpp_context *context = next_context (pfile); - - context->direct_p = true; - context->macro = macro; - context->buff = NULL; - FIRST (context).token = first; - LAST (context).token = first + count; -} - -/* Push a traditional macro's replacement text. */ -void -_cpp_push_text_context (cpp_reader *pfile, cpp_hashnode *macro, - const uchar *start, size_t len) -{ - cpp_context *context = next_context (pfile); - - context->direct_p = true; - context->macro = macro; - context->buff = NULL; - CUR (context) = start; - RLIMIT (context) = start + len; - macro->flags |= NODE_DISABLED; -} - -/* Expand an argument ARG before replacing parameters in a - function-like macro. This works by pushing a context with the - argument's tokens, and then expanding that into a temporary buffer - as if it were a normal part of the token stream. collect_args() - has terminated the argument's tokens with a CPP_EOF so that we know - when we have fully expanded the argument. */ -static void -expand_arg (cpp_reader *pfile, macro_arg *arg) -{ - unsigned int capacity; - bool saved_warn_trad; - - if (arg->count == 0) - return; - - /* Don't warn about funlike macros when pre-expanding. */ - saved_warn_trad = CPP_WTRADITIONAL (pfile); - CPP_WTRADITIONAL (pfile) = 0; - - /* Loop, reading in the arguments. */ - capacity = 256; - arg->expanded = xmalloc (capacity * sizeof (cpp_token *)); - - push_ptoken_context (pfile, NULL, NULL, arg->first, arg->count + 1); - for (;;) - { - const cpp_token *token; - - if (arg->expanded_count + 1 >= capacity) - { - capacity *= 2; - arg->expanded = xrealloc (arg->expanded, - capacity * sizeof (cpp_token *)); - } - - token = cpp_get_token (pfile); - - if (token->type == CPP_EOF) - break; - - arg->expanded[arg->expanded_count++] = token; - } - - _cpp_pop_context (pfile); - - CPP_WTRADITIONAL (pfile) = saved_warn_trad; -} - -/* Pop the current context off the stack, re-enabling the macro if the - context represented a macro's replacement list. The context - structure is not freed so that we can re-use it later. */ -void -_cpp_pop_context (cpp_reader *pfile) -{ - cpp_context *context = pfile->context; - - if (context->macro) - context->macro->flags &= ~NODE_DISABLED; - - if (context->buff) - _cpp_release_buff (pfile, context->buff); - - pfile->context = context->prev; -} - -/* External routine to get a token. Also used nearly everywhere - internally, except for places where we know we can safely call - _cpp_lex_token directly, such as lexing a directive name. - - Macro expansions and directives are transparently handled, - including entering included files. Thus tokens are post-macro - expansion, and after any intervening directives. External callers - see CPP_EOF only at EOF. Internal callers also see it when meeting - a directive inside a macro call, when at the end of a directive and - state.in_directive is still 1, and at the end of argument - pre-expansion. */ -const cpp_token * -cpp_get_token (cpp_reader *pfile) -{ - const cpp_token *result; - - for (;;) - { - cpp_hashnode *node; - cpp_context *context = pfile->context; - - /* Context->prev == 0 <=> base context. */ - if (!context->prev) - result = _cpp_lex_token (pfile); - else if (FIRST (context).token != LAST (context).token) - { - if (context->direct_p) - result = FIRST (context).token++; - else - result = *FIRST (context).ptoken++; - - if (result->flags & PASTE_LEFT) - { - paste_all_tokens (pfile, result); - if (pfile->state.in_directive) - continue; - return padding_token (pfile, result); - } - } - else - { - _cpp_pop_context (pfile); - if (pfile->state.in_directive) - continue; - return &pfile->avoid_paste; - } - - if (pfile->state.in_directive && result->type == CPP_COMMENT) - continue; - - if (result->type != CPP_NAME) - break; - - node = result->val.node; - - if (node->type != NT_MACRO || (result->flags & NO_EXPAND)) - break; - - if (!(node->flags & NODE_DISABLED)) - { - if (!pfile->state.prevent_expansion - && enter_macro_context (pfile, node)) - { - if (pfile->state.in_directive) - continue; - return padding_token (pfile, result); - } - } - else - { - /* Flag this token as always unexpandable. FIXME: move this - to collect_args()?. */ - cpp_token *t = _cpp_temp_token (pfile); - t->type = result->type; - t->flags = result->flags | NO_EXPAND; - t->val.str = result->val.str; - result = t; - } - - break; - } - - return result; -} - -/* Returns true if we're expanding an object-like macro that was - defined in a system header. Just checks the macro at the top of - the stack. Used for diagnostic suppression. */ -int -cpp_sys_macro_p (cpp_reader *pfile) -{ - cpp_hashnode *node = pfile->context->macro; - - return node && node->value.macro && node->value.macro->syshdr; -} - -/* Read each token in, until end of the current file. Directives are - transparently processed. */ -void -cpp_scan_nooutput (cpp_reader *pfile) -{ - /* Request a CPP_EOF token at the end of this file, rather than - transparently continuing with the including file. */ - pfile->buffer->return_at_eof = true; - - if (CPP_OPTION (pfile, traditional)) - while (_cpp_read_logical_line_trad (pfile)) - ; - else - while (cpp_get_token (pfile)->type != CPP_EOF) - ; -} - -/* Step back one (or more) tokens. Can only step mack more than 1 if - they are from the lexer, and not from macro expansion. */ -void -_cpp_backup_tokens (cpp_reader *pfile, unsigned int count) -{ - if (pfile->context->prev == NULL) - { - pfile->lookaheads += count; - while (count--) - { - pfile->cur_token--; - if (pfile->cur_token == pfile->cur_run->base - /* Possible with -fpreprocessed and no leading #line. */ - && pfile->cur_run->prev != NULL) - { - pfile->cur_run = pfile->cur_run->prev; - pfile->cur_token = pfile->cur_run->limit; - } - } - } - else - { - if (count != 1) - abort (); - if (pfile->context->direct_p) - FIRST (pfile->context).token--; - else - FIRST (pfile->context).ptoken--; - } -} - -/* #define directive parsing and handling. */ - -/* Returns nonzero if a macro redefinition warning is required. */ -static bool -warn_of_redefinition (cpp_reader *pfile, const cpp_hashnode *node, - const cpp_macro *macro2) -{ - const cpp_macro *macro1; - unsigned int i; - - /* Some redefinitions need to be warned about regardless. */ - if (node->flags & NODE_WARN) - return true; - - /* Redefinition of a macro is allowed if and only if the old and new - definitions are the same. (6.10.3 paragraph 2). */ - macro1 = node->value.macro; - - /* Don't check count here as it can be different in valid - traditional redefinitions with just whitespace differences. */ - if (macro1->paramc != macro2->paramc - || macro1->fun_like != macro2->fun_like - || macro1->variadic != macro2->variadic) - return true; - - /* Check parameter spellings. */ - for (i = 0; i < macro1->paramc; i++) - if (macro1->params[i] != macro2->params[i]) - return true; - - /* Check the replacement text or tokens. */ - if (CPP_OPTION (pfile, traditional)) - return _cpp_expansions_different_trad (macro1, macro2); - - if (macro1->count != macro2->count) - return true; - - for (i = 0; i < macro1->count; i++) - if (!_cpp_equiv_tokens (¯o1->exp.tokens[i], ¯o2->exp.tokens[i])) - return true; - - return false; -} - -/* Free the definition of hashnode H. */ -void -_cpp_free_definition (cpp_hashnode *h) -{ - /* Macros and assertions no longer have anything to free. */ - h->type = NT_VOID; - /* Clear builtin flag in case of redefinition. */ - h->flags &= ~(NODE_BUILTIN | NODE_DISABLED); -} - -/* Save parameter NODE to the parameter list of macro MACRO. Returns - zero on success, nonzero if the parameter is a duplicate. */ -bool -_cpp_save_parameter (cpp_reader *pfile, cpp_macro *macro, cpp_hashnode *node) -{ - unsigned int len; - /* Constraint 6.10.3.6 - duplicate parameter names. */ - if (node->flags & NODE_MACRO_ARG) - { - cpp_error (pfile, CPP_DL_ERROR, "duplicate macro parameter \"%s\"", - NODE_NAME (node)); - return true; - } - - if (BUFF_ROOM (pfile->a_buff) - < (macro->paramc + 1) * sizeof (cpp_hashnode *)) - _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (cpp_hashnode *)); - - ((cpp_hashnode **) BUFF_FRONT (pfile->a_buff))[macro->paramc++] = node; - node->flags |= NODE_MACRO_ARG; - len = macro->paramc * sizeof (union _cpp_hashnode_value); - if (len > pfile->macro_buffer_len) - { - pfile->macro_buffer = xrealloc (pfile->macro_buffer, len); - pfile->macro_buffer_len = len; - } - ((union _cpp_hashnode_value *) pfile->macro_buffer)[macro->paramc - 1] - = node->value; - - node->value.arg_index = macro->paramc; - return false; -} - -/* Check the syntax of the parameters in a MACRO definition. Returns - false if an error occurs. */ -static bool -parse_params (cpp_reader *pfile, cpp_macro *macro) -{ - unsigned int prev_ident = 0; - - for (;;) - { - const cpp_token *token = _cpp_lex_token (pfile); - - switch (token->type) - { - default: - /* Allow/ignore comments in parameter lists if we are - preserving comments in macro expansions. */ - if (token->type == CPP_COMMENT - && ! CPP_OPTION (pfile, discard_comments_in_macro_exp)) - continue; - - cpp_error (pfile, CPP_DL_ERROR, - "\"%s\" may not appear in macro parameter list", - cpp_token_as_text (pfile, token)); - return false; - - case CPP_NAME: - if (prev_ident) - { - cpp_error (pfile, CPP_DL_ERROR, - "macro parameters must be comma-separated"); - return false; - } - prev_ident = 1; - - if (_cpp_save_parameter (pfile, macro, token->val.node)) - return false; - continue; - - case CPP_CLOSE_PAREN: - if (prev_ident || macro->paramc == 0) - return true; - - /* Fall through to pick up the error. */ - case CPP_COMMA: - if (!prev_ident) - { - cpp_error (pfile, CPP_DL_ERROR, "parameter name missing"); - return false; - } - prev_ident = 0; - continue; - - case CPP_ELLIPSIS: - macro->variadic = 1; - if (!prev_ident) - { - _cpp_save_parameter (pfile, macro, - pfile->spec_nodes.n__VA_ARGS__); - pfile->state.va_args_ok = 1; - if (! CPP_OPTION (pfile, c99) && CPP_OPTION (pfile, pedantic)) - cpp_error (pfile, CPP_DL_PEDWARN, - "anonymous variadic macros were introduced in C99"); - } - else if (CPP_OPTION (pfile, pedantic)) - cpp_error (pfile, CPP_DL_PEDWARN, - "ISO C does not permit named variadic macros"); - - /* We're at the end, and just expect a closing parenthesis. */ - token = _cpp_lex_token (pfile); - if (token->type == CPP_CLOSE_PAREN) - return true; - /* Fall through. */ - - case CPP_EOF: - cpp_error (pfile, CPP_DL_ERROR, "missing ')' in macro parameter list"); - return false; - } - } -} - -/* Allocate room for a token from a macro's replacement list. */ -static cpp_token * -alloc_expansion_token (cpp_reader *pfile, cpp_macro *macro) -{ - if (BUFF_ROOM (pfile->a_buff) < (macro->count + 1) * sizeof (cpp_token)) - _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (cpp_token)); - - return &((cpp_token *) BUFF_FRONT (pfile->a_buff))[macro->count++]; -} - -/* Lex a token from the expansion of MACRO, but mark parameters as we - find them and warn of traditional stringification. */ -static cpp_token * -lex_expansion_token (cpp_reader *pfile, cpp_macro *macro) -{ - cpp_token *token; - - pfile->cur_token = alloc_expansion_token (pfile, macro); - token = _cpp_lex_direct (pfile); - - /* Is this a parameter? */ - if (token->type == CPP_NAME - && (token->val.node->flags & NODE_MACRO_ARG) != 0) - { - token->type = CPP_MACRO_ARG; - token->val.arg_no = token->val.node->value.arg_index; - } - else if (CPP_WTRADITIONAL (pfile) && macro->paramc > 0 - && (token->type == CPP_STRING || token->type == CPP_CHAR)) - check_trad_stringification (pfile, macro, &token->val.str); - - return token; -} - -static bool -create_iso_definition (cpp_reader *pfile, cpp_macro *macro) -{ - cpp_token *token; - const cpp_token *ctoken; - - /* Get the first token of the expansion (or the '(' of a - function-like macro). */ - ctoken = _cpp_lex_token (pfile); - - if (ctoken->type == CPP_OPEN_PAREN && !(ctoken->flags & PREV_WHITE)) - { - bool ok = parse_params (pfile, macro); - macro->params = (cpp_hashnode **) BUFF_FRONT (pfile->a_buff); - if (!ok) - return false; - - /* Success. Commit the parameter array. */ - BUFF_FRONT (pfile->a_buff) = (uchar *) ¯o->params[macro->paramc]; - macro->fun_like = 1; - } - else if (ctoken->type != CPP_EOF && !(ctoken->flags & PREV_WHITE)) - cpp_error (pfile, CPP_DL_PEDWARN, - "ISO C requires whitespace after the macro name"); - - if (macro->fun_like) - token = lex_expansion_token (pfile, macro); - else - { - token = alloc_expansion_token (pfile, macro); - *token = *ctoken; - } - - for (;;) - { - /* Check the stringifying # constraint 6.10.3.2.1 of - function-like macros when lexing the subsequent token. */ - if (macro->count > 1 && token[-1].type == CPP_HASH && macro->fun_like) - { - if (token->type == CPP_MACRO_ARG) - { - token->flags &= ~PREV_WHITE; - token->flags |= STRINGIFY_ARG; - token->flags |= token[-1].flags & PREV_WHITE; - token[-1] = token[0]; - macro->count--; - } - /* Let assembler get away with murder. */ - else if ((CPP_OPTION (pfile, lang) != CLK_ASM) - && (!CPP_OPTION(pfile, allow_naked_hash))) - { - cpp_error (pfile, CPP_DL_ERROR, - "'#' is not followed by a macro parameter"); - return false; - } - } - - if (token->type == CPP_EOF) - break; - - /* Paste operator constraint 6.10.3.3.1. */ - if (token->type == CPP_PASTE) - { - /* Token-paste ##, can appear in both object-like and - function-like macros, but not at the ends. */ - if (--macro->count > 0) - token = lex_expansion_token (pfile, macro); - - if (macro->count == 0 || token->type == CPP_EOF) - { - cpp_error (pfile, CPP_DL_ERROR, - "'##' cannot appear at either end of a macro expansion"); - return false; - } - - token[-1].flags |= PASTE_LEFT; - } - - token = lex_expansion_token (pfile, macro); - } - - macro->exp.tokens = (cpp_token *) BUFF_FRONT (pfile->a_buff); - - /* Don't count the CPP_EOF. */ - macro->count--; - - /* Clear whitespace on first token for warn_of_redefinition(). */ - if (macro->count) - macro->exp.tokens[0].flags &= ~PREV_WHITE; - - /* Commit the memory. */ - BUFF_FRONT (pfile->a_buff) = (uchar *) ¯o->exp.tokens[macro->count]; - - return true; -} - -/* Parse a macro and save its expansion. Returns nonzero on success. */ -bool -_cpp_create_definition (cpp_reader *pfile, cpp_hashnode *node) -{ - cpp_macro *macro; - unsigned int i; - bool ok; - - macro = (cpp_macro *) _cpp_aligned_alloc (pfile, sizeof (cpp_macro)); - macro->line = pfile->directive_line; - macro->params = 0; - macro->paramc = 0; - macro->variadic = 0; - macro->used = !CPP_OPTION (pfile, warn_unused_macros); - macro->count = 0; - macro->fun_like = 0; - /* To suppress some diagnostics. */ - macro->syshdr = pfile->map->sysp != 0; - - if (CPP_OPTION (pfile, traditional)) - ok = _cpp_create_trad_definition (pfile, macro); - else - { - cpp_token *saved_cur_token = pfile->cur_token; - - ok = create_iso_definition (pfile, macro); - - /* Restore lexer position because of games lex_expansion_token() - plays lexing the macro. We set the type for SEEN_EOL() in - cpplib.c. - - Longer term we should lex the whole line before coming here, - and just copy the expansion. */ - saved_cur_token[-1].type = pfile->cur_token[-1].type; - pfile->cur_token = saved_cur_token; - - /* Stop the lexer accepting __VA_ARGS__. */ - pfile->state.va_args_ok = 0; - } - - /* Clear the fast argument lookup indices. */ - for (i = macro->paramc; i-- > 0; ) - { - struct cpp_hashnode *node = macro->params[i]; - node->flags &= ~ NODE_MACRO_ARG; - node->value = ((union _cpp_hashnode_value *) pfile->macro_buffer)[i]; - } - - if (!ok) - return ok; - - if (node->type == NT_MACRO) - { - if (CPP_OPTION (pfile, warn_unused_macros)) - _cpp_warn_if_unused_macro (pfile, node, NULL); - - if (warn_of_redefinition (pfile, node, macro)) - { - cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->directive_line, 0, - "\"%s\" redefined", NODE_NAME (node)); - - if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN)) - cpp_error_with_line (pfile, CPP_DL_PEDWARN, - node->value.macro->line, 0, - "this is the location of the previous definition"); - } - } - - if (node->type != NT_VOID) - _cpp_free_definition (node); - - /* Enter definition in hash table. */ - node->type = NT_MACRO; - node->value.macro = macro; - if (! ustrncmp (NODE_NAME (node), DSC ("__STDC_"))) - node->flags |= NODE_WARN; - - return ok; -} - -/* Warn if a token in STRING matches one of a function-like MACRO's - parameters. */ -static void -check_trad_stringification (cpp_reader *pfile, const cpp_macro *macro, - const cpp_string *string) -{ - unsigned int i, len; - const uchar *p, *q, *limit; - - /* Loop over the string. */ - limit = string->text + string->len - 1; - for (p = string->text + 1; p < limit; p = q) - { - /* Find the start of an identifier. */ - while (p < limit && !is_idstart (*p)) - p++; - - /* Find the end of the identifier. */ - q = p; - while (q < limit && is_idchar (*q)) - q++; - - len = q - p; - - /* Loop over the function macro arguments to see if the - identifier inside the string matches one of them. */ - for (i = 0; i < macro->paramc; i++) - { - const cpp_hashnode *node = macro->params[i]; - - if (NODE_LEN (node) == len - && !memcmp (p, NODE_NAME (node), len)) - { - cpp_error (pfile, CPP_DL_WARNING, - "macro argument \"%s\" would be stringified in traditional C", - NODE_NAME (node)); - break; - } - } - } -} - -/* Returns the name, arguments and expansion of a macro, in a format - suitable to be read back in again, and therefore also for DWARF 2 - debugging info. e.g. "PASTE(X, Y) X ## Y", or "MACNAME EXPANSION". - Caller is expected to generate the "#define" bit if needed. The - returned text is temporary, and automatically freed later. */ -const unsigned char * -cpp_macro_definition (cpp_reader *pfile, const cpp_hashnode *node) -{ - unsigned int i, len; - const cpp_macro *macro = node->value.macro; - unsigned char *buffer; - - if (node->type != NT_MACRO || (node->flags & NODE_BUILTIN)) - { - cpp_error (pfile, CPP_DL_ICE, - "invalid hash type %d in cpp_macro_definition", node->type); - return 0; - } - - /* Calculate length. */ - len = NODE_LEN (node) + 2; /* ' ' and NUL. */ - if (macro->fun_like) - { - len += 4; /* "()" plus possible final ".." of named - varargs (we have + 1 below). */ - for (i = 0; i < macro->paramc; i++) - len += NODE_LEN (macro->params[i]) + 1; /* "," */ - } - - /* This should match below where we fill in the buffer. */ - if (CPP_OPTION (pfile, traditional)) - len += _cpp_replacement_text_len (macro); - else - { - for (i = 0; i < macro->count; i++) - { - cpp_token *token = ¯o->exp.tokens[i]; - - if (token->type == CPP_MACRO_ARG) - len += NODE_LEN (macro->params[token->val.arg_no - 1]); - else - len += cpp_token_len (token); - - if (token->flags & STRINGIFY_ARG) - len++; /* "#" */ - if (token->flags & PASTE_LEFT) - len += 3; /* " ##" */ - if (token->flags & PREV_WHITE) - len++; /* " " */ - } - } - - if (len > pfile->macro_buffer_len) - { - pfile->macro_buffer = xrealloc (pfile->macro_buffer, len); - pfile->macro_buffer_len = len; - } - - /* Fill in the buffer. Start with the macro name. */ - buffer = pfile->macro_buffer; - memcpy (buffer, NODE_NAME (node), NODE_LEN (node)); - buffer += NODE_LEN (node); - - /* Parameter names. */ - if (macro->fun_like) - { - *buffer++ = '('; - for (i = 0; i < macro->paramc; i++) - { - cpp_hashnode *param = macro->params[i]; - - if (param != pfile->spec_nodes.n__VA_ARGS__) - { - memcpy (buffer, NODE_NAME (param), NODE_LEN (param)); - buffer += NODE_LEN (param); - } - - if (i + 1 < macro->paramc) - /* Don't emit a space after the comma here; we're trying - to emit a Dwarf-friendly definition, and the Dwarf spec - forbids spaces in the argument list. */ - *buffer++ = ','; - else if (macro->variadic) - *buffer++ = '.', *buffer++ = '.', *buffer++ = '.'; - } - *buffer++ = ')'; - } - - /* The Dwarf spec requires a space after the macro name, even if the - definition is the empty string. */ - *buffer++ = ' '; - - if (CPP_OPTION (pfile, traditional)) - buffer = _cpp_copy_replacement_text (macro, buffer); - else if (macro->count) - /* Expansion tokens. */ - { - for (i = 0; i < macro->count; i++) - { - cpp_token *token = ¯o->exp.tokens[i]; - - if (token->flags & PREV_WHITE) - *buffer++ = ' '; - if (token->flags & STRINGIFY_ARG) - *buffer++ = '#'; - - if (token->type == CPP_MACRO_ARG) - { - memcpy (buffer, - NODE_NAME (macro->params[token->val.arg_no - 1]), - NODE_LEN (macro->params[token->val.arg_no - 1])); - buffer += NODE_LEN (macro->params[token->val.arg_no - 1]); - } - else - buffer = cpp_spell_token (pfile, token, buffer); - - if (token->flags & PASTE_LEFT) - { - *buffer++ = ' '; - *buffer++ = '#'; - *buffer++ = '#'; - /* Next has PREV_WHITE; see _cpp_create_definition. */ - } - } - } - - *buffer = '\0'; - return pfile->macro_buffer; -} diff --git a/support/cpp2/cpptrad.c b/support/cpp2/cpptrad.c deleted file mode 100644 index 6315b107..00000000 --- a/support/cpp2/cpptrad.c +++ /dev/null @@ -1,1110 +0,0 @@ -/* CPP Library - traditional lexical analysis and macro expansion. - Copyright (C) 2002, 2004 Free Software Foundation, Inc. - Contributed by Neil Booth, May 2002 - -This program 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 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include "config.h" -#include "system.h" -#include "cpplib.h" -#include "cpphash.h" - -/* The replacement text of a function-like macro is stored as a - contiguous sequence of aligned blocks, each representing the text - between subsequent parameters. - - Each block comprises the text between its surrounding parameters, - the length of that text, and the one-based index of the following - parameter. The final block in the replacement text is easily - recognizable as it has an argument index of zero. */ - -struct block -{ - unsigned int text_len; - unsigned short arg_index; - uchar text[1]; -}; - -#define BLOCK_HEADER_LEN offsetof (struct block, text) -#define BLOCK_LEN(TEXT_LEN) CPP_ALIGN (BLOCK_HEADER_LEN + (TEXT_LEN)) - -/* Structure holding information about a function-like macro - invocation. */ -struct fun_macro -{ - /* Memory buffer holding the trad_arg array. */ - _cpp_buff *buff; - - /* An array of size the number of macro parameters + 1, containing - the offsets of the start of each macro argument in the output - buffer. The argument continues until the character before the - start of the next one. */ - size_t *args; - - /* The hashnode of the macro. */ - cpp_hashnode *node; - - /* The offset of the macro name in the output buffer. */ - size_t offset; - - /* The line the macro name appeared on. */ - unsigned int line; - - /* Zero-based index of argument being currently lexed. */ - unsigned int argc; -}; - -/* Lexing state. It is mostly used to prevent macro expansion. */ -enum ls {ls_none = 0, /* Normal state. */ - ls_fun_open, /* When looking for '('. */ - ls_fun_close, /* When looking for ')'. */ - ls_defined, /* After defined. */ - ls_defined_close, /* Looking for ')' of defined(). */ - ls_hash, /* After # in preprocessor conditional. */ - ls_predicate, /* After the predicate, maybe paren? */ - ls_answer}; /* In answer to predicate. */ - -/* Lexing TODO: Maybe handle space in escaped newlines. Stop cpplex.c - from recognizing comments and directives during its lexing pass. */ - -static const uchar *skip_whitespace (cpp_reader *, const uchar *, int); -static cpp_hashnode *lex_identifier (cpp_reader *, const uchar *); -static const uchar *copy_comment (cpp_reader *, const uchar *, int); -static void check_output_buffer (cpp_reader *, size_t); -static void push_replacement_text (cpp_reader *, cpp_hashnode *); -static bool scan_parameters (cpp_reader *, cpp_macro *); -static bool recursive_macro (cpp_reader *, cpp_hashnode *); -static void save_replacement_text (cpp_reader *, cpp_macro *, unsigned int); -static void maybe_start_funlike (cpp_reader *, cpp_hashnode *, const uchar *, - struct fun_macro *); -static void save_argument (struct fun_macro *, size_t); -static void replace_args_and_push (cpp_reader *, struct fun_macro *); -static size_t canonicalize_text (uchar *, const uchar *, size_t, uchar *); - -/* Ensures we have N bytes' space in the output buffer, and - reallocates it if not. */ -static void -check_output_buffer (cpp_reader *pfile, size_t n) -{ - /* We might need two bytes to terminate an unterminated comment, and - one more to terminate the line with a NUL. */ - n += 2 + 1; - - if (n > (size_t) (pfile->out.limit - pfile->out.cur)) - { - size_t size = pfile->out.cur - pfile->out.base; - size_t new_size = (size + n) * 3 / 2; - - pfile->out.base = xrealloc (pfile->out.base, new_size); - pfile->out.limit = pfile->out.base + new_size; - pfile->out.cur = pfile->out.base + size; - } -} - -/* Skip a C-style block comment in a macro as a result of -CC. - Buffer->cur points to the initial asterisk of the comment. */ -static void -skip_macro_block_comment (cpp_reader *pfile) -{ - const uchar *cur = pfile->buffer->cur; - - cur++; - if (*cur == '/') - cur++; - - /* People like decorating comments with '*', so check for '/' - instead for efficiency. */ - while(! (*cur++ == '/' && cur[-2] == '*') ) - ; - - pfile->buffer->cur = cur; -} - -/* CUR points to the asterisk introducing a comment in the current - context. IN_DEFINE is true if we are in the replacement text of a - macro. - - The asterisk and following comment is copied to the buffer pointed - to by pfile->out.cur, which must be of sufficient size. - Unterminated comments are diagnosed, and correctly terminated in - the output. pfile->out.cur is updated depending upon IN_DEFINE, - -C, -CC and pfile->state.in_directive. - - Returns a pointer to the first character after the comment in the - input buffer. */ -static const uchar * -copy_comment (cpp_reader *pfile, const uchar *cur, int in_define) -{ - bool unterminated, copy = false; - unsigned int from_line = pfile->line; - cpp_buffer *buffer = pfile->buffer; - - buffer->cur = cur; - if (pfile->context->prev) - unterminated = false, skip_macro_block_comment (pfile); - else - unterminated = _cpp_skip_block_comment (pfile); - - if (unterminated) - cpp_error_with_line (pfile, CPP_DL_ERROR, from_line, 0, - "unterminated comment"); - - /* Comments in directives become spaces so that tokens are properly - separated when the ISO preprocessor re-lexes the line. The - exception is #define. */ - if (pfile->state.in_directive) - { - if (in_define) - { - if (CPP_OPTION (pfile, discard_comments_in_macro_exp)) - pfile->out.cur--; - else - copy = true; - } - else - pfile->out.cur[-1] = ' '; - } - else if (CPP_OPTION (pfile, discard_comments)) - pfile->out.cur--; - else - copy = true; - - if (copy) - { - size_t len = (size_t) (buffer->cur - cur); - memcpy (pfile->out.cur, cur, len); - pfile->out.cur += len; - if (unterminated) - { - *pfile->out.cur++ = '*'; - *pfile->out.cur++ = '/'; - } - } - - return buffer->cur; -} - -/* CUR points to any character in the input buffer. Skips over all - contiguous horizontal white space and NULs, including comments if - SKIP_COMMENTS, until reaching the first non-horizontal-whitespace - character or the end of the current context. Escaped newlines are - removed. - - The whitespace is copied verbatim to the output buffer, except that - comments are handled as described in copy_comment(). - pfile->out.cur is updated. - - Returns a pointer to the first character after the whitespace in - the input buffer. */ -static const uchar * -skip_whitespace (cpp_reader *pfile, const uchar *cur, int skip_comments) -{ - uchar *out = pfile->out.cur; - - for (;;) - { - unsigned int c = *cur++; - *out++ = c; - - if (is_nvspace (c)) - continue; - - if (c == '/' && *cur == '*' && skip_comments) - { - pfile->out.cur = out; - cur = copy_comment (pfile, cur, false /* in_define */); - out = pfile->out.cur; - continue; - } - - out--; - break; - } - - pfile->out.cur = out; - return cur - 1; -} - -/* Lexes and outputs an identifier starting at CUR, which is assumed - to point to a valid first character of an identifier. Returns - the hashnode, and updates out.cur. */ -static cpp_hashnode * -lex_identifier (cpp_reader *pfile, const uchar *cur) -{ - size_t len; - uchar *out = pfile->out.cur; - cpp_hashnode *result; - - do - *out++ = *cur++; - while (is_numchar (*cur)); - - CUR (pfile->context) = cur; - len = out - pfile->out.cur; - result = (cpp_hashnode *) ht_lookup (pfile->hash_table, pfile->out.cur, - len, HT_ALLOC); - pfile->out.cur = out; - return result; -} - -/* Overlays the true file buffer temporarily with text of length LEN - starting at START. The true buffer is restored upon calling - restore_buff(). */ -void -_cpp_overlay_buffer (cpp_reader *pfile, const uchar *start, size_t len) -{ - cpp_buffer *buffer = pfile->buffer; - - pfile->overlaid_buffer = buffer; - buffer->saved_cur = buffer->cur; - buffer->saved_rlimit = buffer->rlimit; - /* Prevent the ISO lexer from scanning a fresh line. */ - pfile->saved_line = pfile->line--; - buffer->need_line = false; - - buffer->cur = start; - buffer->rlimit = start + len; -} - -/* Restores a buffer overlaid by _cpp_overlay_buffer(). */ -void -_cpp_remove_overlay (cpp_reader *pfile) -{ - cpp_buffer *buffer = pfile->overlaid_buffer; - - buffer->cur = buffer->saved_cur; - buffer->rlimit = buffer->saved_rlimit; - buffer->need_line = true; - - pfile->overlaid_buffer = NULL; - pfile->line = pfile->saved_line; -} - -/* Reads a logical line into the output buffer. Returns TRUE if there - is more text left in the buffer. */ -bool -_cpp_read_logical_line_trad (cpp_reader *pfile) -{ - do - { - if (pfile->buffer->need_line && !_cpp_get_fresh_line (pfile)) - return false; - } - while (!_cpp_scan_out_logical_line (pfile, NULL) || pfile->state.skipping); - - return pfile->buffer != NULL; -} - -/* Set up state for finding the opening '(' of a function-like - macro. */ -static void -maybe_start_funlike (cpp_reader *pfile, cpp_hashnode *node, const uchar *start, struct fun_macro *macro) -{ - unsigned int n = node->value.macro->paramc + 1; - - if (macro->buff) - _cpp_release_buff (pfile, macro->buff); - macro->buff = _cpp_get_buff (pfile, n * sizeof (size_t)); - macro->args = (size_t *) BUFF_FRONT (macro->buff); - macro->node = node; - macro->offset = start - pfile->out.base; - macro->argc = 0; -} - -/* Save the OFFSET of the start of the next argument to MACRO. */ -static void -save_argument (struct fun_macro *macro, size_t offset) -{ - macro->argc++; - if (macro->argc <= macro->node->value.macro->paramc) - macro->args[macro->argc] = offset; -} - -/* Copies the next logical line in the current buffer (starting at - buffer->cur) to the output buffer. The output is guaranteed to - terminate with a NUL character. buffer->cur is updated. - - If MACRO is non-NULL, then we are scanning the replacement list of - MACRO, and we call save_replacement_text() every time we meet an - argument. */ -bool -_cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro) -{ - bool result = true; - cpp_context *context; - const uchar *cur; - uchar *out; - struct fun_macro fmacro; - unsigned int c, paren_depth = 0, quote; - enum ls lex_state = ls_none; - bool header_ok; - const uchar *start_of_input_line; - - fmacro.buff = NULL; - - quote = 0; - header_ok = pfile->state.angled_headers; - CUR (pfile->context) = pfile->buffer->cur; - RLIMIT (pfile->context) = pfile->buffer->rlimit; - pfile->out.cur = pfile->out.base; - pfile->out.first_line = pfile->line; - /* start_of_input_line is needed to make sure that directives really, - really start at the first character of the line. */ - start_of_input_line = pfile->buffer->cur; - new_context: - context = pfile->context; - cur = CUR (context); - check_output_buffer (pfile, RLIMIT (context) - cur); - out = pfile->out.cur; - - for (;;) - { - if (!context->prev - && cur >= pfile->buffer->notes[pfile->buffer->cur_note].pos) - { - pfile->buffer->cur = cur; - _cpp_process_line_notes (pfile, false); - } - c = *cur++; - *out++ = c; - - /* Whitespace should "continue" out of the switch, - non-whitespace should "break" out of it. */ - switch (c) - { - case ' ': - case '\t': - case '\f': - case '\v': - case '\0': - continue; - - case '\n': - /* If this is a macro's expansion, pop it. */ - if (context->prev) - { - pfile->out.cur = out - 1; - _cpp_pop_context (pfile); - goto new_context; - } - - /* Omit the newline from the output buffer. */ - pfile->out.cur = out - 1; - pfile->buffer->cur = cur; - pfile->buffer->need_line = true; - pfile->line++; - - if ((lex_state == ls_fun_open || lex_state == ls_fun_close) - && !pfile->state.in_directive - && _cpp_get_fresh_line (pfile)) - { - /* Newlines in arguments become a space, but we don't - clear any in-progress quote. */ - if (lex_state == ls_fun_close) - out[-1] = ' '; - cur = pfile->buffer->cur; - continue; - } - goto done; - - case '<': - if (header_ok) - quote = '>'; - break; - case '>': - if (c == quote) - quote = 0; - break; - - case '"': - case '\'': - if (c == quote) - quote = 0; - else if (!quote) - quote = c; - break; - - case '\\': - /* Skip escaped quotes here, it's easier than above. */ - if (*cur == '\\' || *cur == '"' || *cur == '\'') - *out++ = *cur++; - break; - - case '/': - /* Traditional CPP does not recognize comments within - literals. */ - if (!quote && *cur == '*') - { - pfile->out.cur = out; - cur = copy_comment (pfile, cur, macro != 0); - out = pfile->out.cur; - continue; - } - break; - - case '_': - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': - case 's': case 't': case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': - case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': - case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - if (!pfile->state.skipping && (quote == 0 || macro)) - { - cpp_hashnode *node; - uchar *out_start = out - 1; - - pfile->out.cur = out_start; - node = lex_identifier (pfile, cur - 1); - out = pfile->out.cur; - cur = CUR (context); - - if (node->type == NT_MACRO - /* Should we expand for ls_answer? */ - && (lex_state == ls_none || lex_state == ls_fun_open) - && !pfile->state.prevent_expansion) - { - /* Macros invalidate MI optimization. */ - pfile->mi_valid = false; - if (! (node->flags & NODE_BUILTIN) - && node->value.macro->fun_like) - { - maybe_start_funlike (pfile, node, out_start, &fmacro); - lex_state = ls_fun_open; - fmacro.line = pfile->line; - continue; - } - else if (!recursive_macro (pfile, node)) - { - /* Remove the object-like macro's name from the - output, and push its replacement text. */ - pfile->out.cur = out_start; - push_replacement_text (pfile, node); - lex_state = ls_none; - goto new_context; - } - } - else if (macro && (node->flags & NODE_MACRO_ARG) != 0) - { - /* Found a parameter in the replacement text of a - #define. Remove its name from the output. */ - pfile->out.cur = out_start; - save_replacement_text (pfile, macro, node->value.arg_index); - out = pfile->out.base; - } - else if (lex_state == ls_hash) - { - lex_state = ls_predicate; - continue; - } - else if (pfile->state.in_expression - && node == pfile->spec_nodes.n_defined) - { - lex_state = ls_defined; - continue; - } - } - break; - - case '(': - if (quote == 0) - { - paren_depth++; - if (lex_state == ls_fun_open) - { - if (recursive_macro (pfile, fmacro.node)) - lex_state = ls_none; - else - { - lex_state = ls_fun_close; - paren_depth = 1; - out = pfile->out.base + fmacro.offset; - fmacro.args[0] = fmacro.offset; - } - } - else if (lex_state == ls_predicate) - lex_state = ls_answer; - else if (lex_state == ls_defined) - lex_state = ls_defined_close; - } - break; - - case ',': - if (quote == 0 && lex_state == ls_fun_close && paren_depth == 1) - save_argument (&fmacro, out - pfile->out.base); - break; - - case ')': - if (quote == 0) - { - paren_depth--; - if (lex_state == ls_fun_close && paren_depth == 0) - { - cpp_macro *m = fmacro.node->value.macro; - - m->used = 1; - lex_state = ls_none; - save_argument (&fmacro, out - pfile->out.base); - - /* A single zero-length argument is no argument. */ - if (fmacro.argc == 1 - && m->paramc == 0 - && out == pfile->out.base + fmacro.offset + 1) - fmacro.argc = 0; - - if (_cpp_arguments_ok (pfile, m, fmacro.node, fmacro.argc)) - { - /* Remove the macro's invocation from the - output, and push its replacement text. */ - pfile->out.cur = (pfile->out.base - + fmacro.offset); - CUR (context) = cur; - replace_args_and_push (pfile, &fmacro); - goto new_context; - } - } - else if (lex_state == ls_answer || lex_state == ls_defined_close) - lex_state = ls_none; - } - break; - - case '#': - if (cur - 1 == start_of_input_line - /* A '#' from a macro doesn't start a directive. */ - && !pfile->context->prev - && !pfile->state.in_directive) - { - /* A directive. With the way _cpp_handle_directive - currently works, we only want to call it if either we - know the directive is OK, or we want it to fail and - be removed from the output. If we want it to be - passed through (the assembler case) then we must not - call _cpp_handle_directive. */ - pfile->out.cur = out; - cur = skip_whitespace (pfile, cur, true /* skip_comments */); - out = pfile->out.cur; - - if (*cur == '\n') - { - /* Null directive. Ignore it and don't invalidate - the MI optimization. */ - pfile->buffer->need_line = true; - pfile->line++; - result = false; - goto done; - } - else - { - bool do_it = false; - - if (is_numstart (*cur) - && CPP_OPTION (pfile, lang) != CLK_ASM) - do_it = true; - else if (is_idstart (*cur)) - /* Check whether we know this directive, but don't - advance. */ - do_it = lex_identifier (pfile, cur)->is_directive; - - if (do_it || CPP_OPTION (pfile, lang) != CLK_ASM) - { - /* This is a kludge. We want to have the ISO - preprocessor lex the next token. */ - pfile->buffer->cur = cur; - _cpp_handle_directive (pfile, false /* indented */); - result = false; - goto done; - } - } - } - - if (pfile->state.in_expression) - { - lex_state = ls_hash; - continue; - } - break; - - default: - break; - } - - /* Non-whitespace disables MI optimization and stops treating - '<' as a quote in #include. */ - header_ok = false; - if (!pfile->state.in_directive) - pfile->mi_valid = false; - - if (lex_state == ls_none) - continue; - - /* Some of these transitions of state are syntax errors. The - ISO preprocessor will issue errors later. */ - if (lex_state == ls_fun_open) - /* Missing '('. */ - lex_state = ls_none; - else if (lex_state == ls_hash - || lex_state == ls_predicate - || lex_state == ls_defined) - lex_state = ls_none; - - /* ls_answer and ls_defined_close keep going until ')'. */ - } - - done: - if (fmacro.buff) - _cpp_release_buff (pfile, fmacro.buff); - - if (lex_state == ls_fun_close) - cpp_error_with_line (pfile, CPP_DL_ERROR, fmacro.line, 0, - "unterminated argument list invoking macro \"%s\"", - NODE_NAME (fmacro.node)); - return result; -} - -/* Push a context holding the replacement text of the macro NODE on - the context stack. NODE is either object-like, or a function-like - macro with no arguments. */ -static void -push_replacement_text (cpp_reader *pfile, cpp_hashnode *node) -{ - size_t len; - const uchar *text; - uchar *buf; - - if (node->flags & NODE_BUILTIN) - { - text = _cpp_builtin_macro_text (pfile, node); - len = ustrlen (text); - buf = _cpp_unaligned_alloc (pfile, len + 1); - memcpy (buf, text, len); - buf[len]='\n'; - text = buf; - } - else - { - cpp_macro *macro = node->value.macro; - macro->used = 1; - text = macro->exp.text; - len = macro->count; - } - - _cpp_push_text_context (pfile, node, text, len); -} - -/* Returns TRUE if traditional macro recursion is detected. */ -static bool -recursive_macro (cpp_reader *pfile, cpp_hashnode *node) -{ - bool recursing = !!(node->flags & NODE_DISABLED); - - /* Object-like macros that are already expanding are necessarily - recursive. - - However, it is possible to have traditional function-like macros - that are not infinitely recursive but recurse to any given depth. - Further, it is easy to construct examples that get ever longer - until the point they stop recursing. So there is no easy way to - detect true recursion; instead we assume any expansion more than - 20 deep since the first invocation of this macro must be - recursing. */ - if (recursing && node->value.macro->fun_like) - { - size_t depth = 0; - cpp_context *context = pfile->context; - - do - { - depth++; - if (context->macro == node && depth > 20) - break; - context = context->prev; - } - while (context); - recursing = context != NULL; - } - - if (recursing) - cpp_error (pfile, CPP_DL_ERROR, - "detected recursion whilst expanding macro \"%s\"", - NODE_NAME (node)); - - return recursing; -} - -/* Return the length of the replacement text of a function-like or - object-like non-builtin macro. */ -size_t -_cpp_replacement_text_len (const cpp_macro *macro) -{ - size_t len; - - if (macro->fun_like && (macro->paramc != 0)) - { - const uchar *exp; - - len = 0; - for (exp = macro->exp.text;;) - { - struct block *b = (struct block *) exp; - - len += b->text_len; - if (b->arg_index == 0) - break; - len += NODE_LEN (macro->params[b->arg_index - 1]); - exp += BLOCK_LEN (b->text_len); - } - } - else - len = macro->count; - - return len; -} - -/* Copy the replacement text of MACRO to DEST, which must be of - sufficient size. It is not NUL-terminated. The next character is - returned. */ -uchar * -_cpp_copy_replacement_text (const cpp_macro *macro, uchar *dest) -{ - if (macro->fun_like && (macro->paramc != 0)) - { - const uchar *exp; - - for (exp = macro->exp.text;;) - { - struct block *b = (struct block *) exp; - cpp_hashnode *param; - - memcpy (dest, b->text, b->text_len); - dest += b->text_len; - if (b->arg_index == 0) - break; - param = macro->params[b->arg_index - 1]; - memcpy (dest, NODE_NAME (param), NODE_LEN (param)); - dest += NODE_LEN (param); - exp += BLOCK_LEN (b->text_len); - } - } - else - { - memcpy (dest, macro->exp.text, macro->count); - dest += macro->count; - } - - return dest; -} - -/* Push a context holding the replacement text of the macro NODE on - the context stack. NODE is either object-like, or a function-like - macro with no arguments. */ -static void -replace_args_and_push (cpp_reader *pfile, struct fun_macro *fmacro) -{ - cpp_macro *macro = fmacro->node->value.macro; - - if (macro->paramc == 0) - push_replacement_text (pfile, fmacro->node); - else - { - const uchar *exp; - uchar *p; - _cpp_buff *buff; - size_t len = 0; - - /* Calculate the length of the argument-replaced text. */ - for (exp = macro->exp.text;;) - { - struct block *b = (struct block *) exp; - - len += b->text_len; - if (b->arg_index == 0) - break; - len += (fmacro->args[b->arg_index] - - fmacro->args[b->arg_index - 1] - 1); - exp += BLOCK_LEN (b->text_len); - } - - /* Allocate room for the expansion plus \n. */ - buff = _cpp_get_buff (pfile, len + 1); - - /* Copy the expansion and replace arguments. */ - p = BUFF_FRONT (buff); - for (exp = macro->exp.text;;) - { - struct block *b = (struct block *) exp; - size_t arglen; - - memcpy (p, b->text, b->text_len); - p += b->text_len; - if (b->arg_index == 0) - break; - arglen = (fmacro->args[b->arg_index] - - fmacro->args[b->arg_index - 1] - 1); - memcpy (p, pfile->out.base + fmacro->args[b->arg_index - 1], - arglen); - p += arglen; - exp += BLOCK_LEN (b->text_len); - } - - /* \n-terminate. */ - *p = '\n'; - _cpp_push_text_context (pfile, fmacro->node, BUFF_FRONT (buff), len); - - /* So we free buffer allocation when macro is left. */ - pfile->context->buff = buff; - } -} - -/* Read and record the parameters, if any, of a function-like macro - definition. Destroys pfile->out.cur. - - Returns true on success, false on failure (syntax error or a - duplicate parameter). On success, CUR (pfile->context) is just - past the closing parenthesis. */ -static bool -scan_parameters (cpp_reader *pfile, cpp_macro *macro) -{ - const uchar *cur = CUR (pfile->context) + 1; - bool ok; - - for (;;) - { - cur = skip_whitespace (pfile, cur, true /* skip_comments */); - - if (is_idstart (*cur)) - { - ok = false; - if (_cpp_save_parameter (pfile, macro, lex_identifier (pfile, cur))) - break; - cur = skip_whitespace (pfile, CUR (pfile->context), - true /* skip_comments */); - if (*cur == ',') - { - cur++; - continue; - } - ok = (*cur == ')'); - break; - } - - ok = (*cur == ')' && macro->paramc == 0); - break; - } - - if (!ok) - cpp_error (pfile, CPP_DL_ERROR, "syntax error in macro parameter list"); - - CUR (pfile->context) = cur + (*cur == ')'); - - return ok; -} - -/* Save the text from pfile->out.base to pfile->out.cur as - the replacement text for the current macro, followed by argument - ARG_INDEX, with zero indicating the end of the replacement - text. */ -static void -save_replacement_text (cpp_reader *pfile, cpp_macro *macro, - unsigned int arg_index) -{ - size_t len = pfile->out.cur - pfile->out.base; - uchar *exp; - - if (macro->paramc == 0) - { - /* Object-like and function-like macros without parameters - simply store their \n-terminated replacement text. */ - exp = _cpp_unaligned_alloc (pfile, len + 1); - memcpy (exp, pfile->out.base, len); - exp[len] = '\n'; - macro->exp.text = exp; - macro->count = len; - } - else - { - /* Store the text's length (unsigned int), the argument index - (unsigned short, base 1) and then the text. */ - size_t blen = BLOCK_LEN (len); - struct block *block; - - if (macro->count + blen > BUFF_ROOM (pfile->a_buff)) - _cpp_extend_buff (pfile, &pfile->a_buff, macro->count + blen); - - exp = BUFF_FRONT (pfile->a_buff); - block = (struct block *) (exp + macro->count); - macro->exp.text = exp; - - /* Write out the block information. */ - block->text_len = len; - block->arg_index = arg_index; - memcpy (block->text, pfile->out.base, len); - - /* Lex the rest into the start of the output buffer. */ - pfile->out.cur = pfile->out.base; - - macro->count += blen; - - /* If we've finished, commit the memory. */ - if (arg_index == 0) - BUFF_FRONT (pfile->a_buff) += macro->count; - } -} - -/* Analyze and save the replacement text of a macro. Returns true on - success. */ -bool -_cpp_create_trad_definition (cpp_reader *pfile, cpp_macro *macro) -{ - const uchar *cur; - uchar *limit; - cpp_context *context = pfile->context; - - /* The context has not been set up for command line defines, and CUR - has not been updated for the macro name for in-file defines. */ - pfile->out.cur = pfile->out.base; - CUR (context) = pfile->buffer->cur; - RLIMIT (context) = pfile->buffer->rlimit; - check_output_buffer (pfile, RLIMIT (context) - CUR (context)); - - /* Is this a function-like macro? */ - if (* CUR (context) == '(') - { - bool ok = scan_parameters (pfile, macro); - - /* Remember the params so we can clear NODE_MACRO_ARG flags. */ - macro->params = (cpp_hashnode **) BUFF_FRONT (pfile->a_buff); - - /* Setting macro to NULL indicates an error occurred, and - prevents unnecessary work in _cpp_scan_out_logical_line. */ - if (!ok) - macro = NULL; - else - { - BUFF_FRONT (pfile->a_buff) = (uchar *) ¯o->params[macro->paramc]; - macro->fun_like = 1; - } - } - - /* Skip leading whitespace in the replacement text. */ - pfile->buffer->cur - = skip_whitespace (pfile, CUR (context), - CPP_OPTION (pfile, discard_comments_in_macro_exp)); - - pfile->state.prevent_expansion++; - _cpp_scan_out_logical_line (pfile, macro); - pfile->state.prevent_expansion--; - - if (!macro) - return false; - - /* Skip trailing white space. */ - cur = pfile->out.base; - limit = pfile->out.cur; - while (limit > cur && is_space (limit[-1])) - limit--; - pfile->out.cur = limit; - save_replacement_text (pfile, macro, 0); - - return true; -} - -/* Copy SRC of length LEN to DEST, but convert all contiguous - whitespace to a single space, provided it is not in quotes. The - quote currently in effect is pointed to by PQUOTE, and is updated - by the function. Returns the number of bytes copied. */ -static size_t -canonicalize_text (uchar *dest, const uchar *src, size_t len, uchar *pquote) -{ - uchar *orig_dest = dest; - uchar quote = *pquote; - - while (len) - { - if (is_space (*src) && !quote) - { - do - src++, len--; - while (len && is_space (*src)); - *dest++ = ' '; - } - else - { - if (*src == '\'' || *src == '"') - { - if (!quote) - quote = *src; - else if (quote == *src) - quote = 0; - } - *dest++ = *src++, len--; - } - } - - *pquote = quote; - return dest - orig_dest; -} - -/* Returns true if MACRO1 and MACRO2 have expansions different other - than in the form of their whitespace. */ -bool -_cpp_expansions_different_trad (const cpp_macro *macro1, - const cpp_macro *macro2) -{ - uchar *p1 = xmalloc (macro1->count + macro2->count); - uchar *p2 = p1 + macro1->count; - uchar quote1 = 0, quote2 = 0; - bool mismatch; - size_t len1, len2; - - if (macro1->paramc > 0) - { - const uchar *exp1 = macro1->exp.text, *exp2 = macro2->exp.text; - - mismatch = true; - for (;;) - { - struct block *b1 = (struct block *) exp1; - struct block *b2 = (struct block *) exp2; - - if (b1->arg_index != b2->arg_index) - break; - - len1 = canonicalize_text (p1, b1->text, b1->text_len, "e1); - len2 = canonicalize_text (p2, b2->text, b2->text_len, "e2); - if (len1 != len2 || memcmp (p1, p2, len1)) - break; - if (b1->arg_index == 0) - { - mismatch = false; - break; - } - exp1 += BLOCK_LEN (b1->text_len); - exp2 += BLOCK_LEN (b2->text_len); - } - } - else - { - len1 = canonicalize_text (p1, macro1->exp.text, macro1->count, "e1); - len2 = canonicalize_text (p2, macro2->exp.text, macro2->count, "e2); - mismatch = (len1 != len2 || memcmp (p1, p2, len1)); - } - - free (p1); - return mismatch; -} diff --git a/support/cpp2/cppucnid.h b/support/cpp2/cppucnid.h deleted file mode 100644 index 1cac7df0..00000000 --- a/support/cpp2/cppucnid.h +++ /dev/null @@ -1,336 +0,0 @@ -/* Table of UCNs which are valid in identifiers. - Copyright (C) 2003 Free Software Foundation, Inc. - -This program 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 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* Automatically generated from cppucnid.tab, do not edit */ - -/* This file reproduces the table in ISO/IEC 9899:1999 (C99) Annex - D, which is itself a reproduction from ISO/IEC TR 10176:1998, and - the similar table from ISO/IEC 14882:1988 (C++98) Annex E, which is - a reproduction of ISO/IEC PDTR 10176. Unfortunately these tables - are not identical. */ - -#ifndef CPPUCNID_H -#define CPPUCNID_H - -#define C99 1 -#define CXX 2 -#define DIG 4 - -struct ucnrange -{ - unsigned short lo, hi; - unsigned short flags; -}; - -static const struct ucnrange ucnranges[] = { - { 0x00aa, 0x00aa, C99 }, /* Latin */ - { 0x00b5, 0x00b5, C99 }, /* Special characters */ - { 0x00b7, 0x00b7, C99 }, - { 0x00ba, 0x00ba, C99 }, /* Latin */ - { 0x00c0, 0x00d6, CXX|C99 }, - { 0x00d8, 0x00f6, CXX|C99 }, - { 0x00f8, 0x01f5, CXX|C99 }, - { 0x01fa, 0x0217, CXX|C99 }, - { 0x0250, 0x02a8, CXX|C99 }, - { 0x02b0, 0x02b8, C99 }, /* Special characters */ - { 0x02bb, 0x02bb, C99 }, - { 0x02bd, 0x02c1, C99 }, - { 0x02d0, 0x02d1, C99 }, - { 0x02e0, 0x02e4, C99 }, - { 0x037a, 0x037a, C99 }, - { 0x0384, 0x0384, CXX }, /* Greek */ - { 0x0386, 0x0386, C99 }, - { 0x0388, 0x038a, CXX|C99 }, - { 0x038c, 0x038c, CXX|C99 }, - { 0x038e, 0x03a1, CXX|C99 }, - { 0x03a3, 0x03ce, CXX|C99 }, - { 0x03d0, 0x03d6, CXX|C99 }, - { 0x03da, 0x03da, CXX|C99 }, - { 0x03dc, 0x03dc, CXX|C99 }, - { 0x03de, 0x03de, CXX|C99 }, - { 0x03e0, 0x03e0, CXX|C99 }, - { 0x03e2, 0x03f3, CXX|C99 }, - { 0x0401, 0x040c, CXX|C99 }, /* Cyrillic */ - { 0x040d, 0x040d, CXX }, - { 0x040e, 0x040e, C99 }, - { 0x040f, 0x044f, CXX|C99 }, - { 0x0451, 0x045c, CXX|C99 }, - { 0x045e, 0x0481, CXX|C99 }, - { 0x0490, 0x04c4, CXX|C99 }, - { 0x04c7, 0x04c8, CXX|C99 }, - { 0x04cb, 0x04cc, CXX|C99 }, - { 0x04d0, 0x04eb, CXX|C99 }, - { 0x04ee, 0x04f5, CXX|C99 }, - { 0x04f8, 0x04f9, CXX|C99 }, - { 0x0531, 0x0556, CXX|C99 }, /* Armenian */ - { 0x0559, 0x0559, C99 }, /* Special characters */ - { 0x0561, 0x0587, CXX|C99 }, /* Armenian */ - { 0x05b0, 0x05b9, C99 }, /* Hebrew */ - { 0x05bb, 0x05bd, C99 }, - { 0x05bf, 0x05bf, C99 }, - { 0x05c1, 0x05c2, C99 }, - { 0x05d0, 0x05ea, CXX|C99 }, - { 0x05f0, 0x05f2, CXX|C99 }, - { 0x05f3, 0x05f4, CXX }, - { 0x0621, 0x063a, CXX|C99 }, /* Arabic */ - { 0x0640, 0x0652, CXX|C99 }, - { 0x0660, 0x0669, C99|DIG }, /* Digits */ - { 0x0670, 0x06b7, CXX|C99 }, /* Arabic */ - { 0x06ba, 0x06be, CXX|C99 }, - { 0x06c0, 0x06ce, CXX|C99 }, - { 0x06d0, 0x06dc, C99 }, - { 0x06e5, 0x06e7, CXX|C99 }, - { 0x06e8, 0x06e8, C99 }, - { 0x06ea, 0x06ed, C99 }, - { 0x06f0, 0x06f9, C99|DIG }, /* Digits */ - { 0x0901, 0x0903, C99 }, /* Devanagari */ - { 0x0905, 0x0939, CXX|C99 }, - { 0x093d, 0x093d, C99 }, /* Special characters */ - { 0x093e, 0x094d, C99 }, /* Devanagari */ - { 0x0950, 0x0952, C99 }, - { 0x0958, 0x0962, CXX|C99 }, - { 0x0963, 0x0963, C99 }, - { 0x0966, 0x096f, C99|DIG }, /* Digits */ - { 0x0981, 0x0983, C99 }, /* Bengali */ - { 0x0985, 0x098c, CXX|C99 }, - { 0x098f, 0x0990, CXX|C99 }, - { 0x0993, 0x09a8, CXX|C99 }, - { 0x09aa, 0x09b0, CXX|C99 }, - { 0x09b2, 0x09b2, CXX|C99 }, - { 0x09b6, 0x09b9, CXX|C99 }, - { 0x09be, 0x09c4, C99 }, - { 0x09c7, 0x09c8, C99 }, - { 0x09cb, 0x09cd, C99 }, - { 0x09dc, 0x09dd, CXX|C99 }, - { 0x09df, 0x09e1, CXX|C99 }, - { 0x09e2, 0x09e3, C99 }, - { 0x09e6, 0x09ef, C99|DIG }, /* Digits */ - { 0x09f0, 0x09f1, CXX|C99 }, /* Bengali */ - { 0x0a02, 0x0a02, C99 }, /* Gurmukhi */ - { 0x0a05, 0x0a0a, CXX|C99 }, - { 0x0a0f, 0x0a10, CXX|C99 }, - { 0x0a13, 0x0a28, CXX|C99 }, - { 0x0a2a, 0x0a30, CXX|C99 }, - { 0x0a32, 0x0a33, CXX|C99 }, - { 0x0a35, 0x0a36, CXX|C99 }, - { 0x0a38, 0x0a39, CXX|C99 }, - { 0x0a3e, 0x0a42, C99 }, - { 0x0a47, 0x0a48, C99 }, - { 0x0a4b, 0x0a4d, C99 }, - { 0x0a59, 0x0a5c, CXX|C99 }, - { 0x0a5e, 0x0a5e, CXX|C99 }, - { 0x0a66, 0x0a6f, C99|DIG }, /* Digits */ - { 0x0a74, 0x0a74, C99 }, /* Gurmukhi */ - { 0x0a81, 0x0a83, C99 }, /* Gujarati */ - { 0x0a85, 0x0a8b, CXX|C99 }, - { 0x0a8d, 0x0a8d, CXX|C99 }, - { 0x0a8f, 0x0a91, CXX|C99 }, - { 0x0a93, 0x0aa8, CXX|C99 }, - { 0x0aaa, 0x0ab0, CXX|C99 }, - { 0x0ab2, 0x0ab3, CXX|C99 }, - { 0x0ab5, 0x0ab9, CXX|C99 }, - { 0x0abd, 0x0ac5, C99 }, - { 0x0ac7, 0x0ac9, C99 }, - { 0x0acb, 0x0acd, C99 }, - { 0x0ad0, 0x0ad0, C99 }, - { 0x0ae0, 0x0ae0, CXX|C99 }, - { 0x0ae6, 0x0aef, C99|DIG }, /* Digits */ - { 0x0b01, 0x0b03, C99 }, /* Oriya */ - { 0x0b05, 0x0b0c, CXX|C99 }, - { 0x0b0f, 0x0b10, CXX|C99 }, - { 0x0b13, 0x0b28, CXX|C99 }, - { 0x0b2a, 0x0b30, CXX|C99 }, - { 0x0b32, 0x0b33, CXX|C99 }, - { 0x0b36, 0x0b39, CXX|C99 }, - { 0x0b3d, 0x0b3d, C99 }, /* Special characters */ - { 0x0b3e, 0x0b43, C99 }, /* Oriya */ - { 0x0b47, 0x0b48, C99 }, - { 0x0b4b, 0x0b4d, C99 }, - { 0x0b5c, 0x0b5d, CXX|C99 }, - { 0x0b5f, 0x0b61, CXX|C99 }, - { 0x0b66, 0x0b6f, C99|DIG }, /* Digits */ - { 0x0b82, 0x0b83, C99 }, /* Tamil */ - { 0x0b85, 0x0b8a, CXX|C99 }, - { 0x0b8e, 0x0b90, CXX|C99 }, - { 0x0b92, 0x0b95, CXX|C99 }, - { 0x0b99, 0x0b9a, CXX|C99 }, - { 0x0b9c, 0x0b9c, CXX|C99 }, - { 0x0b9e, 0x0b9f, CXX|C99 }, - { 0x0ba3, 0x0ba4, CXX|C99 }, - { 0x0ba8, 0x0baa, CXX|C99 }, - { 0x0bae, 0x0bb5, CXX|C99 }, - { 0x0bb7, 0x0bb9, CXX|C99 }, - { 0x0bbe, 0x0bc2, C99 }, - { 0x0bc6, 0x0bc8, C99 }, - { 0x0bca, 0x0bcd, C99 }, - { 0x0be7, 0x0bef, C99|DIG }, /* Digits */ - { 0x0c01, 0x0c03, C99 }, /* Telugu */ - { 0x0c05, 0x0c0c, CXX|C99 }, - { 0x0c0e, 0x0c10, CXX|C99 }, - { 0x0c12, 0x0c28, CXX|C99 }, - { 0x0c2a, 0x0c33, CXX|C99 }, - { 0x0c35, 0x0c39, CXX|C99 }, - { 0x0c3e, 0x0c44, C99 }, - { 0x0c46, 0x0c48, C99 }, - { 0x0c4a, 0x0c4d, C99 }, - { 0x0c60, 0x0c61, CXX|C99 }, - { 0x0c66, 0x0c6f, C99|DIG }, /* Digits */ - { 0x0c82, 0x0c83, C99 }, /* Kannada */ - { 0x0c85, 0x0c8c, CXX|C99 }, - { 0x0c8e, 0x0c90, CXX|C99 }, - { 0x0c92, 0x0ca8, CXX|C99 }, - { 0x0caa, 0x0cb3, CXX|C99 }, - { 0x0cb5, 0x0cb9, CXX|C99 }, - { 0x0cbe, 0x0cc4, C99 }, - { 0x0cc6, 0x0cc8, C99 }, - { 0x0cca, 0x0ccd, C99 }, - { 0x0cde, 0x0cde, C99 }, - { 0x0ce0, 0x0ce1, CXX|C99 }, - { 0x0ce6, 0x0cef, C99|DIG }, /* Digits */ - { 0x0d02, 0x0d03, C99 }, /* Malayalam */ - { 0x0d05, 0x0d0c, CXX|C99 }, - { 0x0d0e, 0x0d10, CXX|C99 }, - { 0x0d12, 0x0d28, CXX|C99 }, - { 0x0d2a, 0x0d39, CXX|C99 }, - { 0x0d3e, 0x0d43, C99 }, - { 0x0d46, 0x0d48, C99 }, - { 0x0d4a, 0x0d4d, C99 }, - { 0x0d60, 0x0d61, CXX|C99 }, - { 0x0d66, 0x0d6f, C99|DIG }, /* Digits */ - { 0x0e01, 0x0e30, CXX|C99 }, /* Thai */ - { 0x0e31, 0x0e31, C99 }, - { 0x0e32, 0x0e33, CXX|C99 }, - { 0x0e34, 0x0e3a, C99 }, - { 0x0e40, 0x0e46, CXX|C99 }, - { 0x0e47, 0x0e49, C99 }, - { 0x0e50, 0x0e59, CXX|C99|DIG }, /* Digits */ - { 0x0e5a, 0x0e5b, CXX|C99 }, /* Thai */ - { 0x0e81, 0x0e82, CXX|C99 }, /* Lao */ - { 0x0e84, 0x0e84, CXX|C99 }, - { 0x0e87, 0x0e88, CXX|C99 }, - { 0x0e8a, 0x0e8a, CXX|C99 }, - { 0x0e8d, 0x0e8d, CXX|C99 }, - { 0x0e94, 0x0e97, CXX|C99 }, - { 0x0e99, 0x0e9f, CXX|C99 }, - { 0x0ea1, 0x0ea3, CXX|C99 }, - { 0x0ea5, 0x0ea5, CXX|C99 }, - { 0x0ea7, 0x0ea7, CXX|C99 }, - { 0x0eaa, 0x0eab, CXX|C99 }, - { 0x0ead, 0x0eae, CXX|C99 }, - { 0x0eaf, 0x0eaf, CXX }, - { 0x0eb0, 0x0eb0, CXX|C99 }, - { 0x0eb1, 0x0eb1, C99 }, - { 0x0eb2, 0x0eb3, CXX|C99 }, - { 0x0eb4, 0x0eb9, C99 }, - { 0x0ebb, 0x0ebc, C99 }, - { 0x0ebd, 0x0ebd, CXX|C99 }, - { 0x0ec0, 0x0ec4, CXX|C99 }, - { 0x0ec6, 0x0ec6, CXX|C99 }, - { 0x0ec8, 0x0ecd, C99 }, - { 0x0ed0, 0x0ed9, C99|DIG }, /* Digits */ - { 0x0edc, 0x0edd, C99 }, /* Lao */ - { 0x0f00, 0x0f00, C99 }, /* Tibetan */ - { 0x0f18, 0x0f19, C99 }, - { 0x0f20, 0x0f33, C99|DIG }, /* Digits */ - { 0x0f35, 0x0f35, C99 }, /* Tibetan */ - { 0x0f37, 0x0f37, C99 }, - { 0x0f39, 0x0f39, C99 }, - { 0x0f3e, 0x0f47, C99 }, - { 0x0f49, 0x0f69, C99 }, - { 0x0f71, 0x0f84, C99 }, - { 0x0f86, 0x0f8b, C99 }, - { 0x0f90, 0x0f95, C99 }, - { 0x0f97, 0x0f97, C99 }, - { 0x0f99, 0x0fad, C99 }, - { 0x0fb1, 0x0fb7, C99 }, - { 0x0fb9, 0x0fb9, C99 }, - { 0x10a0, 0x10c5, CXX|C99 }, /* Georgian */ - { 0x10d0, 0x10f6, CXX|C99 }, - { 0x1100, 0x1159, CXX }, /* Hangul */ - { 0x1161, 0x11a2, CXX }, - { 0x11a8, 0x11f9, CXX }, - { 0x1e00, 0x1e9a, CXX|C99 }, /* Latin */ - { 0x1e9b, 0x1e9b, C99 }, - { 0x1ea0, 0x1ef9, CXX|C99 }, - { 0x1f00, 0x1f15, CXX|C99 }, /* Greek */ - { 0x1f18, 0x1f1d, CXX|C99 }, - { 0x1f20, 0x1f45, CXX|C99 }, - { 0x1f48, 0x1f4d, CXX|C99 }, - { 0x1f50, 0x1f57, CXX|C99 }, - { 0x1f59, 0x1f59, CXX|C99 }, - { 0x1f5b, 0x1f5b, CXX|C99 }, - { 0x1f5d, 0x1f5d, CXX|C99 }, - { 0x1f5f, 0x1f7d, CXX|C99 }, - { 0x1f80, 0x1fb4, CXX|C99 }, - { 0x1fb6, 0x1fbc, CXX|C99 }, - { 0x1fbe, 0x1fbe, C99 }, /* Special characters */ - { 0x1fc2, 0x1fc4, CXX|C99 }, /* Greek */ - { 0x1fc6, 0x1fcc, CXX|C99 }, - { 0x1fd0, 0x1fd3, CXX|C99 }, - { 0x1fd6, 0x1fdb, CXX|C99 }, - { 0x1fe0, 0x1fec, CXX|C99 }, - { 0x1ff2, 0x1ff4, CXX|C99 }, - { 0x1ff6, 0x1ffc, CXX|C99 }, - { 0x203f, 0x2040, C99 }, /* Special characters */ - { 0x207f, 0x207f, C99 }, /* Latin */ - { 0x2102, 0x2102, C99 }, /* Special characters */ - { 0x2107, 0x2107, C99 }, - { 0x210a, 0x2113, C99 }, - { 0x2115, 0x2115, C99 }, - { 0x2118, 0x211d, C99 }, - { 0x2124, 0x2124, C99 }, - { 0x2126, 0x2126, C99 }, - { 0x2128, 0x2128, C99 }, - { 0x212a, 0x2131, C99 }, - { 0x2133, 0x2138, C99 }, - { 0x2160, 0x2182, C99 }, - { 0x3005, 0x3007, C99 }, - { 0x3021, 0x3029, C99 }, - { 0x3041, 0x3093, CXX|C99 }, /* Hiragana */ - { 0x3094, 0x3094, CXX }, - { 0x309b, 0x309c, CXX|C99 }, - { 0x309d, 0x309e, CXX }, - { 0x30a1, 0x30f6, CXX|C99 }, /* Katakana */ - { 0x30f7, 0x30fa, CXX }, - { 0x30fb, 0x30fc, CXX|C99 }, - { 0x30fd, 0x30fe, CXX }, - { 0x3105, 0x312c, CXX|C99 }, /* Bopomofo */ - { 0x4e00, 0x9fa5, CXX|C99 }, /* CJK Unified Ideographs */ - { 0xac00, 0xd7a3, C99 }, /* Hangul */ - { 0xf900, 0xfa2d, CXX }, /* CJK Unified Ideographs */ - { 0xfb1f, 0xfb36, CXX }, - { 0xfb38, 0xfb3c, CXX }, - { 0xfb3e, 0xfb3e, CXX }, - { 0xfb40, 0xfb44, CXX }, - { 0xfb46, 0xfbb1, CXX }, - { 0xfbd3, 0xfd3f, CXX }, - { 0xfd50, 0xfd8f, CXX }, - { 0xfd92, 0xfdc7, CXX }, - { 0xfdf0, 0xfdfb, CXX }, - { 0xfe70, 0xfe72, CXX }, - { 0xfe74, 0xfe74, CXX }, - { 0xfe76, 0xfefc, CXX }, - { 0xff21, 0xff3a, CXX }, - { 0xff41, 0xff5a, CXX }, - { 0xff66, 0xffbe, CXX }, - { 0xffc2, 0xffc7, CXX }, - { 0xffca, 0xffcf, CXX }, - { 0xffd2, 0xffd7, CXX }, - { 0xffda, 0xffdc, CXX }, -}; - -#endif /* cppucnid.h */ diff --git a/support/cpp2/diagnostic.c b/support/cpp2/diagnostic.c index 7b1155b9..8dc988fd 100644 --- a/support/cpp2/diagnostic.c +++ b/support/cpp2/diagnostic.c @@ -1,5 +1,6 @@ /* Language-independent diagnostic subroutines for the GNU Compiler Collection - Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. Contributed by Gabriel Dos Reis This file is part of GCC. @@ -16,8 +17,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ /* This file implements the language independent aspect of diagnostic @@ -27,11 +28,12 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #undef FLOAT /* This is for hpux. They should change hpux. */ #undef FFS /* Some systems define this in param.h. */ #include "system.h" -#include "input.h" +#include "options.h" #include "version.h" #include "input.h" #include "intl.h" #include "diagnostic.h" +#include "opts.h" /* Prototypes. */ @@ -43,25 +45,15 @@ static void default_diagnostic_finalizer (diagnostic_context *, diagnostic_info *); static void error_recursion (diagnostic_context *) ATTRIBUTE_NORETURN; -static bool text_specifies_location (text_info *, location_t *); static bool diagnostic_count_diagnostic (diagnostic_context *, diagnostic_info *); static void diagnostic_action_after_output (diagnostic_context *, diagnostic_info *); static void real_abort (void) ATTRIBUTE_NORETURN; -extern int rtl_dump_and_exit; - /* A diagnostic_context surrogate for stderr. */ static diagnostic_context global_diagnostic_context; diagnostic_context *global_dc = &global_diagnostic_context; - -/* Boilerplate text used in two locations. */ -#define bug_report_request \ -"Please submit a full bug report,\n\ -with preprocessed source if appropriate.\n\ -See %s for instructions.\n" - /* Return a malloc'd string containing MSG formatted a la printf. The caller is responsible for freeing the memory. */ @@ -98,10 +90,12 @@ diagnostic_initialize (diagnostic_context *context) /* By default, diagnostics are sent to stderr. */ context->printer->buffer->stream = stderr; /* By default, we emit prefixes once per message. */ - context->printer->prefixing_rule = DIAGNOSTICS_SHOW_PREFIX_ONCE; + context->printer->wrapping.rule = DIAGNOSTICS_SHOW_PREFIX_ONCE; memset (context->diagnostic_count, 0, sizeof context->diagnostic_count); - context->warnings_are_errors_message = warnings_are_errors; + context->issue_warnings_are_errors_message = true; + context->warning_as_error_requested = false; + context->show_option_requested = false; context->abort_on_error = false; context->internal_error = NULL; diagnostic_starter (context) = default_diagnostic_starter; @@ -109,51 +103,31 @@ diagnostic_initialize (diagnostic_context *context) context->last_module = 0; context->last_function = NULL; context->lock = 0; - context->x_data = NULL; } -/* Returns true if the next format specifier in TEXT is a format specifier - for a location_t. If so, update the object pointed by LOCUS to reflect - the specified location in *TEXT->args_ptr. */ -static bool -text_specifies_location (text_info *text, location_t *locus) +/* Initialize DIAGNOSTIC, where the message MSG has already been + translated. */ +void +diagnostic_set_info_translated (diagnostic_info *diagnostic, const char *msg, + va_list *args, location_t location, + diagnostic_t kind) { - const char *p; - /* Skip any leading text. */ - for (p = text->format_spec; *p && *p != '%'; ++p) - ; - - /* Extract the location information if any. */ - if (p[0] == '%' && p[1] == 'H') - { - *locus = *va_arg (*text->args_ptr, location_t *); - text->format_spec = p + 2; - return true; - } - else if (p[0] == '%' && p[1] == 'J') - { - tree t = va_arg (*text->args_ptr, tree); - *locus = DECL_SOURCE_LOCATION (t); - text->format_spec = p + 2; - return true; - } - - return false; + diagnostic->message.err_no = errno; + diagnostic->message.args_ptr = args; + diagnostic->message.format_spec = msg; + diagnostic->location = location; + diagnostic->kind = kind; + diagnostic->option_index = 0; } +/* Initialize DIAGNOSTIC, where the message GMSGID has not yet been + translated. */ void -diagnostic_set_info (diagnostic_info *diagnostic, const char *msgid, +diagnostic_set_info (diagnostic_info *diagnostic, const char *gmsgid, va_list *args, location_t location, diagnostic_t kind) { - diagnostic->message.err_no = errno; - diagnostic->message.args_ptr = args; - diagnostic->message.format_spec = _(msgid); - /* If the diagnostic message doesn't specify a location, - use LOCATION. */ - if (!text_specifies_location (&diagnostic->message, &diagnostic->location)) - diagnostic->location = location; - diagnostic->kind = kind; + diagnostic_set_info_translated (diagnostic, _(gmsgid), args, location, kind); } /* Return a malloc'd string describing a location. The caller is @@ -167,16 +141,18 @@ diagnostic_build_prefix (diagnostic_info *diagnostic) #undef DEFINE_DIAGNOSTIC_KIND "must-not-happen" }; - if (diagnostic->kind >= DK_LAST_DIAGNOSTIC_KIND) - abort(); - - return diagnostic->location.file - ? build_message_string ("%s:%d: %s", - diagnostic->location.file, - diagnostic->location.line, - _(diagnostic_kind_text[diagnostic->kind])) - : build_message_string ("%s: %s", progname, - _(diagnostic_kind_text[diagnostic->kind])); + const char *text = _(diagnostic_kind_text[diagnostic->kind]); + expanded_location s = expand_location (diagnostic->location); + gcc_assert (diagnostic->kind < DK_LAST_DIAGNOSTIC_KIND); + + return + (s.file == NULL + ? build_message_string ("%s: %s", progname, text) +#ifdef USE_MAPPED_LOCATION + : flag_show_column && s.column != 0 + ? build_message_string ("%s:%d:%d: %s", s.file, s.line, s.column, text) +#endif + : build_message_string ("%s:%d: %s", s.file, s.line, text)); } /* Count a diagnostic. Return true if the message should be printed. */ @@ -188,8 +164,7 @@ diagnostic_count_diagnostic (diagnostic_context *context, switch (kind) { default: - abort(); - break; + gcc_unreachable (); case DK_ICE: #ifndef ENABLE_CHECKING @@ -200,8 +175,9 @@ diagnostic_count_diagnostic (diagnostic_context *context, || diagnostic_kind_count (context, DK_SORRY) > 0) && !context->abort_on_error) { + expanded_location s = expand_location (diagnostic->location); fnotice (stderr, "%s:%d: confused by earlier errors, bailing out\n", - diagnostic->location.file, diagnostic->location.line); + s.file, s.line); exit (FATAL_EXIT_CODE); } #endif @@ -219,17 +195,16 @@ diagnostic_count_diagnostic (diagnostic_context *context, if (!diagnostic_report_warnings_p ()) return false; - if (!warnings_are_errors) + if (!context->warning_as_error_requested) { ++diagnostic_kind_count (context, DK_WARNING); break; } - - if (context->warnings_are_errors_message) + else if (context->issue_warnings_are_errors_message) { pp_verbatim (context->printer, "%s: warnings being treated as errors\n", progname); - context->warnings_are_errors_message = false; + context->issue_warnings_are_errors_message = false; } /* And fall through. */ @@ -259,13 +234,20 @@ diagnostic_action_after_output (diagnostic_context *context, case DK_SORRY: if (context->abort_on_error) real_abort (); + if (flag_fatal_errors) + { + fnotice (stderr, "compilation terminated due to -Wfatal-errors.\n"); + exit (FATAL_EXIT_CODE); + } break; case DK_ICE: if (context->abort_on_error) real_abort (); - fnotice (stderr, bug_report_request, bug_report_url); + fnotice (stderr, "Please submit a full bug report,\n" + "with preprocessed source if appropriate.\n" + "See %s for instructions.\n", bug_report_url); exit (FATAL_EXIT_CODE); case DK_FATAL: @@ -276,19 +258,17 @@ diagnostic_action_after_output (diagnostic_context *context, exit (FATAL_EXIT_CODE); default: - real_abort (); + gcc_unreachable (); } } /* Prints out, if necessary, the name of the current function - that caused an error. Called from all error and warning functions. - We ignore the FILE parameter, as it cannot be relied upon. */ - + that caused an error. Called from all error and warning functions. */ void diagnostic_report_current_function (diagnostic_context *context) { diagnostic_report_current_module (context); - (*lang_hooks.print_error_function) (context, input_filename); + lang_hooks.print_error_function (context, input_filename); } void @@ -302,18 +282,23 @@ diagnostic_report_current_module (diagnostic_context *context) pp_needs_newline (context->printer) = false; } - if (input_file_stack && diagnostic_last_module_changed (context)) + p = input_file_stack; + if (p && diagnostic_last_module_changed (context)) { - p = input_file_stack; + expanded_location xloc = expand_location (p->location); pp_verbatim (context->printer, "In file included from %s:%d", - p->location.file, p->location.line); + xloc.file, xloc.line); while ((p = p->next) != NULL) - pp_verbatim (context->printer, - ",\n from %s:%d", - p->location.file, p->location.line); - pp_verbatim (context->printer, ":\n"); + { + xloc = expand_location (p->location); + pp_verbatim (context->printer, + ",\n from %s:%d", + xloc.file, xloc.line); + } + pp_verbatim (context->printer, ":"); diagnostic_set_last_module (context); + pp_newline (context->printer); } } @@ -327,7 +312,7 @@ default_diagnostic_starter (diagnostic_context *context, static void default_diagnostic_finalizer (diagnostic_context *context, - diagnostic_info *diagnostic __attribute__((unused))) + diagnostic_info *diagnostic ATTRIBUTE_UNUSED) { pp_destroy_prefix (context->printer); } @@ -342,16 +327,40 @@ void diagnostic_report_diagnostic (diagnostic_context *context, diagnostic_info *diagnostic) { - if (context->lock++ && diagnostic->kind < DK_SORRY) - error_recursion (context); + if (context->lock > 0) + { + /* If we're reporting an ICE in the middle of some other error, + try to flush out the previous error, then let this one + through. Don't do this more than once. */ + if (diagnostic->kind == DK_ICE && context->lock == 1) + pp_flush (context->printer); + else + error_recursion (context); + } + + if (diagnostic->option_index + && ! option_enabled (diagnostic->option_index)) + return; + + context->lock++; if (diagnostic_count_diagnostic (context, diagnostic)) { + const char *saved_format_spec = diagnostic->message.format_spec; + + if (context->show_option_requested && diagnostic->option_index) + diagnostic->message.format_spec + = ACONCAT ((diagnostic->message.format_spec, + " [", cl_options[diagnostic->option_index].opt_text, "]", NULL)); + + diagnostic->message.locus = &diagnostic->location; + pp_format (context->printer, &diagnostic->message); (*diagnostic_starter (context)) (context, diagnostic); - pp_format_text (context->printer, &diagnostic->message); + pp_output_formatted_text (context->printer); (*diagnostic_finalizer (context)) (context, diagnostic); pp_flush (context->printer); diagnostic_action_after_output (context, diagnostic); + diagnostic->message.format_spec = saved_format_spec; } context->lock--; @@ -370,20 +379,10 @@ trim_filename (const char *name) /* First skip any "../" in each filename. This allows us to give a proper reference to a file in a subdirectory. */ - while (p[0] == '.' && p[1] == '.' - && (p[2] == DIR_SEPARATOR -#ifdef DIR_SEPARATOR_2 - || p[2] == DIR_SEPARATOR_2 -#endif - )) + while (p[0] == '.' && p[1] == '.' && IS_DIR_SEPARATOR (p[2])) p += 3; - while (q[0] == '.' && q[1] == '.' - && (q[2] == DIR_SEPARATOR -#ifdef DIR_SEPARATOR_2 - || p[2] == DIR_SEPARATOR_2 -#endif - )) + while (q[0] == '.' && q[1] == '.' && IS_DIR_SEPARATOR (q[2])) q += 3; /* Now skip any parts the two filenames have in common. */ @@ -391,11 +390,7 @@ trim_filename (const char *name) p++, q++; /* Now go backwards until the previous directory separator. */ - while (p > name && p[-1] != DIR_SEPARATOR -#ifdef DIR_SEPARATOR_2 - && p[-1] != DIR_SEPARATOR_2 -#endif - ) + while (p > name && !IS_DIR_SEPARATOR (p[-1])) p--; return p; @@ -407,15 +402,16 @@ trim_filename (const char *name) /* Text to be emitted verbatim to the error message stream; this produces no prefix and disables line-wrapping. Use rarely. */ void -verbatim (const char *msgid, ...) +verbatim (const char *gmsgid, ...) { text_info text; va_list ap; - va_start (ap, msgid); + va_start (ap, gmsgid); text.err_no = errno; text.args_ptr = ≈ - text.format_spec = _(msgid); + text.format_spec = _(gmsgid); + text.locus = NULL; pp_format_verbatim (global_dc->printer, &text); pp_flush (global_dc->printer); va_end (ap); @@ -424,13 +420,13 @@ verbatim (const char *msgid, ...) /* An informative note. Use this for additional details on an error message. */ void -inform (const char *msgid, ...) +inform (const char *gmsgid, ...) { diagnostic_info diagnostic; va_list ap; - va_start (ap, msgid); - diagnostic_set_info (&diagnostic, msgid, &ap, input_location, DK_NOTE); + va_start (ap, gmsgid); + diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_NOTE); report_diagnostic (&diagnostic); va_end (ap); } @@ -438,13 +434,27 @@ inform (const char *msgid, ...) /* A warning. Use this for code which is correct according to the relevant language specification but is likely to be buggy anyway. */ void -warning (const char *msgid, ...) +warning (int opt, const char *gmsgid, ...) { diagnostic_info diagnostic; va_list ap; - va_start (ap, msgid); - diagnostic_set_info (&diagnostic, msgid, &ap, input_location, DK_WARNING); + va_start (ap, gmsgid); + diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_WARNING); + diagnostic.option_index = opt; + + report_diagnostic (&diagnostic); + va_end (ap); +} + +void +warning0 (const char *gmsgid, ...) +{ + diagnostic_info diagnostic; + va_list ap; + + va_start (ap, gmsgid); + diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_WARNING); report_diagnostic (&diagnostic); va_end (ap); } @@ -458,13 +468,13 @@ warning (const char *msgid, ...) of the -pedantic command-line switch. To get a warning enabled only with that switch, write "if (pedantic) pedwarn (...);" */ void -pedwarn (const char *msgid, ...) +pedwarn (const char *gmsgid, ...) { diagnostic_info diagnostic; va_list ap; - va_start (ap, msgid); - diagnostic_set_info (&diagnostic, msgid, &ap, input_location, + va_start (ap, gmsgid); + diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, pedantic_error_kind ()); report_diagnostic (&diagnostic); va_end (ap); @@ -473,13 +483,13 @@ pedwarn (const char *msgid, ...) /* A hard error: the code is definitely ill-formed, and an object file will not be produced. */ void -error (const char *msgid, ...) +error (const char *gmsgid, ...) { diagnostic_info diagnostic; va_list ap; - va_start (ap, msgid); - diagnostic_set_info (&diagnostic, msgid, &ap, input_location, DK_ERROR); + va_start (ap, gmsgid); + diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_ERROR); report_diagnostic (&diagnostic); va_end (ap); } @@ -488,13 +498,13 @@ error (const char *msgid, ...) required by the relevant specification but not implemented by GCC. An object file will not be produced. */ void -sorry (const char *msgid, ...) +sorry (const char *gmsgid, ...) { diagnostic_info diagnostic; va_list ap; - va_start (ap, msgid); - diagnostic_set_info (&diagnostic, msgid, &ap, input_location, DK_SORRY); + va_start (ap, gmsgid); + diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_SORRY); report_diagnostic (&diagnostic); va_end (ap); } @@ -503,18 +513,17 @@ sorry (const char *msgid, ...) continue. Do not use this for internal consistency checks; that's internal_error. Use of this function should be rare. */ void -fatal_error (const char *msgid, ...) +fatal_error (const char *gmsgid, ...) { diagnostic_info diagnostic; va_list ap; - va_start (ap, msgid); - diagnostic_set_info (&diagnostic, msgid, &ap, input_location, DK_FATAL); + va_start (ap, gmsgid); + diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_FATAL); report_diagnostic (&diagnostic); va_end (ap); - /* NOTREACHED */ - real_abort (); + gcc_unreachable (); } /* An internal consistency check has failed. We make no attempt to @@ -522,18 +531,17 @@ fatal_error (const char *msgid, ...) a more specific message, or some other good reason, you should use abort () instead of calling this function directly. */ void -internal_error (const char *msgid, ...) +internal_error (const char *gmsgid, ...) { diagnostic_info diagnostic; va_list ap; - va_start (ap, msgid); - diagnostic_set_info (&diagnostic, msgid, &ap, input_location, DK_ICE); + va_start (ap, gmsgid); + diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_ICE); report_diagnostic (&diagnostic); va_end (ap); - /* NOTREACHED */ - real_abort (); + gcc_unreachable (); } /* Special case error functions. Most are implemented in terms of the @@ -542,12 +550,12 @@ internal_error (const char *msgid, ...) /* Print a diagnostic MSGID on FILE. This is just fprintf, except it runs its second argument through gettext. */ void -fnotice (FILE *file, const char *msgid, ...) +fnotice (FILE *file, const char *cmsgid, ...) { va_list ap; - va_start (ap, msgid); - vfprintf (file, _(msgid), ap); + va_start (ap, cmsgid); + vfprintf (file, _(cmsgid), ap); va_end (ap); } @@ -559,13 +567,22 @@ fnotice (FILE *file, const char *msgid, ...) static void error_recursion (diagnostic_context *context) { + diagnostic_info diagnostic; + if (context->lock < 3) pp_flush (context->printer); fnotice (stderr, "Internal compiler error: Error reporting routines re-entered.\n"); - fnotice (stderr, bug_report_request, bug_report_url); - exit (FATAL_EXIT_CODE); + + /* Call diagnostic_action_after_output to get the "please submit a bug + report" message. It only looks at the kind field of diagnostic_info. */ + diagnostic.kind = DK_ICE; + diagnostic_action_after_output (context, &diagnostic); + + /* Do not use gcc_unreachable here; that goes through internal_error + and therefore would cause infinite recursion. */ + real_abort (); } /* Report an internal compiler error in a friendly manner. This is diff --git a/support/cpp2/diagnostic.h b/support/cpp2/diagnostic.h index daf24279..3a3204bd 100644 --- a/support/cpp2/diagnostic.h +++ b/support/cpp2/diagnostic.h @@ -1,5 +1,6 @@ /* Various declarations for language-independent diagnostics subroutines. - Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. Contributed by Gabriel Dos Reis This file is part of GCC. @@ -16,8 +17,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ #ifndef GCC_DIAGNOSTIC_H #define GCC_DIAGNOSTIC_H @@ -42,6 +43,8 @@ typedef struct location_t location; /* The kind of diagnostic it is about. */ diagnostic_t kind; + /* Which OPT_* directly controls this diagnostic. */ + int option_index; } diagnostic_info; #define pedantic_error_kind() (flag_pedantic_errors ? DK_ERROR : DK_WARNING) @@ -65,7 +68,14 @@ struct diagnostic_context /* True if we should display the "warnings are being tread as error" message, usually displayed once per compiler run. */ - bool warnings_are_errors_message; + bool issue_warnings_are_errors_message; + + /* True if it has been requested that warnings be treated as errors. */ + bool warning_as_error_requested; + + /* True if we should print the command line option which controls + each diagnostic, if known. */ + bool show_option_requested; /* True if we should raise a SIGABRT on errors. */ bool abort_on_error; @@ -94,9 +104,6 @@ struct diagnostic_context int last_module; int lock; - - /* Hook for front-end extensions. */ - void *x_data; }; /* Client supplied function to announce a diagnostic. */ @@ -113,11 +120,11 @@ struct diagnostic_context #define diagnostic_format_decoder(DC) ((DC)->printer->format_decoder) /* Same as output_prefixing_rule. Works on 'diagnostic_context *'. */ -#define diagnostic_prefixing_rule(DC) ((DC)->printer->prefixing_rule) +#define diagnostic_prefixing_rule(DC) ((DC)->printer->wrapping.rule) /* Maximum characters per line in automatic line wrapping mode. Zero means don't wrap lines. */ -#define diagnostic_line_cutoff(DC) ((DC)->printer->ideal_maximum_length) +#define diagnostic_line_cutoff(DC) ((DC)->printer->wrapping.line_cutoff) #define diagnostic_flush_buffer(DC) pp_base_flush ((DC)->printer) @@ -174,12 +181,27 @@ extern void diagnostic_report_current_module (diagnostic_context *); extern void diagnostic_report_current_function (diagnostic_context *); extern void diagnostic_report_diagnostic (diagnostic_context *, diagnostic_info *); +#ifdef ATTRIBUTE_GCC_DIAG extern void diagnostic_set_info (diagnostic_info *, const char *, va_list *, - location_t, diagnostic_t); + location_t, diagnostic_t) ATTRIBUTE_GCC_DIAG(2,0); +extern void diagnostic_set_info_translated (diagnostic_info *, const char *, + va_list *, location_t, + diagnostic_t) + ATTRIBUTE_GCC_DIAG(2,0); +#endif extern char *diagnostic_build_prefix (diagnostic_info *); /* Pure text formatting support functions. */ -extern void verbatim (const char *, ...); extern char *file_name_as_prefix (const char *); +/* In tree-pretty-print.c */ +extern int dump_generic_node (pretty_printer *, tree, int, int, bool); +extern void print_generic_stmt (FILE *, tree, int); +extern void print_generic_stmt_indented (FILE *, tree, int, int); +extern void print_generic_expr (FILE *, tree, int); +extern void print_generic_decl (FILE *, tree, int); + +extern void debug_generic_expr (tree); +extern void debug_generic_stmt (tree); +extern void debug_c_tree (tree); #endif /* ! GCC_DIAGNOSTIC_H */ diff --git a/support/cpp2/except.h b/support/cpp2/except.h index 5093a650..d5e391d9 100644 --- a/support/cpp2/except.h +++ b/support/cpp2/except.h @@ -1,5 +1,5 @@ /* Exception Handling interface routines. - Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. Contributed by Mike Stump . @@ -17,14 +17,12 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ struct function; -struct inline_remap; - /* Per-function EH data. Used only in except.c, but GC and others manipulate pointers to the opaque type. */ struct eh_status; @@ -35,62 +33,25 @@ struct eh_region; /* Test: is exception handling turned on? */ extern int doing_eh (int); -/* Start an exception handling region. All instructions emitted after - this point are considered to be part of the region until an - expand_eh_region_end variant is invoked. */ -extern void expand_eh_region_start (void); - -/* End an exception handling region for a cleanup. HANDLER is an - expression to expand for the cleanup. */ -extern void expand_eh_region_end_cleanup (tree); - -/* End an exception handling region for a try block, and prepares - for subsequent calls to expand_start_catch. */ -extern void expand_start_all_catch (void); - -/* Begin a catch clause. TYPE is an object to be matched by the - runtime, or a list of such objects, or null if this is a catch-all - clause. */ -extern void expand_start_catch (tree); - -/* End a catch clause. Control will resume after the try/catch block. */ -extern void expand_end_catch (void); - -/* End a sequence of catch handlers for a try block. */ -extern void expand_end_all_catch (void); - -/* End an exception region for an exception type filter. ALLOWED is a - TREE_LIST of TREE_VALUE objects to be matched by the runtime. - FAILURE is a function to invoke if a mismatch occurs. */ -extern void expand_eh_region_end_allowed (tree, tree); - -/* End an exception region for a must-not-throw filter. FAILURE is a - function to invoke if an uncaught exception propagates this far. */ -extern void expand_eh_region_end_must_not_throw (tree); - -/* End an exception region for a throw. No handling goes on here, - but it's the easiest way for the front-end to indicate what type - is being thrown. */ -extern void expand_eh_region_end_throw (tree); - -/* End a fixup region. Within this region the cleanups for the immediately - enclosing region are _not_ run. This is used for goto cleanup to avoid - destroying an object twice. */ -extern void expand_eh_region_end_fixup (tree); - /* Note that the current EH region (if any) may contain a throw, or a call to a function which itself may contain a throw. */ -extern void note_eh_region_may_contain_throw (void); +extern void note_eh_region_may_contain_throw (struct eh_region *); +extern void note_current_region_may_contain_throw (void); /* Invokes CALLBACK for every exception handler label. Only used by old loop hackery; should not be used by new code. */ extern void for_each_eh_label (void (*) (rtx)); +/* Invokes CALLBACK for every exception region in the current function. */ +extern void for_each_eh_region (void (*) (struct eh_region *)); + /* Determine if the given INSN can throw an exception. */ +extern bool can_throw_internal_1 (int, bool); extern bool can_throw_internal (rtx); +extern bool can_throw_external_1 (int, bool); extern bool can_throw_external (rtx); -/* Set current_function_nothrow and cfun->all_throwers_are_sibcalls. */ +/* Set TREE_NOTHROW and cfun->all_throwers_are_sibcalls. */ extern void set_nothrow_function_flags (void); /* After initial rtl generation, call back to finish generating @@ -119,10 +80,39 @@ extern void expand_builtin_eh_return (tree, tree); extern void expand_eh_return (void); extern rtx expand_builtin_extend_pointer (tree); extern rtx get_exception_pointer (struct function *); -extern int duplicate_eh_regions (struct function *, struct inline_remap *); +extern rtx get_exception_filter (struct function *); +typedef tree (*duplicate_eh_regions_map) (tree, void *); +extern int duplicate_eh_regions (struct function *, duplicate_eh_regions_map, void *, int); extern void sjlj_emit_function_exit_after (rtx); - +extern void default_init_unwind_resume_libfunc (void); + +extern struct eh_region *gen_eh_region_cleanup (struct eh_region *, + struct eh_region *); +extern struct eh_region *gen_eh_region_try (struct eh_region *); +extern struct eh_region *gen_eh_region_catch (struct eh_region *, tree); +extern struct eh_region *gen_eh_region_allowed (struct eh_region *, tree); +extern struct eh_region *gen_eh_region_must_not_throw (struct eh_region *); +extern int get_eh_region_number (struct eh_region *); +extern bool get_eh_region_may_contain_throw (struct eh_region *); +extern tree get_eh_region_tree_label (struct eh_region *); +extern void set_eh_region_tree_label (struct eh_region *, tree); + +extern void foreach_reachable_handler (int, bool, + void (*) (struct eh_region *, void *), + void *); + +extern void collect_eh_region_array (void); +extern void expand_resx_expr (tree); +extern void verify_eh_tree (struct function *); +extern void dump_eh_tree (FILE *, struct function *); + +/* tree-eh.c */ +extern void add_stmt_to_eh_region_fn (struct function *, tree, int); +extern bool remove_stmt_from_eh_region_fn (struct function *, tree); +extern int lookup_stmt_eh_region_fn (struct function *, tree); +extern int lookup_stmt_eh_region (tree); +extern bool verify_eh_edges (tree); /* If non-NULL, this is a function that returns an expression to be executed if an unhandled exception is propagated out of a cleanup @@ -145,7 +135,7 @@ extern tree (*lang_eh_runtime_type) (tree); #ifndef MUST_USE_SJLJ_EXCEPTIONS # if !(defined (EH_RETURN_DATA_REGNO) \ - && (defined (IA64_UNWIND_INFO) \ + && (defined (TARGET_UNWIND_INFO) \ || (DWARF2_UNWIND_INFO \ && (defined (EH_RETURN_HANDLER_RTX) \ || defined (HAVE_eh_return))))) @@ -167,10 +157,19 @@ extern tree (*lang_eh_runtime_type) (tree); # if !defined(EH_RETURN_HANDLER_RTX) && !defined(HAVE_eh_return) #error "EH_RETURN_HANDLER_RTX or eh_return required" # endif -# if !defined(DWARF2_UNWIND_INFO) && !defined(IA64_UNWIND_INFO) - #error "{DWARF2,IA64}_UNWIND_INFO required" +# if !defined(DWARF2_UNWIND_INFO) && !defined(TARGET_UNWIND_INFO) + #error "{DWARF2,TARGET}_UNWIND_INFO required" # endif # endif #else # define USING_SJLJ_EXCEPTIONS MUST_USE_SJLJ_EXCEPTIONS #endif + +struct throw_stmt_node GTY(()) +{ + tree stmt; + int region_nr; +}; + +extern struct htab *get_eh_throw_stmt_table (struct function *); +extern void set_eh_throw_stmt_table (struct function *, struct htab *); diff --git a/support/cpp2/hashtab.c b/support/cpp2/hashtab.c deleted file mode 100644 index 231fbc0d..00000000 --- a/support/cpp2/hashtab.c +++ /dev/null @@ -1,853 +0,0 @@ -/* An expandable hash tables datatype. - Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. - Contributed by Vladimir Makarov (vmakarov@cygnus.com). - -This file is part of the libiberty library. -Libiberty is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public -License as published by the Free Software Foundation; either -version 2 of the License, or (at your option) any later version. - -Libiberty 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 -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with libiberty; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -/* This package implements basic hash table functionality. It is possible - to search for an entry, create an entry and destroy an entry. - - Elements in the table are generic pointers. - - The size of the table is not fixed; if the occupancy of the table - grows too high the hash table will be expanded. - - The abstract data implementation is based on generalized Algorithm D - from Knuth's book "The art of computer programming". Hash table is - expanded by creation of new hash table and transferring elements from - the old table to the new table. */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#ifdef HAVE_STDLIB_H -#include -#endif - -#ifdef HAVE_STRING_H -#include -#endif - -#ifdef HAVE_MALLOC_H -#include -#endif - -#include - -#include "libiberty.h" -#include "hashtab.h" - -/* This macro defines reserved value for empty table entry. */ - -#define EMPTY_ENTRY ((PTR) 0) - -/* This macro defines reserved value for table entry which contained - a deleted element. */ - -#define DELETED_ENTRY ((PTR) 1) - -static unsigned long higher_prime_number PARAMS ((unsigned long)); -static hashval_t hash_pointer PARAMS ((const void *)); -static int eq_pointer PARAMS ((const void *, const void *)); -static int htab_expand PARAMS ((htab_t)); -static PTR *find_empty_slot_for_expand PARAMS ((htab_t, hashval_t)); - -/* At some point, we could make these be NULL, and modify the - hash-table routines to handle NULL specially; that would avoid - function-call overhead for the common case of hashing pointers. */ -htab_hash htab_hash_pointer = hash_pointer; -htab_eq htab_eq_pointer = eq_pointer; - -/* The following function returns a nearest prime number which is - greater than N, and near a power of two. */ - -static unsigned long -higher_prime_number (n) - unsigned long n; -{ - /* These are primes that are near, but slightly smaller than, a - power of two. */ - static const unsigned long primes[] = { - (unsigned long) 7, - (unsigned long) 13, - (unsigned long) 31, - (unsigned long) 61, - (unsigned long) 127, - (unsigned long) 251, - (unsigned long) 509, - (unsigned long) 1021, - (unsigned long) 2039, - (unsigned long) 4093, - (unsigned long) 8191, - (unsigned long) 16381, - (unsigned long) 32749, - (unsigned long) 65521, - (unsigned long) 131071, - (unsigned long) 262139, - (unsigned long) 524287, - (unsigned long) 1048573, - (unsigned long) 2097143, - (unsigned long) 4194301, - (unsigned long) 8388593, - (unsigned long) 16777213, - (unsigned long) 33554393, - (unsigned long) 67108859, - (unsigned long) 134217689, - (unsigned long) 268435399, - (unsigned long) 536870909, - (unsigned long) 1073741789, - (unsigned long) 2147483647, - /* 4294967291L */ - ((unsigned long) 2147483647) + ((unsigned long) 2147483644), - }; - - const unsigned long *low = &primes[0]; - const unsigned long *high = &primes[sizeof(primes) / sizeof(primes[0])]; - - while (low != high) - { - const unsigned long *mid = low + (high - low) / 2; - if (n > *mid) - low = mid + 1; - else - high = mid; - } - - /* If we've run out of primes, abort. */ - if (n > *low) - { - fprintf (stderr, "Cannot find prime bigger than %lu\n", n); - abort (); - } - - return *low; -} - -/* Returns a hash code for P. */ - -static hashval_t -hash_pointer (p) - const PTR p; -{ - return (hashval_t) ((long)p >> 3); -} - -/* Returns non-zero if P1 and P2 are equal. */ - -static int -eq_pointer (p1, p2) - const PTR p1; - const PTR p2; -{ - return p1 == p2; -} - -/* This function creates table with length slightly longer than given - source length. Created hash table is initiated as empty (all the - hash table entries are EMPTY_ENTRY). The function returns the - created hash table, or NULL if memory allocation fails. */ - -htab_t -htab_create_alloc (size, hash_f, eq_f, del_f, alloc_f, free_f) - size_t size; - htab_hash hash_f; - htab_eq eq_f; - htab_del del_f; - htab_alloc alloc_f; - htab_free free_f; -{ - htab_t result; - - size = higher_prime_number (size); - result = (htab_t) (*alloc_f) (1, sizeof (struct htab)); - if (result == NULL) - return NULL; - result->entries = (PTR *) (*alloc_f) (size, sizeof (PTR)); - if (result->entries == NULL) - { - if (free_f != NULL) - (*free_f) (result); - return NULL; - } - result->size = size; - result->hash_f = hash_f; - result->eq_f = eq_f; - result->del_f = del_f; - result->alloc_f = alloc_f; - result->free_f = free_f; - return result; -} - -/* As above, but use the variants of alloc_f and free_f which accept - an extra argument. */ - -htab_t -htab_create_alloc_ex (size, hash_f, eq_f, del_f, alloc_arg, alloc_f, - free_f) - size_t size; - htab_hash hash_f; - htab_eq eq_f; - htab_del del_f; - PTR alloc_arg; - htab_alloc_with_arg alloc_f; - htab_free_with_arg free_f; -{ - htab_t result; - - size = higher_prime_number (size); - result = (htab_t) (*alloc_f) (alloc_arg, 1, sizeof (struct htab)); - if (result == NULL) - return NULL; - result->entries = (PTR *) (*alloc_f) (alloc_arg, size, sizeof (PTR)); - if (result->entries == NULL) - { - if (free_f != NULL) - (*free_f) (alloc_arg, result); - return NULL; - } - result->size = size; - result->hash_f = hash_f; - result->eq_f = eq_f; - result->del_f = del_f; - result->alloc_arg = alloc_arg; - result->alloc_with_arg_f = alloc_f; - result->free_with_arg_f = free_f; - return result; -} - -/* Update the function pointers and allocation parameter in the htab_t. */ - -void -htab_set_functions_ex (htab, hash_f, eq_f, del_f, alloc_arg, alloc_f, free_f) - htab_t htab; - htab_hash hash_f; - htab_eq eq_f; - htab_del del_f; - PTR alloc_arg; - htab_alloc_with_arg alloc_f; - htab_free_with_arg free_f; -{ - htab->hash_f = hash_f; - htab->eq_f = eq_f; - htab->del_f = del_f; - htab->alloc_arg = alloc_arg; - htab->alloc_with_arg_f = alloc_f; - htab->free_with_arg_f = free_f; -} - -/* These functions exist solely for backward compatibility. */ - -#undef htab_create -htab_t -htab_create (size, hash_f, eq_f, del_f) - size_t size; - htab_hash hash_f; - htab_eq eq_f; - htab_del del_f; -{ - return htab_create_alloc (size, hash_f, eq_f, del_f, xcalloc, free); -} - -htab_t -htab_try_create (size, hash_f, eq_f, del_f) - size_t size; - htab_hash hash_f; - htab_eq eq_f; - htab_del del_f; -{ - return htab_create_alloc (size, hash_f, eq_f, del_f, calloc, free); -} - -/* This function frees all memory allocated for given hash table. - Naturally the hash table must already exist. */ - -void -htab_delete (htab) - htab_t htab; -{ - int i; - - if (htab->del_f) - for (i = htab->size - 1; i >= 0; i--) - if (htab->entries[i] != EMPTY_ENTRY - && htab->entries[i] != DELETED_ENTRY) - (*htab->del_f) (htab->entries[i]); - - if (htab->free_f != NULL) - { - (*htab->free_f) (htab->entries); - (*htab->free_f) (htab); - } - else if (htab->free_with_arg_f != NULL) - { - (*htab->free_with_arg_f) (htab->alloc_arg, htab->entries); - (*htab->free_with_arg_f) (htab->alloc_arg, htab); - } -} - -/* This function clears all entries in the given hash table. */ - -void -htab_empty (htab) - htab_t htab; -{ - int i; - - if (htab->del_f) - for (i = htab->size - 1; i >= 0; i--) - if (htab->entries[i] != EMPTY_ENTRY - && htab->entries[i] != DELETED_ENTRY) - (*htab->del_f) (htab->entries[i]); - - memset (htab->entries, 0, htab->size * sizeof (PTR)); -} - -/* Similar to htab_find_slot, but without several unwanted side effects: - - Does not call htab->eq_f when it finds an existing entry. - - Does not change the count of elements/searches/collisions in the - hash table. - This function also assumes there are no deleted entries in the table. - HASH is the hash value for the element to be inserted. */ - -static PTR * -find_empty_slot_for_expand (htab, hash) - htab_t htab; - hashval_t hash; -{ - size_t size = htab->size; - unsigned int index = hash % size; - PTR *slot = htab->entries + index; - hashval_t hash2; - - if (*slot == EMPTY_ENTRY) - return slot; - else if (*slot == DELETED_ENTRY) - abort (); - - hash2 = 1 + hash % (size - 2); - for (;;) - { - index += hash2; - if (index >= size) - index -= size; - - slot = htab->entries + index; - if (*slot == EMPTY_ENTRY) - return slot; - else if (*slot == DELETED_ENTRY) - abort (); - } -} - -/* The following function changes size of memory allocated for the - entries and repeatedly inserts the table elements. The occupancy - of the table after the call will be about 50%. Naturally the hash - table must already exist. Remember also that the place of the - table entries is changed. If memory allocation failures are allowed, - this function will return zero, indicating that the table could not be - expanded. If all goes well, it will return a non-zero value. */ - -static int -htab_expand (htab) - htab_t htab; -{ - PTR *oentries; - PTR *olimit; - PTR *p; - PTR *nentries; - size_t nsize; - - oentries = htab->entries; - olimit = oentries + htab->size; - - /* Resize only when table after removal of unused elements is either - too full or too empty. */ - if ((htab->n_elements - htab->n_deleted) * 2 > htab->size - || ((htab->n_elements - htab->n_deleted) * 8 < htab->size - && htab->size > 32)) - nsize = higher_prime_number ((htab->n_elements - htab->n_deleted) * 2); - else - nsize = htab->size; - - if (htab->alloc_with_arg_f != NULL) - nentries = (PTR *) (*htab->alloc_with_arg_f) (htab->alloc_arg, nsize, - sizeof (PTR *)); - else - nentries = (PTR *) (*htab->alloc_f) (nsize, sizeof (PTR *)); - if (nentries == NULL) - return 0; - htab->entries = nentries; - htab->size = nsize; - - htab->n_elements -= htab->n_deleted; - htab->n_deleted = 0; - - p = oentries; - do - { - PTR x = *p; - - if (x != EMPTY_ENTRY && x != DELETED_ENTRY) - { - PTR *q = find_empty_slot_for_expand (htab, (*htab->hash_f) (x)); - - *q = x; - } - - p++; - } - while (p < olimit); - - if (htab->free_f != NULL) - (*htab->free_f) (oentries); - else if (htab->free_with_arg_f != NULL) - (*htab->free_with_arg_f) (htab->alloc_arg, oentries); - return 1; -} - -/* This function searches for a hash table entry equal to the given - element. It cannot be used to insert or delete an element. */ - -PTR -htab_find_with_hash (htab, element, hash) - htab_t htab; - const PTR element; - hashval_t hash; -{ - unsigned int index; - hashval_t hash2; - size_t size; - PTR entry; - - htab->searches++; - size = htab->size; - index = hash % size; - - entry = htab->entries[index]; - if (entry == EMPTY_ENTRY - || (entry != DELETED_ENTRY && (*htab->eq_f) (entry, element))) - return entry; - - hash2 = 1 + hash % (size - 2); - - for (;;) - { - htab->collisions++; - index += hash2; - if (index >= size) - index -= size; - - entry = htab->entries[index]; - if (entry == EMPTY_ENTRY - || (entry != DELETED_ENTRY && (*htab->eq_f) (entry, element))) - return entry; - } -} - -/* Like htab_find_slot_with_hash, but compute the hash value from the - element. */ - -PTR -htab_find (htab, element) - htab_t htab; - const PTR element; -{ - return htab_find_with_hash (htab, element, (*htab->hash_f) (element)); -} - -/* This function searches for a hash table slot containing an entry - equal to the given element. To delete an entry, call this with - INSERT = 0, then call htab_clear_slot on the slot returned (possibly - after doing some checks). To insert an entry, call this with - INSERT = 1, then write the value you want into the returned slot. - When inserting an entry, NULL may be returned if memory allocation - fails. */ - -PTR * -htab_find_slot_with_hash (htab, element, hash, insert) - htab_t htab; - const PTR element; - hashval_t hash; - enum insert_option insert; -{ - PTR *first_deleted_slot; - unsigned int index; - hashval_t hash2; - size_t size; - PTR entry; - - if (insert == INSERT && htab->size * 3 <= htab->n_elements * 4 - && htab_expand (htab) == 0) - return NULL; - - size = htab->size; - index = hash % size; - - htab->searches++; - first_deleted_slot = NULL; - - entry = htab->entries[index]; - if (entry == EMPTY_ENTRY) - goto empty_entry; - else if (entry == DELETED_ENTRY) - first_deleted_slot = &htab->entries[index]; - else if ((*htab->eq_f) (entry, element)) - return &htab->entries[index]; - - hash2 = 1 + hash % (size - 2); - for (;;) - { - htab->collisions++; - index += hash2; - if (index >= size) - index -= size; - - entry = htab->entries[index]; - if (entry == EMPTY_ENTRY) - goto empty_entry; - else if (entry == DELETED_ENTRY) - { - if (!first_deleted_slot) - first_deleted_slot = &htab->entries[index]; - } - else if ((*htab->eq_f) (entry, element)) - return &htab->entries[index]; - } - - empty_entry: - if (insert == NO_INSERT) - return NULL; - - if (first_deleted_slot) - { - htab->n_deleted--; - *first_deleted_slot = EMPTY_ENTRY; - return first_deleted_slot; - } - - htab->n_elements++; - return &htab->entries[index]; -} - -/* Like htab_find_slot_with_hash, but compute the hash value from the - element. */ - -PTR * -htab_find_slot (htab, element, insert) - htab_t htab; - const PTR element; - enum insert_option insert; -{ - return htab_find_slot_with_hash (htab, element, (*htab->hash_f) (element), - insert); -} - -/* This function deletes an element with the given value from hash - table. If there is no matching element in the hash table, this - function does nothing. */ - -void -htab_remove_elt (htab, element) - htab_t htab; - PTR element; -{ - PTR *slot; - - slot = htab_find_slot (htab, element, NO_INSERT); - if (*slot == EMPTY_ENTRY) - return; - - if (htab->del_f) - (*htab->del_f) (*slot); - - *slot = DELETED_ENTRY; - htab->n_deleted++; -} - -/* This function clears a specified slot in a hash table. It is - useful when you've already done the lookup and don't want to do it - again. */ - -void -htab_clear_slot (htab, slot) - htab_t htab; - PTR *slot; -{ - if (slot < htab->entries || slot >= htab->entries + htab->size - || *slot == EMPTY_ENTRY || *slot == DELETED_ENTRY) - abort (); - - if (htab->del_f) - (*htab->del_f) (*slot); - - *slot = DELETED_ENTRY; - htab->n_deleted++; -} - -/* This function scans over the entire hash table calling - CALLBACK for each live entry. If CALLBACK returns false, - the iteration stops. INFO is passed as CALLBACK's second - argument. */ - -void -htab_traverse_noresize (htab, callback, info) - htab_t htab; - htab_trav callback; - PTR info; -{ - PTR *slot; - PTR *limit; - - slot = htab->entries; - limit = slot + htab->size; - - do - { - PTR x = *slot; - - if (x != EMPTY_ENTRY && x != DELETED_ENTRY) - if (!(*callback) (slot, info)) - break; - } - while (++slot < limit); -} - -/* Like htab_traverse_noresize, but does resize the table when it is - too empty to improve effectivity of subsequent calls. */ - -void -htab_traverse (htab, callback, info) - htab_t htab; - htab_trav callback; - PTR info; -{ - if ((htab->n_elements - htab->n_deleted) * 8 < htab->size) - htab_expand (htab); - - htab_traverse_noresize (htab, callback, info); -} - -/* Return the current size of given hash table. */ - -size_t -htab_size (htab) - htab_t htab; -{ - return htab->size; -} - -/* Return the current number of elements in given hash table. */ - -size_t -htab_elements (htab) - htab_t htab; -{ - return htab->n_elements - htab->n_deleted; -} - -/* Return the fraction of fixed collisions during all work with given - hash table. */ - -double -htab_collisions (htab) - htab_t htab; -{ - if (htab->searches == 0) - return 0.0; - - return (double) htab->collisions / (double) htab->searches; -} - -/* Hash P as a null-terminated string. - - Copied from gcc/hashtable.c. Zack had the following to say with respect - to applicability, though note that unlike hashtable.c, this hash table - implementation re-hashes rather than chain buckets. - - http://gcc.gnu.org/ml/gcc-patches/2001-08/msg01021.html - From: Zack Weinberg - Date: Fri, 17 Aug 2001 02:15:56 -0400 - - I got it by extracting all the identifiers from all the source code - I had lying around in mid-1999, and testing many recurrences of - the form "H_n = H_{n-1} * K + c_n * L + M" where K, L, M were either - prime numbers or the appropriate identity. This was the best one. - I don't remember exactly what constituted "best", except I was - looking at bucket-length distributions mostly. - - So it should be very good at hashing identifiers, but might not be - as good at arbitrary strings. - - I'll add that it thoroughly trounces the hash functions recommended - for this use at http://burtleburtle.net/bob/hash/index.html, both - on speed and bucket distribution. I haven't tried it against the - function they just started using for Perl's hashes. */ - -hashval_t -htab_hash_string (p) - const PTR p; -{ - const unsigned char *str = (const unsigned char *) p; - hashval_t r = 0; - unsigned char c; - - while ((c = *str++) != 0) - r = r * 67 + c - 113; - - return r; -} - -/* DERIVED FROM: --------------------------------------------------------------------- -lookup2.c, by Bob Jenkins, December 1996, Public Domain. -hash(), hash2(), hash3, and mix() are externally useful functions. -Routines to test the hash are included if SELF_TEST is defined. -You can use this free for any purpose. It has no warranty. --------------------------------------------------------------------- -*/ - -/* --------------------------------------------------------------------- -mix -- mix 3 32-bit values reversibly. -For every delta with one or two bit set, and the deltas of all three - high bits or all three low bits, whether the original value of a,b,c - is almost all zero or is uniformly distributed, -* If mix() is run forward or backward, at least 32 bits in a,b,c - have at least 1/4 probability of changing. -* If mix() is run forward, every bit of c will change between 1/3 and - 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) -mix() was built out of 36 single-cycle latency instructions in a - structure that could supported 2x parallelism, like so: - a -= b; - a -= c; x = (c>>13); - b -= c; a ^= x; - b -= a; x = (a<<8); - c -= a; b ^= x; - c -= b; x = (b>>13); - ... - Unfortunately, superscalar Pentiums and Sparcs can't take advantage - of that parallelism. They've also turned some of those single-cycle - latency instructions into multi-cycle latency instructions. Still, - this is the fastest good hash I could find. There were about 2^^68 - to choose from. I only looked at a billion or so. --------------------------------------------------------------------- -*/ -/* same, but slower, works on systems that might have 8 byte hashval_t's */ -#define mix(a,b,c) \ -{ \ - a -= b; a -= c; a ^= (c>>13); \ - b -= c; b -= a; b ^= (a<< 8); \ - c -= a; c -= b; c ^= ((b&0xffffffff)>>13); \ - a -= b; a -= c; a ^= ((c&0xffffffff)>>12); \ - b -= c; b -= a; b = (b ^ (a<<16)) & 0xffffffff; \ - c -= a; c -= b; c = (c ^ (b>> 5)) & 0xffffffff; \ - a -= b; a -= c; a = (a ^ (c>> 3)) & 0xffffffff; \ - b -= c; b -= a; b = (b ^ (a<<10)) & 0xffffffff; \ - c -= a; c -= b; c = (c ^ (b>>15)) & 0xffffffff; \ -} - -/* --------------------------------------------------------------------- -hash() -- hash a variable-length key into a 32-bit value - k : the key (the unaligned variable-length array of bytes) - len : the length of the key, counting by bytes - level : can be any 4-byte value -Returns a 32-bit value. Every bit of the key affects every bit of -the return value. Every 1-bit and 2-bit delta achieves avalanche. -About 36+6len instructions. - -The best hash table sizes are powers of 2. There is no need to do -mod a prime (mod is sooo slow!). If you need less than 32 bits, -use a bitmask. For example, if you need only 10 bits, do - h = (h & hashmask(10)); -In which case, the hash table should have hashsize(10) elements. - -If you are hashing n strings (ub1 **)k, do it like this: - for (i=0, h=0; i= 12) /* aligned */ - { - a += *(hashval_t *)(k+0); - b += *(hashval_t *)(k+4); - c += *(hashval_t *)(k+8); - mix(a,b,c); - k += 12; len -= 12; - } - else /* unaligned */ -#endif - while (len >= 12) - { - a += (k[0] +((hashval_t)k[1]<<8) +((hashval_t)k[2]<<16) +((hashval_t)k[3]<<24)); - b += (k[4] +((hashval_t)k[5]<<8) +((hashval_t)k[6]<<16) +((hashval_t)k[7]<<24)); - c += (k[8] +((hashval_t)k[9]<<8) +((hashval_t)k[10]<<16)+((hashval_t)k[11]<<24)); - mix(a,b,c); - k += 12; len -= 12; - } - - /*------------------------------------- handle the last 11 bytes */ - c += length; - switch(len) /* all the case statements fall through */ - { - case 11: c+=((hashval_t)k[10]<<24); - case 10: c+=((hashval_t)k[9]<<16); - case 9 : c+=((hashval_t)k[8]<<8); - /* the first byte of c is reserved for the length */ - case 8 : b+=((hashval_t)k[7]<<24); - case 7 : b+=((hashval_t)k[6]<<16); - case 6 : b+=((hashval_t)k[5]<<8); - case 5 : b+=k[4]; - case 4 : a+=((hashval_t)k[3]<<24); - case 3 : a+=((hashval_t)k[2]<<16); - case 2 : a+=((hashval_t)k[1]<<8); - case 1 : a+=k[0]; - /* case 0: nothing left to add */ - } - mix(a,b,c); - /*-------------------------------------------- report the result */ - return c; -} diff --git a/support/cpp2/hashtab.h b/support/cpp2/hashtab.h deleted file mode 100644 index f7bd4ae6..00000000 --- a/support/cpp2/hashtab.h +++ /dev/null @@ -1,195 +0,0 @@ -/* An expandable hash tables datatype. - Copyright (C) 1999, 2000, 2002, 2003 Free Software Foundation, Inc. - Contributed by Vladimir Makarov (vmakarov@cygnus.com). - -This program 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 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* This package implements basic hash table functionality. It is possible - to search for an entry, create an entry and destroy an entry. - - Elements in the table are generic pointers. - - The size of the table is not fixed; if the occupancy of the table - grows too high the hash table will be expanded. - - The abstract data implementation is based on generalized Algorithm D - from Knuth's book "The art of computer programming". Hash table is - expanded by creation of new hash table and transferring elements from - the old table to the new table. */ - -#ifndef __HASHTAB_H__ -#define __HASHTAB_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#include "ansidecl.h" - -#ifndef GTY -#define GTY(X) -#endif - -/* The type for a hash code. */ -typedef unsigned int hashval_t; - -/* Callback function pointer types. */ - -/* Calculate hash of a table entry. */ -typedef hashval_t (*htab_hash) PARAMS ((const void *)); - -/* Compare a table entry with a possible entry. The entry already in - the table always comes first, so the second element can be of a - different type (but in this case htab_find and htab_find_slot - cannot be used; instead the variants that accept a hash value - must be used). */ -typedef int (*htab_eq) PARAMS ((const void *, const void *)); - -/* Cleanup function called whenever a live element is removed from - the hash table. */ -typedef void (*htab_del) PARAMS ((void *)); - -/* Function called by htab_traverse for each live element. The first - arg is the slot of the element (which can be passed to htab_clear_slot - if desired), the second arg is the auxiliary pointer handed to - htab_traverse. Return 1 to continue scan, 0 to stop. */ -typedef int (*htab_trav) PARAMS ((void **, void *)); - -/* Memory-allocation function, with the same functionality as calloc(). - Iff it returns NULL, the hash table implementation will pass an error - code back to the user, so if your code doesn't handle errors, - best if you use xcalloc instead. */ -typedef PTR (*htab_alloc) PARAMS ((size_t, size_t)); - -/* We also need a free() routine. */ -typedef void (*htab_free) PARAMS ((PTR)); - -/* Memory allocation and deallocation; variants which take an extra - argument. */ -typedef PTR (*htab_alloc_with_arg) PARAMS ((void *, size_t, size_t)); -typedef void (*htab_free_with_arg) PARAMS ((void *, void *)); - -/* Hash tables are of the following type. The structure - (implementation) of this type is not needed for using the hash - tables. All work with hash table should be executed only through - functions mentioned below. The size of this structure is subject to - change. */ - -struct htab GTY(()) -{ - /* Pointer to hash function. */ - htab_hash hash_f; - - /* Pointer to comparison function. */ - htab_eq eq_f; - - /* Pointer to cleanup function. */ - htab_del del_f; - - /* Table itself. */ - PTR * GTY ((use_param (""), length ("%h.size"))) entries; - - /* Current size (in entries) of the hash table */ - size_t size; - - /* Current number of elements including also deleted elements */ - size_t n_elements; - - /* Current number of deleted elements in the table */ - size_t n_deleted; - - /* The following member is used for debugging. Its value is number - of all calls of `htab_find_slot' for the hash table. */ - unsigned int searches; - - /* The following member is used for debugging. Its value is number - of collisions fixed for time of work with the hash table. */ - unsigned int collisions; - - /* Pointers to allocate/free functions. */ - htab_alloc alloc_f; - htab_free free_f; - - /* Alternate allocate/free functions, which take an extra argument. */ - PTR GTY((skip (""))) alloc_arg; - htab_alloc_with_arg alloc_with_arg_f; - htab_free_with_arg free_with_arg_f; -}; - -typedef struct htab *htab_t; - -/* An enum saying whether we insert into the hash table or not. */ -enum insert_option {NO_INSERT, INSERT}; - -/* The prototypes of the package functions. */ - -extern htab_t htab_create_alloc PARAMS ((size_t, htab_hash, - htab_eq, htab_del, - htab_alloc, htab_free)); - -extern htab_t htab_create_alloc_ex PARAMS ((size_t, htab_hash, - htab_eq, htab_del, - PTR, htab_alloc_with_arg, - htab_free_with_arg)); - -/* Backward-compatibility functions. */ -extern htab_t htab_create PARAMS ((size_t, htab_hash, htab_eq, htab_del)); -extern htab_t htab_try_create PARAMS ((size_t, htab_hash, htab_eq, htab_del)); - -extern void htab_set_functions_ex PARAMS ((htab_t, htab_hash, - htab_eq, htab_del, - PTR, htab_alloc_with_arg, - htab_free_with_arg)); - -extern void htab_delete PARAMS ((htab_t)); -extern void htab_empty PARAMS ((htab_t)); - -extern PTR htab_find PARAMS ((htab_t, const void *)); -extern PTR *htab_find_slot PARAMS ((htab_t, const void *, - enum insert_option)); -extern PTR htab_find_with_hash PARAMS ((htab_t, const void *, - hashval_t)); -extern PTR *htab_find_slot_with_hash PARAMS ((htab_t, const void *, - hashval_t, - enum insert_option)); -extern void htab_clear_slot PARAMS ((htab_t, void **)); -extern void htab_remove_elt PARAMS ((htab_t, void *)); - -extern void htab_traverse PARAMS ((htab_t, htab_trav, void *)); -extern void htab_traverse_noresize PARAMS ((htab_t, htab_trav, void *)); - -extern size_t htab_size PARAMS ((htab_t)); -extern size_t htab_elements PARAMS ((htab_t)); -extern double htab_collisions PARAMS ((htab_t)); - -/* A hash function for pointers. */ -extern htab_hash htab_hash_pointer; - -/* An equality function for pointers. */ -extern htab_eq htab_eq_pointer; - -/* A hash function for null-terminated strings. */ -extern hashval_t htab_hash_string PARAMS ((const PTR)); - -/* An iterative hash function for arbitrary data. */ -extern hashval_t iterative_hash PARAMS ((const PTR, size_t, hashval_t)); -/* Shorthand for hashing something with an intrinsic size. */ -#define iterative_hash_object(OB,INIT) iterative_hash (&OB, sizeof (OB), INIT) - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __HASHTAB_H */ diff --git a/support/cpp2/hashtable.c b/support/cpp2/hashtable.c deleted file mode 100644 index 58f19d05..00000000 --- a/support/cpp2/hashtable.c +++ /dev/null @@ -1,310 +0,0 @@ -/* Hash tables. - Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc. - -This program 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 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - In other words, you are welcome to use, share and improve this program. - You are forbidden to forbid anyone else to use, share and improve - what you give them. Help stamp out software-hoarding! */ - -#include "config.h" -#include "system.h" -#include "hashtable.h" - -/* The code below is a specialization of Vladimir Makarov's expandable - hash tables (see libiberty/hashtab.c). The abstraction penalty was - too high to continue using the generic form. This code knows - intrinsically how to calculate a hash value, and how to compare an - existing entry with a potential new one. Also, the ability to - delete members from the table has been removed. */ - -static unsigned int calc_hash (const unsigned char *, size_t); -static void ht_expand (hash_table *); -static double approx_sqrt (double); - -/* Calculate the hash of the string STR of length LEN. */ - -static unsigned int -calc_hash (const unsigned char *str, size_t len) -{ - size_t n = len; - unsigned int r = 0; -#define HASHSTEP(r, c) ((r) * 67 + ((c) - 113)); - - while (n--) - r = HASHSTEP (r, *str++); - - return r + len; -#undef HASHSTEP -} - -/* Initialize an identifier hashtable. */ - -hash_table * -ht_create (unsigned int order) -{ - unsigned int nslots = 1 << order; - hash_table *table; - - table = xcalloc (1, sizeof (hash_table)); - - /* Strings need no alignment. */ - _obstack_begin (&table->stack, 0, 0, - (void *(*) (long)) xmalloc, - (void (*) (void *)) free); - - obstack_alignment_mask (&table->stack) = 0; - - table->entries = xcalloc (nslots, sizeof (hashnode)); - table->nslots = nslots; - return table; -} - -/* Frees all memory associated with a hash table. */ - -void -ht_destroy (hash_table *table) -{ - obstack_free (&table->stack, NULL); - free (table->entries); - free (table); -} - -/* Returns the hash entry for the a STR of length LEN. If that string - already exists in the table, returns the existing entry, and, if - INSERT is CPP_ALLOCED, frees the last obstack object. If the - identifier hasn't been seen before, and INSERT is CPP_NO_INSERT, - returns NULL. Otherwise insert and returns a new entry. A new - string is alloced if INSERT is CPP_ALLOC, otherwise INSERT is - CPP_ALLOCED and the item is assumed to be at the top of the - obstack. */ -hashnode -ht_lookup (hash_table *table, const unsigned char *str, size_t len, - enum ht_lookup_option insert) -{ - unsigned int hash = calc_hash (str, len); - unsigned int hash2; - unsigned int index; - size_t sizemask; - hashnode node; - - sizemask = table->nslots - 1; - index = hash & sizemask; - table->searches++; - - node = table->entries[index]; - - if (node != NULL) - { - if (node->hash_value == hash - && HT_LEN (node) == (unsigned int) len - && !memcmp (HT_STR (node), str, len)) - { - if (insert == HT_ALLOCED) - /* The string we search for was placed at the end of the - obstack. Release it. */ - obstack_free (&table->stack, (void *) str); - return node; - } - - /* hash2 must be odd, so we're guaranteed to visit every possible - location in the table during rehashing. */ - hash2 = ((hash * 17) & sizemask) | 1; - - for (;;) - { - table->collisions++; - index = (index + hash2) & sizemask; - node = table->entries[index]; - if (node == NULL) - break; - - if (node->hash_value == hash - && HT_LEN (node) == (unsigned int) len - && !memcmp (HT_STR (node), str, len)) - { - if (insert == HT_ALLOCED) - /* The string we search for was placed at the end of the - obstack. Release it. */ - obstack_free (&table->stack, (void *) str); - return node; - } - } - } - - if (insert == HT_NO_INSERT) - return NULL; - - node = (*table->alloc_node) (table); - table->entries[index] = node; - - HT_LEN (node) = (unsigned int) len; - node->hash_value = hash; - if (insert == HT_ALLOC) - HT_STR (node) = obstack_copy0 (&table->stack, str, len); - else - HT_STR (node) = str; - - if (++table->nelements * 4 >= table->nslots * 3) - /* Must expand the string table. */ - ht_expand (table); - - return node; -} - -/* Double the size of a hash table, re-hashing existing entries. */ - -static void -ht_expand (hash_table *table) -{ - hashnode *nentries, *p, *limit; - unsigned int size, sizemask; - - size = table->nslots * 2; - nentries = xcalloc (size, sizeof (hashnode)); - sizemask = size - 1; - - p = table->entries; - limit = p + table->nslots; - do - if (*p) - { - unsigned int index, hash, hash2; - - hash = (*p)->hash_value; - index = hash & sizemask; - - if (nentries[index]) - { - hash2 = ((hash * 17) & sizemask) | 1; - do - { - index = (index + hash2) & sizemask; - } - while (nentries[index]); - } - nentries[index] = *p; - } - while (++p < limit); - - free (table->entries); - table->entries = nentries; - table->nslots = size; -} - -/* For all nodes in TABLE, callback CB with parameters TABLE->PFILE, - the node, and V. */ -void -ht_forall (hash_table *table, ht_cb cb, const void *v) -{ - hashnode *p, *limit; - - p = table->entries; - limit = p + table->nslots; - do - if (*p) - { - if ((*cb) (table->pfile, *p, v) == 0) - break; - } - while (++p < limit); -} - -/* Dump allocation statistics to stderr. */ - -void -ht_dump_statistics (hash_table *table) -{ - size_t nelts, nids, overhead, headers; - size_t total_bytes, longest, sum_of_squares; - double exp_len, exp_len2, exp2_len; - hashnode *p, *limit; - -#define SCALE(x) ((unsigned long) ((x) < 1024*10 \ - ? (x) \ - : ((x) < 1024*1024*10 \ - ? (x) / 1024 \ - : (x) / (1024*1024)))) -#define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M')) - - total_bytes = longest = sum_of_squares = nids = 0; - p = table->entries; - limit = p + table->nslots; - do - if (*p) - { - size_t n = HT_LEN (*p); - - total_bytes += n; - sum_of_squares += n * n; - if (n > longest) - longest = n; - nids++; - } - while (++p < limit); - - nelts = table->nelements; - overhead = obstack_memory_used (&table->stack) - total_bytes; - headers = table->nslots * sizeof (hashnode); - - fprintf (stderr, "\nString pool\nentries\t\t%lu\n", - (unsigned long) nelts); - fprintf (stderr, "identifiers\t%lu (%.2f%%)\n", - (unsigned long) nids, nids * 100.0 / nelts); - fprintf (stderr, "slots\t\t%lu\n", - (unsigned long) table->nslots); - fprintf (stderr, "bytes\t\t%lu%c (%lu%c overhead)\n", - SCALE (total_bytes), LABEL (total_bytes), - SCALE (overhead), LABEL (overhead)); - fprintf (stderr, "table size\t%lu%c\n", - SCALE (headers), LABEL (headers)); - - exp_len = (double)total_bytes / (double)nelts; - exp2_len = exp_len * exp_len; - exp_len2 = (double) sum_of_squares / (double) nelts; - - fprintf (stderr, "coll/search\t%.4f\n", - (double) table->collisions / (double) table->searches); - fprintf (stderr, "ins/search\t%.4f\n", - (double) nelts / (double) table->searches); - fprintf (stderr, "avg. entry\t%.2f bytes (+/- %.2f)\n", - exp_len, approx_sqrt (exp_len2 - exp2_len)); - fprintf (stderr, "longest entry\t%lu\n", - (unsigned long) longest); -#undef SCALE -#undef LABEL -} - -/* Return the approximate positive square root of a number N. This is for - statistical reports, not code generation. */ -static double -approx_sqrt (double x) -{ - double s, d; - - if (x < 0) - abort (); - if (x == 0) - return 0; - - s = x; - do - { - d = (s * s - x) / (2 * s); - s -= d; - } - while (d > .0001); - return s; -} diff --git a/support/cpp2/hashtable.h b/support/cpp2/hashtable.h deleted file mode 100644 index 068341c0..00000000 --- a/support/cpp2/hashtable.h +++ /dev/null @@ -1,85 +0,0 @@ -/* Hash tables. - Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc. - -This program 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 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#ifndef GCC_HASHTABLE_H -#define GCC_HASHTABLE_H - -#if defined(__APPLE__) && defined(__MACH__) -#include "libiberty/obstack.h" -#else -#include "obstack.h" -#endif -#define GTY(x) /* nothing */ - -/* This is what each hash table entry points to. It may be embedded - deeply within another object. */ -typedef struct ht_identifier ht_identifier; -struct ht_identifier GTY(()) -{ - const unsigned char *str; - unsigned int len; - unsigned int hash_value; -}; - -#define HT_LEN(NODE) ((NODE)->len) -#define HT_STR(NODE) ((NODE)->str) - -typedef struct ht hash_table; -typedef struct ht_identifier *hashnode; - -enum ht_lookup_option {HT_NO_INSERT = 0, HT_ALLOC, HT_ALLOCED}; - -/* An identifier hash table for cpplib and the front ends. */ -struct ht -{ - /* Identifiers are allocated from here. */ - struct obstack stack; - - hashnode *entries; - /* Call back. */ - hashnode (*alloc_node) (hash_table *); - - unsigned int nslots; /* Total slots in the entries array. */ - unsigned int nelements; /* Number of live elements. */ - - /* Link to reader, if any. For the benefit of cpplib. */ - struct cpp_reader *pfile; - - /* Table usage statistics. */ - unsigned int searches; - unsigned int collisions; -}; - -/* Initialize the hashtable with 2 ^ order entries. */ -extern hash_table *ht_create (unsigned int order); - -/* Frees all memory associated with a hash table. */ -extern void ht_destroy (hash_table *); - -extern hashnode ht_lookup (hash_table *, const unsigned char *, - size_t, enum ht_lookup_option); - -/* For all nodes in TABLE, make a callback. The callback takes - TABLE->PFILE, the node, and a PTR, and the callback sequence stops - if the callback returns zero. */ -typedef int (*ht_cb) (struct cpp_reader *, hashnode, const void *); -extern void ht_forall (hash_table *, ht_cb, const void *); - -/* Dump allocation statistics to stderr. */ -extern void ht_dump_statistics (hash_table *); - -#endif /* GCC_HASHTABLE_H */ diff --git a/support/cpp2/hwint.h b/support/cpp2/hwint.h index 4fed004c..9b28a3ad 100644 --- a/support/cpp2/hwint.h +++ b/support/cpp2/hwint.h @@ -1,5 +1,5 @@ /* HOST_WIDE_INT definitions for the GNU compiler. - Copyright (C) 1998, 2002 Free Software Foundation, Inc. + Copyright (C) 1998, 2002, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -15,6 +15,12 @@ #define HOST_BITS_PER_INT (CHAR_BIT * SIZEOF_INT) #define HOST_BITS_PER_LONG (CHAR_BIT * SIZEOF_LONG) +/* The string that should be inserted into a printf style format to + indicate a "long long" operand. */ +#ifndef HOST_LONG_LONG_FORMAT +#define HOST_LONG_LONG_FORMAT "ll" +#endif + /* If HAVE_LONG_LONG and SIZEOF_LONG_LONG aren't defined, but GCC_VERSION >= 3000, assume this is the second or later stage of a bootstrap, we do have long long, and it's 64 bits. (This is @@ -74,10 +80,11 @@ extern char sizeof_long_long_must_be_8[sizeof(long long) == 8 ? 1 : -1]; # define HOST_WIDE_INT_PRINT_DOUBLE_HEX "0x%lx%08lx" # endif #else -# define HOST_WIDE_INT_PRINT "ll" +# define HOST_WIDE_INT_PRINT HOST_LONG_LONG_FORMAT # define HOST_WIDE_INT_PRINT_C "LL" /* We can assume that 'long long' is at least 64 bits. */ -# define HOST_WIDE_INT_PRINT_DOUBLE_HEX "0x%llx%016llx" +# define HOST_WIDE_INT_PRINT_DOUBLE_HEX \ + "0x%" HOST_LONG_LONG_FORMAT "x%016" HOST_LONG_LONG_FORMAT "x" #endif /* HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG */ #define HOST_WIDE_INT_PRINT_DEC "%" HOST_WIDE_INT_PRINT "d" @@ -109,11 +116,35 @@ extern char sizeof_long_long_must_be_8[sizeof(long long) == 8 ? 1 : -1]; #error "This line should be impossible to reach" # endif # endif -# define HOST_WIDEST_INT_PRINT_DEC "%lld" -# define HOST_WIDEST_INT_PRINT_DEC_C "%lldLL" -# define HOST_WIDEST_INT_PRINT_UNSIGNED "%llu" -# define HOST_WIDEST_INT_PRINT_HEX "0x%llx" -# define HOST_WIDEST_INT_PRINT_DOUBLE_HEX "0x%llx%016llx" +# define HOST_WIDEST_INT_PRINT_DEC "%" HOST_LONG_LONG_FORMAT "d" +# define HOST_WIDEST_INT_PRINT_DEC_C "%" HOST_LONG_LONG_FORMAT "dLL" +# define HOST_WIDEST_INT_PRINT_UNSIGNED "%" HOST_LONG_LONG_FORMAT "u" +# define HOST_WIDEST_INT_PRINT_HEX "0x%" HOST_LONG_LONG_FORMAT "x" +# define HOST_WIDEST_INT_PRINT_DOUBLE_HEX \ + "0x%" HOST_LONG_LONG_FORMAT "x%016" HOST_LONG_LONG_FORMAT "x" +#endif + +/* Define HOST_WIDEST_FAST_INT to the widest integer type supported + efficiently in hardware. (That is, the widest integer type that fits + in a hardware register.) Normally this is "long" but on some hosts it + should be "long long" or "__int64". This is no convenient way to + autodect this, so such systems must set a flag in config.host; see there + for details. */ + +#ifdef USE_LONG_LONG_FOR_WIDEST_FAST_INT +# ifdef HAVE_LONG_LONG +# define HOST_WIDEST_FAST_INT long long +# define HOST_BITS_PER_WIDEST_FAST_INT HOST_BITS_PER_LONGLONG +# elif defined (HAVE___INT64) +# define HOST_WIDEST_FAST_INT __int64 +# define HOST_BITS_PER_WIDEST_FAST_INT HOST_BITS_PER___INT64 +# else +# error "Your host said it wantted to use long long or __int64 but neither" +# error "exist" +# endif +#else +# define HOST_WIDEST_FAST_INT long +# define HOST_BITS_PER_WIDEST_FAST_INT HOST_BITS_PER_LONG #endif #endif /* ! GCC_HWINT_H */ diff --git a/support/cpp2/input.h b/support/cpp2/input.h index ff014f6d..0ca3ccfd 100644 --- a/support/cpp2/input.h +++ b/support/cpp2/input.h @@ -1,6 +1,6 @@ /* Declarations for variables relating to reading the source file. Used by parsers, lexical analyzers, and error message routines. - Copyright (C) 1993, 1997, 1998, 2000, 2003 Free Software Foundation, Inc. + Copyright (C) 1993, 1997, 1998, 2000, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -16,15 +16,40 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ #ifndef GCC_INPUT_H #define GCC_INPUT_H -/* The data structure used to record a location in a translation unit. */ -/* Long-term, we want to get rid of this and typedef fileline location_t. */ -struct location_s GTY (()) +#include "line-map.h" +extern struct line_maps line_table; + +/* The location for declarations in "" */ +#define BUILTINS_LOCATION ((source_location) 2) + +#ifdef USE_MAPPED_LOCATION + +typedef struct +{ + /* The name of the source file involved. */ + const char *file; + + /* The line-location in the source file. */ + int line; + + int column; +} expanded_location; + +extern expanded_location expand_location (source_location); + +#define UNKNOWN_LOCATION ((source_location) 0) +typedef source_location location_t; /* deprecated typedef */ +typedef source_location source_locus; /* to be removed */ + +#else /* ! USE_MAPPED_LOCATION */ + +struct location_s GTY(()) { /* The name of the source file involved. */ const char *file; @@ -32,7 +57,16 @@ struct location_s GTY (()) /* The line-location in the source file. */ int line; }; + +typedef struct location_s expanded_location; typedef struct location_s location_t; +typedef location_t *source_locus; + +#define expand_location(FILELINE) (FILELINE) +extern location_t unknown_location; +#define UNKNOWN_LOCATION unknown_location + +#endif /* ! USE_MAPPED_LOCATION */ struct file_stack { @@ -44,20 +78,24 @@ struct file_stack extern const char *main_input_filename; extern location_t input_location; -#define input_line (input_location.line) -#define input_filename (input_location.file) +#ifdef USE_MAPPED_LOCATION +extern void push_srcloc (location_t); +#else /* ! USE_MAPPED_LOCATION */ +extern void push_srcloc (const char *name, int line); +#endif /* ! USE_MAPPED_LOCATION */ +extern void pop_srcloc (void); + +#define LOCATION_FILE(LOC) ((expand_location (LOC)).file) +#define LOCATION_LINE(LOC) ((expand_location (LOC)).line) + +#define input_line LOCATION_LINE(input_location) +#define input_filename LOCATION_FILE(input_location) /* Stack of currently pending input files. The line member is not accurate for the innermost file on the stack. */ extern struct file_stack *input_file_stack; -/* Stack of EXPR_WITH_FILE_LOCATION nested expressions. */ -extern struct file_stack *expr_wfl_stack; - /* Incremented on each change to input_file_stack. */ extern int input_file_stack_tick; -extern void push_srcloc (const char *name, int line); -extern void pop_srcloc (void); - #endif diff --git a/support/cpp2/intl.h b/support/cpp2/intl.h index 80a945b4..a118c0a9 100644 --- a/support/cpp2/intl.h +++ b/support/cpp2/intl.h @@ -1,5 +1,5 @@ /* intl.h - internationalization - Copyright 1998, 2001, 2003 Free Software Foundation, Inc. + Copyright 1998, 2001, 2003, 2004 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,8 +13,8 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free - Software Foundation, 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ + Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ #ifndef GCC_INTL_H #define GCC_INTL_H @@ -51,4 +51,11 @@ extern size_t gcc_gettext_width (const char *); # define N_(msgid) msgid #endif +#ifndef G_ +# define G_(gmsgid) gmsgid +#endif + +extern const char *open_quote; +extern const char *close_quote; + #endif /* intl.h */ diff --git a/support/cpp2/libcpp/charset.c b/support/cpp2/libcpp/charset.c new file mode 100644 index 00000000..78c89816 --- /dev/null +++ b/support/cpp2/libcpp/charset.c @@ -0,0 +1,1672 @@ +/* CPP Library - charsets + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 + Free Software Foundation, Inc. + + Broken out of c-lex.c Apr 2003, adding valid C99 UCN ranges. + +This program 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 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "config.h" +#include "system.h" +#include "cpplib.h" +#include "internal.h" + +/* Character set handling for C-family languages. + + Terminological note: In what follows, "charset" or "character set" + will be taken to mean both an abstract set of characters and an + encoding for that set. + + The C99 standard discusses two character sets: source and execution. + The source character set is used for internal processing in translation + phases 1 through 4; the execution character set is used thereafter. + Both are required by 5.2.1.2p1 to be multibyte encodings, not wide + character encodings (see 3.7.2, 3.7.3 for the standardese meanings + of these terms). Furthermore, the "basic character set" (listed in + 5.2.1p3) is to be encoded in each with values one byte wide, and is + to appear in the initial shift state. + + It is not explicitly mentioned, but there is also a "wide execution + character set" used to encode wide character constants and wide + string literals; this is supposed to be the result of applying the + standard library function mbstowcs() to an equivalent narrow string + (6.4.5p5). However, the behavior of hexadecimal and octal + \-escapes is at odds with this; they are supposed to be translated + directly to wchar_t values (6.4.4.4p5,6). + + The source character set is not necessarily the character set used + to encode physical source files on disk; translation phase 1 converts + from whatever that encoding is to the source character set. + + The presence of universal character names in C99 (6.4.3 et seq.) + forces the source character set to be isomorphic to ISO 10646, + that is, Unicode. There is no such constraint on the execution + character set; note also that the conversion from source to + execution character set does not occur for identifiers (5.1.1.2p1#5). + + For convenience of implementation, the source character set's + encoding of the basic character set should be identical to the + execution character set OF THE HOST SYSTEM's encoding of the basic + character set, and it should not be a state-dependent encoding. + + cpplib uses UTF-8 or UTF-EBCDIC for the source character set, + depending on whether the host is based on ASCII or EBCDIC (see + respectively Unicode section 2.3/ISO10646 Amendment 2, and Unicode + Technical Report #16). With limited exceptions, it relies on the + system library's iconv() primitive to do charset conversion + (specified in SUSv2). */ + +#if !HAVE_ICONV +/* Make certain that the uses of iconv(), iconv_open(), iconv_close() + below, which are guarded only by if statements with compile-time + constant conditions, do not cause link errors. */ +#define iconv_open(x, y) (errno = EINVAL, (iconv_t)-1) +#define iconv(a,b,c,d,e) (errno = EINVAL, (size_t)-1) +#define iconv_close(x) (void)0 +#define ICONV_CONST +#endif + +#if HOST_CHARSET == HOST_CHARSET_ASCII +#define SOURCE_CHARSET "UTF-8" +#define LAST_POSSIBLY_BASIC_SOURCE_CHAR 0x7e +#elif HOST_CHARSET == HOST_CHARSET_EBCDIC +#define SOURCE_CHARSET "UTF-EBCDIC" +#define LAST_POSSIBLY_BASIC_SOURCE_CHAR 0xFF +#else +#error "Unrecognized basic host character set" +#endif + +#ifndef EILSEQ +#define EILSEQ EINVAL +#endif + +/* This structure is used for a resizable string buffer throughout. */ +/* Don't call it strbuf, as that conflicts with unistd.h on systems + such as DYNIX/ptx where unistd.h includes stropts.h. */ +struct _cpp_strbuf +{ + uchar *text; + size_t asize; + size_t len; +}; + +/* This is enough to hold any string that fits on a single 80-column + line, even if iconv quadruples its size (e.g. conversion from + ASCII to UTF-32) rounded up to a power of two. */ +#define OUTBUF_BLOCK_SIZE 256 + +/* Conversions between UTF-8 and UTF-16/32 are implemented by custom + logic. This is because a depressing number of systems lack iconv, + or have have iconv libraries that do not do these conversions, so + we need a fallback implementation for them. To ensure the fallback + doesn't break due to neglect, it is used on all systems. + + UTF-32 encoding is nice and simple: a four-byte binary number, + constrained to the range 00000000-7FFFFFFF to avoid questions of + signedness. We do have to cope with big- and little-endian + variants. + + UTF-16 encoding uses two-byte binary numbers, again in big- and + little-endian variants, for all values in the 00000000-0000FFFF + range. Values in the 00010000-0010FFFF range are encoded as pairs + of two-byte numbers, called "surrogate pairs": given a number S in + this range, it is mapped to a pair (H, L) as follows: + + H = (S - 0x10000) / 0x400 + 0xD800 + L = (S - 0x10000) % 0x400 + 0xDC00 + + Two-byte values in the D800...DFFF range are ill-formed except as a + component of a surrogate pair. Even if the encoding within a + two-byte value is little-endian, the H member of the surrogate pair + comes first. + + There is no way to encode values in the 00110000-7FFFFFFF range, + which is not currently a problem as there are no assigned code + points in that range; however, the author expects that it will + eventually become necessary to abandon UTF-16 due to this + limitation. Note also that, because of these pairs, UTF-16 does + not meet the requirements of the C standard for a wide character + encoding (see 3.7.3 and 6.4.4.4p11). + + UTF-8 encoding looks like this: + + value range encoded as + 00000000-0000007F 0xxxxxxx + 00000080-000007FF 110xxxxx 10xxxxxx + 00000800-0000FFFF 1110xxxx 10xxxxxx 10xxxxxx + 00010000-001FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + 00200000-03FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + 04000000-7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + + Values in the 0000D800 ... 0000DFFF range (surrogates) are invalid, + which means that three-byte sequences ED xx yy, with A0 <= xx <= BF, + never occur. Note also that any value that can be encoded by a + given row of the table can also be encoded by all successive rows, + but this is not done; only the shortest possible encoding for any + given value is valid. For instance, the character 07C0 could be + encoded as any of DF 80, E0 9F 80, F0 80 9F 80, F8 80 80 9F 80, or + FC 80 80 80 9F 80. Only the first is valid. + + An implementation note: the transformation from UTF-16 to UTF-8, or + vice versa, is easiest done by using UTF-32 as an intermediary. */ + +/* Internal primitives which go from an UTF-8 byte stream to native-endian + UTF-32 in a cppchar_t, or vice versa; this avoids an extra marshal/unmarshal + operation in several places below. */ +static inline int +one_utf8_to_cppchar (const uchar **inbufp, size_t *inbytesleftp, + cppchar_t *cp) +{ + static const uchar masks[6] = { 0x7F, 0x1F, 0x0F, 0x07, 0x02, 0x01 }; + static const uchar patns[6] = { 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + + cppchar_t c; + const uchar *inbuf = *inbufp; + size_t nbytes, i; + + if (*inbytesleftp < 1) + return EINVAL; + + c = *inbuf; + if (c < 0x80) + { + *cp = c; + *inbytesleftp -= 1; + *inbufp += 1; + return 0; + } + + /* The number of leading 1-bits in the first byte indicates how many + bytes follow. */ + for (nbytes = 2; nbytes < 7; nbytes++) + if ((c & ~masks[nbytes-1]) == patns[nbytes-1]) + goto found; + return EILSEQ; + found: + + if (*inbytesleftp < nbytes) + return EINVAL; + + c = (c & masks[nbytes-1]); + inbuf++; + for (i = 1; i < nbytes; i++) + { + cppchar_t n = *inbuf++; + if ((n & 0xC0) != 0x80) + return EILSEQ; + c = ((c << 6) + (n & 0x3F)); + } + + /* Make sure the shortest possible encoding was used. */ + if (c <= 0x7F && nbytes > 1) return EILSEQ; + if (c <= 0x7FF && nbytes > 2) return EILSEQ; + if (c <= 0xFFFF && nbytes > 3) return EILSEQ; + if (c <= 0x1FFFFF && nbytes > 4) return EILSEQ; + if (c <= 0x3FFFFFF && nbytes > 5) return EILSEQ; + + /* Make sure the character is valid. */ + if (c > 0x7FFFFFFF || (c >= 0xD800 && c <= 0xDFFF)) return EILSEQ; + + *cp = c; + *inbufp = inbuf; + *inbytesleftp -= nbytes; + return 0; +} + +static inline int +one_cppchar_to_utf8 (cppchar_t c, uchar **outbufp, size_t *outbytesleftp) +{ + static const uchar masks[6] = { 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + static const uchar limits[6] = { 0x80, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE }; + size_t nbytes; + uchar buf[6], *p = &buf[6]; + uchar *outbuf = *outbufp; + + nbytes = 1; + if (c < 0x80) + *--p = c; + else + { + do + { + *--p = ((c & 0x3F) | 0x80); + c >>= 6; + nbytes++; + } + while (c >= 0x3F || (c & limits[nbytes-1])); + *--p = (c | masks[nbytes-1]); + } + + if (*outbytesleftp < nbytes) + return E2BIG; + + while (p < &buf[6]) + *outbuf++ = *p++; + *outbytesleftp -= nbytes; + *outbufp = outbuf; + return 0; +} + +/* The following four functions transform one character between the two + encodings named in the function name. All have the signature + int (*)(iconv_t bigend, const uchar **inbufp, size_t *inbytesleftp, + uchar **outbufp, size_t *outbytesleftp) + + BIGEND must have the value 0 or 1, coerced to (iconv_t); it is + interpreted as a boolean indicating whether big-endian or + little-endian encoding is to be used for the member of the pair + that is not UTF-8. + + INBUFP, INBYTESLEFTP, OUTBUFP, OUTBYTESLEFTP work exactly as they + do for iconv. + + The return value is either 0 for success, or an errno value for + failure, which may be E2BIG (need more space), EILSEQ (ill-formed + input sequence), ir EINVAL (incomplete input sequence). */ + +static inline int +one_utf8_to_utf32 (iconv_t bigend, const uchar **inbufp, size_t *inbytesleftp, + uchar **outbufp, size_t *outbytesleftp) +{ + uchar *outbuf; + cppchar_t s = 0; + int rval; + + /* Check for space first, since we know exactly how much we need. */ + if (*outbytesleftp < 4) + return E2BIG; + + rval = one_utf8_to_cppchar (inbufp, inbytesleftp, &s); + if (rval) + return rval; + + outbuf = *outbufp; + outbuf[bigend ? 3 : 0] = (s & 0x000000FF); + outbuf[bigend ? 2 : 1] = (s & 0x0000FF00) >> 8; + outbuf[bigend ? 1 : 2] = (s & 0x00FF0000) >> 16; + outbuf[bigend ? 0 : 3] = (s & 0xFF000000) >> 24; + + *outbufp += 4; + *outbytesleftp -= 4; + return 0; +} + +static inline int +one_utf32_to_utf8 (iconv_t bigend, const uchar **inbufp, size_t *inbytesleftp, + uchar **outbufp, size_t *outbytesleftp) +{ + cppchar_t s; + int rval; + const uchar *inbuf; + + if (*inbytesleftp < 4) + return EINVAL; + + inbuf = *inbufp; + + s = inbuf[bigend ? 0 : 3] << 24; + s += inbuf[bigend ? 1 : 2] << 16; + s += inbuf[bigend ? 2 : 1] << 8; + s += inbuf[bigend ? 3 : 0]; + + if (s >= 0x7FFFFFFF || (s >= 0xD800 && s <= 0xDFFF)) + return EILSEQ; + + rval = one_cppchar_to_utf8 (s, outbufp, outbytesleftp); + if (rval) + return rval; + + *inbufp += 4; + *inbytesleftp -= 4; + return 0; +} + +static inline int +one_utf8_to_utf16 (iconv_t bigend, const uchar **inbufp, size_t *inbytesleftp, + uchar **outbufp, size_t *outbytesleftp) +{ + int rval; + cppchar_t s = 0; + const uchar *save_inbuf = *inbufp; + size_t save_inbytesleft = *inbytesleftp; + uchar *outbuf = *outbufp; + + rval = one_utf8_to_cppchar (inbufp, inbytesleftp, &s); + if (rval) + return rval; + + if (s > 0x0010FFFF) + { + *inbufp = save_inbuf; + *inbytesleftp = save_inbytesleft; + return EILSEQ; + } + + if (s < 0xFFFF) + { + if (*outbytesleftp < 2) + { + *inbufp = save_inbuf; + *inbytesleftp = save_inbytesleft; + return E2BIG; + } + outbuf[bigend ? 1 : 0] = (s & 0x00FF); + outbuf[bigend ? 0 : 1] = (s & 0xFF00) >> 8; + + *outbufp += 2; + *outbytesleftp -= 2; + return 0; + } + else + { + cppchar_t hi, lo; + + if (*outbytesleftp < 4) + { + *inbufp = save_inbuf; + *inbytesleftp = save_inbytesleft; + return E2BIG; + } + + hi = (s - 0x10000) / 0x400 + 0xD800; + lo = (s - 0x10000) % 0x400 + 0xDC00; + + /* Even if we are little-endian, put the high surrogate first. + ??? Matches practice? */ + outbuf[bigend ? 1 : 0] = (hi & 0x00FF); + outbuf[bigend ? 0 : 1] = (hi & 0xFF00) >> 8; + outbuf[bigend ? 3 : 2] = (lo & 0x00FF); + outbuf[bigend ? 2 : 3] = (lo & 0xFF00) >> 8; + + *outbufp += 4; + *outbytesleftp -= 4; + return 0; + } +} + +static inline int +one_utf16_to_utf8 (iconv_t bigend, const uchar **inbufp, size_t *inbytesleftp, + uchar **outbufp, size_t *outbytesleftp) +{ + cppchar_t s; + const uchar *inbuf = *inbufp; + int rval; + + if (*inbytesleftp < 2) + return EINVAL; + s = inbuf[bigend ? 0 : 1] << 8; + s += inbuf[bigend ? 1 : 0]; + + /* Low surrogate without immediately preceding high surrogate is invalid. */ + if (s >= 0xDC00 && s <= 0xDFFF) + return EILSEQ; + /* High surrogate must have a following low surrogate. */ + else if (s >= 0xD800 && s <= 0xDBFF) + { + cppchar_t hi = s, lo; + if (*inbytesleftp < 4) + return EINVAL; + + lo = inbuf[bigend ? 2 : 3] << 8; + lo += inbuf[bigend ? 3 : 2]; + + if (lo < 0xDC00 || lo > 0xDFFF) + return EILSEQ; + + s = (hi - 0xD800) * 0x400 + (lo - 0xDC00) + 0x10000; + } + + rval = one_cppchar_to_utf8 (s, outbufp, outbytesleftp); + if (rval) + return rval; + + /* Success - update the input pointers (one_cppchar_to_utf8 has done + the output pointers for us). */ + if (s <= 0xFFFF) + { + *inbufp += 2; + *inbytesleftp -= 2; + } + else + { + *inbufp += 4; + *inbytesleftp -= 4; + } + return 0; +} + +/* Helper routine for the next few functions. The 'const' on + one_conversion means that we promise not to modify what function is + pointed to, which lets the inliner see through it. */ + +static inline bool +conversion_loop (int (*const one_conversion)(iconv_t, const uchar **, size_t *, + uchar **, size_t *), + iconv_t cd, const uchar *from, size_t flen, struct _cpp_strbuf *to) +{ + const uchar *inbuf; + uchar *outbuf; + size_t inbytesleft, outbytesleft; + int rval; + + inbuf = from; + inbytesleft = flen; + outbuf = to->text + to->len; + outbytesleft = to->asize - to->len; + + for (;;) + { + do + rval = one_conversion (cd, &inbuf, &inbytesleft, + &outbuf, &outbytesleft); + while (inbytesleft && !rval); + + if (__builtin_expect (inbytesleft == 0, 1)) + { + to->len = to->asize - outbytesleft; + return true; + } + if (rval != E2BIG) + { + errno = rval; + return false; + } + + outbytesleft += OUTBUF_BLOCK_SIZE; + to->asize += OUTBUF_BLOCK_SIZE; + to->text = XRESIZEVEC (uchar, to->text, to->asize); + outbuf = to->text + to->asize - outbytesleft; + } +} + + +/* These functions convert entire strings between character sets. + They all have the signature + + bool (*)(iconv_t cd, const uchar *from, size_t flen, struct _cpp_strbuf *to); + + The input string FROM is converted as specified by the function + name plus the iconv descriptor CD (which may be fake), and the + result appended to TO. On any error, false is returned, otherwise true. */ + +/* These four use the custom conversion code above. */ +static bool +convert_utf8_utf16 (iconv_t cd, const uchar *from, size_t flen, + struct _cpp_strbuf *to) +{ + return conversion_loop (one_utf8_to_utf16, cd, from, flen, to); +} + +static bool +convert_utf8_utf32 (iconv_t cd, const uchar *from, size_t flen, + struct _cpp_strbuf *to) +{ + return conversion_loop (one_utf8_to_utf32, cd, from, flen, to); +} + +static bool +convert_utf16_utf8 (iconv_t cd, const uchar *from, size_t flen, + struct _cpp_strbuf *to) +{ + return conversion_loop (one_utf16_to_utf8, cd, from, flen, to); +} + +static bool +convert_utf32_utf8 (iconv_t cd, const uchar *from, size_t flen, + struct _cpp_strbuf *to) +{ + return conversion_loop (one_utf32_to_utf8, cd, from, flen, to); +} + +/* Identity conversion, used when we have no alternative. */ +static bool +convert_no_conversion (iconv_t cd ATTRIBUTE_UNUSED, + const uchar *from, size_t flen, struct _cpp_strbuf *to) +{ + if (to->len + flen > to->asize) + { + to->asize = to->len + flen; + to->text = XRESIZEVEC (uchar, to->text, to->asize); + } + memcpy (to->text + to->len, from, flen); + to->len += flen; + return true; +} + +/* And this one uses the system iconv primitive. It's a little + different, since iconv's interface is a little different. */ +#if HAVE_ICONV +static bool +convert_using_iconv (iconv_t cd, const uchar *from, size_t flen, + struct _cpp_strbuf *to) +{ + ICONV_CONST char *inbuf; + char *outbuf; + size_t inbytesleft, outbytesleft; + + /* Reset conversion descriptor and check that it is valid. */ + if (iconv (cd, 0, 0, 0, 0) == (size_t)-1) + return false; + + inbuf = (ICONV_CONST char *)from; + inbytesleft = flen; + outbuf = (char *)to->text + to->len; + outbytesleft = to->asize - to->len; + + for (;;) + { + iconv (cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); + if (__builtin_expect (inbytesleft == 0, 1)) + { + to->len = to->asize - outbytesleft; + return true; + } + if (errno != E2BIG) + return false; + + outbytesleft += OUTBUF_BLOCK_SIZE; + to->asize += OUTBUF_BLOCK_SIZE; + to->text = XRESIZEVEC (uchar, to->text, to->asize); + outbuf = (char *)to->text + to->asize - outbytesleft; + } +} +#else +#define convert_using_iconv 0 /* prevent undefined symbol error below */ +#endif + +/* Arrange for the above custom conversion logic to be used automatically + when conversion between a suitable pair of character sets is requested. */ + +#define APPLY_CONVERSION(CONVERTER, FROM, FLEN, TO) \ + CONVERTER.func (CONVERTER.cd, FROM, FLEN, TO) + +struct conversion +{ + const char *pair; + convert_f func; + iconv_t fake_cd; +}; +static const struct conversion conversion_tab[] = { + { "UTF-8/UTF-32LE", convert_utf8_utf32, (iconv_t)0 }, + { "UTF-8/UTF-32BE", convert_utf8_utf32, (iconv_t)1 }, + { "UTF-8/UTF-16LE", convert_utf8_utf16, (iconv_t)0 }, + { "UTF-8/UTF-16BE", convert_utf8_utf16, (iconv_t)1 }, + { "UTF-32LE/UTF-8", convert_utf32_utf8, (iconv_t)0 }, + { "UTF-32BE/UTF-8", convert_utf32_utf8, (iconv_t)1 }, + { "UTF-16LE/UTF-8", convert_utf16_utf8, (iconv_t)0 }, + { "UTF-16BE/UTF-8", convert_utf16_utf8, (iconv_t)1 }, +}; + +/* Subroutine of cpp_init_iconv: initialize and return a + cset_converter structure for conversion from FROM to TO. If + iconv_open() fails, issue an error and return an identity + converter. Silently return an identity converter if FROM and TO + are identical. */ +static struct cset_converter +init_iconv_desc (cpp_reader *pfile, const char *to, const char *from) +{ + struct cset_converter ret; + char *pair; + size_t i; + + if (!strcasecmp (to, from)) + { + ret.func = convert_no_conversion; + ret.cd = (iconv_t) -1; + return ret; + } + + pair = (char *) alloca(strlen(to) + strlen(from) + 2); + + strcpy(pair, from); + strcat(pair, "/"); + strcat(pair, to); + for (i = 0; i < ARRAY_SIZE (conversion_tab); i++) + if (!strcasecmp (pair, conversion_tab[i].pair)) + { + ret.func = conversion_tab[i].func; + ret.cd = conversion_tab[i].fake_cd; + return ret; + } + + /* No custom converter - try iconv. */ + if (HAVE_ICONV) + { + ret.func = convert_using_iconv; + ret.cd = iconv_open (to, from); + + if (ret.cd == (iconv_t) -1) + { + if (errno == EINVAL) + cpp_error (pfile, CPP_DL_ERROR, /* FIXME should be DL_SORRY */ + "conversion from %s to %s not supported by iconv", + from, to); + else + cpp_errno (pfile, CPP_DL_ERROR, "iconv_open"); + + ret.func = convert_no_conversion; + } + } + else + { + cpp_error (pfile, CPP_DL_ERROR, /* FIXME: should be DL_SORRY */ + "no iconv implementation, cannot convert from %s to %s", + from, to); + ret.func = convert_no_conversion; + ret.cd = (iconv_t) -1; + } + return ret; +} + +/* If charset conversion is requested, initialize iconv(3) descriptors + for conversion from the source character set to the execution + character sets. If iconv is not present in the C library, and + conversion is requested, issue an error. */ + +void +cpp_init_iconv (cpp_reader *pfile) +{ + const char *ncset = CPP_OPTION (pfile, narrow_charset); + const char *wcset = CPP_OPTION (pfile, wide_charset); + const char *default_wcset; + + bool be = CPP_OPTION (pfile, bytes_big_endian); + + if (CPP_OPTION (pfile, wchar_precision) >= 32) + default_wcset = be ? "UTF-32BE" : "UTF-32LE"; + else if (CPP_OPTION (pfile, wchar_precision) >= 16) + default_wcset = be ? "UTF-16BE" : "UTF-16LE"; + else + /* This effectively means that wide strings are not supported, + so don't do any conversion at all. */ + default_wcset = SOURCE_CHARSET; + + if (!ncset) + ncset = SOURCE_CHARSET; + if (!wcset) + wcset = default_wcset; + + pfile->narrow_cset_desc = init_iconv_desc (pfile, ncset, SOURCE_CHARSET); + pfile->wide_cset_desc = init_iconv_desc (pfile, wcset, SOURCE_CHARSET); +} + +/* Destroy iconv(3) descriptors set up by cpp_init_iconv, if necessary. */ +void +_cpp_destroy_iconv (cpp_reader *pfile) +{ + if (HAVE_ICONV) + { + if (pfile->narrow_cset_desc.func == convert_using_iconv) + iconv_close (pfile->narrow_cset_desc.cd); + if (pfile->wide_cset_desc.func == convert_using_iconv) + iconv_close (pfile->wide_cset_desc.cd); + } +} + +/* Utility routine for use by a full compiler. C is a character taken + from the *basic* source character set, encoded in the host's + execution encoding. Convert it to (the target's) execution + encoding, and return that value. + + Issues an internal error if C's representation in the narrow + execution character set fails to be a single-byte value (C99 + 5.2.1p3: "The representation of each member of the source and + execution character sets shall fit in a byte.") May also issue an + internal error if C fails to be a member of the basic source + character set (testing this exactly is too hard, especially when + the host character set is EBCDIC). */ +cppchar_t +cpp_host_to_exec_charset (cpp_reader *pfile, cppchar_t c) +{ + uchar sbuf[1]; + struct _cpp_strbuf tbuf; + + /* This test is merely an approximation, but it suffices to catch + the most important thing, which is that we don't get handed a + character outside the unibyte range of the host character set. */ + if (c > LAST_POSSIBLY_BASIC_SOURCE_CHAR) + { + cpp_error (pfile, CPP_DL_ICE, + "character 0x%lx is not in the basic source character set\n", + (unsigned long)c); + return 0; + } + + /* Being a character in the unibyte range of the host character set, + we can safely splat it into a one-byte buffer and trust that that + is a well-formed string. */ + sbuf[0] = c; + + /* This should never need to reallocate, but just in case... */ + tbuf.asize = 1; + tbuf.text = XNEWVEC (uchar, tbuf.asize); + tbuf.len = 0; + + if (!APPLY_CONVERSION (pfile->narrow_cset_desc, sbuf, 1, &tbuf)) + { + cpp_errno (pfile, CPP_DL_ICE, "converting to execution character set"); + return 0; + } + if (tbuf.len != 1) + { + cpp_error (pfile, CPP_DL_ICE, + "character 0x%lx is not unibyte in execution character set", + (unsigned long)c); + return 0; + } + c = tbuf.text[0]; + free(tbuf.text); + return c; +} + + + +/* Utility routine that computes a mask of the form 0000...111... with + WIDTH 1-bits. */ +static inline size_t +width_to_mask (size_t width) +{ + width = MIN (width, BITS_PER_CPPCHAR_T); + if (width >= CHAR_BIT * sizeof (size_t)) + return ~(size_t) 0; + else + return ((size_t) 1 << width) - 1; +} + +/* A large table of unicode character information. */ +enum { + /* Valid in a C99 identifier? */ + C99 = 1, + /* Valid in a C99 identifier, but not as the first character? */ + DIG = 2, + /* Valid in a C++ identifier? */ + CXX = 4, + /* NFC representation is not valid in an identifier? */ + CID = 8, + /* Might be valid NFC form? */ + NFC = 16, + /* Might be valid NFKC form? */ + NKC = 32, + /* Certain preceding characters might make it not valid NFC/NKFC form? */ + CTX = 64 +}; + +static const struct { + /* Bitmap of flags above. */ + unsigned char flags; + /* Combining class of the character. */ + unsigned char combine; + /* Last character in the range described by this entry. */ + unsigned short end; +} ucnranges[] = { +#include "ucnid.h" +}; + +/* Returns 1 if C is valid in an identifier, 2 if C is valid except at + the start of an identifier, and 0 if C is not valid in an + identifier. We assume C has already gone through the checks of + _cpp_valid_ucn. Also update NST for C if returning nonzero. The + algorithm is a simple binary search on the table defined in + ucnid.h. */ + +static int +ucn_valid_in_identifier (cpp_reader *pfile, cppchar_t c, + struct normalize_state *nst) +{ + int mn, mx, md; + + if (c > 0xFFFF) + return 0; + + mn = 0; + mx = ARRAY_SIZE (ucnranges) - 1; + while (mx != mn) + { + md = (mn + mx) / 2; + if (c <= ucnranges[md].end) + mx = md; + else + mn = md + 1; + } + + /* When -pedantic, we require the character to have been listed by + the standard for the current language. Otherwise, we accept the + union of the acceptable sets for C++98 and C99. */ + if (! (ucnranges[mn].flags & (C99 | CXX))) + return 0; + + if (CPP_PEDANTIC (pfile) + && ((CPP_OPTION (pfile, c99) && !(ucnranges[mn].flags & C99)) + || (CPP_OPTION (pfile, cplusplus) + && !(ucnranges[mn].flags & CXX)))) + return 0; + + /* Update NST. */ + if (ucnranges[mn].combine != 0 && ucnranges[mn].combine < nst->prev_class) + nst->level = normalized_none; + else if (ucnranges[mn].flags & CTX) + { + bool safe; + cppchar_t p = nst->previous; + + /* Easy cases from Bengali, Oriya, Tamil, Jannada, and Malayalam. */ + if (c == 0x09BE) + safe = p != 0x09C7; /* Use 09CB instead of 09C7 09BE. */ + else if (c == 0x0B3E) + safe = p != 0x0B47; /* Use 0B4B instead of 0B47 0B3E. */ + else if (c == 0x0BBE) + safe = p != 0x0BC6 && p != 0x0BC7; /* Use 0BCA/0BCB instead. */ + else if (c == 0x0CC2) + safe = p != 0x0CC6; /* Use 0CCA instead of 0CC6 0CC2. */ + else if (c == 0x0D3E) + safe = p != 0x0D46 && p != 0x0D47; /* Use 0D4A/0D4B instead. */ + /* For Hangul, characters in the range AC00-D7A3 are NFC/NFKC, + and are combined algorithmically from a sequence of the form + 1100-1112 1161-1175 11A8-11C2 + (if the third is not present, it is treated as 11A7, which is not + really a valid character). + Unfortunately, C99 allows (only) the NFC form, but C++ allows + only the combining characters. */ + else if (c >= 0x1161 && c <= 0x1175) + safe = p < 0x1100 || p > 0x1112; + else if (c >= 0x11A8 && c <= 0x11C2) + safe = (p < 0xAC00 || p > 0xD7A3 || (p - 0xAC00) % 28 != 0); + else + { + /* Uh-oh, someone updated ucnid.h without updating this code. */ + cpp_error (pfile, CPP_DL_ICE, "Character %x might not be NFKC", c); + safe = true; + } + if (!safe && c < 0x1161) + nst->level = normalized_none; + else if (!safe) + nst->level = MAX (nst->level, normalized_identifier_C); + } + else if (ucnranges[mn].flags & NKC) + ; + else if (ucnranges[mn].flags & NFC) + nst->level = MAX (nst->level, normalized_C); + else if (ucnranges[mn].flags & CID) + nst->level = MAX (nst->level, normalized_identifier_C); + else + nst->level = normalized_none; + nst->previous = c; + nst->prev_class = ucnranges[mn].combine; + + /* In C99, UCN digits may not begin identifiers. */ + if (CPP_OPTION (pfile, c99) && (ucnranges[mn].flags & DIG)) + return 2; + + return 1; +} + +/* [lex.charset]: The character designated by the universal character + name \UNNNNNNNN is that character whose character short name in + ISO/IEC 10646 is NNNNNNNN; the character designated by the + universal character name \uNNNN is that character whose character + short name in ISO/IEC 10646 is 0000NNNN. If the hexadecimal value + for a universal character name is less than 0x20 or in the range + 0x7F-0x9F (inclusive), or if the universal character name + designates a character in the basic source character set, then the + program is ill-formed. + + *PSTR must be preceded by "\u" or "\U"; it is assumed that the + buffer end is delimited by a non-hex digit. Returns zero if the + UCN has not been consumed. + + Otherwise the nonzero value of the UCN, whether valid or invalid, + is returned. Diagnostics are emitted for invalid values. PSTR + is updated to point one beyond the UCN, or to the syntactically + invalid character. + + IDENTIFIER_POS is 0 when not in an identifier, 1 for the start of + an identifier, or 2 otherwise. */ + +cppchar_t +_cpp_valid_ucn (cpp_reader *pfile, const uchar **pstr, + const uchar *limit, int identifier_pos, + struct normalize_state *nst) +{ + cppchar_t result, c; + unsigned int length; + const uchar *str = *pstr; + const uchar *base = str - 2; + + if (!CPP_OPTION (pfile, cplusplus) && !CPP_OPTION (pfile, c99)) + cpp_error (pfile, CPP_DL_WARNING, + "universal character names are only valid in C++ and C99"); + else if (CPP_WTRADITIONAL (pfile) && identifier_pos == 0) + cpp_error (pfile, CPP_DL_WARNING, + "the meaning of '\\%c' is different in traditional C", + (int) str[-1]); + + if (str[-1] == 'u') + length = 4; + else if (str[-1] == 'U') + length = 8; + else + { + cpp_error (pfile, CPP_DL_ICE, "In _cpp_valid_ucn but not a UCN"); + length = 4; + } + + result = 0; + do + { + c = *str; + if (!ISXDIGIT (c)) + break; + str++; + result = (result << 4) + hex_value (c); + } + while (--length && str < limit); + + /* Partial UCNs are not valid in strings, but decompose into + multiple tokens in identifiers, so we can't give a helpful + error message in that case. */ + if (length && identifier_pos) + return 0; + + *pstr = str; + if (length) + { + cpp_error (pfile, CPP_DL_ERROR, + "incomplete universal character name %.*s", + (int) (str - base), base); + result = 1; + } + /* The standard permits $, @ and ` to be specified as UCNs. We use + hex escapes so that this also works with EBCDIC hosts. */ + else if ((result < 0xa0 + && (result != 0x24 && result != 0x40 && result != 0x60)) + || (result & 0x80000000) + || (result >= 0xD800 && result <= 0xDFFF)) + { + cpp_error (pfile, CPP_DL_ERROR, + "%.*s is not a valid universal character", + (int) (str - base), base); + result = 1; + } + else if (identifier_pos && result == 0x24 + && CPP_OPTION (pfile, dollars_in_ident)) + { + if (CPP_OPTION (pfile, warn_dollars) && !pfile->state.skipping) + { + CPP_OPTION (pfile, warn_dollars) = 0; + cpp_error (pfile, CPP_DL_PEDWARN, "'$' in identifier or number"); + } + NORMALIZE_STATE_UPDATE_IDNUM (nst); + } + else if (identifier_pos) + { + int validity = ucn_valid_in_identifier (pfile, result, nst); + + if (validity == 0) + cpp_error (pfile, CPP_DL_ERROR, + "universal character %.*s is not valid in an identifier", + (int) (str - base), base); + else if (validity == 2 && identifier_pos == 1) + cpp_error (pfile, CPP_DL_ERROR, + "universal character %.*s is not valid at the start of an identifier", + (int) (str - base), base); + } + + if (result == 0) + result = 1; + + return result; +} + +/* Convert an UCN, pointed to by FROM, to UTF-8 encoding, then translate + it to the execution character set and write the result into TBUF. + An advanced pointer is returned. Issues all relevant diagnostics. */ +static const uchar * +convert_ucn (cpp_reader *pfile, const uchar *from, const uchar *limit, + struct _cpp_strbuf *tbuf, bool wide) +{ + cppchar_t ucn; + uchar buf[6]; + uchar *bufp = buf; + size_t bytesleft = 6; + int rval; + struct cset_converter cvt + = wide ? pfile->wide_cset_desc : pfile->narrow_cset_desc; + struct normalize_state nst = INITIAL_NORMALIZE_STATE; + + from++; /* Skip u/U. */ + ucn = _cpp_valid_ucn (pfile, &from, limit, 0, &nst); + + rval = one_cppchar_to_utf8 (ucn, &bufp, &bytesleft); + if (rval) + { + errno = rval; + cpp_errno (pfile, CPP_DL_ERROR, + "converting UCN to source character set"); + } + else if (!APPLY_CONVERSION (cvt, buf, 6 - bytesleft, tbuf)) + cpp_errno (pfile, CPP_DL_ERROR, + "converting UCN to execution character set"); + + return from; +} + +/* Subroutine of convert_hex and convert_oct. N is the representation + in the execution character set of a numeric escape; write it into the + string buffer TBUF and update the end-of-string pointer therein. WIDE + is true if it's a wide string that's being assembled in TBUF. This + function issues no diagnostics and never fails. */ +static void +emit_numeric_escape (cpp_reader *pfile, cppchar_t n, + struct _cpp_strbuf *tbuf, bool wide) +{ + if (wide) + { + /* We have to render this into the target byte order, which may not + be our byte order. */ + bool bigend = CPP_OPTION (pfile, bytes_big_endian); + size_t width = CPP_OPTION (pfile, wchar_precision); + size_t cwidth = CPP_OPTION (pfile, char_precision); + size_t cmask = width_to_mask (cwidth); + size_t nbwc = width / cwidth; + size_t i; + size_t off = tbuf->len; + cppchar_t c; + + if (tbuf->len + nbwc > tbuf->asize) + { + tbuf->asize += OUTBUF_BLOCK_SIZE; + tbuf->text = XRESIZEVEC (uchar, tbuf->text, tbuf->asize); + } + + for (i = 0; i < nbwc; i++) + { + c = n & cmask; + n >>= cwidth; + tbuf->text[off + (bigend ? nbwc - i - 1 : i)] = c; + } + tbuf->len += nbwc; + } + else + { + /* Note: this code does not handle the case where the target + and host have a different number of bits in a byte. */ + if (tbuf->len + 1 > tbuf->asize) + { + tbuf->asize += OUTBUF_BLOCK_SIZE; + tbuf->text = XRESIZEVEC (uchar, tbuf->text, tbuf->asize); + } + tbuf->text[tbuf->len++] = n; + } +} + +/* Convert a hexadecimal escape, pointed to by FROM, to the execution + character set and write it into the string buffer TBUF. Returns an + advanced pointer, and issues diagnostics as necessary. + No character set translation occurs; this routine always produces the + execution-set character with numeric value equal to the given hex + number. You can, e.g. generate surrogate pairs this way. */ +static const uchar * +convert_hex (cpp_reader *pfile, const uchar *from, const uchar *limit, + struct _cpp_strbuf *tbuf, bool wide) +{ + cppchar_t c, n = 0, overflow = 0; + int digits_found = 0; + size_t width = (wide ? CPP_OPTION (pfile, wchar_precision) + : CPP_OPTION (pfile, char_precision)); + size_t mask = width_to_mask (width); + + if (CPP_WTRADITIONAL (pfile)) + cpp_error (pfile, CPP_DL_WARNING, + "the meaning of '\\x' is different in traditional C"); + + from++; /* Skip 'x'. */ + while (from < limit) + { + c = *from; + if (! hex_p (c)) + break; + from++; + overflow |= n ^ (n << 4 >> 4); + n = (n << 4) + hex_value (c); + digits_found = 1; + } + + if (!digits_found) + { + cpp_error (pfile, CPP_DL_ERROR, + "\\x used with no following hex digits"); + return from; + } + + if (overflow | (n != (n & mask))) + { + cpp_error (pfile, CPP_DL_PEDWARN, + "hex escape sequence out of range"); + n &= mask; + } + + emit_numeric_escape (pfile, n, tbuf, wide); + + return from; +} + +/* Convert an octal escape, pointed to by FROM, to the execution + character set and write it into the string buffer TBUF. Returns an + advanced pointer, and issues diagnostics as necessary. + No character set translation occurs; this routine always produces the + execution-set character with numeric value equal to the given octal + number. */ +static const uchar * +convert_oct (cpp_reader *pfile, const uchar *from, const uchar *limit, + struct _cpp_strbuf *tbuf, bool wide) +{ + size_t count = 0; + cppchar_t c, n = 0; + size_t width = (wide ? CPP_OPTION (pfile, wchar_precision) + : CPP_OPTION (pfile, char_precision)); + size_t mask = width_to_mask (width); + bool overflow = false; + + while (from < limit && count++ < 3) + { + c = *from; + if (c < '0' || c > '7') + break; + from++; + overflow |= n ^ (n << 3 >> 3); + n = (n << 3) + c - '0'; + } + + if (n != (n & mask)) + { + cpp_error (pfile, CPP_DL_PEDWARN, + "octal escape sequence out of range"); + n &= mask; + } + + emit_numeric_escape (pfile, n, tbuf, wide); + + return from; +} + +/* Convert an escape sequence (pointed to by FROM) to its value on + the target, and to the execution character set. Do not scan past + LIMIT. Write the converted value into TBUF. Returns an advanced + pointer. Handles all relevant diagnostics. */ +static const uchar * +convert_escape (cpp_reader *pfile, const uchar *from, const uchar *limit, + struct _cpp_strbuf *tbuf, bool wide) +{ + /* Values of \a \b \e \f \n \r \t \v respectively. */ +#if HOST_CHARSET == HOST_CHARSET_ASCII + static const uchar charconsts[] = { 7, 8, 27, 12, 10, 13, 9, 11 }; +#elif HOST_CHARSET == HOST_CHARSET_EBCDIC + static const uchar charconsts[] = { 47, 22, 39, 12, 21, 13, 5, 11 }; +#else +#error "unknown host character set" +#endif + + uchar c; + struct cset_converter cvt + = wide ? pfile->wide_cset_desc : pfile->narrow_cset_desc; + + c = *from; + switch (c) + { + /* UCNs, hex escapes, and octal escapes are processed separately. */ + case 'u': case 'U': + return convert_ucn (pfile, from, limit, tbuf, wide); + + case 'x': + return convert_hex (pfile, from, limit, tbuf, wide); + break; + + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + return convert_oct (pfile, from, limit, tbuf, wide); + + /* Various letter escapes. Get the appropriate host-charset + value into C. */ + case '\\': case '\'': case '"': case '?': break; + + case '(': case '{': case '[': case '%': + /* '\(', etc, can be used at the beginning of a line in a long + string split onto multiple lines with \-newline, to prevent + Emacs or other text editors from getting confused. '\%' can + be used to prevent SCCS from mangling printf format strings. */ + if (CPP_PEDANTIC (pfile)) + goto unknown; + break; + + case 'b': c = charconsts[1]; break; + case 'f': c = charconsts[3]; break; + case 'n': c = charconsts[4]; break; + case 'r': c = charconsts[5]; break; + case 't': c = charconsts[6]; break; + case 'v': c = charconsts[7]; break; + + case 'a': + if (CPP_WTRADITIONAL (pfile)) + cpp_error (pfile, CPP_DL_WARNING, + "the meaning of '\\a' is different in traditional C"); + c = charconsts[0]; + break; + + case 'e': case 'E': + if (CPP_PEDANTIC (pfile)) + cpp_error (pfile, CPP_DL_PEDWARN, + "non-ISO-standard escape sequence, '\\%c'", (int) c); + c = charconsts[2]; + break; + + default: + unknown: + if (ISGRAPH (c)) + cpp_error (pfile, CPP_DL_PEDWARN, + "unknown escape sequence '\\%c'", (int) c); + else + { + /* diagnostic.c does not support "%03o". When it does, this + code can use %03o directly in the diagnostic again. */ + char buf[32]; + sprintf(buf, "%03o", (int) c); + cpp_error (pfile, CPP_DL_PEDWARN, + "unknown escape sequence: '\\%s'", buf); + } + } + + /* Now convert what we have to the execution character set. */ + if (!APPLY_CONVERSION (cvt, &c, 1, tbuf)) + cpp_errno (pfile, CPP_DL_ERROR, + "converting escape sequence to execution character set"); + + return from + 1; +} + +/* FROM is an array of cpp_string structures of length COUNT. These + are to be converted from the source to the execution character set, + escape sequences translated, and finally all are to be + concatenated. WIDE indicates whether or not to produce a wide + string. The result is written into TO. Returns true for success, + false for failure. */ +bool +cpp_interpret_string (cpp_reader *pfile, const cpp_string *from, size_t count, + cpp_string *to, bool wide) +{ + struct _cpp_strbuf tbuf; + const uchar *p, *base, *limit; + size_t i; + struct cset_converter cvt + = wide ? pfile->wide_cset_desc : pfile->narrow_cset_desc; + + tbuf.asize = MAX (OUTBUF_BLOCK_SIZE, from->len); + tbuf.text = XNEWVEC (uchar, tbuf.asize); + tbuf.len = 0; + + for (i = 0; i < count; i++) + { + p = from[i].text; + if (*p == 'L') p++; + p++; /* Skip leading quote. */ + limit = from[i].text + from[i].len - 1; /* Skip trailing quote. */ + + for (;;) + { + base = p; + while (p < limit && *p != '\\') + p++; + if (p > base) + { + /* We have a run of normal characters; these can be fed + directly to convert_cset. */ + if (!APPLY_CONVERSION (cvt, base, p - base, &tbuf)) + goto fail; + } + if (p == limit) + break; + + p = convert_escape (pfile, p + 1, limit, &tbuf, wide); + } + } + /* NUL-terminate the 'to' buffer and translate it to a cpp_string + structure. */ + emit_numeric_escape (pfile, 0, &tbuf, wide); + tbuf.text = XRESIZEVEC (uchar, tbuf.text, tbuf.len); + to->text = tbuf.text; + to->len = tbuf.len; + return true; + + fail: + cpp_errno (pfile, CPP_DL_ERROR, "converting to execution character set"); + free (tbuf.text); + return false; +} + +/* Subroutine of do_line and do_linemarker. Convert escape sequences + in a string, but do not perform character set conversion. */ +bool +cpp_interpret_string_notranslate (cpp_reader *pfile, const cpp_string *from, + size_t count, cpp_string *to, bool wide) +{ + struct cset_converter save_narrow_cset_desc = pfile->narrow_cset_desc; + bool retval; + + pfile->narrow_cset_desc.func = convert_no_conversion; + pfile->narrow_cset_desc.cd = (iconv_t) -1; + + retval = cpp_interpret_string (pfile, from, count, to, wide); + + pfile->narrow_cset_desc = save_narrow_cset_desc; + return retval; +} + + +/* Subroutine of cpp_interpret_charconst which performs the conversion + to a number, for narrow strings. STR is the string structure returned + by cpp_interpret_string. PCHARS_SEEN and UNSIGNEDP are as for + cpp_interpret_charconst. */ +static cppchar_t +narrow_str_to_charconst (cpp_reader *pfile, cpp_string str, + unsigned int *pchars_seen, int *unsignedp) +{ + size_t width = CPP_OPTION (pfile, char_precision); + size_t max_chars = CPP_OPTION (pfile, int_precision) / width; + size_t mask = width_to_mask (width); + size_t i; + cppchar_t result, c; + bool unsigned_p; + + /* The value of a multi-character character constant, or a + single-character character constant whose representation in the + execution character set is more than one byte long, is + implementation defined. This implementation defines it to be the + number formed by interpreting the byte sequence in memory as a + big-endian binary number. If overflow occurs, the high bytes are + lost, and a warning is issued. + + We don't want to process the NUL terminator handed back by + cpp_interpret_string. */ + result = 0; + for (i = 0; i < str.len - 1; i++) + { + c = str.text[i] & mask; + if (width < BITS_PER_CPPCHAR_T) + result = (result << width) | c; + else + result = c; + } + + if (i > max_chars) + { + i = max_chars; + cpp_error (pfile, CPP_DL_WARNING, + "character constant too long for its type"); + } + else if (i > 1 && CPP_OPTION (pfile, warn_multichar)) + cpp_error (pfile, CPP_DL_WARNING, "multi-character character constant"); + + /* Multichar constants are of type int and therefore signed. */ + if (i > 1) + unsigned_p = 0; + else + unsigned_p = CPP_OPTION (pfile, unsigned_char); + + /* Truncate the constant to its natural width, and simultaneously + sign- or zero-extend to the full width of cppchar_t. + For single-character constants, the value is WIDTH bits wide. + For multi-character constants, the value is INT_PRECISION bits wide. */ + if (i > 1) + width = CPP_OPTION (pfile, int_precision); + if (width < BITS_PER_CPPCHAR_T) + { + mask = ((cppchar_t) 1 << width) - 1; + if (unsigned_p || !(result & (1 << (width - 1)))) + result &= mask; + else + result |= ~mask; + } + *pchars_seen = i; + *unsignedp = unsigned_p; + return result; +} + +/* Subroutine of cpp_interpret_charconst which performs the conversion + to a number, for wide strings. STR is the string structure returned + by cpp_interpret_string. PCHARS_SEEN and UNSIGNEDP are as for + cpp_interpret_charconst. */ +static cppchar_t +wide_str_to_charconst (cpp_reader *pfile, cpp_string str, + unsigned int *pchars_seen, int *unsignedp) +{ + bool bigend = CPP_OPTION (pfile, bytes_big_endian); + size_t width = CPP_OPTION (pfile, wchar_precision); + size_t cwidth = CPP_OPTION (pfile, char_precision); + size_t mask = width_to_mask (width); + size_t cmask = width_to_mask (cwidth); + size_t nbwc = width / cwidth; + size_t off, i; + cppchar_t result = 0, c; + + /* This is finicky because the string is in the target's byte order, + which may not be our byte order. Only the last character, ignoring + the NUL terminator, is relevant. */ + off = str.len - (nbwc * 2); + result = 0; + for (i = 0; i < nbwc; i++) + { + c = bigend ? str.text[off + i] : str.text[off + nbwc - i - 1]; + result = (result << cwidth) | (c & cmask); + } + + /* Wide character constants have type wchar_t, and a single + character exactly fills a wchar_t, so a multi-character wide + character constant is guaranteed to overflow. */ + if (off > 0) + cpp_error (pfile, CPP_DL_WARNING, + "character constant too long for its type"); + + /* Truncate the constant to its natural width, and simultaneously + sign- or zero-extend to the full width of cppchar_t. */ + if (width < BITS_PER_CPPCHAR_T) + { + if (CPP_OPTION (pfile, unsigned_wchar) || !(result & (1 << (width - 1)))) + result &= mask; + else + result |= ~mask; + } + + *unsignedp = CPP_OPTION (pfile, unsigned_wchar); + *pchars_seen = 1; + return result; +} + +/* Interpret a (possibly wide) character constant in TOKEN. + PCHARS_SEEN points to a variable that is filled in with the number + of characters seen, and UNSIGNEDP to a variable that indicates + whether the result has signed type. */ +cppchar_t +cpp_interpret_charconst (cpp_reader *pfile, const cpp_token *token, + unsigned int *pchars_seen, int *unsignedp) +{ + cpp_string str = { 0, 0 }; + bool wide = (token->type == CPP_WCHAR); + cppchar_t result; + + /* an empty constant will appear as L'' or '' */ + if (token->val.str.len == (size_t) (2 + wide)) + { + cpp_error (pfile, CPP_DL_ERROR, "empty character constant"); + return 0; + } + else if (!cpp_interpret_string (pfile, &token->val.str, 1, &str, wide)) + return 0; + + if (wide) + result = wide_str_to_charconst (pfile, str, pchars_seen, unsignedp); + else + result = narrow_str_to_charconst (pfile, str, pchars_seen, unsignedp); + + if (str.text != token->val.str.text) + free ((void *)str.text); + + return result; +} + +/* Convert an identifier denoted by ID and LEN, which might contain + UCN escapes, to the source character set, either UTF-8 or + UTF-EBCDIC. Assumes that the identifier is actually a valid identifier. */ +cpp_hashnode * +_cpp_interpret_identifier (cpp_reader *pfile, const uchar *id, size_t len) +{ + /* It turns out that a UCN escape always turns into fewer characters + than the escape itself, so we can allocate a temporary in advance. */ + uchar * buf = (uchar *) alloca (len + 1); + uchar * bufp = buf; + size_t idp; + + for (idp = 0; idp < len; idp++) + if (id[idp] != '\\') + *bufp++ = id[idp]; + else + { + unsigned length = id[idp+1] == 'u' ? 4 : 8; + cppchar_t value = 0; + size_t bufleft = len - (bufp - buf); + int rval; + + idp += 2; + while (length && idp < len && ISXDIGIT (id[idp])) + { + value = (value << 4) + hex_value (id[idp]); + idp++; + length--; + } + idp--; + + /* Special case for EBCDIC: if the identifier contains + a '$' specified using a UCN, translate it to EBCDIC. */ + if (value == 0x24) + { + *bufp++ = '$'; + continue; + } + + rval = one_cppchar_to_utf8 (value, &bufp, &bufleft); + if (rval) + { + errno = rval; + cpp_errno (pfile, CPP_DL_ERROR, + "converting UCN to source character set"); + break; + } + } + + return CPP_HASHNODE (ht_lookup (pfile->hash_table, + buf, bufp - buf, HT_ALLOC)); +} + +/* Convert an input buffer (containing the complete contents of one + source file) from INPUT_CHARSET to the source character set. INPUT + points to the input buffer, SIZE is its allocated size, and LEN is + the length of the meaningful data within the buffer. The + translated buffer is returned, and *ST_SIZE is set to the length of + the meaningful data within the translated buffer. + + INPUT is expected to have been allocated with xmalloc. This function + will either return INPUT, or free it and return a pointer to another + xmalloc-allocated block of memory. */ +uchar * +_cpp_convert_input (cpp_reader *pfile, const char *input_charset, + uchar *input, size_t size, size_t len, off_t *st_size) +{ + struct cset_converter input_cset; + struct _cpp_strbuf to; + + input_cset = init_iconv_desc (pfile, SOURCE_CHARSET, input_charset); + if (input_cset.func == convert_no_conversion) + { + to.text = input; + to.asize = size; + to.len = len; + } + else + { + to.asize = MAX (65536, len); + to.text = XNEWVEC (uchar, to.asize); + to.len = 0; + + if (!APPLY_CONVERSION (input_cset, input, len, &to)) + cpp_error (pfile, CPP_DL_ERROR, + "failure to convert %s to %s", + CPP_OPTION (pfile, input_charset), SOURCE_CHARSET); + + free (input); + } + + /* Clean up the mess. */ + if (input_cset.func == convert_using_iconv) + iconv_close (input_cset.cd); + + /* Resize buffer if we allocated substantially too much, or if we + haven't enough space for the \n-terminator. */ + if (to.len + 4096 < to.asize || to.len >= to.asize) + to.text = XRESIZEVEC (uchar, to.text, to.len + 1); + + /* If the file is using old-school Mac line endings (\r only), + terminate with another \r, not an \n, so that we do not mistake + the \r\n sequence for a single DOS line ending and erroneously + issue the "No newline at end of file" diagnostic. */ + if (to.text[to.len - 1] == '\r') + to.text[to.len] = '\r'; + else + to.text[to.len] = '\n'; + + *st_size = to.len; + return to.text; +} + +/* Decide on the default encoding to assume for input files. */ +const char * +_cpp_default_encoding (void) +{ + const char *current_encoding = NULL; + + /* We disable this because the default codeset is 7-bit ASCII on + most platforms, and this causes conversion failures on every + file in GCC that happens to have one of the upper 128 characters + in it -- most likely, as part of the name of a contributor. + We should definitely recognize in-band markers of file encoding, + like: + - the appropriate Unicode byte-order mark (FE FF) to recognize + UTF16 and UCS4 (in both big-endian and little-endian flavors) + and UTF8 + - a "#i", "#d", "/ *", "//", " #p" or "#p" (for #pragma) to + distinguish ASCII and EBCDIC. + - now we can parse something like "#pragma GCC encoding + on the first line, or even Emacs/VIM's mode line tags (there's + a problem here in that VIM uses the last line, and Emacs has + its more elaborate "local variables" convention). + - investigate whether Java has another common convention, which + would be friendly to support. + (Zack Weinberg and Paolo Bonzini, May 20th 2004) */ +#if defined (HAVE_LOCALE_H) && defined (HAVE_LANGINFO_CODESET) && 0 + setlocale (LC_CTYPE, ""); + current_encoding = nl_langinfo (CODESET); +#endif + if (current_encoding == NULL || *current_encoding == '\0') + current_encoding = SOURCE_CHARSET; + + return current_encoding; +} diff --git a/support/cpp2/libcpp/directives.c b/support/cpp2/libcpp/directives.c new file mode 100644 index 00000000..26029229 --- /dev/null +++ b/support/cpp2/libcpp/directives.c @@ -0,0 +1,2288 @@ +/* CPP Library. (Directive handling.) + Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + Contributed by Per Bothner, 1994-95. + Based on CCCP program by Paul Rubin, June 1986 + Adapted to ANSI C, Richard Stallman, Jan 1987 + +This program 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 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "config.h" +#include "system.h" +#include "cpplib.h" +#include "internal.h" +#include "mkdeps.h" +#include "obstack.h" + +/* Stack of conditionals currently in progress + (including both successful and failing conditionals). */ +struct if_stack +{ + struct if_stack *next; + unsigned int line; /* Line where condition started. */ + const cpp_hashnode *mi_cmacro;/* macro name for #ifndef around entire file */ + bool skip_elses; /* Can future #else / #elif be skipped? */ + bool was_skipping; /* If were skipping on entry. */ + int type; /* Most recent conditional for diagnostics. */ +}; + +/* Contains a registered pragma or pragma namespace. */ +typedef void (*pragma_cb) (cpp_reader *); +struct pragma_entry +{ + struct pragma_entry *next; + const cpp_hashnode *pragma; /* Name and length. */ + bool is_nspace; + bool allow_expansion; + bool is_internal; + union { + pragma_cb handler; + struct pragma_entry *space; + } u; +}; + +/* Values for the origin field of struct directive. KANDR directives + come from traditional (K&R) C. STDC89 directives come from the + 1989 C standard. EXTENSION directives are extensions. */ +#define KANDR 0 +#define STDC89 1 +#define EXTENSION 2 + +/* Values for the flags field of struct directive. COND indicates a + conditional; IF_COND an opening conditional. INCL means to treat + "..." and <...> as q-char and h-char sequences respectively. IN_I + means this directive should be handled even if -fpreprocessed is in + effect (these are the directives with callback hooks). + + EXPAND is set on directives that are always macro-expanded. */ +#define COND (1 << 0) +#define IF_COND (1 << 1) +#define INCL (1 << 2) +#define IN_I (1 << 3) +#define EXPAND (1 << 4) + +/* Defines one #-directive, including how to handle it. */ +typedef void (*directive_handler) (cpp_reader *); +typedef struct directive directive; +struct directive +{ + directive_handler handler; /* Function to handle directive. */ + const uchar *name; /* Name of directive. */ + unsigned short length; /* Length of name. */ + unsigned char origin; /* Origin of directive. */ + unsigned char flags; /* Flags describing this directive. */ +}; + +/* Forward declarations. */ + +static void skip_rest_of_line (cpp_reader *); +static void check_eol (cpp_reader *); +static void start_directive (cpp_reader *); +static void prepare_directive_trad (cpp_reader *); +static void end_directive (cpp_reader *, int); +static void directive_diagnostics (cpp_reader *, const directive *, int); +static void run_directive (cpp_reader *, int, const char *, size_t); +static char *glue_header_name (cpp_reader *); +static const char *parse_include (cpp_reader *, int *, const cpp_token ***); +static void push_conditional (cpp_reader *, int, int, const cpp_hashnode *); +static unsigned int read_flag (cpp_reader *, unsigned int); +static int strtoul_for_line (const uchar *, unsigned int, unsigned long *); +static void do_diagnostic (cpp_reader *, int, int); +static cpp_hashnode *lex_macro_node (cpp_reader *); +static int undefine_macros (cpp_reader *, cpp_hashnode *, void *); +static void do_include_common (cpp_reader *, enum include_type); +static struct pragma_entry *lookup_pragma_entry (struct pragma_entry *, + const cpp_hashnode *); +static struct pragma_entry *insert_pragma_entry (cpp_reader *, + struct pragma_entry **, + const cpp_hashnode *, + pragma_cb, + bool, bool); +static void register_pragma (cpp_reader *, const char *, const char *, + pragma_cb, bool, bool); +static int count_registered_pragmas (struct pragma_entry *); +static char ** save_registered_pragmas (struct pragma_entry *, char **); +static char ** restore_registered_pragmas (cpp_reader *, struct pragma_entry *, + char **); +static void do_pragma_once (cpp_reader *); +static void do_pragma_poison (cpp_reader *); +static void do_pragma_system_header (cpp_reader *); +static void do_pragma_dependency (cpp_reader *); +static void do_pragma_sdcc_hash (cpp_reader *pfile); +static void do_pragma_preproc_asm (cpp_reader *pfile); +static void do_pragma_pedantic_parse_number (cpp_reader *pfile); +static void do_linemarker (cpp_reader *); +static const cpp_token *get_token_no_padding (cpp_reader *); +static const cpp_token *get__Pragma_string (cpp_reader *); +static void destringize_and_run (cpp_reader *, const cpp_string *); +static int parse_answer (cpp_reader *, struct answer **, int); +static cpp_hashnode *parse_assertion (cpp_reader *, struct answer **, int); +static struct answer ** find_answer (cpp_hashnode *, const struct answer *); +static void handle_assertion (cpp_reader *, const char *, int); + +/* This is the table of directive handlers. It is ordered by + frequency of occurrence; the numbers at the end are directive + counts from all the source code I have lying around (egcs and libc + CVS as of 1999-05-18, plus grub-0.5.91, linux-2.2.9, and + pcmcia-cs-3.0.9). This is no longer important as directive lookup + is now O(1). All extensions other than #warning and #include_next + are deprecated. The name is where the extension appears to have + come from. */ + +#define DIRECTIVE_TABLE \ +D(define, T_DEFINE = 0, KANDR, IN_I) /* 270554 */ \ +D(include, T_INCLUDE, KANDR, INCL | EXPAND) /* 52262 */ \ +D(endif, T_ENDIF, KANDR, COND) /* 45855 */ \ +D(ifdef, T_IFDEF, KANDR, COND | IF_COND) /* 22000 */ \ +D(if, T_IF, KANDR, COND | IF_COND | EXPAND) /* 18162 */ \ +D(else, T_ELSE, KANDR, COND) /* 9863 */ \ +D(ifndef, T_IFNDEF, KANDR, COND | IF_COND) /* 9675 */ \ +D(undef, T_UNDEF, KANDR, IN_I) /* 4837 */ \ +D(line, T_LINE, KANDR, EXPAND) /* 2465 */ \ +D(elif, T_ELIF, STDC89, COND | EXPAND) /* 610 */ \ +D(error, T_ERROR, STDC89, 0) /* 475 */ \ +D(pragma, T_PRAGMA, STDC89, IN_I) /* 195 */ \ +D(warning, T_WARNING, EXTENSION, 0) /* 22 */ \ +D(include_next, T_INCLUDE_NEXT, EXTENSION, INCL | EXPAND) /* 19 */ \ +D(ident, T_IDENT, EXTENSION, IN_I) /* 11 */ \ +D(import, T_IMPORT, EXTENSION, INCL | EXPAND) /* 0 ObjC */ \ +D(assert, T_ASSERT, EXTENSION, 0) /* 0 SVR4 */ \ +D(unassert, T_UNASSERT, EXTENSION, 0) /* 0 SVR4 */ \ +D(sccs, T_SCCS, EXTENSION, IN_I) /* 0 SVR4? */ + +/* #sccs is synonymous with #ident. */ +#define do_sccs do_ident + +/* Use the table to generate a series of prototypes, an enum for the + directive names, and an array of directive handlers. */ + +#define D(name, t, o, f) static void do_##name (cpp_reader *); +DIRECTIVE_TABLE +#undef D + +#define D(n, tag, o, f) tag, +enum +{ + DIRECTIVE_TABLE + N_DIRECTIVES +}; +#undef D + +#define D(name, t, origin, flags) \ +{ do_##name, (const uchar *) #name, \ + sizeof #name - 1, origin, flags }, +static const directive dtable[] = +{ +DIRECTIVE_TABLE +}; +#undef D +#undef DIRECTIVE_TABLE + +/* Wrapper struct directive for linemarkers. + The origin is more or less true - the original K+R cpp + did use this notation in its preprocessed output. */ +static const directive linemarker_dir = +{ + do_linemarker, U"#", 1, KANDR, IN_I +}; + +#define SEEN_EOL() (pfile->cur_token[-1].type == CPP_EOF) + +/* Skip any remaining tokens in a directive. */ +static void +skip_rest_of_line (cpp_reader *pfile) +{ + /* Discard all stacked contexts. */ + while (pfile->context->prev) + _cpp_pop_context (pfile); + + /* Sweep up all tokens remaining on the line. */ + if (! SEEN_EOL ()) + while (_cpp_lex_token (pfile)->type != CPP_EOF) + ; +} + +/* Ensure there are no stray tokens at the end of a directive. */ +static void +check_eol (cpp_reader *pfile) +{ + if (! SEEN_EOL () && _cpp_lex_token (pfile)->type != CPP_EOF) + cpp_error (pfile, CPP_DL_PEDWARN, "extra tokens at end of #%s directive", + pfile->directive->name); +} + +/* Ensure there are no stray tokens other than comments at the end of + a directive, and gather the comments. */ +static const cpp_token ** +check_eol_return_comments (cpp_reader *pfile) +{ + size_t c; + size_t capacity = 8; + const cpp_token **buf; + + buf = XNEWVEC (const cpp_token *, capacity); + c = 0; + if (! SEEN_EOL ()) + { + while (1) + { + const cpp_token *tok; + + tok = _cpp_lex_token (pfile); + if (tok->type == CPP_EOF) + break; + if (tok->type != CPP_COMMENT) + cpp_error (pfile, CPP_DL_PEDWARN, + "extra tokens at end of #%s directive", + pfile->directive->name); + else + { + if (c + 1 >= capacity) + { + capacity *= 2; + buf = XRESIZEVEC (const cpp_token *, buf, capacity); + } + buf[c] = tok; + ++c; + } + } + } + buf[c] = NULL; + return buf; +} + +/* Called when entering a directive, _Pragma or command-line directive. */ +static void +start_directive (cpp_reader *pfile) +{ + /* Setup in-directive state. */ + pfile->state.in_directive = 1; + pfile->state.save_comments = 0; + pfile->directive_result.type = CPP_PADDING; + + /* Some handlers need the position of the # for diagnostics. */ + pfile->directive_line = pfile->line_table->highest_line; +} + +/* Called when leaving a directive, _Pragma or command-line directive. */ +static void +end_directive (cpp_reader *pfile, int skip_line) +{ + if (CPP_OPTION (pfile, traditional)) + { + /* Revert change of prepare_directive_trad. */ + pfile->state.prevent_expansion--; + + if (pfile->directive != &dtable[T_DEFINE]) + _cpp_remove_overlay (pfile); + } + /* We don't skip for an assembler #. */ + else if (skip_line) + { + skip_rest_of_line (pfile); + if (!pfile->keep_tokens) + { + pfile->cur_run = &pfile->base_run; + pfile->cur_token = pfile->base_run.base; + } + } + + /* Restore state. */ + pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments); + pfile->state.in_directive = 0; + pfile->state.in_expression = 0; + pfile->state.angled_headers = 0; + pfile->directive = 0; +} + +/* Prepare to handle the directive in pfile->directive. */ +static void +prepare_directive_trad (cpp_reader *pfile) +{ + if (pfile->directive != &dtable[T_DEFINE]) + { + bool no_expand = (pfile->directive + && ! (pfile->directive->flags & EXPAND)); + bool was_skipping = pfile->state.skipping; + + pfile->state.in_expression = (pfile->directive == &dtable[T_IF] + || pfile->directive == &dtable[T_ELIF]); + if (pfile->state.in_expression) + pfile->state.skipping = false; + + if (no_expand) + pfile->state.prevent_expansion++; + _cpp_scan_out_logical_line (pfile, NULL); + if (no_expand) + pfile->state.prevent_expansion--; + + pfile->state.skipping = was_skipping; + _cpp_overlay_buffer (pfile, pfile->out.base, + pfile->out.cur - pfile->out.base); + } + + /* Stop ISO C from expanding anything. */ + pfile->state.prevent_expansion++; +} + +/* Output diagnostics for a directive DIR. INDENTED is nonzero if + the '#' was indented. */ +static void +directive_diagnostics (cpp_reader *pfile, const directive *dir, int indented) +{ + /* Issue -pedantic warnings for extensions. */ + if (CPP_PEDANTIC (pfile) + && ! pfile->state.skipping + && dir->origin == EXTENSION) + cpp_error (pfile, CPP_DL_PEDWARN, "#%s is a GCC extension", dir->name); + + /* Traditionally, a directive is ignored unless its # is in + column 1. Therefore in code intended to work with K+R + compilers, directives added by C89 must have their # + indented, and directives present in traditional C must not. + This is true even of directives in skipped conditional + blocks. #elif cannot be used at all. */ + if (CPP_WTRADITIONAL (pfile)) + { + if (dir == &dtable[T_ELIF]) + cpp_error (pfile, CPP_DL_WARNING, + "suggest not using #elif in traditional C"); + else if (indented && dir->origin == KANDR) + cpp_error (pfile, CPP_DL_WARNING, + "traditional C ignores #%s with the # indented", + dir->name); + else if (!indented && dir->origin != KANDR) + cpp_error (pfile, CPP_DL_WARNING, + "suggest hiding #%s from traditional C with an indented #", + dir->name); + } +} + +/* Check if we have a known directive. INDENTED is nonzero if the + '#' of the directive was indented. This function is in this file + to save unnecessarily exporting dtable etc. to lex.c. Returns + nonzero if the line of tokens has been handled, zero if we should + continue processing the line. */ +int +_cpp_handle_directive (cpp_reader *pfile, int indented) +{ + const directive *dir = 0; + const cpp_token *dname; + bool was_parsing_args = pfile->state.parsing_args; + bool was_discarding_output = pfile->state.discarding_output; + int skip = 1; + + if (was_discarding_output) + pfile->state.prevent_expansion = 0; + + if (was_parsing_args) + { + if (CPP_OPTION (pfile, pedantic)) + cpp_error (pfile, CPP_DL_PEDWARN, + "embedding a directive within macro arguments is not portable"); + pfile->state.parsing_args = 0; + pfile->state.prevent_expansion = 0; + } + start_directive (pfile); + dname = _cpp_lex_token (pfile); + + if (dname->type == CPP_NAME) + { + if (dname->val.node->is_directive) + dir = &dtable[dname->val.node->directive_index]; + } + /* We do not recognize the # followed by a number extension in + assembler code. */ + else if (dname->type == CPP_NUMBER && CPP_OPTION (pfile, lang) != CLK_ASM) + { + dir = &linemarker_dir; + if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, preprocessed) + && ! pfile->state.skipping) + cpp_error (pfile, CPP_DL_PEDWARN, + "style of line directive is a GCC extension"); + } + + if (dir) + { + /* If we have a directive that is not an opening conditional, + invalidate any control macro. */ + if (! (dir->flags & IF_COND)) + pfile->mi_valid = false; + + /* Kluge alert. In order to be sure that code like this + + #define HASH # + HASH define foo bar + + does not cause '#define foo bar' to get executed when + compiled with -save-temps, we recognize directives in + -fpreprocessed mode only if the # is in column 1. macro.c + puts a space in front of any '#' at the start of a macro. */ + if (CPP_OPTION (pfile, preprocessed) + && (indented || !(dir->flags & IN_I))) + { + skip = 0; + dir = 0; + } + else + { + /* In failed conditional groups, all non-conditional + directives are ignored. Before doing that, whether + skipping or not, we should lex angle-bracketed headers + correctly, and maybe output some diagnostics. */ + pfile->state.angled_headers = dir->flags & INCL; + pfile->state.directive_wants_padding = dir->flags & INCL; + if (! CPP_OPTION (pfile, preprocessed)) + directive_diagnostics (pfile, dir, indented); + if (pfile->state.skipping && !(dir->flags & COND)) + dir = 0; + } + } + else if (dname->type == CPP_EOF) + ; /* CPP_EOF is the "null directive". */ + else + { + /* An unknown directive. Don't complain about it in assembly + source: we don't know where the comments are, and # may + introduce assembler pseudo-ops. Don't complain about invalid + directives in skipped conditional groups (6.10 p4). */ + if (CPP_OPTION (pfile, lang) == CLK_ASM) + skip = 0; + else if (!pfile->state.skipping) + cpp_error (pfile, CPP_DL_ERROR, "invalid preprocessing directive #%s", + cpp_token_as_text (pfile, dname)); + } + + pfile->directive = dir; + if (CPP_OPTION (pfile, traditional)) + prepare_directive_trad (pfile); + + if (dir) + pfile->directive->handler (pfile); + else if (skip == 0) + _cpp_backup_tokens (pfile, 1); + + end_directive (pfile, skip); + if (was_parsing_args) + { + /* Restore state when within macro args. */ + pfile->state.parsing_args = 2; + pfile->state.prevent_expansion = 1; + } + if (was_discarding_output) + pfile->state.prevent_expansion = 1; + return skip; +} + +/* Directive handler wrapper used by the command line option + processor. BUF is \n terminated. */ +static void +run_directive (cpp_reader *pfile, int dir_no, const char *buf, size_t count) +{ + cpp_push_buffer (pfile, (const uchar *) buf, count, + /* from_stage3 */ true); + /* Disgusting hack. */ + if (dir_no == T_PRAGMA && pfile->buffer->prev) + pfile->buffer->file = pfile->buffer->prev->file; + start_directive (pfile); + + /* This is a short-term fix to prevent a leading '#' being + interpreted as a directive. */ + _cpp_clean_line (pfile); + + pfile->directive = &dtable[dir_no]; + if (CPP_OPTION (pfile, traditional)) + prepare_directive_trad (pfile); + pfile->directive->handler (pfile); + end_directive (pfile, 1); + if (dir_no == T_PRAGMA) + pfile->buffer->file = NULL; + _cpp_pop_buffer (pfile); +} + +/* Checks for validity the macro name in #define, #undef, #ifdef and + #ifndef directives. */ +static cpp_hashnode * +lex_macro_node (cpp_reader *pfile) +{ + const cpp_token *token = _cpp_lex_token (pfile); + + /* The token immediately after #define must be an identifier. That + identifier may not be "defined", per C99 6.10.8p4. + In C++, it may not be any of the "named operators" either, + per C++98 [lex.digraph], [lex.key]. + Finally, the identifier may not have been poisoned. (In that case + the lexer has issued the error message for us.) */ + + if (token->type == CPP_NAME) + { + cpp_hashnode *node = token->val.node; + + if (node == pfile->spec_nodes.n_defined) + cpp_error (pfile, CPP_DL_ERROR, + "\"defined\" cannot be used as a macro name"); + else if (! (node->flags & NODE_POISONED)) + return node; + } + else if (token->flags & NAMED_OP) + cpp_error (pfile, CPP_DL_ERROR, + "\"%s\" cannot be used as a macro name as it is an operator in C++", + NODE_NAME (token->val.node)); + else if (token->type == CPP_EOF) + cpp_error (pfile, CPP_DL_ERROR, "no macro name given in #%s directive", + pfile->directive->name); + else + cpp_error (pfile, CPP_DL_ERROR, "macro names must be identifiers"); + + return NULL; +} + +/* Process a #define directive. Most work is done in macro.c. */ +static void +do_define (cpp_reader *pfile) +{ + cpp_hashnode *node = lex_macro_node (pfile); + + if (node) + { + /* If we have been requested to expand comments into macros, + then re-enable saving of comments. */ + pfile->state.save_comments = + ! CPP_OPTION (pfile, discard_comments_in_macro_exp); + + if (_cpp_create_definition (pfile, node)) + if (pfile->cb.define) + pfile->cb.define (pfile, pfile->directive_line, node); + } +} + +/* Handle #undef. Mark the identifier NT_VOID in the hash table. */ +static void +do_undef (cpp_reader *pfile) +{ + cpp_hashnode *node = lex_macro_node (pfile); + + if (node) + { + if (pfile->cb.undef) + pfile->cb.undef (pfile, pfile->directive_line, node); + + /* 6.10.3.5 paragraph 2: [#undef] is ignored if the specified + identifier is not currently defined as a macro name. */ + if (node->type == NT_MACRO) + { + if (node->flags & NODE_WARN) + cpp_error (pfile, CPP_DL_WARNING, + "undefining \"%s\"", NODE_NAME (node)); + + if (CPP_OPTION (pfile, warn_unused_macros)) + _cpp_warn_if_unused_macro (pfile, node, NULL); + + _cpp_free_definition (node); + } + } + + check_eol (pfile); +} + +/* Undefine a single macro/assertion/whatever. */ + +static int +undefine_macros (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *h, + void *data_p ATTRIBUTE_UNUSED) +{ + /* Body of _cpp_free_definition inlined here for speed. + Macros and assertions no longer have anything to free. */ + h->type = NT_VOID; + h->flags &= ~(NODE_POISONED|NODE_BUILTIN|NODE_DISABLED); + return 1; +} + +/* Undefine all macros and assertions. */ + +void +cpp_undef_all (cpp_reader *pfile) +{ + cpp_forall_identifiers (pfile, undefine_macros, NULL); +} + + +/* Helper routine used by parse_include. Reinterpret the current line + as an h-char-sequence (< ... >); we are looking at the first token + after the <. Returns a malloced filename. */ +static char * +glue_header_name (cpp_reader *pfile) +{ + const cpp_token *token; + char *buffer; + size_t len, total_len = 0, capacity = 1024; + + /* To avoid lexed tokens overwriting our glued name, we can only + allocate from the string pool once we've lexed everything. */ + buffer = XNEWVEC (char, capacity); + for (;;) + { + token = get_token_no_padding (pfile); + + if (token->type == CPP_GREATER) + break; + if (token->type == CPP_EOF) + { + cpp_error (pfile, CPP_DL_ERROR, "missing terminating > character"); + break; + } + + len = cpp_token_len (token) + 2; /* Leading space, terminating \0. */ + if (total_len + len > capacity) + { + capacity = (capacity + len) * 2; + buffer = XRESIZEVEC (char, buffer, capacity); + } + + if (token->flags & PREV_WHITE) + buffer[total_len++] = ' '; + + total_len = (cpp_spell_token (pfile, token, (uchar *) &buffer[total_len], + true) + - (uchar *) buffer); + } + + buffer[total_len] = '\0'; + return buffer; +} + +/* Returns the file name of #include, #include_next, #import and + #pragma dependency. The string is malloced and the caller should + free it. Returns NULL on error. */ +static const char * +parse_include (cpp_reader *pfile, int *pangle_brackets, + const cpp_token ***buf) +{ + char *fname; + const cpp_token *header; + + /* Allow macro expansion. */ + header = get_token_no_padding (pfile); + if (header->type == CPP_STRING || header->type == CPP_HEADER_NAME) + { + fname = XNEWVEC (char, header->val.str.len - 1); + memcpy (fname, header->val.str.text + 1, header->val.str.len - 2); + fname[header->val.str.len - 2] = '\0'; + *pangle_brackets = header->type == CPP_HEADER_NAME; + } + else if (header->type == CPP_LESS) + { + fname = glue_header_name (pfile); + *pangle_brackets = 1; + } + else + { + const unsigned char *dir; + + if (pfile->directive == &dtable[T_PRAGMA]) + dir = U"pragma dependency"; + else + dir = pfile->directive->name; + cpp_error (pfile, CPP_DL_ERROR, "#%s expects \"FILENAME\" or ", + dir); + + return NULL; + } + + if (buf == NULL || CPP_OPTION (pfile, discard_comments)) + check_eol (pfile); + else + { + /* If we are not discarding comments, then gather them while + doing the eol check. */ + *buf = check_eol_return_comments (pfile); + } + + return fname; +} + +/* Handle #include, #include_next and #import. */ +static void +do_include_common (cpp_reader *pfile, enum include_type type) +{ + const char *fname; + int angle_brackets; + const cpp_token **buf = NULL; + + /* Re-enable saving of comments if requested, so that the include + callback can dump comments which follow #include. */ + pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments); + + fname = parse_include (pfile, &angle_brackets, &buf); + if (!fname) + { + if (buf) + XDELETEVEC (buf); + return; + } + + if (!*fname) + { + cpp_error (pfile, CPP_DL_ERROR, "empty filename in #%s", + pfile->directive->name); + XDELETEVEC (fname); + if (buf) + XDELETEVEC (buf); + return; + } + + /* Prevent #include recursion. */ + if (pfile->line_table->depth >= CPP_STACK_MAX) + cpp_error (pfile, CPP_DL_ERROR, "#include nested too deeply"); + else + { + /* Get out of macro context, if we are. */ + skip_rest_of_line (pfile); + + if (pfile->cb.include) + pfile->cb.include (pfile, pfile->directive_line, + pfile->directive->name, fname, angle_brackets, + buf); + + _cpp_stack_include (pfile, fname, angle_brackets, type); + } + + XDELETEVEC (fname); + if (buf) + XDELETEVEC (buf); +} + +static void +do_include (cpp_reader *pfile) +{ + do_include_common (pfile, IT_INCLUDE); +} + +static void +do_import (cpp_reader *pfile) +{ + do_include_common (pfile, IT_IMPORT); +} + +static void +do_include_next (cpp_reader *pfile) +{ + enum include_type type = IT_INCLUDE_NEXT; + + /* If this is the primary source file, warn and use the normal + search logic. */ + if (! pfile->buffer->prev) + { + cpp_error (pfile, CPP_DL_WARNING, + "#include_next in primary source file"); + type = IT_INCLUDE; + } + do_include_common (pfile, type); +} + +/* Subroutine of do_linemarker. Read possible flags after file name. + LAST is the last flag seen; 0 if this is the first flag. Return the + flag if it is valid, 0 at the end of the directive. Otherwise + complain. */ +static unsigned int +read_flag (cpp_reader *pfile, unsigned int last) +{ + const cpp_token *token = _cpp_lex_token (pfile); + + if (token->type == CPP_NUMBER && token->val.str.len == 1) + { + unsigned int flag = token->val.str.text[0] - '0'; + + if (flag > last && flag <= 4 + && (flag != 4 || last == 3) + && (flag != 2 || last == 0)) + return flag; + } + + if (token->type != CPP_EOF) + cpp_error (pfile, CPP_DL_ERROR, "invalid flag \"%s\" in line directive", + cpp_token_as_text (pfile, token)); + return 0; +} + +/* Subroutine of do_line and do_linemarker. Convert a number in STR, + of length LEN, to binary; store it in NUMP, and return 0 if the + number was well-formed, 1 if not. Temporary, hopefully. */ +static int +strtoul_for_line (const uchar *str, unsigned int len, long unsigned int *nump) +{ + unsigned long reg = 0; + uchar c; + while (len--) + { + c = *str++; + if (!ISDIGIT (c)) + return 1; + reg *= 10; + reg += c - '0'; + } + *nump = reg; + return 0; +} + +/* Interpret #line command. + Note that the filename string (if any) is a true string constant + (escapes are interpreted), unlike in #line. */ +static void +do_line (cpp_reader *pfile) +{ + const struct line_maps *line_table = pfile->line_table; + const struct line_map *map = &line_table->maps[line_table->used - 1]; + + /* skip_rest_of_line() may cause line table to be realloc()ed so note down + sysp right now. */ + + unsigned char map_sysp = map->sysp; + const cpp_token *token; + const char *new_file = map->to_file; + unsigned long new_lineno; + + /* C99 raised the minimum limit on #line numbers. */ + unsigned int cap = CPP_OPTION (pfile, c99) ? 2147483647 : 32767; + + /* #line commands expand macros. */ + token = cpp_get_token (pfile); + if (token->type != CPP_NUMBER + || strtoul_for_line (token->val.str.text, token->val.str.len, + &new_lineno)) + { + cpp_error (pfile, CPP_DL_ERROR, + "\"%s\" after #line is not a positive integer", + cpp_token_as_text (pfile, token)); + return; + } + + if (CPP_PEDANTIC (pfile) && (new_lineno == 0 || new_lineno > cap)) + cpp_error (pfile, CPP_DL_PEDWARN, "line number out of range"); + + token = cpp_get_token (pfile); + if (token->type == CPP_STRING) + { + cpp_string s = { 0, 0 }; + if (cpp_interpret_string_notranslate (pfile, &token->val.str, 1, + &s, false)) + new_file = (const char *)s.text; + check_eol (pfile); + } + else if (token->type != CPP_EOF) + { + cpp_error (pfile, CPP_DL_ERROR, "\"%s\" is not a valid filename", + cpp_token_as_text (pfile, token)); + return; + } + + skip_rest_of_line (pfile); + _cpp_do_file_change (pfile, LC_RENAME, new_file, new_lineno, + map_sysp); +} + +/* Interpret the # 44 "file" [flags] notation, which has slightly + different syntax and semantics from #line: Flags are allowed, + and we never complain about the line number being too big. */ +static void +do_linemarker (cpp_reader *pfile) +{ + const struct line_maps *line_table = pfile->line_table; + const struct line_map *map = &line_table->maps[line_table->used - 1]; + const cpp_token *token; + const char *new_file = map->to_file; + unsigned long new_lineno; + unsigned int new_sysp = map->sysp; + enum lc_reason reason = LC_RENAME; + int flag; + + /* Back up so we can get the number again. Putting this in + _cpp_handle_directive risks two calls to _cpp_backup_tokens in + some circumstances, which can segfault. */ + _cpp_backup_tokens (pfile, 1); + + /* #line commands expand macros. */ + token = cpp_get_token (pfile); + if (token->type != CPP_NUMBER + || strtoul_for_line (token->val.str.text, token->val.str.len, + &new_lineno)) + { + cpp_error (pfile, CPP_DL_ERROR, + "\"%s\" after # is not a positive integer", + cpp_token_as_text (pfile, token)); + return; + } + + token = cpp_get_token (pfile); + if (token->type == CPP_STRING) + { + cpp_string s = { 0, 0 }; + if (cpp_interpret_string_notranslate (pfile, &token->val.str, + 1, &s, false)) + new_file = (const char *)s.text; + + new_sysp = 0; + flag = read_flag (pfile, 0); + if (flag == 1) + { + reason = LC_ENTER; + /* Fake an include for cpp_included (). */ + _cpp_fake_include (pfile, new_file); + flag = read_flag (pfile, flag); + } + else if (flag == 2) + { + reason = LC_LEAVE; + flag = read_flag (pfile, flag); + } + if (flag == 3) + { + new_sysp = 1; + flag = read_flag (pfile, flag); + if (flag == 4) + new_sysp = 2; + pfile->buffer->sysp = new_sysp; + } + + check_eol (pfile); + } + else if (token->type != CPP_EOF) + { + cpp_error (pfile, CPP_DL_ERROR, "\"%s\" is not a valid filename", + cpp_token_as_text (pfile, token)); + return; + } + + skip_rest_of_line (pfile); + _cpp_do_file_change (pfile, reason, new_file, new_lineno, new_sysp); +} + +/* Arrange the file_change callback. pfile->line has changed to + FILE_LINE of TO_FILE, for reason REASON. SYSP is 1 for a system + header, 2 for a system header that needs to be extern "C" protected, + and zero otherwise. */ +void +_cpp_do_file_change (cpp_reader *pfile, enum lc_reason reason, + const char *to_file, unsigned int file_line, + unsigned int sysp) +{ + const struct line_map *map = linemap_add (pfile->line_table, reason, sysp, + to_file, file_line); + if (map != NULL) + linemap_line_start (pfile->line_table, map->to_line, 127); + + if (pfile->cb.file_change) + pfile->cb.file_change (pfile, map); +} + +/* Report a warning or error detected by the program we are + processing. Use the directive's tokens in the error message. */ +static void +do_diagnostic (cpp_reader *pfile, int code, int print_dir) +{ + if (_cpp_begin_message (pfile, code, pfile->cur_token[-1].src_loc, 0)) + { + if (print_dir) + fprintf (stderr, "#%s ", pfile->directive->name); + pfile->state.prevent_expansion++; + cpp_output_line (pfile, stderr); + pfile->state.prevent_expansion--; + } +} + +static void +do_error (cpp_reader *pfile) +{ + do_diagnostic (pfile, CPP_DL_ERROR, 1); +} + +static void +do_warning (cpp_reader *pfile) +{ + /* We want #warning diagnostics to be emitted in system headers too. */ + do_diagnostic (pfile, CPP_DL_WARNING_SYSHDR, 1); +} + +/* Report program identification. */ +static void +do_ident (cpp_reader *pfile) +{ + const cpp_token *str = cpp_get_token (pfile); + + if (str->type != CPP_STRING) + cpp_error (pfile, CPP_DL_ERROR, "invalid #%s directive", + pfile->directive->name); + else if (pfile->cb.ident) + pfile->cb.ident (pfile, pfile->directive_line, &str->val.str); + + check_eol (pfile); +} + +/* Lookup a PRAGMA name in a singly-linked CHAIN. Returns the + matching entry, or NULL if none is found. The returned entry could + be the start of a namespace chain, or a pragma. */ +static struct pragma_entry * +lookup_pragma_entry (struct pragma_entry *chain, const cpp_hashnode *pragma) +{ + while (chain && chain->pragma != pragma) + chain = chain->next; + + return chain; +} + +/* Create and insert a pragma entry for NAME at the beginning of a + singly-linked CHAIN. If handler is NULL, it is a namespace, + otherwise it is a pragma and its handler. If INTERNAL is true + this pragma is being inserted by libcpp itself. */ +static struct pragma_entry * +insert_pragma_entry (cpp_reader *pfile, struct pragma_entry **chain, + const cpp_hashnode *pragma, pragma_cb handler, + bool allow_expansion, bool internal) +{ + struct pragma_entry *new_entry; + + new_entry = (struct pragma_entry *) + _cpp_aligned_alloc (pfile, sizeof (struct pragma_entry)); + new_entry->pragma = pragma; + if (handler) + { + new_entry->is_nspace = 0; + new_entry->u.handler = handler; + } + else + { + new_entry->is_nspace = 1; + new_entry->u.space = NULL; + } + + new_entry->allow_expansion = allow_expansion; + new_entry->is_internal = internal; + new_entry->next = *chain; + *chain = new_entry; + return new_entry; +} + +/* Register a pragma NAME in namespace SPACE. If SPACE is null, it + goes in the global namespace. HANDLER is the handler it will call, + which must be non-NULL. If ALLOW_EXPANSION is set, allow macro + expansion while parsing pragma NAME. INTERNAL is true if this is a + pragma registered by cpplib itself, false if it is registered via + cpp_register_pragma */ +static void +register_pragma (cpp_reader *pfile, const char *space, const char *name, + pragma_cb handler, bool allow_expansion, bool internal) +{ + struct pragma_entry **chain = &pfile->pragmas; + struct pragma_entry *entry; + const cpp_hashnode *node; + + if (!handler) + abort (); + + if (space) + { + node = cpp_lookup (pfile, U space, strlen (space)); + entry = lookup_pragma_entry (*chain, node); + if (!entry) + entry = insert_pragma_entry (pfile, chain, node, NULL, + allow_expansion, internal); + else if (!entry->is_nspace) + goto clash; + chain = &entry->u.space; + } + + /* Check for duplicates. */ + node = cpp_lookup (pfile, U name, strlen (name)); + entry = lookup_pragma_entry (*chain, node); + if (entry) + { + if (entry->is_nspace) + clash: + cpp_error (pfile, CPP_DL_ICE, + "registering \"%s\" as both a pragma and a pragma namespace", + NODE_NAME (node)); + else if (space) + cpp_error (pfile, CPP_DL_ICE, "#pragma %s %s is already registered", + space, name); + else + cpp_error (pfile, CPP_DL_ICE, "#pragma %s is already registered", name); + } + else + insert_pragma_entry (pfile, chain, node, handler, allow_expansion, + internal); +} + +/* Register a pragma NAME in namespace SPACE. If SPACE is null, it + goes in the global namespace. HANDLER is the handler it will call, + which must be non-NULL. If ALLOW_EXPANSION is set, allow macro + expansion while parsing pragma NAME. This function is exported + from libcpp. */ +void +cpp_register_pragma (cpp_reader *pfile, const char *space, const char *name, + pragma_cb handler, bool allow_expansion) +{ + register_pragma (pfile, space, name, handler, allow_expansion, false); +} + +/* Register the pragmas the preprocessor itself handles. */ +void +_cpp_init_internal_pragmas (cpp_reader *pfile) +{ + /* Pragmas in the global namespace. */ + register_pragma (pfile, 0, "once", do_pragma_once, false, true); + + /* New GCC-specific pragmas should be put in the GCC namespace. */ + register_pragma (pfile, "GCC", "poison", do_pragma_poison, false, true); + register_pragma (pfile, "GCC", "system_header", do_pragma_system_header, + false, true); + register_pragma (pfile, "GCC", "dependency", do_pragma_dependency, + false, true); + + /* Kevin abuse for SDCC. */ + cpp_register_pragma(pfile, 0, "sdcc_hash", do_pragma_sdcc_hash, false); + /* SDCC _asm specific */ + cpp_register_pragma(pfile, 0, "preproc_asm", do_pragma_preproc_asm, false); + /* SDCC specific */ + cpp_register_pragma(pfile, 0, "pedantic_parse_number", do_pragma_pedantic_parse_number, false); +} + +/* Return the number of registered pragmas in PE. */ + +static int +count_registered_pragmas (struct pragma_entry *pe) +{ + int ct = 0; + for (; pe != NULL; pe = pe->next) + { + if (pe->is_nspace) + ct += count_registered_pragmas (pe->u.space); + ct++; + } + return ct; +} + +/* Save into SD the names of the registered pragmas referenced by PE, + and return a pointer to the next free space in SD. */ + +static char ** +save_registered_pragmas (struct pragma_entry *pe, char **sd) +{ + for (; pe != NULL; pe = pe->next) + { + if (pe->is_nspace) + sd = save_registered_pragmas (pe->u.space, sd); + *sd++ = (char *) xmemdup (HT_STR (&pe->pragma->ident), + HT_LEN (&pe->pragma->ident), + HT_LEN (&pe->pragma->ident) + 1); + } + return sd; +} + +/* Return a newly-allocated array which saves the names of the + registered pragmas. */ + +char ** +_cpp_save_pragma_names (cpp_reader *pfile) +{ + int ct = count_registered_pragmas (pfile->pragmas); + char **result = XNEWVEC (char *, ct); + (void) save_registered_pragmas (pfile->pragmas, result); + return result; +} + +/* Restore from SD the names of the registered pragmas referenced by PE, + and return a pointer to the next unused name in SD. */ + +static char ** +restore_registered_pragmas (cpp_reader *pfile, struct pragma_entry *pe, + char **sd) +{ + for (; pe != NULL; pe = pe->next) + { + if (pe->is_nspace) + sd = restore_registered_pragmas (pfile, pe->u.space, sd); + pe->pragma = cpp_lookup (pfile, U *sd, strlen (*sd)); + free (*sd); + sd++; + } + return sd; +} + +/* Restore the names of the registered pragmas from SAVED. */ + +void +_cpp_restore_pragma_names (cpp_reader *pfile, char **saved) +{ + (void) restore_registered_pragmas (pfile, pfile->pragmas, saved); + free (saved); +} + +/* Pragmata handling. We handle some, and pass the rest on to the + front end. C99 defines three pragmas and says that no macro + expansion is to be performed on them; whether or not macro + expansion happens for other pragmas is implementation defined. + This implementation never macro-expands the text after #pragma. + + The library user has the option of deferring execution of + #pragmas not handled by cpplib, in which case they are converted + to CPP_PRAGMA tokens and inserted into the output stream. */ +static void +do_pragma (cpp_reader *pfile) +{ + const struct pragma_entry *p = NULL; + const cpp_token *token, *pragma_token = pfile->cur_token; + unsigned int count = 1; + + /* Save the current position so that defer_pragmas mode can + copy the entire current line to a string. It will not work + to use _cpp_backup_tokens as that does not reverse buffer->cur. */ + const uchar *line_start = CPP_BUFFER (pfile)->cur; + + pfile->state.prevent_expansion++; + + token = cpp_get_token (pfile); + if (token->type == CPP_NAME) + { + p = lookup_pragma_entry (pfile->pragmas, token->val.node); + if (p && p->is_nspace) + { + count = 2; + token = cpp_get_token (pfile); + if (token->type == CPP_NAME) + p = lookup_pragma_entry (p->u.space, token->val.node); + else + p = NULL; + } + } + + if (p) + { + if (p->is_internal || !CPP_OPTION (pfile, defer_pragmas)) + { + /* Since the handler below doesn't get the line number, that it + might need for diagnostics, make sure it has the right + numbers in place. */ + if (pfile->cb.line_change) + (*pfile->cb.line_change) (pfile, pragma_token, false); + /* Never expand macros if handling a deferred pragma, since + the macro definitions now applicable may be different + from those at the point the pragma appeared. */ + if (p->allow_expansion && !pfile->state.in_deferred_pragma) + pfile->state.prevent_expansion--; + (*p->u.handler) (pfile); + if (p->allow_expansion && !pfile->state.in_deferred_pragma) + pfile->state.prevent_expansion++; + } + else + { + /* Squirrel away the pragma text. Pragmas are + newline-terminated. */ + const uchar *line_end; + uchar *s, c, cc; + cpp_string body; + cpp_token *ptok; + + for (line_end = line_start; (c = *line_end) != '\n'; line_end++) + if (c == '"' || c == '\'') + { + /* Skip over string literal. */ + do + { + cc = *++line_end; + if (cc == '\\' && line_end[1] != '\n') + line_end++; + else if (cc == '\n') + { + line_end--; + break; + } + } + while (cc != c); + } + else if (c == '/') + { + if (line_end[1] == '*') + { + /* Skip over C block comment, unless it is multi-line. + When encountering multi-line block comment, terminate + the pragma token right before that block comment. */ + const uchar *le = line_end + 2; + while (*le != '\n') + if (*le++ == '*' && *le == '/') + { + line_end = le; + break; + } + if (line_end < le) + break; + } + else if (line_end[1] == '/' + && (CPP_OPTION (pfile, cplusplus_comments) + || cpp_in_system_header (pfile))) + { + line_end += 2; + while (*line_end != '\n') + line_end++; + break; + } + } + + body.len = (line_end - line_start) + 1; + s = _cpp_unaligned_alloc (pfile, body.len + 1); + memcpy (s, line_start, body.len - 1); + s[body.len - 1] = '\n'; + s[body.len] = '\0'; + body.text = s; + + /* Create a CPP_PRAGMA token. */ + ptok = &pfile->directive_result; + ptok->src_loc = pragma_token->src_loc; + ptok->type = CPP_PRAGMA; + ptok->flags = pragma_token->flags | NO_EXPAND; + ptok->val.str = body; + } + } + else if (pfile->cb.def_pragma) + { + _cpp_backup_tokens (pfile, count); + pfile->cb.def_pragma (pfile, pfile->directive_line); + } + + pfile->state.prevent_expansion--; +} + +/* Handle #pragma once. */ +static void +do_pragma_once (cpp_reader *pfile) +{ + if (pfile->buffer->prev == NULL) + cpp_error (pfile, CPP_DL_WARNING, "#pragma once in main file"); + + check_eol (pfile); + _cpp_mark_file_once_only (pfile, pfile->buffer->file); +} + +/* Handle #pragma GCC poison, to poison one or more identifiers so + that the lexer produces a hard error for each subsequent usage. */ +static void +do_pragma_poison (cpp_reader *pfile) +{ + const cpp_token *tok; + cpp_hashnode *hp; + + pfile->state.poisoned_ok = 1; + for (;;) + { + tok = _cpp_lex_token (pfile); + if (tok->type == CPP_EOF) + break; + if (tok->type != CPP_NAME) + { + cpp_error (pfile, CPP_DL_ERROR, + "invalid #pragma GCC poison directive"); + break; + } + + hp = tok->val.node; + if (hp->flags & NODE_POISONED) + continue; + + if (hp->type == NT_MACRO) + cpp_error (pfile, CPP_DL_WARNING, "poisoning existing macro \"%s\"", + NODE_NAME (hp)); + _cpp_free_definition (hp); + hp->flags |= NODE_POISONED | NODE_DIAGNOSTIC; + } + pfile->state.poisoned_ok = 0; +} + +/* SDCC specific + sdcc_hash pragma */ +static void +do_pragma_sdcc_hash (cpp_reader *pfile) +{ + const cpp_token *tok = _cpp_lex_token (pfile); + + if (tok->type == CPP_PLUS) + { + CPP_OPTION(pfile, allow_naked_hash)++; + } + else if (tok->type == CPP_MINUS) + { + CPP_OPTION(pfile, allow_naked_hash)--; + } + else + { + cpp_error (pfile, CPP_DL_ERROR, + "invalid #pragma sdcc_hash directive, need '+' or '-'"); + } +} + +/* SDCC specific + pedantic_parse_number pragma */ +static void +do_pragma_pedantic_parse_number (cpp_reader *pfile) +{ + const cpp_token *tok = _cpp_lex_token (pfile); + + if (tok->type == CPP_PLUS) + { + CPP_OPTION(pfile, pedantic_parse_number)++; + } + else if (tok->type == CPP_MINUS) + { + CPP_OPTION(pfile, pedantic_parse_number)--; + } + else + { + cpp_error (pfile, CPP_DL_ERROR, + "invalid #pragma pedantic_parse_number directive, need '+' or '-'"); + } +} + +/* SDCC _asm specific + switch _asm block preprocessing on / off */ +static void +do_pragma_preproc_asm (cpp_reader *pfile) +{ + const cpp_token *tok = _cpp_lex_token (pfile); + + if (tok->type == CPP_PLUS) + { + CPP_OPTION(pfile, preproc_asm)++; + } + else if (tok->type == CPP_MINUS) + { + CPP_OPTION(pfile, preproc_asm)--; + } + else + { + cpp_error (pfile, CPP_DL_ERROR, + "invalid #pragma preproc_asm directive, need '+' or '-'"); + } +} + +/* Mark the current header as a system header. This will suppress + some categories of warnings (notably those from -pedantic). It is + intended for use in system libraries that cannot be implemented in + conforming C, but cannot be certain that their headers appear in a + system include directory. To prevent abuse, it is rejected in the + primary source file. */ +static void +do_pragma_system_header (cpp_reader *pfile) +{ + cpp_buffer *buffer = pfile->buffer; + + if (buffer->prev == 0) + cpp_error (pfile, CPP_DL_WARNING, + "#pragma system_header ignored outside include file"); + else + { + check_eol (pfile); + skip_rest_of_line (pfile); + cpp_make_system_header (pfile, 1, 0); + } +} + +/* Check the modified date of the current include file against a specified + file. Issue a diagnostic, if the specified file is newer. We use this to + determine if a fixed header should be refixed. */ +static void +do_pragma_dependency (cpp_reader *pfile) +{ + const char *fname; + int angle_brackets, ordering; + + fname = parse_include (pfile, &angle_brackets, NULL); + if (!fname) + return; + + ordering = _cpp_compare_file_date (pfile, fname, angle_brackets); + if (ordering < 0) + cpp_error (pfile, CPP_DL_WARNING, "cannot find source file %s", fname); + else if (ordering > 0) + { + cpp_error (pfile, CPP_DL_WARNING, + "current file is older than %s", fname); + if (cpp_get_token (pfile)->type != CPP_EOF) + { + _cpp_backup_tokens (pfile, 1); + do_diagnostic (pfile, CPP_DL_WARNING, 0); + } + } + + free ((void *) fname); +} + +/* Get a token but skip padding. */ +static const cpp_token * +get_token_no_padding (cpp_reader *pfile) +{ + for (;;) + { + const cpp_token *result = cpp_get_token (pfile); + if (result->type != CPP_PADDING) + return result; + } +} + +/* Check syntax is "(string-literal)". Returns the string on success, + or NULL on failure. */ +static const cpp_token * +get__Pragma_string (cpp_reader *pfile) +{ + const cpp_token *string; + + if (get_token_no_padding (pfile)->type != CPP_OPEN_PAREN) + return NULL; + + string = get_token_no_padding (pfile); + if (string->type != CPP_STRING && string->type != CPP_WSTRING) + return NULL; + + if (get_token_no_padding (pfile)->type != CPP_CLOSE_PAREN) + return NULL; + + return string; +} + +/* Destringize IN into a temporary buffer, by removing the first \ of + \" and \\ sequences, and process the result as a #pragma directive. */ +static void +destringize_and_run (cpp_reader *pfile, const cpp_string *in) +{ + const unsigned char *src, *limit; + char *dest, *result; + + dest = result = (char *) alloca (in->len - 1); + src = in->text + 1 + (in->text[0] == 'L'); + limit = in->text + in->len - 1; + while (src < limit) + { + /* We know there is a character following the backslash. */ + if (*src == '\\' && (src[1] == '\\' || src[1] == '"')) + src++; + *dest++ = *src++; + } + *dest = '\n'; + + /* Ugh; an awful kludge. We are really not set up to be lexing + tokens when in the middle of a macro expansion. Use a new + context to force cpp_get_token to lex, and so skip_rest_of_line + doesn't go beyond the end of the text. Also, remember the + current lexing position so we can return to it later. + + Something like line-at-a-time lexing should remove the need for + this. */ + { + cpp_context *saved_context = pfile->context; + cpp_token *saved_cur_token = pfile->cur_token; + tokenrun *saved_cur_run = pfile->cur_run; + + pfile->context = XNEW (cpp_context); + pfile->context->macro = 0; + pfile->context->prev = 0; + run_directive (pfile, T_PRAGMA, result, dest - result); + XDELETE (pfile->context); + pfile->context = saved_context; + pfile->cur_token = saved_cur_token; + pfile->cur_run = saved_cur_run; + } + + /* See above comment. For the moment, we'd like + + token1 _Pragma ("foo") token2 + + to be output as + + token1 + # 7 "file.c" + #pragma foo + # 7 "file.c" + token2 + + Getting the line markers is a little tricky. */ + if (pfile->cb.line_change) + pfile->cb.line_change (pfile, pfile->cur_token, false); +} + +/* Handle the _Pragma operator. */ +void +_cpp_do__Pragma (cpp_reader *pfile) +{ + const cpp_token *string = get__Pragma_string (pfile); + pfile->directive_result.type = CPP_PADDING; + + if (string) + destringize_and_run (pfile, &string->val.str); + else + cpp_error (pfile, CPP_DL_ERROR, + "_Pragma takes a parenthesized string literal"); +} + +/* Handle a pragma that the front end deferred until now. */ +void +cpp_handle_deferred_pragma (cpp_reader *pfile, const cpp_string *s) +{ + cpp_context *saved_context = pfile->context; + cpp_token *saved_cur_token = pfile->cur_token; + tokenrun *saved_cur_run = pfile->cur_run; + bool saved_defer_pragmas = CPP_OPTION (pfile, defer_pragmas); + void (*saved_line_change) (cpp_reader *, const cpp_token *, int) + = pfile->cb.line_change; + + pfile->context = XNEW (cpp_context); + pfile->context->macro = 0; + pfile->context->prev = 0; + pfile->cb.line_change = NULL; + pfile->state.in_deferred_pragma = true; + CPP_OPTION (pfile, defer_pragmas) = false; + + run_directive (pfile, T_PRAGMA, (const char *)s->text, s->len); + + XDELETE (pfile->context); + pfile->context = saved_context; + pfile->cur_token = saved_cur_token; + pfile->cur_run = saved_cur_run; + pfile->cb.line_change = saved_line_change; + pfile->state.in_deferred_pragma = false; + CPP_OPTION (pfile, defer_pragmas) = saved_defer_pragmas; +} + +/* Handle #ifdef. */ +static void +do_ifdef (cpp_reader *pfile) +{ + int skip = 1; + + if (! pfile->state.skipping) + { + const cpp_hashnode *node = lex_macro_node (pfile); + + if (node) + { + skip = node->type != NT_MACRO; + _cpp_mark_macro_used (node); + check_eol (pfile); + } + } + + push_conditional (pfile, skip, T_IFDEF, 0); +} + +/* Handle #ifndef. */ +static void +do_ifndef (cpp_reader *pfile) +{ + int skip = 1; + const cpp_hashnode *node = 0; + + if (! pfile->state.skipping) + { + node = lex_macro_node (pfile); + + if (node) + { + skip = node->type == NT_MACRO; + _cpp_mark_macro_used (node); + check_eol (pfile); + } + } + + push_conditional (pfile, skip, T_IFNDEF, node); +} + +/* _cpp_parse_expr puts a macro in a "#if !defined ()" expression in + pfile->mi_ind_cmacro so we can handle multiple-include + optimizations. If macro expansion occurs in the expression, we + cannot treat it as a controlling conditional, since the expansion + could change in the future. That is handled by cpp_get_token. */ +static void +do_if (cpp_reader *pfile) +{ + int skip = 1; + + if (! pfile->state.skipping) + skip = _cpp_parse_expr (pfile) == false; + + push_conditional (pfile, skip, T_IF, pfile->mi_ind_cmacro); +} + +/* Flip skipping state if appropriate and continue without changing + if_stack; this is so that the error message for missing #endif's + etc. will point to the original #if. */ +static void +do_else (cpp_reader *pfile) +{ + cpp_buffer *buffer = pfile->buffer; + struct if_stack *ifs = buffer->if_stack; + + if (ifs == NULL) + cpp_error (pfile, CPP_DL_ERROR, "#else without #if"); + else + { + if (ifs->type == T_ELSE) + { + cpp_error (pfile, CPP_DL_ERROR, "#else after #else"); + cpp_error_with_line (pfile, CPP_DL_ERROR, ifs->line, 0, + "the conditional began here"); + } + ifs->type = T_ELSE; + + /* Skip any future (erroneous) #elses or #elifs. */ + pfile->state.skipping = ifs->skip_elses; + ifs->skip_elses = true; + + /* Invalidate any controlling macro. */ + ifs->mi_cmacro = 0; + + /* Only check EOL if was not originally skipping. */ + if (!ifs->was_skipping && CPP_OPTION (pfile, warn_endif_labels)) + check_eol (pfile); + } +} + +/* Handle a #elif directive by not changing if_stack either. See the + comment above do_else. */ +static void +do_elif (cpp_reader *pfile) +{ + cpp_buffer *buffer = pfile->buffer; + struct if_stack *ifs = buffer->if_stack; + + if (ifs == NULL) + cpp_error (pfile, CPP_DL_ERROR, "#elif without #if"); + else + { + if (ifs->type == T_ELSE) + { + cpp_error (pfile, CPP_DL_ERROR, "#elif after #else"); + cpp_error_with_line (pfile, CPP_DL_ERROR, ifs->line, 0, + "the conditional began here"); + } + ifs->type = T_ELIF; + + /* Only evaluate this if we aren't skipping elses. During + evaluation, set skipping to false to get lexer warnings. */ + if (ifs->skip_elses) + pfile->state.skipping = 1; + else + { + pfile->state.skipping = 0; + pfile->state.skipping = ! _cpp_parse_expr (pfile); + ifs->skip_elses = ! pfile->state.skipping; + } + + /* Invalidate any controlling macro. */ + ifs->mi_cmacro = 0; + } +} + +/* #endif pops the if stack and resets pfile->state.skipping. */ +static void +do_endif (cpp_reader *pfile) +{ + cpp_buffer *buffer = pfile->buffer; + struct if_stack *ifs = buffer->if_stack; + + if (ifs == NULL) + cpp_error (pfile, CPP_DL_ERROR, "#endif without #if"); + else + { + /* Only check EOL if was not originally skipping. */ + if (!ifs->was_skipping && CPP_OPTION (pfile, warn_endif_labels)) + check_eol (pfile); + + /* If potential control macro, we go back outside again. */ + if (ifs->next == 0 && ifs->mi_cmacro) + { + pfile->mi_valid = true; + pfile->mi_cmacro = ifs->mi_cmacro; + } + + buffer->if_stack = ifs->next; + pfile->state.skipping = ifs->was_skipping; + obstack_free (&pfile->buffer_ob, ifs); + } +} + +/* Push an if_stack entry for a preprocessor conditional, and set + pfile->state.skipping to SKIP. If TYPE indicates the conditional + is #if or #ifndef, CMACRO is a potentially controlling macro, and + we need to check here that we are at the top of the file. */ +static void +push_conditional (cpp_reader *pfile, int skip, int type, + const cpp_hashnode *cmacro) +{ + struct if_stack *ifs; + cpp_buffer *buffer = pfile->buffer; + + ifs = XOBNEW (&pfile->buffer_ob, struct if_stack); + ifs->line = pfile->directive_line; + ifs->next = buffer->if_stack; + ifs->skip_elses = pfile->state.skipping || !skip; + ifs->was_skipping = pfile->state.skipping; + ifs->type = type; + /* This condition is effectively a test for top-of-file. */ + if (pfile->mi_valid && pfile->mi_cmacro == 0) + ifs->mi_cmacro = cmacro; + else + ifs->mi_cmacro = 0; + + pfile->state.skipping = skip; + buffer->if_stack = ifs; +} + +/* Read the tokens of the answer into the macro pool, in a directive + of type TYPE. Only commit the memory if we intend it as permanent + storage, i.e. the #assert case. Returns 0 on success, and sets + ANSWERP to point to the answer. */ +static int +parse_answer (cpp_reader *pfile, struct answer **answerp, int type) +{ + const cpp_token *paren; + struct answer *answer; + unsigned int acount; + + /* In a conditional, it is legal to not have an open paren. We + should save the following token in this case. */ + paren = cpp_get_token (pfile); + + /* If not a paren, see if we're OK. */ + if (paren->type != CPP_OPEN_PAREN) + { + /* In a conditional no answer is a test for any answer. It + could be followed by any token. */ + if (type == T_IF) + { + _cpp_backup_tokens (pfile, 1); + return 0; + } + + /* #unassert with no answer is valid - it removes all answers. */ + if (type == T_UNASSERT && paren->type == CPP_EOF) + return 0; + + cpp_error (pfile, CPP_DL_ERROR, "missing '(' after predicate"); + return 1; + } + + for (acount = 0;; acount++) + { + size_t room_needed; + const cpp_token *token = cpp_get_token (pfile); + cpp_token *dest; + + if (token->type == CPP_CLOSE_PAREN) + break; + + if (token->type == CPP_EOF) + { + cpp_error (pfile, CPP_DL_ERROR, "missing ')' to complete answer"); + return 1; + } + + /* struct answer includes the space for one token. */ + room_needed = (sizeof (struct answer) + acount * sizeof (cpp_token)); + + if (BUFF_ROOM (pfile->a_buff) < room_needed) + _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (struct answer)); + + dest = &((struct answer *) BUFF_FRONT (pfile->a_buff))->first[acount]; + *dest = *token; + + /* Drop whitespace at start, for answer equivalence purposes. */ + if (acount == 0) + dest->flags &= ~PREV_WHITE; + } + + if (acount == 0) + { + cpp_error (pfile, CPP_DL_ERROR, "predicate's answer is empty"); + return 1; + } + + answer = (struct answer *) BUFF_FRONT (pfile->a_buff); + answer->count = acount; + answer->next = NULL; + *answerp = answer; + + return 0; +} + +/* Parses an assertion directive of type TYPE, returning a pointer to + the hash node of the predicate, or 0 on error. If an answer was + supplied, it is placed in ANSWERP, otherwise it is set to 0. */ +static cpp_hashnode * +parse_assertion (cpp_reader *pfile, struct answer **answerp, int type) +{ + cpp_hashnode *result = 0; + const cpp_token *predicate; + + /* We don't expand predicates or answers. */ + pfile->state.prevent_expansion++; + + *answerp = 0; + predicate = cpp_get_token (pfile); + if (predicate->type == CPP_EOF) + cpp_error (pfile, CPP_DL_ERROR, "assertion without predicate"); + else if (predicate->type != CPP_NAME) + cpp_error (pfile, CPP_DL_ERROR, "predicate must be an identifier"); + else if (parse_answer (pfile, answerp, type) == 0) + { + unsigned int len = NODE_LEN (predicate->val.node); + unsigned char *sym = (unsigned char *) alloca (len + 1); + + /* Prefix '#' to get it out of macro namespace. */ + sym[0] = '#'; + memcpy (sym + 1, NODE_NAME (predicate->val.node), len); + result = cpp_lookup (pfile, sym, len + 1); + } + + pfile->state.prevent_expansion--; + return result; +} + +/* Returns a pointer to the pointer to CANDIDATE in the answer chain, + or a pointer to NULL if the answer is not in the chain. */ +static struct answer ** +find_answer (cpp_hashnode *node, const struct answer *candidate) +{ + unsigned int i; + struct answer **result; + + for (result = &node->value.answers; *result; result = &(*result)->next) + { + struct answer *answer = *result; + + if (answer->count == candidate->count) + { + for (i = 0; i < answer->count; i++) + if (! _cpp_equiv_tokens (&answer->first[i], &candidate->first[i])) + break; + + if (i == answer->count) + break; + } + } + + return result; +} + +/* Test an assertion within a preprocessor conditional. Returns + nonzero on failure, zero on success. On success, the result of + the test is written into VALUE, otherwise the value 0. */ +int +_cpp_test_assertion (cpp_reader *pfile, unsigned int *value) +{ + struct answer *answer; + cpp_hashnode *node; + + node = parse_assertion (pfile, &answer, T_IF); + + /* For recovery, an erroneous assertion expression is handled as a + failing assertion. */ + *value = 0; + + if (node) + *value = (node->type == NT_ASSERTION && + (answer == 0 || *find_answer (node, answer) != 0)); + else if (pfile->cur_token[-1].type == CPP_EOF) + _cpp_backup_tokens (pfile, 1); + + /* We don't commit the memory for the answer - it's temporary only. */ + return node == 0; +} + +/* Handle #assert. */ +static void +do_assert (cpp_reader *pfile) +{ + struct answer *new_answer; + cpp_hashnode *node; + + node = parse_assertion (pfile, &new_answer, T_ASSERT); + if (node) + { + size_t answer_size; + + /* Place the new answer in the answer list. First check there + is not a duplicate. */ + new_answer->next = 0; + if (node->type == NT_ASSERTION) + { + if (*find_answer (node, new_answer)) + { + cpp_error (pfile, CPP_DL_WARNING, "\"%s\" re-asserted", + NODE_NAME (node) + 1); + return; + } + new_answer->next = node->value.answers; + } + + answer_size = sizeof (struct answer) + ((new_answer->count - 1) + * sizeof (cpp_token)); + /* Commit or allocate storage for the object. */ + if (pfile->hash_table->alloc_subobject) + { + struct answer *temp_answer = new_answer; + new_answer = (struct answer *) pfile->hash_table->alloc_subobject + (answer_size); + memcpy (new_answer, temp_answer, answer_size); + } + else + BUFF_FRONT (pfile->a_buff) += answer_size; + + node->type = NT_ASSERTION; + node->value.answers = new_answer; + check_eol (pfile); + } +} + +/* Handle #unassert. */ +static void +do_unassert (cpp_reader *pfile) +{ + cpp_hashnode *node; + struct answer *answer; + + node = parse_assertion (pfile, &answer, T_UNASSERT); + /* It isn't an error to #unassert something that isn't asserted. */ + if (node && node->type == NT_ASSERTION) + { + if (answer) + { + struct answer **p = find_answer (node, answer), *temp; + + /* Remove the answer from the list. */ + temp = *p; + if (temp) + *p = temp->next; + + /* Did we free the last answer? */ + if (node->value.answers == 0) + node->type = NT_VOID; + + check_eol (pfile); + } + else + _cpp_free_definition (node); + } + + /* We don't commit the memory for the answer - it's temporary only. */ +} + +/* These are for -D, -U, -A. */ + +/* Process the string STR as if it appeared as the body of a #define. + If STR is just an identifier, define it with value 1. + If STR has anything after the identifier, then it should + be identifier=definition. */ +void +cpp_define (cpp_reader *pfile, const char *str) +{ + char *buf, *p; + size_t count; + + /* Copy the entire option so we can modify it. + Change the first "=" in the string to a space. If there is none, + tack " 1" on the end. */ + + count = strlen (str); + buf = (char *) alloca (count + 3); + memcpy (buf, str, count); + + p = strchr (str, '='); + if (p) + buf[p - str] = ' '; + else + { + buf[count++] = ' '; + buf[count++] = '1'; + } + buf[count] = '\n'; + + run_directive (pfile, T_DEFINE, buf, count); +} + +/* Slight variant of the above for use by initialize_builtins. */ +void +_cpp_define_builtin (cpp_reader *pfile, const char *str) +{ + size_t len = strlen (str); + char *buf = (char *) alloca (len + 1); + memcpy (buf, str, len); + buf[len] = '\n'; + run_directive (pfile, T_DEFINE, buf, len); +} + +/* Process MACRO as if it appeared as the body of an #undef. */ +void +cpp_undef (cpp_reader *pfile, const char *macro) +{ + size_t len = strlen (macro); + char *buf = (char *) alloca (len + 1); + memcpy (buf, macro, len); + buf[len] = '\n'; + run_directive (pfile, T_UNDEF, buf, len); +} + +/* Process the string STR as if it appeared as the body of a #assert. */ +void +cpp_assert (cpp_reader *pfile, const char *str) +{ + handle_assertion (pfile, str, T_ASSERT); +} + +/* Process STR as if it appeared as the body of an #unassert. */ +void +cpp_unassert (cpp_reader *pfile, const char *str) +{ + handle_assertion (pfile, str, T_UNASSERT); +} + +/* Common code for cpp_assert (-A) and cpp_unassert (-A-). */ +static void +handle_assertion (cpp_reader *pfile, const char *str, int type) +{ + size_t count = strlen (str); + const char *p = strchr (str, '='); + + /* Copy the entire option so we can modify it. Change the first + "=" in the string to a '(', and tack a ')' on the end. */ + char *buf = (char *) alloca (count + 2); + + memcpy (buf, str, count); + if (p) + { + buf[p - str] = '('; + buf[count++] = ')'; + } + buf[count] = '\n'; + str = buf; + + run_directive (pfile, type, str, count); +} + +/* The number of errors for a given reader. */ +unsigned int +cpp_errors (cpp_reader *pfile) +{ + return pfile->errors; +} + +/* The options structure. */ +cpp_options * +cpp_get_options (cpp_reader *pfile) +{ + return &pfile->opts; +} + +/* The callbacks structure. */ +cpp_callbacks * +cpp_get_callbacks (cpp_reader *pfile) +{ + return &pfile->cb; +} + +/* Copy the given callbacks structure to our own. */ +void +cpp_set_callbacks (cpp_reader *pfile, cpp_callbacks *cb) +{ + pfile->cb = *cb; +} + +/* The dependencies structure. (Creates one if it hasn't already been.) */ +struct deps * +cpp_get_deps (cpp_reader *pfile) +{ + if (!pfile->deps) + pfile->deps = deps_init (); + return pfile->deps; +} + +/* Push a new buffer on the buffer stack. Returns the new buffer; it + doesn't fail. It does not generate a file change call back; that + is the responsibility of the caller. */ +cpp_buffer * +cpp_push_buffer (cpp_reader *pfile, const uchar *buffer, size_t len, + int from_stage3) +{ + cpp_buffer *new_buffer = XOBNEW (&pfile->buffer_ob, cpp_buffer); + + /* Clears, amongst other things, if_stack and mi_cmacro. */ + memset (new_buffer, 0, sizeof (cpp_buffer)); + + new_buffer->next_line = new_buffer->buf = buffer; + new_buffer->rlimit = buffer + len; + new_buffer->from_stage3 = from_stage3; + new_buffer->prev = pfile->buffer; + new_buffer->need_line = true; + + pfile->buffer = new_buffer; + + return new_buffer; +} + +/* Pops a single buffer, with a file change call-back if appropriate. + Then pushes the next -include file, if any remain. */ +void +_cpp_pop_buffer (cpp_reader *pfile) +{ + cpp_buffer *buffer = pfile->buffer; + struct _cpp_file *inc = buffer->file; + struct if_stack *ifs; + + /* Walk back up the conditional stack till we reach its level at + entry to this file, issuing error messages. */ + for (ifs = buffer->if_stack; ifs; ifs = ifs->next) + cpp_error_with_line (pfile, CPP_DL_ERROR, ifs->line, 0, + "unterminated #%s", dtable[ifs->type].name); + + /* In case of a missing #endif. */ + pfile->state.skipping = 0; + + /* _cpp_do_file_change expects pfile->buffer to be the new one. */ + pfile->buffer = buffer->prev; + + free (buffer->notes); + + /* Free the buffer object now; we may want to push a new buffer + in _cpp_push_next_include_file. */ + obstack_free (&pfile->buffer_ob, buffer); + + if (inc) + { + _cpp_pop_file_buffer (pfile, inc); + + _cpp_do_file_change (pfile, LC_LEAVE, 0, 0, 0); + } +} + +/* Enter all recognized directives in the hash table. */ +void +_cpp_init_directives (cpp_reader *pfile) +{ + unsigned int i; + cpp_hashnode *node; + + for (i = 0; i < (unsigned int) N_DIRECTIVES; i++) + { + node = cpp_lookup (pfile, dtable[i].name, dtable[i].length); + node->is_directive = 1; + node->directive_index = i; + } +} diff --git a/support/cpp2/libcpp/errors.c b/support/cpp2/libcpp/errors.c new file mode 100644 index 00000000..97de4900 --- /dev/null +++ b/support/cpp2/libcpp/errors.c @@ -0,0 +1,189 @@ +/* Default error handlers for CPP Library. + Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1998, 1999, 2000, + 2001, 2002, 2004 Free Software Foundation, Inc. + Written by Per Bothner, 1994. + Based on CCCP program by Paul Rubin, June 1986 + Adapted to ANSI C, Richard Stallman, Jan 1987 + +This program 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 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +#include "config.h" +#include "system.h" +#include "cpplib.h" +#include "internal.h" + +static void print_location (cpp_reader *, source_location, unsigned int); + +/* Print the logical file location (LINE, COL) in preparation for a + diagnostic. Outputs the #include chain if it has changed. A line + of zero suppresses the include stack, and outputs the program name + instead. */ +static void +print_location (cpp_reader *pfile, source_location line, unsigned int col) +{ + if (line == 0) + fprintf (stderr, "%s: ", progname); + else + { + const struct line_map *map; + unsigned int lin; + + map = linemap_lookup (pfile->line_table, line); + linemap_print_containing_files (pfile->line_table, map); + + lin = SOURCE_LINE (map, line); + if (col == 0) + { + col = SOURCE_COLUMN (map, line); + if (col == 0) + col = 1; + } + + if (lin == 0) + fprintf (stderr, "%s:", map->to_file); + else if (CPP_OPTION (pfile, show_column) == 0) + fprintf (stderr, "%s:%u:", map->to_file, lin); + else + fprintf (stderr, "%s:%u:%u:", map->to_file, lin, col); + + fputc (' ', stderr); + } +} + +/* Set up for a diagnostic: print the file and line, bump the error + counter, etc. SRC_LOC is the logical line number; zero means to print + at the location of the previously lexed token, which tends to be + the correct place by default. The column number can be specified either + using COLUMN or (if COLUMN==0) extracting SOURCE_COLUMN from SRC_LOC. + (This may seem redundant, but is useful when pre-scanning (cleaning) a line, + when we haven't yet verified whether the current line_map has a + big enough max_column_hint.) + + Returns 0 if the error has been suppressed. */ +int +_cpp_begin_message (cpp_reader *pfile, int code, + source_location src_loc, unsigned int column) +{ + int level = CPP_DL_EXTRACT (code); + + switch (level) + { + case CPP_DL_WARNING: + case CPP_DL_PEDWARN: + if (cpp_in_system_header (pfile) + && ! CPP_OPTION (pfile, warn_system_headers)) + return 0; + /* Fall through. */ + + case CPP_DL_WARNING_SYSHDR: + if (CPP_OPTION (pfile, warnings_are_errors) + || (level == CPP_DL_PEDWARN && CPP_OPTION (pfile, pedantic_errors))) + { + if (CPP_OPTION (pfile, inhibit_errors)) + return 0; + level = CPP_DL_ERROR; + pfile->errors++; + } + else if (CPP_OPTION (pfile, inhibit_warnings)) + return 0; + break; + + case CPP_DL_ERROR: + if (CPP_OPTION (pfile, inhibit_errors)) + return 0; + /* ICEs cannot be inhibited. */ + case CPP_DL_ICE: + pfile->errors++; + break; + } + + print_location (pfile, src_loc, column); + if (CPP_DL_WARNING_P (level)) + fputs (_("warning: "), stderr); + else if (level == CPP_DL_ICE) + fputs (_("internal error: "), stderr); + else + fputs (_("error: "), stderr); + + return 1; +} + +/* Don't remove the blank before do, as otherwise the exgettext + script will mistake this as a function definition */ +#define v_message(msgid, ap) \ + do { vfprintf (stderr, _(msgid), ap); putc ('\n', stderr); } while (0) + +/* Exported interface. */ + +/* Print an error at the location of the previously lexed token. */ +void +cpp_error (cpp_reader * pfile, int level, const char *msgid, ...) +{ + source_location src_loc; + va_list ap; + + va_start (ap, msgid); + + if (CPP_OPTION (pfile, client_diagnostic)) + pfile->cb.error (pfile, level, _(msgid), &ap); + else + { + if (CPP_OPTION (pfile, traditional)) + { + if (pfile->state.in_directive) + src_loc = pfile->directive_line; + else + src_loc = pfile->line_table->highest_line; + } + else + { + src_loc = pfile->cur_token[-1].src_loc; + } + + if (_cpp_begin_message (pfile, level, src_loc, 0)) + v_message (msgid, ap); + } + + va_end (ap); +} + +/* Print an error at a specific location. */ +void +cpp_error_with_line (cpp_reader *pfile, int level, + source_location src_loc, unsigned int column, + const char *msgid, ...) +{ + va_list ap; + + va_start (ap, msgid); + + if (_cpp_begin_message (pfile, level, src_loc, column)) + v_message (msgid, ap); + + va_end (ap); +} + +void +cpp_errno (cpp_reader *pfile, int level, const char *msgid) +{ + if (msgid[0] == '\0') + msgid = _("stdout"); + + cpp_error (pfile, level, "%s: %s", msgid, xstrerror (errno)); +} diff --git a/support/cpp2/libcpp/expr.c b/support/cpp2/libcpp/expr.c new file mode 100644 index 00000000..32b17238 --- /dev/null +++ b/support/cpp2/libcpp/expr.c @@ -0,0 +1,1544 @@ +/* Parse C expressions for cpplib. + Copyright (C) 1987, 1992, 1994, 1995, 1997, 1998, 1999, 2000, 2001, + 2002, 2004 Free Software Foundation. + Contributed by Per Bothner, 1994. + +This program 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 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include "config.h" +#include "system.h" +#include "cpplib.h" +#include "internal.h" + +#define PART_PRECISION (sizeof (cpp_num_part) * CHAR_BIT) +#define HALF_MASK (~(cpp_num_part) 0 >> (PART_PRECISION / 2)) +#define LOW_PART(num_part) (num_part & HALF_MASK) +#define HIGH_PART(num_part) (num_part >> (PART_PRECISION / 2)) + +struct op +{ + const cpp_token *token; /* The token forming op (for diagnostics). */ + cpp_num value; /* The value logically "right" of op. */ + enum cpp_ttype op; +}; + +/* Some simple utility routines on double integers. */ +#define num_zerop(num) ((num.low | num.high) == 0) +#define num_eq(num1, num2) (num1.low == num2.low && num1.high == num2.high) +static bool num_positive (cpp_num, size_t); +static bool num_greater_eq (cpp_num, cpp_num, size_t); +static cpp_num num_trim (cpp_num, size_t); +static cpp_num num_part_mul (cpp_num_part, cpp_num_part); + +static cpp_num num_unary_op (cpp_reader *, cpp_num, enum cpp_ttype); +static cpp_num num_binary_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype); +static cpp_num num_negate (cpp_num, size_t); +static cpp_num num_bitwise_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype); +static cpp_num num_inequality_op (cpp_reader *, cpp_num, cpp_num, + enum cpp_ttype); +static cpp_num num_equality_op (cpp_reader *, cpp_num, cpp_num, + enum cpp_ttype); +static cpp_num num_mul (cpp_reader *, cpp_num, cpp_num); +static cpp_num num_div_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype); +static cpp_num num_lshift (cpp_num, size_t, size_t); +static cpp_num num_rshift (cpp_num, size_t, size_t); + +static cpp_num append_digit (cpp_num, int, int, size_t); +static cpp_num parse_defined (cpp_reader *); +static cpp_num eval_token (cpp_reader *, const cpp_token *); +static struct op *reduce (cpp_reader *, struct op *, enum cpp_ttype); +static unsigned int interpret_float_suffix (const uchar *, size_t); +static unsigned int interpret_int_suffix (const uchar *, size_t); +static void check_promotion (cpp_reader *, const struct op *); + +/* Token type abuse to create unary plus and minus operators. */ +#define CPP_UPLUS ((enum cpp_ttype) (CPP_LAST_CPP_OP + 1)) +#define CPP_UMINUS ((enum cpp_ttype) (CPP_LAST_CPP_OP + 2)) + +/* With -O2, gcc appears to produce nice code, moving the error + message load and subsequent jump completely out of the main path. */ +#define SYNTAX_ERROR(msgid) \ + do { cpp_error (pfile, CPP_DL_ERROR, msgid); goto syntax_error; } while(0) +#define SYNTAX_ERROR2(msgid, arg) \ + do { cpp_error (pfile, CPP_DL_ERROR, msgid, arg); goto syntax_error; } \ + while(0) + +/* Subroutine of cpp_classify_number. S points to a float suffix of + length LEN, possibly zero. Returns 0 for an invalid suffix, or a + flag vector describing the suffix. */ +static unsigned int +interpret_float_suffix (const uchar *s, size_t len) +{ + size_t f = 0, l = 0, i = 0; + + while (len--) + switch (s[len]) + { + case 'f': case 'F': f++; break; + case 'l': case 'L': l++; break; + case 'i': case 'I': + case 'j': case 'J': i++; break; + default: + return 0; + } + + if (f + l > 1 || i > 1) + return 0; + + return ((i ? CPP_N_IMAGINARY : 0) + | (f ? CPP_N_SMALL : + l ? CPP_N_LARGE : CPP_N_MEDIUM)); +} + +/* Subroutine of cpp_classify_number. S points to an integer suffix + of length LEN, possibly zero. Returns 0 for an invalid suffix, or a + flag vector describing the suffix. */ +static unsigned int +interpret_int_suffix (const uchar *s, size_t len) +{ + size_t u, l, i; + + u = l = i = 0; + + while (len--) + switch (s[len]) + { + case 'u': case 'U': u++; break; + case 'i': case 'I': + case 'j': case 'J': i++; break; + case 'l': case 'L': l++; + /* If there are two Ls, they must be adjacent and the same case. */ + if (l == 2 && s[len] != s[len + 1]) + return 0; + break; + default: + return 0; + } + + if (l > 2 || u > 1 || i > 1) + return 0; + + return ((i ? CPP_N_IMAGINARY : 0) + | (u ? CPP_N_UNSIGNED : 0) + | ((l == 0) ? CPP_N_SMALL + : (l == 1) ? CPP_N_MEDIUM : CPP_N_LARGE)); +} + +/* Categorize numeric constants according to their field (integer, + floating point, or invalid), radix (decimal, octal, hexadecimal), + and type suffixes. */ +unsigned int +cpp_classify_number (cpp_reader *pfile, const cpp_token *token) +{ + const uchar *str = token->val.str.text; + const uchar *limit; + unsigned int max_digit, result, radix; + enum {NOT_FLOAT = 0, AFTER_POINT, AFTER_EXPON} float_flag; + + /* If the lexer has done its job, length one can only be a single + digit. Fast-path this very common case. */ + if (token->val.str.len == 1) + return CPP_N_INTEGER | CPP_N_SMALL | CPP_N_DECIMAL; + + limit = str + token->val.str.len; + float_flag = NOT_FLOAT; + max_digit = 0; + radix = 10; + + /* First, interpret the radix. */ + if (*str == '0') + { + radix = 8; + str++; + + /* Require at least one hex digit to classify it as hex. */ + if ((*str == 'x' || *str == 'X') + && (str[1] == '.' || ISXDIGIT (str[1]))) + { + radix = 16; + str++; + } + } + + /* Now scan for a well-formed integer or float. */ + for (;;) + { + unsigned int c = *str++; + + if (ISDIGIT (c) || (ISXDIGIT (c) && radix == 16)) + { + c = hex_value (c); + if (c > max_digit) + max_digit = c; + } + else if (c == '.') + { + if (float_flag == NOT_FLOAT) + float_flag = AFTER_POINT; + else + SYNTAX_ERROR ("too many decimal points in number"); + } + else if ((radix <= 10 && (c == 'e' || c == 'E')) + || (radix == 16 && (c == 'p' || c == 'P'))) + { + float_flag = AFTER_EXPON; + break; + } + else + { + /* Start of suffix. */ + str--; + break; + } + } + + if (float_flag != NOT_FLOAT && radix == 8) + radix = 10; + + if (max_digit >= radix) + SYNTAX_ERROR2 ("invalid digit \"%c\" in octal constant", '0' + max_digit); + + if (float_flag != NOT_FLOAT) + { + if (radix == 16 && CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, c99)) + cpp_error (pfile, CPP_DL_PEDWARN, + "use of C99 hexadecimal floating constant"); + + if (float_flag == AFTER_EXPON) + { + if (*str == '+' || *str == '-') + str++; + + /* Exponent is decimal, even if string is a hex float. */ + if (!ISDIGIT (*str)) + SYNTAX_ERROR ("exponent has no digits"); + + do + str++; + while (ISDIGIT (*str)); + } + else if (radix == 16) + SYNTAX_ERROR ("hexadecimal floating constants require an exponent"); + + result = interpret_float_suffix (str, limit - str); + if (result == 0) + { + cpp_error (pfile, CPP_DL_ERROR, + "invalid suffix \"%.*s\" on floating constant", + (int) (limit - str), str); + return CPP_N_INVALID; + } + + /* Traditional C didn't accept any floating suffixes. */ + if (limit != str + && CPP_WTRADITIONAL (pfile) + && ! cpp_sys_macro_p (pfile)) + cpp_error (pfile, CPP_DL_WARNING, + "traditional C rejects the \"%.*s\" suffix", + (int) (limit - str), str); + + result |= CPP_N_FLOATING; + } + else + { + result = interpret_int_suffix (str, limit - str); + if (result == 0) + { + cpp_error (pfile, CPP_DL_ERROR, + "invalid suffix \"%.*s\" on integer constant", + (int) (limit - str), str); + return CPP_N_INVALID; + } + + /* Traditional C only accepted the 'L' suffix. + Suppress warning about 'LL' with -Wno-long-long. */ + if (CPP_WTRADITIONAL (pfile) && ! cpp_sys_macro_p (pfile)) + { + int u_or_i = (result & (CPP_N_UNSIGNED|CPP_N_IMAGINARY)); + int large = (result & CPP_N_WIDTH) == CPP_N_LARGE; + + if (u_or_i || (large && CPP_OPTION (pfile, warn_long_long))) + cpp_error (pfile, CPP_DL_WARNING, + "traditional C rejects the \"%.*s\" suffix", + (int) (limit - str), str); + } + + if ((result & CPP_N_WIDTH) == CPP_N_LARGE + && ! CPP_OPTION (pfile, c99) + && CPP_OPTION (pfile, warn_long_long)) + cpp_error (pfile, CPP_DL_PEDWARN, + "use of C99 long long integer constant"); + + result |= CPP_N_INTEGER; + } + + if ((result & CPP_N_IMAGINARY) && CPP_PEDANTIC (pfile)) + cpp_error (pfile, CPP_DL_PEDWARN, + "imaginary constants are a GCC extension"); + + if (radix == 10) + result |= CPP_N_DECIMAL; + else if (radix == 16) + result |= CPP_N_HEX; + else + result |= CPP_N_OCTAL; + + return result; + + syntax_error: + return CPP_N_INVALID; +} + +/* cpp_interpret_integer converts an integer constant into a cpp_num, + of precision options->precision. + + We do not provide any interface for decimal->float conversion, + because the preprocessor doesn't need it and we don't want to + drag in GCC's floating point emulator. */ +cpp_num +cpp_interpret_integer (cpp_reader *pfile, const cpp_token *token, + unsigned int type) +{ + const uchar *p, *end; + cpp_num result; + + result.low = 0; + result.high = 0; + result.unsignedp = !!(type & CPP_N_UNSIGNED); + result.overflow = false; + + p = token->val.str.text; + end = p + token->val.str.len; + + /* Common case of a single digit. */ + if (token->val.str.len == 1) + result.low = p[0] - '0'; + else + { + cpp_num_part max; + size_t precision = CPP_OPTION (pfile, precision); + unsigned int base = 10, c = 0; + bool overflow = false; + + if ((type & CPP_N_RADIX) == CPP_N_OCTAL) + { + base = 8; + p++; + } + else if ((type & CPP_N_RADIX) == CPP_N_HEX) + { + base = 16; + p += 2; + } + + /* We can add a digit to numbers strictly less than this without + needing the precision and slowness of double integers. */ + max = ~(cpp_num_part) 0; + if (precision < PART_PRECISION) + max >>= PART_PRECISION - precision; + max = (max - base + 1) / base + 1; + + for (; p < end; p++) + { + c = *p; + + if (ISDIGIT (c) || (base == 16 && ISXDIGIT (c))) + c = hex_value (c); + else + break; + + /* Strict inequality for when max is set to zero. */ + if (result.low < max) + result.low = result.low * base + c; + else + { + result = append_digit (result, c, base, precision); + overflow |= result.overflow; + max = 0; + } + } + + if (overflow) + cpp_error (pfile, CPP_DL_PEDWARN, + "integer constant is too large for its type"); + /* If too big to be signed, consider it unsigned. Only warn for + decimal numbers. Traditional numbers were always signed (but + we still honor an explicit U suffix); but we only have + traditional semantics in directives. */ + else if (!result.unsignedp + && !(CPP_OPTION (pfile, traditional) + && pfile->state.in_directive) + && !num_positive (result, precision)) + { + if (base == 10) + cpp_error (pfile, CPP_DL_WARNING, + "integer constant is so large that it is unsigned"); + result.unsignedp = true; + } + } + + return result; +} + +/* Append DIGIT to NUM, a number of PRECISION bits being read in base BASE. */ +static cpp_num +append_digit (cpp_num num, int digit, int base, size_t precision) +{ + cpp_num result; + unsigned int shift = 3 + (base == 16); + bool overflow; + cpp_num_part add_high, add_low; + + /* Multiply by 8 or 16. Catching this overflow here means we don't + need to worry about add_high overflowing. */ + overflow = !!(num.high >> (PART_PRECISION - shift)); + result.high = num.high << shift; + result.low = num.low << shift; + result.high |= num.low >> (PART_PRECISION - shift); + result.unsignedp = num.unsignedp; + + if (base == 10) + { + add_low = num.low << 1; + add_high = (num.high << 1) + (num.low >> (PART_PRECISION - 1)); + } + else + add_high = add_low = 0; + + if (add_low + digit < add_low) + add_high++; + add_low += digit; + + if (result.low + add_low < result.low) + add_high++; + if (result.high + add_high < result.high) + overflow = true; + + result.low += add_low; + result.high += add_high; + result.overflow = overflow; + + /* The above code catches overflow of a cpp_num type. This catches + overflow of the (possibly shorter) target precision. */ + num.low = result.low; + num.high = result.high; + result = num_trim (result, precision); + if (!num_eq (result, num)) + result.overflow = true; + + return result; +} + +/* Handle meeting "defined" in a preprocessor expression. */ +static cpp_num +parse_defined (cpp_reader *pfile) +{ + cpp_num result; + int paren = 0; + cpp_hashnode *node = 0; + const cpp_token *token; + cpp_context *initial_context = pfile->context; + + /* Don't expand macros. */ + pfile->state.prevent_expansion++; + + token = cpp_get_token (pfile); + if (token->type == CPP_OPEN_PAREN) + { + paren = 1; + token = cpp_get_token (pfile); + } + + if (token->type == CPP_NAME) + { + node = token->val.node; + if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN) + { + cpp_error (pfile, CPP_DL_ERROR, "missing ')' after \"defined\""); + node = 0; + } + } + else + { + cpp_error (pfile, CPP_DL_ERROR, + "operator \"defined\" requires an identifier"); + if (token->flags & NAMED_OP) + { + cpp_token op; + + op.flags = 0; + op.type = token->type; + cpp_error (pfile, CPP_DL_ERROR, + "(\"%s\" is an alternative token for \"%s\" in C++)", + cpp_token_as_text (pfile, token), + cpp_token_as_text (pfile, &op)); + } + } + + if (node) + { + if (pfile->context != initial_context && CPP_PEDANTIC (pfile)) + cpp_error (pfile, CPP_DL_WARNING, + "this use of \"defined\" may not be portable"); + + _cpp_mark_macro_used (node); + + /* A possible controlling macro of the form #if !defined (). + _cpp_parse_expr checks there was no other junk on the line. */ + pfile->mi_ind_cmacro = node; + } + + pfile->state.prevent_expansion--; + + result.unsignedp = false; + result.high = 0; + result.overflow = false; + result.low = node && node->type == NT_MACRO; + return result; +} + +/* Convert a token into a CPP_NUMBER (an interpreted preprocessing + number or character constant, or the result of the "defined" or "#" + operators). */ +static cpp_num +eval_token (cpp_reader *pfile, const cpp_token *token) +{ + cpp_num result; + unsigned int temp; + int unsignedp = 0; + + result.unsignedp = false; + result.overflow = false; + + switch (token->type) + { + case CPP_NUMBER: + temp = cpp_classify_number (pfile, token); + switch (temp & CPP_N_CATEGORY) + { + case CPP_N_FLOATING: + cpp_error (pfile, CPP_DL_ERROR, + "floating constant in preprocessor expression"); + break; + case CPP_N_INTEGER: + if (!(temp & CPP_N_IMAGINARY)) + return cpp_interpret_integer (pfile, token, temp); + cpp_error (pfile, CPP_DL_ERROR, + "imaginary number in preprocessor expression"); + break; + + case CPP_N_INVALID: + /* Error already issued. */ + break; + } + result.high = result.low = 0; + break; + + case CPP_WCHAR: + case CPP_CHAR: + { + cppchar_t cc = cpp_interpret_charconst (pfile, token, + &temp, &unsignedp); + + result.high = 0; + result.low = cc; + /* Sign-extend the result if necessary. */ + if (!unsignedp && (cppchar_signed_t) cc < 0) + { + if (PART_PRECISION > BITS_PER_CPPCHAR_T) + result.low |= ~(~(cpp_num_part) 0 + >> (PART_PRECISION - BITS_PER_CPPCHAR_T)); + result.high = ~(cpp_num_part) 0; + result = num_trim (result, CPP_OPTION (pfile, precision)); + } + } + break; + + case CPP_NAME: + if (token->val.node == pfile->spec_nodes.n_defined) + return parse_defined (pfile); + else if (CPP_OPTION (pfile, cplusplus) + && (token->val.node == pfile->spec_nodes.n_true + || token->val.node == pfile->spec_nodes.n_false)) + { + result.high = 0; + result.low = (token->val.node == pfile->spec_nodes.n_true); + } + else + { + result.high = 0; + result.low = 0; + if (CPP_OPTION (pfile, warn_undef) && !pfile->state.skip_eval) + cpp_error (pfile, CPP_DL_WARNING, "\"%s\" is not defined", + NODE_NAME (token->val.node)); + } + break; + + default: /* CPP_HASH */ + _cpp_test_assertion (pfile, &temp); + result.high = 0; + result.low = temp; + } + + result.unsignedp = !!unsignedp; + return result; +} + +/* Operator precedence and flags table. + +After an operator is returned from the lexer, if it has priority less +than the operator on the top of the stack, we reduce the stack by one +operator and repeat the test. Since equal priorities do not reduce, +this is naturally right-associative. + +We handle left-associative operators by decrementing the priority of +just-lexed operators by one, but retaining the priority of operators +already on the stack. + +The remaining cases are '(' and ')'. We handle '(' by skipping the +reduction phase completely. ')' is given lower priority than +everything else, including '(', effectively forcing a reduction of the +parenthesized expression. If there is a matching '(', the routine +reduce() exits immediately. If the normal exit route sees a ')', then +there cannot have been a matching '(' and an error message is output. + +The parser assumes all shifted operators require a left operand unless +the flag NO_L_OPERAND is set. These semantics are automatic; any +extra semantics need to be handled with operator-specific code. */ + +/* Flags. If CHECK_PROMOTION, we warn if the effective sign of an + operand changes because of integer promotions. */ +#define NO_L_OPERAND (1 << 0) +#define LEFT_ASSOC (1 << 1) +#define CHECK_PROMOTION (1 << 2) + +/* Operator to priority map. Must be in the same order as the first + N entries of enum cpp_ttype. */ +static const struct cpp_operator +{ + uchar prio; + uchar flags; +} optab[] = +{ + /* EQ */ {0, 0}, /* Shouldn't happen. */ + /* NOT */ {16, NO_L_OPERAND}, + /* GREATER */ {12, LEFT_ASSOC | CHECK_PROMOTION}, + /* LESS */ {12, LEFT_ASSOC | CHECK_PROMOTION}, + /* PLUS */ {14, LEFT_ASSOC | CHECK_PROMOTION}, + /* MINUS */ {14, LEFT_ASSOC | CHECK_PROMOTION}, + /* MULT */ {15, LEFT_ASSOC | CHECK_PROMOTION}, + /* DIV */ {15, LEFT_ASSOC | CHECK_PROMOTION}, + /* MOD */ {15, LEFT_ASSOC | CHECK_PROMOTION}, + /* AND */ {9, LEFT_ASSOC | CHECK_PROMOTION}, + /* OR */ {7, LEFT_ASSOC | CHECK_PROMOTION}, + /* XOR */ {8, LEFT_ASSOC | CHECK_PROMOTION}, + /* RSHIFT */ {13, LEFT_ASSOC}, + /* LSHIFT */ {13, LEFT_ASSOC}, + + /* MIN */ {10, LEFT_ASSOC | CHECK_PROMOTION}, + /* MAX */ {10, LEFT_ASSOC | CHECK_PROMOTION}, + + /* COMPL */ {16, NO_L_OPERAND}, + /* AND_AND */ {6, LEFT_ASSOC}, + /* OR_OR */ {5, LEFT_ASSOC}, + /* QUERY */ {3, 0}, + /* COLON */ {4, LEFT_ASSOC | CHECK_PROMOTION}, + /* COMMA */ {2, LEFT_ASSOC}, + /* OPEN_PAREN */ {1, NO_L_OPERAND}, + /* CLOSE_PAREN */ {0, 0}, + /* EOF */ {0, 0}, + /* EQ_EQ */ {11, LEFT_ASSOC}, + /* NOT_EQ */ {11, LEFT_ASSOC}, + /* GREATER_EQ */ {12, LEFT_ASSOC | CHECK_PROMOTION}, + /* LESS_EQ */ {12, LEFT_ASSOC | CHECK_PROMOTION}, + /* UPLUS */ {16, NO_L_OPERAND}, + /* UMINUS */ {16, NO_L_OPERAND} +}; + +/* Parse and evaluate a C expression, reading from PFILE. + Returns the truth value of the expression. + + The implementation is an operator precedence parser, i.e. a + bottom-up parser, using a stack for not-yet-reduced tokens. + + The stack base is op_stack, and the current stack pointer is 'top'. + There is a stack element for each operator (only), and the most + recently pushed operator is 'top->op'. An operand (value) is + stored in the 'value' field of the stack element of the operator + that precedes it. */ +bool +_cpp_parse_expr (cpp_reader *pfile) +{ + struct op *top = pfile->op_stack; + unsigned int lex_count; + bool saw_leading_not, want_value = true; + + pfile->state.skip_eval = 0; + + /* Set up detection of #if ! defined(). */ + pfile->mi_ind_cmacro = 0; + saw_leading_not = false; + lex_count = 0; + + /* Lowest priority operator prevents further reductions. */ + top->op = CPP_EOF; + + for (;;) + { + struct op op; + + lex_count++; + op.token = cpp_get_token (pfile); + op.op = op.token->type; + + switch (op.op) + { + /* These tokens convert into values. */ + case CPP_NUMBER: + case CPP_CHAR: + case CPP_WCHAR: + case CPP_NAME: + case CPP_HASH: + if (!want_value) + SYNTAX_ERROR2 ("missing binary operator before token \"%s\"", + cpp_token_as_text (pfile, op.token)); + want_value = false; + top->value = eval_token (pfile, op.token); + continue; + + case CPP_NOT: + saw_leading_not = lex_count == 1; + break; + case CPP_PLUS: + if (want_value) + op.op = CPP_UPLUS; + break; + case CPP_MINUS: + if (want_value) + op.op = CPP_UMINUS; + break; + + default: + if ((int) op.op <= (int) CPP_EQ || (int) op.op >= (int) CPP_PLUS_EQ) + SYNTAX_ERROR2 ("token \"%s\" is not valid in preprocessor expressions", + cpp_token_as_text (pfile, op.token)); + break; + } + + /* Check we have a value or operator as appropriate. */ + if (optab[op.op].flags & NO_L_OPERAND) + { + if (!want_value) + SYNTAX_ERROR2 ("missing binary operator before token \"%s\"", + cpp_token_as_text (pfile, op.token)); + } + else if (want_value) + { + /* We want a number (or expression) and haven't got one. + Try to emit a specific diagnostic. */ + if (op.op == CPP_CLOSE_PAREN && top->op == CPP_OPEN_PAREN) + SYNTAX_ERROR ("missing expression between '(' and ')'"); + + if (op.op == CPP_EOF && top->op == CPP_EOF) + SYNTAX_ERROR ("#if with no expression"); + + if (top->op != CPP_EOF && top->op != CPP_OPEN_PAREN) + SYNTAX_ERROR2 ("operator '%s' has no right operand", + cpp_token_as_text (pfile, top->token)); + else if (op.op == CPP_CLOSE_PAREN || op.op == CPP_EOF) + /* Complain about missing paren during reduction. */; + else + SYNTAX_ERROR2 ("operator '%s' has no left operand", + cpp_token_as_text (pfile, op.token)); + } + + top = reduce (pfile, top, op.op); + if (!top) + goto syntax_error; + + if (op.op == CPP_EOF) + break; + + switch (op.op) + { + case CPP_CLOSE_PAREN: + continue; + case CPP_OR_OR: + if (!num_zerop (top->value)) + pfile->state.skip_eval++; + break; + case CPP_AND_AND: + case CPP_QUERY: + if (num_zerop (top->value)) + pfile->state.skip_eval++; + break; + case CPP_COLON: + if (top->op != CPP_QUERY) + SYNTAX_ERROR (" ':' without preceding '?'"); + if (!num_zerop (top[-1].value)) /* Was '?' condition true? */ + pfile->state.skip_eval++; + else + pfile->state.skip_eval--; + default: + break; + } + + want_value = true; + + /* Check for and handle stack overflow. */ + if (++top == pfile->op_limit) + top = _cpp_expand_op_stack (pfile); + + top->op = op.op; + top->token = op.token; + } + + /* The controlling macro expression is only valid if we called lex 3 + times: and . push_conditional () + checks that we are at top-of-file. */ + if (pfile->mi_ind_cmacro && !(saw_leading_not && lex_count == 3)) + pfile->mi_ind_cmacro = 0; + + if (top != pfile->op_stack) + { + cpp_error (pfile, CPP_DL_ICE, "unbalanced stack in #if"); + syntax_error: + return false; /* Return false on syntax error. */ + } + + return !num_zerop (top->value); +} + +/* Reduce the operator / value stack if possible, in preparation for + pushing operator OP. Returns NULL on error, otherwise the top of + the stack. */ +static struct op * +reduce (cpp_reader *pfile, struct op *top, enum cpp_ttype op) +{ + unsigned int prio; + + if (top->op <= CPP_EQ || top->op > CPP_LAST_CPP_OP + 2) + { + bad_op: + cpp_error (pfile, CPP_DL_ICE, "impossible operator '%u'", top->op); + return 0; + } + + if (op == CPP_OPEN_PAREN) + return top; + + /* Decrement the priority of left-associative operators to force a + reduction with operators of otherwise equal priority. */ + prio = optab[op].prio - ((optab[op].flags & LEFT_ASSOC) != 0); + while (prio < optab[top->op].prio) + { + if (CPP_OPTION (pfile, warn_num_sign_change) + && optab[top->op].flags & CHECK_PROMOTION) + check_promotion (pfile, top); + + switch (top->op) + { + case CPP_UPLUS: + case CPP_UMINUS: + case CPP_NOT: + case CPP_COMPL: + top[-1].value = num_unary_op (pfile, top->value, top->op); + break; + + case CPP_PLUS: + case CPP_MINUS: + case CPP_RSHIFT: + case CPP_LSHIFT: + case CPP_MIN: + case CPP_MAX: + case CPP_COMMA: + top[-1].value = num_binary_op (pfile, top[-1].value, + top->value, top->op); + break; + + case CPP_GREATER: + case CPP_LESS: + case CPP_GREATER_EQ: + case CPP_LESS_EQ: + top[-1].value + = num_inequality_op (pfile, top[-1].value, top->value, top->op); + break; + + case CPP_EQ_EQ: + case CPP_NOT_EQ: + top[-1].value + = num_equality_op (pfile, top[-1].value, top->value, top->op); + break; + + case CPP_AND: + case CPP_OR: + case CPP_XOR: + top[-1].value + = num_bitwise_op (pfile, top[-1].value, top->value, top->op); + break; + + case CPP_MULT: + top[-1].value = num_mul (pfile, top[-1].value, top->value); + break; + + case CPP_DIV: + case CPP_MOD: + top[-1].value = num_div_op (pfile, top[-1].value, + top->value, top->op); + break; + + case CPP_OR_OR: + top--; + if (!num_zerop (top->value)) + pfile->state.skip_eval--; + top->value.low = (!num_zerop (top->value) + || !num_zerop (top[1].value)); + top->value.high = 0; + top->value.unsignedp = false; + top->value.overflow = false; + continue; + + case CPP_AND_AND: + top--; + if (num_zerop (top->value)) + pfile->state.skip_eval--; + top->value.low = (!num_zerop (top->value) + && !num_zerop (top[1].value)); + top->value.high = 0; + top->value.unsignedp = false; + top->value.overflow = false; + continue; + + case CPP_OPEN_PAREN: + if (op != CPP_CLOSE_PAREN) + { + cpp_error (pfile, CPP_DL_ERROR, "missing ')' in expression"); + return 0; + } + top--; + top->value = top[1].value; + return top; + + case CPP_COLON: + top -= 2; + if (!num_zerop (top->value)) + { + pfile->state.skip_eval--; + top->value = top[1].value; + } + else + top->value = top[2].value; + top->value.unsignedp = (top[1].value.unsignedp + || top[2].value.unsignedp); + continue; + + case CPP_QUERY: + cpp_error (pfile, CPP_DL_ERROR, "'?' without following ':'"); + return 0; + + default: + goto bad_op; + } + + top--; + if (top->value.overflow && !pfile->state.skip_eval) + cpp_error (pfile, CPP_DL_PEDWARN, + "integer overflow in preprocessor expression"); + } + + if (op == CPP_CLOSE_PAREN) + { + cpp_error (pfile, CPP_DL_ERROR, "missing '(' in expression"); + return 0; + } + + return top; +} + +/* Returns the position of the old top of stack after expansion. */ +struct op * +_cpp_expand_op_stack (cpp_reader *pfile) +{ + size_t old_size = (size_t) (pfile->op_limit - pfile->op_stack); + size_t new_size = old_size * 2 + 20; + + pfile->op_stack = XRESIZEVEC (struct op, pfile->op_stack, new_size); + pfile->op_limit = pfile->op_stack + new_size; + + return pfile->op_stack + old_size; +} + +/* Emits a warning if the effective sign of either operand of OP + changes because of integer promotions. */ +static void +check_promotion (cpp_reader *pfile, const struct op *op) +{ + if (op->value.unsignedp == op[-1].value.unsignedp) + return; + + if (op->value.unsignedp) + { + if (!num_positive (op[-1].value, CPP_OPTION (pfile, precision))) + cpp_error (pfile, CPP_DL_WARNING, + "the left operand of \"%s\" changes sign when promoted", + cpp_token_as_text (pfile, op->token)); + } + else if (!num_positive (op->value, CPP_OPTION (pfile, precision))) + cpp_error (pfile, CPP_DL_WARNING, + "the right operand of \"%s\" changes sign when promoted", + cpp_token_as_text (pfile, op->token)); +} + +/* Clears the unused high order bits of the number pointed to by PNUM. */ +static cpp_num +num_trim (cpp_num num, size_t precision) +{ + if (precision > PART_PRECISION) + { + precision -= PART_PRECISION; + if (precision < PART_PRECISION) + num.high &= ((cpp_num_part) 1 << precision) - 1; + } + else + { + if (precision < PART_PRECISION) + num.low &= ((cpp_num_part) 1 << precision) - 1; + num.high = 0; + } + + return num; +} + +/* True iff A (presumed signed) >= 0. */ +static bool +num_positive (cpp_num num, size_t precision) +{ + if (precision > PART_PRECISION) + { + precision -= PART_PRECISION; + return (num.high & (cpp_num_part) 1 << (precision - 1)) == 0; + } + + return (num.low & (cpp_num_part) 1 << (precision - 1)) == 0; +} + +/* Sign extend a number, with PRECISION significant bits and all + others assumed clear, to fill out a cpp_num structure. */ +cpp_num +cpp_num_sign_extend (cpp_num num, size_t precision) +{ + if (!num.unsignedp) + { + if (precision > PART_PRECISION) + { + precision -= PART_PRECISION; + if (precision < PART_PRECISION + && (num.high & (cpp_num_part) 1 << (precision - 1))) + num.high |= ~(~(cpp_num_part) 0 >> (PART_PRECISION - precision)); + } + else if (num.low & (cpp_num_part) 1 << (precision - 1)) + { + if (precision < PART_PRECISION) + num.low |= ~(~(cpp_num_part) 0 >> (PART_PRECISION - precision)); + num.high = ~(cpp_num_part) 0; + } + } + + return num; +} + +/* Returns the negative of NUM. */ +static cpp_num +num_negate (cpp_num num, size_t precision) +{ + cpp_num copy; + + copy = num; + num.high = ~num.high; + num.low = ~num.low; + if (++num.low == 0) + num.high++; + num = num_trim (num, precision); + num.overflow = (!num.unsignedp && num_eq (num, copy) && !num_zerop (num)); + + return num; +} + +/* Returns true if A >= B. */ +static bool +num_greater_eq (cpp_num pa, cpp_num pb, size_t precision) +{ + bool unsignedp; + + unsignedp = pa.unsignedp || pb.unsignedp; + + if (!unsignedp) + { + /* Both numbers have signed type. If they are of different + sign, the answer is the sign of A. */ + unsignedp = num_positive (pa, precision); + + if (unsignedp != num_positive (pb, precision)) + return unsignedp; + + /* Otherwise we can do an unsigned comparison. */ + } + + return (pa.high > pb.high) || (pa.high == pb.high && pa.low >= pb.low); +} + +/* Returns LHS OP RHS, where OP is a bit-wise operation. */ +static cpp_num +num_bitwise_op (cpp_reader *pfile ATTRIBUTE_UNUSED, + cpp_num lhs, cpp_num rhs, enum cpp_ttype op) +{ + lhs.overflow = false; + lhs.unsignedp = lhs.unsignedp || rhs.unsignedp; + + /* As excess precision is zeroed, there is no need to num_trim () as + these operations cannot introduce a set bit there. */ + if (op == CPP_AND) + { + lhs.low &= rhs.low; + lhs.high &= rhs.high; + } + else if (op == CPP_OR) + { + lhs.low |= rhs.low; + lhs.high |= rhs.high; + } + else + { + lhs.low ^= rhs.low; + lhs.high ^= rhs.high; + } + + return lhs; +} + +/* Returns LHS OP RHS, where OP is an inequality. */ +static cpp_num +num_inequality_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, + enum cpp_ttype op) +{ + bool gte = num_greater_eq (lhs, rhs, CPP_OPTION (pfile, precision)); + + if (op == CPP_GREATER_EQ) + lhs.low = gte; + else if (op == CPP_LESS) + lhs.low = !gte; + else if (op == CPP_GREATER) + lhs.low = gte && !num_eq (lhs, rhs); + else /* CPP_LESS_EQ. */ + lhs.low = !gte || num_eq (lhs, rhs); + + lhs.high = 0; + lhs.overflow = false; + lhs.unsignedp = false; + return lhs; +} + +/* Returns LHS OP RHS, where OP is == or !=. */ +static cpp_num +num_equality_op (cpp_reader *pfile ATTRIBUTE_UNUSED, + cpp_num lhs, cpp_num rhs, enum cpp_ttype op) +{ + /* Work around a 3.0.4 bug; see PR 6950. */ + bool eq = num_eq (lhs, rhs); + if (op == CPP_NOT_EQ) + eq = !eq; + lhs.low = eq; + lhs.high = 0; + lhs.overflow = false; + lhs.unsignedp = false; + return lhs; +} + +/* Shift NUM, of width PRECISION, right by N bits. */ +static cpp_num +num_rshift (cpp_num num, size_t precision, size_t n) +{ + cpp_num_part sign_mask; + bool x = num_positive (num, precision); + + if (num.unsignedp || x) + sign_mask = 0; + else + sign_mask = ~(cpp_num_part) 0; + + if (n >= precision) + num.high = num.low = sign_mask; + else + { + /* Sign-extend. */ + if (precision < PART_PRECISION) + num.high = sign_mask, num.low |= sign_mask << precision; + else if (precision < 2 * PART_PRECISION) + num.high |= sign_mask << (precision - PART_PRECISION); + + if (n >= PART_PRECISION) + { + n -= PART_PRECISION; + num.low = num.high; + num.high = sign_mask; + } + + if (n) + { + num.low = (num.low >> n) | (num.high << (PART_PRECISION - n)); + num.high = (num.high >> n) | (sign_mask << (PART_PRECISION - n)); + } + } + + num = num_trim (num, precision); + num.overflow = false; + return num; +} + +/* Shift NUM, of width PRECISION, left by N bits. */ +static cpp_num +num_lshift (cpp_num num, size_t precision, size_t n) +{ + if (n >= precision) + { + num.overflow = !num.unsignedp && !num_zerop (num); + num.high = num.low = 0; + } + else + { + cpp_num orig, maybe_orig; + size_t m = n; + + orig = num; + if (m >= PART_PRECISION) + { + m -= PART_PRECISION; + num.high = num.low; + num.low = 0; + } + if (m) + { + num.high = (num.high << m) | (num.low >> (PART_PRECISION - m)); + num.low <<= m; + } + num = num_trim (num, precision); + + if (num.unsignedp) + num.overflow = false; + else + { + maybe_orig = num_rshift (num, precision, n); + num.overflow = !num_eq (orig, maybe_orig); + } + } + + return num; +} + +/* The four unary operators: +, -, ! and ~. */ +static cpp_num +num_unary_op (cpp_reader *pfile, cpp_num num, enum cpp_ttype op) +{ + switch (op) + { + case CPP_UPLUS: + if (CPP_WTRADITIONAL (pfile) && !pfile->state.skip_eval) + cpp_error (pfile, CPP_DL_WARNING, + "traditional C rejects the unary plus operator"); + num.overflow = false; + break; + + case CPP_UMINUS: + num = num_negate (num, CPP_OPTION (pfile, precision)); + break; + + case CPP_COMPL: + num.high = ~num.high; + num.low = ~num.low; + num = num_trim (num, CPP_OPTION (pfile, precision)); + num.overflow = false; + break; + + default: /* case CPP_NOT: */ + num.low = num_zerop (num); + num.high = 0; + num.overflow = false; + num.unsignedp = false; + break; + } + + return num; +} + +/* The various binary operators. */ +static cpp_num +num_binary_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op) +{ + cpp_num result; + size_t precision = CPP_OPTION (pfile, precision); + bool gte; + size_t n; + + switch (op) + { + /* Shifts. */ + case CPP_LSHIFT: + case CPP_RSHIFT: + if (!rhs.unsignedp && !num_positive (rhs, precision)) + { + /* A negative shift is a positive shift the other way. */ + if (op == CPP_LSHIFT) + op = CPP_RSHIFT; + else + op = CPP_LSHIFT; + rhs = num_negate (rhs, precision); + } + if (rhs.high) + n = ~0; /* Maximal. */ + else + n = rhs.low; + if (op == CPP_LSHIFT) + lhs = num_lshift (lhs, precision, n); + else + lhs = num_rshift (lhs, precision, n); + break; + + /* Min / Max. */ + case CPP_MIN: + case CPP_MAX: + { + bool unsignedp = lhs.unsignedp || rhs.unsignedp; + + gte = num_greater_eq (lhs, rhs, precision); + if (op == CPP_MIN) + gte = !gte; + if (!gte) + lhs = rhs; + lhs.unsignedp = unsignedp; + } + break; + + /* Arithmetic. */ + case CPP_MINUS: + rhs = num_negate (rhs, precision); + case CPP_PLUS: + result.low = lhs.low + rhs.low; + result.high = lhs.high + rhs.high; + if (result.low < lhs.low) + result.high++; + result.unsignedp = lhs.unsignedp || rhs.unsignedp; + result.overflow = false; + + result = num_trim (result, precision); + if (!result.unsignedp) + { + bool lhsp = num_positive (lhs, precision); + result.overflow = (lhsp == num_positive (rhs, precision) + && lhsp != num_positive (result, precision)); + } + return result; + + /* Comma. */ + default: /* case CPP_COMMA: */ + if (CPP_PEDANTIC (pfile) && (!CPP_OPTION (pfile, c99) + || !pfile->state.skip_eval)) + cpp_error (pfile, CPP_DL_PEDWARN, + "comma operator in operand of #if"); + lhs = rhs; + break; + } + + return lhs; +} + +/* Multiplies two unsigned cpp_num_parts to give a cpp_num. This + cannot overflow. */ +static cpp_num +num_part_mul (cpp_num_part lhs, cpp_num_part rhs) +{ + cpp_num result; + cpp_num_part middle[2], temp; + + result.low = LOW_PART (lhs) * LOW_PART (rhs); + result.high = HIGH_PART (lhs) * HIGH_PART (rhs); + + middle[0] = LOW_PART (lhs) * HIGH_PART (rhs); + middle[1] = HIGH_PART (lhs) * LOW_PART (rhs); + + temp = result.low; + result.low += LOW_PART (middle[0]) << (PART_PRECISION / 2); + if (result.low < temp) + result.high++; + + temp = result.low; + result.low += LOW_PART (middle[1]) << (PART_PRECISION / 2); + if (result.low < temp) + result.high++; + + result.high += HIGH_PART (middle[0]); + result.high += HIGH_PART (middle[1]); + result.unsignedp = true; + result.overflow = false; + + return result; +} + +/* Multiply two preprocessing numbers. */ +static cpp_num +num_mul (cpp_reader *pfile, cpp_num lhs, cpp_num rhs) +{ + cpp_num result, temp; + bool unsignedp = lhs.unsignedp || rhs.unsignedp; + bool overflow, negate = false; + size_t precision = CPP_OPTION (pfile, precision); + + /* Prepare for unsigned multiplication. */ + if (!unsignedp) + { + if (!num_positive (lhs, precision)) + negate = !negate, lhs = num_negate (lhs, precision); + if (!num_positive (rhs, precision)) + negate = !negate, rhs = num_negate (rhs, precision); + } + + overflow = lhs.high && rhs.high; + result = num_part_mul (lhs.low, rhs.low); + + temp = num_part_mul (lhs.high, rhs.low); + result.high += temp.low; + if (temp.high) + overflow = true; + + temp = num_part_mul (lhs.low, rhs.high); + result.high += temp.low; + if (temp.high) + overflow = true; + + temp.low = result.low, temp.high = result.high; + result = num_trim (result, precision); + if (!num_eq (result, temp)) + overflow = true; + + if (negate) + result = num_negate (result, precision); + + if (unsignedp) + result.overflow = false; + else + result.overflow = overflow || (num_positive (result, precision) ^ !negate + && !num_zerop (result)); + result.unsignedp = unsignedp; + + return result; +} + +/* Divide two preprocessing numbers, returning the answer or the + remainder depending upon OP. */ +static cpp_num +num_div_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op) +{ + cpp_num result, sub; + cpp_num_part mask; + bool unsignedp = lhs.unsignedp || rhs.unsignedp; + bool negate = false, lhs_neg = false; + size_t i, precision = CPP_OPTION (pfile, precision); + + /* Prepare for unsigned division. */ + if (!unsignedp) + { + if (!num_positive (lhs, precision)) + negate = !negate, lhs_neg = true, lhs = num_negate (lhs, precision); + if (!num_positive (rhs, precision)) + negate = !negate, rhs = num_negate (rhs, precision); + } + + /* Find the high bit. */ + if (rhs.high) + { + i = precision - 1; + mask = (cpp_num_part) 1 << (i - PART_PRECISION); + for (; ; i--, mask >>= 1) + if (rhs.high & mask) + break; + } + else if (rhs.low) + { + if (precision > PART_PRECISION) + i = precision - PART_PRECISION - 1; + else + i = precision - 1; + mask = (cpp_num_part) 1 << i; + for (; ; i--, mask >>= 1) + if (rhs.low & mask) + break; + } + else + { + if (!pfile->state.skip_eval) + cpp_error (pfile, CPP_DL_ERROR, "division by zero in #if"); + return lhs; + } + + /* First nonzero bit of RHS is bit I. Do naive division by + shifting the RHS fully left, and subtracting from LHS if LHS is + at least as big, and then repeating but with one less shift. + This is not very efficient, but is easy to understand. */ + + rhs.unsignedp = true; + lhs.unsignedp = true; + i = precision - i - 1; + sub = num_lshift (rhs, precision, i); + + result.high = result.low = 0; + for (;;) + { + if (num_greater_eq (lhs, sub, precision)) + { + lhs = num_binary_op (pfile, lhs, sub, CPP_MINUS); + if (i >= PART_PRECISION) + result.high |= (cpp_num_part) 1 << (i - PART_PRECISION); + else + result.low |= (cpp_num_part) 1 << i; + } + if (i-- == 0) + break; + sub.low = (sub.low >> 1) | (sub.high << (PART_PRECISION - 1)); + sub.high >>= 1; + } + + /* We divide so that the remainder has the sign of the LHS. */ + if (op == CPP_DIV) + { + result.unsignedp = unsignedp; + result.overflow = false; + if (!unsignedp) + { + if (negate) + result = num_negate (result, precision); + result.overflow = num_positive (result, precision) ^ !negate; + } + + return result; + } + + /* CPP_MOD. */ + lhs.unsignedp = unsignedp; + lhs.overflow = false; + if (lhs_neg) + lhs = num_negate (lhs, precision); + + return lhs; +} diff --git a/support/cpp2/libcpp/files.c b/support/cpp2/libcpp/files.c new file mode 100644 index 00000000..702aa4c8 --- /dev/null +++ b/support/cpp2/libcpp/files.c @@ -0,0 +1,1606 @@ +/* Part of CPP library. File handling. + Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1998, + 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Written by Per Bothner, 1994. + Based on CCCP program by Paul Rubin, June 1986 + Adapted to ANSI C, Richard Stallman, Jan 1987 + Split out of cpplib.c, Zack Weinberg, Oct 1998 + Reimplemented, Neil Booth, Jul 2003 + +This program 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 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "config.h" +#include "system.h" +#include "cpplib.h" +#include "internal.h" +#include "mkdeps.h" +#include "hashtab.h" +#include "md5.h" +#include + +/* Variable length record files on VMS will have a stat size that includes + record control characters that won't be included in the read size. */ +#ifdef VMS +# define FAB_C_VAR 2 /* variable length records (see Starlet fabdef.h) */ +# define STAT_SIZE_RELIABLE(ST) ((ST).st_fab_rfm != FAB_C_VAR) +#else +# define STAT_SIZE_RELIABLE(ST) true +#endif + +#ifdef __DJGPP__ +#include + /* For DJGPP redirected input is opened in text mode. */ +# define set_stdin_to_binary_mode() \ + if (! isatty (0)) setmode (0, O_BINARY) +#else +# define set_stdin_to_binary_mode() /* Nothing */ +#endif + +/* This structure represents a file searched for by CPP, whether it + exists or not. An instance may be pointed to by more than one + file_hash_entry; at present no reference count is kept. */ +struct _cpp_file +{ + /* Filename as given to #include or command line switch. */ + const char *name; + + /* The full path used to find the file. */ + const char *path; + + /* The full path of the pch file. */ + const char *pchname; + + /* The file's path with the basename stripped. NULL if it hasn't + been calculated yet. */ + const char *dir_name; + + /* Chain through all files. */ + struct _cpp_file *next_file; + + /* The contents of NAME after calling read_file(). */ + const uchar *buffer; + + /* The macro, if any, preventing re-inclusion. */ + const cpp_hashnode *cmacro; + + /* The directory in the search path where FILE was found. Used for + #include_next and determining whether a header is a system + header. */ + cpp_dir *dir; + + /* As filled in by stat(2) for the file. */ + struct stat st; + + /* File descriptor. Invalid if -1, otherwise open. */ + int fd; + + /* Zero if this file was successfully opened and stat()-ed, + otherwise errno obtained from failure. */ + int err_no; + + /* Number of times the file has been stacked for preprocessing. */ + unsigned short stack_count; + + /* If opened with #import or contains #pragma once. */ + bool once_only; + + /* If read() failed before. */ + bool dont_read; + + /* If this file is the main file. */ + bool main_file; + + /* If BUFFER above contains the true contents of the file. */ + bool buffer_valid; + + /* File is a PCH (on return from find_include_file). */ + bool pch; +}; + +/* A singly-linked list for all searches for a given file name, with + its head pointed to by a slot in FILE_HASH. The file name is what + appeared between the quotes in a #include directive; it can be + determined implicitly from the hash table location or explicitly + from FILE->name. + + FILE is a structure containing details about the file that was + found with that search, or details of how the search failed. + + START_DIR is the starting location of the search in the include + chain. The current directories for "" includes are also hashed in + the hash table and therefore unique. Files that are looked up + without using a search path, such as absolute filenames and file + names from the command line share a special starting directory so + they don't cause cache hits with normal include-chain lookups. + + If START_DIR is NULL then the entry is for a directory, not a file, + and the directory is in DIR. Since the starting point in a file + lookup chain is never NULL, this means that simple pointer + comparisons against START_DIR can be made to determine cache hits + in file lookups. + + If a cache lookup fails because of e.g. an extra "./" in the path, + then nothing will break. It is just less efficient as CPP will + have to do more work re-preprocessing the file, and/or comparing + its contents against earlier once-only files. +*/ +struct file_hash_entry +{ + struct file_hash_entry *next; + cpp_dir *start_dir; + union + { + _cpp_file *file; + cpp_dir *dir; + } u; +}; + +static bool open_file (_cpp_file *file); +static bool pch_open_file (cpp_reader *pfile, _cpp_file *file, + bool *invalid_pch); +static bool find_file_in_dir (cpp_reader *pfile, _cpp_file *file, + bool *invalid_pch); +static bool read_file_guts (cpp_reader *pfile, _cpp_file *file); +static bool read_file (cpp_reader *pfile, _cpp_file *file); +static bool should_stack_file (cpp_reader *, _cpp_file *file, bool import); +static struct cpp_dir *search_path_head (cpp_reader *, const char *fname, + int angle_brackets, enum include_type); +static const char *dir_name_of_file (_cpp_file *file); +static void open_file_failed (cpp_reader *pfile, _cpp_file *file, int); +static struct file_hash_entry *search_cache (struct file_hash_entry *head, + const cpp_dir *start_dir); +static _cpp_file *make_cpp_file (cpp_reader *, cpp_dir *, const char *fname); +static void destroy_cpp_file (_cpp_file *); +static cpp_dir *make_cpp_dir (cpp_reader *, const char *dir_name, int sysp); +static void allocate_file_hash_entries (cpp_reader *pfile); +static struct file_hash_entry *new_file_hash_entry (cpp_reader *pfile); +static int report_missing_guard (void **slot, void *b); +static hashval_t file_hash_hash (const void *p); +static int file_hash_eq (const void *p, const void *q); +static char *read_filename_string (int ch, FILE *f); +static void read_name_map (cpp_dir *dir); +static char *remap_filename (cpp_reader *pfile, _cpp_file *file); +static char *append_file_to_dir (const char *fname, cpp_dir *dir); +static bool validate_pch (cpp_reader *, _cpp_file *file, const char *pchname); +static int pchf_save_compare (const void *e1, const void *e2); +static int pchf_compare (const void *d_p, const void *e_p); +static bool check_file_against_entries (cpp_reader *, _cpp_file *, bool); + +/* Given a filename in FILE->PATH, with the empty string interpreted + as , open it. + + On success FILE contains an open file descriptor and stat + information for the file. On failure the file descriptor is -1 and + the appropriate errno is also stored in FILE. Returns TRUE iff + successful. + + We used to open files in nonblocking mode, but that caused more + problems than it solved. Do take care not to acquire a controlling + terminal by mistake (this can't happen on sane systems, but + paranoia is a virtue). + + Use the three-argument form of open even though we aren't + specifying O_CREAT, to defend against broken system headers. + + O_BINARY tells some runtime libraries (notably DJGPP) not to do + newline translation; we can handle DOS line breaks just fine + ourselves. */ +static bool +open_file (_cpp_file *file) +{ + if (file->path[0] == '\0') + { + file->fd = 0; + set_stdin_to_binary_mode (); + } + else + file->fd = open (file->path, O_RDONLY | O_NOCTTY | O_BINARY, 0666); + + if (file->fd != -1) + { + if (fstat (file->fd, &file->st) == 0) + { + if (!S_ISDIR (file->st.st_mode)) + { + file->err_no = 0; + return true; + } + + /* Ignore a directory and continue the search. The file we're + looking for may be elsewhere in the search path. */ + errno = ENOENT; + } + + close (file->fd); + file->fd = -1; + } + else if (errno == ENOTDIR) + errno = ENOENT; + + file->err_no = errno; + + return false; +} + +/* Temporary PCH intercept of opening a file. Try to find a PCH file + based on FILE->name and FILE->dir, and test those found for + validity using PFILE->cb.valid_pch. Return true iff a valid file is + found. Set *INVALID_PCH if a PCH file is found but wasn't valid. */ + +static bool +pch_open_file (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch) +{ + static const char extension[] = ".gch"; + const char *path = file->path; + size_t len, flen; + char *pchname; + struct stat st; + bool valid = false; + + /* No PCH on or if not requested. */ + if (file->name[0] == '\0' || !pfile->cb.valid_pch) + return false; + + flen = strlen (path); + len = flen + sizeof (extension); + pchname = XNEWVEC (char, len); + memcpy (pchname, path, flen); + memcpy (pchname + flen, extension, sizeof (extension)); + + if (stat (pchname, &st) == 0) + { + DIR *pchdir; + struct dirent *d; + size_t dlen, plen = len; + + if (!S_ISDIR (st.st_mode)) + valid = validate_pch (pfile, file, pchname); + else if ((pchdir = opendir (pchname)) != NULL) + { + pchname[plen - 1] = '/'; + while ((d = readdir (pchdir)) != NULL) + { + dlen = strlen (d->d_name) + 1; + if ((strcmp (d->d_name, ".") == 0) + || (strcmp (d->d_name, "..") == 0)) + continue; + if (dlen + plen > len) + { + len += dlen + 64; + pchname = XRESIZEVEC (char, pchname, len); + } + memcpy (pchname + plen, d->d_name, dlen); + valid = validate_pch (pfile, file, pchname); + if (valid) + break; + } + closedir (pchdir); + } + if (valid) + file->pch = true; + else + *invalid_pch = true; + } + + if (valid) + file->pchname = pchname; + else + free (pchname); + + return valid; +} + +/* Try to open the path FILE->name appended to FILE->dir. This is + where remap and PCH intercept the file lookup process. Return true + if the file was found, whether or not the open was successful. + Set *INVALID_PCH to true if a PCH file is found but wasn't valid. */ + +static bool +find_file_in_dir (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch) +{ + char *path; + + if (CPP_OPTION (pfile, remap) && (path = remap_filename (pfile, file))) + ; + else + if (file->dir->construct) + path = file->dir->construct (file->name, file->dir); + else + path = append_file_to_dir (file->name, file->dir); + + if (path) + { + file->path = path; + if (pch_open_file (pfile, file, invalid_pch)) + return true; + + if (open_file (file)) + return true; + + if (file->err_no != ENOENT) + { + open_file_failed (pfile, file, 0); + return true; + } + + free (path); + file->path = file->name; + } + else + { + file->err_no = ENOENT; + file->path = NULL; + } + + return false; +} + +/* Return tue iff the missing_header callback found the given HEADER. */ +static bool +search_path_exhausted (cpp_reader *pfile, const char *header, _cpp_file *file) +{ + missing_header_cb func = pfile->cb.missing_header; + + /* When the regular search path doesn't work, try context dependent + headers search paths. */ + if (func + && file->dir == NULL) + { + if ((file->path = func (pfile, header, &file->dir)) != NULL) + { + if (open_file (file)) + return true; + free ((void *)file->path); + } + file->path = file->name; + } + + return false; +} + +bool +_cpp_find_failed (_cpp_file *file) +{ + return file->err_no != 0; +} + +/* Given a filename FNAME search for such a file in the include path + starting from START_DIR. If FNAME is the empty string it is + interpreted as STDIN if START_DIR is PFILE->no_search_path. + + If the file is not found in the file cache fall back to the O/S and + add the result to our cache. + + If the file was not found in the filesystem, or there was an error + opening it, then ERR_NO is nonzero and FD is -1. If the file was + found, then ERR_NO is zero and FD could be -1 or an open file + descriptor. FD can be -1 if the file was found in the cache and + had previously been closed. To open it again pass the return value + to open_file(). +*/ +_cpp_file * +_cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, bool fake, int angle_brackets) +{ + struct file_hash_entry *entry, **hash_slot; + _cpp_file *file; + bool invalid_pch = false; + + /* Ensure we get no confusion between cached files and directories. */ + if (start_dir == NULL) + cpp_error (pfile, CPP_DL_ICE, "NULL directory in find_file"); + + hash_slot = (struct file_hash_entry **) + htab_find_slot_with_hash (pfile->file_hash, fname, + htab_hash_string (fname), + INSERT); + + /* First check the cache before we resort to memory allocation. */ + entry = search_cache (*hash_slot, start_dir); + if (entry) + return entry->u.file; + + file = make_cpp_file (pfile, start_dir, fname); + + /* Try each path in the include chain. */ + for (; !fake ;) + { + if (find_file_in_dir (pfile, file, &invalid_pch)) + break; + + file->dir = file->dir->next; + if (file->dir == NULL) + { + if (search_path_exhausted (pfile, fname, file)) + { + /* Although this file must not go in the cache, because + the file found might depend on things (like the current file) + that aren't represented in the cache, it still has to go in + the list of all files so that #import works. */ + file->next_file = pfile->all_files; + pfile->all_files = file; + return file; + } + + open_file_failed (pfile, file, angle_brackets); + if (invalid_pch) + { + cpp_error (pfile, CPP_DL_ERROR, + "one or more PCH files were found, but they were invalid"); + if (!cpp_get_options (pfile)->warn_invalid_pch) + cpp_error (pfile, CPP_DL_ERROR, + "use -Winvalid-pch for more information"); + } + break; + } + + /* Only check the cache for the starting location (done above) + and the quote and bracket chain heads because there are no + other possible starting points for searches. */ + if (file->dir != pfile->bracket_include + && file->dir != pfile->quote_include) + continue; + + entry = search_cache (*hash_slot, file->dir); + if (entry) + break; + } + + if (entry) + { + /* Cache for START_DIR too, sharing the _cpp_file structure. */ + free ((char *) file->name); + free (file); + file = entry->u.file; + } + else + { + /* This is a new file; put it in the list. */ + file->next_file = pfile->all_files; + pfile->all_files = file; + } + + /* Store this new result in the hash table. */ + entry = new_file_hash_entry (pfile); + entry->next = *hash_slot; + entry->start_dir = start_dir; + entry->u.file = file; + *hash_slot = entry; + + return file; +} + +/* Read a file into FILE->buffer, returning true on success. + + If FILE->fd is something weird, like a block device, we don't want + to read it at all. Don't even try to figure out what something is, + except for plain files and block devices, since there is no + reliable portable way of doing this. + + FIXME: Flush file cache and try again if we run out of memory. */ +static bool +read_file_guts (cpp_reader *pfile, _cpp_file *file) +{ + ssize_t size, total, count; + uchar *buf; + bool regular; + + if (S_ISBLK (file->st.st_mode)) + { + cpp_error (pfile, CPP_DL_ERROR, "%s is a block device", file->path); + return false; + } + + regular = S_ISREG (file->st.st_mode); + if (regular) + { + /* off_t might have a wider range than ssize_t - in other words, + the max size of a file might be bigger than the address + space. We can't handle a file that large. (Anyone with + a single source file bigger than 2GB needs to rethink + their coding style.) Some systems (e.g. AIX 4.1) define + SSIZE_MAX to be much smaller than the actual range of the + type. Use INTTYPE_MAXIMUM unconditionally to ensure this + does not bite us. */ +#ifndef __BORLANDC__ + if (file->st.st_size > INTTYPE_MAXIMUM (ssize_t)) + { + cpp_error (pfile, CPP_DL_ERROR, "%s is too large", file->path); + return false; + } +#endif + + size = file->st.st_size; + } + else + /* 8 kilobytes is a sensible starting size. It ought to be bigger + than the kernel pipe buffer, and it's definitely bigger than + the majority of C source files. */ + size = 8 * 1024; + + buf = XNEWVEC (uchar, size + 1); + total = 0; + while ((count = read (file->fd, buf + total, size - total)) > 0) + { + total += count; + + if (total == size) + { + if (regular) + break; + size *= 2; + buf = XRESIZEVEC (uchar, buf, size + 1); + } + } + + if (count < 0) + { + cpp_errno (pfile, CPP_DL_ERROR, file->path); + return false; + } + +#ifndef __BORLANDC__ + /* For some reason, even though we opened with O_BINARY, + * Borland C++ seems to insist on doing CR/LF -> LF + * translations for us, which results in the file appearing + * shorter than stat told us it should be. + * + * This sucks, but don't bother throwing a warning. + */ + if (regular && total != size && STAT_SIZE_RELIABLE (file->st)) + cpp_error (pfile, CPP_DL_WARNING, + "%s is shorter than expected", file->path); +#endif + + file->buffer = _cpp_convert_input (pfile, CPP_OPTION (pfile, input_charset), + buf, size, total, &file->st.st_size); + file->buffer_valid = true; + + return true; +} + +/* Convenience wrapper around read_file_guts that opens the file if + necessary and closes the file descriptor after reading. FILE must + have been passed through find_file() at some stage. */ +static bool +read_file (cpp_reader *pfile, _cpp_file *file) +{ + /* If we already have its contents in memory, succeed immediately. */ + if (file->buffer_valid) + return true; + + /* If an earlier read failed for some reason don't try again. */ + if (file->dont_read || file->err_no) + return false; + + if (file->fd == -1 && !open_file (file)) + { + open_file_failed (pfile, file, 0); + return false; + } + + file->dont_read = !read_file_guts (pfile, file); + close (file->fd); + file->fd = -1; + + return !file->dont_read; +} + +/* Returns TRUE if FILE's contents have been successfully placed in + FILE->buffer and the file should be stacked, otherwise false. */ +static bool +should_stack_file (cpp_reader *pfile, _cpp_file *file, bool import) +{ + _cpp_file *f; + + /* Skip once-only files. */ + if (file->once_only) + return false; + + /* We must mark the file once-only if #import now, before header + guard checks. Otherwise, undefining the header guard might + cause the file to be re-stacked. */ + if (import) + { + _cpp_mark_file_once_only (pfile, file); + + /* Don't stack files that have been stacked before. */ + if (file->stack_count) + return false; + } + + /* Skip if the file had a header guard and the macro is defined. + PCH relies on this appearing before the PCH handler below. */ + if (file->cmacro && file->cmacro->type == NT_MACRO) + return false; + + /* Handle PCH files immediately; don't stack them. */ + if (file->pch) + { + pfile->cb.read_pch (pfile, file->pchname, file->fd, file->path); + close (file->fd); + file->fd = -1; + return false; + } + + if (!read_file (pfile, file)) + return false; + + /* Check the file against the PCH file. This is done before + checking against files we've already seen, since it may save on + I/O. */ + if (check_file_against_entries (pfile, file, import)) + { + /* If this isn't a #import, but yet we can't include the file, + that means that it was #import-ed in the PCH file, + so we can never include it again. */ + if (! import) + _cpp_mark_file_once_only (pfile, file); + return false; + } + + /* Now we've read the file's contents, we can stack it if there + are no once-only files. */ + if (!pfile->seen_once_only) + return true; + + /* We may have read the file under a different name. Look + for likely candidates and compare file contents to be sure. */ + for (f = pfile->all_files; f; f = f->next_file) + { + if (f == file) + continue; + + if ((import || f->once_only) + && f->err_no == 0 + && f->st.st_mtime == file->st.st_mtime + && f->st.st_size == file->st.st_size) + { + _cpp_file *ref_file; + bool same_file_p = false; + + if (f->buffer && !f->buffer_valid) + { + /* We already have a buffer but it is not valid, because + the file is still stacked. Make a new one. */ + ref_file = make_cpp_file (pfile, f->dir, f->name); + ref_file->path = f->path; + } + else + /* The file is not stacked anymore. We can reuse it. */ + ref_file = f; + + same_file_p = read_file (pfile, ref_file) + /* Size might have changed in read_file(). */ + && ref_file->st.st_size == file->st.st_size + && !memcmp (ref_file->buffer, + file->buffer, + file->st.st_size); + + if (f->buffer && !f->buffer_valid) + { + ref_file->path = 0; + destroy_cpp_file (ref_file); + } + + if (same_file_p) + break; + } + } + + return f == NULL; +} + +/* Place the file referenced by FILE into a new buffer on the buffer + stack if possible. IMPORT is true if this stacking attempt is + because of a #import directive. Returns true if a buffer is + stacked. */ +bool +_cpp_stack_file (cpp_reader *pfile, _cpp_file *file, bool import) +{ + cpp_buffer *buffer; + int sysp; + + if (!should_stack_file (pfile, file, import)) + return false; + + if (pfile->buffer == NULL || file->dir == NULL) + sysp = 0; + else + sysp = MAX (pfile->buffer->sysp, file->dir->sysp); + + /* Add the file to the dependencies on its first inclusion. */ + if (CPP_OPTION (pfile, deps.style) > !!sysp && !file->stack_count) + { + if (!file->main_file || !CPP_OPTION (pfile, deps.ignore_main_file)) + deps_add_dep (pfile->deps, file->path); + } + + /* Clear buffer_valid since _cpp_clean_line messes it up. */ + file->buffer_valid = false; + file->stack_count++; + + /* Stack the buffer. */ + buffer = cpp_push_buffer (pfile, file->buffer, file->st.st_size, + CPP_OPTION (pfile, preprocessed)); + buffer->file = file; + buffer->sysp = sysp; + + /* Initialize controlling macro state. */ + pfile->mi_valid = true; + pfile->mi_cmacro = 0; + + /* Generate the call back. */ + _cpp_do_file_change (pfile, LC_ENTER, file->path, 1, sysp); + + return true; +} + +/* Mark FILE to be included once only. */ +void +_cpp_mark_file_once_only (cpp_reader *pfile, _cpp_file *file) +{ + pfile->seen_once_only = true; + file->once_only = true; +} + +/* Return the directory from which searching for FNAME should start, + considering the directive TYPE and ANGLE_BRACKETS. If there is + nothing left in the path, returns NULL. */ +static struct cpp_dir * +search_path_head (cpp_reader *pfile, const char *fname, int angle_brackets, + enum include_type type) +{ + cpp_dir *dir; + _cpp_file *file; + + if (IS_ABSOLUTE_PATH (fname)) + return &pfile->no_search_path; + + /* pfile->buffer is NULL when processing an -include command-line flag. */ + file = pfile->buffer == NULL ? pfile->main_file : pfile->buffer->file; + + /* For #include_next, skip in the search path past the dir in which + the current file was found, but if it was found via an absolute + path use the normal search logic. */ + if (type == IT_INCLUDE_NEXT && file->dir) + dir = file->dir->next; + else if (angle_brackets) + dir = pfile->bracket_include; + else if (type == IT_CMDLINE) + /* -include and -imacros use the #include "" chain with the + preprocessor's cwd prepended. */ + return make_cpp_dir (pfile, "./", false); + else if (pfile->quote_ignores_source_dir) + dir = pfile->quote_include; + else + return make_cpp_dir (pfile, dir_name_of_file (file), + pfile->buffer ? pfile->buffer->sysp : 0); + + if (dir == NULL) + cpp_error (pfile, CPP_DL_ERROR, + "no include path in which to search for %s", fname); + + return dir; +} + +/* Strip the basename from the file's path. It ends with a slash if + of nonzero length. Note that this procedure also works for + , which is represented by the empty string. */ +static const char * +dir_name_of_file (_cpp_file *file) +{ + if (!file->dir_name) + { + size_t len = lbasename (file->path) - file->path; + char *dir_name = XNEWVEC (char, len + 1); + + memcpy (dir_name, file->path, len); + dir_name[len] = '\0'; + file->dir_name = dir_name; + } + + return file->dir_name; +} + +/* Handles #include-family directives (distinguished by TYPE), + including HEADER, and the command line -imacros and -include. + Returns true if a buffer was stacked. */ +bool +_cpp_stack_include (cpp_reader *pfile, const char *fname, int angle_brackets, + enum include_type type) +{ + struct cpp_dir *dir; + _cpp_file *file; + + dir = search_path_head (pfile, fname, angle_brackets, type); + if (!dir) + return false; + + file = _cpp_find_file (pfile, fname, dir, false, angle_brackets); + + /* Compensate for the increment in linemap_add. In the case of a + normal #include, we're currently at the start of the line + *following* the #include. A separate source_location for this + location makes no sense (until we do the LC_LEAVE), and + complicates LAST_SOURCE_LINE_LOCATION. This does not apply if we + found a PCH file (in which case linemap_add is not called) or we + were included from the command-line. */ + if (! file->pch && file->err_no == 0 && type != IT_CMDLINE) + pfile->line_table->highest_location--; + + return _cpp_stack_file (pfile, file, type == IT_IMPORT); +} + +/* Could not open FILE. The complication is dependency output. */ +static void +open_file_failed (cpp_reader *pfile, _cpp_file *file, int angle_brackets) +{ + int sysp = pfile->line_table->highest_line > 1 && pfile->buffer ? pfile->buffer->sysp : 0; + bool print_dep = CPP_OPTION (pfile, deps.style) > (angle_brackets || !!sysp); + + errno = file->err_no; + if (print_dep && CPP_OPTION (pfile, deps.missing_files) && errno == ENOENT) + deps_add_dep (pfile->deps, file->name); + else + { + /* If we are outputting dependencies but not for this file then + don't error because we can still produce correct output. */ + if (CPP_OPTION (pfile, deps.style) && ! print_dep) + cpp_errno (pfile, CPP_DL_WARNING, file->path); + else + cpp_errno (pfile, CPP_DL_ERROR, file->path); + } +} + +/* Search in the chain beginning at HEAD for a file whose search path + started at START_DIR != NULL. */ +static struct file_hash_entry * +search_cache (struct file_hash_entry *head, const cpp_dir *start_dir) +{ + while (head && head->start_dir != start_dir) + head = head->next; + + return head; +} + +/* Allocate a new _cpp_file structure. */ +static _cpp_file * +make_cpp_file (cpp_reader *pfile, cpp_dir *dir, const char *fname) +{ + _cpp_file *file; + + file = XCNEW (_cpp_file); + file->main_file = !pfile->buffer; + file->fd = -1; + file->dir = dir; + file->name = xstrdup (fname); + + return file; +} + +/* Release a _cpp_file structure. */ +static void +destroy_cpp_file (_cpp_file *file) +{ + if (file->buffer) + free ((void *) file->buffer); + free ((void *) file->name); + free (file); +} + +/* A hash of directory names. The directory names are the path names + of files which contain a #include "", the included file name is + appended to this directories. + + To avoid duplicate entries we follow the convention that all + non-empty directory names should end in a '/'. DIR_NAME must be + stored in permanently allocated memory. */ +static cpp_dir * +make_cpp_dir (cpp_reader *pfile, const char *dir_name, int sysp) +{ + struct file_hash_entry *entry, **hash_slot; + cpp_dir *dir; + + hash_slot = (struct file_hash_entry **) + htab_find_slot_with_hash (pfile->dir_hash, dir_name, + htab_hash_string (dir_name), + INSERT); + + /* Have we already hashed this directory? */ + for (entry = *hash_slot; entry; entry = entry->next) + if (entry->start_dir == NULL) + return entry->u.dir; + + dir = XCNEW (cpp_dir); + dir->next = pfile->quote_include; + dir->name = (char *) dir_name; + dir->len = strlen (dir_name); + dir->sysp = sysp; + dir->construct = 0; + + /* Store this new result in the hash table. */ + entry = new_file_hash_entry (pfile); + entry->next = *hash_slot; + entry->start_dir = NULL; + entry->u.dir = dir; + *hash_slot = entry; + + return dir; +} + +/* Create a new block of memory for file hash entries. */ +static void +allocate_file_hash_entries (cpp_reader *pfile) +{ + pfile->file_hash_entries_used = 0; + pfile->file_hash_entries_allocated = 127; + pfile->file_hash_entries = XNEWVEC (struct file_hash_entry, + pfile->file_hash_entries_allocated); +} + +/* Return a new file hash entry. */ +static struct file_hash_entry * +new_file_hash_entry (cpp_reader *pfile) +{ + if (pfile->file_hash_entries_used == pfile->file_hash_entries_allocated) + allocate_file_hash_entries (pfile); + + return &pfile->file_hash_entries[pfile->file_hash_entries_used++]; +} + +/* Returns TRUE if a file FNAME has ever been successfully opened. + This routine is not intended to correctly handle filenames aliased + by links or redundant . or .. traversals etc. */ +bool +cpp_included (cpp_reader *pfile, const char *fname) +{ + struct file_hash_entry *entry; + + entry = (struct file_hash_entry *) + htab_find_with_hash (pfile->file_hash, fname, htab_hash_string (fname)); + + while (entry && (entry->start_dir == NULL || entry->u.file->err_no)) + entry = entry->next; + + return entry != NULL; +} + +/* Calculate the hash value of a file hash entry P. */ + +static hashval_t +file_hash_hash (const void *p) +{ + struct file_hash_entry *entry = (struct file_hash_entry *) p; + const char *hname; + if (entry->start_dir) + hname = entry->u.file->name; + else + hname = entry->u.dir->name; + + return htab_hash_string (hname); +} + +/* Compare a string Q against a file hash entry P. */ +static int +file_hash_eq (const void *p, const void *q) +{ + struct file_hash_entry *entry = (struct file_hash_entry *) p; + const char *fname = (const char *) q; + const char *hname; + + if (entry->start_dir) + hname = entry->u.file->name; + else + hname = entry->u.dir->name; + + return strcmp (hname, fname) == 0; +} + +/* Initialize everything in this source file. */ +void +_cpp_init_files (cpp_reader *pfile) +{ + pfile->file_hash = htab_create_alloc (127, file_hash_hash, file_hash_eq, + NULL, xcalloc, free); + pfile->dir_hash = htab_create_alloc (127, file_hash_hash, file_hash_eq, + NULL, xcalloc, free); + allocate_file_hash_entries (pfile); +} + +/* Finalize everything in this source file. */ +void +_cpp_cleanup_files (cpp_reader *pfile) +{ + htab_delete (pfile->file_hash); + htab_delete (pfile->dir_hash); +} + +/* Enter a file name in the hash for the sake of cpp_included. */ +void +_cpp_fake_include (cpp_reader *pfile, const char *fname) +{ + _cpp_find_file (pfile, fname, pfile->buffer->file->dir, true, 0); +} + +/* Not everyone who wants to set system-header-ness on a buffer can + see the details of a buffer. This is an exported interface because + fix-header needs it. */ +void +cpp_make_system_header (cpp_reader *pfile, int syshdr, int externc) +{ + int flags = 0; + const struct line_maps *line_table = pfile->line_table; + const struct line_map *map = &line_table->maps[line_table->used-1]; + + /* 1 = system header, 2 = system header to be treated as C. */ + if (syshdr) + flags = 1 + (externc != 0); + pfile->buffer->sysp = flags; + _cpp_do_file_change (pfile, LC_RENAME, map->to_file, + SOURCE_LINE (map, pfile->line_table->highest_line), flags); +} + +/* Allow the client to change the current file. Used by the front end + to achieve pseudo-file names like . + If REASON is LC_LEAVE, then NEW_NAME must be NULL. */ +void +cpp_change_file (cpp_reader *pfile, enum lc_reason reason, + const char *new_name) +{ + _cpp_do_file_change (pfile, reason, new_name, 1, 0); +} + +/* Callback function for htab_traverse. */ +static int +report_missing_guard (void **slot, void *b) +{ + struct file_hash_entry *entry = (struct file_hash_entry *) *slot; + int *bannerp = (int *) b; + + /* Skip directories. */ + if (entry->start_dir != NULL) + { + _cpp_file *file = entry->u.file; + + /* We don't want MI guard advice for the main file. */ + if (file->cmacro == NULL && file->stack_count == 1 && !file->main_file) + { + if (*bannerp == 0) + { + fputs (_("Multiple include guards may be useful for:\n"), + stderr); + *bannerp = 1; + } + + fputs (entry->u.file->path, stderr); + putc ('\n', stderr); + } + } + + return 0; +} + +/* Report on all files that might benefit from a multiple include guard. + Triggered by -H. */ +void +_cpp_report_missing_guards (cpp_reader *pfile) +{ + int banner = 0; + + htab_traverse (pfile->file_hash, report_missing_guard, &banner); +} + +/* Locate HEADER, and determine whether it is newer than the current + file. If it cannot be located or dated, return -1, if it is + newer, return 1, otherwise 0. */ +int +_cpp_compare_file_date (cpp_reader *pfile, const char *fname, + int angle_brackets) +{ + _cpp_file *file; + struct cpp_dir *dir; + + dir = search_path_head (pfile, fname, angle_brackets, IT_INCLUDE); + if (!dir) + return -1; + + file = _cpp_find_file (pfile, fname, dir, false, angle_brackets); + if (file->err_no) + return -1; + + if (file->fd != -1) + { + close (file->fd); + file->fd = -1; + } + + return file->st.st_mtime > pfile->buffer->file->st.st_mtime; +} + +/* Pushes the given file onto the buffer stack. Returns nonzero if + successful. */ +bool +cpp_push_include (cpp_reader *pfile, const char *fname) +{ + return _cpp_stack_include (pfile, fname, false, IT_CMDLINE); +} + +/* Do appropriate cleanup when a file INC's buffer is popped off the + input stack. */ +void +_cpp_pop_file_buffer (cpp_reader *pfile, _cpp_file *file) +{ + /* Record the inclusion-preventing macro, which could be NULL + meaning no controlling macro. */ + if (pfile->mi_valid && file->cmacro == NULL) + file->cmacro = pfile->mi_cmacro; + + /* Invalidate control macros in the #including file. */ + pfile->mi_valid = false; + + if (file->buffer) + { + free ((void *) file->buffer); + file->buffer = NULL; + file->buffer_valid = false; + } +} + +/* Set the include chain for "" to QUOTE, for <> to BRACKET. If + QUOTE_IGNORES_SOURCE_DIR, then "" includes do not look in the + directory of the including file. + + If BRACKET does not lie in the QUOTE chain, it is set to QUOTE. */ +void +cpp_set_include_chains (cpp_reader *pfile, cpp_dir *quote, cpp_dir *bracket, + int quote_ignores_source_dir) +{ + pfile->quote_include = quote; + pfile->bracket_include = quote; + pfile->quote_ignores_source_dir = quote_ignores_source_dir; + + for (; quote; quote = quote->next) + { + quote->name_map = NULL; + quote->len = strlen (quote->name); + if (quote == bracket) + pfile->bracket_include = bracket; + } +} + +/* Append the file name to the directory to create the path, but don't + turn / into // or // into ///; // may be a namespace escape. */ +static char * +append_file_to_dir (const char *fname, cpp_dir *dir) +{ + size_t dlen, flen; + char *path; + + dlen = dir->len; + flen = strlen (fname); + path = XNEWVEC (char, dlen + 1 + flen + 1); + memcpy (path, dir->name, dlen); + if (dlen && path[dlen - 1] != '/') + path[dlen++] = '/'; + memcpy (&path[dlen], fname, flen + 1); + + return path; +} + +/* Read a space delimited string of unlimited length from a stdio + file F. */ +static char * +read_filename_string (int ch, FILE *f) +{ + char *alloc, *set; + int len; + + len = 20; + set = alloc = XNEWVEC (char, len + 1); + if (! is_space (ch)) + { + *set++ = ch; + while ((ch = getc (f)) != EOF && ! is_space (ch)) + { + if (set - alloc == len) + { + len *= 2; + alloc = XRESIZEVEC (char, alloc, len + 1); + set = alloc + len / 2; + } + *set++ = ch; + } + } + *set = '\0'; + ungetc (ch, f); + return alloc; +} + +/* Read the file name map file for DIR. */ +static void +read_name_map (cpp_dir *dir) +{ + static const char FILE_NAME_MAP_FILE[] = "header.gcc"; + char *name; + FILE *f; + size_t len, count = 0, room = 9; + + len = dir->len; + name = (char *) alloca (len + sizeof (FILE_NAME_MAP_FILE) + 1); + memcpy (name, dir->name, len); + if (len && name[len - 1] != '/') + name[len++] = '/'; + strcpy (name + len, FILE_NAME_MAP_FILE); + f = fopen (name, "r"); + + dir->name_map = XNEWVEC (const char *, room); + + /* Silently return NULL if we cannot open. */ + if (f) + { + int ch; + + while ((ch = getc (f)) != EOF) + { + char *to; + + if (is_space (ch)) + continue; + + if (count + 2 > room) + { + room += 8; + dir->name_map = XRESIZEVEC (const char *, dir->name_map, room); + } + + dir->name_map[count] = read_filename_string (ch, f); + while ((ch = getc (f)) != EOF && is_hspace (ch)) + ; + + to = read_filename_string (ch, f); + if (IS_ABSOLUTE_PATH (to)) + dir->name_map[count + 1] = to; + else + { + dir->name_map[count + 1] = append_file_to_dir (to, dir); + free (to); + } + + count += 2; + while ((ch = getc (f)) != '\n') + if (ch == EOF) + break; + } + + fclose (f); + } + + /* Terminate the list of maps. */ + dir->name_map[count] = NULL; +} + +/* Remap a FILE's name based on the file_name_map, if any, for + FILE->dir. If the file name has any directory separators, + recursively check those directories too. */ +static char * +remap_filename (cpp_reader *pfile, _cpp_file *file) +{ + const char *fname, *p; + char *new_dir; + cpp_dir *dir; + size_t index, len; + + dir = file->dir; + fname = file->name; + + for (;;) + { + if (!dir->name_map) + read_name_map (dir); + + for (index = 0; dir->name_map[index]; index += 2) + if (!strcmp (dir->name_map[index], fname)) + return xstrdup (dir->name_map[index + 1]); + + p = strchr (fname, '/'); + if (!p || p == fname) + return NULL; + + len = dir->len + (p - fname + 1); + new_dir = XNEWVEC (char, len + 1); + memcpy (new_dir, dir->name, dir->len); + memcpy (new_dir + dir->len, fname, p - fname + 1); + new_dir[len] = '\0'; + + dir = make_cpp_dir (pfile, new_dir, dir->sysp); + fname = p + 1; + } +} + +/* Returns true if PCHNAME is a valid PCH file for FILE. */ +static bool +validate_pch (cpp_reader *pfile, _cpp_file *file, const char *pchname) +{ + const char *saved_path = file->path; + bool valid = false; + + file->path = pchname; + if (open_file (file)) + { + valid = 1 & pfile->cb.valid_pch (pfile, pchname, file->fd); + + if (!valid) + { + close (file->fd); + file->fd = -1; + } + + if (CPP_OPTION (pfile, print_include_names)) + { + unsigned int i; + for (i = 1; i < pfile->line_table->depth; i++) + putc ('.', stderr); + fprintf (stderr, "%c %s\n", + valid ? '!' : 'x', pchname); + } + } + + file->path = saved_path; + return valid; +} + +/* Get the path associated with the _cpp_file F. The path includes + the base name from the include directive and the directory it was + found in via the search path. */ + +const char * +cpp_get_path (struct _cpp_file *f) +{ + return f->path; +} + +/* Get the directory associated with the _cpp_file F. */ + +cpp_dir * +cpp_get_dir (struct _cpp_file *f) +{ + return f->dir; +} + +/* Get the cpp_buffer currently associated with the cpp_reader + PFILE. */ + +cpp_buffer * +cpp_get_buffer (cpp_reader *pfile) +{ + return pfile->buffer; +} + +/* Get the _cpp_file associated with the cpp_buffer B. */ + +_cpp_file * +cpp_get_file (cpp_buffer *b) +{ + return b->file; +} + +/* Get the previous cpp_buffer given a cpp_buffer B. The previous + buffer is the buffer that included the given buffer. */ + +cpp_buffer * +cpp_get_prev (cpp_buffer *b) +{ + return b->prev; +} + +/* This data structure holds the list of header files that were seen + while the PCH was being built. The 'entries' field is kept sorted + in memcmp() order; yes, this means that on little-endian systems, + it's sorted initially by the least-significant byte of 'size', but + that's OK. The code does rely on having entries with the same size + next to each other. */ + +struct pchf_entry { + /* The size of this file. This is used to save running a MD5 checksum + if the sizes don't match. */ + off_t size; + /* The MD5 checksum of this file. */ + unsigned char sum[16]; + /* Is this file to be included only once? */ + bool once_only; +}; + +struct pchf_data { + /* Number of pchf_entry structures. */ + size_t count; + + /* Are there any values with once_only set? + This is used as an optimisation, it means we don't have to search + the structure if we're processing a regular #include. */ + bool have_once_only; + + struct pchf_entry entries[1]; +}; + +static struct pchf_data *pchf; + +/* A qsort ordering function for pchf_entry structures. */ + +static int +pchf_save_compare (const void *e1, const void *e2) +{ + return memcmp (e1, e2, sizeof (struct pchf_entry)); +} + +/* Create and write to F a pchf_data structure. */ + +bool +_cpp_save_file_entries (cpp_reader *pfile, FILE *fp) +{ + size_t count = 0; + struct pchf_data *result; + size_t result_size; + _cpp_file *f; + + for (f = pfile->all_files; f; f = f->next_file) + ++count; + + result_size = (sizeof (struct pchf_data) + + sizeof (struct pchf_entry) * (count - 1)); + result = XCNEWVAR (struct pchf_data, result_size); + + result->count = 0; + result->have_once_only = false; + + for (f = pfile->all_files; f; f = f->next_file) + { + size_t count; + + /* This should probably never happen, since if a read error occurred + the PCH file shouldn't be written... */ + if (f->dont_read || f->err_no) + continue; + + if (f->stack_count == 0) + continue; + + count = result->count++; + + result->entries[count].once_only = f->once_only; + /* |= is avoided in the next line because of an HP C compiler bug */ + result->have_once_only = result->have_once_only | f->once_only; + if (f->buffer_valid) + md5_buffer ((const char *)f->buffer, + f->st.st_size, result->entries[count].sum); + else + { + FILE *ff; + int oldfd = f->fd; + + if (!open_file (f)) + { + open_file_failed (pfile, f, 0); + return false; + } + ff = fdopen (f->fd, "rb"); + md5_stream (ff, result->entries[count].sum); + fclose (ff); + f->fd = oldfd; + } + result->entries[count].size = f->st.st_size; + } + + result_size = (sizeof (struct pchf_data) + + sizeof (struct pchf_entry) * (result->count - 1)); + + qsort (result->entries, result->count, sizeof (struct pchf_entry), + pchf_save_compare); + + return fwrite (result, result_size, 1, fp) == 1; +} + +/* Read the pchf_data structure from F. */ + +bool +_cpp_read_file_entries (cpp_reader *pfile ATTRIBUTE_UNUSED, FILE *f) +{ + struct pchf_data d; + + if (fread (&d, sizeof (struct pchf_data) - sizeof (struct pchf_entry), 1, f) + != 1) + return false; + + pchf = XNEWVAR (struct pchf_data, sizeof (struct pchf_data) + + sizeof (struct pchf_entry) * (d.count - 1)); + memcpy (pchf, &d, sizeof (struct pchf_data) - sizeof (struct pchf_entry)); + if (fread (pchf->entries, sizeof (struct pchf_entry), d.count, f) + != d.count) + return false; + return true; +} + +/* The parameters for pchf_compare. */ + +struct pchf_compare_data +{ + /* The size of the file we're looking for. */ + off_t size; + + /* The MD5 checksum of the file, if it's been computed. */ + unsigned char sum[16]; + + /* Is SUM valid? */ + bool sum_computed; + + /* Do we need to worry about entries that don't have ONCE_ONLY set? */ + bool check_included; + + /* The file that we're searching for. */ + _cpp_file *f; +}; + +/* bsearch comparison function; look for D_P in E_P. */ + +static int +pchf_compare (const void *d_p, const void *e_p) +{ + const struct pchf_entry *e = (const struct pchf_entry *)e_p; + struct pchf_compare_data *d = (struct pchf_compare_data *)d_p; + int result; + + result = memcmp (&d->size, &e->size, sizeof (off_t)); + if (result != 0) + return result; + + if (! d->sum_computed) + { + _cpp_file *const f = d->f; + + md5_buffer ((const char *)f->buffer, f->st.st_size, d->sum); + d->sum_computed = true; + } + + result = memcmp (d->sum, e->sum, 16); + if (result != 0) + return result; + + if (d->check_included || e->once_only) + return 0; + else + return 1; +} + +/* Check that F is not in a list read from a PCH file (if any). + Assumes that f->buffer_valid is true. Return TRUE if the file + should not be read. */ + +static bool +check_file_against_entries (cpp_reader *pfile ATTRIBUTE_UNUSED, + _cpp_file *f, + bool check_included) +{ + struct pchf_compare_data d; + + if (pchf == NULL + || (! check_included && ! pchf->have_once_only)) + return false; + + d.size = f->st.st_size; + d.sum_computed = false; + d.f = f; + d.check_included = check_included; + return bsearch (&d, pchf->entries, pchf->count, sizeof (struct pchf_entry), + pchf_compare) != NULL; +} diff --git a/support/cpp2/libcpp/identifiers.c b/support/cpp2/libcpp/identifiers.c new file mode 100644 index 00000000..18070b13 --- /dev/null +++ b/support/cpp2/libcpp/identifiers.c @@ -0,0 +1,120 @@ +/* Hash tables for the CPP library. + Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998, + 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + Written by Per Bothner, 1994. + Based on CCCP program by Paul Rubin, June 1986 + Adapted to ANSI C, Richard Stallman, Jan 1987 + +This program 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 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +#include "config.h" +#include "system.h" +#include "cpplib.h" +#include "internal.h" + +static cpp_hashnode *alloc_node (hash_table *); + +/* Return an identifier node for hashtable.c. Used by cpplib except + when integrated with the C front ends. */ +static cpp_hashnode * +alloc_node (hash_table *table) +{ + cpp_hashnode *node; + + node = XOBNEW (&table->pfile->hash_ob, cpp_hashnode); + memset (node, 0, sizeof (cpp_hashnode)); + return node; +} + +/* Set up the identifier hash table. Use TABLE if non-null, otherwise + create our own. */ +void +_cpp_init_hashtable (cpp_reader *pfile, hash_table *table) +{ + struct spec_nodes *s; + + if (table == NULL) + { + pfile->our_hashtable = 1; + table = ht_create (13); /* 8K (=2^13) entries. */ + table->alloc_node = (hashnode (*) (hash_table *)) alloc_node; + + _obstack_begin (&pfile->hash_ob, 0, 0, + (void *(*) (long)) xmalloc, + (void (*) (void *)) free); + } + + table->pfile = pfile; + pfile->hash_table = table; + + /* Now we can initialize things that use the hash table. */ + _cpp_init_directives (pfile); + _cpp_init_internal_pragmas (pfile); + + s = &pfile->spec_nodes; + s->n_defined = cpp_lookup (pfile, DSC("defined")); + s->n_true = cpp_lookup (pfile, DSC("true")); + s->n_false = cpp_lookup (pfile, DSC("false")); + s->n__VA_ARGS__ = cpp_lookup (pfile, DSC("__VA_ARGS__")); + s->n__VA_ARGS__->flags |= NODE_DIAGNOSTIC; + /* SDCC _asm specific */ + s->n__asm = cpp_lookup (pfile, DSC("_asm")); +} + +/* Tear down the identifier hash table. */ +void +_cpp_destroy_hashtable (cpp_reader *pfile) +{ + if (pfile->our_hashtable) + { + ht_destroy (pfile->hash_table); + obstack_free (&pfile->hash_ob, 0); + } +} + +/* Returns the hash entry for the STR of length LEN, creating one + if necessary. */ +cpp_hashnode * +cpp_lookup (cpp_reader *pfile, const unsigned char *str, unsigned int len) +{ + /* ht_lookup cannot return NULL. */ + return CPP_HASHNODE (ht_lookup (pfile->hash_table, str, len, HT_ALLOC)); +} + +/* Determine whether the str STR, of length LEN, is a defined macro. */ +int +cpp_defined (cpp_reader *pfile, const unsigned char *str, int len) +{ + cpp_hashnode *node; + + node = CPP_HASHNODE (ht_lookup (pfile->hash_table, str, len, HT_NO_INSERT)); + + /* If it's of type NT_MACRO, it cannot be poisoned. */ + return node && node->type == NT_MACRO; +} + +/* For all nodes in the hashtable, callback CB with parameters PFILE, + the node, and V. */ +void +cpp_forall_identifiers (cpp_reader *pfile, cpp_cb cb, void *v) +{ + /* We don't need a proxy since the hash table's identifier comes + first in cpp_hashnode. */ + ht_forall (pfile->hash_table, (ht_cb) cb, v); +} diff --git a/support/cpp2/libcpp/include/cpp-id-data.h b/support/cpp2/libcpp/include/cpp-id-data.h new file mode 100644 index 00000000..2445186c --- /dev/null +++ b/support/cpp2/libcpp/include/cpp-id-data.h @@ -0,0 +1,78 @@ +/* Structures that hang off cpp_identifier, for PCH. + Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + +This program 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 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "cpplib.h" + +#if !defined (HAVE_UCHAR) && !defined (IN_GCC) +typedef unsigned char uchar; +#endif + +#define U (const unsigned char *) /* Intended use: U"string" */ + +/* Chained list of answers to an assertion. */ +struct answer GTY(()) +{ + struct answer *next; + unsigned int count; + cpp_token GTY ((length ("%h.count"))) first[1]; +}; + +/* Each macro definition is recorded in a cpp_macro structure. + Variadic macros cannot occur with traditional cpp. */ +struct cpp_macro GTY(()) +{ + /* Parameters, if any. */ + cpp_hashnode ** GTY ((nested_ptr (union tree_node, + "%h ? CPP_HASHNODE (GCC_IDENT_TO_HT_IDENT (%h)) : NULL", + "%h ? HT_IDENT_TO_GCC_IDENT (HT_NODE (%h)) : NULL"), + length ("%h.paramc"))) + params; + + /* Replacement tokens (ISO) or replacement text (traditional). See + comment at top of cpptrad.c for how traditional function-like + macros are encoded. */ + union cpp_macro_u + { + cpp_token * GTY ((tag ("0"), length ("%0.count"))) tokens; + const unsigned char * GTY ((tag ("1"))) text; + } GTY ((desc ("%1.traditional"))) exp; + + /* Definition line number. */ + source_location line; + + /* Number of tokens in expansion, or bytes for traditional macros. */ + unsigned int count; + + /* Number of parameters. */ + unsigned short paramc; + + /* If a function-like macro. */ + unsigned int fun_like : 1; + + /* If a variadic macro. */ + unsigned int variadic : 1; + + /* If macro defined in system header. */ + unsigned int syshdr : 1; + + /* Nonzero if it has been expanded or had its existence tested. */ + unsigned int used : 1; + + /* Indicate which field of 'exp' is in use. */ + unsigned int traditional : 1; +}; diff --git a/support/cpp2/libcpp/include/cpplib.h b/support/cpp2/libcpp/include/cpplib.h new file mode 100644 index 00000000..4e879b9d --- /dev/null +++ b/support/cpp2/libcpp/include/cpplib.h @@ -0,0 +1,868 @@ +/* Definitions for CPP library. + Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, + 2004, 2005 + Free Software Foundation, Inc. + Written by Per Bothner, 1994-95. + +This program 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 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ +#ifndef LIBCPP_CPPLIB_H +#define LIBCPP_CPPLIB_H + +#include +#include "symtab.h" +#include "line-map.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct cpp_reader cpp_reader; +typedef struct cpp_buffer cpp_buffer; +typedef struct cpp_options cpp_options; +typedef struct cpp_token cpp_token; +typedef struct cpp_string cpp_string; +typedef struct cpp_hashnode cpp_hashnode; +typedef struct cpp_macro cpp_macro; +typedef struct cpp_callbacks cpp_callbacks; +typedef struct cpp_dir cpp_dir; + +struct answer; +struct _cpp_file; + +/* The first three groups, apart from '=', can appear in preprocessor + expressions (+= and -= are used to indicate unary + and - resp.). + This allows a lookup table to be implemented in _cpp_parse_expr. + + The first group, to CPP_LAST_EQ, can be immediately followed by an + '='. The lexer needs operators ending in '=', like ">>=", to be in + the same order as their counterparts without the '=', like ">>". */ + +#define TTYPE_TABLE \ + OP(EQ, "=") \ + OP(NOT, "!") \ + OP(GREATER, ">") /* compare */ \ + OP(LESS, "<") \ + OP(PLUS, "+") /* math */ \ + OP(MINUS, "-") \ + OP(MULT, "*") \ + OP(DIV, "/") \ + OP(MOD, "%") \ + OP(AND, "&") /* bit ops */ \ + OP(OR, "|") \ + OP(XOR, "^") \ + OP(RSHIFT, ">>") \ + OP(LSHIFT, "<<") \ + OP(MIN, "?") \ + \ + OP(COMPL, "~") \ + OP(AND_AND, "&&") /* logical */ \ + OP(OR_OR, "||") \ + OP(QUERY, "?") \ + OP(COLON, ":") \ + OP(COMMA, ",") /* grouping */ \ + OP(OPEN_PAREN, "(") \ + OP(CLOSE_PAREN, ")") \ + TK(EOF, NONE) \ + OP(EQ_EQ, "==") /* compare */ \ + OP(NOT_EQ, "!=") \ + OP(GREATER_EQ, ">=") \ + OP(LESS_EQ, "<=") \ + \ + /* These two are unary + / - in preprocessor expressions. */ \ + OP(PLUS_EQ, "+=") /* math */ \ + OP(MINUS_EQ, "-=") \ + \ + OP(MULT_EQ, "*=") \ + OP(DIV_EQ, "/=") \ + OP(MOD_EQ, "%=") \ + OP(AND_EQ, "&=") /* bit ops */ \ + OP(OR_EQ, "|=") \ + OP(XOR_EQ, "^=") \ + OP(RSHIFT_EQ, ">>=") \ + OP(LSHIFT_EQ, "<<=") \ + OP(MIN_EQ, "?=") \ + /* Digraphs together, beginning with CPP_FIRST_DIGRAPH. */ \ + OP(HASH, "#") /* digraphs */ \ + OP(PASTE, "##") \ + OP(OPEN_SQUARE, "[") \ + OP(CLOSE_SQUARE, "]") \ + OP(OPEN_BRACE, "{") \ + OP(CLOSE_BRACE, "}") \ + /* The remainder of the punctuation. Order is not significant. */ \ + OP(SEMICOLON, ";") /* structure */ \ + OP(ELLIPSIS, "...") \ + OP(PLUS_PLUS, "++") /* increment */ \ + OP(MINUS_MINUS, "--") \ + OP(DEREF, "->") /* accessors */ \ + OP(DOT, ".") \ + OP(SCOPE, "::") \ + OP(DEREF_STAR, "->*") \ + OP(DOT_STAR, ".*") \ + OP(ATSIGN, "@") /* used in Objective-C */ \ + \ + TK(NAME, IDENT) /* word */ \ + TK(AT_NAME, IDENT) /* @word - Objective-C */ \ + TK(NUMBER, LITERAL) /* 34_be+ta */ \ + \ + TK(CHAR, LITERAL) /* 'char' */ \ + TK(WCHAR, LITERAL) /* L'char' */ \ + TK(OTHER, LITERAL) /* stray punctuation */ \ + \ + TK(STRING, LITERAL) /* "string" */ \ + TK(WSTRING, LITERAL) /* L"string" */ \ + TK(OBJC_STRING, LITERAL) /* @"string" - Objective-C */ \ + TK(HEADER_NAME, LITERAL) /* in #include */ \ + \ + TK(COMMENT, LITERAL) /* Only if output comments. */ \ + /* SPELL_LITERAL happens to DTRT. */ \ + TK(MACRO_ARG, NONE) /* Macro argument. */ \ + TK(PRAGMA, NONE) /* Only if deferring pragmas */ \ + TK(PADDING, NONE) /* Whitespace for -E. */ \ +\ + /* SDCC _asm specific */ \ + TK(ASM, LITERAL) /* _asm ... _endasm ; */ + +#define OP(e, s) CPP_ ## e, +#define TK(e, s) CPP_ ## e, +enum cpp_ttype +{ + TTYPE_TABLE + N_TTYPES, + + /* Positions in the table. */ + CPP_LAST_EQ = CPP_MAX, + CPP_FIRST_DIGRAPH = CPP_HASH, + CPP_LAST_PUNCTUATOR= CPP_DOT_STAR, + CPP_LAST_CPP_OP = CPP_LESS_EQ +}; +#undef OP +#undef TK + +/* C language kind, used when calling cpp_create_reader. */ +enum c_lang {CLK_GNUC89 = 0, CLK_GNUC99, CLK_STDC89, CLK_STDC94, CLK_STDC99, + CLK_GNUCXX, CLK_CXX98, CLK_ASM}; + +/* Payload of a NUMBER, STRING, CHAR or COMMENT token. */ +struct cpp_string GTY(()) +{ + unsigned int len; + const unsigned char *text; +}; + +/* Flags for the cpp_token structure. */ +#define PREV_WHITE (1 << 0) /* If whitespace before this token. */ +#define DIGRAPH (1 << 1) /* If it was a digraph. */ +#define STRINGIFY_ARG (1 << 2) /* If macro argument to be stringified. */ +#define PASTE_LEFT (1 << 3) /* If on LHS of a ## operator. */ +#define NAMED_OP (1 << 4) /* C++ named operators. */ +#define NO_EXPAND (1 << 5) /* Do not macro-expand this token. */ +#define BOL (1 << 6) /* Token at beginning of line. */ + +/* Specify which field, if any, of the cpp_token union is used. */ + +enum cpp_token_fld_kind { + CPP_TOKEN_FLD_NODE, + CPP_TOKEN_FLD_SOURCE, + CPP_TOKEN_FLD_STR, + CPP_TOKEN_FLD_ARG_NO, + CPP_TOKEN_FLD_NONE +}; + +/* A preprocessing token. This has been carefully packed and should + occupy 16 bytes on 32-bit hosts and 24 bytes on 64-bit hosts. */ +struct cpp_token GTY(()) +{ + source_location src_loc; /* Location of first char of token. */ + ENUM_BITFIELD(cpp_ttype) type : CHAR_BIT; /* token type */ + unsigned char flags; /* flags - see above */ + + union cpp_token_u + { + /* An identifier. */ + cpp_hashnode * + GTY ((nested_ptr (union tree_node, + "%h ? CPP_HASHNODE (GCC_IDENT_TO_HT_IDENT (%h)) : NULL", + "%h ? HT_IDENT_TO_GCC_IDENT (HT_NODE (%h)) : NULL"), + tag ("CPP_TOKEN_FLD_NODE"))) + node; + + /* Inherit padding from this token. */ + cpp_token * GTY ((tag ("CPP_TOKEN_FLD_SOURCE"))) source; + + /* A string, or number. */ + struct cpp_string GTY ((tag ("CPP_TOKEN_FLD_STR"))) str; + + /* Argument no. for a CPP_MACRO_ARG. */ + unsigned int GTY ((tag ("CPP_TOKEN_FLD_ARG_NO"))) arg_no; + } GTY ((desc ("cpp_token_val_index (&%1)"))) val; +}; + +/* Say which field is in use. */ +extern enum cpp_token_fld_kind cpp_token_val_index (cpp_token *tok); + +/* A type wide enough to hold any multibyte source character. + cpplib's character constant interpreter requires an unsigned type. + Also, a typedef for the signed equivalent. + The width of this type is capped at 32 bits; there do exist targets + where wchar_t is 64 bits, but only in a non-default mode, and there + would be no meaningful interpretation for a wchar_t value greater + than 2^32 anyway -- the widest wide-character encoding around is + ISO 10646, which stops at 2^31. */ +#if CHAR_BIT * SIZEOF_INT >= 32 +# define CPPCHAR_SIGNED_T int +#elif CHAR_BIT * SIZEOF_LONG >= 32 +# define CPPCHAR_SIGNED_T long +#else +# error "Cannot find a least-32-bit signed integer type" +#endif +typedef unsigned CPPCHAR_SIGNED_T cppchar_t; +typedef CPPCHAR_SIGNED_T cppchar_signed_t; + +/* Style of header dependencies to generate. */ +enum cpp_deps_style { DEPS_NONE = 0, DEPS_USER, DEPS_SYSTEM }; + +/* The possible normalization levels, from most restrictive to least. */ +enum cpp_normalize_level { + /* In NFKC. */ + normalized_KC = 0, + /* In NFC. */ + normalized_C, + /* In NFC, except for subsequences where being in NFC would make + the identifier invalid. */ + normalized_identifier_C, + /* Not normalized at all. */ + normalized_none +}; + +/* This structure is nested inside struct cpp_reader, and + carries all the options visible to the command line. */ +struct cpp_options +{ + /* Characters between tab stops. */ + unsigned int tabstop; + + /* The language we're preprocessing. */ + enum c_lang lang; + + /* Nonzero means use extra default include directories for C++. */ + unsigned char cplusplus; + + /* Nonzero means handle cplusplus style comments. */ + unsigned char cplusplus_comments; + + /* Nonzero means define __OBJC__, treat @ as a special token, and + use the OBJC[PLUS]_INCLUDE_PATH environment variable. */ + unsigned char objc; + + /* Nonzero means don't copy comments into the output file. */ + unsigned char discard_comments; + + /* Nonzero means don't copy comments into the output file during + macro expansion. */ + unsigned char discard_comments_in_macro_exp; + + /* Nonzero means process the ISO trigraph sequences. */ + unsigned char trigraphs; + + /* Nonzero means process the ISO digraph sequences. */ + unsigned char digraphs; + + /* Nonzero means to allow hexadecimal floats and LL suffixes. */ + unsigned char extended_numbers; + + /* Nonzero means print names of header files (-H). */ + unsigned char print_include_names; + + /* Nonzero means cpp_pedwarn causes a hard error. */ + unsigned char pedantic_errors; + + /* Nonzero means don't print warning messages. */ + unsigned char inhibit_warnings; + + /* Nonzero means complain about deprecated features. */ + unsigned char warn_deprecated; + + /* Nonzero means don't suppress warnings from system headers. */ + unsigned char warn_system_headers; + + /* Nonzero means don't print error messages. Has no option to + select it, but can be set by a user of cpplib (e.g. fix-header). */ + unsigned char inhibit_errors; + + /* Nonzero means warn if slash-star appears in a comment. */ + unsigned char warn_comments; + + /* Nonzero means warn if a user-supplied include directory does not + exist. */ + unsigned char warn_missing_include_dirs; + + /* Nonzero means warn if there are any trigraphs. */ + unsigned char warn_trigraphs; + + /* Nonzero means warn about multicharacter charconsts. */ + unsigned char warn_multichar; + + /* Nonzero means warn about various incompatibilities with + traditional C. */ + unsigned char warn_traditional; + + /* Nonzero means warn about long long numeric constants. */ + unsigned char warn_long_long; + + /* Nonzero means warn about text after an #endif (or #else). */ + unsigned char warn_endif_labels; + + /* Nonzero means warn about implicit sign changes owing to integer + promotions. */ + unsigned char warn_num_sign_change; + + /* Zero means don't warn about __VA_ARGS__ usage in c89 pedantic mode. + Presumably the usage is protected by the appropriate #ifdef. */ + unsigned char warn_variadic_macros; + + /* Nonzero means turn warnings into errors. */ + unsigned char warnings_are_errors; + + /* Nonzero means we should look for header.gcc files that remap file + names. */ + unsigned char remap; + + /* Zero means dollar signs are punctuation. */ + unsigned char dollars_in_ident; + + /* Nonzero means UCNs are accepted in identifiers. */ + unsigned char extended_identifiers; + + /* True if we should warn about dollars in identifiers or numbers + for this translation unit. */ + unsigned char warn_dollars; + + /* Nonzero means warn if undefined identifiers are evaluated in an #if. */ + unsigned char warn_undef; + + /* Nonzero means warn of unused macros from the main file. */ + unsigned char warn_unused_macros; + + /* Nonzero for the 1999 C Standard, including corrigenda and amendments. */ + unsigned char c99; + + /* Nonzero if we are conforming to a specific C or C++ standard. */ + unsigned char std; + + /* Nonzero means give all the error messages the ANSI standard requires. */ + unsigned char pedantic; + + /* Nonzero means we're looking at already preprocessed code, so don't + bother trying to do macro expansion and whatnot. */ + unsigned char preprocessed; + + /* Print column number in error messages. */ + unsigned char show_column; + + /* Nonzero means handle C++ alternate operator names. */ + unsigned char operator_names; + + /* True for traditional preprocessing. */ + unsigned char traditional; + + /* Holds the name of the target (execution) character set. */ + const char *narrow_charset; + + /* Holds the name of the target wide character set. */ + const char *wide_charset; + + /* Holds the name of the input character set. */ + const char *input_charset; + + /* The minimum permitted level of normalization before a warning + is generated. */ + enum cpp_normalize_level warn_normalize; + + /* True to warn about precompiled header files we couldn't use. */ + bool warn_invalid_pch; + + /* True if dependencies should be restored from a precompiled header. */ + bool restore_pch_deps; + + /* SDCC abuse by Kevin: allow naked '#' characters in expanded macros + * (see _cpp_create_definition in cppmacro.c) + */ + unsigned char allow_naked_hash; + + /* SDCC _asm specific + switch _asm block preprocessing on / off */ + unsigned char preproc_asm; + + /* SDCC specific + object file exetnsion */ + const char *obj_ext; + + /* SDCC specific + pedantic_parse_number */ + unsigned char pedantic_parse_number; + + /* Dependency generation. */ + struct + { + /* Style of header dependencies to generate. */ + enum cpp_deps_style style; + + /* Assume missing files are generated files. */ + bool missing_files; + + /* Generate phony targets for each dependency apart from the first + one. */ + bool phony_targets; + + /* If true, no dependency is generated on the main file. */ + bool ignore_main_file; + } deps; + + /* Target-specific features set by the front end or client. */ + + /* Precision for target CPP arithmetic, target characters, target + ints and target wide characters, respectively. */ + size_t precision, char_precision, int_precision, wchar_precision; + + /* True means chars (wide chars) are unsigned. */ + bool unsigned_char, unsigned_wchar; + + /* True if the most significant byte in a word has the lowest + address in memory. */ + bool bytes_big_endian; + + /* Nonzero means __STDC__ should have the value 0 in system headers. */ + unsigned char stdc_0_in_system_headers; + + /* True means return pragmas as tokens rather than processing + them directly. */ + bool defer_pragmas; + + /* True means error callback should be used for diagnostics. */ + bool client_diagnostic; +}; + +/* Callback for header lookup for HEADER, which is the name of a + source file. It is used as a method of last resort to find headers + that are not otherwise found during the normal include processing. + The return value is the malloced name of a header to try and open, + if any, or NULL otherwise. This callback is called only if the + header is otherwise unfound. */ +typedef const char *(*missing_header_cb)(cpp_reader *, const char *header, cpp_dir **); + +/* Call backs to cpplib client. */ +struct cpp_callbacks +{ + /* Called when a new line of preprocessed output is started. */ + void (*line_change) (cpp_reader *, const cpp_token *, int); + + /* Called when switching to/from a new file. + The line_map is for the new file. It is NULL if there is no new file. + (In C this happens when done with + and also + when done with a main file.) This can be used for resource cleanup. */ + void (*file_change) (cpp_reader *, const struct line_map *); + + void (*dir_change) (cpp_reader *, const char *); + void (*include) (cpp_reader *, unsigned int, const unsigned char *, + const char *, int, const cpp_token **); + void (*define) (cpp_reader *, unsigned int, cpp_hashnode *); + void (*undef) (cpp_reader *, unsigned int, cpp_hashnode *); + void (*ident) (cpp_reader *, unsigned int, const cpp_string *); + void (*def_pragma) (cpp_reader *, unsigned int); + int (*valid_pch) (cpp_reader *, const char *, int); + void (*read_pch) (cpp_reader *, const char *, int, const char *); + missing_header_cb missing_header; + + /* Called to emit a diagnostic if client_diagnostic option is true. + This callback receives the translated message. */ + void (*error) (cpp_reader *, int, const char *, va_list *) + ATTRIBUTE_FPTR_PRINTF(3,0); +}; + +/* Chain of directories to look for include files in. */ +struct cpp_dir +{ + /* NULL-terminated singly-linked list. */ + struct cpp_dir *next; + + /* NAME of the directory, NUL-terminated. */ + char *name; + unsigned int len; + + /* One if a system header, two if a system header that has extern + "C" guards for C++. */ + unsigned char sysp; + + /* Mapping of file names for this directory for MS-DOS and related + platforms. A NULL-terminated array of (from, to) pairs. */ + const char **name_map; + + /* Routine to construct pathname, given the search path name and the + HEADER we are trying to find, return a constructed pathname to + try and open. If this is NULL, the constructed pathname is as + constructed by append_file_to_dir. */ + char *(*construct) (const char *header, cpp_dir *dir); + + /* The C front end uses these to recognize duplicated + directories in the search path. */ + ino_t ino; + dev_t dev; + + /* Is this a user-supplied directory? */ + bool user_supplied_p; +}; + +/* Name under which this program was invoked. */ +extern const char *progname; + +/* The structure of a node in the hash table. The hash table has + entries for all identifiers: either macros defined by #define + commands (type NT_MACRO), assertions created with #assert + (NT_ASSERTION), or neither of the above (NT_VOID). Builtin macros + like __LINE__ are flagged NODE_BUILTIN. Poisoned identifiers are + flagged NODE_POISONED. NODE_OPERATOR (C++ only) indicates an + identifier that behaves like an operator such as "xor". + NODE_DIAGNOSTIC is for speed in lex_token: it indicates a + diagnostic may be required for this node. Currently this only + applies to __VA_ARGS__ and poisoned identifiers. */ + +/* Hash node flags. */ +#define NODE_OPERATOR (1 << 0) /* C++ named operator. */ +#define NODE_POISONED (1 << 1) /* Poisoned identifier. */ +#define NODE_BUILTIN (1 << 2) /* Builtin macro. */ +#define NODE_DIAGNOSTIC (1 << 3) /* Possible diagnostic when lexed. */ +#define NODE_WARN (1 << 4) /* Warn if redefined or undefined. */ +#define NODE_DISABLED (1 << 5) /* A disabled macro. */ +#define NODE_MACRO_ARG (1 << 6) /* Used during #define processing. */ + +/* Different flavors of hash node. */ +enum node_type +{ + NT_VOID = 0, /* No definition yet. */ + NT_MACRO, /* A macro of some form. */ + NT_ASSERTION /* Predicate for #assert. */ +}; + +/* Different flavors of builtin macro. _Pragma is an operator, but we + handle it with the builtin code for efficiency reasons. */ +enum builtin_type +{ + BT_SPECLINE = 0, /* `__LINE__' */ + BT_DATE, /* `__DATE__' */ + BT_FILE, /* `__FILE__' */ + BT_BASE_FILE, /* `__BASE_FILE__' */ + BT_INCLUDE_LEVEL, /* `__INCLUDE_LEVEL__' */ + BT_TIME, /* `__TIME__' */ + BT_STDC, /* `__STDC__' */ + BT_PRAGMA /* `_Pragma' operator */ +}; + +#define CPP_HASHNODE(HNODE) ((cpp_hashnode *) (HNODE)) +#define HT_NODE(NODE) ((ht_identifier *) (NODE)) +#define NODE_LEN(NODE) HT_LEN (&(NODE)->ident) +#define NODE_NAME(NODE) HT_STR (&(NODE)->ident) + +/* Specify which field, if any, of the union is used. */ + +enum { + NTV_MACRO, + NTV_ANSWER, + NTV_BUILTIN, + NTV_ARGUMENT, + NTV_NONE +}; + +#define CPP_HASHNODE_VALUE_IDX(HNODE) \ + ((HNODE.flags & NODE_MACRO_ARG) ? NTV_ARGUMENT \ + : HNODE.type == NT_MACRO ? ((HNODE.flags & NODE_BUILTIN) \ + ? NTV_BUILTIN : NTV_MACRO) \ + : HNODE.type == NT_ASSERTION ? NTV_ANSWER \ + : NTV_NONE) + +/* The common part of an identifier node shared amongst all 3 C front + ends. Also used to store CPP identifiers, which are a superset of + identifiers in the grammatical sense. */ + +union _cpp_hashnode_value GTY(()) +{ + /* If a macro. */ + cpp_macro * GTY((tag ("NTV_MACRO"))) macro; + /* Answers to an assertion. */ + struct answer * GTY ((tag ("NTV_ANSWER"))) answers; + /* Code for a builtin macro. */ + enum builtin_type GTY ((tag ("NTV_BUILTIN"))) builtin; + /* Macro argument index. */ + unsigned short GTY ((tag ("NTV_ARGUMENT"))) arg_index; +}; + +struct cpp_hashnode GTY(()) +{ + struct ht_identifier ident; + unsigned int is_directive : 1; + unsigned int directive_index : 7; /* If is_directive, + then index into directive table. + Otherwise, a NODE_OPERATOR. */ + unsigned char rid_code; /* Rid code - for front ends. */ + ENUM_BITFIELD(node_type) type : 8; /* CPP node type. */ + unsigned char flags; /* CPP flags. */ + + union _cpp_hashnode_value GTY ((desc ("CPP_HASHNODE_VALUE_IDX (%1)"))) value; +}; + +/* Call this first to get a handle to pass to other functions. + + If you want cpplib to manage its own hashtable, pass in a NULL + pointer. Otherwise you should pass in an initialized hash table + that cpplib will share; this technique is used by the C front + ends. */ +extern cpp_reader *cpp_create_reader (enum c_lang, struct ht *, + struct line_maps *); + +/* Call this to change the selected language standard (e.g. because of + command line options). */ +extern void cpp_set_lang (cpp_reader *, enum c_lang); + +/* Set the include paths. */ +extern void cpp_set_include_chains (cpp_reader *, cpp_dir *, cpp_dir *, int); + +/* Call these to get pointers to the options, callback, and deps + structures for a given reader. These pointers are good until you + call cpp_finish on that reader. You can either edit the callbacks + through the pointer returned from cpp_get_callbacks, or set them + with cpp_set_callbacks. */ +extern cpp_options *cpp_get_options (cpp_reader *); +extern cpp_callbacks *cpp_get_callbacks (cpp_reader *); +extern void cpp_set_callbacks (cpp_reader *, cpp_callbacks *); +extern struct deps *cpp_get_deps (cpp_reader *); + +/* This function reads the file, but does not start preprocessing. It + returns the name of the original file; this is the same as the + input file, except for preprocessed input. This will generate at + least one file change callback, and possibly a line change callback + too. If there was an error opening the file, it returns NULL. */ +extern const char *cpp_read_main_file (cpp_reader *, const char *); + +/* Set up built-ins like __FILE__. */ +extern void cpp_init_builtins (cpp_reader *, int); + +/* This is called after options have been parsed, and partially + processed. */ +extern void cpp_post_options (cpp_reader *); + +/* Set up translation to the target character set. */ +extern void cpp_init_iconv (cpp_reader *); + +/* Call this to finish preprocessing. If you requested dependency + generation, pass an open stream to write the information to, + otherwise NULL. It is your responsibility to close the stream. + + Returns cpp_errors (pfile). */ +extern int cpp_finish (cpp_reader *, FILE *deps_stream); + +/* Call this to release the handle at the end of preprocessing. Any + use of the handle after this function returns is invalid. Returns + cpp_errors (pfile). */ +extern void cpp_destroy (cpp_reader *); + +/* Error count. */ +extern unsigned int cpp_errors (cpp_reader *); + +extern unsigned int cpp_token_len (const cpp_token *); +extern unsigned char *cpp_token_as_text (cpp_reader *, const cpp_token *); +extern unsigned char *cpp_spell_token (cpp_reader *, const cpp_token *, + unsigned char *, bool); +extern void cpp_register_pragma (cpp_reader *, const char *, const char *, + void (*) (cpp_reader *), bool); +extern void cpp_handle_deferred_pragma (cpp_reader *, const cpp_string *); +extern int cpp_avoid_paste (cpp_reader *, const cpp_token *, + const cpp_token *); +extern const cpp_token *cpp_get_token (cpp_reader *); +extern const unsigned char *cpp_macro_definition (cpp_reader *, + const cpp_hashnode *); +extern void _cpp_backup_tokens (cpp_reader *, unsigned int); + +/* Evaluate a CPP_CHAR or CPP_WCHAR token. */ +extern cppchar_t cpp_interpret_charconst (cpp_reader *, const cpp_token *, + unsigned int *, int *); +/* Evaluate a vector of CPP_STRING or CPP_WSTRING tokens. */ +extern bool cpp_interpret_string (cpp_reader *, + const cpp_string *, size_t, + cpp_string *, bool); +extern bool cpp_interpret_string_notranslate (cpp_reader *, + const cpp_string *, size_t, + cpp_string *, bool); + +/* Convert a host character constant to the execution character set. */ +extern cppchar_t cpp_host_to_exec_charset (cpp_reader *, cppchar_t); + +/* Used to register macros and assertions, perhaps from the command line. + The text is the same as the command line argument. */ +extern void cpp_define (cpp_reader *, const char *); +extern void cpp_assert (cpp_reader *, const char *); +extern void cpp_undef (cpp_reader *, const char *); +extern void cpp_unassert (cpp_reader *, const char *); + +/* Undefine all macros and assertions. */ +extern void cpp_undef_all (cpp_reader *); + +extern cpp_buffer *cpp_push_buffer (cpp_reader *, const unsigned char *, + size_t, int); +extern int cpp_defined (cpp_reader *, const unsigned char *, int); + +/* A preprocessing number. Code assumes that any unused high bits of + the double integer are set to zero. */ +typedef unsigned HOST_WIDE_INT cpp_num_part; +typedef struct cpp_num cpp_num; +struct cpp_num +{ + cpp_num_part high; + cpp_num_part low; + bool unsignedp; /* True if value should be treated as unsigned. */ + bool overflow; /* True if the most recent calculation overflowed. */ +}; + +/* cpplib provides two interfaces for interpretation of preprocessing + numbers. + + cpp_classify_number categorizes numeric constants according to + their field (integer, floating point, or invalid), radix (decimal, + octal, hexadecimal), and type suffixes. */ + +#define CPP_N_CATEGORY 0x000F +#define CPP_N_INVALID 0x0000 +#define CPP_N_INTEGER 0x0001 +#define CPP_N_FLOATING 0x0002 + +#define CPP_N_WIDTH 0x00F0 +#define CPP_N_SMALL 0x0010 /* int, float. */ +#define CPP_N_MEDIUM 0x0020 /* long, double. */ +#define CPP_N_LARGE 0x0040 /* long long, long double. */ + +#define CPP_N_RADIX 0x0F00 +#define CPP_N_DECIMAL 0x0100 +#define CPP_N_HEX 0x0200 +#define CPP_N_OCTAL 0x0400 + +#define CPP_N_UNSIGNED 0x1000 /* Properties. */ +#define CPP_N_IMAGINARY 0x2000 + +/* Classify a CPP_NUMBER token. The return value is a combination of + the flags from the above sets. */ +extern unsigned cpp_classify_number (cpp_reader *, const cpp_token *); + +/* Evaluate a token classified as category CPP_N_INTEGER. */ +extern cpp_num cpp_interpret_integer (cpp_reader *, const cpp_token *, + unsigned int type); + +/* Sign extend a number, with PRECISION significant bits and all + others assumed clear, to fill out a cpp_num structure. */ +cpp_num cpp_num_sign_extend (cpp_num, size_t); + +/* Diagnostic levels. To get a diagnostic without associating a + position in the translation unit with it, use cpp_error_with_line + with a line number of zero. */ + +/* Warning, an error with -Werror. */ +#define CPP_DL_WARNING 0x00 +/* Same as CPP_DL_WARNING, except it is not suppressed in system headers. */ +#define CPP_DL_WARNING_SYSHDR 0x01 +/* Warning, an error with -pedantic-errors or -Werror. */ +#define CPP_DL_PEDWARN 0x02 +/* An error. */ +#define CPP_DL_ERROR 0x03 +/* An internal consistency check failed. Prints "internal error: ", + otherwise the same as CPP_DL_ERROR. */ +#define CPP_DL_ICE 0x04 +/* Extracts a diagnostic level from an int. */ +#define CPP_DL_EXTRACT(l) (l & 0xf) +/* Nonzero if a diagnostic level is one of the warnings. */ +#define CPP_DL_WARNING_P(l) (CPP_DL_EXTRACT (l) >= CPP_DL_WARNING \ + && CPP_DL_EXTRACT (l) <= CPP_DL_PEDWARN) + +/* Output a diagnostic of some kind. */ +extern void cpp_error (cpp_reader *, int, const char *msgid, ...) + ATTRIBUTE_PRINTF_3; + +/* Output a diagnostic with "MSGID: " preceding the + error string of errno. No location is printed. */ +extern void cpp_errno (cpp_reader *, int, const char *msgid); + +/* Same as cpp_error, except additionally specifies a position as a + (translation unit) physical line and physical column. If the line is + zero, then no location is printed. */ +extern void cpp_error_with_line (cpp_reader *, int, source_location, unsigned, + const char *msgid, ...) ATTRIBUTE_PRINTF_5; + +/* In cpplex.c */ +extern int cpp_ideq (const cpp_token *, const char *); +extern void cpp_output_line (cpp_reader *, FILE *); +extern void cpp_output_token (const cpp_token *, FILE *); +extern const char *cpp_type2name (enum cpp_ttype); +/* Returns the value of an escape sequence, truncated to the correct + target precision. PSTR points to the input pointer, which is just + after the backslash. LIMIT is how much text we have. WIDE is true + if the escape sequence is part of a wide character constant or + string literal. Handles all relevant diagnostics. */ +extern cppchar_t cpp_parse_escape (cpp_reader *, const unsigned char ** pstr, + const unsigned char *limit, int wide); + +/* In cpphash.c */ + +/* Lookup an identifier in the hashtable. Puts the identifier in the + table if it is not already there. */ +extern cpp_hashnode *cpp_lookup (cpp_reader *, const unsigned char *, + unsigned int); + +typedef int (*cpp_cb) (cpp_reader *, cpp_hashnode *, void *); +extern void cpp_forall_identifiers (cpp_reader *, cpp_cb, void *); + +/* In cppmacro.c */ +extern void cpp_scan_nooutput (cpp_reader *); +extern int cpp_sys_macro_p (cpp_reader *); +extern unsigned char *cpp_quote_string (unsigned char *, const unsigned char *, + unsigned int); + +/* In cppfiles.c */ +extern bool cpp_included (cpp_reader *, const char *); +extern void cpp_make_system_header (cpp_reader *, int, int); +extern bool cpp_push_include (cpp_reader *, const char *); +extern void cpp_change_file (cpp_reader *, enum lc_reason, const char *); +extern const char *cpp_get_path (struct _cpp_file *); +extern cpp_dir *cpp_get_dir (struct _cpp_file *); +extern cpp_buffer *cpp_get_buffer (cpp_reader *); +extern struct _cpp_file *cpp_get_file (cpp_buffer *); +extern cpp_buffer *cpp_get_prev (cpp_buffer *); + +/* In cpppch.c */ +struct save_macro_data; +extern int cpp_save_state (cpp_reader *, FILE *); +extern int cpp_write_pch_deps (cpp_reader *, FILE *); +extern int cpp_write_pch_state (cpp_reader *, FILE *); +extern int cpp_valid_state (cpp_reader *, const char *, int); +extern void cpp_prepare_state (cpp_reader *, struct save_macro_data **); +extern int cpp_read_state (cpp_reader *, const char *, FILE *, + struct save_macro_data *); + +#ifdef __cplusplus +} +#endif + +#endif /* ! LIBCPP_CPPLIB_H */ diff --git a/support/cpp2/libcpp/include/line-map.h b/support/cpp2/libcpp/include/line-map.h new file mode 100644 index 00000000..7e9ede01 --- /dev/null +++ b/support/cpp2/libcpp/include/line-map.h @@ -0,0 +1,180 @@ +/* Map logical line numbers to (source file, line number) pairs. + Copyright (C) 2001, 2003, 2004 + Free Software Foundation, Inc. + +This program 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 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +#ifndef LIBCPP_LINE_MAP_H +#define LIBCPP_LINE_MAP_H + +/* Reason for adding a line change with add_line_map (). LC_ENTER is + when including a new file, e.g. a #include directive in C. + LC_LEAVE is when reaching a file's end. LC_RENAME is when a file + name or line number changes for neither of the above reasons + (e.g. a #line directive in C). */ +enum lc_reason {LC_ENTER = 0, LC_LEAVE, LC_RENAME}; + +/* A logical line/column number, i.e. an "index" into a line_map. */ +/* Long-term, we want to use this to replace struct location_s (in input.h), + and effectively typedef source_location location_t. */ +typedef unsigned int source_location; + +/* Physical source file TO_FILE at line TO_LINE at column 0 is represented + by the logical START_LOCATION. TO_LINE+L at column C is represented by + START_LOCATION+(L*(1<start_location) >> (MAP)->column_bits) + (MAP)->to_line) + +#define SOURCE_COLUMN(MAP, LINE) \ + (((LINE) - (MAP)->start_location) & ((1 << (MAP)->column_bits) - 1)) + +/* Returns the last source line within a map. This is the (last) line + of the #include, or other directive, that caused a map change. */ +#define LAST_SOURCE_LINE(MAP) \ + SOURCE_LINE (MAP, LAST_SOURCE_LINE_LOCATION (MAP)) +#define LAST_SOURCE_LINE_LOCATION(MAP) \ + ((((MAP)[1].start_location - 1 - (MAP)->start_location) \ + & ~((1 << (MAP)->column_bits) - 1)) \ + + (MAP)->start_location) + +/* Returns the map a given map was included from. */ +#define INCLUDED_FROM(SET, MAP) (&(SET)->maps[(MAP)->included_from]) + +/* Nonzero if the map is at the bottom of the include stack. */ +#define MAIN_FILE_P(MAP) ((MAP)->included_from < 0) + +/* Set LOC to a source position that is the same line as the most recent + linemap_line_start, but with the specified TO_COLUMN column number. */ + +#define LINEMAP_POSITION_FOR_COLUMN(LOC, SET, TO_COLUMN) { \ + unsigned int to_column = (TO_COLUMN); \ + struct line_maps *set = (SET); \ + if (__builtin_expect (to_column >= set->max_column_hint, 0)) \ + (LOC) = linemap_position_for_column (set, to_column); \ + else { \ + source_location r = set->highest_line; \ + r = r + to_column; \ + if (r >= set->highest_location) \ + set->highest_location = r; \ + (LOC) = r; \ + }} + + +extern source_location +linemap_position_for_column (struct line_maps *set, unsigned int to_column); +#endif /* !LIBCPP_LINE_MAP_H */ diff --git a/support/cpp2/libcpp/include/mkdeps.h b/support/cpp2/libcpp/include/mkdeps.h new file mode 100644 index 00000000..02649701 --- /dev/null +++ b/support/cpp2/libcpp/include/mkdeps.h @@ -0,0 +1,80 @@ +/* Dependency generator for Makefile fragments. + Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc. + Contributed by Zack Weinberg, Mar 2000 + +This program 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 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +#ifndef LIBCPP_MKDEPS_H +#define LIBCPP_MKDEPS_H + +/* This is the data structure used by all the functions in mkdeps.c. + It's quite straightforward, but should be treated as opaque. */ + +struct deps; +struct cpp_reader; + +/* Create a deps buffer. */ +extern struct deps *deps_init (void); + +/* Destroy a deps buffer. */ +extern void deps_free (struct deps *); + +/* Add a set of "vpath" directories. The second argument is a colon- + separated list of pathnames, like you would set Make's VPATH + variable to. If a dependency or target name begins with any of + these pathnames (and the next path element is not "..") that + pathname is stripped off. */ +extern void deps_add_vpath (struct deps *, const char *); + +/* Add a target (appears on left side of the colon) to the deps list. Takes + a boolean indicating whether to quote the target for MAKE. */ +extern void deps_add_target (struct deps *, const char *, int); + +/* Sets the default target if none has been given already. An empty + string as the default target is interpreted as stdin. */ +extern void deps_add_default_target (struct cpp_reader *, const char *); + +/* Add a dependency (appears on the right side of the colon) to the + deps list. Dependencies will be printed in the order that they + were entered with this function. By convention, the first + dependency entered should be the primary source file. */ +extern void deps_add_dep (struct deps *, const char *); + +/* Write out a deps buffer to a specified file. The third argument + is the number of columns to word-wrap at (0 means don't wrap). */ +extern void deps_write (const struct deps *, FILE *, unsigned int); + +/* Write out a deps buffer to a file, in a form that can be read back + with deps_restore. Returns nonzero on error, in which case the + error number will be in errno. */ +extern int deps_save (struct deps *, FILE *); + +/* Read back dependency information written with deps_save into + the deps buffer. The third argument may be NULL, in which case + the dependency information is just skipped, or it may be a filename, + in which case that filename is skipped. */ +extern int deps_restore (struct deps *, FILE *, const char *); + +/* For each dependency *except the first*, emit a dummy rule for that + file, causing it to depend on nothing. This is used to work around + the intermediate-file deletion misfeature in Make, in some + automatic dependency schemes. */ +extern void deps_phony_targets (const struct deps *, FILE *); + +#endif /* ! LIBCPP_MKDEPS_H */ diff --git a/support/cpp2/libcpp/include/symtab.h b/support/cpp2/libcpp/include/symtab.h new file mode 100644 index 00000000..cbcf230d --- /dev/null +++ b/support/cpp2/libcpp/include/symtab.h @@ -0,0 +1,100 @@ +/* Hash tables. + Copyright (C) 2000, 2001, 2003, 2004 Free Software Foundation, Inc. + +This program 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 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef LIBCPP_SYMTAB_H +#define LIBCPP_SYMTAB_H + +#if defined(__APPLE__) && defined(__MACH__) +#include "libiberty/obstack.h" +#else +#include "obstack.h" +#endif +#define GTY(x) /* nothing */ + +/* This is what each hash table entry points to. It may be embedded + deeply within another object. */ +typedef struct ht_identifier ht_identifier; +struct ht_identifier GTY(()) +{ + const unsigned char *str; + unsigned int len; + unsigned int hash_value; +}; + +#define HT_LEN(NODE) ((NODE)->len) +#define HT_STR(NODE) ((NODE)->str) + +typedef struct ht hash_table; +typedef struct ht_identifier *hashnode; + +enum ht_lookup_option {HT_NO_INSERT = 0, HT_ALLOC, HT_ALLOCED}; + +/* An identifier hash table for cpplib and the front ends. */ +struct ht +{ + /* Identifiers are allocated from here. */ + struct obstack stack; + + hashnode *entries; + /* Call back, allocate a node. */ + hashnode (*alloc_node) (hash_table *); + /* Call back, allocate something that hangs off a node like a cpp_macro. + NULL means use the usual allocator. */ + void * (*alloc_subobject) (size_t); + + unsigned int nslots; /* Total slots in the entries array. */ + unsigned int nelements; /* Number of live elements. */ + + /* Link to reader, if any. For the benefit of cpplib. */ + struct cpp_reader *pfile; + + /* Table usage statistics. */ + unsigned int searches; + unsigned int collisions; + + /* Should 'entries' be freed when it is no longer needed? */ + bool entries_owned; +}; + +/* Initialize the hashtable with 2 ^ order entries. */ +extern hash_table *ht_create (unsigned int order); + +/* Frees all memory associated with a hash table. */ +extern void ht_destroy (hash_table *); + +extern hashnode ht_lookup (hash_table *, const unsigned char *, + size_t, enum ht_lookup_option); +extern hashnode ht_lookup_with_hash (hash_table *, const unsigned char *, + size_t, unsigned int, + enum ht_lookup_option); +#define HT_HASHSTEP(r, c) ((r) * 67 + ((c) - 113)); +#define HT_HASHFINISH(r, len) ((r) + (len)) + +/* For all nodes in TABLE, make a callback. The callback takes + TABLE->PFILE, the node, and a PTR, and the callback sequence stops + if the callback returns zero. */ +typedef int (*ht_cb) (struct cpp_reader *, hashnode, const void *); +extern void ht_forall (hash_table *, ht_cb, const void *); + +/* Restore the hash table. */ +extern void ht_load (hash_table *ht, hashnode *entries, + unsigned int nslots, unsigned int nelements, bool own); + +/* Dump allocation statistics to stderr. */ +extern void ht_dump_statistics (hash_table *); + +#endif /* LIBCPP_SYMTAB_H */ diff --git a/support/cpp2/libcpp/init.c b/support/cpp2/libcpp/init.c new file mode 100644 index 00000000..726dafd6 --- /dev/null +++ b/support/cpp2/libcpp/init.c @@ -0,0 +1,644 @@ +/* CPP Library. + Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Contributed by Per Bothner, 1994-95. + Based on CCCP program by Paul Rubin, June 1986 + Adapted to ANSI C, Richard Stallman, Jan 1987 + +This program 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 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "config.h" +#include "system.h" +#include "cpplib.h" +#include "internal.h" +#include "mkdeps.h" +#ifdef ENABLE_NLS +#include "localedir.h" +#endif + +static void init_library (void); +static void mark_named_operators (cpp_reader *); +static void read_original_filename (cpp_reader *); +static void read_original_directory (cpp_reader *); +static void post_options (cpp_reader *); + +/* If we have designated initializers (GCC >2.7) these tables can be + initialized, constant data. Otherwise, they have to be filled in at + runtime. */ +#if HAVE_DESIGNATED_INITIALIZERS + +#define init_trigraph_map() /* Nothing. */ +#define TRIGRAPH_MAP \ +__extension__ const uchar _cpp_trigraph_map[UCHAR_MAX + 1] = { + +#define END }; +#define s(p, v) [p] = v, + +#else + +#define TRIGRAPH_MAP uchar _cpp_trigraph_map[UCHAR_MAX + 1] = { 0 }; \ + static void init_trigraph_map (void) { \ + unsigned char *x = _cpp_trigraph_map; + +#define END } +#define s(p, v) x[p] = v; + +#endif + +TRIGRAPH_MAP + s('=', '#') s(')', ']') s('!', '|') + s('(', '[') s('\'', '^') s('>', '}') + s('/', '\\') s('<', '{') s('-', '~') +END + +#undef s +#undef END +#undef TRIGRAPH_MAP + +/* A set of booleans indicating what CPP features each source language + requires. */ +struct lang_flags +{ + char c99; + char cplusplus; + char extended_numbers; + char extended_identifiers; + char std; + char cplusplus_comments; + char digraphs; +}; + +static const struct lang_flags lang_defaults[] = +{ /* c99 c++ xnum xid std // digr */ + /* GNUC89 */ { 0, 0, 1, 0, 0, 1, 1 }, + /* GNUC99 */ { 1, 0, 1, 0, 0, 1, 1 }, + /* STDC89 */ { 0, 0, 0, 0, 1, 0, 0 }, + /* STDC94 */ { 0, 0, 0, 0, 1, 0, 1 }, + /* STDC99 */ { 1, 0, 1, 0, 1, 1, 1 }, + /* GNUCXX */ { 0, 1, 1, 0, 0, 1, 1 }, + /* CXX98 */ { 0, 1, 1, 0, 1, 1, 1 }, + /* ASM */ { 0, 0, 1, 0, 0, 1, 0 } + /* xid should be 1 for GNUC99, STDC99, GNUCXX and CXX98 when no + longer experimental (when all uses of identifiers in the compiler + have been audited for correct handling of extended + identifiers). */ +}; + +/* Sets internal flags correctly for a given language. */ +void +cpp_set_lang (cpp_reader *pfile, enum c_lang lang) +{ + const struct lang_flags *l = &lang_defaults[(int) lang]; + + CPP_OPTION (pfile, lang) = lang; + + CPP_OPTION (pfile, c99) = l->c99; + CPP_OPTION (pfile, cplusplus) = l->cplusplus; + CPP_OPTION (pfile, extended_numbers) = l->extended_numbers; + CPP_OPTION (pfile, extended_identifiers) = l->extended_identifiers; + CPP_OPTION (pfile, std) = l->std; + CPP_OPTION (pfile, trigraphs) = l->std; + CPP_OPTION (pfile, cplusplus_comments) = l->cplusplus_comments; + CPP_OPTION (pfile, digraphs) = l->digraphs; +} + +/* Initialize library global state. */ +static void +init_library (void) +{ + static int initialized = 0; + + if (! initialized) + { + initialized = 1; + + /* Set up the trigraph map. This doesn't need to do anything if + we were compiled with a compiler that supports C99 designated + initializers. */ + init_trigraph_map (); + +#ifdef ENABLE_NLS + (void) bindtextdomain (PACKAGE, LOCALEDIR); +#endif + } +} + +/* Initialize a cpp_reader structure. */ +cpp_reader * +cpp_create_reader (enum c_lang lang, hash_table *table, + struct line_maps *line_table) +{ + cpp_reader *pfile; + + /* Initialize this instance of the library if it hasn't been already. */ + init_library (); + + pfile = XCNEW (cpp_reader); + + cpp_set_lang (pfile, lang); + CPP_OPTION (pfile, warn_multichar) = 1; + CPP_OPTION (pfile, discard_comments) = 1; + CPP_OPTION (pfile, discard_comments_in_macro_exp) = 1; + CPP_OPTION (pfile, show_column) = 1; + CPP_OPTION (pfile, tabstop) = 8; + CPP_OPTION (pfile, operator_names) = 1; + CPP_OPTION (pfile, warn_trigraphs) = 2; + CPP_OPTION (pfile, warn_endif_labels) = 1; + CPP_OPTION (pfile, warn_deprecated) = 1; + CPP_OPTION (pfile, warn_long_long) = !CPP_OPTION (pfile, c99); + CPP_OPTION (pfile, dollars_in_ident) = 1; + CPP_OPTION (pfile, warn_dollars) = 1; + CPP_OPTION (pfile, warn_variadic_macros) = 1; + CPP_OPTION (pfile, warn_normalize) = normalized_C; + + /* Default CPP arithmetic to something sensible for the host for the + benefit of dumb users like fix-header. */ + CPP_OPTION (pfile, precision) = CHAR_BIT * sizeof (long); + CPP_OPTION (pfile, char_precision) = CHAR_BIT; + CPP_OPTION (pfile, wchar_precision) = CHAR_BIT * sizeof (int); + CPP_OPTION (pfile, int_precision) = CHAR_BIT * sizeof (int); + CPP_OPTION (pfile, unsigned_char) = 0; + CPP_OPTION (pfile, unsigned_wchar) = 1; + CPP_OPTION (pfile, bytes_big_endian) = 1; /* does not matter */ + + /* Default to no charset conversion. */ + CPP_OPTION (pfile, narrow_charset) = _cpp_default_encoding (); + CPP_OPTION (pfile, wide_charset) = 0; + + /* Default the input character set to UTF-8. */ + CPP_OPTION (pfile, input_charset) = _cpp_default_encoding (); + + /* SDCC specific */ + CPP_OPTION (pfile, preproc_asm) = 1; + CPP_OPTION (pfile, pedantic_parse_number) = 0; + CPP_OPTION (pfile, obj_ext) = NULL; + + /* A fake empty "directory" used as the starting point for files + looked up without a search path. Name cannot be '/' because we + don't want to prepend anything at all to filenames using it. All + other entries are correct zero-initialized. */ + pfile->no_search_path.name = (char *) ""; + + /* Initialize the line map. */ + pfile->line_table = line_table; + + /* Initialize lexer state. */ + pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments); + + /* Set up static tokens. */ + pfile->avoid_paste.type = CPP_PADDING; + pfile->avoid_paste.val.source = NULL; + pfile->eof.type = CPP_EOF; + pfile->eof.flags = 0; + + /* Create a token buffer for the lexer. */ + _cpp_init_tokenrun (&pfile->base_run, 250); + pfile->cur_run = &pfile->base_run; + pfile->cur_token = pfile->base_run.base; + + /* Initialize the base context. */ + pfile->context = &pfile->base_context; + pfile->base_context.macro = 0; + pfile->base_context.prev = pfile->base_context.next = 0; + + /* Aligned and unaligned storage. */ + pfile->a_buff = _cpp_get_buff (pfile, 0); + pfile->u_buff = _cpp_get_buff (pfile, 0); + + /* The expression parser stack. */ + _cpp_expand_op_stack (pfile); + + /* Initialize the buffer obstack. */ + _obstack_begin (&pfile->buffer_ob, 0, 0, + (void *(*) (long)) xmalloc, + (void (*) (void *)) free); + + _cpp_init_files (pfile); + + _cpp_init_hashtable (pfile, table); + + return pfile; +} + +/* Free resources used by PFILE. Accessing PFILE after this function + returns leads to undefined behavior. Returns the error count. */ +void +cpp_destroy (cpp_reader *pfile) +{ + cpp_context *context, *contextn; + tokenrun *run, *runn; + + free (pfile->op_stack); + + while (CPP_BUFFER (pfile) != NULL) + _cpp_pop_buffer (pfile); + + if (pfile->out.base) + free (pfile->out.base); + + if (pfile->macro_buffer) + { + free (pfile->macro_buffer); + pfile->macro_buffer = NULL; + pfile->macro_buffer_len = 0; + } + + if (pfile->deps) + deps_free (pfile->deps); + obstack_free (&pfile->buffer_ob, 0); + + _cpp_destroy_hashtable (pfile); + _cpp_cleanup_files (pfile); + _cpp_destroy_iconv (pfile); + + _cpp_free_buff (pfile->a_buff); + _cpp_free_buff (pfile->u_buff); + _cpp_free_buff (pfile->free_buffs); + + for (run = &pfile->base_run; run; run = runn) + { + runn = run->next; + free (run->base); + if (run != &pfile->base_run) + free (run); + } + + for (context = pfile->base_context.next; context; context = contextn) + { + contextn = context->next; + free (context); + } + + free (pfile); +} + +/* This structure defines one built-in identifier. A node will be + entered in the hash table under the name NAME, with value VALUE. + + There are two tables of these. builtin_array holds all the + "builtin" macros: these are handled by builtin_macro() in + macro.c. Builtin is somewhat of a misnomer -- the property of + interest is that these macros require special code to compute their + expansions. The value is a "builtin_type" enumerator. + + operator_array holds the C++ named operators. These are keywords + which act as aliases for punctuators. In C++, they cannot be + altered through #define, and #if recognizes them as operators. In + C, these are not entered into the hash table at all (but see + ). The value is a token-type enumerator. */ +struct builtin +{ + const uchar *name; + unsigned short len; + unsigned short value; +}; + +#define B(n, t) { DSC(n), t } +static const struct builtin builtin_array[] = +{ + B("__TIME__", BT_TIME), + B("__DATE__", BT_DATE), + B("__FILE__", BT_FILE), + B("__BASE_FILE__", BT_BASE_FILE), + B("__LINE__", BT_SPECLINE), + B("__INCLUDE_LEVEL__", BT_INCLUDE_LEVEL), + /* Keep builtins not used for -traditional-cpp at the end, and + update init_builtins() if any more are added. */ + B("_Pragma", BT_PRAGMA), + B("__STDC__", BT_STDC), +}; + +static const struct builtin operator_array[] = +{ + B("and", CPP_AND_AND), + B("and_eq", CPP_AND_EQ), + B("bitand", CPP_AND), + B("bitor", CPP_OR), + B("compl", CPP_COMPL), + B("not", CPP_NOT), + B("not_eq", CPP_NOT_EQ), + B("or", CPP_OR_OR), + B("or_eq", CPP_OR_EQ), + B("xor", CPP_XOR), + B("xor_eq", CPP_XOR_EQ) +}; +#undef B + +/* Mark the C++ named operators in the hash table. */ +static void +mark_named_operators (cpp_reader *pfile) +{ + const struct builtin *b; + + for (b = operator_array; + b < (operator_array + ARRAY_SIZE (operator_array)); + b++) + { + cpp_hashnode *hp = cpp_lookup (pfile, b->name, b->len); + hp->flags |= NODE_OPERATOR; + hp->is_directive = 0; + hp->directive_index = b->value; + } +} + +/* Read the builtins table above and enter them, and language-specific + macros, into the hash table. HOSTED is true if this is a hosted + environment. */ +void +cpp_init_builtins (cpp_reader *pfile, int hosted) +{ + const struct builtin *b; + size_t n = ARRAY_SIZE (builtin_array); + + if (CPP_OPTION (pfile, traditional)) + n -= 2; + else if (! CPP_OPTION (pfile, stdc_0_in_system_headers) + || CPP_OPTION (pfile, std)) + { + n--; + _cpp_define_builtin (pfile, "__STDC__ 1"); + } + + for (b = builtin_array; b < builtin_array + n; b++) + { + cpp_hashnode *hp = cpp_lookup (pfile, b->name, b->len); + hp->type = NT_MACRO; + hp->flags |= NODE_BUILTIN | NODE_WARN; + hp->value.builtin = (enum builtin_type) b->value; + } + + if (CPP_OPTION (pfile, cplusplus)) + _cpp_define_builtin (pfile, "__cplusplus 1"); + else if (CPP_OPTION (pfile, lang) == CLK_ASM) + _cpp_define_builtin (pfile, "__ASSEMBLER__ 1"); + else if (CPP_OPTION (pfile, lang) == CLK_STDC94) + _cpp_define_builtin (pfile, "__STDC_VERSION__ 199409L"); + else if (CPP_OPTION (pfile, c99)) + _cpp_define_builtin (pfile, "__STDC_VERSION__ 199901L"); + + if (hosted) + _cpp_define_builtin (pfile, "__STDC_HOSTED__ 1"); + else + _cpp_define_builtin (pfile, "__STDC_HOSTED__ 0"); + + if (CPP_OPTION (pfile, objc)) + _cpp_define_builtin (pfile, "__OBJC__ 1"); +} + +/* Sanity-checks are dependent on command-line options, so it is + called as a subroutine of cpp_read_main_file (). */ +#if ENABLE_CHECKING +static void sanity_checks (cpp_reader *); +static void sanity_checks (cpp_reader *pfile) +{ + cppchar_t test = 0; + size_t max_precision = 2 * CHAR_BIT * sizeof (cpp_num_part); + + /* Sanity checks for assumptions about CPP arithmetic and target + type precisions made by cpplib. */ + test--; + if (test < 1) + cpp_error (pfile, CPP_DL_ICE, "cppchar_t must be an unsigned type"); + + if (CPP_OPTION (pfile, precision) > max_precision) + cpp_error (pfile, CPP_DL_ICE, + "preprocessor arithmetic has maximum precision of %lu bits;" + " target requires %lu bits", + (unsigned long) max_precision, + (unsigned long) CPP_OPTION (pfile, precision)); + + if (CPP_OPTION (pfile, precision) < CPP_OPTION (pfile, int_precision)) + cpp_error (pfile, CPP_DL_ICE, + "CPP arithmetic must be at least as precise as a target int"); + + if (CPP_OPTION (pfile, char_precision) < 8) + cpp_error (pfile, CPP_DL_ICE, "target char is less than 8 bits wide"); + + if (CPP_OPTION (pfile, wchar_precision) < CPP_OPTION (pfile, char_precision)) + cpp_error (pfile, CPP_DL_ICE, + "target wchar_t is narrower than target char"); + + if (CPP_OPTION (pfile, int_precision) < CPP_OPTION (pfile, char_precision)) + cpp_error (pfile, CPP_DL_ICE, + "target int is narrower than target char"); + + /* This is assumed in eval_token() and could be fixed if necessary. */ + if (sizeof (cppchar_t) > sizeof (cpp_num_part)) + cpp_error (pfile, CPP_DL_ICE, + "CPP half-integer narrower than CPP character"); + + if (CPP_OPTION (pfile, wchar_precision) > BITS_PER_CPPCHAR_T) + cpp_error (pfile, CPP_DL_ICE, + "CPP on this host cannot handle wide character constants over" + " %lu bits, but the target requires %lu bits", + (unsigned long) BITS_PER_CPPCHAR_T, + (unsigned long) CPP_OPTION (pfile, wchar_precision)); +} +#else +# define sanity_checks(PFILE) +#endif + +/* This is called after options have been parsed, and partially + processed. */ +void +cpp_post_options (cpp_reader *pfile) +{ + sanity_checks (pfile); + + post_options (pfile); + + /* Mark named operators before handling command line macros. */ + if (CPP_OPTION (pfile, cplusplus) && CPP_OPTION (pfile, operator_names)) + mark_named_operators (pfile); +} + +/* Setup for processing input from the file named FNAME, or stdin if + it is the empty string. Return the original filename + on success (e.g. foo.i->foo.c), or NULL on failure. */ +const char * +cpp_read_main_file (cpp_reader *pfile, const char *fname) +{ + if (CPP_OPTION (pfile, deps.style) != DEPS_NONE) + { + if (!pfile->deps) + pfile->deps = deps_init (); + + /* Set the default target (if there is none already). */ + deps_add_default_target (pfile, fname); + } + + pfile->main_file + = _cpp_find_file (pfile, fname, &pfile->no_search_path, false, 0); + if (_cpp_find_failed (pfile->main_file)) + return NULL; + + _cpp_stack_file (pfile, pfile->main_file, false); + + /* For foo.i, read the original filename foo.c now, for the benefit + of the front ends. */ + if (CPP_OPTION (pfile, preprocessed)) + { + read_original_filename (pfile); + fname = pfile->line_table->maps[pfile->line_table->used-1].to_file; + } + return fname; +} + +/* For preprocessed files, if the first tokens are of the form # NUM. + handle the directive so we know the original file name. This will + generate file_change callbacks, which the front ends must handle + appropriately given their state of initialization. */ +static void +read_original_filename (cpp_reader *pfile) +{ + const cpp_token *token, *token1; + + /* Lex ahead; if the first tokens are of the form # NUM, then + process the directive, otherwise back up. */ + token = _cpp_lex_direct (pfile); + if (token->type == CPP_HASH) + { + pfile->state.in_directive = 1; + token1 = _cpp_lex_direct (pfile); + _cpp_backup_tokens (pfile, 1); + pfile->state.in_directive = 0; + + /* If it's a #line directive, handle it. */ + if (token1->type == CPP_NUMBER) + { + _cpp_handle_directive (pfile, token->flags & PREV_WHITE); + read_original_directory (pfile); + return; + } + } + + /* Backup as if nothing happened. */ + _cpp_backup_tokens (pfile, 1); +} + +/* For preprocessed files, if the tokens following the first filename + line is of the form # "/path/name//", handle the + directive so we know the original current directory. */ +static void +read_original_directory (cpp_reader *pfile) +{ + const cpp_token *hash, *token; + + /* Lex ahead; if the first tokens are of the form # NUM, then + process the directive, otherwise back up. */ + hash = _cpp_lex_direct (pfile); + if (hash->type != CPP_HASH) + { + _cpp_backup_tokens (pfile, 1); + return; + } + + token = _cpp_lex_direct (pfile); + + if (token->type != CPP_NUMBER) + { + _cpp_backup_tokens (pfile, 2); + return; + } + + token = _cpp_lex_direct (pfile); + + if (token->type != CPP_STRING + || ! (token->val.str.len >= 5 + && token->val.str.text[token->val.str.len-2] == '/' + && token->val.str.text[token->val.str.len-3] == '/')) + { + _cpp_backup_tokens (pfile, 3); + return; + } + + if (pfile->cb.dir_change) + { + char *debugdir = (char *) alloca (token->val.str.len - 3); + + memcpy (debugdir, (const char *) token->val.str.text + 1, + token->val.str.len - 4); + debugdir[token->val.str.len - 4] = '\0'; + + pfile->cb.dir_change (pfile, debugdir); + } +} + +/* This is called at the end of preprocessing. It pops the last + buffer and writes dependency output, and returns the number of + errors. + + Maybe it should also reset state, such that you could call + cpp_start_read with a new filename to restart processing. */ +int +cpp_finish (cpp_reader *pfile, FILE *deps_stream) +{ + /* Warn about unused macros before popping the final buffer. */ + if (CPP_OPTION (pfile, warn_unused_macros)) + cpp_forall_identifiers (pfile, _cpp_warn_if_unused_macro, NULL); + + /* lex.c leaves the final buffer on the stack. This it so that + it returns an unending stream of CPP_EOFs to the client. If we + popped the buffer, we'd dereference a NULL buffer pointer and + segfault. It's nice to allow the client to do worry-free excess + cpp_get_token calls. */ + while (pfile->buffer) + _cpp_pop_buffer (pfile); + + /* Don't write the deps file if there are errors. */ + if (CPP_OPTION (pfile, deps.style) != DEPS_NONE + && deps_stream && pfile->errors == 0) + { + deps_write (pfile->deps, deps_stream, 72); + + if (CPP_OPTION (pfile, deps.phony_targets)) + deps_phony_targets (pfile->deps, deps_stream); + } + + /* Report on headers that could use multiple include guards. */ + if (CPP_OPTION (pfile, print_include_names)) + _cpp_report_missing_guards (pfile); + + return pfile->errors; +} + +static void +post_options (cpp_reader *pfile) +{ + /* -Wtraditional is not useful in C++ mode. */ + if (CPP_OPTION (pfile, cplusplus)) + CPP_OPTION (pfile, warn_traditional) = 0; + + /* Permanently disable macro expansion if we are rescanning + preprocessed text. Read preprocesed source in ISO mode. */ + if (CPP_OPTION (pfile, preprocessed)) + { + pfile->state.prevent_expansion = 1; + CPP_OPTION (pfile, traditional) = 0; + } + + if (CPP_OPTION (pfile, warn_trigraphs) == 2) + CPP_OPTION (pfile, warn_trigraphs) = !CPP_OPTION (pfile, trigraphs); + + if (CPP_OPTION (pfile, traditional)) + { + CPP_OPTION (pfile, cplusplus_comments) = 0; + + /* Traditional CPP does not accurately track column information. */ + CPP_OPTION (pfile, show_column) = 0; + CPP_OPTION (pfile, trigraphs) = 0; + CPP_OPTION (pfile, warn_trigraphs) = 0; + } +} diff --git a/support/cpp2/libcpp/internal.h b/support/cpp2/libcpp/internal.h new file mode 100644 index 00000000..960f153e --- /dev/null +++ b/support/cpp2/libcpp/internal.h @@ -0,0 +1,661 @@ +/* Part of CPP library. + Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. + +This program 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 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* This header defines all the internal data structures and functions + that need to be visible across files. It should not be used outside + cpplib. */ + +#ifndef LIBCPP_INTERNAL_H +#define LIBCPP_INTERNAL_H + +#include "symtab.h" +#include "cpp-id-data.h" + +#ifndef HAVE_ICONV_H +#undef HAVE_ICONV +#endif + +#if HAVE_ICONV +#include +#else +#define HAVE_ICONV 0 +typedef int iconv_t; /* dummy */ +#endif + +struct directive; /* Deliberately incomplete. */ +struct pending_option; +struct op; +struct _cpp_strbuf; + +typedef bool (*convert_f) (iconv_t, const unsigned char *, size_t, + struct _cpp_strbuf *); +struct cset_converter +{ + convert_f func; + iconv_t cd; +}; + +#define BITS_PER_CPPCHAR_T (CHAR_BIT * sizeof (cppchar_t)) + +/* Test if a sign is valid within a preprocessing number. */ +#define VALID_SIGN(c, prevc) \ + (((c) == '+' || (c) == '-') && \ + ((prevc) == 'e' || (prevc) == 'E' \ + || (((prevc) == 'p' || (prevc) == 'P') \ + && CPP_OPTION (pfile, extended_numbers)))) + +#define CPP_OPTION(PFILE, OPTION) ((PFILE)->opts.OPTION) +#define CPP_BUFFER(PFILE) ((PFILE)->buffer) +#define CPP_BUF_COLUMN(BUF, CUR) ((CUR) - (BUF)->line_base) +#define CPP_BUF_COL(BUF) CPP_BUF_COLUMN(BUF, (BUF)->cur) + +#define CPP_INCREMENT_LINE(PFILE, COLS_HINT) do { \ + const struct line_maps *line_table = PFILE->line_table; \ + const struct line_map *map = &line_table->maps[line_table->used-1]; \ + unsigned int line = SOURCE_LINE (map, line_table->highest_line); \ + linemap_line_start (PFILE->line_table, line + 1, COLS_HINT); \ + } while (0) + +/* Maximum nesting of cpp_buffers. We use a static limit, partly for + efficiency, and partly to limit runaway recursion. */ +#define CPP_STACK_MAX 200 + +/* Host alignment handling. */ +struct dummy +{ + char c; + union + { + double d; + int *p; + } u; +}; + +#define DEFAULT_ALIGNMENT offsetof (struct dummy, u) +#define CPP_ALIGN2(size, align) (((size) + ((align) - 1)) & ~((align) - 1)) +#define CPP_ALIGN(size) CPP_ALIGN2 (size, DEFAULT_ALIGNMENT) + +#define _cpp_mark_macro_used(NODE) do { \ + if ((NODE)->type == NT_MACRO && !((NODE)->flags & NODE_BUILTIN)) \ + (NODE)->value.macro->used = 1; } while (0) + +/* A generic memory buffer, and operations on it. */ +typedef struct _cpp_buff _cpp_buff; +struct _cpp_buff +{ + struct _cpp_buff *next; + unsigned char *base, *cur, *limit; +}; + +extern _cpp_buff *_cpp_get_buff (cpp_reader *, size_t); +extern void _cpp_release_buff (cpp_reader *, _cpp_buff *); +extern void _cpp_extend_buff (cpp_reader *, _cpp_buff **, size_t); +extern _cpp_buff *_cpp_append_extend_buff (cpp_reader *, _cpp_buff *, size_t); +extern void _cpp_free_buff (_cpp_buff *); +extern unsigned char *_cpp_aligned_alloc (cpp_reader *, size_t); +extern unsigned char *_cpp_unaligned_alloc (cpp_reader *, size_t); + +#define BUFF_ROOM(BUFF) (size_t) ((BUFF)->limit - (BUFF)->cur) +#define BUFF_FRONT(BUFF) ((BUFF)->cur) +#define BUFF_LIMIT(BUFF) ((BUFF)->limit) + +/* #include types. */ +enum include_type {IT_INCLUDE, IT_INCLUDE_NEXT, IT_IMPORT, IT_CMDLINE}; + +union utoken +{ + const cpp_token *token; + const cpp_token **ptoken; +}; + +/* A "run" of tokens; part of a chain of runs. */ +typedef struct tokenrun tokenrun; +struct tokenrun +{ + tokenrun *next, *prev; + cpp_token *base, *limit; +}; + +/* Accessor macros for struct cpp_context. */ +#define FIRST(c) ((c)->u.iso.first) +#define LAST(c) ((c)->u.iso.last) +#define CUR(c) ((c)->u.trad.cur) +#define RLIMIT(c) ((c)->u.trad.rlimit) + +typedef struct cpp_context cpp_context; +struct cpp_context +{ + /* Doubly-linked list. */ + cpp_context *next, *prev; + + union + { + /* For ISO macro expansion. Contexts other than the base context + are contiguous tokens. e.g. macro expansions, expanded + argument tokens. */ + struct + { + union utoken first; + union utoken last; + } iso; + + /* For traditional macro expansion. */ + struct + { + const unsigned char *cur; + const unsigned char *rlimit; + } trad; + } u; + + /* If non-NULL, a buffer used for storage related to this context. + When the context is popped, the buffer is released. */ + _cpp_buff *buff; + + /* For a macro context, the macro node, otherwise NULL. */ + cpp_hashnode *macro; + + /* True if utoken element is token, else ptoken. */ + bool direct_p; +}; + +struct lexer_state +{ + /* Nonzero if first token on line is CPP_HASH. */ + unsigned char in_directive; + + /* Nonzero if in a directive that will handle padding tokens itself. + #include needs this to avoid problems with computed include and + spacing between tokens. */ + unsigned char directive_wants_padding; + + /* True if we are skipping a failed conditional group. */ + unsigned char skipping; + + /* Nonzero if in a directive that takes angle-bracketed headers. */ + unsigned char angled_headers; + + /* Nonzero if in a #if or #elif directive. */ + unsigned char in_expression; + + /* Nonzero to save comments. Turned off if discard_comments, and in + all directives apart from #define. */ + unsigned char save_comments; + + /* Nonzero if lexing __VA_ARGS__ is valid. */ + unsigned char va_args_ok; + + /* Nonzero if lexing poisoned identifiers is valid. */ + unsigned char poisoned_ok; + + /* Nonzero to prevent macro expansion. */ + unsigned char prevent_expansion; + + /* Nonzero when handling a deferred pragma. */ + unsigned char in_deferred_pragma; + + /* Nonzero when parsing arguments to a function-like macro. */ + unsigned char parsing_args; + + /* Nonzero if prevent_expansion is true only because output is + being discarded. */ + unsigned char discarding_output; + + /* Nonzero to skip evaluating part of an expression. */ + unsigned int skip_eval; +}; + +/* Special nodes - identifiers with predefined significance. */ +struct spec_nodes +{ + cpp_hashnode *n_defined; /* defined operator */ + cpp_hashnode *n_true; /* C++ keyword true */ + cpp_hashnode *n_false; /* C++ keyword false */ + cpp_hashnode *n__VA_ARGS__; /* C99 vararg macros */ + /* SDCC _asm specific */ + cpp_hashnode *n__asm; /* _asm ... _endasm ; */ +}; + +typedef struct _cpp_line_note _cpp_line_note; +struct _cpp_line_note +{ + /* Location in the clean line the note refers to. */ + const unsigned char *pos; + + /* Type of note. The 9 'from' trigraph characters represent those + trigraphs, '\\' an escaped newline, ' ' an escaped newline with + intervening space, and anything else is invalid. */ + unsigned int type; +}; + +/* Represents the contents of a file cpplib has read in. */ +struct cpp_buffer +{ + const unsigned char *cur; /* Current location. */ + const unsigned char *line_base; /* Start of current physical line. */ + const unsigned char *next_line; /* Start of to-be-cleaned logical line. */ + + const unsigned char *buf; /* Entire character buffer. */ + const unsigned char *rlimit; /* Writable byte at end of file. */ + + _cpp_line_note *notes; /* Array of notes. */ + unsigned int cur_note; /* Next note to process. */ + unsigned int notes_used; /* Number of notes. */ + unsigned int notes_cap; /* Size of allocated array. */ + + struct cpp_buffer *prev; + + /* Pointer into the file table; non-NULL if this is a file buffer. + Used for include_next and to record control macros. */ + struct _cpp_file *file; + + /* Value of if_stack at start of this file. + Used to prohibit unmatched #endif (etc) in an include file. */ + struct if_stack *if_stack; + + /* True if we need to get the next clean line. */ + bool need_line; + + /* True if we have already warned about C++ comments in this file. + The warning happens only for C89 extended mode with -pedantic on, + or for -Wtraditional, and only once per file (otherwise it would + be far too noisy). */ + unsigned int warned_cplusplus_comments : 1; + + /* True if we don't process trigraphs and escaped newlines. True + for preprocessed input, command line directives, and _Pragma + buffers. */ + unsigned int from_stage3 : 1; + + /* At EOF, a buffer is automatically popped. If RETURN_AT_EOF is + true, a CPP_EOF token is then returned. Otherwise, the next + token from the enclosing buffer is returned. */ + unsigned int return_at_eof : 1; + + /* One for a system header, two for a C system header file that therefore + needs to be extern "C" protected in C++, and zero otherwise. */ + unsigned char sysp; + + /* The directory of the this buffer's file. Its NAME member is not + allocated, so we don't need to worry about freeing it. */ + struct cpp_dir dir; + + /* Descriptor for converting from the input character set to the + source character set. */ + struct cset_converter input_cset_desc; +}; + +/* A cpp_reader encapsulates the "state" of a pre-processor run. + Applying cpp_get_token repeatedly yields a stream of pre-processor + tokens. Usually, there is only one cpp_reader object active. */ +struct cpp_reader +{ + /* Top of buffer stack. */ + cpp_buffer *buffer; + + /* Overlaid buffer (can be different after processing #include). */ + cpp_buffer *overlaid_buffer; + + /* Lexer state. */ + struct lexer_state state; + + /* Source line tracking. */ + struct line_maps *line_table; + + /* The line of the '#' of the current directive. */ + source_location directive_line; + + /* Memory buffers. */ + _cpp_buff *a_buff; /* Aligned permanent storage. */ + _cpp_buff *u_buff; /* Unaligned permanent storage. */ + _cpp_buff *free_buffs; /* Free buffer chain. */ + + /* Context stack. */ + struct cpp_context base_context; + struct cpp_context *context; + + /* If in_directive, the directive if known. */ + const struct directive *directive; + + /* Token generated while handling a directive, if any. */ + cpp_token directive_result; + + /* Search paths for include files. */ + struct cpp_dir *quote_include; /* "" */ + struct cpp_dir *bracket_include; /* <> */ + struct cpp_dir no_search_path; /* No path. */ + + /* Chain of all hashed _cpp_file instances. */ + struct _cpp_file *all_files; + + struct _cpp_file *main_file; + + /* File and directory hash table. */ + struct htab *file_hash; + struct htab *dir_hash; + struct file_hash_entry *file_hash_entries; + unsigned int file_hash_entries_allocated, file_hash_entries_used; + + /* Nonzero means don't look for #include "foo" the source-file + directory. */ + bool quote_ignores_source_dir; + + /* Nonzero if any file has contained #pragma once or #import has + been used. */ + bool seen_once_only; + + /* Multiple include optimization. */ + const cpp_hashnode *mi_cmacro; + const cpp_hashnode *mi_ind_cmacro; + bool mi_valid; + + /* Lexing. */ + cpp_token *cur_token; + tokenrun base_run, *cur_run; + unsigned int lookaheads; + + /* Nonzero prevents the lexer from re-using the token runs. */ + unsigned int keep_tokens; + + /* Error counter for exit code. */ + unsigned int errors; + + /* Buffer to hold macro definition string. */ + unsigned char *macro_buffer; + unsigned int macro_buffer_len; + + /* Descriptor for converting from the source character set to the + execution character set. */ + struct cset_converter narrow_cset_desc; + + /* Descriptor for converting from the source character set to the + wide execution character set. */ + struct cset_converter wide_cset_desc; + + /* Date and time text. Calculated together if either is requested. */ + const unsigned char *date; + const unsigned char *time; + + /* EOF token, and a token forcing paste avoidance. */ + cpp_token avoid_paste; + cpp_token eof; + + /* Opaque handle to the dependencies of mkdeps.c. */ + struct deps *deps; + + /* Obstack holding all macro hash nodes. This never shrinks. + See identifiers.c */ + struct obstack hash_ob; + + /* Obstack holding buffer and conditional structures. This is a + real stack. See directives.c. */ + struct obstack buffer_ob; + + /* Pragma table - dynamic, because a library user can add to the + list of recognized pragmas. */ + struct pragma_entry *pragmas; + + /* Call backs to cpplib client. */ + struct cpp_callbacks cb; + + /* Identifier hash table. */ + struct ht *hash_table; + + /* Expression parser stack. */ + struct op *op_stack, *op_limit; + + /* User visible options. */ + struct cpp_options opts; + + /* Special nodes - identifiers with predefined significance to the + preprocessor. */ + struct spec_nodes spec_nodes; + + /* Whether cpplib owns the hashtable. */ + bool our_hashtable; + + /* Traditional preprocessing output buffer (a logical line). */ + struct + { + unsigned char *base; + unsigned char *limit; + unsigned char *cur; + source_location first_line; + } out; + + /* Used for buffer overlays by traditional.c. */ + const unsigned char *saved_cur, *saved_rlimit, *saved_line_base; + + /* A saved list of the defined macros, for dependency checking + of precompiled headers. */ + struct cpp_savedstate *savedstate; +}; + +/* Character classes. Based on the more primitive macros in safe-ctype.h. + If the definition of `numchar' looks odd to you, please look up the + definition of a pp-number in the C standard [section 6.4.8 of C99]. + + In the unlikely event that characters other than \r and \n enter + the set is_vspace, the macro handle_newline() in lex.c must be + updated. */ +#define _dollar_ok(x) ((x) == '$' && CPP_OPTION (pfile, dollars_in_ident)) + +#define is_idchar(x) (ISIDNUM(x) || _dollar_ok(x)) +#define is_numchar(x) ISIDNUM(x) +#define is_idstart(x) (ISIDST(x) || _dollar_ok(x)) +#define is_numstart(x) ISDIGIT(x) +#define is_hspace(x) ISBLANK(x) +#define is_vspace(x) IS_VSPACE(x) +#define is_nvspace(x) IS_NVSPACE(x) +#define is_space(x) IS_SPACE_OR_NUL(x) + +/* This table is constant if it can be initialized at compile time, + which is the case if cpp was compiled with GCC >=2.7, or another + compiler that supports C99. */ +#if HAVE_DESIGNATED_INITIALIZERS +extern const unsigned char _cpp_trigraph_map[UCHAR_MAX + 1]; +#else +extern unsigned char _cpp_trigraph_map[UCHAR_MAX + 1]; +#endif + +/* Macros. */ + +static inline int cpp_in_system_header (cpp_reader *); +static inline int +cpp_in_system_header (cpp_reader *pfile) +{ + return pfile->buffer ? pfile->buffer->sysp : 0; +} +#define CPP_PEDANTIC(PF) CPP_OPTION (PF, pedantic) +#define CPP_WTRADITIONAL(PF) CPP_OPTION (PF, warn_traditional) + +/* In errors.c */ +extern int _cpp_begin_message (cpp_reader *, int, + source_location, unsigned int); + +/* In macro.c */ +extern void _cpp_free_definition (cpp_hashnode *); +extern bool _cpp_create_definition (cpp_reader *, cpp_hashnode *); +extern void _cpp_pop_context (cpp_reader *); +extern void _cpp_push_text_context (cpp_reader *, cpp_hashnode *, + const unsigned char *, size_t); +extern bool _cpp_save_parameter (cpp_reader *, cpp_macro *, cpp_hashnode *); +extern bool _cpp_arguments_ok (cpp_reader *, cpp_macro *, const cpp_hashnode *, + unsigned int); +extern const unsigned char *_cpp_builtin_macro_text (cpp_reader *, + cpp_hashnode *); +int _cpp_warn_if_unused_macro (cpp_reader *, cpp_hashnode *, void *); +/* In identifiers.c */ +extern void _cpp_init_hashtable (cpp_reader *, hash_table *); +extern void _cpp_destroy_hashtable (cpp_reader *); + +/* In files.c */ +typedef struct _cpp_file _cpp_file; +extern _cpp_file *_cpp_find_file (cpp_reader *, const char *, cpp_dir *, + bool, int); +extern bool _cpp_find_failed (_cpp_file *); +extern void _cpp_mark_file_once_only (cpp_reader *, struct _cpp_file *); +extern void _cpp_fake_include (cpp_reader *, const char *); +extern bool _cpp_stack_file (cpp_reader *, _cpp_file*, bool); +extern bool _cpp_stack_include (cpp_reader *, const char *, int, + enum include_type); +extern int _cpp_compare_file_date (cpp_reader *, const char *, int); +extern void _cpp_report_missing_guards (cpp_reader *); +extern void _cpp_init_files (cpp_reader *); +extern void _cpp_cleanup_files (cpp_reader *); +extern void _cpp_pop_file_buffer (cpp_reader *, struct _cpp_file *); +extern bool _cpp_save_file_entries (cpp_reader *pfile, FILE *f); +extern bool _cpp_read_file_entries (cpp_reader *, FILE *); + +/* In expr.c */ +extern bool _cpp_parse_expr (cpp_reader *); +extern struct op *_cpp_expand_op_stack (cpp_reader *); + +/* In lex.c */ +extern void _cpp_process_line_notes (cpp_reader *, int); +extern void _cpp_clean_line (cpp_reader *); +extern bool _cpp_get_fresh_line (cpp_reader *); +extern bool _cpp_skip_block_comment (cpp_reader *); +extern cpp_token *_cpp_temp_token (cpp_reader *); +extern const cpp_token *_cpp_lex_token (cpp_reader *); +extern cpp_token *_cpp_lex_direct (cpp_reader *); +extern int _cpp_equiv_tokens (const cpp_token *, const cpp_token *); +extern void _cpp_init_tokenrun (tokenrun *, unsigned int); + +/* In init.c. */ +extern void _cpp_maybe_push_include_file (cpp_reader *); + +/* In directives.c */ +extern int _cpp_test_assertion (cpp_reader *, unsigned int *); +extern int _cpp_handle_directive (cpp_reader *, int); +extern void _cpp_define_builtin (cpp_reader *, const char *); +extern char ** _cpp_save_pragma_names (cpp_reader *); +extern void _cpp_restore_pragma_names (cpp_reader *, char **); +extern void _cpp_do__Pragma (cpp_reader *); +extern void _cpp_init_directives (cpp_reader *); +extern void _cpp_init_internal_pragmas (cpp_reader *); +extern void _cpp_do_file_change (cpp_reader *, enum lc_reason, const char *, + unsigned int, unsigned int); +extern void _cpp_pop_buffer (cpp_reader *); + +/* In traditional.c. */ +extern bool _cpp_scan_out_logical_line (cpp_reader *, cpp_macro *); +extern bool _cpp_read_logical_line_trad (cpp_reader *); +extern void _cpp_overlay_buffer (cpp_reader *pfile, const unsigned char *, + size_t); +extern void _cpp_remove_overlay (cpp_reader *); +extern bool _cpp_create_trad_definition (cpp_reader *, cpp_macro *); +extern bool _cpp_expansions_different_trad (const cpp_macro *, + const cpp_macro *); +extern unsigned char *_cpp_copy_replacement_text (const cpp_macro *, + unsigned char *); +extern size_t _cpp_replacement_text_len (const cpp_macro *); + +/* In charset.c. */ + +/* The normalization state at this point in the sequence. + It starts initialized to all zeros, and at the end + 'level' is the normalization level of the sequence. */ + +struct normalize_state +{ + /* The previous character. */ + cppchar_t previous; + /* The combining class of the previous character. */ + unsigned char prev_class; + /* The lowest normalization level so far. */ + enum cpp_normalize_level level; +}; +#define INITIAL_NORMALIZE_STATE { 0, 0, normalized_KC } +#define NORMALIZE_STATE_RESULT(st) ((st)->level) + +/* We saw a character that matches ISIDNUM(), update a + normalize_state appropriately. */ +#define NORMALIZE_STATE_UPDATE_IDNUM(st) \ + ((st)->previous = 0, (st)->prev_class = 0) + +extern cppchar_t _cpp_valid_ucn (cpp_reader *, const unsigned char **, + const unsigned char *, int, + struct normalize_state *state); +extern void _cpp_destroy_iconv (cpp_reader *); +extern unsigned char *_cpp_convert_input (cpp_reader *, const char *, + unsigned char *, size_t, size_t, + off_t *); +extern const char *_cpp_default_encoding (void); +extern cpp_hashnode * _cpp_interpret_identifier (cpp_reader *pfile, + const unsigned char *id, + size_t len); + +/* Utility routines and macros. */ +#define DSC(str) (const unsigned char *)str, sizeof str - 1 + +/* These are inline functions instead of macros so we can get type + checking. */ +static inline int ustrcmp (const unsigned char *, const unsigned char *); +static inline int ustrncmp (const unsigned char *, const unsigned char *, + size_t); +static inline size_t ustrlen (const unsigned char *); +static inline unsigned char *uxstrdup (const unsigned char *); +static inline unsigned char *ustrchr (const unsigned char *, int); +static inline int ufputs (const unsigned char *, FILE *); + +/* Use a const char for the second parameter since it is usually a literal. */ +static inline int ustrcspn (const unsigned char *, const char *); + +static inline int +ustrcmp (const unsigned char *s1, const unsigned char *s2) +{ + return strcmp ((const char *)s1, (const char *)s2); +} + +static inline int +ustrncmp (const unsigned char *s1, const unsigned char *s2, size_t n) +{ + return strncmp ((const char *)s1, (const char *)s2, n); +} + +static inline int +ustrcspn (const unsigned char *s1, const char *s2) +{ + return strcspn ((const char *)s1, s2); +} + +static inline size_t +ustrlen (const unsigned char *s1) +{ + return strlen ((const char *)s1); +} + +static inline unsigned char * +uxstrdup (const unsigned char *s1) +{ + return (unsigned char *) xstrdup ((const char *)s1); +} + +static inline unsigned char * +ustrchr (const unsigned char *s1, int c) +{ + return (unsigned char *) strchr ((const char *)s1, c); +} + +static inline int +ufputs (const unsigned char *s, FILE *f) +{ + return fputs ((const char *)s, f); +} + +#endif /* ! LIBCPP_INTERNAL_H */ diff --git a/support/cpp2/libcpp/lex.c b/support/cpp2/libcpp/lex.c new file mode 100644 index 00000000..c4a56380 --- /dev/null +++ b/support/cpp2/libcpp/lex.c @@ -0,0 +1,2066 @@ +/* CPP Library - lexical analysis. + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Contributed by Per Bothner, 1994-95. + Based on CCCP program by Paul Rubin, June 1986 + Adapted to ANSI C, Richard Stallman, Jan 1987 + Broken out to separate file, Zack Weinberg, Mar 2000 + +This program 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 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "config.h" +#include "system.h" +#include "cpplib.h" +#include "internal.h" +#include + +enum spell_type +{ + SPELL_OPERATOR = 0, + SPELL_IDENT, + SPELL_LITERAL, + SPELL_NONE +}; + +struct token_spelling +{ + enum spell_type category; + const unsigned char *name; +}; + +static const unsigned char *const digraph_spellings[] = +{ U"%:", U"%:%:", U"<:", U":>", U"<%", U"%>" }; + +#define OP(e, s) { SPELL_OPERATOR, U s }, +#define TK(e, s) { SPELL_ ## s, U #e }, +static const struct token_spelling token_spellings[N_TTYPES] = { TTYPE_TABLE }; +#undef OP +#undef TK + +#define TOKEN_SPELL(token) (token_spellings[(token)->type].category) +#define TOKEN_NAME(token) (token_spellings[(token)->type].name) + +static void add_line_note (cpp_buffer *, const uchar *, unsigned int); +static int skip_line_comment (cpp_reader *); +static void skip_whitespace (cpp_reader *, cppchar_t); +static void lex_string (cpp_reader *, cpp_token *, const uchar *); +static void save_comment (cpp_reader *, cpp_token *, const uchar *, cppchar_t); +static void create_literal (cpp_reader *, cpp_token *, const uchar *, + unsigned int, enum cpp_ttype); +static bool warn_in_comment (cpp_reader *, _cpp_line_note *); +static int name_p (cpp_reader *, const cpp_string *); +static tokenrun *next_tokenrun (tokenrun *); + +static _cpp_buff *new_buff (size_t); + + +/* Utility routine: + + Compares, the token TOKEN to the NUL-terminated string STRING. + TOKEN must be a CPP_NAME. Returns 1 for equal, 0 for unequal. */ +int +cpp_ideq (const cpp_token *token, const char *string) +{ + if (token->type != CPP_NAME) + return 0; + + return !ustrcmp (NODE_NAME (token->val.node), (const uchar *) string); +} + +/* Record a note TYPE at byte POS into the current cleaned logical + line. */ +static void +add_line_note (cpp_buffer *buffer, const uchar *pos, unsigned int type) +{ + if (buffer->notes_used == buffer->notes_cap) + { + buffer->notes_cap = buffer->notes_cap * 2 + 200; + buffer->notes = XRESIZEVEC (_cpp_line_note, buffer->notes, + buffer->notes_cap); + } + + buffer->notes[buffer->notes_used].pos = pos; + buffer->notes[buffer->notes_used].type = type; + buffer->notes_used++; +} + +/* Returns with a logical line that contains no escaped newlines or + trigraphs. This is a time-critical inner loop. */ +void +_cpp_clean_line (cpp_reader *pfile) +{ + cpp_buffer *buffer; + const uchar *s; + uchar c, *d, *p; + + buffer = pfile->buffer; + buffer->cur_note = buffer->notes_used = 0; + buffer->cur = buffer->line_base = buffer->next_line; + buffer->need_line = false; + s = buffer->next_line - 1; + + if (!buffer->from_stage3) + { + /* Short circuit for the common case of an un-escaped line with + no trigraphs. The primary win here is by not writing any + data back to memory until we have to. */ + for (;;) + { + c = *++s; + if (c == '\n' || c == '\r') + { + d = (uchar *) s; + + if (s == buffer->rlimit) + goto done; + + /* DOS line ending? */ + if (c == '\r' && s[1] == '\n') + s++; + + if (s == buffer->rlimit) + goto done; + + /* check for escaped newline */ + p = d; + while (p != buffer->next_line && is_nvspace (p[-1])) + p--; + if (p == buffer->next_line || p[-1] != '\\') + goto done; + + /* Have an escaped newline; process it and proceed to + the slow path. */ + add_line_note (buffer, p - 1, p != d ? ' ' : '\\'); + d = p - 2; + buffer->next_line = p - 1; + break; + } + if (c == '?' && s[1] == '?' && _cpp_trigraph_map[s[2]]) + { + /* Have a trigraph. We may or may not have to convert + it. Add a line note regardless, for -Wtrigraphs. */ + add_line_note (buffer, s, s[2]); + if (CPP_OPTION (pfile, trigraphs)) + { + /* We do, and that means we have to switch to the + slow path. */ + d = (uchar *) s; + *d = _cpp_trigraph_map[s[2]]; + s += 2; + break; + } + } + } + + + for (;;) + { + c = *++s; + *++d = c; + + if (c == '\n' || c == '\r') + { + /* Handle DOS line endings. */ + if (c == '\r' && s != buffer->rlimit && s[1] == '\n') + s++; + if (s == buffer->rlimit) + break; + + /* Escaped? */ + p = d; + while (p != buffer->next_line && is_nvspace (p[-1])) + p--; + if (p == buffer->next_line || p[-1] != '\\') + break; + + add_line_note (buffer, p - 1, p != d ? ' ': '\\'); + d = p - 2; + buffer->next_line = p - 1; + } + else if (c == '?' && s[1] == '?' && _cpp_trigraph_map[s[2]]) + { + /* Add a note regardless, for the benefit of -Wtrigraphs. */ + add_line_note (buffer, d, s[2]); + if (CPP_OPTION (pfile, trigraphs)) + { + *d = _cpp_trigraph_map[s[2]]; + s += 2; + } + } + } + } + else + { + do + s++; + while (*s != '\n' && *s != '\r'); + d = (uchar *) s; + + /* Handle DOS line endings. */ + if (*s == '\r' && s != buffer->rlimit && s[1] == '\n') + s++; + } + + done: + *d = '\n'; + /* A sentinel note that should never be processed. */ + add_line_note (buffer, d + 1, '\n'); + buffer->next_line = s + 1; +} + +/* Return true if the trigraph indicated by NOTE should be warned + about in a comment. */ +static bool +warn_in_comment (cpp_reader *pfile, _cpp_line_note *note) +{ + const uchar *p; + + /* Within comments we don't warn about trigraphs, unless the + trigraph forms an escaped newline, as that may change + behavior. */ + if (note->type != '/') + return false; + + /* If -trigraphs, then this was an escaped newline iff the next note + is coincident. */ + if (CPP_OPTION (pfile, trigraphs)) + return note[1].pos == note->pos; + + /* Otherwise, see if this forms an escaped newline. */ + p = note->pos + 3; + while (is_nvspace (*p)) + p++; + + /* There might have been escaped newlines between the trigraph and the + newline we found. Hence the position test. */ + return (*p == '\n' && p < note[1].pos); +} + +/* Process the notes created by add_line_note as far as the current + location. */ +void +_cpp_process_line_notes (cpp_reader *pfile, int in_comment) +{ + cpp_buffer *buffer = pfile->buffer; + + for (;;) + { + _cpp_line_note *note = &buffer->notes[buffer->cur_note]; + unsigned int col; + + if (note->pos > buffer->cur) + break; + + buffer->cur_note++; + col = CPP_BUF_COLUMN (buffer, note->pos + 1); + + if (note->type == '\\' || note->type == ' ') + { + if (note->type == ' ' && !in_comment) + cpp_error_with_line (pfile, CPP_DL_WARNING, pfile->line_table->highest_line, col, + "backslash and newline separated by space"); + + if (buffer->next_line > buffer->rlimit) + { + cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->line_table->highest_line, col, + "backslash-newline at end of file"); + /* Prevent "no newline at end of file" warning. */ + buffer->next_line = buffer->rlimit; + } + + buffer->line_base = note->pos; + CPP_INCREMENT_LINE (pfile, 0); + } + else if (_cpp_trigraph_map[note->type]) + { + if (CPP_OPTION (pfile, warn_trigraphs) + && (!in_comment || warn_in_comment (pfile, note))) + { + if (CPP_OPTION (pfile, trigraphs)) + cpp_error_with_line (pfile, CPP_DL_WARNING, pfile->line_table->highest_line, col, + "trigraph ??%c converted to %c", + note->type, + (int) _cpp_trigraph_map[note->type]); + else + { + cpp_error_with_line + (pfile, CPP_DL_WARNING, pfile->line_table->highest_line, col, + "trigraph ??%c ignored, use -trigraphs to enable", + note->type); + } + } + } + else + abort (); + } +} + +/* SDCC _asm specific */ +/* Skip an _asm ... _endasm block. We find the end of the comment by + seeing _endasm. Returns non-zero if _asm terminated by EOF, zero + otherwise. */ +static int +skip_asm_block (cpp_reader *pfile) +{ +#define _ENDASM_STR "endasm" +#define _ENDASM_LEN ((sizeof _ENDASM_STR) - 1) + + cpp_buffer *buffer = pfile->buffer; + cppchar_t c = EOF; + int prev_space = 0; + int ret = 1; + + while (buffer->cur != buffer->rlimit) + { + prev_space = is_space(c); + c = *buffer->cur++; + + if (prev_space && c == '_') + { + if (buffer->cur + _ENDASM_LEN <= buffer->rlimit && + strncmp(buffer->cur, _ENDASM_STR, _ENDASM_LEN) == 0) + { + buffer->cur += _ENDASM_LEN; + ret = 0; + break; + } + } + else if (c == '\n') + { + unsigned int cols; + --buffer->cur; + _cpp_process_line_notes (pfile, true); + if (buffer->next_line >= buffer->rlimit) + return true; + _cpp_clean_line (pfile); + + cols = buffer->next_line - buffer->line_base; + CPP_INCREMENT_LINE (pfile, cols); + } + } + + _cpp_process_line_notes (pfile, true); + return ret; +} + +/* Skip a C-style block comment. We find the end of the comment by + seeing if an asterisk is before every '/' we encounter. Returns + nonzero if comment terminated by EOF, zero otherwise. + + Buffer->cur points to the initial asterisk of the comment. */ +bool +_cpp_skip_block_comment (cpp_reader *pfile) +{ + cpp_buffer *buffer = pfile->buffer; + const uchar *cur = buffer->cur; + uchar c; + + cur++; + if (*cur == '/') + cur++; + + for (;;) + { + /* People like decorating comments with '*', so check for '/' + instead for efficiency. */ + c = *cur++; + + if (c == '/') + { + if (cur[-2] == '*') + break; + + /* Warn about potential nested comments, but not if the '/' + comes immediately before the true comment delimiter. + Don't bother to get it right across escaped newlines. */ + if (CPP_OPTION (pfile, warn_comments) + && cur[0] == '*' && cur[1] != '/') + { + buffer->cur = cur; + cpp_error_with_line (pfile, CPP_DL_WARNING, + pfile->line_table->highest_line, CPP_BUF_COL (buffer), + "\"/*\" within comment"); + } + } + else if (c == '\n') + { + unsigned int cols; + buffer->cur = cur - 1; + _cpp_process_line_notes (pfile, true); + if (buffer->next_line >= buffer->rlimit) + return true; + _cpp_clean_line (pfile); + + cols = buffer->next_line - buffer->line_base; + CPP_INCREMENT_LINE (pfile, cols); + + cur = buffer->cur; + } + } + + buffer->cur = cur; + _cpp_process_line_notes (pfile, true); + return false; +} + +/* Skip a C++ line comment, leaving buffer->cur pointing to the + terminating newline. Handles escaped newlines. Returns nonzero + if a multiline comment. */ +static int +skip_line_comment (cpp_reader *pfile) +{ + cpp_buffer *buffer = pfile->buffer; + unsigned int orig_line = pfile->line_table->highest_line; + + while (*buffer->cur != '\n') + buffer->cur++; + + _cpp_process_line_notes (pfile, true); + return orig_line != pfile->line_table->highest_line; +} + +/* Skips whitespace, saving the next non-whitespace character. */ +static void +skip_whitespace (cpp_reader *pfile, cppchar_t c) +{ + cpp_buffer *buffer = pfile->buffer; + bool saw_NUL = false; + + do + { + /* Horizontal space always OK. */ + if (c == ' ' || c == '\t') + ; + /* Just \f \v or \0 left. */ + else if (c == '\0') + saw_NUL = true; + else if (pfile->state.in_directive && CPP_PEDANTIC (pfile)) + cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->line_table->highest_line, + CPP_BUF_COL (buffer), + "%s in preprocessing directive", + c == '\f' ? "form feed" : "vertical tab"); + + c = *buffer->cur++; + } + /* We only want non-vertical space, i.e. ' ' \t \f \v \0. */ + while (is_nvspace (c)); + + if (saw_NUL) + cpp_error (pfile, CPP_DL_WARNING, "null character(s) ignored"); + + buffer->cur--; +} + +/* See if the characters of a number token are valid in a name (no + '.', '+' or '-'). */ +static int +name_p (cpp_reader *pfile, const cpp_string *string) +{ + unsigned int i; + + for (i = 0; i < string->len; i++) + if (!is_idchar (string->text[i])) + return 0; + + return 1; +} + +/* After parsing an identifier or other sequence, produce a warning about + sequences not in NFC/NFKC. */ +static void +warn_about_normalization (cpp_reader *pfile, + const cpp_token *token, + const struct normalize_state *s) +{ + if (CPP_OPTION (pfile, warn_normalize) < NORMALIZE_STATE_RESULT (s) + && !pfile->state.skipping) + { + /* Make sure that the token is printed using UCNs, even + if we'd otherwise happily print UTF-8. */ + unsigned char *buf = XNEWVEC (unsigned char, cpp_token_len (token)); + size_t sz; + + sz = cpp_spell_token (pfile, token, buf, false) - buf; + if (NORMALIZE_STATE_RESULT (s) == normalized_C) + cpp_error_with_line (pfile, CPP_DL_WARNING, token->src_loc, 0, + "`%.*s' is not in NFKC", (int) sz, buf); + else + cpp_error_with_line (pfile, CPP_DL_WARNING, token->src_loc, 0, + "`%.*s' is not in NFC", (int) sz, buf); + } +} + +/* Returns TRUE if the sequence starting at buffer->cur is invalid in + an identifier. FIRST is TRUE if this starts an identifier. */ +static bool +forms_identifier_p (cpp_reader *pfile, int first, + struct normalize_state *state) +{ + cpp_buffer *buffer = pfile->buffer; + + if (*buffer->cur == '$') + { + if (!CPP_OPTION (pfile, dollars_in_ident)) + return false; + + buffer->cur++; + if (CPP_OPTION (pfile, warn_dollars) && !pfile->state.skipping) + { + CPP_OPTION (pfile, warn_dollars) = 0; + cpp_error (pfile, CPP_DL_PEDWARN, "'$' in identifier or number"); + } + + return true; + } + + /* Is this a syntactically valid UCN? */ + if (CPP_OPTION (pfile, extended_identifiers) + && *buffer->cur == '\\' + && (buffer->cur[1] == 'u' || buffer->cur[1] == 'U')) + { + buffer->cur += 2; + if (_cpp_valid_ucn (pfile, &buffer->cur, buffer->rlimit, 1 + !first, + state)) + return true; + buffer->cur -= 2; + } + + return false; +} + +/* Lex an identifier starting at BUFFER->CUR - 1. */ +static cpp_hashnode * +lex_identifier (cpp_reader *pfile, const uchar *base, bool starts_ucn, + struct normalize_state *nst) +{ + cpp_hashnode *result; + const uchar *cur; + unsigned int len; + unsigned int hash = HT_HASHSTEP (0, *base); + + cur = pfile->buffer->cur; + if (! starts_ucn) + while (ISIDNUM (*cur)) + { + hash = HT_HASHSTEP (hash, *cur); + cur++; + } + pfile->buffer->cur = cur; + if (starts_ucn || forms_identifier_p (pfile, false, nst)) + { + /* Slower version for identifiers containing UCNs (or $). */ + do { + while (ISIDNUM (*pfile->buffer->cur)) + { + pfile->buffer->cur++; + NORMALIZE_STATE_UPDATE_IDNUM (nst); + } + } while (forms_identifier_p (pfile, false, nst)); + result = _cpp_interpret_identifier (pfile, base, + pfile->buffer->cur - base); + } + else + { + len = cur - base; + hash = HT_HASHFINISH (hash, len); + + result = (cpp_hashnode *) + ht_lookup_with_hash (pfile->hash_table, base, len, hash, HT_ALLOC); + } + + /* Rarely, identifiers require diagnostics when lexed. */ + if (__builtin_expect ((result->flags & NODE_DIAGNOSTIC) + && !pfile->state.skipping, 0)) + { + /* It is allowed to poison the same identifier twice. */ + if ((result->flags & NODE_POISONED) && !pfile->state.poisoned_ok) + cpp_error (pfile, CPP_DL_ERROR, "attempt to use poisoned \"%s\"", + NODE_NAME (result)); + + /* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the + replacement list of a variadic macro. */ + if (result == pfile->spec_nodes.n__VA_ARGS__ + && !pfile->state.va_args_ok) + cpp_error (pfile, CPP_DL_PEDWARN, + "__VA_ARGS__ can only appear in the expansion" + " of a C99 variadic macro"); + } + + return result; +} + +/* SDCC specific */ +/* Pedantic parse a number, beginning with character C, skipping embedded + backslash-newlines. LEADING_PERIOD is nonzero if there was a "." + before C. Place the result in NUMBER. */ +static void +pedantic_lex_number (cpp_reader *pfile, cpp_string *number) +{ +#define get_effective_char(pfile) (*pfile->buffer->cur++) +#define BACKUP() (--pfile->buffer->cur) + + enum num_type_e { NT_DEC, NT_HEX } num_type = NT_DEC; + enum num_part_e { NP_WHOLE, NP_FRACT, NP_EXP, NP_INT_SUFFIX, NP_FLOAT_SUFFIX } num_part = NP_WHOLE; + + uchar c = *(pfile->buffer->cur - 1); + struct obstack *stack = &pfile->hash_table->stack; + cpp_buffer *buffer = pfile->buffer; + int len = 0; + int has_whole = 0; + int has_fract = 0; + + if ('.' == c) + { + num_part = NP_FRACT; + ++len; + obstack_1grow (stack, '.'); + c = get_effective_char(pfile); + } + else + { + if ('0' == c) + { + has_whole = 1; + ++len; + obstack_1grow (stack, c); + c = get_effective_char(pfile); + + switch (c) + { + case 'X': + case 'x': + num_type = NT_HEX; + ++len; + obstack_1grow (stack, c); + c = get_effective_char(pfile); + break; + + case '.': + num_part = NP_FRACT; + ++len; + obstack_1grow (stack, c); + c = get_effective_char(pfile); + break; + } + } + } + + for (; ; ) + { + switch (num_part) + { + case NP_WHOLE: + if (NT_DEC == num_type) + { + while (ISDIGIT (c)) + { + has_whole = 1; + ++len; + obstack_1grow (stack, c); + c = get_effective_char(pfile); + } + + if ('.' == c) + { + num_part = NP_FRACT; + ++len; + obstack_1grow (stack, c); + c = get_effective_char(pfile); + continue; + } + else if ('E' == c || 'e' == c) + { + if (has_whole || has_fract) + { + num_part = NP_EXP; + ++len; + obstack_1grow (stack, c); + c = get_effective_char(pfile); + continue; + } + else + break; + } + } + else + { + while (ISXDIGIT (c)) + { + has_whole = 1; + ++len; + obstack_1grow (stack, c); + c = get_effective_char(pfile); + } + + if ('.' == c) + { + num_part = NP_FRACT; + ++len; + obstack_1grow (stack, c); + c = get_effective_char(pfile); + continue; + } + else if ('P' == c || 'p' == c) + { + if (has_whole || has_fract) + { + num_part = NP_EXP; + ++len; + obstack_1grow (stack, c); + c = get_effective_char(pfile); + continue; + } + else + break; + } + } + num_part = NP_INT_SUFFIX; + continue; + + case NP_FRACT: + if (NT_DEC == num_type) + { + while (ISDIGIT (c)) + { + has_fract = 1; + ++len; + obstack_1grow (stack, c); + c = get_effective_char(pfile); + } + + if ('E' == c || 'e' == c) + { + if (has_whole || has_fract) + { + num_part = NP_EXP; + ++len; + obstack_1grow (stack, c); + c = get_effective_char(pfile); + continue; + } + } + } + else + { + while (ISXDIGIT (c)) + { + has_fract = 1; + ++len; + obstack_1grow (stack, c); + c = get_effective_char(pfile); + } + + if ('P' == c || 'p' == c) + { + if (has_whole || has_fract) + { + num_part = NP_EXP; + ++len; + obstack_1grow (stack, c); + c = get_effective_char(pfile); + continue; + } + } + } + num_part = NP_FLOAT_SUFFIX; + continue; + + case NP_EXP: + if ('+' == c || '-' == c) + { + ++len; + obstack_1grow (stack, c); + c = get_effective_char(pfile); + } + + while (ISDIGIT (c)) + { + ++len; + obstack_1grow (stack, c); + c = get_effective_char(pfile); + } + + num_part = NP_FLOAT_SUFFIX; + continue; + + case NP_INT_SUFFIX: + if ('L' == c || 'l' == c) + { + uchar prevc = c; + + ++len; + obstack_1grow (stack, c); + c = get_effective_char(pfile); + + if (c == prevc) + { + ++len; + obstack_1grow (stack, c); + c = get_effective_char(pfile); + } + } + else if ('U' == c || 'u' == c) + { + ++len; + obstack_1grow (stack, c); + c = get_effective_char(pfile); + } + break; + + case NP_FLOAT_SUFFIX: + if ('F' == c || 'f' == c) + { + ++len; + obstack_1grow (stack, c); + c = get_effective_char(pfile); + } + else if ('L' == c || 'l' == c) + { + ++len; + obstack_1grow (stack, c); + c = get_effective_char(pfile); + } + break; + } + break; + } + + /* Step back over the unwanted char. */ + BACKUP (); + + number->text = obstack_finish (stack); + number->len = len; +} + +/* Lex a number to NUMBER starting at BUFFER->CUR - 1. */ +static void +lex_number (cpp_reader *pfile, cpp_string *number, + struct normalize_state *nst) +{ + const uchar *cur; + const uchar *base; + uchar *dest; + + base = pfile->buffer->cur - 1; + do + { + cur = pfile->buffer->cur; + + /* N.B. ISIDNUM does not include $. */ + while (ISIDNUM (*cur) || *cur == '.' || VALID_SIGN (*cur, cur[-1])) + { + cur++; + NORMALIZE_STATE_UPDATE_IDNUM (nst); + } + + pfile->buffer->cur = cur; + } + while (forms_identifier_p (pfile, false, nst)); + + number->len = cur - base; + dest = _cpp_unaligned_alloc (pfile, number->len + 1); + memcpy (dest, base, number->len); + dest[number->len] = '\0'; + number->text = dest; +} + +/* Create a token of type TYPE with a literal spelling. */ +static void +create_literal (cpp_reader *pfile, cpp_token *token, const uchar *base, + unsigned int len, enum cpp_ttype type) +{ + uchar *dest = _cpp_unaligned_alloc (pfile, len + 1); + + memcpy (dest, base, len); + dest[len] = '\0'; + token->type = type; + token->val.str.len = len; + token->val.str.text = dest; +} + +/* Lexes a string, character constant, or angle-bracketed header file + name. The stored string contains the spelling, including opening + quote and leading any leading 'L'. It returns the type of the + literal, or CPP_OTHER if it was not properly terminated. + + The spelling is NUL-terminated, but it is not guaranteed that this + is the first NUL since embedded NULs are preserved. */ +static void +lex_string (cpp_reader *pfile, cpp_token *token, const uchar *base) +{ + bool saw_NUL = false; + const uchar *cur; + cppchar_t terminator; + enum cpp_ttype type; + + cur = base; + terminator = *cur++; + if (terminator == 'L') + terminator = *cur++; + if (terminator == '\"') + type = *base == 'L' ? CPP_WSTRING: CPP_STRING; + else if (terminator == '\'') + type = *base == 'L' ? CPP_WCHAR: CPP_CHAR; + else + terminator = '>', type = CPP_HEADER_NAME; + + for (;;) + { + cppchar_t c = *cur++; + + /* In #include-style directives, terminators are not escapable. */ + if (c == '\\' && !pfile->state.angled_headers && *cur != '\n') + cur++; + else if (c == terminator) + break; + else if (c == '\n') + { + cur--; + type = CPP_OTHER; + break; + } + else if (c == '\0') + saw_NUL = true; + } + + if (saw_NUL && !pfile->state.skipping) + cpp_error (pfile, CPP_DL_WARNING, + "null character(s) preserved in literal"); + + pfile->buffer->cur = cur; + create_literal (pfile, token, base, cur - base, type); +} + +/* Fixed _WIN32 problem with CR-CR-LF sequences when outputting + comment blocks (when executed with -C option) and + _asm (SDCPP specific) blocks */ + +/* Count and copy characters from src to dest, excluding CRs: + CRs are automatically generated, because the output is + opened in TEXT mode. If dest == NULL, only count chars */ +static unsigned int +copy_text_chars (char *dest, const char *src, unsigned int len) +{ + unsigned int n = 0; + const char *p; + + for (p = src; p != src + len; ++p) + { + assert(*p != '\0'); + + if (*p != '\r') + { + if (dest != NULL) + *dest++ = *p; + ++n; + } + } + + return n; +} + +/* SDCC _asm specific */ +/* The stored comment includes the comment start and any terminator. */ +static void +save_asm (cpp_reader *pfile, cpp_token *token, const unsigned char *from) +{ +#define _ASM_STR "_asm" +#define _ASM_LEN ((sizeof _ASM_STR) - 1) + + unsigned char *buffer; + unsigned int text_len, len; + + len = pfile->buffer->cur - from; + /* + _ASM_LEN for the initial '_asm'. */ + text_len = copy_text_chars (NULL, from, len) + _ASM_LEN; + buffer = _cpp_unaligned_alloc (pfile, text_len); + + + token->type = CPP_ASM; + token->val.str.len = text_len; + token->val.str.text = buffer; + + memcpy (buffer, _ASM_STR, _ASM_LEN); + copy_text_chars (buffer + _ASM_LEN, from, len); +} + +/* The stored comment includes the comment start and any terminator. */ +static void +save_comment (cpp_reader *pfile, cpp_token *token, const unsigned char *from, + cppchar_t type) +{ + unsigned char *buffer; + unsigned int len, clen; + + len = pfile->buffer->cur - from + 1; /* + 1 for the initial '/'. */ + + /* C++ comments probably (not definitely) have moved past a new + line, which we don't want to save in the comment. */ + if (is_vspace (pfile->buffer->cur[-1])) + len--; + + /* If we are currently in a directive, then we need to store all + C++ comments as C comments internally, and so we need to + allocate a little extra space in that case. + + Note that the only time we encounter a directive here is + when we are saving comments in a "#define". */ + clen = (pfile->state.in_directive && type == '/') ? len + 2 : len; + + buffer = _cpp_unaligned_alloc (pfile, clen); + + token->type = CPP_COMMENT; + token->val.str.len = clen; + token->val.str.text = buffer; + + buffer[0] = '/'; + copy_text_chars (buffer + 1, from, len); + + /* Finish conversion to a C comment, if necessary. */ + if (pfile->state.in_directive && type == '/') + { + buffer[1] = '*'; + buffer[clen - 2] = '*'; + buffer[clen - 1] = '/'; + } +} + +/* Allocate COUNT tokens for RUN. */ +void +_cpp_init_tokenrun (tokenrun *run, unsigned int count) +{ + run->base = XNEWVEC (cpp_token, count); + run->limit = run->base + count; + run->next = NULL; +} + +/* Returns the next tokenrun, or creates one if there is none. */ +static tokenrun * +next_tokenrun (tokenrun *run) +{ + if (run->next == NULL) + { + run->next = XNEW (tokenrun); + run->next->prev = run; + _cpp_init_tokenrun (run->next, 250); + } + + return run->next; +} + +/* Allocate a single token that is invalidated at the same time as the + rest of the tokens on the line. Has its line and col set to the + same as the last lexed token, so that diagnostics appear in the + right place. */ +cpp_token * +_cpp_temp_token (cpp_reader *pfile) +{ + cpp_token *old, *result; + + old = pfile->cur_token - 1; + if (pfile->cur_token == pfile->cur_run->limit) + { + pfile->cur_run = next_tokenrun (pfile->cur_run); + pfile->cur_token = pfile->cur_run->base; + } + + result = pfile->cur_token++; + result->src_loc = old->src_loc; + return result; +} + +/* Lex a token into RESULT (external interface). Takes care of issues + like directive handling, token lookahead, multiple include + optimization and skipping. */ +const cpp_token * +_cpp_lex_token (cpp_reader *pfile) +{ + cpp_token *result; + + for (;;) + { + if (pfile->cur_token == pfile->cur_run->limit) + { + pfile->cur_run = next_tokenrun (pfile->cur_run); + pfile->cur_token = pfile->cur_run->base; + } + + if (pfile->lookaheads) + { + pfile->lookaheads--; + result = pfile->cur_token++; + } + else + result = _cpp_lex_direct (pfile); + + if (result->flags & BOL) + { + /* Is this a directive. If _cpp_handle_directive returns + false, it is an assembler #. */ + if (result->type == CPP_HASH + /* 6.10.3 p 11: Directives in a list of macro arguments + gives undefined behavior. This implementation + handles the directive as normal. */ + && pfile->state.parsing_args != 1 + && _cpp_handle_directive (pfile, result->flags & PREV_WHITE)) + { + if (pfile->directive_result.type == CPP_PADDING) + continue; + else + { + result = &pfile->directive_result; + break; + } + } + + if (pfile->cb.line_change && !pfile->state.skipping) + pfile->cb.line_change (pfile, result, pfile->state.parsing_args); + } + + /* We don't skip tokens in directives. */ + if (pfile->state.in_directive) + break; + + /* Outside a directive, invalidate controlling macros. At file + EOF, _cpp_lex_direct takes care of popping the buffer, so we never + get here and MI optimization works. */ + pfile->mi_valid = false; + + if (!pfile->state.skipping || result->type == CPP_EOF) + break; + } + + return result; +} + +/* Returns true if a fresh line has been loaded. */ +bool +_cpp_get_fresh_line (cpp_reader *pfile) +{ + int return_at_eof; + + /* We can't get a new line until we leave the current directive. */ + if (pfile->state.in_directive) + return false; + + for (;;) + { + cpp_buffer *buffer = pfile->buffer; + + if (!buffer->need_line) + return true; + + if (buffer->next_line < buffer->rlimit) + { + _cpp_clean_line (pfile); + return true; + } + + /* First, get out of parsing arguments state. */ + if (pfile->state.parsing_args) + return false; + + /* End of buffer. Non-empty files should end in a newline. */ + if (buffer->buf != buffer->rlimit + && buffer->next_line > buffer->rlimit + && !buffer->from_stage3) + { + /* Only warn once. */ + buffer->next_line = buffer->rlimit; + cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->line_table->highest_line, + CPP_BUF_COLUMN (buffer, buffer->cur), + "no newline at end of file"); + } + + return_at_eof = buffer->return_at_eof; + _cpp_pop_buffer (pfile); + if (pfile->buffer == NULL || return_at_eof) + return false; + } +} + +#define IF_NEXT_IS(CHAR, THEN_TYPE, ELSE_TYPE) \ + do \ + { \ + result->type = ELSE_TYPE; \ + if (*buffer->cur == CHAR) \ + buffer->cur++, result->type = THEN_TYPE; \ + } \ + while (0) + +/* Lex a token into pfile->cur_token, which is also incremented, to + get diagnostics pointing to the correct location. + + Does not handle issues such as token lookahead, multiple-include + optimization, directives, skipping etc. This function is only + suitable for use by _cpp_lex_token, and in special cases like + lex_expansion_token which doesn't care for any of these issues. + + When meeting a newline, returns CPP_EOF if parsing a directive, + otherwise returns to the start of the token buffer if permissible. + Returns the location of the lexed token. */ +cpp_token * +_cpp_lex_direct (cpp_reader *pfile) +{ + cppchar_t c; + cpp_buffer *buffer; + const unsigned char *comment_start; + cpp_token *result = pfile->cur_token++; + + fresh_line: + result->flags = 0; + buffer = pfile->buffer; + if (buffer->need_line) + { + if (!_cpp_get_fresh_line (pfile)) + { + result->type = CPP_EOF; + if (!pfile->state.in_directive) + { + /* Tell the compiler the line number of the EOF token. */ + result->src_loc = pfile->line_table->highest_line; + result->flags = BOL; + } + return result; + } + if (!pfile->keep_tokens) + { + pfile->cur_run = &pfile->base_run; + result = pfile->base_run.base; + pfile->cur_token = result + 1; + } + result->flags = BOL; + if (pfile->state.parsing_args == 2) + result->flags |= PREV_WHITE; + } + buffer = pfile->buffer; + update_tokens_line: + result->src_loc = pfile->line_table->highest_line; + + skipped_white: + if (buffer->cur >= buffer->notes[buffer->cur_note].pos + && !pfile->overlaid_buffer) + { + _cpp_process_line_notes (pfile, false); + result->src_loc = pfile->line_table->highest_line; + } + c = *buffer->cur++; + + LINEMAP_POSITION_FOR_COLUMN (result->src_loc, pfile->line_table, + CPP_BUF_COLUMN (buffer, buffer->cur)); + + switch (c) + { + case ' ': case '\t': case '\f': case '\v': case '\0': + result->flags |= PREV_WHITE; + skip_whitespace (pfile, c); + goto skipped_white; + + case '\n': + if (buffer->cur < buffer->rlimit) + CPP_INCREMENT_LINE (pfile, 0); + buffer->need_line = true; + goto fresh_line; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + struct normalize_state nst = INITIAL_NORMALIZE_STATE; + result->type = CPP_NUMBER; + if (CPP_OPTION(pfile, pedantic_parse_number)) + pedantic_lex_number (pfile, &result->val.str); + else + lex_number (pfile, &result->val.str, &nst); + warn_about_normalization (pfile, result, &nst); + break; + } + + case 'L': + /* 'L' may introduce wide characters or strings. */ + if (*buffer->cur == '\'' || *buffer->cur == '"') + { + lex_string (pfile, result, buffer->cur - 1); + break; + } + /* Fall through. */ + + case '_': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': + case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': + case 's': case 't': case 'u': case 'v': case 'w': case 'x': + case 'y': case 'z': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + case 'G': case 'H': case 'I': case 'J': case 'K': + case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': + case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': + result->type = CPP_NAME; + { + struct normalize_state nst = INITIAL_NORMALIZE_STATE; + result->val.node = lex_identifier (pfile, buffer->cur - 1, false, + &nst); + warn_about_normalization (pfile, result, &nst); + } + + /* SDCC _asm specific */ + /* handle _asm ... _endasm ; */ + if (CPP_OPTION(pfile, preproc_asm) == 0 && result->val.node == pfile->spec_nodes.n__asm) + { + comment_start = buffer->cur; + result->type = CPP_ASM; + skip_asm_block (pfile); + /* Save the _asm block as a token in its own right. */ + save_asm (pfile, result, comment_start); + } + /* Convert named operators to their proper types. */ + else if (result->val.node->flags & NODE_OPERATOR) + { + result->flags |= NAMED_OP; + result->type = (enum cpp_ttype) result->val.node->directive_index; + } + break; + + case '\'': + case '"': + lex_string (pfile, result, buffer->cur - 1); + break; + + case '/': + /* A potential block or line comment. */ + comment_start = buffer->cur; + c = *buffer->cur; + + if (c == '*') + { + if (_cpp_skip_block_comment (pfile)) + cpp_error (pfile, CPP_DL_ERROR, "unterminated comment"); + } + else if (c == '/' && (CPP_OPTION (pfile, cplusplus_comments) + || cpp_in_system_header (pfile))) + { + /* Warn about comments only if pedantically GNUC89, and not + in system headers. */ + if (CPP_OPTION (pfile, lang) == CLK_GNUC89 && CPP_PEDANTIC (pfile) + && ! buffer->warned_cplusplus_comments) + { + cpp_error (pfile, CPP_DL_PEDWARN, + "C++ style comments are not allowed in ISO C90"); + cpp_error (pfile, CPP_DL_PEDWARN, + "(this will be reported only once per input file)"); + buffer->warned_cplusplus_comments = 1; + } + + if (skip_line_comment (pfile) && CPP_OPTION (pfile, warn_comments)) + cpp_error (pfile, CPP_DL_WARNING, "multi-line comment"); + } + else if (c == '=') + { + buffer->cur++; + result->type = CPP_DIV_EQ; + break; + } + else + { + result->type = CPP_DIV; + break; + } + + if (!pfile->state.save_comments) + { + result->flags |= PREV_WHITE; + goto update_tokens_line; + } + + /* Save the comment as a token in its own right. */ + save_comment (pfile, result, comment_start, c); + break; + + case '<': + if (pfile->state.angled_headers) + { + lex_string (pfile, result, buffer->cur - 1); + break; + } + + result->type = CPP_LESS; + if (*buffer->cur == '=') + buffer->cur++, result->type = CPP_LESS_EQ; + else if (*buffer->cur == '<') + { + buffer->cur++; + IF_NEXT_IS ('=', CPP_LSHIFT_EQ, CPP_LSHIFT); + } + else if (*buffer->cur == '?' && CPP_OPTION (pfile, cplusplus)) + { + buffer->cur++; + IF_NEXT_IS ('=', CPP_MIN_EQ, CPP_MIN); + } + else if (CPP_OPTION (pfile, digraphs)) + { + if (*buffer->cur == ':') + { + buffer->cur++; + result->flags |= DIGRAPH; + result->type = CPP_OPEN_SQUARE; + } + else if (*buffer->cur == '%') + { + buffer->cur++; + result->flags |= DIGRAPH; + result->type = CPP_OPEN_BRACE; + } + } + break; + + case '>': + result->type = CPP_GREATER; + if (*buffer->cur == '=') + buffer->cur++, result->type = CPP_GREATER_EQ; + else if (*buffer->cur == '>') + { + buffer->cur++; + IF_NEXT_IS ('=', CPP_RSHIFT_EQ, CPP_RSHIFT); + } + else if (*buffer->cur == '?' && CPP_OPTION (pfile, cplusplus)) + { + buffer->cur++; + IF_NEXT_IS ('=', CPP_MAX_EQ, CPP_MAX); + } + break; + + case '%': + result->type = CPP_MOD; + if (*buffer->cur == '=') + buffer->cur++, result->type = CPP_MOD_EQ; + else if (CPP_OPTION (pfile, digraphs)) + { + if (*buffer->cur == ':') + { + buffer->cur++; + result->flags |= DIGRAPH; + result->type = CPP_HASH; + if (*buffer->cur == '%' && buffer->cur[1] == ':') + buffer->cur += 2, result->type = CPP_PASTE; + } + else if (*buffer->cur == '>') + { + buffer->cur++; + result->flags |= DIGRAPH; + result->type = CPP_CLOSE_BRACE; + } + } + break; + + case '.': + result->type = CPP_DOT; + if (ISDIGIT (*buffer->cur)) + { + struct normalize_state nst = INITIAL_NORMALIZE_STATE; + result->type = CPP_NUMBER; + if (CPP_OPTION(pfile, pedantic_parse_number)) + pedantic_lex_number (pfile, &result->val.str); + else + lex_number (pfile, &result->val.str, &nst); + warn_about_normalization (pfile, result, &nst); + } + else if (*buffer->cur == '.' && buffer->cur[1] == '.') + buffer->cur += 2, result->type = CPP_ELLIPSIS; + else if (*buffer->cur == '*' && CPP_OPTION (pfile, cplusplus)) + buffer->cur++, result->type = CPP_DOT_STAR; + break; + + case '+': + result->type = CPP_PLUS; + if (*buffer->cur == '+') + buffer->cur++, result->type = CPP_PLUS_PLUS; + else if (*buffer->cur == '=') + buffer->cur++, result->type = CPP_PLUS_EQ; + break; + + case '-': + result->type = CPP_MINUS; + if (*buffer->cur == '>') + { + buffer->cur++; + result->type = CPP_DEREF; + if (*buffer->cur == '*' && CPP_OPTION (pfile, cplusplus)) + buffer->cur++, result->type = CPP_DEREF_STAR; + } + else if (*buffer->cur == '-') + buffer->cur++, result->type = CPP_MINUS_MINUS; + else if (*buffer->cur == '=') + buffer->cur++, result->type = CPP_MINUS_EQ; + break; + + case '&': + result->type = CPP_AND; + if (*buffer->cur == '&') + buffer->cur++, result->type = CPP_AND_AND; + else if (*buffer->cur == '=') + buffer->cur++, result->type = CPP_AND_EQ; + break; + + case '|': + result->type = CPP_OR; + if (*buffer->cur == '|') + buffer->cur++, result->type = CPP_OR_OR; + else if (*buffer->cur == '=') + buffer->cur++, result->type = CPP_OR_EQ; + break; + + case ':': + result->type = CPP_COLON; + if (*buffer->cur == ':' && CPP_OPTION (pfile, cplusplus)) + buffer->cur++, result->type = CPP_SCOPE; + else if (*buffer->cur == '>' && CPP_OPTION (pfile, digraphs)) + { + buffer->cur++; + result->flags |= DIGRAPH; + result->type = CPP_CLOSE_SQUARE; + } + break; + + case '*': IF_NEXT_IS ('=', CPP_MULT_EQ, CPP_MULT); break; + case '=': IF_NEXT_IS ('=', CPP_EQ_EQ, CPP_EQ); break; + case '!': IF_NEXT_IS ('=', CPP_NOT_EQ, CPP_NOT); break; + case '^': IF_NEXT_IS ('=', CPP_XOR_EQ, CPP_XOR); break; + case '#': IF_NEXT_IS ('#', CPP_PASTE, CPP_HASH); break; + + case '?': result->type = CPP_QUERY; break; + case '~': result->type = CPP_COMPL; break; + case ',': result->type = CPP_COMMA; break; + case '(': result->type = CPP_OPEN_PAREN; break; + case ')': result->type = CPP_CLOSE_PAREN; break; + case '[': result->type = CPP_OPEN_SQUARE; break; + case ']': result->type = CPP_CLOSE_SQUARE; break; + case '{': result->type = CPP_OPEN_BRACE; break; + case '}': result->type = CPP_CLOSE_BRACE; break; + case ';': result->type = CPP_SEMICOLON; break; + + /* @ is a punctuator in Objective-C. */ + case '@': result->type = CPP_ATSIGN; break; + + case '$': + case '\\': + { + const uchar *base = --buffer->cur; + struct normalize_state nst = INITIAL_NORMALIZE_STATE; + + if (forms_identifier_p (pfile, true, &nst)) + { + result->type = CPP_NAME; + result->val.node = lex_identifier (pfile, base, true, &nst); + warn_about_normalization (pfile, result, &nst); + break; + } + buffer->cur++; + } + + default: + create_literal (pfile, result, buffer->cur - 1, 1, CPP_OTHER); + break; + } + + return result; +} + +/* An upper bound on the number of bytes needed to spell TOKEN. + Does not include preceding whitespace. */ +unsigned int +cpp_token_len (const cpp_token *token) +{ + unsigned int len; + + switch (TOKEN_SPELL (token)) + { + default: len = 4; break; + case SPELL_LITERAL: len = token->val.str.len; break; + case SPELL_IDENT: len = NODE_LEN (token->val.node) * 10; break; + } + + return len; +} + +/* Parse UTF-8 out of NAMEP and place a \U escape in BUFFER. + Return the number of bytes read out of NAME. (There are always + 10 bytes written to BUFFER.) */ + +static size_t +utf8_to_ucn (unsigned char *buffer, const unsigned char *name) +{ + int j; + int ucn_len = 0; + int ucn_len_c; + unsigned t; + unsigned long utf32; + + /* Compute the length of the UTF-8 sequence. */ + for (t = *name; t & 0x80; t <<= 1) + ucn_len++; + + utf32 = *name & (0x7F >> ucn_len); + for (ucn_len_c = 1; ucn_len_c < ucn_len; ucn_len_c++) + { + utf32 = (utf32 << 6) | (*++name & 0x3F); + + /* Ill-formed UTF-8. */ + if ((*name & ~0x3F) != 0x80) + abort (); + } + + *buffer++ = '\\'; + *buffer++ = 'U'; + for (j = 7; j >= 0; j--) + *buffer++ = "0123456789abcdef"[(utf32 >> (4 * j)) & 0xF]; + return ucn_len; +} + + +/* Write the spelling of a token TOKEN to BUFFER. The buffer must + already contain the enough space to hold the token's spelling. + Returns a pointer to the character after the last character written. + FORSTRING is true if this is to be the spelling after translation + phase 1 (this is different for UCNs). + FIXME: Would be nice if we didn't need the PFILE argument. */ +unsigned char * +cpp_spell_token (cpp_reader *pfile, const cpp_token *token, + unsigned char *buffer, bool forstring) +{ + switch (TOKEN_SPELL (token)) + { + case SPELL_OPERATOR: + { + const unsigned char *spelling; + unsigned char c; + + if (token->flags & DIGRAPH) + spelling + = digraph_spellings[(int) token->type - (int) CPP_FIRST_DIGRAPH]; + else if (token->flags & NAMED_OP) + goto spell_ident; + else + spelling = TOKEN_NAME (token); + + while ((c = *spelling++) != '\0') + *buffer++ = c; + } + break; + + spell_ident: + case SPELL_IDENT: + if (forstring) + { + memcpy (buffer, NODE_NAME (token->val.node), + NODE_LEN (token->val.node)); + buffer += NODE_LEN (token->val.node); + } + else + { + size_t i; + const unsigned char * name = NODE_NAME (token->val.node); + + for (i = 0; i < NODE_LEN (token->val.node); i++) + if (name[i] & ~0x7F) + { + i += utf8_to_ucn (buffer, name + i) - 1; + buffer += 10; + } + else + *buffer++ = NODE_NAME (token->val.node)[i]; + } + break; + + case SPELL_LITERAL: + memcpy (buffer, token->val.str.text, token->val.str.len); + buffer += token->val.str.len; + break; + + case SPELL_NONE: + cpp_error (pfile, CPP_DL_ICE, + "unspellable token %s", TOKEN_NAME (token)); + break; + } + + return buffer; +} + +/* Returns TOKEN spelt as a null-terminated string. The string is + freed when the reader is destroyed. Useful for diagnostics. */ +unsigned char * +cpp_token_as_text (cpp_reader *pfile, const cpp_token *token) +{ + unsigned int len = cpp_token_len (token) + 1; + unsigned char *start = _cpp_unaligned_alloc (pfile, len), *end; + + end = cpp_spell_token (pfile, token, start, false); + end[0] = '\0'; + + return start; +} + +/* Used by C front ends, which really should move to using + cpp_token_as_text. */ +const char * +cpp_type2name (enum cpp_ttype type) +{ + return (const char *) token_spellings[type].name; +} + +/* Writes the spelling of token to FP, without any preceding space. + Separated from cpp_spell_token for efficiency - to avoid stdio + double-buffering. */ +void +cpp_output_token (const cpp_token *token, FILE *fp) +{ + switch (TOKEN_SPELL (token)) + { + case SPELL_OPERATOR: + { + const unsigned char *spelling; + int c; + + if (token->flags & DIGRAPH) + spelling + = digraph_spellings[(int) token->type - (int) CPP_FIRST_DIGRAPH]; + else if (token->flags & NAMED_OP) + goto spell_ident; + else + spelling = TOKEN_NAME (token); + + c = *spelling; + do + putc (c, fp); + while ((c = *++spelling) != '\0'); + } + break; + + spell_ident: + case SPELL_IDENT: + { + size_t i; + const unsigned char * name = NODE_NAME (token->val.node); + + for (i = 0; i < NODE_LEN (token->val.node); i++) + if (name[i] & ~0x7F) + { + unsigned char buffer[10]; + i += utf8_to_ucn (buffer, name + i) - 1; + fwrite (buffer, 1, 10, fp); + } + else + fputc (NODE_NAME (token->val.node)[i], fp); + } + break; + + case SPELL_LITERAL: + fwrite (token->val.str.text, 1, token->val.str.len, fp); + break; + + case SPELL_NONE: + /* An error, most probably. */ + break; + } +} + +/* Compare two tokens. */ +int +_cpp_equiv_tokens (const cpp_token *a, const cpp_token *b) +{ + if (a->type == b->type && a->flags == b->flags) + switch (TOKEN_SPELL (a)) + { + default: /* Keep compiler happy. */ + case SPELL_OPERATOR: + return 1; + case SPELL_NONE: + return (a->type != CPP_MACRO_ARG || a->val.arg_no == b->val.arg_no); + case SPELL_IDENT: + return a->val.node == b->val.node; + case SPELL_LITERAL: + return (a->val.str.len == b->val.str.len + && !memcmp (a->val.str.text, b->val.str.text, + a->val.str.len)); + } + + return 0; +} + +/* Returns nonzero if a space should be inserted to avoid an + accidental token paste for output. For simplicity, it is + conservative, and occasionally advises a space where one is not + needed, e.g. "." and ".2". */ +int +cpp_avoid_paste (cpp_reader *pfile, const cpp_token *token1, + const cpp_token *token2) +{ + enum cpp_ttype a = token1->type, b = token2->type; + cppchar_t c; + + if (token1->flags & NAMED_OP) + a = CPP_NAME; + if (token2->flags & NAMED_OP) + b = CPP_NAME; + + c = EOF; + if (token2->flags & DIGRAPH) + c = digraph_spellings[(int) b - (int) CPP_FIRST_DIGRAPH][0]; + else if (token_spellings[b].category == SPELL_OPERATOR) + c = token_spellings[b].name[0]; + + /* Quickly get everything that can paste with an '='. */ + if ((int) a <= (int) CPP_LAST_EQ && c == '=') + return 1; + + switch (a) + { + case CPP_GREATER: return c == '>' || c == '?'; + case CPP_LESS: return c == '<' || c == '?' || c == '%' || c == ':'; + case CPP_PLUS: return c == '+'; + case CPP_MINUS: return c == '-' || c == '>'; + case CPP_DIV: return c == '/' || c == '*'; /* Comments. */ + case CPP_MOD: return c == ':' || c == '>'; + case CPP_AND: return c == '&'; + case CPP_OR: return c == '|'; + case CPP_COLON: return c == ':' || c == '>'; + case CPP_DEREF: return c == '*'; + case CPP_DOT: return c == '.' || c == '%' || b == CPP_NUMBER; + case CPP_HASH: return c == '#' || c == '%'; /* Digraph form. */ + case CPP_NAME: return ((b == CPP_NUMBER + && name_p (pfile, &token2->val.str)) + || b == CPP_NAME + || b == CPP_CHAR || b == CPP_STRING); /* L */ + case CPP_NUMBER: return (b == CPP_NUMBER || b == CPP_NAME + || c == '.' || c == '+' || c == '-'); + /* UCNs */ + case CPP_OTHER: return ((token1->val.str.text[0] == '\\' + && b == CPP_NAME) + || (CPP_OPTION (pfile, objc) + && token1->val.str.text[0] == '@' + && (b == CPP_NAME || b == CPP_STRING))); + default: break; + } + + return 0; +} + +/* Output all the remaining tokens on the current line, and a newline + character, to FP. Leading whitespace is removed. If there are + macros, special token padding is not performed. */ +void +cpp_output_line (cpp_reader *pfile, FILE *fp) +{ + const cpp_token *token; + + token = cpp_get_token (pfile); + while (token->type != CPP_EOF) + { + cpp_output_token (token, fp); + token = cpp_get_token (pfile); + if (token->flags & PREV_WHITE) + putc (' ', fp); + } + + putc ('\n', fp); +} + +/* Memory buffers. Changing these three constants can have a dramatic + effect on performance. The values here are reasonable defaults, + but might be tuned. If you adjust them, be sure to test across a + range of uses of cpplib, including heavy nested function-like macro + expansion. Also check the change in peak memory usage (NJAMD is a + good tool for this). */ +#define MIN_BUFF_SIZE 8000 +#define BUFF_SIZE_UPPER_BOUND(MIN_SIZE) (MIN_BUFF_SIZE + (MIN_SIZE) * 3 / 2) +#define EXTENDED_BUFF_SIZE(BUFF, MIN_EXTRA) \ + (MIN_EXTRA + ((BUFF)->limit - (BUFF)->cur) * 2) + +#if MIN_BUFF_SIZE > BUFF_SIZE_UPPER_BOUND (0) + #error BUFF_SIZE_UPPER_BOUND must be at least as large as MIN_BUFF_SIZE! +#endif + +/* Create a new allocation buffer. Place the control block at the end + of the buffer, so that buffer overflows will cause immediate chaos. */ +static _cpp_buff * +new_buff (size_t len) +{ + _cpp_buff *result; + unsigned char *base; + + if (len < MIN_BUFF_SIZE) + len = MIN_BUFF_SIZE; + len = CPP_ALIGN (len); + + base = XNEWVEC (unsigned char, len + sizeof (_cpp_buff)); + result = (_cpp_buff *) (base + len); + result->base = base; + result->cur = base; + result->limit = base + len; + result->next = NULL; + return result; +} + +/* Place a chain of unwanted allocation buffers on the free list. */ +void +_cpp_release_buff (cpp_reader *pfile, _cpp_buff *buff) +{ + _cpp_buff *end = buff; + + while (end->next) + end = end->next; + end->next = pfile->free_buffs; + pfile->free_buffs = buff; +} + +/* Return a free buffer of size at least MIN_SIZE. */ +_cpp_buff * +_cpp_get_buff (cpp_reader *pfile, size_t min_size) +{ + _cpp_buff *result, **p; + + for (p = &pfile->free_buffs;; p = &(*p)->next) + { + size_t size; + + if (*p == NULL) + return new_buff (min_size); + result = *p; + size = result->limit - result->base; + /* Return a buffer that's big enough, but don't waste one that's + way too big. */ + if (size >= min_size && size <= BUFF_SIZE_UPPER_BOUND (min_size)) + break; + } + + *p = result->next; + result->next = NULL; + result->cur = result->base; + return result; +} + +/* Creates a new buffer with enough space to hold the uncommitted + remaining bytes of BUFF, and at least MIN_EXTRA more bytes. Copies + the excess bytes to the new buffer. Chains the new buffer after + BUFF, and returns the new buffer. */ +_cpp_buff * +_cpp_append_extend_buff (cpp_reader *pfile, _cpp_buff *buff, size_t min_extra) +{ + size_t size = EXTENDED_BUFF_SIZE (buff, min_extra); + _cpp_buff *new_buff = _cpp_get_buff (pfile, size); + + buff->next = new_buff; + memcpy (new_buff->base, buff->cur, BUFF_ROOM (buff)); + return new_buff; +} + +/* Creates a new buffer with enough space to hold the uncommitted + remaining bytes of the buffer pointed to by BUFF, and at least + MIN_EXTRA more bytes. Copies the excess bytes to the new buffer. + Chains the new buffer before the buffer pointed to by BUFF, and + updates the pointer to point to the new buffer. */ +void +_cpp_extend_buff (cpp_reader *pfile, _cpp_buff **pbuff, size_t min_extra) +{ + _cpp_buff *new_buff, *old_buff = *pbuff; + size_t size = EXTENDED_BUFF_SIZE (old_buff, min_extra); + + new_buff = _cpp_get_buff (pfile, size); + memcpy (new_buff->base, old_buff->cur, BUFF_ROOM (old_buff)); + new_buff->next = old_buff; + *pbuff = new_buff; +} + +/* Free a chain of buffers starting at BUFF. */ +void +_cpp_free_buff (_cpp_buff *buff) +{ + _cpp_buff *next; + + for (; buff; buff = next) + { + next = buff->next; + free (buff->base); + } +} + +/* Allocate permanent, unaligned storage of length LEN. */ +unsigned char * +_cpp_unaligned_alloc (cpp_reader *pfile, size_t len) +{ + _cpp_buff *buff = pfile->u_buff; + unsigned char *result = buff->cur; + + if (len > (size_t) (buff->limit - result)) + { + buff = _cpp_get_buff (pfile, len); + buff->next = pfile->u_buff; + pfile->u_buff = buff; + result = buff->cur; + } + + buff->cur = result + len; + return result; +} + +/* Allocate permanent, unaligned storage of length LEN from a_buff. + That buffer is used for growing allocations when saving macro + replacement lists in a #define, and when parsing an answer to an + assertion in #assert, #unassert or #if (and therefore possibly + whilst expanding macros). It therefore must not be used by any + code that they might call: specifically the lexer and the guts of + the macro expander. + + All existing other uses clearly fit this restriction: storing + registered pragmas during initialization. */ +unsigned char * +_cpp_aligned_alloc (cpp_reader *pfile, size_t len) +{ + _cpp_buff *buff = pfile->a_buff; + unsigned char *result = buff->cur; + + if (len > (size_t) (buff->limit - result)) + { + buff = _cpp_get_buff (pfile, len); + buff->next = pfile->a_buff; + pfile->a_buff = buff; + result = buff->cur; + } + + buff->cur = result + len; + return result; +} + +/* Say which field of TOK is in use. */ + +enum cpp_token_fld_kind +cpp_token_val_index (cpp_token *tok) +{ + switch (TOKEN_SPELL (tok)) + { + case SPELL_IDENT: + return CPP_TOKEN_FLD_NODE; + case SPELL_LITERAL: + return CPP_TOKEN_FLD_STR; + case SPELL_NONE: + if (tok->type == CPP_MACRO_ARG) + return CPP_TOKEN_FLD_ARG_NO; + else if (tok->type == CPP_PADDING) + return CPP_TOKEN_FLD_SOURCE; + else if (tok->type == CPP_PRAGMA) + return CPP_TOKEN_FLD_STR; + /* else fall through */ + default: + return CPP_TOKEN_FLD_NONE; + } +} diff --git a/support/cpp2/libcpp/line-map.c b/support/cpp2/libcpp/line-map.c new file mode 100644 index 00000000..c95eacde --- /dev/null +++ b/support/cpp2/libcpp/line-map.c @@ -0,0 +1,348 @@ +/* Map logical line numbers to (source file, line number) pairs. + Copyright (C) 2001, 2003, 2004 + Free Software Foundation, Inc. + +This program 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 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +#include "config.h" +#include "system.h" +#include "line-map.h" + +static void trace_include (const struct line_maps *, const struct line_map *); + +/* Initialize a line map set. */ + +void +linemap_init (struct line_maps *set) +{ + set->maps = NULL; + set->allocated = 0; + set->used = 0; + set->last_listed = -1; + set->trace_includes = false; + set->depth = 0; + set->cache = 0; + set->highest_location = 0; + set->highest_line = 0; + set->max_column_hint = 0; +} + +/* Check for and warn about line_maps entered but not exited. */ + +void +linemap_check_files_exited (struct line_maps *set) +{ + struct line_map *map; + /* Depending upon whether we are handling preprocessed input or + not, this can be a user error or an ICE. */ + for (map = &set->maps[set->used - 1]; ! MAIN_FILE_P (map); + map = INCLUDED_FROM (set, map)) + fprintf (stderr, "line-map.c: file \"%s\" entered but not left\n", + map->to_file); +} + +/* Free a line map set. */ + +void +linemap_free (struct line_maps *set) +{ + if (set->maps) + { + linemap_check_files_exited (set); + + free (set->maps); + } +} + +/* Add a mapping of logical source line to physical source file and + line number. + + The text pointed to by TO_FILE must have a lifetime + at least as long as the final call to lookup_line (). An empty + TO_FILE means standard input. If reason is LC_LEAVE, and + TO_FILE is NULL, then TO_FILE, TO_LINE and SYSP are given their + natural values considering the file we are returning to. + + FROM_LINE should be monotonic increasing across calls to this + function. A call to this function can relocate the previous set of + A call to this function can relocate the previous set of + maps, so any stored line_map pointers should not be used. */ + +const struct line_map * +linemap_add (struct line_maps *set, enum lc_reason reason, + unsigned int sysp, const char *to_file, unsigned int to_line) +{ + struct line_map *map; + source_location start_location = set->highest_location + 1; + + if (set->used && start_location < set->maps[set->used - 1].start_location) + abort (); + + if (set->used == set->allocated) + { + set->allocated = 2 * set->allocated + 256; + set->maps = XRESIZEVEC (struct line_map, set->maps, set->allocated); + } + + map = &set->maps[set->used]; + + if (to_file && *to_file == '\0') + to_file = ""; + + /* If we don't keep our line maps consistent, we can easily + segfault. Don't rely on the client to do it for us. */ + if (set->depth == 0) + reason = LC_ENTER; + else if (reason == LC_LEAVE) + { + struct line_map *from; + bool error; + + if (MAIN_FILE_P (map - 1)) + { + if (to_file == NULL) + { + set->depth--; + return NULL; + } + error = true; + reason = LC_RENAME; + from = map - 1; + } + else + { + from = INCLUDED_FROM (set, map - 1); + error = to_file && strcmp (from->to_file, to_file); + } + + /* Depending upon whether we are handling preprocessed input or + not, this can be a user error or an ICE. */ + if (error) + fprintf (stderr, "line-map.c: file \"%s\" left but not entered\n", + to_file); + + /* A TO_FILE of NULL is special - we use the natural values. */ + if (error || to_file == NULL) + { + to_file = from->to_file; + to_line = SOURCE_LINE (from, from[1].start_location); + sysp = from->sysp; + } + } + + map->reason = reason; + map->sysp = sysp; + map->start_location = start_location; + map->to_file = to_file; + map->to_line = to_line; + set->cache = set->used++; + map->column_bits = 0; + set->highest_location = start_location; + set->highest_line = start_location; + set->max_column_hint = 0; + + if (reason == LC_ENTER) + { + map->included_from = set->depth == 0 ? -1 : (int) (set->used - 2); + set->depth++; + if (set->trace_includes) + trace_include (set, map); + } + else if (reason == LC_RENAME) + map->included_from = map[-1].included_from; + else if (reason == LC_LEAVE) + { + set->depth--; + map->included_from = INCLUDED_FROM (set, map - 1)->included_from; + } + + return map; +} + +source_location +linemap_line_start (struct line_maps *set, unsigned int to_line, + unsigned int max_column_hint) +{ + struct line_map *map = &set->maps[set->used - 1]; + source_location highest = set->highest_location; + source_location r; + unsigned int last_line = SOURCE_LINE (map, set->highest_line); + int line_delta = to_line - last_line; + bool add_map = false; + if (line_delta < 0 + || (line_delta > 10 && line_delta * map->column_bits > 1000) + || (max_column_hint >= (1U << map->column_bits)) + || (max_column_hint <= 80 && map->column_bits >= 10)) + { + add_map = true; + } + else + max_column_hint = set->max_column_hint; + if (add_map) + { + int column_bits; + if (max_column_hint > 100000 || highest > 0xC0000000) + { + /* If the column number is ridiculous or we've allocated a huge + number of source_locations, give up on column numbers. */ + max_column_hint = 0; + if (highest >0xF0000000) + return 0; + column_bits = 0; + } + else + { + column_bits = 7; + while (max_column_hint >= (1U << column_bits)) + column_bits++; + max_column_hint = 1U << column_bits; + } + /* Allocate the new line_map. However, if the current map only has a + single line we can sometimes just increase its column_bits instead. */ + if (line_delta < 0 + || last_line != map->to_line + || SOURCE_COLUMN (map, highest) >= (1U << column_bits)) + map = (struct line_map*) linemap_add (set, LC_RENAME, map->sysp, + map->to_file, to_line); + map->column_bits = column_bits; + r = map->start_location + ((to_line - map->to_line) << column_bits); + } + else + r = highest - SOURCE_COLUMN (map, highest) + + (line_delta << map->column_bits); + set->highest_line = r; + if (r > set->highest_location) + set->highest_location = r; + set->max_column_hint = max_column_hint; + return r; +} + +source_location +linemap_position_for_column (struct line_maps *set, unsigned int to_column) +{ + source_location r = set->highest_line; + if (to_column >= set->max_column_hint) + { + if (r >= 0xC000000 || to_column > 100000) + { + /* Running low on source_locations - disable column numbers. */ + return r; + } + else + { + struct line_map *map = &set->maps[set->used - 1]; + r = linemap_line_start (set, SOURCE_LINE (map, r), to_column + 50); + } + } + r = r + to_column; + if (r >= set->highest_location) + set->highest_location = r; + return r; +} + +/* Given a logical line, returns the map from which the corresponding + (source file, line) pair can be deduced. Since the set is built + chronologically, the logical lines are monotonic increasing, and so + the list is sorted and we can use a binary search. */ + +const struct line_map * +linemap_lookup (struct line_maps *set, source_location line) +{ + unsigned int md, mn, mx; + const struct line_map *cached; + + mn = set->cache; + mx = set->used; + + cached = &set->maps[mn]; + /* We should get a segfault if no line_maps have been added yet. */ + if (line >= cached->start_location) + { + if (mn + 1 == mx || line < cached[1].start_location) + return cached; + } + else + { + mx = mn; + mn = 0; + } + + while (mx - mn > 1) + { + md = (mn + mx) / 2; + if (set->maps[md].start_location > line) + mx = md; + else + mn = md; + } + + set->cache = mn; + return &set->maps[mn]; +} + +/* Print the file names and line numbers of the #include commands + which led to the map MAP, if any, to stderr. Nothing is output if + the most recently listed stack is the same as the current one. */ + +void +linemap_print_containing_files (struct line_maps *set, + const struct line_map *map) +{ + if (MAIN_FILE_P (map) || set->last_listed == map->included_from) + return; + + set->last_listed = map->included_from; + map = INCLUDED_FROM (set, map); + + fprintf (stderr, _("In file included from %s:%u"), + map->to_file, LAST_SOURCE_LINE (map)); + + while (! MAIN_FILE_P (map)) + { + map = INCLUDED_FROM (set, map); + /* Translators note: this message is used in conjunction + with "In file included from %s:%ld" and some other + tricks. We want something like this: + + | In file included from sys/select.h:123, + | from sys/types.h:234, + | from userfile.c:31: + | bits/select.h:45: + + with all the "from"s lined up. + The trailing comma is at the beginning of this message, + and the trailing colon is not translated. */ + fprintf (stderr, _(",\n from %s:%u"), + map->to_file, LAST_SOURCE_LINE (map)); + } + + fputs (":\n", stderr); +} + +/* Print an include trace, for e.g. the -H option of the preprocessor. */ + +static void +trace_include (const struct line_maps *set, const struct line_map *map) +{ + unsigned int i = set->depth; + + while (--i) + putc ('.', stderr); + fprintf (stderr, " %s\n", map->to_file); +} diff --git a/support/cpp2/libcpp/macro.c b/support/cpp2/libcpp/macro.c new file mode 100644 index 00000000..b4143110 --- /dev/null +++ b/support/cpp2/libcpp/macro.c @@ -0,0 +1,1792 @@ +/* Part of CPP library. (Macro and #define handling.) + Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998, + 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Written by Per Bothner, 1994. + Based on CCCP program by Paul Rubin, June 1986 + Adapted to ANSI C, Richard Stallman, Jan 1987 + +This program 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 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +#include "config.h" +#include "system.h" +#include "cpplib.h" +#include "internal.h" + +typedef struct macro_arg macro_arg; +struct macro_arg +{ + const cpp_token **first; /* First token in unexpanded argument. */ + const cpp_token **expanded; /* Macro-expanded argument. */ + const cpp_token *stringified; /* Stringified argument. */ + unsigned int count; /* # of tokens in argument. */ + unsigned int expanded_count; /* # of tokens in expanded argument. */ +}; + +/* Macro expansion. */ + +static int enter_macro_context (cpp_reader *, cpp_hashnode *); +static int builtin_macro (cpp_reader *, cpp_hashnode *); +static void push_token_context (cpp_reader *, cpp_hashnode *, + const cpp_token *, unsigned int); +static void push_ptoken_context (cpp_reader *, cpp_hashnode *, _cpp_buff *, + const cpp_token **, unsigned int); +static _cpp_buff *collect_args (cpp_reader *, const cpp_hashnode *); +static cpp_context *next_context (cpp_reader *); +static const cpp_token *padding_token (cpp_reader *, const cpp_token *); +static void expand_arg (cpp_reader *, macro_arg *); +static const cpp_token *new_string_token (cpp_reader *, uchar *, unsigned int); +static const cpp_token *stringify_arg (cpp_reader *, macro_arg *); +static void paste_all_tokens (cpp_reader *, const cpp_token *); +static bool paste_tokens (cpp_reader *, const cpp_token **, const cpp_token *); +static void replace_args (cpp_reader *, cpp_hashnode *, cpp_macro *, + macro_arg *); +static _cpp_buff *funlike_invocation_p (cpp_reader *, cpp_hashnode *); +static bool create_iso_definition (cpp_reader *, cpp_macro *); + +/* #define directive parsing and handling. */ + +static cpp_token *alloc_expansion_token (cpp_reader *, cpp_macro *); +static cpp_token *lex_expansion_token (cpp_reader *, cpp_macro *); +static bool warn_of_redefinition (cpp_reader *, const cpp_hashnode *, + const cpp_macro *); +static bool parse_params (cpp_reader *, cpp_macro *); +static void check_trad_stringification (cpp_reader *, const cpp_macro *, + const cpp_string *); + +/* Emits a warning if NODE is a macro defined in the main file that + has not been used. */ +int +_cpp_warn_if_unused_macro (cpp_reader *pfile, cpp_hashnode *node, + void *v ATTRIBUTE_UNUSED) +{ + if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN)) + { + cpp_macro *macro = node->value.macro; + + if (!macro->used + && MAIN_FILE_P (linemap_lookup (pfile->line_table, macro->line))) + cpp_error_with_line (pfile, CPP_DL_WARNING, macro->line, 0, + "macro \"%s\" is not used", NODE_NAME (node)); + } + + return 1; +} + +/* Allocates and returns a CPP_STRING token, containing TEXT of length + LEN, after null-terminating it. TEXT must be in permanent storage. */ +static const cpp_token * +new_string_token (cpp_reader *pfile, unsigned char *text, unsigned int len) +{ + cpp_token *token = _cpp_temp_token (pfile); + + text[len] = '\0'; + token->type = CPP_STRING; + token->val.str.len = len; + token->val.str.text = text; + token->flags = 0; + return token; +} + +static const char * const monthnames[] = +{ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +/* Helper function for builtin_macro. Returns the text generated by + a builtin macro. */ +const uchar * +_cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node) +{ + const struct line_map *map; + const uchar *result = NULL; + unsigned int number = 1; + + switch (node->value.builtin) + { + default: + cpp_error (pfile, CPP_DL_ICE, "invalid built-in macro \"%s\"", + NODE_NAME (node)); + break; + + case BT_FILE: + case BT_BASE_FILE: + { + unsigned int len; + const char *name; + uchar *buf; + map = linemap_lookup (pfile->line_table, pfile->line_table->highest_line); + + if (node->value.builtin == BT_BASE_FILE) + while (! MAIN_FILE_P (map)) + map = INCLUDED_FROM (pfile->line_table, map); + + name = map->to_file; + len = strlen (name); + buf = _cpp_unaligned_alloc (pfile, len * 2 + 3); + result = buf; + *buf = '"'; + buf = cpp_quote_string (buf + 1, (const unsigned char *) name, len); + *buf++ = '"'; + *buf = '\0'; + } + break; + + case BT_INCLUDE_LEVEL: + /* The line map depth counts the primary source as level 1, but + historically __INCLUDE_DEPTH__ has called the primary source + level 0. */ + number = pfile->line_table->depth - 1; + break; + + case BT_SPECLINE: + map = &pfile->line_table->maps[pfile->line_table->used-1]; + /* If __LINE__ is embedded in a macro, it must expand to the + line of the macro's invocation, not its definition. + Otherwise things like assert() will not work properly. */ + if (CPP_OPTION (pfile, traditional)) + number = pfile->line_table->highest_line; + else + number = pfile->cur_token[-1].src_loc; + number = SOURCE_LINE (map, number); + break; + + /* __STDC__ has the value 1 under normal circumstances. + However, if (a) we are in a system header, (b) the option + stdc_0_in_system_headers is true (set by target config), and + (c) we are not in strictly conforming mode, then it has the + value 0. (b) and (c) are already checked in cpp_init_builtins. */ + case BT_STDC: + if (cpp_in_system_header (pfile)) + number = 0; + else + number = 1; + break; + + case BT_DATE: + case BT_TIME: + if (pfile->date == NULL) + { + /* Allocate __DATE__ and __TIME__ strings from permanent + storage. We only do this once, and don't generate them + at init time, because time() and localtime() are very + slow on some systems. */ + time_t tt; + struct tm *tb = NULL; + + /* (time_t) -1 is a legitimate value for "number of seconds + since the Epoch", so we have to do a little dance to + distinguish that from a genuine error. */ + errno = 0; + tt = time(NULL); + if (tt != (time_t)-1 || errno == 0) + tb = localtime (&tt); + + if (tb) + { + pfile->date = _cpp_unaligned_alloc (pfile, + sizeof ("\"Oct 11 1347\"")); + sprintf ((char *) pfile->date, "\"%s %2d %4d\"", + monthnames[tb->tm_mon], tb->tm_mday, + tb->tm_year + 1900); + + pfile->time = _cpp_unaligned_alloc (pfile, + sizeof ("\"12:34:56\"")); + sprintf ((char *) pfile->time, "\"%02d:%02d:%02d\"", + tb->tm_hour, tb->tm_min, tb->tm_sec); + } + else + { + cpp_errno (pfile, CPP_DL_WARNING, + "could not determine date and time"); + + pfile->date = U"\"??? ?? ????\""; + pfile->time = U"\"??:??:??\""; + } + } + + if (node->value.builtin == BT_DATE) + result = pfile->date; + else + result = pfile->time; + break; + } + + if (result == NULL) + { + /* 21 bytes holds all NUL-terminated unsigned 64-bit numbers. */ + result = _cpp_unaligned_alloc (pfile, 21); + sprintf ((char *) result, "%u", number); + } + + return result; +} + +/* Convert builtin macros like __FILE__ to a token and push it on the + context stack. Also handles _Pragma, for which a new token may not + be created. Returns 1 if it generates a new token context, 0 to + return the token to the caller. */ +static int +builtin_macro (cpp_reader *pfile, cpp_hashnode *node) +{ + const uchar *buf; + size_t len; + char *nbuf; + + if (node->value.builtin == BT_PRAGMA) + { + /* Don't interpret _Pragma within directives. The standard is + not clear on this, but to me this makes most sense. */ + if (pfile->state.in_directive) + return 0; + + _cpp_do__Pragma (pfile); + if (pfile->directive_result.type == CPP_PRAGMA) + { + cpp_token *tok = _cpp_temp_token (pfile); + *tok = pfile->directive_result; + push_token_context (pfile, NULL, tok, 1); + } + + return 1; + } + + buf = _cpp_builtin_macro_text (pfile, node); + len = ustrlen (buf); + nbuf = (char *) alloca (len + 1); + memcpy (nbuf, buf, len); + nbuf[len]='\n'; + + cpp_push_buffer (pfile, (uchar *) nbuf, len, /* from_stage3 */ true); + _cpp_clean_line (pfile); + + /* Set pfile->cur_token as required by _cpp_lex_direct. */ + pfile->cur_token = _cpp_temp_token (pfile); + push_token_context (pfile, NULL, _cpp_lex_direct (pfile), 1); + if (pfile->buffer->cur != pfile->buffer->rlimit) + cpp_error (pfile, CPP_DL_ICE, "invalid built-in macro \"%s\"", + NODE_NAME (node)); + _cpp_pop_buffer (pfile); + + return 1; +} + +/* Copies SRC, of length LEN, to DEST, adding backslashes before all + backslashes and double quotes. DEST must be of sufficient size. + Returns a pointer to the end of the string. */ +uchar * +cpp_quote_string (uchar *dest, const uchar *src, unsigned int len) +{ + while (len--) + { + uchar c = *src++; + + if (c == '\\' || c == '"') + { + *dest++ = '\\'; + *dest++ = c; + } + else + *dest++ = c; + } + + return dest; +} + +/* Convert a token sequence ARG to a single string token according to + the rules of the ISO C #-operator. */ +static const cpp_token * +stringify_arg (cpp_reader *pfile, macro_arg *arg) +{ + unsigned char *dest; + unsigned int i, escape_it, backslash_count = 0; + const cpp_token *source = NULL; + size_t len; + + if (BUFF_ROOM (pfile->u_buff) < 3) + _cpp_extend_buff (pfile, &pfile->u_buff, 3); + dest = BUFF_FRONT (pfile->u_buff); + *dest++ = '"'; + + /* Loop, reading in the argument's tokens. */ + for (i = 0; i < arg->count; i++) + { + const cpp_token *token = arg->first[i]; + + if (token->type == CPP_PADDING) + { + if (source == NULL) + source = token->val.source; + continue; + } + + escape_it = (token->type == CPP_STRING || token->type == CPP_WSTRING + || token->type == CPP_CHAR || token->type == CPP_WCHAR); + + /* Room for each char being written in octal, initial space and + final quote and NUL. */ + len = cpp_token_len (token); + if (escape_it) + len *= 4; + len += 3; + + if ((size_t) (BUFF_LIMIT (pfile->u_buff) - dest) < len) + { + size_t len_so_far = dest - BUFF_FRONT (pfile->u_buff); + _cpp_extend_buff (pfile, &pfile->u_buff, len); + dest = BUFF_FRONT (pfile->u_buff) + len_so_far; + } + + /* Leading white space? */ + if (dest - 1 != BUFF_FRONT (pfile->u_buff)) + { + if (source == NULL) + source = token; + if (source->flags & PREV_WHITE) + *dest++ = ' '; + } + source = NULL; + + if (escape_it) + { + _cpp_buff *buff = _cpp_get_buff (pfile, len); + unsigned char *buf = BUFF_FRONT (buff); + len = cpp_spell_token (pfile, token, buf, true) - buf; + dest = cpp_quote_string (dest, buf, len); + _cpp_release_buff (pfile, buff); + } + else + dest = cpp_spell_token (pfile, token, dest, true); + + if (token->type == CPP_OTHER && token->val.str.text[0] == '\\') + backslash_count++; + else + backslash_count = 0; + } + + /* Ignore the final \ of invalid string literals. */ + if (backslash_count & 1) + { + cpp_error (pfile, CPP_DL_WARNING, + "invalid string literal, ignoring final '\\'"); + dest--; + } + + /* Commit the memory, including NUL, and return the token. */ + *dest++ = '"'; + len = dest - BUFF_FRONT (pfile->u_buff); + BUFF_FRONT (pfile->u_buff) = dest + 1; + return new_string_token (pfile, dest - len, len); +} + +/* Try to paste two tokens. On success, return nonzero. In any + case, PLHS is updated to point to the pasted token, which is + guaranteed to not have the PASTE_LEFT flag set. */ +static bool +paste_tokens (cpp_reader *pfile, const cpp_token **plhs, const cpp_token *rhs) +{ + unsigned char *buf, *end; + const cpp_token *lhs; + unsigned int len; + bool valid; + + lhs = *plhs; + len = cpp_token_len (lhs) + cpp_token_len (rhs) + 1; + buf = (unsigned char *) alloca (len); + end = cpp_spell_token (pfile, lhs, buf, false); + + /* Avoid comment headers, since they are still processed in stage 3. + It is simpler to insert a space here, rather than modifying the + lexer to ignore comments in some circumstances. Simply returning + false doesn't work, since we want to clear the PASTE_LEFT flag. */ + if (lhs->type == CPP_DIV && rhs->type != CPP_EQ) + *end++ = ' '; + end = cpp_spell_token (pfile, rhs, end, false); + *end = '\n'; + + cpp_push_buffer (pfile, buf, end - buf, /* from_stage3 */ true); + _cpp_clean_line (pfile); + + /* Set pfile->cur_token as required by _cpp_lex_direct. */ + pfile->cur_token = _cpp_temp_token (pfile); + *plhs = _cpp_lex_direct (pfile); + valid = pfile->buffer->cur == pfile->buffer->rlimit; + _cpp_pop_buffer (pfile); + + return valid; +} + +/* Handles an arbitrarily long sequence of ## operators, with initial + operand LHS. This implementation is left-associative, + non-recursive, and finishes a paste before handling succeeding + ones. If a paste fails, we back up to the RHS of the failing ## + operator before pushing the context containing the result of prior + successful pastes, with the effect that the RHS appears in the + output stream after the pasted LHS normally. */ +static void +paste_all_tokens (cpp_reader *pfile, const cpp_token *lhs) +{ + const cpp_token *rhs; + cpp_context *context = pfile->context; + + do + { + /* Take the token directly from the current context. We can do + this, because we are in the replacement list of either an + object-like macro, or a function-like macro with arguments + inserted. In either case, the constraints to #define + guarantee we have at least one more token. */ + if (context->direct_p) + rhs = FIRST (context).token++; + else + rhs = *FIRST (context).ptoken++; + + if (rhs->type == CPP_PADDING) + abort (); + + if (!paste_tokens (pfile, &lhs, rhs)) + { + _cpp_backup_tokens (pfile, 1); + + /* Mandatory error for all apart from assembler. */ + if (CPP_OPTION (pfile, lang) != CLK_ASM) + cpp_error (pfile, CPP_DL_ERROR, + "pasting \"%s\" and \"%s\" does not give a valid preprocessing token", + cpp_token_as_text (pfile, lhs), + cpp_token_as_text (pfile, rhs)); + break; + } + } + while (rhs->flags & PASTE_LEFT); + + /* Put the resulting token in its own context. */ + push_token_context (pfile, NULL, lhs, 1); +} + +/* Returns TRUE if the number of arguments ARGC supplied in an + invocation of the MACRO referenced by NODE is valid. An empty + invocation to a macro with no parameters should pass ARGC as zero. + + Note that MACRO cannot necessarily be deduced from NODE, in case + NODE was redefined whilst collecting arguments. */ +bool +_cpp_arguments_ok (cpp_reader *pfile, cpp_macro *macro, const cpp_hashnode *node, unsigned int argc) +{ + if (argc == macro->paramc) + return true; + + if (argc < macro->paramc) + { + /* As an extension, a rest argument is allowed to not appear in + the invocation at all. + e.g. #define debug(format, args...) something + debug("string"); + + This is exactly the same as if there had been an empty rest + argument - debug("string", ). */ + + if (argc + 1 == macro->paramc && macro->variadic) + { + if (CPP_PEDANTIC (pfile) && ! macro->syshdr) + cpp_error (pfile, CPP_DL_PEDWARN, + "ISO C99 requires rest arguments to be used"); + return true; + } + + cpp_error (pfile, CPP_DL_ERROR, + "macro \"%s\" requires %u arguments, but only %u given", + NODE_NAME (node), macro->paramc, argc); + } + else + cpp_error (pfile, CPP_DL_ERROR, + "macro \"%s\" passed %u arguments, but takes just %u", + NODE_NAME (node), argc, macro->paramc); + + return false; +} + +/* Reads and returns the arguments to a function-like macro + invocation. Assumes the opening parenthesis has been processed. + If there is an error, emits an appropriate diagnostic and returns + NULL. Each argument is terminated by a CPP_EOF token, for the + future benefit of expand_arg(). */ +static _cpp_buff * +collect_args (cpp_reader *pfile, const cpp_hashnode *node) +{ + _cpp_buff *buff, *base_buff; + cpp_macro *macro; + macro_arg *args, *arg; + const cpp_token *token; + unsigned int argc; + + macro = node->value.macro; + if (macro->paramc) + argc = macro->paramc; + else + argc = 1; + buff = _cpp_get_buff (pfile, argc * (50 * sizeof (cpp_token *) + + sizeof (macro_arg))); + base_buff = buff; + args = (macro_arg *) buff->base; + memset (args, 0, argc * sizeof (macro_arg)); + buff->cur = (unsigned char *) &args[argc]; + arg = args, argc = 0; + + /* Collect the tokens making up each argument. We don't yet know + how many arguments have been supplied, whether too many or too + few. Hence the slightly bizarre usage of "argc" and "arg". */ + do + { + unsigned int paren_depth = 0; + unsigned int ntokens = 0; + + argc++; + arg->first = (const cpp_token **) buff->cur; + + for (;;) + { + /* Require space for 2 new tokens (including a CPP_EOF). */ + if ((unsigned char *) &arg->first[ntokens + 2] > buff->limit) + { + buff = _cpp_append_extend_buff (pfile, buff, + 1000 * sizeof (cpp_token *)); + arg->first = (const cpp_token **) buff->cur; + } + + token = cpp_get_token (pfile); + + if (token->type == CPP_PADDING) + { + /* Drop leading padding. */ + if (ntokens == 0) + continue; + } + else if (token->type == CPP_OPEN_PAREN) + paren_depth++; + else if (token->type == CPP_CLOSE_PAREN) + { + if (paren_depth-- == 0) + break; + } + else if (token->type == CPP_COMMA) + { + /* A comma does not terminate an argument within + parentheses or as part of a variable argument. */ + if (paren_depth == 0 + && ! (macro->variadic && argc == macro->paramc)) + break; + } + else if (token->type == CPP_EOF + || (token->type == CPP_HASH && token->flags & BOL)) + break; + + arg->first[ntokens++] = token; + } + + /* Drop trailing padding. */ + while (ntokens > 0 && arg->first[ntokens - 1]->type == CPP_PADDING) + ntokens--; + + arg->count = ntokens; + arg->first[ntokens] = &pfile->eof; + + /* Terminate the argument. Excess arguments loop back and + overwrite the final legitimate argument, before failing. */ + if (argc <= macro->paramc) + { + buff->cur = (unsigned char *) &arg->first[ntokens + 1]; + if (argc != macro->paramc) + arg++; + } + } + while (token->type != CPP_CLOSE_PAREN && token->type != CPP_EOF); + + if (token->type == CPP_EOF) + { + /* We still need the CPP_EOF to end directives, and to end + pre-expansion of a macro argument. Step back is not + unconditional, since we don't want to return a CPP_EOF to our + callers at the end of an -include-d file. */ + if (pfile->context->prev || pfile->state.in_directive) + _cpp_backup_tokens (pfile, 1); + cpp_error (pfile, CPP_DL_ERROR, + "unterminated argument list invoking macro \"%s\"", + NODE_NAME (node)); + } + else + { + /* A single empty argument is counted as no argument. */ + if (argc == 1 && macro->paramc == 0 && args[0].count == 0) + argc = 0; + if (_cpp_arguments_ok (pfile, macro, node, argc)) + { + /* GCC has special semantics for , ## b where b is a varargs + parameter: we remove the comma if b was omitted entirely. + If b was merely an empty argument, the comma is retained. + If the macro takes just one (varargs) parameter, then we + retain the comma only if we are standards conforming. + + If FIRST is NULL replace_args () swallows the comma. */ + if (macro->variadic && (argc < macro->paramc + || (argc == 1 && args[0].count == 0 + && !CPP_OPTION (pfile, std)))) + args[macro->paramc - 1].first = NULL; + return base_buff; + } + } + + /* An error occurred. */ + _cpp_release_buff (pfile, base_buff); + return NULL; +} + +/* Search for an opening parenthesis to the macro of NODE, in such a + way that, if none is found, we don't lose the information in any + intervening padding tokens. If we find the parenthesis, collect + the arguments and return the buffer containing them. */ +static _cpp_buff * +funlike_invocation_p (cpp_reader *pfile, cpp_hashnode *node) +{ + const cpp_token *token, *padding = NULL; + + for (;;) + { + token = cpp_get_token (pfile); + if (token->type != CPP_PADDING) + break; + if (padding == NULL + || (!(padding->flags & PREV_WHITE) && token->val.source == NULL)) + padding = token; + } + + if (token->type == CPP_OPEN_PAREN) + { + pfile->state.parsing_args = 2; + return collect_args (pfile, node); + } + + /* CPP_EOF can be the end of macro arguments, or the end of the + file. We mustn't back up over the latter. Ugh. */ + if (token->type != CPP_EOF || token == &pfile->eof) + { + /* Back up. We may have skipped padding, in which case backing + up more than one token when expanding macros is in general + too difficult. We re-insert it in its own context. */ + _cpp_backup_tokens (pfile, 1); + if (padding) + push_token_context (pfile, NULL, padding, 1); + } + + return NULL; +} + +/* Push the context of a macro with hash entry NODE onto the context + stack. If we can successfully expand the macro, we push a context + containing its yet-to-be-rescanned replacement list and return one. + Otherwise, we don't push a context and return zero. */ +static int +enter_macro_context (cpp_reader *pfile, cpp_hashnode *node) +{ + /* The presence of a macro invalidates a file's controlling macro. */ + pfile->mi_valid = false; + + pfile->state.angled_headers = false; + + /* Handle standard macros. */ + if (! (node->flags & NODE_BUILTIN)) + { + cpp_macro *macro = node->value.macro; + + if (macro->fun_like) + { + _cpp_buff *buff; + + pfile->state.prevent_expansion++; + pfile->keep_tokens++; + pfile->state.parsing_args = 1; + buff = funlike_invocation_p (pfile, node); + pfile->state.parsing_args = 0; + pfile->keep_tokens--; + pfile->state.prevent_expansion--; + + if (buff == NULL) + { + if (CPP_WTRADITIONAL (pfile) && ! node->value.macro->syshdr) + cpp_error (pfile, CPP_DL_WARNING, + "function-like macro \"%s\" must be used with arguments in traditional C", + NODE_NAME (node)); + + return 0; + } + + if (macro->paramc > 0) + replace_args (pfile, node, macro, (macro_arg *) buff->base); + _cpp_release_buff (pfile, buff); + } + + /* Disable the macro within its expansion. */ + node->flags |= NODE_DISABLED; + + macro->used = 1; + + if (macro->paramc == 0) + push_token_context (pfile, node, macro->exp.tokens, macro->count); + + return 1; + } + + /* Handle built-in macros and the _Pragma operator. */ + return builtin_macro (pfile, node); +} + +/* Replace the parameters in a function-like macro of NODE with the + actual ARGS, and place the result in a newly pushed token context. + Expand each argument before replacing, unless it is operated upon + by the # or ## operators. */ +static void +replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro, macro_arg *args) +{ + unsigned int i, total; + const cpp_token *src, *limit; + const cpp_token **dest, **first; + macro_arg *arg; + _cpp_buff *buff; + + /* First, fully macro-expand arguments, calculating the number of + tokens in the final expansion as we go. The ordering of the if + statements below is subtle; we must handle stringification before + pasting. */ + total = macro->count; + limit = macro->exp.tokens + macro->count; + + for (src = macro->exp.tokens; src < limit; src++) + if (src->type == CPP_MACRO_ARG) + { + /* Leading and trailing padding tokens. */ + total += 2; + + /* We have an argument. If it is not being stringified or + pasted it is macro-replaced before insertion. */ + arg = &args[src->val.arg_no - 1]; + + if (src->flags & STRINGIFY_ARG) + { + if (!arg->stringified) + arg->stringified = stringify_arg (pfile, arg); + } + else if ((src->flags & PASTE_LEFT) + || (src > macro->exp.tokens && (src[-1].flags & PASTE_LEFT))) + total += arg->count - 1; + else + { + if (!arg->expanded) + expand_arg (pfile, arg); + total += arg->expanded_count - 1; + } + } + + /* Now allocate space for the expansion, copy the tokens and replace + the arguments. */ + buff = _cpp_get_buff (pfile, total * sizeof (cpp_token *)); + first = (const cpp_token **) buff->base; + dest = first; + + for (src = macro->exp.tokens; src < limit; src++) + { + unsigned int count; + const cpp_token **from, **paste_flag; + + if (src->type != CPP_MACRO_ARG) + { + *dest++ = src; + continue; + } + + paste_flag = 0; + arg = &args[src->val.arg_no - 1]; + if (src->flags & STRINGIFY_ARG) + count = 1, from = &arg->stringified; + else if (src->flags & PASTE_LEFT) + count = arg->count, from = arg->first; + else if (src != macro->exp.tokens && (src[-1].flags & PASTE_LEFT)) + { + count = arg->count, from = arg->first; + if (dest != first) + { + if (dest[-1]->type == CPP_COMMA + && macro->variadic + && src->val.arg_no == macro->paramc) + { + /* Swallow a pasted comma if from == NULL, otherwise + drop the paste flag. */ + if (from == NULL) + dest--; + else + paste_flag = dest - 1; + } + /* Remove the paste flag if the RHS is a placemarker. */ + else if (count == 0) + paste_flag = dest - 1; + } + } + else + count = arg->expanded_count, from = arg->expanded; + + /* Padding on the left of an argument (unless RHS of ##). */ + if ((!pfile->state.in_directive || pfile->state.directive_wants_padding) + && src != macro->exp.tokens && !(src[-1].flags & PASTE_LEFT)) + *dest++ = padding_token (pfile, src); + + if (count) + { + memcpy (dest, from, count * sizeof (cpp_token *)); + dest += count; + + /* With a non-empty argument on the LHS of ##, the last + token should be flagged PASTE_LEFT. */ + if (src->flags & PASTE_LEFT) + paste_flag = dest - 1; + } + + /* Avoid paste on RHS (even case count == 0). */ + if (!pfile->state.in_directive && !(src->flags & PASTE_LEFT)) + *dest++ = &pfile->avoid_paste; + + /* Add a new paste flag, or remove an unwanted one. */ + if (paste_flag) + { + cpp_token *token = _cpp_temp_token (pfile); + token->type = (*paste_flag)->type; + token->val = (*paste_flag)->val; + if (src->flags & PASTE_LEFT) + token->flags = (*paste_flag)->flags | PASTE_LEFT; + else + token->flags = (*paste_flag)->flags & ~PASTE_LEFT; + *paste_flag = token; + } + } + + /* Free the expanded arguments. */ + for (i = 0; i < macro->paramc; i++) + if (args[i].expanded) + free (args[i].expanded); + + push_ptoken_context (pfile, node, buff, first, dest - first); +} + +/* Return a special padding token, with padding inherited from SOURCE. */ +static const cpp_token * +padding_token (cpp_reader *pfile, const cpp_token *source) +{ + cpp_token *result = _cpp_temp_token (pfile); + + result->type = CPP_PADDING; + + /* Data in GCed data structures cannot be made const so far, so we + need a cast here. */ + result->val.source = (cpp_token *) source; + result->flags = 0; + return result; +} + +/* Get a new uninitialized context. Create a new one if we cannot + re-use an old one. */ +static cpp_context * +next_context (cpp_reader *pfile) +{ + cpp_context *result = pfile->context->next; + + if (result == 0) + { + result = XNEW (cpp_context); + result->prev = pfile->context; + result->next = 0; + pfile->context->next = result; + } + + pfile->context = result; + return result; +} + +/* Push a list of pointers to tokens. */ +static void +push_ptoken_context (cpp_reader *pfile, cpp_hashnode *macro, _cpp_buff *buff, + const cpp_token **first, unsigned int count) +{ + cpp_context *context = next_context (pfile); + + context->direct_p = false; + context->macro = macro; + context->buff = buff; + FIRST (context).ptoken = first; + LAST (context).ptoken = first + count; +} + +/* Push a list of tokens. */ +static void +push_token_context (cpp_reader *pfile, cpp_hashnode *macro, + const cpp_token *first, unsigned int count) +{ + cpp_context *context = next_context (pfile); + + context->direct_p = true; + context->macro = macro; + context->buff = NULL; + FIRST (context).token = first; + LAST (context).token = first + count; +} + +/* Push a traditional macro's replacement text. */ +void +_cpp_push_text_context (cpp_reader *pfile, cpp_hashnode *macro, + const uchar *start, size_t len) +{ + cpp_context *context = next_context (pfile); + + context->direct_p = true; + context->macro = macro; + context->buff = NULL; + CUR (context) = start; + RLIMIT (context) = start + len; + macro->flags |= NODE_DISABLED; +} + +/* Expand an argument ARG before replacing parameters in a + function-like macro. This works by pushing a context with the + argument's tokens, and then expanding that into a temporary buffer + as if it were a normal part of the token stream. collect_args() + has terminated the argument's tokens with a CPP_EOF so that we know + when we have fully expanded the argument. */ +static void +expand_arg (cpp_reader *pfile, macro_arg *arg) +{ + unsigned int capacity; + bool saved_warn_trad; + + if (arg->count == 0) + return; + + /* Don't warn about funlike macros when pre-expanding. */ + saved_warn_trad = CPP_WTRADITIONAL (pfile); + CPP_WTRADITIONAL (pfile) = 0; + + /* Loop, reading in the arguments. */ + capacity = 256; + arg->expanded = XNEWVEC (const cpp_token *, capacity); + + push_ptoken_context (pfile, NULL, NULL, arg->first, arg->count + 1); + for (;;) + { + const cpp_token *token; + + if (arg->expanded_count + 1 >= capacity) + { + capacity *= 2; + arg->expanded = XRESIZEVEC (const cpp_token *, arg->expanded, + capacity); + } + + token = cpp_get_token (pfile); + + if (token->type == CPP_EOF) + break; + + arg->expanded[arg->expanded_count++] = token; + } + + _cpp_pop_context (pfile); + + CPP_WTRADITIONAL (pfile) = saved_warn_trad; +} + +/* Pop the current context off the stack, re-enabling the macro if the + context represented a macro's replacement list. The context + structure is not freed so that we can re-use it later. */ +void +_cpp_pop_context (cpp_reader *pfile) +{ + cpp_context *context = pfile->context; + + if (context->macro) + context->macro->flags &= ~NODE_DISABLED; + + if (context->buff) + _cpp_release_buff (pfile, context->buff); + + pfile->context = context->prev; +} + +/* External routine to get a token. Also used nearly everywhere + internally, except for places where we know we can safely call + _cpp_lex_token directly, such as lexing a directive name. + + Macro expansions and directives are transparently handled, + including entering included files. Thus tokens are post-macro + expansion, and after any intervening directives. External callers + see CPP_EOF only at EOF. Internal callers also see it when meeting + a directive inside a macro call, when at the end of a directive and + state.in_directive is still 1, and at the end of argument + pre-expansion. */ +const cpp_token * +cpp_get_token (cpp_reader *pfile) +{ + const cpp_token *result; + + for (;;) + { + cpp_hashnode *node; + cpp_context *context = pfile->context; + + /* Context->prev == 0 <=> base context. */ + if (!context->prev) + result = _cpp_lex_token (pfile); + else if (FIRST (context).token != LAST (context).token) + { + if (context->direct_p) + result = FIRST (context).token++; + else + result = *FIRST (context).ptoken++; + + if (result->flags & PASTE_LEFT) + { + paste_all_tokens (pfile, result); + if (pfile->state.in_directive) + continue; + return padding_token (pfile, result); + } + } + else + { + _cpp_pop_context (pfile); + if (pfile->state.in_directive) + continue; + return &pfile->avoid_paste; + } + + if (pfile->state.in_directive && result->type == CPP_COMMENT) + continue; + + if (result->type != CPP_NAME) + break; + + node = result->val.node; + + if (node->type != NT_MACRO || (result->flags & NO_EXPAND)) + break; + + if (!(node->flags & NODE_DISABLED)) + { + if (!pfile->state.prevent_expansion + && enter_macro_context (pfile, node)) + { + if (pfile->state.in_directive) + continue; + return padding_token (pfile, result); + } + } + else + { + /* Flag this token as always unexpandable. FIXME: move this + to collect_args()?. */ + cpp_token *t = _cpp_temp_token (pfile); + t->type = result->type; + t->flags = result->flags | NO_EXPAND; + t->val = result->val; + result = t; + } + + break; + } + + return result; +} + +/* Returns true if we're expanding an object-like macro that was + defined in a system header. Just checks the macro at the top of + the stack. Used for diagnostic suppression. */ +int +cpp_sys_macro_p (cpp_reader *pfile) +{ + cpp_hashnode *node = pfile->context->macro; + + return node && node->value.macro && node->value.macro->syshdr; +} + +/* Read each token in, until end of the current file. Directives are + transparently processed. */ +void +cpp_scan_nooutput (cpp_reader *pfile) +{ + /* Request a CPP_EOF token at the end of this file, rather than + transparently continuing with the including file. */ + pfile->buffer->return_at_eof = true; + + pfile->state.discarding_output++; + pfile->state.prevent_expansion++; + + if (CPP_OPTION (pfile, traditional)) + while (_cpp_read_logical_line_trad (pfile)) + ; + else + while (cpp_get_token (pfile)->type != CPP_EOF) + ; + + pfile->state.discarding_output--; + pfile->state.prevent_expansion--; +} + +/* Step back one (or more) tokens. Can only step mack more than 1 if + they are from the lexer, and not from macro expansion. */ +void +_cpp_backup_tokens (cpp_reader *pfile, unsigned int count) +{ + if (pfile->context->prev == NULL) + { + pfile->lookaheads += count; + while (count--) + { + pfile->cur_token--; + if (pfile->cur_token == pfile->cur_run->base + /* Possible with -fpreprocessed and no leading #line. */ + && pfile->cur_run->prev != NULL) + { + pfile->cur_run = pfile->cur_run->prev; + pfile->cur_token = pfile->cur_run->limit; + } + } + } + else + { + if (count != 1) + abort (); + if (pfile->context->direct_p) + FIRST (pfile->context).token--; + else + FIRST (pfile->context).ptoken--; + } +} + +/* #define directive parsing and handling. */ + +/* Returns nonzero if a macro redefinition warning is required. */ +static bool +warn_of_redefinition (cpp_reader *pfile, const cpp_hashnode *node, + const cpp_macro *macro2) +{ + const cpp_macro *macro1; + unsigned int i; + + /* Some redefinitions need to be warned about regardless. */ + if (node->flags & NODE_WARN) + return true; + + /* Redefinition of a macro is allowed if and only if the old and new + definitions are the same. (6.10.3 paragraph 2). */ + macro1 = node->value.macro; + + /* Don't check count here as it can be different in valid + traditional redefinitions with just whitespace differences. */ + if (macro1->paramc != macro2->paramc + || macro1->fun_like != macro2->fun_like + || macro1->variadic != macro2->variadic) + return true; + + /* Check parameter spellings. */ + for (i = 0; i < macro1->paramc; i++) + if (macro1->params[i] != macro2->params[i]) + return true; + + /* Check the replacement text or tokens. */ + if (CPP_OPTION (pfile, traditional)) + return _cpp_expansions_different_trad (macro1, macro2); + + if (macro1->count != macro2->count) + return true; + + for (i = 0; i < macro1->count; i++) + if (!_cpp_equiv_tokens (¯o1->exp.tokens[i], ¯o2->exp.tokens[i])) + return true; + + return false; +} + +/* Free the definition of hashnode H. */ +void +_cpp_free_definition (cpp_hashnode *h) +{ + /* Macros and assertions no longer have anything to free. */ + h->type = NT_VOID; + /* Clear builtin flag in case of redefinition. */ + h->flags &= ~(NODE_BUILTIN | NODE_DISABLED); +} + +/* Save parameter NODE to the parameter list of macro MACRO. Returns + zero on success, nonzero if the parameter is a duplicate. */ +bool +_cpp_save_parameter (cpp_reader *pfile, cpp_macro *macro, cpp_hashnode *node) +{ + unsigned int len; + /* Constraint 6.10.3.6 - duplicate parameter names. */ + if (node->flags & NODE_MACRO_ARG) + { + cpp_error (pfile, CPP_DL_ERROR, "duplicate macro parameter \"%s\"", + NODE_NAME (node)); + return true; + } + + if (BUFF_ROOM (pfile->a_buff) + < (macro->paramc + 1) * sizeof (cpp_hashnode *)) + _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (cpp_hashnode *)); + + ((cpp_hashnode **) BUFF_FRONT (pfile->a_buff))[macro->paramc++] = node; + node->flags |= NODE_MACRO_ARG; + len = macro->paramc * sizeof (union _cpp_hashnode_value); + if (len > pfile->macro_buffer_len) + { + pfile->macro_buffer = XRESIZEVEC (unsigned char, pfile->macro_buffer, + len); + pfile->macro_buffer_len = len; + } + ((union _cpp_hashnode_value *) pfile->macro_buffer)[macro->paramc - 1] + = node->value; + + node->value.arg_index = macro->paramc; + return false; +} + +/* Check the syntax of the parameters in a MACRO definition. Returns + false if an error occurs. */ +static bool +parse_params (cpp_reader *pfile, cpp_macro *macro) +{ + unsigned int prev_ident = 0; + + for (;;) + { + const cpp_token *token = _cpp_lex_token (pfile); + + switch (token->type) + { + default: + /* Allow/ignore comments in parameter lists if we are + preserving comments in macro expansions. */ + if (token->type == CPP_COMMENT + && ! CPP_OPTION (pfile, discard_comments_in_macro_exp)) + continue; + + cpp_error (pfile, CPP_DL_ERROR, + "\"%s\" may not appear in macro parameter list", + cpp_token_as_text (pfile, token)); + return false; + + case CPP_NAME: + if (prev_ident) + { + cpp_error (pfile, CPP_DL_ERROR, + "macro parameters must be comma-separated"); + return false; + } + prev_ident = 1; + + if (_cpp_save_parameter (pfile, macro, token->val.node)) + return false; + continue; + + case CPP_CLOSE_PAREN: + if (prev_ident || macro->paramc == 0) + return true; + + /* Fall through to pick up the error. */ + case CPP_COMMA: + if (!prev_ident) + { + cpp_error (pfile, CPP_DL_ERROR, "parameter name missing"); + return false; + } + prev_ident = 0; + continue; + + case CPP_ELLIPSIS: + macro->variadic = 1; + if (!prev_ident) + { + _cpp_save_parameter (pfile, macro, + pfile->spec_nodes.n__VA_ARGS__); + pfile->state.va_args_ok = 1; + if (! CPP_OPTION (pfile, c99) + && CPP_OPTION (pfile, pedantic) + && CPP_OPTION (pfile, warn_variadic_macros)) + cpp_error (pfile, CPP_DL_PEDWARN, + "anonymous variadic macros were introduced in C99"); + } + else if (CPP_OPTION (pfile, pedantic) + && CPP_OPTION (pfile, warn_variadic_macros)) + cpp_error (pfile, CPP_DL_PEDWARN, + "ISO C does not permit named variadic macros"); + + /* We're at the end, and just expect a closing parenthesis. */ + token = _cpp_lex_token (pfile); + if (token->type == CPP_CLOSE_PAREN) + return true; + /* Fall through. */ + + case CPP_EOF: + cpp_error (pfile, CPP_DL_ERROR, "missing ')' in macro parameter list"); + return false; + } + } +} + +/* Allocate room for a token from a macro's replacement list. */ +static cpp_token * +alloc_expansion_token (cpp_reader *pfile, cpp_macro *macro) +{ + if (BUFF_ROOM (pfile->a_buff) < (macro->count + 1) * sizeof (cpp_token)) + _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (cpp_token)); + + return &((cpp_token *) BUFF_FRONT (pfile->a_buff))[macro->count++]; +} + +/* Lex a token from the expansion of MACRO, but mark parameters as we + find them and warn of traditional stringification. */ +static cpp_token * +lex_expansion_token (cpp_reader *pfile, cpp_macro *macro) +{ + cpp_token *token; + + pfile->cur_token = alloc_expansion_token (pfile, macro); + token = _cpp_lex_direct (pfile); + + /* Is this a parameter? */ + if (token->type == CPP_NAME + && (token->val.node->flags & NODE_MACRO_ARG) != 0) + { + token->type = CPP_MACRO_ARG; + token->val.arg_no = token->val.node->value.arg_index; + } + else if (CPP_WTRADITIONAL (pfile) && macro->paramc > 0 + && (token->type == CPP_STRING || token->type == CPP_CHAR)) + check_trad_stringification (pfile, macro, &token->val.str); + + return token; +} + +static bool +create_iso_definition (cpp_reader *pfile, cpp_macro *macro) +{ + cpp_token *token; + const cpp_token *ctoken; + + /* Get the first token of the expansion (or the '(' of a + function-like macro). */ + ctoken = _cpp_lex_token (pfile); + + if (ctoken->type == CPP_OPEN_PAREN && !(ctoken->flags & PREV_WHITE)) + { + bool ok = parse_params (pfile, macro); + macro->params = (cpp_hashnode **) BUFF_FRONT (pfile->a_buff); + if (!ok) + return false; + + /* Success. Commit or allocate the parameter array. */ + if (pfile->hash_table->alloc_subobject) + { + cpp_hashnode **params = + (cpp_hashnode **) pfile->hash_table->alloc_subobject + (sizeof (cpp_hashnode *) * macro->paramc); + memcpy (params, macro->params, + sizeof (cpp_hashnode *) * macro->paramc); + macro->params = params; + } + else + BUFF_FRONT (pfile->a_buff) = (uchar *) ¯o->params[macro->paramc]; + macro->fun_like = 1; + } + else if (ctoken->type != CPP_EOF && !(ctoken->flags & PREV_WHITE)) + { + /* While ISO C99 requires whitespace before replacement text + in a macro definition, ISO C90 with TC1 allows there characters + from the basic source character set. */ + if (CPP_OPTION (pfile, c99)) + cpp_error (pfile, CPP_DL_PEDWARN, + "ISO C99 requires whitespace after the macro name"); + else + { + int warntype = CPP_DL_WARNING; + switch (ctoken->type) + { + case CPP_ATSIGN: + case CPP_AT_NAME: + case CPP_OBJC_STRING: + /* '@' is not in basic character set. */ + warntype = CPP_DL_PEDWARN; + break; + case CPP_OTHER: + /* Basic character set sans letters, digits and _. */ + if (strchr ("!\"#%&'()*+,-./:;<=>?[\\]^{|}~", + ctoken->val.str.text[0]) == NULL) + warntype = CPP_DL_PEDWARN; + break; + default: + /* All other tokens start with a character from basic + character set. */ + break; + } + cpp_error (pfile, warntype, + "missing whitespace after the macro name"); + } + } + + if (macro->fun_like) + token = lex_expansion_token (pfile, macro); + else + { + token = alloc_expansion_token (pfile, macro); + *token = *ctoken; + } + + for (;;) + { + /* Check the stringifying # constraint 6.10.3.2.1 of + function-like macros when lexing the subsequent token. */ + if (macro->count > 1 && token[-1].type == CPP_HASH && macro->fun_like) + { + if (token->type == CPP_MACRO_ARG) + { + token->flags &= ~PREV_WHITE; + token->flags |= STRINGIFY_ARG; + token->flags |= token[-1].flags & PREV_WHITE; + token[-1] = token[0]; + macro->count--; + } + /* Let assembler get away with murder. */ + else if ((CPP_OPTION (pfile, lang) != CLK_ASM) + && (!CPP_OPTION(pfile, allow_naked_hash))) + { + cpp_error (pfile, CPP_DL_ERROR, + "'#' is not followed by a macro parameter"); + return false; + } + } + + if (token->type == CPP_EOF) + break; + + /* Paste operator constraint 6.10.3.3.1. */ + if (token->type == CPP_PASTE) + { + /* Token-paste ##, can appear in both object-like and + function-like macros, but not at the ends. */ + if (--macro->count > 0) + token = lex_expansion_token (pfile, macro); + + if (macro->count == 0 || token->type == CPP_EOF) + { + cpp_error (pfile, CPP_DL_ERROR, + "'##' cannot appear at either end of a macro expansion"); + return false; + } + + token[-1].flags |= PASTE_LEFT; + } + + token = lex_expansion_token (pfile, macro); + } + + macro->exp.tokens = (cpp_token *) BUFF_FRONT (pfile->a_buff); + macro->traditional = 0; + + /* Don't count the CPP_EOF. */ + macro->count--; + + /* Clear whitespace on first token for warn_of_redefinition(). */ + if (macro->count) + macro->exp.tokens[0].flags &= ~PREV_WHITE; + + /* Commit or allocate the memory. */ + if (pfile->hash_table->alloc_subobject) + { + cpp_token *tokns = + (cpp_token *) pfile->hash_table->alloc_subobject (sizeof (cpp_token) + * macro->count); + memcpy (tokns, macro->exp.tokens, sizeof (cpp_token) * macro->count); + macro->exp.tokens = tokns; + } + else + BUFF_FRONT (pfile->a_buff) = (uchar *) ¯o->exp.tokens[macro->count]; + + return true; +} + +/* Parse a macro and save its expansion. Returns nonzero on success. */ +bool +_cpp_create_definition (cpp_reader *pfile, cpp_hashnode *node) +{ + cpp_macro *macro; + unsigned int i; + bool ok; + + if (pfile->hash_table->alloc_subobject) + macro = (cpp_macro *) pfile->hash_table->alloc_subobject + (sizeof (cpp_macro)); + else + macro = (cpp_macro *) _cpp_aligned_alloc (pfile, sizeof (cpp_macro)); + macro->line = pfile->directive_line; + macro->params = 0; + macro->paramc = 0; + macro->variadic = 0; + macro->used = !CPP_OPTION (pfile, warn_unused_macros); + macro->count = 0; + macro->fun_like = 0; + /* To suppress some diagnostics. */ + macro->syshdr = pfile->buffer && pfile->buffer->sysp != 0; + + if (CPP_OPTION (pfile, traditional)) + ok = _cpp_create_trad_definition (pfile, macro); + else + { + cpp_token *saved_cur_token = pfile->cur_token; + + ok = create_iso_definition (pfile, macro); + + /* Restore lexer position because of games lex_expansion_token() + plays lexing the macro. We set the type for SEEN_EOL() in + directives.c. + + Longer term we should lex the whole line before coming here, + and just copy the expansion. */ + saved_cur_token[-1].type = pfile->cur_token[-1].type; + pfile->cur_token = saved_cur_token; + + /* Stop the lexer accepting __VA_ARGS__. */ + pfile->state.va_args_ok = 0; + } + + /* Clear the fast argument lookup indices. */ + for (i = macro->paramc; i-- > 0; ) + { + struct cpp_hashnode *node = macro->params[i]; + node->flags &= ~ NODE_MACRO_ARG; + node->value = ((union _cpp_hashnode_value *) pfile->macro_buffer)[i]; + } + + if (!ok) + return ok; + + if (node->type == NT_MACRO) + { + if (CPP_OPTION (pfile, warn_unused_macros)) + _cpp_warn_if_unused_macro (pfile, node, NULL); + + if (warn_of_redefinition (pfile, node, macro)) + { + cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->directive_line, 0, + "\"%s\" redefined", NODE_NAME (node)); + + if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN)) + cpp_error_with_line (pfile, CPP_DL_PEDWARN, + node->value.macro->line, 0, + "this is the location of the previous definition"); + } + } + + if (node->type != NT_VOID) + _cpp_free_definition (node); + + /* Enter definition in hash table. */ + node->type = NT_MACRO; + node->value.macro = macro; + if (! ustrncmp (NODE_NAME (node), DSC ("__STDC_"))) + node->flags |= NODE_WARN; + + return ok; +} + +/* Warn if a token in STRING matches one of a function-like MACRO's + parameters. */ +static void +check_trad_stringification (cpp_reader *pfile, const cpp_macro *macro, + const cpp_string *string) +{ + unsigned int i, len; + const uchar *p, *q, *limit; + + /* Loop over the string. */ + limit = string->text + string->len - 1; + for (p = string->text + 1; p < limit; p = q) + { + /* Find the start of an identifier. */ + while (p < limit && !is_idstart (*p)) + p++; + + /* Find the end of the identifier. */ + q = p; + while (q < limit && is_idchar (*q)) + q++; + + len = q - p; + + /* Loop over the function macro arguments to see if the + identifier inside the string matches one of them. */ + for (i = 0; i < macro->paramc; i++) + { + const cpp_hashnode *node = macro->params[i]; + + if (NODE_LEN (node) == len + && !memcmp (p, NODE_NAME (node), len)) + { + cpp_error (pfile, CPP_DL_WARNING, + "macro argument \"%s\" would be stringified in traditional C", + NODE_NAME (node)); + break; + } + } + } +} + +/* Returns the name, arguments and expansion of a macro, in a format + suitable to be read back in again, and therefore also for DWARF 2 + debugging info. e.g. "PASTE(X, Y) X ## Y", or "MACNAME EXPANSION". + Caller is expected to generate the "#define" bit if needed. The + returned text is temporary, and automatically freed later. */ +const unsigned char * +cpp_macro_definition (cpp_reader *pfile, const cpp_hashnode *node) +{ + unsigned int i, len; + const cpp_macro *macro = node->value.macro; + unsigned char *buffer; + + if (node->type != NT_MACRO || (node->flags & NODE_BUILTIN)) + { + cpp_error (pfile, CPP_DL_ICE, + "invalid hash type %d in cpp_macro_definition", node->type); + return 0; + } + + /* Calculate length. */ + len = NODE_LEN (node) + 2; /* ' ' and NUL. */ + if (macro->fun_like) + { + len += 4; /* "()" plus possible final ".." of named + varargs (we have + 1 below). */ + for (i = 0; i < macro->paramc; i++) + len += NODE_LEN (macro->params[i]) + 1; /* "," */ + } + + /* This should match below where we fill in the buffer. */ + if (CPP_OPTION (pfile, traditional)) + len += _cpp_replacement_text_len (macro); + else + { + for (i = 0; i < macro->count; i++) + { + cpp_token *token = ¯o->exp.tokens[i]; + + if (token->type == CPP_MACRO_ARG) + len += NODE_LEN (macro->params[token->val.arg_no - 1]); + else + len += cpp_token_len (token); + + if (token->flags & STRINGIFY_ARG) + len++; /* "#" */ + if (token->flags & PASTE_LEFT) + len += 3; /* " ##" */ + if (token->flags & PREV_WHITE) + len++; /* " " */ + } + } + + if (len > pfile->macro_buffer_len) + { + pfile->macro_buffer = XRESIZEVEC (unsigned char, + pfile->macro_buffer, len); + pfile->macro_buffer_len = len; + } + + /* Fill in the buffer. Start with the macro name. */ + buffer = pfile->macro_buffer; + memcpy (buffer, NODE_NAME (node), NODE_LEN (node)); + buffer += NODE_LEN (node); + + /* Parameter names. */ + if (macro->fun_like) + { + *buffer++ = '('; + for (i = 0; i < macro->paramc; i++) + { + cpp_hashnode *param = macro->params[i]; + + if (param != pfile->spec_nodes.n__VA_ARGS__) + { + memcpy (buffer, NODE_NAME (param), NODE_LEN (param)); + buffer += NODE_LEN (param); + } + + if (i + 1 < macro->paramc) + /* Don't emit a space after the comma here; we're trying + to emit a Dwarf-friendly definition, and the Dwarf spec + forbids spaces in the argument list. */ + *buffer++ = ','; + else if (macro->variadic) + *buffer++ = '.', *buffer++ = '.', *buffer++ = '.'; + } + *buffer++ = ')'; + } + + /* The Dwarf spec requires a space after the macro name, even if the + definition is the empty string. */ + *buffer++ = ' '; + + if (CPP_OPTION (pfile, traditional)) + buffer = _cpp_copy_replacement_text (macro, buffer); + else if (macro->count) + /* Expansion tokens. */ + { + for (i = 0; i < macro->count; i++) + { + cpp_token *token = ¯o->exp.tokens[i]; + + if (token->flags & PREV_WHITE) + *buffer++ = ' '; + if (token->flags & STRINGIFY_ARG) + *buffer++ = '#'; + + if (token->type == CPP_MACRO_ARG) + { + memcpy (buffer, + NODE_NAME (macro->params[token->val.arg_no - 1]), + NODE_LEN (macro->params[token->val.arg_no - 1])); + buffer += NODE_LEN (macro->params[token->val.arg_no - 1]); + } + else + buffer = cpp_spell_token (pfile, token, buffer, false); + + if (token->flags & PASTE_LEFT) + { + *buffer++ = ' '; + *buffer++ = '#'; + *buffer++ = '#'; + /* Next has PREV_WHITE; see _cpp_create_definition. */ + } + } + } + + *buffer = '\0'; + return pfile->macro_buffer; +} diff --git a/support/cpp2/libcpp/mkdeps.c b/support/cpp2/libcpp/mkdeps.c new file mode 100644 index 00000000..31feb826 --- /dev/null +++ b/support/cpp2/libcpp/mkdeps.c @@ -0,0 +1,363 @@ +/* Dependency generator for Makefile fragments. + Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc. + Contributed by Zack Weinberg, Mar 2000 + +This program 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 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +#include "config.h" +#include "system.h" +#include "mkdeps.h" +#include "internal.h" + +/* Keep this structure local to this file, so clients don't find it + easy to start making assumptions. */ +struct deps +{ + const char **targetv; + unsigned int ntargets; /* number of slots actually occupied */ + unsigned int targets_size; /* amt of allocated space - in words */ + + const char **depv; + unsigned int ndeps; + unsigned int deps_size; +}; + +static const char *munge (const char *); + +/* Given a filename, quote characters in that filename which are + significant to Make. Note that it's not possible to quote all such + characters - e.g. \n, %, *, ?, [, \ (in some contexts), and ~ are + not properly handled. It isn't possible to get this right in any + current version of Make. (??? Still true? Old comment referred to + 3.76.1.) */ + +static const char * +munge (const char *filename) +{ + int len; + const char *p, *q; + char *dst, *buffer; + + for (p = filename, len = 0; *p; p++, len++) + { + switch (*p) + { + case ' ': + case '\t': + /* GNU make uses a weird quoting scheme for white space. + A space or tab preceded by 2N+1 backslashes represents + N backslashes followed by space; a space or tab + preceded by 2N backslashes represents N backslashes at + the end of a file name; and backslashes in other + contexts should not be doubled. */ + for (q = p - 1; filename <= q && *q == '\\'; q--) + len++; + len++; + break; + + case '$': + /* '$' is quoted by doubling it. */ + len++; + break; + } + } + + /* Now we know how big to make the buffer. */ + buffer = xmalloc (len + 1); + + for (p = filename, dst = buffer; *p; p++, dst++) + { + switch (*p) + { + case ' ': + case '\t': + for (q = p - 1; filename <= q && *q == '\\'; q--) + *dst++ = '\\'; + *dst++ = '\\'; + break; + + case '$': + *dst++ = '$'; + break; + + default: + /* nothing */; + } + *dst = *p; + } + + *dst = '\0'; + return buffer; +} + +/* Public routines. */ + +struct deps * +deps_init (void) +{ + struct deps *d = xmalloc (sizeof (struct deps)); + + /* Allocate space for the vectors only if we need it. */ + + d->targetv = 0; + d->depv = 0; + + d->ntargets = 0; + d->targets_size = 0; + d->ndeps = 0; + d->deps_size = 0; + + return d; +} + +void +deps_free (struct deps *d) +{ + unsigned int i; + + if (d->targetv) + { + for (i = 0; i < d->ntargets; i++) + free ((void *) d->targetv[i]); + free (d->targetv); + } + + if (d->depv) + { + for (i = 0; i < d->ndeps; i++) + free ((void *) d->depv[i]); + free (d->depv); + } + + free (d); +} + +/* Adds a target T. We make a copy, so it need not be a permanent + string. QUOTE is true if the string should be quoted. */ +void +deps_add_target (struct deps *d, const char *t, int quote) +{ + if (d->ntargets == d->targets_size) + { + d->targets_size = d->targets_size * 2 + 4; + d->targetv = xrealloc (d->targetv, + d->targets_size * sizeof (const char *)); + } + + if (quote) + t = munge (t); /* Also makes permanent copy. */ + else + t = xstrdup (t); + + d->targetv[d->ntargets++] = t; +} + +/* Sets the default target if none has been given already. An empty + string as the default target in interpreted as stdin. The string + is quoted for MAKE. */ +void +deps_add_default_target (cpp_reader *pfile, const char *tgt) +{ + struct deps *d = pfile->deps; + + /* Only if we have no targets. */ + if (d->ntargets) + return; + + if (tgt[0] == '\0') + deps_add_target (d, "-", 1); + else + { +#ifndef TARGET_OBJECT_SUFFIX +# define TARGET_OBJECT_SUFFIX ".o" +#endif + const char *start = lbasename (tgt); + char *o; + char *suffix; + const char *obj_ext; + + if (NULL == CPP_OPTION (pfile, obj_ext)) + obj_ext = TARGET_OBJECT_SUFFIX; + else if (CPP_OPTION (pfile, obj_ext)[0] != '.') + { + char *t = alloca (strlen (CPP_OPTION (pfile, obj_ext)) + 2); + t[0] = '.'; + strcpy (&t[1], CPP_OPTION (pfile, obj_ext)); + obj_ext = t; + } + else + obj_ext = CPP_OPTION (pfile, obj_ext); + + o = (char *) alloca (strlen (start) + strlen (obj_ext) + 1); + + strcpy (o, start); + + suffix = strrchr (o, '.'); + if (!suffix) + suffix = o + strlen (o); + strcpy (suffix, obj_ext); + + deps_add_target (d, o, 1); + } +} + +void +deps_add_dep (struct deps *d, const char *t) +{ + t = munge (t); /* Also makes permanent copy. */ + + if (d->ndeps == d->deps_size) + { + d->deps_size = d->deps_size * 2 + 8; + d->depv = xrealloc (d->depv, d->deps_size * sizeof (const char *)); + } + d->depv[d->ndeps++] = t; +} + +void +deps_write (const struct deps *d, FILE *fp, unsigned int colmax) +{ + unsigned int size, i, column; + + column = 0; + if (colmax && colmax < 34) + colmax = 34; + + for (i = 0; i < d->ntargets; i++) + { + size = strlen (d->targetv[i]); + column += size; + if (colmax && column > colmax) + { + fputs (" \\\n ", fp); + column = 1 + size; + } + if (i) + { + putc (' ', fp); + column++; + } + fputs (d->targetv[i], fp); + } + + putc (':', fp); + putc (' ', fp); + column += 2; + + for (i = 0; i < d->ndeps; i++) + { + size = strlen (d->depv[i]); + column += size; + if (colmax && column > colmax) + { + fputs (" \\\n ", fp); + column = 1 + size; + } + if (i) + { + putc (' ', fp); + column++; + } + fputs (d->depv[i], fp); + } + putc ('\n', fp); +} + +void +deps_phony_targets (const struct deps *d, FILE *fp) +{ + unsigned int i; + + for (i = 1; i < d->ndeps; i++) + { + putc ('\n', fp); + fputs (d->depv[i], fp); + putc (':', fp); + putc ('\n', fp); + } +} + +/* Write out a deps buffer to a file, in a form that can be read back + with deps_restore. Returns nonzero on error, in which case the + error number will be in errno. */ + +int +deps_save (struct deps *deps, FILE *f) +{ + unsigned int i; + + /* The cppreader structure contains makefile dependences. Write out this + structure. */ + + /* The number of dependences. */ + if (fwrite (&deps->ndeps, sizeof (deps->ndeps), 1, f) != 1) + return -1; + /* The length of each dependence followed by the string. */ + for (i = 0; i < deps->ndeps; i++) + { + size_t num_to_write = strlen (deps->depv[i]); + if (fwrite (&num_to_write, sizeof (size_t), 1, f) != 1) + return -1; + if (fwrite (deps->depv[i], num_to_write, 1, f) != 1) + return -1; + } + + return 0; +} + +/* Read back dependency information written with deps_save into + the deps buffer. The third argument may be NULL, in which case + the dependency information is just skipped, or it may be a filename, + in which case that filename is skipped. */ + +int +deps_restore (struct deps *deps, FILE *fd, const char *self) +{ + unsigned int i, count; + size_t num_to_read; + size_t buf_size = 512; + char *buf = xmalloc (buf_size); + + /* Number of dependences. */ + if (fread (&count, 1, sizeof (count), fd) != sizeof (count)) + return -1; + + /* The length of each dependence string, followed by the string. */ + for (i = 0; i < count; i++) + { + /* Read in # bytes in string. */ + if (fread (&num_to_read, 1, sizeof (size_t), fd) != sizeof (size_t)) + return -1; + if (buf_size < num_to_read + 1) + { + buf_size = num_to_read + 1 + 127; + buf = xrealloc (buf, buf_size); + } + if (fread (buf, 1, num_to_read, fd) != num_to_read) + return -1; + buf[num_to_read] = '\0'; + + /* Generate makefile dependencies from .pch if -nopch-deps. */ + if (self != NULL && strcmp (buf, self) != 0) + deps_add_dep (deps, buf); + } + + free (buf); + return 0; +} diff --git a/support/cpp2/libcpp/symtab.c b/support/cpp2/libcpp/symtab.c new file mode 100644 index 00000000..ffa28f5f --- /dev/null +++ b/support/cpp2/libcpp/symtab.c @@ -0,0 +1,335 @@ +/* Hash tables. + Copyright (C) 2000, 2001, 2003, 2004 Free Software Foundation, Inc. + +This program 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 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +#include "config.h" +#include "system.h" +#include "symtab.h" + +/* The code below is a specialization of Vladimir Makarov's expandable + hash tables (see libiberty/hashtab.c). The abstraction penalty was + too high to continue using the generic form. This code knows + intrinsically how to calculate a hash value, and how to compare an + existing entry with a potential new one. Also, the ability to + delete members from the table has been removed. */ + +static unsigned int calc_hash (const unsigned char *, size_t); +static void ht_expand (hash_table *); +static double approx_sqrt (double); + +/* Calculate the hash of the string STR of length LEN. */ + +static unsigned int +calc_hash (const unsigned char *str, size_t len) +{ + size_t n = len; + unsigned int r = 0; + + while (n--) + r = HT_HASHSTEP (r, *str++); + + return HT_HASHFINISH (r, len); +} + +/* Initialize an identifier hashtable. */ + +hash_table * +ht_create (unsigned int order) +{ + unsigned int nslots = 1 << order; + hash_table *table; + + table = XCNEW (hash_table); + + /* Strings need no alignment. */ + _obstack_begin (&table->stack, 0, 0, + (void *(*) (long)) xmalloc, + (void (*) (void *)) free); + + obstack_alignment_mask (&table->stack) = 0; + + table->entries = XCNEWVEC (hashnode, nslots); + table->entries_owned = true; + table->nslots = nslots; + return table; +} + +/* Frees all memory associated with a hash table. */ + +void +ht_destroy (hash_table *table) +{ + obstack_free (&table->stack, NULL); + if (table->entries_owned) + free (table->entries); + free (table); +} + +/* Returns the hash entry for the a STR of length LEN. If that string + already exists in the table, returns the existing entry, and, if + INSERT is CPP_ALLOCED, frees the last obstack object. If the + identifier hasn't been seen before, and INSERT is CPP_NO_INSERT, + returns NULL. Otherwise insert and returns a new entry. A new + string is alloced if INSERT is CPP_ALLOC, otherwise INSERT is + CPP_ALLOCED and the item is assumed to be at the top of the + obstack. */ +hashnode +ht_lookup (hash_table *table, const unsigned char *str, size_t len, + enum ht_lookup_option insert) +{ + return ht_lookup_with_hash (table, str, len, calc_hash (str, len), + insert); +} + +hashnode +ht_lookup_with_hash (hash_table *table, const unsigned char *str, + size_t len, unsigned int hash, + enum ht_lookup_option insert) +{ + unsigned int hash2; + unsigned int index; + size_t sizemask; + hashnode node; + + sizemask = table->nslots - 1; + index = hash & sizemask; + table->searches++; + + node = table->entries[index]; + + if (node != NULL) + { + if (node->hash_value == hash + && HT_LEN (node) == (unsigned int) len + && !memcmp (HT_STR (node), str, len)) + { + if (insert == HT_ALLOCED) + /* The string we search for was placed at the end of the + obstack. Release it. */ + obstack_free (&table->stack, (void *) str); + return node; + } + + /* hash2 must be odd, so we're guaranteed to visit every possible + location in the table during rehashing. */ + hash2 = ((hash * 17) & sizemask) | 1; + + for (;;) + { + table->collisions++; + index = (index + hash2) & sizemask; + node = table->entries[index]; + if (node == NULL) + break; + + if (node->hash_value == hash + && HT_LEN (node) == (unsigned int) len + && !memcmp (HT_STR (node), str, len)) + { + if (insert == HT_ALLOCED) + /* The string we search for was placed at the end of the + obstack. Release it. */ + obstack_free (&table->stack, (void *) str); + return node; + } + } + } + + if (insert == HT_NO_INSERT) + return NULL; + + node = (*table->alloc_node) (table); + table->entries[index] = node; + + HT_LEN (node) = (unsigned int) len; + node->hash_value = hash; + if (insert == HT_ALLOC) + HT_STR (node) = (const unsigned char *) obstack_copy0 (&table->stack, + str, len); + else + HT_STR (node) = str; + + if (++table->nelements * 4 >= table->nslots * 3) + /* Must expand the string table. */ + ht_expand (table); + + return node; +} + +/* Double the size of a hash table, re-hashing existing entries. */ + +static void +ht_expand (hash_table *table) +{ + hashnode *nentries, *p, *limit; + unsigned int size, sizemask; + + size = table->nslots * 2; + nentries = XCNEWVEC (hashnode, size); + sizemask = size - 1; + + p = table->entries; + limit = p + table->nslots; + do + if (*p) + { + unsigned int index, hash, hash2; + + hash = (*p)->hash_value; + index = hash & sizemask; + + if (nentries[index]) + { + hash2 = ((hash * 17) & sizemask) | 1; + do + { + index = (index + hash2) & sizemask; + } + while (nentries[index]); + } + nentries[index] = *p; + } + while (++p < limit); + + if (table->entries_owned) + free (table->entries); + table->entries_owned = true; + table->entries = nentries; + table->nslots = size; +} + +/* For all nodes in TABLE, callback CB with parameters TABLE->PFILE, + the node, and V. */ +void +ht_forall (hash_table *table, ht_cb cb, const void *v) +{ + hashnode *p, *limit; + + p = table->entries; + limit = p + table->nslots; + do + if (*p) + { + if ((*cb) (table->pfile, *p, v) == 0) + break; + } + while (++p < limit); +} + +/* Restore the hash table. */ +void +ht_load (hash_table *ht, hashnode *entries, + unsigned int nslots, unsigned int nelements, + bool own) +{ + if (ht->entries_owned) + free (ht->entries); + ht->entries = entries; + ht->nslots = nslots; + ht->nelements = nelements; + ht->entries_owned = own; +} + +/* Dump allocation statistics to stderr. */ + +void +ht_dump_statistics (hash_table *table) +{ + size_t nelts, nids, overhead, headers; + size_t total_bytes, longest; + double sum_of_squares, exp_len, exp_len2, exp2_len; + hashnode *p, *limit; + +#define SCALE(x) ((unsigned long) ((x) < 1024*10 \ + ? (x) \ + : ((x) < 1024*1024*10 \ + ? (x) / 1024 \ + : (x) / (1024*1024)))) +#define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M')) + + total_bytes = longest = sum_of_squares = nids = 0; + p = table->entries; + limit = p + table->nslots; + do + if (*p) + { + size_t n = HT_LEN (*p); + + total_bytes += n; + sum_of_squares += (double) n * n; + if (n > longest) + longest = n; + nids++; + } + while (++p < limit); + + nelts = table->nelements; + overhead = obstack_memory_used (&table->stack) - total_bytes; + headers = table->nslots * sizeof (hashnode); + + fprintf (stderr, "\nString pool\nentries\t\t%lu\n", + (unsigned long) nelts); + fprintf (stderr, "identifiers\t%lu (%.2f%%)\n", + (unsigned long) nids, nids * 100.0 / nelts); + fprintf (stderr, "slots\t\t%lu\n", + (unsigned long) table->nslots); + fprintf (stderr, "bytes\t\t%lu%c (%lu%c overhead)\n", + SCALE (total_bytes), LABEL (total_bytes), + SCALE (overhead), LABEL (overhead)); + fprintf (stderr, "table size\t%lu%c\n", + SCALE (headers), LABEL (headers)); + + exp_len = (double)total_bytes / (double)nelts; + exp2_len = exp_len * exp_len; + exp_len2 = (double) sum_of_squares / (double) nelts; + + fprintf (stderr, "coll/search\t%.4f\n", + (double) table->collisions / (double) table->searches); + fprintf (stderr, "ins/search\t%.4f\n", + (double) nelts / (double) table->searches); + fprintf (stderr, "avg. entry\t%.2f bytes (+/- %.2f)\n", + exp_len, approx_sqrt (exp_len2 - exp2_len)); + fprintf (stderr, "longest entry\t%lu\n", + (unsigned long) longest); +#undef SCALE +#undef LABEL +} + +/* Return the approximate positive square root of a number N. This is for + statistical reports, not code generation. */ +static double +approx_sqrt (double x) +{ + double s, d; + + if (x < 0) + abort (); + if (x == 0) + return 0; + + s = x; + do + { + d = (s * s - x) / (2 * s); + s -= d; + } + while (d > .0001); + return s; +} diff --git a/support/cpp2/libcpp/system.h b/support/cpp2/libcpp/system.h new file mode 100644 index 00000000..3e0d89da --- /dev/null +++ b/support/cpp2/libcpp/system.h @@ -0,0 +1,437 @@ +/* Get common system includes and various definitions and declarations based + on autoconf macros. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 + Free Software Foundation, Inc. + +This file is part of libcpp (aka cpplib). + +GCC 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 2, or (at your option) any later +version. + +GCC 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 GCC; see the file COPYING. If not, write to the Free +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ + + +#ifndef LIBCPP_SYSTEM_H +#define LIBCPP_SYSTEM_H + +/* We must include stdarg.h before stdio.h. */ +#include + +#ifdef HAVE_STDDEF_H +# include +#endif + +#include + +/* Define a generic NULL if one hasn't already been defined. */ +#ifndef NULL +#define NULL 0 +#endif + +/* Use the unlocked open routines from libiberty. */ +#define fopen(PATH,MODE) fopen_unlocked(PATH,MODE) +#define fdopen(FILDES,MODE) fdopen_unlocked(FILDES,MODE) +#define freopen(PATH,MODE,STREAM) freopen_unlocked(PATH,MODE,STREAM) + +/* The compiler is not a multi-threaded application and therefore we + do not have to use the locking functions. In fact, using the locking + functions can cause the compiler to be significantly slower under + I/O bound conditions (such as -g -O0 on very large source files). + + HAVE_DECL_PUTC_UNLOCKED actually indicates whether or not the stdio + code is multi-thread safe by default. If it is set to 0, then do + not worry about using the _unlocked functions. + + fputs_unlocked, fwrite_unlocked, and fprintf_unlocked are + extensions and need to be prototyped by hand (since we do not + define _GNU_SOURCE). */ + +#if defined HAVE_DECL_PUTC_UNLOCKED && HAVE_DECL_PUTC_UNLOCKED + +# ifdef HAVE_PUTC_UNLOCKED +# undef putc +# define putc(C, Stream) putc_unlocked (C, Stream) +# endif +# ifdef HAVE_PUTCHAR_UNLOCKED +# undef putchar +# define putchar(C) putchar_unlocked (C) +# endif +# ifdef HAVE_GETC_UNLOCKED +# undef getc +# define getc(Stream) getc_unlocked (Stream) +# endif +# ifdef HAVE_GETCHAR_UNLOCKED +# undef getchar +# define getchar() getchar_unlocked () +# endif +# ifdef HAVE_FPUTC_UNLOCKED +# undef fputc +# define fputc(C, Stream) fputc_unlocked (C, Stream) +# endif + +# ifdef HAVE_CLEARERR_UNLOCKED +# undef clearerr +# define clearerr(Stream) clearerr_unlocked (Stream) +# if defined (HAVE_DECL_CLEARERR_UNLOCKED) && !HAVE_DECL_CLEARERR_UNLOCKED +extern void clearerr_unlocked (FILE *); +# endif +# endif +# ifdef HAVE_FEOF_UNLOCKED +# undef feof +# define feof(Stream) feof_unlocked (Stream) +# if defined (HAVE_DECL_FEOF_UNLOCKED) && !HAVE_DECL_FEOF_UNLOCKED +extern int feof_unlocked (FILE *); +# endif +# endif +# ifdef HAVE_FILENO_UNLOCKED +# undef fileno +# define fileno(Stream) fileno_unlocked (Stream) +# if defined (HAVE_DECL_FILENO_UNLOCKED) && !HAVE_DECL_FILENO_UNLOCKED +extern int fileno_unlocked (FILE *); +# endif +# endif +# ifdef HAVE_FFLUSH_UNLOCKED +# undef fflush +# define fflush(Stream) fflush_unlocked (Stream) +# if defined (HAVE_DECL_FFLUSH_UNLOCKED) && !HAVE_DECL_FFLUSH_UNLOCKED +extern int fflush_unlocked (FILE *); +# endif +# endif +# ifdef HAVE_FGETC_UNLOCKED +# undef fgetc +# define fgetc(Stream) fgetc_unlocked (Stream) +# if defined (HAVE_DECL_FGETC_UNLOCKED) && !HAVE_DECL_FGETC_UNLOCKED +extern int fgetc_unlocked (FILE *); +# endif +# endif +# ifdef HAVE_FGETS_UNLOCKED +# undef fgets +# define fgets(S, n, Stream) fgets_unlocked (S, n, Stream) +# if defined (HAVE_DECL_FGETS_UNLOCKED) && !HAVE_DECL_FGETS_UNLOCKED +extern char *fgets_unlocked (char *, int, FILE *); +# endif +# endif +# ifdef HAVE_FPUTS_UNLOCKED +# undef fputs +# define fputs(String, Stream) fputs_unlocked (String, Stream) +# if defined (HAVE_DECL_FPUTS_UNLOCKED) && !HAVE_DECL_FPUTS_UNLOCKED +extern int fputs_unlocked (const char *, FILE *); +# endif +# endif +# ifdef HAVE_FERROR_UNLOCKED +# undef ferror +# define ferror(Stream) ferror_unlocked (Stream) +# if defined (HAVE_DECL_FERROR_UNLOCKED) && !HAVE_DECL_FERROR_UNLOCKED +extern int ferror_unlocked (FILE *); +# endif +# endif +# ifdef HAVE_FREAD_UNLOCKED +# undef fread +# define fread(Ptr, Size, N, Stream) fread_unlocked (Ptr, Size, N, Stream) +# if defined (HAVE_DECL_FREAD_UNLOCKED) && !HAVE_DECL_FREAD_UNLOCKED +extern size_t fread_unlocked (void *, size_t, size_t, FILE *); +# endif +# endif +# ifdef HAVE_FWRITE_UNLOCKED +# undef fwrite +# define fwrite(Ptr, Size, N, Stream) fwrite_unlocked (Ptr, Size, N, Stream) +# if defined (HAVE_DECL_FWRITE_UNLOCKED) && !HAVE_DECL_FWRITE_UNLOCKED +extern size_t fwrite_unlocked (const void *, size_t, size_t, FILE *); +# endif +# endif +# ifdef HAVE_FPRINTF_UNLOCKED +# undef fprintf +/* We can't use a function-like macro here because we don't know if + we have varargs macros. */ +# define fprintf fprintf_unlocked +# if defined (HAVE_DECL_FPRINTF_UNLOCKED) && !HAVE_DECL_FPRINTF_UNLOCKED +extern int fprintf_unlocked (FILE *, const char *, ...); +# endif +# endif + +#endif + +/* ??? Glibc's fwrite/fread_unlocked macros cause + "warning: signed and unsigned type in conditional expression". */ +#undef fread_unlocked +#undef fwrite_unlocked + +#include +#include + +#if !defined (errno) && defined (HAVE_DECL_ERRNO) && !HAVE_DECL_ERRNO +extern int errno; +#endif + +/* Some of glibc's string inlines cause warnings. Plus we'd rather + rely on (and therefore test) GCC's string builtins. */ +#define __NO_STRING_INLINES + +#ifdef STRING_WITH_STRINGS +# include +# include +#else +# ifdef HAVE_STRING_H +# include +# else +# ifdef HAVE_STRINGS_H +# include +# endif +# endif +#endif + +#ifdef HAVE_STDLIB_H +# include +#endif + +#ifdef HAVE_UNISTD_H +# include +#endif + +#if HAVE_LIMITS_H +# include +#endif + +/* Infrastructure for defining missing _MAX and _MIN macros. Note that + macros defined with these cannot be used in #if. */ + +/* The extra casts work around common compiler bugs. */ +#define INTTYPE_SIGNED(t) (! ((t) 0 < (t) -1)) +/* The outer cast is needed to work around a bug in Cray C 5.0.3.0. + It is necessary at least when t == time_t. */ +#define INTTYPE_MINIMUM(t) ((t) (INTTYPE_SIGNED (t) \ + ? ~ (t) 0 << (sizeof(t) * CHAR_BIT - 1) : (t) 0)) +#define INTTYPE_MAXIMUM(t) ((t) (~ (t) 0 - INTTYPE_MINIMUM (t))) + +/* Use that infrastructure to provide a few constants. */ +#ifndef UCHAR_MAX +# define UCHAR_MAX INTTYPE_MAXIMUM (unsigned char) +#endif + +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# ifdef HAVE_TIME_H +# include +# endif +# endif +#endif + +#ifdef HAVE_FCNTL_H +# include +#else +# ifdef HAVE_SYS_FILE_H +# include +# endif +#endif + +#ifdef HAVE_LOCALE_H +# include +#endif + +#ifdef HAVE_LANGINFO_CODESET +# include +#endif + +#ifndef HAVE_SETLOCALE +# define setlocale(category, locale) (locale) +#endif + +#ifdef ENABLE_NLS +#include +#else +/* Stubs. */ +# undef dgettext +# define dgettext(package, msgid) (msgid) +#endif + +#ifndef _ +# define _(msgid) dgettext (PACKAGE, msgid) +#endif + +#ifndef N_ +# define N_(msgid) msgid +#endif + +/* Some systems define these in, e.g., param.h. We undefine these names + here to avoid the warnings. We prefer to use our definitions since we + know they are correct. */ + +#undef MIN +#undef MAX +#define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) +#define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) + +/* The HAVE_DECL_* macros are three-state, undefined, 0 or 1. If they + are defined to 0 then we must provide the relevant declaration + here. These checks will be in the undefined state while configure + is running so be careful to test "defined (HAVE_DECL_*)". */ + +#if defined (HAVE_DECL_ABORT) && !HAVE_DECL_ABORT +extern void abort (void); +#endif + +#if HAVE_SYS_STAT_H +# include +#endif + +/* Test if something is a normal file. */ +#ifndef S_ISREG +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif + +/* Test if something is a directory. */ +#ifndef S_ISDIR +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif + +/* Test if something is a character special file. */ +#ifndef S_ISCHR +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#endif + +/* Test if something is a block special file. */ +#ifndef S_ISBLK +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#endif + +/* Test if something is a socket. */ +#ifndef S_ISSOCK +# ifdef S_IFSOCK +# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +# else +# define S_ISSOCK(m) 0 +# endif +#endif + +/* Test if something is a FIFO. */ +#ifndef S_ISFIFO +# ifdef S_IFIFO +# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +# else +# define S_ISFIFO(m) 0 +# endif +#endif + +/* Approximate O_NOCTTY and O_BINARY. */ +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif +#ifndef O_BINARY +# define O_BINARY 0 +#endif + +/* Filename handling macros. */ +#include "filenames.h" + +/* Get libiberty declarations. */ +#include "libiberty.h" +#if defined(__APPLE__) && defined(__MACH__) +#include +#else +#include +#endif + +/* 1 if we have C99 designated initializers. + + ??? C99 designated initializers are not supported by most C++ + compilers, including G++. -- gdr, 2005-05-18 */ +#if !defined(HAVE_DESIGNATED_INITIALIZERS) +#if defined(__APPLE__) && (__MACH__) +#define HAVE_DESIGNATED_INITIALIZERS 0 +#else +#define HAVE_DESIGNATED_INITIALIZERS \ + ((!defined(__cplusplus) && (GCC_VERSION >= 2007)) \ + || (__STDC_VERSION__ >= 199901L)) +#endif +#endif + +/* Be conservative and only use enum bitfields with GCC. + FIXME: provide a complete autoconf test for buggy enum bitfields. */ + +#if (GCC_VERSION > 2000) +#define ENUM_BITFIELD(TYPE) __extension__ enum TYPE +#else +#define ENUM_BITFIELD(TYPE) unsigned int +#endif + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *) 0)->MEMBER) +#endif + +/* __builtin_expect(A, B) evaluates to A, but notifies the compiler that + the most likely value of A is B. This feature was added at some point + between 2.95 and 3.0. Let's use 3.0 as the lower bound for now. */ +#if (GCC_VERSION < 3000) +#define __builtin_expect(a, b) (a) +#endif + +/* Provide a fake boolean type. We make no attempt to use the + C99 _Bool, as it may not be available in the bootstrap compiler, + and even if it is, it is liable to be buggy. + This must be after all inclusion of system headers, as some of + them will mess us up. */ +#undef bool +#undef true +#undef false +#undef TRUE +#undef FALSE + +#ifndef __cplusplus +#define bool unsigned char +#endif +#define true 1 +#define false 0 + +/* Some compilers do not allow the use of unsigned char in bitfields. */ +#define BOOL_BITFIELD unsigned int + +/* Poison identifiers we do not want to use. */ +#if (GCC_VERSION >= 3000) +#undef calloc +#undef strdup +#undef malloc +#undef realloc + #pragma GCC poison calloc strdup + #pragma GCC poison malloc realloc + +/* Libiberty macros that are no longer used in GCC. */ +#undef ANSI_PROTOTYPES +#undef PTR_CONST +#undef LONG_DOUBLE +#undef VPARAMS +#undef VA_OPEN +#undef VA_FIXEDARG +#undef VA_CLOSE +#undef VA_START + #pragma GCC poison ANSI_PROTOTYPES PTR_CONST LONG_DOUBLE VPARAMS VA_OPEN \ + VA_FIXEDARG VA_CLOSE VA_START + +/* Note: not all uses of the `index' token (e.g. variable names and + structure members) have been eliminated. */ +#undef bcopy +#undef bzero +#undef bcmp +#undef rindex + #pragma GCC poison bcopy bzero bcmp rindex + +#endif /* GCC >= 3.0 */ + +/* SDCC specific */ +#include "sdcpp.h" + +#endif /* ! LIBCPP_SYSTEM_H */ diff --git a/support/cpp2/libcpp/traditional.c b/support/cpp2/libcpp/traditional.c new file mode 100644 index 00000000..a543348d --- /dev/null +++ b/support/cpp2/libcpp/traditional.c @@ -0,0 +1,1113 @@ +/* CPP Library - traditional lexical analysis and macro expansion. + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Contributed by Neil Booth, May 2002 + +This program 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 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "config.h" +#include "system.h" +#include "cpplib.h" +#include "internal.h" + +/* The replacement text of a function-like macro is stored as a + contiguous sequence of aligned blocks, each representing the text + between subsequent parameters. + + Each block comprises the text between its surrounding parameters, + the length of that text, and the one-based index of the following + parameter. The final block in the replacement text is easily + recognizable as it has an argument index of zero. */ + +struct block +{ + unsigned int text_len; + unsigned short arg_index; + uchar text[1]; +}; + +#define BLOCK_HEADER_LEN offsetof (struct block, text) +#define BLOCK_LEN(TEXT_LEN) CPP_ALIGN (BLOCK_HEADER_LEN + (TEXT_LEN)) + +/* Structure holding information about a function-like macro + invocation. */ +struct fun_macro +{ + /* Memory buffer holding the trad_arg array. */ + _cpp_buff *buff; + + /* An array of size the number of macro parameters + 1, containing + the offsets of the start of each macro argument in the output + buffer. The argument continues until the character before the + start of the next one. */ + size_t *args; + + /* The hashnode of the macro. */ + cpp_hashnode *node; + + /* The offset of the macro name in the output buffer. */ + size_t offset; + + /* The line the macro name appeared on. */ + unsigned int line; + + /* Zero-based index of argument being currently lexed. */ + unsigned int argc; +}; + +/* Lexing state. It is mostly used to prevent macro expansion. */ +enum ls {ls_none = 0, /* Normal state. */ + ls_fun_open, /* When looking for '('. */ + ls_fun_close, /* When looking for ')'. */ + ls_defined, /* After defined. */ + ls_defined_close, /* Looking for ')' of defined(). */ + ls_hash, /* After # in preprocessor conditional. */ + ls_predicate, /* After the predicate, maybe paren? */ + ls_answer}; /* In answer to predicate. */ + +/* Lexing TODO: Maybe handle space in escaped newlines. Stop lex.c + from recognizing comments and directives during its lexing pass. */ + +static const uchar *skip_whitespace (cpp_reader *, const uchar *, int); +static cpp_hashnode *lex_identifier (cpp_reader *, const uchar *); +static const uchar *copy_comment (cpp_reader *, const uchar *, int); +static void check_output_buffer (cpp_reader *, size_t); +static void push_replacement_text (cpp_reader *, cpp_hashnode *); +static bool scan_parameters (cpp_reader *, cpp_macro *); +static bool recursive_macro (cpp_reader *, cpp_hashnode *); +static void save_replacement_text (cpp_reader *, cpp_macro *, unsigned int); +static void maybe_start_funlike (cpp_reader *, cpp_hashnode *, const uchar *, + struct fun_macro *); +static void save_argument (struct fun_macro *, size_t); +static void replace_args_and_push (cpp_reader *, struct fun_macro *); +static size_t canonicalize_text (uchar *, const uchar *, size_t, uchar *); + +/* Ensures we have N bytes' space in the output buffer, and + reallocates it if not. */ +static void +check_output_buffer (cpp_reader *pfile, size_t n) +{ + /* We might need two bytes to terminate an unterminated comment, and + one more to terminate the line with a NUL. */ + n += 2 + 1; + + if (n > (size_t) (pfile->out.limit - pfile->out.cur)) + { + size_t size = pfile->out.cur - pfile->out.base; + size_t new_size = (size + n) * 3 / 2; + + pfile->out.base = XRESIZEVEC (unsigned char, pfile->out.base, new_size); + pfile->out.limit = pfile->out.base + new_size; + pfile->out.cur = pfile->out.base + size; + } +} + +/* Skip a C-style block comment in a macro as a result of -CC. + Buffer->cur points to the initial asterisk of the comment. */ +static void +skip_macro_block_comment (cpp_reader *pfile) +{ + const uchar *cur = pfile->buffer->cur; + + cur++; + if (*cur == '/') + cur++; + + /* People like decorating comments with '*', so check for '/' + instead for efficiency. */ + while(! (*cur++ == '/' && cur[-2] == '*') ) + ; + + pfile->buffer->cur = cur; +} + +/* CUR points to the asterisk introducing a comment in the current + context. IN_DEFINE is true if we are in the replacement text of a + macro. + + The asterisk and following comment is copied to the buffer pointed + to by pfile->out.cur, which must be of sufficient size. + Unterminated comments are diagnosed, and correctly terminated in + the output. pfile->out.cur is updated depending upon IN_DEFINE, + -C, -CC and pfile->state.in_directive. + + Returns a pointer to the first character after the comment in the + input buffer. */ +static const uchar * +copy_comment (cpp_reader *pfile, const uchar *cur, int in_define) +{ + bool unterminated, copy = false; + source_location src_loc = pfile->line_table->highest_line; + cpp_buffer *buffer = pfile->buffer; + + buffer->cur = cur; + if (pfile->context->prev) + unterminated = false, skip_macro_block_comment (pfile); + else + unterminated = _cpp_skip_block_comment (pfile); + + if (unterminated) + cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0, + "unterminated comment"); + + /* Comments in directives become spaces so that tokens are properly + separated when the ISO preprocessor re-lexes the line. The + exception is #define. */ + if (pfile->state.in_directive) + { + if (in_define) + { + if (CPP_OPTION (pfile, discard_comments_in_macro_exp)) + pfile->out.cur--; + else + copy = true; + } + else + pfile->out.cur[-1] = ' '; + } + else if (CPP_OPTION (pfile, discard_comments)) + pfile->out.cur--; + else + copy = true; + + if (copy) + { + size_t len = (size_t) (buffer->cur - cur); + memcpy (pfile->out.cur, cur, len); + pfile->out.cur += len; + if (unterminated) + { + *pfile->out.cur++ = '*'; + *pfile->out.cur++ = '/'; + } + } + + return buffer->cur; +} + +/* CUR points to any character in the input buffer. Skips over all + contiguous horizontal white space and NULs, including comments if + SKIP_COMMENTS, until reaching the first non-horizontal-whitespace + character or the end of the current context. Escaped newlines are + removed. + + The whitespace is copied verbatim to the output buffer, except that + comments are handled as described in copy_comment(). + pfile->out.cur is updated. + + Returns a pointer to the first character after the whitespace in + the input buffer. */ +static const uchar * +skip_whitespace (cpp_reader *pfile, const uchar *cur, int skip_comments) +{ + uchar *out = pfile->out.cur; + + for (;;) + { + unsigned int c = *cur++; + *out++ = c; + + if (is_nvspace (c)) + continue; + + if (c == '/' && *cur == '*' && skip_comments) + { + pfile->out.cur = out; + cur = copy_comment (pfile, cur, false /* in_define */); + out = pfile->out.cur; + continue; + } + + out--; + break; + } + + pfile->out.cur = out; + return cur - 1; +} + +/* Lexes and outputs an identifier starting at CUR, which is assumed + to point to a valid first character of an identifier. Returns + the hashnode, and updates out.cur. */ +static cpp_hashnode * +lex_identifier (cpp_reader *pfile, const uchar *cur) +{ + size_t len; + uchar *out = pfile->out.cur; + cpp_hashnode *result; + + do + *out++ = *cur++; + while (is_numchar (*cur)); + + CUR (pfile->context) = cur; + len = out - pfile->out.cur; + result = (cpp_hashnode *) ht_lookup (pfile->hash_table, pfile->out.cur, + len, HT_ALLOC); + pfile->out.cur = out; + return result; +} + +/* Overlays the true file buffer temporarily with text of length LEN + starting at START. The true buffer is restored upon calling + restore_buff(). */ +void +_cpp_overlay_buffer (cpp_reader *pfile, const uchar *start, size_t len) +{ + cpp_buffer *buffer = pfile->buffer; + + pfile->overlaid_buffer = buffer; + pfile->saved_cur = buffer->cur; + pfile->saved_rlimit = buffer->rlimit; + pfile->saved_line_base = buffer->next_line; + buffer->need_line = false; + + buffer->cur = start; + buffer->line_base = start; + buffer->rlimit = start + len; +} + +/* Restores a buffer overlaid by _cpp_overlay_buffer(). */ +void +_cpp_remove_overlay (cpp_reader *pfile) +{ + cpp_buffer *buffer = pfile->overlaid_buffer; + + buffer->cur = pfile->saved_cur; + buffer->rlimit = pfile->saved_rlimit; + buffer->line_base = pfile->saved_line_base; + buffer->need_line = true; + + pfile->overlaid_buffer = NULL; +} + +/* Reads a logical line into the output buffer. Returns TRUE if there + is more text left in the buffer. */ +bool +_cpp_read_logical_line_trad (cpp_reader *pfile) +{ + do + { + if (pfile->buffer->need_line && !_cpp_get_fresh_line (pfile)) + return false; + } + while (!_cpp_scan_out_logical_line (pfile, NULL) || pfile->state.skipping); + + return pfile->buffer != NULL; +} + +/* Set up state for finding the opening '(' of a function-like + macro. */ +static void +maybe_start_funlike (cpp_reader *pfile, cpp_hashnode *node, const uchar *start, struct fun_macro *macro) +{ + unsigned int n = node->value.macro->paramc + 1; + + if (macro->buff) + _cpp_release_buff (pfile, macro->buff); + macro->buff = _cpp_get_buff (pfile, n * sizeof (size_t)); + macro->args = (size_t *) BUFF_FRONT (macro->buff); + macro->node = node; + macro->offset = start - pfile->out.base; + macro->argc = 0; +} + +/* Save the OFFSET of the start of the next argument to MACRO. */ +static void +save_argument (struct fun_macro *macro, size_t offset) +{ + macro->argc++; + if (macro->argc <= macro->node->value.macro->paramc) + macro->args[macro->argc] = offset; +} + +/* Copies the next logical line in the current buffer (starting at + buffer->cur) to the output buffer. The output is guaranteed to + terminate with a NUL character. buffer->cur is updated. + + If MACRO is non-NULL, then we are scanning the replacement list of + MACRO, and we call save_replacement_text() every time we meet an + argument. */ +bool +_cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro) +{ + bool result = true; + cpp_context *context; + const uchar *cur; + uchar *out; + struct fun_macro fmacro; + unsigned int c, paren_depth = 0, quote; + enum ls lex_state = ls_none; + bool header_ok; + const uchar *start_of_input_line; + + fmacro.buff = NULL; + + quote = 0; + header_ok = pfile->state.angled_headers; + CUR (pfile->context) = pfile->buffer->cur; + RLIMIT (pfile->context) = pfile->buffer->rlimit; + pfile->out.cur = pfile->out.base; + pfile->out.first_line = pfile->line_table->highest_line; + /* start_of_input_line is needed to make sure that directives really, + really start at the first character of the line. */ + start_of_input_line = pfile->buffer->cur; + new_context: + context = pfile->context; + cur = CUR (context); + check_output_buffer (pfile, RLIMIT (context) - cur); + out = pfile->out.cur; + + for (;;) + { + if (!context->prev + && cur >= pfile->buffer->notes[pfile->buffer->cur_note].pos) + { + pfile->buffer->cur = cur; + _cpp_process_line_notes (pfile, false); + } + c = *cur++; + *out++ = c; + + /* Whitespace should "continue" out of the switch, + non-whitespace should "break" out of it. */ + switch (c) + { + case ' ': + case '\t': + case '\f': + case '\v': + case '\0': + continue; + + case '\n': + /* If this is a macro's expansion, pop it. */ + if (context->prev) + { + pfile->out.cur = out - 1; + _cpp_pop_context (pfile); + goto new_context; + } + + /* Omit the newline from the output buffer. */ + pfile->out.cur = out - 1; + pfile->buffer->cur = cur; + pfile->buffer->need_line = true; + CPP_INCREMENT_LINE (pfile, 0); + + if ((lex_state == ls_fun_open || lex_state == ls_fun_close) + && !pfile->state.in_directive + && _cpp_get_fresh_line (pfile)) + { + /* Newlines in arguments become a space, but we don't + clear any in-progress quote. */ + if (lex_state == ls_fun_close) + out[-1] = ' '; + cur = pfile->buffer->cur; + continue; + } + goto done; + + case '<': + if (header_ok) + quote = '>'; + break; + case '>': + if (c == quote) + quote = 0; + break; + + case '"': + case '\'': + if (c == quote) + quote = 0; + else if (!quote) + quote = c; + break; + + case '\\': + /* Skip escaped quotes here, it's easier than above. */ + if (*cur == '\\' || *cur == '"' || *cur == '\'') + *out++ = *cur++; + break; + + case '/': + /* Traditional CPP does not recognize comments within + literals. */ + if (!quote && *cur == '*') + { + pfile->out.cur = out; + cur = copy_comment (pfile, cur, macro != 0); + out = pfile->out.cur; + continue; + } + break; + + case '_': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': + case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': + case 's': case 't': case 'u': case 'v': case 'w': case 'x': + case 'y': case 'z': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': + case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': + case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': + if (!pfile->state.skipping && (quote == 0 || macro)) + { + cpp_hashnode *node; + uchar *out_start = out - 1; + + pfile->out.cur = out_start; + node = lex_identifier (pfile, cur - 1); + out = pfile->out.cur; + cur = CUR (context); + + if (node->type == NT_MACRO + /* Should we expand for ls_answer? */ + && (lex_state == ls_none || lex_state == ls_fun_open) + && !pfile->state.prevent_expansion) + { + /* Macros invalidate MI optimization. */ + pfile->mi_valid = false; + if (! (node->flags & NODE_BUILTIN) + && node->value.macro->fun_like) + { + maybe_start_funlike (pfile, node, out_start, &fmacro); + lex_state = ls_fun_open; + fmacro.line = pfile->line_table->highest_line; + continue; + } + else if (!recursive_macro (pfile, node)) + { + /* Remove the object-like macro's name from the + output, and push its replacement text. */ + pfile->out.cur = out_start; + push_replacement_text (pfile, node); + lex_state = ls_none; + goto new_context; + } + } + else if (macro && (node->flags & NODE_MACRO_ARG) != 0) + { + /* Found a parameter in the replacement text of a + #define. Remove its name from the output. */ + pfile->out.cur = out_start; + save_replacement_text (pfile, macro, node->value.arg_index); + out = pfile->out.base; + } + else if (lex_state == ls_hash) + { + lex_state = ls_predicate; + continue; + } + else if (pfile->state.in_expression + && node == pfile->spec_nodes.n_defined) + { + lex_state = ls_defined; + continue; + } + } + break; + + case '(': + if (quote == 0) + { + paren_depth++; + if (lex_state == ls_fun_open) + { + if (recursive_macro (pfile, fmacro.node)) + lex_state = ls_none; + else + { + lex_state = ls_fun_close; + paren_depth = 1; + out = pfile->out.base + fmacro.offset; + fmacro.args[0] = fmacro.offset; + } + } + else if (lex_state == ls_predicate) + lex_state = ls_answer; + else if (lex_state == ls_defined) + lex_state = ls_defined_close; + } + break; + + case ',': + if (quote == 0 && lex_state == ls_fun_close && paren_depth == 1) + save_argument (&fmacro, out - pfile->out.base); + break; + + case ')': + if (quote == 0) + { + paren_depth--; + if (lex_state == ls_fun_close && paren_depth == 0) + { + cpp_macro *m = fmacro.node->value.macro; + + m->used = 1; + lex_state = ls_none; + save_argument (&fmacro, out - pfile->out.base); + + /* A single zero-length argument is no argument. */ + if (fmacro.argc == 1 + && m->paramc == 0 + && out == pfile->out.base + fmacro.offset + 1) + fmacro.argc = 0; + + if (_cpp_arguments_ok (pfile, m, fmacro.node, fmacro.argc)) + { + /* Remove the macro's invocation from the + output, and push its replacement text. */ + pfile->out.cur = (pfile->out.base + + fmacro.offset); + CUR (context) = cur; + replace_args_and_push (pfile, &fmacro); + goto new_context; + } + } + else if (lex_state == ls_answer || lex_state == ls_defined_close) + lex_state = ls_none; + } + break; + + case '#': + if (cur - 1 == start_of_input_line + /* A '#' from a macro doesn't start a directive. */ + && !pfile->context->prev + && !pfile->state.in_directive) + { + /* A directive. With the way _cpp_handle_directive + currently works, we only want to call it if either we + know the directive is OK, or we want it to fail and + be removed from the output. If we want it to be + passed through (the assembler case) then we must not + call _cpp_handle_directive. */ + pfile->out.cur = out; + cur = skip_whitespace (pfile, cur, true /* skip_comments */); + out = pfile->out.cur; + + if (*cur == '\n') + { + /* Null directive. Ignore it and don't invalidate + the MI optimization. */ + pfile->buffer->need_line = true; + CPP_INCREMENT_LINE (pfile, 0); + result = false; + goto done; + } + else + { + bool do_it = false; + + if (is_numstart (*cur) + && CPP_OPTION (pfile, lang) != CLK_ASM) + do_it = true; + else if (is_idstart (*cur)) + /* Check whether we know this directive, but don't + advance. */ + do_it = lex_identifier (pfile, cur)->is_directive; + + if (do_it || CPP_OPTION (pfile, lang) != CLK_ASM) + { + /* This is a kludge. We want to have the ISO + preprocessor lex the next token. */ + pfile->buffer->cur = cur; + _cpp_handle_directive (pfile, false /* indented */); + result = false; + goto done; + } + } + } + + if (pfile->state.in_expression) + { + lex_state = ls_hash; + continue; + } + break; + + default: + break; + } + + /* Non-whitespace disables MI optimization and stops treating + '<' as a quote in #include. */ + header_ok = false; + if (!pfile->state.in_directive) + pfile->mi_valid = false; + + if (lex_state == ls_none) + continue; + + /* Some of these transitions of state are syntax errors. The + ISO preprocessor will issue errors later. */ + if (lex_state == ls_fun_open) + /* Missing '('. */ + lex_state = ls_none; + else if (lex_state == ls_hash + || lex_state == ls_predicate + || lex_state == ls_defined) + lex_state = ls_none; + + /* ls_answer and ls_defined_close keep going until ')'. */ + } + + done: + if (fmacro.buff) + _cpp_release_buff (pfile, fmacro.buff); + + if (lex_state == ls_fun_close) + cpp_error_with_line (pfile, CPP_DL_ERROR, fmacro.line, 0, + "unterminated argument list invoking macro \"%s\"", + NODE_NAME (fmacro.node)); + return result; +} + +/* Push a context holding the replacement text of the macro NODE on + the context stack. NODE is either object-like, or a function-like + macro with no arguments. */ +static void +push_replacement_text (cpp_reader *pfile, cpp_hashnode *node) +{ + size_t len; + const uchar *text; + uchar *buf; + + if (node->flags & NODE_BUILTIN) + { + text = _cpp_builtin_macro_text (pfile, node); + len = ustrlen (text); + buf = _cpp_unaligned_alloc (pfile, len + 1); + memcpy (buf, text, len); + buf[len]='\n'; + text = buf; + } + else + { + cpp_macro *macro = node->value.macro; + macro->used = 1; + text = macro->exp.text; + macro->traditional = 1; + len = macro->count; + } + + _cpp_push_text_context (pfile, node, text, len); +} + +/* Returns TRUE if traditional macro recursion is detected. */ +static bool +recursive_macro (cpp_reader *pfile, cpp_hashnode *node) +{ + bool recursing = !!(node->flags & NODE_DISABLED); + + /* Object-like macros that are already expanding are necessarily + recursive. + + However, it is possible to have traditional function-like macros + that are not infinitely recursive but recurse to any given depth. + Further, it is easy to construct examples that get ever longer + until the point they stop recursing. So there is no easy way to + detect true recursion; instead we assume any expansion more than + 20 deep since the first invocation of this macro must be + recursing. */ + if (recursing && node->value.macro->fun_like) + { + size_t depth = 0; + cpp_context *context = pfile->context; + + do + { + depth++; + if (context->macro == node && depth > 20) + break; + context = context->prev; + } + while (context); + recursing = context != NULL; + } + + if (recursing) + cpp_error (pfile, CPP_DL_ERROR, + "detected recursion whilst expanding macro \"%s\"", + NODE_NAME (node)); + + return recursing; +} + +/* Return the length of the replacement text of a function-like or + object-like non-builtin macro. */ +size_t +_cpp_replacement_text_len (const cpp_macro *macro) +{ + size_t len; + + if (macro->fun_like && (macro->paramc != 0)) + { + const uchar *exp; + + len = 0; + for (exp = macro->exp.text;;) + { + struct block *b = (struct block *) exp; + + len += b->text_len; + if (b->arg_index == 0) + break; + len += NODE_LEN (macro->params[b->arg_index - 1]); + exp += BLOCK_LEN (b->text_len); + } + } + else + len = macro->count; + + return len; +} + +/* Copy the replacement text of MACRO to DEST, which must be of + sufficient size. It is not NUL-terminated. The next character is + returned. */ +uchar * +_cpp_copy_replacement_text (const cpp_macro *macro, uchar *dest) +{ + if (macro->fun_like && (macro->paramc != 0)) + { + const uchar *exp; + + for (exp = macro->exp.text;;) + { + struct block *b = (struct block *) exp; + cpp_hashnode *param; + + memcpy (dest, b->text, b->text_len); + dest += b->text_len; + if (b->arg_index == 0) + break; + param = macro->params[b->arg_index - 1]; + memcpy (dest, NODE_NAME (param), NODE_LEN (param)); + dest += NODE_LEN (param); + exp += BLOCK_LEN (b->text_len); + } + } + else + { + memcpy (dest, macro->exp.text, macro->count); + dest += macro->count; + } + + return dest; +} + +/* Push a context holding the replacement text of the macro NODE on + the context stack. NODE is either object-like, or a function-like + macro with no arguments. */ +static void +replace_args_and_push (cpp_reader *pfile, struct fun_macro *fmacro) +{ + cpp_macro *macro = fmacro->node->value.macro; + + if (macro->paramc == 0) + push_replacement_text (pfile, fmacro->node); + else + { + const uchar *exp; + uchar *p; + _cpp_buff *buff; + size_t len = 0; + + /* Calculate the length of the argument-replaced text. */ + for (exp = macro->exp.text;;) + { + struct block *b = (struct block *) exp; + + len += b->text_len; + if (b->arg_index == 0) + break; + len += (fmacro->args[b->arg_index] + - fmacro->args[b->arg_index - 1] - 1); + exp += BLOCK_LEN (b->text_len); + } + + /* Allocate room for the expansion plus \n. */ + buff = _cpp_get_buff (pfile, len + 1); + + /* Copy the expansion and replace arguments. */ + p = BUFF_FRONT (buff); + for (exp = macro->exp.text;;) + { + struct block *b = (struct block *) exp; + size_t arglen; + + memcpy (p, b->text, b->text_len); + p += b->text_len; + if (b->arg_index == 0) + break; + arglen = (fmacro->args[b->arg_index] + - fmacro->args[b->arg_index - 1] - 1); + memcpy (p, pfile->out.base + fmacro->args[b->arg_index - 1], + arglen); + p += arglen; + exp += BLOCK_LEN (b->text_len); + } + + /* \n-terminate. */ + *p = '\n'; + _cpp_push_text_context (pfile, fmacro->node, BUFF_FRONT (buff), len); + + /* So we free buffer allocation when macro is left. */ + pfile->context->buff = buff; + } +} + +/* Read and record the parameters, if any, of a function-like macro + definition. Destroys pfile->out.cur. + + Returns true on success, false on failure (syntax error or a + duplicate parameter). On success, CUR (pfile->context) is just + past the closing parenthesis. */ +static bool +scan_parameters (cpp_reader *pfile, cpp_macro *macro) +{ + const uchar *cur = CUR (pfile->context) + 1; + bool ok; + + for (;;) + { + cur = skip_whitespace (pfile, cur, true /* skip_comments */); + + if (is_idstart (*cur)) + { + ok = false; + if (_cpp_save_parameter (pfile, macro, lex_identifier (pfile, cur))) + break; + cur = skip_whitespace (pfile, CUR (pfile->context), + true /* skip_comments */); + if (*cur == ',') + { + cur++; + continue; + } + ok = (*cur == ')'); + break; + } + + ok = (*cur == ')' && macro->paramc == 0); + break; + } + + if (!ok) + cpp_error (pfile, CPP_DL_ERROR, "syntax error in macro parameter list"); + + CUR (pfile->context) = cur + (*cur == ')'); + + return ok; +} + +/* Save the text from pfile->out.base to pfile->out.cur as + the replacement text for the current macro, followed by argument + ARG_INDEX, with zero indicating the end of the replacement + text. */ +static void +save_replacement_text (cpp_reader *pfile, cpp_macro *macro, + unsigned int arg_index) +{ + size_t len = pfile->out.cur - pfile->out.base; + uchar *exp; + + if (macro->paramc == 0) + { + /* Object-like and function-like macros without parameters + simply store their \n-terminated replacement text. */ + exp = _cpp_unaligned_alloc (pfile, len + 1); + memcpy (exp, pfile->out.base, len); + exp[len] = '\n'; + macro->exp.text = exp; + macro->traditional = 1; + macro->count = len; + } + else + { + /* Store the text's length (unsigned int), the argument index + (unsigned short, base 1) and then the text. */ + size_t blen = BLOCK_LEN (len); + struct block *block; + + if (macro->count + blen > BUFF_ROOM (pfile->a_buff)) + _cpp_extend_buff (pfile, &pfile->a_buff, macro->count + blen); + + exp = BUFF_FRONT (pfile->a_buff); + block = (struct block *) (exp + macro->count); + macro->exp.text = exp; + macro->traditional = 1; + + /* Write out the block information. */ + block->text_len = len; + block->arg_index = arg_index; + memcpy (block->text, pfile->out.base, len); + + /* Lex the rest into the start of the output buffer. */ + pfile->out.cur = pfile->out.base; + + macro->count += blen; + + /* If we've finished, commit the memory. */ + if (arg_index == 0) + BUFF_FRONT (pfile->a_buff) += macro->count; + } +} + +/* Analyze and save the replacement text of a macro. Returns true on + success. */ +bool +_cpp_create_trad_definition (cpp_reader *pfile, cpp_macro *macro) +{ + const uchar *cur; + uchar *limit; + cpp_context *context = pfile->context; + + /* The context has not been set up for command line defines, and CUR + has not been updated for the macro name for in-file defines. */ + pfile->out.cur = pfile->out.base; + CUR (context) = pfile->buffer->cur; + RLIMIT (context) = pfile->buffer->rlimit; + check_output_buffer (pfile, RLIMIT (context) - CUR (context)); + + /* Is this a function-like macro? */ + if (* CUR (context) == '(') + { + bool ok = scan_parameters (pfile, macro); + + /* Remember the params so we can clear NODE_MACRO_ARG flags. */ + macro->params = (cpp_hashnode **) BUFF_FRONT (pfile->a_buff); + + /* Setting macro to NULL indicates an error occurred, and + prevents unnecessary work in _cpp_scan_out_logical_line. */ + if (!ok) + macro = NULL; + else + { + BUFF_FRONT (pfile->a_buff) = (uchar *) ¯o->params[macro->paramc]; + macro->fun_like = 1; + } + } + + /* Skip leading whitespace in the replacement text. */ + pfile->buffer->cur + = skip_whitespace (pfile, CUR (context), + CPP_OPTION (pfile, discard_comments_in_macro_exp)); + + pfile->state.prevent_expansion++; + _cpp_scan_out_logical_line (pfile, macro); + pfile->state.prevent_expansion--; + + if (!macro) + return false; + + /* Skip trailing white space. */ + cur = pfile->out.base; + limit = pfile->out.cur; + while (limit > cur && is_space (limit[-1])) + limit--; + pfile->out.cur = limit; + save_replacement_text (pfile, macro, 0); + + return true; +} + +/* Copy SRC of length LEN to DEST, but convert all contiguous + whitespace to a single space, provided it is not in quotes. The + quote currently in effect is pointed to by PQUOTE, and is updated + by the function. Returns the number of bytes copied. */ +static size_t +canonicalize_text (uchar *dest, const uchar *src, size_t len, uchar *pquote) +{ + uchar *orig_dest = dest; + uchar quote = *pquote; + + while (len) + { + if (is_space (*src) && !quote) + { + do + src++, len--; + while (len && is_space (*src)); + *dest++ = ' '; + } + else + { + if (*src == '\'' || *src == '"') + { + if (!quote) + quote = *src; + else if (quote == *src) + quote = 0; + } + *dest++ = *src++, len--; + } + } + + *pquote = quote; + return dest - orig_dest; +} + +/* Returns true if MACRO1 and MACRO2 have expansions different other + than in the form of their whitespace. */ +bool +_cpp_expansions_different_trad (const cpp_macro *macro1, + const cpp_macro *macro2) +{ + uchar *p1 = XNEWVEC (uchar, macro1->count + macro2->count); + uchar *p2 = p1 + macro1->count; + uchar quote1 = 0, quote2 = 0; + bool mismatch; + size_t len1, len2; + + if (macro1->paramc > 0) + { + const uchar *exp1 = macro1->exp.text, *exp2 = macro2->exp.text; + + mismatch = true; + for (;;) + { + struct block *b1 = (struct block *) exp1; + struct block *b2 = (struct block *) exp2; + + if (b1->arg_index != b2->arg_index) + break; + + len1 = canonicalize_text (p1, b1->text, b1->text_len, "e1); + len2 = canonicalize_text (p2, b2->text, b2->text_len, "e2); + if (len1 != len2 || memcmp (p1, p2, len1)) + break; + if (b1->arg_index == 0) + { + mismatch = false; + break; + } + exp1 += BLOCK_LEN (b1->text_len); + exp2 += BLOCK_LEN (b2->text_len); + } + } + else + { + len1 = canonicalize_text (p1, macro1->exp.text, macro1->count, "e1); + len2 = canonicalize_text (p2, macro2->exp.text, macro2->count, "e2); + mismatch = (len1 != len2 || memcmp (p1, p2, len1)); + } + + free (p1); + return mismatch; +} diff --git a/support/cpp2/libcpp/ucnid.h b/support/cpp2/libcpp/ucnid.h new file mode 100644 index 00000000..7323dccb --- /dev/null +++ b/support/cpp2/libcpp/ucnid.h @@ -0,0 +1,801 @@ +/* Unicode characters and various properties. + Copyright (C) 2003, 2005 Free Software Foundation, Inc. + + This program 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 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + + Copyright (C) 1991-2005 Unicode, Inc. All rights reserved. + Distributed under the Terms of Use in + http://www.unicode.org/copyright.html. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of the Unicode data files and any associated + documentation (the "Data Files") or Unicode software and any + associated documentation (the "Software") to deal in the Data Files + or Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, and/or + sell copies of the Data Files or Software, and to permit persons to + whom the Data Files or Software are furnished to do so, provided + that (a) the above copyright notice(s) and this permission notice + appear with all copies of the Data Files or Software, (b) both the + above copyright notice(s) and this permission notice appear in + associated documentation, and (c) there is clear notice in each + modified Data File or in the Software as well as in the + documentation associated with the Data File(s) or Software that the + data or software has been modified. + + THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY + OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE + COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR + ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY + DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + OF THE DATA FILES OR SOFTWARE. + + Except as contained in this notice, the name of a copyright holder + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in these Data Files or Software without prior + written authorization of the copyright holder. */ + +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x00a9 }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x00aa }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x00b4 }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x00b5 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x00b6 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x00b7 }, +{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x00b9 }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x00ba }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x00bf }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x00d6 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x00d7 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x00f6 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x00f7 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0131 }, +{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x0133 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x013e }, +{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x0140 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0148 }, +{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x0149 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x017e }, +{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x017f }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x01c3 }, +{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x01cc }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x01f0 }, +{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x01f3 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x01f5 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x01f9 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0217 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x024f }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x02a8 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x02af }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x02b8 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x02ba }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x02bb }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x02bc }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x02c1 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x02cf }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x02d1 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x02df }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x02e4 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0379 }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x037a }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0383 }, +{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0x0384 }, +{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x0385 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0386 }, +{ 0| 0| 0|CID| 0| 0| 0, 0, 0x0387 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x038a }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x038b }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x038c }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x038d }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x03a1 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x03a2 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x03ce }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x03cf }, +{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x03d6 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x03d9 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x03da }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x03db }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x03dc }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x03dd }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x03de }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x03df }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x03e0 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x03e1 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x03ef }, +{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x03f2 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x03f3 }, +{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x0400 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x040c }, +{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x040d }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x040e }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x044f }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0450 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x045c }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x045d }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0481 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x048f }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x04c4 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x04c6 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x04c8 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x04ca }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x04cc }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x04cf }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x04eb }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x04ed }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x04f5 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x04f7 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x04f9 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0530 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0556 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0558 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0559 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0560 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0586 }, +{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x0587 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x05af }, +{ C99| 0| 0|CID|NFC|NKC| 0, 10, 0x05b0 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 11, 0x05b1 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 12, 0x05b2 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 13, 0x05b3 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 14, 0x05b4 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 15, 0x05b5 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 16, 0x05b6 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 17, 0x05b7 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 18, 0x05b8 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 19, 0x05b9 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x05ba }, +{ C99| 0| 0|CID|NFC|NKC| 0, 20, 0x05bb }, +{ C99| 0| 0|CID|NFC|NKC| 0, 21, 0x05bc }, +{ C99| 0| 0|CID|NFC|NKC| 0, 22, 0x05bd }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x05be }, +{ C99| 0| 0|CID|NFC|NKC| 0, 23, 0x05bf }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x05c0 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 24, 0x05c1 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 25, 0x05c2 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x05cf }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x05ea }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x05ef }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x05f2 }, +{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x05f4 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0620 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x063a }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x063f }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x064a }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 27, 0x064b }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 28, 0x064c }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 29, 0x064d }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 30, 0x064e }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 31, 0x064f }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 32, 0x0650 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 33, 0x0651 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 34, 0x0652 }, +{ 0| 0| 0|CID|NFC|NKC|CTX, 0, 0x065f }, +{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x0669 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x066f }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0674 }, +{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x0678 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x06b7 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x06b9 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x06be }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x06bf }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x06ce }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x06cf }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x06d5 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x06d6 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x06d7 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x06d8 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x06d9 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x06da }, +{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x06db }, +{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x06dc }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x06e4 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x06e6 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 230, 0x06e7 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x06e8 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x06e9 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 220, 0x06ea }, +{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x06eb }, +{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x06ec }, +{ C99| 0| 0|CID|NFC|NKC| 0, 220, 0x06ed }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x06ef }, +{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x06f9 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0900 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0903 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0904 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0939 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x093c }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x094c }, +{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x094d }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x094f }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0950 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x0951 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 220, 0x0952 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0957 }, +{ C99| 0|CXX|CID| 0| 0| 0, 0, 0x095f }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0962 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0963 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0965 }, +{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x096f }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0980 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0983 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0984 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x098c }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x098e }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0990 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0992 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x09a8 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x09a9 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x09b0 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x09b1 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x09b2 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x09b5 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x09b9 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x09bd }, +{ C99| 0| 0|CID|NFC|NKC|CTX, 0, 0x09be }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x09c4 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x09c6 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x09c8 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x09ca }, +{ C99| 0| 0| 0|NFC|NKC| 0, 0, 0x09cb }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x09cc }, +{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x09cd }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x09db }, +{ C99| 0|CXX|CID| 0| 0| 0, 0, 0x09dd }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x09de }, +{ C99| 0|CXX|CID| 0| 0| 0, 0, 0x09df }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x09e1 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x09e3 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x09e5 }, +{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x09ef }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x09f1 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a01 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0a02 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a04 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a0a }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a0e }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a10 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a12 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a28 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a29 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a30 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a31 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a32 }, +{ C99| 0|CXX|CID| 0| 0| 0, 0, 0x0a33 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a34 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a35 }, +{ C99| 0|CXX|CID| 0| 0| 0, 0, 0x0a36 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a37 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a39 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a3d }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0a42 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a46 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0a48 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a4a }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0a4c }, +{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x0a4d }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a58 }, +{ C99| 0|CXX|CID| 0| 0| 0, 0, 0x0a5b }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a5c }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a5d }, +{ C99| 0|CXX|CID| 0| 0| 0, 0, 0x0a5e }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a65 }, +{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x0a6f }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a73 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0a74 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a80 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0a83 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a84 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a8b }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a8c }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a8d }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a8e }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a91 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a92 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0aa8 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0aa9 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ab0 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ab1 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ab3 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ab4 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ab9 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0abc }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0ac5 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ac6 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0ac9 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0aca }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0acc }, +{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x0acd }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0acf }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0ad0 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0adf }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ae0 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ae5 }, +{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x0aef }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b00 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0b03 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b04 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b0c }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b0e }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b10 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b12 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b28 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b29 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b30 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b31 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b33 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b35 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b39 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b3c }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0b3d }, +{ C99| 0| 0|CID|NFC|NKC|CTX, 0, 0x0b3e }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0b43 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b46 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0b48 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b4a }, +{ C99| 0| 0| 0|NFC|NKC| 0, 0, 0x0b4b }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0b4c }, +{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x0b4d }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b5b }, +{ C99| 0|CXX|CID| 0| 0| 0, 0, 0x0b5d }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b5e }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b61 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b65 }, +{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x0b6f }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b81 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0b83 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b84 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b8a }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b8d }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b90 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b91 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b95 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b98 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b9a }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b9b }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b9c }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b9d }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b9f }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ba2 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ba4 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ba7 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0baa }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0bad }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0bb5 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0bb6 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0bb9 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0bbd }, +{ C99| 0| 0|CID|NFC|NKC|CTX, 0, 0x0bbe }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0bc2 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0bc5 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0bc8 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0bc9 }, +{ C99| 0| 0| 0|NFC|NKC| 0, 0, 0x0bcb }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0bcc }, +{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x0bcd }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0be6 }, +{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x0bef }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c00 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0c03 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c04 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0c0c }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c0d }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0c10 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c11 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0c28 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c29 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0c33 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c34 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0c39 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c3d }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0c44 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c45 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0c48 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c49 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0c4c }, +{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x0c4d }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c5f }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0c61 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c65 }, +{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x0c6f }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c81 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0c83 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c84 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0c8c }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c8d }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0c90 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c91 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ca8 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ca9 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0cb3 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0cb4 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0cb9 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0cbd }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0cc1 }, +{ C99| 0| 0|CID|NFC|NKC|CTX, 0, 0x0cc2 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0cc4 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0cc5 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0cc8 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0cc9 }, +{ C99| 0| 0| 0|NFC|NKC| 0, 0, 0x0cca }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0ccc }, +{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x0ccd }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0cdd }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0cde }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0cdf }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ce1 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ce5 }, +{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x0cef }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0d01 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0d03 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0d04 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0d0c }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0d0d }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0d10 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0d11 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0d28 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0d29 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0d39 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0d3d }, +{ C99| 0| 0|CID|NFC|NKC|CTX, 0, 0x0d3e }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0d43 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0d45 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0d48 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0d49 }, +{ C99| 0| 0| 0|NFC|NKC| 0, 0, 0x0d4b }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0d4c }, +{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x0d4d }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0d5f }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0d61 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0d65 }, +{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x0d6f }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0e00 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e30 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0e31 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e32 }, +{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x0e33 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0e37 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 103, 0x0e38 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 103, 0x0e39 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x0e3a }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0e3f }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e46 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0e47 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 107, 0x0e48 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 107, 0x0e49 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0e4e }, +{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e4f }, +{ C99|DIG|CXX|CID|NFC|NKC| 0, 0, 0x0e59 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e5b }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0e80 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e82 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0e83 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e84 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0e86 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e88 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0e89 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e8a }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0e8c }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e8d }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0e93 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e97 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0e98 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e9f }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ea0 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ea3 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ea4 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ea5 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ea6 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ea7 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ea9 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0eab }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0eac }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0eae }, +{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x0eaf }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0eb0 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0eb1 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0eb2 }, +{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x0eb3 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0eb7 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 118, 0x0eb8 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 118, 0x0eb9 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0eba }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0ebc }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ebd }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ebf }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ec4 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ec5 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ec6 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ec7 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 122, 0x0ec8 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 122, 0x0ec9 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 122, 0x0eca }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0ecd }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ecf }, +{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x0ed9 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0edb }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x0edd }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0eff }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f00 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f17 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 220, 0x0f18 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 220, 0x0f19 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f1f }, +{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x0f33 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f34 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 220, 0x0f35 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f36 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 220, 0x0f37 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f38 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 216, 0x0f39 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f3d }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f42 }, +{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f43 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f47 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f48 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f4c }, +{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f4d }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f51 }, +{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f52 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f56 }, +{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f57 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f5b }, +{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f5c }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f68 }, +{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f69 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f70 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 129, 0x0f71 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 130, 0x0f72 }, +{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f73 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 132, 0x0f74 }, +{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f76 }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x0f77 }, +{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f78 }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x0f79 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 130, 0x0f7a }, +{ C99| 0| 0|CID|NFC|NKC| 0, 130, 0x0f7b }, +{ C99| 0| 0|CID|NFC|NKC| 0, 130, 0x0f7c }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f7f }, +{ C99| 0| 0|CID|NFC|NKC| 0, 130, 0x0f80 }, +{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f81 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x0f82 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x0f83 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x0f84 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f85 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x0f86 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f8b }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f8f }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f92 }, +{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f93 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f95 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f96 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f97 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f98 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f9c }, +{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f9d }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0fa1 }, +{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0fa2 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0fa6 }, +{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0fa7 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0fab }, +{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0fac }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0fad }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0fb0 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0fb7 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0fb8 }, +{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0fb9 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x109f }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x10c5 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x10cf }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x10f6 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x10ff }, +{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x1159 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1160 }, +{ 0| 0|CXX|CID|NFC|NKC|CTX, 0, 0x1175 }, +{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x11a2 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x11a7 }, +{ 0| 0|CXX|CID|NFC|NKC|CTX, 0, 0x11c2 }, +{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x11f9 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1dff }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1e99 }, +{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x1e9a }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x1e9b }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1e9f }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1ef9 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1eff }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f15 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1f17 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f1d }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1f1f }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f45 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1f47 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f4d }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1f4f }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f57 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1f58 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f59 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1f5a }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f5b }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1f5c }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f5d }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1f5e }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f70 }, +{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1f71 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f72 }, +{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1f73 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f74 }, +{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1f75 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f76 }, +{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1f77 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f78 }, +{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1f79 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f7a }, +{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1f7b }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f7c }, +{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1f7d }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1f7f }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fb4 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1fb5 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fba }, +{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1fbb }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fbc }, +{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x1fbd }, +{ C99| 0| 0| 0| 0| 0| 0, 0, 0x1fbe }, +{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x1fc1 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fc4 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1fc5 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fc8 }, +{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1fc9 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fca }, +{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1fcb }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fcc }, +{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x1fcf }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fd2 }, +{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1fd3 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1fd5 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fda }, +{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1fdb }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1fdf }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fe2 }, +{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1fe3 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fea }, +{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1feb }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fec }, +{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x1ff1 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1ff4 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1ff5 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1ff8 }, +{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1ff9 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1ffa }, +{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1ffb }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1ffc }, +{ 0| 0| 0|CID| 0| 0| 0, 0, 0x203e }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x2040 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x207e }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x207f }, +{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x2101 }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x2102 }, +{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x2106 }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x2107 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x2109 }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x2113 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x2114 }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x2115 }, +{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x2117 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x2118 }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x211d }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x2123 }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x2124 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x2125 }, +{ C99| 0| 0| 0| 0| 0| 0, 0, 0x2126 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x2127 }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x2128 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x2129 }, +{ C99| 0| 0|CID| 0| 0| 0, 0, 0x212a }, +{ C99| 0| 0| 0| 0| 0| 0, 0, 0x212b }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x212d }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x212e }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x2131 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x2132 }, +{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x2138 }, +{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x215f }, +{ C99|DIG| 0|CID|NFC| 0| 0, 0, 0x217f }, +{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x2182 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x3004 }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x3006 }, +{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x3007 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x3020 }, +{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x3029 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x3040 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x3093 }, +{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x3094 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x309a }, +{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x309c }, +{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x309e }, +{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x30a0 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x30f6 }, +{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x30fa }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x30fc }, +{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x30fe }, +{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x3104 }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x312c }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x4dff }, +{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x9fa5 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xabff }, +{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0xd7a3 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xf8ff }, +{ 0| 0|CXX| 0| 0| 0| 0, 0, 0xfa0d }, +{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0xfa0f }, +{ 0| 0|CXX| 0| 0| 0| 0, 0, 0xfa10 }, +{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0xfa11 }, +{ 0| 0|CXX| 0| 0| 0| 0, 0, 0xfa12 }, +{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0xfa14 }, +{ 0| 0|CXX| 0| 0| 0| 0, 0, 0xfa1e }, +{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0xfa1f }, +{ 0| 0|CXX| 0| 0| 0| 0, 0, 0xfa20 }, +{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0xfa21 }, +{ 0| 0|CXX| 0| 0| 0| 0, 0, 0xfa22 }, +{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0xfa24 }, +{ 0| 0|CXX| 0| 0| 0| 0, 0, 0xfa26 }, +{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0xfa29 }, +{ 0| 0|CXX| 0| 0| 0| 0, 0, 0xfa2d }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfb1e }, +{ 0| 0|CXX|CID| 0| 0| 0, 0, 0xfb1f }, +{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xfb29 }, +{ 0| 0|CXX|CID| 0| 0| 0, 0, 0xfb36 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfb37 }, +{ 0| 0|CXX|CID| 0| 0| 0, 0, 0xfb3c }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfb3d }, +{ 0| 0|CXX|CID| 0| 0| 0, 0, 0xfb3e }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfb3f }, +{ 0| 0|CXX|CID| 0| 0| 0, 0, 0xfb41 }, +{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0xfb42 }, +{ 0| 0|CXX|CID| 0| 0| 0, 0, 0xfb44 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfb45 }, +{ 0| 0|CXX|CID| 0| 0| 0, 0, 0xfb4e }, +{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xfbb1 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfbd2 }, +{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xfd3d }, +{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0xfd3f }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfd4f }, +{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xfd8f }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfd91 }, +{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xfdc7 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfdef }, +{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xfdfb }, +{ 0| 0| 0|CID|NFC| 0| 0, 0, 0xfe6f }, +{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xfe72 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfe73 }, +{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xfe74 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfe75 }, +{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xfefc }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xff20 }, +{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xff3a }, +{ 0| 0| 0|CID|NFC| 0| 0, 0, 0xff40 }, +{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xff5a }, +{ 0| 0| 0|CID|NFC| 0| 0, 0, 0xff65 }, +{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xffbe }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xffc1 }, +{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xffc7 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xffc9 }, +{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xffcf }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xffd1 }, +{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xffd7 }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xffd9 }, +{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xffdc }, +{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xffff }, diff --git a/support/cpp2/libiberty/fopen_unlocked.c b/support/cpp2/libiberty/fopen_unlocked.c new file mode 100644 index 00000000..3c3cefed --- /dev/null +++ b/support/cpp2/libiberty/fopen_unlocked.c @@ -0,0 +1,126 @@ +/* Implement fopen_unlocked and related functions. + Copyright (C) 2005 Free Software Foundation, Inc. + Written by Kaveh R. Ghazi . + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* + +@deftypefn Extension void unlock_stream (FILE * @var{stream}) + +If the OS supports it, ensure that the supplied stream is setup to +avoid any multi-threaded locking. Otherwise leave the @code{FILE} +pointer unchanged. If the @var{stream} is @code{NULL} do nothing. + +@end deftypefn + +@deftypefn Extension void unlock_std_streams (void) + +If the OS supports it, ensure that the standard I/O streams, +@code{stdin}, @code{stdout} and @code{stderr} are setup to avoid any +multi-threaded locking. Otherwise do nothing. + +@end deftypefn + +@deftypefn Extension {FILE *} fopen_unlocked (const char *@var{path}, const char * @var{mode}) + +Opens and returns a @code{FILE} pointer via @code{fopen}. If the +operating system supports it, ensure that the stream is setup to avoid +any multi-threaded locking. Otherwise return the @code{FILE} pointer +unchanged. + +@end deftypefn + +@deftypefn Extension {FILE *} fdopen_unlocked (int @var{fildes}, const char * @var{mode}) + +Opens and returns a @code{FILE} pointer via @code{fdopen}. If the +operating system supports it, ensure that the stream is setup to avoid +any multi-threaded locking. Otherwise return the @code{FILE} pointer +unchanged. + +@end deftypefn + +@deftypefn Extension {FILE *} freopen_unlocked (const char * @var{path}, const char * @var{mode}, FILE * @var{stream}) + +Opens and returns a @code{FILE} pointer via @code{freopen}. If the +operating system supports it, ensure that the stream is setup to avoid +any multi-threaded locking. Otherwise return the @code{FILE} pointer +unchanged. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#ifdef HAVE_STDIO_EXT_H +#include +#endif + +#include "libiberty.h" + +/* This is an inline helper function to consolidate attempts to unlock + a stream. */ + +static inline void +unlock_1 (FILE *const fp ATTRIBUTE_UNUSED) +{ +#if defined(HAVE___FSETLOCKING) && defined(FSETLOCKING_BYCALLER) + if (fp) + __fsetlocking (fp, FSETLOCKING_BYCALLER); +#endif +} + +void +unlock_stream (FILE *fp) +{ + unlock_1 (fp); +} + +void +unlock_std_streams (void) +{ + unlock_1 (stdin); + unlock_1 (stdout); + unlock_1 (stderr); +} + +FILE * +fopen_unlocked (const char *path, const char *mode) +{ + FILE *const fp = fopen (path, mode); + unlock_1 (fp); + return fp; +} + +FILE * +fdopen_unlocked (int fildes, const char *mode) +{ + FILE *const fp = fdopen (fildes, mode); + unlock_1 (fp); + return fp; +} + +FILE * +freopen_unlocked (const char *path, const char *mode, FILE *stream) +{ + FILE *const fp = freopen (path, mode, stream); + unlock_1 (fp); + return fp; +} diff --git a/support/cpp2/libiberty/hashtab.c b/support/cpp2/libiberty/hashtab.c new file mode 100644 index 00000000..a5671a0a --- /dev/null +++ b/support/cpp2/libiberty/hashtab.c @@ -0,0 +1,934 @@ +/* An expandable hash tables datatype. + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 + Free Software Foundation, Inc. + Contributed by Vladimir Makarov (vmakarov@cygnus.com). + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* This package implements basic hash table functionality. It is possible + to search for an entry, create an entry and destroy an entry. + + Elements in the table are generic pointers. + + The size of the table is not fixed; if the occupancy of the table + grows too high the hash table will be expanded. + + The abstract data implementation is based on generalized Algorithm D + from Knuth's book "The art of computer programming". Hash table is + expanded by creation of new hash table and transferring elements from + the old table to the new table. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_MALLOC_H +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_STDINT_H +#include +#endif + +#include + +#include "libiberty.h" +#include "ansidecl.h" +#include "hashtab.h" + +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + +static unsigned int higher_prime_index (unsigned long); +static hashval_t htab_mod_1 (hashval_t, hashval_t, hashval_t, int); +static hashval_t htab_mod (hashval_t, htab_t); +static hashval_t htab_mod_m2 (hashval_t, htab_t); +static hashval_t hash_pointer (const void *); +static int eq_pointer (const void *, const void *); +static int htab_expand (htab_t); +static PTR *find_empty_slot_for_expand (htab_t, hashval_t); + +/* At some point, we could make these be NULL, and modify the + hash-table routines to handle NULL specially; that would avoid + function-call overhead for the common case of hashing pointers. */ +htab_hash htab_hash_pointer = hash_pointer; +htab_eq htab_eq_pointer = eq_pointer; + +/* Table of primes and multiplicative inverses. + + Note that these are not minimally reduced inverses. Unlike when generating + code to divide by a constant, we want to be able to use the same algorithm + all the time. All of these inverses (are implied to) have bit 32 set. + + For the record, here's the function that computed the table; it's a + vastly simplified version of the function of the same name from gcc. */ + +#if 0 +unsigned int +ceil_log2 (unsigned int x) +{ + int i; + for (i = 31; i >= 0 ; --i) + if (x > (1u << i)) + return i+1; + abort (); +} + +unsigned int +choose_multiplier (unsigned int d, unsigned int *mlp, unsigned char *shiftp) +{ + unsigned long long mhigh; + double nx; + int lgup, post_shift; + int pow, pow2; + int n = 32, precision = 32; + + lgup = ceil_log2 (d); + pow = n + lgup; + pow2 = n + lgup - precision; + + nx = ldexp (1.0, pow) + ldexp (1.0, pow2); + mhigh = nx / d; + + *shiftp = lgup - 1; + *mlp = mhigh; + return mhigh >> 32; +} +#endif + +struct prime_ent +{ + hashval_t prime; + hashval_t inv; + hashval_t inv_m2; /* inverse of prime-2 */ + hashval_t shift; +}; + +static struct prime_ent const prime_tab[] = { + { 7, 0x24924925, 0x9999999b, 2 }, + { 13, 0x3b13b13c, 0x745d1747, 3 }, + { 31, 0x08421085, 0x1a7b9612, 4 }, + { 61, 0x0c9714fc, 0x15b1e5f8, 5 }, + { 127, 0x02040811, 0x0624dd30, 6 }, + { 251, 0x05197f7e, 0x073260a5, 7 }, + { 509, 0x01824366, 0x02864fc8, 8 }, + { 1021, 0x00c0906d, 0x014191f7, 9 }, + { 2039, 0x0121456f, 0x0161e69e, 10 }, + { 4093, 0x00300902, 0x00501908, 11 }, + { 8191, 0x00080041, 0x00180241, 12 }, + { 16381, 0x000c0091, 0x00140191, 13 }, + { 32749, 0x002605a5, 0x002a06e6, 14 }, + { 65521, 0x000f00e2, 0x00110122, 15 }, + { 131071, 0x00008001, 0x00018003, 16 }, + { 262139, 0x00014002, 0x0001c004, 17 }, + { 524287, 0x00002001, 0x00006001, 18 }, + { 1048573, 0x00003001, 0x00005001, 19 }, + { 2097143, 0x00004801, 0x00005801, 20 }, + { 4194301, 0x00000c01, 0x00001401, 21 }, + { 8388593, 0x00001e01, 0x00002201, 22 }, + { 16777213, 0x00000301, 0x00000501, 23 }, + { 33554393, 0x00001381, 0x00001481, 24 }, + { 67108859, 0x00000141, 0x000001c1, 25 }, + { 134217689, 0x000004e1, 0x00000521, 26 }, + { 268435399, 0x00000391, 0x000003b1, 27 }, + { 536870909, 0x00000019, 0x00000029, 28 }, + { 1073741789, 0x0000008d, 0x00000095, 29 }, + { 2147483647, 0x00000003, 0x00000007, 30 }, + /* Avoid "decimal constant so large it is unsigned" for 4294967291. */ + { 0xfffffffb, 0x00000006, 0x00000008, 31 } +}; + +/* The following function returns an index into the above table of the + nearest prime number which is greater than N, and near a power of two. */ + +static unsigned int +higher_prime_index (unsigned long n) +{ + unsigned int low = 0; + unsigned int high = sizeof(prime_tab) / sizeof(prime_tab[0]); + + while (low != high) + { + unsigned int mid = low + (high - low) / 2; + if (n > prime_tab[mid].prime) + low = mid + 1; + else + high = mid; + } + + /* If we've run out of primes, abort. */ + if (n > prime_tab[low].prime) + { + fprintf (stderr, "Cannot find prime bigger than %lu\n", n); + abort (); + } + + return low; +} + +/* Returns a hash code for P. */ + +static hashval_t +hash_pointer (const PTR p) +{ + return (hashval_t) ((long)p >> 3); +} + +/* Returns non-zero if P1 and P2 are equal. */ + +static int +eq_pointer (const PTR p1, const PTR p2) +{ + return p1 == p2; +} + + +/* The parens around the function names in the next two definitions + are essential in order to prevent macro expansions of the name. + The bodies, however, are expanded as expected, so they are not + recursive definitions. */ + +/* Return the current size of given hash table. */ + +#define htab_size(htab) ((htab)->size) + +size_t +(htab_size) (htab_t htab) +{ + return htab_size (htab); +} + +/* Return the current number of elements in given hash table. */ + +#define htab_elements(htab) ((htab)->n_elements - (htab)->n_deleted) + +size_t +(htab_elements) (htab_t htab) +{ + return htab_elements (htab); +} + +/* Return X % Y. */ + +static inline hashval_t +htab_mod_1 (hashval_t x, hashval_t y, hashval_t inv, int shift) +{ + /* The multiplicative inverses computed above are for 32-bit types, and + requires that we be able to compute a highpart multiply. */ +#ifdef UNSIGNED_64BIT_TYPE + __extension__ typedef UNSIGNED_64BIT_TYPE ull; + if (sizeof (hashval_t) * CHAR_BIT <= 32) + { + hashval_t t1, t2, t3, t4, q, r; + + t1 = ((ull)x * inv) >> 32; + t2 = x - t1; + t3 = t2 >> 1; + t4 = t1 + t3; + q = t4 >> shift; + r = x - (q * y); + + return r; + } +#endif + + /* Otherwise just use the native division routines. */ + return x % y; +} + +/* Compute the primary hash for HASH given HTAB's current size. */ + +static inline hashval_t +htab_mod (hashval_t hash, htab_t htab) +{ + const struct prime_ent *p = &prime_tab[htab->size_prime_index]; + return htab_mod_1 (hash, p->prime, p->inv, p->shift); +} + +/* Compute the secondary hash for HASH given HTAB's current size. */ + +static inline hashval_t +htab_mod_m2 (hashval_t hash, htab_t htab) +{ + const struct prime_ent *p = &prime_tab[htab->size_prime_index]; + return 1 + htab_mod_1 (hash, p->prime - 2, p->inv_m2, p->shift); +} + +/* This function creates table with length slightly longer than given + source length. Created hash table is initiated as empty (all the + hash table entries are HTAB_EMPTY_ENTRY). The function returns the + created hash table, or NULL if memory allocation fails. */ + +htab_t +htab_create_alloc (size_t size, htab_hash hash_f, htab_eq eq_f, + htab_del del_f, htab_alloc alloc_f, htab_free free_f) +{ + htab_t result; + unsigned int size_prime_index; + + size_prime_index = higher_prime_index (size); + size = prime_tab[size_prime_index].prime; + + result = (htab_t) (*alloc_f) (1, sizeof (struct htab)); + if (result == NULL) + return NULL; + result->entries = (PTR *) (*alloc_f) (size, sizeof (PTR)); + if (result->entries == NULL) + { + if (free_f != NULL) + (*free_f) (result); + return NULL; + } + result->size = size; + result->size_prime_index = size_prime_index; + result->hash_f = hash_f; + result->eq_f = eq_f; + result->del_f = del_f; + result->alloc_f = alloc_f; + result->free_f = free_f; + return result; +} + +/* As above, but use the variants of alloc_f and free_f which accept + an extra argument. */ + +htab_t +htab_create_alloc_ex (size_t size, htab_hash hash_f, htab_eq eq_f, + htab_del del_f, void *alloc_arg, + htab_alloc_with_arg alloc_f, + htab_free_with_arg free_f) +{ + htab_t result; + unsigned int size_prime_index; + + size_prime_index = higher_prime_index (size); + size = prime_tab[size_prime_index].prime; + + result = (htab_t) (*alloc_f) (alloc_arg, 1, sizeof (struct htab)); + if (result == NULL) + return NULL; + result->entries = (PTR *) (*alloc_f) (alloc_arg, size, sizeof (PTR)); + if (result->entries == NULL) + { + if (free_f != NULL) + (*free_f) (alloc_arg, result); + return NULL; + } + result->size = size; + result->size_prime_index = size_prime_index; + result->hash_f = hash_f; + result->eq_f = eq_f; + result->del_f = del_f; + result->alloc_arg = alloc_arg; + result->alloc_with_arg_f = alloc_f; + result->free_with_arg_f = free_f; + return result; +} + +/* Update the function pointers and allocation parameter in the htab_t. */ + +void +htab_set_functions_ex (htab_t htab, htab_hash hash_f, htab_eq eq_f, + htab_del del_f, PTR alloc_arg, + htab_alloc_with_arg alloc_f, htab_free_with_arg free_f) +{ + htab->hash_f = hash_f; + htab->eq_f = eq_f; + htab->del_f = del_f; + htab->alloc_arg = alloc_arg; + htab->alloc_with_arg_f = alloc_f; + htab->free_with_arg_f = free_f; +} + +/* These functions exist solely for backward compatibility. */ + +#undef htab_create +htab_t +htab_create (size_t size, htab_hash hash_f, htab_eq eq_f, htab_del del_f) +{ + return htab_create_alloc (size, hash_f, eq_f, del_f, xcalloc, free); +} + +htab_t +htab_try_create (size_t size, htab_hash hash_f, htab_eq eq_f, htab_del del_f) +{ + return htab_create_alloc (size, hash_f, eq_f, del_f, calloc, free); +} + +/* This function frees all memory allocated for given hash table. + Naturally the hash table must already exist. */ + +void +htab_delete (htab_t htab) +{ + size_t size = htab_size (htab); + PTR *entries = htab->entries; + int i; + + if (htab->del_f) + for (i = size - 1; i >= 0; i--) + if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY) + (*htab->del_f) (entries[i]); + + if (htab->free_f != NULL) + { + (*htab->free_f) (entries); + (*htab->free_f) (htab); + } + else if (htab->free_with_arg_f != NULL) + { + (*htab->free_with_arg_f) (htab->alloc_arg, entries); + (*htab->free_with_arg_f) (htab->alloc_arg, htab); + } +} + +/* This function clears all entries in the given hash table. */ + +void +htab_empty (htab_t htab) +{ + size_t size = htab_size (htab); + PTR *entries = htab->entries; + int i; + + if (htab->del_f) + for (i = size - 1; i >= 0; i--) + if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY) + (*htab->del_f) (entries[i]); + + memset (entries, 0, size * sizeof (PTR)); +} + +/* Similar to htab_find_slot, but without several unwanted side effects: + - Does not call htab->eq_f when it finds an existing entry. + - Does not change the count of elements/searches/collisions in the + hash table. + This function also assumes there are no deleted entries in the table. + HASH is the hash value for the element to be inserted. */ + +static PTR * +find_empty_slot_for_expand (htab_t htab, hashval_t hash) +{ + hashval_t index = htab_mod (hash, htab); + size_t size = htab_size (htab); + PTR *slot = htab->entries + index; + hashval_t hash2; + + if (*slot == HTAB_EMPTY_ENTRY) + return slot; + else if (*slot == HTAB_DELETED_ENTRY) + abort (); + + hash2 = htab_mod_m2 (hash, htab); + for (;;) + { + index += hash2; + if (index >= size) + index -= size; + + slot = htab->entries + index; + if (*slot == HTAB_EMPTY_ENTRY) + return slot; + else if (*slot == HTAB_DELETED_ENTRY) + abort (); + } +} + +/* The following function changes size of memory allocated for the + entries and repeatedly inserts the table elements. The occupancy + of the table after the call will be about 50%. Naturally the hash + table must already exist. Remember also that the place of the + table entries is changed. If memory allocation failures are allowed, + this function will return zero, indicating that the table could not be + expanded. If all goes well, it will return a non-zero value. */ + +static int +htab_expand (htab_t htab) +{ + PTR *oentries; + PTR *olimit; + PTR *p; + PTR *nentries; + size_t nsize, osize, elts; + unsigned int oindex, nindex; + + oentries = htab->entries; + oindex = htab->size_prime_index; + osize = htab->size; + olimit = oentries + osize; + elts = htab_elements (htab); + + /* Resize only when table after removal of unused elements is either + too full or too empty. */ + if (elts * 2 > osize || (elts * 8 < osize && osize > 32)) + { + nindex = higher_prime_index (elts * 2); + nsize = prime_tab[nindex].prime; + } + else + { + nindex = oindex; + nsize = osize; + } + + if (htab->alloc_with_arg_f != NULL) + nentries = (PTR *) (*htab->alloc_with_arg_f) (htab->alloc_arg, nsize, + sizeof (PTR *)); + else + nentries = (PTR *) (*htab->alloc_f) (nsize, sizeof (PTR *)); + if (nentries == NULL) + return 0; + htab->entries = nentries; + htab->size = nsize; + htab->size_prime_index = nindex; + htab->n_elements -= htab->n_deleted; + htab->n_deleted = 0; + + p = oentries; + do + { + PTR x = *p; + + if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY) + { + PTR *q = find_empty_slot_for_expand (htab, (*htab->hash_f) (x)); + + *q = x; + } + + p++; + } + while (p < olimit); + + if (htab->free_f != NULL) + (*htab->free_f) (oentries); + else if (htab->free_with_arg_f != NULL) + (*htab->free_with_arg_f) (htab->alloc_arg, oentries); + return 1; +} + +/* This function searches for a hash table entry equal to the given + element. It cannot be used to insert or delete an element. */ + +PTR +htab_find_with_hash (htab_t htab, const PTR element, hashval_t hash) +{ + hashval_t index, hash2; + size_t size; + PTR entry; + + htab->searches++; + size = htab_size (htab); + index = htab_mod (hash, htab); + + entry = htab->entries[index]; + if (entry == HTAB_EMPTY_ENTRY + || (entry != HTAB_DELETED_ENTRY && (*htab->eq_f) (entry, element))) + return entry; + + hash2 = htab_mod_m2 (hash, htab); + for (;;) + { + htab->collisions++; + index += hash2; + if (index >= size) + index -= size; + + entry = htab->entries[index]; + if (entry == HTAB_EMPTY_ENTRY + || (entry != HTAB_DELETED_ENTRY && (*htab->eq_f) (entry, element))) + return entry; + } +} + +/* Like htab_find_slot_with_hash, but compute the hash value from the + element. */ + +PTR +htab_find (htab_t htab, const PTR element) +{ + return htab_find_with_hash (htab, element, (*htab->hash_f) (element)); +} + +/* This function searches for a hash table slot containing an entry + equal to the given element. To delete an entry, call this with + insert=NO_INSERT, then call htab_clear_slot on the slot returned + (possibly after doing some checks). To insert an entry, call this + with insert=INSERT, then write the value you want into the returned + slot. When inserting an entry, NULL may be returned if memory + allocation fails. */ + +PTR * +htab_find_slot_with_hash (htab_t htab, const PTR element, + hashval_t hash, enum insert_option insert) +{ + PTR *first_deleted_slot; + hashval_t index, hash2; + size_t size; + PTR entry; + + size = htab_size (htab); + if (insert == INSERT && size * 3 <= htab->n_elements * 4) + { + if (htab_expand (htab) == 0) + return NULL; + size = htab_size (htab); + } + + index = htab_mod (hash, htab); + + htab->searches++; + first_deleted_slot = NULL; + + entry = htab->entries[index]; + if (entry == HTAB_EMPTY_ENTRY) + goto empty_entry; + else if (entry == HTAB_DELETED_ENTRY) + first_deleted_slot = &htab->entries[index]; + else if ((*htab->eq_f) (entry, element)) + return &htab->entries[index]; + + hash2 = htab_mod_m2 (hash, htab); + for (;;) + { + htab->collisions++; + index += hash2; + if (index >= size) + index -= size; + + entry = htab->entries[index]; + if (entry == HTAB_EMPTY_ENTRY) + goto empty_entry; + else if (entry == HTAB_DELETED_ENTRY) + { + if (!first_deleted_slot) + first_deleted_slot = &htab->entries[index]; + } + else if ((*htab->eq_f) (entry, element)) + return &htab->entries[index]; + } + + empty_entry: + if (insert == NO_INSERT) + return NULL; + + if (first_deleted_slot) + { + htab->n_deleted--; + *first_deleted_slot = HTAB_EMPTY_ENTRY; + return first_deleted_slot; + } + + htab->n_elements++; + return &htab->entries[index]; +} + +/* Like htab_find_slot_with_hash, but compute the hash value from the + element. */ + +PTR * +htab_find_slot (htab_t htab, const PTR element, enum insert_option insert) +{ + return htab_find_slot_with_hash (htab, element, (*htab->hash_f) (element), + insert); +} + +/* This function deletes an element with the given value from hash + table (the hash is computed from the element). If there is no matching + element in the hash table, this function does nothing. */ + +void +htab_remove_elt (htab_t htab, PTR element) +{ + htab_remove_elt_with_hash (htab, element, (*htab->hash_f) (element)); +} + + +/* This function deletes an element with the given value from hash + table. If there is no matching element in the hash table, this + function does nothing. */ + +void +htab_remove_elt_with_hash (htab_t htab, PTR element, hashval_t hash) +{ + PTR *slot; + + slot = htab_find_slot_with_hash (htab, element, hash, NO_INSERT); + if (*slot == HTAB_EMPTY_ENTRY) + return; + + if (htab->del_f) + (*htab->del_f) (*slot); + + *slot = HTAB_DELETED_ENTRY; + htab->n_deleted++; +} + +/* This function clears a specified slot in a hash table. It is + useful when you've already done the lookup and don't want to do it + again. */ + +void +htab_clear_slot (htab_t htab, PTR *slot) +{ + if (slot < htab->entries || slot >= htab->entries + htab_size (htab) + || *slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY) + abort (); + + if (htab->del_f) + (*htab->del_f) (*slot); + + *slot = HTAB_DELETED_ENTRY; + htab->n_deleted++; +} + +/* This function scans over the entire hash table calling + CALLBACK for each live entry. If CALLBACK returns false, + the iteration stops. INFO is passed as CALLBACK's second + argument. */ + +void +htab_traverse_noresize (htab_t htab, htab_trav callback, PTR info) +{ + PTR *slot; + PTR *limit; + + slot = htab->entries; + limit = slot + htab_size (htab); + + do + { + PTR x = *slot; + + if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY) + if (!(*callback) (slot, info)) + break; + } + while (++slot < limit); +} + +/* Like htab_traverse_noresize, but does resize the table when it is + too empty to improve effectivity of subsequent calls. */ + +void +htab_traverse (htab_t htab, htab_trav callback, PTR info) +{ + if (htab_elements (htab) * 8 < htab_size (htab)) + htab_expand (htab); + + htab_traverse_noresize (htab, callback, info); +} + +/* Return the fraction of fixed collisions during all work with given + hash table. */ + +double +htab_collisions (htab_t htab) +{ + if (htab->searches == 0) + return 0.0; + + return (double) htab->collisions / (double) htab->searches; +} + +/* Hash P as a null-terminated string. + + Copied from gcc/hashtable.c. Zack had the following to say with respect + to applicability, though note that unlike hashtable.c, this hash table + implementation re-hashes rather than chain buckets. + + http://gcc.gnu.org/ml/gcc-patches/2001-08/msg01021.html + From: Zack Weinberg + Date: Fri, 17 Aug 2001 02:15:56 -0400 + + I got it by extracting all the identifiers from all the source code + I had lying around in mid-1999, and testing many recurrences of + the form "H_n = H_{n-1} * K + c_n * L + M" where K, L, M were either + prime numbers or the appropriate identity. This was the best one. + I don't remember exactly what constituted "best", except I was + looking at bucket-length distributions mostly. + + So it should be very good at hashing identifiers, but might not be + as good at arbitrary strings. + + I'll add that it thoroughly trounces the hash functions recommended + for this use at http://burtleburtle.net/bob/hash/index.html, both + on speed and bucket distribution. I haven't tried it against the + function they just started using for Perl's hashes. */ + +hashval_t +htab_hash_string (const PTR p) +{ + const unsigned char *str = (const unsigned char *) p; + hashval_t r = 0; + unsigned char c; + + while ((c = *str++) != 0) + r = r * 67 + c - 113; + + return r; +} + +/* DERIVED FROM: +-------------------------------------------------------------------- +lookup2.c, by Bob Jenkins, December 1996, Public Domain. +hash(), hash2(), hash3, and mix() are externally useful functions. +Routines to test the hash are included if SELF_TEST is defined. +You can use this free for any purpose. It has no warranty. +-------------------------------------------------------------------- +*/ + +/* +-------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. +For every delta with one or two bit set, and the deltas of all three + high bits or all three low bits, whether the original value of a,b,c + is almost all zero or is uniformly distributed, +* If mix() is run forward or backward, at least 32 bits in a,b,c + have at least 1/4 probability of changing. +* If mix() is run forward, every bit of c will change between 1/3 and + 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) +mix() was built out of 36 single-cycle latency instructions in a + structure that could supported 2x parallelism, like so: + a -= b; + a -= c; x = (c>>13); + b -= c; a ^= x; + b -= a; x = (a<<8); + c -= a; b ^= x; + c -= b; x = (b>>13); + ... + Unfortunately, superscalar Pentiums and Sparcs can't take advantage + of that parallelism. They've also turned some of those single-cycle + latency instructions into multi-cycle latency instructions. Still, + this is the fastest good hash I could find. There were about 2^^68 + to choose from. I only looked at a billion or so. +-------------------------------------------------------------------- +*/ +/* same, but slower, works on systems that might have 8 byte hashval_t's */ +#define mix(a,b,c) \ +{ \ + a -= b; a -= c; a ^= (c>>13); \ + b -= c; b -= a; b ^= (a<< 8); \ + c -= a; c -= b; c ^= ((b&0xffffffff)>>13); \ + a -= b; a -= c; a ^= ((c&0xffffffff)>>12); \ + b -= c; b -= a; b = (b ^ (a<<16)) & 0xffffffff; \ + c -= a; c -= b; c = (c ^ (b>> 5)) & 0xffffffff; \ + a -= b; a -= c; a = (a ^ (c>> 3)) & 0xffffffff; \ + b -= c; b -= a; b = (b ^ (a<<10)) & 0xffffffff; \ + c -= a; c -= b; c = (c ^ (b>>15)) & 0xffffffff; \ +} + +/* +-------------------------------------------------------------------- +hash() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + len : the length of the key, counting by bytes + level : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Every 1-bit and 2-bit delta achieves avalanche. +About 36+6len instructions. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (ub1 **)k, do it like this: + for (i=0, h=0; i= 12) /* aligned */ + { + a += *(hashval_t *)(k+0); + b += *(hashval_t *)(k+4); + c += *(hashval_t *)(k+8); + mix(a,b,c); + k += 12; len -= 12; + } + else /* unaligned */ +#endif + while (len >= 12) + { + a += (k[0] +((hashval_t)k[1]<<8) +((hashval_t)k[2]<<16) +((hashval_t)k[3]<<24)); + b += (k[4] +((hashval_t)k[5]<<8) +((hashval_t)k[6]<<16) +((hashval_t)k[7]<<24)); + c += (k[8] +((hashval_t)k[9]<<8) +((hashval_t)k[10]<<16)+((hashval_t)k[11]<<24)); + mix(a,b,c); + k += 12; len -= 12; + } + + /*------------------------------------- handle the last 11 bytes */ + c += length; + switch(len) /* all the case statements fall through */ + { + case 11: c+=((hashval_t)k[10]<<24); + case 10: c+=((hashval_t)k[9]<<16); + case 9 : c+=((hashval_t)k[8]<<8); + /* the first byte of c is reserved for the length */ + case 8 : b+=((hashval_t)k[7]<<24); + case 7 : b+=((hashval_t)k[6]<<16); + case 6 : b+=((hashval_t)k[5]<<8); + case 5 : b+=k[4]; + case 4 : a+=((hashval_t)k[3]<<24); + case 3 : a+=((hashval_t)k[2]<<16); + case 2 : a+=((hashval_t)k[1]<<8); + case 1 : a+=k[0]; + /* case 0: nothing left to add */ + } + mix(a,b,c); + /*-------------------------------------------- report the result */ + return c; +} diff --git a/support/cpp2/libiberty/hashtab.h b/support/cpp2/libiberty/hashtab.h new file mode 100644 index 00000000..77eee14e --- /dev/null +++ b/support/cpp2/libiberty/hashtab.h @@ -0,0 +1,206 @@ +/* An expandable hash tables datatype. + Copyright (C) 1999, 2000, 2002, 2003, 2004 Free Software Foundation, Inc. + Contributed by Vladimir Makarov (vmakarov@cygnus.com). + +This program 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* This package implements basic hash table functionality. It is possible + to search for an entry, create an entry and destroy an entry. + + Elements in the table are generic pointers. + + The size of the table is not fixed; if the occupancy of the table + grows too high the hash table will be expanded. + + The abstract data implementation is based on generalized Algorithm D + from Knuth's book "The art of computer programming". Hash table is + expanded by creation of new hash table and transferring elements from + the old table to the new table. */ + +#ifndef __HASHTAB_H__ +#define __HASHTAB_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "ansidecl.h" + +#ifndef GTY +#define GTY(X) +#endif + +/* The type for a hash code. */ +typedef unsigned int hashval_t; + +/* Callback function pointer types. */ + +/* Calculate hash of a table entry. */ +typedef hashval_t (*htab_hash) (const void *); + +/* Compare a table entry with a possible entry. The entry already in + the table always comes first, so the second element can be of a + different type (but in this case htab_find and htab_find_slot + cannot be used; instead the variants that accept a hash value + must be used). */ +typedef int (*htab_eq) (const void *, const void *); + +/* Cleanup function called whenever a live element is removed from + the hash table. */ +typedef void (*htab_del) (void *); + +/* Function called by htab_traverse for each live element. The first + arg is the slot of the element (which can be passed to htab_clear_slot + if desired), the second arg is the auxiliary pointer handed to + htab_traverse. Return 1 to continue scan, 0 to stop. */ +typedef int (*htab_trav) (void **, void *); + +/* Memory-allocation function, with the same functionality as calloc(). + Iff it returns NULL, the hash table implementation will pass an error + code back to the user, so if your code doesn't handle errors, + best if you use xcalloc instead. */ +typedef void *(*htab_alloc) (size_t, size_t); + +/* We also need a free() routine. */ +typedef void (*htab_free) (void *); + +/* Memory allocation and deallocation; variants which take an extra + argument. */ +typedef void *(*htab_alloc_with_arg) (void *, size_t, size_t); +typedef void (*htab_free_with_arg) (void *, void *); + +/* This macro defines reserved value for empty table entry. */ + +#define HTAB_EMPTY_ENTRY ((PTR) 0) + +/* This macro defines reserved value for table entry which contained + a deleted element. */ + +#define HTAB_DELETED_ENTRY ((PTR) 1) + +/* Hash tables are of the following type. The structure + (implementation) of this type is not needed for using the hash + tables. All work with hash table should be executed only through + functions mentioned below. The size of this structure is subject to + change. */ + +struct htab GTY(()) +{ + /* Pointer to hash function. */ + htab_hash hash_f; + + /* Pointer to comparison function. */ + htab_eq eq_f; + + /* Pointer to cleanup function. */ + htab_del del_f; + + /* Table itself. */ + void ** GTY ((use_param, length ("%h.size"))) entries; + + /* Current size (in entries) of the hash table. */ + size_t size; + + /* Current number of elements including also deleted elements. */ + size_t n_elements; + + /* Current number of deleted elements in the table. */ + size_t n_deleted; + + /* The following member is used for debugging. Its value is number + of all calls of `htab_find_slot' for the hash table. */ + unsigned int searches; + + /* The following member is used for debugging. Its value is number + of collisions fixed for time of work with the hash table. */ + unsigned int collisions; + + /* Pointers to allocate/free functions. */ + htab_alloc alloc_f; + htab_free free_f; + + /* Alternate allocate/free functions, which take an extra argument. */ + void * GTY((skip)) alloc_arg; + htab_alloc_with_arg alloc_with_arg_f; + htab_free_with_arg free_with_arg_f; + + /* Current size (in entries) of the hash table, as an index into the + table of primes. */ + unsigned int size_prime_index; +}; + +typedef struct htab *htab_t; + +/* An enum saying whether we insert into the hash table or not. */ +enum insert_option {NO_INSERT, INSERT}; + +/* The prototypes of the package functions. */ + +extern htab_t htab_create_alloc (size_t, htab_hash, + htab_eq, htab_del, + htab_alloc, htab_free); + +extern htab_t htab_create_alloc_ex (size_t, htab_hash, + htab_eq, htab_del, + void *, htab_alloc_with_arg, + htab_free_with_arg); + +/* Backward-compatibility functions. */ +extern htab_t htab_create (size_t, htab_hash, htab_eq, htab_del); +extern htab_t htab_try_create (size_t, htab_hash, htab_eq, htab_del); + +extern void htab_set_functions_ex (htab_t, htab_hash, + htab_eq, htab_del, + void *, htab_alloc_with_arg, + htab_free_with_arg); + +extern void htab_delete (htab_t); +extern void htab_empty (htab_t); + +extern void * htab_find (htab_t, const void *); +extern void ** htab_find_slot (htab_t, const void *, enum insert_option); +extern void * htab_find_with_hash (htab_t, const void *, hashval_t); +extern void ** htab_find_slot_with_hash (htab_t, const void *, + hashval_t, enum insert_option); +extern void htab_clear_slot (htab_t, void **); +extern void htab_remove_elt (htab_t, void *); +extern void htab_remove_elt_with_hash (htab_t, void *, hashval_t); + +extern void htab_traverse (htab_t, htab_trav, void *); +extern void htab_traverse_noresize (htab_t, htab_trav, void *); + +extern size_t htab_size (htab_t); +extern size_t htab_elements (htab_t); +extern double htab_collisions (htab_t); + +/* A hash function for pointers. */ +extern htab_hash htab_hash_pointer; + +/* An equality function for pointers. */ +extern htab_eq htab_eq_pointer; + +/* A hash function for null-terminated strings. */ +extern hashval_t htab_hash_string (const void *); + +/* An iterative hash function for arbitrary data. */ +extern hashval_t iterative_hash (const void *, size_t, hashval_t); +/* Shorthand for hashing something with an intrinsic size. */ +#define iterative_hash_object(OB,INIT) iterative_hash (&OB, sizeof (OB), INIT) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __HASHTAB_H */ diff --git a/support/cpp2/libiberty/md5.c b/support/cpp2/libiberty/md5.c new file mode 100644 index 00000000..83e0beb3 --- /dev/null +++ b/support/cpp2/libiberty/md5.c @@ -0,0 +1,430 @@ +/* md5.c - Functions to compute MD5 message digest of files or memory blocks + according to the definition of MD5 in RFC 1321 from April 1992. + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + + NOTE: This source is derived from an old version taken from the GNU C + Library (glibc). + + This program 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 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Ulrich Drepper , 1995. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#if STDC_HEADERS || defined _LIBC +# include +# include +#else +# ifndef HAVE_MEMCPY +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# endif +#endif + +#include "ansidecl.h" +#include "md5.h" + +#ifdef _LIBC +# include +# if __BYTE_ORDER == __BIG_ENDIAN +# define WORDS_BIGENDIAN 1 +# endif +#endif + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#else +# define SWAP(n) (n) +#endif + + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. (RFC 1321, 3.1: Step 1) */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +void +md5_init_ctx (struct md5_ctx *ctx) +{ + ctx->A = (md5_uint32) 0x67452301; + ctx->B = (md5_uint32) 0xefcdab89; + ctx->C = (md5_uint32) 0x98badcfe; + ctx->D = (md5_uint32) 0x10325476; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +/* Put result from CTX in first 16 bytes following RESBUF. The result + must be in little endian byte order. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +void * +md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) +{ + ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A); + ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B); + ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C); + ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +void * +md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) +{ + /* Take yet unprocessed bytes into account. */ + md5_uint32 bytes = ctx->buflen; + size_t pad; + + /* Now count remaining bytes. */ + ctx->total[0] += bytes; + if (ctx->total[0] < bytes) + ++ctx->total[1]; + + pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; + memcpy (&ctx->buffer[bytes], fillbuf, pad); + + /* Put the 64-bit file length in *bits* at the end of the buffer. */ + *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3); + *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) | + (ctx->total[0] >> 29)); + + /* Process last bytes. */ + md5_process_block (ctx->buffer, bytes + pad + 8, ctx); + + return md5_read_ctx (ctx, resbuf); +} + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +int +md5_stream (FILE *stream, void *resblock) +{ + /* Important: BLOCKSIZE must be a multiple of 64. */ +#define BLOCKSIZE 4096 + struct md5_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + do + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + } + while (sum < BLOCKSIZE && n != 0); + if (n == 0 && ferror (stream)) + return 1; + + /* If end of file is reached, end the loop. */ + if (n == 0) + break; + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + md5_process_block (buffer, BLOCKSIZE, &ctx); + } + + /* Add the last bytes if necessary. */ + if (sum > 0) + md5_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + md5_finish_ctx (&ctx, resblock); + return 0; +} + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +md5_buffer (const char *buffer, size_t len, void *resblock) +{ + struct md5_ctx ctx; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + md5_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return md5_finish_ctx (&ctx, resblock); +} + + +void +md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx) +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; + + memcpy (&ctx->buffer[left_over], buffer, add); + ctx->buflen += add; + + if (left_over + add > 64) + { + md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx); + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], + (left_over + add) & 63); + ctx->buflen = (left_over + add) & 63; + } + + buffer = (const void *) ((const char *) buffer + add); + len -= add; + } + + /* Process available complete blocks. */ + if (len > 64) + { +#if !_STRING_ARCH_unaligned +/* To check alignment gcc has an appropriate operator. Other + compilers don't. */ +# if __GNUC__ >= 2 +# define UNALIGNED_P(p) (((md5_uintptr) p) % __alignof__ (md5_uint32) != 0) +# else +# define UNALIGNED_P(p) (((md5_uintptr) p) % sizeof (md5_uint32) != 0) +# endif + if (UNALIGNED_P (buffer)) + while (len > 64) + { + md5_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); + buffer = (const char *) buffer + 64; + len -= 64; + } + else +#endif + md5_process_block (buffer, len & ~63, ctx); + buffer = (const void *) ((const char *) buffer + (len & ~63)); + len &= 63; + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + memcpy (ctx->buffer, buffer, len); + ctx->buflen = len; + } +} + + +/* These are the four functions used in the four steps of the MD5 algorithm + and defined in the RFC 1321. The first function is a little bit optimized + (as found in Colin Plumbs public domain implementation). */ +/* #define FF(b, c, d) ((b & c) | (~b & d)) */ +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) FF (d, b, c) +#define FH(b, c, d) (b ^ c ^ d) +#define FI(b, c, d) (c ^ (b | ~d)) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. */ + +void +md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx) +{ + md5_uint32 correct_words[16]; + const md5_uint32 *words = (const md5_uint32 *) buffer; + size_t nwords = len / sizeof (md5_uint32); + const md5_uint32 *endp = words + nwords; + md5_uint32 A = ctx->A; + md5_uint32 B = ctx->B; + md5_uint32 C = ctx->C; + md5_uint32 D = ctx->D; + + /* First increment the byte count. RFC 1321 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] += len; + if (ctx->total[0] < len) + ++ctx->total[1]; + + /* Process all bytes in the buffer with 64 bytes in each round of + the loop. */ + while (words < endp) + { + md5_uint32 *cwp = correct_words; + md5_uint32 A_save = A; + md5_uint32 B_save = B; + md5_uint32 C_save = C; + md5_uint32 D_save = D; + + /* First round: using the given function, the context and a constant + the next context is computed. Because the algorithms processing + unit is a 32-bit word and it is determined to work on words in + little endian byte order we perhaps have to change the byte order + before the computation. To reduce the work for the next steps + we store the swapped words in the array CORRECT_WORDS. */ + +#define OP(a, b, c, d, s, T) \ + do \ + { \ + a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ + ++words; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* It is unfortunate that C does not provide an operator for + cyclic rotation. Hope the C compiler is smart enough. */ +#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) + + /* Before we start, one word to the strange constants. + They are defined in RFC 1321 as + + T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 + */ + + /* Round 1. */ + OP (A, B, C, D, 7, (md5_uint32) 0xd76aa478); + OP (D, A, B, C, 12, (md5_uint32) 0xe8c7b756); + OP (C, D, A, B, 17, (md5_uint32) 0x242070db); + OP (B, C, D, A, 22, (md5_uint32) 0xc1bdceee); + OP (A, B, C, D, 7, (md5_uint32) 0xf57c0faf); + OP (D, A, B, C, 12, (md5_uint32) 0x4787c62a); + OP (C, D, A, B, 17, (md5_uint32) 0xa8304613); + OP (B, C, D, A, 22, (md5_uint32) 0xfd469501); + OP (A, B, C, D, 7, (md5_uint32) 0x698098d8); + OP (D, A, B, C, 12, (md5_uint32) 0x8b44f7af); + OP (C, D, A, B, 17, (md5_uint32) 0xffff5bb1); + OP (B, C, D, A, 22, (md5_uint32) 0x895cd7be); + OP (A, B, C, D, 7, (md5_uint32) 0x6b901122); + OP (D, A, B, C, 12, (md5_uint32) 0xfd987193); + OP (C, D, A, B, 17, (md5_uint32) 0xa679438e); + OP (B, C, D, A, 22, (md5_uint32) 0x49b40821); + + /* For the second to fourth round we have the possibly swapped words + in CORRECT_WORDS. Redefine the macro to take an additional first + argument specifying the function to use. */ +#undef OP +#define OP(a, b, c, d, k, s, T) \ + do \ + { \ + a += FX (b, c, d) + correct_words[k] + T; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + +#define FX(b, c, d) FG (b, c, d) + + /* Round 2. */ + OP (A, B, C, D, 1, 5, (md5_uint32) 0xf61e2562); + OP (D, A, B, C, 6, 9, (md5_uint32) 0xc040b340); + OP (C, D, A, B, 11, 14, (md5_uint32) 0x265e5a51); + OP (B, C, D, A, 0, 20, (md5_uint32) 0xe9b6c7aa); + OP (A, B, C, D, 5, 5, (md5_uint32) 0xd62f105d); + OP (D, A, B, C, 10, 9, (md5_uint32) 0x02441453); + OP (C, D, A, B, 15, 14, (md5_uint32) 0xd8a1e681); + OP (B, C, D, A, 4, 20, (md5_uint32) 0xe7d3fbc8); + OP (A, B, C, D, 9, 5, (md5_uint32) 0x21e1cde6); + OP (D, A, B, C, 14, 9, (md5_uint32) 0xc33707d6); + OP (C, D, A, B, 3, 14, (md5_uint32) 0xf4d50d87); + OP (B, C, D, A, 8, 20, (md5_uint32) 0x455a14ed); + OP (A, B, C, D, 13, 5, (md5_uint32) 0xa9e3e905); + OP (D, A, B, C, 2, 9, (md5_uint32) 0xfcefa3f8); + OP (C, D, A, B, 7, 14, (md5_uint32) 0x676f02d9); + OP (B, C, D, A, 12, 20, (md5_uint32) 0x8d2a4c8a); + +#undef FX +#define FX(b, c, d) FH (b, c, d) + + /* Round 3. */ + OP (A, B, C, D, 5, 4, (md5_uint32) 0xfffa3942); + OP (D, A, B, C, 8, 11, (md5_uint32) 0x8771f681); + OP (C, D, A, B, 11, 16, (md5_uint32) 0x6d9d6122); + OP (B, C, D, A, 14, 23, (md5_uint32) 0xfde5380c); + OP (A, B, C, D, 1, 4, (md5_uint32) 0xa4beea44); + OP (D, A, B, C, 4, 11, (md5_uint32) 0x4bdecfa9); + OP (C, D, A, B, 7, 16, (md5_uint32) 0xf6bb4b60); + OP (B, C, D, A, 10, 23, (md5_uint32) 0xbebfbc70); + OP (A, B, C, D, 13, 4, (md5_uint32) 0x289b7ec6); + OP (D, A, B, C, 0, 11, (md5_uint32) 0xeaa127fa); + OP (C, D, A, B, 3, 16, (md5_uint32) 0xd4ef3085); + OP (B, C, D, A, 6, 23, (md5_uint32) 0x04881d05); + OP (A, B, C, D, 9, 4, (md5_uint32) 0xd9d4d039); + OP (D, A, B, C, 12, 11, (md5_uint32) 0xe6db99e5); + OP (C, D, A, B, 15, 16, (md5_uint32) 0x1fa27cf8); + OP (B, C, D, A, 2, 23, (md5_uint32) 0xc4ac5665); + +#undef FX +#define FX(b, c, d) FI (b, c, d) + + /* Round 4. */ + OP (A, B, C, D, 0, 6, (md5_uint32) 0xf4292244); + OP (D, A, B, C, 7, 10, (md5_uint32) 0x432aff97); + OP (C, D, A, B, 14, 15, (md5_uint32) 0xab9423a7); + OP (B, C, D, A, 5, 21, (md5_uint32) 0xfc93a039); + OP (A, B, C, D, 12, 6, (md5_uint32) 0x655b59c3); + OP (D, A, B, C, 3, 10, (md5_uint32) 0x8f0ccc92); + OP (C, D, A, B, 10, 15, (md5_uint32) 0xffeff47d); + OP (B, C, D, A, 1, 21, (md5_uint32) 0x85845dd1); + OP (A, B, C, D, 8, 6, (md5_uint32) 0x6fa87e4f); + OP (D, A, B, C, 15, 10, (md5_uint32) 0xfe2ce6e0); + OP (C, D, A, B, 6, 15, (md5_uint32) 0xa3014314); + OP (B, C, D, A, 13, 21, (md5_uint32) 0x4e0811a1); + OP (A, B, C, D, 4, 6, (md5_uint32) 0xf7537e82); + OP (D, A, B, C, 11, 10, (md5_uint32) 0xbd3af235); + OP (C, D, A, B, 2, 15, (md5_uint32) 0x2ad7d2bb); + OP (B, C, D, A, 9, 21, (md5_uint32) 0xeb86d391); + + /* Add the starting values of the context. */ + A += A_save; + B += B_save; + C += C_save; + D += D_save; + } + + /* Put checksum in context given as argument. */ + ctx->A = A; + ctx->B = B; + ctx->C = C; + ctx->D = D; +} diff --git a/support/cpp2/line-map.c b/support/cpp2/line-map.c deleted file mode 100644 index 521c4e5c..00000000 --- a/support/cpp2/line-map.c +++ /dev/null @@ -1,237 +0,0 @@ -/* Map logical line numbers to (source file, line number) pairs. - Copyright (C) 2001, 2003 - Free Software Foundation, Inc. - -This program 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 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - In other words, you are welcome to use, share and improve this program. - You are forbidden to forbid anyone else to use, share and improve - what you give them. Help stamp out software-hoarding! */ - -#include "config.h" -#include "system.h" -#include "line-map.h" -#include "intl.h" - -static void trace_include (const struct line_maps *, const struct line_map *); - -/* Initialize a line map set. */ - -void -linemap_init (struct line_maps *set) -{ - set->maps = 0; - set->allocated = 0; - set->used = 0; - set->last_listed = -1; - set->trace_includes = false; - set->depth = 0; -} - -/* Free a line map set. */ - -void -linemap_free (struct line_maps *set) -{ - if (set->maps) - { - struct line_map *map; - - /* Depending upon whether we are handling preprocessed input or - not, this can be a user error or an ICE. */ - for (map = CURRENT_LINE_MAP (set); ! MAIN_FILE_P (map); - map = INCLUDED_FROM (set, map)) - fprintf (stderr, "line-map.c: file \"%s\" entered but not left\n", - map->to_file); - - free (set->maps); - } -} - -/* Add a mapping of logical source line to physical source file and - line number. - - The text pointed to by TO_FILE must have a lifetime - at least as long as the final call to lookup_line (). An empty - TO_FILE means standard input. If reason is LC_LEAVE, and - TO_FILE is NULL, then TO_FILE, TO_LINE and SYSP are given their - natural values considering the file we are returning to. - - FROM_LINE should be monotonic increasing across calls to this - function. A call to this function can relocate the previous set of - maps, so any stored line_map pointers should not be used. */ - -const struct line_map * -linemap_add (struct line_maps *set, enum lc_reason reason, - unsigned int sysp, source_location from_line, - const char *to_file, unsigned int to_line) -{ - struct line_map *map; - - if (set->used && from_line < set->maps[set->used - 1].from_line) - abort (); - - if (set->used == set->allocated) - { - set->allocated = 2 * set->allocated + 256; - set->maps = xrealloc (set->maps, set->allocated * sizeof (struct line_map)); - } - - map = &set->maps[set->used++]; - - if (to_file && *to_file == '\0') - to_file = ""; - - /* If we don't keep our line maps consistent, we can easily - segfault. Don't rely on the client to do it for us. */ - if (set->depth == 0) - reason = LC_ENTER; - else if (reason == LC_LEAVE) - { - struct line_map *from; - bool error; - - if (MAIN_FILE_P (map - 1)) - { - if (to_file == NULL) - { - set->depth--; - set->used--; - return NULL; - } - error = true; - reason = LC_RENAME; - from = map - 1; - } - else - { - from = INCLUDED_FROM (set, map - 1); - error = to_file && strcmp (from->to_file, to_file); - } - - /* Depending upon whether we are handling preprocessed input or - not, this can be a user error or an ICE. */ - if (error) - fprintf (stderr, "line-map.c: file \"%s\" left but not entered\n", - to_file); - - /* A TO_FILE of NULL is special - we use the natural values. */ - if (error || to_file == NULL) - { - to_file = from->to_file; - to_line = LAST_SOURCE_LINE (from) + 1; - sysp = from->sysp; - } - } - - map->reason = reason; - map->sysp = sysp; - map->from_line = from_line; - map->to_file = to_file; - map->to_line = to_line; - - if (reason == LC_ENTER) - { - map->included_from = set->depth == 0 ? -1 : (int) (set->used - 2); - set->depth++; - if (set->trace_includes) - trace_include (set, map); - } - else if (reason == LC_RENAME) - map->included_from = map[-1].included_from; - else if (reason == LC_LEAVE) - { - set->depth--; - map->included_from = INCLUDED_FROM (set, map - 1)->included_from; - } - - return map; -} - -/* Given a logical line, returns the map from which the corresponding - (source file, line) pair can be deduced. Since the set is built - chronologically, the logical lines are monotonic increasing, and so - the list is sorted and we can use a binary search. */ - -const struct line_map * -linemap_lookup (struct line_maps *set, source_location line) -{ - unsigned int md, mn = 0, mx = set->used; - - if (mx == 0) - abort (); - - while (mx - mn > 1) - { - md = (mn + mx) / 2; - if (set->maps[md].from_line > line) - mx = md; - else - mn = md; - } - - return &set->maps[mn]; -} - -/* Print the file names and line numbers of the #include commands - which led to the map MAP, if any, to stderr. Nothing is output if - the most recently listed stack is the same as the current one. */ - -void -linemap_print_containing_files (struct line_maps *set, - const struct line_map *map) -{ - if (MAIN_FILE_P (map) || set->last_listed == map->included_from) - return; - - set->last_listed = map->included_from; - map = INCLUDED_FROM (set, map); - - fprintf (stderr, _("In file included from %s:%u"), - map->to_file, LAST_SOURCE_LINE (map)); - - while (! MAIN_FILE_P (map)) - { - map = INCLUDED_FROM (set, map); - /* Translators note: this message is used in conjunction - with "In file included from %s:%ld" and some other - tricks. We want something like this: - - | In file included from sys/select.h:123, - | from sys/types.h:234, - | from userfile.c:31: - | bits/select.h:45: - - with all the "from"s lined up. - The trailing comma is at the beginning of this message, - and the trailing colon is not translated. */ - fprintf (stderr, _(",\n from %s:%u"), - map->to_file, LAST_SOURCE_LINE (map)); - } - - fputs (":\n", stderr); -} - -/* Print an include trace, for e.g. the -H option of the preprocessor. */ - -static void -trace_include (const struct line_maps *set, const struct line_map *map) -{ - unsigned int i = set->depth; - - while (--i) - putc ('.', stderr); - fprintf (stderr, " %s\n", map->to_file); -} diff --git a/support/cpp2/line-map.h b/support/cpp2/line-map.h deleted file mode 100644 index c57f51a6..00000000 --- a/support/cpp2/line-map.h +++ /dev/null @@ -1,126 +0,0 @@ -/* Map logical line numbers to (source file, line number) pairs. - Copyright (C) 2001, 2003 - Free Software Foundation, Inc. - -This program 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 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - In other words, you are welcome to use, share and improve this program. - You are forbidden to forbid anyone else to use, share and improve - what you give them. Help stamp out software-hoarding! */ - -#ifndef GCC_LINE_MAP_H -#define GCC_LINE_MAP_H - -/* Reason for adding a line change with add_line_map (). LC_ENTER is - when including a new file, e.g. a #include directive in C. - LC_LEAVE is when reaching a file's end. LC_RENAME is when a file - name or line number changes for neither of the above reasons - (e.g. a #line directive in C). */ -enum lc_reason {LC_ENTER = 0, LC_LEAVE, LC_RENAME}; - -/* A logical line number, i,e, an "index" into a line_map. */ -/* Long-term, we want to use this to replace struct location_s (in input.h), - and effectively typedef source_location location_t. */ -typedef unsigned int source_location; -typedef source_location fileline; /* deprecated name */ - -/* The logical line FROM_LINE maps to physical source file TO_FILE at - line TO_LINE, and subsequently one-to-one until the next line_map - structure in the set. INCLUDED_FROM is an index into the set that - gives the line mapping at whose end the current one was included. - File(s) at the bottom of the include stack have this set to -1. - REASON is the reason for creation of this line map, SYSP is one for - a system header, two for a C system header file that therefore - needs to be extern "C" protected in C++, and zero otherwise. */ -struct line_map -{ - const char *to_file; - unsigned int to_line; - source_location from_line; - int included_from; - ENUM_BITFIELD (lc_reason) reason : CHAR_BIT; - unsigned char sysp; -}; - -/* A set of chronological line_map structures. */ -struct line_maps -{ - struct line_map *maps; - unsigned int allocated; - unsigned int used; - - /* The most recently listed include stack, if any, starts with - LAST_LISTED as the topmost including file. -1 indicates nothing - has been listed yet. */ - int last_listed; - - /* Depth of the include stack, including the current file. */ - unsigned int depth; - - /* If true, prints an include trace a la -H. */ - bool trace_includes; -}; - -/* Initialize a line map set. */ -extern void linemap_init (struct line_maps *); - -/* Free a line map set. */ -extern void linemap_free (struct line_maps *); - -/* Add a mapping of logical source line to physical source file and - line number. - - The text pointed to by TO_FILE must have a lifetime - at least as long as the final call to lookup_line (). An empty - TO_FILE means standard input. If reason is LC_LEAVE, and - TO_FILE is NULL, then TO_FILE, TO_LINE and SYSP are given their - natural values considering the file we are returning to. - - FROM_LINE should be monotonic increasing across calls to this - function. A call to this function can relocate the previous set of - maps, so any stored line_map pointers should not be used. */ -extern const struct line_map *linemap_add - (struct line_maps *, enum lc_reason, unsigned int sysp, - source_location from_line, const char *to_file, unsigned int to_line); - -/* Given a logical line, returns the map from which the corresponding - (source file, line) pair can be deduced. */ -extern const struct line_map *linemap_lookup - (struct line_maps *, source_location); - -/* Print the file names and line numbers of the #include commands - which led to the map MAP, if any, to stderr. Nothing is output if - the most recently listed stack is the same as the current one. */ -extern void linemap_print_containing_files (struct line_maps *, - const struct line_map *); - -/* Converts a map and logical line to source line. */ -#define SOURCE_LINE(MAP, LINE) ((LINE) + (MAP)->to_line - (MAP)->from_line) - -/* Returns the last source line within a map. This is the (last) line - of the #include, or other directive, that caused a map change. */ -#define LAST_SOURCE_LINE(MAP) SOURCE_LINE ((MAP), (MAP)[1].from_line - 1) - -/* Returns the map a given map was included from. */ -#define INCLUDED_FROM(SET, MAP) (&(SET)->maps[(MAP)->included_from]) - -/* Nonzero if the map is at the bottom of the include stack. */ -#define MAIN_FILE_P(MAP) ((MAP)->included_from < 0) - -/* The current line map. Saves a call to lookup_line if the caller is - sure he is in the scope of the current map. */ -#define CURRENT_LINE_MAP(MAPS) ((MAPS)->maps + (MAPS)->used - 1) - -#endif /* !GCC_LINE_MAP_H */ diff --git a/support/cpp2/md5.h b/support/cpp2/md5.h new file mode 100644 index 00000000..e3578934 --- /dev/null +++ b/support/cpp2/md5.h @@ -0,0 +1,139 @@ +/* md5.h - Declaration of functions and data types used for MD5 sum + computing library functions. + Copyright 1995, 1996, 2000 Free Software Foundation, Inc. + NOTE: The canonical source of this file is maintained with the GNU C + Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. + + This program 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 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _MD5_H +#define _MD5_H 1 + +#include + +#if defined HAVE_LIMITS_H || _LIBC +# include +#endif + +/* The following contortions are an attempt to use the C preprocessor + to determine an unsigned integral type that is 32 bits wide. An + alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but + doing that would require that the configure script compile and *run* + the resulting executable. Locally running cross-compiled executables + is usually not possible. */ + +#ifdef _LIBC +# include +typedef u_int32_t md5_uint32; +typedef uintptr_t md5_uintptr; +#else +# define INT_MAX_32_BITS 2147483647 + +/* If UINT_MAX isn't defined, assume it's a 32-bit type. + This should be valid for all systems GNU cares about because + that doesn't include 16-bit systems, and only modern systems + (that certainly have ) have 64+-bit integral types. */ + +# ifndef INT_MAX +# define INT_MAX INT_MAX_32_BITS +# endif + +# if INT_MAX == INT_MAX_32_BITS + typedef unsigned int md5_uint32; +# else +# if SHRT_MAX == INT_MAX_32_BITS + typedef unsigned short md5_uint32; +# else +# if LONG_MAX == INT_MAX_32_BITS + typedef unsigned long md5_uint32; +# else + /* The following line is intended to evoke an error. + Using #error is not portable enough. */ + "Cannot determine unsigned 32-bit data type." +# endif +# endif +# endif +/* We have to make a guess about the integer type equivalent in size + to pointers which should always be correct. */ +typedef unsigned long int md5_uintptr; +#endif + +/* Structure to save state of computation between the single steps. */ +struct md5_ctx +{ + md5_uint32 A; + md5_uint32 B; + md5_uint32 C; + md5_uint32 D; + + md5_uint32 total[2]; + md5_uint32 buflen; + char buffer[128] ATTRIBUTE_ALIGNED_ALIGNOF(md5_uint32); +}; + +/* + * The following three functions are build up the low level used in + * the functions `md5_stream' and `md5_buffer'. + */ + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +extern void md5_init_ctx (struct md5_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ +extern void md5_process_block (const void *buffer, size_t len, + struct md5_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 64. */ +extern void md5_process_bytes (const void *buffer, size_t len, + struct md5_ctx *ctx); + +/* Process the remaining bytes in the buffer and put result from CTX + in first 16 bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +extern void *md5_finish_ctx (struct md5_ctx *ctx, void *resbuf); + + +/* Put result from CTX in first 16 bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +extern void *md5_read_ctx (const struct md5_ctx *ctx, void *resbuf); + + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +extern int md5_stream (FILE *stream, void *resblock); + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *md5_buffer (const char *buffer, size_t len, void *resblock); + +#endif diff --git a/support/cpp2/mkdeps.c b/support/cpp2/mkdeps.c deleted file mode 100644 index d50d2bf7..00000000 --- a/support/cpp2/mkdeps.c +++ /dev/null @@ -1,364 +0,0 @@ -/* Dependency generator for Makefile fragments. - Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc. - Contributed by Zack Weinberg, Mar 2000 - -This program 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 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - In other words, you are welcome to use, share and improve this program. - You are forbidden to forbid anyone else to use, share and improve - what you give them. Help stamp out software-hoarding! */ - -#include "config.h" -#include "system.h" -#include "mkdeps.h" -#include "cpplib.h" -#include "cpphash.h" - -/* Keep this structure local to this file, so clients don't find it - easy to start making assumptions. */ -struct deps -{ - const char **targetv; - unsigned int ntargets; /* number of slots actually occupied */ - unsigned int targets_size; /* amt of allocated space - in words */ - - const char **depv; - unsigned int ndeps; - unsigned int deps_size; -}; - -static const char *munge (const char *); - -/* Given a filename, quote characters in that filename which are - significant to Make. Note that it's not possible to quote all such - characters - e.g. \n, %, *, ?, [, \ (in some contexts), and ~ are - not properly handled. It isn't possible to get this right in any - current version of Make. (??? Still true? Old comment referred to - 3.76.1.) */ - -static const char * -munge (const char *filename) -{ - int len; - const char *p, *q; - char *dst, *buffer; - - for (p = filename, len = 0; *p; p++, len++) - { - switch (*p) - { - case ' ': - case '\t': - /* GNU make uses a weird quoting scheme for white space. - A space or tab preceded by 2N+1 backslashes represents - N backslashes followed by space; a space or tab - preceded by 2N backslashes represents N backslashes at - the end of a file name; and backslashes in other - contexts should not be doubled. */ - for (q = p - 1; filename <= q && *q == '\\'; q--) - len++; - len++; - break; - - case '$': - /* '$' is quoted by doubling it. */ - len++; - break; - } - } - - /* Now we know how big to make the buffer. */ - buffer = xmalloc (len + 1); - - for (p = filename, dst = buffer; *p; p++, dst++) - { - switch (*p) - { - case ' ': - case '\t': - for (q = p - 1; filename <= q && *q == '\\'; q--) - *dst++ = '\\'; - *dst++ = '\\'; - break; - - case '$': - *dst++ = '$'; - break; - - default: - /* nothing */; - } - *dst = *p; - } - - *dst = '\0'; - return buffer; -} - -/* Public routines. */ - -struct deps * -deps_init (void) -{ - struct deps *d = xmalloc (sizeof (struct deps)); - - /* Allocate space for the vectors only if we need it. */ - - d->targetv = 0; - d->depv = 0; - - d->ntargets = 0; - d->targets_size = 0; - d->ndeps = 0; - d->deps_size = 0; - - return d; -} - -void -deps_free (struct deps *d) -{ - unsigned int i; - - if (d->targetv) - { - for (i = 0; i < d->ntargets; i++) - free ((void *) d->targetv[i]); - free (d->targetv); - } - - if (d->depv) - { - for (i = 0; i < d->ndeps; i++) - free ((void *) d->depv[i]); - free (d->depv); - } - - free (d); -} - -/* Adds a target T. We make a copy, so it need not be a permanent - string. QUOTE is true if the string should be quoted. */ -void -deps_add_target (struct deps *d, const char *t, int quote) -{ - if (d->ntargets == d->targets_size) - { - d->targets_size = d->targets_size * 2 + 4; - d->targetv = xrealloc (d->targetv, - d->targets_size * sizeof (const char *)); - } - - if (quote) - t = munge (t); /* Also makes permanent copy. */ - else - t = xstrdup (t); - - d->targetv[d->ntargets++] = t; -} - -/* Sets the default target if none has been given already. An empty - string as the default target in interpreted as stdin. The string - is quoted for MAKE. */ -void -deps_add_default_target (cpp_reader *pfile, const char *tgt) -{ - struct deps *d = pfile->deps; - - /* Only if we have no targets. */ - if (d->ntargets) - return; - - if (tgt[0] == '\0') - deps_add_target (d, "-", 1); - else - { -#ifndef TARGET_OBJECT_SUFFIX -# define TARGET_OBJECT_SUFFIX ".o" -#endif - const char *start = lbasename (tgt); - char *o; - char *suffix; - const char *obj_ext; - - if (NULL == CPP_OPTION (pfile, obj_ext)) - obj_ext = TARGET_OBJECT_SUFFIX; - else if (CPP_OPTION (pfile, obj_ext)[0] != '.') - { - char *t = alloca (strlen (CPP_OPTION (pfile, obj_ext)) + 2); - t[0] = '.'; - strcpy (&t[1], CPP_OPTION (pfile, obj_ext)); - obj_ext = t; - } - else - obj_ext = CPP_OPTION (pfile, obj_ext); - - o = (char *) alloca (strlen (start) + strlen (obj_ext) + 1); - - strcpy (o, start); - - suffix = strrchr (o, '.'); - if (!suffix) - suffix = o + strlen (o); - strcpy (suffix, obj_ext); - - deps_add_target (d, o, 1); - } -} - -void -deps_add_dep (struct deps *d, const char *t) -{ - t = munge (t); /* Also makes permanent copy. */ - - if (d->ndeps == d->deps_size) - { - d->deps_size = d->deps_size * 2 + 8; - d->depv = xrealloc (d->depv, d->deps_size * sizeof (const char *)); - } - d->depv[d->ndeps++] = t; -} - -void -deps_write (const struct deps *d, FILE *fp, unsigned int colmax) -{ - unsigned int size, i, column; - - column = 0; - if (colmax && colmax < 34) - colmax = 34; - - for (i = 0; i < d->ntargets; i++) - { - size = strlen (d->targetv[i]); - column += size; - if (colmax && column > colmax) - { - fputs (" \\\n ", fp); - column = 1 + size; - } - if (i) - { - putc (' ', fp); - column++; - } - fputs (d->targetv[i], fp); - } - - putc (':', fp); - putc (' ', fp); - column += 2; - - for (i = 0; i < d->ndeps; i++) - { - size = strlen (d->depv[i]); - column += size; - if (colmax && column > colmax) - { - fputs (" \\\n ", fp); - column = 1 + size; - } - if (i) - { - putc (' ', fp); - column++; - } - fputs (d->depv[i], fp); - } - putc ('\n', fp); -} - -void -deps_phony_targets (const struct deps *d, FILE *fp) -{ - unsigned int i; - - for (i = 1; i < d->ndeps; i++) - { - putc ('\n', fp); - fputs (d->depv[i], fp); - putc (':', fp); - putc ('\n', fp); - } -} - -/* Write out a deps buffer to a file, in a form that can be read back - with deps_restore. Returns nonzero on error, in which case the - error number will be in errno. */ - -int -deps_save (struct deps *deps, FILE *f) -{ - unsigned int i; - - /* The cppreader structure contains makefile dependences. Write out this - structure. */ - - /* The number of dependences. */ - if (fwrite (&deps->ndeps, sizeof (deps->ndeps), 1, f) != 1) - return -1; - /* The length of each dependence followed by the string. */ - for (i = 0; i < deps->ndeps; i++) - { - size_t num_to_write = strlen (deps->depv[i]); - if (fwrite (&num_to_write, sizeof (size_t), 1, f) != 1) - return -1; - if (fwrite (deps->depv[i], num_to_write, 1, f) != 1) - return -1; - } - - return 0; -} - -/* Read back dependency information written with deps_save into - the deps buffer. The third argument may be NULL, in which case - the dependency information is just skipped, or it may be a filename, - in which case that filename is skipped. */ - -int -deps_restore (struct deps *deps, FILE *fd, const char *self) -{ - unsigned int i, count; - size_t num_to_read; - size_t buf_size = 512; - char *buf = xmalloc (buf_size); - - /* Number of dependences. */ - if (fread (&count, 1, sizeof (count), fd) != sizeof (count)) - return -1; - - /* The length of each dependence string, followed by the string. */ - for (i = 0; i < count; i++) - { - /* Read in # bytes in string. */ - if (fread (&num_to_read, 1, sizeof (size_t), fd) != sizeof (size_t)) - return -1; - if (buf_size < num_to_read + 1) - { - buf_size = num_to_read + 1 + 127; - buf = xrealloc (buf, buf_size); - } - if (fread (buf, 1, num_to_read, fd) != num_to_read) - return -1; - buf[num_to_read] = '\0'; - - /* Generate makefile dependencies from .pch if -nopch-deps. */ - if (self != NULL && strcmp (buf, self) != 0) - deps_add_dep (deps, buf); - } - - free (buf); - return 0; -} diff --git a/support/cpp2/mkdeps.h b/support/cpp2/mkdeps.h deleted file mode 100644 index db2e00e0..00000000 --- a/support/cpp2/mkdeps.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Dependency generator for Makefile fragments. - Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc. - Contributed by Zack Weinberg, Mar 2000 - -This program 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 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - In other words, you are welcome to use, share and improve this program. - You are forbidden to forbid anyone else to use, share and improve - what you give them. Help stamp out software-hoarding! */ - -#ifndef GCC_MKDEPS_H -#define GCC_MKDEPS_H - -/* This is the data structure used by all the functions in mkdeps.c. - It's quite straightforward, but should be treated as opaque. */ - -struct deps; -struct cpp_reader; - -/* Create a deps buffer. */ -extern struct deps *deps_init (void); - -/* Destroy a deps buffer. */ -extern void deps_free (struct deps *); - -/* Add a target (appears on left side of the colon) to the deps list. Takes - a boolean indicating whether to quote the target for MAKE. */ -extern void deps_add_target (struct deps *, const char *, int); - -/* Sets the default target if none has been given already. An empty - string as the default target is interpreted as stdin. */ -extern void deps_add_default_target (struct cpp_reader *, const char *); - -/* Add a dependency (appears on the right side of the colon) to the - deps list. Dependencies will be printed in the order that they - were entered with this function. By convention, the first - dependency entered should be the primary source file. */ -extern void deps_add_dep (struct deps *, const char *); - -/* Write out a deps buffer to a specified file. The third argument - is the number of columns to word-wrap at (0 means don't wrap). */ -extern void deps_write (const struct deps *, FILE *, unsigned int); - -/* Write out a deps buffer to a file, in a form that can be read back - with deps_restore. Returns nonzero on error, in which case the - error number will be in errno. */ -extern int deps_save (struct deps *, FILE *); - -/* Read back dependency information written with deps_save into - the deps buffer. The third argument may be NULL, in which case - the dependency information is just skipped, or it may be a filename, - in which case that filename is skipped. */ -extern int deps_restore (struct deps *, FILE *, const char *); - -/* For each dependency *except the first*, emit a dummy rule for that - file, causing it to depend on nothing. This is used to work around - the intermediate-file deletion misfeature in Make, in some - automatic dependency schemes. */ -extern void deps_phony_targets (const struct deps *, FILE *); - -#endif /* ! GCC_MKDEPS_H */ diff --git a/support/cpp2/move-if-change b/support/cpp2/move-if-change index 66d8b8ad..d267e721 100644 --- a/support/cpp2/move-if-change +++ b/support/cpp2/move-if-change @@ -1,11 +1,26 @@ #!/bin/sh -# Like mv $1 $2, but if the files are the same, just delete $1. -# Status is 0 if $2 is changed, 1 otherwise. + +# Copyright (C) 1996 Free Software Foundation, Inc. +# +# This program 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 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + if test -r $2 then if -cmp -s $1 $2 +cmp $1 $2 > /dev/null then echo $2 is unchanged rm -f $1 diff --git a/support/cpp2/opt-functions.awk b/support/cpp2/opt-functions.awk new file mode 100644 index 00000000..f392060c --- /dev/null +++ b/support/cpp2/opt-functions.awk @@ -0,0 +1,169 @@ +# Copyright (C) 2003,2004 Free Software Foundation, Inc. +# Contributed by Kelley Cook, June 2004. +# Original code from Neil Booth, May 2003. +# +# This program 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 2, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Some common subroutines for use by opt[ch]-gen.awk. + +# Return nonzero if FLAGS contains a flag matching REGEX. +function flag_set_p(regex, flags) +{ + return (" " flags " ") ~ (" " regex " ") +} + +# Return STRING if FLAGS contains a flag matching regexp REGEX, +# otherwise return the empty string. +function test_flag(regex, flags, string) +{ + if (flag_set_p(regex, flags)) + return string + return "" +} + +# If FLAGS contains a "NAME(...argument...)" flag, return the value +# of the argument. Return the empty string otherwise. +function opt_args(name, flags) +{ + flags = " " flags + if (flags !~ " " name "\\(") + return "" + sub(".* " name "\\(", "", flags) + sub("\\).*", "", flags) + + return flags +} + +# Return the Nth comma-separated element of S. Return the empty string +# if S does not contain N elements. +function nth_arg(n, s) +{ + while (n-- > 0) { + if (s !~ ",") + return "" + sub("[^,]*, *", "", s) + } + sub(",.*", "", s) + return s +} + +# Return a bitmask of CL_* values for option flags FLAGS. +function switch_flags (flags) +{ + result = "0" + for (j = 0; j < n_langs; j++) { + regex = langs[j] + gsub ( "\\+", "\\+", regex ) + result = result test_flag(regex, flags, " | " macros[j]) + } + result = result \ + test_flag("Common", flags, " | CL_COMMON") \ + test_flag("Target", flags, " | CL_TARGET") \ + test_flag("Joined", flags, " | CL_JOINED") \ + test_flag("JoinedOrMissing", flags, " | CL_JOINED | CL_MISSING_OK") \ + test_flag("Separate", flags, " | CL_SEPARATE") \ + test_flag("RejectNegative", flags, " | CL_REJECT_NEGATIVE") \ + test_flag("UInteger", flags, " | CL_UINTEGER") \ + test_flag("Undocumented", flags, " | CL_UNDOCUMENTED") \ + test_flag("Report", flags, " | CL_REPORT") + sub( "^0 \\| ", "", result ) + return result +} + +# If FLAGS includes a Var flag, return the name of the variable it specifies. +# Return the empty string otherwise. +function var_name(flags) +{ + return nth_arg(0, opt_args("Var", flags)) +} + +# Return true if the option described by FLAGS has a globally-visible state. +function global_state_p(flags) +{ + return (var_name(flags) != "" \ + || opt_args("Mask", flags) != "" \ + || opt_args("InverseMask", flags) != "") +} + +# Return true if the option described by FLAGS must have some state +# associated with it. +function needs_state_p(flags) +{ + return flag_set_p("Target", flags) +} + +# If FLAGS describes an option that needs a static state variable, +# return the name of that variable, otherwise return "". NAME is +# the name of the option. +function static_var(name, flags) +{ + if (global_state_p(flags) || !needs_state_p(flags)) + return "" + gsub ("[^A-Za-z0-9]", "_", name) + return "VAR_" name +} + +# Return the type of variable that should be associated with the given flags. +function var_type(flags) +{ + if (!flag_set_p("Joined.*", flags)) + return "int " + else if (flag_set_p("UInteger", flags)) + return "int " + else + return "const char *" +} + +# Given that an option has flags FLAGS, return an initializer for the +# "var_cond" and "var_value" fields of its cl_options[] entry. +function var_set(flags) +{ + s = nth_arg(1, opt_args("Var", flags)) + if (s != "") + return "CLVC_EQUAL, " s + s = opt_args("Mask", flags); + if (s != "") { + vn = var_name(flags); + if (vn) + return "CLVC_BIT_SET, OPTION_MASK_" s + else + return "CLVC_BIT_SET, MASK_" s + } + s = nth_arg(0, opt_args("InverseMask", flags)); + if (s != "") { + vn = var_name(flags); + if (vn) + return "CLVC_BIT_CLEAR, OPTION_MASK_" s + else + return "CLVC_BIT_CLEAR, MASK_" s + } + if (var_type(flags) == "const char *") + return "CLVC_STRING, 0" + return "CLVC_BOOLEAN, 0" +} + +# Given that an option called NAME has flags FLAGS, return an initializer +# for the "flag_var" field of its cl_options[] entry. +function var_ref(name, flags) +{ + name = var_name(flags) static_var(name, flags) + if (name != "") + return "&" name + if (opt_args("Mask", flags) != "") + return "&target_flags" + if (opt_args("InverseMask", flags) != "") + return "&target_flags" + return "0" +} diff --git a/support/cpp2/opt-gather.awk b/support/cpp2/opt-gather.awk new file mode 100644 index 00000000..87dd37ab --- /dev/null +++ b/support/cpp2/opt-gather.awk @@ -0,0 +1,54 @@ +# Copyright (C) 2003,2004 Free Software Foundation, Inc. +# Contributed by Kelley Cook, June 2004. +# Original code from Neil Booth, May 2003. +# +# This program 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 2, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# This Awk script takes a list of *.opt files and combines them into +# a three-field sorted list suitable for input into opt[ch]-gen.awk. +# +# Usage: awk -f opt-gather.awk file1.opt [...] > outputfile + +function sort(ARRAY, ELEMENTS) +{ + for (i = 2; i <= ELEMENTS; ++i) { + for (j = i; ARRAY[j-1] > ARRAY[j]; --j) { + temp = ARRAY[j] + ARRAY[j] = ARRAY[j-1] + ARRAY[j-1] = temp + } + } + return +} + +BEGIN { numrec = 0 } + +# Ignore comments and blank lines +/^[ \t]*(;|$)/ { flag = 0; next } +/^[^ \t]/ { if (flag == 0) { + record[++numrec] = $0 + flag = 1 } + else { + record[numrec] = record[numrec] SUBSEP $0 + } +} + +# Sort it and output it +END { + sort(record,numrec) + + for (i = 1; i <= numrec; i++) { + print record[i] } +} diff --git a/support/cpp2/optc-gen.awk b/support/cpp2/optc-gen.awk new file mode 100644 index 00000000..08232f37 --- /dev/null +++ b/support/cpp2/optc-gen.awk @@ -0,0 +1,168 @@ +# Copyright (C) 2003,2004 Free Software Foundation, Inc. +# Contributed by Kelley Cook, June 2004. +# Original code from Neil Booth, May 2003. +# +# This program 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 2, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# This Awk script reads in the option records generated from +# opt-gather.awk, combines the flags of duplicat options and generates a +# C file. +# +# This program uses functions from opt-functions.awk +# +# Usage: awk -f opt-functions.awk -f optc-gen.awk \ +# [-v header_name=header.h] < inputfile > options.c + +BEGIN { + n_opts = 0 + n_langs = 0 + quote = "\042" + comma = "," + FS=SUBSEP + # Default the name of header created from opth-gen.awk to options.h + if (header_name == "") header_name="options.h" +} + +# Collect the text and flags of each option into an array + { + if ($1 == "Language") { + langs[n_langs] = $2 + n_langs++; + } + else { + name = opt_args("Mask", $1) + if (name == "") { + opts[n_opts] = $1 + flags[n_opts] = $2 + help[n_opts] = $3 + n_opts++; + } + } + } + +# Dump that array of options into a C file. +END { +print "/* This file is auto-generated by opts.sh. */" +print "" +n_headers = split(header_name, headers, " ") +for (i = 1; i <= n_headers; i++) + print "#include " quote headers[i] quote +print "#include " quote "opts.h" quote +print "#include " quote "intl.h" quote +print "" + +for (i = 0; i < n_opts; i++) { + name = var_name(flags[i]); + if (name == "") + continue; + + if (flag_set_p("VarExists", flags[i])) + continue; + + init = opt_args("Init", flags[i]) + if (init != "") + init = " = " init; + else if (name in var_seen) + continue; + + print "/* Set by -" opts[i] "." + print " " help[i] " */" + print var_type(flags[i]) name init ";" + print "" + + var_seen[name] = 1; +} + +print "" +print "/* Local state variables. */" +for (i = 0; i < n_opts; i++) { + name = static_var(opts[i], flags[i]); + if (name != "") + print "static " var_type(flags[i]) name ";" +} +print "" + +print "const char * const lang_names[] =\n{" +for (i = 0; i < n_langs; i++) { + macros[i] = "CL_" langs[i] + gsub( "[^A-Za-z0-9_]", "X", macros[i] ) + s = substr(" ", length (macros[i])) + print " " quote langs[i] quote "," + } + +print " 0\n};\n" +print "const unsigned int cl_options_count = N_OPTS;\n" + +print "const struct cl_option cl_options[] =\n{" + +for (i = 0; i < n_opts; i++) + back_chain[i] = "N_OPTS"; + +for (i = 0; i < n_opts; i++) { + # Combine the flags of identical switches. Switches + # appear many times if they are handled by many front + # ends, for example. + while( i + 1 != n_opts && opts[i] == opts[i + 1] ) { + flags[i + 1] = flags[i] " " flags[i + 1]; + i++; + } + + len = length (opts[i]); + enum = "OPT_" opts[i] + if (opts[i] == "finline-limit=") + enum = enum "eq" + gsub ("[^A-Za-z0-9]", "_", enum) + + # If this switch takes joined arguments, back-chain all + # subsequent switches to it for which it is a prefix. If + # a later switch S is a longer prefix of a switch T, T + # will be back-chained to S in a later iteration of this + # for() loop, which is what we want. + if (flag_set_p("Joined.*", flags[i])) { + for (j = i + 1; j < n_opts; j++) { + if (substr (opts[j], 1, len) != opts[i]) + break; + back_chain[j] = enum; + } + } + + s = substr(" ", length (opts[i])) + if (i + 1 == n_opts) + comma = "" + + if (help[i] == "") + hlp = "0" + else + hlp = quote help[i] quote; + + printf(" { %c-%s%c,\n %s,\n %s, %u,\n", + quote, opts[i], quote, hlp, back_chain[i], len) + condition = opt_args("Condition", flags[i]) + cl_flags = switch_flags(flags[i]) + if (condition != "") + printf("#if %s\n" \ + " %s,\n" \ + "#else\n" \ + " CL_DISABLED,\n" \ + "#endif\n", + condition, cl_flags, cl_flags) + else + printf(" %s,\n", cl_flags) + printf(" %s, %s }%s\n", var_ref(opts[i], flags[i]), + var_set(flags[i]), comma) +} + +print "};" +} diff --git a/support/cpp2/opth-gen.awk b/support/cpp2/opth-gen.awk new file mode 100644 index 00000000..09d1a9a0 --- /dev/null +++ b/support/cpp2/opth-gen.awk @@ -0,0 +1,185 @@ +# Copyright (C) 2003,2004 Free Software Foundation, Inc. +# Contributed by Kelley Cook, June 2004. +# Original code from Neil Booth, May 2003. +# +# This program 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 2, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# This Awk script reads in the option records generated from +# opt-gather.awk, combines the flags of duplicate options and generates a +# C header file. +# +# This program uses functions from opt-functions.awk +# Usage: awk -f opt-functions.awk -f opth-gen.awk < inputfile > options.h + +BEGIN { + n_opts = 0 + n_langs = 0 + n_extra_masks = 0 + quote = "\042" + comma = "," + FS=SUBSEP +} + +# Collect the text and flags of each option into an array + { + if ($1 == "Language") { + langs[n_langs] = $2 + n_langs++; + } + else { + name = opt_args("Mask", $1) + if (name == "") { + opts[n_opts] = $1 + flags[n_opts] = $2 + help[n_opts] = $3 + n_opts++; + } + else { + extra_masks[n_extra_masks++] = name + } + } + } + +# Dump out an enumeration into a .h file. +# Combine the flags of duplicate options. +END { +print "/* This file is auto-generated by opts.sh. */" +print "" +print "#ifndef OPTIONS_H" +print "#define OPTIONS_H" +print "" +print "extern int target_flags;" +print "" + +for (i = 0; i < n_opts; i++) { + name = var_name(flags[i]); + if (name == "") + continue; + + print "extern " var_type(flags[i]) name ";" +} +print "" + +for (i = 0; i < n_opts; i++) { + name = opt_args("Mask", flags[i]) + vname = var_name(flags[i]) + mask = "MASK_" + if (vname != "") { + mask = "OPTION_MASK_" + } + if (name != "" && !flag_set_p("MaskExists", flags[i])) + print "#define " mask name " (1 << " masknum[vname]++ ")" +} +for (i = 0; i < n_extra_masks; i++) { + print "#define MASK_" extra_masks[i] " (1 << " masknum[""]++ ")" +} + +for (var in masknum) { + if (masknum[var] > 31) { + if (var == "") + print "#error too many target masks" + else + print "#error too many masks for " var + } +} +print "" + +for (i = 0; i < n_opts; i++) { + name = opt_args("Mask", flags[i]) + vname = var_name(flags[i]) + macro = "OPTION_" + mask = "OPTION_MASK_" + if (vname == "") { + vname = "target_flags" + macro = "TARGET_" + mask = "MASK_" + } + if (name != "" && !flag_set_p("MaskExists", flags[i])) + print "#define " macro name \ + " ((" vname " & " mask name ") != 0)" +} +for (i = 0; i < n_extra_masks; i++) { + print "#define TARGET_" extra_masks[i] \ + " ((target_flags & MASK_" extra_masks[i] ") != 0)" +} +print "" + +for (i = 0; i < n_opts; i++) { + opt = opt_args("InverseMask", flags[i]) + if (opt ~ ",") + print "#define TARGET_" nth_arg(1, opt) \ + " ((target_flags & MASK_" nth_arg(0, opt) ") == 0)" +} +print "" + +for (i = 0; i < n_langs; i++) { + macros[i] = "CL_" langs[i] + gsub( "[^A-Za-z0-9_]", "X", macros[i] ) + s = substr(" ", length (macros[i])) + print "#define " macros[i] s " (1 << " i ")" + } + +print "" +print "enum opt_code" +print "{" + +for (i = 0; i < n_opts; i++) + back_chain[i] = "N_OPTS"; + +for (i = 0; i < n_opts; i++) { + # Combine the flags of identical switches. Switches + # appear many times if they are handled by many front + # ends, for example. + while( i + 1 != n_opts && opts[i] == opts[i + 1] ) { + flags[i + 1] = flags[i] " " flags[i + 1]; + i++; + } + + len = length (opts[i]); + enum = "OPT_" opts[i] + if (opts[i] == "finline-limit=") + enum = enum "eq" + gsub ("[^A-Za-z0-9]", "_", enum) + + # If this switch takes joined arguments, back-chain all + # subsequent switches to it for which it is a prefix. If + # a later switch S is a longer prefix of a switch T, T + # will be back-chained to S in a later iteration of this + # for() loop, which is what we want. + if (flag_set_p("Joined.*", flags[i])) { + for (j = i + 1; j < n_opts; j++) { + if (substr (opts[j], 1, len) != opts[i]) + break; + back_chain[j] = enum; + } + } + + s = substr(" ", length (opts[i])) + if (i + 1 == n_opts) + comma = "" + + if (help[i] == "") + hlp = "0" + else + hlp = "N_(\"" help[i] "\")"; + + print " " enum "," s "/* -" opts[i] " */" +} + +print " N_OPTS" +print "};" +print "" +print "#endif /* OPTIONS_H */" +} diff --git a/support/cpp2/options_vc_in.c b/support/cpp2/options_vc_in.c deleted file mode 100644 index ab232e73..00000000 --- a/support/cpp2/options_vc_in.c +++ /dev/null @@ -1,221 +0,0 @@ -/* This file is auto-generated by opts.sh. */ - -#include -#include "options.h" -#include "opts.h" - -const char * const lang_names[] = -{ - "SDCPP", - 0 -}; - -const unsigned int cl_options_count = N_OPTS; - -const struct cl_option cl_options[] = -{ - { "--help", - N_("Display this information"), - N_OPTS, 5, CL_COMMON }, - { "--version", - N_("Display the compiler's version"), - N_OPTS, 8, CL_COMMON }, - { "-A", - N_("-A= Assert the to . Putting '-' before disables the to "), - N_OPTS, 1, CL_SDCPP | CL_JOINED | CL_SEPARATE }, - { "-C", - N_("Do not discard comments"), - N_OPTS, 1, CL_SDCPP }, - { "-CC", - N_("Do not discard comments in macro expansions"), - N_OPTS, 2, CL_SDCPP }, - { "-D", - N_("-D[=] Define a with as its value. If just is given, is taken to be 1"), - N_OPTS, 1, CL_SDCPP | CL_JOINED | CL_SEPARATE }, - { "-H", - N_("Print the name of header files as they are used"), - N_OPTS, 1, CL_SDCPP }, - { "-I", - N_("-I Add to the end of the main include path. -I- gives more include path control; see info documentation"), - N_OPTS, 1, CL_SDCPP | CL_JOINED | CL_SEPARATE }, - { "-M", - N_("Generate make dependencies"), - N_OPTS, 1, CL_SDCPP }, - { "-MD", - N_("Generate make dependencies and compile"), - N_OPTS, 2, CL_SDCPP | CL_SEPARATE }, - { "-MF", - N_("-MF Write dependency output to the given file"), - N_OPTS, 2, CL_SDCPP | CL_JOINED | CL_SEPARATE }, - { "-MG", - N_("Treat missing header files as generated files"), - N_OPTS, 2, CL_SDCPP }, - { "-MM", - N_("Like -M but ignore system header files"), - N_OPTS, 2, CL_SDCPP }, - { "-MMD", - N_("Like -MD but ignore system header files"), - N_OPTS, 3, CL_SDCPP | CL_SEPARATE }, - { "-MP", - N_("Generate phony targets for all headers"), - N_OPTS, 2, CL_SDCPP }, - { "-MQ", - N_("-MQ Add a MAKE-quoted target"), - N_OPTS, 2, CL_SDCPP | CL_JOINED | CL_SEPARATE }, - { "-MT", - N_("-MT Add an unquoted target"), - N_OPTS, 2, CL_SDCPP | CL_JOINED | CL_SEPARATE }, - { "-P", - N_("Do not generate #line directives"), - N_OPTS, 1, CL_SDCPP }, - { "-U", - N_("-U Undefine "), - N_OPTS, 1, CL_SDCPP | CL_JOINED | CL_SEPARATE }, - { "-Wall", - N_("Enable most warning messages"), - N_OPTS, 4, CL_SDCPP }, - { "-Wcomment", - N_("Warn about possibly nested block comments, and C++ comments spanning more than one physical line"), - N_OPTS, 8, CL_SDCPP }, - { "-Wcomments", - N_("Synonym for -Wcomment"), - N_OPTS, 9, CL_SDCPP }, - { "-Wdeprecated", - N_("Warn about deprecated compiler features"), - N_OPTS, 11, CL_SDCPP }, - { "-Wendif-labels", - N_("Warn about stray tokens after #elif and #endif"), - N_OPTS, 13, CL_SDCPP }, - { "-Werror", - N_("Treat all warnings as errors"), - N_OPTS, 6, CL_SDCPP }, - { "-Wimport", - N_("Deprecated. This switch has no effect."), - N_OPTS, 7, CL_SDCPP }, - { "-Wsystem-headers", - N_("Do not suppress warnings from system headers"), - N_OPTS, 15, CL_SDCPP }, - { "-Wtrigraphs", - N_("Warn if trigraphs are encountered that might affect the meaning of the program"), - N_OPTS, 10, CL_SDCPP }, - { "-Wundef", - N_("Warn if an undefined macro is used in an #if directive"), - N_OPTS, 6, CL_SDCPP }, - { "-Wunused-macros", - N_("Warn about macros defined in the main file that are not used"), - N_OPTS, 14, CL_SDCPP }, - { "-ansi", - N_("A synonym for -std=c89."), - N_OPTS, 4, CL_SDCPP }, - { "-d", - N_("-d Enable dumps from specific passes of the compiler"), - N_OPTS, 1, CL_SDCPP | CL_JOINED }, - { "-fdollars-in-identifiers", - N_("Permit '$' as an identifier character"), - N_OPTS, 23, CL_SDCPP }, - { "-fexec-charset=", - N_("-fexec-charset= Convert all strings and character constants to character set "), - N_OPTS, 14, CL_SDCPP | CL_JOINED | CL_REJECT_NEGATIVE }, - { "-finput-charset=", - N_("-finput-charset= Specify the default character set for source files."), - N_OPTS, 15, CL_SDCPP | CL_JOINED | CL_REJECT_NEGATIVE }, - { "-fpreprocessed", - N_("Treat the input file as already preprocessed"), - N_OPTS, 13, CL_SDCPP }, - { "-fshow-column", - 0, - N_OPTS, 12, CL_SDCPP }, - { "-fsigned-char", - N_("Make \"char\" signed by default"), - N_OPTS, 12, CL_SDCPP }, - { "-ftabstop=", - N_("-ftabstop= Distance between tab stops for column reporting"), - N_OPTS, 9, CL_SDCPP | CL_JOINED | CL_REJECT_NEGATIVE | CL_UINTEGER }, - { "-funsigned-char", - N_("Make \"char\" unsigned by default"), - N_OPTS, 14, CL_SDCPP }, - { "-fwide-exec-charset=", - N_("-fwide-exec-charset= Convert all wide strings and character constants to character set "), - N_OPTS, 19, CL_SDCPP | CL_JOINED | CL_REJECT_NEGATIVE }, - { "-fworking-directory", - N_("Generate a #line directive pointing at the current working directory"), - N_OPTS, 18, CL_SDCPP }, - { "-idirafter", - N_("-idirafter Add to the end of the system include path"), - N_OPTS, 9, CL_SDCPP | CL_JOINED | CL_SEPARATE }, - { "-imacros", - N_("-imacros Accept definition of macros in "), - N_OPTS, 7, CL_SDCPP | CL_JOINED | CL_SEPARATE }, - { "-include", - N_("-include Include the contents of before other files"), - N_OPTS, 7, CL_SDCPP | CL_JOINED | CL_SEPARATE }, - { "-iprefix", - N_("-iprefix Specify as a prefix for next two options"), - N_OPTS, 7, CL_SDCPP | CL_JOINED | CL_SEPARATE }, - { "-isysroot", - N_("-isysroot Set to be the system root directory"), - N_OPTS, 8, CL_SDCPP | CL_JOINED | CL_SEPARATE }, - { "-isystem", - N_("-isystem Add to the start of the system include path"), - N_OPTS, 7, CL_SDCPP | CL_JOINED | CL_SEPARATE }, - { "-iwithprefix", - N_("-iwithprefix Add to the end of the system include path"), - N_OPTS, 11, CL_SDCPP | CL_JOINED | CL_SEPARATE }, - { "-iwithprefixbefore", - N_("-iwithprefixbefore Add to the end of the main include path"), - OPT_iwithprefix, 17, CL_SDCPP | CL_JOINED | CL_SEPARATE }, - { "-lang-asm", - 0, - N_OPTS, 8, CL_UNDOCUMENTED }, - { "-lang-objc", - 0, - N_OPTS, 9, CL_SDCPP | CL_UNDOCUMENTED }, - { "-nostdinc", - N_("Do not search standard system include directories (those specified with -isystem will still be used)"), - N_OPTS, 8, CL_SDCPP }, - { "-o", - N_("-o Place output into "), - N_OPTS, 1, CL_SDCPP | CL_JOINED | CL_SEPARATE }, - { "-obj-ext=", - N_("-obj-ext= Define object file extension, used for generation of make dependencies"), - OPT_o, 8, CL_SDCPP | CL_JOINED }, - { "-pedantic", - N_("Issue warnings needed for strict compliance to the standard"), - N_OPTS, 8, CL_SDCPP }, - { "-pedantic-errors", - N_("Like -pedantic but issue them as errors"), - N_OPTS, 15, CL_SDCPP }, - { "-pedantic-parse-number", - N_("Pedantic parse number"), - N_OPTS, 21, CL_SDCPP }, - { "-remap", - N_("Remap file names when including files"), - N_OPTS, 5, CL_SDCPP }, - { "-std=c89", - N_("Conform to the ISO 1990 C standard"), - N_OPTS, 7, CL_SDCPP }, - { "-std=c99", - N_("Conform to the ISO 1999 C standard"), - N_OPTS, 7, CL_SDCPP }, - { "-std=iso9899:1990", - N_("Conform to the ISO 1990 C standard"), - N_OPTS, 16, 0 }, - { "-std=iso9899:199409", - N_("Conform to the ISO 1990 C standard as amended in 1994"), - N_OPTS, 18, CL_SDCPP }, - { "-std=iso9899:1999", - N_("Conform to the ISO 1999 C standard"), - N_OPTS, 16, 0 }, - { "-traditional-cpp", - N_("Enable traditional preprocessing"), - N_OPTS, 15, CL_SDCPP }, - { "-trigraphs", - N_("-trigraphs Support ISO C trigraphs"), - N_OPTS, 9, CL_SDCPP }, - { "-v", - N_("Enable verbose output"), - N_OPTS, 1, CL_SDCPP }, - { "-w", - N_("Suppress warnings"), - N_OPTS, 1, CL_SDCPP } -}; diff --git a/support/cpp2/options_vc_in.h b/support/cpp2/options_vc_in.h deleted file mode 100644 index 142b24cd..00000000 --- a/support/cpp2/options_vc_in.h +++ /dev/null @@ -1,76 +0,0 @@ -/* This file is auto-generated by opts.sh. */ - -#define CL_SDCPP (1 << 0) - -enum opt_code -{ - OPT__help, /* --help */ - OPT__version, /* --version */ - OPT_A, /* -A */ - OPT_C, /* -C */ - OPT_CC, /* -CC */ - OPT_D, /* -D */ - OPT_H, /* -H */ - OPT_I, /* -I */ - OPT_M, /* -M */ - OPT_MD, /* -MD */ - OPT_MF, /* -MF */ - OPT_MG, /* -MG */ - OPT_MM, /* -MM */ - OPT_MMD, /* -MMD */ - OPT_MP, /* -MP */ - OPT_MQ, /* -MQ */ - OPT_MT, /* -MT */ - OPT_P, /* -P */ - OPT_U, /* -U */ - OPT_Wall, /* -Wall */ - OPT_Wcomment, /* -Wcomment */ - OPT_Wcomments, /* -Wcomments */ - OPT_Wdeprecated, /* -Wdeprecated */ - OPT_Wendif_labels, /* -Wendif-labels */ - OPT_Werror, /* -Werror */ - OPT_Wimport, /* -Wimport */ - OPT_Wsystem_headers, /* -Wsystem-headers */ - OPT_Wtrigraphs, /* -Wtrigraphs */ - OPT_Wundef, /* -Wundef */ - OPT_Wunused_macros, /* -Wunused-macros */ - OPT_ansi, /* -ansi */ - OPT_d, /* -d */ - OPT_fdollars_in_identifiers, /* -fdollars-in-identifiers */ - OPT_fexec_charset_, /* -fexec-charset= */ - OPT_finput_charset_, /* -finput-charset= */ - OPT_fpreprocessed, /* -fpreprocessed */ - OPT_fshow_column, /* -fshow-column */ - OPT_fsigned_char, /* -fsigned-char */ - OPT_ftabstop_, /* -ftabstop= */ - OPT_funsigned_char, /* -funsigned-char */ - OPT_fwide_exec_charset_, /* -fwide-exec-charset= */ - OPT_fworking_directory, /* -fworking-directory */ - OPT_idirafter, /* -idirafter */ - OPT_imacros, /* -imacros */ - OPT_include, /* -include */ - OPT_iprefix, /* -iprefix */ - OPT_isysroot, /* -isysroot */ - OPT_isystem, /* -isystem */ - OPT_iwithprefix, /* -iwithprefix */ - OPT_iwithprefixbefore, /* -iwithprefixbefore */ - OPT_lang_asm, /* -lang-asm */ - OPT_lang_objc, /* -lang-objc */ - OPT_nostdinc, /* -nostdinc */ - OPT_o, /* -o */ - OPT_obj_ext_, /* -obj-ext= */ - OPT_pedantic, /* -pedantic */ - OPT_pedantic_errors, /* -pedantic-errors */ - OPT_pedantic_parse_number, /* -pedantic-parse-number */ - OPT_remap, /* -remap */ - OPT_std_c89, /* -std=c89 */ - OPT_std_c99, /* -std=c99 */ - OPT_std_iso9899_1990, /* -std=iso9899:1990 */ - OPT_std_iso9899_199409, /* -std=iso9899:199409 */ - OPT_std_iso9899_1999, /* -std=iso9899:1999 */ - OPT_traditional_cpp, /* -traditional-cpp */ - OPT_trigraphs, /* -trigraphs */ - OPT_v, /* -v */ - OPT_w, /* -w */ - N_OPTS -}; diff --git a/support/cpp2/opts.c b/support/cpp2/opts.c index 5323a32a..20e8cb95 100644 --- a/support/cpp2/opts.c +++ b/support/cpp2/opts.c @@ -29,9 +29,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA /* True if we should exit after parsing options. */ bool exit_after_options; -/* Don't print warning messages. -w. */ -bool inhibit_warnings; - /* Treat warnings as errors. -Werror. */ bool warnings_are_errors; @@ -119,14 +116,14 @@ find_opt (const char *input, int lang_mask) { const struct cl_option *opt = &cl_options[mn]; - /* Is this switch a prefix of the input? */ - if (!strncmp (input, opt->opt_text + 1, opt->opt_len)) + /* Is the input either an exact match or a prefix that takes a + joined argument? */ + if (!strncmp (input, opt->opt_text + 1, opt->opt_len) + && (input[opt->opt_len] == '\0' || (opt->flags & CL_JOINED))) { - /* If language is OK, and the match is exact or the switch - takes a joined argument, return it. */ - if ((opt->flags & lang_mask) - && (input[opt->opt_len] == '\0' || (opt->flags & CL_JOINED))) - return mn; + /* If language is OK, return it. */ + if (opt->flags & lang_mask) + /* If we haven't remembered a prior match, remember this one. Any prior match is necessarily better. */ @@ -199,7 +196,7 @@ complain_wrong_lang (const char *text, const struct cl_option *option, bad_lang = write_langs (lang_mask); /* Eventually this should become a hard error IMO. */ - warning ("command line option \"%s\" is valid for %s but not for %s", + warning (0, "command line option \"%s\" is valid for %s but not for %s", text, ok_langs, bad_lang); free (ok_langs); @@ -220,10 +217,12 @@ handle_option (const char **argv, unsigned int lang_mask) opt = argv[0]; - /* Drop the "no-" from negative switches. */ - if ((opt[1] == 'W' || opt[1] == 'f') + opt_index = find_opt (opt + 1, lang_mask | CL_COMMON | CL_TARGET); + if (opt_index == cl_options_count + && (opt[1] == 'W' || opt[1] == 'f' || opt[1] == 'm') && opt[2] == 'n' && opt[3] == 'o' && opt[4] == '-') { + /* Drop the "no-" from negative switches. */ size_t len = strlen (opt) - 3; dup = xmalloc (len + 1); @@ -232,9 +231,9 @@ handle_option (const char **argv, unsigned int lang_mask) memcpy (dup + 2, opt + 5, len - 2 + 1); opt = dup; value = 0; + opt_index = find_opt (opt + 1, lang_mask | CL_COMMON | CL_TARGET); } - opt_index = find_opt (opt + 1, lang_mask | CL_COMMON); if (opt_index == cl_options_count) goto done; @@ -248,6 +247,14 @@ handle_option (const char **argv, unsigned int lang_mask) /* We've recognized this switch. */ result = 1; + /* Check to see if the option is disabled for this configuration. */ + if (option->flags & CL_DISABLED) + { + error ("command line option %qs" + " is not supported by this configuration", opt); + goto done; + } + /* Sort out any argument the switch takes. */ if (option->flags & CL_JOINED) { @@ -278,7 +285,7 @@ handle_option (const char **argv, unsigned int lang_mask) /* Now we've swallowed any potential argument, complain if this is a switch for a different front end. */ - if (!(option->flags & (lang_mask | CL_COMMON))) + if (!(option->flags & (lang_mask | CL_COMMON | CL_TARGET))) { complain_wrong_lang (argv[0], option, lang_mask); goto done; @@ -286,7 +293,7 @@ handle_option (const char **argv, unsigned int lang_mask) if (arg == NULL && (option->flags & (CL_JOINED | CL_SEPARATE))) { - if (!(*lang_hooks.missing_argument) (opt, opt_index)) + if (!lang_hooks.missing_argument (opt, opt_index)) error ("missing argument to \"%s\"", opt); goto done; } @@ -303,6 +310,34 @@ handle_option (const char **argv, unsigned int lang_mask) } } + if (option->flag_var) + switch (option->var_type) + { + case CLVC_BOOLEAN: + *(int *) option->flag_var = value; + break; + + case CLVC_EQUAL: + *(int *) option->flag_var = (value + ? option->var_value + : !option->var_value); + break; + + case CLVC_BIT_CLEAR: + case CLVC_BIT_SET: + if ((value != 0) == (option->var_type == CLVC_BIT_SET)) + *(int *) option->flag_var |= option->var_value; + else + *(int *) option->flag_var &= ~option->var_value; + ////if (option->flag_var == &target_flags) + //// target_flags_explicit |= option->var_value; + break; + + case CLVC_STRING: + *(const char **) option->flag_var = arg; + break; + } + if (option->flags & lang_mask) if ((*lang_hooks.handle_option) (opt_index, arg, value) == 0) result = 0; @@ -311,12 +346,25 @@ handle_option (const char **argv, unsigned int lang_mask) if (common_handle_option (opt_index, arg, value) == 0) result = 0; + ////if (result && (option->flags & CL_TARGET)) + //// if (!targetm.handle_option (opt_index, arg, value)) + //// result = 0; + done: if (dup) free (dup); return result; } +/* Handle FILENAME from the command line. */ +void +add_input_filename (const char *filename) +{ + num_in_fnames++; + in_fnames = xrealloc (in_fnames, num_in_fnames * sizeof (in_fnames[0])); + in_fnames[num_in_fnames - 1] = filename; +} + /* Decode and handle the vector of command line options. LANG_MASK contains has a single bit set representing the current language. */ @@ -349,15 +397,6 @@ handle_options (unsigned int argc, const char **argv, unsigned int lang_mask) } } -/* Handle FILENAME from the command line. */ -void -add_input_filename (const char *filename) -{ - num_in_fnames++; - in_fnames = xrealloc (in_fnames, num_in_fnames * sizeof (in_fnames[0])); - in_fnames[num_in_fnames - 1] = filename; -} - /* Parse command line options and set default flag values. Do minimal options processing. */ void @@ -366,7 +405,7 @@ decode_options (unsigned int argc, const char **argv) unsigned int lang_mask; /* Perform language-specific options initialization. */ - lang_mask = (*lang_hooks.init_options) (argc, argv); + lang_mask = lang_hooks.init_options (argc, argv); lang_hooks.initialize_diagnostics (global_dc); @@ -377,7 +416,10 @@ decode_options (unsigned int argc, const char **argv) } /* Handle target- and language-independent options. Return zero to - generate an "unknown option" message. */ + generate an "unknown option" message. Only options that need + extra handling need to be listed here; if you simply want + VALUE assigned to a variable, it happens automatically. */ + static int common_handle_option (size_t scode, const char *arg, int value ATTRIBUTE_UNUSED) @@ -459,7 +501,7 @@ print_filtered_help (unsigned int flag) const char *help, *opt, *tab; static char *printed; - if (flag == CL_COMMON) + if (flag == CL_COMMON || flag == CL_TARGET) { filter = flag; if (!printed) @@ -606,3 +648,65 @@ wrap_help (const char *help, const char *item, unsigned int item_width) } while (remaining); } + +/* Return 1 if OPTION is enabled, 0 if it is disabled, or -1 if it isn't + a simple on-off switch. */ + +int +option_enabled (int opt_idx) +{ + const struct cl_option *option = &(cl_options[opt_idx]); + if (option->flag_var) + switch (option->var_type) + { + case CLVC_BOOLEAN: + return *(int *) option->flag_var != 0; + + case CLVC_EQUAL: + return *(int *) option->flag_var == option->var_value; + + case CLVC_BIT_CLEAR: + return (*(int *) option->flag_var & option->var_value) == 0; + + case CLVC_BIT_SET: + return (*(int *) option->flag_var & option->var_value) != 0; + + case CLVC_STRING: + break; + } + return -1; +} + +/* Fill STATE with the current state of option OPTION. Return true if + there is some state to store. */ + +bool +get_option_state (int option, struct cl_option_state *state) +{ + if (cl_options[option].flag_var == 0) + return false; + + switch (cl_options[option].var_type) + { + case CLVC_BOOLEAN: + case CLVC_EQUAL: + state->data = cl_options[option].flag_var; + state->size = sizeof (int); + break; + + case CLVC_BIT_CLEAR: + case CLVC_BIT_SET: + state->ch = option_enabled (option); + state->data = &state->ch; + state->size = 1; + break; + + case CLVC_STRING: + state->data = *(const char **) cl_options[option].flag_var; + if (state->data == 0) + state->data = ""; + state->size = strlen (state->data) + 1; + break; + } + return true; +} diff --git a/support/cpp2/opts.h b/support/cpp2/opts.h index eb7c8681..2c2340c3 100644 --- a/support/cpp2/opts.h +++ b/support/cpp2/opts.h @@ -1,5 +1,5 @@ /* Command line option handling. - Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of GCC. @@ -15,14 +15,30 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ #ifndef GCC_OPTS_H #define GCC_OPTS_H -extern void decode_options (unsigned int argc, const char **argv); -extern void add_input_filename (const char *filename); +/* Specifies how a switch's VAR_VALUE relates to its FLAG_VAR. */ +enum cl_var_type { + /* The switch is enabled when FLAG_VAR is nonzero. */ + CLVC_BOOLEAN, + + /* The switch is enabled when FLAG_VAR == VAR_VALUE. */ + CLVC_EQUAL, + + /* The switch is enabled when VAR_VALUE is not set in FLAG_VAR. */ + CLVC_BIT_CLEAR, + + /* The switch is enabled when VAR_VALUE is set in FLAG_VAR. */ + CLVC_BIT_SET, + + /* The switch takes a string argument and FLAG_VAR points to that + argument. */ + CLVC_STRING +}; struct cl_option { @@ -31,12 +47,26 @@ struct cl_option unsigned short back_chain; unsigned char opt_len; unsigned int flags; + void *flag_var; + enum cl_var_type var_type; + int var_value; +}; + +/* Records that the state of an option consists of SIZE bytes starting + at DATA. DATA might point to CH in some cases. */ +struct cl_option_state { + const void *data; + size_t size; + char ch; }; extern const struct cl_option cl_options[]; extern const unsigned int cl_options_count; extern const char *const lang_names[]; +#define CL_DISABLED (1 << 21) /* Disabled in this configuration. */ +#define CL_TARGET (1 << 22) /* Target-specific option. */ +#define CL_REPORT (1 << 23) /* Report argument with -fverbose-asm */ #define CL_JOINED (1 << 24) /* If takes joined argument. */ #define CL_SEPARATE (1 << 25) /* If takes a separate argument. */ #define CL_REJECT_NEGATIVE (1 << 26) /* Reject no- form. */ @@ -53,4 +83,8 @@ extern const char **in_fnames; extern unsigned num_in_fnames; +extern void decode_options (unsigned int argc, const char **argv); +extern int option_enabled (int opt_idx); +extern bool get_option_state (int, struct cl_option_state *); + #endif diff --git a/support/cpp2/opts.sh b/support/cpp2/opts.sh deleted file mode 100755 index 871c8554..00000000 --- a/support/cpp2/opts.sh +++ /dev/null @@ -1,175 +0,0 @@ -#!/bin/sh -# -# Copyright (C) 2003 Free Software Foundation, Inc. -# Contributed by Neil Booth, May 2003. -# -# This program 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 2, or (at your option) any -# later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# Usage: opts.sh moveifchange srcdir outfile.c outfile.h file1.opt [ ...] - -# Always operate in the C locale. -LANG=C -LANGUAGE=C -LC_ALL=C -export LANG LANGUAGE LC_ALL - -# Set AWK if environment has not already set it. -AWK=${AWK-awk} - -SORT=sort # Could be /bin/sort or /usr/bin/sort - -MOVEIFCHANGE=$1; shift -C_FILE=$1; shift -H_FILE=$1; shift -TMP_C_FILE=tmp-${C_FILE} -TMP_H_FILE=tmp-${H_FILE} - -${AWK} ' - # Ignore comments and blank lines - /^[ \t]*(;|$)/ { next } - # Note that RS="" falls foul of gawk 3.1.2 bugs - /^[^ \t]/ { record = $0 - do { getline tmp; - if (!(tmp ~ "^[ \t]*(;|$)")) - record = record "\034" tmp - } while (tmp != "") - print record - } -' "$@" | ${SORT} | ${AWK} ' - function switch_flags (flags, result) - { - flags = " " flags " " - result = "0" - for (j = 0; j < n_langs; j++) { - regex = " " langs[j] " " - gsub ( "\\+", "\\+", regex ) - if (flags ~ regex) - result = result " | " macros[j] - } - if (flags ~ " Common ") result = result " | CL_COMMON" - if (flags ~ " Joined ") result = result " | CL_JOINED" - if (flags ~ " JoinedOrMissing ") \ - result = result " | CL_JOINED | CL_MISSING_OK" - if (flags ~ " Separate ") result = result " | CL_SEPARATE" - if (flags ~ " RejectNegative ") result = result " | CL_REJECT_NEGATIVE" - if (flags ~ " UInteger ") result = result " | CL_UINTEGER" - if (flags ~ " Undocumented ") result = result " | CL_UNDOCUMENTED" - sub( "^0 \\| ", "", result ) - return result - } - - BEGIN { - FS = "\034" - n_opts = 0 - n_langs = 0 - } - -# Collect the text and flags of each option into an array - { - if ($1 == "Language") { - langs[n_langs] = $2 - n_langs++; - } else { - opts[n_opts] = $1 - flags[n_opts] = $2 - help[n_opts] = $3 - n_opts++; - } - } - -# Dump out an enumeration into a .h file, and an array of options into a -# C file. Combine the flags of duplicate options. - END { - c_file = "'${TMP_C_FILE}'" - h_file = "'${TMP_H_FILE}'" - realh_file = "'${H_FILE}'" - comma = "," - - print "/* This file is auto-generated by opts.sh. */\n" > c_file - print "#include " >> c_file - print "#include \"" realh_file "\"" >> c_file - print "#include \"opts.h\"\n" >> c_file - print "const char * const lang_names[] =\n{" >> c_file - - print "/* This file is auto-generated by opts.sh. */\n" > h_file - for (i = 0; i < n_langs; i++) { - macros[i] = "CL_" langs[i] - gsub( "[^A-Za-z0-9_]", "X", macros[i] ) - s = substr(" ", length (macros[i])) - print "#define " macros[i] s " (1 << " i ")" >> h_file - print " \"" langs[i] "\"," >> c_file - } - - print " 0\n};\n" >> c_file - print "const unsigned int cl_options_count = N_OPTS;\n" >> c_file - print "const struct cl_option cl_options[] =\n{" >> c_file - - print "\nenum opt_code\n{" >> h_file - - for (i = 0; i < n_opts; i++) - back_chain[i] = "N_OPTS"; - - for (i = 0; i < n_opts; i++) { - # Combine the flags of identical switches. Switches - # appear many times if they are handled by many front - # ends, for example. - while( i + 1 != n_opts && opts[i] == opts[i + 1] ) { - flags[i + 1] = flags[i] " " flags[i + 1]; - i++; - } - - len = length (opts[i]); - enum = "OPT_" opts[i] - if (opts[i] == "finline-limit=") - enum = enum "eq" - gsub ("[^A-Za-z0-9]", "_", enum) - - # If this switch takes joined arguments, back-chain all - # subsequent switches to it for which it is a prefix. If - # a later switch S is a longer prefix of a switch T, T - # will be back-chained to S in a later iteration of this - # for() loop, which is what we want. - if (flags[i] ~ "Joined") { - for (j = i + 1; j < n_opts; j++) { - if (substr (opts[j], 1, len) != opts[i]) - break; - back_chain[j] = enum; - } - } - - s = substr(" ", length (opts[i])) - if (i + 1 == n_opts) - comma = "" - - if (help[i] == "") - hlp = "0" - else - hlp = "N_(\"" help[i] "\")"; - - printf(" %s,%s/* -%s */\n", enum, s, opts[i]) >> h_file - printf(" { \"-%s\",\n %s,\n %s, %u, %s }%s\n", - opts[i], hlp, back_chain[i], len, - switch_flags(flags[i]), comma) >> c_file - } - - print " N_OPTS\n};" >> h_file - print "};" >> c_file - } -' - -# Copy the newly generated files back to the correct names only if different. -# This is to prevent a cascade of file rebuilds when not necessary. -${MOVEIFCHANGE} ${TMP_H_FILE} ${H_FILE} -${MOVEIFCHANGE} ${TMP_C_FILE} ${C_FILE} diff --git a/support/cpp2/output.h b/support/cpp2/output.h index 05a37437..3cb091fc 100644 --- a/support/cpp2/output.h +++ b/support/cpp2/output.h @@ -1,7 +1,7 @@ /* Declarations for insn-output.c. These functions are defined in recog.c, final.c, and varasm.c. Copyright (C) 1987, 1991, 1994, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of GCC. @@ -17,8 +17,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ #ifndef GCC_OUTPUT_H #define GCC_OUTPUT_H @@ -49,6 +49,10 @@ extern void init_insn_lengths (void); get its actual length. Otherwise, get its maximum length. */ extern int get_attr_length (rtx); +/* Obtain the current length of an insn. If branch shortening has been done, + get its actual length. Otherwise, get its minimum length. */ +extern int get_attr_min_length (rtx); + /* Make a pass over all insns and compute their actual lengths by shortening any branches of variable length if possible. */ extern void shorten_branches (rtx); @@ -66,12 +70,12 @@ extern void final_start_function (rtx, FILE *, int); extern void final_end_function (void); /* Output assembler code for some insns: all or part of a function. */ -extern void final (rtx, FILE *, int, int); +extern void final (rtx, FILE *, int); /* The final scan for one insn, INSN. Args are same as in `final', except that INSN is the insn being scanned. Value returned is the next insn to be scanned. */ -extern rtx final_scan_insn (rtx, FILE *, int, int, int, int *); +extern rtx final_scan_insn (rtx, FILE *, int, int, int *); /* Replace a SUBREG with a REG or a MEM, based on the thing it is a subreg of. */ @@ -144,24 +148,17 @@ extern void leaf_renumber_regs_insn (rtx); /* Locate the proper template for the given insn-code. */ extern const char *get_insn_template (int, rtx); -/* Add function NAME to the weak symbols list. VALUE is a weak alias - associated with NAME. */ -extern int add_weak (tree, const char *, const char *); - /* Functions in flow.c */ -extern void allocate_for_life_analysis (void); -extern int regno_uninitialized (unsigned int); extern int regno_clobbered_at_setjmp (int); -extern void find_basic_blocks (rtx, int, FILE *); -extern bool cleanup_cfg (int); -extern bool delete_unreachable_blocks (void); -extern void check_function_return_warnings (void); /* Functions in varasm.c. */ /* Tell assembler to switch to text section. */ extern void text_section (void); +/* Tell assembler to switch to unlikely-to-be-executed text section. */ +extern void unlikely_text_section (void); + /* Tell assembler to switch to data section. */ extern void data_section (void); @@ -172,6 +169,9 @@ extern void readonly_data_section (void); /* Determine if we're in the text section. */ extern int in_text_section (void); +/* Determine if we're in the unlikely-to-be-executed text section. */ +extern int in_unlikely_text_section (void); + #ifdef CTORS_SECTION_ASM_OP extern void ctors_section (void); #endif @@ -213,6 +213,9 @@ extern void named_section (tree, const char *, int); /* Tell assembler to switch to the section for function DECL. */ extern void function_section (tree); +/* Tell assembler to switch to the most recently used text section. */ +extern void current_function_section (tree); + /* Tell assembler to switch to the section for string merging. */ extern void mergeable_string_section (tree, unsigned HOST_WIDE_INT, unsigned int); @@ -281,7 +284,6 @@ extern void assemble_zeros (unsigned HOST_WIDE_INT); /* Assemble an alignment pseudo op for an ALIGN-bit boundary. */ extern void assemble_align (int); -extern void assemble_eh_align (int); /* Assemble a string constant with the specified C string as contents. */ extern void assemble_string (const char *, int); @@ -291,13 +293,17 @@ extern void assemble_external_libcall (rtx); /* Assemble a label named NAME. */ extern void assemble_label (const char *); -extern void assemble_eh_label (const char *); -/* Output to FILE a reference to the assembler name of a C-level name NAME. - If NAME starts with a *, the rest of NAME is output verbatim. - Otherwise NAME is transformed in an implementation-defined way - (usually by the addition of an underscore). - Many macros in the tm file are defined to call this function. */ +/* Output to FILE (an assembly file) a reference to NAME. If NAME + starts with a *, the rest of NAME is output verbatim. Otherwise + NAME is transformed in a target-specific way (usually by the + addition of an underscore). */ +extern void assemble_name_raw (FILE *, const char *); + +/* Like assemble_name_raw, but should be used when NAME might refer to + an entity that is also represented as a tree (like a function or + variable). If NAME does refer to such an entity, that entity will + be marked as referenced. */ extern void assemble_name (FILE *, const char *); /* Return the assembler directive for creating a given kind of integer @@ -318,8 +324,8 @@ extern bool default_assemble_integer (rtx, unsigned int, int); /* Assemble the integer constant X into an object of SIZE bytes. ALIGN is the alignment of the integer in bits. Return 1 if we were able to output - the constant, otherwise 0. If FORCE is nonzero, abort if we can't output - the constant. */ + the constant, otherwise 0. If FORCE is nonzero the constant must + be outputable. */ extern bool assemble_integer (rtx, unsigned, unsigned, int); /* An interface to assemble_integer for the common case in which a value is @@ -398,11 +404,6 @@ extern const char *weak_global_object_name; extern int current_function_is_leaf; -/* Nonzero if function being compiled doesn't contain any instructions - that can throw an exception. This is set prior to final. */ - -extern int current_function_nothrow; - /* Nonzero if function being compiled doesn't modify the stack pointer (ignoring the prologue and epilogue). This is only valid after life_analysis has run. */ @@ -418,7 +419,7 @@ extern int current_function_uses_only_leaf_regs; /* Default file in which to dump debug output. */ #ifdef BUFSIZ -extern FILE *rtl_dump_file; +extern FILE *dump_file; #endif /* Nonnull if the insn currently being emitted was a COND_EXEC pattern. */ @@ -428,10 +429,38 @@ extern rtx current_insn_predicate; extern rtx current_output_insn; /* Nonzero while outputting an `asm' with operands. - This means that inconsistencies are the user's fault, so don't abort. + This means that inconsistencies are the user's fault, so don't die. The precise value is the insn being output, to pass to error_for_asm. */ extern rtx this_is_asm_operands; +/* Carry information from ASM_DECLARE_OBJECT_NAME + to ASM_FINISH_DECLARE_OBJECT. */ +extern int size_directive_output; +extern tree last_assemble_variable_decl; + +enum in_section { no_section, in_text, in_unlikely_executed_text, in_data, + in_named +#ifdef BSS_SECTION_ASM_OP + , in_bss +#endif +#ifdef CTORS_SECTION_ASM_OP + , in_ctors +#endif +#ifdef DTORS_SECTION_ASM_OP + , in_dtors +#endif +#ifdef READONLY_DATA_SECTION_ASM_OP + , in_readonly_data +#endif +#ifdef EXTRA_SECTIONS + , EXTRA_SECTIONS +#endif +}; + +extern const char *last_text_section_name; +extern enum in_section last_text_section; +extern bool first_function_block_is_cold; + /* Decide whether DECL needs to be in a writable section. RELOC is the same as for SELECT_SECTION. */ extern bool decl_readonly_section (tree, int); @@ -475,17 +504,57 @@ extern void no_asm_to_stream (FILE *); #define SECTION_NOTYPE 0x80000 /* don't output @progbits */ #define SECTION_MACH_DEP 0x100000 /* subsequent bits reserved for target */ -extern unsigned int get_named_section_flags (const char *); +/* A helper function for default_elf_select_section and + default_elf_unique_section. Categorizes the DECL. */ + +enum section_category +{ + SECCAT_TEXT, + + SECCAT_RODATA, + SECCAT_RODATA_MERGE_STR, + SECCAT_RODATA_MERGE_STR_INIT, + SECCAT_RODATA_MERGE_CONST, + SECCAT_SRODATA, + + SECCAT_DATA, + + /* To optimize loading of shared programs, define following subsections + of data section: + _REL Contains data that has relocations, so they get grouped + together and dynamic linker will visit fewer pages in memory. + _RO Contains data that is otherwise read-only. This is useful + with prelinking as most relocations won't be dynamically + linked and thus stay read only. + _LOCAL Marks data containing relocations only to local objects. + These relocations will get fully resolved by prelinking. */ + SECCAT_DATA_REL, + SECCAT_DATA_REL_LOCAL, + SECCAT_DATA_REL_RO, + SECCAT_DATA_REL_RO_LOCAL, + + SECCAT_SDATA, + SECCAT_TDATA, + + SECCAT_BSS, + SECCAT_SBSS, + SECCAT_TBSS +}; + + extern bool set_named_section_flags (const char *, unsigned int); -extern void named_section_flags (const char *, unsigned int); +#define named_section_flags(NAME, FLAGS) \ + named_section_real((NAME), (FLAGS), /*decl=*/NULL_TREE) +extern void named_section_real (const char *, unsigned int, tree); extern bool named_section_first_declaration (const char *); extern unsigned int default_section_type_flags (tree, const char *, int); extern unsigned int default_section_type_flags_1 (tree, const char *, int, int); -extern void default_no_named_section (const char *, unsigned int); -extern void default_elf_asm_named_section (const char *, unsigned int); -extern void default_coff_asm_named_section (const char *, unsigned int); -extern void default_pe_asm_named_section (const char *, unsigned int); +extern void default_no_named_section (const char *, unsigned int, tree); +extern void default_elf_asm_named_section (const char *, unsigned int, tree); +extern enum section_category categorize_decl_for_section (tree, int, int); +extern void default_coff_asm_named_section (const char *, unsigned int, tree); +extern void default_pe_asm_named_section (const char *, unsigned int, tree); extern void default_stabs_asm_out_destructor (rtx, int); extern void default_named_section_asm_out_destructor (rtx, int); @@ -500,6 +569,8 @@ extern void default_elf_select_section_1 (tree, int, unsigned HOST_WIDE_INT, int); extern void default_unique_section (tree, int); extern void default_unique_section_1 (tree, int, int); +extern void default_function_rodata_section (tree); +extern void default_no_function_rodata_section (tree); extern void default_select_rtx_section (enum machine_mode, rtx, unsigned HOST_WIDE_INT); extern void default_elf_select_rtx_section (enum machine_mode, rtx, @@ -509,6 +580,7 @@ extern const char *default_strip_name_encoding (const char *); extern bool default_binds_local_p (tree); extern bool default_binds_local_p_1 (tree, int); extern void default_globalize_label (FILE *, const char *); +extern void default_emit_unwind_label (FILE *, tree, int, int); extern void default_internal_label (FILE *, const char *, unsigned long); extern void default_file_start (void); extern void file_end_indicate_exec_stack (void); @@ -516,4 +588,24 @@ extern bool default_valid_pointer_mode (enum machine_mode); extern int default_address_cost (rtx); +/* dbxout helper functions */ +#if defined DBX_DEBUGGING_INFO || defined XCOFF_DEBUGGING_INFO + +extern void dbxout_int (int); +extern void dbxout_stabd (int, int); +extern void dbxout_begin_stabn (int); +extern void dbxout_begin_stabn_sline (int); +extern void dbxout_begin_empty_stabs (int); +extern void dbxout_begin_simple_stabs (const char *, int); +extern void dbxout_begin_simple_stabs_desc (const char *, int, int); + +extern void dbxout_stab_value_zero (void); +extern void dbxout_stab_value_label (const char *); +extern void dbxout_stab_value_label_diff (const char *, const char *); +extern void dbxout_stab_value_internal_label (const char *, int *); +extern void dbxout_stab_value_internal_label_diff (const char *, int *, + const char *); + +#endif + #endif /* ! GCC_OUTPUT_H */ diff --git a/support/cpp2/prefix.c b/support/cpp2/prefix.c index 6204ee92..a559bcd3 100644 --- a/support/cpp2/prefix.c +++ b/support/cpp2/prefix.c @@ -1,5 +1,5 @@ /* Utility to update paths from internal to external forms. - Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003 + Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of GCC. @@ -16,8 +16,8 @@ Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ /* This file contains routines to update a path, both to canonicalize the directory format and to handle any prefix translation. @@ -122,6 +122,10 @@ save_string (const char *s, int len) #if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY) +#ifndef WIN32_REGISTRY_KEY +# define WIN32_REGISTRY_KEY BASEVER +#endif + /* Look up "key" in the registry, as above. */ static char * @@ -155,11 +159,11 @@ lookup_key (char *key) size = 32; dst = xmalloc (size); - res = RegQueryValueExA (reg_key, key, 0, &type, dst, &size); + res = RegQueryValueExA (reg_key, key, 0, &type, (LPBYTE) dst, &size); if (res == ERROR_MORE_DATA && type == REG_SZ) { dst = xrealloc (dst, size); - res = RegQueryValueExA (reg_key, key, 0, &type, dst, &size); + res = RegQueryValueExA (reg_key, key, 0, &type, (LPBYTE) dst, &size); } if (type != REG_SZ || res != ERROR_SUCCESS) @@ -236,16 +240,20 @@ tr (char *string, int c1, int c2) while (*string++); } -/* Update PATH using KEY if PATH starts with PREFIX. The returned - string is always malloc-ed, and the caller is responsible for - freeing it. */ +/* Update PATH using KEY if PATH starts with PREFIX as a directory. + The returned string is always malloc-ed, and the caller is + responsible for freeing it. */ char * update_path (const char *path, const char *key) { char *result, *p; + const int len = strlen (std_prefix); - if (! strncmp (path, std_prefix, strlen (std_prefix)) && key != 0) + if (! strncmp (path, std_prefix, len) + && (IS_DIR_SEPARATOR(path[len]) + || path[len] == '\0') + && key != 0) { bool free_key = false; @@ -255,7 +263,7 @@ update_path (const char *path, const char *key) free_key = true; } - result = concat (key, &path[strlen (std_prefix)], NULL); + result = concat (key, &path[len], NULL); if (free_key) free ((char *) key); result = translate_name (result); diff --git a/support/cpp2/prefix.h b/support/cpp2/prefix.h index 25f21159..e6e653ad 100644 --- a/support/cpp2/prefix.h +++ b/support/cpp2/prefix.h @@ -15,8 +15,8 @@ Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ #ifndef GCC_PREFIX_H diff --git a/support/cpp2/pretty-print.c b/support/cpp2/pretty-print.c index 9ef12f23..ca8d7a91 100644 --- a/support/cpp2/pretty-print.c +++ b/support/cpp2/pretty-print.c @@ -1,5 +1,5 @@ /* Various declarations for language-independent pretty-print subroutines. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. Contributed by Gabriel Dos Reis This file is part of GCC. @@ -16,13 +16,14 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ #include "config.h" #undef FLOAT /* This is for hpux. They should change hpux. */ #undef FFS /* Some systems define this in param.h. */ #include "system.h" +#include "intl.h" #include "pretty-print.h" #define obstack_chunk_alloc xmalloc @@ -30,7 +31,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA /* A pointer to the formatted diagnostic message. */ #define pp_formatted_text_data(PP) \ - ((const char *) obstack_base (&pp_base (PP)->buffer->obstack)) + ((const char *) obstack_base (pp_base (PP)->buffer->obstack)) /* Format an integer given by va_arg (ARG, type-specifier T) where type-specifier is a precision modifier as indicated by PREC. F is @@ -90,7 +91,7 @@ pp_clear_state (pretty_printer *pp) } /* Flush the formatted text of PRETTY-PRINTER onto the attached stream. */ -static inline void +void pp_write_text_to_stream (pretty_printer *pp) { const char *text = pp_formatted_text (pp); @@ -146,7 +147,7 @@ pp_maybe_wrap_text (pretty_printer *pp, const char *start, const char *end) static inline void pp_append_r (pretty_printer *pp, const char *start, int length) { - obstack_grow (&pp->buffer->obstack, start, length); + obstack_grow (pp->buffer->obstack, start, length); pp->buffer->line_length += length; } @@ -163,8 +164,7 @@ pp_base_indent (pretty_printer *pp) pp_space (pp); } -/* Format a message pointed to by TEXT. The following format specifiers are - recognized as being client independent: +/* The following format specifiers are recognized as being client independent: %d, %i: (signed) integer in base ten. %u: unsigned integer in base ten. %o: unsigned integer in base eight. @@ -176,51 +176,250 @@ pp_base_indent (pretty_printer *pp) %s: string. %p: pointer. %m: strerror(text->err_no) - does not consume a value from args_ptr. - %%: `%'. - %.*s: a substring the length of which is specified by an integer. - %H: location_t. */ + %%: '%'. + %<: opening quote. + %>: closing quote. + %': apostrophe (should only be used in untranslated messages; + translations should use appropriate punctuation directly). + %.*s: a substring the length of which is specified by an argument + integer. + %Ns: likewise, but length specified as constant in the format string. + %H: location_t. + %J: a decl tree, from which DECL_SOURCE_LOCATION will be recorded. + Flag 'q': quote formatted text (must come immediately after '%'). + + Arguments can be used sequentially, or through %N$ resp. *N$ + notation Nth argument after the format string. If %N$ / *N$ + notation is used, it must be used for all arguments, except %m, %%, + %<, %> and %', which may not have a number, as they do not consume + an argument. When %M$.*N$s is used, M must be N + 1. (This may + also be written %M$.*s, provided N is not otherwise used.) The + format string must have conversion specifiers with argument numbers + 1 up to highest argument; each argument may only be used once. + A format string can have at most 30 arguments. */ + +/* Formatting phases 1 and 2: render TEXT->format_spec plus + TEXT->args_ptr into a series of chunks in PP->buffer->args[]. + Phase 3 is in pp_base_format_text. */ + void -pp_base_format_text (pretty_printer *pp, text_info *text) +pp_base_format (pretty_printer *pp, text_info *text) { - for (; *text->format_spec; ++text->format_spec) + output_buffer *buffer = pp->buffer; + const char *p; + const char **args; + struct chunk_info *new_chunk_array; + + unsigned int curarg = 0, chunk = 0, argno; + pp_wrapping_mode_t old_wrapping_mode; + bool any_unnumbered = false, any_numbered = false; + const char **formatters[PP_NL_ARGMAX]; + + /* Allocate a new chunk structure. */ + new_chunk_array = XOBNEW (&buffer->chunk_obstack, struct chunk_info); + new_chunk_array->prev = buffer->cur_chunk_array; + buffer->cur_chunk_array = new_chunk_array; + args = new_chunk_array->args; + + /* Formatting phase 1: split up TEXT->format_spec into chunks in + PP->buffer->args[]. Even-numbered chunks are to be output + verbatim, odd-numbered chunks are format specifiers. + %m, %%, %<, %>, and %' are replaced with the appropriate text at + this point. */ + + memset (formatters, 0, sizeof formatters); + + for (p = text->format_spec; *p; ) + { + while (*p != '\0' && *p != '%') + { + obstack_1grow (&buffer->chunk_obstack, *p); + p++; + } + + if (*p == '\0') + break; + + switch (*++p) + { + case '\0': + gcc_unreachable (); + + case '%': + obstack_1grow (&buffer->chunk_obstack, '%'); + p++; + continue; + + case '<': + obstack_grow (&buffer->chunk_obstack, + open_quote, strlen (open_quote)); + p++; + continue; + + case '>': + case '\'': + obstack_grow (&buffer->chunk_obstack, + close_quote, strlen (close_quote)); + p++; + continue; + + case 'm': + { + const char *errstr = xstrerror (text->err_no); + obstack_grow (&buffer->chunk_obstack, errstr, strlen (errstr)); + } + p++; + continue; + + default: + /* Handled in phase 2. Terminate the plain chunk here. */ + obstack_1grow (&buffer->chunk_obstack, '\0'); + gcc_assert (chunk < PP_NL_ARGMAX * 2); + args[chunk++] = XOBFINISH (&buffer->chunk_obstack, const char *); + break; + } + + if (ISDIGIT (*p)) + { + char *end; + argno = strtoul (p, &end, 10) - 1; + p = end; + gcc_assert (*p == '$'); + p++; + + any_numbered = true; + gcc_assert (!any_unnumbered); + } + else + { + argno = curarg++; + any_unnumbered = true; + gcc_assert (!any_numbered); + } + gcc_assert (argno < PP_NL_ARGMAX); + gcc_assert (!formatters[argno]); + formatters[argno] = &args[chunk]; + do + { + obstack_1grow (&buffer->chunk_obstack, *p); + p++; + } + while (strchr ("qwl+#", p[-1])); + + if (p[-1] == '.') + { + /* We handle '%.Ns' and '%.*s' or '%M$.*N$s' + (where M == N + 1). */ + if (ISDIGIT (*p)) + { + do + { + obstack_1grow (&buffer->chunk_obstack, *p); + p++; + } + while (ISDIGIT (p[-1])); + gcc_assert (p[-1] == 's'); + } + else + { + gcc_assert (*p == '*'); + obstack_1grow (&buffer->chunk_obstack, '*'); + p++; + + if (ISDIGIT (*p)) + { + char *end; + unsigned int argno2 = strtoul (p, &end, 10) - 1; + p = end; + gcc_assert (argno2 == argno - 1); + gcc_assert (!any_unnumbered); + gcc_assert (*p == '$'); + + p++; + formatters[argno2] = formatters[argno]; + } + else + { + gcc_assert (!any_numbered); + formatters[argno+1] = formatters[argno]; + curarg++; + } + gcc_assert (*p == 's'); + obstack_1grow (&buffer->chunk_obstack, 's'); + p++; + } + } + if (*p == '\0') + break; + + obstack_1grow (&buffer->chunk_obstack, '\0'); + gcc_assert (chunk < PP_NL_ARGMAX * 2); + args[chunk++] = XOBFINISH (&buffer->chunk_obstack, const char *); + } + + obstack_1grow (&buffer->chunk_obstack, '\0'); + gcc_assert (chunk < PP_NL_ARGMAX * 2); + args[chunk++] = XOBFINISH (&buffer->chunk_obstack, const char *); + args[chunk] = 0; + + /* Set output to the argument obstack, and switch line-wrapping and + prefixing off. */ + buffer->obstack = &buffer->chunk_obstack; + old_wrapping_mode = pp_set_verbatim_wrapping (pp); + + /* Second phase. Replace each formatter with the formatted text it + corresponds to. */ + + for (argno = 0; formatters[argno]; argno++) { int precision = 0; bool wide = false; + bool plus = false; + bool hash = false; + bool quote = false; - /* Ignore text. */ - { - const char *p = text->format_spec; - while (*p && *p != '%') - ++p; - pp_wrap_text (pp, text->format_spec, p); - text->format_spec = p; - } + /* We do not attempt to enforce any ordering on the modifier + characters. */ - if (*text->format_spec == '\0') - break; + for (p = *formatters[argno];; p++) + { + switch (*p) + { + case 'q': + gcc_assert (!quote); + quote = true; + continue; + + case '+': + gcc_assert (!plus); + plus = true; + continue; + + case '#': + gcc_assert (!hash); + hash = true; + continue; + + case 'w': + gcc_assert (!wide); + wide = true; + continue; + + case 'l': + /* We don't support precision beyond that of "long long". */ + gcc_assert (precision < 2); + precision++; + continue; + } + break; + } + + gcc_assert (!wide || precision == 0); - /* We got a '%'. Parse precision modifiers, if any. */ - switch (*++text->format_spec) - { - case 'w': - wide = true; - ++text->format_spec; - break; - - case 'l': - do - ++precision; - while (*++text->format_spec == 'l'); - break; - - default: - break; - } - /* We don't support precision beyond that of "long long". */ - if (precision > 2) - abort(); - - switch (*text->format_spec) + if (quote) + pp_string (pp, open_quote); + + switch (*p) { case 'c': pp_character (pp, va_arg (*text->args_ptr, int)); @@ -228,92 +427,148 @@ pp_base_format_text (pretty_printer *pp, text_info *text) case 'd': case 'i': - if (wide) - pp_wide_integer (pp, va_arg (*text->args_ptr, HOST_WIDE_INT)); - else - pp_integer_with_precision - (pp, *text->args_ptr, precision, int, "d"); + if (wide) + pp_wide_integer (pp, va_arg (*text->args_ptr, HOST_WIDE_INT)); + else + pp_integer_with_precision + (pp, *text->args_ptr, precision, int, "d"); break; case 'o': - if (wide) - pp_scalar (pp, "%" HOST_WIDE_INT_PRINT "o", - va_arg (*text->args_ptr, unsigned HOST_WIDE_INT)); - else - pp_integer_with_precision - (pp, *text->args_ptr, precision, unsigned, "u"); + if (wide) + pp_scalar (pp, "%" HOST_WIDE_INT_PRINT "o", + va_arg (*text->args_ptr, unsigned HOST_WIDE_INT)); + else + pp_integer_with_precision + (pp, *text->args_ptr, precision, unsigned, "o"); break; case 's': pp_string (pp, va_arg (*text->args_ptr, const char *)); break; - case 'p': - pp_pointer (pp, va_arg (*text->args_ptr, void *)); - break; + case 'p': + pp_pointer (pp, va_arg (*text->args_ptr, void *)); + break; case 'u': - if (wide) - pp_scalar (pp, HOST_WIDE_INT_PRINT_UNSIGNED, - va_arg (*text->args_ptr, unsigned HOST_WIDE_INT)); - else - pp_integer_with_precision - (pp, *text->args_ptr, precision, unsigned, "u"); + if (wide) + pp_scalar (pp, HOST_WIDE_INT_PRINT_UNSIGNED, + va_arg (*text->args_ptr, unsigned HOST_WIDE_INT)); + else + pp_integer_with_precision + (pp, *text->args_ptr, precision, unsigned, "u"); break; case 'x': - if (wide) - pp_scalar (pp, HOST_WIDE_INT_PRINT_HEX, - va_arg (*text->args_ptr, unsigned HOST_WIDE_INT)); - else - pp_integer_with_precision - (pp, *text->args_ptr, precision, unsigned, "x"); + if (wide) + pp_scalar (pp, HOST_WIDE_INT_PRINT_HEX, + va_arg (*text->args_ptr, unsigned HOST_WIDE_INT)); + else + pp_integer_with_precision + (pp, *text->args_ptr, precision, unsigned, "x"); break; - case 'm': - pp_string (pp, xstrerror (text->err_no)); + case 'H': + { + location_t *locus = va_arg (*text->args_ptr, location_t *); + gcc_assert (text->locus != NULL); + *text->locus = *locus; + } break; - case '%': - pp_character (pp, '%'); + case 'J': + { + tree t = va_arg (*text->args_ptr, tree); + gcc_assert (text->locus != NULL); + *text->locus = DECL_SOURCE_LOCATION (t); + } break; - case 'H': - { - const location_t *locus = va_arg (*text->args_ptr, location_t *); - pp_string (pp, "file '"); - pp_string (pp, locus->file); - pp_string (pp, "', line "); - pp_decimal_int (pp, locus->line); - } - break; - case '.': { int n; const char *s; - /* We handle no precision specifier but `%.*s'. */ - if (*++text->format_spec != '*') - abort (); - else if (*++text->format_spec != 's') - abort (); - n = va_arg (*text->args_ptr, int); + + /* We handle '%.Ns' and '%.*s' or '%M$.*N$s' + (where M == N + 1). The format string should be verified + already from the first phase. */ + p++; + if (ISDIGIT (*p)) + { + char *end; + n = strtoul (p, &end, 10); + p = end; + gcc_assert (*p == 's'); + } + else + { + gcc_assert (*p == '*'); + p++; + gcc_assert (*p == 's'); + n = va_arg (*text->args_ptr, int); + + /* This consumes a second entry in the formatters array. */ + gcc_assert (formatters[argno] == formatters[argno+1]); + argno++; + } + s = va_arg (*text->args_ptr, const char *); pp_append_text (pp, s, s + n); } break; default: - if (!pp_format_decoder (pp) || !(*pp_format_decoder (pp)) (pp, text)) - { - /* Hmmm. The client failed to install a format translator - but called us with an unrecognized format. Or, maybe, the - translated string just contains an invalid format, or - has formats in the wrong order. Sorry. */ - abort (); - } + { + bool ok; + + gcc_assert (pp_format_decoder (pp)); + ok = pp_format_decoder (pp) (pp, text, p, + precision, wide, plus, hash); + gcc_assert (ok); + } } + + if (quote) + pp_string (pp, close_quote); + + obstack_1grow (&buffer->chunk_obstack, '\0'); + *formatters[argno] = XOBFINISH (&buffer->chunk_obstack, const char *); } + +#ifdef ENABLE_CHECKING + for (; argno < PP_NL_ARGMAX; argno++) + gcc_assert (!formatters[argno]); +#endif + + /* Revert to normal obstack and wrapping mode. */ + buffer->obstack = &buffer->formatted_obstack; + buffer->line_length = 0; + pp_wrapping_mode (pp) = old_wrapping_mode; + pp_clear_state (pp); +} + +/* Format of a message pointed to by TEXT. */ +void +pp_base_output_formatted_text (pretty_printer *pp) +{ + unsigned int chunk; + output_buffer *buffer = pp_buffer (pp); + struct chunk_info *chunk_array = buffer->cur_chunk_array; + const char **args = chunk_array->args; + + gcc_assert (buffer->obstack == &buffer->formatted_obstack); + gcc_assert (buffer->line_length == 0); + + /* This is a third phase, first 2 phases done in pp_base_format_args. + Now we actually print it. */ + for (chunk = 0; args[chunk]; chunk++) + pp_string (pp, args[chunk]); + + /* Deallocate the chunk structure and everything after it (i.e. the + associated series of formatted strings). */ + buffer->cur_chunk_array = chunk_array->prev; + obstack_free (&buffer->chunk_obstack, chunk_array); } /* Helper subroutine of output_verbatim and verbatim. Do the appropriate @@ -321,17 +576,15 @@ pp_base_format_text (pretty_printer *pp, text_info *text) void pp_base_format_verbatim (pretty_printer *pp, text_info *text) { - diagnostic_prefixing_rule_t rule = pp_prefixing_rule (pp); - int line_cutoff = pp_line_cutoff (pp); - /* Set verbatim mode. */ - pp->prefixing_rule = DIAGNOSTICS_SHOW_PREFIX_NEVER; - pp_line_cutoff (pp) = 0; + pp_wrapping_mode_t oldmode = pp_set_verbatim_wrapping (pp); + /* Do the actual formatting. */ - pp_format_text (pp, text); + pp_format (pp, text); + pp_output_formatted_text (pp); + /* Restore previous settings. */ - pp_prefixing_rule (pp) = rule; - pp_line_cutoff (pp) = line_cutoff; + pp_wrapping_mode (pp) = oldmode; } /* Flush the content of BUFFER onto the attached stream. */ @@ -359,7 +612,7 @@ pp_base_set_line_maximum_length (pretty_printer *pp, int length) void pp_base_clear_output_area (pretty_printer *pp) { - obstack_free (&pp->buffer->obstack, obstack_base (&pp->buffer->obstack)); + obstack_free (pp->buffer->obstack, obstack_base (pp->buffer->obstack)); pp->buffer->line_length = 0; } @@ -423,7 +676,9 @@ pp_construct (pretty_printer *pp, const char *prefix, int maximum_length) { memset (pp, 0, sizeof (pretty_printer)); pp->buffer = xcalloc (1, sizeof (output_buffer)); - obstack_init (&pp->buffer->obstack); + obstack_init (&pp->buffer->chunk_obstack); + obstack_init (&pp->buffer->formatted_obstack); + pp->buffer->obstack = &pp->buffer->formatted_obstack; pp->buffer->stream = stderr; pp_line_cutoff (pp) = maximum_length; pp_prefixing_rule (pp) = DIAGNOSTICS_SHOW_PREFIX_ONCE; @@ -454,7 +709,7 @@ pp_base_append_text (pretty_printer *pp, const char *start, const char *end) const char * pp_base_formatted_text (pretty_printer *pp) { - obstack_1grow (&pp->buffer->obstack, '\0'); + obstack_1grow (pp->buffer->obstack, '\0'); return pp_formatted_text_data (pp); } @@ -464,7 +719,7 @@ const char * pp_base_last_position_in_text (const pretty_printer *pp) { const char *p = NULL; - struct obstack *text = &pp->buffer->obstack; + struct obstack *text = pp->buffer->obstack; if (obstack_base (text) != obstack_next_free (text)) p = ((const char *) obstack_next_free (text)) - 1; @@ -491,7 +746,9 @@ pp_printf (pretty_printer *pp, const char *msg, ...) text.err_no = errno; text.args_ptr = ≈ text.format_spec = msg; - pp_format_text (pp, &text); + text.locus = NULL; + pp_format (pp, &text); + pp_output_formatted_text (pp); va_end (ap); } @@ -507,6 +764,7 @@ pp_verbatim (pretty_printer *pp, const char *msg, ...) text.err_no = errno; text.args_ptr = ≈ text.format_spec = msg; + text.locus = NULL; pp_format_verbatim (pp, &text); va_end (ap); } @@ -517,7 +775,7 @@ pp_verbatim (pretty_printer *pp, const char *msg, ...) void pp_base_newline (pretty_printer *pp) { - obstack_1grow (&pp->buffer->obstack, '\n'); + obstack_1grow (pp->buffer->obstack, '\n'); pp->buffer->line_length = 0; } @@ -532,7 +790,7 @@ pp_base_character (pretty_printer *pp, int c) if (ISSPACE (c)) return; } - obstack_1grow (&pp->buffer->obstack, c); + obstack_1grow (pp->buffer->obstack, c); ++pp->buffer->line_length; } @@ -544,4 +802,14 @@ pp_base_string (pretty_printer *pp, const char *str) pp_maybe_wrap_text (pp, str, str + (str ? strlen (str) : 0)); } +/* Maybe print out a whitespace if needed. */ +void +pp_base_maybe_space (pretty_printer *pp) +{ + if (pp_base (pp)->padding != pp_none) + { + pp_space (pp); + pp_base (pp)->padding = pp_none; + } +} diff --git a/support/cpp2/pretty-print.h b/support/cpp2/pretty-print.h index 1691aec2..b2c6772b 100644 --- a/support/cpp2/pretty-print.h +++ b/support/cpp2/pretty-print.h @@ -1,5 +1,5 @@ /* Various declarations for language-independent pretty-print subroutines. - Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. Contributed by Gabriel Dos Reis This file is part of GCC. @@ -16,8 +16,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ #ifndef GCC_PRETTY_PRINT_H #define GCC_PRETTY_PRINT_H @@ -25,6 +25,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "obstack.h" #include "input.h" +/* Maximum number of format string arguments. */ +#define PP_NL_ARGMAX 30 + /* The type of a text to be formatted according a format specification along with a list of things. */ typedef struct @@ -32,6 +35,7 @@ typedef struct const char *format_spec; va_list *args_ptr; int err_no; /* for %m */ + location_t *locus; } text_info; /* How often diagnostics are prefixed by their locations: @@ -46,12 +50,42 @@ typedef enum DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE = 0x2 } diagnostic_prefixing_rule_t; +/* The chunk_info data structure forms a stack of the results from the + first phase of formatting (pp_base_format) which have not yet been + output (pp_base_output_formatted_text). A stack is necessary because + the diagnostic starter may decide to generate its own output by way + of the formatter. */ +struct chunk_info +{ + /* Pointer to previous chunk on the stack. */ + struct chunk_info *prev; + + /* Array of chunks to output. Each chunk is a NUL-terminated string. + In the first phase of formatting, even-numbered chunks are + to be output verbatim, odd-numbered chunks are format specifiers. + The second phase replaces all odd-numbered chunks with formatted + text, and the third phase simply emits all the chunks in sequence + with appropriate line-wrapping. */ + const char *args[PP_NL_ARGMAX * 2]; +}; + /* The output buffer datatype. This is best seen as an abstract datatype whose fields should not be accessed directly by clients. */ typedef struct { - /* The obstack where the text is built up. */ - struct obstack obstack; + /* Obstack where the text is built up. */ + struct obstack formatted_obstack; + + /* Obstack containing a chunked representation of the format + specification plus arguments. */ + struct obstack chunk_obstack; + + /* Currently active obstack: one of the above two. This is used so + that the text formatters don't need to know which phase we're in. */ + struct obstack *obstack; + + /* Stack of chunk arrays. These come from the chunk_obstack. */ + struct chunk_info *cur_chunk_array; /* Where to output formatted text. */ FILE *stream; @@ -72,11 +106,34 @@ typedef enum pp_none, pp_before, pp_after } pp_padding; +/* Structure for switching in and out of verbatim mode in a convenient + manner. */ +typedef struct +{ + /* Current prefixing rule. */ + diagnostic_prefixing_rule_t rule; + + /* The ideal upper bound of number of characters per line, as suggested + by front-end. */ + int line_cutoff; +} pp_wrapping_mode_t; + +/* Maximum characters per line in automatic line wrapping mode. + Zero means don't wrap lines. */ +#define pp_line_cutoff(PP) pp_base (PP)->wrapping.line_cutoff + +/* Prefixing rule used in formatting a diagnostic message. */ +#define pp_prefixing_rule(PP) pp_base (PP)->wrapping.rule + +/* Get or set the wrapping mode as a single entity. */ +#define pp_wrapping_mode(PP) pp_base (PP)->wrapping + /* The type of a hook that formats client-specific data onto a pretty_pinter. A client-supplied formatter returns true if everything goes well, otherwise it returns false. */ typedef struct pretty_print_info pretty_printer; -typedef bool (*printer_fn) (pretty_printer *, text_info *); +typedef bool (*printer_fn) (pretty_printer *, text_info *, const char *, + int, bool, bool, bool); /* Client supplied function used to decode formats. */ #define pp_format_decoder(PP) pp_base (PP)->format_decoder @@ -85,16 +142,9 @@ typedef bool (*printer_fn) (pretty_printer *, text_info *); formatting. */ #define pp_needs_newline(PP) pp_base (PP)->need_newline -/* Maximum characters per line in automatic line wrapping mode. - Zero means don't wrap lines. */ -#define pp_line_cutoff(PP) pp_base (PP)->ideal_maximum_length - /* True if PRETTY-PTINTER is in line-wrapping mode. */ #define pp_is_wrapping_line(PP) (pp_line_cutoff (PP) > 0) -/* Prefixing rule used in formatting a diagnostic message. */ -#define pp_prefixing_rule(PP) pp_base (PP)->prefixing_rule - /* The amount of whitespace to be emitted when starting a new line. */ #define pp_indentation(PP) pp_base (PP)->indent_skip @@ -116,15 +166,11 @@ struct pretty_print_info account the case of a very very looong prefix. */ int maximum_length; - /* The ideal upper bound of number of characters per line, as suggested - by front-end. */ - int ideal_maximum_length; - /* Indentation count. */ int indent_skip; - /* Current prefixing rule. */ - diagnostic_prefixing_rule_t prefixing_rule; + /* Current wrapping mode. */ + pp_wrapping_mode_t wrapping; /* If non-NULL, this function formats a TEXT into the BUFFER. When called, TEXT->format_spec points to a format code. FORMAT_DECODER should call @@ -158,7 +204,9 @@ struct pretty_print_info #define pp_append_text(PP, B, E) \ pp_base_append_text (pp_base (PP), B, E) #define pp_flush(PP) pp_base_flush (pp_base (PP)) -#define pp_format_text(PP, TI) pp_base_format_text (pp_base (PP), TI) +#define pp_format(PP, TI) pp_base_format (pp_base (PP), TI) +#define pp_output_formatted_text(PP) \ + pp_base_output_formatted_text (pp_base (PP)) #define pp_format_verbatim(PP, TI) \ pp_base_format_verbatim (pp_base (PP), TI) @@ -205,6 +253,7 @@ struct pretty_print_info } while (0) #define pp_maybe_newline_and_indent(PP, N) \ if (pp_needs_newline (PP)) pp_newline_and_indent (PP, N) +#define pp_maybe_space(PP) pp_base_maybe_space (pp_base (PP)) #define pp_separate_with(PP, C) \ do { \ pp_character (PP, C); \ @@ -220,6 +269,8 @@ struct pretty_print_info #define pp_decimal_int(PP, I) pp_scalar (PP, "%d", I) #define pp_wide_integer(PP, I) \ pp_scalar (PP, HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT) I) +#define pp_widest_integer(PP, I) \ + pp_scalar (PP, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT) I) #define pp_pointer(PP, P) pp_scalar (PP, "%p", P) #define pp_identifier(PP, ID) pp_string (PP, ID) @@ -228,7 +279,7 @@ struct pretty_print_info IDENTIFIER_POINTER (T) + IDENTIFIER_LENGTH (T)) #define pp_unsupported_tree(PP, T) \ - pp_verbatim (pp_base (PP), "#`%s' not supported by %s#", \ + pp_verbatim (pp_base (PP), "#%qs not supported by %s#", \ tree_code_name[(int) TREE_CODE (T)], __FUNCTION__) @@ -247,15 +298,40 @@ extern const char *pp_base_formatted_text (pretty_printer *); extern const char *pp_base_last_position_in_text (const pretty_printer *); extern void pp_base_emit_prefix (pretty_printer *); extern void pp_base_append_text (pretty_printer *, const char *, const char *); -extern void pp_printf (pretty_printer *, const char *, ...) ATTRIBUTE_PRINTF_2; -extern void pp_verbatim (pretty_printer *, const char *, ...); + +/* This header may be included before toplev.h, hence the duplicate + definitions to allow for GCC-specific formats. */ +#if GCC_VERSION >= 3005 +#define ATTRIBUTE_GCC_PPDIAG(m, n) __attribute__ ((__format__ (__gcc_diag__, m ,n))) ATTRIBUTE_NONNULL(m) +#else +#define ATTRIBUTE_GCC_PPDIAG(m, n) ATTRIBUTE_NONNULL(m) +#endif +extern void pp_printf (pretty_printer *, const char *, ...) + ATTRIBUTE_GCC_PPDIAG(2,3); + +extern void pp_verbatim (pretty_printer *, const char *, ...) + ATTRIBUTE_GCC_PPDIAG(2,3); extern void pp_base_flush (pretty_printer *); -extern void pp_base_format_text (pretty_printer *, text_info *); +extern void pp_base_format (pretty_printer *, text_info *); +extern void pp_base_output_formatted_text (pretty_printer *); extern void pp_base_format_verbatim (pretty_printer *, text_info *); extern void pp_base_indent (pretty_printer *); extern void pp_base_newline (pretty_printer *); extern void pp_base_character (pretty_printer *, int); extern void pp_base_string (pretty_printer *, const char *); +extern void pp_write_text_to_stream (pretty_printer *pp); +extern void pp_base_maybe_space (pretty_printer *); + +/* Switch into verbatim mode and return the old mode. */ +static inline pp_wrapping_mode_t +pp_set_verbatim_wrapping_ (pretty_printer *pp) +{ + pp_wrapping_mode_t oldmode = pp_wrapping_mode (pp); + pp_line_cutoff (pp) = 0; + pp_prefixing_rule (pp) = DIAGNOSTICS_SHOW_PREFIX_NEVER; + return oldmode; +} +#define pp_set_verbatim_wrapping(PP) pp_set_verbatim_wrapping_ (pp_base (PP)) #endif /* GCC_PRETTY_PRINT_H */ diff --git a/support/cpp2/sdcpp-opts.c b/support/cpp2/sdcpp-opts.c index 8f8e85e0..56d74399 100644 --- a/support/cpp2/sdcpp-opts.c +++ b/support/cpp2/sdcpp-opts.c @@ -1,5 +1,5 @@ /* C/ObjC/C++ command line option handling. - Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. Contributed by Neil Booth. This file is part of GCC. @@ -16,8 +16,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ #include "config.h" #include "system.h" @@ -27,6 +27,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "c-incpath.h" #include "opts.h" #include "options.h" +#include "mkdeps.h" #ifndef DOLLARS_IN_IDENTIFIERS # define DOLLARS_IN_IDENTIFIERS true @@ -75,6 +76,9 @@ static bool quote_chain_split; /* If -Wunused-macros. */ static bool warn_unused_macros; +/* If -Wvariadic-macros. */ +static bool warn_variadic_macros = true; + /* Number of deferred options. */ static size_t deferred_count; @@ -132,6 +136,7 @@ sdcpp_common_missing_argument (const char *opt, size_t code) case OPT_idirafter: case OPT_isysroot: case OPT_isystem: + case OPT_iquote: error ("missing path after \"%s\"", opt); break; @@ -166,7 +171,7 @@ defer_opt (enum opt_code code, const char *arg) unsigned int sdcpp_common_init_options (unsigned int argc, const char **argv ATTRIBUTE_UNUSED) { - parse_in = cpp_create_reader (CLK_GNUC89, NULL); + parse_in = cpp_create_reader (CLK_GNUC89, NULL, &line_table); cpp_opts = cpp_get_options (parse_in); cpp_opts->dollars_in_ident = DOLLARS_IN_IDENTIFIERS; @@ -176,7 +181,7 @@ sdcpp_common_init_options (unsigned int argc, const char **argv ATTRIBUTE_UNUSED before passing on command-line options to cpplib. */ cpp_opts->warn_dollars = 0; - deferred_opts = xmalloc (argc * sizeof (struct deferred_opt)); + deferred_opts = XNEWVEC (struct deferred_opt, argc); return CL_SDCPP; } @@ -227,13 +232,14 @@ sdcpp_common_handle_option (size_t scode, const char *arg, int value) case OPT_I: if (strcmp (arg, "-")) - add_path (xstrdup (arg), BRACKET, 0); + add_path (xstrdup (arg), BRACKET, 0, true); else { if (quote_chain_split) error ("-I- specified twice"); quote_chain_split = true; split_quote_chain (); + inform ("obsolete option -I- used, please use -iquote instead"); } break; @@ -309,6 +315,7 @@ sdcpp_common_handle_option (size_t scode, const char *arg, int value) case OPT_Werror: cpp_opts->warnings_are_errors = value; + global_dc->warning_as_error_requested = value; break; case OPT_Wimport: @@ -325,6 +332,10 @@ sdcpp_common_handle_option (size_t scode, const char *arg, int value) cpp_opts->warn_system_headers = value; break; + case OPT_Wtraditional: + cpp_opts->warn_traditional = value; + break; + case OPT_Wtrigraphs: cpp_opts->warn_trigraphs = value; break; @@ -337,6 +348,10 @@ sdcpp_common_handle_option (size_t scode, const char *arg, int value) warn_unused_macros = value; break; + case OPT_Wvariadic_macros: + warn_variadic_macros = value; + break; + case OPT_ansi: set_std_c89 (false, true); break; @@ -361,6 +376,10 @@ sdcpp_common_handle_option (size_t scode, const char *arg, int value) case OPT_fpch_deps: cpp_opts->restore_pch_deps = value; break; + + case OPT_fpch_preprocess: + flag_pch_preprocess = value; + break; #endif case OPT_fpreprocessed: @@ -390,7 +409,7 @@ sdcpp_common_handle_option (size_t scode, const char *arg, int value) break; case OPT_idirafter: - add_path (xstrdup (arg), AFTER, 0); + add_path (xstrdup (arg), AFTER, 0, true); break; case OPT_imacros: @@ -402,12 +421,16 @@ sdcpp_common_handle_option (size_t scode, const char *arg, int value) iprefix = arg; break; + case OPT_iquote: + add_path (xstrdup (arg), QUOTE, 0, true); + break; + case OPT_isysroot: sysroot = arg; break; case OPT_isystem: - add_path (xstrdup (arg), SYSTEM, 0); + add_path (xstrdup (arg), SYSTEM, 0, true); break; case OPT_iwithprefix: @@ -459,6 +482,13 @@ sdcpp_common_handle_option (size_t scode, const char *arg, int value) cpp_opts->pedantic_parse_number = 1; break; +#if 0 // pch not supported by sdcpp + case OPT_print_pch_checksum: + c_common_print_pch_checksum (stdout); + exit_after_options = true; + break; +#endif + case OPT_remap: cpp_opts->remap = 1; break; @@ -503,7 +533,7 @@ sdcpp_common_post_options (const char **pfilename) /* Canonicalize the input and output filenames. */ if (in_fnames == NULL) { - in_fnames = xmalloc (sizeof (in_fnames[0])); + in_fnames = XNEWVEC (const char *, 1); in_fnames[0] = ""; } else if (strcmp (in_fnames[0], "-") == 0) @@ -547,8 +577,7 @@ sdcpp_common_post_options (const char **pfilename) cb->dir_change = cb_dir_change; cpp_post_options (parse_in); - saved_lineno = input_line; - input_line = 0; + input_location = UNKNOWN_LOCATION; /* If an error has occurred in cpplib, note it so we fail immediately. */ @@ -563,7 +592,7 @@ sdcpp_common_post_options (const char **pfilename) return false; } - if (flag_working_directory && ! flag_no_line_commands) + if (flag_working_directory && !flag_no_line_commands) pp_dir_change (parse_in, get_src_pwd ()); return 1; @@ -573,8 +602,6 @@ sdcpp_common_post_options (const char **pfilename) bool sdcpp_common_init (void) { - input_line = saved_lineno; - /* Default CPP arithmetic to something sensible for the host for the benefit of dumb users like fix-header. */ cpp_opts->precision = CHAR_BIT * sizeof (long); @@ -588,6 +615,11 @@ sdcpp_common_init (void) are known. */ cpp_init_iconv (parse_in); +#if 0 + if (version_flag) + c_common_print_pch_checksum (stderr); +#endif + finish_options (); preprocess_file (parse_in); return false; @@ -666,6 +698,7 @@ check_deps_environment_vars (void) deps_file = spec; deps_append = 1; + deps_seen = true; } } @@ -674,13 +707,22 @@ static void handle_deferred_opts (void) { size_t i; + struct deps *deps; + + /* Avoid allocating the deps buffer if we don't need it. + (This flag may be true without there having been -MT or -MQ + options, but we'll still need the deps buffer.) */ + if (!deps_seen) + return; + + deps = cpp_get_deps (parse_in); for (i = 0; i < deferred_count; i++) { struct deferred_opt *opt = &deferred_opts[i]; if (opt->code == OPT_MT || opt->code == OPT_MQ) - cpp_add_dependency_target (parse_in, opt->arg, opt->code == OPT_MQ); + deps_add_target (deps, opt->arg, opt->code == OPT_MQ); } } @@ -713,6 +755,11 @@ sanitize_cpp_opts (void) cpp_opts->unsigned_char = !flag_signed_char; cpp_opts->stdc_0_in_system_headers = STDC_0_IN_SYSTEM_HEADERS; + /* Similarly with -Wno-variadic-macros. No check for c99 here, since + this also turns off warnings about GCCs extension. */ + cpp_opts->warn_variadic_macros + = warn_variadic_macros && (pedantic || warn_traditional); + /* If we're generating preprocessor output, emit current directory if explicitly requested */ if (flag_working_directory == -1) @@ -731,12 +778,12 @@ add_prefixed_path (const char *suffix, size_t chain) prefix = iprefix ? iprefix : cpp_GCC_INCLUDE_DIR; prefix_len = iprefix ? strlen (iprefix) : cpp_GCC_INCLUDE_DIR_len; - path = xmalloc (prefix_len + suffix_len + 1); + path = (char *) xmalloc (prefix_len + suffix_len + 1); memcpy (path, prefix, prefix_len); memcpy (path + prefix_len, suffix, suffix_len); path[prefix_len + suffix_len] = '\0'; - add_path (path, chain, 0); + add_path (path, chain, 0, false); } /* Handle -D, -U, -A, -imacros, and the first -include. */ @@ -747,7 +794,10 @@ finish_options (void) { size_t i; - cpp_change_file (parse_in, LC_RENAME, _("")); + cb_file_change (parse_in, + linemap_add (&line_table, LC_RENAME, 0, + _(""), 0)); + cpp_init_builtins (parse_in, 0 /*flag_hosted*/); /* We're about to send user input to cpplib, so make it warn for @@ -806,7 +856,7 @@ push_command_line_include (void) { struct deferred_opt *opt = &deferred_opts[include_cursor++]; - if (! cpp_opts->preprocessed && opt->code == OPT_include + if (!cpp_opts->preprocessed && opt->code == OPT_include && cpp_push_include (parse_in, opt->arg)) return; } @@ -817,19 +867,18 @@ push_command_line_include (void) /* -Wunused-macros should only warn about macros defined hereafter. */ cpp_opts->warn_unused_macros = warn_unused_macros; /* Restore the line map from . */ - if (! cpp_opts->preprocessed) - cpp_change_file (parse_in, LC_RENAME, main_input_filename); + if (!cpp_opts->preprocessed) + cpp_change_file (parse_in, LC_RENAME, this_input_filename); /* Set this here so the client can change the option if it wishes, and after stacking the main file so we don't trace the main file. */ - cpp_get_line_maps (parse_in)->trace_includes - = cpp_opts->print_include_names; + line_table.trace_includes = cpp_opts->print_include_names; } } /* File change callback. Has to handle -include files. */ static void -cb_file_change (cpp_reader *pfile ATTRIBUTE_UNUSED, +cb_file_change (cpp_reader * ARG_UNUSED (pfile), const struct line_map *new_map) { pp_file_change (new_map); @@ -839,10 +888,10 @@ cb_file_change (cpp_reader *pfile ATTRIBUTE_UNUSED, } void -cb_dir_change (cpp_reader *pfile ATTRIBUTE_UNUSED, const char *dir) +cb_dir_change (cpp_reader * ARG_UNUSED (pfile), const char *dir) { - if (! set_src_pwd (dir)) - warning ("too late for # directive to set debug directory"); + if (!set_src_pwd (dir)) + warning (0, "too late for # directive to set debug directory"); } /* Set the C 89 standard (with 1994 amendments if C94, without GNU diff --git a/support/cpp2/sdcpp.c b/support/cpp2/sdcpp.c index def45e24..794879ef 100644 --- a/support/cpp2/sdcpp.c +++ b/support/cpp2/sdcpp.c @@ -25,7 +25,7 @@ #include "config.h" #include "system.h" #include "cpplib.h" -#include "cpphash.h" +#include "internal.h" #include "version.h" #include "mkdeps.h" #include "opts.h" @@ -74,10 +74,16 @@ const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; const char *main_input_filename; +#ifndef USE_MAPPED_LOCATION +location_t unknown_location = { NULL, 0 }; +#endif + /* Current position in real source file. */ location_t input_location; +struct line_maps line_table; + /* Stack of currently pending input files. */ struct file_stack *input_file_stack; @@ -137,6 +143,14 @@ static const char *src_pwd; be called with a NULL argument to test whether src_pwd has NOT been initialized yet. */ +/* From intl.c */ +/* Opening quotation mark for diagnostics. */ +const char *open_quote = "'"; + +/* Closing quotation mark for diagnostics. */ +const char *close_quote = "'"; +/* ----------- */ + bool set_src_pwd (const char *pwd) { @@ -292,7 +306,7 @@ decode_d_option (const char *arg) break; default: - warning ("unrecognized gcc debugging option: %c", c); + warning (0, "unrecognized gcc debugging option: %c", c); break; } } diff --git a/support/cpp2/sdcpp.dsp b/support/cpp2/sdcpp.dsp index 5b145663..75aa885a 100644 --- a/support/cpp2/sdcpp.dsp +++ b/support/cpp2/sdcpp.dsp @@ -43,7 +43,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "." /I ".\libiberty" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FR /FD /D /GZ "HAVE_CONFIG_H" /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "." /I ".\libiberty" /I ".\win32" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /FR /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "." /I ".\libiberty" /I ".\win32" /I ".\sdcpp" /I ".\sdcpp\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /FR /FD /GZ /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" @@ -70,7 +70,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /I "." /I ".\libiberty" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I "." /I ".\libiberty" /I ".\win32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_WIN32" /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "." /I ".\libiberty" /I ".\win32" /I ".\sdcpp" /I ".\sdcpp\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_WIN32" /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" @@ -90,82 +90,89 @@ LINK32=link.exe # Name "sdcpp - Win32 Release" # Begin Group "Source Files" +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Group "libcpp" + # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File -SOURCE=".\c-incpath.c" +SOURCE=.\libcpp\charset.c # End Source File # Begin Source File -SOURCE=".\c-ppoutput.c" +SOURCE=.\libcpp\directives.c # End Source File # Begin Source File -SOURCE=.\libiberty\concat.c +SOURCE=.\libcpp\errors.c # End Source File # Begin Source File -SOURCE=.\cppcharset.c +SOURCE=.\libcpp\expr.c # End Source File # Begin Source File -SOURCE=.\cppdefault.c +SOURCE=.\libcpp\files.c # End Source File # Begin Source File -SOURCE=.\cpperror.c +SOURCE=.\libcpp\identifiers.c # End Source File # Begin Source File -SOURCE=.\cppexp.c +SOURCE=.\libcpp\init.c # End Source File # Begin Source File -SOURCE=.\cppfiles.c +SOURCE=.\libcpp\internal.h # End Source File # Begin Source File -SOURCE=.\cpphash.c +SOURCE=.\libcpp\lex.c # End Source File # Begin Source File -SOURCE=.\cppinit.c +SOURCE=".\libcpp\line-map.c" # End Source File # Begin Source File -SOURCE=.\cpplex.c +SOURCE=.\libcpp\macro.c # End Source File # Begin Source File -SOURCE=.\cpplib.c +SOURCE=.\libcpp\makeucnid.c # End Source File # Begin Source File -SOURCE=.\cppmacro.c +SOURCE=.\libcpp\mkdeps.c # End Source File # Begin Source File -SOURCE=.\cpptrad.c +SOURCE=.\libcpp\symtab.c # End Source File # Begin Source File -SOURCE=.\diagnostic.c +SOURCE=.\libcpp\system.h # End Source File # Begin Source File -SOURCE=.\win32\dirent.c +SOURCE=.\libcpp\traditional.c # End Source File # Begin Source File -SOURCE=.\libiberty\getpwd.c +SOURCE=.\libcpp\ucnid.h # End Source File +# End Group +# Begin Group "libiberty" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File -SOURCE=.\hashtab.c +SOURCE=.\libiberty\concat.c # End Source File # Begin Source File -SOURCE=.\hashtable.c +SOURCE=.\libiberty\getpwd.c # End Source File # Begin Source File @@ -177,75 +184,92 @@ SOURCE=.\libiberty\lbasename.c # End Source File # Begin Source File -SOURCE=".\line-map.c" +SOURCE=.\libiberty\obstack.c # End Source File # Begin Source File -SOURCE=.\mkdeps.c +SOURCE=".\libiberty\safe-ctype.c" # End Source File # Begin Source File -SOURCE=.\libiberty\obstack.c +SOURCE=".\libiberty\splay-tree.c" # End Source File # Begin Source File -SOURCE=.\options.c +SOURCE=.\libiberty\vasprintf.c # End Source File # Begin Source File -SOURCE=.\opts.c +SOURCE=.\libiberty\xexit.c # End Source File # Begin Source File -SOURCE=.\prefix.c +SOURCE=.\libiberty\xmalloc.c # End Source File # Begin Source File -SOURCE=".\pretty-print.c" +SOURCE=.\libiberty\xmemdup.c # End Source File # Begin Source File -SOURCE=".\libiberty\safe-ctype.c" +SOURCE=.\libiberty\xstrdup.c # End Source File # Begin Source File -SOURCE=".\sdcpp-opts.c" +SOURCE=.\libiberty\xstrerror.c +# End Source File +# End Group +# Begin Group "win32" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\win32\dirent.c # End Source File +# End Group # Begin Source File -SOURCE=.\sdcpp.c +SOURCE=".\c-incpath.c" # End Source File # Begin Source File -SOURCE=".\libiberty\splay-tree.c" +SOURCE=".\c-ppoutput.c" # End Source File # Begin Source File -SOURCE=.\libiberty\vasprintf.c +SOURCE=.\cppdefault.c # End Source File # Begin Source File -SOURCE=.\version.c +SOURCE=.\diagnostic.c # End Source File # Begin Source File -SOURCE=.\libiberty\xexit.c +SOURCE=.\options.c # End Source File # Begin Source File -SOURCE=.\libiberty\xmalloc.c +SOURCE=.\opts.c # End Source File # Begin Source File -SOURCE=.\libiberty\xmemdup.c +SOURCE=.\prefix.c # End Source File # Begin Source File -SOURCE=.\libiberty\xstrdup.c +SOURCE=".\pretty-print.c" # End Source File # Begin Source File -SOURCE=.\libiberty\xstrerror.c +SOURCE=".\sdcpp-opts.c" +# End Source File +# Begin Source File + +SOURCE=.\sdcpp.c +# End Source File +# Begin Source File + +SOURCE=.\version.c # End Source File # End Group # Begin Group "Header Files" diff --git a/support/cpp2/sdcpp.h b/support/cpp2/sdcpp.h index 9f7ece75..8b7e7c8c 100644 --- a/support/cpp2/sdcpp.h +++ b/support/cpp2/sdcpp.h @@ -119,7 +119,6 @@ extern const struct lang_hooks lang_hooks; #ifndef GCC_DIAG_STYLE #define GCC_DIAG_STYLE __gcc_diag__ #endif - /* None of these functions are suitable for ATTRIBUTE_PRINTF, because each language front end can extend them with its own set of format specifiers. We must use custom format checks. */ @@ -128,10 +127,26 @@ extern const struct lang_hooks lang_hooks; #else #define ATTRIBUTE_GCC_DIAG(m, n) ATTRIBUTE_NONNULL(m) #endif -extern void warning (const char *, ...); -extern void error (const char *, ...); +/* None of these functions are suitable for ATTRIBUTE_PRINTF, because + each language front end can extend them with its own set of format + specifiers. We must use custom format checks. */ +#if GCC_VERSION >= 4001 +#define ATTRIBUTE_GCC_DIAG(m, n) __attribute__ ((__format__ (GCC_DIAG_STYLE, m, n))) ATTRIBUTE_NONNULL(m) +#else +#define ATTRIBUTE_GCC_DIAG(m, n) ATTRIBUTE_NONNULL(m) +#endif +extern void internal_error (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2) + ATTRIBUTE_NORETURN; +extern void warning0 (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2); +/* Pass one of the OPT_W* from options.h as the first parameter. */ +extern void warning (int, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3); +extern void error (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2); extern void fatal_error (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2) ATTRIBUTE_NORETURN; +extern void pedwarn (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2); +extern void sorry (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2); +extern void inform (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2); +extern void verbatim (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2); #ifdef BUFSIZ /* N.B. Unlike all the others, fnotice is just gettext+fprintf, and @@ -181,13 +196,10 @@ extern int flag_signed_char; extern int flag_pedantic_errors; -/* Don't print warning messages. -w. */ - -extern bool inhibit_warnings; - /* * From c-common.h */ +#include "hwint.h" #include "cpplib.h" /* Nonzero means don't output line number information. */ diff --git a/support/cpp2/sdcpp.opt b/support/cpp2/sdcpp.opt index fe06f28a..b4d655ad 100644 --- a/support/cpp2/sdcpp.opt +++ b/support/cpp2/sdcpp.opt @@ -1,5 +1,5 @@ ; Options for the SDCPP front end. -; Copyright (C) 2003 Free Software Foundation, Inc. +; Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. ; ; This file is part of GCC. ; @@ -15,47 +15,10 @@ ; ; You should have received a copy of the GNU General Public License ; along with GCC; see the file COPYING. If not, write to the Free -; Software Foundation, 59 Temple Place - Suite 330, Boston, MA -; 02111-1307, USA. - - -; This file is processed by the script opts.sh. It is a database of -; command line options, with each record separated by a blank line, -; and each field appearing on its own line. The first field is the -; command-line switch with the leading "-" removed. All options -; beginning with "f" or "W" are implicitly assumed to take a "no-" -; form; this form should not be listed. If you do not want this -; negative form and you want it to be automatically rejected, add -; RejectNegative to the second field. - -; The second field is a space-separated list of which parts of the -; compiler recognize the switch, as declared by "Language" entries. -; If the switch takes an argument, then you should also specify -; "Joined" and/or "Separate" to indicate where the argument can -; appear. If a Joined argument can legitimately be omitted, specify -; "JoinedOrMissing" instead of "Joined". If the argument to a switch -; is a non-negative integer, you can specify "UInteger" and the switch -; decoder will convert the argument for you, or complain to the user -; if the argument is invalid. - -; The third field is the help text to output with --help. This is -; automatically line-wrapped on output. Normally the switch is output -; automatically, with the help text on the right hand side of the -; output. However, if the help text contains a tab character, the -; text to the left of the tab is output instead of the switch, and the -; text to its right forms the help. This is useful for elaborating on -; what type of argument a switch takes, for example. If the second -; field contains "Undocumented" then nothing is output with --help. -; Only do this with good reason like the switch being internal between -; the driver and the front end - it is not an excuse to leave a switch -; undocumented. - -; Comments can appear on their own line anwhere in the file, preceded -; by a semicolon. Whitespace is permitted before the semicolon. - -; For each switch XXX below, an enumeration constant is created by the -; script opts.sh spelt OPT_XXX, but with all non-alphanumeric -; characters replaced with an underscore. +; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +; 02110-1301, USA. + +; See the GCC internals manual for a description of this file's format. ; Please try to keep this file in ASCII collating order. @@ -165,6 +128,10 @@ Werror SDCPP Treat all warnings as errors +Wfatal-errors +SDCPP Var(flag_fatal_errors) +Exit on the first error occurred + Wimport SDCPP Deprecated. This switch has no effect. @@ -177,6 +144,10 @@ Wsystem-headers SDCPP Do not suppress warnings from system headers +Wtraditional +SDCPP Var(warn_traditional) +Warn about features not present in traditional C + Wtrigraphs SDCPP Warn if trigraphs are encountered that might affect the meaning of the program @@ -189,6 +160,10 @@ Wunused-macros SDCPP Warn about macros defined in the main file that are not used +Wvariadic-macros +SDCPP +Do not warn about using variadic macros when -pedantic + ansi SDCPP A synonym for -std=c89. @@ -263,6 +238,10 @@ isystem SDCPP Joined Separate -isystem Add to the start of the system include path +iquote +SDCPP Joined Separate +-iquote Add to the end of the quote include path + iwithprefix SDCPP Joined Separate -iwithprefix Add to the end of the system include path @@ -290,7 +269,7 @@ SDCPP Joined -obj-ext= Define object file extension, used for generation of make dependencies pedantic -SDCPP +SDCPP Var(pedantic) Issue warnings needed for strict compliance to the standard pedantic-errors @@ -337,8 +316,12 @@ v SDCPP Enable verbose output +;***version +;***SDCPP Var(version_flag) +;***Display the compiler's version + w -SDCPP +SDCPP Var(inhibit_warnings) Suppress warnings ; This comment is to ensure we retain the blank line above. diff --git a/support/cpp2/sdcppa.dsp b/support/cpp2/sdcppa.dsp index fc97e827..6d14bd0a 100644 --- a/support/cpp2/sdcppa.dsp +++ b/support/cpp2/sdcppa.dsp @@ -66,7 +66,7 @@ SOURCE=".\auto-host_vc_in.h" !IF "$(CFG)" == "sdcppa - Win32 Release" # Begin Custom Build -InputPath=.\auto-host_vc_in.h +InputPath=".\auto-host_vc_in.h" "auto-host.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" copy auto-host_vc_in.h auto-host.h > nul @@ -76,7 +76,7 @@ InputPath=.\auto-host_vc_in.h !ELSEIF "$(CFG)" == "sdcppa - Win32 Debug" # Begin Custom Build -InputPath=.\auto-host_vc_in.h +InputPath=".\auto-host_vc_in.h" "auto-host.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" copy auto-host_vc_in.h auto-host.h > nul @@ -88,53 +88,40 @@ InputPath=.\auto-host_vc_in.h # End Source File # Begin Source File -SOURCE=.\options_vc_in.c +SOURCE=.\sdcpp.opt !IF "$(CFG)" == "sdcppa - Win32 Release" # Begin Custom Build -InputPath=.\options_vc_in.c +InputPath=.\sdcpp.opt -"options.c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy options_vc_in.c options.c > nul - -# End Custom Build - -!ELSEIF "$(CFG)" == "sdcppa - Win32 Debug" - -# Begin Custom Build -InputPath=.\options_vc_in.c +BuildCmds= \ + gawk -f opt-gather.awk sdcpp.opt | gawk -f opt-functions.awk -f optc-gen.awk -v header_name="config.h system.h options.h" > options.c \ + gawk -f opt-gather.awk sdcpp.opt | gawk -f opt-functions.awk -f opth-gen.awk > options.h \ + "options.c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy options_vc_in.c options.c > nul - -# End Custom Build - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\options_vc_in.h - -!IF "$(CFG)" == "sdcppa - Win32 Release" - -# Begin Custom Build -InputPath=.\options_vc_in.h + $(BuildCmds) "options.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy options_vc_in.h options.h > nul - + $(BuildCmds) # End Custom Build !ELSEIF "$(CFG)" == "sdcppa - Win32 Debug" # Begin Custom Build -InputPath=.\options_vc_in.h +InputPath=.\sdcpp.opt -"options.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy options_vc_in.h options.h > nul +BuildCmds= \ + gawk -f opt-gather.awk sdcpp.opt | gawk -f opt-functions.awk -f optc-gen.awk -v header_name="config.h system.h options.h" > options.c \ + gawk -f opt-gather.awk sdcpp.opt | gawk -f opt-functions.awk -f opth-gen.awk > options.h \ + +"options.c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) + +"options.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) # End Custom Build !ENDIF diff --git a/support/cpp2/symcat.h b/support/cpp2/symcat.h index 61ce1e9b..03a12921 100644 --- a/support/cpp2/symcat.h +++ b/support/cpp2/symcat.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef SYM_CAT_H #define SYM_CAT_H diff --git a/support/cpp2/system.h b/support/cpp2/system.h deleted file mode 100644 index 7226e38b..00000000 --- a/support/cpp2/system.h +++ /dev/null @@ -1,676 +0,0 @@ -/* Get common system includes and various definitions and declarations based - on autoconf macros. - Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 - Free Software Foundation, Inc. - -This file is part of GCC. - -GCC 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 2, or (at your option) any later -version. - -GCC 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 GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ - - -#ifndef GCC_SYSTEM_H -#define GCC_SYSTEM_H - -/* We must include stdarg.h before stdio.h. */ -#include - -#ifndef va_copy -# ifdef __va_copy -# define va_copy(d,s) __va_copy((d),(s)) -# else -# define va_copy(d,s) ((d) = (s)) -# endif -#endif - -#ifdef HAVE_STDDEF_H -# include -#endif - -#include - -/* Define a generic NULL if one hasn't already been defined. */ -#ifndef NULL -#define NULL 0 -#endif - -/* The compiler is not a multi-threaded application and therefore we - do not have to use the locking functions. In fact, using the locking - functions can cause the compiler to be significantly slower under - I/O bound conditions (such as -g -O0 on very large source files). - - HAVE_DECL_PUTC_UNLOCKED actually indicates whether or not the stdio - code is multi-thread safe by default. If it is set to 0, then do - not worry about using the _unlocked functions. - - fputs_unlocked, fwrite_unlocked, and fprintf_unlocked are - extensions and need to be prototyped by hand (since we do not - define _GNU_SOURCE). */ - -#if defined HAVE_DECL_PUTC_UNLOCKED && HAVE_DECL_PUTC_UNLOCKED - -# ifdef HAVE_PUTC_UNLOCKED -# undef putc -# define putc(C, Stream) putc_unlocked (C, Stream) -# endif -# ifdef HAVE_FPUTC_UNLOCKED -# undef fputc -# define fputc(C, Stream) fputc_unlocked (C, Stream) -# endif - -# ifdef HAVE_FPUTS_UNLOCKED -# undef fputs -# define fputs(String, Stream) fputs_unlocked (String, Stream) -# if defined (HAVE_DECL_FPUTS_UNLOCKED) && !HAVE_DECL_FPUTS_UNLOCKED -extern int fputs_unlocked (const char *, FILE *); -# endif -# endif -# ifdef HAVE_FWRITE_UNLOCKED -# undef fwrite -# define fwrite(Ptr, Size, N, Stream) fwrite_unlocked (Ptr, Size, N, Stream) -# if defined (HAVE_DECL_FWRITE_UNLOCKED) && !HAVE_DECL_FWRITE_UNLOCKED -extern int fwrite_unlocked (const void *, size_t, size_t, FILE *); -# endif -# endif -# ifdef HAVE_FPRINTF_UNLOCKED -# undef fprintf -/* We can't use a function-like macro here because we don't know if - we have varargs macros. */ -# define fprintf fprintf_unlocked -# if defined (HAVE_DECL_FPRINTF_UNLOCKED) && !HAVE_DECL_FPRINTF_UNLOCKED -extern int fprintf_unlocked (FILE *, const char *, ...); -# endif -# endif - -#endif - -/* ??? Glibc's fwrite/fread_unlocked macros cause - "warning: signed and unsigned type in conditional expression". */ -#undef fread_unlocked -#undef fwrite_unlocked - -/* There are an extraordinary number of issues with . - The last straw is that it varies with the locale. Use libiberty's - replacement instead. */ -#if defined(__APPLE__) && defined(__MACH__) -#include -#else -#include -#endif - -#include - -#include - -#if !defined (errno) && defined (HAVE_DECL_ERRNO) && !HAVE_DECL_ERRNO -extern int errno; -#endif - -/* Some of glibc's string inlines cause warnings. Plus we'd rather - rely on (and therefore test) GCC's string builtins. */ -#define __NO_STRING_INLINES - -#ifdef STRING_WITH_STRINGS -# include -# include -#else -# ifdef HAVE_STRING_H -# include -# else -# ifdef HAVE_STRINGS_H -# include -# endif -# endif -#endif - -#ifdef HAVE_STDLIB_H -# include -#endif - -/* If we don't have an overriding definition, set SUCCESS_EXIT_CODE and - FATAL_EXIT_CODE to EXIT_SUCCESS and EXIT_FAILURE respectively, - or 0 and 1 if those macros are not defined. */ -#ifndef SUCCESS_EXIT_CODE -# ifdef EXIT_SUCCESS -# define SUCCESS_EXIT_CODE EXIT_SUCCESS -# else -# define SUCCESS_EXIT_CODE 0 -# endif -#endif - -#ifndef FATAL_EXIT_CODE -# ifdef EXIT_FAILURE -# define FATAL_EXIT_CODE EXIT_FAILURE -# else -# define FATAL_EXIT_CODE 1 -# endif -#endif - -#ifdef HAVE_UNISTD_H -# include -#endif - -#ifdef HAVE_SYS_PARAM_H -# include -/* We use this identifier later and it appears in some vendor param.h's. */ -# undef PREFETCH -#endif - -#if HAVE_LIMITS_H -# include -#endif - -/* Get definitions of HOST_WIDE_INT and HOST_WIDEST_INT. */ -#include "hwint.h" - -/* A macro to determine whether a VALUE lies inclusively within a - certain range without evaluating the VALUE more than once. This - macro won't warn if the VALUE is unsigned and the LOWER bound is - zero, as it would e.g. with "VALUE >= 0 && ...". Note the LOWER - bound *is* evaluated twice, and LOWER must not be greater than - UPPER. However the bounds themselves can be either positive or - negative. */ -#define IN_RANGE(VALUE, LOWER, UPPER) \ - ((unsigned HOST_WIDE_INT) ((VALUE) - (LOWER)) <= ((UPPER) - (LOWER))) - -/* Infrastructure for defining missing _MAX and _MIN macros. Note that - macros defined with these cannot be used in #if. */ - -/* The extra casts work around common compiler bugs. */ -#define INTTYPE_SIGNED(t) (! ((t) 0 < (t) -1)) -/* The outer cast is needed to work around a bug in Cray C 5.0.3.0. - It is necessary at least when t == time_t. */ -#define INTTYPE_MINIMUM(t) ((t) (INTTYPE_SIGNED (t) \ - ? ~ (t) 0 << (sizeof(t) * CHAR_BIT - 1) : (t) 0)) -#define INTTYPE_MAXIMUM(t) ((t) (~ (t) 0 - INTTYPE_MINIMUM (t))) - -/* Use that infrastructure to provide a few constants. */ -#ifndef UCHAR_MAX -# define UCHAR_MAX INTTYPE_MAXIMUM (unsigned char) -#endif - -#ifdef TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# ifdef HAVE_TIME_H -# include -# endif -# endif -#endif - -#ifdef HAVE_FCNTL_H -# include -#else -# ifdef HAVE_SYS_FILE_H -# include -# endif -#endif - -#ifndef SEEK_SET -# define SEEK_SET 0 -# define SEEK_CUR 1 -# define SEEK_END 2 -#endif -#ifndef F_OK -# define F_OK 0 -# define X_OK 1 -# define W_OK 2 -# define R_OK 4 -#endif -#ifndef O_RDONLY -# define O_RDONLY 0 -#endif -#ifndef O_WRONLY -# define O_WRONLY 1 -#endif - -/* Some systems define these in, e.g., param.h. We undefine these names - here to avoid the warnings. We prefer to use our definitions since we - know they are correct. */ - -#undef MIN -#undef MAX -#define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) -#define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) - -/* Returns the least number N such that N * Y >= X. */ -#define CEIL(x,y) (((x) + (y) - 1) / (y)) - -#ifdef HAVE_SYS_WAIT_H -#include -#endif - -#ifndef WIFSIGNALED -#define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f) -#endif -#ifndef WTERMSIG -#define WTERMSIG(S) ((S) & 0x7f) -#endif -#ifndef WIFEXITED -#define WIFEXITED(S) (((S) & 0xff) == 0) -#endif -#ifndef WEXITSTATUS -#define WEXITSTATUS(S) (((S) & 0xff00) >> 8) -#endif -#ifndef WSTOPSIG -#define WSTOPSIG WEXITSTATUS -#endif -#ifndef WCOREDUMP -#define WCOREDUMP(S) ((S) & WCOREFLG) -#endif -#ifndef WCOREFLG -#define WCOREFLG 0200 -#endif - -/* The HAVE_DECL_* macros are three-state, undefined, 0 or 1. If they - are defined to 0 then we must provide the relevant declaration - here. These checks will be in the undefined state while configure - is running so be careful to test "defined (HAVE_DECL_*)". */ - -#if defined (HAVE_DECL_ATOF) && !HAVE_DECL_ATOF -extern double atof (const char *); -#endif - -#if defined (HAVE_DECL_ATOL) && !HAVE_DECL_ATOL -extern long atol (const char *); -#endif - -#if defined (HAVE_DECL_FREE) && !HAVE_DECL_FREE -extern void free (void *); -#endif - -#if defined (HAVE_DECL_GETCWD) && !HAVE_DECL_GETCWD -extern char *getcwd (char *, size_t); -#endif - -#if defined (HAVE_DECL_GETENV) && !HAVE_DECL_GETENV -extern char *getenv (const char *); -#endif - -#if defined (HAVE_DECL_GETOPT) && !HAVE_DECL_GETOPT -extern int getopt (int, char * const *, const char *); -#endif - -#if defined (HAVE_DECL_GETWD) && !HAVE_DECL_GETWD -extern char *getwd (char *); -#endif - -#if defined (HAVE_DECL_SBRK) && !HAVE_DECL_SBRK -extern void *sbrk (int); -#endif - -#if defined (HAVE_DECL_STRSTR) && !HAVE_DECL_STRSTR -extern char *strstr (const char *, const char *); -#endif - -#ifdef HAVE_MALLOC_H -#include -#endif - -#if defined (HAVE_DECL_MALLOC) && !HAVE_DECL_MALLOC -extern void *malloc (size_t); -#endif - -#if defined (HAVE_DECL_CALLOC) && !HAVE_DECL_CALLOC -extern void *calloc (size_t, size_t); -#endif - -#if defined (HAVE_DECL_REALLOC) && !HAVE_DECL_REALLOC -extern void *realloc (void *, size_t); -#endif - -/* If the system doesn't provide strsignal, we get it defined in - libiberty but no declaration is supplied. */ -/* Disabled since it causes errors on solaris -#if !defined (HAVE_STRSIGNAL) \ - || (defined (HAVE_DECL_STRSIGNAL) && !HAVE_DECL_STRSIGNAL) -# ifndef strsignal -extern const char *strsignal (int); -# endif -#endif -*/ - -#ifdef HAVE_GETRLIMIT -# if defined (HAVE_DECL_GETRLIMIT) && !HAVE_DECL_GETRLIMIT -# ifndef getrlimit -struct rlimit; -extern int getrlimit (int, struct rlimit *); -# endif -# endif -#endif - -#ifdef HAVE_SETRLIMIT -# if defined (HAVE_DECL_SETRLIMIT) && !HAVE_DECL_SETRLIMIT -# ifndef setrlimit -struct rlimit; -extern int setrlimit (int, const struct rlimit *); -# endif -# endif -#endif - -#if defined (HAVE_DECL_ABORT) && !HAVE_DECL_ABORT -extern void abort (void); -#endif - -#if defined (HAVE_DECL_SNPRINTF) && !HAVE_DECL_SNPRINTF -extern int snprintf (char *, size_t, const char *, ...); -#endif - -/* 1 if we have C99 designated initializers. */ -#if !defined(HAVE_DESIGNATED_INITIALIZERS) -#if defined(__APPLE__) && (__MACH__) -#define HAVE_DESIGNATED_INITIALIZERS 0 -#else -#define HAVE_DESIGNATED_INITIALIZERS \ - ((GCC_VERSION >= 2007) || (__STDC_VERSION__ >= 199901L)) -#endif -#endif - -/* 1 if we have _Bool. */ -#ifndef HAVE__BOOL -# define HAVE__BOOL \ - ((GCC_VERSION >= 3000) || (__STDC_VERSION__ >= 199901L)) -#endif - - -#if HAVE_SYS_STAT_H -# include -#endif - -/* Test if something is a normal file. */ -#ifndef S_ISREG -#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) -#endif - -/* Test if something is a directory. */ -#ifndef S_ISDIR -#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#endif - -/* Test if something is a character special file. */ -#ifndef S_ISCHR -#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) -#endif - -/* Test if something is a block special file. */ -#ifndef S_ISBLK -#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) -#endif - -/* Test if something is a socket. */ -#ifndef S_ISSOCK -# ifdef S_IFSOCK -# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) -# else -# define S_ISSOCK(m) 0 -# endif -#endif - -/* Test if something is a FIFO. */ -#ifndef S_ISFIFO -# ifdef S_IFIFO -# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) -# else -# define S_ISFIFO(m) 0 -# endif -#endif - -/* Approximate O_NONBLOCK. */ -#ifndef O_NONBLOCK -#define O_NONBLOCK O_NDELAY -#endif - -/* Approximate O_NOCTTY. */ -#ifndef O_NOCTTY -#define O_NOCTTY 0 -#endif - -/* Define well known filenos if the system does not define them. */ -#ifndef STDIN_FILENO -# define STDIN_FILENO 0 -#endif -#ifndef STDOUT_FILENO -# define STDOUT_FILENO 1 -#endif -#ifndef STDERR_FILENO -# define STDERR_FILENO 2 -#endif - -/* Some systems have mkdir that takes a single argument. */ -#ifdef MKDIR_TAKES_ONE_ARG -# define mkdir(a,b) mkdir(a) -#endif - -/* Provide a way to print an address via printf. */ -#ifndef HOST_PTR_PRINTF -# ifdef HAVE_PRINTF_PTR -# define HOST_PTR_PRINTF "%p" -# elif SIZEOF_INT == SIZEOF_VOID_P -# define HOST_PTR_PRINTF "%x" -# elif SIZEOF_LONG == SIZEOF_VOID_P -# define HOST_PTR_PRINTF "%lx" -# else -# define HOST_PTR_PRINTF "%llx" -# endif -#endif /* ! HOST_PTR_PRINTF */ - -/* By default, colon separates directories in a path. */ -#ifndef PATH_SEPARATOR -#define PATH_SEPARATOR ':' -#endif - -/* Filename handling macros. */ -#include "filenames.h" - -/* These should be phased out in favor of IS_DIR_SEPARATOR, where possible. */ -#ifndef DIR_SEPARATOR -# define DIR_SEPARATOR '/' -# ifdef HAVE_DOS_BASED_FILE_SYSTEM -# define DIR_SEPARATOR_2 '\\' -# endif -#endif - -/* Get libiberty declarations. */ -#include "libiberty.h" - -/* Provide a default for the HOST_BIT_BUCKET. - This suffices for POSIX-like hosts. */ - -#ifndef HOST_BIT_BUCKET -#define HOST_BIT_BUCKET "/dev/null" -#endif - -/* Be conservative and only use enum bitfields with GCC. - FIXME: provide a complete autoconf test for buggy enum bitfields. */ - -#if (GCC_VERSION > 2000) -#define ENUM_BITFIELD(TYPE) __extension__ enum TYPE -#else -#define ENUM_BITFIELD(TYPE) unsigned int -#endif - -/* We only use bool bitfields with gcc3. Some supposedly C99 - compilers don't handle them correctly. */ -#if (GCC_VERSION >= 3000) -#define BOOL_BITFIELD _Bool -#else -#define BOOL_BITFIELD unsigned int -#endif - -#ifndef offsetof -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *) 0)->MEMBER) -#endif - -/* Various error reporting routines want to use __FUNCTION__. */ -#if (GCC_VERSION < 2007) -#ifndef __FUNCTION__ -#define __FUNCTION__ "?" -#endif /* ! __FUNCTION__ */ -#endif - -/* __builtin_expect(A, B) evaluates to A, but notifies the compiler that - the most likely value of A is B. This feature was added at some point - between 2.95 and 3.0. Let's use 3.0 as the lower bound for now. */ -#if (GCC_VERSION < 3000) -#define __builtin_expect(a, b) (a) -#endif - -/* Provide some sort of boolean type. We use stdbool.h if it's - available. This must be after all inclusion of system headers, - as some of them will mess us up. */ -#undef bool -#undef true -#undef false -#undef TRUE -#undef FALSE - -#ifdef HAVE_STDBOOL_H -# include -#else -# if !HAVE__BOOL -typedef char _Bool; -# endif -# define bool _Bool -# define true 1 -# define false 0 -#endif - -#define TRUE true -#define FALSE false - -/* As the last action in this file, we poison the identifiers that - shouldn't be used. Note, luckily gcc-3.0's token-based integrated - preprocessor won't trip on poisoned identifiers that arrive from - the expansion of macros. E.g. #define strrchr rindex, won't error - if rindex is poisoned after this directive is issued and later on - strrchr is called. - - Note: We define bypass macros for the few cases where we really - want to use the libc memory allocation routines. Otherwise we - insist you use the "x" versions from libiberty. */ - -#define really_call_malloc malloc -#define really_call_calloc calloc -#define really_call_realloc realloc - -#if defined(FLEX_SCANNER) || defined(YYBISON) || defined(YYBYACC) -/* Flex and bison use malloc and realloc. Yuk. Note that this means - really_call_* cannot be used in a .l or .y file. */ -#define malloc xmalloc -#define realloc xrealloc -#endif - -#if (GCC_VERSION >= 3000) - -/* Note autoconf checks for prototype declarations and includes - system.h while doing so. Only poison these tokens if actually - compiling gcc, so that the autoconf declaration tests for malloc - etc don't spuriously fail. */ -#ifdef IN_GCC -#undef calloc -#undef strdup - #pragma GCC poison calloc strdup - -#if !defined(FLEX_SCANNER) && !defined(YYBISON) -#undef malloc -#undef realloc - #pragma GCC poison malloc realloc -#endif - -/* Old target macros that have moved to the target hooks structure. */ - #pragma GCC poison ASM_OPEN_PAREN ASM_CLOSE_PAREN \ - FUNCTION_PROLOGUE FUNCTION_EPILOGUE \ - FUNCTION_END_PROLOGUE FUNCTION_BEGIN_EPILOGUE \ - DECL_MACHINE_ATTRIBUTES COMP_TYPE_ATTRIBUTES INSERT_ATTRIBUTES \ - VALID_MACHINE_DECL_ATTRIBUTE VALID_MACHINE_TYPE_ATTRIBUTE \ - SET_DEFAULT_TYPE_ATTRIBUTES SET_DEFAULT_DECL_ATTRIBUTES \ - MERGE_MACHINE_TYPE_ATTRIBUTES MERGE_MACHINE_DECL_ATTRIBUTES \ - MD_INIT_BUILTINS MD_EXPAND_BUILTIN ASM_OUTPUT_CONSTRUCTOR \ - ASM_OUTPUT_DESTRUCTOR SIGNED_CHAR_SPEC MAX_CHAR_TYPE_SIZE \ - WCHAR_UNSIGNED UNIQUE_SECTION SELECT_SECTION SELECT_RTX_SECTION \ - ENCODE_SECTION_INFO STRIP_NAME_ENCODING ASM_GLOBALIZE_LABEL \ - ASM_OUTPUT_MI_THUNK CONST_COSTS RTX_COSTS DEFAULT_RTX_COSTS \ - ADDRESS_COST MACHINE_DEPENDENT_REORG ASM_FILE_START ASM_FILE_END \ - ASM_SIMPLIFY_DWARF_ADDR INIT_TARGET_OPTABS INIT_SUBTARGET_OPTABS \ - INIT_GOFAST_OPTABS MULSI3_LIBCALL MULDI3_LIBCALL DIVSI3_LIBCALL \ - DIVDI3_LIBCALL UDIVSI3_LIBCALL UDIVDI3_LIBCALL MODSI3_LIBCALL \ - MODDI3_LIBCALL UMODSI3_LIBCALL UMODDI3_LIBCALL BUILD_VA_LIST_TYPE \ - PRETEND_OUTGOING_VARARGS_NAMED STRUCT_VALUE_INCOMING_REGNUM \ - SPLIT_COMPLEX_ARGS - -/* Other obsolete target macros, or macros that used to be in target - headers and were not used, and may be obsolete or may never have - been used. */ - #pragma GCC poison INT_ASM_OP ASM_OUTPUT_EH_REGION_BEG CPP_PREDEFINES \ - ASM_OUTPUT_EH_REGION_END ASM_OUTPUT_LABELREF_AS_INT SMALL_STACK \ - DOESNT_NEED_UNWINDER EH_TABLE_LOOKUP OBJC_SELECTORS_WITHOUT_LABELS \ - OMIT_EH_TABLE EASY_DIV_EXPR IMPLICIT_FIX_EXPR \ - LONGJMP_RESTORE_FROM_STACK MAX_INT_TYPE_SIZE ASM_IDENTIFY_GCC \ - STDC_VALUE TRAMPOLINE_ALIGN ASM_IDENTIFY_GCC_AFTER_SOURCE \ - SLOW_ZERO_EXTEND SUBREG_REGNO_OFFSET DWARF_LINE_MIN_INSTR_LENGTH \ - TRADITIONAL_RETURN_FLOAT NO_BUILTIN_SIZE_TYPE \ - NO_BUILTIN_PTRDIFF_TYPE NO_BUILTIN_WCHAR_TYPE NO_BUILTIN_WINT_TYPE \ - BLOCK_PROFILER BLOCK_PROFILER_CODE FUNCTION_BLOCK_PROFILER \ - FUNCTION_BLOCK_PROFILER_EXIT MACHINE_STATE_SAVE \ - MACHINE_STATE_RESTORE SCCS_DIRECTIVE SECTION_ASM_OP \ - ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL ASM_OUTPUT_INTERNAL_LABEL \ - OBJC_PROLOGUE ALLOCATE_TRAMPOLINE HANDLE_PRAGMA ROUND_TYPE_SIZE \ - ROUND_TYPE_SIZE_UNIT CONST_SECTION_ASM_OP CRT_GET_RFIB_TEXT \ - DBX_LBRAC_FIRST DBX_OUTPUT_ENUM DBX_OUTPUT_SOURCE_FILENAME \ - DBX_WORKING_DIRECTORY INSN_CACHE_DEPTH INSN_CACHE_SIZE \ - INSN_CACHE_LINE_WIDTH INIT_SECTION_PREAMBLE NEED_ATEXIT ON_EXIT \ - EXIT_BODY OBJECT_FORMAT_ROSE MULTIBYTE_CHARS MAP_CHARACTER \ - LIBGCC_NEEDS_DOUBLE FINAL_PRESCAN_LABEL DEFAULT_CALLER_SAVES \ - LOAD_ARGS_REVERSED MAX_INTEGER_COMPUTATION_MODE \ - CONVERT_HARD_REGISTER_TO_SSA_P ASM_OUTPUT_MAIN_SOURCE_FILENAME \ - FIRST_INSN_ADDRESS TEXT_SECTION SHARED_BSS_SECTION_ASM_OP \ - PROMOTED_MODE EXPAND_BUILTIN_VA_END \ - LINKER_DOES_NOT_WORK_WITH_DWARF2 - -/* Hooks that are no longer used. */ - #pragma GCC poison LANG_HOOKS_FUNCTION_MARK LANG_HOOKS_FUNCTION_FREE \ - LANG_HOOKS_MARK_TREE LANG_HOOKS_INSERT_DEFAULT_ATTRIBUTES - -/* Libiberty macros that are no longer used in GCC. */ -#undef ANSI_PROTOTYPES -#undef PTR_CONST -#undef LONG_DOUBLE -#undef VPARAMS -#undef VA_OPEN -#undef VA_FIXEDARG -#undef VA_CLOSE -#undef VA_START - #pragma GCC poison ANSI_PROTOTYPES PTR_CONST LONG_DOUBLE VPARAMS VA_OPEN \ - VA_FIXEDARG VA_CLOSE VA_START -#endif /* IN_GCC */ - -/* Note: not all uses of the `index' token (e.g. variable names and - structure members) have been eliminated. */ -#undef bcopy -#undef bzero -#undef bcmp -#undef rindex - #pragma GCC poison bcopy bzero bcmp rindex - -#endif /* GCC >= 3.0 */ - -/* SDCC specific */ -#include "sdcpp.h" - -#endif /* ! GCC_SYSTEM_H */ diff --git a/support/cpp2/version.c b/support/cpp2/version.c index 1918d696..661dce94 100644 --- a/support/cpp2/version.c +++ b/support/cpp2/version.c @@ -5,7 +5,7 @@ please modify this string to indicate that, e.g. by putting your organization's name in parentheses at the end of the string. */ -const char version_string[] = "3.4.6 + SDCC"; +const char version_string[] = "4.1.1 + SDCC"; /* This is the location of the online document giving instructions for reporting bugs. If you distribute a modified version of GCC,