aboutsummaryrefslogtreecommitdiff
path: root/gdb/parse.c
diff options
context:
space:
mode:
authorTom Tromey <tom@tromey.com>2021-03-08 07:27:57 -0700
committerTom Tromey <tom@tromey.com>2021-03-08 07:28:37 -0700
commit8227d9e2f4af14c7e36f1792747bd5d7edf71d6a (patch)
treeccd72473a386dc22c44b237893aea832b1e78451 /gdb/parse.c
parent4933522da0d59823d2bfef3706e2252203365e9c (diff)
downloadgdb-8227d9e2f4af14c7e36f1792747bd5d7edf71d6a.zip
gdb-8227d9e2f4af14c7e36f1792747bd5d7edf71d6a.tar.gz
gdb-8227d9e2f4af14c7e36f1792747bd5d7edf71d6a.tar.bz2
Add operation-related methods to parser_state
This adds several operation-related methods to parser_state. These methods make it more convenient to change the parsers to be operation-based. Because byacc has poor support for C++, a stack of operations is added to parser_state. A parser can push operations, then later pop them for combination into new operations. This approach avoids the memory leaks that would result if raw pointers were used in the parsers, at the cost of parser productions not being type-safe (they can't indicate that they return an operation). This also introduces analogs of some write_exp functions, like write_exp_string_vector, write_dollar_variable, and write_exp_symbol_reference. gdb/ChangeLog 2021-03-08 Tom Tromey <tom@tromey.com> * parser-defs.h (struct parser_state) <push, push_new, push_c_string, push_symbol, push_dollar, pop, pop_vector, wrap, wrap2>: New methods. <m_operations>: New member. * parse.c (parser_state::push_c_string) (parser_state::push_symbol, parser_state::push_dollar): New methods.
Diffstat (limited to 'gdb/parse.c')
-rw-r--r--gdb/parse.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/gdb/parse.c b/gdb/parse.c
index 79b1ca1..d6f98bf 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -545,6 +545,133 @@ parser_state::mark_completion_tag (enum type_code tag, const char *ptr,
m_completion_state.expout_completion_name.reset (xstrndup (ptr, length));
}
+/* See parser-defs.h. */
+
+void
+parser_state::push_c_string (int kind, struct stoken_vector *vec)
+{
+ std::vector<std::string> data (vec->len);
+ for (int i = 0; i < vec->len; ++i)
+ data[i] = std::string (vec->tokens[i].ptr, vec->tokens[i].length);
+
+ push_new<expr::c_string_operation> ((enum c_string_type_values) kind,
+ std::move (data));
+}
+
+/* See parser-defs.h. */
+
+void
+parser_state::push_symbol (const char *name, block_symbol sym)
+{
+ if (sym.symbol != nullptr)
+ {
+ if (symbol_read_needs_frame (sym.symbol))
+ block_tracker->update (sym);
+ push_new<expr::var_value_operation> (sym.symbol, sym.block);
+ }
+ else
+ {
+ struct bound_minimal_symbol msymbol = lookup_bound_minimal_symbol (name);
+ if (msymbol.minsym != NULL)
+ push_new<expr::var_msym_value_operation> (msymbol.minsym,
+ msymbol.objfile);
+ else if (!have_full_symbols () && !have_partial_symbols ())
+ error (_("No symbol table is loaded. Use the \"file\" command."));
+ else
+ error (_("No symbol \"%s\" in current context."), name);
+ }
+}
+
+/* See parser-defs.h. */
+
+void
+parser_state::push_dollar (struct stoken str)
+{
+ struct block_symbol sym;
+ struct bound_minimal_symbol msym;
+ struct internalvar *isym = NULL;
+ std::string copy;
+
+ /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1)
+ and $$digits (equivalent to $<-digits> if you could type that). */
+
+ int negate = 0;
+ int i = 1;
+ /* Double dollar means negate the number and add -1 as well.
+ Thus $$ alone means -1. */
+ if (str.length >= 2 && str.ptr[1] == '$')
+ {
+ negate = 1;
+ i = 2;
+ }
+ if (i == str.length)
+ {
+ /* Just dollars (one or two). */
+ i = -negate;
+ goto handle_last;
+ }
+ /* Is the rest of the token digits? */
+ for (; i < str.length; i++)
+ if (!(str.ptr[i] >= '0' && str.ptr[i] <= '9'))
+ break;
+ if (i == str.length)
+ {
+ i = atoi (str.ptr + 1 + negate);
+ if (negate)
+ i = -i;
+ goto handle_last;
+ }
+
+ /* Handle tokens that refer to machine registers:
+ $ followed by a register name. */
+ i = user_reg_map_name_to_regnum (gdbarch (),
+ str.ptr + 1, str.length - 1);
+ if (i >= 0)
+ goto handle_register;
+
+ /* Any names starting with $ are probably debugger internal variables. */
+
+ copy = copy_name (str);
+ isym = lookup_only_internalvar (copy.c_str () + 1);
+ if (isym)
+ {
+ push_new<expr::internalvar_operation> (isym);
+ return;
+ }
+
+ /* On some systems, such as HP-UX and hppa-linux, certain system routines
+ have names beginning with $ or $$. Check for those, first. */
+
+ sym = lookup_symbol (copy.c_str (), NULL, VAR_DOMAIN, NULL);
+ if (sym.symbol)
+ {
+ push_new<expr::var_value_operation> (sym.symbol, sym.block);
+ return;
+ }
+ msym = lookup_bound_minimal_symbol (copy.c_str ());
+ if (msym.minsym)
+ {
+ push_new<expr::var_msym_value_operation> (msym.minsym, msym.objfile);
+ return;
+ }
+
+ /* Any other names are assumed to be debugger internal variables. */
+
+ push_new<expr::internalvar_operation>
+ (create_internalvar (copy.c_str () + 1));
+ return;
+handle_last:
+ push_new<expr::last_operation> (i);
+ return;
+handle_register:
+ str.length--;
+ str.ptr++;
+ push_new<expr::register_operation> (copy_name (str));
+ block_tracker->update (expression_context_block,
+ INNERMOST_BLOCK_FOR_REGISTERS);
+ return;
+}
+
/* Recognize tokens that start with '$'. These include: