+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;
+ size_t id_len;
+
+ --exp_p;
+ while (p != limit && is_idchar[(int) *p])
+ {
+ p++;
+ }
+
+ id_len = size_fromInt (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, 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')
+ {
+ /* 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;
+}
+
+/*
+ * special extension string that can be added to the last macro argument to
+ * allow it to absorb the "rest" of the arguments when expanded. Ex:
+ * #define wow(a, b...) process (b, a, b)
+ * { wow (1, 2, 3); } -> { process (2, 3, 1, 2, 3); }
+ * { wow (one, two); } -> { process (two, one, two); }
+ * if this "rest_arg" is used with the concat token '##' and if it is not
+ * supplied then the token attached to with ## will not be outputted. Ex:
+ * #define wow (a, b...) process (b ## , a, ## b)
+ * { wow (1, 2); } -> { process (2, 1, 2); }
+ * { wow (one); } -> { process (one); {
+ */
+
+/*@-readonlytrans@*/
+static char rest_extension[] = "...";
+/*:=readonlytrans@*/
+
+/*@notfunction@*/
+#define REST_EXTENSION_LENGTH (sizeof (rest_extension) - 1)
+
+/* Create a DEFINITION node from a #define directive. Arguments are
+ as for do_define. */
+
+
+static /*@null@*/ macroDef
+create_definition (/*@exposed@*/ char *buf, char *limit,
+ cppReader *pfile, bool predefinition,
+ bool noExpand)
+{
+ char *bp; /* temp ptr into input buffer */
+ char *symname; /* remember where symbol name starts */
+ size_t sym_length; /* and how long it is */
+ int rest_args = 0; /* really int! */
+ int line;
+ int col;
+ cstring file = (CPPBUFFER (pfile) != NULL)
+ ? CPPBUFFER (pfile)->nominal_fname : cstring_makeLiteralTemp ("");
+ DEFINITION *defn;
+ int arglengths = 0; /* Accumulate lengths of arg names
+ plus number of args. */
+ macroDef mdef;
+ char save = *limit;
+ *limit = '\0';
+ DPRINTF (("Create definition: %s", buf));
+ *limit = save;
+
+ cppBuffer_getLineAndColumn (CPPBUFFER (pfile), &line, &col);
+
+ bp = buf;
+
+ while (is_hor_space[(int) *bp])
+ {
+ bp++;
+ }
+
+ symname = bp; /* remember where it starts */
+
+ sym_length = cppReader_checkMacroName (pfile, bp, cstring_makeLiteralTemp ("macro"));
+
+ bp += sym_length;
+
+ /* Lossage will occur if identifiers or control keywords are broken
+ across lines using backslash. This is not the right place to take
+ care of that. */
+
+ if (*bp == '(') {
+ struct arglist *arg_ptrs = NULL;
+ int argno = 0;
+
+ bp++; /* skip '(' */
+ SKIP_WHITE_SPACE (bp);
+
+ /* Loop over macro argument names. */
+ while (*bp != ')')
+ {
+ struct arglist *temp = (struct arglist *) dmalloc (sizeof (*temp));
+ temp->name = bp;
+ temp->next = arg_ptrs;
+ temp->argno = argno++;
+ temp->rest_args = 0;
+
+ arg_ptrs = temp;
+
+ if (rest_args != 0)
+ {
+ cppReader_pedwarn (pfile,
+ message ("another parameter follows `%s'",
+ cstring_fromChars (rest_extension)));
+ }
+
+ if (!is_idstart[(int) *bp])
+ {
+ cppReader_pedwarnLit (pfile,
+ cstring_makeLiteralTemp ("invalid character in macro parameter name"));
+ }
+
+ /* Find the end of the arg name. */
+ while (is_idchar[(int) *bp])
+ {
+ bp++;
+ /* do we have a "special" rest-args extension here? */
+ if (limit - bp > size_toInt (REST_EXTENSION_LENGTH)
+ && strncmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0)
+ {
+ rest_args = 1;
+ temp->rest_args = 1;
+ /*@innerbreak@*/ break;
+ }
+ }
+
+ temp->length = size_fromInt (bp - temp->name);
+
+ if (rest_args != 0)
+ {
+ bp += REST_EXTENSION_LENGTH;
+ }
+
+ arglengths += temp->length + 2;
+ SKIP_WHITE_SPACE (bp);
+
+ if (temp->length == 0 || (*bp != ',' && *bp != ')')) {
+ cppReader_errorLit (pfile,
+ cstring_makeLiteralTemp ("Parameter list for #define is not parseable"));
+ goto nope;
+ }
+
+ if (*bp == ',') {
+ bp++;
+ SKIP_WHITE_SPACE (bp);
+ }
+ if (bp >= limit) {
+ cppReader_errorLit (pfile,
+ cstring_makeLiteralTemp ("unterminated parameter list in `#define'"));
+ goto nope;
+ }
+ {
+ struct arglist *otemp;
+
+ for (otemp = temp->next; otemp != NULL; otemp = otemp->next)
+ {
+ if (temp->length == otemp->length &&
+ strncmp (temp->name, otemp->name, temp->length) == 0) {
+ cstring name = cstring_copyLength (temp->name, temp->length);
+ cppReader_error (pfile,
+ message ("duplicate argument name `%x' in `#define'", name));
+ goto nope;
+ }
+ }
+ }
+ }
+
+ ++bp; /* skip paren */
+ SKIP_WHITE_SPACE (bp);
+ /* now everything from bp before limit is the definition. */
+ defn = collect_expansion (pfile, bp, limit, argno, arg_ptrs);
+ defn->rest_args = rest_args;
+
+ /* Now set defn->args.argnames to the result of concatenating
+ the argument names in reverse order
+ with comma-space between them. */
+ defn->args.argnames = (char *) dmalloc (size_fromInt (arglengths + 1));
+
+ {
+ struct arglist *temp;
+ int i = 0;
+ for (temp = arg_ptrs; temp != NULL; temp = temp->next)
+ {
+ memcpy (&defn->args.argnames[i], temp->name, temp->length);
+ i += temp->length;
+ if (temp->next != 0)
+ {
+ defn->args.argnames[i++] = ',';
+ defn->args.argnames[i++] = ' ';
+ }
+ }
+
+ defn->args.argnames[i] = '\0';
+ }
+
+ sfree (arg_ptrs);
+ } else {
+ /* Simple expansion or empty definition. */
+
+ if (bp < limit)
+ {
+ if (is_hor_space[(int) *bp]) {
+ bp++;
+ SKIP_WHITE_SPACE (bp);
+ } else {
+ switch (*bp) {
+ 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 '}': case '~':
+ cppReader_warning (pfile,
+ message ("Missing white space after #define %x",
+ cstring_prefix (cstring_fromChars (symname),
+ sym_length)));
+ break;
+
+ default:
+ cppReader_pedwarn (pfile,
+ message ("Missing white space after #define %x",
+ cstring_prefix (cstring_fromChars (symname),
+ sym_length)));
+ break;
+ }
+ }
+ }
+ /* now everything from bp before limit is the definition. */
+ defn = collect_expansion (pfile, bp, limit, -1, NULL);
+ defn->args.argnames = mstring_createEmpty ();
+ }
+
+ defn->noExpand = noExpand;
+ DPRINTF (("No expand: %d", noExpand));
+
+ defn->line = line;
+
+ /* not: llassert (cstring_isUndefined (defn->file)); */
+ defn->file = file;
+
+ /* OP is null if this is a predefinition */
+ defn->predefined = predefinition;
+ mdef.defn = defn;
+ mdef.symnam = symname;
+ mdef.symlen = sym_length;