Exemplo n.º 1
0
/* CUR points to any character in the input buffer.  Skips over all
   contiguous horizontal white space and NULs, including comments if
   SKIP_COMMENTS, until reaching the first non-horizontal-whitespace
   character or the end of the current context.  Escaped newlines are
   removed.

   The whitespace is copied verbatim to the output buffer, except that
   comments are handled as described in copy_comment().
   pfile->out.cur is updated.

   Returns a pointer to the first character after the whitespace in
   the input buffer.  */
static const uchar *
skip_whitespace (cpp_reader *pfile, const uchar *cur, int skip_comments)
{
  uchar *out = pfile->out.cur;

  for (;;)
    {
      unsigned int c = *cur++;
      *out++ = c;

      if (is_nvspace (c))
	continue;

      if (c == '/' && *cur == '*' && skip_comments)
	{
	  pfile->out.cur = out;
	  cur = copy_comment (pfile, cur, false /* in_define */);
	  out = pfile->out.cur;
	  continue;
	}

      out--;
      break;
    }

  pfile->out.cur = out;
  return cur - 1;
}
Exemplo n.º 2
0
/* Skips whitespace, saving the next non-whitespace character.  */
static void
skip_whitespace (cpp_reader *pfile, cppchar_t c)
{
  cpp_buffer *buffer = pfile->buffer;
  bool saw_NUL = false;

  do
    {
      /* Horizontal space always OK.  */
      if (c == ' ' || c == '\t')
	;
      /* Just \f \v or \0 left.  */
      else if (c == '\0')
	saw_NUL = true;
      else if (pfile->state.in_directive && CPP_PEDANTIC (pfile))
	cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->line_table->highest_line,
			     CPP_BUF_COL (buffer),
			     "%s in preprocessing directive",
			     c == '\f' ? "form feed" : "vertical tab");

      c = *buffer->cur++;
    }
  /* We only want non-vertical space, i.e. ' ' \t \f \v \0.  */
  while (is_nvspace (c));

  if (saw_NUL)
    cpp_error (pfile, CPP_DL_WARNING, "null character(s) ignored");

  buffer->cur--;
}
Exemplo n.º 3
0
/* Return true if the trigraph indicated by NOTE should be warned
   about in a comment.  */
static bool
warn_in_comment (cpp_reader *pfile, _cpp_line_note *note)
{
  const uchar *p;

  /* Within comments we don't warn about trigraphs, unless the
     trigraph forms an escaped newline, as that may change
     behavior.  */
  if (note->type != '/')
    return false;

  /* If -trigraphs, then this was an escaped newline iff the next note
     is coincident.  */
  if (CPP_OPTION (pfile, trigraphs))
    return note[1].pos == note->pos;

  /* Otherwise, see if this forms an escaped newline.  */
  p = note->pos + 3;
  while (is_nvspace (*p))
    p++;

  /* There might have been escaped newlines between the trigraph and the
     newline we found.  Hence the position test.  */
  return (*p == '\n' && p < note[1].pos);
}
Exemplo n.º 4
0
/* Writes out the preprocessed file, handling spacing and paste
   avoidance issues.  */
void
_cpp_preprocess_dir_only (cpp_reader *pfile,
			  const struct _cpp_dir_only_callbacks *cb)
{
  struct cpp_buffer *buffer;
  const unsigned char *cur, *base, *next_line, *rlimit;
  cppchar_t c, last_c;
  unsigned flags;
  linenum_type lines;
  int col;
  source_location loc;

 restart:
  /* Buffer initialization ala _cpp_clean_line(). */
  buffer = pfile->buffer;
  buffer->cur_note = buffer->notes_used = 0;
  buffer->cur = buffer->line_base = buffer->next_line;
  buffer->need_line = false;

  /* This isn't really needed.  It prevents a compiler warning, though. */
  loc = pfile->line_table->highest_line;

  /* Scan initialization. */
  next_line = cur = base = buffer->cur;
  rlimit = buffer->rlimit;
  flags = DO_BOL;
  lines = 0;
  col = 1;

  for (last_c = '\n', c = *cur; cur < rlimit; last_c = c, c = *++cur, ++col)
    {
      /* Skip over escaped newlines. */
      if (__builtin_expect (c == '\\', false))
	{
	  const unsigned char *tmp = cur + 1;

	  while (is_nvspace (*tmp) && tmp < rlimit)
	    tmp++;
	  if (*tmp == '\r')
	    tmp++;
	  if (*tmp == '\n' && tmp < rlimit)
	    {
	      CPP_INCREMENT_LINE (pfile, 0);
	      lines++;
	      col = 0;
	      cur = tmp;
	      c = last_c;
	      continue;
	    }
	}

      if (__builtin_expect (last_c == '#', false) && !(flags & DO_SPECIAL))
	{
	  if (c != '#' && (flags & DO_BOL))
	  {
	    struct line_maps *line_table;

	    if (!pfile->state.skipping && next_line != base)
	      cb->print_lines (lines, base, next_line - base);

	    /* Prep things for directive handling. */
	    buffer->next_line = cur;
	    buffer->need_line = true;
	    _cpp_get_fresh_line (pfile);

	    /* Ensure proper column numbering for generated error messages. */
	    buffer->line_base -= col - 1;

	    _cpp_handle_directive (pfile, 0 /* ignore indented */);

	    /* Sanitize the line settings.  Duplicate #include's can mess
	       things up. */
	    line_table = pfile->line_table;
	    line_table->highest_location = line_table->highest_line;

	    /* The if block prevents us from outputing line information when
	       the file ends with a directive and no newline.  Note that we
	       must use pfile->buffer, not buffer. */
	    if (pfile->buffer->next_line < pfile->buffer->rlimit)
	      cb->maybe_print_line (pfile->line_table->highest_line);

	    goto restart;
	  }

	  flags &= ~DO_BOL;
	  pfile->mi_valid = false;
	}
      else if (__builtin_expect (last_c == '/', false) \
	       && !(flags & DO_SPECIAL) && c != '*' && c != '/')
	{
	  /* If a previous slash is not starting a block comment, clear the
	     DO_BOL flag.  */
	  flags &= ~DO_BOL;
	  pfile->mi_valid = false;
	}

      switch (c)
	{
	case '/':
	  if ((flags & DO_BLOCK_COMMENT) && last_c == '*')
	    {
	      flags &= ~DO_BLOCK_COMMENT;
	      c = 0;
	    }
	  else if (!(flags & DO_SPECIAL) && last_c == '/')
	    flags |= DO_LINE_COMMENT;
	  else if (!(flags & DO_SPECIAL))
	    /* Mark the position for possible error reporting. */
	    loc = linemap_position_for_column (pfile->line_table, col);

	  break;

	case '*':
	  if (!(flags & DO_SPECIAL))
	    {
	      if (last_c == '/')
		flags |= DO_BLOCK_COMMENT;
	      else
		{
		  flags &= ~DO_BOL;
		  pfile->mi_valid = false;
		}
	    }

	  break;

	case '\'':
	case '"':
	  {
	    unsigned state = (c == '"') ? DO_STRING : DO_CHAR;

	    if (!(flags & DO_SPECIAL))
	      {
		flags |= state;
		flags &= ~DO_BOL;
		pfile->mi_valid = false;
	      }
	    else if ((flags & state) && last_c != '\\')
	      flags &= ~state;

	    break;
	  }

	case '\\':
	  {
	    if ((flags & (DO_STRING | DO_CHAR)) && last_c == '\\')
	      c = 0;

	    if (!(flags & DO_SPECIAL))
	      {
		flags &= ~DO_BOL;
		pfile->mi_valid = false;
	      }

	    break;
	  }

	case '\n':
	  CPP_INCREMENT_LINE (pfile, 0);
	  lines++;
	  col = 0;
	  flags &= ~DO_LINE_SPECIAL;
	  if (!(flags & DO_SPECIAL))
	    flags |= DO_BOL;
	  break;

	case '#':
	  next_line = cur;
	  /* Don't update DO_BOL yet. */
	  break;

	case ' ': case '\t': case '\f': case '\v': case '\0':
	  break;

	default:
	  if (!(flags & DO_SPECIAL))
	    {
	      flags &= ~DO_BOL;
	      pfile->mi_valid = false;
	    }
	  break;
	}
    }

  if (flags & DO_BLOCK_COMMENT)
    cpp_error_with_line (pfile, CPP_DL_ERROR, loc, 0, "unterminated comment");

  if (!pfile->state.skipping && cur != base)
    {
      /* If the file was not newline terminated, add rlimit, which is
         guaranteed to point to a newline, to the end of our range.  */
      if (cur[-1] != '\n')
	{
	  cur++;
	  CPP_INCREMENT_LINE (pfile, 0);
	  lines++;
	}

      cb->print_lines (lines, base, cur - base);
    }

  _cpp_pop_buffer (pfile);
  if (pfile->buffer)
    goto restart;
}
Exemplo n.º 5
0
/* Returns with a logical line that contains no escaped newlines or
   trigraphs.  This is a time-critical inner loop.  */
void
_cpp_clean_line (cpp_reader *pfile)
{
  cpp_buffer *buffer;
  const uchar *s;
  uchar c, *d, *p;

  buffer = pfile->buffer;
  buffer->cur_note = buffer->notes_used = 0;
  buffer->cur = buffer->line_base = buffer->next_line;
  buffer->need_line = false;
  s = buffer->next_line - 1;

  if (!buffer->from_stage3)
    {
      const uchar *pbackslash = NULL;

      /* Short circuit for the common case of an un-escaped line with
	 no trigraphs.  The primary win here is by not writing any
	 data back to memory until we have to.  */
      for (;;)
	{
	  c = *++s;
	  if (__builtin_expect (c == '\n', false)
	      || __builtin_expect (c == '\r', false))
	    {
	      d = (uchar *) s;

	      if (__builtin_expect (s == buffer->rlimit, false))
		goto done;

	      /* DOS line ending? */
	      if (__builtin_expect (c == '\r', false)
		  && s[1] == '\n')
		{
		  s++;
		  if (s == buffer->rlimit)
		    goto done;
		}

	      if (__builtin_expect (pbackslash == NULL, true))
		goto done;

	      /* Check for escaped newline.  */
	      p = d;
	      while (is_nvspace (p[-1]))
		p--;
	      if (p - 1 != pbackslash)
		goto done;

	      /* Have an escaped newline; process it and proceed to
		 the slow path.  */
	      add_line_note (buffer, p - 1, p != d ? ' ' : '\\');
	      d = p - 2;
	      buffer->next_line = p - 1;
	      break;
	    }
	  if (__builtin_expect (c == '\\', false))
	    pbackslash = s;
	  else if (__builtin_expect (c == '?', false)
		   && __builtin_expect (s[1] == '?', false)
		   && _cpp_trigraph_map[s[2]])
	    {
	      /* Have a trigraph.  We may or may not have to convert
		 it.  Add a line note regardless, for -Wtrigraphs.  */
	      add_line_note (buffer, s, s[2]);
	      if (CPP_OPTION (pfile, trigraphs))
		{
		  /* We do, and that means we have to switch to the
		     slow path.  */
		  d = (uchar *) s;
		  *d = _cpp_trigraph_map[s[2]];
		  s += 2;
		  break;
		}
	    }
	}


      for (;;)
	{
	  c = *++s;
	  *++d = c;

	  if (c == '\n' || c == '\r')
	    {
		  /* Handle DOS line endings.  */
	      if (c == '\r' && s != buffer->rlimit && s[1] == '\n')
		s++;
	      if (s == buffer->rlimit)
		break;

	      /* Escaped?  */
	      p = d;
	      while (p != buffer->next_line && is_nvspace (p[-1]))
		p--;
	      if (p == buffer->next_line || p[-1] != '\\')
		break;

	      add_line_note (buffer, p - 1, p != d ? ' ': '\\');
	      d = p - 2;
	      buffer->next_line = p - 1;
	    }
	  else if (c == '?' && s[1] == '?' && _cpp_trigraph_map[s[2]])
	    {
	      /* Add a note regardless, for the benefit of -Wtrigraphs.  */
	      add_line_note (buffer, d, s[2]);
	      if (CPP_OPTION (pfile, trigraphs))
		{
		  *d = _cpp_trigraph_map[s[2]];
		  s += 2;
		}
	    }
	}
    }
  else
    {
      do
	s++;
      while (*s != '\n' && *s != '\r');
      d = (uchar *) s;

      /* Handle DOS line endings.  */
      if (*s == '\r' && s != buffer->rlimit && s[1] == '\n')
	s++;
    }

 done:
  *d = '\n';
  /* A sentinel note that should never be processed.  */
  add_line_note (buffer, d + 1, '\n');
  buffer->next_line = s + 1;
}