aboutsummaryrefslogtreecommitdiff
path: root/gcc/cpptrad.c
diff options
context:
space:
mode:
authorNeil Booth <neil@daikokuya.demon.co.uk>2002-06-07 06:26:32 +0000
committerNeil Booth <neil@gcc.gnu.org>2002-06-07 06:26:32 +0000
commitc70f6ed31478e27420d2038d09f3a343422db22f (patch)
tree6aed42053a56ed0593bc263de6125d7efc67c493 /gcc/cpptrad.c
parentaec2ac46a748e1d224db7cf7ce05a4516918c8ff (diff)
downloadgcc-c70f6ed31478e27420d2038d09f3a343422db22f.zip
gcc-c70f6ed31478e27420d2038d09f3a343422db22f.tar.gz
gcc-c70f6ed31478e27420d2038d09f3a343422db22f.tar.bz2
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.c239
1 files changed, 206 insertions, 33 deletions
diff --git a/gcc/cpptrad.c b/gcc/cpptrad.c
index 6397248..3886b45 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 *) &macro->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;
}