From: simon.marchi@polymtl.ca
To: gdb-patches@sourceware.org
Cc: Simon Marchi <simon.marchi@polymtl.ca>
Subject: [PATCH 12/17] gdb: move ada-exp-parser.y's support code to ada-exp-parser.c
Date: Fri, 4 Sep 2026 12:56:44 -0400 [thread overview]
Message-ID: <20260904170338.1643894-13-simon.marchi@polymtl.ca> (raw)
In-Reply-To: <20260904170338.1643894-1-simon.marchi@polymtl.ca>
From: Simon Marchi <simon.marchi@polymtl.ca>
Similar to the previous commit, but for the Ada expression parser.
This one is slightly different because the Ada parser also uses a
flex-generated lexer (the only one in the GDB tree to do so). So a few
functions are moved from ada-exp.l to ada-exp-parser.{c,h}. But the idea
remains the same.
The lexer_init function is still defined in ada-exp.l, because it needs to
see some special macros defined in ada-lex-gen.c.
Put the parser support code inside the ada_exp_parser namespace.
Change-Id: I38bee40f9b6c91c947ba8ab25fe9caa6fb9f9f15
---
gdb/Makefile.in | 2 +
gdb/ada-exp-parser.c | 1351 ++++++++++++++++++++++++++++++++++++++++++
gdb/ada-exp-parser.h | 427 +++++++++++++
gdb/ada-exp-parser.y | 1152 +----------------------------------
gdb/ada-lang.c | 1 +
gdb/ada-lang.h | 2 -
gdb/ada-lex.l | 429 +-------------
7 files changed, 1790 insertions(+), 1574 deletions(-)
create mode 100644 gdb/ada-exp-parser.c
create mode 100644 gdb/ada-exp-parser.h
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 4cd503e2175f..d2cfecb0def9 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1032,6 +1032,7 @@ TARGET_FLAGS_TO_PASS = \
# Files that should wind up in SFILES and whose corresponding .o
# should be in COMMON_OBS.
COMMON_SFILES = \
+ ada-exp-parser.c \
ada-lang.c \
ada-tasks.c \
ada-typeprint.c \
@@ -1275,6 +1276,7 @@ HFILES_NO_SRCDIR = \
aarch64-ravenscar-thread.h \
aarch64-tdep.h \
ada-casefold.h \
+ ada-exp-parser.h \
ada-exp.h \
ada-lang.h \
addrmap.h \
diff --git a/gdb/ada-exp-parser.c b/gdb/ada-exp-parser.c
new file mode 100644
index 000000000000..4cae9e4d1fe8
--- /dev/null
+++ b/gdb/ada-exp-parser.c
@@ -0,0 +1,1351 @@
+/* Support code for the Ada expression parser, for GDB.
+
+ Copyright (C) 1986-2026 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/>. */
+
+#include "ada-exp-parser.h"
+#include "ada-exp-parser-gen.h"
+#include "ada-lang.h"
+#include "ada-lex-gen.h"
+#include "block.h"
+#include "cli/cli-style.h"
+#include "gdbsupport/scoped_restore.h"
+#include "parser-defs.h"
+
+using namespace expr;
+
+/* The entry point of the bison/yacc-generated parser, defined in
+ ada-exp-parser-gen.c. Bison produces a declaration for ada_yyparse in
+ ada-exp-parser-gen.h, but byacc does not, hence this declaration. */
+
+int ada_yyparse ();
+
+/* Likewise, byacc does not produce a declaration for ada_yydebug. */
+
+extern int ada_yydebug;
+
+namespace ada_exp_parser
+{
+
+/* See ada-exp-parser.h. */
+
+struct parser_state *pstate;
+
+/* See ada-exp-parser.h. */
+
+struct ada_parse_state *ada_parser;
+
+/* See ada-exp-parser.h. */
+
+void
+canonicalizeNumeral (char *s1, const char *s2)
+{
+ for (; *s2 != '\000'; s2 += 1)
+ {
+ if (*s2 != '_')
+ {
+ *s1 = c_tolower(*s2);
+ s1 += 1;
+ }
+ }
+ s1[0] = '\000';
+}
+
+/* See ada-exp-parser.h. */
+
+int
+processInt (struct parser_state *par_state, const char *base0,
+ const char *num0, const char *exp0)
+{
+ long exp;
+ int base;
+ /* For the based literal with an "f" prefix, we'll return a
+ floating-point number. This counts the number of "l"s seen,
+ to decide the width of the floating-point number to return. -1
+ means no "f". */
+ int floating_point_l_count = -1;
+
+ if (base0 == NULL)
+ base = 10;
+ else
+ {
+ char *end_of_base;
+ base = strtol (base0, &end_of_base, 10);
+ if (base < 2 || base > 16)
+ error (_("Invalid base: %d."), base);
+ while (*end_of_base == 'l')
+ {
+ ++floating_point_l_count;
+ ++end_of_base;
+ }
+ /* This assertion is ensured by the pattern. */
+ gdb_assert (floating_point_l_count == -1 || *end_of_base == 'f');
+ if (*end_of_base == 'f')
+ {
+ ++end_of_base;
+ ++floating_point_l_count;
+ }
+ /* This assertion is ensured by the pattern. */
+ gdb_assert (*end_of_base == '#');
+ }
+
+ if (exp0 == NULL)
+ exp = 0;
+ else
+ exp = strtol(exp0, (char **) NULL, 10);
+
+ gdb_mpz result;
+ while (c_isxdigit (*num0))
+ {
+ int dig = fromhex (*num0);
+ if (dig >= base)
+ error (_("Invalid digit `%c' in based literal"), *num0);
+ result *= base;
+ result += dig;
+ ++num0;
+ }
+
+ while (exp > 0)
+ {
+ result *= base;
+ exp -= 1;
+ }
+
+ if (floating_point_l_count > -1)
+ {
+ struct type *fp_type;
+ if (floating_point_l_count == 0)
+ fp_type = language_lookup_primitive_type (par_state->language (),
+ par_state->gdbarch (),
+ "float");
+ else if (floating_point_l_count == 1)
+ fp_type = language_lookup_primitive_type (par_state->language (),
+ par_state->gdbarch (),
+ "long_float");
+ else
+ {
+ /* This assertion is ensured by the pattern. */
+ gdb_assert (floating_point_l_count == 2);
+ fp_type = language_lookup_primitive_type (par_state->language (),
+ par_state->gdbarch (),
+ "long_long_float");
+ }
+
+ ada_yylval.typed_val_float.type = fp_type;
+ result.write (gdb::make_array_view (ada_yylval.typed_val_float.val,
+ fp_type->length ()),
+ type_byte_order (fp_type),
+ true);
+
+ return FLOAT;
+ }
+
+ 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 ());
+ int long_long_bits = gdbarch_long_long_bit (par_state->gdbarch ());
+
+ if (fits_in_type (1, *value, int_bits, true))
+ ada_yylval.typed_val.type = parse_type (par_state)->builtin_int;
+ else if (fits_in_type (1, *value, long_bits, true))
+ ada_yylval.typed_val.type = parse_type (par_state)->builtin_long;
+ else if (fits_in_type (1, *value, long_bits, false))
+ ada_yylval.typed_val.type
+ = builtin_type (par_state->gdbarch ())->builtin_unsigned_long;
+ else if (fits_in_type (1, *value, long_long_bits, true))
+ ada_yylval.typed_val.type = parse_type (par_state)->builtin_long_long;
+ else if (fits_in_type (1, *value, long_long_bits, false))
+ ada_yylval.typed_val.type
+ = builtin_type (par_state->gdbarch ())->builtin_unsigned_long_long;
+ else if (fits_in_type (1, *value, 128, true))
+ ada_yylval.typed_val.type
+ = language_lookup_primitive_type (par_state->language (),
+ par_state->gdbarch (),
+ "long_long_long_integer");
+ else if (fits_in_type (1, *value, 128, false))
+ ada_yylval.typed_val.type
+ = language_lookup_primitive_type (par_state->language (),
+ par_state->gdbarch (),
+ "unsigned_long_long_long_integer");
+ else
+ error (_("Integer literal out of range"));
+
+ ada_yylval.typed_val.val = value;
+ return INT;
+}
+
+/* See ada-exp-parser.h. */
+
+int
+processReal (struct parser_state *par_state, const char *num0)
+{
+ ada_yylval.typed_val_float.type = parse_type (par_state)->builtin_long_double;
+
+ bool parsed = parse_float (num0, strlen (num0),
+ ada_yylval.typed_val_float.type,
+ ada_yylval.typed_val_float.val);
+ gdb_assert (parsed);
+ return FLOAT;
+}
+
+
+/* See ada-exp-parser.h. */
+
+struct stoken
+processId (const char *name0, int len)
+{
+ char *name = (char *) obstack_alloc (&ada_parser->temp_space, len + 11);
+ int i0, i;
+ struct stoken result;
+
+ result.ptr = name;
+ while (len > 0 && c_isspace (name0[len-1]))
+ len -= 1;
+
+ if (name0[0] == '<' || strstr (name0, "___") != NULL)
+ {
+ strncpy (name, name0, len);
+ name[len] = '\000';
+ result.length = len;
+ return result;
+ }
+
+ bool in_quotes = false;
+ i = i0 = 0;
+ while (i0 < len)
+ {
+ if (name0[i0] == COMPLETE_CHAR)
+ {
+ /* Just ignore. */
+ ++i0;
+ }
+ else if (in_quotes)
+ name[i++] = name0[i0++];
+ else if (c_isalnum (name0[i0]))
+ {
+ name[i] = c_tolower (name0[i0]);
+ i += 1; i0 += 1;
+ }
+ else if (c_isspace (name0[i0]))
+ i0 += 1;
+ else if (name0[i0] == '\'')
+ {
+ /* Copy the starting quote, but not the ending quote. */
+ if (!in_quotes)
+ name[i++] = name0[i0++];
+ in_quotes = !in_quotes;
+ }
+ else
+ name[i++] = name0[i0++];
+ }
+ name[i] = '\000';
+
+ result.length = i;
+ return result;
+}
+
+/* See ada-exp-parser.h. */
+
+struct stoken
+processString (const char *text, int len)
+{
+ const char *p;
+ char *q;
+ const char *lim = text + len;
+ struct stoken result;
+
+ q = (char *) obstack_alloc (&ada_parser->temp_space, len);
+ result.ptr = q;
+ p = text;
+ while (p < lim)
+ {
+ if (p[0] == '[' && p[1] == '"' && p+2 < lim)
+ {
+ if (p[2] == '"') /* "...["""]... */
+ {
+ *q = '"';
+ p += 4;
+ }
+ else
+ {
+ const char *end;
+ ULONGEST chr = strtoulst (p + 2, &end, 16);
+ if (chr > 0xff)
+ error (_("wide strings are not yet supported"));
+ *q = (char) chr;
+ p = end + 1;
+ }
+ }
+ else
+ *q = *p;
+ q += 1;
+ p += 1;
+ }
+ result.length = q - result.ptr;
+ return result;
+}
+
+/* See ada-exp-parser.h. */
+
+int
+find_dot_all (const char *str)
+{
+ int i;
+
+ for (i = 0; str[i] != '\000'; i++)
+ if (str[i] == '.')
+ {
+ int i0 = i;
+
+ do
+ i += 1;
+ while (c_isspace (str[i]));
+
+ if (strncasecmp (str + i, "all", 3) == 0
+ && !c_isalnum (str[i + 3]) && str[i + 3] != '_')
+ return i0;
+ }
+ return -1;
+}
+
+/* Returns non-zero iff string SUBSEQ matches a subsequence of STR, ignoring
+ case. */
+
+static int
+subseqMatch (const char *subseq, const char *str)
+{
+ if (subseq[0] == '\0')
+ return 1;
+ else if (str[0] == '\0')
+ return 0;
+ else if (c_tolower (subseq[0]) == c_tolower (str[0]))
+ return subseqMatch (subseq+1, str+1) || subseqMatch (subseq, str+1);
+ else
+ return subseqMatch (subseq, str+1);
+}
+
+
+static const struct { const char *name; int code; }
+attributes[] = {
+ { "address", TICK_ADDRESS },
+ { "unchecked_access", TICK_ACCESS },
+ { "unrestricted_access", TICK_ACCESS },
+ { "access", TICK_ACCESS },
+ { "first", TICK_FIRST },
+ { "last", TICK_LAST },
+ { "length", TICK_LENGTH },
+ { "max", TICK_MAX },
+ { "min", TICK_MIN },
+ { "modulus", TICK_MODULUS },
+ { "object_size", TICK_OBJECT_SIZE },
+ { "pos", TICK_POS },
+ { "range", TICK_RANGE },
+ { "size", TICK_SIZE },
+ { "tag", TICK_TAG },
+ { "val", TICK_VAL },
+ { "enum_rep", TICK_ENUM_REP },
+ { "enum_val", TICK_ENUM_VAL },
+};
+
+/* See ada-exp-parser.h. */
+
+int
+processAttribute (const char *str)
+{
+ gdb_assert (*str == '\'');
+ ++str;
+ while (c_isspace (*str))
+ ++str;
+
+ int len = strlen (str);
+ if (len > 0 && str[len - 1] == COMPLETE_CHAR)
+ {
+ /* This is enforced by YY_INPUT. */
+ gdb_assert (pstate->parse_completion);
+ ada_yylval.sval.ptr = obstack_strndup (&ada_parser->temp_space,
+ str, len - 1);
+ ada_yylval.sval.length = len - 1;
+ return TICK_COMPLETE;
+ }
+
+ for (const auto &item : attributes)
+ if (strcasecmp (str, item.name) == 0)
+ return item.code;
+
+ std::optional<int> found;
+ for (const auto &item : attributes)
+ if (subseqMatch (str, item.name))
+ {
+ if (!found.has_value ())
+ found = item.code;
+ else
+ error (_("ambiguous attribute name: `%s'"), str);
+ }
+ if (!found.has_value ())
+ error (_("unrecognized attribute: `%s'"), str);
+
+ return *found;
+}
+
+bool
+ada_tick_completer::complete (struct expression *exp,
+ completion_tracker &tracker)
+{
+ completion_list output;
+ for (const auto &item : attributes)
+ {
+ if (strncasecmp (item.name, m_name.c_str (), m_name.length ()) == 0)
+ output.emplace_back (xstrdup (item.name));
+ }
+ tracker.add_completions (std::move (output));
+ return true;
+}
+
+/* See ada-exp-parser.h. */
+
+void
+rewind_to_char (int ch)
+{
+ pstate->lexptr -= ada_yyleng;
+ while (c_toupper (*pstate->lexptr) != c_toupper (ch))
+ pstate->lexptr -= 1;
+ ada_yyrestart (NULL);
+}
+
+/* See ada-exp-parser.h. */
+
+operation_up
+resolve (operation_up &&op, bool deprocedure_p, struct type *context_type)
+{
+ operation_up result = std::move (op);
+ ada_resolvable *res = dynamic_cast<ada_resolvable *> (result.get ());
+ if (res != nullptr)
+ return res->replace (std::move (result),
+ pstate->expout.get (),
+ deprocedure_p,
+ pstate->parse_completion,
+ pstate->block_tracker,
+ context_type);
+ return result;
+}
+
+/* See ada-exp-parser.h. */
+
+operation_up
+ada_pop (bool deprocedure_p, struct type *context_type)
+{
+ /* Of course it's ok to call parser_state::pop here... */
+ return resolve (pstate->pop (), deprocedure_p, context_type);
+}
+
+/* See ada-exp-parser.h. */
+
+void
+ada_addrof (struct type *type)
+{
+ operation_up arg = ada_pop (false);
+ operation_up addr = make_operation<unop_addr_operation> (std::move (arg));
+ operation_up wrapped
+ = make_operation<ada_wrapped_operation> (std::move (addr));
+ if (type != nullptr)
+ wrapped = make_operation<unop_cast_operation> (std::move (wrapped), type);
+ pstate->push (std::move (wrapped));
+}
+
+/* See ada-exp-parser.h. */
+
+operation_up
+maybe_overload (enum exp_opcode op, operation_up &lhs, operation_up &rhs)
+{
+ struct value *args[2];
+
+ int nargs = 1;
+ args[0] = lhs->evaluate (nullptr, pstate->expout.get (),
+ EVAL_AVOID_SIDE_EFFECTS);
+ if (rhs == nullptr)
+ args[1] = nullptr;
+ else
+ {
+ args[1] = rhs->evaluate (nullptr, pstate->expout.get (),
+ EVAL_AVOID_SIDE_EFFECTS);
+ ++nargs;
+ }
+
+ block_symbol fn = ada_find_operator_symbol (op, pstate->parse_completion,
+ nargs, args);
+ if (fn.symbol == nullptr)
+ return {};
+
+ if (symbol_read_needs_frame (fn.symbol))
+ pstate->block_tracker->update (fn.block, INNERMOST_BLOCK_FOR_SYMBOLS);
+ operation_up callee = make_operation<ada_var_value_operation> (fn);
+
+ std::vector<operation_up> argvec;
+ argvec.push_back (std::move (lhs));
+ if (rhs != nullptr)
+ argvec.push_back (std::move (rhs));
+ return make_operation<ada_funcall_operation> (std::move (callee),
+ std::move (argvec));
+}
+
+/* See ada-exp-parser.h. */
+
+void
+ada_funcall (int nargs)
+{
+ /* We use the ordinary pop here, because we're going to do
+ resolution in a separate step, in order to handle array
+ indices. */
+ std::vector<operation_up> args = pstate->pop_vector (nargs);
+ /* Call parser_state::pop here, because we don't want to
+ function-convert the callee slot of a call we're already
+ constructing. */
+ operation_up callee = pstate->pop ();
+
+ ada_var_value_operation *vvo
+ = dynamic_cast<ada_var_value_operation *> (callee.get ());
+ int array_arity = 0;
+ struct type *callee_t = nullptr;
+ if (vvo == nullptr
+ || vvo->get_symbol ()->domain () != UNDEF_DOMAIN)
+ {
+ struct value *callee_v = callee->evaluate (nullptr,
+ pstate->expout.get (),
+ EVAL_AVOID_SIDE_EFFECTS);
+ callee_t = ada_check_typedef (callee_v->type ());
+ array_arity = ada_array_arity (callee_t);
+ }
+
+ for (int i = 0; i < nargs; ++i)
+ {
+ struct type *subtype = nullptr;
+ if (i < array_arity)
+ subtype = ada_index_type (callee_t, i + 1, "array type");
+ args[i] = resolve (std::move (args[i]), true, subtype);
+ }
+
+ std::unique_ptr<ada_funcall_operation> funcall
+ (new ada_funcall_operation (std::move (callee), std::move (args)));
+ funcall->resolve (pstate->expout.get (), true, pstate->parse_completion,
+ pstate->block_tracker, nullptr);
+ pstate->push (std::move (funcall));
+}
+
+/* See ada-exp-parser.h. */
+
+ada_choices_component *
+choice_component ()
+{
+ ada_component *last = ada_parser->components.back ().get ();
+ return gdb::checked_static_cast<ada_choices_component *> (last);
+}
+
+/* See ada-exp-parser.h. */
+
+ada_component_up
+pop_component ()
+{
+ ada_component_up result = std::move (ada_parser->components.back ());
+ ada_parser->components.pop_back ();
+ return result;
+}
+
+/* See ada-exp-parser.h. */
+
+std::vector<ada_component_up>
+pop_components (int n)
+{
+ std::vector<ada_component_up> result (n);
+ for (int i = 1; i <= n; ++i)
+ result[n - i] = pop_component ();
+ return result;
+}
+
+/* Pop the most recent association from the global stack, and return
+ it. */
+static ada_association_up
+pop_association ()
+{
+ ada_association_up result = std::move (ada_parser->associations.back ());
+ ada_parser->associations.pop_back ();
+ return result;
+}
+
+/* See ada-exp-parser.h. */
+
+std::vector<ada_association_up>
+pop_associations (int n)
+{
+ std::vector<ada_association_up> result (n);
+ for (int i = 1; i <= n; ++i)
+ result[n - i] = pop_association ();
+ return result;
+}
+
+/* See ada-exp-parser.h. */
+
+std::unique_ptr<expr_completion_base>
+make_tick_completer (struct stoken tok)
+{
+ return (std::unique_ptr<expr_completion_base>
+ (new ada_tick_completer (std::string (tok.ptr, tok.length))));
+}
+
+/* Emit expression to access an instance of SYM, in block BLOCK (if
+ non-NULL). */
+
+static void
+write_var_from_sym (struct parser_state *par_state, block_symbol sym)
+{
+ if (symbol_read_needs_frame (sym.symbol))
+ par_state->block_tracker->update (sym.block, INNERMOST_BLOCK_FOR_SYMBOLS);
+
+ par_state->push_new<ada_var_value_operation> (sym);
+}
+
+/* See ada-exp-parser.h. */
+
+void
+write_int (struct parser_state *par_state, LONGEST arg, struct type *type)
+{
+ pstate->push_new<long_const_operation> (type, arg);
+ ada_wrap<ada_wrapped_operation> ();
+}
+
+/* Emit expression corresponding to the renamed object named
+ designated by RENAMED_ENTITY[0 .. RENAMED_ENTITY_LEN-1] in the
+ context of ORIG_LEFT_CONTEXT, to which is applied the operations
+ encoded by RENAMING_EXPR. MAX_DEPTH is the maximum number of
+ cascaded renamings to allow. If ORIG_LEFT_CONTEXT is null, it
+ defaults to the currently selected block. ORIG_SYMBOL is the
+ symbol that originally encoded the renaming. It is needed only
+ because its prefix also qualifies any index variables used to index
+ or slice an array. It should not be necessary once we go to the
+ new encoding entirely (FIXME pnh 7/20/2007). */
+
+static void
+write_object_renaming (struct parser_state *par_state,
+ const struct block *orig_left_context,
+ const char *renamed_entity, int renamed_entity_len,
+ const char *renaming_expr, int max_depth)
+{
+ char *name;
+ enum { SIMPLE_INDEX, LOWER_BOUND, UPPER_BOUND } slice_state;
+
+ if (max_depth <= 0)
+ error (_("Could not find renamed symbol"));
+
+ if (orig_left_context == NULL)
+ orig_left_context = get_selected_block ();
+
+ name = obstack_strndup (&ada_parser->temp_space, renamed_entity,
+ renamed_entity_len);
+ block_symbol sym_info = ada_lookup_encoded_symbol (name, orig_left_context,
+ SEARCH_VFT);
+ if (sym_info.symbol == NULL)
+ error (_("Could not find renamed variable: %ps"),
+ styled_string (variable_name_style.style (),
+ ada_decode (name).c_str ()));
+ else if (sym_info.symbol->loc_class () == LOC_TYPEDEF)
+ /* We have a renaming of an old-style renaming symbol. Don't
+ trust the block information. */
+ sym_info.block = orig_left_context;
+
+ {
+ const char *inner_renamed_entity;
+ int inner_renamed_entity_len;
+ const char *inner_renaming_expr;
+
+ switch (ada_parse_renaming (sym_info.symbol, &inner_renamed_entity,
+ &inner_renamed_entity_len,
+ &inner_renaming_expr))
+ {
+ case ADA_NOT_RENAMING:
+ write_var_from_sym (par_state, sym_info);
+ break;
+ case ADA_OBJECT_RENAMING:
+ write_object_renaming (par_state, sym_info.block,
+ inner_renamed_entity, inner_renamed_entity_len,
+ inner_renaming_expr, max_depth - 1);
+ break;
+ default:
+ goto BadEncoding;
+ }
+ }
+
+ slice_state = SIMPLE_INDEX;
+ while (*renaming_expr == 'X')
+ {
+ renaming_expr += 1;
+
+ switch (*renaming_expr) {
+ case 'A':
+ renaming_expr += 1;
+ ada_wrap<ada_unop_ind_operation> ();
+ break;
+ case 'L':
+ slice_state = LOWER_BOUND;
+ [[fallthrough]];
+ case 'S':
+ renaming_expr += 1;
+ if (c_isdigit (*renaming_expr))
+ {
+ char *next;
+ long val = strtol (renaming_expr, &next, 10);
+ if (next == renaming_expr)
+ goto BadEncoding;
+ renaming_expr = next;
+ write_int (par_state, val, parse_type (par_state)->builtin_int);
+ }
+ else
+ {
+ const char *end;
+ char *index_name;
+
+ end = strchr (renaming_expr, 'X');
+ if (end == NULL)
+ end = renaming_expr + strlen (renaming_expr);
+
+ index_name = obstack_strndup (&ada_parser->temp_space,
+ renaming_expr,
+ end - renaming_expr);
+ renaming_expr = end;
+
+ block_symbol index_sym_info
+ = ada_lookup_encoded_symbol (index_name, orig_left_context,
+ SEARCH_VFT);
+ if (index_sym_info.symbol == NULL)
+ error (_("Could not find %s"), index_name);
+ else if (index_sym_info.symbol->loc_class () == LOC_TYPEDEF)
+ /* Index is an old-style renaming symbol. */
+ index_sym_info.block = orig_left_context;
+ write_var_from_sym (par_state, index_sym_info);
+ }
+ if (slice_state == SIMPLE_INDEX)
+ ada_funcall (1);
+ else if (slice_state == LOWER_BOUND)
+ slice_state = UPPER_BOUND;
+ else if (slice_state == UPPER_BOUND)
+ {
+ ada_wrap3<ada_ternop_slice_operation> ();
+ slice_state = SIMPLE_INDEX;
+ }
+ break;
+
+ case 'R':
+ {
+ const char *end;
+
+ renaming_expr += 1;
+
+ if (slice_state != SIMPLE_INDEX)
+ goto BadEncoding;
+ end = strchr (renaming_expr, 'X');
+ if (end == NULL)
+ end = renaming_expr + strlen (renaming_expr);
+
+ operation_up arg = ada_pop ();
+ pstate->push_new<ada_structop_operation>
+ (std::move (arg), std::string (renaming_expr,
+ end - renaming_expr));
+ renaming_expr = end;
+ break;
+ }
+
+ default:
+ goto BadEncoding;
+ }
+ }
+ if (slice_state == SIMPLE_INDEX)
+ return;
+
+ BadEncoding:
+ error (_("Internal error in encoding of renaming declaration"));
+}
+
+/* See ada-exp-parser.h. */
+
+const struct block*
+block_lookup (const struct block *context, const char *raw_name)
+{
+ const char *name;
+ struct symtab *symtab;
+ const struct block *result = NULL;
+
+ std::string name_storage;
+ if (raw_name[0] == '\'')
+ {
+ raw_name += 1;
+ name = raw_name;
+ }
+ else
+ {
+ name_storage = ada_encode (raw_name);
+ name = name_storage.c_str ();
+ }
+
+ std::vector<struct block_symbol> syms
+ = ada_lookup_symbol_list (name, context, SEARCH_FUNCTION_DOMAIN);
+
+ if (context == NULL
+ && (syms.empty () || syms[0].symbol->loc_class () != LOC_BLOCK))
+ symtab = lookup_symtab (current_program_space, name);
+ else
+ symtab = NULL;
+
+ if (symtab != NULL)
+ result = symtab->compunit ().blockvector ()->static_block ();
+ else if (syms.empty () || syms[0].symbol->loc_class () != LOC_BLOCK)
+ {
+ if (context == NULL)
+ error (_("No file or function \"%s\"."), raw_name);
+ else
+ error (_("No function \"%s\" in specified context."), raw_name);
+ }
+ else
+ {
+ if (syms.size () > 1)
+ warning (_("Function name \"%s\" ambiguous here"), raw_name);
+ result = syms[0].symbol->value_block ();
+ }
+
+ return result;
+}
+
+static struct symbol*
+select_possible_type_sym (const std::vector<struct block_symbol> &syms)
+{
+ int i;
+ int preferred_index;
+ struct type *preferred_type;
+
+ preferred_index = -1; preferred_type = NULL;
+ for (i = 0; i < syms.size (); i += 1)
+ switch (syms[i].symbol->loc_class ())
+ {
+ case LOC_TYPEDEF:
+ if (ada_prefer_type (syms[i].symbol->type (), preferred_type))
+ {
+ preferred_index = i;
+ preferred_type = syms[i].symbol->type ();
+ }
+ break;
+ case LOC_REGISTER:
+ case LOC_ARG:
+ case LOC_REF_ARG:
+ case LOC_REGPARM_ADDR:
+ case LOC_LOCAL:
+ case LOC_COMPUTED:
+ return NULL;
+ default:
+ break;
+ }
+ if (preferred_type == NULL)
+ return NULL;
+ return syms[preferred_index].symbol;
+}
+
+static struct type*
+find_primitive_type (struct parser_state *par_state, const char *name)
+{
+ struct type *type;
+ type = language_lookup_primitive_type (par_state->language (),
+ par_state->gdbarch (),
+ name);
+ if (type == NULL && streq ("system__address", name))
+ type = type_system_address (par_state);
+
+ if (type != NULL)
+ {
+ /* Check to see if we have a regular definition of this
+ type that just didn't happen to have been read yet. */
+ struct symbol *sym;
+ char *expanded_name =
+ (char *) alloca (strlen (name) + sizeof ("standard__"));
+ strcpy (expanded_name, "standard__");
+ strcat (expanded_name, name);
+ sym = ada_lookup_symbol (expanded_name, NULL, SEARCH_TYPE_DOMAIN).symbol;
+ if (sym != NULL && sym->loc_class () == LOC_TYPEDEF)
+ type = sym->type ();
+ }
+
+ return type;
+}
+
+static int
+chop_selector (const char *name, int end)
+{
+ int i;
+ for (i = end - 1; i > 0; i -= 1)
+ if (name[i] == '.' || (name[i] == '_' && name[i+1] == '_'))
+ return i;
+ return -1;
+}
+
+/* If NAME is a string beginning with a separator (either '__', or
+ '.'), chop this separator and return the result; else, return
+ NAME. */
+
+static const char *
+chop_separator (const char *name)
+{
+ if (*name == '.')
+ return name + 1;
+
+ if (name[0] == '_' && name[1] == '_')
+ return name + 2;
+
+ return name;
+}
+
+/* Given that SELS is a string of the form (<sep><identifier>)*, where
+ <sep> is '__' or '.', write the indicated sequence of
+ STRUCTOP_STRUCT expression operators. Returns a pointer to the
+ last operation that was pushed. */
+static ada_structop_operation *
+write_selectors (struct parser_state *par_state, const char *sels)
+{
+ ada_structop_operation *result = nullptr;
+ while (*sels != '\0')
+ {
+ const char *p = chop_separator (sels);
+ sels = p;
+ while (*sels != '\0' && *sels != '.'
+ && (sels[0] != '_' || sels[1] != '_'))
+ sels += 1;
+ operation_up arg = ada_pop ();
+ result = new ada_structop_operation (std::move (arg),
+ std::string (p, sels - p));
+ pstate->push (operation_up (result));
+ }
+ return result;
+}
+
+/* Write a variable access (OP_VAR_VALUE) to ambiguous encoded name
+ NAME[0..LEN-1], in block context BLOCK, to be resolved later. Writes
+ a temporary symbol that is valid until the next call to ada_parse.
+ */
+static void
+write_ambiguous_var (struct parser_state *par_state,
+ const struct block *block, const char *name, int len)
+{
+ struct symbol *sym = new (&ada_parser->temp_space) symbol ();
+
+ sym->set_domain (UNDEF_DOMAIN);
+ sym->set_linkage_name (obstack_strndup (&ada_parser->temp_space, name, len));
+ sym->set_language (language_ada, nullptr);
+
+ block_symbol bsym { sym, block };
+ par_state->push_new<ada_var_value_operation> (bsym);
+}
+
+/* A convenient wrapper around ada_get_field_index that takes
+ a non NUL-terminated FIELD_NAME0 and a FIELD_NAME_LEN instead
+ of a NUL-terminated field name. */
+
+static int
+ada_nget_field_index (const struct type *type, const char *field_name0,
+ int field_name_len, int maybe_missing)
+{
+ char *field_name = (char *) alloca ((field_name_len + 1) * sizeof (char));
+
+ strncpy (field_name, field_name0, field_name_len);
+ field_name[field_name_len] = '\0';
+ return ada_get_field_index (type, field_name, maybe_missing);
+}
+
+/* If encoded_field_name is the name of a field inside symbol SYM,
+ then return the type of that field. Otherwise, return NULL.
+
+ This function is actually recursive, so if ENCODED_FIELD_NAME
+ doesn't match one of the fields of our symbol, then try to see
+ if ENCODED_FIELD_NAME could not be a succession of field names
+ (in other words, the user entered an expression of the form
+ TYPE_NAME.FIELD1.FIELD2.FIELD3), in which case we evaluate
+ each field name sequentially to obtain the desired field type.
+ In case of failure, we return NULL. */
+
+static struct type *
+get_symbol_field_type (struct symbol *sym, const char *encoded_field_name)
+{
+ const char *field_name = encoded_field_name;
+ const char *subfield_name;
+ struct type *type = sym->type ();
+ int fieldno;
+
+ if (type == NULL || field_name == NULL)
+ return NULL;
+ type = check_typedef (type);
+
+ while (field_name[0] != '\0')
+ {
+ field_name = chop_separator (field_name);
+
+ fieldno = ada_get_field_index (type, field_name, 1);
+ if (fieldno >= 0)
+ return type->field (fieldno).type ();
+
+ subfield_name = field_name;
+ while (*subfield_name != '\0' && *subfield_name != '.'
+ && (subfield_name[0] != '_' || subfield_name[1] != '_'))
+ subfield_name += 1;
+
+ if (subfield_name[0] == '\0')
+ return NULL;
+
+ fieldno = ada_nget_field_index (type, field_name,
+ subfield_name - field_name, 1);
+ if (fieldno < 0)
+ return NULL;
+
+ type = type->field (fieldno).type ();
+ field_name = subfield_name;
+ }
+
+ return NULL;
+}
+
+/* See ada-exp-parser.h. */
+
+struct type*
+write_var_or_type (struct parser_state *par_state,
+ const struct block *block, struct stoken name0)
+{
+ int depth;
+ char *encoded_name;
+ int name_len;
+
+ std::string name_storage = ada_encode (name0.ptr);
+
+ if (block == nullptr)
+ {
+ 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 ());
+ par_state->push (std::move (op));
+ return nullptr;
+ }
+
+ block = par_state->expression_context_block;
+ }
+
+ name_len = name_storage.size ();
+ encoded_name = obstack_strndup (&ada_parser->temp_space,
+ name_storage.c_str (),
+ name_len);
+ for (depth = 0; depth < MAX_RENAMING_CHAIN_LENGTH; depth += 1)
+ {
+ int tail_index;
+
+ tail_index = name_len;
+ while (tail_index > 0)
+ {
+ struct symbol *type_sym;
+ struct symbol *renaming_sym;
+ const char* renaming;
+ int renaming_len;
+ const char* renaming_expr;
+ int terminator = encoded_name[tail_index];
+
+ encoded_name[tail_index] = '\0';
+ /* In order to avoid double-encoding, we want to only pass
+ the decoded form to lookup functions. */
+ std::string decoded_name = ada_decode (encoded_name);
+ encoded_name[tail_index] = terminator;
+
+ std::vector<struct block_symbol> syms
+ = ada_lookup_symbol_list (decoded_name.c_str (), block,
+ SEARCH_VFT);
+
+ type_sym = select_possible_type_sym (syms);
+
+ if (type_sym != NULL)
+ renaming_sym = type_sym;
+ else if (syms.size () == 1)
+ renaming_sym = syms[0].symbol;
+ else
+ renaming_sym = NULL;
+
+ switch (ada_parse_renaming (renaming_sym, &renaming,
+ &renaming_len, &renaming_expr))
+ {
+ case ADA_NOT_RENAMING:
+ break;
+ case ADA_PACKAGE_RENAMING:
+ case ADA_EXCEPTION_RENAMING:
+ case ADA_SUBPROGRAM_RENAMING:
+ {
+ int alloc_len = renaming_len + name_len - tail_index + 1;
+ char *new_name
+ = (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;
+ name_len = renaming_len + name_len - tail_index;
+ goto TryAfterRenaming;
+ }
+ case ADA_OBJECT_RENAMING:
+ write_object_renaming (par_state, block, renaming, renaming_len,
+ renaming_expr, MAX_RENAMING_CHAIN_LENGTH);
+ write_selectors (par_state, encoded_name + tail_index);
+ return NULL;
+ default:
+ internal_error (_("impossible value from ada_parse_renaming"));
+ }
+
+ if (type_sym != NULL)
+ {
+ struct type *field_type;
+
+ if (tail_index == name_len)
+ return type_sym->type ();
+
+ /* We have some extraneous characters after the type name.
+ If this is an expression "TYPE_NAME.FIELD0.[...].FIELDN",
+ then try to get the type of FIELDN. */
+ field_type
+ = get_symbol_field_type (type_sym, encoded_name + tail_index);
+ if (field_type != NULL)
+ return field_type;
+ else
+ error (_("Invalid attempt to select from type: \"%s\"."),
+ name0.ptr);
+ }
+ else if (tail_index == name_len && syms.empty ())
+ {
+ struct type *type = find_primitive_type (par_state,
+ encoded_name);
+
+ if (type != NULL)
+ return type;
+ }
+
+ if (syms.size () == 1)
+ {
+ write_var_from_sym (par_state, syms[0]);
+ write_selectors (par_state, encoded_name + tail_index);
+ return NULL;
+ }
+ else if (syms.empty ())
+ {
+ struct objfile *objfile = nullptr;
+ if (block != nullptr)
+ objfile = block->objfile ();
+
+ bound_minimal_symbol msym
+ = ada_lookup_simple_minsym (decoded_name.c_str (), objfile);
+ if (msym.minsym != NULL)
+ {
+ par_state->push_new<ada_var_msym_value_operation> (msym);
+ /* Maybe cause error here rather than later? FIXME? */
+ write_selectors (par_state, encoded_name + tail_index);
+ return NULL;
+ }
+
+ if (tail_index == name_len
+ && strncmp (encoded_name, "standard__",
+ sizeof ("standard__") - 1) == 0)
+ error (_("No definition of \"%s\" found."), name0.ptr);
+
+ tail_index = chop_selector (encoded_name, tail_index);
+ }
+ else
+ {
+ write_ambiguous_var (par_state, block, encoded_name,
+ tail_index);
+ write_selectors (par_state, encoded_name + tail_index);
+ return NULL;
+ }
+ }
+
+ if (!current_program_space->has_full_symbols ()
+ && !current_program_space->has_partial_symbols ()
+ && block == NULL)
+ error (_("No symbol table is loaded. Use the \"%ps\" command."),
+ styled_string (command_style.style (), "file"));
+ if (block == par_state->expression_context_block)
+ error (_("No definition of \"%s\" in current context."), name0.ptr);
+ else
+ error (_("No definition of \"%s\" in specified context."), name0.ptr);
+
+ TryAfterRenaming: ;
+ }
+
+ error (_("Could not find renamed symbol \"%s\""), name0.ptr);
+
+}
+
+/* Because ada_completer_word_break_characters does not contain '.' --
+ and it cannot easily be added, this breaks other completions -- we
+ have to recreate the completion word-splitting here, so that we can
+ provide a prefix that is then used when completing field names.
+ Without this, an attempt like "complete print abc.d" will give a
+ result like "print def" rather than "print abc.def". */
+
+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 > m_original_expr && end[-1] != '.' && !c_isspace (end[-1]); --end)
+ {
+ /* Nothing. */
+ }
+ /* Now find the start of the prefix. */
+ const char *ptr = end;
+ /* Here we allow '.'. */
+ for (;
+ 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. */
+ }
+ /* ... except, skip leading spaces. */
+ ptr = skip_spaces (ptr);
+
+ return std::string (ptr, end);
+}
+
+/* See ada-exp-parser.h. */
+
+struct type *
+write_var_or_type_completion (struct parser_state *par_state,
+ const struct block *block, struct stoken name0)
+{
+ int tail_index = chop_selector (name0.ptr, name0.length);
+ /* If there's no separator, just defer to ordinary symbol
+ completion. */
+ if (tail_index == -1)
+ return write_var_or_type (par_state, block, name0);
+
+ std::string copy (name0.ptr, tail_index);
+ struct type *type = write_var_or_type (par_state, block,
+ { copy.c_str (),
+ (int) copy.length () });
+ /* For completion purposes, it's enough that we return a type
+ here. */
+ if (type != nullptr)
+ return type;
+
+ ada_structop_operation *op = write_selectors (par_state,
+ name0.ptr + tail_index);
+ op->set_prefix (ada_parser->find_completion_bounds ());
+ par_state->mark_struct_expression (op);
+ return nullptr;
+}
+
+/* See ada-exp-parser.h. */
+
+void
+write_name_assoc (struct parser_state *par_state, struct stoken name)
+{
+ if (strchr (name.ptr, '.') == NULL)
+ {
+ std::vector<struct block_symbol> syms
+ = ada_lookup_symbol_list (name.ptr,
+ par_state->expression_context_block,
+ SEARCH_VFT);
+
+ if (syms.size () != 1 || syms[0].symbol->loc_class () == LOC_TYPEDEF)
+ pstate->push_new<ada_string_operation> (copy_name (name));
+ else
+ write_var_from_sym (par_state, syms[0]);
+ }
+ else
+ if (write_var_or_type (par_state, NULL, name) != NULL)
+ error (_("Invalid use of type."));
+
+ push_association<ada_name_association> (ada_pop ());
+}
+
+/* See ada-exp-parser.h. */
+
+struct type *
+type_for_char (struct parser_state *par_state, ULONGEST value)
+{
+ if (value <= 0xff)
+ return language_string_char_type (par_state->language (),
+ par_state->gdbarch ());
+ else if (value <= 0xffff)
+ return language_lookup_primitive_type (par_state->language (),
+ par_state->gdbarch (),
+ "wide_character");
+ return language_lookup_primitive_type (par_state->language (),
+ par_state->gdbarch (),
+ "wide_wide_character");
+}
+
+/* See ada-exp-parser.h. */
+
+struct type *
+type_system_address (struct parser_state *par_state)
+{
+ struct type *type
+ = language_lookup_primitive_type (par_state->language (),
+ par_state->gdbarch (),
+ "system__address");
+ return type != NULL ? type : parse_type (par_state)->builtin_data_ptr;
+}
+
+/* See ada-exp-parser.h. */
+
+void
+ada_yyerror (const char *msg)
+{
+ ada_exp_parser::pstate->parse_error (msg);
+}
+
+} /* namespace ada_exp_parser */
+
+/* See ada-exp-parser.h. */
+
+int
+ada_parse (struct parser_state *par_state)
+{
+ using namespace ada_exp_parser;
+
+ /* Setting up the parser state. */
+ scoped_restore pstate_restore = make_scoped_restore (&pstate, par_state);
+ gdb_assert (par_state != NULL);
+
+ ada_parse_state parser (par_state->lexptr);
+ scoped_restore parser_restore = make_scoped_restore (&ada_parser, &parser);
+
+ scoped_restore restore_yydebug = make_scoped_restore (&ada_yydebug,
+ par_state->debug);
+
+ lexer_init (ada_yyin); /* (Re-)initialize lexer. */
+
+ int result = ada_yyparse ();
+ if (!result)
+ {
+ struct type *context_type = nullptr;
+ if (par_state->void_context_p)
+ context_type = parse_type (par_state)->builtin_void;
+ pstate->set_operation (ada_pop (true, context_type));
+ }
+ return result;
+}
diff --git a/gdb/ada-exp-parser.h b/gdb/ada-exp-parser.h
new file mode 100644
index 000000000000..0f438647437e
--- /dev/null
+++ b/gdb/ada-exp-parser.h
@@ -0,0 +1,427 @@
+/* Support code for the Ada expression parser, for GDB.
+
+ Copyright (C) 1986-2026 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 GDB_ADA_EXP_PARSER_H
+#define GDB_ADA_EXP_PARSER_H
+
+#include "ada-exp.h"
+#include "parser-defs.h"
+
+/* The character we use to represent the completion point. */
+#define COMPLETE_CHAR '\001'
+
+namespace ada_exp_parser
+{
+
+using ada_assign_up = std::unique_ptr<expr::ada_assign_operation>;
+
+/* 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 ();
+
+ const gdb_mpz *push_integer (gdb_mpz &&val)
+ {
+ auto &result = m_int_storage.emplace_back (new gdb_mpz (std::move (val)));
+ return result.get ();
+ }
+
+ /* The components being constructed during this parse. */
+ std::vector<expr::ada_component_up> components;
+
+ /* The associations being constructed during this parse. */
+ std::vector<expr::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;
+
+ /* Track currently active iterated assignment names. */
+ gdb::unordered_string_map<std::vector<expr::ada_index_var_operation *>>
+ iterated_associations;
+
+ auto_obstack temp_space;
+
+ /* 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
+ 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;
+};
+
+/* Expression completer for attributes. */
+struct ada_tick_completer : public expr_completion_base
+{
+ explicit ada_tick_completer (std::string &&name)
+ : m_name (std::move (name))
+ {
+ }
+
+ bool complete (struct expression *exp,
+ completion_tracker &tracker) override;
+
+private:
+
+ std::string m_name;
+};
+
+/* The current state of the parser, used internally when parsing an
+ expression. */
+
+extern struct parser_state *pstate;
+
+/* The current Ada parser object. */
+
+extern struct ada_parse_state *ada_parser;
+
+/* Initialize the lexer for processing new expression.
+
+ This function is implemented in ada-lex.l, because it needs to see some
+ macros in ada-lex-gen.c. */
+
+void lexer_init (FILE *inp);
+
+/* Copy S2 to S1, removing all underscores, and downcasing all letters. */
+
+void canonicalizeNumeral (char *s1, const char *s2);
+
+/* Return TEXT[0..LEN-1], a string literal without surrounding quotes,
+ with special hex character notations replaced with characters.
+ Result valid until the next call to ada_parse. */
+
+stoken processString (const char *text, int len);
+
+/* Interprets the prefix of NUM that consists of digits of the given BASE
+ as an integer of that BASE, with the string EXP as an exponent.
+ Puts value in yylval, and returns INT, if the string is valid. Causes
+ an error if the number is improperly formatted. BASE, if NULL, defaults
+ to "10", and EXP to "1". The EXP does not contain a leading 'e' or 'E'.
+ */
+
+int processInt (parser_state *par_state, const char *base0, const char *num0,
+ const char *exp0);
+
+/* Parse NUM0 as a floating-point literal, store the result in yylval,
+ and return the FLOAT token. */
+
+int processReal (struct parser_state *par_state, const char *num0);
+
+/* Store a canonicalized version of NAME0[0..LEN-1] in yylval.ssym. The
+ resulting string is valid until the next call to ada_parse. If
+ NAME0 contains the substring "___", it is assumed to be already
+ encoded and the resulting name is equal to it. Similarly, if the name
+ starts with '<', it is copied verbatim. Otherwise, it differs
+ from NAME0 in that:
+ + Characters between '...' are transferred verbatim to yylval.ssym.
+ + Trailing "'" characters in quoted sequences are removed (a leading quote is
+ preserved to indicate that the name is not to be GNAT-encoded).
+ + Unquoted whitespace is removed.
+ + Unquoted alphabetic characters are mapped to lower case.
+ Result is returned as a struct stoken, but for convenience, the string
+ is also null-terminated. Result string valid until the next call of
+ ada_parse.
+ */
+
+stoken processId (const char *name0, int len);
+
+/* Return the syntactic code corresponding to the attribute name or
+ abbreviation STR. */
+
+int processAttribute (const char *str);
+
+/* Returns the position within STR of the '.' in a
+ '.{WHITE}*all' component of a dotted name, or -1 if there is none.
+ Note: we actually don't need this routine, since 'all' can never be an
+ Ada identifier. Thus, looking up foo.all or foo.all.x as a name
+ must fail, and will eventually be interpreted as (foo).all or
+ (foo).all.x. However, this does avoid an extraneous lookup. */
+
+int find_dot_all (const char *str);
+
+/* Back up lexptr by yyleng and then to the rightmost occurrence of
+ character CH, case-folded (there must be one). WARNING: since
+ lexptr points to the next input character that Flex has not yet
+ transferred to its internal buffer, the use of this function
+ depends on the assumption that Flex calls YY_INPUT only when it is
+ logically necessary to do so (thus, there is no reading ahead
+ farther than needed to identify the next token.) */
+
+void rewind_to_char (int ch);
+
+/* Like parser_state::pop, but handles Ada type resolution.
+ DEPROCEDURE_P and CONTEXT_TYPE are passed to the resolve method, if
+ called. */
+
+expr::operation_up ada_pop (bool deprocedure_p = true,
+ struct type *context_type = nullptr);
+
+/* Handle operator overloading. Either returns a function all
+ operation wrapping the arguments, or it returns null, leaving the
+ caller to construct the appropriate operation. If RHS is null, a
+ unary operator is assumed. */
+
+expr::operation_up maybe_overload (enum exp_opcode op, expr::operation_up &lhs,
+ expr::operation_up &rhs);
+
+/* Handle Ada type resolution for OP. DEPROCEDURE_P and CONTEXT_TYPE
+ are passed to the resolve method, if called. */
+
+expr::operation_up resolve (expr::operation_up &&op, bool deprocedure_p,
+ struct type *context_type);
+
+/* Pop NARGS operands, then a callee operand, and use these to
+ construct and push a new Ada function call operation. */
+
+void ada_funcall (int nargs);
+
+/* Pop the most recent component from the global stack, and return
+ it. */
+
+expr::ada_component_up pop_component ();
+
+/* Create and push an address-of operation, as appropriate for Ada.
+ If TYPE is not NULL, the resulting operation will be wrapped in a
+ cast to TYPE. */
+
+void ada_addrof (type *type = nullptr);
+
+/* Make a new ada_tick_completer and wrap it in a unique pointer. */
+
+std::unique_ptr<expr_completion_base> make_tick_completer (struct stoken tok);
+
+/* Pop the N most recent components from the global stack, and return
+ them in a vector. */
+
+std::vector<expr::ada_component_up> pop_components (int n);
+
+/* Examine the final element of the 'components' vector, and return it
+ as a pointer to an ada_choices_component. The caller is
+ responsible for ensuring that the final element is in fact an
+ ada_choices_component. */
+
+expr::ada_choices_component *choice_component ();
+
+/* Pop the N most recent associations from the global stack, and
+ return them in a vector. */
+
+std::vector<expr::ada_association_up> pop_associations (int n);
+
+/* Return the type of System.Address for PAR_STATE, or the builtin data
+ pointer type if that type is not defined. */
+
+type *type_system_address (parser_state *par_state);
+
+/* Write integer or boolean constant ARG of type TYPE. */
+
+void write_int (parser_state *par_state, LONGEST arg, type *type);
+
+/* Look up NAME0 (an unencoded identifier or dotted name) in BLOCK (or
+ expression_block_context if NULL). If it denotes a type, return
+ that type. Otherwise, write expression code to evaluate it as an
+ object and return NULL. In this second case, NAME0 will, in general,
+ have the form <name>(.<selector_name>)*, where <name> is an object
+ or renaming encoded in the debugging data. Calls error if no
+ prefix <name> matches a name in the debugging data (i.e., matches
+ either a complete name or, as a wild-card match, the final
+ identifier). */
+
+type *write_var_or_type (parser_state *par_state,
+ const block *block, stoken name0);
+
+/* A wrapper for write_var_or_type that is used specifically when
+ completion is requested for the last of a sequence of
+ identifiers. */
+
+type *write_var_or_type_completion (struct parser_state *par_state,
+ const block *block,
+ struct stoken name0);
+
+/* Look up the block for the function or file named RAW_NAME, in the
+ context of CONTEXT (or the global context if NULL). Calls error if
+ no matching block is found. */
+
+const block *block_lookup (const block *context, const char *raw_name);
+
+/* Write a left side of a component association (e.g., NAME in NAME =>
+ exp). If NAME has the form of a selected component, write it as an
+ ordinary expression. If it is a simple variable that unambiguously
+ corresponds to exactly one symbol that does not denote a type or an
+ object renaming, also write it normally as an OP_VAR_VALUE.
+ Otherwise, write it as an OP_NAME.
+
+ Unfortunately, we don't know at this point whether NAME is supposed
+ to denote a record component name or the value of an array index.
+ Therefore, it is not appropriate to disambiguate an ambiguous name
+ as we normally would, nor to replace a renaming with its referent.
+ As a result, in the (one hopes) rare case that one writes an
+ aggregate such as (R => 42) where R renames an object or is an
+ ambiguous name, one must write instead ((R) => 42). */
+
+void write_name_assoc (parser_state *par_state, stoken name);
+
+/* Return the character type appropriate for the character constant
+ VALUE: a normal, wide, or wide-wide character type depending on the
+ magnitude of VALUE. */
+
+type *type_for_char (parser_state *par_state, ULONGEST value);
+
+/* The error handler invoked by the generated parser. Report MSG as a
+ parse error on the current parser state. */
+
+void ada_yyerror (const char *msg);
+
+/* Like parser_state::wrap, but use ada_pop to pop the value. */
+
+template<typename T, typename... Args>
+void
+ada_wrap (Args... args)
+{
+ expr::operation_up arg = ada_pop ();
+ pstate->push_new<T> (std::move (arg), std::forward<Args> (args)...);
+}
+
+/* Like parser_state::wrap, but use ada_pop to pop the value, and
+ handle unary overloading. */
+
+template<typename T>
+void
+ada_wrap_overload (enum exp_opcode op)
+{
+ expr::operation_up arg = ada_pop ();
+ expr::operation_up empty;
+
+ expr::operation_up call = maybe_overload (op, arg, empty);
+ if (call == nullptr)
+ call = expr::make_operation<T> (std::move (arg));
+ pstate->push (std::move (call));
+}
+
+/* A variant of parser_state::wrap2 that uses ada_pop to pop both
+ operands, and then pushes a new Ada-wrapped operation of the
+ template type T. */
+
+template<typename T>
+void
+ada_un_wrap2 (enum exp_opcode op)
+{
+ expr::operation_up rhs = ada_pop ();
+ expr::operation_up lhs = ada_pop ();
+
+ expr::operation_up wrapped = maybe_overload (op, lhs, rhs);
+ if (wrapped == nullptr)
+ {
+ wrapped = expr::make_operation<T> (std::move (lhs), std::move (rhs));
+ wrapped = expr::make_operation<expr::ada_wrapped_operation> (
+ std::move (wrapped));
+ }
+ pstate->push (std::move (wrapped));
+}
+
+/* A variant of parser_state::wrap2 that uses ada_pop to pop both
+ operands. Unlike ada_un_wrap2, ada_wrapped_operation is not
+ used. */
+
+template<typename T>
+void
+ada_wrap2 (enum exp_opcode op)
+{
+ expr::operation_up rhs = ada_pop ();
+ expr::operation_up lhs = ada_pop ();
+ expr::operation_up call = maybe_overload (op, lhs, rhs);
+ if (call == nullptr)
+ call = expr::make_operation<T> (std::move (lhs), std::move (rhs));
+ pstate->push (std::move (call));
+}
+
+/* A variant of parser_state::wrap2 that uses ada_pop to pop both
+ operands. OP is also passed to the constructor of the new binary
+ operation. */
+
+template<typename T>
+void
+ada_wrap_op (enum exp_opcode op)
+{
+ expr::operation_up rhs = ada_pop ();
+ expr::operation_up lhs = ada_pop ();
+ expr::operation_up call = maybe_overload (op, lhs, rhs);
+ if (call == nullptr)
+ call = expr::make_operation<T> (op, std::move (lhs), std::move (rhs));
+ pstate->push (std::move (call));
+}
+
+/* Pop three operands using ada_pop, then construct a new ternary
+ operation of type T and push it. */
+
+template<typename T>
+void
+ada_wrap3 ()
+{
+ expr::operation_up rhs = ada_pop ();
+ expr::operation_up mid = ada_pop ();
+ expr::operation_up lhs = ada_pop ();
+ pstate->push_new<T> (std::move (lhs), std::move (mid), std::move (rhs));
+}
+
+/* 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)
+{
+ ada_parser->components.emplace_back (new T (std::forward<Arg> (args)...));
+}
+
+/* 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)
+{
+ ada_parser->associations.emplace_back (new T (std::forward<Arg> (args)...));
+}
+
+} /* namespace ada_exp_parser */
+
+/* The Ada expression parser entry point. */
+
+int ada_parse (struct parser_state *par_state);
+
+#endif /* GDB_ADA_EXP_PARSER_H */
diff --git a/gdb/ada-exp-parser.y b/gdb/ada-exp-parser.y
index 433293d22ad9..0a629f82cc86 100644
--- a/gdb/ada-exp-parser.y
+++ b/gdb/ada-exp-parser.y
@@ -40,412 +40,19 @@
#include "value.h"
#include "parser-defs.h"
#include "language.h"
+#include "ada-exp-parser.h"
#include "ada-lang.h"
#include "frame.h"
#include "block.h"
#include "ada-exp.h"
+#include "ada-exp-parser.h"
#include "cli/cli-style.h"
-/* The state of the parser, used internally when we are parsing the
- expression. */
-
-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
-{
- explicit ada_parse_state (const char *expr)
- : m_original_expr (expr)
- {
- }
-
- 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 ();
- }
-
- /* 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;
-
- /* The stack of currently active assignment expressions. This is used
- to implement '@', the target name symbol. */
- std::vector<ada_assign_up> assignments;
-
- /* Track currently active iterated assignment names. */
- gdb::unordered_string_map<std::vector<ada_index_var_operation *>>
- iterated_associations;
-
- auto_obstack temp_space;
-
- /* 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
- 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;
-};
-
-/* The current Ada parser object. */
-
-static ada_parse_state *ada_parser;
-
-int yyparse (void);
+using namespace ada_exp_parser;
static int yylex (void);
-static void yyerror (const char *);
-
-static void write_int (struct parser_state *, LONGEST, struct type *);
-
-static void write_object_renaming (struct parser_state *,
- const struct block *, const char *, int,
- const char *, int);
-
-static struct type* write_var_or_type (struct parser_state *,
- const struct block *, struct stoken);
-static struct type *write_var_or_type_completion (struct parser_state *,
- const struct block *,
- struct stoken);
-
-static void write_name_assoc (struct parser_state *, struct stoken);
-
-static const struct block *block_lookup (const struct block *, const char *);
-
-static void write_ambiguous_var (struct parser_state *,
- const struct block *, const char *, int);
-
-static struct type *type_for_char (struct parser_state *, ULONGEST);
-
-static struct type *type_system_address (struct parser_state *);
-
-/* Handle Ada type resolution for OP. DEPROCEDURE_P and CONTEXT_TYPE
- are passed to the resolve method, if called. */
-static operation_up
-resolve (operation_up &&op, bool deprocedure_p, struct type *context_type)
-{
- operation_up result = std::move (op);
- ada_resolvable *res = dynamic_cast<ada_resolvable *> (result.get ());
- if (res != nullptr)
- return res->replace (std::move (result),
- pstate->expout.get (),
- deprocedure_p,
- pstate->parse_completion,
- pstate->block_tracker,
- context_type);
- return result;
-}
-
-/* Like parser_state::pop, but handles Ada type resolution.
- DEPROCEDURE_P and CONTEXT_TYPE are passed to the resolve method, if
- called. */
-static operation_up
-ada_pop (bool deprocedure_p = true, struct type *context_type = nullptr)
-{
- /* Of course it's ok to call parser_state::pop here... */
- return resolve (pstate->pop (), deprocedure_p, context_type);
-}
-
-/* Like parser_state::wrap, but use ada_pop to pop the value. */
-template<typename T, typename... Args>
-void
-ada_wrap (Args... args)
-{
- operation_up arg = ada_pop ();
- pstate->push_new<T> (std::move (arg), std::forward<Args> (args)...);
-}
-
-/* Create and push an address-of operation, as appropriate for Ada.
- If TYPE is not NULL, the resulting operation will be wrapped in a
- cast to TYPE. */
-static void
-ada_addrof (struct type *type = nullptr)
-{
- operation_up arg = ada_pop (false);
- operation_up addr = make_operation<unop_addr_operation> (std::move (arg));
- operation_up wrapped
- = make_operation<ada_wrapped_operation> (std::move (addr));
- if (type != nullptr)
- wrapped = make_operation<unop_cast_operation> (std::move (wrapped), type);
- pstate->push (std::move (wrapped));
-}
-
-/* Handle operator overloading. Either returns a function all
- operation wrapping the arguments, or it returns null, leaving the
- caller to construct the appropriate operation. If RHS is null, a
- unary operator is assumed. */
-static operation_up
-maybe_overload (enum exp_opcode op, operation_up &lhs, operation_up &rhs)
-{
- struct value *args[2];
-
- int nargs = 1;
- args[0] = lhs->evaluate (nullptr, pstate->expout.get (),
- EVAL_AVOID_SIDE_EFFECTS);
- if (rhs == nullptr)
- args[1] = nullptr;
- else
- {
- args[1] = rhs->evaluate (nullptr, pstate->expout.get (),
- EVAL_AVOID_SIDE_EFFECTS);
- ++nargs;
- }
-
- block_symbol fn = ada_find_operator_symbol (op, pstate->parse_completion,
- nargs, args);
- if (fn.symbol == nullptr)
- return {};
-
- if (symbol_read_needs_frame (fn.symbol))
- pstate->block_tracker->update (fn.block, INNERMOST_BLOCK_FOR_SYMBOLS);
- operation_up callee = make_operation<ada_var_value_operation> (fn);
-
- std::vector<operation_up> argvec;
- argvec.push_back (std::move (lhs));
- if (rhs != nullptr)
- argvec.push_back (std::move (rhs));
- return make_operation<ada_funcall_operation> (std::move (callee),
- std::move (argvec));
-}
-
-/* Like parser_state::wrap, but use ada_pop to pop the value, and
- handle unary overloading. */
-template<typename T>
-void
-ada_wrap_overload (enum exp_opcode op)
-{
- operation_up arg = ada_pop ();
- operation_up empty;
-
- operation_up call = maybe_overload (op, arg, empty);
- if (call == nullptr)
- call = make_operation<T> (std::move (arg));
- pstate->push (std::move (call));
-}
-
-/* A variant of parser_state::wrap2 that uses ada_pop to pop both
- operands, and then pushes a new Ada-wrapped operation of the
- template type T. */
-template<typename T>
-void
-ada_un_wrap2 (enum exp_opcode op)
-{
- operation_up rhs = ada_pop ();
- operation_up lhs = ada_pop ();
-
- operation_up wrapped = maybe_overload (op, lhs, rhs);
- if (wrapped == nullptr)
- {
- wrapped = make_operation<T> (std::move (lhs), std::move (rhs));
- wrapped = make_operation<ada_wrapped_operation> (std::move (wrapped));
- }
- pstate->push (std::move (wrapped));
-}
-
-/* A variant of parser_state::wrap2 that uses ada_pop to pop both
- operands. Unlike ada_un_wrap2, ada_wrapped_operation is not
- used. */
-template<typename T>
-void
-ada_wrap2 (enum exp_opcode op)
-{
- operation_up rhs = ada_pop ();
- operation_up lhs = ada_pop ();
- operation_up call = maybe_overload (op, lhs, rhs);
- if (call == nullptr)
- call = make_operation<T> (std::move (lhs), std::move (rhs));
- pstate->push (std::move (call));
-}
-
-/* A variant of parser_state::wrap2 that uses ada_pop to pop both
- operands. OP is also passed to the constructor of the new binary
- operation. */
-template<typename T>
-void
-ada_wrap_op (enum exp_opcode op)
-{
- operation_up rhs = ada_pop ();
- operation_up lhs = ada_pop ();
- operation_up call = maybe_overload (op, lhs, rhs);
- if (call == nullptr)
- call = make_operation<T> (op, std::move (lhs), std::move (rhs));
- pstate->push (std::move (call));
-}
-
-/* Pop three operands using ada_pop, then construct a new ternary
- operation of type T and push it. */
-template<typename T>
-void
-ada_wrap3 ()
-{
- operation_up rhs = ada_pop ();
- operation_up mid = ada_pop ();
- operation_up lhs = ada_pop ();
- pstate->push_new<T> (std::move (lhs), std::move (mid), std::move (rhs));
-}
-
-/* Pop NARGS operands, then a callee operand, and use these to
- construct and push a new Ada function call operation. */
-static void
-ada_funcall (int nargs)
-{
- /* We use the ordinary pop here, because we're going to do
- resolution in a separate step, in order to handle array
- indices. */
- std::vector<operation_up> args = pstate->pop_vector (nargs);
- /* Call parser_state::pop here, because we don't want to
- function-convert the callee slot of a call we're already
- constructing. */
- operation_up callee = pstate->pop ();
-
- ada_var_value_operation *vvo
- = dynamic_cast<ada_var_value_operation *> (callee.get ());
- int array_arity = 0;
- struct type *callee_t = nullptr;
- if (vvo == nullptr
- || vvo->get_symbol ()->domain () != UNDEF_DOMAIN)
- {
- struct value *callee_v = callee->evaluate (nullptr,
- pstate->expout.get (),
- EVAL_AVOID_SIDE_EFFECTS);
- callee_t = ada_check_typedef (callee_v->type ());
- array_arity = ada_array_arity (callee_t);
- }
-
- for (int i = 0; i < nargs; ++i)
- {
- struct type *subtype = nullptr;
- if (i < array_arity)
- subtype = ada_index_type (callee_t, i + 1, "array type");
- args[i] = resolve (std::move (args[i]), true, subtype);
- }
-
- std::unique_ptr<ada_funcall_operation> funcall
- (new ada_funcall_operation (std::move (callee), std::move (args)));
- funcall->resolve (pstate->expout.get (), true, pstate->parse_completion,
- pstate->block_tracker, nullptr);
- pstate->push (std::move (funcall));
-}
-
-/* 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)
-{
- ada_parser->components.emplace_back (new T (std::forward<Arg> (args)...));
-}
-
-/* Examine the final element of the 'components' vector, and return it
- as a pointer to an ada_choices_component. The caller is
- responsible for ensuring that the final element is in fact an
- ada_choices_component. */
-static ada_choices_component *
-choice_component ()
-{
- ada_component *last = ada_parser->components.back ().get ();
- return gdb::checked_static_cast<ada_choices_component *> (last);
-}
-
-/* Pop the most recent component from the global stack, and return
- it. */
-static ada_component_up
-pop_component ()
-{
- ada_component_up result = std::move (ada_parser->components.back ());
- ada_parser->components.pop_back ();
- return result;
-}
-
-/* Pop the N most recent components from the global stack, and return
- them in a vector. */
-static std::vector<ada_component_up>
-pop_components (int n)
-{
- std::vector<ada_component_up> result (n);
- for (int i = 1; i <= n; ++i)
- result[n - i] = pop_component ();
- return result;
-}
-
-/* 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)
-{
- ada_parser->associations.emplace_back (new T (std::forward<Arg> (args)...));
-}
-
-/* Pop the most recent association from the global stack, and return
- it. */
-static ada_association_up
-pop_association ()
-{
- ada_association_up result = std::move (ada_parser->associations.back ());
- ada_parser->associations.pop_back ();
- return result;
-}
-
-/* Pop the N most recent associations from the global stack, and
- return them in a vector. */
-static std::vector<ada_association_up>
-pop_associations (int n)
-{
- std::vector<ada_association_up> result (n);
- for (int i = 1; i <= n; ++i)
- result[n - i] = pop_association ();
- return result;
-}
-
-/* Expression completer for attributes. */
-struct ada_tick_completer : public expr_completion_base
-{
- explicit ada_tick_completer (std::string &&name)
- : m_name (std::move (name))
- {
- }
-
- bool complete (struct expression *exp,
- completion_tracker &tracker) override;
-
-private:
-
- std::string m_name;
-};
-
-/* Make a new ada_tick_completer and wrap it in a unique pointer. */
-static std::unique_ptr<expr_completion_base>
-make_tick_completer (struct stoken tok)
-{
- return (std::unique_ptr<expr_completion_base>
- (new ada_tick_completer (std::string (tok.ptr, tok.length))));
-}
-
%}
%union
@@ -1236,756 +843,3 @@ primary : '*' primary %prec '.'
/* defs.h and non-standard stdlib.h files. */
#define qsort __qsort__dummy
#include "ada-lex-gen.c"
-
-int
-ada_parse (struct parser_state *par_state)
-{
- /* Setting up the parser state. */
- scoped_restore pstate_restore = make_scoped_restore (&pstate, par_state);
- gdb_assert (par_state != NULL);
-
- 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);
-
- lexer_init (yyin); /* (Re-)initialize lexer. */
-
- int result = yyparse ();
- if (!result)
- {
- struct type *context_type = nullptr;
- if (par_state->void_context_p)
- context_type = parse_type (par_state)->builtin_void;
- pstate->set_operation (ada_pop (true, context_type));
- }
- return result;
-}
-
-static void
-yyerror (const char *msg)
-{
- pstate->parse_error (msg);
-}
-
-/* Emit expression to access an instance of SYM, in block BLOCK (if
- non-NULL). */
-
-static void
-write_var_from_sym (struct parser_state *par_state, block_symbol sym)
-{
- if (symbol_read_needs_frame (sym.symbol))
- par_state->block_tracker->update (sym.block, INNERMOST_BLOCK_FOR_SYMBOLS);
-
- par_state->push_new<ada_var_value_operation> (sym);
-}
-
-/* Write integer or boolean constant ARG of type TYPE. */
-
-static void
-write_int (struct parser_state *par_state, LONGEST arg, struct type *type)
-{
- pstate->push_new<long_const_operation> (type, arg);
- ada_wrap<ada_wrapped_operation> ();
-}
-
-/* Emit expression corresponding to the renamed object named
- designated by RENAMED_ENTITY[0 .. RENAMED_ENTITY_LEN-1] in the
- context of ORIG_LEFT_CONTEXT, to which is applied the operations
- encoded by RENAMING_EXPR. MAX_DEPTH is the maximum number of
- cascaded renamings to allow. If ORIG_LEFT_CONTEXT is null, it
- defaults to the currently selected block. ORIG_SYMBOL is the
- symbol that originally encoded the renaming. It is needed only
- because its prefix also qualifies any index variables used to index
- or slice an array. It should not be necessary once we go to the
- new encoding entirely (FIXME pnh 7/20/2007). */
-
-static void
-write_object_renaming (struct parser_state *par_state,
- const struct block *orig_left_context,
- const char *renamed_entity, int renamed_entity_len,
- const char *renaming_expr, int max_depth)
-{
- char *name;
- enum { SIMPLE_INDEX, LOWER_BOUND, UPPER_BOUND } slice_state;
-
- if (max_depth <= 0)
- error (_("Could not find renamed symbol"));
-
- if (orig_left_context == NULL)
- orig_left_context = get_selected_block ();
-
- name = obstack_strndup (&ada_parser->temp_space, renamed_entity,
- renamed_entity_len);
- block_symbol sym_info = ada_lookup_encoded_symbol (name, orig_left_context,
- SEARCH_VFT);
- if (sym_info.symbol == NULL)
- error (_("Could not find renamed variable: %ps"),
- styled_string (variable_name_style.style (),
- ada_decode (name).c_str ()));
- else if (sym_info.symbol->loc_class () == LOC_TYPEDEF)
- /* We have a renaming of an old-style renaming symbol. Don't
- trust the block information. */
- sym_info.block = orig_left_context;
-
- {
- const char *inner_renamed_entity;
- int inner_renamed_entity_len;
- const char *inner_renaming_expr;
-
- switch (ada_parse_renaming (sym_info.symbol, &inner_renamed_entity,
- &inner_renamed_entity_len,
- &inner_renaming_expr))
- {
- case ADA_NOT_RENAMING:
- write_var_from_sym (par_state, sym_info);
- break;
- case ADA_OBJECT_RENAMING:
- write_object_renaming (par_state, sym_info.block,
- inner_renamed_entity, inner_renamed_entity_len,
- inner_renaming_expr, max_depth - 1);
- break;
- default:
- goto BadEncoding;
- }
- }
-
- slice_state = SIMPLE_INDEX;
- while (*renaming_expr == 'X')
- {
- renaming_expr += 1;
-
- switch (*renaming_expr) {
- case 'A':
- renaming_expr += 1;
- ada_wrap<ada_unop_ind_operation> ();
- break;
- case 'L':
- slice_state = LOWER_BOUND;
- [[fallthrough]];
- case 'S':
- renaming_expr += 1;
- if (c_isdigit (*renaming_expr))
- {
- char *next;
- long val = strtol (renaming_expr, &next, 10);
- if (next == renaming_expr)
- goto BadEncoding;
- renaming_expr = next;
- write_int (par_state, val, parse_type (par_state)->builtin_int);
- }
- else
- {
- const char *end;
- char *index_name;
-
- end = strchr (renaming_expr, 'X');
- if (end == NULL)
- end = renaming_expr + strlen (renaming_expr);
-
- index_name = obstack_strndup (&ada_parser->temp_space,
- renaming_expr,
- end - renaming_expr);
- renaming_expr = end;
-
- block_symbol index_sym_info
- = ada_lookup_encoded_symbol (index_name, orig_left_context,
- SEARCH_VFT);
- if (index_sym_info.symbol == NULL)
- error (_("Could not find %s"), index_name);
- else if (index_sym_info.symbol->loc_class () == LOC_TYPEDEF)
- /* Index is an old-style renaming symbol. */
- index_sym_info.block = orig_left_context;
- write_var_from_sym (par_state, index_sym_info);
- }
- if (slice_state == SIMPLE_INDEX)
- ada_funcall (1);
- else if (slice_state == LOWER_BOUND)
- slice_state = UPPER_BOUND;
- else if (slice_state == UPPER_BOUND)
- {
- ada_wrap3<ada_ternop_slice_operation> ();
- slice_state = SIMPLE_INDEX;
- }
- break;
-
- case 'R':
- {
- const char *end;
-
- renaming_expr += 1;
-
- if (slice_state != SIMPLE_INDEX)
- goto BadEncoding;
- end = strchr (renaming_expr, 'X');
- if (end == NULL)
- end = renaming_expr + strlen (renaming_expr);
-
- operation_up arg = ada_pop ();
- pstate->push_new<ada_structop_operation>
- (std::move (arg), std::string (renaming_expr,
- end - renaming_expr));
- renaming_expr = end;
- break;
- }
-
- default:
- goto BadEncoding;
- }
- }
- if (slice_state == SIMPLE_INDEX)
- return;
-
- BadEncoding:
- error (_("Internal error in encoding of renaming declaration"));
-}
-
-static const struct block*
-block_lookup (const struct block *context, const char *raw_name)
-{
- const char *name;
- struct symtab *symtab;
- const struct block *result = NULL;
-
- std::string name_storage;
- if (raw_name[0] == '\'')
- {
- raw_name += 1;
- name = raw_name;
- }
- else
- {
- name_storage = ada_encode (raw_name);
- name = name_storage.c_str ();
- }
-
- std::vector<struct block_symbol> syms
- = ada_lookup_symbol_list (name, context, SEARCH_FUNCTION_DOMAIN);
-
- if (context == NULL
- && (syms.empty () || syms[0].symbol->loc_class () != LOC_BLOCK))
- symtab = lookup_symtab (current_program_space, name);
- else
- symtab = NULL;
-
- if (symtab != NULL)
- result = symtab->compunit ().blockvector ()->static_block ();
- else if (syms.empty () || syms[0].symbol->loc_class () != LOC_BLOCK)
- {
- if (context == NULL)
- error (_("No file or function \"%s\"."), raw_name);
- else
- error (_("No function \"%s\" in specified context."), raw_name);
- }
- else
- {
- if (syms.size () > 1)
- warning (_("Function name \"%s\" ambiguous here"), raw_name);
- result = syms[0].symbol->value_block ();
- }
-
- return result;
-}
-
-static struct symbol*
-select_possible_type_sym (const std::vector<struct block_symbol> &syms)
-{
- int i;
- int preferred_index;
- struct type *preferred_type;
-
- preferred_index = -1; preferred_type = NULL;
- for (i = 0; i < syms.size (); i += 1)
- switch (syms[i].symbol->loc_class ())
- {
- case LOC_TYPEDEF:
- if (ada_prefer_type (syms[i].symbol->type (), preferred_type))
- {
- preferred_index = i;
- preferred_type = syms[i].symbol->type ();
- }
- break;
- case LOC_REGISTER:
- case LOC_ARG:
- case LOC_REF_ARG:
- case LOC_REGPARM_ADDR:
- case LOC_LOCAL:
- case LOC_COMPUTED:
- return NULL;
- default:
- break;
- }
- if (preferred_type == NULL)
- return NULL;
- return syms[preferred_index].symbol;
-}
-
-static struct type*
-find_primitive_type (struct parser_state *par_state, const char *name)
-{
- struct type *type;
- type = language_lookup_primitive_type (par_state->language (),
- par_state->gdbarch (),
- name);
- if (type == NULL && streq ("system__address", name))
- type = type_system_address (par_state);
-
- if (type != NULL)
- {
- /* Check to see if we have a regular definition of this
- type that just didn't happen to have been read yet. */
- struct symbol *sym;
- char *expanded_name =
- (char *) alloca (strlen (name) + sizeof ("standard__"));
- strcpy (expanded_name, "standard__");
- strcat (expanded_name, name);
- sym = ada_lookup_symbol (expanded_name, NULL, SEARCH_TYPE_DOMAIN).symbol;
- if (sym != NULL && sym->loc_class () == LOC_TYPEDEF)
- type = sym->type ();
- }
-
- return type;
-}
-
-static int
-chop_selector (const char *name, int end)
-{
- int i;
- for (i = end - 1; i > 0; i -= 1)
- if (name[i] == '.' || (name[i] == '_' && name[i+1] == '_'))
- return i;
- return -1;
-}
-
-/* If NAME is a string beginning with a separator (either '__', or
- '.'), chop this separator and return the result; else, return
- NAME. */
-
-static const char *
-chop_separator (const char *name)
-{
- if (*name == '.')
- return name + 1;
-
- if (name[0] == '_' && name[1] == '_')
- return name + 2;
-
- return name;
-}
-
-/* Given that SELS is a string of the form (<sep><identifier>)*, where
- <sep> is '__' or '.', write the indicated sequence of
- STRUCTOP_STRUCT expression operators. Returns a pointer to the
- last operation that was pushed. */
-static ada_structop_operation *
-write_selectors (struct parser_state *par_state, const char *sels)
-{
- ada_structop_operation *result = nullptr;
- while (*sels != '\0')
- {
- const char *p = chop_separator (sels);
- sels = p;
- while (*sels != '\0' && *sels != '.'
- && (sels[0] != '_' || sels[1] != '_'))
- sels += 1;
- operation_up arg = ada_pop ();
- result = new ada_structop_operation (std::move (arg),
- std::string (p, sels - p));
- pstate->push (operation_up (result));
- }
- return result;
-}
-
-/* Write a variable access (OP_VAR_VALUE) to ambiguous encoded name
- NAME[0..LEN-1], in block context BLOCK, to be resolved later. Writes
- a temporary symbol that is valid until the next call to ada_parse.
- */
-static void
-write_ambiguous_var (struct parser_state *par_state,
- const struct block *block, const char *name, int len)
-{
- struct symbol *sym = new (&ada_parser->temp_space) symbol ();
-
- sym->set_domain (UNDEF_DOMAIN);
- sym->set_linkage_name (obstack_strndup (&ada_parser->temp_space, name, len));
- sym->set_language (language_ada, nullptr);
-
- block_symbol bsym { sym, block };
- par_state->push_new<ada_var_value_operation> (bsym);
-}
-
-/* A convenient wrapper around ada_get_field_index that takes
- a non NUL-terminated FIELD_NAME0 and a FIELD_NAME_LEN instead
- of a NUL-terminated field name. */
-
-static int
-ada_nget_field_index (const struct type *type, const char *field_name0,
- int field_name_len, int maybe_missing)
-{
- char *field_name = (char *) alloca ((field_name_len + 1) * sizeof (char));
-
- strncpy (field_name, field_name0, field_name_len);
- field_name[field_name_len] = '\0';
- return ada_get_field_index (type, field_name, maybe_missing);
-}
-
-/* If encoded_field_name is the name of a field inside symbol SYM,
- then return the type of that field. Otherwise, return NULL.
-
- This function is actually recursive, so if ENCODED_FIELD_NAME
- doesn't match one of the fields of our symbol, then try to see
- if ENCODED_FIELD_NAME could not be a succession of field names
- (in other words, the user entered an expression of the form
- TYPE_NAME.FIELD1.FIELD2.FIELD3), in which case we evaluate
- each field name sequentially to obtain the desired field type.
- In case of failure, we return NULL. */
-
-static struct type *
-get_symbol_field_type (struct symbol *sym, const char *encoded_field_name)
-{
- const char *field_name = encoded_field_name;
- const char *subfield_name;
- struct type *type = sym->type ();
- int fieldno;
-
- if (type == NULL || field_name == NULL)
- return NULL;
- type = check_typedef (type);
-
- while (field_name[0] != '\0')
- {
- field_name = chop_separator (field_name);
-
- fieldno = ada_get_field_index (type, field_name, 1);
- if (fieldno >= 0)
- return type->field (fieldno).type ();
-
- subfield_name = field_name;
- while (*subfield_name != '\0' && *subfield_name != '.'
- && (subfield_name[0] != '_' || subfield_name[1] != '_'))
- subfield_name += 1;
-
- if (subfield_name[0] == '\0')
- return NULL;
-
- fieldno = ada_nget_field_index (type, field_name,
- subfield_name - field_name, 1);
- if (fieldno < 0)
- return NULL;
-
- type = type->field (fieldno).type ();
- field_name = subfield_name;
- }
-
- return NULL;
-}
-
-/* Look up NAME0 (an unencoded identifier or dotted name) in BLOCK (or
- expression_block_context if NULL). If it denotes a type, return
- that type. Otherwise, write expression code to evaluate it as an
- object and return NULL. In this second case, NAME0 will, in general,
- have the form <name>(.<selector_name>)*, where <name> is an object
- or renaming encoded in the debugging data. Calls error if no
- prefix <name> matches a name in the debugging data (i.e., matches
- either a complete name or, as a wild-card match, the final
- identifier). */
-
-static struct type*
-write_var_or_type (struct parser_state *par_state,
- const struct block *block, struct stoken name0)
-{
- int depth;
- char *encoded_name;
- int name_len;
-
- std::string name_storage = ada_encode (name0.ptr);
-
- if (block == nullptr)
- {
- 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 ());
- par_state->push (std::move (op));
- return nullptr;
- }
-
- block = par_state->expression_context_block;
- }
-
- name_len = name_storage.size ();
- encoded_name = obstack_strndup (&ada_parser->temp_space,
- name_storage.c_str (),
- name_len);
- for (depth = 0; depth < MAX_RENAMING_CHAIN_LENGTH; depth += 1)
- {
- int tail_index;
-
- tail_index = name_len;
- while (tail_index > 0)
- {
- struct symbol *type_sym;
- struct symbol *renaming_sym;
- const char* renaming;
- int renaming_len;
- const char* renaming_expr;
- int terminator = encoded_name[tail_index];
-
- encoded_name[tail_index] = '\0';
- /* In order to avoid double-encoding, we want to only pass
- the decoded form to lookup functions. */
- std::string decoded_name = ada_decode (encoded_name);
- encoded_name[tail_index] = terminator;
-
- std::vector<struct block_symbol> syms
- = ada_lookup_symbol_list (decoded_name.c_str (), block,
- SEARCH_VFT);
-
- type_sym = select_possible_type_sym (syms);
-
- if (type_sym != NULL)
- renaming_sym = type_sym;
- else if (syms.size () == 1)
- renaming_sym = syms[0].symbol;
- else
- renaming_sym = NULL;
-
- switch (ada_parse_renaming (renaming_sym, &renaming,
- &renaming_len, &renaming_expr))
- {
- case ADA_NOT_RENAMING:
- break;
- case ADA_PACKAGE_RENAMING:
- case ADA_EXCEPTION_RENAMING:
- case ADA_SUBPROGRAM_RENAMING:
- {
- int alloc_len = renaming_len + name_len - tail_index + 1;
- char *new_name
- = (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;
- name_len = renaming_len + name_len - tail_index;
- goto TryAfterRenaming;
- }
- case ADA_OBJECT_RENAMING:
- write_object_renaming (par_state, block, renaming, renaming_len,
- renaming_expr, MAX_RENAMING_CHAIN_LENGTH);
- write_selectors (par_state, encoded_name + tail_index);
- return NULL;
- default:
- internal_error (_("impossible value from ada_parse_renaming"));
- }
-
- if (type_sym != NULL)
- {
- struct type *field_type;
-
- if (tail_index == name_len)
- return type_sym->type ();
-
- /* We have some extraneous characters after the type name.
- If this is an expression "TYPE_NAME.FIELD0.[...].FIELDN",
- then try to get the type of FIELDN. */
- field_type
- = get_symbol_field_type (type_sym, encoded_name + tail_index);
- if (field_type != NULL)
- return field_type;
- else
- error (_("Invalid attempt to select from type: \"%s\"."),
- name0.ptr);
- }
- else if (tail_index == name_len && syms.empty ())
- {
- struct type *type = find_primitive_type (par_state,
- encoded_name);
-
- if (type != NULL)
- return type;
- }
-
- if (syms.size () == 1)
- {
- write_var_from_sym (par_state, syms[0]);
- write_selectors (par_state, encoded_name + tail_index);
- return NULL;
- }
- else if (syms.empty ())
- {
- struct objfile *objfile = nullptr;
- if (block != nullptr)
- objfile = block->objfile ();
-
- bound_minimal_symbol msym
- = ada_lookup_simple_minsym (decoded_name.c_str (), objfile);
- if (msym.minsym != NULL)
- {
- par_state->push_new<ada_var_msym_value_operation> (msym);
- /* Maybe cause error here rather than later? FIXME? */
- write_selectors (par_state, encoded_name + tail_index);
- return NULL;
- }
-
- if (tail_index == name_len
- && strncmp (encoded_name, "standard__",
- sizeof ("standard__") - 1) == 0)
- error (_("No definition of \"%s\" found."), name0.ptr);
-
- tail_index = chop_selector (encoded_name, tail_index);
- }
- else
- {
- write_ambiguous_var (par_state, block, encoded_name,
- tail_index);
- write_selectors (par_state, encoded_name + tail_index);
- return NULL;
- }
- }
-
- if (!current_program_space->has_full_symbols ()
- && !current_program_space->has_partial_symbols ()
- && block == NULL)
- error (_("No symbol table is loaded. Use the \"%ps\" command."),
- styled_string (command_style.style (), "file"));
- if (block == par_state->expression_context_block)
- error (_("No definition of \"%s\" in current context."), name0.ptr);
- else
- error (_("No definition of \"%s\" in specified context."), name0.ptr);
-
- TryAfterRenaming: ;
- }
-
- error (_("Could not find renamed symbol \"%s\""), name0.ptr);
-
-}
-
-/* Because ada_completer_word_break_characters does not contain '.' --
- and it cannot easily be added, this breaks other completions -- we
- have to recreate the completion word-splitting here, so that we can
- provide a prefix that is then used when completing field names.
- Without this, an attempt like "complete print abc.d" will give a
- result like "print def" rather than "print abc.def". */
-
-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 > m_original_expr && end[-1] != '.' && !c_isspace (end[-1]); --end)
- {
- /* Nothing. */
- }
- /* Now find the start of the prefix. */
- const char *ptr = end;
- /* Here we allow '.'. */
- for (;
- 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. */
- }
- /* ... except, skip leading spaces. */
- ptr = skip_spaces (ptr);
-
- return std::string (ptr, end);
-}
-
-/* A wrapper for write_var_or_type that is used specifically when
- completion is requested for the last of a sequence of
- identifiers. */
-
-static struct type *
-write_var_or_type_completion (struct parser_state *par_state,
- const struct block *block, struct stoken name0)
-{
- int tail_index = chop_selector (name0.ptr, name0.length);
- /* If there's no separator, just defer to ordinary symbol
- completion. */
- if (tail_index == -1)
- return write_var_or_type (par_state, block, name0);
-
- std::string copy (name0.ptr, tail_index);
- struct type *type = write_var_or_type (par_state, block,
- { copy.c_str (),
- (int) copy.length () });
- /* For completion purposes, it's enough that we return a type
- here. */
- if (type != nullptr)
- return type;
-
- ada_structop_operation *op = write_selectors (par_state,
- name0.ptr + tail_index);
- op->set_prefix (ada_parser->find_completion_bounds ());
- par_state->mark_struct_expression (op);
- return nullptr;
-}
-
-/* Write a left side of a component association (e.g., NAME in NAME =>
- exp). If NAME has the form of a selected component, write it as an
- ordinary expression. If it is a simple variable that unambiguously
- corresponds to exactly one symbol that does not denote a type or an
- object renaming, also write it normally as an OP_VAR_VALUE.
- Otherwise, write it as an OP_NAME.
-
- Unfortunately, we don't know at this point whether NAME is supposed
- to denote a record component name or the value of an array index.
- Therefore, it is not appropriate to disambiguate an ambiguous name
- as we normally would, nor to replace a renaming with its referent.
- As a result, in the (one hopes) rare case that one writes an
- aggregate such as (R => 42) where R renames an object or is an
- ambiguous name, one must write instead ((R) => 42). */
-
-static void
-write_name_assoc (struct parser_state *par_state, struct stoken name)
-{
- if (strchr (name.ptr, '.') == NULL)
- {
- std::vector<struct block_symbol> syms
- = ada_lookup_symbol_list (name.ptr,
- par_state->expression_context_block,
- SEARCH_VFT);
-
- if (syms.size () != 1 || syms[0].symbol->loc_class () == LOC_TYPEDEF)
- pstate->push_new<ada_string_operation> (copy_name (name));
- else
- write_var_from_sym (par_state, syms[0]);
- }
- else
- if (write_var_or_type (par_state, NULL, name) != NULL)
- error (_("Invalid use of type."));
-
- push_association<ada_name_association> (ada_pop ());
-}
-
-static struct type *
-type_for_char (struct parser_state *par_state, ULONGEST value)
-{
- if (value <= 0xff)
- return language_string_char_type (par_state->language (),
- par_state->gdbarch ());
- else if (value <= 0xffff)
- return language_lookup_primitive_type (par_state->language (),
- par_state->gdbarch (),
- "wide_character");
- return language_lookup_primitive_type (par_state->language (),
- par_state->gdbarch (),
- "wide_wide_character");
-}
-
-static struct type *
-type_system_address (struct parser_state *par_state)
-{
- struct type *type
- = language_lookup_primitive_type (par_state->language (),
- par_state->gdbarch (),
- "system__address");
- return type != NULL ? type : parse_type (par_state)->builtin_data_ptr;
-}
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 02410949bcab..0bbd7ff93e84 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -18,6 +18,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#include "ada-exp-parser.h"
#include "event-top.h"
#include "exceptions.h"
#include "extract-store-integer.h"
diff --git a/gdb/ada-lang.h b/gdb/ada-lang.h
index e224f99dcc19..cf89a90f2f5e 100644
--- a/gdb/ada-lang.h
+++ b/gdb/ada-lang.h
@@ -153,8 +153,6 @@ extern int ada_get_field_index (const struct type *type,
const char *field_name,
int maybe_missing);
-extern int ada_parse (struct parser_state *); /* Defined in ada-exp-parser.y */
-
/* Defined in ada-typeprint.c */
extern void ada_print_type (struct type *, const char *, struct ui_file *, int,
int, const struct type_print_options *);
diff --git a/gdb/ada-lex.l b/gdb/ada-lex.l
index dab1ad0d0067..62edcd251966 100644
--- a/gdb/ada-lex.l
+++ b/gdb/ada-lex.l
@@ -57,16 +57,6 @@ DIAGNOSTIC_IGNORE_REGISTER
#define NUMERAL_WIDTH 256
#define LONGEST_SIGN ((ULONGEST) 1 << (sizeof(LONGEST) * HOST_CHAR_BIT - 1))
-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 *);
-static int processReal (struct parser_state *, const char *);
-static struct stoken processId (const char *, int);
-static int processAttribute (const char *);
-static int find_dot_all (const char *);
-static void rewind_to_char (int);
-
#undef YY_DECL
#define YY_DECL static int yylex ( void )
@@ -74,9 +64,6 @@ static void rewind_to_char (int);
Defining YY_NO_INPUT comments it out. */
#define YY_NO_INPUT
-/* The character we use to represent the completion point. */
-#define COMPLETE_CHAR '\001'
-
#undef YY_INPUT
#define YY_INPUT(BUF, RESULT, MAX_SIZE) \
if ( *pstate->lexptr == '\000' ) \
@@ -335,423 +322,19 @@ false { return FALSEKEYWORD; }
. { error (_("Invalid character '%s' in expression."), yytext); }
%%
-/* Initialize the lexer for processing new expression. */
+namespace ada_exp_parser
+{
+
+/* See ada-exp-parser.h. */
-static void
+void
lexer_init (FILE *inp)
{
BEGIN INITIAL;
yyrestart (inp);
}
-
-/* Copy S2 to S1, removing all underscores, and downcasing all letters. */
-
-static void
-canonicalizeNumeral (char *s1, const char *s2)
-{
- for (; *s2 != '\000'; s2 += 1)
- {
- if (*s2 != '_')
- {
- *s1 = c_tolower(*s2);
- s1 += 1;
- }
- }
- s1[0] = '\000';
-}
-
-/* Interprets the prefix of NUM that consists of digits of the given BASE
- as an integer of that BASE, with the string EXP as an exponent.
- Puts value in yylval, and returns INT, if the string is valid. Causes
- an error if the number is improperly formatted. BASE, if NULL, defaults
- to "10", and EXP to "1". The EXP does not contain a leading 'e' or 'E'.
- */
-
-static int
-processInt (struct parser_state *par_state, const char *base0,
- const char *num0, const char *exp0)
-{
- long exp;
- int base;
- /* For the based literal with an "f" prefix, we'll return a
- floating-point number. This counts the number of "l"s seen,
- to decide the width of the floating-point number to return. -1
- means no "f". */
- int floating_point_l_count = -1;
-
- if (base0 == NULL)
- base = 10;
- else
- {
- char *end_of_base;
- base = strtol (base0, &end_of_base, 10);
- if (base < 2 || base > 16)
- error (_("Invalid base: %d."), base);
- while (*end_of_base == 'l')
- {
- ++floating_point_l_count;
- ++end_of_base;
- }
- /* This assertion is ensured by the pattern. */
- gdb_assert (floating_point_l_count == -1 || *end_of_base == 'f');
- if (*end_of_base == 'f')
- {
- ++end_of_base;
- ++floating_point_l_count;
- }
- /* This assertion is ensured by the pattern. */
- gdb_assert (*end_of_base == '#');
- }
-
- if (exp0 == NULL)
- exp = 0;
- else
- exp = strtol(exp0, (char **) NULL, 10);
-
- gdb_mpz result;
- while (c_isxdigit (*num0))
- {
- int dig = fromhex (*num0);
- if (dig >= base)
- error (_("Invalid digit `%c' in based literal"), *num0);
- result *= base;
- result += dig;
- ++num0;
- }
-
- while (exp > 0)
- {
- result *= base;
- exp -= 1;
- }
-
- if (floating_point_l_count > -1)
- {
- struct type *fp_type;
- if (floating_point_l_count == 0)
- fp_type = language_lookup_primitive_type (par_state->language (),
- par_state->gdbarch (),
- "float");
- else if (floating_point_l_count == 1)
- fp_type = language_lookup_primitive_type (par_state->language (),
- par_state->gdbarch (),
- "long_float");
- else
- {
- /* This assertion is ensured by the pattern. */
- gdb_assert (floating_point_l_count == 2);
- fp_type = language_lookup_primitive_type (par_state->language (),
- par_state->gdbarch (),
- "long_long_float");
- }
-
- yylval.typed_val_float.type = fp_type;
- result.write (gdb::make_array_view (yylval.typed_val_float.val,
- fp_type->length ()),
- type_byte_order (fp_type),
- true);
-
- return FLOAT;
- }
-
- 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 ());
- int long_long_bits = gdbarch_long_long_bit (par_state->gdbarch ());
-
- if (fits_in_type (1, *value, int_bits, true))
- yylval.typed_val.type = parse_type (par_state)->builtin_int;
- else if (fits_in_type (1, *value, long_bits, true))
- yylval.typed_val.type = parse_type (par_state)->builtin_long;
- else if (fits_in_type (1, *value, long_bits, false))
- yylval.typed_val.type
- = builtin_type (par_state->gdbarch ())->builtin_unsigned_long;
- else if (fits_in_type (1, *value, long_long_bits, true))
- yylval.typed_val.type = parse_type (par_state)->builtin_long_long;
- else if (fits_in_type (1, *value, long_long_bits, false))
- yylval.typed_val.type
- = builtin_type (par_state->gdbarch ())->builtin_unsigned_long_long;
- else if (fits_in_type (1, *value, 128, true))
- yylval.typed_val.type
- = language_lookup_primitive_type (par_state->language (),
- par_state->gdbarch (),
- "long_long_long_integer");
- else if (fits_in_type (1, *value, 128, false))
- yylval.typed_val.type
- = language_lookup_primitive_type (par_state->language (),
- par_state->gdbarch (),
- "unsigned_long_long_long_integer");
- else
- error (_("Integer literal out of range"));
-
- yylval.typed_val.val = value;
- return INT;
-}
-
-static int
-processReal (struct parser_state *par_state, const char *num0)
-{
- yylval.typed_val_float.type = parse_type (par_state)->builtin_long_double;
-
- bool parsed = parse_float (num0, strlen (num0),
- yylval.typed_val_float.type,
- yylval.typed_val_float.val);
- gdb_assert (parsed);
- return FLOAT;
-}
-
-
-/* Store a canonicalized version of NAME0[0..LEN-1] in yylval.ssym. The
- resulting string is valid until the next call to ada_parse. If
- NAME0 contains the substring "___", it is assumed to be already
- encoded and the resulting name is equal to it. Similarly, if the name
- starts with '<', it is copied verbatim. Otherwise, it differs
- from NAME0 in that:
- + Characters between '...' are transferred verbatim to yylval.ssym.
- + Trailing "'" characters in quoted sequences are removed (a leading quote is
- preserved to indicate that the name is not to be GNAT-encoded).
- + Unquoted whitespace is removed.
- + Unquoted alphabetic characters are mapped to lower case.
- Result is returned as a struct stoken, but for convenience, the string
- is also null-terminated. Result string valid until the next call of
- ada_parse.
- */
-static struct stoken
-processId (const char *name0, int len)
-{
- char *name = (char *) obstack_alloc (&ada_parser->temp_space, len + 11);
- int i0, i;
- struct stoken result;
-
- result.ptr = name;
- while (len > 0 && c_isspace (name0[len-1]))
- len -= 1;
-
- if (name0[0] == '<' || strstr (name0, "___") != NULL)
- {
- strncpy (name, name0, len);
- name[len] = '\000';
- result.length = len;
- return result;
- }
-
- bool in_quotes = false;
- i = i0 = 0;
- while (i0 < len)
- {
- if (name0[i0] == COMPLETE_CHAR)
- {
- /* Just ignore. */
- ++i0;
- }
- else if (in_quotes)
- name[i++] = name0[i0++];
- else if (c_isalnum (name0[i0]))
- {
- name[i] = c_tolower (name0[i0]);
- i += 1; i0 += 1;
- }
- else if (c_isspace (name0[i0]))
- i0 += 1;
- else if (name0[i0] == '\'')
- {
- /* Copy the starting quote, but not the ending quote. */
- if (!in_quotes)
- name[i++] = name0[i0++];
- in_quotes = !in_quotes;
- }
- else
- name[i++] = name0[i0++];
- }
- name[i] = '\000';
-
- result.length = i;
- return result;
-}
-
-/* Return TEXT[0..LEN-1], a string literal without surrounding quotes,
- with special hex character notations replaced with characters.
- Result valid until the next call to ada_parse. */
-
-static struct stoken
-processString (const char *text, int len)
-{
- const char *p;
- char *q;
- const char *lim = text + len;
- struct stoken result;
-
- q = (char *) obstack_alloc (&ada_parser->temp_space, len);
- result.ptr = q;
- p = text;
- while (p < lim)
- {
- if (p[0] == '[' && p[1] == '"' && p+2 < lim)
- {
- if (p[2] == '"') /* "...["""]... */
- {
- *q = '"';
- p += 4;
- }
- else
- {
- const char *end;
- ULONGEST chr = strtoulst (p + 2, &end, 16);
- if (chr > 0xff)
- error (_("wide strings are not yet supported"));
- *q = (char) chr;
- p = end + 1;
- }
- }
- else
- *q = *p;
- q += 1;
- p += 1;
- }
- result.length = q - result.ptr;
- return result;
-}
-
-/* Returns the position within STR of the '.' in a
- '.{WHITE}*all' component of a dotted name, or -1 if there is none.
- Note: we actually don't need this routine, since 'all' can never be an
- Ada identifier. Thus, looking up foo.all or foo.all.x as a name
- must fail, and will eventually be interpreted as (foo).all or
- (foo).all.x. However, this does avoid an extraneous lookup. */
-
-static int
-find_dot_all (const char *str)
-{
- int i;
-
- for (i = 0; str[i] != '\000'; i++)
- if (str[i] == '.')
- {
- int i0 = i;
-
- do
- i += 1;
- while (c_isspace (str[i]));
-
- if (strncasecmp (str + i, "all", 3) == 0
- && !c_isalnum (str[i + 3]) && str[i + 3] != '_')
- return i0;
- }
- return -1;
-}
-
-/* Returns non-zero iff string SUBSEQ matches a subsequence of STR, ignoring
- case. */
-
-static int
-subseqMatch (const char *subseq, const char *str)
-{
- if (subseq[0] == '\0')
- return 1;
- else if (str[0] == '\0')
- return 0;
- else if (c_tolower (subseq[0]) == c_tolower (str[0]))
- return subseqMatch (subseq+1, str+1) || subseqMatch (subseq, str+1);
- else
- return subseqMatch (subseq, str+1);
-}
-
-
-static const struct { const char *name; int code; }
-attributes[] = {
- { "address", TICK_ADDRESS },
- { "unchecked_access", TICK_ACCESS },
- { "unrestricted_access", TICK_ACCESS },
- { "access", TICK_ACCESS },
- { "first", TICK_FIRST },
- { "last", TICK_LAST },
- { "length", TICK_LENGTH },
- { "max", TICK_MAX },
- { "min", TICK_MIN },
- { "modulus", TICK_MODULUS },
- { "object_size", TICK_OBJECT_SIZE },
- { "pos", TICK_POS },
- { "range", TICK_RANGE },
- { "size", TICK_SIZE },
- { "tag", TICK_TAG },
- { "val", TICK_VAL },
- { "enum_rep", TICK_ENUM_REP },
- { "enum_val", TICK_ENUM_VAL },
-};
-
-/* Return the syntactic code corresponding to the attribute name or
- abbreviation STR. */
-
-static int
-processAttribute (const char *str)
-{
- gdb_assert (*str == '\'');
- ++str;
- while (c_isspace (*str))
- ++str;
-
- int len = strlen (str);
- if (len > 0 && str[len - 1] == COMPLETE_CHAR)
- {
- /* This is enforced by YY_INPUT. */
- gdb_assert (pstate->parse_completion);
- yylval.sval.ptr = obstack_strndup (&ada_parser->temp_space,
- str, len - 1);
- yylval.sval.length = len - 1;
- return TICK_COMPLETE;
- }
-
- for (const auto &item : attributes)
- if (strcasecmp (str, item.name) == 0)
- return item.code;
-
- std::optional<int> found;
- for (const auto &item : attributes)
- if (subseqMatch (str, item.name))
- {
- if (!found.has_value ())
- found = item.code;
- else
- error (_("ambiguous attribute name: `%s'"), str);
- }
- if (!found.has_value ())
- error (_("unrecognized attribute: `%s'"), str);
-
- return *found;
-}
-
-bool
-ada_tick_completer::complete (struct expression *exp,
- completion_tracker &tracker)
-{
- completion_list output;
- for (const auto &item : attributes)
- {
- if (strncasecmp (item.name, m_name.c_str (), m_name.length ()) == 0)
- output.emplace_back (xstrdup (item.name));
- }
- tracker.add_completions (std::move (output));
- return true;
-}
-
-/* Back up lexptr by yyleng and then to the rightmost occurrence of
- character CH, case-folded (there must be one). WARNING: since
- lexptr points to the next input character that Flex has not yet
- transferred to its internal buffer, the use of this function
- depends on the assumption that Flex calls YY_INPUT only when it is
- logically necessary to do so (thus, there is no reading ahead
- farther than needed to identify the next token.) */
-
-static void
-rewind_to_char (int ch)
-{
- pstate->lexptr -= yyleng;
- while (c_toupper (*pstate->lexptr) != c_toupper (ch))
- pstate->lexptr -= 1;
- yyrestart (NULL);
-}
+} /* namespace ada_exp_parser */
/* Dummy definition to suppress warnings about unused static definitions. */
typedef void (*dummy_function) ();
--
2.55.0
next prev parent reply other threads:[~2026-09-04 17:16 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-04 16:56 [PATCH 00/17] Move C++ support code out of .y files simon.marchi
2026-09-04 16:56 ` [PATCH 01/17] gdb/ada-exp-parser: remove name_info struct simon.marchi
2026-09-04 16:56 ` [PATCH 02/17] gdb: replace parse_type macros with functions simon.marchi
2026-09-04 16:56 ` [PATCH 03/17] gdb: suffix flex/bison output files with -gen.c simon.marchi
2026-09-04 16:56 ` [PATCH 04/17] gdb: move parser output post-processing to a script simon.marchi
2026-09-05 0:38 ` Kevin Buettner
2026-09-05 3:59 ` Simon Marchi
2026-09-04 16:56 ` [PATCH 05/17] gdb: let the parser and lexer generators prefix their symbols simon.marchi
2026-09-04 16:56 ` [PATCH 06/17] gdb: separate cp-name-parser's symbol prefix with an underscore simon.marchi
2026-09-04 16:56 ` [PATCH 07/17] gdb: make $(YACC) and $(FLEX) generate headers simon.marchi
2026-09-04 16:56 ` [PATCH 08/17] gdb: add check for stale build generated files simon.marchi
2026-09-04 16:56 ` [PATCH 09/17] gdb: move cp-name-parser.y's support code to cp-name-parser.c simon.marchi
2026-09-04 16:56 ` [PATCH 10/17] gdb: rename LANG-exp.y to LANG-exp-parser.y simon.marchi
2026-09-04 16:56 ` [PATCH 11/17] gdb: move c-exp-parser.y's support code to c-exp-parser.c simon.marchi
2026-09-04 16:56 ` simon.marchi [this message]
2026-09-05 0:16 ` [PATCH 12/17] gdb: move ada-exp-parser.y's support code to ada-exp-parser.c Kevin Buettner
2026-09-04 16:56 ` [PATCH 13/17] gdb: move d-exp-parser.y's support code to d-exp-parser.c simon.marchi
2026-09-04 16:56 ` [PATCH 14/17] gdb: move f-exp-parser.y's support code to f-exp-parser.c simon.marchi
2026-09-04 16:56 ` [PATCH 15/17] gdb: move go-exp-parser.y's support code to go-exp-parser.c simon.marchi
2026-09-04 16:56 ` [PATCH 16/17] gdb: move m2-exp-parser.y's support code to m2-exp-parser.c simon.marchi
2026-09-05 0:30 ` Kevin Buettner
2026-09-05 4:04 ` Simon Marchi
2026-09-04 16:56 ` [PATCH 17/17] gdb: move p-exp-parser.y's support code to p-exp-parser.c simon.marchi
2026-09-05 0:29 ` Kevin Buettner
2026-09-05 0:50 ` [PATCH 00/17] Move C++ support code out of .y files Kevin Buettner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260904170338.1643894-13-simon.marchi@polymtl.ca \
--to=simon.marchi@polymtl.ca \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox