+ if (!cppReader_isTraditional (pfile) && expected_delimiter == '\0')
+ {
+ /* If ANSI, put in a "@ " marker to prevent token pasting.
+ But not if "inside a string" (which in ANSI mode
+ happens only for -D option). */
+ *exp_p++ = '@';
+ *exp_p++ = ' ';
+ }
+
+ *exp_p = '\0';
+
+ defn->length = size_fromInt (exp_p - defn->expansion);
+
+ /* Crash now if we overrun the allocated size. */
+ if (defn->length + 1 > maxsize)
+ {
+ llfatalbug (cstring_makeLiteral ("Maximum definition size exceeded."));
+ }
+
+ return defn;
+}
+
+/*
+** evans 2001-12-31
+** Gasp...cut-and-pasted from above to deal with pfile (should replace throughout with this...)
+*/
+
+static DEFINITION *
+collect_expansionLoc (fileloc loc, char *buf, char *limit,
+ int nargs, /*@null@*/ struct arglist *arglist)
+{
+ DEFINITION *defn;
+ char *p, *lastp, *exp_p;
+ struct reflist *endpat = NULL;
+ /* Pointer to first nonspace after last ## seen. */
+ char *concat = 0;
+ /* Pointer to first nonspace after last single-# seen. */
+ char *stringify = 0;
+ size_t maxsize;
+ char expected_delimiter = '\0';
+
+
+ /* Scan thru the replacement list, ignoring comments and quoted
+ strings, picking up on the macro calls. It does a linear search
+ thru the arg list on every potential symbol. Profiling might say
+ that something smarter should happen. */
+
+ if (limit < buf)
+ {
+ llfatalbug (message ("%q: Limit is less than initial buffer pointer",
+ fileloc_unparse (loc)));
+ }
+
+ /* Find the beginning of the trailing whitespace. */
+ p = buf;
+
+ while (p < limit && is_space[(int) limit[-1]])
+ {
+ limit--;
+ }
+
+ /* Allocate space for the text in the macro definition.
+ Leading and trailing whitespace chars need 2 bytes each.
+ Each other input char may or may not need 1 byte,
+ so this is an upper bound. The extra 5 are for invented
+ leading and trailing newline-marker and final null. */
+ maxsize = (sizeof (*defn) + (limit - p) + 5);
+
+ /* Occurrences of '@' get doubled, so allocate extra space for them. */
+ while (p < limit)
+ {
+ if (*p++ == '@')
+ {
+ maxsize++;
+ }
+ }
+
+ defn = (DEFINITION *) dmalloc (maxsize);
+ defn->noExpand = FALSE;
+ defn->file = NULL;
+ defn->pattern = NULL;
+ defn->nargs = nargs;
+ defn->predefined = NULL;
+
+ exp_p = defn->expansion = (char *) defn + sizeof (*defn);
+
+ defn->line = 0;
+ defn->rest_args = NULL;
+ defn->args.argnames = NULL;
+
+ lastp = exp_p;
+
+ p = buf;
+
+ /* Add one initial space escape-marker to prevent accidental
+ token-pasting (often removed by cpplib_macroExpand). */
+ *exp_p++ = '@';
+ *exp_p++ = ' ';
+
+ if (limit - p >= 2 && p[0] == '#' && p[1] == '#') {
+ voptgenerror (FLG_PREPROC,
+ cstring_makeLiteral ("Paste marker ## at start of macro definition"),
+ loc);
+ p += 2;
+ }
+
+ /* Process the main body of the definition. */
+ while (p < limit) {
+ int skipped_arg = 0;
+ register char c = *p++;
+
+ *exp_p++ = c;
+
+ if (TRUE) { /* !cppReader_isTraditional (pfile)) { */
+ switch (c) {
+ case '\'':
+ case '\"':
+ if (expected_delimiter != '\0')
+ {
+ if (c == expected_delimiter)
+ expected_delimiter = '\0';
+ }
+ else
+ {
+ expected_delimiter = c;
+ }
+ /*@switchbreak@*/ break;
+
+ case '\\':
+ if (p < limit && (expected_delimiter != '\0'))
+ {
+ /* In a string, backslash goes through
+ and makes next char ordinary. */
+ *exp_p++ = *p++;
+ }
+ /*@switchbreak@*/ break;
+
+ case '@':
+ /* An '@' in a string or character constant stands for itself,
+ and does not need to be escaped. */
+ if (expected_delimiter == '\0')
+ {
+ *exp_p++ = c;
+ }
+
+ /*@switchbreak@*/ break;
+
+ case '#':
+ /* # is ordinary inside a string. */
+ if (expected_delimiter != '\0')
+ {
+ /*@switchbreak@*/ break;
+ }
+
+ if (p < limit && *p == '#') {
+ /* ##: concatenate preceding and following tokens. */
+ /* Take out the first #, discard preceding whitespace. */
+ exp_p--;
+
+ /*@-usedef@*/
+ while (exp_p > lastp && is_hor_space[(int) exp_p[-1]])
+ {
+ --exp_p;
+ }
+ /*@=usedef@*/
+
+ /* Skip the second #. */
+ p++;
+ /* Discard following whitespace. */
+ SKIP_WHITE_SPACE (p);
+ concat = p;
+ if (p == limit)
+ {
+ voptgenerror (FLG_PREPROC,
+ cstring_makeLiteral ("`##' at end of macro definition"),
+ loc);
+ }
+ } else if (nargs >= 0) {
+ /* Single #: stringify following argument ref.
+ Don't leave the # in the expansion. */
+ exp_p--;
+ SKIP_WHITE_SPACE (p);
+ if (p == limit || ! is_idstart[(int) *p]
+ || (*p == 'L' && p + 1 < limit && (p[1] == '\'' || p[1] == '\"')))
+ {
+ voptgenerror
+ (FLG_PREPROC,
+ cstring_makeLiteral ("`#' operator is not followed by a macro argument name"),
+ loc);
+ }
+ else
+ stringify = p;
+ } else {
+ ; /* BADBRANCH; */
+ }
+
+ /*@switchbreak@*/ break;
+ }
+ } else {
+ /* In -traditional mode, recognize arguments inside strings and
+ and character constants, and ignore special properties of #.
+ Arguments inside strings are considered "stringified", but no
+ extra quote marks are supplied. */
+ switch (c) {
+ case '\'':
+ case '\"':
+ if (expected_delimiter != '\0') {
+ if (c == expected_delimiter)
+ expected_delimiter = '\0';
+ } else
+ expected_delimiter = c;
+ /*@switchbreak@*/ break;
+
+ case '\\':
+ /* Backslash quotes delimiters and itself, but not macro args. */
+ if (expected_delimiter != '\0' && p < limit
+ && (*p == expected_delimiter || *p == '\\')) {
+ *exp_p++ = *p++;
+ continue;
+ }
+ /*@switchbreak@*/ break;
+
+ case '/':
+ if (expected_delimiter != '\0') /* No comments inside strings. */
+ /*@switchbreak@*/ break;
+ if (*p == '*') {
+ /* If we find a comment that wasn't removed by cppReader_handleDirective,
+ this must be -traditional. So replace the comment with
+ nothing at all. */
+ exp_p--;
+ p += 1;
+ while (p < limit && !(p[-2] == '*' && p[-1] == '/'))
+ {
+ p++;
+ }
+ }
+ /*@switchbreak@*/ break;
+ }
+ }
+
+ /* Handle the start of a symbol. */
+ if (is_idchar[(int) c] && nargs > 0) {
+ char *id_beg = p - 1;
+ int id_len;
+
+ --exp_p;
+ while (p != limit && is_idchar[(int) *p])
+ {
+ p++;
+ }
+
+ id_len = p - id_beg;
+
+ if (is_idstart[(int) c]
+ && ! (id_len == 1 && c == 'L' && (*p == '\'' || *p == '\"'))) {
+ register struct arglist *arg;
+
+ for (arg = arglist; arg != NULL; arg = arg->next) {
+ struct reflist *tpat;
+
+ if (arg->name[0] == c
+ && arg->length == id_len
+ && strncmp (arg->name, id_beg, size_fromInt (id_len)) == 0) {
+ char *p1;
+
+ if (expected_delimiter) { /* && CPPOPTIONS (pfile)->warn_stringify) { */
+ if (FALSE) { /* cppReader_isTraditional (pfile)) { */
+ voptgenerror (FLG_PREPROC,
+ message ("macro argument `%x' is stringified.",
+ cstring_prefix (cstring_fromChars (arg->name), id_len)),
+ loc);
+
+ } else {
+ voptgenerror (FLG_PREPROC,
+ message ("Macro arg `%x' would be stringified with -traditional.",
+ cstring_prefix (cstring_fromChars (arg->name), id_len)),
+ loc);
+
+ }
+ }
+ /* If ANSI, don't actually substitute inside a string. */
+ if (TRUE /* !cppReader_isTraditional (pfile) */ && expected_delimiter)
+ /*@innerbreak@*/ break;
+ /* make a pat node for this arg and append it to the end of
+ the pat list */
+ tpat = (struct reflist *) dmalloc (sizeof (*tpat));
+ tpat->next = NULL;
+ tpat->raw_before = (concat == id_beg);
+ tpat->raw_after = 0;
+ tpat->rest_args = arg->rest_args;
+ tpat->stringify = (FALSE /* cppReader_isTraditional (pfile) */
+ ? expected_delimiter != '\0'
+ : stringify == id_beg);
+
+ if (endpat == NULL)
+ {
+ defn->pattern = tpat;
+ }
+ else
+ {
+ endpat->next = tpat;
+ /*@-branchstate@*/
+ } /*@=branchstate@*/ /* evs 2000 was =branchstate */
+
+ endpat = tpat;
+
+ tpat->argno = arg->argno;
+ tpat->nchars = exp_p - lastp;
+
+ p1 = p;
+
+ SKIP_WHITE_SPACE (p1);
+
+ if (p1 + 2 <= limit && p1[0] == '#' && p1[1] == '#')
+ {
+ tpat->raw_after = 1;
+ }
+
+ lastp = exp_p; /* place to start copying from next time */
+ skipped_arg = 1;
+
+ /*@innerbreak@*/ break;
+ }
+ }
+ }
+
+ /* If this was not a macro arg, copy it into the expansion. */
+ if (skipped_arg == 0) {
+ register char *lim1 = p;
+ p = id_beg;
+
+ while (p != lim1)
+ {
+ *exp_p++ = *p++;
+ }
+
+ if (stringify == id_beg)
+ {
+ voptgenerror
+ (FLG_PREPROC,
+ cstring_makeLiteral ("# operator should be followed by a macro argument name"),
+ loc);
+ }
+ }
+ }
+ }
+
+ if (/*!cppReader_isTraditional (pfile) && */ expected_delimiter == '\0')