Beispiel #1
0
	string lexer::parse_quoted_string(location_ptr &location, char end_quote, bool allow_escapes) {

		string quoted_string;

		while (current != end) {
			char c = next_char();
			if (c == '\n') {
				break;
			}

			if (c == end_quote) {
				return quoted_string;
			}

			if (c == '\\' && allow_escapes) {
				quoted_string += parse_escape_sequence();
			} else {
				if (c & 0x80) {
					logger.warning(make_location(), boost::format("invalid 7-bit ASCII character '%c'") % c);
				}

				quoted_string += c;
			}
		}

		logger.error(location, format("unterminated %s literal")
			% (end_quote == '\'' ? "character" : "string"));
		return quoted_string;
	}
Beispiel #2
0
static value make_list(constant loc, cstlist csts, int has_tail, bool save_location, fncode fn)
{
  struct list *l;

  if (has_tail && csts != NULL)
    {
      l = csts->cst ? make_constant(csts->cst, FALSE, fn) : NULL;
      csts = csts->next;
    }
  else
    l = NULL;

  GCPRO1(l);
  /* Remember that csts is in reverse order ... */
  while (csts)
    {
      value tmp = make_constant(csts->cst, save_location, fn);

      l = alloc_list(tmp, l);
      SET_READONLY(l); SET_IMMUTABLE(l);
      csts = csts->next;
    }
  if (save_location)
    {
      value vloc = make_location(&loc->loc);
      l = alloc_list(vloc, l);
      SET_READONLY(l); SET_IMMUTABLE(l);
    }
  GCPOP(1);

  return l;
}
Beispiel #3
0
static value make_quote(constant c, bool save_location, fncode fn)
{
  struct list *l;
  value quote;

  l = alloc_list(make_constant(c->u.constant, save_location, fn), NULL);
  SET_READONLY(l); SET_IMMUTABLE(l);
  GCPRO1(l);
  quote = make_gsymbol("quote", fn);
  l = alloc_list(quote, l);
  SET_READONLY(l); SET_IMMUTABLE(l);
  if (save_location)
    {
      value loc = make_location(&c->loc);
      l = alloc_list(loc, l);
      SET_READONLY(l); SET_IMMUTABLE(l);
    }
  GCPOP(1);

  return l;
}
Beispiel #4
0
	token lexer::next_token() {
		skip();

		if (current == end) {
			auto location = make_location();
			return token(location, token_type::END_OF_INPUT, "end of file");
		}

		char c = next_char();
		auto start = make_location();

		if (c == '<') {
			if (consume_next_if('<')) {
				return token(start, token_type::OPERATOR, "<<", operator_type::SHIFT_LEFT);
			} else if (consume_next_if('=')) {
				return token(start, token_type::OPERATOR, "<=", operator_type::LTE);
			} else if (consume_next_if('>')) {
				return token(start, token_type::OPERATOR, "<>", operator_type::NEQ);
			}
		} else if (c == '>') {
			if (consume_next_if('>')) {
				return token(start, token_type::OPERATOR, "<<", operator_type::SHIFT_RIGHT);
			} else if (consume_next_if('=')) {
				return token(start, token_type::OPERATOR, "<=", operator_type::GTE);
			}
		} else if (c == '=' && consume_next_if('=')) {
			return token(start, token_type::OPERATOR, "==", operator_type::EQ);
		} else if (c == '!' && consume_next_if('=')) {
			return token(start, token_type::OPERATOR, "!=", operator_type::NEQ);
		} else if (c == '&' && consume_next_if('&')) {
			return token(start, token_type::OPERATOR, "&&", operator_type::AND);
		} else if (c == '|' && consume_next_if('|')) {
			return token(start, token_type::OPERATOR, "||", operator_type::OR);
		} else if (c == '\'') {
			string quoted_string = parse_quoted_string(start, c, true);
			if (quoted_string.length() == 0) {
				logger.warning(start, "empty character literal; assuming null terminator");

				return token(start, token_type::INTEGER, quoted_string, 0);
			}

			if (quoted_string.length() > 1) {
				logger.error(start, "multi-byte character literal");
			}

			uint8_t value = quoted_string[0];
			return token(start, token_type::INTEGER, quoted_string, value);
		} else if (c == '"') {
			string quoted_string = parse_quoted_string(start, c, true);

			return token(start, token_type::QUOTED_STRING,  quoted_string, quote_type::DOUBLE_QUOTE);
		} else if (c == ':' && is_identifier_first_char(peek_char())) {
			return token(start, token_type::LABEL, append_while(next_char(), &lexer::is_identifier_char));
		} else if (c == '$' && is_identifier_first_char(peek_char())) {
			return token(start, token_type::SYMBOL, append_while(next_char(), &lexer::is_identifier_char),
					symbol_type::EXPLICIT);
		} else if (is_identifier_first_char(c)) {
			string identifier = append_while(c, &lexer::is_identifier_char);
			if (consume_next_if(':')) {
				return token(start, token_type::LABEL, identifier);
			} else {
				return parse_identifier(start, identifier);
			}
		} else if (isdigit(c)) {
			return parse_number(start, append_while(c, &lexer::is_identifier_char));
		} else if (c == '[') {
			iterator start_pos = current;
			uint32_t start_col = column;
			auto stack_op_token = parse_stack_operation(start);
			if (stack_op_token) {
				return *stack_op_token;
			} else {
				current = start_pos;
				column = start_col;
			}
		} else if (c == '\n') {
			next_line();

			return token(start, token_type::NEWLINE, "newline");
		}

		return token(start, token_type::CHARACTER, c);
	}
Beispiel #5
0
	char lexer::parse_escape_sequence() {
		char c = next_char();
		if (c == '\0') {
			return c;
		}

		switch (c) {
		case '\'':
			return '\'';
		case '"':
			return '"';
		case '?':
			return '?';
		case '\\':
			return '\\';
		case '0':
			return '\0';
		case 'a':
			return '\a';
		case 'b':
			return '\b';
		case 'f':
			return '\f';
		case 'n':
			return '\n';
		case 'r':
			return '\r';
		case 't':
			return '\t';
		case 'v':
			return '\v';
		case 'x':
		case 'X':
			{
				char firstDigit = next_char();
				if (firstDigit == '\0') {
					return firstDigit;
				}

				if (!isxdigit(firstDigit)) {
					logger.error(make_location(), format("invalid hex digit '%c' following hex escape")
						% firstDigit);
					move_back();
					return '\0';
				}

				uint8_t parsed_int = parse_hex_digit(firstDigit);
				// check if it's a two digit hex escape
				if (current != end && isxdigit(*current)) {
					parsed_int = (parsed_int * 16) + parse_hex_digit(next_char());
				}

				if (parsed_int & 0x80) {
					logger.warning(make_location(), boost::format("invalid 7-bit ASCII character '%#02x'")
						% parsed_int);
				}

				return parsed_int;
			}
		default:
			logger.error(make_location(), format("unrecognized escape character '%c'") % c);
			return c;
		}
	}
static void
test_show_locus (function *fun)
{
  tree fndecl = fun->decl;
  tree identifier = DECL_NAME (fndecl);
  const char *fnname = IDENTIFIER_POINTER (identifier);
  location_t fnstart = fun->function_start_locus;
  int fnstart_line = LOCATION_LINE (fnstart);

  diagnostic_finalizer (global_dc) = custom_diagnostic_finalizer;

  /* Hardcode the "terminal width", to verify the behavior of
     very wide lines.  */
  global_dc->caret_max_width = 70;

  if (0 == strcmp (fnname, "test_simple"))
    {
      const int line = fnstart_line + 2;
      rich_location richloc (line_table, get_loc (line, 15));
      add_range (&richloc, get_loc (line, 10), get_loc (line, 14), false);
      add_range (&richloc, get_loc (line, 16), get_loc (line, 16), false);
      warning_at_rich_loc (&richloc, 0, "test");
    }

  if (0 == strcmp (fnname, "test_simple_2"))
    {
      const int line = fnstart_line + 2;
      rich_location richloc (line_table, get_loc (line, 24));
      add_range (&richloc, get_loc (line, 6), get_loc (line, 22), false);
      add_range (&richloc, get_loc (line, 26), get_loc (line, 43), false);
      warning_at_rich_loc (&richloc, 0, "test");
    }

  if (0 == strcmp (fnname, "test_multiline"))
    {
      const int line = fnstart_line + 2;
      rich_location richloc (line_table, get_loc (line + 1, 7));
      add_range (&richloc, get_loc (line, 7), get_loc (line, 23), false);
      add_range (&richloc, get_loc (line + 1, 9), get_loc (line + 1, 26),
		 false);
      warning_at_rich_loc (&richloc, 0, "test");
    }

  if (0 == strcmp (fnname, "test_many_lines"))
    {
      const int line = fnstart_line + 2;
      rich_location richloc (line_table, get_loc (line + 5, 7));
      add_range (&richloc, get_loc (line, 7), get_loc (line + 4, 65), false);
      add_range (&richloc, get_loc (line + 5, 9), get_loc (line + 10, 61),
		 false);
      warning_at_rich_loc (&richloc, 0, "test");
    }

  /* Example of a rich_location where the range is larger than
     one character.  */
  if (0 == strcmp (fnname, "test_richloc_from_proper_range"))
    {
      const int line = fnstart_line + 2;
      location_t start = get_loc (line, 12);
      location_t finish = get_loc (line, 16);
      rich_location richloc (line_table, make_location (start, start, finish));
      warning_at_rich_loc (&richloc, 0, "test");
    }

  /* Example of a single-range location where the range starts
     before the caret.  */
  if (0 == strcmp (fnname, "test_caret_within_proper_range"))
    {
      const int line = fnstart_line + 2;
      warning_at (make_location (get_loc (line, 16), get_loc (line, 12),
				 get_loc (line, 20)),
		  0, "test");
    }

  /* Example of a very wide line, where the information of interest
     is beyond the width of the terminal (hardcoded above).  */
  if (0 == strcmp (fnname, "test_very_wide_line"))
    {
      const int line = fnstart_line + 2;
      global_dc->show_ruler_p = true;
      warning_at (make_location (get_loc (line, 94), get_loc (line, 90),
				 get_loc (line, 98)),
		  0, "test");
      global_dc->show_ruler_p = false;
    }

  /* Example of multiple carets.  */
  if (0 == strcmp (fnname, "test_multiple_carets"))
    {
      const int line = fnstart_line + 2;
      location_t caret_a = get_loc (line, 7);
      location_t caret_b = get_loc (line, 11);
      rich_location richloc (line_table, caret_a);
      add_range (&richloc, caret_b, caret_b, true);
      global_dc->caret_chars[0] = 'A';
      global_dc->caret_chars[1] = 'B';
      warning_at_rich_loc (&richloc, 0, "test");
      global_dc->caret_chars[0] = '^';
      global_dc->caret_chars[1] = '^';
    }

  /* Tests of rendering fixit hints.  */
  if (0 == strcmp (fnname, "test_fixit_insert"))
    {
      const int line = fnstart_line + 2;
      location_t start = get_loc (line, 19);
      location_t finish = get_loc (line, 22);
      rich_location richloc (line_table, make_location (start, start, finish));
      richloc.add_fixit_insert_before ("{");
      richloc.add_fixit_insert_after ("}");
      warning_at_rich_loc (&richloc, 0, "example of insertion hints");
    }

  if (0 == strcmp (fnname, "test_fixit_remove"))
    {
      const int line = fnstart_line + 2;
      location_t start = get_loc (line, 8);
      location_t finish = get_loc (line, 8);
      rich_location richloc (line_table, make_location (start, start, finish));
      source_range src_range;
      src_range.m_start = start;
      src_range.m_finish = finish;
      richloc.add_fixit_remove (src_range);
      warning_at_rich_loc (&richloc, 0, "example of a removal hint");
    }

  if (0 == strcmp (fnname, "test_fixit_replace"))
    {
      const int line = fnstart_line + 2;
      location_t start = get_loc (line, 2);
      location_t finish = get_loc (line, 19);
      rich_location richloc (line_table, make_location (start, start, finish));
      source_range src_range;
      src_range.m_start = start;
      src_range.m_finish = finish;
      richloc.add_fixit_replace (src_range, "gtk_widget_show_all");
      warning_at_rich_loc (&richloc, 0, "example of a replacement hint");
    }

  /* Example of two carets where both carets appear to have an off-by-one
     error appearing one column early.
     Seen with gfortran.dg/associate_5.f03.
     In an earlier version of the printer, the printing of caret 0 aka
     "1" was suppressed due to it appearing within the leading whitespace
     before the text in its line.  Ensure that we at least faithfully
     print both carets, at the given (erroneous) locations.  */
  if (0 == strcmp (fnname, "test_caret_on_leading_whitespace"))
    {
      const int line = fnstart_line + 3;
      location_t caret_a = get_loc (line, 5);
      location_t caret_b = get_loc (line - 1, 19);
      rich_location richloc (line_table, caret_a);
      richloc.add_range (caret_b, true);
      global_dc->caret_chars[0] = '1';
      global_dc->caret_chars[1] = '2';
      warning_at_rich_loc (&richloc, 0, "test");
      global_dc->caret_chars[0] = '^';
      global_dc->caret_chars[1] = '^';
    }

  /* Example of using the "%q+D" format code, which as well as printing
     a quoted decl, overrides the given location to use the location of
     the decl.  */
  if (0 == strcmp (fnname, "test_percent_q_plus_d"))
    {
      const int line = fnstart_line + 3;
      tree local = (*fun->local_decls)[0];
      warning_at (input_location, 0,
		  "example of plus in format code for %q+D", local);
    }

  /* Example of many locations and many fixits.
     Underline (separately) every word in a comment, and convert them
     to upper case.  */
  if (0 == strcmp (fnname, "test_many_nested_locations"))
    {
      const char *file = LOCATION_FILE (fnstart);
      const int start_line = fnstart_line + 2;
      const int finish_line = start_line + 7;
      location_t loc = get_loc (start_line - 1, 2);
      rich_location richloc (line_table, loc);
      for (int line = start_line; line <= finish_line; line++)
	{
	  int line_size;
	  const char *content = location_get_source_line (file, line,
							  &line_size);
	  gcc_assert (content);
	  /* Split line up into words.  */
	  for (int idx = 0; idx < line_size; idx++)
	    {
	      if (ISALPHA (content[idx]))
		{
		  int start_idx = idx;
		  while (idx < line_size && ISALPHA (content[idx]))
		    idx++;
		  if (idx == line_size || !ISALPHA (content[idx]))
		    {
		      location_t start_of_word = get_loc (line, start_idx);
		      location_t end_of_word = get_loc (line, idx - 1);
		      location_t word
			= make_location (start_of_word, start_of_word,
					 end_of_word);
		      richloc.add_range (word, true);

		      /* Add a fixit, converting to upper case.  */
		      char *copy = xstrndup (content + start_idx,
					     idx - start_idx);
		      for (char *ch = copy; *ch; ch++)
			*ch = TOUPPER (*ch);
		      richloc.add_fixit_replace (word, copy);
		      free (copy);
		    }
		}
	    }
	}
      /* Verify that we added enough locations to fully exercise
	 rich_location.  We want to exceed both the
	 statically-allocated buffer in class rich_location,
	 and then trigger a reallocation of the dynamic buffer.  */
      gcc_assert (richloc.get_num_locations () > 3 + (2 * 16));
      warning_at_rich_loc (&richloc, 0, "test of %i locations",
			   richloc.get_num_locations ());
    }
}
static void
add_range (rich_location *richloc, location_t start, location_t finish,
	   bool show_caret_p)
{
  richloc->add_range (make_location (start, start, finish), show_caret_p);
}