diff options
| author | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
|---|---|---|
| committer | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
| commit | 268a53de823a6750d6256ee1fb1e7707b4b45740 (patch) | |
| tree | 42c1799a9a82b2f7d9790ee9fe181d72a7274751 /support/cpp/libcpp | |
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'support/cpp/libcpp')
| -rw-r--r-- | support/cpp/libcpp/charset.c | 1797 | ||||
| -rw-r--r-- | support/cpp/libcpp/directives.c | 2560 | ||||
| -rw-r--r-- | support/cpp/libcpp/errors.c | 238 | ||||
| -rw-r--r-- | support/cpp/libcpp/expr.c | 1793 | ||||
| -rw-r--r-- | support/cpp/libcpp/files.c | 1827 | ||||
| -rw-r--r-- | support/cpp/libcpp/identifiers.c | 121 | ||||
| -rw-r--r-- | support/cpp/libcpp/include/cpp-id-data.h | 81 | ||||
| -rw-r--r-- | support/cpp/libcpp/include/cpplib.h | 1012 | ||||
| -rw-r--r-- | support/cpp/libcpp/include/line-map.h | 193 | ||||
| -rw-r--r-- | support/cpp/libcpp/include/mkdeps.h | 80 | ||||
| -rw-r--r-- | support/cpp/libcpp/include/symtab.h | 104 | ||||
| -rw-r--r-- | support/cpp/libcpp/init.c | 721 | ||||
| -rw-r--r-- | support/cpp/libcpp/internal.h | 745 | ||||
| -rw-r--r-- | support/cpp/libcpp/lex.c | 2906 | ||||
| -rw-r--r-- | support/cpp/libcpp/line-map.c | 319 | ||||
| -rw-r--r-- | support/cpp/libcpp/macro.c | 2136 | ||||
| -rw-r--r-- | support/cpp/libcpp/mkdeps.c | 447 | ||||
| -rw-r--r-- | support/cpp/libcpp/symtab.c | 363 | ||||
| -rw-r--r-- | support/cpp/libcpp/system.h | 448 | ||||
| -rw-r--r-- | support/cpp/libcpp/traditional.c | 1170 | ||||
| -rw-r--r-- | support/cpp/libcpp/ucnid.h | 801 |
21 files changed, 19862 insertions, 0 deletions
diff --git a/support/cpp/libcpp/charset.c b/support/cpp/libcpp/charset.c new file mode 100644 index 0000000..cba19a6 --- /dev/null +++ b/support/cpp/libcpp/charset.c @@ -0,0 +1,1797 @@ +/* CPP Library - charsets + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006, 2008, 2009, + 2010 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 3, 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; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#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, 0x03, 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 + +#define CONVERT_ICONV_GROW_BUFFER \ + do { \ + outbytesleft += OUTBUF_BLOCK_SIZE; \ + to->asize += OUTBUF_BLOCK_SIZE; \ + to->text = XRESIZEVEC (uchar, to->text, to->asize); \ + outbuf = (char *)to->text + to->asize - outbytesleft; \ + } while (0) + +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)) + { + /* Close out any shift states, returning to the initial state. */ + if (iconv (cd, 0, 0, &outbuf, &outbytesleft) == (size_t)-1) + { + if (errno != E2BIG) + return false; + + CONVERT_ICONV_GROW_BUFFER; + if (iconv (cd, 0, 0, &outbuf, &outbytesleft) == (size_t)-1) + return false; + } + + to->len = to->asize - outbytesleft; + return true; + } + if (errno != E2BIG) + return false; + + CONVERT_ICONV_GROW_BUFFER; + } +} +#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; + ret.width = -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; + ret.width = -1; + return ret; + } + + /* No custom converter - try iconv. */ + if (HAVE_ICONV) + { + ret.func = convert_using_iconv; + ret.cd = iconv_open (to, from); + ret.width = -1; + + 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; + ret.width = -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->narrow_cset_desc.width = CPP_OPTION (pfile, char_precision); + pfile->utf8_cset_desc = init_iconv_desc (pfile, "UTF-8", SOURCE_CHARSET); + pfile->utf8_cset_desc.width = CPP_OPTION (pfile, char_precision); + pfile->char16_cset_desc = init_iconv_desc (pfile, + be ? "UTF-16BE" : "UTF-16LE", + SOURCE_CHARSET); + pfile->char16_cset_desc.width = 16; + pfile->char32_cset_desc = init_iconv_desc (pfile, + be ? "UTF-32BE" : "UTF-32LE", + SOURCE_CHARSET); + pfile->char32_cset_desc.width = 32; + pfile->wide_cset_desc = init_iconv_desc (pfile, wcset, SOURCE_CHARSET); + pfile->wide_cset_desc.width = CPP_OPTION (pfile, wchar_precision); +} + +/* 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->utf8_cset_desc.func == convert_using_iconv) + iconv_close (pfile->utf8_cset_desc.cd); + if (pfile->char16_cset_desc.func == convert_using_iconv) + iconv_close (pfile->char16_cset_desc.cd); + if (pfile->char32_cset_desc.func == convert_using_iconv) + iconv_close (pfile->char32_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 corresponds to a surrogate code point + (in the range 0xD800-0xDFFF, inclusive), the program is ill-formed. + Additionally, if the hexadecimal value for a universal-character-name + outside a character or string literal corresponds to a control character + (in either of the ranges 0x00-0x1F or 0x7F-0x9F, both inclusive) or to a + character in the basic source character set, the program is ill-formed. + + C99 6.4.3: A universal character name shall not specify a character + whose short identifier is less than 00A0 other than 0024 ($), 0040 (@), + or 0060 (`), nor one in the range D800 through DFFF inclusive. + + *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_warning (pfile, CPP_W_TRADITIONAL, + "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 C99 standard permits $, @ and ` to be specified as UCNs. We use + hex escapes so that this also works with EBCDIC hosts. + C++0x permits everything below 0xa0 within literals; + ucn_valid_in_identifier will complain about identifiers. */ + else if ((result < 0xa0 + && !CPP_OPTION (pfile, cplusplus) + && (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, struct cset_converter cvt) +{ + cppchar_t ucn; + uchar buf[6]; + uchar *bufp = buf; + size_t bytesleft = 6; + int rval; + 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, struct cset_converter cvt) +{ + size_t width = cvt.width; + + if (width != CPP_OPTION (pfile, char_precision)) + { + /* 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 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, struct cset_converter cvt) +{ + cppchar_t c, n = 0, overflow = 0; + int digits_found = 0; + size_t width = cvt.width; + size_t mask = width_to_mask (width); + + if (CPP_WTRADITIONAL (pfile)) + cpp_warning (pfile, CPP_W_TRADITIONAL, + "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, cvt); + + 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, struct cset_converter cvt) +{ + size_t count = 0; + cppchar_t c, n = 0; + size_t width = cvt.width; + 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, cvt); + + 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, struct cset_converter cvt) +{ + /* 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; + + c = *from; + switch (c) + { + /* UCNs, hex escapes, and octal escapes are processed separately. */ + case 'u': case 'U': + return convert_ucn (pfile, from, limit, tbuf, cvt); + + case 'x': + return convert_hex (pfile, from, limit, tbuf, cvt); + break; + + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + return convert_oct (pfile, from, limit, tbuf, cvt); + + /* 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_warning (pfile, CPP_W_TRADITIONAL, + "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; +} + +/* TYPE is a token type. The return value is the conversion needed to + convert from source to execution character set for the given type. */ +static struct cset_converter +converter_for_type (cpp_reader *pfile, enum cpp_ttype type) +{ + switch (type) + { + default: + return pfile->narrow_cset_desc; + case CPP_UTF8STRING: + return pfile->utf8_cset_desc; + case CPP_CHAR16: + case CPP_STRING16: + return pfile->char16_cset_desc; + case CPP_CHAR32: + case CPP_STRING32: + return pfile->char32_cset_desc; + case CPP_WCHAR: + case CPP_WSTRING: + return pfile->wide_cset_desc; + } +} + +/* 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, enum cpp_ttype type) +{ + struct _cpp_strbuf tbuf; + const uchar *p, *base, *limit; + size_t i; + struct cset_converter cvt = converter_for_type (pfile, type); + + 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 == 'u') + { + if (*++p == '8') + p++; + } + else if (*p == 'L' || *p == 'U') p++; + if (*p == 'R') + { + const uchar *prefix; + + /* Skip over 'R"'. */ + p += 2; + prefix = p; + while (*p != '(') + p++; + p++; + limit = from[i].text + from[i].len; + if (limit >= p + (p - prefix) + 1) + limit -= (p - prefix) + 1; + + /* Raw strings are all normal characters; these can be fed + directly to convert_cset. */ + if (!APPLY_CONVERSION (cvt, p, limit - p, &tbuf)) + goto fail; + + continue; + } + + 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, cvt); + } + } + /* NUL-terminate the 'to' buffer and translate it to a cpp_string + structure. */ + emit_numeric_escape (pfile, 0, &tbuf, cvt); + 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, + enum cpp_ttype type ATTRIBUTE_UNUSED) +{ + 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; + pfile->narrow_cset_desc.width = CPP_OPTION (pfile, char_precision); + + retval = cpp_interpret_string (pfile, from, count, to, CPP_STRING); + + 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_warning (pfile, CPP_W_MULTICHAR, "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. TYPE is the token type. */ +static cppchar_t +wide_str_to_charconst (cpp_reader *pfile, cpp_string str, + unsigned int *pchars_seen, int *unsignedp, + enum cpp_ttype type) +{ + bool bigend = CPP_OPTION (pfile, bytes_big_endian); + size_t width = converter_for_type (pfile, type).width; + 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 (str.len > nbwc * 2) + 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 (type == CPP_CHAR16 || type == CPP_CHAR32 + || CPP_OPTION (pfile, unsigned_wchar) + || !(result & (1 << (width - 1)))) + result &= mask; + else + result |= ~mask; + } + + if (type == CPP_CHAR16 || type == CPP_CHAR32 + || CPP_OPTION (pfile, unsigned_wchar)) + *unsignedp = 1; + else + *unsignedp = 0; + + *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_CHAR); + cppchar_t result; + + /* an empty constant will appear as L'', u'', U'' 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, token->type)) + return 0; + + if (wide) + result = wide_str_to_charconst (pfile, str, pchars_seen, unsignedp, + token->type); + 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, *ST_SIZE is set to the length of + the meaningful data within the translated buffer, and *BUFFER_START + is set to the start of the returned buffer. *BUFFER_START may + differ from the return value in the case of a BOM or other ignored + marker information. + + INPUT is expected to have been allocated with xmalloc. This + function will either set *BUFFER_START to INPUT, or free it and set + *BUFFER_START to 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, + const unsigned char **buffer_start, off_t *st_size) +{ + struct cset_converter input_cset; + struct _cpp_strbuf to; + unsigned char *buffer; + + 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.len && to.text[to.len - 1] == '\r') + to.text[to.len] = '\r'; + else + to.text[to.len] = '\n'; + + buffer = to.text; + *st_size = to.len; +#if HOST_CHARSET == HOST_CHARSET_ASCII + /* The HOST_CHARSET test just above ensures that the source charset + is UTF-8. So, ignore a UTF-8 BOM if we see one. Note that + glib'c UTF-8 iconv() provider (as of glibc 2.7) does not ignore a + BOM -- however, even if it did, we would still need this code due + to the 'convert_no_conversion' case. */ + if (to.len >= 3 && to.text[0] == 0xef && to.text[1] == 0xbb + && to.text[2] == 0xbf) + { + *st_size -= 3; + buffer += 3; + } +#endif + + *buffer_start = to.text; + return buffer; +} + +/* 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 <xyz> + 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/cpp/libcpp/directives.c b/support/cpp/libcpp/directives.c new file mode 100644 index 0000000..f244ae5 --- /dev/null +++ b/support/cpp/libcpp/directives.c @@ -0,0 +1,2560 @@ +/* CPP Library. (Directive handling.) + Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002, 2003, 2004, 2005, + 2007, 2008, 2009, 2010 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 3, 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; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#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; + linenum_type 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 is_internal; + bool is_deferred; + bool allow_expansion; + union { + pragma_cb handler; + struct pragma_entry *space; + unsigned int ident; + } 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) +#define DEPRECATED (1 << 5) + +/* 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 *, bool); +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 ***, + source_location *); +static void push_conditional (cpp_reader *, int, int, const cpp_hashnode *); +static unsigned int read_flag (cpp_reader *, unsigned int); +static bool strtolinenum (const uchar *, size_t, linenum_type *, bool *); +static void do_diagnostic (cpp_reader *, int, int, int); +static cpp_hashnode *lex_macro_node (cpp_reader *, bool); +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 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_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, source_location); +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); +static void do_pragma_push_macro (cpp_reader *); +static void do_pragma_pop_macro (cpp_reader *); +static void cpp_pop_definition (cpp_reader *, struct def_pragma_macro *); + +/* 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, #include_next, + and #import 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, DEPRECATED) /* 0 SVR4 */ \ +D(unassert, T_UNASSERT, EXTENSION, DEPRECATED) /* 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, UC"#", 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. If + EXPAND is true, tokens macro-expanding to nothing are allowed. */ +static void +check_eol (cpp_reader *pfile, bool expand) +{ + if (! SEEN_EOL () && (expand + ? cpp_get_token (pfile) + : _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. */ + if (!pfile->state.in_deferred_pragma) + pfile->state.prevent_expansion--; + + if (pfile->directive != &dtable[T_DEFINE]) + _cpp_remove_overlay (pfile); + } + else if (pfile->state.in_deferred_pragma) + ; + /* 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 or deprecated warnings for extensions. We let + -pedantic take precedence if both are applicable. */ + if (! pfile->state.skipping) + { + if (dir->origin == EXTENSION + && !(dir == &dtable[T_IMPORT] && CPP_OPTION (pfile, objc)) + && CPP_PEDANTIC (pfile)) + cpp_error (pfile, CPP_DL_PEDWARN, "#%s is a GCC extension", dir->name); + else if (((dir->flags & DEPRECATED) != 0 + || (dir == &dtable[T_IMPORT] && !CPP_OPTION (pfile, objc))) + && CPP_OPTION (pfile, cpp_warn_deprecated)) + cpp_warning (pfile, CPP_W_DEPRECATED, + "#%s is a deprecated 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_warning (pfile, CPP_W_TRADITIONAL, + "suggest not using #elif in traditional C"); + else if (indented && dir->origin == KANDR) + cpp_warning (pfile, CPP_W_TRADITIONAL, + "traditional C ignores #%s with the # indented", + dir->name); + else if (!indented && dir->origin != KANDR) + cpp_warning (pfile, CPP_W_TRADITIONAL, + "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, cpp_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.node->is_directive) + dir = &dtable[dname->val.node.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. + + We exclude the -fdirectives-only case because macro expansion + has not been performed yet, and block comments can cause spaces + to preceed the directive. */ + if (CPP_OPTION (pfile, preprocessed) + && !CPP_OPTION (pfile, directives_only) + && (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 && !pfile->state.in_deferred_pragma) + { + /* 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); + 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); + _cpp_pop_buffer (pfile); +} + +/* Checks for validity the macro name in #define, #undef, #ifdef and + #ifndef directives. IS_DEF_OR_UNDEF is true if this call is + processing a #define or #undefine directive, and false + otherwise. */ +static cpp_hashnode * +lex_macro_node (cpp_reader *pfile, bool is_def_or_undef) +{ + 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.node; + + if (is_def_or_undef && 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.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, true); + + 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 (pfile->cb.before_define) + pfile->cb.before_define (pfile); + + if (_cpp_create_definition (pfile, node)) + if (pfile->cb.define) + pfile->cb.define (pfile, pfile->directive_line, node); + + node->flags &= ~NODE_USED; + } +} + +/* 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, true); + + if (node) + { + if (pfile->cb.before_define) + pfile->cb.before_define (pfile); + + 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, false); +} + +/* 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|NODE_USED); + 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. LOCATION is the source location + of the file name. */ + +static const char * +parse_include (cpp_reader *pfile, int *pangle_brackets, + const cpp_token ***buf, source_location *location) +{ + char *fname; + const cpp_token *header; + + /* Allow macro expansion. */ + header = get_token_no_padding (pfile); + *location = header->src_loc; + if ((header->type == CPP_STRING && header->val.str.text[0] != 'R') + || 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 = UC"pragma dependency"; + else + dir = pfile->directive->name; + cpp_error (pfile, CPP_DL_ERROR, "#%s expects \"FILENAME\" or <FILENAME>", + dir); + + return NULL; + } + + if (pfile->directive == &dtable[T_PRAGMA]) + { + /* This pragma allows extra tokens after the file name. */ + } + else if (buf == NULL || CPP_OPTION (pfile, discard_comments)) + check_eol (pfile, true); + 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; + source_location location; + + /* 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, &location); + if (!fname) + { + if (buf) + XDELETEVEC (buf); + return; + } + + if (!*fname) + { + cpp_error_with_line (pfile, CPP_DL_ERROR, location, 0, + "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 (cpp_in_primary_file (pfile)) + { + 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 false if the + number was well-formed, true if not. WRAPPED is set to true if the + number did not fit into 'unsigned long'. */ +static bool +strtolinenum (const uchar *str, size_t len, linenum_type *nump, bool *wrapped) +{ + linenum_type reg = 0; + linenum_type reg_prev = 0; + + uchar c; + *wrapped = false; + while (len--) + { + c = *str++; + if (!ISDIGIT (c)) + return true; + reg *= 10; + reg += c - '0'; + if (reg < reg_prev) + *wrapped = true; + reg_prev = reg; + } + *nump = reg; + return false; +} + +/* 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; + linenum_type new_lineno; + + /* C99 raised the minimum limit on #line numbers. */ + linenum_type cap = CPP_OPTION (pfile, c99) ? 2147483647 : 32767; + bool wrapped; + + /* #line commands expand macros. */ + token = cpp_get_token (pfile); + if (token->type != CPP_NUMBER + || strtolinenum (token->val.str.text, token->val.str.len, + &new_lineno, &wrapped)) + { + if (token->type == CPP_EOF) + cpp_error (pfile, CPP_DL_ERROR, "unexpected end of file after #line"); + else + 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 || wrapped)) + cpp_error (pfile, CPP_DL_PEDWARN, "line number out of range"); + else if (wrapped) + cpp_error (pfile, CPP_DL_WARNING, "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, CPP_STRING)) + new_file = (const char *)s.text; + check_eol (pfile, true); + } + 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_VERBATIM, 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; + linenum_type new_lineno; + unsigned int new_sysp = map->sysp; + enum lc_reason reason = LC_RENAME_VERBATIM; + int flag; + bool wrapped; + + /* 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 + || strtolinenum (token->val.str.text, token->val.str.len, + &new_lineno, &wrapped)) + { + /* Unlike #line, there does not seem to be a way to get an EOF + here. So, it should be safe to always spell the token. */ + 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, CPP_STRING)) + 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, false); + } + 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); + + /* Compensate for the increment in linemap_add that occurs in + _cpp_do_file_change. We're currently at the start of the line + *following* the #line directive. A separate source_location for this + location makes no sense (until we do the LC_LEAVE), and + complicates LAST_SOURCE_LINE_LOCATION. */ + pfile->line_table->highest_location--; + + _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, linenum_type 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 reason, int print_dir) +{ + const unsigned char *dir_name; + unsigned char *line; + source_location src_loc = pfile->cur_token[-1].src_loc; + + if (print_dir) + dir_name = pfile->directive->name; + else + dir_name = NULL; + pfile->state.prevent_expansion++; + line = cpp_output_line_to_string (pfile, dir_name); + pfile->state.prevent_expansion--; + + if (code == CPP_DL_WARNING_SYSHDR && reason) + cpp_warning_with_line_syshdr (pfile, reason, src_loc, 0, "%s", line); + else if (code == CPP_DL_WARNING && reason) + cpp_warning_with_line (pfile, reason, src_loc, 0, "%s", line); + else + cpp_error_with_line (pfile, code, src_loc, 0, "%s", line); + free (line); +} + +static void +do_error (cpp_reader *pfile) +{ + do_diagnostic (pfile, CPP_DL_ERROR, 0, 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, CPP_W_WARNING_DIRECTIVE, 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, false); +} + +/* 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 blank pragma entry at the beginning of a + singly-linked CHAIN. */ +static struct pragma_entry * +new_pragma_entry (cpp_reader *pfile, struct pragma_entry **chain) +{ + struct pragma_entry *new_entry; + + new_entry = (struct pragma_entry *) + _cpp_aligned_alloc (pfile, sizeof (struct pragma_entry)); + + memset (new_entry, 0, sizeof (struct pragma_entry)); + 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. */ +static struct pragma_entry * +register_pragma_1 (cpp_reader *pfile, const char *space, const char *name, + bool allow_name_expansion) +{ + struct pragma_entry **chain = &pfile->pragmas; + struct pragma_entry *entry; + const cpp_hashnode *node; + + if (space) + { + node = cpp_lookup (pfile, UC space, strlen (space)); + entry = lookup_pragma_entry (*chain, node); + if (!entry) + { + entry = new_pragma_entry (pfile, chain); + entry->pragma = node; + entry->is_nspace = true; + entry->allow_expansion = allow_name_expansion; + } + else if (!entry->is_nspace) + goto clash; + else if (entry->allow_expansion != allow_name_expansion) + { + cpp_error (pfile, CPP_DL_ICE, + "registering pragmas in namespace \"%s\" with mismatched " + "name expansion", space); + return NULL; + } + chain = &entry->u.space; + } + else if (allow_name_expansion) + { + cpp_error (pfile, CPP_DL_ICE, + "registering pragma \"%s\" with name expansion " + "and no namespace", name); + return NULL; + } + + /* Check for duplicates. */ + node = cpp_lookup (pfile, UC name, strlen (name)); + entry = lookup_pragma_entry (*chain, node); + if (entry == NULL) + { + entry = new_pragma_entry (pfile, chain); + entry->pragma = node; + return 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); + + return NULL; +} + +/* Register a cpplib internal pragma SPACE NAME with HANDLER. */ +static void +register_pragma_internal (cpp_reader *pfile, const char *space, + const char *name, pragma_cb handler) +{ + struct pragma_entry *entry; + + entry = register_pragma_1 (pfile, space, name, false); + entry->is_internal = true; + entry->u.handler = handler; +} + +/* 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) +{ + struct pragma_entry *entry; + + if (!handler) + { + cpp_error (pfile, CPP_DL_ICE, "registering pragma with NULL handler"); + return; + } + + entry = register_pragma_1 (pfile, space, name, false); + if (entry) + { + entry->allow_expansion = allow_expansion; + entry->u.handler = handler; + } +} + +/* Similarly, but create mark the pragma for deferred processing. + When found, a CPP_PRAGMA token will be insertted into the stream + with IDENT in the token->u.pragma slot. */ +void +cpp_register_deferred_pragma (cpp_reader *pfile, const char *space, + const char *name, unsigned int ident, + bool allow_expansion, bool allow_name_expansion) +{ + struct pragma_entry *entry; + + entry = register_pragma_1 (pfile, space, name, allow_name_expansion); + if (entry) + { + entry->is_deferred = true; + entry->allow_expansion = allow_expansion; + entry->u.ident = ident; + } +} + +/* Register the pragmas the preprocessor itself handles. */ +void +_cpp_init_internal_pragmas (cpp_reader *pfile) +{ + /* Pragmas in the global namespace. */ + register_pragma_internal (pfile, 0, "once", do_pragma_once); + register_pragma_internal (pfile, 0, "push_macro", do_pragma_push_macro); + register_pragma_internal (pfile, 0, "pop_macro", do_pragma_pop_macro); + + /* New GCC-specific pragmas should be put in the GCC namespace. */ + register_pragma_internal (pfile, "GCC", "poison", do_pragma_poison); + register_pragma_internal (pfile, "GCC", "system_header", + do_pragma_system_header); + register_pragma_internal (pfile, "GCC", "dependency", do_pragma_dependency); +} + +/* 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, UC *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 allows for a mix of both, since GCC did not + traditionally macro expand its (few) pragmas, whereas OpenMP + specifies that macro expansion should happen. */ +static void +do_pragma (cpp_reader *pfile) +{ + const struct pragma_entry *p = NULL; + const cpp_token *token, *pragma_token = pfile->cur_token; + cpp_token ns_token; + unsigned int count = 1; + + pfile->state.prevent_expansion++; + + token = cpp_get_token (pfile); + ns_token = *token; + if (token->type == CPP_NAME) + { + p = lookup_pragma_entry (pfile->pragmas, token->val.node.node); + if (p && p->is_nspace) + { + bool allow_name_expansion = p->allow_expansion; + if (allow_name_expansion) + pfile->state.prevent_expansion--; + token = cpp_get_token (pfile); + if (token->type == CPP_NAME) + p = lookup_pragma_entry (p->u.space, token->val.node.node); + else + p = NULL; + if (allow_name_expansion) + pfile->state.prevent_expansion++; + count = 2; + } + } + + if (p) + { + if (p->is_deferred) + { + pfile->directive_result.src_loc = pragma_token->src_loc; + pfile->directive_result.type = CPP_PRAGMA; + pfile->directive_result.flags = pragma_token->flags; + pfile->directive_result.val.pragma = p->u.ident; + pfile->state.in_deferred_pragma = true; + pfile->state.pragma_allow_expansion = p->allow_expansion; + if (!p->allow_expansion) + pfile->state.prevent_expansion++; + } + else + { + /* 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); + if (p->allow_expansion) + pfile->state.prevent_expansion--; + (*p->u.handler) (pfile); + if (p->allow_expansion) + pfile->state.prevent_expansion++; + } + } + else if (pfile->cb.def_pragma) + { + if (count == 1 || pfile->context->prev == NULL) + _cpp_backup_tokens (pfile, count); + else + { + /* Invalid name comes from macro expansion, _cpp_backup_tokens + won't allow backing 2 tokens. */ + /* ??? The token buffer is leaked. Perhaps if def_pragma hook + reads both tokens, we could perhaps free it, but if it doesn't, + we don't know the exact lifespan. */ + cpp_token *toks = XNEWVEC (cpp_token, 2); + toks[0] = ns_token; + toks[0].flags |= NO_EXPAND; + toks[1] = *token; + toks[1].flags |= NO_EXPAND; + _cpp_push_token_context (pfile, NULL, toks, 2); + } + pfile->cb.def_pragma (pfile, pfile->directive_line); + } + + pfile->state.prevent_expansion--; +} + +/* Handle #pragma once. */ +static void +do_pragma_once (cpp_reader *pfile) +{ + if (cpp_in_primary_file (pfile)) + cpp_error (pfile, CPP_DL_WARNING, "#pragma once in main file"); + + check_eol (pfile, false); + _cpp_mark_file_once_only (pfile, pfile->buffer->file); +} + +/* Handle #pragma push_macro(STRING). */ +static void +do_pragma_push_macro (cpp_reader *pfile) +{ + cpp_hashnode *node; + size_t defnlen; + const uchar *defn = NULL; + char *macroname, *dest; + const char *limit, *src; + const cpp_token *txt; + struct def_pragma_macro *c; + + txt = get__Pragma_string (pfile); + if (!txt) + { + source_location src_loc = pfile->cur_token[-1].src_loc; + cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0, + "invalid #pragma push_macro directive"); + check_eol (pfile, false); + skip_rest_of_line (pfile); + return; + } + dest = macroname = (char *) alloca (txt->val.str.len + 2); + src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L')); + limit = (const char *) (txt->val.str.text + txt->val.str.len - 1); + while (src < limit) + { + /* We know there is a character following the backslash. */ + if (*src == '\\' && (src[1] == '\\' || src[1] == '"')) + src++; + *dest++ = *src++; + } + *dest = 0; + check_eol (pfile, false); + skip_rest_of_line (pfile); + c = XNEW (struct def_pragma_macro); + memset (c, 0, sizeof (struct def_pragma_macro)); + c->name = XNEWVAR (char, strlen (macroname) + 1); + strcpy (c->name, macroname); + c->next = pfile->pushed_macros; + node = _cpp_lex_identifier (pfile, c->name); + if (node->type == NT_VOID) + c->is_undef = 1; + else + { + defn = cpp_macro_definition (pfile, node); + defnlen = ustrlen (defn); + c->definition = XNEWVEC (uchar, defnlen + 2); + c->definition[defnlen] = '\n'; + c->definition[defnlen + 1] = 0; + c->line = node->value.macro->line; + c->syshdr = node->value.macro->syshdr; + c->used = node->value.macro->used; + memcpy (c->definition, defn, defnlen); + } + + pfile->pushed_macros = c; +} + +/* Handle #pragma pop_macro(STRING). */ +static void +do_pragma_pop_macro (cpp_reader *pfile) +{ + char *macroname, *dest; + const char *limit, *src; + const cpp_token *txt; + struct def_pragma_macro *l = NULL, *c = pfile->pushed_macros; + txt = get__Pragma_string (pfile); + if (!txt) + { + source_location src_loc = pfile->cur_token[-1].src_loc; + cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0, + "invalid #pragma pop_macro directive"); + check_eol (pfile, false); + skip_rest_of_line (pfile); + return; + } + dest = macroname = (char *) alloca (txt->val.str.len + 2); + src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L')); + limit = (const char *) (txt->val.str.text + txt->val.str.len - 1); + while (src < limit) + { + /* We know there is a character following the backslash. */ + if (*src == '\\' && (src[1] == '\\' || src[1] == '"')) + src++; + *dest++ = *src++; + } + *dest = 0; + check_eol (pfile, false); + skip_rest_of_line (pfile); + + while (c != NULL) + { + if (!strcmp (c->name, macroname)) + { + if (!l) + pfile->pushed_macros = c->next; + else + l->next = c->next; + cpp_pop_definition (pfile, c); + free (c->definition); + free (c->name); + free (c); + break; + } + l = c; + c = c->next; + } +} + +/* 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.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; +} + +/* 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) +{ + if (cpp_in_primary_file (pfile)) + cpp_error (pfile, CPP_DL_WARNING, + "#pragma system_header ignored outside include file"); + else + { + check_eol (pfile, false); + 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; + source_location location; + + fname = parse_include (pfile, &angle_brackets, NULL, &location); + 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, 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; + const cpp_token *paren; + + paren = get_token_no_padding (pfile); + if (paren->type == CPP_EOF) + _cpp_backup_tokens (pfile, 1); + if (paren->type != CPP_OPEN_PAREN) + return NULL; + + string = get_token_no_padding (pfile); + if (string->type == CPP_EOF) + _cpp_backup_tokens (pfile, 1); + if (string->type != CPP_STRING && string->type != CPP_WSTRING + && string->type != CPP_STRING32 && string->type != CPP_STRING16 + && string->type != CPP_UTF8STRING) + return NULL; + + paren = get_token_no_padding (pfile); + if (paren->type == CPP_EOF) + _cpp_backup_tokens (pfile, 1); + if (paren->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; + cpp_context *saved_context; + cpp_token *saved_cur_token; + tokenrun *saved_cur_run; + cpp_token *toks; + int count; + const struct directive *save_directive; + + 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. */ + saved_context = pfile->context; + saved_cur_token = pfile->cur_token; + saved_cur_run = pfile->cur_run; + + pfile->context = XNEW (cpp_context); + pfile->context->macro = 0; + pfile->context->prev = 0; + pfile->context->next = 0; + + /* Inline run_directive, since we need to delay the _cpp_pop_buffer + until we've read all of the tokens that we want. */ + cpp_push_buffer (pfile, (const uchar *) result, dest - result, + /* from_stage3 */ true); + /* ??? Antique Disgusting Hack. What does this do? */ + if (pfile->buffer->prev) + pfile->buffer->file = pfile->buffer->prev->file; + + start_directive (pfile); + _cpp_clean_line (pfile); + save_directive = pfile->directive; + pfile->directive = &dtable[T_PRAGMA]; + do_pragma (pfile); + end_directive (pfile, 1); + pfile->directive = save_directive; + + /* We always insert at least one token, the directive result. It'll + either be a CPP_PADDING or a CPP_PRAGMA. In the later case, we + need to insert *all* of the tokens, including the CPP_PRAGMA_EOL. */ + + /* If we're not handling the pragma internally, read all of the tokens from + the string buffer now, while the string buffer is still installed. */ + /* ??? Note that the token buffer allocated here is leaked. It's not clear + to me what the true lifespan of the tokens are. It would appear that + the lifespan is the entire parse of the main input stream, in which case + this may not be wrong. */ + if (pfile->directive_result.type == CPP_PRAGMA) + { + int maxcount; + + count = 1; + maxcount = 50; + toks = XNEWVEC (cpp_token, maxcount); + toks[0] = pfile->directive_result; + + do + { + if (count == maxcount) + { + maxcount = maxcount * 3 / 2; + toks = XRESIZEVEC (cpp_token, toks, maxcount); + } + toks[count] = *cpp_get_token (pfile); + /* Macros have been already expanded by cpp_get_token + if the pragma allowed expansion. */ + toks[count++].flags |= NO_EXPAND; + } + while (toks[count-1].type != CPP_PRAGMA_EOL); + } + else + { + count = 1; + toks = XNEW (cpp_token); + toks[0] = pfile->directive_result; + + /* If we handled the entire pragma internally, make sure we get the + line number correct for the next token. */ + if (pfile->cb.line_change) + pfile->cb.line_change (pfile, pfile->cur_token, false); + } + + /* Finish inlining run_directive. */ + pfile->buffer->file = NULL; + _cpp_pop_buffer (pfile); + + /* Reset the old macro state before ... */ + XDELETE (pfile->context); + pfile->context = saved_context; + pfile->cur_token = saved_cur_token; + pfile->cur_run = saved_cur_run; + + /* ... inserting the new tokens we collected. */ + _cpp_push_token_context (pfile, NULL, toks, count); +} + +/* Handle the _Pragma operator. Return 0 on error, 1 if ok. */ +int +_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); + return 1; + } + cpp_error (pfile, CPP_DL_ERROR, + "_Pragma takes a parenthesized string literal"); + return 0; +} + +/* Handle #ifdef. */ +static void +do_ifdef (cpp_reader *pfile) +{ + int skip = 1; + + if (! pfile->state.skipping) + { + cpp_hashnode *node = lex_macro_node (pfile, false); + + if (node) + { + /* Do not treat conditional macros as being defined. This is due to + the powerpc and spu ports using conditional macros for 'vector', + 'bool', and 'pixel' to act as conditional keywords. This messes + up tests like #ifndef bool. */ + skip = (node->type != NT_MACRO + || ((node->flags & NODE_CONDITIONAL) != 0)); + _cpp_mark_macro_used (node); + if (!(node->flags & NODE_USED)) + { + node->flags |= NODE_USED; + if (node->type == NT_MACRO) + { + if ((node->flags & NODE_BUILTIN) + && pfile->cb.user_builtin_macro) + pfile->cb.user_builtin_macro (pfile, node); + if (pfile->cb.used_define) + pfile->cb.used_define (pfile, pfile->directive_line, node); + } + else + { + if (pfile->cb.used_undef) + pfile->cb.used_undef (pfile, pfile->directive_line, node); + } + } + if (pfile->cb.used) + pfile->cb.used (pfile, pfile->directive_line, node); + check_eol (pfile, false); + } + } + + push_conditional (pfile, skip, T_IFDEF, 0); +} + +/* Handle #ifndef. */ +static void +do_ifndef (cpp_reader *pfile) +{ + int skip = 1; + cpp_hashnode *node = 0; + + if (! pfile->state.skipping) + { + node = lex_macro_node (pfile, false); + + if (node) + { + /* Do not treat conditional macros as being defined. This is due to + the powerpc and spu ports using conditional macros for 'vector', + 'bool', and 'pixel' to act as conditional keywords. This messes + up tests like #ifndef bool. */ + skip = (node->type == NT_MACRO + && ((node->flags & NODE_CONDITIONAL) == 0)); + _cpp_mark_macro_used (node); + if (!(node->flags & NODE_USED)) + { + node->flags |= NODE_USED; + if (node->type == NT_MACRO) + { + if ((node->flags & NODE_BUILTIN) + && pfile->cb.user_builtin_macro) + pfile->cb.user_builtin_macro (pfile, node); + if (pfile->cb.used_define) + pfile->cb.used_define (pfile, pfile->directive_line, node); + } + else + { + if (pfile->cb.used_undef) + pfile->cb.used_undef (pfile, pfile->directive_line, node); + } + } + if (pfile->cb.used) + pfile->cb.used (pfile, pfile->directive_line, node); + check_eol (pfile, false); + } + } + + 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, true) == 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, false); + } +} + +/* 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; + + if (! ifs->was_skipping) + { + bool value; + /* The standard mandates that the expression be parsed even + if we are skipping elses at this point -- the lexical + restrictions on #elif only apply to skipped groups, but + this group is not being skipped. Temporarily set + skipping to false to get lexer warnings. */ + pfile->state.skipping = 0; + value = _cpp_parse_expr (pfile, false); + if (ifs->skip_elses) + pfile->state.skipping = 1; + else + { + pfile->state.skipping = ! value; + ifs->skip_elses = value; + } + } + + /* 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, false); + + /* 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. PRED_LOC is the location of the + predicate. */ +static int +parse_answer (cpp_reader *pfile, struct answer **answerp, int type, + source_location pred_loc) +{ + 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_with_line (pfile, CPP_DL_ERROR, pred_loc, 0, + "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_with_line (pfile, CPP_DL_ERROR, predicate->src_loc, 0, + "predicate must be an identifier"); + else if (parse_answer (pfile, answerp, type, predicate->src_loc) == 0) + { + unsigned int len = NODE_LEN (predicate->val.node.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.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, false); + } +} + +/* 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, false); + } + 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; + const char *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); +} + + +/* Use to build macros to be run through cpp_define() as + described above. + Example: cpp_define_formatted (pfile, "MACRO=%d", value); */ + +void +cpp_define_formatted (cpp_reader *pfile, const char *fmt, ...) +{ + char *ptr = NULL; + + va_list ap; + va_start (ap, fmt); + vasprintf (&ptr, fmt, ap); + va_end (ap); + + cpp_define (pfile, ptr); + free (ptr); +} + + +/* 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); +} + +/* Replace a previous definition DEF of the macro STR. If DEF is NULL, + or first element is zero, then the macro should be undefined. */ +static void +cpp_pop_definition (cpp_reader *pfile, struct def_pragma_macro *c) +{ + cpp_hashnode *node = _cpp_lex_identifier (pfile, c->name); + if (node == NULL) + return; + + if (pfile->cb.before_define) + pfile->cb.before_define (pfile); + + if (node->type == NT_MACRO) + { + if (pfile->cb.undef) + pfile->cb.undef (pfile, pfile->directive_line, node); + if (CPP_OPTION (pfile, warn_unused_macros)) + _cpp_warn_if_unused_macro (pfile, node, NULL); + } + if (node->type != NT_VOID) + _cpp_free_definition (node); + + if (c->is_undef) + return; + { + size_t namelen; + const uchar *dn; + cpp_hashnode *h = NULL; + cpp_buffer *nbuf; + + namelen = ustrcspn (c->definition, "( \n"); + h = cpp_lookup (pfile, c->definition, namelen); + dn = c->definition + namelen; + + h->type = NT_VOID; + h->flags &= ~(NODE_POISONED|NODE_BUILTIN|NODE_DISABLED|NODE_USED); + nbuf = cpp_push_buffer (pfile, dn, ustrchr (dn, '\n') - dn, true); + if (nbuf != NULL) + { + _cpp_clean_line (pfile); + nbuf->sysp = 1; + if (!_cpp_create_definition (pfile, h)) + abort (); + _cpp_pop_buffer (pfile); + } + else + abort (); + h->value.macro->line = c->line; + h->value.macro->syshdr = c->syshdr; + h->value.macro->used = c->used; + } +} + +/* 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 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/cpp/libcpp/errors.c b/support/cpp/libcpp/errors.c new file mode 100644 index 0000000..c586749 --- /dev/null +++ b/support/cpp/libcpp/errors.c @@ -0,0 +1,238 @@ +/* Default error handlers for CPP Library. + Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1998, 1999, 2000, + 2001, 2002, 2004, 2008, 2009, 2010 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 3, 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; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. + + 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" + +/* Print a diagnostic at the location of the previously lexed token. */ + +ATTRIBUTE_FPTR_PRINTF(4,0) +static bool +cpp_diagnostic (cpp_reader * pfile, int level, int reason, + const char *msgid, va_list *ap) +{ + source_location src_loc; + bool ret; + + if (CPP_OPTION (pfile, traditional)) + { + if (pfile->state.in_directive) + src_loc = pfile->directive_line; + else + src_loc = pfile->line_table->highest_line; + } + /* We don't want to refer to a token before the beginning of the + current run -- that is invalid. */ + else if (pfile->cur_token == pfile->cur_run->base) + { + if (pfile->cur_run->prev != NULL) + src_loc = pfile->cur_run->prev->limit->src_loc; + else + src_loc = 0; + } + else + { + src_loc = pfile->cur_token[-1].src_loc; + } + + if (!pfile->cb.error) + abort (); + ret = pfile->cb.error (pfile, level, reason, src_loc, 0, _(msgid), ap); + + return ret; +} + +/* Print a warning or error, depending on the value of LEVEL. */ + +bool +cpp_error (cpp_reader * pfile, int level, const char *msgid, ...) +{ + va_list ap; + bool ret; + + va_start (ap, msgid); + + ret = cpp_diagnostic (pfile, level, CPP_W_NONE, msgid, &ap); + + va_end (ap); + return ret; +} + +/* Print a warning. The warning reason may be given in REASON. */ + +bool +cpp_warning (cpp_reader * pfile, int reason, const char *msgid, ...) +{ + va_list ap; + bool ret; + + va_start (ap, msgid); + + ret = cpp_diagnostic (pfile, CPP_DL_WARNING, reason, msgid, &ap); + + va_end (ap); + return ret; +} + +/* Print a pedantic warning. The warning reason may be given in REASON. */ + +bool +cpp_pedwarning (cpp_reader * pfile, int reason, const char *msgid, ...) +{ + va_list ap; + bool ret; + + va_start (ap, msgid); + + ret = cpp_diagnostic (pfile, CPP_DL_PEDWARN, reason, msgid, &ap); + + va_end (ap); + return ret; +} + +/* Print a warning, including system headers. The warning reason may be + given in REASON. */ + +bool +cpp_warning_syshdr (cpp_reader * pfile, int reason, const char *msgid, ...) +{ + va_list ap; + bool ret; + + va_start (ap, msgid); + + ret = cpp_diagnostic (pfile, CPP_DL_WARNING_SYSHDR, reason, msgid, &ap); + + va_end (ap); + return ret; +} + +/* Print a diagnostic at a specific location. */ + +ATTRIBUTE_FPTR_PRINTF(6,0) +static bool +cpp_diagnostic_with_line (cpp_reader * pfile, int level, int reason, + source_location src_loc, unsigned int column, + const char *msgid, va_list *ap) +{ + bool ret; + + if (!pfile->cb.error) + abort (); + ret = pfile->cb.error (pfile, level, reason, src_loc, column, _(msgid), ap); + + return ret; +} + +/* Print a warning or error, depending on the value of LEVEL. */ + +bool +cpp_error_with_line (cpp_reader *pfile, int level, + source_location src_loc, unsigned int column, + const char *msgid, ...) +{ + va_list ap; + bool ret; + + va_start (ap, msgid); + + ret = cpp_diagnostic_with_line (pfile, level, CPP_W_NONE, src_loc, + column, msgid, &ap); + + va_end (ap); + return ret; +} + +/* Print a warning. The warning reason may be given in REASON. */ + +bool +cpp_warning_with_line (cpp_reader *pfile, int reason, + source_location src_loc, unsigned int column, + const char *msgid, ...) +{ + va_list ap; + bool ret; + + va_start (ap, msgid); + + ret = cpp_diagnostic_with_line (pfile, CPP_DL_WARNING, reason, src_loc, + column, msgid, &ap); + + va_end (ap); + return ret; +} + +/* Print a pedantic warning. The warning reason may be given in REASON. */ + +bool +cpp_pedwarning_with_line (cpp_reader *pfile, int reason, + source_location src_loc, unsigned int column, + const char *msgid, ...) +{ + va_list ap; + bool ret; + + va_start (ap, msgid); + + ret = cpp_diagnostic_with_line (pfile, CPP_DL_PEDWARN, reason, src_loc, + column, msgid, &ap); + + va_end (ap); + return ret; +} + +/* Print a warning, including system headers. The warning reason may be + given in REASON. */ + +bool +cpp_warning_with_line_syshdr (cpp_reader *pfile, int reason, + source_location src_loc, unsigned int column, + const char *msgid, ...) +{ + va_list ap; + bool ret; + + va_start (ap, msgid); + + ret = cpp_diagnostic_with_line (pfile, CPP_DL_WARNING_SYSHDR, reason, src_loc, + column, msgid, &ap); + + va_end (ap); + return ret; +} + +/* Print a warning or error, depending on the value of LEVEL. Include + information from errno. */ + +bool +cpp_errno (cpp_reader *pfile, int level, const char *msgid) +{ + if (msgid[0] == '\0') + msgid = _("stdout"); + + return cpp_error (pfile, level, "%s: %s", msgid, xstrerror (errno)); +} diff --git a/support/cpp/libcpp/expr.c b/support/cpp/libcpp/expr.c new file mode 100644 index 0000000..d9bae17 --- /dev/null +++ b/support/cpp/libcpp/expr.c @@ -0,0 +1,1793 @@ +/* Parse C expressions for cpplib. + Copyright (C) 1987, 1992, 1994, 1995, 1997, 1998, 1999, 2000, 2001, + 2002, 2004, 2008, 2009, 2010 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 3, 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; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#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. */ + source_location loc; /* The location of this value. */ + 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, + source_location); +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 flags; + size_t f, d, l, w, q, i; + + flags = 0; + f = d = l = w = q = i = 0; + + /* Process decimal float suffixes, which are two letters starting + with d or D. Order and case are significant. */ + if (len == 2 && (*s == 'd' || *s == 'D')) + { + bool uppercase = (*s == 'D'); + switch (s[1]) + { + case 'f': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_SMALL): 0); break; + case 'F': return (uppercase ? (CPP_N_DFLOAT | CPP_N_SMALL) : 0); break; + case 'd': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_MEDIUM): 0); break; + case 'D': return (uppercase ? (CPP_N_DFLOAT | CPP_N_MEDIUM) : 0); break; + case 'l': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_LARGE) : 0); break; + case 'L': return (uppercase ? (CPP_N_DFLOAT | CPP_N_LARGE) : 0); break; + default: + /* Additional two-character suffixes beginning with D are not + for decimal float constants. */ + break; + } + } + + /* Recognize a fixed-point suffix. */ + switch (s[len-1]) + { + case 'k': case 'K': flags = CPP_N_ACCUM; break; + case 'r': case 'R': flags = CPP_N_FRACT; break; + default: break; + } + + /* Continue processing a fixed-point suffix. The suffix is case + insensitive except for ll or LL. Order is significant. */ + if (flags) + { + if (len == 1) + return flags; + len--; + + if (*s == 'u' || *s == 'U') + { + flags |= CPP_N_UNSIGNED; + if (len == 1) + return flags; + len--; + s++; + } + + switch (*s) + { + case 'h': case 'H': + if (len == 1) + return flags |= CPP_N_SMALL; + break; + case 'l': + if (len == 1) + return flags |= CPP_N_MEDIUM; + if (len == 2 && s[1] == 'l') + return flags |= CPP_N_LARGE; + break; + case 'L': + if (len == 1) + return flags |= CPP_N_MEDIUM; + if (len == 2 && s[1] == 'L') + return flags |= CPP_N_LARGE; + break; + default: + break; + } + /* Anything left at this point is invalid. */ + return 0; + } + + /* In any remaining valid suffix, the case and order don't matter. */ + while (len--) + switch (s[len]) + { + case 'f': case 'F': f++; break; + case 'd': case 'D': d++; break; + case 'l': case 'L': l++; break; + case 'w': case 'W': w++; break; + case 'q': case 'Q': q++; break; + case 'i': case 'I': + case 'j': case 'J': i++; break; + default: + return 0; + } + + if (f + d + l + w + q > 1 || i > 1) + return 0; + + return ((i ? CPP_N_IMAGINARY : 0) + | (f ? CPP_N_SMALL : + d ? CPP_N_MEDIUM : + l ? CPP_N_LARGE : + w ? CPP_N_MD_W : + q ? CPP_N_MD_Q : CPP_N_DEFAULT)); +} + +/* 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; + bool seen_digit; + + /* 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; + seen_digit = false; + + /* 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++; + } + else if ((*str == 'b' || *str == 'B') && (str[1] == '0' || str[1] == '1')) + { + radix = 2; + str++; + } + } + + /* Now scan for a well-formed integer or float. */ + for (;;) + { + unsigned int c = *str++; + + if (ISDIGIT (c) || (ISXDIGIT (c) && radix == 16)) + { + seen_digit = true; + 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; + } + } + + /* The suffix may be for decimal fixed-point constants without exponent. */ + if (radix != 16 && float_flag == NOT_FLOAT) + { + result = interpret_float_suffix (str, limit - str); + if ((result & CPP_N_FRACT) || (result & CPP_N_ACCUM)) + { + result |= CPP_N_FLOATING; + /* We need to restore the radix to 10, if the radix is 8. */ + if (radix == 8) + radix = 10; + + if (CPP_PEDANTIC (pfile)) + cpp_error (pfile, CPP_DL_PEDWARN, + "fixed-point constants are a GCC extension"); + goto syntax_ok; + } + else + result = 0; + } + + if (float_flag != NOT_FLOAT && radix == 8) + radix = 10; + + if (max_digit >= radix) + { + if (radix == 2) + SYNTAX_ERROR2 ("invalid digit \"%c\" in binary constant", '0' + max_digit); + else + SYNTAX_ERROR2 ("invalid digit \"%c\" in octal constant", '0' + max_digit); + } + + if (float_flag != NOT_FLOAT) + { + if (radix == 2) + { + cpp_error (pfile, CPP_DL_ERROR, + "invalid prefix \"0b\" for floating constant"); + return CPP_N_INVALID; + } + + if (radix == 16 && !seen_digit) + SYNTAX_ERROR ("no digits in hexadecimal floating constant"); + + 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_warning (pfile, CPP_W_TRADITIONAL, + "traditional C rejects the \"%.*s\" suffix", + (int) (limit - str), str); + + /* A suffix for double is a GCC extension via decimal float support. + If the suffix also specifies an imaginary value we'll catch that + later. */ + if ((result == CPP_N_MEDIUM) && CPP_PEDANTIC (pfile)) + cpp_error (pfile, CPP_DL_PEDWARN, + "suffix for double constant is a GCC extension"); + + /* Radix must be 10 for decimal floats. */ + if ((result & CPP_N_DFLOAT) && radix != 10) + { + cpp_error (pfile, CPP_DL_ERROR, + "invalid suffix \"%.*s\" with hexadecimal floating constant", + (int) (limit - str), str); + return CPP_N_INVALID; + } + + if ((result & (CPP_N_FRACT | CPP_N_ACCUM)) && CPP_PEDANTIC (pfile)) + cpp_error (pfile, CPP_DL_PEDWARN, + "fixed-point constants are a GCC extension"); + + if ((result & CPP_N_DFLOAT) && CPP_PEDANTIC (pfile)) + cpp_error (pfile, CPP_DL_PEDWARN, + "decimal float constants are a GCC extension"); + + 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 + && CPP_OPTION (pfile, cpp_warn_long_long); + + if (u_or_i || large) + cpp_warning (pfile, large ? CPP_W_LONG_LONG : CPP_W_TRADITIONAL, + "traditional C rejects the \"%.*s\" suffix", + (int) (limit - str), str); + } + + if ((result & CPP_N_WIDTH) == CPP_N_LARGE + && CPP_OPTION (pfile, cpp_warn_long_long)) + { + const char *message = CPP_OPTION (pfile, cplusplus) + ? N_("use of C++0x long long integer constant") + : N_("use of C99 long long integer constant"); + + if (CPP_OPTION (pfile, c99)) + cpp_warning (pfile, CPP_W_LONG_LONG, "%s", message); + else + cpp_pedwarning (pfile, CPP_W_LONG_LONG, "%s", message); + } + + result |= CPP_N_INTEGER; + } + + syntax_ok: + if ((result & CPP_N_IMAGINARY) && CPP_PEDANTIC (pfile)) + cpp_error (pfile, CPP_DL_PEDWARN, + "imaginary constants are a GCC extension"); + if (radix == 2 && CPP_PEDANTIC (pfile)) + cpp_error (pfile, CPP_DL_PEDWARN, + "binary constants are a GCC extension"); + + if (radix == 10) + result |= CPP_N_DECIMAL; + else if (radix == 16) + result |= CPP_N_HEX; + else if (radix == 2) + result |= CPP_N_BINARY; + 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; + } + else if ((type & CPP_N_RADIX) == CPP_N_BINARY) + { + base = 2; + 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)) + { + /* This is for constants within the range of uintmax_t but + not that of intmax_t. For such decimal constants, a + diagnostic is required for C99 as the selected type must + be signed and not having a type is a constraint violation + (DR#298, TC3), so this must be a pedwarn. For C90, + unsigned long is specified to be used for a constant that + does not fit in signed long; if uintmax_t has the same + range as unsigned long this means only a warning is + appropriate here. C90 permits the preprocessor to use a + wider range than unsigned long in the compiler, so if + uintmax_t is wider than unsigned long no diagnostic is + required for such constants in preprocessor #if + expressions and the compiler will pedwarn for such + constants outside the range of unsigned long that reach + the compiler so a diagnostic is not required there + either; thus, pedwarn for C99 but use a plain warning for + C90. */ + if (base == 10) + cpp_error (pfile, (CPP_OPTION (pfile, c99) + ? CPP_DL_PEDWARN + : 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; + bool overflow; + cpp_num_part add_high, add_low; + + /* Multiply by 2, 8 or 16. Catching this overflow here means we don't + need to worry about add_high overflowing. */ + switch (base) + { + case 2: + shift = 1; + break; + + case 16: + shift = 4; + break; + + default: + shift = 3; + } + 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.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); + if (!(node->flags & NODE_USED)) + { + node->flags |= NODE_USED; + if (node->type == NT_MACRO) + { + if ((node->flags & NODE_BUILTIN) + && pfile->cb.user_builtin_macro) + pfile->cb.user_builtin_macro (pfile, node); + if (pfile->cb.used_define) + pfile->cb.used_define (pfile, pfile->directive_line, node); + } + else + { + if (pfile->cb.used_undef) + pfile->cb.used_undef (pfile, pfile->directive_line, 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--; + + /* Do not treat conditional macros as being defined. This is due to the + powerpc and spu ports using conditional macros for 'vector', 'bool', and + 'pixel' to act as conditional keywords. This messes up tests like #ifndef + bool. */ + result.unsignedp = false; + result.high = 0; + result.overflow = false; + result.low = (node && node->type == NT_MACRO + && (node->flags & NODE_CONDITIONAL) == 0); + 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: + case CPP_CHAR16: + case CPP_CHAR32: + { + 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.node == pfile->spec_nodes.n_defined) + return parse_defined (pfile); + else if (CPP_OPTION (pfile, cplusplus) + && (token->val.node.node == pfile->spec_nodes.n_true + || token->val.node.node == pfile->spec_nodes.n_false)) + { + result.high = 0; + result.low = (token->val.node.node == pfile->spec_nodes.n_true); + } + else + { + result.high = 0; + result.low = 0; + if (CPP_OPTION (pfile, warn_undef) && !pfile->state.skip_eval) + cpp_warning (pfile, CPP_W_UNDEF, "\"%s\" is not defined", + NODE_NAME (token->val.node.node)); + } + break; + + case CPP_HASH: + if (!pfile->state.skipping) + { + /* A pedantic warning takes precedence over a deprecated + warning here. */ + if (CPP_PEDANTIC (pfile)) + cpp_error (pfile, CPP_DL_PEDWARN, + "assertions are a GCC extension"); + else if (CPP_OPTION (pfile, cpp_warn_deprecated)) + cpp_warning (pfile, CPP_W_DEPRECATED, + "assertions are a deprecated extension"); + } + _cpp_test_assertion (pfile, &temp); + result.high = 0; + result.low = temp; + break; + + default: + abort (); + } + + 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}, + + /* COMPL */ {16, NO_L_OPERAND}, + /* AND_AND */ {6, LEFT_ASSOC}, + /* OR_OR */ {5, LEFT_ASSOC}, + /* Note that QUERY, COLON, and COMMA must have the same precedence. + However, there are some special cases for these in reduce(). */ + /* QUERY */ {4, 0}, + /* COLON */ {4, LEFT_ASSOC | CHECK_PROMOTION}, + /* COMMA */ {4, 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, bool is_if) +{ + 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; + op.loc = op.token->src_loc; + + switch (op.op) + { + /* These tokens convert into values. */ + case CPP_NUMBER: + case CPP_CHAR: + case CPP_WCHAR: + case CPP_CHAR16: + case CPP_CHAR32: + 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_ERROR2 ("%s with no expression", is_if ? "#if" : "#elif"); + + 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; + top->loc = op.token->src_loc; + } + + /* The controlling macro expression is only valid if we called lex 3 + times: <!> <defined expression> and <EOF>. 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 %s", + is_if ? "#if" : "#elif"); + 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); + top[-1].loc = top->loc; + break; + + case CPP_PLUS: + case CPP_MINUS: + case CPP_RSHIFT: + case CPP_LSHIFT: + case CPP_COMMA: + top[-1].value = num_binary_op (pfile, top[-1].value, + top->value, top->op); + top[-1].loc = top->loc; + 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); + top[-1].loc = top->loc; + break; + + case CPP_EQ_EQ: + case CPP_NOT_EQ: + top[-1].value + = num_equality_op (pfile, top[-1].value, top->value, top->op); + top[-1].loc = top->loc; + break; + + case CPP_AND: + case CPP_OR: + case CPP_XOR: + top[-1].value + = num_bitwise_op (pfile, top[-1].value, top->value, top->op); + top[-1].loc = top->loc; + break; + + case CPP_MULT: + top[-1].value = num_mul (pfile, top[-1].value, top->value); + top[-1].loc = top->loc; + break; + + case CPP_DIV: + case CPP_MOD: + top[-1].value = num_div_op (pfile, top[-1].value, + top->value, top->op, top->loc); + top[-1].loc = top->loc; + 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; + top->loc = top[1].loc; + 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; + top->loc = top[1].loc; + continue; + + case CPP_OPEN_PAREN: + if (op != CPP_CLOSE_PAREN) + { + cpp_error_with_line (pfile, CPP_DL_ERROR, + top->token->src_loc, + 0, "missing ')' in expression"); + return 0; + } + top--; + top->value = top[1].value; + top->loc = top[1].loc; + return top; + + case CPP_COLON: + top -= 2; + if (!num_zerop (top->value)) + { + pfile->state.skip_eval--; + top->value = top[1].value; + top->loc = top[1].loc; + } + else + { + top->value = top[2].value; + top->loc = top[2].loc; + } + top->value.unsignedp = (top[1].value.unsignedp + || top[2].value.unsignedp); + continue; + + case CPP_QUERY: + /* COMMA and COLON should not reduce a QUERY operator. */ + if (op == CPP_COMMA || op == CPP_COLON) + return top; + 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_with_line (pfile, CPP_DL_WARNING, op[-1].loc, 0, + "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_with_line (pfile, CPP_DL_WARNING, op->loc, 0, + "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_warning (pfile, CPP_W_TRADITIONAL, + "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); + 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; + + /* 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, LHS and RHS, returning the answer + or the remainder depending upon OP. LOCATION is the source location + of this operator (for diagnostics). */ + +static cpp_num +num_div_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op, + source_location location) +{ + 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_with_line (pfile, CPP_DL_ERROR, location, 0, + "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 + && !num_zerop (result)); + } + + return result; + } + + /* CPP_MOD. */ + lhs.unsignedp = unsignedp; + lhs.overflow = false; + if (lhs_neg) + lhs = num_negate (lhs, precision); + + return lhs; +} diff --git a/support/cpp/libcpp/files.c b/support/cpp/libcpp/files.c new file mode 100644 index 0000000..6484be5 --- /dev/null +++ b/support/cpp/libcpp/files.c @@ -0,0 +1,1827 @@ +/* Part of CPP library. File handling. + Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1998, + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 + 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 3, 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; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "cpplib.h" +#include "internal.h" +#include "mkdeps.h" +#include "obstack.h" +#include "hashtab.h" +#include "md5.h" +#include <dirent.h> + +/* 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 <io.h> + /* 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; + + /* Pointer to the real start of BUFFER. read_file() might increment + BUFFER; when freeing, this this pointer must be used instead. */ + const uchar *buffer_start; + + /* 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; +}; + +/* 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; + source_location location; + union + { + _cpp_file *file; + cpp_dir *dir; + } u; +}; + +/* Number of entries to put in a file_hash_entry pool. */ +#define FILE_HASH_POOL_SIZE 127 + +/* A file hash entry pool. We allocate file_hash_entry object from + one of these. */ +struct file_hash_entry_pool +{ + /* Number of entries used from this pool. */ + unsigned int file_hash_entries_used; + /* Next pool in the chain; used when freeing. */ + struct file_hash_entry_pool *next; + /* The memory pool. */ + struct file_hash_entry pool[FILE_HASH_POOL_SIZE]; +}; + +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 <stdin>, 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; + } +#if defined(_WIN32) && !defined(__CYGWIN__) + else if (errno == EACCES) + { + /* On most UNIX systems, open succeeds on a directory. Above, + we check if we have opened a directory and if so, set errno + to ENOENT. However, on Windows, opening a directory + fails with EACCES. We want to return ENOENT in that + case too. */ + if (stat (file->path, &file->st) == 0 + && S_ISDIR (file->st.st_mode)) + errno = ENOENT; + else + /* The call to stat may have reset errno. */ + errno = EACCES; + } +#endif + 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 <stdin> or if not requested. */ + if (file->name[0] == '\0' || !pfile->cb.valid_pch) + return false; + + /* If the file is not included as first include from either the toplevel + file or the command-line it is not a valid use of PCH. */ + if (pfile->all_files + && pfile->all_files->next_file) + 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) + *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) + { + hashval_t hv = htab_hash_string (path); + char *copy; + void **pp; + + if (htab_find_with_hash (pfile->nonexistent_file_hash, path, hv) != NULL) + { + file->err_no = ENOENT; + return false; + } + + 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; + } + + /* We copy the path name onto an obstack partly so that we don't + leak the memory, but mostly so that we don't fragment the + heap. */ + copy = (char *) obstack_copy0 (&pfile->nonexistent_file_ob, path, + strlen (path)); + free (path); + pp = htab_find_slot_with_hash (pfile->nonexistent_file_hash, + copy, hv, INSERT); + *pp = copy; + + 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; + bool saw_bracket_include = false; + bool saw_quote_include = false; + struct cpp_dir *found_in_cache = NULL; + + /* 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; + } + + 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"); + } + open_file_failed (pfile, file, angle_brackets); + 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) + saw_bracket_include = true; + else if (file->dir == pfile->quote_include) + saw_quote_include = true; + else + continue; + + entry = search_cache (*hash_slot, file->dir); + if (entry) + { + found_in_cache = file->dir; + 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->location = pfile->line_table->highest_location; + entry->u.file = file; + *hash_slot = entry; + + /* If we passed the quote or bracket chain heads, cache them also. + This speeds up processing if there are lots of -I options. */ + if (saw_bracket_include + && pfile->bracket_include != start_dir + && found_in_cache != pfile->bracket_include) + { + entry = new_file_hash_entry (pfile); + entry->next = *hash_slot; + entry->start_dir = pfile->bracket_include; + entry->location = pfile->line_table->highest_location; + entry->u.file = file; + *hash_slot = entry; + } + if (saw_quote_include + && pfile->quote_include != start_dir + && found_in_cache != pfile->quote_include) + { + entry = new_file_hash_entry (pfile); + entry->next = *hash_slot; + entry->start_dir = pfile->quote_include; + entry->location = pfile->line_table->highest_location; + 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. */ + if (file->st.st_size > INTTYPE_MAXIMUM (ssize_t)) + { + cpp_error (pfile, CPP_DL_ERROR, "%s is too large", file->path); + return false; + } + + 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; + } + + if (regular && total != size && STAT_SIZE_RELIABLE (file->st)) + cpp_error (pfile, CPP_DL_WARNING, + "%s is shorter than expected", file->path); + + file->buffer = _cpp_convert_input (pfile, + CPP_OPTION (pfile, input_charset), + buf, size, total, + &file->buffer_start, + &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->pchname) + { + pfile->cb.read_pch (pfile, file->pchname, file->fd, file->path); + file->fd = -1; + free ((void *) file->pchname); + file->pchname = NULL; + 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) + && !CPP_OPTION (pfile, directives_only)); + 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 + && file->dir != &pfile->no_search_path) + 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 + <stdin>, 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 that occurs in + _cpp_stack_file. 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->pchname == NULL && 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); + /* If the preprocessor output (other than dependency information) is + being used, we must also flag an error. */ + if (CPP_OPTION (pfile, deps.need_preprocessor_output)) + cpp_errno (pfile, CPP_DL_FATAL, file->path); + } + else + { + /* If we are not outputting dependencies, or if we are and dependencies + were requested for this file, or if preprocessor output is needed + in addition to dependency information, this is an error. + + Otherwise (outputting dependencies but not for this file, and not + using the preprocessor output), we can still produce correct output + so it's only a warning. */ + if (CPP_OPTION (pfile, deps.style) == DEPS_NONE + || print_dep + || CPP_OPTION (pfile, deps.need_preprocessor_output)) + cpp_errno (pfile, CPP_DL_FATAL, file->path); + else + cpp_errno (pfile, CPP_DL_WARNING, 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_start) + free ((void *) file->buffer_start); + free ((void *) file->name); + free (file); +} + +/* Release all the files allocated by this reader. */ +static void +destroy_all_cpp_files (cpp_reader *pfile) +{ + _cpp_file *iter = pfile->all_files; + while (iter) + { + _cpp_file *next = iter->next_file; + destroy_cpp_file (iter); + iter = next; + } +} + +/* 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->location = pfile->line_table->highest_location; + 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) +{ + struct file_hash_entry_pool *pool = XNEW (struct file_hash_entry_pool); + pool->file_hash_entries_used = 0; + pool->next = pfile->file_hash_entries; + pfile->file_hash_entries = pool; +} + +/* Return a new file hash entry. */ +static struct file_hash_entry * +new_file_hash_entry (cpp_reader *pfile) +{ + unsigned int idx; + if (pfile->file_hash_entries->file_hash_entries_used == FILE_HASH_POOL_SIZE) + allocate_file_hash_entries (pfile); + + idx = pfile->file_hash_entries->file_hash_entries_used++; + return &pfile->file_hash_entries->pool[idx]; +} + +/* Free the file hash entry pools. */ +static void +free_file_hash_entries (cpp_reader *pfile) +{ + struct file_hash_entry_pool *iter = pfile->file_hash_entries; + while (iter) + { + struct file_hash_entry_pool *next = iter->next; + free (iter); + iter = next; + } +} + +/* 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; +} + +/* Returns TRUE if a file FNAME has ever been successfully opened + before LOCATION. This routine is not intended to correctly handle + filenames aliased by links or redundant . or .. traversals etc. */ +bool +cpp_included_before (cpp_reader *pfile, const char *fname, + source_location location) +{ + 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->location > location)) + 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; +} + +/* Compare entries in the nonexistent file hash table. These are just + strings. */ +static int +nonexistent_file_hash_eq (const void *p, const void *q) +{ + return strcmp ((const char *) p, (const char *) q) == 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); + pfile->nonexistent_file_hash = htab_create_alloc (127, htab_hash_string, + nonexistent_file_hash_eq, + NULL, xcalloc, free); + _obstack_begin (&pfile->nonexistent_file_ob, 0, 0, + (void *(*) (size_t)) xmalloc, + (void (*) (void *)) free); +} + +/* Finalize everything in this source file. */ +void +_cpp_cleanup_files (cpp_reader *pfile) +{ + htab_delete (pfile->file_hash); + htab_delete (pfile->dir_hash); + htab_delete (pfile->nonexistent_file_hash); + obstack_free (&pfile->nonexistent_file_ob, 0); + free_file_hash_entries (pfile); + destroy_all_cpp_files (pfile); +} + +/* Make the parser forget about files it has seen. This can be useful + for resetting the parser to start another run. */ +void +cpp_clear_file_cache (cpp_reader *pfile) +{ + _cpp_cleanup_files (pfile); + pfile->file_hash_entries = NULL; + pfile->all_files = NULL; + _cpp_init_files (pfile); +} + +/* 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 <built-in>. + 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); +} + +struct report_missing_guard_data +{ + const char **paths; + size_t count; +}; + +/* Callback function for htab_traverse. */ +static int +report_missing_guard (void **slot, void *d) +{ + struct file_hash_entry *entry = (struct file_hash_entry *) *slot; + struct report_missing_guard_data *data + = (struct report_missing_guard_data *) d; + + /* 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->once_only && file->cmacro == NULL + && file->stack_count == 1 && !file->main_file) + { + if (data->paths == NULL) + { + data->paths = XCNEWVEC (const char *, data->count); + data->count = 0; + } + + data->paths[data->count++] = file->path; + } + } + + /* Keep traversing the hash table. */ + return 1; +} + +/* Comparison function for qsort. */ +static int +report_missing_guard_cmp (const void *p1, const void *p2) +{ + return strcmp (*(const char *const *) p1, *(const char *const *) p2); +} + +/* Report on all files that might benefit from a multiple include guard. + Triggered by -H. */ +void +_cpp_report_missing_guards (cpp_reader *pfile) +{ + struct report_missing_guard_data data; + + data.paths = NULL; + data.count = htab_elements (pfile->file_hash); + htab_traverse (pfile->file_hash, report_missing_guard, &data); + + if (data.paths != NULL) + { + size_t i; + + /* Sort the paths to avoid outputting them in hash table + order. */ + qsort (data.paths, data.count, sizeof (const char *), + report_missing_guard_cmp); + fputs (_("Multiple include guards may be useful for:\n"), + stderr); + for (i = 0; i < data.count; i++) + { + fputs (data.paths[i], stderr); + putc ('\n', stderr); + } + free (data.paths); + } +} + +/* 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_start) + { + free ((void *) file->buffer_start); + file->buffer_start = NULL; + file->buffer = NULL; + file->buffer_valid = false; + } +} + +/* Inteface to file statistics record in _cpp_file structure. */ +struct stat * +_cpp_get_file_stat (_cpp_file *file) +{ + return &file->st; +} + +/* 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/cpp/libcpp/identifiers.c b/support/cpp/libcpp/identifiers.c new file mode 100644 index 0000000..67378df --- /dev/null +++ b/support/cpp/libcpp/identifiers.c @@ -0,0 +1,121 @@ +/* Hash tables for the CPP library. + Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998, + 1999, 2000, 2001, 2002, 2007, 2009 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 3, 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; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. + + 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 hashnode alloc_node (hash_table *); + +/* Return an identifier node for hashtable.c. Used by cpplib except + when integrated with the C front ends. */ +static hashnode +alloc_node (hash_table *table) +{ + cpp_hashnode *node; + + node = XOBNEW (&table->pfile->hash_ob, cpp_hashnode); + memset (node, 0, sizeof (cpp_hashnode)); + return HT_NODE (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 = alloc_node; + + _obstack_begin (&pfile->hash_ob, 0, 0, + (void *(*) (size_t)) 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; +} + +/* 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; +} + +/* We don't need a proxy since the hash table's identifier comes first + in cpp_hashnode. However, in case this is ever changed, we have a + static assertion for it. */ +extern char proxy_assertion_broken[offsetof (struct cpp_hashnode, ident) == 0 ? 1 : -1]; + +/* 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) +{ + ht_forall (pfile->hash_table, (ht_cb) cb, v); +} diff --git a/support/cpp/libcpp/include/cpp-id-data.h b/support/cpp/libcpp/include/cpp-id-data.h new file mode 100644 index 0000000..a57edad --- /dev/null +++ b/support/cpp/libcpp/include/cpp-id-data.h @@ -0,0 +1,81 @@ +/* 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, 2009 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 3, 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; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "cpplib.h" + +#if !defined (HAVE_UCHAR) && !defined (IN_GCC) +typedef unsigned char uchar; +#endif + +#define UC (const unsigned char *) /* Intended use: UC"string" */ + +/* Chained list of answers to an assertion. */ +struct GTY(()) answer { + 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 GTY(()) cpp_macro { + /* 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; + + /* Indicate whether the tokens include extra CPP_PASTE tokens at the + end to track invalid redefinitions with consecutive CPP_PASTE + tokens. */ + unsigned int extra_tokens : 1; +}; diff --git a/support/cpp/libcpp/include/cpplib.h b/support/cpp/libcpp/include/cpplib.h new file mode 100644 index 0000000..6882514 --- /dev/null +++ b/support/cpp/libcpp/include/cpplib.h @@ -0,0 +1,1012 @@ +/* Definitions for CPP library. + Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, + 2004, 2005, 2007, 2008, 2009, 2010 + 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 3, 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; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. + + 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 <sys/types.h> +#include "symtab.h" +#include "line-map.h" + +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 ">>". + + See the cpp_operator table optab in expr.c if you change the order or + add or remove anything in the first group. */ + +#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(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, "<<=") \ + /* 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(CHAR16, LITERAL) /* u'char' */ \ + TK(CHAR32, LITERAL) /* U'char' */ \ + TK(OTHER, LITERAL) /* stray punctuation */ \ + \ + TK(STRING, LITERAL) /* "string" */ \ + TK(WSTRING, LITERAL) /* L"string" */ \ + TK(STRING16, LITERAL) /* u"string" */ \ + TK(STRING32, LITERAL) /* U"string" */ \ + TK(UTF8STRING, LITERAL) /* u8"string" */ \ + TK(OBJC_STRING, LITERAL) /* @"string" - Objective-C */ \ + TK(HEADER_NAME, LITERAL) /* <stdio.h> in #include */ \ + \ + TK(COMMENT, LITERAL) /* Only if output comments. */ \ + /* SPELL_LITERAL happens to DTRT. */ \ + TK(MACRO_ARG, NONE) /* Macro argument. */ \ + TK(PRAGMA, NONE) /* Only for deferred pragmas. */ \ + TK(PRAGMA_EOL, NONE) /* End-of-line for deferred 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_LSHIFT, + CPP_FIRST_DIGRAPH = CPP_HASH, + CPP_LAST_PUNCTUATOR= CPP_ATSIGN, + 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_GNUC1X, + CLK_STDC89, CLK_STDC94, CLK_STDC99, CLK_STDC1X, + CLK_GNUCXX, CLK_CXX98, CLK_GNUCXX0X, CLK_CXX0X, CLK_ASM}; + +/* Payload of a NUMBER, STRING, CHAR or COMMENT token. */ +struct GTY(()) 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. */ +#define PURE_ZERO (1 << 7) /* Single 0 digit, used by the C++ frontend, + set in c-lex.c. */ +#define SP_DIGRAPH (1 << 8) /* # or ## token was a digraph. */ +#define SP_PREV_WHITE (1 << 9) /* If whitespace before a ## + operator, or before this token + after a # operator. */ +#define PREV_NL (1 <<11) /* If a newline before this token. */ +#define ENTER_ASM (1 <<12) /* enter an __asm __endasm pair. */ +#define EXIT_ASM (1 <<13) /* exit an __asm __endasm pair. */ + +/* 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_TOKEN_NO, + CPP_TOKEN_FLD_PRAGMA, + CPP_TOKEN_FLD_NONE +}; + +/* A macro argument in the cpp_token union. */ +struct GTY(()) cpp_macro_arg { + /* Argument number. */ + unsigned int arg_no; +}; + +/* An identifier in the cpp_token union. */ +struct GTY(()) cpp_identifier { + /* The canonical (UTF-8) spelling of the 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"))) + node; +}; + +/* 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 GTY(()) cpp_token { + source_location src_loc; /* Location of first char of token. */ + ENUM_BITFIELD(cpp_ttype) type : CHAR_BIT; /* token type */ + unsigned short flags; /* flags - see above */ + + union cpp_token_u + { + /* An identifier. */ + struct cpp_identifier GTY ((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. */ + struct cpp_macro_arg GTY ((tag ("CPP_TOKEN_FLD_ARG_NO"))) macro_arg; + + /* Original token no. for a CPP_PASTE (from a sequence of + consecutive paste tokens in a macro expansion). */ + unsigned int GTY ((tag ("CPP_TOKEN_FLD_TOKEN_NO"))) token_no; + + /* Caller-supplied identifier for a CPP_PRAGMA. */ + unsigned int GTY ((tag ("CPP_TOKEN_FLD_PRAGMA"))) pragma; + } 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, use + the OBJC[PLUS]_INCLUDE_PATH environment variable, and allow + "#import". */ + 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 process u/U prefix literals (UTF-16/32). */ + unsigned char uliterals; + + /* Nonzero means print names of header files (-H). */ + unsigned char print_include_names; + + /* Nonzero means complain about deprecated features. */ + unsigned char cpp_warn_deprecated; + + /* 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 cpp_warn_traditional; + + /* Nonzero means warn about long long numeric constants. */ + unsigned char cpp_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 warn about builtin macros that are redefined or + explicitly undefined. */ + unsigned char warn_builtin_macro_redefined; + + /* 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 cpp_pedantic; + + /* Nonzero means we're looking at already preprocessed code, so don't + bother trying to do macro expansion and whatnot. */ + unsigned char preprocessed; + + /* Nonzero means handle C++ alternate operator names. */ + unsigned char operator_names; + + /* Nonzero means warn about use of C++ alternate operator names. */ + unsigned char warn_cxx_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; + + /* If true, intend to use the preprocessor output (e.g., for compilation) + in addition to the dependency info. */ + bool need_preprocessor_output; + } 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 disables tokenization outside of preprocessing directives. */ + bool directives_only; +}; + +/* 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 <built-in>+<command line> 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; + + /* Context-sensitive macro support. Returns macro (if any) that should + be expanded. */ + cpp_hashnode * (*macro_to_expand) (cpp_reader *, const cpp_token *); + + /* Called to emit a diagnostic. This callback receives the + translated message. */ + bool (*error) (cpp_reader *, int, int, source_location, unsigned int, + const char *, va_list *) + ATTRIBUTE_FPTR_PRINTF(6,0); + + /* Callbacks for when a macro is expanded, or tested (whether + defined or not at the time) in #ifdef, #ifndef or "defined". */ + void (*used_define) (cpp_reader *, unsigned int, cpp_hashnode *); + void (*used_undef) (cpp_reader *, unsigned int, cpp_hashnode *); + /* Called before #define and #undef or other macro definition + changes are processed. */ + void (*before_define) (cpp_reader *); + /* Called whenever a macro is expanded or tested. + Second argument is the location of the start of the current expansion. */ + void (*used) (cpp_reader *, source_location, cpp_hashnode *); + + /* Callback that can change a user builtin into normal macro. */ + bool (*user_builtin_macro) (cpp_reader *, cpp_hashnode *); +}; + +#ifdef VMS +#define INO_T_CPP ino_t ino[3] +#else +#define INO_T_CPP ino_t ino +#endif + +/* 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; + + /* Is this a user-supplied directory? */ + bool user_supplied_p; + + /* The canonicalized NAME as determined by lrealpath. This field + is only used by hosts that lack reliable inode numbers. */ + char *canonical_name; + + /* 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_CPP; + dev_t dev; +}; + +/* 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__, poisoned identifiers, and -Wc++-compat + warnings about NODE_OPERATOR. */ + +/* 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. */ +#define NODE_USED (1 << 7) /* Dumped with -dU. */ +#define NODE_CONDITIONAL (1 << 8) /* Conditional macro */ +#define NODE_WARN_OPERATOR (1 << 9) /* Warn about C++ named operator. */ + +/* 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 cpp_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 */ + BT_TIMESTAMP, /* `__TIMESTAMP__' */ + BT_COUNTER, /* `__COUNTER__' */ + BT_FUNCTION, /* `__func__' */ + BT_FIRST_USER, /* User defined builtin macros. */ + BT_LAST_USER = BT_FIRST_USER + 31 +}; + +#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 GTY(()) _cpp_hashnode_value { + /* 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 cpp_builtin_type GTY ((tag ("NTV_BUILTIN"))) builtin; + /* Macro argument index. */ + unsigned short GTY ((tag ("NTV_ARGUMENT"))) arg_index; +}; + +struct GTY(()) cpp_hashnode { + 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 : 6; /* CPP node type. */ + unsigned int flags : 10; /* 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 *); + +/* Reset the cpp_reader's line_map. This is only used after reading a + PCH file. */ +extern void cpp_set_line_map (cpp_reader *, 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 with special behavior. Use cpp_init_builtins() + instead unless your know what you are doing. */ +extern void cpp_init_special_builtins (cpp_reader *); + +/* 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. */ +extern void 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. */ +extern void cpp_destroy (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_register_deferred_pragma (cpp_reader *, const char *, + const char *, unsigned, bool, bool); +extern int cpp_avoid_paste (cpp_reader *, const cpp_token *, + const cpp_token *); +extern const cpp_token *cpp_get_token (cpp_reader *); +extern const cpp_token *cpp_get_token_with_location (cpp_reader *, + source_location *); +extern const unsigned char *cpp_macro_definition (cpp_reader *, + cpp_hashnode *); +extern void _cpp_backup_tokens (cpp_reader *, unsigned int); +extern const cpp_token *cpp_peek_token (cpp_reader *, int); + +/* Evaluate a CPP_*CHAR* token. */ +extern cppchar_t cpp_interpret_charconst (cpp_reader *, const cpp_token *, + unsigned int *, int *); +/* Evaluate a vector of CPP_*STRING* tokens. */ +extern bool cpp_interpret_string (cpp_reader *, + const cpp_string *, size_t, + cpp_string *, enum cpp_ttype); +extern bool cpp_interpret_string_notranslate (cpp_reader *, + const cpp_string *, size_t, + cpp_string *, enum cpp_ttype); + +/* 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_define_formatted (cpp_reader *pfile, + const char *fmt, ...) ATTRIBUTE_PRINTF_2; +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, shrot _Fract/Accum */ +#define CPP_N_MEDIUM 0x0020 /* long, double, long _Fract/_Accum. */ +#define CPP_N_LARGE 0x0040 /* long long, long double, + long long _Fract/Accum. */ + +#define CPP_N_WIDTH_MD 0xF0000 /* machine defined. */ +#define CPP_N_MD_W 0x10000 +#define CPP_N_MD_Q 0x20000 + +#define CPP_N_RADIX 0x0F00 +#define CPP_N_DECIMAL 0x0100 +#define CPP_N_HEX 0x0200 +#define CPP_N_OCTAL 0x0400 +#define CPP_N_BINARY 0x0800 + +#define CPP_N_UNSIGNED 0x1000 /* Properties. */ +#define CPP_N_IMAGINARY 0x2000 +#define CPP_N_DFLOAT 0x4000 +#define CPP_N_DEFAULT 0x8000 + +#define CPP_N_FRACT 0x100000 /* Fract types. */ +#define CPP_N_ACCUM 0x200000 /* Accum types. */ + +/* 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. */ + +enum { + /* Warning, an error with -Werror. */ + CPP_DL_WARNING = 0, + /* Same as CPP_DL_WARNING, except it is not suppressed in system headers. */ + CPP_DL_WARNING_SYSHDR, + /* Warning, an error with -pedantic-errors or -Werror. */ + CPP_DL_PEDWARN, + /* An error. */ + CPP_DL_ERROR, + /* An internal consistency check failed. Prints "internal error: ", + otherwise the same as CPP_DL_ERROR. */ + CPP_DL_ICE, + /* An informative note following a warning. */ + CPP_DL_NOTE, + /* A fatal error. */ + CPP_DL_FATAL +}; + +/* Warning reason codes. Use a reason code of zero for unclassified warnings + and errors that are not warnings. */ +enum { + CPP_W_NONE = 0, + CPP_W_DEPRECATED, + CPP_W_COMMENTS, + CPP_W_MISSING_INCLUDE_DIRS, + CPP_W_TRIGRAPHS, + CPP_W_MULTICHAR, + CPP_W_TRADITIONAL, + CPP_W_LONG_LONG, + CPP_W_ENDIF_LABELS, + CPP_W_NUM_SIGN_CHANGE, + CPP_W_VARIADIC_MACROS, + CPP_W_BUILTIN_MACRO_REDEFINED, + CPP_W_DOLLARS, + CPP_W_UNDEF, + CPP_W_UNUSED_MACROS, + CPP_W_CXX_OPERATOR_NAMES, + CPP_W_NORMALIZE, + CPP_W_INVALID_PCH, + CPP_W_WARNING_DIRECTIVE +}; + +/* Output a diagnostic of some kind. */ +extern bool cpp_error (cpp_reader *, int, const char *msgid, ...) + ATTRIBUTE_PRINTF_3; +extern bool cpp_warning (cpp_reader *, int, const char *msgid, ...) + ATTRIBUTE_PRINTF_3; +extern bool cpp_pedwarning (cpp_reader *, int, const char *msgid, ...) + ATTRIBUTE_PRINTF_3; +extern bool cpp_warning_syshdr (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 bool 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 bool cpp_error_with_line (cpp_reader *, int, source_location, + unsigned, const char *msgid, ...) + ATTRIBUTE_PRINTF_5; +extern bool cpp_warning_with_line (cpp_reader *, int, source_location, + unsigned, const char *msgid, ...) + ATTRIBUTE_PRINTF_5; +extern bool cpp_pedwarning_with_line (cpp_reader *, int, source_location, + unsigned, const char *msgid, ...) + ATTRIBUTE_PRINTF_5; +extern bool cpp_warning_with_line_syshdr (cpp_reader *, int, source_location, + unsigned, const char *msgid, ...) + ATTRIBUTE_PRINTF_5; + +/* In lex.c */ +extern int cpp_ideq (const cpp_token *, const char *); +extern void cpp_output_line (cpp_reader *, FILE *); +extern unsigned char *cpp_output_line_to_string (cpp_reader *, + const unsigned char *); +extern void cpp_output_token (const cpp_token *, FILE *); +extern const char *cpp_type2name (enum cpp_ttype, unsigned char flags); +/* 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); + +/* Structure used to hold a comment block at a given location in the + source code. */ + +typedef struct +{ + /* Text of the comment including the terminators. */ + char *comment; + + /* source location for the given comment. */ + source_location sloc; +} cpp_comment; + +/* Structure holding all comments for a given cpp_reader. */ + +typedef struct +{ + /* table of comment entries. */ + cpp_comment *entries; + + /* number of actual entries entered in the table. */ + int count; + + /* number of entries allocated currently. */ + int allocated; +} cpp_comment_table; + +/* Returns the table of comments encountered by the preprocessor. This + table is only populated when pfile->state.save_comments is true. */ +extern cpp_comment_table *cpp_get_comments (cpp_reader *); + +/* In hash.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 macro.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 files.c */ +extern bool cpp_included (cpp_reader *, const char *); +extern bool cpp_included_before (cpp_reader *, const char *, source_location); +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 *); +extern void cpp_clear_file_cache (cpp_reader *); + +/* In pch.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 *); + +#endif /* ! LIBCPP_CPPLIB_H */ diff --git a/support/cpp/libcpp/include/line-map.h b/support/cpp/libcpp/include/line-map.h new file mode 100644 index 0000000..3234423 --- /dev/null +++ b/support/cpp/libcpp/include/line-map.h @@ -0,0 +1,193 @@ +/* Map logical line numbers to (source file, line number) pairs. + Copyright (C) 2001, 2003, 2004, 2007, 2008, 2009, 2010 + 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 3, 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; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. + + 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 + +#ifndef GTY +#define GTY(x) /* nothing */ +#endif + +/* 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); LC_RENAME_VERBATIM is like LC_RENAME + but a filename of "" is not specially interpreted as standard input. */ +enum lc_reason {LC_ENTER = 0, LC_LEAVE, LC_RENAME, LC_RENAME_VERBATIM}; + +/* The type of line numbers. */ +typedef unsigned int linenum_type; + +/* A logical line/column number, i.e. an "index" into a line_map. */ +typedef unsigned int source_location; + +/* Memory allocation function typedef. Works like xrealloc. */ +typedef void *(*line_map_realloc) (void *, size_t); + +/* 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<<column_bits))+C, as long as C<(1<<column_bits), + and the result_location is less than the next line_map's start_location. + (The top line is line 1 and the leftmost column is column 1; line/column 0 + means "entire file/line" or "unknown line/column" or "not applicable".) + 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 GTY(()) line_map { + const char *to_file; + linenum_type to_line; + source_location start_location; + int included_from; + ENUM_BITFIELD (lc_reason) reason : CHAR_BIT; + /* The sysp field isn't really needed now that it's in cpp_buffer. */ + unsigned char sysp; + /* Number of the low-order source_location bits used for a column number. */ + unsigned int column_bits : 8; +}; + +/* A set of chronological line_map structures. */ +struct GTY(()) line_maps { + struct line_map * GTY ((length ("%h.used"))) maps; + unsigned int allocated; + unsigned int used; + + unsigned int cache; + + /* 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; + + /* Highest source_location "given out". */ + source_location highest_location; + + /* Start of line of highest source_location "given out". */ + source_location highest_line; + + /* The maximum column number we can quickly allocate. Higher numbers + may require allocating a new line_map. */ + unsigned int max_column_hint; + + /* If non-null, the allocator to use when resizing 'maps'. If null, + xrealloc is used. */ + line_map_realloc reallocator; +}; + +/* Initialize a line map set. */ +extern void linemap_init (struct line_maps *); + +/* Free a line map set. */ +extern void linemap_free (struct line_maps *); + +/* Check for and warn about line_maps entered but not exited. */ + +extern void linemap_check_files_exited (struct line_maps *); + +/* Return a source_location for the start (i.e. column==0) of + (physical) line TO_LINE in the current source file (as in the + most recent linemap_add). MAX_COLUMN_HINT is the highest column + number we expect to use in this line (but it does not change + the highest_location). */ + +extern source_location linemap_line_start +(struct line_maps *set, linenum_type to_line, unsigned int max_column_hint); + +/* 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. + + 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, + const char *to_file, linenum_type 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); + +/* source_location values from 0 to RESERVED_LOCATION_COUNT-1 will + be reserved for libcpp user as special values, no token from libcpp + will contain any of those locations. */ +#define RESERVED_LOCATION_COUNT 2 + +/* Converts a map and a source_location to source line. */ +#define SOURCE_LINE(MAP, LOC) \ + ((((LOC) - (MAP)->start_location) >> (MAP)->column_bits) + (MAP)->to_line) + +#define SOURCE_COLUMN(MAP, LOC) \ + (((LOC) - (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_COLUMN(MAP) \ + SOURCE_COLUMN (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) do { \ + 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; \ + }} while (0) + + +extern source_location +linemap_position_for_column (struct line_maps *set, unsigned int to_column); + +#endif /* !LIBCPP_LINE_MAP_H */ diff --git a/support/cpp/libcpp/include/mkdeps.h b/support/cpp/libcpp/include/mkdeps.h new file mode 100644 index 0000000..f743ee7 --- /dev/null +++ b/support/cpp/libcpp/include/mkdeps.h @@ -0,0 +1,80 @@ +/* Dependency generator for Makefile fragments. + Copyright (C) 2000, 2001, 2003, 2009 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 3, 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; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. + + 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/cpp/libcpp/include/symtab.h b/support/cpp/libcpp/include/symtab.h new file mode 100644 index 0000000..4107a6f --- /dev/null +++ b/support/cpp/libcpp/include/symtab.h @@ -0,0 +1,104 @@ +/* Hash tables. + Copyright (C) 2000, 2001, 2003, 2004, 2007, 2008, 2009, 2010 + 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 3, 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; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef LIBCPP_SYMTAB_H +#define LIBCPP_SYMTAB_H + +#include "obstack.h" + +#ifndef GTY +#define GTY(x) /* nothing */ +#endif + +/* This is what each hash table entry points to. It may be embedded + deeply within another object. */ +typedef struct ht_identifier ht_identifier; +typedef struct ht_identifier *ht_identifier_ptr; +struct GTY(()) ht_identifier { + 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}; + +/* 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 *); + +/* For all nodes in TABLE, call the callback. If the callback returns + a nonzero value, the node is removed from the table. */ +extern void ht_purge (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/cpp/libcpp/init.c b/support/cpp/libcpp/init.c new file mode 100644 index 0000000..a884f46 --- /dev/null +++ b/support/cpp/libcpp/init.c @@ -0,0 +1,721 @@ +/* CPP Library. + Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, + 2009, 2010 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 3, 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; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#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 *, int); +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; + char uliterals; +}; + +static const struct lang_flags lang_defaults[] = +{ /* c99 c++ xnum xid std // digr ulit */ + /* GNUC89 */ { 0, 0, 1, 0, 0, 1, 1, 0 }, + /* GNUC99 */ { 1, 0, 1, 0, 0, 1, 1, 1 }, + /* GNUC1X */ { 1, 0, 1, 0, 0, 1, 1, 1 }, + /* STDC89 */ { 0, 0, 0, 0, 1, 0, 0, 0 }, + /* STDC94 */ { 0, 0, 0, 0, 1, 0, 1, 0 }, + /* STDC99 */ { 1, 0, 1, 0, 1, 1, 1, 0 }, + /* STDC1X */ { 1, 0, 1, 0, 1, 1, 1, 0 }, + /* GNUCXX */ { 0, 1, 1, 0, 0, 1, 1, 0 }, + /* CXX98 */ { 0, 1, 1, 0, 1, 1, 1, 0 }, + /* GNUCXX0X */ { 1, 1, 1, 0, 0, 1, 1, 1 }, + /* CXX0X */ { 1, 1, 1, 0, 1, 1, 1, 1 }, + /* ASM */ { 0, 0, 1, 0, 0, 1, 0, 0 } + /* xid should be 1 for GNUC99, STDC99, GNUCXX, CXX98, GNUCXX0X, and + CXX0X 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; + /* Trigraphs processing is always enabled in sdcpp */ + CPP_OPTION (pfile, trigraphs) = 1; + CPP_OPTION (pfile, cplusplus_comments) = l->cplusplus_comments; + CPP_OPTION (pfile, digraphs) = l->digraphs; + CPP_OPTION (pfile, uliterals) = l->uliterals; +} + +/* 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, tabstop) = 8; + CPP_OPTION (pfile, operator_names) = 1; + /* Trigraphs wrning is always enabled in sdcpp */ + CPP_OPTION (pfile, warn_trigraphs) = 1; + CPP_OPTION (pfile, warn_endif_labels) = 1; + CPP_OPTION (pfile, cpp_warn_deprecated) = 1; + CPP_OPTION (pfile, cpp_warn_long_long) = 0; + CPP_OPTION (pfile, dollars_in_ident) = 1; + CPP_OPTION (pfile, warn_dollars) = 1; + CPP_OPTION (pfile, warn_variadic_macros) = 1; + CPP_OPTION (pfile, warn_builtin_macro_redefined) = 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 (); + + /* 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); + + /* Initialize table for push_macro/pop_macro. */ + pfile->pushed_macros = 0; + + /* The expression parser stack. */ + _cpp_expand_op_stack (pfile); + + /* Initialize the buffer obstack. */ + _obstack_begin (&pfile->buffer_ob, 0, 0, + (void *(*) (size_t)) xmalloc, + (void (*) (void *)) free); + + _cpp_init_files (pfile); + + _cpp_init_hashtable (pfile, table); + + return pfile; +} + +/* Set the line_table entry in PFILE. This is called after reading a + PCH file, as the old line_table will be incorrect. */ +void +cpp_set_line_map (cpp_reader *pfile, struct line_maps *line_table) +{ + pfile->line_table = line_table; +} + +/* 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; + struct def_pragma_macro *pmacro; + tokenrun *run, *runn; + int i; + + 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); + } + + if (pfile->comments.entries) + { + for (i = 0; i < pfile->comments.count; i++) + free (pfile->comments.entries[i].comment); + + free (pfile->comments.entries); + } + if (pfile->pushed_macros) + { + do + { + pmacro = pfile->pushed_macros; + pfile->pushed_macros = pmacro->next; + free (pmacro->name); + free (pmacro); + } + while (pfile->pushed_macros); + } + + 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 "cpp_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 + <iso646.h>). The value is a token-type enumerator. */ +struct builtin_macro +{ + const uchar *const name; + const unsigned short len; + const unsigned short value; + const bool always_warn_if_redefined; +}; + +#define B(n, t, f) { DSC(n), t, f } +static const struct builtin_macro builtin_array[] = +{ + B("__TIMESTAMP__", BT_TIMESTAMP, false), + B("__TIME__", BT_TIME, false), + B("__DATE__", BT_DATE, false), + B("__FILE__", BT_FILE, false), + B("__func__", BT_FUNCTION, false), + B("__BASE_FILE__", BT_BASE_FILE, false), + B("__LINE__", BT_SPECLINE, true), + B("__INCLUDE_LEVEL__", BT_INCLUDE_LEVEL, true), + B("__COUNTER__", BT_COUNTER, true), + /* Keep builtins not used for -traditional-cpp at the end, and + update init_builtins() if any more are added. */ + B("_Pragma", BT_PRAGMA, true), + B("__STDC__", BT_STDC, true), +}; +#undef B + +struct builtin_operator +{ + const uchar *const name; + const unsigned short len; + const unsigned short value; +}; + +#define B(n, t) { DSC(n), t } +static const struct builtin_operator 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, int flags) +{ + const struct builtin_operator *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 |= flags; + hp->is_directive = 0; + hp->directive_index = b->value; + } +} + +/* Helper function of cpp_type2name. Return the string associated with + named operator TYPE. */ +const char * +cpp_named_operator2name (enum cpp_ttype type) +{ + const struct builtin_operator *b; + + for (b = operator_array; + b < (operator_array + ARRAY_SIZE (operator_array)); + b++) + { + if (type == b->value) + return (const char *) b->name; + } + + return NULL; +} + +void +cpp_init_special_builtins (cpp_reader *pfile) +{ + const struct builtin_macro *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--; + + 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; + if (b->always_warn_if_redefined + || CPP_OPTION (pfile, warn_builtin_macro_redefined)) + hp->flags |= NODE_WARN; + hp->value.builtin = (enum cpp_builtin_type) 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) +{ + cpp_init_special_builtins (pfile); + + if (!CPP_OPTION (pfile, traditional) + && (! CPP_OPTION (pfile, stdc_0_in_system_headers) + || CPP_OPTION (pfile, std))) + _cpp_define_builtin (pfile, "__STDC__ 1"); + + 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, lang) == CLK_STDC1X + || CPP_OPTION (pfile, lang) == CLK_GNUC1X) + _cpp_define_builtin (pfile, "__STDC_VERSION__ 201112L"); + 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) +{ + int flags; + + sanity_checks (pfile); + + post_options (pfile); + + /* Mark named operators before handling command line macros. */ + flags = 0; + if (CPP_OPTION (pfile, cplusplus) && CPP_OPTION (pfile, operator_names)) + flags |= NODE_OPERATOR; + if (CPP_OPTION (pfile, warn_cxx_operator_names)) + flags |= NODE_DIAGNOSTIC | NODE_WARN_OPERATOR; + if (flags != 0) + mark_named_operators (pfile, flags); +} + +/* 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 # <line> "/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. + + Maybe it should also reset state, such that you could call + cpp_start_read with a new filename to restart processing. */ +void +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); + + if (CPP_OPTION (pfile, deps.style) != DEPS_NONE + && deps_stream) + { + 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); +} + +static void +post_options (cpp_reader *pfile) +{ + /* -Wtraditional is not useful in C++ mode. */ + if (CPP_OPTION (pfile, cplusplus)) + CPP_OPTION (pfile, cpp_warn_traditional) = 0; + + /* Permanently disable macro expansion if we are rescanning + preprocessed text. Read preprocesed source in ISO mode. */ + if (CPP_OPTION (pfile, preprocessed)) + { + if (!CPP_OPTION (pfile, directives_only)) + pfile->state.prevent_expansion = 1; + CPP_OPTION (pfile, traditional) = 0; + } + + if (CPP_OPTION (pfile, traditional)) + { + CPP_OPTION (pfile, cplusplus_comments) = 0; + } +} diff --git a/support/cpp/libcpp/internal.h b/support/cpp/libcpp/internal.h new file mode 100644 index 0000000..eeed29d --- /dev/null +++ b/support/cpp/libcpp/internal.h @@ -0,0 +1,745 @@ +/* Part of CPP library. + Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, + 2008, 2009, 2010 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 3, 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; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +/* 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" + +#if HAVE_ICONV +#include <iconv.h> +#else +#define HAVE_ICONV 0 +typedef int iconv_t; /* dummy */ +#endif + +#ifdef __cplusplus +extern "C" { +#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; + int width; +}; + +#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]; \ + linenum_type 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 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; + + /* Nonzero when handling a deferred pragma. */ + unsigned char in_deferred_pragma; + + /* Nonzero if the deferred pragma being handled allows macro expansion. */ + unsigned char pragma_allow_expansion; +}; + +/* 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 ; */ + cpp_hashnode *n__endasm; /* __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, 0 represents a note that has already been handled, + 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; + + /* Saved value of __TIMESTAMP__ macro - date and time of last modification + of the assotiated file. */ + const unsigned char *timestamp; + + /* 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; +}; + +/* The list of saved macros by push_macro pragma. */ +struct def_pragma_macro { + /* Chain element to previous saved macro. */ + struct def_pragma_macro *next; + /* Name of the macro. */ + char *name; + /* The stored macro content. */ + unsigned char *definition; + + /* Definition line number. */ + source_location line; + /* 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; + + /* Mark if we save an undefined macro. */ + unsigned int is_undef : 1; +}; + +/* 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; + + /* When expanding a macro at top-level, this is the location of the + macro invocation. */ + source_location invocation_location; + + /* True if this call to cpp_get_token should consider setting + invocation_location. */ + bool set_invocation_location; + + /* 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_pool *file_hash_entries; + + /* Negative path lookup hash table. */ + struct htab *nonexistent_file_hash; + struct obstack nonexistent_file_ob; + + /* 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; + + /* 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 + UTF-8 execution character set. */ + struct cset_converter utf8_cset_desc; + + /* Descriptor for converting from the source character set to the + UTF-16 execution character set. */ + struct cset_converter char16_cset_desc; + + /* Descriptor for converting from the source character set to the + UTF-32 execution character set. */ + struct cset_converter char32_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; + + /* Next value of __COUNTER__ macro. */ + unsigned int counter; + + /* Table of comments, when state.save_comments is true. */ + cpp_comment_table comments; + + /* List of saved macros by push_macro. */ + struct def_pragma_macro *pushed_macros; +}; + +/* 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, cpp_pedantic) +#define CPP_WTRADITIONAL(PF) CPP_OPTION (PF, cpp_warn_traditional) + +static inline int cpp_in_primary_file (cpp_reader *); +static inline int +cpp_in_primary_file (cpp_reader *pfile) +{ + return pfile->line_table->depth == 1; +} + +/* 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 *); +extern int _cpp_warn_if_unused_macro (cpp_reader *, cpp_hashnode *, void *); +extern void _cpp_push_token_context (cpp_reader *, cpp_hashnode *, + const cpp_token *, unsigned int); +extern void _cpp_backup_tokens_direct (cpp_reader *, unsigned int); + +/* 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 *); +extern struct stat *_cpp_get_file_stat (_cpp_file *); + +/* In expr.c */ +extern bool _cpp_parse_expr (cpp_reader *, bool); +extern struct op *_cpp_expand_op_stack (cpp_reader *); + +/* In lex.c */ +extern int _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); +extern cpp_hashnode *_cpp_lex_identifier (cpp_reader *, const char *); + +/* In init.c. */ +extern void _cpp_maybe_push_include_file (cpp_reader *); +extern const char *cpp_named_operator2name (enum cpp_ttype type); + +/* 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 int _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 *, + linenum_type, unsigned int); +extern void _cpp_pop_buffer (cpp_reader *); + +/* In directives.c */ +struct _cpp_dir_only_callbacks +{ + /* Called to print a block of lines. */ + void (*print_lines) (int, const void *, size_t); + void (*maybe_print_line) (source_location); +}; + +extern void _cpp_preprocess_dir_only (cpp_reader *, + const struct _cpp_dir_only_callbacks *); + +/* 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, + const unsigned char **, 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); +} + +#ifdef __cplusplus +} +#endif + +#endif /* ! LIBCPP_INTERNAL_H */ diff --git a/support/cpp/libcpp/lex.c b/support/cpp/libcpp/lex.c new file mode 100644 index 0000000..ccb4b0f --- /dev/null +++ b/support/cpp/libcpp/lex.c @@ -0,0 +1,2906 @@ +/* CPP Library - lexical analysis. + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 + 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 3, 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; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "cpplib.h" +#include "internal.h" +#include <assert.h> + +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[] = +{ UC"%:", UC"%:%:", UC"<:", UC":>", UC"<%", UC"%>" }; + +#define OP(e, s) { SPELL_OPERATOR, UC s }, +#define TK(e, s) { SPELL_ ## s, UC #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 store_comment (cpp_reader *, cpp_token *); +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); + +int in_asm = 0; + +/* 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.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++; +} + + +/* Fast path to find line special characters using optimized character + scanning algorithms. Anything complicated falls back to the slow + path below. Since this loop is very hot it's worth doing these kinds + of optimizations. + + One of the paths through the ifdefs should provide + + const uchar *search_line_fast (const uchar *s, const uchar *end); + + Between S and END, search for \n, \r, \\, ?. Return a pointer to + the found character. + + Note that the last character of the buffer is *always* a newline, + as forced by _cpp_convert_input. This fact can be used to avoid + explicitly looking for the end of the buffer. */ + +/* Configure gives us an ifdef test. */ +#ifndef WORDS_BIGENDIAN +#define WORDS_BIGENDIAN 0 +#endif + +/* We'd like the largest integer that fits into a register. There's nothing + in <stdint.h> that gives us that. For most hosts this is unsigned long, + but MS decided on an LLP64 model. Thankfully when building with GCC we + can get the "real" word size. */ +#ifdef __GNUC__ +typedef unsigned int word_type __attribute__((__mode__(__word__))); +#else +typedef unsigned long word_type; +#endif + +/* The code below is only expecting sizes 4 or 8. + Die at compile-time if this expectation is violated. */ +typedef char check_word_type_size + [(sizeof(word_type) == 8 || sizeof(word_type) == 4) * 2 - 1]; + +/* Return X with the first N bytes forced to values that won't match one + of the interesting characters. Note that NUL is not interesting. */ + +static inline word_type +acc_char_mask_misalign (word_type val, unsigned int n) +{ + word_type mask = -1; + if (WORDS_BIGENDIAN) + mask >>= n * 8; + else + mask <<= n * 8; + return val & mask; +} + +/* Return X replicated to all byte positions within WORD_TYPE. */ + +static inline word_type +acc_char_replicate (uchar x) +{ + word_type ret; + + ret = (x << 24) | (x << 16) | (x << 8) | x; + if (sizeof(word_type) == 8) + ret = (ret << 16 << 16) | ret; + return ret; +} + +/* Return non-zero if some byte of VAL is (probably) C. */ + +static inline word_type +acc_char_cmp (word_type val, word_type c) +{ +#if defined(__GNUC__) && defined(__alpha__) + /* We can get exact results using a compare-bytes instruction. + Get (val == c) via (0 >= (val ^ c)). */ + return __builtin_alpha_cmpbge (0, val ^ c); +#else + word_type magic = 0x7efefefeU; + if (sizeof(word_type) == 8) + magic = (magic << 16 << 16) | 0xfefefefeU; + magic |= 1; + + val ^= c; + return ((val + magic) ^ ~val) & ~magic; +#endif +} + +/* Given the result of acc_char_cmp is non-zero, return the index of + the found character. If this was a false positive, return -1. */ + +static inline int +acc_char_index (word_type cmp ATTRIBUTE_UNUSED, + word_type val ATTRIBUTE_UNUSED) +{ +#if defined(__GNUC__) && defined(__alpha__) && !WORDS_BIGENDIAN + /* The cmpbge instruction sets *bits* of the result corresponding to + matches in the bytes with no false positives. */ + return __builtin_ctzl (cmp); +#else + unsigned int i; + + /* ??? It would be nice to force unrolling here, + and have all of these constants folded. */ + for (i = 0; i < sizeof(word_type); ++i) + { + uchar c; + if (WORDS_BIGENDIAN) + c = (val >> (sizeof(word_type) - i - 1) * 8) & 0xff; + else + c = (val >> i * 8) & 0xff; + + if (c == '\n' || c == '\r' || c == '\\' || c == '?') + return i; + } + + return -1; +#endif +} + +/* A version of the fast scanner using bit fiddling techniques. + + For 32-bit words, one would normally perform 16 comparisons and + 16 branches. With this algorithm one performs 24 arithmetic + operations and one branch. Whether this is faster with a 32-bit + word size is going to be somewhat system dependent. + + For 64-bit words, we eliminate twice the number of comparisons + and branches without increasing the number of arithmetic operations. + It's almost certainly going to be a win with 64-bit word size. */ + +static const uchar * search_line_acc_char (const uchar *, const uchar *) + ATTRIBUTE_UNUSED; + +static const uchar * +search_line_acc_char (const uchar *s, const uchar *end ATTRIBUTE_UNUSED) +{ + const word_type repl_nl = acc_char_replicate ('\n'); + const word_type repl_cr = acc_char_replicate ('\r'); + const word_type repl_bs = acc_char_replicate ('\\'); + const word_type repl_qm = acc_char_replicate ('?'); + + unsigned int misalign; + const word_type *p; + word_type val, t; + + /* Align the buffer. Mask out any bytes from before the beginning. */ + p = (word_type *)((uintptr_t)s & -sizeof(word_type)); + val = *p; + misalign = (uintptr_t)s & (sizeof(word_type) - 1); + if (misalign) + val = acc_char_mask_misalign (val, misalign); + + /* Main loop. */ + while (1) + { + t = acc_char_cmp (val, repl_nl); + t |= acc_char_cmp (val, repl_cr); + t |= acc_char_cmp (val, repl_bs); + t |= acc_char_cmp (val, repl_qm); + + if (__builtin_expect (t != 0, 0)) + { + int i = acc_char_index (t, val); + if (i >= 0) + return (const uchar *)p + i; + } + + val = *++p; + } +} + +#define search_line_fast search_line_acc_char + +/* 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; + + if (!buffer->from_stage3) + { + const uchar *pbackslash = NULL; + + /* Fast path. This is 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. */ + while (1) + { + /* Perform an optimized search for \n, \r, \\, ?. */ + s = search_line_fast (s, buffer->rlimit); + + c = *s; + if (c == '\\') + { + /* Record the location of the backslash and continue. */ + pbackslash = s++; + } + else if (__builtin_expect (c == '?', 0)) + { + if (__builtin_expect (s[1] == '?', false) + && _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; + goto slow_path; + } + } + /* Not a trigraph. Continue on fast-path. */ + s++; + } + else + break; + } + + /* This must be \r or \n. We're either done, or we'll be forced + to write back to the buffer and continue on the slow path. */ + d = (uchar *) s; + + if (__builtin_expect (s == buffer->rlimit, false)) + goto done; + + /* DOS line ending? */ + if (__builtin_expect (c == '\r', false) && s[1] == '\n') + { + s++; + if (s == buffer->rlimit) + goto done; + } + + if (__builtin_expect (pbackslash == NULL, true)) + goto done; + + /* Check for escaped newline. */ + p = d; + while (is_nvspace (p[-1])) + p--; + if (p - 1 != pbackslash) + 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; + + slow_path: + while (1) + { + 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 + { + while (*s != '\n' && *s != '\r') + s++; + 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. */ +int +_cpp_process_line_notes (cpp_reader *pfile, int in_comment) +{ + int ret = 0; + 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; + } + + ret = PREV_NL; + + 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_warning_with_line (pfile, CPP_W_TRIGRAPHS, + pfile->line_table->highest_line, col, + "trigraph ??%c converted to %c", + note->type, + (int) _cpp_trigraph_map[note->type]); + else + { + cpp_warning_with_line + (pfile, CPP_W_TRIGRAPHS, + pfile->line_table->highest_line, col, + "trigraph ??%c ignored, use -trigraphs to enable", + note->type); + } + } + } + else if (note->type == 0) + /* Already processed in lex_raw_string. */; + else + abort (); + } + return ret; +} + +/* 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 +_sdcpp_skip_asm_block (cpp_reader *pfile) +{ +#define ENDASM_STR "endasm" +#define ENDASM_LEN ((sizeof ENDASM_STR) - 1) + + cpp_buffer *buffer = pfile->buffer; + uchar c = EOF; + int prev_space = false; + + while (buffer->cur != buffer->rlimit) + { + prev_space = is_space(c); + c = *buffer->cur++; + + if (prev_space && c == '_' && *buffer->cur == '_') + { + /* check if it is __endasm */ + ++buffer->cur; + if (buffer->cur + ENDASM_LEN <= buffer->rlimit && + strncmp((const char *)buffer->cur, ENDASM_STR, ENDASM_LEN) == 0) + { + buffer->cur += ENDASM_LEN; + 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 false; +} + +/* 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_warning_with_line (pfile, CPP_W_COMMENTS, + 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; + source_location 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_warning_with_line (pfile, CPP_W_NORMALIZE, token->src_loc, 0, + "`%.*s' is not in NFKC", (int) sz, buf); + else + cpp_warning_with_line (pfile, CPP_W_NORMALIZE, 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; +} + +/* Helper function to get the cpp_hashnode of the identifier BASE. */ +static cpp_hashnode * +lex_identifier_intern (cpp_reader *pfile, const uchar *base) +{ + cpp_hashnode *result; + const uchar *cur; + unsigned int len; + unsigned int hash = HT_HASHSTEP (0, *base); + + cur = base + 1; + while (ISIDNUM (*cur)) + { + hash = HT_HASHSTEP (hash, *cur); + cur++; + } + 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"); + + /* For -Wc++-compat, warn about use of C++ named operators. */ + if (result->flags & NODE_WARN_OPERATOR) + cpp_warning (pfile, CPP_W_CXX_OPERATOR_NAMES, + "identifier \"%s\" is a special operator name in C++", + NODE_NAME (result)); + } + + return result; +} + +/* Get the cpp_hashnode of an identifier specified by NAME in + the current cpp_reader object. If none is found, NULL is returned. */ +cpp_hashnode * +_cpp_lex_identifier (cpp_reader *pfile, const char *name) +{ + cpp_hashnode *result; + result = lex_identifier_intern (pfile, (uchar *) name); + return result; +} + +/* 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"); + + /* For -Wc++-compat, warn about use of C++ named operators. */ + if (result->flags & NODE_WARN_OPERATOR) + cpp_warning (pfile, CPP_W_CXX_OPERATOR_NAMES, + "identifier \"%s\" is a special operator name in C++", + NODE_NAME (result)); + } + + return result; +} + +/* sdpcc 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, NT_BIN } 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; + 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 'B': + case 'b': + if (!CPP_OPTION (pfile, std)) + { + num_type = NT_BIN; + ++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 if (NT_HEX == num_type) + { + 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; + } + } + else /* (NT_BIN == num_type) */ + { + while ((c=='0') || (c=='1')) + { + 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; +} + +/* Subroutine of lex_raw_string: Append LEN chars from BASE to the buffer + sequence from *FIRST_BUFF_P to LAST_BUFF_P. */ + +static void +bufring_append (cpp_reader *pfile, const uchar *base, size_t len, + _cpp_buff **first_buff_p, _cpp_buff **last_buff_p) +{ + _cpp_buff *first_buff = *first_buff_p; + _cpp_buff *last_buff = *last_buff_p; + + if (first_buff == NULL) + first_buff = last_buff = _cpp_get_buff (pfile, len); + else if (len > BUFF_ROOM (last_buff)) + { + size_t room = BUFF_ROOM (last_buff); + memcpy (BUFF_FRONT (last_buff), base, room); + BUFF_FRONT (last_buff) += room; + base += room; + len -= room; + last_buff = _cpp_append_extend_buff (pfile, last_buff, len); + } + + memcpy (BUFF_FRONT (last_buff), base, len); + BUFF_FRONT (last_buff) += len; + + *first_buff_p = first_buff; + *last_buff_p = last_buff; +} + +/* Lexes a raw string. The stored string contains the spelling, including + double quotes, delimiter string, '(' and ')', any leading + 'L', 'u', 'U' or 'u8' and 'R' modifier. 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_raw_string (cpp_reader *pfile, cpp_token *token, const uchar *base, + const uchar *cur) +{ + source_location saw_NUL = 0; + const uchar *raw_prefix; + unsigned int raw_prefix_len = 0; + enum cpp_ttype type; + size_t total_len = 0; + _cpp_buff *first_buff = NULL, *last_buff = NULL; + _cpp_line_note *note = &pfile->buffer->notes[pfile->buffer->cur_note]; + + type = (*base == 'L' ? CPP_WSTRING : + *base == 'U' ? CPP_STRING32 : + *base == 'u' ? (base[1] == '8' ? CPP_UTF8STRING : CPP_STRING16) + : CPP_STRING); + + raw_prefix = cur + 1; + while (raw_prefix_len < 16) + { + switch (raw_prefix[raw_prefix_len]) + { + case ' ': case '(': case ')': case '\\': case '\t': + case '\v': case '\f': case '\n': default: + break; + /* Basic source charset except the above chars. */ + 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': + case '0': case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + case '_': case '{': case '}': case '#': case '[': case ']': + case '<': case '>': case '%': case ':': case ';': case '.': + case '?': case '*': case '+': case '-': case '/': case '^': + case '&': case '|': case '~': case '!': case '=': case ',': + case '"': case '\'': + raw_prefix_len++; + continue; + } + break; + } + + if (raw_prefix[raw_prefix_len] != '(') + { + int col = CPP_BUF_COLUMN (pfile->buffer, raw_prefix + raw_prefix_len) + + 1; + if (raw_prefix_len == 16) + cpp_error_with_line (pfile, CPP_DL_ERROR, token->src_loc, col, + "raw string delimiter longer than 16 characters"); + else + cpp_error_with_line (pfile, CPP_DL_ERROR, token->src_loc, col, + "invalid character '%c' in raw string delimiter", + (int) raw_prefix[raw_prefix_len]); + pfile->buffer->cur = raw_prefix - 1; + create_literal (pfile, token, base, raw_prefix - 1 - base, CPP_OTHER); + return; + } + + cur = raw_prefix + raw_prefix_len + 1; + for (;;) + { +#define BUF_APPEND(STR,LEN) \ + do { \ + bufring_append (pfile, (const uchar *)(STR), (LEN), \ + &first_buff, &last_buff); \ + total_len += (LEN); \ + } while (0); + + cppchar_t c; + + /* If we previously performed any trigraph or line splicing + transformations, undo them within the body of the raw string. */ + while (note->pos < cur) + ++note; + for (; note->pos == cur; ++note) + { + switch (note->type) + { + case '\\': + case ' ': + /* Restore backslash followed by newline. */ + BUF_APPEND (base, cur - base); + base = cur; + BUF_APPEND ("\\", 1); + after_backslash: + if (note->type == ' ') + { + /* GNU backslash whitespace newline extension. FIXME + could be any sequence of non-vertical space. When we + can properly restore any such sequence, we should mark + this note as handled so _cpp_process_line_notes + doesn't warn. */ + BUF_APPEND (" ", 1); + } + + BUF_APPEND ("\n", 1); + break; + + case 0: + /* Already handled. */ + break; + + default: + if (_cpp_trigraph_map[note->type]) + { + /* Don't warn about this trigraph in + _cpp_process_line_notes, since trigraphs show up as + trigraphs in raw strings. */ + uchar type = note->type; + note->type = 0; + + if (!CPP_OPTION (pfile, trigraphs)) + /* If we didn't convert the trigraph in the first + place, don't do anything now either. */ + break; + + BUF_APPEND (base, cur - base); + base = cur; + BUF_APPEND ("??", 2); + + /* ??/ followed by newline gets two line notes, one for + the trigraph and one for the backslash/newline. */ + if (type == '/' && note[1].pos == cur) + { + if (note[1].type != '\\' + && note[1].type != ' ') + abort (); + BUF_APPEND ("/", 1); + ++note; + goto after_backslash; + } + /* The ) from ??) could be part of the suffix. */ + else if (type == ')' + && strncmp ((const char *) cur+1, + (const char *) raw_prefix, + raw_prefix_len) == 0 + && cur[raw_prefix_len+1] == '"') + { + BUF_APPEND (")", 1); + base++; + cur += raw_prefix_len + 2; + goto break_outer_loop; + } + else + { + /* Skip the replacement character. */ + base = ++cur; + BUF_APPEND (&type, 1); + } + } + else + abort (); + break; + } + } + c = *cur++; + + if (c == ')' + && strncmp ((const char *) cur, (const char *) raw_prefix, + raw_prefix_len) == 0 + && cur[raw_prefix_len] == '"') + { + cur += raw_prefix_len + 1; + break; + } + else if (c == '\n') + { + if (pfile->state.in_directive + || pfile->state.parsing_args + || pfile->state.in_deferred_pragma) + { + cur--; + type = CPP_OTHER; + cpp_error_with_line (pfile, CPP_DL_ERROR, token->src_loc, 0, + "unterminated raw string"); + break; + } + + BUF_APPEND (base, cur - base); + + if (pfile->buffer->cur < pfile->buffer->rlimit) + CPP_INCREMENT_LINE (pfile, 0); + pfile->buffer->need_line = true; + + pfile->buffer->cur = cur-1; + _cpp_process_line_notes (pfile, false); + if (!_cpp_get_fresh_line (pfile)) + { + source_location src_loc = token->src_loc; + token->type = CPP_EOF; + /* Tell the compiler the line number of the EOF token. */ + token->src_loc = pfile->line_table->highest_line; + token->flags = BOL; + if (first_buff != NULL) + _cpp_release_buff (pfile, first_buff); + cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0, + "unterminated raw string"); + return; + } + + cur = base = pfile->buffer->cur; + note = &pfile->buffer->notes[pfile->buffer->cur_note]; + } + else if (c == '\0' && !saw_NUL) + LINEMAP_POSITION_FOR_COLUMN (saw_NUL, pfile->line_table, + CPP_BUF_COLUMN (pfile->buffer, cur)); + } + break_outer_loop: + + if (saw_NUL && !pfile->state.skipping) + cpp_error_with_line (pfile, CPP_DL_WARNING, saw_NUL, 0, + "null character(s) preserved in literal"); + + pfile->buffer->cur = cur; + if (first_buff == NULL) + create_literal (pfile, token, base, cur - base, type); + else + { + uchar *dest = _cpp_unaligned_alloc (pfile, total_len + (cur - base) + 1); + + token->type = type; + token->val.str.len = total_len + (cur - base); + token->val.str.text = dest; + last_buff = first_buff; + while (last_buff != NULL) + { + memcpy (dest, last_buff->base, + BUFF_FRONT (last_buff) - last_buff->base); + dest += BUFF_FRONT (last_buff) - last_buff->base; + last_buff = last_buff->next; + } + _cpp_release_buff (pfile, first_buff); + memcpy (dest, base, cur - base); + dest[cur - base] = '\0'; + } +} + +/* Lexes a string, character constant, or angle-bracketed header file + name. The stored string contains the spelling, including opening + quote and any leading 'L', 'u', 'U' or 'u8' and optional + 'R' modifier. It returns the type of the literal, or CPP_OTHER + if it was not properly terminated, or CPP_LESS for an unterminated + header name which must be relexed as normal tokens. + + 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 == 'U') + terminator = *cur++; + else if (terminator == 'u') + { + terminator = *cur++; + if (terminator == '8') + terminator = *cur++; + } + if (terminator == 'R') + { + lex_raw_string (pfile, token, base, cur); + return; + } + if (terminator == '"') + type = (*base == 'L' ? CPP_WSTRING : + *base == 'U' ? CPP_STRING32 : + *base == 'u' ? (base[1] == '8' ? CPP_UTF8STRING : CPP_STRING16) + : CPP_STRING); + else if (terminator == '\'') + type = (*base == 'L' ? CPP_WCHAR : + *base == 'U' ? CPP_CHAR32 : + *base == 'u' ? CPP_CHAR16 : 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--; + /* Unmatched quotes always yield undefined behavior, but + greedy lexing means that what appears to be an unterminated + header name may actually be a legitimate sequence of tokens. */ + if (terminator == '>') + { + token->type = CPP_LESS; + return; + } + 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"); + + if (type == CPP_OTHER && CPP_OPTION (pfile, lang) != CLK_ASM) + cpp_error (pfile, CPP_DL_PEDWARN, "missing terminating %c character", + (int) terminator); + + pfile->buffer->cur = cur; + create_literal (pfile, token, base, cur - base, type); +} + +/* sdcpp specific */ +/* 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 (unsigned char *dest, const unsigned char *src, unsigned int len) +{ + unsigned int n = 0; + const unsigned 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 +_sdcpp_save_asm (cpp_reader *pfile, cpp_token *token, const unsigned char *from, int is_asm) +{ +#define _ASM_STR "__asm" +#define _ASM_LEN ((sizeof _ASM_STR) - 1) +#define _ASM_STR1 "_asm" +#define _ASM_LEN1 ((sizeof _ASM_STR1) - 1) + + unsigned char *buffer; + unsigned int text_len, len; + unsigned int asm_len = is_asm ? _ASM_LEN : _ASM_LEN1; + const char *asm_str = is_asm ? _ASM_STR : _ASM_STR1; + + 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); +} + +/* Return the comment table. The client may not make any assumption + about the ordering of the table. */ +cpp_comment_table * +cpp_get_comments (cpp_reader *pfile) +{ + return &pfile->comments; +} + +/* Append a comment to the end of the comment table. */ +static void +store_comment (cpp_reader *pfile, cpp_token *token) +{ + int len; + + if (pfile->comments.allocated == 0) + { + pfile->comments.allocated = 256; + pfile->comments.entries = (cpp_comment *) xmalloc + (pfile->comments.allocated * sizeof (cpp_comment)); + } + + if (pfile->comments.count == pfile->comments.allocated) + { + pfile->comments.allocated *= 2; + pfile->comments.entries = (cpp_comment *) xrealloc + (pfile->comments.entries, + pfile->comments.allocated * sizeof (cpp_comment)); + } + + len = token->val.str.len; + + /* Copy comment. Note, token may not be NULL terminated. */ + pfile->comments.entries[pfile->comments.count].comment = + (char *) xmalloc (sizeof (char) * (len + 1)); + memcpy (pfile->comments.entries[pfile->comments.count].comment, + token->val.str.text, len); + pfile->comments.entries[pfile->comments.count].comment[len] = '\0'; + + /* Set source location. */ + pfile->comments.entries[pfile->comments.count].sloc = token->src_loc; + + /* Increment the count of entries in the comment table. */ + pfile->comments.count++; +} + +/* 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, i; + + 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 or in argument parsing, 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 || pfile->state.parsing_args) + && 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] = '/'; + /* sdcpp specific */ + copy_text_chars (buffer + 1, from, len); + + /* Finish conversion to a C comment, if necessary. */ + if ((pfile->state.in_directive || pfile->state.parsing_args) && type == '/') + { + buffer[1] = '*'; + buffer[clen - 2] = '*'; + buffer[clen - 1] = '/'; + /* As there can be in a C++ comments illegal sequences for C comments + we need to filter them out. */ + for (i = 2; i < (clen - 2); i++) + if (buffer[i] == '/' && (buffer[i - 1] == '*' || buffer[i + 1] == '*')) + buffer[i] = '|'; + } + + /* Finally store this comment for use by clients of libcpp. */ + store_comment (pfile, token); +} + +/* 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; +} + +/* Look ahead in the input stream. */ +const cpp_token * +cpp_peek_token (cpp_reader *pfile, int index) +{ + cpp_context *context = pfile->context; + const cpp_token *peektok; + int count; + + /* First, scan through any pending cpp_context objects. */ + while (context->prev) + { + ptrdiff_t sz = (context->direct_p + ? LAST (context).token - FIRST (context).token + : LAST (context).ptoken - FIRST (context).ptoken); + + if (index < (int) sz) + return (context->direct_p + ? FIRST (context).token + index + : *(FIRST (context).ptoken + index)); + + index -= (int) sz; + context = context->prev; + } + + /* We will have to read some new tokens after all (and do so + without invalidating preceding tokens). */ + count = index; + pfile->keep_tokens++; + + do + { + peektok = _cpp_lex_token (pfile); + if (peektok->type == CPP_EOF) + return peektok; + } + while (index--); + + _cpp_backup_tokens_direct (pfile, count + 1); + pfile->keep_tokens--; + + return peektok; +} + +/* 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; + ptrdiff_t sz = pfile->cur_run->limit - pfile->cur_token; + ptrdiff_t la = (ptrdiff_t) pfile->lookaheads; + + old = pfile->cur_token - 1; + /* Any pre-existing lookaheads must not be clobbered. */ + if (la) + { + if (sz <= la) + { + tokenrun *next = next_tokenrun (pfile->cur_run); + + if (sz < la) + memmove (next->base + 1, next->base, + (la - sz) * sizeof (cpp_token)); + + next->base[0] = pfile->cur_run->limit[-1]; + } + + if (sz > 1) + memmove (pfile->cur_token + 1, pfile->cur_token, + MIN (la, sz - 1) * sizeof (cpp_token)); + } + + if (!sz && 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; + } + /* We assume that the current token is somewhere in the current + run. */ + if (pfile->cur_token < pfile->cur_run->base + || pfile->cur_token >= pfile->cur_run->limit) + abort (); + + 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) + { + if (_cpp_handle_directive (pfile, result->flags & PREV_WHITE)) + { + if (pfile->directive_result.type == CPP_PADDING) + continue; + result = &pfile->directive_result; + } + } + else if (pfile->state.in_deferred_pragma) + result = &pfile->directive_result; + + 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 || pfile->state.in_deferred_pragma) + 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) + { + /* Clip to buffer size. */ + buffer->next_line = buffer->rlimit; + } + + 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 (pfile->state.in_deferred_pragma) + { + result->type = CPP_PRAGMA_EOL; + pfile->state.in_deferred_pragma = false; + if (!pfile->state.pragma_allow_expansion) + pfile->state.prevent_expansion--; + return result; + } + 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) + { + result->flags |= _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; + /* sdcpp specific */ + 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': + case 'u': + case 'U': + case 'R': + /* 'L', 'u', 'U', 'u8' or 'R' may introduce wide characters, + wide strings or raw strings. */ + if (c == 'L' || CPP_OPTION (pfile, uliterals)) + { + if ((*buffer->cur == '\'' && c != 'R') + || *buffer->cur == '"' + || (*buffer->cur == 'R' + && c != 'R' + && buffer->cur[1] == '"' + && CPP_OPTION (pfile, uliterals)) + || (*buffer->cur == '8' + && c == 'u' + && (buffer->cur[1] == '"' + || (buffer->cur[1] == 'R' && buffer->cur[2] == '"')))) + { + 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 '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 'S': case 'T': case 'V': case 'W': case 'X': + case 'Y': case 'Z': + result->type = CPP_NAME; + { + struct normalize_state nst = INITIAL_NORMALIZE_STATE; + result->val.node.node = lex_identifier (pfile, buffer->cur - 1, false, + &nst); + warn_about_normalization (pfile, result, &nst); + } + + /* SDCC __asm specific */ + /* handle __asm ... __endasm ; */ + if (result->val.node.node == pfile->spec_nodes.n__asm) + { + if (CPP_OPTION (pfile, preproc_asm) == 0) + { + comment_start = buffer->cur; + result->type = CPP_ASM; + _sdcpp_skip_asm_block (pfile); + /* Save the __asm block as a token in its own right. */ + _sdcpp_save_asm (pfile, result, comment_start, result->val.node.node == pfile->spec_nodes.n__asm); + } + result->flags |= ENTER_ASM; + } + else if (result->val.node.node == pfile->spec_nodes.n__endasm) + { + result->flags |= EXIT_ASM; + } + /* Convert named operators to their proper types. */ + else if (result->val.node.node->flags & NODE_OPERATOR) + { + result->flags |= NAMED_OP; + result->type = (enum cpp_ttype) result->val.node.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_warning (pfile, CPP_W_COMMENTS, "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); + if (result->type != CPP_LESS) + 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 (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); + } + 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, result->val.token_no = 0; + } + 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; + /* sdcpp specific */ + 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); result->val.token_no = 0; 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.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 = 6; break; + case SPELL_LITERAL: len = token->val.str.len; break; + case SPELL_IDENT: len = NODE_LEN (token->val.node.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; +} + +/* Given a token TYPE corresponding to a digraph, return a pointer to + the spelling of the digraph. */ +static const unsigned char * +cpp_digraph2name (enum cpp_ttype type) +{ + return digraph_spellings[(int) type - (int) CPP_FIRST_DIGRAPH]; +} + +/* 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 = cpp_digraph2name (token->type); + 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), + NODE_LEN (token->val.node.node)); + buffer += NODE_LEN (token->val.node.node); + } + else + { + size_t i; + const unsigned char * name = NODE_NAME (token->val.node.node); + + for (i = 0; i < NODE_LEN (token->val.node.node); i++) + if (name[i] & ~0x7F) + { + i += utf8_to_ucn (buffer, name + i) - 1; + buffer += 10; + } + else + *buffer++ = NODE_NAME (token->val.node.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; +} + +/* Returns a pointer to a string which spells the token defined by + TYPE and FLAGS. Used by C front ends, which really should move to + using cpp_token_as_text. */ +const char * +cpp_type2name (enum cpp_ttype type, unsigned char flags) +{ + if (flags & DIGRAPH) + return (const char *) cpp_digraph2name (type); + else if (flags & NAMED_OP) + return cpp_named_operator2name (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) +{ + if (token->flags & ENTER_ASM) + in_asm++; + if (token->flags & EXIT_ASM) + in_asm--; + + switch (TOKEN_SPELL (token)) + { + case SPELL_OPERATOR: + { + const unsigned char *spelling; + int c; + + if (token->flags & DIGRAPH) + spelling = cpp_digraph2name (token->type); + 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.node); + + for (i = 0; i < NODE_LEN (token->val.node.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.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: + /* token_no is used to track where multiple consecutive ## + tokens were originally located. */ + return (a->type != CPP_PASTE || a->val.token_no == b->val.token_no); + case SPELL_NONE: + return (a->type != CPP_MACRO_ARG + || a->val.macro_arg.arg_no == b->val.macro_arg.arg_no); + case SPELL_IDENT: + return a->val.node.node == b->val.node.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 == '>'; + case CPP_LESS: return 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); + if (in_asm && token->flags & PREV_NL) + fputs ("\x87 ", fp); + } + + putc ('\n', fp); +} + +/* Return a string representation of all the remaining tokens on the + current line. The result is allocated using xmalloc and must be + freed by the caller. */ +unsigned char * +cpp_output_line_to_string (cpp_reader *pfile, const unsigned char *dir_name) +{ + const cpp_token *token; + unsigned int out = dir_name ? ustrlen (dir_name) : 0; + unsigned int alloced = 120 + out; + unsigned char *result = (unsigned char *) xmalloc (alloced); + + /* If DIR_NAME is empty, there are no initial contents. */ + if (dir_name) + { + sprintf ((char *) result, "#%s ", dir_name); + out += 2; + } + + token = cpp_get_token (pfile); + while (token->type != CPP_EOF) + { + unsigned char *last; + /* Include room for a possible space and the terminating nul. */ + unsigned int len = cpp_token_len (token) + 2; + + if (out + len > alloced) + { + alloced *= 2; + if (out + len > alloced) + alloced = out + len; + result = (unsigned char *) xrealloc (result, alloced); + } + + last = cpp_spell_token (pfile, token, &result[out], 0); + out = last - result; + + token = cpp_get_token (pfile); + if (token->flags & PREV_WHITE) + result[out++] = ' '; + } + + result[out] = '\0'; + return result; +} + +/* 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_OPERATOR: + if (tok->type == CPP_PASTE) + return CPP_TOKEN_FLD_TOKEN_NO; + else + return CPP_TOKEN_FLD_NONE; + 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_PRAGMA; + /* else fall through */ + default: + return CPP_TOKEN_FLD_NONE; + } +} diff --git a/support/cpp/libcpp/line-map.c b/support/cpp/libcpp/line-map.c new file mode 100644 index 0000000..a82c428 --- /dev/null +++ b/support/cpp/libcpp/line-map.c @@ -0,0 +1,319 @@ +/* Map logical line numbers to (source file, line number) pairs. + Copyright (C) 2001, 2003, 2004, 2007, 2008, 2009 + 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 3, 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; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. + + 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 = RESERVED_LOCATION_COUNT - 1; + set->highest_line = RESERVED_LOCATION_COUNT - 1; + set->max_column_hint = 0; + set->reallocator = 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 + 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, linenum_type 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) + { + line_map_realloc reallocator + = set->reallocator ? set->reallocator : xrealloc; + set->allocated = 2 * set->allocated + 256; + set->maps + = (struct line_map *) (*reallocator) (set->maps, + set->allocated + * sizeof (struct line_map)); + memset (&set->maps[set->used], 0, ((set->allocated - set->used) + * sizeof (struct line_map))); + } + + map = &set->maps[set->used]; + + if (to_file && *to_file == '\0' && reason != LC_RENAME_VERBATIM) + to_file = "<stdin>"; + + if (reason == LC_RENAME_VERBATIM) + reason = LC_RENAME; + + /* 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, linenum_type 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; + linenum_type 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 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/cpp/libcpp/macro.c b/support/cpp/libcpp/macro.c new file mode 100644 index 0000000..a89ec33 --- /dev/null +++ b/support/cpp/libcpp/macro.c @@ -0,0 +1,2136 @@ +/* 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, + 2006, 2007, 2008, 2009, 2010 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 3, 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; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. + + 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 *, + const cpp_token *); +static int builtin_macro (cpp_reader *, cpp_hashnode *); +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 *, + _cpp_buff **); +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 *, + _cpp_buff **); +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 *, 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_warning_with_line (pfile, CPP_W_UNUSED_MACROS, 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; + linenum_type number = 1; + + switch (node->value.builtin) + { + default: + cpp_error (pfile, CPP_DL_ICE, "invalid built-in macro \"%s\"", + NODE_NAME (node)); + break; + + case BT_TIMESTAMP: + { + cpp_buffer *pbuffer = cpp_get_buffer (pfile); + if (pbuffer->timestamp == NULL) + { + /* Initialize timestamp value of the assotiated file. */ + struct _cpp_file *file = cpp_get_file (pbuffer); + if (file) + { + /* Generate __TIMESTAMP__ string, that represents + the date and time of the last modification + of the current source file. The string constant + looks like "Sun Sep 16 01:03:52 1973". */ + struct tm *tb = NULL; + struct stat *st = _cpp_get_file_stat (file); + if (st) + tb = localtime (&st->st_mtime); + if (tb) + { + char *str = asctime (tb); + size_t len = strlen (str); + unsigned char *buf = _cpp_unaligned_alloc (pfile, len + 2); + buf[0] = '"'; + strcpy ((char *) buf + 1, str); + buf[len] = '"'; + pbuffer->timestamp = buf; + } + else + { + cpp_errno (pfile, CPP_DL_WARNING, + "could not determine file timestamp"); + pbuffer->timestamp = UC"\"??? ??? ?? ??:??:?? ????\""; + } + } + } + result = pbuffer->timestamp; + } + break; + case BT_FUNCTION: + { + uchar *buf; + buf = _cpp_unaligned_alloc (pfile, 256); + memset (buf, 255, 256); + buf[0] = buf[254] = '"'; + buf[255] = 0; + result = buf; + } + 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. */ + number = SOURCE_LINE (map, + CPP_OPTION (pfile, traditional) + ? pfile->line_table->highest_line + : pfile->cur_token[-1].src_loc); + 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 = UC"\"??? ?? ????\""; + pfile->time = UC"\"??:??:??\""; + } + } + + if (node->value.builtin == BT_DATE) + result = pfile->date; + else + result = pfile->time; + break; + + case BT_COUNTER: + if (CPP_OPTION (pfile, directives_only) && pfile->state.in_directive) + cpp_error (pfile, CPP_DL_ERROR, + "__COUNTER__ expanded inside directive with -fdirectives-only"); + number = pfile->counter++; + 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; + + return _cpp_do__Pragma (pfile); + } + + 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); + _cpp_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->flags & PREV_WHITE) + && token->val.source == NULL)) + source = token->val.source; + continue; + } + + escape_it = (token->type == CPP_STRING || token->type == CPP_CHAR + || token->type == CPP_WSTRING || token->type == CPP_WCHAR + || token->type == CPP_STRING32 || token->type == CPP_CHAR32 + || token->type == CPP_STRING16 || token->type == CPP_CHAR16 + || token->type == CPP_UTF8STRING); + + /* 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, *lhsend; + cpp_token *lhs; + unsigned int len; + + len = cpp_token_len (*plhs) + cpp_token_len (rhs) + 1; + buf = (unsigned char *) alloca (len); + end = lhsend = cpp_spell_token (pfile, *plhs, 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 ((*plhs)->type == CPP_DIV && rhs->type != CPP_EQ) + *end++ = ' '; + /* In one obscure case we might see padding here. */ + if (rhs->type != CPP_PADDING) + 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); + lhs = _cpp_lex_direct (pfile); + if (pfile->buffer->cur != pfile->buffer->rlimit) + { + source_location saved_loc = lhs->src_loc; + + _cpp_pop_buffer (pfile); + _cpp_backup_tokens (pfile, 1); + *lhsend = '\0'; + + /* We have to remove the PASTE_LEFT flag from the old lhs, but + we want to keep the new location. */ + *lhs = **plhs; + *plhs = lhs; + lhs->src_loc = saved_loc; + lhs->flags &= ~PASTE_LEFT; + + /* 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", + buf, cpp_token_as_text (pfile, rhs)); + return false; + } + + *plhs = lhs; + _cpp_pop_buffer (pfile); + return true; +} + +/* 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) + { + if (rhs->flags & PASTE_LEFT) + abort (); + } + if (!paste_tokens (pfile, &lhs, rhs)) + break; + } + while (rhs->flags & PASTE_LEFT); + + /* Put the resulting token in its own context. */ + _cpp_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(). If there are any deferred + #pragma directives among macro arguments, store pointers to the + CPP_PRAGMA ... CPP_PRAGMA_EOL tokens into *PRAGMA_BUFF buffer. */ +static _cpp_buff * +collect_args (cpp_reader *pfile, const cpp_hashnode *node, + _cpp_buff **pragma_buff) +{ + _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; + else if (token->type == CPP_PRAGMA) + { + cpp_token *newtok = _cpp_temp_token (pfile); + + /* CPP_PRAGMA token lives in directive_result, which will + be overwritten on the next directive. */ + *newtok = *token; + token = newtok; + do + { + if (*pragma_buff == NULL + || BUFF_ROOM (*pragma_buff) < sizeof (cpp_token *)) + { + _cpp_buff *next; + if (*pragma_buff == NULL) + *pragma_buff + = _cpp_get_buff (pfile, 32 * sizeof (cpp_token *)); + else + { + next = *pragma_buff; + *pragma_buff + = _cpp_get_buff (pfile, + (BUFF_FRONT (*pragma_buff) + - (*pragma_buff)->base) * 2); + (*pragma_buff)->next = next; + } + } + *(const cpp_token **) BUFF_FRONT (*pragma_buff) = token; + BUFF_FRONT (*pragma_buff) += sizeof (cpp_token *); + if (token->type == CPP_PRAGMA_EOL) + break; + token = cpp_get_token (pfile); + } + while (token->type != CPP_EOF); + + /* In deferred pragmas parsing_args and prevent_expansion + had been changed, reset it. */ + pfile->state.parsing_args = 2; + pfile->state.prevent_expansion = 1; + + if (token->type == CPP_EOF) + break; + else + continue; + } + + 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. PRAGMA_BUFF + argument is the same as in collect_args. */ +static _cpp_buff * +funlike_invocation_p (cpp_reader *pfile, cpp_hashnode *node, + _cpp_buff **pragma_buff) +{ + 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, pragma_buff); + } + + /* 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) + _cpp_push_token_context (pfile, NULL, padding, 1); + } + + return NULL; +} + +/* Return the real number of tokens in the expansion of MACRO. */ +static inline unsigned int +macro_real_token_count (const cpp_macro *macro) +{ + unsigned int i; + if (__builtin_expect (!macro->extra_tokens, true)) + return macro->count; + for (i = 0; i < macro->count; i++) + if (macro->exp.tokens[i].type == CPP_PASTE) + return i; + abort (); + return 0; //makes compiler happy +} + +/* 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. + If there were additionally any unexpanded deferred #pragma directives + among macro arguments, push another context containing the + pragma tokens before the yet-to-be-rescanned replacement list + and return two. Otherwise, we don't push a context and return zero. */ +static int +enter_macro_context (cpp_reader *pfile, cpp_hashnode *node, + const cpp_token *result) +{ + /* The presence of a macro invalidates a file's controlling macro. */ + pfile->mi_valid = false; + + pfile->state.angled_headers = false; + + if ((node->flags & NODE_BUILTIN) && !(node->flags & NODE_USED)) + { + node->flags |= NODE_USED; + if ((!pfile->cb.user_builtin_macro + || !pfile->cb.user_builtin_macro (pfile, node)) + && pfile->cb.used_define) + pfile->cb.used_define (pfile, pfile->directive_line, node); + } + + /* Handle standard macros. */ + if (! (node->flags & NODE_BUILTIN)) + { + cpp_macro *macro = node->value.macro; + _cpp_buff *pragma_buff = NULL; + + 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, &pragma_buff); + pfile->state.parsing_args = 0; + pfile->keep_tokens--; + pfile->state.prevent_expansion--; + + if (buff == NULL) + { + if (CPP_WTRADITIONAL (pfile) && ! node->value.macro->syshdr) + cpp_warning (pfile, CPP_W_TRADITIONAL, + "function-like macro \"%s\" must be used with arguments in traditional C", + NODE_NAME (node)); + + if (pragma_buff) + _cpp_release_buff (pfile, pragma_buff); + + 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; + + if (!(node->flags & NODE_USED)) + { + node->flags |= NODE_USED; + if (pfile->cb.used_define) + pfile->cb.used_define (pfile, pfile->directive_line, node); + } + + if (pfile->cb.used) + pfile->cb.used (pfile, result->src_loc, node); + + macro->used = 1; + + if (macro->paramc == 0) + _cpp_push_token_context (pfile, node, macro->exp.tokens, + macro_real_token_count (macro)); + + if (pragma_buff) + { + if (!pfile->state.in_directive) + _cpp_push_token_context (pfile, NULL, + padding_token (pfile, result), 1); + do + { + _cpp_buff *tail = pragma_buff->next; + pragma_buff->next = NULL; + push_ptoken_context (pfile, NULL, pragma_buff, + (const cpp_token **) pragma_buff->base, + ((const cpp_token **) BUFF_FRONT (pragma_buff) + - (const cpp_token **) pragma_buff->base)); + pragma_buff = tail; + } + while (pragma_buff != NULL); + return 2; + } + + 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; + unsigned int count; + + /* 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. */ + count = macro_real_token_count (macro); + total = count; + limit = macro->exp.tokens + 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.macro_arg.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.macro_arg.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.macro_arg.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; + } + else if (CPP_PEDANTIC (pfile) && ! macro->syshdr + && ! CPP_OPTION (pfile, c99) + && ! cpp_in_system_header (pfile)) + { + cpp_error (pfile, CPP_DL_PEDWARN, + "invoking macro %s argument %d: " + "empty macro arguments are undefined" + " in ISO C90 and ISO C++98", + NODE_NAME (node), + src->val.macro_arg.arg_no); + } + + /* 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. */ +void +_cpp_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; + bool can_set = pfile->set_invocation_location; + pfile->set_invocation_location = false; + + 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.node; + + if (node->type != NT_MACRO || (result->flags & NO_EXPAND)) + break; + + if (!(node->flags & NODE_DISABLED)) + { + int ret = 0; + /* If not in a macro context, and we're going to start an + expansion, record the location. */ + if (can_set && !context->macro) + pfile->invocation_location = result->src_loc; + if (pfile->state.prevent_expansion) + break; + + /* Conditional macros require that a predicate be evaluated + first. */ + if ((node->flags & NODE_CONDITIONAL) != 0) + { + if (pfile->cb.macro_to_expand) + { + bool whitespace_after; + const cpp_token *peek_tok = cpp_peek_token (pfile, 0); + + whitespace_after = (peek_tok->type == CPP_PADDING + || (peek_tok->flags & PREV_WHITE)); + node = pfile->cb.macro_to_expand (pfile, result); + if (node) + ret = enter_macro_context (pfile, node, result); + else if (whitespace_after) + { + /* If macro_to_expand hook returned NULL and it + ate some tokens, see if we don't need to add + a padding token in between this and the + next token. */ + peek_tok = cpp_peek_token (pfile, 0); + if (peek_tok->type != CPP_PADDING + && (peek_tok->flags & PREV_WHITE) == 0) + _cpp_push_token_context (pfile, NULL, + padding_token (pfile, + peek_tok), 1); + } + } + } + else + ret = enter_macro_context (pfile, node, result); + if (ret) + { + if (pfile->state.in_directive || ret == 2) + 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; +} + +/* Like cpp_get_token, but also returns a location separate from the + one provided by the returned token. LOC is an out parameter; *LOC + is set to the location "as expected by the user". This matters + when a token results from macro expansion -- the token's location + will indicate where the macro is defined, but *LOC will be the + location of the start of the expansion. */ +const cpp_token * +cpp_get_token_with_location (cpp_reader *pfile, source_location *loc) +{ + const cpp_token *result; + + pfile->set_invocation_location = true; + result = cpp_get_token (pfile); + if (pfile->context->macro) + *loc = pfile->invocation_location; + else + *loc = result->src_loc; + + 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 obtained from the lexer. */ +void +_cpp_backup_tokens_direct (cpp_reader *pfile, unsigned int count) +{ + 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; + } + } +} + +/* Step back one (or more) tokens. Can only step back 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) + _cpp_backup_tokens_direct (pfile, count); + 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, 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; + + /* Suppress warnings for builtins that lack the NODE_WARN flag. */ + if (node->flags & NODE_BUILTIN) + { + if (!pfile->cb.user_builtin_macro + || !pfile->cb.user_builtin_macro (pfile, node)) + return false; + } + + /* Redefinitions of conditional (context-sensitive) macros, on + the other hand, must be allowed silently. */ + if (node->flags & NODE_CONDITIONAL) + return false; + + /* 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 | NODE_USED); +} + +/* 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.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, cpp_pedantic) + && CPP_OPTION (pfile, warn_variadic_macros)) + cpp_pedwarning + (pfile, CPP_W_VARIADIC_MACROS, + "anonymous variadic macros were introduced in C99"); + } + else if (CPP_OPTION (pfile, cpp_pedantic) + && CPP_OPTION (pfile, warn_variadic_macros)) + cpp_pedwarning (pfile, CPP_W_VARIADIC_MACROS, + "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, *saved_cur_token; + + saved_cur_token = pfile->cur_token; + pfile->cur_token = alloc_expansion_token (pfile, macro); + token = _cpp_lex_direct (pfile); + pfile->cur_token = saved_cur_token; + + /* Is this a parameter? */ + if (token->type == CPP_NAME + && (token->val.node.node->flags & NODE_MACRO_ARG) != 0) + { + token->type = CPP_MACRO_ARG; + token->val.macro_arg.arg_no = token->val.node.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; + bool following_paste_op = false; + #define paste_op_error_msg \ + N_("'##' cannot appear at either end of a macro expansion") + unsigned int num_extra_tokens = 0; + + /* 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) + { + if (token->flags & PREV_WHITE) + token->flags |= SP_PREV_WHITE; + if (token[-1].flags & DIGRAPH) + token->flags |= SP_DIGRAPH; + 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. */ + /* sdcpp specific: don't complain abuout naked hash */ + 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) + { + /* Paste operator constraint 6.10.3.3.1: + Token-paste ##, can appear in both object-like and + function-like macros, but not at the end. */ + if (following_paste_op) + { + cpp_error (pfile, CPP_DL_ERROR, paste_op_error_msg); + return false; + } + 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 beginning. */ + if (macro->count == 1) + { + cpp_error (pfile, CPP_DL_ERROR, paste_op_error_msg); + return false; + } + + if (token[-1].flags & PASTE_LEFT) + { + macro->extra_tokens = 1; + num_extra_tokens++; + token->val.token_no = macro->count - 1; + } + else + { + --macro->count; + token[-1].flags |= PASTE_LEFT; + if (token->flags & DIGRAPH) + token[-1].flags |= SP_DIGRAPH; + if (token->flags & PREV_WHITE) + token[-1].flags |= SP_PREV_WHITE; + } + } + + following_paste_op = (token->type == CPP_PASTE); + 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); + if (num_extra_tokens) + { + /* Place second and subsequent ## or %:%: tokens in + sequences of consecutive such tokens at the end of the + list to preserve information about where they appear, how + they are spelt and whether they are preceded by + whitespace without otherwise interfering with macro + expansion. */ + cpp_token *normal_dest = tokns; + cpp_token *extra_dest = tokns + macro->count - num_extra_tokens; + unsigned int i; + for (i = 0; i < macro->count; i++) + { + if (macro->exp.tokens[i].type == CPP_PASTE) + *extra_dest++ = macro->exp.tokens[i]; + else + *normal_dest++ = macro->exp.tokens[i]; + } + } + else + 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; + macro->extra_tokens = 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 + { + ok = create_iso_definition (pfile, 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. */ + + /* 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)) + { + const int reason = (node->flags & NODE_BUILTIN) + ? CPP_W_BUILTIN_MACRO_REDEFINED : CPP_W_NONE; + bool warned; + + warned = cpp_pedwarning_with_line (pfile, reason, + pfile->directive_line, 0, + "\"%s\" redefined", + NODE_NAME (node)); + + if (warned && node->type == NT_MACRO && !(node->flags & NODE_BUILTIN)) + cpp_error_with_line (pfile, CPP_DL_NOTE, + 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_")) + && ustrcmp (NODE_NAME (node), (const uchar *) "__STDC_FORMAT_MACROS") + /* __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS are mentioned + in the C standard, as something that one must use in C++. + However DR#593 indicates that these aren't actually mentioned + in the C++ standard. We special-case them anyway. */ + && ustrcmp (NODE_NAME (node), (const uchar *) "__STDC_LIMIT_MACROS") + && ustrcmp (NODE_NAME (node), (const uchar *) "__STDC_CONSTANT_MACROS")) + node->flags |= NODE_WARN; + + /* If user defines one of the conditional macros, remove the + conditional flag */ + node->flags &= ~NODE_CONDITIONAL; + + 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, cpp_hashnode *node) +{ + unsigned int i, len; + const cpp_macro *macro; + unsigned char *buffer; + + if (node->type != NT_MACRO || (node->flags & NODE_BUILTIN)) + { + if (node->type != NT_MACRO + || !pfile->cb.user_builtin_macro + || !pfile->cb.user_builtin_macro (pfile, node)) + { + cpp_error (pfile, CPP_DL_ICE, + "invalid hash type %d in cpp_macro_definition", + node->type); + return 0; + } + } + + macro = node->value.macro; + /* 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 + { + unsigned int count = macro_real_token_count (macro); + for (i = 0; i < count; i++) + { + cpp_token *token = ¯o->exp.tokens[i]; + + if (token->type == CPP_MACRO_ARG) + len += NODE_LEN (macro->params[token->val.macro_arg.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. */ + { + unsigned int count = macro_real_token_count (macro); + for (i = 0; i < 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.macro_arg.arg_no - 1]), + NODE_LEN (macro->params[token->val.macro_arg.arg_no - 1])); + buffer += NODE_LEN (macro->params[token->val.macro_arg.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/cpp/libcpp/mkdeps.c b/support/cpp/libcpp/mkdeps.c new file mode 100644 index 0000000..144f0d1 --- /dev/null +++ b/support/cpp/libcpp/mkdeps.c @@ -0,0 +1,447 @@ +/* Dependency generator for Makefile fragments. + Copyright (C) 2000, 2001, 2003, 2007, 2008, 2009 + 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 3, 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; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. + + 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; + + const char **vpathv; + size_t *vpathlv; + unsigned int nvpaths; + unsigned int vpaths_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; + + case '#': + /* '#' is quoted with a backslash. */ + len++; + break; + } + } + + /* Now we know how big to make the buffer. */ + buffer = XNEWVEC (char, 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; + + case '#': + *dst++ = '\\'; + break; + + default: + /* nothing */; + } + *dst = *p; + } + + *dst = '\0'; + return buffer; +} + +/* If T begins with any of the partial pathnames listed in d->vpathv, + then advance T to point beyond that pathname. */ +static const char * +apply_vpath (struct deps *d, const char *t) +{ + if (d->vpathv) + { + unsigned int i; + for (i = 0; i < d->nvpaths; i++) + { + if (!strncmp (d->vpathv[i], t, d->vpathlv[i])) + { + const char *p = t + d->vpathlv[i]; + if (!IS_DIR_SEPARATOR (*p)) + goto not_this_one; + + /* Do not simplify $(vpath)/../whatever. ??? Might not + be necessary. */ + if (p[1] == '.' && p[2] == '.' && IS_DIR_SEPARATOR (p[3])) + goto not_this_one; + + /* found a match */ + t = t + d->vpathlv[i] + 1; + break; + } + not_this_one:; + } + } + + /* Remove leading ./ in any case. */ + while (t[0] == '.' && IS_DIR_SEPARATOR (t[1])) + { + t += 2; + /* If we removed a leading ./, then also remove any /s after the + first. */ + while (IS_DIR_SEPARATOR (t[0])) + ++t; + } + + return t; +} + +/* Public routines. */ + +struct deps * +deps_init (void) +{ + return XCNEW (struct deps); +} + +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); + } + + if (d->vpathv) + { + for (i = 0; i < d->nvpaths; i++) + free ((void *) d->vpathv[i]); + free (d->vpathv); + free (d->vpathlv); + } + + 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 = XRESIZEVEC (const char *, d->targetv, d->targets_size); + } + + t = apply_vpath (d, t); + 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 (apply_vpath (d, t)); /* Also makes permanent copy. */ + + if (d->ndeps == d->deps_size) + { + d->deps_size = d->deps_size * 2 + 8; + d->depv = XRESIZEVEC (const char *, d->depv, d->deps_size); + } + d->depv[d->ndeps++] = t; +} + +void +deps_add_vpath (struct deps *d, const char *vpath) +{ + const char *elem, *p; + char *copy; + size_t len; + + for (elem = vpath; *elem; elem = p) + { + for (p = elem; *p && *p != ':'; p++); + len = p - elem; + copy = XNEWVEC (char, len + 1); + memcpy (copy, elem, len); + copy[len] = '\0'; + if (*p == ':') + p++; + + if (d->nvpaths == d->vpaths_size) + { + d->vpaths_size = d->vpaths_size * 2 + 8; + d->vpathv = XRESIZEVEC (const char *, d->vpathv, d->vpaths_size); + d->vpathlv = XRESIZEVEC (size_t, d->vpathlv, d->vpaths_size); + } + d->vpathv[d->nvpaths] = copy; + d->vpathlv[d->nvpaths] = len; + d->nvpaths++; + } +} + +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 (i) + { + if (colmax && column > colmax) + { + fputs (" \\\n ", fp); + column = 1 + size; + } + else + { + putc (' ', fp); + column++; + } + } + fputs (d->targetv[i], fp); + } + + putc (':', fp); + column++; + + for (i = 0; i < d->ndeps; i++) + { + size = strlen (d->depv[i]); + column += size; + if (colmax && column > colmax) + { + fputs (" \\\n ", fp); + column = 1 + size; + } + else + { + 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 = XNEWVEC (char, 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 = XRESIZEVEC (char, 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/cpp/libcpp/symtab.c b/support/cpp/libcpp/symtab.c new file mode 100644 index 0000000..18be40d --- /dev/null +++ b/support/cpp/libcpp/symtab.c @@ -0,0 +1,363 @@ +/* Hash tables. + Copyright (C) 2000, 2001, 2003, 2004, 2008, 2009 + 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 3, 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; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. + + 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. */ + +static unsigned int calc_hash (const unsigned char *, size_t); +static void ht_expand (hash_table *); +static double approx_sqrt (double); + +/* A deleted entry. */ +#define DELETED ((hashnode) -1) + +/* 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 *(*) (size_t)) 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. 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 allocated. */ +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; + unsigned int deleted_index = table->nslots; + size_t sizemask; + hashnode node; + + sizemask = table->nslots - 1; + index = hash & sizemask; + table->searches++; + + node = table->entries[index]; + + if (node != NULL) + { + if (node == DELETED) + deleted_index = index; + else if (node->hash_value == hash + && HT_LEN (node) == (unsigned int) len + && !memcmp (HT_STR (node), str, len)) + 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 == DELETED) + { + if (deleted_index != table->nslots) + deleted_index = index; + } + else if (node->hash_value == hash + && HT_LEN (node) == (unsigned int) len + && !memcmp (HT_STR (node), str, len)) + return node; + } + } + + if (insert == HT_NO_INSERT) + return NULL; + + /* We prefer to overwrite the first deleted slot we saw. */ + if (deleted_index != table->nslots) + index = deleted_index; + + node = (*table->alloc_node) (table); + table->entries[index] = node; + + HT_LEN (node) = (unsigned int) len; + node->hash_value = hash; + + if (table->alloc_subobject) + { + char *chars = (char *) table->alloc_subobject (len + 1); + memcpy (chars, str, len); + chars[len] = '\0'; + HT_STR (node) = (const unsigned char *) chars; + } + else + HT_STR (node) = (const unsigned char *) obstack_copy0 (&table->stack, + str, len); + + 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 && *p != DELETED) + { + 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 && *p != DELETED) + { + if ((*cb) (table->pfile, *p, v) == 0) + break; + } + while (++p < limit); +} + +/* Like ht_forall, but a nonzero return from the callback means that + the entry should be removed from the table. */ +void +ht_purge (hash_table *table, ht_cb cb, const void *v) +{ + hashnode *p, *limit; + + p = table->entries; + limit = p + table->nslots; + do + if (*p && *p != DELETED) + { + if ((*cb) (table->pfile, *p, v)) + *p = DELETED; + } + 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, deleted = 0; + 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 == DELETED) + ++deleted; + else 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, "deleted\t\t%lu\n", + (unsigned long) deleted); + 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/cpp/libcpp/system.h b/support/cpp/libcpp/system.h new file mode 100644 index 0000000..9dc83e6 --- /dev/null +++ b/support/cpp/libcpp/system.h @@ -0,0 +1,448 @@ +/* Get common system includes and various definitions and declarations based + on autoconf macros. + Copyright (C) 1998-2014 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 3, 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 COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + + +#ifndef LIBCPP_SYSTEM_H +#define LIBCPP_SYSTEM_H + +/* We must include stdarg.h before stdio.h. */ +#include <stdarg.h> + +#ifdef HAVE_STDDEF_H +# include <stddef.h> +#endif +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif +#ifdef HAVE_INTTYPES_H +# include <inttypes.h> +#endif + +#include <stdio.h> + +/* Define a generic NULL if one hasn't already been defined. */ +#ifndef NULL +#define NULL 0 +#endif + +/* Use the unlocked open routines from libiberty. */ + +/* Some of these are #define on some systems, e.g. on AIX to redirect + the names to 64bit capable functions for LARGE_FILES support. These + redefs are pointless here so we can override them. */ + +#undef fopen +#undef freopen + +#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 __cplusplus +extern "C" { +#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 + +#ifdef __cplusplus +} +#endif + +#endif + +/* ??? Glibc's fwrite/fread_unlocked macros cause + "warning: signed and unsigned type in conditional expression". */ +#undef fread_unlocked +#undef fwrite_unlocked + +#include <sys/types.h> +#include <errno.h> + +#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 <string.h> +# include <strings.h> +#else +# ifdef HAVE_STRING_H +# include <string.h> +# else +# ifdef HAVE_STRINGS_H +# include <strings.h> +# endif +# endif +#endif + +#ifdef HAVE_STDLIB_H +# include <stdlib.h> +#endif + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#if HAVE_LIMITS_H +# include <limits.h> +#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 <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# ifdef HAVE_TIME_H +# include <time.h> +# endif +# endif +#endif + +#ifdef HAVE_FCNTL_H +# include <fcntl.h> +#else +# ifdef HAVE_SYS_FILE_H +# include <sys/file.h> +# endif +#endif + +#ifdef HAVE_LOCALE_H +# include <locale.h> +#endif + +#ifdef HAVE_LANGINFO_CODESET +# include <langinfo.h> +#endif + +#ifndef HAVE_SETLOCALE +# define setlocale(category, locale) (locale) +#endif + +#ifdef ENABLE_NLS +#include <libintl.h> +#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_*)". */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined (HAVE_DECL_ABORT) && !HAVE_DECL_ABORT +extern void abort (void); +#endif + +#ifdef __cplusplus +} +#endif + +#if HAVE_SYS_STAT_H +# include <sys/stat.h> +#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" +#include "safe-ctype.h" + +/* 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) +#define HAVE_DESIGNATED_INITIALIZERS \ + (!defined(__cplusplus) \ + && ((GCC_VERSION >= 2007) || (__STDC_VERSION__ >= 199901L))) +#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/cpp/libcpp/traditional.c b/support/cpp/libcpp/traditional.c new file mode 100644 index 0000000..7ff11bb --- /dev/null +++ b/support/cpp/libcpp/traditional.c @@ -0,0 +1,1170 @@ +/* CPP Library - traditional lexical analysis and macro expansion. + Copyright (C) 2002, 2004, 2005, 2007, 2008, 2009 + 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 3, 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; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#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. */ + source_location 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; + fmacro.args = NULL; + fmacro.node = NULL; + fmacro.offset = 0; + fmacro.line = 0; + fmacro.argc = 0; + + 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; + int cxtquote = 0; + + /* Get an estimate of the length of the argument-replaced text. + This is a worst case estimate, assuming that every replacement + text character needs quoting. */ + for (exp = macro->exp.text;;) + { + struct block *b = (struct block *) exp; + + len += b->text_len; + if (b->arg_index == 0) + break; + len += 2 * (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. */ + /* Accumulate actual length, including quoting as necessary */ + p = BUFF_FRONT (buff); + len = 0; + for (exp = macro->exp.text;;) + { + struct block *b = (struct block *) exp; + size_t arglen; + int argquote; + uchar *base; + uchar *in; + + len += b->text_len; + /* Copy the non-argument text literally, keeping + track of whether matching quotes have been seen. */ + for (arglen = b->text_len, in = b->text; arglen > 0; arglen--) + { + if (*in == '"') + cxtquote = ! cxtquote; + *p++ = *in++; + } + /* Done if no more arguments */ + if (b->arg_index == 0) + break; + arglen = (fmacro->args[b->arg_index] + - fmacro->args[b->arg_index - 1] - 1); + base = pfile->out.base + fmacro->args[b->arg_index - 1]; + in = base; +#if 0 + /* Skip leading whitespace in the text for the argument to + be substituted. To be compatible with gcc 2.95, we would + also need to trim trailing whitespace. Gcc 2.95 trims + leading and trailing whitespace, which may be a bug. The + current gcc testsuite explicitly checks that this leading + and trailing whitespace in actual arguments is + preserved. */ + while (arglen > 0 && is_space (*in)) + { + in++; + arglen--; + } +#endif + for (argquote = 0; arglen > 0; arglen--) + { + if (cxtquote && *in == '"') + { + if (in > base && *(in-1) != '\\') + argquote = ! argquote; + /* Always add backslash before double quote if argument + is expanded in a quoted context */ + *p++ = '\\'; + len++; + } + else if (cxtquote && argquote && *in == '\\') + { + /* Always add backslash before a backslash in an argument + that is expanded in a quoted context and also in the + range of a quoted context in the argument itself. */ + *p++ = '\\'; + len++; + } + *p++ = *in++; + len++; + } + 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/cpp/libcpp/ucnid.h b/support/cpp/libcpp/ucnid.h new file mode 100644 index 0000000..e5690b2 --- /dev/null +++ b/support/cpp/libcpp/ucnid.h @@ -0,0 +1,801 @@ +/* Unicode characters and various properties. + Copyright (C) 2003, 2005, 2009 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 3, 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; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. + + + 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 }, |
