[v3,090/206] Add c-exp.h and c_string_operation

Message ID 20210220201609.838264-91-tom@tromey.com
State New
Headers show
Series
  • Refactor expressions
Related show

Commit Message

Tom Tromey Feb. 20, 2021, 8:14 p.m.
This adds the new file c-exp.h, where C operation classes will be
declared.  The first such class, c_string_operation, is also added
here.

gdb/ChangeLog
2021-02-20  Tom Tromey  <tom@tromey.com>

	* c-lang.c (c_string_operation::evaluate): New method.
	* c-exp.h: New file.
---
 gdb/ChangeLog |   5 ++
 gdb/c-exp.h   |  46 ++++++++++++++++++
 gdb/c-lang.c  | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 177 insertions(+)
 create mode 100644 gdb/c-exp.h

-- 
2.26.2

Patch

diff --git a/gdb/c-exp.h b/gdb/c-exp.h
new file mode 100644
index 00000000000..5558a773e98
--- /dev/null
+++ b/gdb/c-exp.h
@@ -0,0 +1,46 @@ 
+/* Definitions for C expressions
+
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef C_EXP_H
+#define C_EXP_H
+
+#include "expop.h"
+
+namespace expr
+{
+
+class c_string_operation
+  : public tuple_holding_operation<enum c_string_type_values,
+				   std::vector<std::string>>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return OP_STRING; }
+};
+
+}/* namespace expr */
+
+#endif /* C_EXP_H */
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 16ff3c7378a..d191d07a00a 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -37,6 +37,7 @@ 
 #include "gdbcore.h"
 #include "gdbarch.h"
 #include "compile/compile-internal.h"
+#include "c-exp.h"
 
 /* Given a C string type, STR_TYPE, return the corresponding target
    character set name.  */
@@ -728,6 +729,131 @@  evaluate_subexp_c (struct type *expect_type, struct expression *exp,
     }
   return evaluate_subexp_standard (expect_type, exp, pos, noside);
 }
+
+namespace expr
+{
+
+value *
+c_string_operation::evaluate (struct type *expect_type,
+			      struct expression *exp,
+			      enum noside noside)
+{
+  struct type *type;
+  struct value *result;
+  c_string_type dest_type;
+  const char *dest_charset;
+  int satisfy_expected = 0;
+
+  auto_obstack output;
+
+  dest_type = std::get<0> (m_storage);
+
+  switch (dest_type & ~C_CHAR)
+    {
+    case C_STRING:
+      type = language_string_char_type (exp->language_defn,
+					exp->gdbarch);
+      break;
+    case C_WIDE_STRING:
+      type = lookup_typename (exp->language_defn, "wchar_t", NULL, 0);
+      break;
+    case C_STRING_16:
+      type = lookup_typename (exp->language_defn, "char16_t", NULL, 0);
+      break;
+    case C_STRING_32:
+      type = lookup_typename (exp->language_defn, "char32_t", NULL, 0);
+      break;
+    default:
+      internal_error (__FILE__, __LINE__, _("unhandled c_string_type"));
+    }
+
+  /* Ensure TYPE_LENGTH is valid for TYPE.  */
+  check_typedef (type);
+
+  /* If the caller expects an array of some integral type,
+     satisfy them.  If something odder is expected, rely on the
+     caller to cast.  */
+  if (expect_type && expect_type->code () == TYPE_CODE_ARRAY)
+    {
+      struct type *element_type
+	= check_typedef (TYPE_TARGET_TYPE (expect_type));
+
+      if (element_type->code () == TYPE_CODE_INT
+	  || element_type->code () == TYPE_CODE_CHAR)
+	{
+	  type = element_type;
+	  satisfy_expected = 1;
+	}
+    }
+
+  dest_charset = charset_for_string_type (dest_type, exp->gdbarch);
+
+  if (noside != EVAL_SKIP)
+    {
+      for (const std::string &item : std::get<1> (m_storage))
+	parse_one_string (&output, item.c_str (), item.size (),
+			  dest_charset, type);
+    }
+
+  if (noside == EVAL_SKIP)
+    {
+      /* Return a dummy value of the appropriate type.  */
+      if (expect_type != NULL)
+	result = allocate_value (expect_type);
+      else if ((dest_type & C_CHAR) != 0)
+	result = allocate_value (type);
+      else
+	result = value_cstring ("", 0, type);
+      return result;
+    }
+
+  if ((dest_type & C_CHAR) != 0)
+    {
+      LONGEST value;
+
+      if (obstack_object_size (&output) != TYPE_LENGTH (type))
+	error (_("Could not convert character "
+		 "constant to target character set"));
+      value = unpack_long (type, (gdb_byte *) obstack_base (&output));
+      result = value_from_longest (type, value);
+    }
+  else
+    {
+      int i;
+
+      /* Write the terminating character.  */
+      for (i = 0; i < TYPE_LENGTH (type); ++i)
+	obstack_1grow (&output, 0);
+
+      if (satisfy_expected)
+	{
+	  LONGEST low_bound, high_bound;
+	  int element_size = TYPE_LENGTH (type);
+
+	  if (!get_discrete_bounds (expect_type->index_type (),
+				    &low_bound, &high_bound))
+	    {
+	      low_bound = 0;
+	      high_bound = (TYPE_LENGTH (expect_type) / element_size) - 1;
+	    }
+	  if (obstack_object_size (&output) / element_size
+	      > (high_bound - low_bound + 1))
+	    error (_("Too many array elements"));
+
+	  result = allocate_value (expect_type);
+	  memcpy (value_contents_raw (result), obstack_base (&output),
+		  obstack_object_size (&output));
+	}
+      else
+	result = value_cstring ((const char *) obstack_base (&output),
+				obstack_object_size (&output),
+				type);
+    }
+  return result;
+}
+
+} /* namespace expr */
+
 
 /* See c-lang.h.  */