コード例 #1
0
ファイル: macroexp.c プロジェクト: 5kg/gdb
static void
set_token (struct macro_buffer *tok, char *start, char *end)
{
  init_shared_buffer (tok, start, end - start);
  tok->last_token = 0;

  /* Presumed; get_identifier may overwrite this.  */
  tok->is_identifier = 0;
}
コード例 #2
0
ファイル: macroexp.c プロジェクト: 5kg/gdb
char *
macro_expand_next (char **lexptr,
                   macro_lookup_ftype *lookup_func,
                   void *lookup_baton)
{
  struct macro_buffer src, dest, tok;
  struct cleanup *back_to;

  /* Set up SRC to refer to the input text, pointed to by *lexptr.  */
  init_shared_buffer (&src, *lexptr, strlen (*lexptr));

  /* Set up DEST to receive the expansion, if there is one.  */
  init_buffer (&dest, 0);
  dest.last_token = 0;
  back_to = make_cleanup (cleanup_macro_buffer, &dest);

  /* Get the text's first preprocessing token.  */
  if (! get_token (&tok, &src))
    {
      do_cleanups (back_to);
      return 0;
    }

  /* If it's a macro invocation, expand it.  */
  if (maybe_expand (&dest, &tok, &src, 0, lookup_func, lookup_baton))
    {
      /* It was a macro invocation!  Package up the expansion as a
         null-terminated string and return it.  Set *lexptr to the
         start of the next token in the input.  */
      appendc (&dest, '\0');
      discard_cleanups (back_to);
      *lexptr = src.text;
      return dest.text;
    }
  else
    {
      /* It wasn't a macro invocation.  */
      do_cleanups (back_to);
      return 0;
    }
}
コード例 #3
0
ファイル: macroexp.c プロジェクト: 5kg/gdb
char *
macro_expand (const char *source,
              macro_lookup_ftype *lookup_func,
              void *lookup_func_baton)
{
  struct macro_buffer src, dest;
  struct cleanup *back_to;

  init_shared_buffer (&src, (char *) source, strlen (source));

  init_buffer (&dest, 0);
  dest.last_token = 0;
  back_to = make_cleanup (cleanup_macro_buffer, &dest);

  scan (&dest, &src, 0, lookup_func, lookup_func_baton);

  appendc (&dest, '\0');

  discard_cleanups (back_to);
  return dest.text;
}
コード例 #4
0
ファイル: macroexp.c プロジェクト: 5kg/gdb
static void
substitute_args (struct macro_buffer *dest, 
                 struct macro_definition *def,
		 int is_varargs, const struct macro_buffer *va_arg_name,
                 int argc, struct macro_buffer *argv,
                 struct macro_name_list *no_loop,
                 macro_lookup_ftype *lookup_func,
                 void *lookup_baton)
{
  /* A macro buffer for the macro's replacement list.  */
  struct macro_buffer replacement_list;
  /* The token we are currently considering.  */
  struct macro_buffer tok;
  /* The replacement list's pointer from just before TOK was lexed.  */
  char *original_rl_start;
  /* We have a single lookahead token to handle token splicing.  */
  struct macro_buffer lookahead;
  /* The lookahead token might not be valid.  */
  int lookahead_valid;
  /* The replacement list's pointer from just before LOOKAHEAD was
     lexed.  */
  char *lookahead_rl_start;

  init_shared_buffer (&replacement_list, (char *) def->replacement,
                      strlen (def->replacement));

  gdb_assert (dest->len == 0);
  dest->last_token = 0;

  original_rl_start = replacement_list.text;
  if (! get_token (&tok, &replacement_list))
    return;
  lookahead_rl_start = replacement_list.text;
  lookahead_valid = get_token (&lookahead, &replacement_list);

  for (;;)
    {
      /* Just for aesthetics.  If we skipped some whitespace, copy
         that to DEST.  */
      if (tok.text > original_rl_start)
        {
          appendmem (dest, original_rl_start, tok.text - original_rl_start);
          dest->last_token = dest->len;
        }

      /* Is this token the stringification operator?  */
      if (tok.len == 1
          && tok.text[0] == '#')
	{
	  int arg;

	  if (!lookahead_valid)
	    error (_("Stringification operator requires an argument."));

	  arg = find_parameter (&lookahead, is_varargs, va_arg_name,
				def->argc, def->argv);
	  if (arg == -1)
	    error (_("Argument to stringification operator must name "
		     "a macro parameter."));

	  stringify (dest, argv[arg].text, argv[arg].len);

	  /* Read one token and let the loop iteration code handle the
	     rest.  */
	  lookahead_rl_start = replacement_list.text;
	  lookahead_valid = get_token (&lookahead, &replacement_list);
	}
      /* Is this token the splicing operator?  */
      else if (tok.len == 2
	       && tok.text[0] == '#'
	       && tok.text[1] == '#')
	error (_("Stray splicing operator"));
      /* Is the next token the splicing operator?  */
      else if (lookahead_valid
	       && lookahead.len == 2
	       && lookahead.text[0] == '#'
	       && lookahead.text[1] == '#')
	{
	  int finished = 0;
	  int prev_was_comma = 0;

	  /* Note that GCC warns if the result of splicing is not a
	     token.  In the debugger there doesn't seem to be much
	     benefit from doing this.  */

	  /* Insert the first token.  */
	  if (tok.len == 1 && tok.text[0] == ',')
	    prev_was_comma = 1;
	  else
	    {
	      int arg = find_parameter (&tok, is_varargs, va_arg_name,
					def->argc, def->argv);

	      if (arg != -1)
		appendmem (dest, argv[arg].text, argv[arg].len);
	      else
		appendmem (dest, tok.text, tok.len);
	    }

	  /* Apply a possible sequence of ## operators.  */
	  for (;;)
	    {
	      if (! get_token (&tok, &replacement_list))
		error (_("Splicing operator at end of macro"));

	      /* Handle a comma before a ##.  If we are handling
		 varargs, and the token on the right hand side is the
		 varargs marker, and the final argument is empty or
		 missing, then drop the comma.  This is a GNU
		 extension.  There is one ambiguous case here,
		 involving pedantic behavior with an empty argument,
		 but we settle that in favor of GNU-style (GCC uses an
		 option).  If we aren't dealing with varargs, we
		 simply insert the comma.  */
	      if (prev_was_comma)
		{
		  if (! (is_varargs
			 && tok.len == va_arg_name->len
			 && !memcmp (tok.text, va_arg_name->text, tok.len)
			 && argv[argc - 1].len == 0))
		    appendmem (dest, ",", 1);
		  prev_was_comma = 0;
		}

	      /* Insert the token.  If it is a parameter, insert the
		 argument.  If it is a comma, treat it specially.  */
	      if (tok.len == 1 && tok.text[0] == ',')
		prev_was_comma = 1;
	      else
		{
		  int arg = find_parameter (&tok, is_varargs, va_arg_name,
					    def->argc, def->argv);

		  if (arg != -1)
		    appendmem (dest, argv[arg].text, argv[arg].len);
		  else
		    appendmem (dest, tok.text, tok.len);
		}

	      /* Now read another token.  If it is another splice, we
		 loop.  */
	      original_rl_start = replacement_list.text;
	      if (! get_token (&tok, &replacement_list))
		{
		  finished = 1;
		  break;
		}

	      if (! (tok.len == 2
		     && tok.text[0] == '#'
		     && tok.text[1] == '#'))
		break;
	    }

	  if (prev_was_comma)
	    {
	      /* We saw a comma.  Insert it now.  */
	      appendmem (dest, ",", 1);
	    }

          dest->last_token = dest->len;
	  if (finished)
	    lookahead_valid = 0;
	  else
	    {
	      /* Set up for the loop iterator.  */
	      lookahead = tok;
	      lookahead_rl_start = original_rl_start;
	      lookahead_valid = 1;
	    }
	}
      else
	{
	  /* Is this token an identifier?  */
	  int substituted = 0;
	  int arg = find_parameter (&tok, is_varargs, va_arg_name,
				    def->argc, def->argv);

	  if (arg != -1)
	    {
	      struct macro_buffer arg_src;

	      /* Expand any macro invocations in the argument text,
		 and append the result to dest.  Remember that scan
		 mutates its source, so we need to scan a new buffer
		 referring to the argument's text, not the argument
		 itself.  */
	      init_shared_buffer (&arg_src, argv[arg].text, argv[arg].len);
	      scan (dest, &arg_src, no_loop, lookup_func, lookup_baton);
	      substituted = 1;
	    }

	  /* If it wasn't a parameter, then just copy it across.  */
	  if (! substituted)
	    append_tokens_without_splicing (dest, &tok);
	}

      if (! lookahead_valid)
	break;

      tok = lookahead;
      original_rl_start = lookahead_rl_start;

      lookahead_rl_start = replacement_list.text;
      lookahead_valid = get_token (&lookahead, &replacement_list);
    }
}
コード例 #5
0
ファイル: macroexp.c プロジェクト: 5kg/gdb
static struct macro_buffer *
gather_arguments (const char *name, struct macro_buffer *src,
		  int nargs, int *argc_p)
{
  struct macro_buffer tok;
  int args_len, args_size;
  struct macro_buffer *args = NULL;
  struct cleanup *back_to = make_cleanup (free_current_contents, &args);

  /* Does SRC start with an opening paren token?  Read from a copy of
     SRC, so SRC itself is unaffected if we don't find an opening
     paren.  */
  {
    struct macro_buffer temp;

    init_shared_buffer (&temp, src->text, src->len);

    if (! get_token (&tok, &temp)
        || tok.len != 1
        || tok.text[0] != '(')
      {
        discard_cleanups (back_to);
        return 0;
      }
  }

  /* Consume SRC's opening paren.  */
  get_token (&tok, src);

  args_len = 0;
  args_size = 6;
  args = (struct macro_buffer *) xmalloc (sizeof (*args) * args_size);

  for (;;)
    {
      struct macro_buffer *arg;
      int depth;

      /* Make sure we have room for the next argument.  */
      if (args_len >= args_size)
        {
          args_size *= 2;
          args = xrealloc (args, sizeof (*args) * args_size);
        }

      /* Initialize the next argument.  */
      arg = &args[args_len++];
      set_token (arg, src->text, src->text);

      /* Gather the argument's tokens.  */
      depth = 0;
      for (;;)
        {
          if (! get_token (&tok, src))
            error (_("Malformed argument list for macro `%s'."), name);
      
          /* Is tok an opening paren?  */
          if (tok.len == 1 && tok.text[0] == '(')
            depth++;

          /* Is tok is a closing paren?  */
          else if (tok.len == 1 && tok.text[0] == ')')
            {
              /* If it's a closing paren at the top level, then that's
                 the end of the argument list.  */
              if (depth == 0)
                {
		  /* In the varargs case, the last argument may be
		     missing.  Add an empty argument in this case.  */
		  if (nargs != -1 && args_len == nargs - 1)
		    {
		      /* Make sure we have room for the argument.  */
		      if (args_len >= args_size)
			{
			  args_size++;
			  args = xrealloc (args, sizeof (*args) * args_size);
			}
		      arg = &args[args_len++];
		      set_token (arg, src->text, src->text);
		    }

                  discard_cleanups (back_to);
                  *argc_p = args_len;
                  return args;
                }

              depth--;
            }

          /* If tok is a comma at top level, then that's the end of
             the current argument.  However, if we are handling a
             variadic macro and we are computing the last argument, we
             want to include the comma and remaining tokens.  */
          else if (tok.len == 1 && tok.text[0] == ',' && depth == 0
		   && (nargs == -1 || args_len < nargs))
            break;

          /* Extend the current argument to enclose this token.  If
             this is the current argument's first token, leave out any
             leading whitespace, just for aesthetics.  */
          if (arg->len == 0)
            {
              arg->text = tok.text;
              arg->len = tok.len;
              arg->last_token = 0;
            }
          else
            {
              arg->len = (tok.text + tok.len) - arg->text;
              arg->last_token = tok.text - arg->text;
            }
        }
    }
}
コード例 #6
0
ファイル: macroexp.c プロジェクト: 5kg/gdb
/* Append the macro buffer SRC to the end of DEST, and ensure that
   doing so doesn't splice the token at the end of SRC with the token
   at the beginning of DEST.  SRC and DEST must have their last_token
   fields set.  Upon return, DEST's last_token field is set correctly.

   For example:

   If DEST is "(" and SRC is "y", then we can return with
   DEST set to "(y" --- we've simply appended the two buffers.

   However, if DEST is "x" and SRC is "y", then we must not return
   with DEST set to "xy" --- that would splice the two tokens "x" and
   "y" together to make a single token "xy".  However, it would be
   fine to return with DEST set to "x y".  Similarly, "<" and "<" must
   yield "< <", not "<<", etc.  */
static void
append_tokens_without_splicing (struct macro_buffer *dest,
                                struct macro_buffer *src)
{
  int original_dest_len = dest->len;
  struct macro_buffer dest_tail, new_token;

  gdb_assert (src->last_token != -1);
  gdb_assert (dest->last_token != -1);
  
  /* First, just try appending the two, and call get_token to see if
     we got a splice.  */
  appendmem (dest, src->text, src->len);

  /* If DEST originally had no token abutting its end, then we can't
     have spliced anything, so we're done.  */
  if (dest->last_token == original_dest_len)
    {
      dest->last_token = original_dest_len + src->last_token;
      return;
    }

  /* Set DEST_TAIL to point to the last token in DEST, followed by
     all the stuff we just appended.  */
  init_shared_buffer (&dest_tail,
                      dest->text + dest->last_token,
                      dest->len - dest->last_token);

  /* Re-parse DEST's last token.  We know that DEST used to contain
     at least one token, so if it doesn't contain any after the
     append, then we must have spliced "/" and "*" or "/" and "/" to
     make a comment start.  (Just for the record, I got this right
     the first time.  This is not a bug fix.)  */
  if (get_token (&new_token, &dest_tail)
      && (new_token.text + new_token.len
          == dest->text + original_dest_len))
    {
      /* No splice, so we're done.  */
      dest->last_token = original_dest_len + src->last_token;
      return;
    }

  /* Okay, a simple append caused a splice.  Let's chop dest back to
     its original length and try again, but separate the texts with a
     space.  */
  dest->len = original_dest_len;
  appendc (dest, ' ');
  appendmem (dest, src->text, src->len);

  init_shared_buffer (&dest_tail,
                      dest->text + dest->last_token,
                      dest->len - dest->last_token);

  /* Try to re-parse DEST's last token, as above.  */
  if (get_token (&new_token, &dest_tail)
      && (new_token.text + new_token.len
          == dest->text + original_dest_len))
    {
      /* No splice, so we're done.  */
      dest->last_token = original_dest_len + 1 + src->last_token;
      return;
    }

  /* As far as I know, there's no case where inserting a space isn't
     enough to prevent a splice.  */
  internal_error (__FILE__, __LINE__,
                  _("unable to avoid splicing tokens during macro expansion"));
}
コード例 #7
0
ファイル: macroexp.c プロジェクト: 5kg/gdb
/* Expand a call to a macro named ID, whose definition is DEF.  Append
   its expansion to DEST.  SRC is the input text following the ID
   token.  We are currently rescanning the expansions of the macros
   named in NO_LOOP; don't re-expand them.  Use LOOKUP_FUNC and
   LOOKUP_BATON to find definitions for any nested macro references.

   Return 1 if we decided to expand it, zero otherwise.  (If it's a
   function-like macro name that isn't followed by an argument list,
   we don't expand it.)  If we return zero, leave SRC unchanged.  */
static int
expand (const char *id,
        struct macro_definition *def, 
        struct macro_buffer *dest,
        struct macro_buffer *src,
        struct macro_name_list *no_loop,
        macro_lookup_ftype *lookup_func,
        void *lookup_baton)
{
  struct macro_name_list new_no_loop;

  /* Create a new node to be added to the front of the no-expand list.
     This list is appropriate for re-scanning replacement lists, but
     it is *not* appropriate for scanning macro arguments; invocations
     of the macro whose arguments we are gathering *do* get expanded
     there.  */
  new_no_loop.name = id;
  new_no_loop.next = no_loop;

  /* What kind of macro are we expanding?  */
  if (def->kind == macro_object_like)
    {
      struct macro_buffer replacement_list;

      init_shared_buffer (&replacement_list, (char *) def->replacement,
                          strlen (def->replacement));

      scan (dest, &replacement_list, &new_no_loop, lookup_func, lookup_baton);
      return 1;
    }
  else if (def->kind == macro_function_like)
    {
      struct cleanup *back_to = make_cleanup (null_cleanup, 0);
      int argc = 0;
      struct macro_buffer *argv = NULL;
      struct macro_buffer substituted;
      struct macro_buffer substituted_src;
      struct macro_buffer va_arg_name = {0};
      int is_varargs = 0;

      if (def->argc >= 1)
	{
	  if (strcmp (def->argv[def->argc - 1], "...") == 0)
	    {
	      /* In C99-style varargs, substitution is done using
		 __VA_ARGS__.  */
	      init_shared_buffer (&va_arg_name, "__VA_ARGS__",
				  strlen ("__VA_ARGS__"));
	      is_varargs = 1;
	    }
	  else
	    {
	      int len = strlen (def->argv[def->argc - 1]);

	      if (len > 3
		  && strcmp (def->argv[def->argc - 1] + len - 3, "...") == 0)
		{
		  /* In GNU-style varargs, the name of the
		     substitution parameter is the name of the formal
		     argument without the "...".  */
		  init_shared_buffer (&va_arg_name,
				      (char *) def->argv[def->argc - 1],
				      len - 3);
		  is_varargs = 1;
		}
	    }
	}

      make_cleanup (free_current_contents, &argv);
      argv = gather_arguments (id, src, is_varargs ? def->argc : -1,
			       &argc);

      /* If we couldn't find any argument list, then we don't expand
         this macro.  */
      if (! argv)
        {
          do_cleanups (back_to);
          return 0;
        }

      /* Check that we're passing an acceptable number of arguments for
         this macro.  */
      if (argc != def->argc)
        {
	  if (is_varargs && argc >= def->argc - 1)
	    {
	      /* Ok.  */
	    }
          /* Remember that a sequence of tokens like "foo()" is a
             valid invocation of a macro expecting either zero or one
             arguments.  */
          else if (! (argc == 1
		      && argv[0].len == 0
		      && def->argc == 0))
            error (_("Wrong number of arguments to macro `%s' "
                   "(expected %d, got %d)."),
                   id, def->argc, argc);
        }

      /* Note that we don't expand macro invocations in the arguments
         yet --- we let subst_args take care of that.  Parameters that
         appear as operands of the stringifying operator "#" or the
         splicing operator "##" don't get macro references expanded,
         so we can't really tell whether it's appropriate to macro-
         expand an argument until we see how it's being used.  */
      init_buffer (&substituted, 0);
      make_cleanup (cleanup_macro_buffer, &substituted);
      substitute_args (&substituted, def, is_varargs, &va_arg_name,
		       argc, argv, no_loop, lookup_func, lookup_baton);

      /* Now `substituted' is the macro's replacement list, with all
         argument values substituted into it properly.  Re-scan it for
         macro references, but don't expand invocations of this macro.

         We create a new buffer, `substituted_src', which points into
         `substituted', and scan that.  We can't scan `substituted'
         itself, since the tokenization process moves the buffer's
         text pointer around, and we still need to be able to find
         `substituted's original text buffer after scanning it so we
         can free it.  */
      init_shared_buffer (&substituted_src, substituted.text, substituted.len);
      scan (dest, &substituted_src, &new_no_loop, lookup_func, lookup_baton);

      do_cleanups (back_to);

      return 1;
    }
  else
    internal_error (__FILE__, __LINE__, _("bad macro definition kind"));
}
コード例 #8
0
/* Given the macro definition DEF, being invoked with the actual
   arguments given by ARGC and ARGV, substitute the arguments into the
   replacement list, and store the result in DEST.

   If it is necessary to expand macro invocations in one of the
   arguments, use LOOKUP_FUNC and LOOKUP_BATON to find the macro
   definitions, and don't expand invocations of the macros listed in
   NO_LOOP.  */
static void
substitute_args (struct macro_buffer *dest, 
                 struct macro_definition *def,
                 int argc, struct macro_buffer *argv,
                 struct macro_name_list *no_loop,
                 macro_lookup_ftype *lookup_func,
                 void *lookup_baton)
{
  /* A macro buffer for the macro's replacement list.  */
  struct macro_buffer replacement_list;

  init_shared_buffer (&replacement_list, (char *) def->replacement,
                      strlen (def->replacement));

  gdb_assert (dest->len == 0);
  dest->last_token = 0;

  for (;;)
    {
      struct macro_buffer tok;
      char *original_rl_start = replacement_list.text;
      int substituted = 0;
      
      /* Find the next token in the replacement list.  */
      if (! get_token (&tok, &replacement_list))
        break;

      /* Just for aesthetics.  If we skipped some whitespace, copy
         that to DEST.  */
      if (tok.text > original_rl_start)
        {
          appendmem (dest, original_rl_start, tok.text - original_rl_start);
          dest->last_token = dest->len;
        }

      /* Is this token the stringification operator?  */
      if (tok.len == 1
          && tok.text[0] == '#')
        error ("Stringification is not implemented yet.");

      /* Is this token the splicing operator?  */
      if (tok.len == 2
          && tok.text[0] == '#'
          && tok.text[1] == '#')
        error ("Token splicing is not implemented yet.");

      /* Is this token an identifier?  */
      if (tok.is_identifier)
        {
          int i;

          /* Is it the magic varargs parameter?  */
          if (tok.len == 11
              && ! memcmp (tok.text, "__VA_ARGS__", 11))
            error ("Variable-arity macros not implemented yet.");

          /* Is it one of the parameters?  */
          for (i = 0; i < def->argc; i++)
            if (tok.len == strlen (def->argv[i])
                && ! memcmp (tok.text, def->argv[i], tok.len))
              {
                struct macro_buffer arg_src;

                /* Expand any macro invocations in the argument text,
                   and append the result to dest.  Remember that scan
                   mutates its source, so we need to scan a new buffer
                   referring to the argument's text, not the argument
                   itself.  */
                init_shared_buffer (&arg_src, argv[i].text, argv[i].len);
                scan (dest, &arg_src, no_loop, lookup_func, lookup_baton);
                substituted = 1;
                break;
              }
        }

      /* If it wasn't a parameter, then just copy it across.  */
      if (! substituted)
        append_tokens_without_splicing (dest, &tok);
    }
}