diff options
author | Neil Booth <neil@daikokuya.demon.co.uk> | 2002-06-09 20:04:17 +0000 |
---|---|---|
committer | Neil Booth <neil@gcc.gnu.org> | 2002-06-09 20:04:17 +0000 |
commit | 1ce676a061d91b434a62d90d7a2f5d8fdf07e8af (patch) | |
tree | a2b5349f1ee2ab348cfc3c37c8f4c9a4ca8a6b1b /gcc/cpptrad.c | |
parent | 25f2e176414291186a206bb5f7cdc3e98563b38b (diff) | |
download | gcc-1ce676a061d91b434a62d90d7a2f5d8fdf07e8af.zip gcc-1ce676a061d91b434a62d90d7a2f5d8fdf07e8af.tar.gz gcc-1ce676a061d91b434a62d90d7a2f5d8fdf07e8af.tar.bz2 |
cpphash.h (_cpp_push_text_context): Update.
* cpphash.h (_cpp_push_text_context): Update.
(_cpp_arguments_ok): New.
* cppmacro.c (_cpp_arguments_ok): New, split out from...
(collect_args): ...here.
(_cpp_push_text_context): Change inputs.
* cpptrad.c (struct fun_macro, maybe_start_funlike, save_argument,
replace_args_and_push): New.
(lex_identifier, _cpp_lex_identifier_trad, scan_parameters):
Don't use IS macros directly.
(scan_out_logical_line): Handle function-like macro argument
collection.
(push_replacement_text): Update.
(replacement_length): Remove.
(_cpp_create_trad_definition): Don't skip whitespace before
checking for '('.
From-SVN: r54412
Diffstat (limited to 'gcc/cpptrad.c')
-rw-r--r-- | gcc/cpptrad.c | 296 |
1 files changed, 243 insertions, 53 deletions
diff --git a/gcc/cpptrad.c b/gcc/cpptrad.c index 3886b45..7ba9d92 100644 --- a/gcc/cpptrad.c +++ b/gcc/cpptrad.c @@ -44,6 +44,29 @@ struct block #define BLOCK_HEADER_LEN offsetof (struct block, text) #define BLOCK_LEN(TEXT_LEN) CPP_ALIGN (BLOCK_HEADER_LEN + TEXT_LEN) +/* Structure holding information about a function-like macro + invocation. */ +struct fun_macro +{ + /* Memory buffer holding the trad_arg array. */ + _cpp_buff *buff; + + /* An array of size the number of macro parameters + 1, containing + the offsets of the start of each macro argument in the output + buffer. The argument continues until the character before the + start of the next one. */ + size_t *args; + + /* The hashnode of the macro. */ + cpp_hashnode *node; + + /* The offset of the macro name in the output buffer. */ + size_t offset; + + /* Zero-based index of argument being currently lexed. */ + unsigned int argc; +}; + /* Lexing TODO: Handle -C, maybe -CC, and space in escaped newlines. Stop cpplex.c from recognizing comments and directives during its lexing pass. Get rid of line_base usage - seems pointless? Do we @@ -62,7 +85,10 @@ static void push_replacement_text PARAMS ((cpp_reader *, cpp_hashnode *)); static bool scan_parameters PARAMS ((cpp_reader *, cpp_macro *)); static void save_replacement_text PARAMS ((cpp_reader *, cpp_macro *, unsigned int)); -static unsigned int replacement_length PARAMS ((cpp_macro *)); +static void maybe_start_funlike PARAMS ((cpp_reader *, cpp_hashnode *, + const uchar *, struct fun_macro *)); +static void save_argument PARAMS ((struct fun_macro *, size_t)); +static void replace_args_and_push PARAMS ((cpp_reader *, struct fun_macro *)); /* Ensures we have N bytes' space in the output buffer, and reallocates it if not. */ @@ -205,10 +231,10 @@ lex_identifier (pfile, cur) { do *out++ = *cur++; - while (ISIDNUM (*cur)); + while (is_numchar (*cur)); cur = skip_escaped_newlines (pfile, cur); } - while (ISIDNUM (*cur)); + while (is_numchar (*cur)); CUR (pfile->context) = cur; len = out - pfile->trad_out_cur; @@ -226,7 +252,7 @@ _cpp_lex_identifier_trad (pfile) { const uchar *cur = skip_whitespace (pfile, CUR (pfile->context)); - if (!ISIDST (*cur)) + if (!is_idstart (*cur)) { CUR (pfile->context) = cur; return NULL; @@ -309,12 +335,45 @@ _cpp_read_logical_line_trad (pfile) return true; } +/* Set up state for finding the opening '(' of a function-like + macro. */ +static void +maybe_start_funlike (pfile, node, start, macro) + cpp_reader *pfile; + cpp_hashnode *node; + const uchar *start; + struct fun_macro *macro; +{ + unsigned int n = node->value.macro->paramc + 1; + + if (macro->buff) + _cpp_release_buff (pfile, macro->buff); + macro->buff = _cpp_get_buff (pfile, n * sizeof (size_t)); + macro->args = (size_t *) BUFF_FRONT (macro->buff); + macro->node = node; + macro->offset = start - pfile->trad_out_base; + macro->argc = 0; + + pfile->state.parsing_args = 1; +} + +/* Save the OFFSET of the start of the next argument to MACRO. */ +static void +save_argument (macro, offset) + struct fun_macro *macro; + size_t offset; +{ + macro->argc++; + if (macro->argc <= macro->node->value.macro->paramc) + macro->args[macro->argc] = offset; +} + /* Copies the next logical line in the current buffer to the output buffer. The output is guaranteed to terminate with a NUL character. If MACRO is non-NULL, then we are scanning the replacement list of - MACRO, and we call save_replacement_text every time we meet an + MACRO, and we call save_replacement_text() every time we meet an argument. */ static void scan_out_logical_line (pfile, macro) @@ -323,9 +382,11 @@ scan_out_logical_line (pfile, macro) { cpp_context *context; const uchar *cur; - unsigned int c, quote = 0; + unsigned int c, paren_depth, quote = 0; uchar *out; + struct fun_macro fmacro; + fmacro.buff = NULL; new_context: context = pfile->context; cur = CUR (context); @@ -357,16 +418,22 @@ scan_out_logical_line (pfile, macro) cur--; if (!pfile->buffer->from_stage3) cpp_error (pfile, DL_PEDWARN, "no newline at end of file"); + if (pfile->state.parsing_args == 2) + cpp_error (pfile, DL_ERROR, + "unterminated argument list invoking macro \"%s\"", + NODE_NAME (fmacro.node)); pfile->line++; - goto finish_output; + goto done; case '\r': case '\n': cur = handle_newline (pfile, cur - 1); - out[-1] = '\0'; - finish_output: - CUR (context) = cur; - pfile->trad_out_cur = out - 1; - return; + if (pfile->state.parsing_args == 2) + { + /* Newlines in arguments become a space. */ + out[-1] = ' '; + continue; + } + goto done; case '"': case '\'': @@ -418,16 +485,25 @@ scan_out_logical_line (pfile, macro) pfile->trad_out_cur = --out; node = lex_identifier (pfile, cur - 1); - if (node->type == NT_MACRO && !pfile->state.prevent_expansion) + if (node->type == NT_MACRO + && pfile->state.parsing_args != 2 + && !pfile->state.prevent_expansion) { - /* Remove the macro name from the output. */ - pfile->trad_out_cur = out; - push_replacement_text (pfile, node); - goto new_context; + if (node->value.macro->fun_like) + maybe_start_funlike (pfile, node, out, &fmacro); + else + { + /* Remove the object-like macro's name from the + output, and push its replacement text. */ + pfile->trad_out_cur = out; + push_replacement_text (pfile, node); + goto new_context; + } } else if (macro && node->arg_index) { - /* Remove the macro name from the output. */ + /* Found a parameter in the replacement text of a + #define. Remove its name from the output. */ pfile->trad_out_cur = out; save_replacement_text (pfile, macro, node->arg_index); } @@ -437,15 +513,91 @@ scan_out_logical_line (pfile, macro) } break; + case '(': + if (quote == 0) + { + paren_depth++; + if (pfile->state.parsing_args == 1) + { + const uchar *p = pfile->trad_out_base + fmacro.offset; + + /* Invoke a prior function-like macro if there is only + white space in-between. */ + while (is_numchar (*p)) + p++; + while (is_space (*p)) + p++; + + if (p == out - 1) + { + pfile->state.parsing_args = 2; + paren_depth = 1; + out = pfile->trad_out_base + fmacro.offset; + fmacro.args[0] = fmacro.offset; + } + else + pfile->state.parsing_args = 0; + } + } + break; + + case ',': + if (quote == 0 && pfile->state.parsing_args == 2 && paren_depth == 1) + save_argument (&fmacro, out - pfile->trad_out_base); + break; + + case ')': + if (quote == 0) + { + paren_depth--; + if (pfile->state.parsing_args == 2 && paren_depth == 0) + { + cpp_macro *m = fmacro.node->value.macro; + + pfile->state.parsing_args = 0; + save_argument (&fmacro, out - pfile->trad_out_base); + + /* A single whitespace argument is no argument. */ + if (fmacro.argc == 1 && m->paramc == 0) + { + const uchar *p = pfile->trad_out_base; + p += fmacro.args[0]; + while (is_space (*p)) + p++; + if (p == pfile->trad_out_base + fmacro.args[1]) + fmacro.argc = 0; + } + + if (_cpp_arguments_ok (pfile, m, fmacro.node, fmacro.argc)) + { + /* Remove the macro's invocation from the + output, and push its replacement text. */ + pfile->trad_out_cur = (pfile->trad_out_base + + fmacro.offset); + CUR (context) = cur; + replace_args_and_push (pfile, &fmacro); + goto new_context; + } + } + } + break; + default: break; } } + + done: + out[-1] = '\0'; + CUR (context) = cur; + pfile->trad_out_cur = out - 1; + if (fmacro.buff) + _cpp_release_buff (pfile, fmacro.buff); } /* Push a context holding the replacement text of the macro NODE on - the context stack. Doesn't yet handle special built-ins or - function-like macros. */ + the context stack. NODE is either object-like, or a function-like + macro with no arguments. */ static void push_replacement_text (pfile, node) cpp_reader *pfile; @@ -453,9 +605,70 @@ push_replacement_text (pfile, node) { cpp_macro *macro = node->value.macro; - _cpp_push_text_context (pfile, node, - macro->exp.text, - macro->exp.text + macro->count); + _cpp_push_text_context (pfile, node, macro->exp.text, macro->count); +} + +/* Push a context holding the replacement text of the macro NODE on + the context stack. NODE is either object-like, or a function-like + macro with no arguments. */ +static void +replace_args_and_push (pfile, fmacro) + cpp_reader *pfile; + struct fun_macro *fmacro; +{ + cpp_macro *macro = fmacro->node->value.macro; + + if (macro->paramc == 0) + push_replacement_text (pfile, fmacro->node); + else + { + const uchar *exp; + uchar *p; + _cpp_buff *buff; + size_t len = 0; + + /* Calculate the length of the argument-replaced text. */ + for (exp = macro->exp.text;;) + { + struct block *b = (struct block *) exp; + + len += b->text_len; + if (b->arg_index == 0) + break; + len += (fmacro->args[b->arg_index] + - fmacro->args[b->arg_index - 1] - 1); + exp += BLOCK_LEN (b->text_len); + } + + /* Allocate room for the expansion plus NUL. */ + buff = _cpp_get_buff (pfile, len + 1); + + /* Copy the expansion and replace arguments. */ + p = BUFF_FRONT (buff); + for (exp = macro->exp.text;;) + { + struct block *b = (struct block *) exp; + size_t arglen; + + memcpy (p, b->text, b->text_len); + p += b->text_len; + if (b->arg_index == 0) + break; + arglen = (fmacro->args[b->arg_index] + - fmacro->args[b->arg_index - 1] - 1); + memcpy (p, pfile->trad_out_base + fmacro->args[b->arg_index - 1], + arglen); + p += arglen; + exp += BLOCK_LEN (b->text_len); + } + + /* NUL-terminate. */ + *p = '\0'; + _cpp_push_text_context (pfile, fmacro->node, BUFF_FRONT (buff), len); + + /* So we free buffer allocation when macro is left. */ + pfile->context->buff = buff; + } } /* Read and record the parameters, if any, of a function-like macro @@ -476,7 +689,7 @@ scan_parameters (pfile, macro) { cur = skip_whitespace (pfile, cur); - if (ISIDST (*cur)) + if (is_idstart (*cur)) { ok = false; if (_cpp_save_parameter (pfile, macro, lex_identifier (pfile, cur))) @@ -500,25 +713,6 @@ scan_parameters (pfile, macro) return ok; } -/* Calculate the length of the replacement text of MACRO. */ -static unsigned int -replacement_length (macro) - cpp_macro *macro; -{ - unsigned int result = 0; - const uchar *exp = macro->exp.text; - - for (;;) - { - struct block *block = (struct block *) exp; - - result += block->text_len; - if (block->arg_index == 0) - return result; - exp += BLOCK_LEN (block->text_len); - } -} - /* Save the text from pfile->trad_out_base to pfile->trad_out_cur as the replacement text for the current macro, followed by argument ARG_INDEX, with zero indicating the end of the replacement @@ -568,10 +762,7 @@ save_replacement_text (pfile, macro, arg_index) in the replacement list, excluding the parameter names, and save this in macro->count, else store the total bytes in the replacement text so far (including block headers). */ - if (arg_index == 0) - macro->count = replacement_length (macro); - else - macro->count += blen; + macro->count += blen; } } @@ -585,13 +776,11 @@ _cpp_create_trad_definition (pfile, macro) const uchar *cur; uchar *limit; - /* Skip leading whitespace now. */ - CUR (pfile->context) = skip_whitespace (pfile, CUR (pfile->context)); - /* Is this a function-like macro? */ if (* CUR (pfile->context) == '(') { - /* Setting macro to NULL indicates an error occurred. */ + /* Setting macro to NULL indicates an error occurred, and + prevents unnecessary work in scan_out_logical_line. */ if (!scan_parameters (pfile, macro)) macro = NULL; else @@ -601,10 +790,11 @@ _cpp_create_trad_definition (pfile, macro) BUFF_FRONT (pfile->a_buff) = (uchar *) ¯o->params[macro->paramc]; macro->fun_like = 1; } - - CUR (pfile->context) = skip_whitespace (pfile, CUR (pfile->context)); } + /* Skip leading whitespace in the replacement text. */ + CUR (pfile->context) = skip_whitespace (pfile, CUR (pfile->context)); + pfile->trad_out_cur = pfile->trad_out_base; pfile->state.prevent_expansion++; scan_out_logical_line (pfile, macro); |