1999-04-16 01:33:56 +00:00
/* Parse expressions for GDB.
Copyright ( C ) 1986 , 89 , 90 , 91 , 94 , 1998 Free Software Foundation , Inc .
Modified from expread . y by the Department of Computer Science at the
State University of New York at Buffalo , 1991.
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 2 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 , write to the Free Software
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 .
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 . */
# include "defs.h"
# include "gdb_string.h"
# include <ctype.h>
# include "symtab.h"
# include "gdbtypes.h"
# include "frame.h"
# include "expression.h"
# include "value.h"
# include "command.h"
# include "language.h"
# include "parser-defs.h"
# include "gdbcmd.h"
# include "symfile.h" /* for overlay functions */
1999-04-26 18:23:13 +00:00
# include <ctype.h>
1999-04-16 01:33:56 +00:00
/* 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 ;
static int expressiondebug = 0 ;
extern int hp_som_som_object_present ;
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 FP_REGNUM
{ " fp " , FP_REGNUM } ,
# endif
# ifdef SP_REGNUM
{ " sp " , SP_REGNUM } ,
# endif
# ifdef PS_REGNUM
{ " ps " , PS_REGNUM } ,
# endif
} ;
unsigned num_std_regs = ( sizeof std_regs / sizeof std_regs [ 0 ] ) ;
# endif
/* The generic method for targets to specify how their registers are
named . The mapping can be derived from three sources :
REGISTER_NAME ; std_regs ; or a target specific alias hook . */
int
target_map_name_to_register ( str , len )
char * str ;
int len ;
{
int i ;
/* First try target specific aliases. We try these first because on some
systems standard names can be context dependent ( eg . $ pc on a
multiprocessor can be could be any of several PCs ) . */
# ifdef REGISTER_NAME_ALIAS_HOOK
i = REGISTER_NAME_ALIAS_HOOK ( str , len ) ;
if ( i > = 0 )
return i ;
# endif
/* Search architectural register name space. */
for ( i = 0 ; i < NUM_REGS ; i + + )
if ( REGISTER_NAME ( i ) & & len = = strlen ( REGISTER_NAME ( i ) )
& & STREQN ( str , REGISTER_NAME ( i ) , len ) )
{
return i ;
}
/* Try standard aliases */
for ( i = 0 ; i < num_std_regs ; i + + )
if ( std_regs [ i ] . name & & len = = strlen ( std_regs [ i ] . name )
& & STREQN ( str , std_regs [ i ] . name , len ) )
{
return std_regs [ i ] . regnum ;
}
return - 1 ;
}
/* Begin counting arguments for a function call,
saving the data about any containing call . */
void
start_arglist ( )
{
register struct funcall * new ;
new = ( struct funcall * ) xmalloc ( sizeof ( struct funcall ) ) ;
new - > next = funcall_chain ;
new - > arglist_len = arglist_len ;
arglist_len = 0 ;
funcall_chain = new ;
}
/* Return the number of arguments in a function call just terminated,
and restore the data for the containing function call . */
int
end_arglist ( )
{
register int val = arglist_len ;
register struct funcall * call = funcall_chain ;
funcall_chain = call - > next ;
arglist_len = call - > arglist_len ;
free ( ( PTR ) call ) ;
return val ;
}
/* Free everything in the funcall chain.
Used when there is an error inside parsing . */
static void
free_funcalls ( )
{
register struct funcall * call , * next ;
for ( call = funcall_chain ; call ; call = next )
{
next = call - > next ;
free ( ( PTR ) call ) ;
}
}
/* This page contains the functions for adding data to the struct expression
being constructed . */
/* 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 */
void
write_exp_elt ( expelt )
union exp_element expelt ;
{
if ( expout_ptr > = expout_size )
{
expout_size * = 2 ;
expout = ( struct expression * )
xrealloc ( ( char * ) expout , sizeof ( struct expression )
+ EXP_ELEM_TO_BYTES ( expout_size ) ) ;
}
expout - > elts [ expout_ptr + + ] = expelt ;
}
void
write_exp_elt_opcode ( expelt )
enum exp_opcode expelt ;
{
union exp_element tmp ;
tmp . opcode = expelt ;
write_exp_elt ( tmp ) ;
}
void
write_exp_elt_sym ( expelt )
struct symbol * expelt ;
{
union exp_element tmp ;
tmp . symbol = expelt ;
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 ;
{
union exp_element tmp ;
tmp . longconst = expelt ;
write_exp_elt ( tmp ) ;
}
void
write_exp_elt_dblcst ( expelt )
DOUBLEST expelt ;
{
union exp_element tmp ;
tmp . doubleconst = expelt ;
write_exp_elt ( tmp ) ;
}
void
write_exp_elt_type ( expelt )
struct type * expelt ;
{
union exp_element tmp ;
tmp . type = expelt ;
write_exp_elt ( tmp ) ;
}
void
write_exp_elt_intern ( expelt )
struct internalvar * expelt ;
{
union exp_element tmp ;
tmp . internalvar = expelt ;
write_exp_elt ( tmp ) ;
}
/* Add a string constant to the end of the expression.
String constants are stored by first writing an expression element
that contains the length of the string , then stuffing the string
constant itself into however many expression elements are needed
to hold it , and then writing another expression element that contains
the length of the string . I . E . an expression element at each end of
the string records the string length , so you can skip over the
expression elements containing the actual string bytes from either
end of the string . Note that this also allows gdb to handle
strings with embedded null bytes , as is required for some languages .
Don ' t be fooled by the fact that the string is null byte terminated ,
this is strictly for the convenience of debugging gdb itself . Gdb
Gdb does not depend up the string being null terminated , since the
actual length is recorded in expression elements at each end of the
string . The null byte is taken into consideration when computing how
many expression elements are required to hold the string constant , of
course . */
void
write_exp_string ( str )
struct stoken str ;
{
register int len = str . length ;
register int lenelt ;
register char * strdata ;
/* Compute the number of expression elements required to hold the string
( including a null byte terminator ) , along with one expression element
at each end to record the actual string length ( not including the
null byte terminator ) . */
lenelt = 2 + BYTES_TO_EXP_ELEM ( len + 1 ) ;
/* Ensure that we have enough available expression elements to store
everything . */
if ( ( expout_ptr + lenelt ) > = expout_size )
{
expout_size = max ( expout_size * 2 , expout_ptr + lenelt + 10 ) ;
expout = ( struct expression * )
xrealloc ( ( char * ) expout , ( sizeof ( struct expression )
+ EXP_ELEM_TO_BYTES ( expout_size ) ) ) ;
}
/* Write the leading length expression element (which advances the current
expression element index ) , then write the string constant followed by a
terminating null byte , and then write the trailing length expression
element . */
write_exp_elt_longcst ( ( LONGEST ) len ) ;
strdata = ( char * ) & expout - > elts [ expout_ptr ] ;
memcpy ( strdata , str . ptr , len ) ;
* ( strdata + len ) = ' \0 ' ;
expout_ptr + = lenelt - 2 ;
write_exp_elt_longcst ( ( LONGEST ) len ) ;
}
/* Add a bitstring constant to the end of the expression.
Bitstring constants are stored by first writing an expression element
that contains the length of the bitstring ( in bits ) , then stuffing the
bitstring constant itself into however many expression elements are
needed to hold it , and then writing another expression element that
contains the length of the bitstring . I . E . an expression element at
each end of the bitstring records the bitstring length , so you can skip
over the expression elements containing the actual bitstring bytes from
either end of the bitstring . */
void
write_exp_bitstring ( str )
struct stoken str ;
{
register int bits = str . length ; /* length in bits */
register int len = ( bits + HOST_CHAR_BIT - 1 ) / HOST_CHAR_BIT ;
register int lenelt ;
register char * strdata ;
/* Compute the number of expression elements required to hold the bitstring,
along with one expression element at each end to record the actual
bitstring length in bits . */
lenelt = 2 + BYTES_TO_EXP_ELEM ( len ) ;
/* Ensure that we have enough available expression elements to store
everything . */
if ( ( expout_ptr + lenelt ) > = expout_size )
{
expout_size = max ( expout_size * 2 , expout_ptr + lenelt + 10 ) ;
expout = ( struct expression * )
xrealloc ( ( char * ) expout , ( sizeof ( struct expression )
+ EXP_ELEM_TO_BYTES ( expout_size ) ) ) ;
}
/* Write the leading length expression element (which advances the current
expression element index ) , then write the bitstring constant , and then
write the trailing length expression element . */
write_exp_elt_longcst ( ( LONGEST ) bits ) ;
strdata = ( char * ) & expout - > elts [ expout_ptr ] ;
memcpy ( strdata , str . ptr , len ) ;
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 ;
{
CORE_ADDR addr ;
write_exp_elt_opcode ( OP_LONG ) ;
write_exp_elt_type ( lookup_pointer_type ( builtin_type_void ) ) ;
addr = SYMBOL_VALUE_ADDRESS ( msymbol ) ;
if ( overlay_debugging )
addr = symbol_overlayed_address ( addr , SYMBOL_BFD_SECTION ( msymbol ) ) ;
write_exp_elt_longcst ( ( LONGEST ) addr ) ;
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 ) ;
}
/* 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 ) . */
struct symbol * sym = NULL ;
struct minimal_symbol * msym = NULL ;
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 = target_map_name_to_register ( str . ptr + 1 , str . length - 1 ) ;
if ( i > = 0 )
goto handle_register ;
/* On HP-UX, certain system routines (millicode) have names beginning
with $ or $ $ , e . g . $ $ dyncall , which handles inter - space procedure
calls on PA - RISC . Check for those , first . */
sym = lookup_symbol ( copy_name ( str ) , ( struct block * ) NULL ,
VAR_NAMESPACE , ( int * ) NULL , ( struct symtab * * ) NULL ) ;
if ( sym )
{
write_exp_elt_opcode ( OP_VAR_VALUE ) ;
write_exp_elt_block ( block_found ) ; /* set by lookup_symbol */
write_exp_elt_sym ( sym ) ;
write_exp_elt_opcode ( OP_VAR_VALUE ) ;
return ;
}
msym = lookup_minimal_symbol ( copy_name ( str ) , NULL , NULL ) ;
if ( msym )
{
write_exp_msymbol ( msym ,
lookup_function_type ( builtin_type_int ) ,
builtin_type_int ) ;
return ;
}
/* 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 ;
}
/* Parse a string that is possibly a namespace / nested class
specification , i . e . , something of the form A : : B : : C : : x . Input
( NAME ) is the entire string ; LEN is the current valid length ; the
output is a string , TOKEN , which points to the largest recognized
prefix which is a series of namespaces or classes . CLASS_PREFIX is
another output , which records whether a nested class spec was
recognized ( = 1 ) or a fully qualified variable name was found ( =
0 ) . ARGPTR is side - effected ( if non - NULL ) to point to beyond the
string recognized and consumed by this routine .
The return value is a pointer to the symbol for the base class or
variable if found , or NULL if not found . Callers must check this
first - - if NULL , the outputs may not be correct .
This function is used c - exp . y . This is used specifically to get
around HP aCC ( and possibly other compilers ) , which insists on
generating names with embedded colons for namespace or nested class
members .
( Argument LEN is currently unused . 1997 - 08 - 27 )
Callers must free memory allocated for the output string TOKEN . */
static const char coloncolon [ 2 ] = { ' : ' , ' : ' } ;
struct symbol *
parse_nested_classes_for_hpacc ( name , len , token , class_prefix , argptr )
char * name ;
int len ;
char * * token ;
int * class_prefix ;
char * * argptr ;
{
/* Comment below comes from decode_line_1 which has very similar
code , which is called for " break " command parsing . */
/* We have what looks like a class or namespace
scope specification ( A : : B ) , possibly with many
levels of namespaces or classes ( A : : B : : C : : D ) .
Some versions of the HP ANSI C + + compiler ( as also possibly
other compilers ) generate class / function / member names with
embedded double - colons if they are inside namespaces . To
handle this , we loop a few times , considering larger and
larger prefixes of the string as though they were single
symbols . So , if the initially supplied string is
A : : B : : C : : D : : foo , we have to look up " A " , then " A::B " ,
then " A::B::C " , then " A::B::C::D " , and finally
" A::B::C::D::foo " as single , monolithic symbols , because
A , B , C or D may be namespaces .
Note that namespaces can nest only inside other
namespaces , and not inside classes . So we need only
consider * prefixes * of the string ; there is no need to look up
" B::C " separately as a symbol in the previous example . */
register char * p ;
char * start , * end ;
char * prefix = NULL ;
char * tmp ;
struct symbol * sym_class = NULL ;
struct symbol * sym_var = NULL ;
struct type * t ;
register int i ;
int colons_found = 0 ;
int prefix_len = 0 ;
int done = 0 ;
char * q ;
/* Check for HP-compiled executable -- in other cases
return NULL , and caller must default to standard GDB
behaviour . */
if ( ! hp_som_som_object_present )
return ( struct symbol * ) NULL ;
p = name ;
/* Skip over whitespace and possible global "::" */
while ( * p & & ( * p = = ' ' | | * p = = ' \t ' ) ) p + + ;
if ( p [ 0 ] = = ' : ' & & p [ 1 ] = = ' : ' )
p + = 2 ;
while ( * p & & ( * p = = ' ' | | * p = = ' \t ' ) ) p + + ;
while ( 1 )
{
/* Get to the end of the next namespace or class spec. */
/* If we're looking at some non-token, fail immediately */
start = p ;
if ( ! ( isalpha ( * p ) | | * p = = ' $ ' | | * p = = ' _ ' ) )
return ( struct symbol * ) NULL ;
p + + ;
while ( * p & & ( isalnum ( * p ) | | * p = = ' $ ' | | * p = = ' _ ' ) ) p + + ;
if ( * p = = ' < ' )
{
/* If we have the start of a template specification,
scan right ahead to its end */
q = find_template_name_end ( p ) ;
if ( q )
p = q ;
}
end = p ;
/* Skip over "::" and whitespace for next time around */
while ( * p & & ( * p = = ' ' | | * p = = ' \t ' ) ) p + + ;
if ( p [ 0 ] = = ' : ' & & p [ 1 ] = = ' : ' )
p + = 2 ;
while ( * p & & ( * p = = ' ' | | * p = = ' \t ' ) ) p + + ;
/* Done with tokens? */
if ( ! * p | | ! ( isalpha ( * p ) | | * p = = ' $ ' | | * p = = ' _ ' ) )
done = 1 ;
tmp = ( char * ) alloca ( prefix_len + end - start + 3 ) ;
if ( prefix )
{
memcpy ( tmp , prefix , prefix_len ) ;
memcpy ( tmp + prefix_len , coloncolon , 2 ) ;
memcpy ( tmp + prefix_len + 2 , start , end - start ) ;
tmp [ prefix_len + 2 + end - start ] = ' \000 ' ;
}
else
{
memcpy ( tmp , start , end - start ) ;
tmp [ end - start ] = ' \000 ' ;
}
prefix = tmp ;
prefix_len = strlen ( prefix ) ;
#if 0 /* DEBUGGING */
printf ( " Searching for nested class spec: Prefix is %s \n " , prefix ) ;
# endif
/* See if the prefix we have now is something we know about */
if ( ! done )
{
/* More tokens to process, so this must be a class/namespace */
sym_class = lookup_symbol ( prefix , 0 , STRUCT_NAMESPACE ,
0 , ( struct symtab * * ) NULL ) ;
}
else
{
/* No more tokens, so try as a variable first */
sym_var = lookup_symbol ( prefix , 0 , VAR_NAMESPACE ,
0 , ( struct symtab * * ) NULL ) ;
/* If failed, try as class/namespace */
if ( ! sym_var )
sym_class = lookup_symbol ( prefix , 0 , STRUCT_NAMESPACE ,
0 , ( struct symtab * * ) NULL ) ;
}
if ( sym_var | |
( sym_class & &
( t = check_typedef ( SYMBOL_TYPE ( sym_class ) ) ,
( TYPE_CODE ( t ) = = TYPE_CODE_STRUCT
| | TYPE_CODE ( t ) = = TYPE_CODE_UNION ) ) ) )
{
/* We found a valid token */
* token = ( char * ) xmalloc ( prefix_len + 1 ) ;
memcpy ( * token , prefix , prefix_len ) ;
( * token ) [ prefix_len ] = ' \000 ' ;
break ;
}
/* No variable or class/namespace found, no more tokens */
if ( done )
return ( struct symbol * ) NULL ;
}
/* Out of loop, so we must have found a valid token */
if ( sym_var )
* class_prefix = 0 ;
else
* class_prefix = 1 ;
if ( argptr )
* argptr = done ? p : end ;
#if 0 /* DEBUGGING */
printf ( " Searching for nested class spec: Token is %s, class_prefix %d \n " , * token , * class_prefix ) ;
# endif
return sym_var ? sym_var : sym_class ; /* found */
}
char *
find_template_name_end ( p )
char * p ;
{
int depth = 1 ;
int just_seen_right = 0 ;
int just_seen_colon = 0 ;
int just_seen_space = 0 ;
if ( ! p | | ( * p ! = ' < ' ) )
return 0 ;
while ( * + + p )
{
switch ( * p )
{
case ' \' ' : case ' \" ' :
case ' { ' : case ' } ' :
/* In future, may want to allow these?? */
return 0 ;
case ' < ' :
depth + + ; /* start nested template */
if ( just_seen_colon | | just_seen_right | | just_seen_space )
return 0 ; /* but not after : or :: or > or space */
break ;
case ' > ' :
if ( just_seen_colon | | just_seen_right )
return 0 ; /* end a (nested?) template */
just_seen_right = 1 ; /* but not after : or :: */
if ( - - depth = = 0 ) /* also disallow >>, insist on > > */
return + + p ; /* if outermost ended, return */
break ;
case ' : ' :
if ( just_seen_space | | ( just_seen_colon > 1 ) )
return 0 ; /* nested class spec coming up */
just_seen_colon + + ; /* we allow :: but not :::: */
break ;
case ' ' :
break ;
default :
if ( ! ( ( * p > = ' a ' & & * p < = ' z ' ) | | /* allow token chars */
( * p > = ' A ' & & * p < = ' Z ' ) | |
( * p > = ' 0 ' & & * p < = ' 9 ' ) | |
( * p = = ' _ ' ) | | ( * p = = ' , ' ) | | /* commas for template args */
( * p = = ' & ' ) | | ( * p = = ' * ' ) | | /* pointer and ref types */
( * p = = ' ( ' ) | | ( * p = = ' ) ' ) | | /* function types */
( * p = = ' [ ' ) | | ( * p = = ' ] ' ) ) ) /* array types */
return 0 ;
}
if ( * p ! = ' ' )
just_seen_space = 0 ;
if ( * p ! = ' : ' )
just_seen_colon = 0 ;
if ( * p ! = ' > ' )
just_seen_right = 0 ;
}
return 0 ;
}
/* Return a null-terminated temporary copy of the name
of a string token . */
char *
copy_name ( token )
struct stoken token ;
{
memcpy ( namecopy , token . ptr , token . length ) ;
namecopy [ token . length ] = 0 ;
return namecopy ;
}
/* 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_expression ( expr )
register struct expression * expr ;
{
register int len =
sizeof ( struct expression ) + EXP_ELEM_TO_BYTES ( expr - > nelts ) ;
register struct expression * temp ;
register int inpos = expr - > nelts , outpos = 0 ;
temp = ( struct expression * ) alloca ( len ) ;
/* Copy the original expression into temp. */
memcpy ( temp , expr , len ) ;
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 . */
int
length_of_subexp ( expr , endpos )
register struct expression * expr ;
register int endpos ;
{
register int oplen = 1 ;
register int args = 0 ;
register int i ;
if ( endpos < 1 )
error ( " ?error in length_of_subexp " ) ;
i = ( int ) expr - > elts [ endpos - 1 ] . opcode ;
switch ( i )
{
/* C++ */
case OP_SCOPE :
oplen = longest_to_int ( expr - > elts [ endpos - 2 ] . longconst ) ;
oplen = 5 + BYTES_TO_EXP_ELEM ( oplen + 1 ) ;
break ;
case OP_LONG :
case OP_DOUBLE :
case OP_VAR_VALUE :
oplen = 4 ;
break ;
case OP_TYPE :
case OP_BOOL :
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 ;
case UNOP_MAX :
case UNOP_MIN :
oplen = 3 ;
break ;
case BINOP_VAL :
case UNOP_CAST :
case UNOP_MEMVAL :
oplen = 3 ;
args = 1 ;
break ;
case UNOP_ABS :
case UNOP_CAP :
case UNOP_CHR :
case UNOP_FLOAT :
case UNOP_HIGH :
case UNOP_ODD :
case UNOP_ORD :
case UNOP_TRUNC :
oplen = 1 ;
args = 1 ;
break ;
case OP_LABELED :
case STRUCTOP_STRUCT :
case STRUCTOP_PTR :
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 ;
case OP_BITSTRING :
oplen = longest_to_int ( expr - > elts [ endpos - 2 ] . longconst ) ;
oplen = ( oplen + HOST_CHAR_BIT - 1 ) / HOST_CHAR_BIT ;
oplen = 4 + BYTES_TO_EXP_ELEM ( oplen ) ;
break ;
case OP_ARRAY :
oplen = 4 ;
args = longest_to_int ( expr - > elts [ endpos - 2 ] . longconst ) ;
args - = longest_to_int ( expr - > elts [ endpos - 3 ] . longconst ) ;
args + = 1 ;
break ;
case TERNOP_COND :
case TERNOP_SLICE :
case TERNOP_SLICE_COUNT :
args = 3 ;
break ;
/* Modula-2 */
case MULTI_SUBSCRIPT :
oplen = 3 ;
args = 1 + longest_to_int ( expr - > elts [ endpos - 2 ] . longconst ) ;
break ;
case BINOP_ASSIGN_MODIFY :
oplen = 3 ;
args = 2 ;
break ;
/* C++ */
case OP_THIS :
oplen = 2 ;
break ;
default :
args = 1 + ( i < ( int ) BINOP_END ) ;
}
while ( args > 0 )
{
oplen + = length_of_subexp ( expr , endpos - oplen ) ;
args - - ;
}
return 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 . */
static void
prefixify_subexp ( inexpr , outexpr , inend , outbeg )
register struct expression * inexpr ;
struct expression * outexpr ;
register int inend ;
int outbeg ;
{
register int oplen = 1 ;
register int args = 0 ;
register int i ;
int * arglens ;
enum exp_opcode opcode ;
/* 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 ;
switch ( opcode )
{
/* C++ */
case OP_SCOPE :
oplen = longest_to_int ( inexpr - > elts [ inend - 2 ] . longconst ) ;
oplen = 5 + BYTES_TO_EXP_ELEM ( oplen + 1 ) ;
break ;
case OP_LONG :
case OP_DOUBLE :
case OP_VAR_VALUE :
oplen = 4 ;
break ;
case OP_TYPE :
case OP_BOOL :
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 ;
case UNOP_MIN :
case UNOP_MAX :
oplen = 3 ;
break ;
case UNOP_CAST :
case UNOP_MEMVAL :
oplen = 3 ;
args = 1 ;
break ;
case UNOP_ABS :
case UNOP_CAP :
case UNOP_CHR :
case UNOP_FLOAT :
case UNOP_HIGH :
case UNOP_ODD :
case UNOP_ORD :
case UNOP_TRUNC :
oplen = 1 ;
args = 1 ;
break ;
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 ;
case OP_BITSTRING :
oplen = longest_to_int ( inexpr - > elts [ inend - 2 ] . longconst ) ;
oplen = ( oplen + HOST_CHAR_BIT - 1 ) / HOST_CHAR_BIT ;
oplen = 4 + BYTES_TO_EXP_ELEM ( oplen ) ;
break ;
case OP_ARRAY :
oplen = 4 ;
args = longest_to_int ( inexpr - > elts [ inend - 2 ] . longconst ) ;
args - = longest_to_int ( inexpr - > elts [ inend - 3 ] . longconst ) ;
args + = 1 ;
break ;
case TERNOP_COND :
case TERNOP_SLICE :
case TERNOP_SLICE_COUNT :
args = 3 ;
break ;
case BINOP_ASSIGN_MODIFY :
oplen = 3 ;
args = 2 ;
break ;
/* Modula-2 */
case MULTI_SUBSCRIPT :
oplen = 3 ;
args = 1 + longest_to_int ( inexpr - > elts [ inend - 2 ] . longconst ) ;
break ;
/* C++ */
case OP_THIS :
oplen = 2 ;
break ;
default :
args = 1 + ( ( int ) opcode < ( int ) BINOP_END ) ;
}
/* Copy the final operator itself, from the end of the input
to the beginning of the output . */
inend - = oplen ;
memcpy ( & outexpr - > elts [ outbeg ] , & inexpr - > elts [ inend ] ,
EXP_ELEM_TO_BYTES ( oplen ) ) ;
outbeg + = oplen ;
/* 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 ) ;
arglens [ i ] = oplen ;
inend - = oplen ;
}
/* 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 + + )
{
oplen = arglens [ i ] ;
inend + = oplen ;
prefixify_subexp ( inexpr , outexpr , inend , outbeg ) ;
outbeg + = oplen ;
}
}
/* This page contains the two entry points to this file. */
/* Read an 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 . */
struct expression *
parse_exp_1 ( stringptr , block , comma )
char * * stringptr ;
struct block * block ;
int comma ;
{
struct cleanup * old_chain ;
lexptr = * stringptr ;
paren_depth = 0 ;
type_stack_depth = 0 ;
comma_terminates = comma ;
if ( lexptr = = 0 | | * lexptr = = 0 )
error_no_arg ( " expression to compute " ) ;
old_chain = make_cleanup ( ( make_cleanup_func ) free_funcalls , 0 ) ;
funcall_chain = 0 ;
expression_context_block = block ? block : get_selected_block ( ) ;
namecopy = ( char * ) alloca ( strlen ( lexptr ) + 1 ) ;
expout_size = 10 ;
expout_ptr = 0 ;
expout = ( struct expression * )
xmalloc ( sizeof ( struct expression ) + EXP_ELEM_TO_BYTES ( expout_size ) ) ;
expout - > language_defn = current_language ;
make_cleanup ( ( make_cleanup_func ) free_current_contents , & expout ) ;
if ( current_language - > la_parser ( ) )
current_language - > la_error ( NULL ) ;
discard_cleanups ( old_chain ) ;
/* Record the actual number of expression elements, and then
reallocate the expression memory so that we free up any
excess elements . */
expout - > nelts = expout_ptr ;
expout = ( struct expression * )
xrealloc ( ( char * ) expout ,
sizeof ( struct expression ) + EXP_ELEM_TO_BYTES ( expout_ptr ) ) ; ;
/* Convert expression from postfix form as generated by yacc
parser , to a prefix form . */
if ( expressiondebug )
dump_prefix_expression ( expout , gdb_stdout ,
" before conversion to prefix form " ) ;
prefixify_expression ( expout ) ;
if ( expressiondebug )
dump_postfix_expression ( expout , gdb_stdout ,
" after conversion to prefix form " ) ;
* stringptr = lexptr ;
return expout ;
}
/* Parse STRING as an expression, and complain if this fails
to use up all of the contents of STRING . */
struct expression *
parse_expression ( string )
char * string ;
{
register struct expression * exp ;
exp = parse_exp_1 ( & string , 0 , 0 ) ;
if ( * string )
error ( " Junk after end of expression. " ) ;
return exp ;
}
/* 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 )
enum type_pieces tp ;
{
if ( type_stack_depth = = type_stack_size )
{
type_stack_size * = 2 ;
type_stack = ( union type_stack_elt * )
xrealloc ( ( char * ) type_stack , type_stack_size * sizeof ( * type_stack ) ) ;
}
type_stack [ type_stack_depth + + ] . piece = tp ;
}
void
push_type_int ( n )
int n ;
{
if ( type_stack_depth = = type_stack_size )
{
type_stack_size * = 2 ;
type_stack = ( union type_stack_elt * )
xrealloc ( ( char * ) type_stack , type_stack_size * sizeof ( * type_stack ) ) ;
}
type_stack [ type_stack_depth + + ] . int_val = n ;
}
enum type_pieces
pop_type ( )
{
if ( type_stack_depth )
return type_stack [ - - type_stack_depth ] . piece ;
return tp_end ;
}
int
pop_type_int ( )
{
if ( type_stack_depth )
return type_stack [ - - type_stack_depth ] . int_val ;
/* "Can't happen". */
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 ;
}
void
_initialize_parse ( )
{
type_stack_size = 80 ;
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 ) ;
add_show_from_set (
add_set_cmd ( " expressiondebug " , class_maintenance , var_zinteger ,
( char * ) & expressiondebug ,
" Set expression debugging. \n \
When non - zero , the internal representation of expressions will be printed . " ,
& setlist ) ,
& showlist ) ;
}