Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH 00/12] Ada iterated assignment, plus parser cleanups
@ 2024-03-21 19:03 Tom Tromey
  2024-03-21 19:03 ` [PATCH 01/12] Introduce and use aggregate_assigner type Tom Tromey
                   ` (12 more replies)
  0 siblings, 13 replies; 14+ messages in thread
From: Tom Tromey @ 2024-03-21 19:03 UTC (permalink / raw)
  To: gdb-patches

This series implements the Ada 2022 iterated assignment feature.  An
earlier version of the patch failed to clear a new global in the
parser, so I also ended up tacking on a series to make sure this
problem can't happen again -- all parser state is moved into a new
object.  (All the parsers should do this, or go further and follow
Rust into recursive descent, IMNSHO.)

Tested on x86-64 Fedora 38.  This has also been running inside AdaCore
for a while now.

---
Tom Tromey (12):
      Introduce and use aggregate_assigner type
      Implement Ada 2022 iterated assignment
      Introduce ada_parse_state
      Move "int_storage" global into ada_parse_state
      Move "components" and "associations" into ada_parse_state
      Move "assignments" global into ada_parse_state
      Move "iterated_associations" into ada_parse_state
      Move "temp_parse_space" into ada_parse_state
      Move "paren_depth" into ada_parse_state
      Move "returned_complete" into ada_parse_state
      Remove "numbuf" global
      Constify ada-lex.l:attributes

 gdb/ada-exp.h                                  | 165 ++++++++++++++-----
 gdb/ada-exp.y                                  | 212 ++++++++++++++++---------
 gdb/ada-lang.c                                 | 202 +++++++++++++----------
 gdb/ada-lex.l                                  |  48 +++---
 gdb/testsuite/gdb.ada/iterated-assign.exp      |  37 +++++
 gdb/testsuite/gdb.ada/iterated-assign/main.adb |  24 +++
 gdb/testsuite/gdb.ada/iterated-assign/pck.adb  |  23 +++
 gdb/testsuite/gdb.ada/iterated-assign/pck.ads  |  26 +++
 8 files changed, 509 insertions(+), 228 deletions(-)
---
base-commit: 7e949f08700b077b78e955c653eb4e9455027101
change-id: 20240321-ada-iterated-assign-da4127ab3d6d

Best regards,
-- 
Tom Tromey <tromey@adacore.com>


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 01/12] Introduce and use aggregate_assigner type
  2024-03-21 19:03 [PATCH 00/12] Ada iterated assignment, plus parser cleanups Tom Tromey
@ 2024-03-21 19:03 ` Tom Tromey
  2024-03-21 19:03 ` [PATCH 02/12] Implement Ada 2022 iterated assignment Tom Tromey
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2024-03-21 19:03 UTC (permalink / raw)
  To: gdb-patches

This patch is a refactoring to add a new aggregate_assigner type.
This type is passed to Ada aggregate assignment operations in place of
passing a number of separate arguments.  This new approach makes it
simpler to change some aspects of aggregate assignment behavior.
---
 gdb/ada-exp.h  |  88 +++++++++++++++++----------------
 gdb/ada-lang.c | 153 +++++++++++++++++++++++++--------------------------------
 2 files changed, 114 insertions(+), 127 deletions(-)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index 69d4e90e410..6122502dcdc 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -588,20 +588,48 @@ class ada_target_operation : public operation
   ada_assign_operation *m_lhs;
 };
 
+/* When constructing an aggregate, an object of this type is created
+   to track the needed state.  */
+
+struct aggregate_assigner
+{
+  /* An lvalue containing LHS (possibly LHS itself).  */
+  value *container;
+
+  /* An lvalue of record or array type; this is the object being
+     assigned to.  */
+  value *lhs;
+
+  /* The expression being evaluated.  */
+  expression *exp;
+
+  /* The bounds of LHS.  This is used by the 'others' component.  */
+  LONGEST low;
+  LONGEST high;
+
+  /* This indicates which sub-components have already been assigned
+     to.  */
+  std::vector<LONGEST> indices;
+
+  /* Assign the result of evaluating ARG to the INDEXth component of
+     LHS (a simple array or a record).  Does not modify the inferior's
+     memory, nor does it modify LHS (unless LHS == CONTAINER).  */
+  void assign (LONGEST index, operation_up &arg);
+
+  /* Add the interval [FROM .. TO] to the sorted set of intervals
+     [ INDICES[0] .. INDICES[1] ],...  The resulting intervals do not
+     overlap.  */
+  void add_interval (LONGEST low, LONGEST high);
+};
+
 /* This abstract class represents a single component in an Ada
    aggregate assignment.  */
 class ada_component
 {
 public:
 
-  /* Assign to LHS, which is part of CONTAINER.  EXP is the expression
-     being evaluated.  INDICES, LOW, and HIGH indicate which
-     sub-components have already been assigned; INDICES should be
-     updated by this call.  */
-  virtual void assign (struct value *container,
-		       struct value *lhs, struct expression *exp,
-		       std::vector<LONGEST> &indices,
-		       LONGEST low, LONGEST high) = 0;
+  /* Assign to ASSIGNER.  */
+  virtual void assign (aggregate_assigner &assigner) = 0;
 
   /* Same as operation::uses_objfile.  */
   virtual bool uses_objfile (struct objfile *objfile) = 0;
@@ -664,10 +692,7 @@ class ada_aggregate_component : public ada_component
   ada_aggregate_component (operation_up &&base,
 			   std::vector<ada_component_up> &&components);
 
-  void assign (struct value *container,
-	       struct value *lhs, struct expression *exp,
-	       std::vector<LONGEST> &indices,
-	       LONGEST low, LONGEST high) override;
+  void assign (aggregate_assigner &assigner) override;
 
   bool uses_objfile (struct objfile *objfile) override;
 
@@ -694,10 +719,7 @@ class ada_positional_component : public ada_component
   {
   }
 
-  void assign (struct value *container,
-	       struct value *lhs, struct expression *exp,
-	       std::vector<LONGEST> &indices,
-	       LONGEST low, LONGEST high) override;
+  void assign (aggregate_assigner &assigner) override;
 
   bool uses_objfile (struct objfile *objfile) override;
 
@@ -719,10 +741,7 @@ class ada_others_component : public ada_component
   {
   }
 
-  void assign (struct value *container,
-	       struct value *lhs, struct expression *exp,
-	       std::vector<LONGEST> &indices,
-	       LONGEST low, LONGEST high) override;
+  void assign (aggregate_assigner &assigner) override;
 
   bool uses_objfile (struct objfile *objfile) override;
 
@@ -740,14 +759,10 @@ class ada_association
 public:
 
   /* Like ada_component::assign, but takes an operation as a
-     parameter.  The operation is evaluated and then assigned into LHS
-     according to the rules of the concrete implementation.  */
-  virtual void assign (struct value *container,
-		       struct value *lhs,
-		       struct expression *exp,
-		       std::vector<LONGEST> &indices,
-		       LONGEST low, LONGEST high,
-		       operation_up &op) = 0;
+     parameter.  The operation is evaluated and then assigned into
+     ASSIGNER according to the rules of the concrete
+     implementation.  */
+  virtual void assign (aggregate_assigner &assigner, operation_up &op) = 0;
 
   /* Same as operation::uses_objfile.  */
   virtual bool uses_objfile (struct objfile *objfile) = 0;
@@ -785,10 +800,7 @@ class ada_choices_component : public ada_component
     m_assocs = std::move (assoc);
   }
 
-  void assign (struct value *container,
-	       struct value *lhs, struct expression *exp,
-	       std::vector<LONGEST> &indices,
-	       LONGEST low, LONGEST high) override;
+  void assign (aggregate_assigner &assigner) override;
 
   bool uses_objfile (struct objfile *objfile) override;
 
@@ -811,11 +823,7 @@ class ada_discrete_range_association : public ada_association
   {
   }
 
-  void assign (struct value *container,
-	       struct value *lhs, struct expression *exp,
-	       std::vector<LONGEST> &indices,
-	       LONGEST low, LONGEST high,
-	       operation_up &op) override;
+  void assign (aggregate_assigner &assigner, operation_up &op) override;
 
   bool uses_objfile (struct objfile *objfile) override;
 
@@ -839,11 +847,7 @@ class ada_name_association : public ada_association
   {
   }
 
-  void assign (struct value *container,
-	       struct value *lhs, struct expression *exp,
-	       std::vector<LONGEST> &indices,
-	       LONGEST low, LONGEST high,
-	       operation_up &op) override;
+  void assign (aggregate_assigner &assigner, operation_up &op) override;
 
   bool uses_objfile (struct objfile *objfile) override;
 
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 493ef3b6c7d..c9cbeca40bc 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -191,9 +191,6 @@ static int ada_is_direct_array_type (struct type *);
 static struct value *ada_index_struct_field (int, struct value *, int,
 					     struct type *);
 
-static void add_component_interval (LONGEST, LONGEST, std::vector<LONGEST> &);
-
-
 static struct type *ada_find_any_type (const char *name);
 
 static symbol_name_matcher_ftype *ada_get_symbol_name_matcher
@@ -9323,13 +9320,10 @@ check_objfile (const std::unique_ptr<ada_component> &comp,
   return comp->uses_objfile (objfile);
 }
 
-/* Assign the result of evaluating ARG to the INDEXth component of LHS
-   (a simple array or a record).  Does not modify the inferior's
-   memory, nor does it modify LHS (unless LHS == CONTAINER).  */
+/* See ada-exp.h.  */
 
-static void
-assign_component (struct value *container, struct value *lhs, LONGEST index,
-		  struct expression *exp, operation_up &arg)
+void
+aggregate_assigner::assign (LONGEST index, operation_up &arg)
 {
   scoped_value_mark mark;
 
@@ -9384,23 +9378,21 @@ ada_aggregate_component::dump (ui_file *stream, int depth)
 }
 
 void
-ada_aggregate_component::assign (struct value *container,
-				 struct value *lhs, struct expression *exp,
-				 std::vector<LONGEST> &indices,
-				 LONGEST low, LONGEST high)
+ada_aggregate_component::assign (aggregate_assigner &assigner)
 {
   if (m_base != nullptr)
     {
-      value *base = m_base->evaluate (nullptr, exp, EVAL_NORMAL);
+      value *base = m_base->evaluate (nullptr, assigner.exp, EVAL_NORMAL);
       if (ada_is_direct_array_type (base->type ()))
 	base = ada_coerce_to_simple_array (base);
-      if (!types_deeply_equal (container->type (), base->type ()))
+      if (!types_deeply_equal (assigner.container->type (), base->type ()))
 	error (_("Type mismatch in delta aggregate"));
-      value_assign_to_component (container, container, base);
+      value_assign_to_component (assigner.container, assigner.container,
+				 base);
     }
 
   for (auto &item : m_components)
-    item->assign (container, lhs, exp, indices, low, high);
+    item->assign (assigner);
 }
 
 /* See ada-exp.h.  */
@@ -9429,7 +9421,7 @@ ada_aggregate_operation::assign_aggregate (struct value *container,
 					   struct expression *exp)
 {
   struct type *lhs_type;
-  LONGEST low_index, high_index;
+  aggregate_assigner assigner;
 
   container = ada_coerce_ref (container);
   if (ada_is_direct_array_type (container->type ()))
@@ -9443,23 +9435,27 @@ ada_aggregate_operation::assign_aggregate (struct value *container,
     {
       lhs = ada_coerce_to_simple_array (lhs);
       lhs_type = check_typedef (lhs->type ());
-      low_index = lhs_type->bounds ()->low.const_val ();
-      high_index = lhs_type->bounds ()->high.const_val ();
+      assigner.low = lhs_type->bounds ()->low.const_val ();
+      assigner.high = lhs_type->bounds ()->high.const_val ();
     }
   else if (lhs_type->code () == TYPE_CODE_STRUCT)
     {
-      low_index = 0;
-      high_index = num_visible_fields (lhs_type) - 1;
+      assigner.low = 0;
+      assigner.high = num_visible_fields (lhs_type) - 1;
     }
   else
     error (_("Left-hand side must be array or record."));
 
-  std::vector<LONGEST> indices (4);
-  indices[0] = indices[1] = low_index - 1;
-  indices[2] = indices[3] = high_index + 1;
+  assigner.indices.push_back (assigner.low - 1);
+  assigner.indices.push_back (assigner.low - 1);
+  assigner.indices.push_back (assigner.high + 1);
+  assigner.indices.push_back (assigner.high + 1);
+
+  assigner.container = container;
+  assigner.lhs = lhs;
+  assigner.exp = exp;
 
-  std::get<0> (m_storage)->assign (container, lhs, exp, indices,
-				   low_index, high_index);
+  std::get<0> (m_storage)->assign (assigner);
 
   return container;
 }
@@ -9483,19 +9479,16 @@ ada_positional_component::dump (ui_file *stream, int depth)
    LOW, where HIGH is the upper bound.  Record the position in
    INDICES.  CONTAINER is as for assign_aggregate.  */
 void
-ada_positional_component::assign (struct value *container,
-				  struct value *lhs, struct expression *exp,
-				  std::vector<LONGEST> &indices,
-				  LONGEST low, LONGEST high)
+ada_positional_component::assign (aggregate_assigner &assigner)
 {
-  LONGEST ind = m_index + low;
+  LONGEST ind = m_index + assigner.low;
 
-  if (ind - 1 == high)
+  if (ind - 1 == assigner.high)
     warning (_("Extra components in aggregate ignored."));
-  if (ind <= high)
+  if (ind <= assigner.high)
     {
-      add_component_interval (ind, ind, indices);
-      assign_component (container, lhs, ind, exp, m_op);
+      assigner.add_interval (ind, ind);
+      assigner.assign (ind, m_op);
     }
 }
 
@@ -9514,23 +9507,21 @@ ada_discrete_range_association::dump (ui_file *stream, int depth)
 }
 
 void
-ada_discrete_range_association::assign (struct value *container,
-					struct value *lhs,
-					struct expression *exp,
-					std::vector<LONGEST> &indices,
-					LONGEST low, LONGEST high,
+ada_discrete_range_association::assign (aggregate_assigner &assigner,
 					operation_up &op)
 {
-  LONGEST lower = value_as_long (m_low->evaluate (nullptr, exp, EVAL_NORMAL));
-  LONGEST upper = value_as_long (m_high->evaluate (nullptr, exp, EVAL_NORMAL));
+  LONGEST lower = value_as_long (m_low->evaluate (nullptr, assigner.exp,
+						  EVAL_NORMAL));
+  LONGEST upper = value_as_long (m_high->evaluate (nullptr, assigner.exp,
+						   EVAL_NORMAL));
 
-  if (lower <= upper && (lower < low || upper > high))
+  if (lower <= upper && (lower < assigner.low || upper > assigner.high))
     error (_("Index in component association out of bounds."));
 
-  add_component_interval (lower, upper, indices);
+  assigner.add_interval (lower, upper);
   while (lower <= upper)
     {
-      assign_component (container, lhs, lower, exp, op);
+      assigner.assign (lower, op);
       lower += 1;
     }
 }
@@ -9549,18 +9540,16 @@ ada_name_association::dump (ui_file *stream, int depth)
 }
 
 void
-ada_name_association::assign (struct value *container,
-			      struct value *lhs,
-			      struct expression *exp,
-			      std::vector<LONGEST> &indices,
-			      LONGEST low, LONGEST high,
+ada_name_association::assign (aggregate_assigner &assigner,
 			      operation_up &op)
 {
   int index;
 
-  if (ada_is_direct_array_type (lhs->type ()))
-    index = longest_to_int (value_as_long (m_val->evaluate (nullptr, exp,
-							    EVAL_NORMAL)));
+  if (ada_is_direct_array_type (assigner.lhs->type ()))
+    {
+      value *tem = m_val->evaluate (nullptr, assigner.exp, EVAL_NORMAL);
+      index = longest_to_int (value_as_long (tem));
+    }
   else
     {
       ada_string_operation *strop
@@ -9586,13 +9575,13 @@ ada_name_association::assign (struct value *container,
 	}
 
       index = 0;
-      if (! find_struct_field (name, lhs->type (), 0,
+      if (! find_struct_field (name, assigner.lhs->type (), 0,
 			       NULL, NULL, NULL, NULL, &index))
 	error (_("Unknown component name: %s."), name);
     }
 
-  add_component_interval (index, index, indices);
-  assign_component (container, lhs, index, exp, op);
+  assigner.add_interval (index, index);
+  assigner.assign (index, op);
 }
 
 bool
@@ -9620,13 +9609,10 @@ ada_choices_component::dump (ui_file *stream, int depth)
    the allowable indices are LOW..HIGH.  Record the indices assigned
    to in INDICES.  CONTAINER is as for assign_aggregate.  */
 void
-ada_choices_component::assign (struct value *container,
-			       struct value *lhs, struct expression *exp,
-			       std::vector<LONGEST> &indices,
-			       LONGEST low, LONGEST high)
+ada_choices_component::assign (aggregate_assigner &assigner)
 {
   for (auto &item : m_assocs)
-    item->assign (container, lhs, exp, indices, low, high, m_op);
+    item->assign (assigner, m_op);
 }
 
 bool
@@ -9647,16 +9633,15 @@ ada_others_component::dump (ui_file *stream, int depth)
    have not been previously assigned.  The index intervals already assigned
    are in INDICES.  CONTAINER is as for assign_aggregate.  */
 void
-ada_others_component::assign (struct value *container,
-			      struct value *lhs, struct expression *exp,
-			      std::vector<LONGEST> &indices,
-			      LONGEST low, LONGEST high)
+ada_others_component::assign (aggregate_assigner &assigner)
 {
-  int num_indices = indices.size ();
+  int num_indices = assigner.indices.size ();
   for (int i = 0; i < num_indices - 2; i += 2)
     {
-      for (LONGEST ind = indices[i + 1] + 1; ind < indices[i + 2]; ind += 1)
-	assign_component (container, lhs, ind, exp, m_op);
+      for (LONGEST ind = assigner.indices[i + 1] + 1;
+	   ind < assigner.indices[i + 2];
+	   ind += 1)
+	assigner.assign (ind, m_op);
     }
 }
 
@@ -9697,46 +9682,44 @@ ada_assign_operation::evaluate (struct type *expect_type,
   return ada_value_assign (arg1, arg2);
 }
 
-} /* namespace expr */
+/* See ada-exp.h.  */
 
-/* Add the interval [LOW .. HIGH] to the sorted set of intervals
-   [ INDICES[0] .. INDICES[1] ],...  The resulting intervals do not
-   overlap.  */
-static void
-add_component_interval (LONGEST low, LONGEST high, 
-			std::vector<LONGEST> &indices)
+void
+aggregate_assigner::add_interval (LONGEST from, LONGEST to)
 {
   int i, j;
 
   int size = indices.size ();
   for (i = 0; i < size; i += 2) {
-    if (high >= indices[i] && low <= indices[i + 1])
+    if (to >= indices[i] && from <= indices[i + 1])
       {
 	int kh;
 
 	for (kh = i + 2; kh < size; kh += 2)
-	  if (high < indices[kh])
+	  if (to < indices[kh])
 	    break;
-	if (low < indices[i])
-	  indices[i] = low;
+	if (from < indices[i])
+	  indices[i] = from;
 	indices[i + 1] = indices[kh - 1];
-	if (high > indices[i + 1])
-	  indices[i + 1] = high;
+	if (to > indices[i + 1])
+	  indices[i + 1] = to;
 	memcpy (indices.data () + i + 2, indices.data () + kh, size - kh);
 	indices.resize (kh - i - 2);
 	return;
       }
-    else if (high < indices[i])
+    else if (to < indices[i])
       break;
   }
 	
   indices.resize (indices.size () + 2);
   for (j = indices.size () - 1; j >= i + 2; j -= 1)
     indices[j] = indices[j - 2];
-  indices[i] = low;
-  indices[i + 1] = high;
+  indices[i] = from;
+  indices[i + 1] = to;
 }
 
+} /* namespace expr */
+
 /* Perform and Ada cast of ARG2 to type TYPE if the type of ARG2
    is different.  */
 

-- 
2.43.0


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 02/12] Implement Ada 2022 iterated assignment
  2024-03-21 19:03 [PATCH 00/12] Ada iterated assignment, plus parser cleanups Tom Tromey
  2024-03-21 19:03 ` [PATCH 01/12] Introduce and use aggregate_assigner type Tom Tromey
@ 2024-03-21 19:03 ` Tom Tromey
  2024-03-21 19:03 ` [PATCH 03/12] Introduce ada_parse_state Tom Tromey
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2024-03-21 19:03 UTC (permalink / raw)
  To: gdb-patches

Ada 2022 includes iterated assignment for array initialization.  This
patch implements a subset of this for gdb.  In particular, only arrays
with integer index types really work -- currently there's no decent
way to get the index type in EVAL_AVOID_SIDE_EFFECTS mode during
parsing.  Fixing this probably requires the Ada parser to take a
somewhat more sophisticated approach to type resolution; and while
this would help fix another bug in this area, this patch is already
useful without it.
---
 gdb/ada-exp.h                                  | 77 ++++++++++++++++++++++++++
 gdb/ada-exp.y                                  | 52 +++++++++++++++--
 gdb/ada-lang.c                                 | 49 +++++++++++++++-
 gdb/ada-lex.l                                  |  1 +
 gdb/testsuite/gdb.ada/iterated-assign.exp      | 37 +++++++++++++
 gdb/testsuite/gdb.ada/iterated-assign/main.adb | 24 ++++++++
 gdb/testsuite/gdb.ada/iterated-assign/pck.adb  | 23 ++++++++
 gdb/testsuite/gdb.ada/iterated-assign/pck.ads  | 26 +++++++++
 8 files changed, 284 insertions(+), 5 deletions(-)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index 6122502dcdc..94e4ea0f47e 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -611,6 +611,15 @@ struct aggregate_assigner
      to.  */
   std::vector<LONGEST> indices;
 
+private:
+
+  /* The current index value.  This is only valid during the 'assign'
+     operation and is part of the implementation of iterated component
+     association.  */
+  LONGEST m_current_index = 0;
+
+public:
+
   /* Assign the result of evaluating ARG to the INDEXth component of
      LHS (a simple array or a record).  Does not modify the inferior's
      memory, nor does it modify LHS (unless LHS == CONTAINER).  */
@@ -620,6 +629,10 @@ struct aggregate_assigner
      [ INDICES[0] .. INDICES[1] ],...  The resulting intervals do not
      overlap.  */
   void add_interval (LONGEST low, LONGEST high);
+
+  /* Return the current index as a value, using the index type of
+     LHS.  */
+  value *current_value () const;
 };
 
 /* This abstract class represents a single component in an Ada
@@ -800,16 +813,80 @@ class ada_choices_component : public ada_component
     m_assocs = std::move (assoc);
   }
 
+  /* Set the underlying operation  */
+  void set_operation (operation_up op)
+  { m_op = std::move (op); }
+
+  /* Set the index variable name for an iterated association.  */
+  void set_name (std::string &&name)
+  { m_name = std::move (name); }
+
+  /* The name of this choice component.  This is empty unless this is
+     an iterated association.  */
+  const std::string &name () const
+  { return m_name; }
+
   void assign (aggregate_assigner &assigner) override;
 
   bool uses_objfile (struct objfile *objfile) override;
 
   void dump (ui_file *stream, int depth) override;
 
+  /* Return the current value of the index variable.  This may only be
+     called underneath a call to 'assign'.  */
+  value *current_value () const
+  { return m_assigner->current_value (); }
+
 private:
 
   std::vector<ada_association_up> m_assocs;
   operation_up m_op;
+
+  /* Name of the variable used for iteration.  This isn't needed for
+     evaluation, only for debug dumping.  This is the empty string for
+     ordinary (non-iterated) choices.  */
+  std::string m_name;
+
+  /* A pointer to the current assignment operation; only valid when in
+     a call to the 'assign' method.  This is used to find the index
+     variable value during the evaluation of the RHS of the =>, via
+     ada_index_var_operation.  */
+  const aggregate_assigner *m_assigner = nullptr;
+};
+
+/* Implement the index variable for iterated component
+   association.  */
+class ada_index_var_operation : public operation
+{
+public:
+
+  ada_index_var_operation ()
+  { }
+
+  /* Link this variable to the choices object.  May only be called
+     once.  */
+  void set_choices (ada_choices_component *var)
+  {
+    gdb_assert (m_var == nullptr && var != nullptr);
+    m_var = var;
+  }
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  {
+    /* It doesn't really matter.  */
+    return OP_VAR_VALUE;
+  }
+
+  void dump (struct ui_file *stream, int depth) const override;
+
+private:
+
+  /* The choices component that introduced the index variable.  */
+  ada_choices_component *m_var = nullptr;
 };
 
 /* An association that uses a discrete range.  */
diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y
index 2b205714d7a..c0a5b0534a6 100644
--- a/gdb/ada-exp.y
+++ b/gdb/ada-exp.y
@@ -422,6 +422,10 @@ typedef std::unique_ptr<ada_assign_operation> ada_assign_up;
    to implement '@', the target name symbol.  */
 static std::vector<ada_assign_up> assignments;
 
+/* Track currently active iterated assignment names.  */
+static std::unordered_map<std::string, std::vector<ada_index_var_operation *>>
+     iterated_associations;
+
 %}
 
 %union
@@ -488,7 +492,7 @@ static std::vector<ada_assign_up> assignments;
     forces a.b.c, e.g., to be LEFT-associated.  */
 %right '.' '(' '[' DOT_ID DOT_COMPLETE
 
-%token NEW OTHERS
+%token NEW OTHERS FOR
 
 \f
 %%
@@ -1098,6 +1102,33 @@ component_group :
 			  ada_choices_component *choices = choice_component ();
 			  choices->set_associations (pop_associations ($1));
 			}
+	|	FOR NAME IN
+			{
+			  std::string name = copy_name ($2);
+
+			  auto iter = iterated_associations.find (name);
+			  if (iter != iterated_associations.end ())
+			    error (_("Nested use of index parameter '%s'"),
+				   name.c_str ());
+
+			  iterated_associations[name] = {};
+			}
+		component_associations
+			{
+			  std::string name = copy_name ($2);
+
+			  ada_choices_component *choices = choice_component ();
+			  choices->set_associations (pop_associations ($5));
+
+			  auto iter = iterated_associations.find (name);
+			  gdb_assert (iter != iterated_associations.end ());
+			  for (ada_index_var_operation *var : iter->second)
+			    var->set_choices (choices);
+
+			  iterated_associations.erase (name);
+
+			  choices->set_name (std::move (name));
+			}
 	;
 
 /* We use this somewhat obscure definition in order to handle NAME => and
@@ -1207,6 +1238,7 @@ ada_parse (struct parser_state *par_state)
   associations.clear ();
   int_storage.clear ();
   assignments.clear ();
+  iterated_associations.clear ();
 
   int result = yyparse ();
   if (!result)
@@ -1652,10 +1684,22 @@ write_var_or_type (struct parser_state *par_state,
   char *encoded_name;
   int name_len;
 
-  if (block == NULL)
-    block = par_state->expression_context_block;
-
   std::string name_storage = ada_encode (name0.ptr);
+
+  if (block == nullptr)
+    {
+      auto iter = iterated_associations.find (name_storage);
+      if (iter != iterated_associations.end ())
+	{
+	  auto op = std::make_unique<ada_index_var_operation> ();
+	  iter->second.push_back (op.get ());
+	  par_state->push (std::move (op));
+	  return nullptr;
+	}
+
+      block = par_state->expression_context_block;
+    }
+
   name_len = name_storage.size ();
   encoded_name = obstack_strndup (&temp_parse_space, name_storage.c_str (),
 				  name_len);
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index c9cbeca40bc..d65ac70f251 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -9343,6 +9343,8 @@ aggregate_assigner::assign (LONGEST index, operation_up &arg)
       elt = ada_to_fixed_value (elt);
     }
 
+  scoped_restore save_index = make_scoped_restore (&m_current_index, index);
+
   ada_aggregate_operation *ag_op
     = dynamic_cast<ada_aggregate_operation *> (arg.get ());
   if (ag_op != nullptr)
@@ -9353,6 +9355,18 @@ aggregate_assigner::assign (LONGEST index, operation_up &arg)
 					      EVAL_NORMAL));
 }
 
+/* See ada-exp.h.  */
+
+value *
+aggregate_assigner::current_value () const
+{
+  /* Note that using an integer type here is incorrect -- the type
+     should be the array's index type.  Unfortunately, though, this
+     isn't currently available during parsing and type resolution.  */
+  struct type *index_type = builtin_type (exp->gdbarch)->builtin_int;
+  return value_from_longest (index_type, m_current_index);
+}
+
 bool
 ada_aggregate_component::uses_objfile (struct objfile *objfile)
 {
@@ -9598,8 +9612,15 @@ ada_choices_component::uses_objfile (struct objfile *objfile)
 void
 ada_choices_component::dump (ui_file *stream, int depth)
 {
-  gdb_printf (stream, _("%*sChoices:\n"), depth, "");
+  if (m_name.empty ())
+    gdb_printf (stream, _("%*sChoices:\n"), depth, "");
+  else
+    {
+      gdb_printf (stream, _("%*sIterated choices:\n"), depth, "");
+      gdb_printf (stream, _("%*sName: %s\n"), depth + 1, "", m_name.c_str ());
+    }
   m_op->dump (stream, depth + 1);
+
   for (const auto &item : m_assocs)
     item->dump (stream, depth + 1);
 }
@@ -9611,10 +9632,36 @@ ada_choices_component::dump (ui_file *stream, int depth)
 void
 ada_choices_component::assign (aggregate_assigner &assigner)
 {
+  scoped_restore save_index = make_scoped_restore (&m_assigner, &assigner);
   for (auto &item : m_assocs)
     item->assign (assigner, m_op);
 }
 
+void
+ada_index_var_operation::dump (struct ui_file *stream, int depth) const
+{
+  gdb_printf (stream, _("%*sIndex variable: %s\n"), depth, "",
+	      m_var->name ().c_str ());
+}
+
+value *
+ada_index_var_operation::evaluate (struct type *expect_type,
+				   struct expression *exp,
+				   enum noside noside)
+{
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    {
+      /* Note that using an integer type here is incorrect -- the type
+	 should be the array's index type.  Unfortunately, though,
+	 this isn't currently available during parsing and type
+	 resolution.  */
+      struct type *index_type = builtin_type (exp->gdbarch)->builtin_int;
+      return value::zero (index_type, not_lval);
+    }
+
+  return m_var->current_value ();
+}
+
 bool
 ada_others_component::uses_objfile (struct objfile *objfile)
 {
diff --git a/gdb/ada-lex.l b/gdb/ada-lex.l
index c54cd5e452a..e1abf9adc25 100644
--- a/gdb/ada-lex.l
+++ b/gdb/ada-lex.l
@@ -227,6 +227,7 @@ abs		{ return ABS; }
 and		{ return _AND_; }
 delta		{ return DELTA; }
 else		{ return ELSE; }
+for		{ return FOR; }
 in		{ return IN; }
 mod		{ return MOD; }
 new		{ return NEW; }
diff --git a/gdb/testsuite/gdb.ada/iterated-assign.exp b/gdb/testsuite/gdb.ada/iterated-assign.exp
new file mode 100644
index 00000000000..76b038fb45c
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/iterated-assign.exp
@@ -0,0 +1,37 @@
+# Copyright 2024 Free Software Foundation, Inc.
+#
+# 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/>.
+
+load_lib "ada.exp"
+
+require allow_ada_tests
+
+standard_ada_testfile main
+
+if {[gdb_compile_ada "${srcfile}" "${binfile}" executable [list debug]] != "" } {
+    return -1
+}
+
+clean_restart ${testfile}
+
+set bp_location [gdb_get_line_number "STOP" ${testdir}/main.adb]
+runto "main.adb:$bp_location"
+
+gdb_test "print a1 := (for i in 1..4 => 2 * i + 1)" \
+    " = \\(3, 5, 7, 9\\)" \
+    "simple iterated assignment"
+
+gdb_test "print a2 := (for i in 1..2 => (for j in 1..2 => 3 * i + j))" \
+    " = \\(\\(4, 5\\), \\(7, 8\\)\\)" \
+    "nested iterated assignment"
diff --git a/gdb/testsuite/gdb.ada/iterated-assign/main.adb b/gdb/testsuite/gdb.ada/iterated-assign/main.adb
new file mode 100644
index 00000000000..239c22cd8a8
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/iterated-assign/main.adb
@@ -0,0 +1,24 @@
+--  Copyright 2024 Free Software Foundation, Inc.
+--
+--  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/>.
+
+with pck; use pck;
+
+procedure Main is
+   A1 : Other_Array_Type := (2, 4, 6, 8);
+   A2 : MD_Array_Type := ((1, 2), (3, 4));
+begin
+   Do_Nothing (A1'Address);  -- STOP
+   Do_Nothing (A2'Address);
+end Main;
diff --git a/gdb/testsuite/gdb.ada/iterated-assign/pck.adb b/gdb/testsuite/gdb.ada/iterated-assign/pck.adb
new file mode 100644
index 00000000000..14580e66be1
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/iterated-assign/pck.adb
@@ -0,0 +1,23 @@
+--  Copyright 2024 Free Software Foundation, Inc.
+--
+--  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/>.
+
+package body Pck is
+
+   procedure Do_Nothing (A : System.Address) is
+   begin
+      null;
+   end Do_Nothing;
+
+end Pck;
diff --git a/gdb/testsuite/gdb.ada/iterated-assign/pck.ads b/gdb/testsuite/gdb.ada/iterated-assign/pck.ads
new file mode 100644
index 00000000000..b77af7264c4
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/iterated-assign/pck.ads
@@ -0,0 +1,26 @@
+--  Copyright 2024 Free Software Foundation, Inc.
+--
+--  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/>.
+
+with System;
+
+package Pck is
+
+   type Other_Array_Type is array (1 .. 4) of Integer;
+
+   type MD_Array_Type is array (1 .. 2, 1 .. 2) of Integer;
+
+   procedure Do_Nothing (A : System.Address);
+
+end Pck;

-- 
2.43.0


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 03/12] Introduce ada_parse_state
  2024-03-21 19:03 [PATCH 00/12] Ada iterated assignment, plus parser cleanups Tom Tromey
  2024-03-21 19:03 ` [PATCH 01/12] Introduce and use aggregate_assigner type Tom Tromey
  2024-03-21 19:03 ` [PATCH 02/12] Implement Ada 2022 iterated assignment Tom Tromey
@ 2024-03-21 19:03 ` Tom Tromey
  2024-03-21 19:03 ` [PATCH 04/12] Move "int_storage" global into ada_parse_state Tom Tromey
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2024-03-21 19:03 UTC (permalink / raw)
  To: gdb-patches

This patch introduces the ada_parse_state class and the ada_parser
global.  It also changes find_completion_bounds to be a method of this
new type.

Note that find_completion_bounds never used its parameter; and because
it is generally fine to use the 'pstate' global throughout the parser,
this patch removes the parameter entirely.
---
 gdb/ada-exp.y | 51 ++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 34 insertions(+), 17 deletions(-)

diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y
index c0a5b0534a6..9452e63ab60 100644
--- a/gdb/ada-exp.y
+++ b/gdb/ada-exp.y
@@ -65,8 +65,26 @@ struct name_info {
 
 static struct parser_state *pstate = NULL;
 
-/* The original expression string.  */
-static const char *original_expr;
+/* Data that must be held for the duration of a parse.  */
+
+struct ada_parse_state
+{
+  explicit ada_parse_state (const char *expr)
+    : m_original_expr (expr)
+  {
+  }
+
+  std::string find_completion_bounds ();
+
+private:
+
+  /* The original expression string.  */
+  const char *m_original_expr;
+};
+
+/* The current Ada parser object.  */
+
+static ada_parse_state *ada_parser;
 
 /* We don't have a good way to manage non-POD data in Yacc, so store
    values here.  The storage here is only valid for the duration of
@@ -102,8 +120,6 @@ static struct type *type_for_char (struct parser_state *, ULONGEST);
 
 static struct type *type_system_address (struct parser_state *);
 
-static std::string find_completion_bounds (struct parser_state *);
-
 using namespace expr;
 
 /* Handle Ada type resolution for OP.  DEPROCEDURE_P and CONTEXT_TYPE
@@ -549,7 +565,7 @@ primary :	primary DOT_COMPLETE
 			  ada_structop_operation *str_op
 			    = (new ada_structop_operation
 			       (std::move (arg), copy_name ($2)));
-			  str_op->set_prefix (find_completion_bounds (pstate));
+			  str_op->set_prefix (ada_parser->find_completion_bounds ());
 			  pstate->push (operation_up (str_op));
 			  pstate->mark_struct_expression (str_op);
 			}
@@ -1223,10 +1239,11 @@ int
 ada_parse (struct parser_state *par_state)
 {
   /* Setting up the parser state.  */
-  scoped_restore pstate_restore = make_scoped_restore (&pstate);
+  scoped_restore pstate_restore = make_scoped_restore (&pstate, par_state);
   gdb_assert (par_state != NULL);
-  pstate = par_state;
-  original_expr = par_state->lexptr;
+
+  ada_parse_state parser (par_state->lexptr);
+  scoped_restore parser_restore = make_scoped_restore (&ada_parser, &parser);
 
   scoped_restore restore_yydebug = make_scoped_restore (&yydebug,
 							par_state->debug);
@@ -1849,13 +1866,13 @@ write_var_or_type (struct parser_state *par_state,
    Without this, an attempt like "complete print abc.d" will give a
    result like "print def" rather than "print abc.def".  */
 
-static std::string
-find_completion_bounds (struct parser_state *par_state)
+std::string
+ada_parse_state::find_completion_bounds ()
 {
   const char *end = pstate->lexptr;
   /* First the end of the prefix.  Here we stop at the token start or
      at '.' or space.  */
-  for (; end > original_expr && end[-1] != '.' && !isspace (end[-1]); --end)
+  for (; end > m_original_expr && end[-1] != '.' && !isspace (end[-1]); --end)
     {
       /* Nothing.  */
     }
@@ -1863,11 +1880,11 @@ find_completion_bounds (struct parser_state *par_state)
   const char *ptr = end;
   /* Here we allow '.'.  */
   for (;
-       ptr > original_expr && (ptr[-1] == '.'
-			       || ptr[-1] == '_'
-			       || (ptr[-1] >= 'a' && ptr[-1] <= 'z')
-			       || (ptr[-1] >= 'A' && ptr[-1] <= 'Z')
-			       || (ptr[-1] & 0xff) >= 0x80);
+       ptr > m_original_expr && (ptr[-1] == '.'
+				 || ptr[-1] == '_'
+				 || (ptr[-1] >= 'a' && ptr[-1] <= 'z')
+				 || (ptr[-1] >= 'A' && ptr[-1] <= 'Z')
+				 || (ptr[-1] & 0xff) >= 0x80);
        --ptr)
     {
       /* Nothing.  */
@@ -1903,7 +1920,7 @@ write_var_or_type_completion (struct parser_state *par_state,
 
   ada_structop_operation *op = write_selectors (par_state,
 						name0.ptr + tail_index);
-  op->set_prefix (find_completion_bounds (par_state));
+  op->set_prefix (ada_parser->find_completion_bounds ());
   par_state->mark_struct_expression (op);
   return nullptr;
 }

-- 
2.43.0


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 04/12] Move "int_storage" global into ada_parse_state
  2024-03-21 19:03 [PATCH 00/12] Ada iterated assignment, plus parser cleanups Tom Tromey
                   ` (2 preceding siblings ...)
  2024-03-21 19:03 ` [PATCH 03/12] Introduce ada_parse_state Tom Tromey
@ 2024-03-21 19:03 ` Tom Tromey
  2024-03-21 19:03 ` [PATCH 05/12] Move "components" and "associations" " Tom Tromey
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2024-03-21 19:03 UTC (permalink / raw)
  To: gdb-patches

This patch moves the "int_storage" global into ada_parse_state.
---
 gdb/ada-exp.y | 17 +++++++++++------
 gdb/ada-lex.l |  3 +--
 2 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y
index 9452e63ab60..a8066414468 100644
--- a/gdb/ada-exp.y
+++ b/gdb/ada-exp.y
@@ -76,8 +76,19 @@ struct ada_parse_state
 
   std::string find_completion_bounds ();
 
+  const gdb_mpz *push_integer (gdb_mpz &&val)
+  {
+    auto &result = m_int_storage.emplace_back (new gdb_mpz (std::move (val)));
+    return result.get ();
+  }
+
 private:
 
+  /* We don't have a good way to manage non-POD data in Yacc, so store
+     values here.  The storage here is only valid for the duration of
+     the parse.  */
+  std::vector<std::unique_ptr<gdb_mpz>> m_int_storage;
+
   /* The original expression string.  */
   const char *m_original_expr;
 };
@@ -86,11 +97,6 @@ private:
 
 static ada_parse_state *ada_parser;
 
-/* We don't have a good way to manage non-POD data in Yacc, so store
-   values here.  The storage here is only valid for the duration of
-   the parse.  */
-static std::vector<std::unique_ptr<gdb_mpz>> int_storage;
-
 int yyparse (void);
 
 static int yylex (void);
@@ -1253,7 +1259,6 @@ ada_parse (struct parser_state *par_state)
   obstack_init (&temp_parse_space);
   components.clear ();
   associations.clear ();
-  int_storage.clear ();
   assignments.clear ();
   iterated_associations.clear ();
 
diff --git a/gdb/ada-lex.l b/gdb/ada-lex.l
index e1abf9adc25..109b95ccc35 100644
--- a/gdb/ada-lex.l
+++ b/gdb/ada-lex.l
@@ -465,8 +465,7 @@ processInt (struct parser_state *par_state, const char *base0,
       return FLOAT;
     }
 
-  const gdb_mpz *value
-    = int_storage.emplace_back (new gdb_mpz (std::move (result))).get ();
+  const gdb_mpz *value = ada_parser->push_integer (std::move (result));
 
   int int_bits = gdbarch_int_bit (par_state->gdbarch ());
   int long_bits = gdbarch_long_bit (par_state->gdbarch ());

-- 
2.43.0


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 05/12] Move "components" and "associations" into ada_parse_state
  2024-03-21 19:03 [PATCH 00/12] Ada iterated assignment, plus parser cleanups Tom Tromey
                   ` (3 preceding siblings ...)
  2024-03-21 19:03 ` [PATCH 04/12] Move "int_storage" global into ada_parse_state Tom Tromey
@ 2024-03-21 19:03 ` Tom Tromey
  2024-03-21 19:03 ` [PATCH 06/12] Move "assignments" global " Tom Tromey
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2024-03-21 19:03 UTC (permalink / raw)
  To: gdb-patches

This patch moves the "components" and "associations" globals into
ada_parse_state.
---
 gdb/ada-exp.y | 32 +++++++++++++++-----------------
 1 file changed, 15 insertions(+), 17 deletions(-)

diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y
index a8066414468..25809b6aa24 100644
--- a/gdb/ada-exp.y
+++ b/gdb/ada-exp.y
@@ -65,6 +65,8 @@ struct name_info {
 
 static struct parser_state *pstate = NULL;
 
+using namespace expr;
+
 /* Data that must be held for the duration of a parse.  */
 
 struct ada_parse_state
@@ -82,6 +84,12 @@ struct ada_parse_state
     return result.get ();
   }
 
+  /* The components being constructed during this parse.  */
+  std::vector<ada_component_up> components;
+
+  /* The associations being constructed during this parse.  */
+  std::vector<ada_association_up> associations;
+
 private:
 
   /* We don't have a good way to manage non-POD data in Yacc, so store
@@ -126,8 +134,6 @@ static struct type *type_for_char (struct parser_state *, ULONGEST);
 
 static struct type *type_system_address (struct parser_state *);
 
-using namespace expr;
-
 /* Handle Ada type resolution for OP.  DEPROCEDURE_P and CONTEXT_TYPE
    are passed to the resolve method, if called.  */
 static operation_up
@@ -336,16 +342,13 @@ ada_funcall (int nargs)
   pstate->push (std::move (funcall));
 }
 
-/* The components being constructed during this parse.  */
-static std::vector<ada_component_up> components;
-
 /* Create a new ada_component_up of the indicated type and arguments,
    and push it on the global 'components' vector.  */
 template<typename T, typename... Arg>
 void
 push_component (Arg... args)
 {
-  components.emplace_back (new T (std::forward<Arg> (args)...));
+  ada_parser->components.emplace_back (new T (std::forward<Arg> (args)...));
 }
 
 /* Examine the final element of the 'components' vector, and return it
@@ -355,7 +358,7 @@ push_component (Arg... args)
 static ada_choices_component *
 choice_component ()
 {
-  ada_component *last = components.back ().get ();
+  ada_component *last = ada_parser->components.back ().get ();
   return gdb::checked_static_cast<ada_choices_component *> (last);
 }
 
@@ -364,8 +367,8 @@ choice_component ()
 static ada_component_up
 pop_component ()
 {
-  ada_component_up result = std::move (components.back ());
-  components.pop_back ();
+  ada_component_up result = std::move (ada_parser->components.back ());
+  ada_parser->components.pop_back ();
   return result;
 }
 
@@ -380,16 +383,13 @@ pop_components (int n)
   return result;
 }
 
-/* The associations being constructed during this parse.  */
-static std::vector<ada_association_up> associations;
-
 /* Create a new ada_association_up of the indicated type and
    arguments, and push it on the global 'associations' vector.  */
 template<typename T, typename... Arg>
 void
 push_association (Arg... args)
 {
-  associations.emplace_back (new T (std::forward<Arg> (args)...));
+  ada_parser->associations.emplace_back (new T (std::forward<Arg> (args)...));
 }
 
 /* Pop the most recent association from the global stack, and return
@@ -397,8 +397,8 @@ push_association (Arg... args)
 static ada_association_up
 pop_association ()
 {
-  ada_association_up result = std::move (associations.back ());
-  associations.pop_back ();
+  ada_association_up result = std::move (ada_parser->associations.back ());
+  ada_parser->associations.pop_back ();
   return result;
 }
 
@@ -1257,8 +1257,6 @@ ada_parse (struct parser_state *par_state)
   lexer_init (yyin);		/* (Re-)initialize lexer.  */
   obstack_free (&temp_parse_space, NULL);
   obstack_init (&temp_parse_space);
-  components.clear ();
-  associations.clear ();
   assignments.clear ();
   iterated_associations.clear ();
 

-- 
2.43.0


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 06/12] Move "assignments" global into ada_parse_state
  2024-03-21 19:03 [PATCH 00/12] Ada iterated assignment, plus parser cleanups Tom Tromey
                   ` (4 preceding siblings ...)
  2024-03-21 19:03 ` [PATCH 05/12] Move "components" and "associations" " Tom Tromey
@ 2024-03-21 19:03 ` Tom Tromey
  2024-03-21 19:03 ` [PATCH 07/12] Move "iterated_associations" " Tom Tromey
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2024-03-21 19:03 UTC (permalink / raw)
  To: gdb-patches

This patch moves the "assignments" global into ada_parse_state.
---
 gdb/ada-exp.y | 25 ++++++++++++-------------
 1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y
index 25809b6aa24..1c5ffff3290 100644
--- a/gdb/ada-exp.y
+++ b/gdb/ada-exp.y
@@ -67,6 +67,9 @@ static struct parser_state *pstate = NULL;
 
 using namespace expr;
 
+/* A convenience typedef.  */
+typedef std::unique_ptr<ada_assign_operation> ada_assign_up;
+
 /* Data that must be held for the duration of a parse.  */
 
 struct ada_parse_state
@@ -90,6 +93,10 @@ struct ada_parse_state
   /* The associations being constructed during this parse.  */
   std::vector<ada_association_up> associations;
 
+  /* The stack of currently active assignment expressions.  This is used
+     to implement '@', the target name symbol.  */
+  std::vector<ada_assign_up> assignments;
+
 private:
 
   /* We don't have a good way to manage non-POD data in Yacc, so store
@@ -437,13 +444,6 @@ make_tick_completer (struct stoken tok)
 	  (new ada_tick_completer (std::string (tok.ptr, tok.length))));
 }
 
-/* A convenience typedef.  */
-typedef std::unique_ptr<ada_assign_operation> ada_assign_up;
-
-/* The stack of currently active assignment expressions.  This is used
-   to implement '@', the target name symbol.  */
-static std::vector<ada_assign_up> assignments;
-
 /* Track currently active iterated assignment names.  */
 static std::unordered_map<std::string, std::vector<ada_index_var_operation *>>
      iterated_associations;
@@ -528,14 +528,14 @@ exp1	:	exp
 			{ ada_wrap2<comma_operation> (BINOP_COMMA); }
 	| 	primary ASSIGN
 			{
-			  assignments.emplace_back
+			  ada_parser->assignments.emplace_back
 			    (new ada_assign_operation (ada_pop (), nullptr));
 			}
 		exp   /* Extension for convenience */
 			{
 			  ada_assign_up assign
-			    = std::move (assignments.back ());
-			  assignments.pop_back ();
+			    = std::move (ada_parser->assignments.back ());
+			  ada_parser->assignments.pop_back ();
 			  value *lhs_val = (assign->eval_for_resolution
 					    (pstate->expout.get ()));
 
@@ -646,11 +646,11 @@ primary :     	aggregate
 
 primary :	'@'
 			{
-			  if (assignments.empty ())
+			  if (ada_parser->assignments.empty ())
 			    error (_("the target name symbol ('@') may only "
 				     "appear in an assignment context"));
 			  ada_assign_operation *current
-			    = assignments.back ().get ();
+			    = ada_parser->assignments.back ().get ();
 			  pstate->push_new<ada_target_operation> (current);
 			}
 	;
@@ -1257,7 +1257,6 @@ ada_parse (struct parser_state *par_state)
   lexer_init (yyin);		/* (Re-)initialize lexer.  */
   obstack_free (&temp_parse_space, NULL);
   obstack_init (&temp_parse_space);
-  assignments.clear ();
   iterated_associations.clear ();
 
   int result = yyparse ();

-- 
2.43.0


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 07/12] Move "iterated_associations" into ada_parse_state
  2024-03-21 19:03 [PATCH 00/12] Ada iterated assignment, plus parser cleanups Tom Tromey
                   ` (5 preceding siblings ...)
  2024-03-21 19:03 ` [PATCH 06/12] Move "assignments" global " Tom Tromey
@ 2024-03-21 19:03 ` Tom Tromey
  2024-03-21 19:03 ` [PATCH 08/12] Move "temp_parse_space" " Tom Tromey
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2024-03-21 19:03 UTC (permalink / raw)
  To: gdb-patches

This patch moves the "iterated_associations" global into
ada_parse_state.
---
 gdb/ada-exp.y | 25 ++++++++++++-------------
 1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y
index 1c5ffff3290..615b74d14d8 100644
--- a/gdb/ada-exp.y
+++ b/gdb/ada-exp.y
@@ -97,6 +97,10 @@ struct ada_parse_state
      to implement '@', the target name symbol.  */
   std::vector<ada_assign_up> assignments;
 
+  /* Track currently active iterated assignment names.  */
+  std::unordered_map<std::string, std::vector<ada_index_var_operation *>>
+       iterated_associations;
+
 private:
 
   /* We don't have a good way to manage non-POD data in Yacc, so store
@@ -444,10 +448,6 @@ make_tick_completer (struct stoken tok)
 	  (new ada_tick_completer (std::string (tok.ptr, tok.length))));
 }
 
-/* Track currently active iterated assignment names.  */
-static std::unordered_map<std::string, std::vector<ada_index_var_operation *>>
-     iterated_associations;
-
 %}
 
 %union
@@ -1128,12 +1128,12 @@ component_group :
 			{
 			  std::string name = copy_name ($2);
 
-			  auto iter = iterated_associations.find (name);
-			  if (iter != iterated_associations.end ())
+			  auto iter = ada_parser->iterated_associations.find (name);
+			  if (iter != ada_parser->iterated_associations.end ())
 			    error (_("Nested use of index parameter '%s'"),
 				   name.c_str ());
 
-			  iterated_associations[name] = {};
+			  ada_parser->iterated_associations[name] = {};
 			}
 		component_associations
 			{
@@ -1142,12 +1142,12 @@ component_group :
 			  ada_choices_component *choices = choice_component ();
 			  choices->set_associations (pop_associations ($5));
 
-			  auto iter = iterated_associations.find (name);
-			  gdb_assert (iter != iterated_associations.end ());
+			  auto iter = ada_parser->iterated_associations.find (name);
+			  gdb_assert (iter != ada_parser->iterated_associations.end ());
 			  for (ada_index_var_operation *var : iter->second)
 			    var->set_choices (choices);
 
-			  iterated_associations.erase (name);
+			  ada_parser->iterated_associations.erase (name);
 
 			  choices->set_name (std::move (name));
 			}
@@ -1257,7 +1257,6 @@ ada_parse (struct parser_state *par_state)
   lexer_init (yyin);		/* (Re-)initialize lexer.  */
   obstack_free (&temp_parse_space, NULL);
   obstack_init (&temp_parse_space);
-  iterated_associations.clear ();
 
   int result = yyparse ();
   if (!result)
@@ -1707,8 +1706,8 @@ write_var_or_type (struct parser_state *par_state,
 
   if (block == nullptr)
     {
-      auto iter = iterated_associations.find (name_storage);
-      if (iter != iterated_associations.end ())
+      auto iter = ada_parser->iterated_associations.find (name_storage);
+      if (iter != ada_parser->iterated_associations.end ())
 	{
 	  auto op = std::make_unique<ada_index_var_operation> ();
 	  iter->second.push_back (op.get ());

-- 
2.43.0


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 08/12] Move "temp_parse_space" into ada_parse_state
  2024-03-21 19:03 [PATCH 00/12] Ada iterated assignment, plus parser cleanups Tom Tromey
                   ` (6 preceding siblings ...)
  2024-03-21 19:03 ` [PATCH 07/12] Move "iterated_associations" " Tom Tromey
@ 2024-03-21 19:03 ` Tom Tromey
  2024-03-21 19:03 ` [PATCH 09/12] Move "paren_depth" " Tom Tromey
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2024-03-21 19:03 UTC (permalink / raw)
  To: gdb-patches

This patch moves the "temp_parse_space" global into ada_parse_state.
It is also renamed to remove the redundant "parse".  Finally, it is
changed to an auto_obstack to avoid the need for any manual
management.
---
 gdb/ada-exp.y | 28 +++++++++++-----------------
 gdb/ada-lex.l |  7 ++++---
 2 files changed, 15 insertions(+), 20 deletions(-)

diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y
index 615b74d14d8..73178a58a0c 100644
--- a/gdb/ada-exp.y
+++ b/gdb/ada-exp.y
@@ -101,6 +101,8 @@ struct ada_parse_state
   std::unordered_map<std::string, std::vector<ada_index_var_operation *>>
        iterated_associations;
 
+  auto_obstack temp_space;
+
 private:
 
   /* We don't have a good way to manage non-POD data in Yacc, so store
@@ -1234,8 +1236,6 @@ primary	:	'*' primary		%prec '.'
 #define yyrestart ada_yyrestart
 #define yytext ada_yytext
 
-static struct obstack temp_parse_space;
-
 /* The following kludge was found necessary to prevent conflicts between */
 /* defs.h and non-standard stdlib.h files.  */
 #define qsort __qsort__dummy
@@ -1255,8 +1255,6 @@ ada_parse (struct parser_state *par_state)
 							par_state->debug);
 
   lexer_init (yyin);		/* (Re-)initialize lexer.  */
-  obstack_free (&temp_parse_space, NULL);
-  obstack_init (&temp_parse_space);
 
   int result = yyparse ();
   if (!result)
@@ -1323,7 +1321,7 @@ write_object_renaming (struct parser_state *par_state,
   if (orig_left_context == NULL)
     orig_left_context = get_selected_block (NULL);
 
-  name = obstack_strndup (&temp_parse_space, renamed_entity,
+  name = obstack_strndup (&ada_parser->temp_space, renamed_entity,
 			  renamed_entity_len);
   ada_lookup_encoded_symbol (name, orig_left_context, SEARCH_VFT, &sym_info);
   if (sym_info.symbol == NULL)
@@ -1389,7 +1387,8 @@ write_object_renaming (struct parser_state *par_state,
 	    if (end == NULL)
 	      end = renaming_expr + strlen (renaming_expr);
 
-	    index_name = obstack_strndup (&temp_parse_space, renaming_expr,
+	    index_name = obstack_strndup (&ada_parser->temp_space,
+					  renaming_expr,
 					  end - renaming_expr);
 	    renaming_expr = end;
 
@@ -1608,10 +1607,10 @@ static void
 write_ambiguous_var (struct parser_state *par_state,
 		     const struct block *block, const char *name, int len)
 {
-  struct symbol *sym = new (&temp_parse_space) symbol ();
+  struct symbol *sym = new (&ada_parser->temp_space) symbol ();
 
   sym->set_domain (UNDEF_DOMAIN);
-  sym->set_linkage_name (obstack_strndup (&temp_parse_space, name, len));
+  sym->set_linkage_name (obstack_strndup (&ada_parser->temp_space, name, len));
   sym->set_language (language_ada, nullptr);
 
   block_symbol bsym { sym, block };
@@ -1719,7 +1718,8 @@ write_var_or_type (struct parser_state *par_state,
     }
 
   name_len = name_storage.size ();
-  encoded_name = obstack_strndup (&temp_parse_space, name_storage.c_str (),
+  encoded_name = obstack_strndup (&ada_parser->temp_space,
+				  name_storage.c_str (),
 				  name_len);
   for (depth = 0; depth < MAX_RENAMING_CHAIN_LENGTH; depth += 1)
     {
@@ -1765,7 +1765,8 @@ write_var_or_type (struct parser_state *par_state,
 	      {
 		int alloc_len = renaming_len + name_len - tail_index + 1;
 		char *new_name
-		  = (char *) obstack_alloc (&temp_parse_space, alloc_len);
+		  = (char *) obstack_alloc (&ada_parser->temp_space,
+					    alloc_len);
 		strncpy (new_name, renaming, renaming_len);
 		strcpy (new_name + renaming_len, encoded_name + tail_index);
 		encoded_name = new_name;
@@ -1987,10 +1988,3 @@ type_system_address (struct parser_state *par_state)
 				      "system__address");
   return  type != NULL ? type : parse_type (par_state)->builtin_data_ptr;
 }
-
-void _initialize_ada_exp ();
-void
-_initialize_ada_exp ()
-{
-  obstack_init (&temp_parse_space);
-}
diff --git a/gdb/ada-lex.l b/gdb/ada-lex.l
index 109b95ccc35..90cb5ba1b8a 100644
--- a/gdb/ada-lex.l
+++ b/gdb/ada-lex.l
@@ -531,7 +531,7 @@ processReal (struct parser_state *par_state, const char *num0)
 static struct stoken
 processId (const char *name0, int len)
 {
-  char *name = (char *) obstack_alloc (&temp_parse_space, len + 11);
+  char *name = (char *) obstack_alloc (&ada_parser->temp_space, len + 11);
   int i0, i;
   struct stoken result;
 
@@ -593,7 +593,7 @@ processString (const char *text, int len)
   const char *lim = text + len;
   struct stoken result;
 
-  q = (char *) obstack_alloc (&temp_parse_space, len);
+  q = (char *) obstack_alloc (&ada_parser->temp_space, len);
   result.ptr = q;
   p = text;
   while (p < lim)
@@ -706,7 +706,8 @@ processAttribute (const char *str)
     {
       /* This is enforced by YY_INPUT.  */
       gdb_assert (pstate->parse_completion);
-      yylval.sval.ptr = obstack_strndup (&temp_parse_space, str, len - 1);
+      yylval.sval.ptr = obstack_strndup (&ada_parser->temp_space,
+					 str, len - 1);
       yylval.sval.length = len - 1;
       return TICK_COMPLETE;
     }

-- 
2.43.0


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 09/12] Move "paren_depth" into ada_parse_state
  2024-03-21 19:03 [PATCH 00/12] Ada iterated assignment, plus parser cleanups Tom Tromey
                   ` (7 preceding siblings ...)
  2024-03-21 19:03 ` [PATCH 08/12] Move "temp_parse_space" " Tom Tromey
@ 2024-03-21 19:03 ` Tom Tromey
  2024-03-21 19:03 ` [PATCH 10/12] Move "returned_complete" " Tom Tromey
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2024-03-21 19:03 UTC (permalink / raw)
  To: gdb-patches

This moves the "paren_depth" global into ada_parse_state.
---
 gdb/ada-exp.y |  3 +++
 gdb/ada-lex.l | 12 ++++--------
 2 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y
index 73178a58a0c..2b058571492 100644
--- a/gdb/ada-exp.y
+++ b/gdb/ada-exp.y
@@ -103,6 +103,9 @@ struct ada_parse_state
 
   auto_obstack temp_space;
 
+  /* Depth of parentheses, used by the lexer.  */
+  int paren_depth = 0;
+
 private:
 
   /* We don't have a good way to manage non-POD data in Yacc, so store
diff --git a/gdb/ada-lex.l b/gdb/ada-lex.l
index 90cb5ba1b8a..9161c4377c0 100644
--- a/gdb/ada-lex.l
+++ b/gdb/ada-lex.l
@@ -108,9 +108,6 @@ static bool returned_complete = false;
       pstate->lexptr += 1;						\
     }
 
-/* Depth of parentheses.  */
-static int paren_depth;
-
 %}
 
 %option case-insensitive interactive nodefault noyywrap
@@ -268,7 +265,7 @@ false		{ return FALSEKEYWORD; }
 
 [-&*+{}@/:<>=|;\[\]] { return yytext[0]; }
 
-","		{ if (paren_depth == 0 && pstate->comma_terminates)
+","		{ if (ada_parser->paren_depth == 0 && pstate->comma_terminates)
 		    {
 		      rewind_to_char (',');
 		      return 0;
@@ -277,15 +274,15 @@ false		{ return FALSEKEYWORD; }
 		    return ',';
 		}
 
-"("		{ paren_depth += 1; return '('; }
-")"		{ if (paren_depth == 0)
+"("		{ ada_parser->paren_depth += 1; return '('; }
+")"		{ if (ada_parser->paren_depth == 0)
 		    {
 		      rewind_to_char (')');
 		      return 0;
 		    }
 		  else
  		    {
-		      paren_depth -= 1;
+		      ada_parser->paren_depth -= 1;
 		      return ')';
 		    }
 		}
@@ -349,7 +346,6 @@ static void
 lexer_init (FILE *inp)
 {
   BEGIN INITIAL;
-  paren_depth = 0;
   returned_complete = false;
   yyrestart (inp);
 }

-- 
2.43.0


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 10/12] Move "returned_complete" into ada_parse_state
  2024-03-21 19:03 [PATCH 00/12] Ada iterated assignment, plus parser cleanups Tom Tromey
                   ` (8 preceding siblings ...)
  2024-03-21 19:03 ` [PATCH 09/12] Move "paren_depth" " Tom Tromey
@ 2024-03-21 19:03 ` Tom Tromey
  2024-03-21 19:03 ` [PATCH 11/12] Remove "numbuf" global Tom Tromey
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2024-03-21 19:03 UTC (permalink / raw)
  To: gdb-patches

This moves the "returned_complete" global into ada_parse_state.
---
 gdb/ada-exp.y |  7 +++++++
 gdb/ada-lex.l | 12 ++----------
 2 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y
index 2b058571492..12f676b75de 100644
--- a/gdb/ada-exp.y
+++ b/gdb/ada-exp.y
@@ -106,6 +106,13 @@ struct ada_parse_state
   /* Depth of parentheses, used by the lexer.  */
   int paren_depth = 0;
 
+  /* When completing, we'll return a special character at the end of the
+     input, to signal the completion position to the lexer.  This is
+     done because flex does not have a generally useful way to detect
+     EOF in a pattern.  This variable records whether the special
+     character has been emitted.  */
+  bool returned_complete = false;
+
 private:
 
   /* We don't have a good way to manage non-POD data in Yacc, so store
diff --git a/gdb/ada-lex.l b/gdb/ada-lex.l
index 9161c4377c0..11221723eb3 100644
--- a/gdb/ada-lex.l
+++ b/gdb/ada-lex.l
@@ -78,13 +78,6 @@ static void rewind_to_char (int);
    Defining YY_NO_INPUT comments it out.  */
 #define YY_NO_INPUT
 
-/* When completing, we'll return a special character at the end of the
-   input, to signal the completion position to the lexer.  This is
-   done because flex does not have a generally useful way to detect
-   EOF in a pattern.  This variable records whether the special
-   character has been emitted.  */
-static bool returned_complete = false;
-
 /* The character we use to represent the completion point.  */
 #define COMPLETE_CHAR '\001'
 
@@ -92,9 +85,9 @@ static bool returned_complete = false;
 #define YY_INPUT(BUF, RESULT, MAX_SIZE)					\
   if ( *pstate->lexptr == '\000' )					\
     {									\
-      if (pstate->parse_completion && !returned_complete)		\
+      if (pstate->parse_completion && !ada_parser->returned_complete)	\
 	{								\
-	  returned_complete = true;					\
+	  ada_parser->returned_complete = true;				\
 	  *(BUF) = COMPLETE_CHAR;					\
 	  (RESULT) = 1;							\
 	}								\
@@ -346,7 +339,6 @@ static void
 lexer_init (FILE *inp)
 {
   BEGIN INITIAL;
-  returned_complete = false;
   yyrestart (inp);
 }
 

-- 
2.43.0


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 11/12] Remove "numbuf" global
  2024-03-21 19:03 [PATCH 00/12] Ada iterated assignment, plus parser cleanups Tom Tromey
                   ` (9 preceding siblings ...)
  2024-03-21 19:03 ` [PATCH 10/12] Move "returned_complete" " Tom Tromey
@ 2024-03-21 19:03 ` Tom Tromey
  2024-03-21 19:03 ` [PATCH 12/12] Constify ada-lex.l:attributes Tom Tromey
  2024-04-02 17:35 ` [PATCH 00/12] Ada iterated assignment, plus parser cleanups Tom Tromey
  12 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2024-03-21 19:03 UTC (permalink / raw)
  To: gdb-patches

The lexer has a "numbuf" global that is only used for temporary
storage.  This patch removes the global and redeclares it at the
points of use.
---
 gdb/ada-lex.l | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/gdb/ada-lex.l b/gdb/ada-lex.l
index 11221723eb3..4e99eaab036 100644
--- a/gdb/ada-lex.l
+++ b/gdb/ada-lex.l
@@ -59,9 +59,7 @@ DIAGNOSTIC_IGNORE_DEPRECATED_REGISTER
 #define NUMERAL_WIDTH 256
 #define LONGEST_SIGN ((ULONGEST) 1 << (sizeof(LONGEST) * HOST_CHAR_BIT - 1))
 
-/* Temporary staging for numeric literals.  */
-static char numbuf[NUMERAL_WIDTH];
- static void canonicalizeNumeral (char *s1, const char *);
+static void canonicalizeNumeral (char *s1, const char *);
 static struct stoken processString (const char*, int);
 static int processInt (struct parser_state *, const char *, const char *,
 		       const char *);
@@ -114,6 +112,7 @@ static void rewind_to_char (int);
 "--".*		 { yyterminate(); }
 
 {NUM10}{POSEXP}  {
+		   char numbuf[NUMERAL_WIDTH];
 		   canonicalizeNumeral (numbuf, yytext);
 		   char *e_ptr = strrchr (numbuf, 'e');
 		   *e_ptr = '\0';
@@ -121,11 +120,13 @@ static void rewind_to_char (int);
 		 }
 
 {NUM10}          {
+		   char numbuf[NUMERAL_WIDTH];
 		   canonicalizeNumeral (numbuf, yytext);
 		   return processInt (pstate, NULL, numbuf, NULL);
 		 }
 
 {NUM10}"#"{HEXDIG}({HEXDIG}|_)*"#"{POSEXP} {
+		   char numbuf[NUMERAL_WIDTH];
 		   canonicalizeNumeral (numbuf, yytext);
 		   char *e_ptr = strrchr (numbuf, 'e');
 		   *e_ptr = '\0';
@@ -139,23 +140,27 @@ static void rewind_to_char (int);
 	   floating-point number is formed by reinterpreting the
 	   bytes, allowing direct control over the bits.  */
 {NUM10}(l{0,2}f)?"#"{HEXDIG}({HEXDIG}|_)*"#" {
+		   char numbuf[NUMERAL_WIDTH];
 		   canonicalizeNumeral (numbuf, yytext);
 		   return processInt (pstate, numbuf, strchr (numbuf, '#') + 1,
 				      NULL);
 		 }
 
 "0x"{HEXDIG}+	{
+		  char numbuf[NUMERAL_WIDTH];
 		  canonicalizeNumeral (numbuf, yytext+2);
 		  return processInt (pstate, "16#", numbuf, NULL);
 		}
 
 
 {NUM10}"."{NUM10}{EXP} {
+		   char numbuf[NUMERAL_WIDTH];
 		   canonicalizeNumeral (numbuf, yytext);
 		   return processReal (pstate, numbuf);
 		}
 
 {NUM10}"."{NUM10} {
+		   char numbuf[NUMERAL_WIDTH];
 		   canonicalizeNumeral (numbuf, yytext);
 		   return processReal (pstate, numbuf);
 		}

-- 
2.43.0


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 12/12] Constify ada-lex.l:attributes
  2024-03-21 19:03 [PATCH 00/12] Ada iterated assignment, plus parser cleanups Tom Tromey
                   ` (10 preceding siblings ...)
  2024-03-21 19:03 ` [PATCH 11/12] Remove "numbuf" global Tom Tromey
@ 2024-03-21 19:03 ` Tom Tromey
  2024-04-02 17:35 ` [PATCH 00/12] Ada iterated assignment, plus parser cleanups Tom Tromey
  12 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2024-03-21 19:03 UTC (permalink / raw)
  To: gdb-patches

While examining the Ada parser globals with 'nm', I noticed that the
lexer's "attributes" array should be const.  This change moves it into
read-only storage.
---
 gdb/ada-lex.l | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gdb/ada-lex.l b/gdb/ada-lex.l
index 4e99eaab036..1b1aaf89005 100644
--- a/gdb/ada-lex.l
+++ b/gdb/ada-lex.l
@@ -662,7 +662,7 @@ subseqMatch (const char *subseq, const char *str)
 }
 
 
-static struct { const char *name; int code; }
+static const struct { const char *name; int code; }
 attributes[] = {
   { "address", TICK_ADDRESS },
   { "unchecked_access", TICK_ACCESS },

-- 
2.43.0


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 00/12] Ada iterated assignment, plus parser cleanups
  2024-03-21 19:03 [PATCH 00/12] Ada iterated assignment, plus parser cleanups Tom Tromey
                   ` (11 preceding siblings ...)
  2024-03-21 19:03 ` [PATCH 12/12] Constify ada-lex.l:attributes Tom Tromey
@ 2024-04-02 17:35 ` Tom Tromey
  12 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2024-04-02 17:35 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

>>>>> "Tom" == Tom Tromey <tromey@adacore.com> writes:

Tom> This series implements the Ada 2022 iterated assignment feature.  An
Tom> earlier version of the patch failed to clear a new global in the
Tom> parser, so I also ended up tacking on a series to make sure this
Tom> problem can't happen again -- all parser state is moved into a new
Tom> object.  (All the parsers should do this, or go further and follow
Tom> Rust into recursive descent, IMNSHO.)

Tom> Tested on x86-64 Fedora 38.  This has also been running inside AdaCore
Tom> for a while now.

I'm checking this in now.

Tom

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2024-04-02 17:35 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-03-21 19:03 [PATCH 00/12] Ada iterated assignment, plus parser cleanups Tom Tromey
2024-03-21 19:03 ` [PATCH 01/12] Introduce and use aggregate_assigner type Tom Tromey
2024-03-21 19:03 ` [PATCH 02/12] Implement Ada 2022 iterated assignment Tom Tromey
2024-03-21 19:03 ` [PATCH 03/12] Introduce ada_parse_state Tom Tromey
2024-03-21 19:03 ` [PATCH 04/12] Move "int_storage" global into ada_parse_state Tom Tromey
2024-03-21 19:03 ` [PATCH 05/12] Move "components" and "associations" " Tom Tromey
2024-03-21 19:03 ` [PATCH 06/12] Move "assignments" global " Tom Tromey
2024-03-21 19:03 ` [PATCH 07/12] Move "iterated_associations" " Tom Tromey
2024-03-21 19:03 ` [PATCH 08/12] Move "temp_parse_space" " Tom Tromey
2024-03-21 19:03 ` [PATCH 09/12] Move "paren_depth" " Tom Tromey
2024-03-21 19:03 ` [PATCH 10/12] Move "returned_complete" " Tom Tromey
2024-03-21 19:03 ` [PATCH 11/12] Remove "numbuf" global Tom Tromey
2024-03-21 19:03 ` [PATCH 12/12] Constify ada-lex.l:attributes Tom Tromey
2024-04-02 17:35 ` [PATCH 00/12] Ada iterated assignment, plus parser cleanups Tom Tromey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox