/* Parse expressions for GDB.
- Copyright (C) 1986, 1989, 1990, 1991 Free Software Foundation, Inc.
+ Copyright (C) 1986, 1989, 1990, 1991, 1994 Free Software Foundation, Inc.
Modified from expread.y by the Department of Computer Science at the
State University of New York at Buffalo, 1991.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* Parse an expression from text in a string,
and return the result as a struct expression pointer.
come first in the result. */
#include "defs.h"
+#include "gdb_string.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "frame.h"
#include "command.h"
#include "language.h"
#include "parser-defs.h"
+\f
+/* Global variables declared in parser-defs.h (and commented there). */
+struct expression *expout;
+int expout_size;
+int expout_ptr;
+struct block *expression_context_block;
+struct block *innermost_block;
+int arglist_len;
+union type_stack_elt *type_stack;
+int type_stack_depth, type_stack_size;
+char *lexptr;
+char *namecopy;
+int paren_depth;
+int comma_terminates;
+\f
+static void
+free_funcalls PARAMS ((void));
static void
prefixify_expression PARAMS ((struct expression *));
static void
prefixify_subexp PARAMS ((struct expression *, struct expression *, int, int));
+/* Data structure for saving values of arglist_len for function calls whose
+ arguments contain other function calls. */
+
+struct funcall
+ {
+ struct funcall *next;
+ int arglist_len;
+ };
+
+static struct funcall *funcall_chain;
+
/* Assign machine-independent names to certain registers
(unless overridden by the REGISTER_NAMES table) */
+#ifdef NO_STD_REGS
+unsigned num_std_regs = 0;
+struct std_regs std_regs[1];
+#else
struct std_regs std_regs[] = {
+
#ifdef PC_REGNUM
{ "pc", PC_REGNUM },
#endif
#ifdef PS_REGNUM
{ "ps", PS_REGNUM },
#endif
+
};
unsigned num_std_regs = (sizeof std_regs / sizeof std_regs[0]);
+#endif
+
/* Begin counting arguments for a function call,
saving the data about any containing call. */
void
start_arglist ()
{
- register struct funcall *new = (struct funcall *) xmalloc (sizeof (struct funcall));
+ register struct funcall *new;
+ new = (struct funcall *) xmalloc (sizeof (struct funcall));
new->next = funcall_chain;
new->arglist_len = arglist_len;
arglist_len = 0;
/* Free everything in the funcall chain.
Used when there is an error inside parsing. */
-void
+static void
free_funcalls ()
{
register struct funcall *call, *next;
write_exp_elt (tmp);
}
+void
+write_exp_elt_block (b)
+ struct block *b;
+{
+ union exp_element tmp;
+ tmp.block = b;
+ write_exp_elt (tmp);
+}
+
void
write_exp_elt_longcst (expelt)
LONGEST expelt;
void
write_exp_elt_dblcst (expelt)
- double expelt;
+ DOUBLEST expelt;
{
union exp_element tmp;
expout_ptr += lenelt - 2;
write_exp_elt_longcst ((LONGEST) bits);
}
+
+/* Add the appropriate elements for a minimal symbol to the end of
+ the expression. The rationale behind passing in text_symbol_type and
+ data_symbol_type was so that Modula-2 could pass in WORD for
+ data_symbol_type. Perhaps it still is useful to have those types vary
+ based on the language, but they no longer have names like "int", so
+ the initial rationale is gone. */
+
+static struct type *msym_text_symbol_type;
+static struct type *msym_data_symbol_type;
+static struct type *msym_unknown_symbol_type;
+
+void
+write_exp_msymbol (msymbol, text_symbol_type, data_symbol_type)
+ struct minimal_symbol *msymbol;
+ struct type *text_symbol_type;
+ struct type *data_symbol_type;
+{
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (lookup_pointer_type (builtin_type_void));
+ write_exp_elt_longcst ((LONGEST) SYMBOL_VALUE_ADDRESS (msymbol));
+ write_exp_elt_opcode (OP_LONG);
+
+ write_exp_elt_opcode (UNOP_MEMVAL);
+ switch (msymbol -> type)
+ {
+ case mst_text:
+ case mst_file_text:
+ case mst_solib_trampoline:
+ write_exp_elt_type (msym_text_symbol_type);
+ break;
+
+ case mst_data:
+ case mst_file_data:
+ case mst_bss:
+ case mst_file_bss:
+ write_exp_elt_type (msym_data_symbol_type);
+ break;
+
+ default:
+ write_exp_elt_type (msym_unknown_symbol_type);
+ break;
+ }
+ write_exp_elt_opcode (UNOP_MEMVAL);
+}
+\f
+/* Recognize tokens that start with '$'. These include:
+
+ $regname A native register name or a "standard
+ register name".
+
+ $variable A convenience variable with a name chosen
+ by the user.
+
+ $digits Value history with index <digits>, starting
+ from the first value which has index 1.
+
+ $$digits Value history with index <digits> relative
+ to the last value. I.E. $$0 is the last
+ value, $$1 is the one previous to that, $$2
+ is the one previous to $$1, etc.
+
+ $ | $0 | $$0 The last value in the value history.
+
+ $$ An abbreviation for the second to the last
+ value in the value history, I.E. $$1
+
+ */
+
+void
+write_dollar_variable (str)
+ struct stoken str;
+{
+ /* 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. */
+ for (i = 0; i < NUM_REGS; i++)
+ if (reg_names[i] && str.length - 1 == strlen (reg_names[i])
+ && STREQN (str.ptr + 1, reg_names[i], str.length - 1))
+ {
+ goto handle_register;
+ }
+ for (i = 0; i < num_std_regs; i++)
+ if (std_regs[i].name && str.length - 1 == strlen (std_regs[i].name)
+ && STREQN (str.ptr + 1, std_regs[i].name, str.length - 1))
+ {
+ i = std_regs[i].regnum;
+ goto handle_register;
+ }
+
+ /* Any other names starting in $ are debugger internal variables. */
+
+ write_exp_elt_opcode (OP_INTERNALVAR);
+ write_exp_elt_intern (lookup_internalvar (copy_name (str) + 1));
+ write_exp_elt_opcode (OP_INTERNALVAR);
+ return;
+ handle_last:
+ write_exp_elt_opcode (OP_LAST);
+ write_exp_elt_longcst ((LONGEST) i);
+ write_exp_elt_opcode (OP_LAST);
+ return;
+ handle_register:
+ write_exp_elt_opcode (OP_REGISTER);
+ write_exp_elt_longcst (i);
+ write_exp_elt_opcode (OP_REGISTER);
+ return;
+}
\f
/* Return a null-terminated temporary copy of the name
of a string token. */
case OP_LONG:
case OP_DOUBLE:
+ case OP_VAR_VALUE:
oplen = 4;
break;
case OP_TYPE:
case OP_BOOL:
- case OP_VAR_VALUE:
case OP_LAST:
case OP_REGISTER:
case OP_INTERNALVAR:
oplen = 3;
break;
+ case OP_COMPLEX:
+ oplen = 1;
+ args = 2;
+ break;
+
case OP_FUNCALL:
+ case OP_F77_UNDETERMINED_ARGLIST:
oplen = 3;
args = 1 + longest_to_int (expr->elts[endpos - 2].longconst);
break;
args = 1;
break;
+ case OP_LABELED:
case STRUCTOP_STRUCT:
case STRUCTOP_PTR:
+/* start-sanitize-gm */
+#ifdef GENERAL_MAGIC
+ case STRUCTOP_FIELD:
+#endif /* GENERAL_MAGIC */
+/* end-sanitize-gm */
args = 1;
/* fall through */
case OP_M2_STRING:
case OP_STRING:
+ case OP_NAME:
+ case OP_EXPRSTRING:
oplen = longest_to_int (expr->elts[endpos - 2].longconst);
oplen = 4 + BYTES_TO_EXP_ELEM (oplen + 1);
break;
break;
case TERNOP_COND:
+ case TERNOP_SLICE:
+ case TERNOP_SLICE_COUNT:
args = 3;
break;
/* Modula-2 */
case MULTI_SUBSCRIPT:
- oplen=3;
+ oplen = 3;
args = 1 + longest_to_int (expr->elts[endpos- 2].longconst);
break;
case OP_LONG:
case OP_DOUBLE:
+ case OP_VAR_VALUE:
oplen = 4;
break;
case OP_TYPE:
case OP_BOOL:
- case OP_VAR_VALUE:
case OP_LAST:
case OP_REGISTER:
case OP_INTERNALVAR:
oplen = 3;
break;
+ case OP_COMPLEX:
+ oplen = 1;
+ args = 2;
+ break;
+
case OP_FUNCALL:
+ case OP_F77_UNDETERMINED_ARGLIST:
oplen = 3;
args = 1 + longest_to_int (inexpr->elts[inend - 2].longconst);
break;
args=1;
break;
- case STRUCTOP_STRUCT:
+ case STRUCTOP_STRUCT:
case STRUCTOP_PTR:
+ case OP_LABELED:
args = 1;
/* fall through */
case OP_M2_STRING:
case OP_STRING:
+ case OP_NAME:
+ case OP_EXPRSTRING:
oplen = longest_to_int (inexpr->elts[inend - 2].longconst);
oplen = 4 + BYTES_TO_EXP_ELEM (oplen + 1);
break;
break;
case TERNOP_COND:
+ case TERNOP_SLICE:
+ case TERNOP_SLICE_COUNT:
args = 3;
break;
/* Modula-2 */
case MULTI_SUBSCRIPT:
- oplen=3;
+ oplen = 3;
args = 1 + longest_to_int (inexpr->elts[inend - 2].longconst);
break;
/* Convert expression from postfix form as generated by yacc
parser, to a prefix form. */
- DUMP_EXPRESSION (expout, stdout, "before conversion to prefix form");
+ DUMP_EXPRESSION (expout, gdb_stdout, "before conversion to prefix form");
prefixify_expression (expout);
- DUMP_EXPRESSION (expout, stdout, "after conversion to prefix form");
+ DUMP_EXPRESSION (expout, gdb_stdout, "after conversion to prefix form");
*stringptr = lexptr;
return expout;
error ("Junk after end of expression.");
return exp;
}
+\f
+/* Stuff for maintaining a stack of types. Currently just used by C, but
+ probably useful for any language which declares its types "backwards". */
void
push_type (tp)
return 0;
}
+/* Pop the type stack and return the type which corresponds to FOLLOW_TYPE
+ as modified by all the stuff on the stack. */
+struct type *
+follow_types (follow_type)
+ struct type *follow_type;
+{
+ int done = 0;
+ int array_size;
+ struct type *range_type;
+
+ while (!done)
+ switch (pop_type ())
+ {
+ case tp_end:
+ done = 1;
+ break;
+ case tp_pointer:
+ follow_type = lookup_pointer_type (follow_type);
+ break;
+ case tp_reference:
+ follow_type = lookup_reference_type (follow_type);
+ break;
+ case tp_array:
+ array_size = pop_type_int ();
+ /* FIXME-type-allocation: need a way to free this type when we are
+ done with it. */
+ range_type =
+ create_range_type ((struct type *) NULL,
+ builtin_type_int, 0,
+ array_size >= 0 ? array_size - 1 : 0);
+ follow_type =
+ create_array_type ((struct type *) NULL,
+ follow_type, range_type);
+ if (array_size < 0)
+ TYPE_ARRAY_UPPER_BOUND_TYPE(follow_type)
+ = BOUND_CANNOT_BE_DETERMINED;
+ break;
+ case tp_function:
+ /* FIXME-type-allocation: need a way to free this type when we are
+ done with it. */
+ follow_type = lookup_function_type (follow_type);
+ break;
+ }
+ return follow_type;
+}
+\f
void
_initialize_parse ()
{
type_stack_depth = 0;
type_stack = (union type_stack_elt *)
xmalloc (type_stack_size * sizeof (*type_stack));
+
+ msym_text_symbol_type =
+ init_type (TYPE_CODE_FUNC, 1, 0, "<text variable, no debug info>", NULL);
+ TYPE_TARGET_TYPE (msym_text_symbol_type) = builtin_type_int;
+ msym_data_symbol_type =
+ init_type (TYPE_CODE_INT, TARGET_INT_BIT / HOST_CHAR_BIT, 0,
+ "<data variable, no debug info>", NULL);
+ msym_unknown_symbol_type =
+ init_type (TYPE_CODE_INT, 1, 0,
+ "<variable (not text or data), no debug info>",
+ NULL);
}