Commit 5ff1a832 by Richard Stallman

*** empty log message ***

From-SVN: r948
parent 830a38ee
...@@ -576,12 +576,14 @@ struct definition { ...@@ -576,12 +576,14 @@ struct definition {
U_CHAR *expansion; U_CHAR *expansion;
int line; /* Line number of definition */ int line; /* Line number of definition */
char *file; /* File of definition */ char *file; /* File of definition */
char rest_args; /* Nonzero if last arg. absorbs the rest */
struct reflist { struct reflist {
struct reflist *next; struct reflist *next;
char stringify; /* nonzero if this arg was preceded by a char stringify; /* nonzero if this arg was preceded by a
# operator. */ # operator. */
char raw_before; /* Nonzero if a ## operator before arg. */ char raw_before; /* Nonzero if a ## operator before arg. */
char raw_after; /* Nonzero if a ## operator after 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 int nchars; /* Number of literal chars to copy before
this arg occurrence. */ this arg occurrence. */
int argno; /* Number of arg to substitute (origin-0) */ int argno; /* Number of arg to substitute (origin-0) */
...@@ -604,6 +606,20 @@ union hashval { ...@@ -604,6 +606,20 @@ union hashval {
KEYDEF *keydef; 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 /* The structure of a node in the hash table. The hash table
has entries for all tokens defined by #define commands (type T_MACRO), has entries for all tokens defined by #define commands (type T_MACRO),
...@@ -4527,6 +4543,7 @@ struct arglist { ...@@ -4527,6 +4543,7 @@ struct arglist {
U_CHAR *name; U_CHAR *name;
int length; int length;
int argno; int argno;
char rest_args;
}; };
/* Create a DEFINITION node from a #define directive. Arguments are /* Create a DEFINITION node from a #define directive. Arguments are
...@@ -4541,6 +4558,7 @@ create_definition (buf, limit, op) ...@@ -4541,6 +4558,7 @@ create_definition (buf, limit, op)
int sym_length; /* and how long it is */ int sym_length; /* and how long it is */
int line = instack[indepth].lineno; int line = instack[indepth].lineno;
char *file = instack[indepth].nominal_fname; char *file = instack[indepth].nominal_fname;
int rest_args = 0;
DEFINITION *defn; DEFINITION *defn;
int arglengths = 0; /* Accumulate lengths of arg names int arglengths = 0; /* Accumulate lengths of arg names
...@@ -4575,16 +4593,30 @@ create_definition (buf, limit, op) ...@@ -4575,16 +4593,30 @@ create_definition (buf, limit, op)
temp->name = bp; temp->name = bp;
temp->next = arg_ptrs; temp->next = arg_ptrs;
temp->argno = argno++; temp->argno = argno++;
temp->rest_args = 0;
arg_ptrs = temp; arg_ptrs = temp;
if (!is_idstart[*bp]) if (rest_args)
pedwarn ("parameter name starts with a digit in `#define'"); 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. */ /* Find the end of the arg name. */
while (is_idchar[*bp]) { while (is_idchar[*bp]) {
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; temp->length = bp - temp->name;
if (rest_args == 1)
bp += REST_EXTENSION_LENGTH;
arglengths += temp->length + 2; arglengths += temp->length + 2;
SKIP_WHITE_SPACE (bp); SKIP_WHITE_SPACE (bp);
if (temp->length == 0 || (*bp != ',' && *bp != ')')) { if (temp->length == 0 || (*bp != ',' && *bp != ')')) {
...@@ -4621,6 +4653,7 @@ create_definition (buf, limit, op) ...@@ -4621,6 +4653,7 @@ create_definition (buf, limit, op)
if (bp < limit && (*bp == ' ' || *bp == '\t')) ++bp; if (bp < limit && (*bp == ' ' || *bp == '\t')) ++bp;
/* now everything from bp before limit is the definition. */ /* now everything from bp before limit is the definition. */
defn = collect_expansion (bp, limit, argno, arg_ptrs); defn = collect_expansion (bp, limit, argno, arg_ptrs);
defn->rest_args = rest_args;
/* Now set defn->args.argnames to the result of concatenating /* Now set defn->args.argnames to the result of concatenating
the argument names in reverse order the argument names in reverse order
...@@ -5063,6 +5096,7 @@ collect_expansion (buf, end, nargs, arglist) ...@@ -5063,6 +5096,7 @@ collect_expansion (buf, end, nargs, arglist)
tpat->next = NULL; tpat->next = NULL;
tpat->raw_before = concat == id_beg; tpat->raw_before = concat == id_beg;
tpat->raw_after = 0; tpat->raw_after = 0;
tpat->rest_args = arg->rest_args;
tpat->stringify = (traditional ? expected_delimiter != '\0' tpat->stringify = (traditional ? expected_delimiter != '\0'
: stringify == id_beg); : stringify == id_beg);
...@@ -6737,6 +6771,7 @@ macroexpand (hp, op) ...@@ -6737,6 +6771,7 @@ macroexpand (hp, op)
register U_CHAR *xbuf; register U_CHAR *xbuf;
int xbuf_len; int xbuf_len;
int start_line = instack[indepth].lineno; int start_line = instack[indepth].lineno;
int rest_args, rest_zero;
CHECK_DEPTH (return;); CHECK_DEPTH (return;);
...@@ -6770,13 +6805,24 @@ macroexpand (hp, op) ...@@ -6770,13 +6805,24 @@ macroexpand (hp, op)
/* Parse all the macro args that are supplied. I counts them. /* Parse all the macro args that are supplied. I counts them.
The first NARGS args are stored in ARGS. 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; i = 0;
rest_args = 0;
do { do {
/* Discard the open-parenthesis or comma before the next arg. */ /* Discard the open-parenthesis or comma before the next arg. */
++instack[indepth].bufp; ++instack[indepth].bufp;
parse_error if (rest_args)
= macarg ((i < nargs || (nargs == 0 && i == 0)) ? &args[i] : 0); 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) { if (parse_error) {
error_with_line (line_for_error (start_line), parse_error); error_with_line (line_for_error (start_line), parse_error);
break; break;
...@@ -6793,12 +6839,16 @@ macroexpand (hp, op) ...@@ -6793,12 +6839,16 @@ macroexpand (hp, op)
i = 0; i = 0;
} }
rest_zero = 0;
if (nargs == 0 && i > 0) if (nargs == 0 && i > 0)
error ("arguments given to macro `%s'", hp->name); error ("arguments given to macro `%s'", hp->name);
else if (i < nargs) { else if (i < nargs) {
/* traditional C allows foo() if foo wants one argument. */ /* traditional C allows foo() if foo wants one argument. */
if (nargs == 1 && i == 0 && traditional) 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) else if (i == 0)
error ("macro `%s' used without args", hp->name); error ("macro `%s' used without args", hp->name);
else if (i == 1) else if (i == 1)
...@@ -6822,7 +6872,7 @@ macroexpand (hp, op) ...@@ -6822,7 +6872,7 @@ macroexpand (hp, op)
copied a piece at a time */ copied a piece at a time */
register int totlen; /* total amount of exp buffer filled so far */ 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. */ /* Macro really takes args. Compute the expansion of this call. */
...@@ -6849,11 +6899,16 @@ macroexpand (hp, op) ...@@ -6849,11 +6899,16 @@ macroexpand (hp, op)
OFFSET is the index in the definition OFFSET is the index in the definition
of where we are copying from. */ of where we are copying from. */
offset = totlen = 0; 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]; register struct argdata *arg = &args[ap->argno];
for (i = 0; i < ap->nchars; i++) /* add chars to XBUF unless rest_args was zero with concatenation */
xbuf[totlen++] = exp[offset++]; 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) { if (ap->stringify != 0) {
int arglen = arg->raw_length; int arglen = arg->raw_length;
...@@ -6977,8 +7032,14 @@ macroexpand (hp, op) ...@@ -6977,8 +7032,14 @@ macroexpand (hp, op)
/* if there is anything left of the definition /* if there is anything left of the definition
after handling the arg list, copy that in too. */ after handling the arg list, copy that in too. */
for (i = offset; i < defn->length; i++) for (i = offset; i < defn->length; i++) {
xbuf[totlen++] = exp[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[totlen] = 0;
xbuf_len = totlen; xbuf_len = totlen;
...@@ -7024,12 +7085,14 @@ macroexpand (hp, op) ...@@ -7024,12 +7085,14 @@ macroexpand (hp, op)
/* /*
* Parse a macro argument and store the info on it into *ARGPTR. * 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. * Return nonzero to indicate a syntax error.
*/ */
static char * static char *
macarg (argptr) macarg (argptr, rest_args)
register struct argdata *argptr; register struct argdata *argptr;
int rest_args;
{ {
FILE_BUF *ip = &instack[indepth]; FILE_BUF *ip = &instack[indepth];
int paren = 0; int paren = 0;
...@@ -7039,7 +7102,7 @@ macarg (argptr) ...@@ -7039,7 +7102,7 @@ macarg (argptr)
/* Try to parse as much of the argument as exists at this /* Try to parse as much of the argument as exists at this
input stack level. */ input stack level. */
U_CHAR *bp = macarg1 (ip->bufp, ip->buf + ip->length, 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, /* If we find the end of the argument at this level,
set up *ARGPTR to point at it in the input stack. */ set up *ARGPTR to point at it in the input stack. */
...@@ -7077,7 +7140,7 @@ macarg (argptr) ...@@ -7077,7 +7140,7 @@ macarg (argptr)
newlines = 0; newlines = 0;
comments = 0; comments = 0;
bp = macarg1 (ip->bufp, ip->buf + ip->length, &paren, bp = macarg1 (ip->bufp, ip->buf + ip->length, &paren,
&newlines, &comments); &newlines, &comments, rest_args);
final_start = bufsize; final_start = bufsize;
bufsize += bp - ip->bufp; bufsize += bp - ip->bufp;
extra += newlines; extra += newlines;
...@@ -7166,13 +7229,15 @@ macarg (argptr) ...@@ -7166,13 +7229,15 @@ macarg (argptr)
Value returned is pointer to stopping place. Value returned is pointer to stopping place.
Increment *NEWLINES each time a newline is passed. 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. */ Set *COMMENTS to 1 if a comment is seen. */
static U_CHAR * static U_CHAR *
macarg1 (start, limit, depthptr, newlines, comments) macarg1 (start, limit, depthptr, newlines, comments, rest_args)
U_CHAR *start; U_CHAR *start;
register U_CHAR *limit; register U_CHAR *limit;
int *depthptr, *newlines, *comments; int *depthptr, *newlines, *comments;
int rest_args;
{ {
register U_CHAR *bp = start; register U_CHAR *bp = start;
...@@ -7243,7 +7308,8 @@ macarg1 (start, limit, depthptr, newlines, comments) ...@@ -7243,7 +7308,8 @@ macarg1 (start, limit, depthptr, newlines, comments)
} }
break; break;
case ',': 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; return bp;
break; break;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment