* This code is derived from software copyrighted by the Free Software
* Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
* Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
/* Parse C expressions for GDB.
Copyright (C) 1986, 1989 Free Software Foundation, Inc.
This file is part of GDB.
GDB 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 1, or (at your option)
GDB 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 GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Parse a C expression from text in a string,
and return the result as a struct expression pointer.
That structure contains arithmetic operations in reverse polish,
with constants represented by operations that are followed by special data.
See expression.h for the details of the format.
What is important here is that it can be built up sequentially
during the process of parsing; the lower levels of the tree always
come first in the result. */
static char sccsid[] = "@(#)expread.y 6.3 (Berkeley) 5/8/91";
static struct expression *expout;
static void write_exp_elt ();
static void write_exp_elt_opcode ();
static void write_exp_elt_sym ();
static void write_exp_elt_longcst ();
static void write_exp_elt_dblcst ();
static void write_exp_elt_type ();
static void write_exp_elt_intern ();
static void write_exp_string ();
static void start_arglist ();
static int end_arglist ();
static void free_funcalls ();
static char *copy_name ();
/* If this is nonzero, this block is used as the lexical context
static struct block *expression_context_block;
/* The innermost context required by the stack and register variables
we've encountered so far. */
struct block *innermost_block;
/* The block in which the most recently discovered symbol was found. */
struct block *block_found;
/* Number of arguments seen so far in innermost function call. */
/* Data structure for saving values of arglist_len
for function calls whose arguments contain other function calls. */
struct funcall *funcall_chain;
/* This kind of datum is used to represent the name
/* For parsing of complicated types.
An array should be preceded in the list by the size of the array. */
{tp_end = -1, tp_pointer, tp_reference, tp_array, tp_function};
static enum type_pieces *type_stack;
static int type_stack_depth, type_stack_size;
static void push_type ();
static enum type_pieces pop_type ();
/* Allow debugging of parsing. */
/* Although the yacc "value" of an expression is not used,
since the result is stored in the structure being created,
other node types do have values. */
struct internalvar *ivar;
%type <voidval> exp exp1 start variable
%type <tval> type typebase
%type <tvec> nonempty_typelist
/* Fancy type parsing. */
%type <voidval> func_mod direct_abs_decl abs_decl
/* Both NAME and TYPENAME tokens represent symbols in the input,
and both convey their data as strings.
But a TYPENAME is a string that happens to be defined as a typedef
or builtin type name (such as int or char)
and a NAME is any other symbol.
Contexts where this distinction is not important can use the
nonterminal "name", which matches either NAME or TYPENAME. */
%token <sval> NAME TYPENAME BLOCKNAME STRING
%type <sval> name name_not_typename typename
%token STRUCT UNION ENUM SIZEOF UNSIGNED COLONCOLON
/* Special type cases, put in to allow the parser to distinguish different
%token SIGNED LONG SHORT INT_KEYWORD
%token <lval> LAST REGNAME
%token <opcode> ASSIGN_MODIFY
%right UNARY INCREMENT DECREMENT
/* Expressions, including the comma operator. */
{ write_exp_elt_opcode (BINOP_COMMA); }
/* Expressions, not including the comma operator. */
exp : '*' exp %prec UNARY
{ write_exp_elt_opcode (UNOP_IND); }
exp : '&' exp %prec UNARY
{ write_exp_elt_opcode (UNOP_ADDR); }
exp : '-' exp %prec UNARY
{ write_exp_elt_opcode (UNOP_NEG); }
exp : '!' exp %prec UNARY
{ write_exp_elt_opcode (UNOP_ZEROP); }
exp : '~' exp %prec UNARY
{ write_exp_elt_opcode (UNOP_LOGNOT); }
exp : INCREMENT exp %prec UNARY
{ write_exp_elt_opcode (UNOP_PREINCREMENT); }
exp : DECREMENT exp %prec UNARY
{ write_exp_elt_opcode (UNOP_PREDECREMENT); }
exp : exp INCREMENT %prec UNARY
{ write_exp_elt_opcode (UNOP_POSTINCREMENT); }
exp : exp DECREMENT %prec UNARY
{ write_exp_elt_opcode (UNOP_POSTDECREMENT); }
exp : SIZEOF exp %prec UNARY
{ write_exp_elt_opcode (UNOP_SIZEOF); }
{ write_exp_elt_opcode (STRUCTOP_PTR);
write_exp_elt_opcode (STRUCTOP_PTR); }
{ write_exp_elt_opcode (STRUCTOP_MPTR); }
{ write_exp_elt_opcode (STRUCTOP_STRUCT);
write_exp_elt_opcode (STRUCTOP_STRUCT); }
{ write_exp_elt_opcode (STRUCTOP_MEMBER); }
{ write_exp_elt_opcode (BINOP_SUBSCRIPT); }
/* This is to save the value of arglist_len
being accumulated by an outer function call. */
{ write_exp_elt_opcode (OP_FUNCALL);
write_exp_elt_longcst ((LONGEST) end_arglist ());
write_exp_elt_opcode (OP_FUNCALL); }
arglist : arglist ',' exp %prec ABOVE_COMMA
exp : '{' type '}' exp %prec UNARY
{ write_exp_elt_opcode (UNOP_MEMVAL);
write_exp_elt_opcode (UNOP_MEMVAL); }
exp : '(' type ')' exp %prec UNARY
{ write_exp_elt_opcode (UNOP_CAST);
write_exp_elt_opcode (UNOP_CAST); }
/* Binary operators in order of decreasing precedence. */
{ write_exp_elt_opcode (BINOP_REPEAT); }
{ write_exp_elt_opcode (BINOP_MUL); }
{ write_exp_elt_opcode (BINOP_DIV); }
{ write_exp_elt_opcode (BINOP_REM); }
{ write_exp_elt_opcode (BINOP_ADD); }
{ write_exp_elt_opcode (BINOP_SUB); }
{ write_exp_elt_opcode (BINOP_LSH); }
{ write_exp_elt_opcode (BINOP_RSH); }
{ write_exp_elt_opcode (BINOP_EQUAL); }
{ write_exp_elt_opcode (BINOP_NOTEQUAL); }
{ write_exp_elt_opcode (BINOP_LEQ); }
{ write_exp_elt_opcode (BINOP_GEQ); }
{ write_exp_elt_opcode (BINOP_LESS); }
{ write_exp_elt_opcode (BINOP_GTR); }
{ write_exp_elt_opcode (BINOP_LOGAND); }
{ write_exp_elt_opcode (BINOP_LOGXOR); }
{ write_exp_elt_opcode (BINOP_LOGIOR); }
{ write_exp_elt_opcode (BINOP_AND); }
{ write_exp_elt_opcode (BINOP_OR); }
exp : exp '?' exp ':' exp %prec '?'
{ write_exp_elt_opcode (TERNOP_COND); }
{ write_exp_elt_opcode (BINOP_ASSIGN); }
exp : exp ASSIGN_MODIFY exp
{ write_exp_elt_opcode (BINOP_ASSIGN_MODIFY);
write_exp_elt_opcode ($2);
write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); }
{ write_exp_elt_opcode (OP_LONG);
if ($1 == (int) $1 || $1 == (unsigned int) $1)
write_exp_elt_type (builtin_type_int);
write_exp_elt_type (BUILTIN_TYPE_LONGEST);
write_exp_elt_longcst ((LONGEST) $1);
write_exp_elt_opcode (OP_LONG); }
write_exp_elt_opcode (OP_LONG);
if ($1 == (unsigned int) $1)
write_exp_elt_type (builtin_type_unsigned_int);
write_exp_elt_type (BUILTIN_TYPE_UNSIGNED_LONGEST);
write_exp_elt_longcst ((LONGEST) $1);
write_exp_elt_opcode (OP_LONG);
{ write_exp_elt_opcode (OP_LONG);
write_exp_elt_type (builtin_type_char);
write_exp_elt_longcst ((LONGEST) $1);
write_exp_elt_opcode (OP_LONG); }
{ write_exp_elt_opcode (OP_DOUBLE);
write_exp_elt_type (builtin_type_double);
write_exp_elt_dblcst ($1);
write_exp_elt_opcode (OP_DOUBLE); }
{ write_exp_elt_opcode (OP_LAST);
write_exp_elt_longcst ((LONGEST) $1);
write_exp_elt_opcode (OP_LAST); }
{ write_exp_elt_opcode (OP_REGISTER);
write_exp_elt_longcst ((LONGEST) $1);
write_exp_elt_opcode (OP_REGISTER); }
{ write_exp_elt_opcode (OP_INTERNALVAR);
write_exp_elt_intern ($1);
write_exp_elt_opcode (OP_INTERNALVAR); }
exp : SIZEOF '(' type ')' %prec UNARY
{ write_exp_elt_opcode (OP_LONG);
write_exp_elt_type (builtin_type_int);
write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3));
write_exp_elt_opcode (OP_LONG); }
{ write_exp_elt_opcode (OP_STRING);
write_exp_elt_opcode (OP_STRING); }
{ write_exp_elt_opcode (OP_THIS);
write_exp_elt_opcode (OP_THIS); }
struct symtab *tem = lookup_symtab (copy_name ($1));
$$ = BLOCKVECTOR_BLOCK (BLOCKVECTOR (tem), 1);
sym = lookup_symbol (copy_name ($1),
expression_context_block,
if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
$$ = SYMBOL_BLOCK_VALUE (sym);
error ("No file or function \"%s\".",
block : block COLONCOLON name
= lookup_symbol (copy_name ($3), $1, VAR_NAMESPACE, 0);
if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK)
error ("No function \"%s\" in specified context.",
$$ = SYMBOL_BLOCK_VALUE (tem); }
variable: block COLONCOLON name
sym = lookup_symbol (copy_name ($3), $1, VAR_NAMESPACE, 0);
error ("No symbol \"%s\" in specified context.",
write_exp_elt_opcode (OP_VAR_VALUE);
write_exp_elt_opcode (OP_VAR_VALUE); }
variable: typebase COLONCOLON name
if (TYPE_CODE (type) != TYPE_CODE_STRUCT
&& TYPE_CODE (type) != TYPE_CODE_UNION)
error ("`%s' is not defined as an aggregate type.",
write_exp_elt_opcode (OP_SCOPE);
write_exp_elt_type (type);
write_exp_elt_opcode (OP_SCOPE);
char *name = copy_name ($2);
sym = lookup_symbol (name, 0, VAR_NAMESPACE, 0);
write_exp_elt_opcode (OP_VAR_VALUE);
write_exp_elt_opcode (OP_VAR_VALUE);
for (i = 0; i < misc_function_count; i++)
if (!strcmp (misc_function_vector[i].name, name))
if (i < misc_function_count)
enum misc_function_type mft =
(enum misc_function_type)
misc_function_vector[i].type;
write_exp_elt_opcode (OP_LONG);
write_exp_elt_type (builtin_type_int);
write_exp_elt_longcst ((LONGEST) misc_function_vector[i].address);
write_exp_elt_opcode (OP_LONG);
write_exp_elt_opcode (UNOP_MEMVAL);
if (mft == mf_data || mft == mf_bss)
write_exp_elt_type (builtin_type_int);
write_exp_elt_type (lookup_function_type (builtin_type_int));
write_exp_elt_type (builtin_type_char);
write_exp_elt_opcode (UNOP_MEMVAL);
&& partial_symtab_list == 0)
error ("No symbol table is loaded. Use the \"symbol-file\" command.");
error ("No symbol \"%s\" in current context.", name);
variable: name_not_typename
sym = lookup_symbol (copy_name ($1),
expression_context_block,
if (innermost_block == 0 ||
contained_in (block_found,
innermost_block = block_found;
write_exp_elt_opcode (OP_VAR_VALUE);
write_exp_elt_opcode (OP_VAR_VALUE);
else if (is_a_field_of_this)
/* C++: it hangs off of `this'. Must
not inadvertently convert from a method call
if (innermost_block == 0 ||
contained_in (block_found, innermost_block))
innermost_block = block_found;
write_exp_elt_opcode (OP_THIS);
write_exp_elt_opcode (OP_THIS);
write_exp_elt_opcode (STRUCTOP_PTR);
write_exp_elt_opcode (STRUCTOP_PTR);
register char *arg = copy_name ($1);
for (i = 0; i < misc_function_count; i++)
if (!strcmp (misc_function_vector[i].name, arg))
if (i < misc_function_count)
enum misc_function_type mft =
(enum misc_function_type)
misc_function_vector[i].type;
write_exp_elt_opcode (OP_LONG);
write_exp_elt_type (builtin_type_int);
write_exp_elt_longcst ((LONGEST) misc_function_vector[i].address);
write_exp_elt_opcode (OP_LONG);
write_exp_elt_opcode (UNOP_MEMVAL);
if (mft == mf_data || mft == mf_bss)
write_exp_elt_type (builtin_type_int);
write_exp_elt_type (lookup_function_type (builtin_type_int));
write_exp_elt_type (builtin_type_char);
write_exp_elt_opcode (UNOP_MEMVAL);
else if (symtab_list == 0
&& partial_symtab_list == 0)
error ("No symbol table is loaded. Use the \"symbol-file\" command.");
error ("No symbol \"%s\" in current context.",
/* This is where the interesting stuff happens. */
struct type *follow_type = $1;
follow_type = lookup_pointer_type (follow_type);
follow_type = lookup_reference_type (follow_type);
array_size = (int) pop_type ();
follow_type = create_array_type (follow_type,
follow_type = lookup_pointer_type (follow_type);
follow_type = lookup_function_type (follow_type);
{ push_type (tp_pointer); $$ = 0; }
{ push_type (tp_pointer); $$ = $2; }
direct_abs_decl: '(' abs_decl ')'
| direct_abs_decl array_mod
push_type ((enum type_pieces) $2);
push_type ((enum type_pieces) $1);
| direct_abs_decl func_mod
{ push_type (tp_function); }
{ push_type (tp_function); }
| typebase COLONCOLON '*'
{ $$ = lookup_member_type (builtin_type_int, $1); }
| type '(' typebase COLONCOLON '*' ')'
{ $$ = lookup_member_type ($1, $3); }
| type '(' typebase COLONCOLON '*' ')' '(' ')'
{ $$ = lookup_member_type
(lookup_function_type ($1), $3); }
| type '(' typebase COLONCOLON '*' ')' '(' nonempty_typelist ')'
{ $$ = lookup_member_type
(lookup_function_type ($1), $3);
{ $$ = lookup_typename (copy_name ($1),
expression_context_block, 0); }
{ $$ = builtin_type_int; }
{ $$ = builtin_type_long; }
{ $$ = builtin_type_short; }
{ $$ = builtin_type_long; }
| UNSIGNED LONG INT_KEYWORD
{ $$ = builtin_type_unsigned_long; }
{ $$ = builtin_type_short; }
| UNSIGNED SHORT INT_KEYWORD
{ $$ = builtin_type_unsigned_short; }
{ $$ = lookup_struct (copy_name ($2),
expression_context_block); }
{ $$ = lookup_union (copy_name ($2),
expression_context_block); }
{ $$ = lookup_enum (copy_name ($2),
expression_context_block); }
{ $$ = lookup_unsigned_typename (copy_name ($2)); }
{ $$ = builtin_type_unsigned_int; }
{ $$ = lookup_typename (copy_name ($2),
expression_context_block, 0); }
{ $$ = builtin_type_int; }
{ $$ = (struct type **)xmalloc (sizeof (struct type *) * 2);
$$[0] = (struct type *)0;
| nonempty_typelist ',' type
{ int len = sizeof (struct type *) * ++($<ivec>1[0]);
$$ = (struct type **)xrealloc ($1, len);
/* Begin counting arguments for a function call,
saving the data about any containing call. */
register struct funcall *new = (struct funcall *) xmalloc (sizeof (struct funcall));
new->next = funcall_chain;
new->arglist_len = arglist_len;
/* Return the number of arguments in a function call just terminated,
and restore the data for the containing function call. */
register int val = arglist_len;
register struct funcall *call = funcall_chain;
funcall_chain = call->next;
arglist_len = call->arglist_len;
/* Free everything in the funcall chain.
Used when there is an error inside parsing. */
register struct funcall *call, *next;
for (call = funcall_chain; call; call = next)
/* This page contains the functions for adding data to the struct expression
/* Add one element to the end of the expression. */
/* To avoid a bug in the Sun 4 compiler, we pass things that can fit into
a register through here */
union exp_element expelt;
if (expout_ptr >= expout_size)
expout = (struct expression *) xrealloc (expout,
sizeof (struct expression)
+ expout_size * sizeof (union exp_element));
expout->elts[expout_ptr++] = expelt;
write_exp_elt_opcode (expelt)
write_exp_elt_sym (expelt)
write_exp_elt_longcst (expelt)
write_exp_elt_dblcst (expelt)
tmp.doubleconst = expelt;
write_exp_elt_type (expelt)
write_exp_elt_intern (expelt)
struct internalvar *expelt;
tmp.internalvar = expelt;
/* Add a string constant to the end of the expression.
Follow it by its length in bytes, as a separate exp_element. */
register int len = str.length;
= (len + sizeof (union exp_element)) / sizeof (union exp_element);
if (expout_ptr >= expout_size)
expout_size = max (expout_size * 2, expout_ptr + 10);
expout = (struct expression *)
xrealloc (expout, (sizeof (struct expression)
+ (expout_size * sizeof (union exp_element))));
bcopy (str.ptr, (char *) &expout->elts[expout_ptr - lenelt], len);
((char *) &expout->elts[expout_ptr - lenelt])[len] = 0;
write_exp_elt_longcst ((LONGEST) len);
/* During parsing of a C expression, the pointer to the next character
/* Tokens that refer to names do so with explicit pointer and length,
so they can share the storage that lexptr is parsing.
When it is necessary to pass a name to a function that expects
a null-terminated string, the substring is copied out
into a block of storage that namecopy points to.
namecopy is allocated once, guaranteed big enough, for each parsing. */
/* Current depth in parentheses within the expression. */
/* Nonzero means stop parsing on first comma (if not within parentheses). */
static int comma_terminates;
/* Take care of parsing a number (anything that starts with a digit).
Set yylval and return the token type; update lexptr.
LEN is the number of characters in it. */
/*** Needs some error checking for the float case ***/
register char *p = lexptr;
for (c = 0; c < len; c++)
/* It's a float since it contains a point. */
if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2)))
if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
if (c != 'l' && c != 'u')
if (c >= '0' && c <= '9')
if (base == 16 && c >= 'a' && c <= 'f')
else if (len == 0 && c == 'l')
else if (len == 0 && c == 'u')
else if (base == 10 && len != 0 && (c == 'e' || c == 'E'))
/* Scientific notation, where we are unlucky enough not
to have a '.' in the string. */
yylval.dval = atof (lexptr);
err_copy = (char *) alloca (olen + 1);
bcopy (lexptr, err_copy, olen);
error ("Invalid number \"%s\".", err_copy);
static struct token tokentab3[] =
{">>=", ASSIGN_MODIFY, BINOP_RSH},
{"<<=", ASSIGN_MODIFY, BINOP_LSH}
static struct token tokentab2[] =
{"+=", ASSIGN_MODIFY, BINOP_ADD},
{"-=", ASSIGN_MODIFY, BINOP_SUB},
{"*=", ASSIGN_MODIFY, BINOP_MUL},
{"/=", ASSIGN_MODIFY, BINOP_DIV},
{"%=", ASSIGN_MODIFY, BINOP_REM},
{"|=", ASSIGN_MODIFY, BINOP_LOGIOR},
{"&=", ASSIGN_MODIFY, BINOP_LOGAND},
{"^=", ASSIGN_MODIFY, BINOP_LOGXOR},
{"++", INCREMENT, BINOP_END},
{"--", DECREMENT, BINOP_END},
{"->", ARROW, BINOP_END},
{"::", COLONCOLON, BINOP_END},
{"==", EQUAL, BINOP_END},
{"!=", NOTEQUAL, BINOP_END},
/* assign machine-independent names to certain registers
* (unless overridden by the REGISTER_NAMES table)
#define NUM_STD_REGS (sizeof std_regs / sizeof std_regs[0])
/* Read one token, getting characters through lexptr. */
/* See if it is a special token of length 3. */
for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++)
if (!strncmp (tokstart, tokentab3[i].operator, 3))
yylval.opcode = tokentab3[i].opcode;
return tokentab3[i].token;
/* See if it is a special token of length 2. */
for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++)
if (!strncmp (tokstart, tokentab2[i].operator, 2))
yylval.opcode = tokentab2[i].opcode;
return tokentab2[i].token;
c = parse_escape (&lexptr);
error ("Invalid character constant.");
if (comma_terminates && paren_depth == 0)
/* Might be a floating point number. */
if (lexptr[1] >= '0' && lexptr[1] <= '9')
break; /* Falls into number code. */
for (namelen = 1; (c = tokstart[namelen]) != '"'; namelen++)
if (c >= '0' && c <= '9')
if (c >= '0' && c <= '9')
yylval.sval.ptr = tokstart + 1;
yylval.sval.length = namelen - 1;
/* Note: We have already dealt with the case of the token '.'.
if ((c >= '0' && c <= '9') || c == '.')
int got_dot = 0, got_e = 0;
register char *p = tokstart;
int hex = c == '0' && (p[1] == 'x' || p[1] == 'X');
if (!hex && !got_e && (*p == 'e' || *p == 'E'))
else if (!hex && !got_dot && *p == '.')
else if (got_e && (p[-1] == 'e' || p[-1] == 'E')
&& (*p == '-' || *p == '+'))
/* This is the sign of the exponent, not the end of the
else if (!got_dot && !got_e && (*p=='l'||*p=='L')){
else if (!got_dot && !got_e && !hex && (*p=='u'||*p=='U')){
else if (*p < '0' || *p > '9'
&& (!hex || ((*p < 'a' || *p > 'f')
&& (*p < 'A' || *p > 'F'))))
return parse_number (p - tokstart);
if (!(c == '_' || c == '$'
|| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
/* We must have come across a bad character (e.g. ';'). */
error ("Invalid character '%c' in expression.", c);
/* It's a name. See how long it is. */
for (c = tokstart[namelen];
(c == '_' || c == '$' || (c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
/* The token "if" terminates the expression and is NOT
removed from the input stream. */
if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f')
/* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1)
and $$digits (equivalent to $<-digits> if you could type that).
Make token type LAST, and put the number (the digits) in yylval. */
/* Double dollar means negate the number and add -1 as well.
Thus $$ alone means -1. */
if (namelen >= 2 && tokstart[1] == '$')
/* Just dollars (one or two) */
/* Is the rest of the token digits? */
if (!(tokstart[c] >= '0' && tokstart[c] <= '9'))
yylval.lval = atoi (tokstart + 1 + negate);
yylval.lval = - yylval.lval;
/* Handle tokens that refer to machine registers:
$ followed by a register name. */
for (c = 0; c < NUM_REGS; c++)
if (namelen - 1 == strlen (reg_names[c])
&& !strncmp (tokstart + 1, reg_names[c], namelen - 1))
for (c = 0; c < NUM_STD_REGS; c++)
if (namelen - 1 == strlen (std_regs[c].name)
&& !strncmp (tokstart + 1, std_regs[c].name, namelen - 1))
yylval.lval = std_regs[c].regnum;
/* Catch specific keywords. Should be done with a data structure. */
if (!strncmp (tokstart, "unsigned", 8))
if (!strncmp (tokstart, "struct", 6))
if (!strncmp (tokstart, "signed", 6))
if (!strncmp (tokstart, "sizeof", 6))
if (!strncmp (tokstart, "union", 5))
if (!strncmp (tokstart, "short", 5))
if (!strncmp (tokstart, "enum", 4))
if (!strncmp (tokstart, "long", 4))
if (!strncmp (tokstart, "this", 4)
&& lookup_symbol ("$this", expression_context_block,
if (!strncmp (tokstart, "int", 3))
yylval.sval.ptr = tokstart;
yylval.sval.length = namelen;
/* Any other names starting in $ are debugger internal variables. */
yylval.ivar = (struct internalvar *) lookup_internalvar (copy_name (yylval.sval) + 1);
/* Use token-type BLOCKNAME for symbols that happen to be defined as
functions or symtabs. If this is not so, then ...
Use token-type TYPENAME for symbols that happen to be defined
currently as names of types; NAME for other symbols.
The caller is not constrained to care about the distinction. */
char *tmp = copy_name (yylval.sval);
if (lookup_partial_symtab (tmp))
sym = lookup_symbol (tmp, expression_context_block,
if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
if (lookup_typename (copy_name (yylval.sval), expression_context_block, 1))
error ("Invalid syntax in expression.");
/* Return a null-terminated temporary copy of the name
bcopy (token.ptr, namecopy, token.length);
namecopy[token.length] = 0;
/* Reverse an expression from suffix form (in which it is constructed)
to prefix form (in which we can conveniently print or execute it). */
static void prefixify_subexp ();
prefixify_expression (expr)
register struct expression *expr;
register int len = sizeof (struct expression) +
expr->nelts * sizeof (union exp_element);
register struct expression *temp;
register int inpos = expr->nelts, outpos = 0;
temp = (struct expression *) alloca (len);
/* Copy the original expression into temp. */
prefixify_subexp (temp, expr, inpos, outpos);
/* Return the number of exp_elements in the subexpression of EXPR
whose last exp_element is at index ENDPOS - 1 in EXPR. */
length_of_subexp (expr, endpos)
register struct expression *expr;
error ("?error in length_of_subexp");
i = (int) expr->elts[endpos - 1].opcode;
oplen = 4 + ((expr->elts[endpos - 2].longconst
+ sizeof (union exp_element))
/ sizeof (union exp_element));
args = 1 + expr->elts[endpos - 2].longconst;
oplen = 3 + ((expr->elts[endpos - 2].longconst
+ sizeof (union exp_element))
/ sizeof (union exp_element));
case BINOP_ASSIGN_MODIFY:
args = 1 + (i < (int) BINOP_END);
oplen += length_of_subexp (expr, endpos - oplen);
/* Copy the subexpression ending just before index INEND in INEXPR
into OUTEXPR, starting at index OUTBEG.
In the process, convert it from suffix to prefix form. */
prefixify_subexp (inexpr, outexpr, inend, outbeg)
register struct expression *inexpr;
struct expression *outexpr;
/* Compute how long the last operation is (in OPLEN),
and also how many preceding subexpressions serve as
arguments for it (in ARGS). */
opcode = inexpr->elts[inend - 1].opcode;
oplen = 4 + ((inexpr->elts[inend - 2].longconst
+ sizeof (union exp_element))
/ sizeof (union exp_element));
args = 1 + inexpr->elts[inend - 2].longconst;
oplen = 3 + ((inexpr->elts[inend - 2].longconst
+ sizeof (union exp_element))
/ sizeof (union exp_element));
case BINOP_ASSIGN_MODIFY:
args = 1 + ((int) opcode < (int) BINOP_END);
/* Copy the final operator itself, from the end of the input
to the beginning of the output. */
bcopy (&inexpr->elts[inend], &outexpr->elts[outbeg],
oplen * sizeof (union exp_element));
/* Find the lengths of the arg subexpressions. */
arglens = (int *) alloca (args * sizeof (int));
for (i = args - 1; i >= 0; i--)
oplen = length_of_subexp (inexpr, inend);
/* Now copy each subexpression, preserving the order of
the subexpressions, but prefixifying each one.
In this loop, inend starts at the beginning of
the expression this level is working on
and marches forward over the arguments.
outbeg does similarly in the output. */
for (i = 0; i < args; i++)
prefixify_subexp (inexpr, outexpr, inend, outbeg);
/* This page contains the two entry points to this file. */
/* Read a C expression from the string *STRINGPTR points to,
parse it, and return a pointer to a struct expression that we malloc.
Use block BLOCK as the lexical context for variable names;
if BLOCK is zero, use the block of the selected stack frame.
Meanwhile, advance *STRINGPTR to point after the expression,
at the first nonwhite character that is not part of the expression
(possibly a null character).
If COMMA is nonzero, stop if a comma is reached. */
parse_c_1 (stringptr, block, comma)
struct cleanup *old_chain;
comma_terminates = comma;
if (lexptr == 0 || *lexptr == 0)
error_no_arg ("expression to compute");
old_chain = make_cleanup (free_funcalls, 0);
expression_context_block = block ? block : get_selected_block ();
namecopy = (char *) alloca (strlen (lexptr) + 1);
expout = (struct expression *)
xmalloc (sizeof (struct expression)
+ expout_size * sizeof (union exp_element));
make_cleanup (free_current_contents, &expout);
discard_cleanups (old_chain);
expout->nelts = expout_ptr;
expout = (struct expression *)
sizeof (struct expression)
+ expout_ptr * sizeof (union exp_element));
prefixify_expression (expout);
/* Parse STRING as an expression, and complain if this fails
to use up all of the contents of STRING. */
parse_c_expression (string)
register struct expression *exp;
exp = parse_c_1 (&string, 0, 0);
error ("Junk after end of expression.");
if (type_stack_depth == type_stack_size)
type_stack = (enum type_pieces *)
xrealloc (type_stack, type_stack_size * sizeof (enum type_pieces));
type_stack[type_stack_depth++] = tp;
return type_stack[--type_stack_depth];
type_stack = (enum type_pieces *)
xmalloc (type_stack_size * sizeof (enum type_pieces));