diff options
author | Neil Booth <neil@daikokuya.demon.co.uk> | 2002-06-07 06:26:32 +0000 |
---|---|---|
committer | Neil Booth <neil@gcc.gnu.org> | 2002-06-07 06:26:32 +0000 |
commit | c70f6ed31478e27420d2038d09f3a343422db22f (patch) | |
tree | 6aed42053a56ed0593bc263de6125d7efc67c493 /gcc/cpptrad.c | |
parent | aec2ac46a748e1d224db7cf7ce05a4516918c8ff (diff) | |
download | gcc-c70f6ed31478e27420d2038d09f3a343422db22f.tar.gz |
cpptrad.c (struct block, [...]): New.
* cpptrad.c (struct block, BLOCK_HEADER_LEN, BLOCK_LEN,
scan_parameters, save_replacement_text, replacement_length): New.
(scan_out_logical_line): Take a macro and save parameters if
non-NULL.
(_cpp_logical_line_trad): Update.
(_cpp_create_trad_definition): Update to handle function-like
macros.
* cpplex.c (new_buff): Update.
(struct dummy, DEFAULT_ALIGNMENT, CPP_ALIGN): Move...
* cpphash.h: ...here.
(CPP_ALIGN2, _cpp_save_parameter): New.
* cppmacro.c (save_parameter): Rename, export.
(parse_params): Update.
From-SVN: r54331
Diffstat (limited to 'gcc/cpptrad.c')
-rw-r--r-- | gcc/cpptrad.c | 239 |
1 files changed, 206 insertions, 33 deletions
diff --git a/gcc/cpptrad.c b/gcc/cpptrad.c index 63972487333..3886b4522c7 100644 --- a/gcc/cpptrad.c +++ b/gcc/cpptrad.c @@ -21,6 +21,29 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "cpplib.h" #include "cpphash.h" +/* The replacement text of a function-like macro is stored as a + contiguous sequence of aligned blocks. Each block represents the + portion of text from the start of the previous block (or the start + of the macro replacement text in the case of the first block) to + the next parameter, or the end of the replacement list if there + are none left. + + Each block consists of an unsigned int, which is the length of text + contained in the third part, an unsigned short, which is the + one-based index of the argument that immediately follows that text, + and the text itself. The final block in the macro expansion is + recognizable as it has an argument index of zero. */ + +struct block +{ + unsigned int text_len; + unsigned short arg_index; + uchar text[1]; +}; + +#define BLOCK_HEADER_LEN offsetof (struct block, text) +#define BLOCK_LEN(TEXT_LEN) CPP_ALIGN (BLOCK_HEADER_LEN + TEXT_LEN) + /* 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 @@ -32,10 +55,14 @@ static const uchar *skip_escaped_newlines PARAMS ((cpp_reader *, static const uchar *skip_whitespace PARAMS ((cpp_reader *, const uchar *)); static cpp_hashnode *lex_identifier PARAMS ((cpp_reader *, const uchar *)); static const uchar *skip_comment PARAMS ((cpp_reader *, const uchar *)); -static void scan_out_logical_line PARAMS ((cpp_reader *pfile)); +static void scan_out_logical_line PARAMS ((cpp_reader *pfile, cpp_macro *)); static void check_output_buffer PARAMS ((cpp_reader *, size_t)); static void restore_buff PARAMS ((cpp_reader *)); 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 *)); /* Ensures we have N bytes' space in the output buffer, and reallocates it if not. */ @@ -272,7 +299,7 @@ _cpp_read_logical_line_trad (pfile) CUR (pfile->context) = buffer->cur; RLIMIT (pfile->context) = buffer->rlimit; pfile->trad_out_cur = pfile->trad_out_base; - scan_out_logical_line (pfile); + scan_out_logical_line (pfile, NULL); buffer->cur = CUR (pfile->context); pfile->trad_line = pfile->line; @@ -284,10 +311,15 @@ _cpp_read_logical_line_trad (pfile) /* Copies the next logical line in the current buffer to the output buffer. The output is guaranteed to terminate with a NUL - character. */ + 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 + argument. */ static void -scan_out_logical_line (pfile) +scan_out_logical_line (pfile, macro) cpp_reader *pfile; + cpp_macro *macro; { cpp_context *context; const uchar *cur; @@ -379,21 +411,30 @@ scan_out_logical_line (pfile) case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': - { - cpp_hashnode *node; - - pfile->trad_out_cur = --out; - node = lex_identifier (pfile, cur - 1); - if (node->type == NT_MACRO) - { - /* Remove the macro name from the output. */ - pfile->trad_out_cur = out; - push_replacement_text (pfile, node); - goto new_context; - } - out = pfile->trad_out_cur; - cur = CUR (context); - } + if (quote == 0 || macro) + { + cpp_hashnode *node; + + pfile->trad_out_cur = --out; + node = lex_identifier (pfile, cur - 1); + + if (node->type == NT_MACRO && !pfile->state.prevent_expansion) + { + /* Remove the macro name from the output. */ + 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. */ + pfile->trad_out_cur = out; + save_replacement_text (pfile, macro, node->arg_index); + } + + out = pfile->trad_out_cur; + cur = CUR (context); + } break; default: @@ -417,36 +458,168 @@ push_replacement_text (pfile, node) macro->exp.text + macro->count); } -/* Analyze and save the replacement text of a macro. */ +/* Read and record the parameters, if any, of a function-like macro + definition. Destroys pfile->trad_out_cur. + + Returns true on success, false on failure (syntax error or a + duplicate parameter). On success, CUR (pfile->context) is just + past the closing parenthesis. */ +static bool +scan_parameters (pfile, macro) + cpp_reader *pfile; + cpp_macro *macro; +{ + const uchar *cur = CUR (pfile->context) + 1; + bool ok; + + for (;;) + { + cur = skip_whitespace (pfile, cur); + + if (ISIDST (*cur)) + { + ok = false; + if (_cpp_save_parameter (pfile, macro, lex_identifier (pfile, cur))) + break; + cur = skip_whitespace (pfile, CUR (pfile->context)); + if (*cur == ',') + { + cur++; + continue; + } + ok = (*cur == ')'); + break; + } + + ok = (*cur == ')' && macro->paramc == 0); + break; + } + + CUR (pfile->context) = cur + (*cur == ')'); + + 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 + text. */ +static void +save_replacement_text (pfile, macro, arg_index) + cpp_reader *pfile; + cpp_macro *macro; + unsigned int arg_index; +{ + size_t len = pfile->trad_out_cur - pfile->trad_out_base; + uchar *exp; + + if (macro->paramc == 0) + { + /* Object-like and function-like macros without parameters + simply store their NUL-terminated replacement text. */ + exp = _cpp_unaligned_alloc (pfile, len + 1); + memcpy (exp, pfile->trad_out_base, len); + exp[len] = '\0'; + macro->exp.text = exp; + macro->count = len; + } + else + { + /* Store the text's length (unsigned int), the argument index + (unsigned short, base 1) and then the text. */ + size_t blen = BLOCK_LEN (len); + struct block *block; + + if (macro->count + blen > BUFF_ROOM (pfile->a_buff)) + _cpp_extend_buff (pfile, &pfile->a_buff, macro->count + blen); + + exp = BUFF_FRONT (pfile->a_buff); + block = (struct block *) (exp + macro->count); + macro->exp.text = exp; + + /* Write out the block information. */ + block->text_len = len; + block->arg_index = arg_index; + memcpy (block->text, pfile->trad_out_base, len); + + /* Lex the rest into the start of the output buffer. */ + pfile->trad_out_cur = pfile->trad_out_base; + + /* If this is the end of the macro, count up the bytes of text + 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; + } +} + +/* Analyze and save the replacement text of a macro. Returns true on + success. */ bool _cpp_create_trad_definition (pfile, macro) cpp_reader *pfile; cpp_macro *macro; { - const uchar *cur, *limit; - uchar *exp; - size_t len; + 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. */ + if (!scan_parameters (pfile, macro)) + macro = NULL; + else + { + /* Success. Commit the parameter array. */ + macro->params = (cpp_hashnode **) BUFF_FRONT (pfile->a_buff); + BUFF_FRONT (pfile->a_buff) = (uchar *) ¯o->params[macro->paramc]; + macro->fun_like = 1; + } + + CUR (pfile->context) = skip_whitespace (pfile, CUR (pfile->context)); + } + pfile->trad_out_cur = pfile->trad_out_base; - scan_out_logical_line (pfile); + pfile->state.prevent_expansion++; + scan_out_logical_line (pfile, macro); + pfile->state.prevent_expansion--; + + if (!macro) + return false; /* Skip trailing white space. */ cur = pfile->trad_out_base; limit = pfile->trad_out_cur; while (limit > cur && is_space (limit[-1])) limit--; - - len = (size_t) (limit - cur); - exp = _cpp_unaligned_alloc (pfile, len + 1); - memcpy (exp, cur, len); - exp[len] = '\0'; - - macro->exp.text = exp; - /* Include NUL. */ - macro->count = len; + pfile->trad_out_cur = limit; + save_replacement_text (pfile, macro, 0); return true; } |