From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id UQVVBd78mmqL7CgAWB0awg (envelope-from ) for ; Fri, 04 Sep 2026 13:16:14 -0400 Authentication-Results: simark.ca; dkim=pass (2048-bit key; unprotected) header.d=polymtl.ca header.i=@polymtl.ca header.a=rsa-sha256 header.s=oct2025 header.b=OKYkNfaQ; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 0F2C61E0A3; Fri, 04 Sep 2026 13:16:14 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-2.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 093131E0A3 for ; Fri, 04 Sep 2026 13:16:06 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B87EA4BA23DC for ; Fri, 4 Sep 2026 17:16:04 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B87EA4BA23DC Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=polymtl.ca header.i=@polymtl.ca header.a=rsa-sha256 header.s=oct2025 header.b=OKYkNfaQ Received: from smtp.polymtl.ca (smtp.polymtl.ca [132.207.4.11]) by sourceware.org (Postfix) with ESMTPS id CA9564BA2E35 for ; Fri, 4 Sep 2026 17:14:23 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org CA9564BA2E35 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=polymtl.ca Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=polymtl.ca ARC-Filter: OpenARC Filter v1.0.0 sourceware.org CA9564BA2E35 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=132.207.4.11 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1788542064; cv=none; b=h3dzp7yydrcDLgw+dz9gRENaLvM3BBePdo1zo6IYNBqi3h2FPsHfAex2Ja09sFDqxtjEZRScSgT7Ee62VkvbuSi049EctrNqsrpltJHDsi+jPM6+n2CuTPHY2mimEo6Hma6UAqpx39QFhKMANXvpuPUkNoiYaaGUzWQ2mWJA6hs= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1788542064; c=relaxed/simple; bh=ypu3hx5mKoUnj3tYZ7Fu0CSNsbHmTEJtIj8WjR3ONGg=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=XE/VkRNcpp+BUH5TjGYNz/dNgGhNzNfZ7j4ycv3lubpn/h+AhAzvYbLoJHTv3SrS3GuhmHHi8lRn6dYRhPdhsbFHRtsJqXzMN8AL4P//PvnsuviIlJizxskQewKS/gbRp8skprE7O3byn1WfGU2uAhr+WkEK+/yYHa9VMDBQIQo= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=polymtl.ca header.i=@polymtl.ca header.a=rsa-sha256 header.s=oct2025 header.b=OKYkNfaQ DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CA9564BA2E35 Received: from simark.ca (simark.ca [158.69.221.121]) (authenticated bits=0) by smtp.polymtl.ca (8.14.7/8.14.7) with ESMTP id 684HEGBM145320 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 4 Sep 2026 13:14:21 -0400 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp.polymtl.ca 684HEGBM145320 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=polymtl.ca; s=oct2025; t=1788542061; bh=jRdwXVlIT14TXo9R09Z5h/9YLYweOyx1vE4NLncsiyk=; h=From:To:Cc:Subject:Date:In-Reply-To:From; b=OKYkNfaQVxM/k1ehPaJZWTkvJ2FqoQ4DV03s6TNPYhdjKACU+6c+oSvPNUJagKOts qaDQ2lfc5+ikVzXV7U0RB6YnomMlpKyrnLIwLoyHYhreFYYVq7IZcYYYaMAuP0j6N7 13CbnN7esUsmbXPwrwUfKqFmbzlObkKUJ9HFxSOPJ3w0Q/y5kOM+leULml2CWVXWb6 kcgPhCqf63CdfSeETl0sLBiORkloqqdCOb4/2lUo7lUpwzigEdNfH8ING1kAG9npEx Ue3NGFl3G35X0X6ra7bEHlCfAQOEIATkNYEmkHt1a8CzSD/HtEKEdjuflXHzco0B1R ouanPPsiHVb8g== Received: by simark.ca (Postfix) id 967A01E1A2; Fri, 04 Sep 2026 13:05:50 -0400 (EDT) From: simon.marchi@polymtl.ca To: gdb-patches@sourceware.org Cc: Simon Marchi 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 Message-ID: <20260904170338.1643894-13-simon.marchi@polymtl.ca> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260904170338.1643894-1-simon.marchi@polymtl.ca> References: <20260904170338.1643894-1-simon.marchi@polymtl.ca> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Poly-FromMTA: (simark.ca [158.69.221.121]) at Fri, 4 Sep 2026 17:14:16 +0000 X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org From: Simon Marchi 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 . */ + +#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 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 (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 (std::move (arg)); + operation_up wrapped + = make_operation (std::move (addr)); + if (type != nullptr) + wrapped = make_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 (fn); + + std::vector argvec; + argvec.push_back (std::move (lhs)); + if (rhs != nullptr) + argvec.push_back (std::move (rhs)); + return make_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 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 (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 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 (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 +pop_components (int n) +{ + std::vector 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 +pop_associations (int n) +{ + std::vector result (n); + for (int i = 1; i <= n; ++i) + result[n - i] = pop_association (); + return result; +} + +/* See ada-exp-parser.h. */ + +std::unique_ptr +make_tick_completer (struct stoken tok) +{ + return (std::unique_ptr + (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 (sym); +} + +/* See ada-exp-parser.h. */ + +void +write_int (struct parser_state *par_state, LONGEST arg, struct type *type) +{ + pstate->push_new (type, arg); + ada_wrap (); +} + +/* 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 (); + 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 (); + 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 + (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 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 &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 ()*, where + 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 (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 (); + 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 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 (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 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 (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_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 . */ + +#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; + +/* 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 components; + + /* The associations being constructed during this parse. */ + std::vector associations; + + /* The stack of currently active assignment expressions. This is used + to implement '@', the target name symbol. */ + std::vector assignments; + + /* Track currently active iterated assignment names. */ + gdb::unordered_string_map> + 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> 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 make_tick_completer (struct stoken tok); + +/* Pop the N most recent components from the global stack, and return + them in a vector. */ + +std::vector 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 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 (.)*, where is an object + or renaming encoded in the debugging data. Calls error if no + prefix 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 +void +ada_wrap (Args... args) +{ + expr::operation_up arg = ada_pop (); + pstate->push_new (std::move (arg), std::forward (args)...); +} + +/* Like parser_state::wrap, but use ada_pop to pop the value, and + handle unary overloading. */ + +template +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 (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 +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 (std::move (lhs), std::move (rhs)); + wrapped = expr::make_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 +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 (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 +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 (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 +void +ada_wrap3 () +{ + expr::operation_up rhs = ada_pop (); + expr::operation_up mid = ada_pop (); + expr::operation_up lhs = ada_pop (); + pstate->push_new (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 +void +push_component (Arg... args) +{ + ada_parser->components.emplace_back (new T (std::forward (args)...)); +} + +/* Create a new ada_association_up of the indicated type and + arguments, and push it on the global 'associations' vector. */ + +template +void +push_association (Arg... args) +{ + ada_parser->associations.emplace_back (new T (std::forward (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_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 components; - - /* The associations being constructed during this parse. */ - std::vector associations; - - /* The stack of currently active assignment expressions. This is used - to implement '@', the target name symbol. */ - std::vector assignments; - - /* Track currently active iterated assignment names. */ - gdb::unordered_string_map> - 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> 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 (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 -void -ada_wrap (Args... args) -{ - operation_up arg = ada_pop (); - pstate->push_new (std::move (arg), std::forward (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 (std::move (arg)); - operation_up wrapped - = make_operation (std::move (addr)); - if (type != nullptr) - wrapped = make_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 (fn); - - std::vector argvec; - argvec.push_back (std::move (lhs)); - if (rhs != nullptr) - argvec.push_back (std::move (rhs)); - return make_operation (std::move (callee), - std::move (argvec)); -} - -/* Like parser_state::wrap, but use ada_pop to pop the value, and - handle unary overloading. */ -template -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 (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 -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 (std::move (lhs), std::move (rhs)); - wrapped = make_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 -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 (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 -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 (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 -void -ada_wrap3 () -{ - operation_up rhs = ada_pop (); - operation_up mid = ada_pop (); - operation_up lhs = ada_pop (); - pstate->push_new (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 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 (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 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 -void -push_component (Arg... args) -{ - ada_parser->components.emplace_back (new T (std::forward (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 (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 -pop_components (int n) -{ - std::vector 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 -void -push_association (Arg... args) -{ - ada_parser->associations.emplace_back (new T (std::forward (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 -pop_associations (int n) -{ - std::vector 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 -make_tick_completer (struct stoken tok) -{ - return (std::unique_ptr - (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 (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 (type, arg); - ada_wrap (); -} - -/* 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 (); - 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 (); - 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 - (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 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 &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 ()*, where - 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 (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 (.)*, where is an object - or renaming encoded in the debugging data. Calls error if no - prefix 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 (); - 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 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 (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 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 (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_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 . */ +#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 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