diff options
| author | Alexander Viro <viro@parcelfarce.linux.theplanet.co.uk> | 2004-06-08 11:23:40 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-07 21:02:06 -0700 |
| commit | 8793aa6363551e96ab623e2927fcc13bb7b84e69 (patch) | |
| tree | ef3adbdd252c555d4199e38bcd41bf6e03922c41 | |
| parent | 7e18e251c72d92c73b3b6cfcff0877bcb433fdb2 (diff) | |
| download | sparse-dev-8793aa6363551e96ab623e2927fcc13bb7b84e69.tar.gz | |
[PATCH] saner handling of argument lists
This does two things:
a) get C99 varargs to use the same mechanism as gcc ones use - all
we need is to internally convert final ... in the list to ident[__VA_ARGS__]
and set its ->next to &variable_argument. After that we don't need any
special-casing for them.
b) take parsing the argument list in a separate function and does
it with all sanity checks; normally it ends up with fewer tests than old
variant.
| -rw-r--r-- | pre-process.c | 108 | ||||
| -rw-r--r-- | validation/preprocessor11.c | 10 |
2 files changed, 93 insertions, 25 deletions
diff --git a/pre-process.c b/pre-process.c index d91c0059..e648035b 100644 --- a/pre-process.c +++ b/pre-process.c @@ -201,8 +201,7 @@ static struct token *find_argument_end(struct token *start, struct token *arglis start->next = &eof_token_entry; return next->next; } - } else if (!nesting && match_op(next, ',') && arglist->next != &variable_argument - && !match_op(arglist, SPECIAL_ELLIPSIS)) { + } else if (!nesting && match_op(next, ',') && arglist->next != &variable_argument) { next->special = SPECIAL_ARG_SEPARATOR; arglist = arglist->next; } @@ -644,6 +643,84 @@ static int token_list_different(struct token *list1, struct token *list2) } } +static struct token *parse_arguments(struct token *list) +{ + struct token *arg = list->next, *next = list; + + if (match_op(arg, ')')) { + list->next = &eof_token_entry; + return arg->next; + } + + while (token_type(arg) == TOKEN_IDENT) { + if (arg->ident == &__VA_ARGS___ident) + goto Eva_args; + next = arg->next; + + if (match_op(next, ',')) { + arg = arg->next = next->next; + continue; + } + + if (match_op(next, ')')) { + arg->next = &eof_token_entry; + return next->next; + } + + /* normal cases are finished here */ + + if (match_op(next, SPECIAL_ELLIPSIS)) { + arg->next = &variable_argument; + if (match_op(next->next, ')')) + return next->next->next; + + arg = next; + goto Enotclosed; + } + + if (eof_token(next)) { + goto Enotclosed; + } else { + arg = next; + goto Ebadstuff; + } + } + + if (match_op(arg, SPECIAL_ELLIPSIS)) { + next = arg->next; + token_type(arg) = TOKEN_IDENT; + arg->ident = &__VA_ARGS___ident; + arg->next = &variable_argument; + if (!match_op(next, ')')) + goto Enotclosed; + return next->next; + } + + if (eof_token(arg)) { + arg = next; + goto Enotclosed; + } + if (match_op(arg, ',')) + goto Emissing; + else + goto Ebadstuff; + + +Emissing: + warn(arg->pos, "parameter name missing"); + return NULL; +Ebadstuff: + warn(arg->pos, "\"%s\" may not appear in macro parameter list", + show_token(arg)); + return NULL; +Enotclosed: + warn(arg->pos, "missing ')' in macro parameter list"); + return NULL; +Eva_args: + warn(arg->pos, "__VA_ARGS__ can only appear in the expansion of a C99 variadic macro"); + return NULL; +} + static int try_arg(struct token *token, enum token_type type, struct token *arglist) { struct ident *ident = token->ident; @@ -653,8 +730,7 @@ static int try_arg(struct token *token, enum token_type type, struct token *argl return 0; for (nr = 0; !eof_token(arglist); nr++, arglist = arglist->next) { - if ((match_op(arglist, SPECIAL_ELLIPSIS) && ident == &__VA_ARGS___ident) || - arglist->ident == ident) { + if (arglist->ident == ident) { token->argnum = nr; token_type(token) = type; return 1; @@ -727,27 +803,9 @@ static int handle_define(struct stream *stream, struct token *head, struct token expansion = left->next; if (!expansion->pos.whitespace && match_op(expansion, '(')) { arglist = expansion; - while (!eof_token(expansion)) { - struct token *next = expansion->next; - if (token_type(expansion) == TOKEN_IDENT) { - if (expansion->ident == &__VA_ARGS___ident) - warn(expansion->pos, "__VA_ARGS__ can only appear in the expansion of a C99 variadic macro"); - if (match_op(next, SPECIAL_ELLIPSIS)) { - expansion->next = &variable_argument; - expansion = next; - next = next->next; - } - } - if (match_op(next, ')')) { - // Terminate the arglist - expansion->next = &eof_token_entry; - expansion = next->next; - break; - } - if (match_op(next, ',')) - expansion->next = next->next; - expansion = next; - } + expansion = parse_arguments(expansion); + if (!expansion) + return 1; arglist = arglist->next; } diff --git a/validation/preprocessor11.c b/validation/preprocessor11.c new file mode 100644 index 00000000..4c6c1c0a --- /dev/null +++ b/validation/preprocessor11.c @@ -0,0 +1,10 @@ +#define A(1) x +#define B(x +#define C(x, +#define D(,) +#define E(__VA_ARGS__) +#define F(x+ +#define G(x..., +#define H(x...,y) +#define I(...+ +#define J(x,y) |
