From: Richard Stallman Date: Sat, 9 May 1992 19:37:06 +0000 (+0000) Subject: *** empty log message *** X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=5ff1a832b47d4016f4c0105e325b3d7e13a9e69c;p=gcc.git *** empty log message *** From-SVN: r948 --- diff --git a/gcc/cccp.c b/gcc/cccp.c index 0533b4bc95a..885412bd4bf 100644 --- a/gcc/cccp.c +++ b/gcc/cccp.c @@ -576,12 +576,14 @@ struct definition { U_CHAR *expansion; int line; /* Line number of definition */ char *file; /* File of definition */ + char rest_args; /* Nonzero if last arg. absorbs the rest */ struct reflist { struct reflist *next; char stringify; /* nonzero if this arg was preceded by a # operator. */ char raw_before; /* Nonzero if a ## operator before arg. */ char raw_after; /* Nonzero if a ## operator after arg. */ + char rest_args; /* Nonzero if this arg. absorbs the rest */ int nchars; /* Number of literal chars to copy before this arg occurrence. */ int argno; /* Number of arg to substitute (origin-0) */ @@ -604,6 +606,20 @@ union hashval { KEYDEF *keydef; }; +/* + * 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 outputed. Ex: + * #define wow(a, b...) process(b ## , a, ## b) + * { wow(1, 2); } -> { process( 2, 1,2); } + * { wow(one); } -> { process( one); { + */ +static char rest_extension[] = "..."; +#define REST_EXTENSION_LENGTH (sizeof (rest_extension) - 1) /* The structure of a node in the hash table. The hash table has entries for all tokens defined by #define commands (type T_MACRO), @@ -4527,6 +4543,7 @@ struct arglist { U_CHAR *name; int length; int argno; + char rest_args; }; /* Create a DEFINITION node from a #define directive. Arguments are @@ -4541,6 +4558,7 @@ create_definition (buf, limit, op) int sym_length; /* and how long it is */ int line = instack[indepth].lineno; char *file = instack[indepth].nominal_fname; + int rest_args = 0; DEFINITION *defn; int arglengths = 0; /* Accumulate lengths of arg names @@ -4575,16 +4593,30 @@ create_definition (buf, limit, op) temp->name = bp; temp->next = arg_ptrs; temp->argno = argno++; + temp->rest_args = 0; arg_ptrs = temp; - if (!is_idstart[*bp]) - pedwarn ("parameter name starts with a digit in `#define'"); + if (rest_args) + pedwarn ("another parameter follows `%s'", + rest_extension); + if (!is_idstart[*bp]) + pedwarn ("invalid character in macro parameter name"); + /* Find the end of the arg name. */ while (is_idchar[*bp]) { bp++; + /* do we have a "special" rest-args extension here? */ + if (limit - bp > REST_EXTENSION_LENGTH && + strncmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0) { + rest_args = 1; + temp->rest_args = 1; + break; + } } temp->length = bp - temp->name; + if (rest_args == 1) + bp += REST_EXTENSION_LENGTH; arglengths += temp->length + 2; SKIP_WHITE_SPACE (bp); if (temp->length == 0 || (*bp != ',' && *bp != ')')) { @@ -4621,6 +4653,7 @@ create_definition (buf, limit, op) if (bp < limit && (*bp == ' ' || *bp == '\t')) ++bp; /* now everything from bp before limit is the definition. */ defn = collect_expansion (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 @@ -5063,6 +5096,7 @@ collect_expansion (buf, end, nargs, arglist) tpat->next = NULL; tpat->raw_before = concat == id_beg; tpat->raw_after = 0; + tpat->rest_args = arg->rest_args; tpat->stringify = (traditional ? expected_delimiter != '\0' : stringify == id_beg); @@ -6737,6 +6771,7 @@ macroexpand (hp, op) register U_CHAR *xbuf; int xbuf_len; int start_line = instack[indepth].lineno; + int rest_args, rest_zero; CHECK_DEPTH (return;); @@ -6770,13 +6805,24 @@ macroexpand (hp, op) /* Parse all the macro args that are supplied. I counts them. The first NARGS args are stored in ARGS. - The rest are discarded. */ + The rest are discarded. + If rest_args is set then we assume macarg absorbed the rest of the args. + */ i = 0; + rest_args = 0; do { /* Discard the open-parenthesis or comma before the next arg. */ ++instack[indepth].bufp; - parse_error - = macarg ((i < nargs || (nargs == 0 && i == 0)) ? &args[i] : 0); + if (rest_args) + continue; + if (i < nargs || (nargs == 0 && i == 0)) { + /* if we are working on last arg which absorbes rest of args... */ + if (i == nargs - 1 && defn->rest_args) + rest_args = 1; + parse_error = macarg (&args[i], rest_args); + } + else + parse_error = macarg (0, 0); if (parse_error) { error_with_line (line_for_error (start_line), parse_error); break; @@ -6793,12 +6839,16 @@ macroexpand (hp, op) i = 0; } + rest_zero = 0; if (nargs == 0 && i > 0) error ("arguments given to macro `%s'", hp->name); else if (i < nargs) { /* traditional C allows foo() if foo wants one argument. */ if (nargs == 1 && i == 0 && traditional) ; + /* the rest args token is allowed to absorb 0 tokens */ + else if (i == nargs - 1 && defn->rest_args) + rest_zero = 1; else if (i == 0) error ("macro `%s' used without args", hp->name); else if (i == 1) @@ -6822,7 +6872,7 @@ macroexpand (hp, op) copied a piece at a time */ register int totlen; /* total amount of exp buffer filled so far */ - register struct reflist *ap; + register struct reflist *ap, *last_ap; /* Macro really takes args. Compute the expansion of this call. */ @@ -6849,11 +6899,16 @@ macroexpand (hp, op) OFFSET is the index in the definition of where we are copying from. */ offset = totlen = 0; - for (ap = defn->pattern; ap != NULL; ap = ap->next) { + for (last_ap = NULL, ap = defn->pattern; ap != NULL; + last_ap = ap, ap = ap->next) { register struct argdata *arg = &args[ap->argno]; - for (i = 0; i < ap->nchars; i++) - xbuf[totlen++] = exp[offset++]; + /* add chars to XBUF unless rest_args was zero with concatenation */ + for (i = 0; i < ap->nchars; i++, offset++) + if (! (rest_zero && ((ap->rest_args && ap->raw_before) + || (last_ap != NULL && last_ap->rest_args + && last_ap->raw_after)))) + xbuf[totlen++] = exp[offset]; if (ap->stringify != 0) { int arglen = arg->raw_length; @@ -6977,8 +7032,14 @@ macroexpand (hp, op) /* if there is anything left of the definition after handling the arg list, copy that in too. */ - for (i = offset; i < defn->length; i++) - xbuf[totlen++] = exp[i]; + for (i = offset; i < defn->length; i++) { + /* if we've reached the end of the macro */ + if (exp[i] == ')') + rest_zero = 0; + if (! (rest_zero && last_ap != NULL && last_ap->rest_args + && last_ap->raw_after)) + xbuf[totlen++] = exp[i]; + } xbuf[totlen] = 0; xbuf_len = totlen; @@ -7024,12 +7085,14 @@ macroexpand (hp, op) /* * Parse a macro argument and store the info on it into *ARGPTR. + * REST_ARGS is passed to macarg1 to make it absorb the rest of the args. * Return nonzero to indicate a syntax error. */ static char * -macarg (argptr) +macarg (argptr, rest_args) register struct argdata *argptr; + int rest_args; { FILE_BUF *ip = &instack[indepth]; int paren = 0; @@ -7039,7 +7102,7 @@ macarg (argptr) /* Try to parse as much of the argument as exists at this input stack level. */ U_CHAR *bp = macarg1 (ip->bufp, ip->buf + ip->length, - &paren, &newlines, &comments); + &paren, &newlines, &comments, rest_args); /* If we find the end of the argument at this level, set up *ARGPTR to point at it in the input stack. */ @@ -7077,7 +7140,7 @@ macarg (argptr) newlines = 0; comments = 0; bp = macarg1 (ip->bufp, ip->buf + ip->length, &paren, - &newlines, &comments); + &newlines, &comments, rest_args); final_start = bufsize; bufsize += bp - ip->bufp; extra += newlines; @@ -7166,13 +7229,15 @@ macarg (argptr) Value returned is pointer to stopping place. Increment *NEWLINES each time a newline is passed. + REST_ARGS notifies macarg1 that it should absorb the rest of the args. Set *COMMENTS to 1 if a comment is seen. */ static U_CHAR * -macarg1 (start, limit, depthptr, newlines, comments) +macarg1 (start, limit, depthptr, newlines, comments, rest_args) U_CHAR *start; register U_CHAR *limit; int *depthptr, *newlines, *comments; + int rest_args; { register U_CHAR *bp = start; @@ -7243,7 +7308,8 @@ macarg1 (start, limit, depthptr, newlines, comments) } break; case ',': - if ((*depthptr) == 0) + /* if we've returned to lowest level and we aren't absorbing all args */ + if ((*depthptr) == 0 && rest_args == 0) return bp; break; }