diff options
-rw-r--r-- | gdb/ChangeLog | 10 | ||||
-rw-r--r-- | gdb/parse.c | 127 | ||||
-rw-r--r-- | gdb/parser-defs.h | 63 |
3 files changed, 200 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 3436e4e..060b9a1 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,15 @@ 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. + +2021-03-08 Tom Tromey <tom@tromey.com> + * parser-defs.h (struct expr_completion_state) <expout_last_op>: New member. (struct parser_state) <mark_struct_expression>: New method. 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: diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h index 9f70ff9..6932559 100644 --- a/gdb/parser-defs.h +++ b/gdb/parser-defs.h @@ -173,6 +173,66 @@ struct parser_state : public expr_builder void mark_completion_tag (enum type_code tag, const char *ptr, int length); + /* Push an operation on the stack. */ + void push (expr::operation_up &&op) + { + m_operations.push_back (std::move (op)); + } + + /* Create a new operation and push it on the stack. */ + template<typename T, typename... Arg> + void push_new (Arg... args) + { + m_operations.emplace_back (new T (std::forward<Arg> (args)...)); + } + + /* Push a new C string operation. */ + void push_c_string (int, struct stoken_vector *vec); + + /* Push a symbol reference. If SYM is nullptr, look for a minimal + symbol. */ + void push_symbol (const char *name, block_symbol sym); + + /* Push a reference to $mumble. This may result in a convenience + variable, a history reference, or a register. */ + void push_dollar (struct stoken str); + + /* Pop an operation from the stack. */ + expr::operation_up pop () + { + expr::operation_up result = std::move (m_operations.back ()); + m_operations.pop_back (); + return result; + } + + /* Pop N elements from the stack and return a vector. */ + std::vector<expr::operation_up> pop_vector (int n) + { + std::vector<expr::operation_up> result (n); + for (int i = 1; i <= n; ++i) + result[n - i] = pop (); + return result; + } + + /* A helper that pops an operation, wraps it in some other + operation, and pushes it again. */ + template<typename T> + void wrap () + { + using namespace expr; + operation_up v = ::expr::make_operation<T> (pop ()); + push (std::move (v)); + } + + /* A helper that pops two operations, wraps them in some other + operation, and pushes the result. */ + template<typename T> + void wrap2 () + { + expr::operation_up rhs = pop (); + expr::operation_up lhs = pop (); + push (expr::make_operation<T> (std::move (lhs), std::move (rhs))); + } /* If this is nonzero, this block is used as the lexical context for symbol names. */ @@ -221,6 +281,9 @@ private: arguments contain other function calls. */ std::vector<int> m_funcall_chain; + + /* Stack of operations. */ + std::vector<expr::operation_up> m_operations; }; /* When parsing expressions we track the innermost block that was |