| /* YACC parser for C expressions, for GDB. | 
 |    Copyright 1986, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, | 
 |    1998, 1999, 2000 | 
 |    Free Software Foundation, Inc. | 
 |  | 
 | 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 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. | 
 |  | 
 |    Note that malloc's and realloc's in this file are transformed to | 
 |    xmalloc and xrealloc respectively by the same sed command in the | 
 |    makefile that remaps any other malloc/realloc inserted by the parser | 
 |    generator.  Doing this with #defines and trying to control the interaction | 
 |    with include files (<malloc.h> and <stdlib.h> for example) just became | 
 |    too messy, particularly when such includes can be inserted at random | 
 |    times by the parser generator.  */ | 
 |     | 
 | %{ | 
 |  | 
 | #include "defs.h" | 
 | #include "gdb_string.h" | 
 | #include <ctype.h> | 
 | #include "expression.h" | 
 | #include "value.h" | 
 | #include "parser-defs.h" | 
 | #include "language.h" | 
 | #include "c-lang.h" | 
 | #include "bfd.h" /* Required by objfiles.h.  */ | 
 | #include "symfile.h" /* Required by objfiles.h.  */ | 
 | #include "objfiles.h" /* For have_full_symbols and have_partial_symbols */ | 
 | #include "charset.h" | 
 |  | 
 | /* Flag indicating we're dealing with HP-compiled objects */  | 
 | extern int hp_som_som_object_present; | 
 |  | 
 | /* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc), | 
 |    as well as gratuitiously global symbol names, so we can have multiple | 
 |    yacc generated parsers in gdb.  Note that these are only the variables | 
 |    produced by yacc.  If other parser generators (bison, byacc, etc) produce | 
 |    additional global names that conflict at link time, then those parser | 
 |    generators need to be fixed instead of adding those names to this list. */ | 
 |  | 
 | #define	yymaxdepth c_maxdepth | 
 | #define	yyparse	c_parse | 
 | #define	yylex	c_lex | 
 | #define	yyerror	c_error | 
 | #define	yylval	c_lval | 
 | #define	yychar	c_char | 
 | #define	yydebug	c_debug | 
 | #define	yypact	c_pact	 | 
 | #define	yyr1	c_r1			 | 
 | #define	yyr2	c_r2			 | 
 | #define	yydef	c_def		 | 
 | #define	yychk	c_chk		 | 
 | #define	yypgo	c_pgo		 | 
 | #define	yyact	c_act		 | 
 | #define	yyexca	c_exca | 
 | #define yyerrflag c_errflag | 
 | #define yynerrs	c_nerrs | 
 | #define	yyps	c_ps | 
 | #define	yypv	c_pv | 
 | #define	yys	c_s | 
 | #define	yy_yys	c_yys | 
 | #define	yystate	c_state | 
 | #define	yytmp	c_tmp | 
 | #define	yyv	c_v | 
 | #define	yy_yyv	c_yyv | 
 | #define	yyval	c_val | 
 | #define	yylloc	c_lloc | 
 | #define yyreds	c_reds		/* With YYDEBUG defined */ | 
 | #define yytoks	c_toks		/* With YYDEBUG defined */ | 
 | #define yyname	c_name		/* With YYDEBUG defined */ | 
 | #define yyrule	c_rule		/* With YYDEBUG defined */ | 
 | #define yylhs	c_yylhs | 
 | #define yylen	c_yylen | 
 | #define yydefred c_yydefred | 
 | #define yydgoto	c_yydgoto | 
 | #define yysindex c_yysindex | 
 | #define yyrindex c_yyrindex | 
 | #define yygindex c_yygindex | 
 | #define yytable	 c_yytable | 
 | #define yycheck	 c_yycheck | 
 |  | 
 | #ifndef YYDEBUG | 
 | #define	YYDEBUG 1		/* Default to yydebug support */ | 
 | #endif | 
 |  | 
 | #define YYFPRINTF parser_fprintf | 
 |  | 
 | int yyparse (void); | 
 |  | 
 | static int yylex (void); | 
 |  | 
 | void yyerror (char *); | 
 |  | 
 | %} | 
 |  | 
 | /* 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.  */ | 
 |  | 
 | %union | 
 |   { | 
 |     LONGEST lval; | 
 |     struct { | 
 |       LONGEST val; | 
 |       struct type *type; | 
 |     } typed_val_int; | 
 |     struct { | 
 |       DOUBLEST dval; | 
 |       struct type *type; | 
 |     } typed_val_float; | 
 |     struct symbol *sym; | 
 |     struct type *tval; | 
 |     struct stoken sval; | 
 |     struct ttype tsym; | 
 |     struct symtoken ssym; | 
 |     int voidval; | 
 |     struct block *bval; | 
 |     enum exp_opcode opcode; | 
 |     struct internalvar *ivar; | 
 |  | 
 |     struct type **tvec; | 
 |     int *ivec; | 
 |   } | 
 |  | 
 | %{ | 
 | /* YYSTYPE gets defined by %union */ | 
 | static int parse_number (char *, int, int, YYSTYPE *); | 
 | %} | 
 |  | 
 | %type <voidval> exp exp1 type_exp start variable qualified_name lcurly | 
 | %type <lval> rcurly | 
 | %type <tval> type typebase | 
 | %type <tvec> nonempty_typelist | 
 | /* %type <bval> block */ | 
 |  | 
 | /* Fancy type parsing.  */ | 
 | %type <voidval> func_mod direct_abs_decl abs_decl | 
 | %type <tval> ptype | 
 | %type <lval> array_mod | 
 |  | 
 | %token <typed_val_int> INT | 
 | %token <typed_val_float> FLOAT | 
 |  | 
 | /* 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> STRING | 
 | %token <ssym> NAME /* BLOCKNAME defined below to give it higher precedence. */ | 
 | %token <tsym> TYPENAME | 
 | %type <sval> name | 
 | %type <ssym> name_not_typename | 
 | %type <tsym> typename | 
 |  | 
 | /* A NAME_OR_INT is a symbol which is not known in the symbol table, | 
 |    but which would parse as a valid number in the current input radix. | 
 |    E.g. "c" when input_radix==16.  Depending on the parse, it will be | 
 |    turned into a name or into a number.  */ | 
 |  | 
 | %token <ssym> NAME_OR_INT  | 
 |  | 
 | %token STRUCT CLASS UNION ENUM SIZEOF UNSIGNED COLONCOLON | 
 | %token TEMPLATE | 
 | %token ERROR | 
 |  | 
 | /* Special type cases, put in to allow the parser to distinguish different | 
 |    legal basetypes.  */ | 
 | %token SIGNED_KEYWORD LONG SHORT INT_KEYWORD CONST_KEYWORD VOLATILE_KEYWORD DOUBLE_KEYWORD | 
 |  | 
 | %token <voidval> VARIABLE | 
 |  | 
 | %token <opcode> ASSIGN_MODIFY | 
 |  | 
 | /* C++ */ | 
 | %token TRUEKEYWORD | 
 | %token FALSEKEYWORD | 
 |  | 
 |  | 
 | %left ',' | 
 | %left ABOVE_COMMA | 
 | %right '=' ASSIGN_MODIFY | 
 | %right '?' | 
 | %left OROR | 
 | %left ANDAND | 
 | %left '|' | 
 | %left '^' | 
 | %left '&' | 
 | %left EQUAL NOTEQUAL | 
 | %left '<' '>' LEQ GEQ | 
 | %left LSH RSH | 
 | %left '@' | 
 | %left '+' '-' | 
 | %left '*' '/' '%' | 
 | %right UNARY INCREMENT DECREMENT | 
 | %right ARROW '.' '[' '(' | 
 | %token <ssym> BLOCKNAME  | 
 | %token <bval> FILENAME | 
 | %type <bval> block | 
 | %left COLONCOLON | 
 |  | 
 |  | 
 | %% | 
 |  | 
 | start   :	exp1 | 
 | 	|	type_exp | 
 | 	; | 
 |  | 
 | type_exp:	type | 
 | 			{ write_exp_elt_opcode(OP_TYPE); | 
 | 			  write_exp_elt_type($1); | 
 | 			  write_exp_elt_opcode(OP_TYPE);} | 
 | 	; | 
 |  | 
 | /* Expressions, including the comma operator.  */ | 
 | exp1	:	exp | 
 | 	|	exp1 ',' exp | 
 | 			{ 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_LOGICAL_NOT); } | 
 | 	; | 
 |  | 
 | exp	:	'~' exp    %prec UNARY | 
 | 			{ write_exp_elt_opcode (UNOP_COMPLEMENT); } | 
 | 	; | 
 |  | 
 | 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); } | 
 | 	; | 
 |  | 
 | exp	:	exp ARROW name | 
 | 			{ write_exp_elt_opcode (STRUCTOP_PTR); | 
 | 			  write_exp_string ($3); | 
 | 			  write_exp_elt_opcode (STRUCTOP_PTR); } | 
 | 	; | 
 |  | 
 | exp	:	exp ARROW qualified_name | 
 | 			{ /* exp->type::name becomes exp->*(&type::name) */ | 
 | 			  /* Note: this doesn't work if name is a | 
 | 			     static member!  FIXME */ | 
 | 			  write_exp_elt_opcode (UNOP_ADDR); | 
 | 			  write_exp_elt_opcode (STRUCTOP_MPTR); } | 
 | 	; | 
 |  | 
 | exp	:	exp ARROW '*' exp | 
 | 			{ write_exp_elt_opcode (STRUCTOP_MPTR); } | 
 | 	; | 
 |  | 
 | exp	:	exp '.' name | 
 | 			{ write_exp_elt_opcode (STRUCTOP_STRUCT); | 
 | 			  write_exp_string ($3); | 
 | 			  write_exp_elt_opcode (STRUCTOP_STRUCT); } | 
 | 	; | 
 |  | 
 | exp	:	exp '.' qualified_name | 
 | 			{ /* exp.type::name becomes exp.*(&type::name) */ | 
 | 			  /* Note: this doesn't work if name is a | 
 | 			     static member!  FIXME */ | 
 | 			  write_exp_elt_opcode (UNOP_ADDR); | 
 | 			  write_exp_elt_opcode (STRUCTOP_MEMBER); } | 
 | 	; | 
 |  | 
 | exp	:	exp '.' '*' exp | 
 | 			{ write_exp_elt_opcode (STRUCTOP_MEMBER); } | 
 | 	; | 
 |  | 
 | exp	:	exp '[' exp1 ']' | 
 | 			{ write_exp_elt_opcode (BINOP_SUBSCRIPT); } | 
 | 	; | 
 |  | 
 | exp	:	exp '('  | 
 | 			/* This is to save the value of arglist_len | 
 | 			   being accumulated by an outer function call.  */ | 
 | 			{ start_arglist (); } | 
 | 		arglist ')'	%prec ARROW | 
 | 			{ write_exp_elt_opcode (OP_FUNCALL); | 
 | 			  write_exp_elt_longcst ((LONGEST) end_arglist ()); | 
 | 			  write_exp_elt_opcode (OP_FUNCALL); } | 
 | 	; | 
 |  | 
 | lcurly	:	'{' | 
 | 			{ start_arglist (); } | 
 | 	; | 
 |  | 
 | arglist	: | 
 | 	; | 
 |  | 
 | arglist	:	exp | 
 | 			{ arglist_len = 1; } | 
 | 	; | 
 |  | 
 | arglist	:	arglist ',' exp   %prec ABOVE_COMMA | 
 | 			{ arglist_len++; } | 
 | 	; | 
 |  | 
 | rcurly	:	'}' | 
 | 			{ $$ = end_arglist () - 1; } | 
 | 	; | 
 | exp	:	lcurly arglist rcurly	%prec ARROW | 
 | 			{ write_exp_elt_opcode (OP_ARRAY); | 
 | 			  write_exp_elt_longcst ((LONGEST) 0); | 
 | 			  write_exp_elt_longcst ((LONGEST) $3); | 
 | 			  write_exp_elt_opcode (OP_ARRAY); } | 
 | 	; | 
 |  | 
 | exp	:	lcurly type rcurly exp  %prec UNARY | 
 | 			{ write_exp_elt_opcode (UNOP_MEMVAL); | 
 | 			  write_exp_elt_type ($2); | 
 | 			  write_exp_elt_opcode (UNOP_MEMVAL); } | 
 | 	; | 
 |  | 
 | exp	:	'(' type ')' exp  %prec UNARY | 
 | 			{ write_exp_elt_opcode (UNOP_CAST); | 
 | 			  write_exp_elt_type ($2); | 
 | 			  write_exp_elt_opcode (UNOP_CAST); } | 
 | 	; | 
 |  | 
 | exp	:	'(' exp1 ')' | 
 | 			{ } | 
 | 	; | 
 |  | 
 | /* Binary operators in order of decreasing precedence.  */ | 
 |  | 
 | exp	:	exp '@' exp | 
 | 			{ write_exp_elt_opcode (BINOP_REPEAT); } | 
 | 	; | 
 |  | 
 | exp	:	exp '*' exp | 
 | 			{ write_exp_elt_opcode (BINOP_MUL); } | 
 | 	; | 
 |  | 
 | exp	:	exp '/' exp | 
 | 			{ write_exp_elt_opcode (BINOP_DIV); } | 
 | 	; | 
 |  | 
 | exp	:	exp '%' exp | 
 | 			{ write_exp_elt_opcode (BINOP_REM); } | 
 | 	; | 
 |  | 
 | exp	:	exp '+' exp | 
 | 			{ write_exp_elt_opcode (BINOP_ADD); } | 
 | 	; | 
 |  | 
 | exp	:	exp '-' exp | 
 | 			{ write_exp_elt_opcode (BINOP_SUB); } | 
 | 	; | 
 |  | 
 | exp	:	exp LSH exp | 
 | 			{ write_exp_elt_opcode (BINOP_LSH); } | 
 | 	; | 
 |  | 
 | exp	:	exp RSH exp | 
 | 			{ write_exp_elt_opcode (BINOP_RSH); } | 
 | 	; | 
 |  | 
 | exp	:	exp EQUAL exp | 
 | 			{ write_exp_elt_opcode (BINOP_EQUAL); } | 
 | 	; | 
 |  | 
 | exp	:	exp NOTEQUAL exp | 
 | 			{ write_exp_elt_opcode (BINOP_NOTEQUAL); } | 
 | 	; | 
 |  | 
 | exp	:	exp LEQ exp | 
 | 			{ write_exp_elt_opcode (BINOP_LEQ); } | 
 | 	; | 
 |  | 
 | exp	:	exp GEQ exp | 
 | 			{ write_exp_elt_opcode (BINOP_GEQ); } | 
 | 	; | 
 |  | 
 | exp	:	exp '<' exp | 
 | 			{ write_exp_elt_opcode (BINOP_LESS); } | 
 | 	; | 
 |  | 
 | exp	:	exp '>' exp | 
 | 			{ write_exp_elt_opcode (BINOP_GTR); } | 
 | 	; | 
 |  | 
 | exp	:	exp '&' exp | 
 | 			{ write_exp_elt_opcode (BINOP_BITWISE_AND); } | 
 | 	; | 
 |  | 
 | exp	:	exp '^' exp | 
 | 			{ write_exp_elt_opcode (BINOP_BITWISE_XOR); } | 
 | 	; | 
 |  | 
 | exp	:	exp '|' exp | 
 | 			{ write_exp_elt_opcode (BINOP_BITWISE_IOR); } | 
 | 	; | 
 |  | 
 | exp	:	exp ANDAND exp | 
 | 			{ write_exp_elt_opcode (BINOP_LOGICAL_AND); } | 
 | 	; | 
 |  | 
 | exp	:	exp OROR exp | 
 | 			{ write_exp_elt_opcode (BINOP_LOGICAL_OR); } | 
 | 	; | 
 |  | 
 | exp	:	exp '?' exp ':' exp	%prec '?' | 
 | 			{ write_exp_elt_opcode (TERNOP_COND); } | 
 | 	; | 
 | 			   | 
 | exp	:	exp '=' exp | 
 | 			{ 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); } | 
 | 	; | 
 |  | 
 | exp	:	INT | 
 | 			{ write_exp_elt_opcode (OP_LONG); | 
 | 			  write_exp_elt_type ($1.type); | 
 | 			  write_exp_elt_longcst ((LONGEST)($1.val)); | 
 | 			  write_exp_elt_opcode (OP_LONG); } | 
 | 	; | 
 |  | 
 | exp	:	NAME_OR_INT | 
 | 			{ YYSTYPE val; | 
 | 			  parse_number ($1.stoken.ptr, $1.stoken.length, 0, &val); | 
 | 			  write_exp_elt_opcode (OP_LONG); | 
 | 			  write_exp_elt_type (val.typed_val_int.type); | 
 | 			  write_exp_elt_longcst ((LONGEST)val.typed_val_int.val); | 
 | 			  write_exp_elt_opcode (OP_LONG); | 
 | 			} | 
 | 	; | 
 |  | 
 |  | 
 | exp	:	FLOAT | 
 | 			{ write_exp_elt_opcode (OP_DOUBLE); | 
 | 			  write_exp_elt_type ($1.type); | 
 | 			  write_exp_elt_dblcst ($1.dval); | 
 | 			  write_exp_elt_opcode (OP_DOUBLE); } | 
 | 	; | 
 |  | 
 | exp	:	variable | 
 | 	; | 
 |  | 
 | exp	:	VARIABLE | 
 | 			/* Already written by write_dollar_variable. */ | 
 | 	; | 
 |  | 
 | exp	:	SIZEOF '(' type ')'	%prec UNARY | 
 | 			{ write_exp_elt_opcode (OP_LONG); | 
 | 			  write_exp_elt_type (builtin_type_int); | 
 | 			  CHECK_TYPEDEF ($3); | 
 | 			  write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3)); | 
 | 			  write_exp_elt_opcode (OP_LONG); } | 
 | 	; | 
 |  | 
 | exp	:	STRING | 
 | 			{ /* C strings are converted into array constants with | 
 | 			     an explicit null byte added at the end.  Thus | 
 | 			     the array upper bound is the string length. | 
 | 			     There is no such thing in C as a completely empty | 
 | 			     string. */ | 
 | 			  char *sp = $1.ptr; int count = $1.length; | 
 | 			  while (count-- > 0) | 
 | 			    { | 
 | 			      write_exp_elt_opcode (OP_LONG); | 
 | 			      write_exp_elt_type (builtin_type_char); | 
 | 			      write_exp_elt_longcst ((LONGEST)(*sp++)); | 
 | 			      write_exp_elt_opcode (OP_LONG); | 
 | 			    } | 
 | 			  write_exp_elt_opcode (OP_LONG); | 
 | 			  write_exp_elt_type (builtin_type_char); | 
 | 			  write_exp_elt_longcst ((LONGEST)'\0'); | 
 | 			  write_exp_elt_opcode (OP_LONG); | 
 | 			  write_exp_elt_opcode (OP_ARRAY); | 
 | 			  write_exp_elt_longcst ((LONGEST) 0); | 
 | 			  write_exp_elt_longcst ((LONGEST) ($1.length)); | 
 | 			  write_exp_elt_opcode (OP_ARRAY); } | 
 | 	; | 
 |  | 
 | /* C++.  */ | 
 | exp     :       TRUEKEYWORD     | 
 |                         { write_exp_elt_opcode (OP_LONG); | 
 |                           write_exp_elt_type (builtin_type_bool); | 
 |                           write_exp_elt_longcst ((LONGEST) 1); | 
 |                           write_exp_elt_opcode (OP_LONG); } | 
 | 	; | 
 |  | 
 | exp     :       FALSEKEYWORD    | 
 |                         { write_exp_elt_opcode (OP_LONG); | 
 |                           write_exp_elt_type (builtin_type_bool); | 
 |                           write_exp_elt_longcst ((LONGEST) 0); | 
 |                           write_exp_elt_opcode (OP_LONG); } | 
 | 	; | 
 |  | 
 | /* end of C++.  */ | 
 |  | 
 | block	:	BLOCKNAME | 
 | 			{ | 
 | 			  if ($1.sym) | 
 | 			    $$ = SYMBOL_BLOCK_VALUE ($1.sym); | 
 | 			  else | 
 | 			    error ("No file or function \"%s\".", | 
 | 				   copy_name ($1.stoken)); | 
 | 			} | 
 | 	|	FILENAME | 
 | 			{ | 
 | 			  $$ = $1; | 
 | 			} | 
 | 	; | 
 |  | 
 | block	:	block COLONCOLON name | 
 | 			{ struct symbol *tem | 
 | 			    = lookup_symbol (copy_name ($3), $1, | 
 | 					     VAR_NAMESPACE, (int *) NULL, | 
 | 					     (struct symtab **) NULL); | 
 | 			  if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK) | 
 | 			    error ("No function \"%s\" in specified context.", | 
 | 				   copy_name ($3)); | 
 | 			  $$ = SYMBOL_BLOCK_VALUE (tem); } | 
 | 	; | 
 |  | 
 | variable:	block COLONCOLON name | 
 | 			{ struct symbol *sym; | 
 | 			  sym = lookup_symbol (copy_name ($3), $1, | 
 | 					       VAR_NAMESPACE, (int *) NULL, | 
 | 					       (struct symtab **) NULL); | 
 | 			  if (sym == 0) | 
 | 			    error ("No symbol \"%s\" in specified context.", | 
 | 				   copy_name ($3)); | 
 |  | 
 | 			  write_exp_elt_opcode (OP_VAR_VALUE); | 
 | 			  /* block_found is set by lookup_symbol.  */ | 
 | 			  write_exp_elt_block (block_found); | 
 | 			  write_exp_elt_sym (sym); | 
 | 			  write_exp_elt_opcode (OP_VAR_VALUE); } | 
 | 	; | 
 |  | 
 | qualified_name:	typebase COLONCOLON name | 
 | 			{ | 
 | 			  struct type *type = $1; | 
 | 			  if (TYPE_CODE (type) != TYPE_CODE_STRUCT | 
 | 			      && TYPE_CODE (type) != TYPE_CODE_UNION) | 
 | 			    error ("`%s' is not defined as an aggregate type.", | 
 | 				   TYPE_NAME (type)); | 
 |  | 
 | 			  write_exp_elt_opcode (OP_SCOPE); | 
 | 			  write_exp_elt_type (type); | 
 | 			  write_exp_string ($3); | 
 | 			  write_exp_elt_opcode (OP_SCOPE); | 
 | 			} | 
 | 	|	typebase COLONCOLON '~' name | 
 | 			{ | 
 | 			  struct type *type = $1; | 
 | 			  struct stoken tmp_token; | 
 | 			  if (TYPE_CODE (type) != TYPE_CODE_STRUCT | 
 | 			      && TYPE_CODE (type) != TYPE_CODE_UNION) | 
 | 			    error ("`%s' is not defined as an aggregate type.", | 
 | 				   TYPE_NAME (type)); | 
 |  | 
 | 			  tmp_token.ptr = (char*) alloca ($4.length + 2); | 
 | 			  tmp_token.length = $4.length + 1; | 
 | 			  tmp_token.ptr[0] = '~'; | 
 | 			  memcpy (tmp_token.ptr+1, $4.ptr, $4.length); | 
 | 			  tmp_token.ptr[tmp_token.length] = 0; | 
 |  | 
 | 			  /* Check for valid destructor name.  */ | 
 | 			  destructor_name_p (tmp_token.ptr, type); | 
 | 			  write_exp_elt_opcode (OP_SCOPE); | 
 | 			  write_exp_elt_type (type); | 
 | 			  write_exp_string (tmp_token); | 
 | 			  write_exp_elt_opcode (OP_SCOPE); | 
 | 			} | 
 | 	; | 
 |  | 
 | variable:	qualified_name | 
 | 	|	COLONCOLON name | 
 | 			{ | 
 | 			  char *name = copy_name ($2); | 
 | 			  struct symbol *sym; | 
 | 			  struct minimal_symbol *msymbol; | 
 |  | 
 | 			  sym = | 
 | 			    lookup_symbol (name, (const struct block *) NULL, | 
 | 					   VAR_NAMESPACE, (int *) NULL, | 
 | 					   (struct symtab **) NULL); | 
 | 			  if (sym) | 
 | 			    { | 
 | 			      write_exp_elt_opcode (OP_VAR_VALUE); | 
 | 			      write_exp_elt_block (NULL); | 
 | 			      write_exp_elt_sym (sym); | 
 | 			      write_exp_elt_opcode (OP_VAR_VALUE); | 
 | 			      break; | 
 | 			    } | 
 |  | 
 | 			  msymbol = lookup_minimal_symbol (name, NULL, NULL); | 
 | 			  if (msymbol != NULL) | 
 | 			    { | 
 | 			      write_exp_msymbol (msymbol, | 
 | 						 lookup_function_type (builtin_type_int), | 
 | 						 builtin_type_int); | 
 | 			    } | 
 | 			  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); | 
 | 			} | 
 | 	; | 
 |  | 
 | variable:	name_not_typename | 
 | 			{ struct symbol *sym = $1.sym; | 
 |  | 
 | 			  if (sym) | 
 | 			    { | 
 | 			      if (symbol_read_needs_frame (sym)) | 
 | 				{ | 
 | 				  if (innermost_block == 0 || | 
 | 				      contained_in (block_found,  | 
 | 						    innermost_block)) | 
 | 				    innermost_block = block_found; | 
 | 				} | 
 |  | 
 | 			      write_exp_elt_opcode (OP_VAR_VALUE); | 
 | 			      /* We want to use the selected frame, not | 
 | 				 another more inner frame which happens to | 
 | 				 be in the same block.  */ | 
 | 			      write_exp_elt_block (NULL); | 
 | 			      write_exp_elt_sym (sym); | 
 | 			      write_exp_elt_opcode (OP_VAR_VALUE); | 
 | 			    } | 
 | 			  else if ($1.is_a_field_of_this) | 
 | 			    { | 
 | 			      /* C++: it hangs off of `this'.  Must | 
 | 			         not inadvertently convert from a method call | 
 | 				 to data ref.  */ | 
 | 			      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_string ($1.stoken); | 
 | 			      write_exp_elt_opcode (STRUCTOP_PTR); | 
 | 			    } | 
 | 			  else | 
 | 			    { | 
 | 			      struct minimal_symbol *msymbol; | 
 | 			      register char *arg = copy_name ($1.stoken); | 
 |  | 
 | 			      msymbol = | 
 | 				lookup_minimal_symbol (arg, NULL, NULL); | 
 | 			      if (msymbol != NULL) | 
 | 				{ | 
 | 				  write_exp_msymbol (msymbol, | 
 | 						     lookup_function_type (builtin_type_int), | 
 | 						     builtin_type_int); | 
 | 				} | 
 | 			      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.", | 
 | 				       copy_name ($1.stoken)); | 
 | 			    } | 
 | 			} | 
 | 	; | 
 |  | 
 | space_identifier : '@' NAME | 
 | 		{ push_type_address_space (copy_name ($2.stoken)); | 
 | 		  push_type (tp_space_identifier); | 
 | 		} | 
 | 	; | 
 |  | 
 | const_or_volatile: const_or_volatile_noopt | 
 | 	| | 
 | 	; | 
 |  | 
 | cv_with_space_id : const_or_volatile space_identifier const_or_volatile | 
 | 	; | 
 |  | 
 | const_or_volatile_or_space_identifier_noopt: cv_with_space_id | 
 | 	| const_or_volatile_noopt  | 
 | 	; | 
 |  | 
 | const_or_volatile_or_space_identifier:  | 
 | 		const_or_volatile_or_space_identifier_noopt | 
 | 	| | 
 | 	; | 
 |  | 
 | abs_decl:	'*' | 
 | 			{ push_type (tp_pointer); $$ = 0; } | 
 | 	|	'*' abs_decl | 
 | 			{ push_type (tp_pointer); $$ = $2; } | 
 | 	|	'&' | 
 | 			{ push_type (tp_reference); $$ = 0; } | 
 | 	|	'&' abs_decl | 
 | 			{ push_type (tp_reference); $$ = $2; } | 
 | 	|	direct_abs_decl | 
 | 	; | 
 |  | 
 | direct_abs_decl: '(' abs_decl ')' | 
 | 			{ $$ = $2; } | 
 | 	|	direct_abs_decl array_mod | 
 | 			{ | 
 | 			  push_type_int ($2); | 
 | 			  push_type (tp_array); | 
 | 			} | 
 | 	|	array_mod | 
 | 			{ | 
 | 			  push_type_int ($1); | 
 | 			  push_type (tp_array); | 
 | 			  $$ = 0; | 
 | 			} | 
 |  | 
 | 	| 	direct_abs_decl func_mod | 
 | 			{ push_type (tp_function); } | 
 | 	|	func_mod | 
 | 			{ push_type (tp_function); } | 
 | 	; | 
 |  | 
 | array_mod:	'[' ']' | 
 | 			{ $$ = -1; } | 
 | 	|	'[' INT ']' | 
 | 			{ $$ = $2.val; } | 
 | 	; | 
 |  | 
 | func_mod:	'(' ')' | 
 | 			{ $$ = 0; } | 
 | 	|	'(' nonempty_typelist ')' | 
 | 			{ free ((PTR)$2); $$ = 0; } | 
 | 	; | 
 |  | 
 | /* We used to try to recognize more pointer to member types here, but | 
 |    that didn't work (shift/reduce conflicts meant that these rules never | 
 |    got executed).  The problem is that | 
 |      int (foo::bar::baz::bizzle) | 
 |    is a function type but | 
 |      int (foo::bar::baz::bizzle::*) | 
 |    is a pointer to member type.  Stroustrup loses again!  */ | 
 |  | 
 | type	:	ptype | 
 | 	|	typebase COLONCOLON '*' | 
 | 			{ $$ = lookup_member_type (builtin_type_int, $1); } | 
 | 	; | 
 |  | 
 | typebase  /* Implements (approximately): (type-qualifier)* type-specifier */ | 
 | 	:	TYPENAME | 
 | 			{ $$ = $1.type; } | 
 | 	|	INT_KEYWORD | 
 | 			{ $$ = builtin_type_int; } | 
 | 	|	LONG | 
 | 			{ $$ = builtin_type_long; } | 
 | 	|	SHORT | 
 | 			{ $$ = builtin_type_short; } | 
 | 	|	LONG INT_KEYWORD | 
 | 			{ $$ = builtin_type_long; } | 
 | 	|	LONG SIGNED_KEYWORD INT_KEYWORD | 
 | 			{ $$ = builtin_type_long; } | 
 | 	|	LONG SIGNED_KEYWORD | 
 | 			{ $$ = builtin_type_long; } | 
 | 	|	SIGNED_KEYWORD LONG INT_KEYWORD | 
 | 			{ $$ = builtin_type_long; } | 
 | 	|	UNSIGNED LONG INT_KEYWORD | 
 | 			{ $$ = builtin_type_unsigned_long; } | 
 | 	|	LONG UNSIGNED INT_KEYWORD | 
 | 			{ $$ = builtin_type_unsigned_long; } | 
 | 	|	LONG UNSIGNED | 
 | 			{ $$ = builtin_type_unsigned_long; } | 
 | 	|	LONG LONG | 
 | 			{ $$ = builtin_type_long_long; } | 
 | 	|	LONG LONG INT_KEYWORD | 
 | 			{ $$ = builtin_type_long_long; } | 
 | 	|	LONG LONG SIGNED_KEYWORD INT_KEYWORD | 
 | 			{ $$ = builtin_type_long_long; } | 
 | 	|	LONG LONG SIGNED_KEYWORD | 
 | 			{ $$ = builtin_type_long_long; } | 
 | 	|	SIGNED_KEYWORD LONG LONG | 
 | 			{ $$ = builtin_type_long_long; } | 
 | 	|	UNSIGNED LONG LONG | 
 | 			{ $$ = builtin_type_unsigned_long_long; } | 
 | 	|	UNSIGNED LONG LONG INT_KEYWORD | 
 | 			{ $$ = builtin_type_unsigned_long_long; } | 
 | 	|	LONG LONG UNSIGNED | 
 | 			{ $$ = builtin_type_unsigned_long_long; } | 
 | 	|	LONG LONG UNSIGNED INT_KEYWORD | 
 | 			{ $$ = builtin_type_unsigned_long_long; } | 
 | 	|	SIGNED_KEYWORD LONG LONG | 
 | 			{ $$ = lookup_signed_typename ("long long"); } | 
 | 	|	SIGNED_KEYWORD LONG LONG INT_KEYWORD | 
 | 			{ $$ = lookup_signed_typename ("long long"); } | 
 | 	|	SHORT INT_KEYWORD | 
 | 			{ $$ = builtin_type_short; } | 
 | 	|	SHORT SIGNED_KEYWORD INT_KEYWORD | 
 | 			{ $$ = builtin_type_short; } | 
 | 	|	SHORT SIGNED_KEYWORD | 
 | 			{ $$ = builtin_type_short; } | 
 | 	|	UNSIGNED SHORT INT_KEYWORD | 
 | 			{ $$ = builtin_type_unsigned_short; } | 
 | 	|	SHORT UNSIGNED  | 
 | 			{ $$ = builtin_type_unsigned_short; } | 
 | 	|	SHORT UNSIGNED INT_KEYWORD | 
 | 			{ $$ = builtin_type_unsigned_short; } | 
 | 	|	DOUBLE_KEYWORD | 
 | 			{ $$ = builtin_type_double; } | 
 | 	|	LONG DOUBLE_KEYWORD | 
 | 			{ $$ = builtin_type_long_double; } | 
 | 	|	STRUCT name | 
 | 			{ $$ = lookup_struct (copy_name ($2), | 
 | 					      expression_context_block); } | 
 | 	|	CLASS name | 
 | 			{ $$ = lookup_struct (copy_name ($2), | 
 | 					      expression_context_block); } | 
 | 	|	UNION name | 
 | 			{ $$ = lookup_union (copy_name ($2), | 
 | 					     expression_context_block); } | 
 | 	|	ENUM name | 
 | 			{ $$ = lookup_enum (copy_name ($2), | 
 | 					    expression_context_block); } | 
 | 	|	UNSIGNED typename | 
 | 			{ $$ = lookup_unsigned_typename (TYPE_NAME($2.type)); } | 
 | 	|	UNSIGNED | 
 | 			{ $$ = builtin_type_unsigned_int; } | 
 | 	|	SIGNED_KEYWORD typename | 
 | 			{ $$ = lookup_signed_typename (TYPE_NAME($2.type)); } | 
 | 	|	SIGNED_KEYWORD | 
 | 			{ $$ = builtin_type_int; } | 
 |                 /* It appears that this rule for templates is never | 
 |                    reduced; template recognition happens by lookahead | 
 |                    in the token processing code in yylex. */          | 
 | 	|	TEMPLATE name '<' type '>' | 
 | 			{ $$ = lookup_template_type(copy_name($2), $4, | 
 | 						    expression_context_block); | 
 | 			} | 
 | 	| const_or_volatile_or_space_identifier_noopt typebase  | 
 | 			{ $$ = follow_types ($2); } | 
 | 	| typebase const_or_volatile_or_space_identifier_noopt  | 
 | 			{ $$ = follow_types ($1); } | 
 | 	; | 
 |  | 
 | typename:	TYPENAME | 
 | 	|	INT_KEYWORD | 
 | 		{ | 
 | 		  $$.stoken.ptr = "int"; | 
 | 		  $$.stoken.length = 3; | 
 | 		  $$.type = builtin_type_int; | 
 | 		} | 
 | 	|	LONG | 
 | 		{ | 
 | 		  $$.stoken.ptr = "long"; | 
 | 		  $$.stoken.length = 4; | 
 | 		  $$.type = builtin_type_long; | 
 | 		} | 
 | 	|	SHORT | 
 | 		{ | 
 | 		  $$.stoken.ptr = "short"; | 
 | 		  $$.stoken.length = 5; | 
 | 		  $$.type = builtin_type_short; | 
 | 		} | 
 | 	; | 
 |  | 
 | nonempty_typelist | 
 | 	:	type | 
 | 		{ $$ = (struct type **) malloc (sizeof (struct type *) * 2); | 
 | 		  $<ivec>$[0] = 1;	/* Number of types in vector */ | 
 | 		  $$[1] = $1; | 
 | 		} | 
 | 	|	nonempty_typelist ',' type | 
 | 		{ int len = sizeof (struct type *) * (++($<ivec>1[0]) + 1); | 
 | 		  $$ = (struct type **) realloc ((char *) $1, len); | 
 | 		  $$[$<ivec>$[0]] = $3; | 
 | 		} | 
 | 	; | 
 |  | 
 | ptype	:	typebase | 
 | 	|	ptype const_or_volatile_or_space_identifier abs_decl const_or_volatile_or_space_identifier | 
 | 		{ $$ = follow_types ($1); } | 
 | 	; | 
 |  | 
 | const_and_volatile: 	CONST_KEYWORD VOLATILE_KEYWORD | 
 | 	| 		VOLATILE_KEYWORD CONST_KEYWORD | 
 | 	; | 
 |  | 
 | const_or_volatile_noopt:  	const_and_volatile  | 
 | 			{ push_type (tp_const); | 
 | 			  push_type (tp_volatile);  | 
 | 			} | 
 | 	| 		CONST_KEYWORD | 
 | 			{ push_type (tp_const); } | 
 | 	| 		VOLATILE_KEYWORD | 
 | 			{ push_type (tp_volatile); } | 
 | 	; | 
 |  | 
 | name	:	NAME { $$ = $1.stoken; } | 
 | 	|	BLOCKNAME { $$ = $1.stoken; } | 
 | 	|	TYPENAME { $$ = $1.stoken; } | 
 | 	|	NAME_OR_INT  { $$ = $1.stoken; } | 
 | 	; | 
 |  | 
 | name_not_typename :	NAME | 
 | 	|	BLOCKNAME | 
 | /* These would be useful if name_not_typename was useful, but it is just | 
 |    a fake for "variable", so these cause reduce/reduce conflicts because | 
 |    the parser can't tell whether NAME_OR_INT is a name_not_typename (=variable, | 
 |    =exp) or just an exp.  If name_not_typename was ever used in an lvalue | 
 |    context where only a name could occur, this might be useful. | 
 |   	|	NAME_OR_INT | 
 |  */ | 
 | 	; | 
 |  | 
 | %% | 
 |  | 
 | /* 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 ***/ | 
 |  | 
 | static int | 
 | parse_number (p, len, parsed_float, putithere) | 
 |      register char *p; | 
 |      register int len; | 
 |      int parsed_float; | 
 |      YYSTYPE *putithere; | 
 | { | 
 |   /* FIXME: Shouldn't these be unsigned?  We don't deal with negative values | 
 |      here, and we do kind of silly things like cast to unsigned.  */ | 
 |   register LONGEST n = 0; | 
 |   register LONGEST prevn = 0; | 
 |   ULONGEST un; | 
 |  | 
 |   register int i = 0; | 
 |   register int c; | 
 |   register int base = input_radix; | 
 |   int unsigned_p = 0; | 
 |  | 
 |   /* Number of "L" suffixes encountered.  */ | 
 |   int long_p = 0; | 
 |  | 
 |   /* We have found a "L" or "U" suffix.  */ | 
 |   int found_suffix = 0; | 
 |  | 
 |   ULONGEST high_bit; | 
 |   struct type *signed_type; | 
 |   struct type *unsigned_type; | 
 |  | 
 |   if (parsed_float) | 
 |     { | 
 |       /* It's a float since it contains a point or an exponent.  */ | 
 |       char c; | 
 |       int num = 0;	/* number of tokens scanned by scanf */ | 
 |       char saved_char = p[len]; | 
 |  | 
 |       p[len] = 0;	/* null-terminate the token */ | 
 |       if (sizeof (putithere->typed_val_float.dval) <= sizeof (float)) | 
 | 	num = sscanf (p, "%g%c", (float *) &putithere->typed_val_float.dval,&c); | 
 |       else if (sizeof (putithere->typed_val_float.dval) <= sizeof (double)) | 
 | 	num = sscanf (p, "%lg%c", (double *) &putithere->typed_val_float.dval,&c); | 
 |       else | 
 | 	{ | 
 | #ifdef SCANF_HAS_LONG_DOUBLE | 
 | 	  num = sscanf (p, "%Lg%c", &putithere->typed_val_float.dval,&c); | 
 | #else | 
 | 	  /* Scan it into a double, then assign it to the long double. | 
 | 	     This at least wins with values representable in the range | 
 | 	     of doubles. */ | 
 | 	  double temp; | 
 | 	  num = sscanf (p, "%lg%c", &temp,&c); | 
 | 	  putithere->typed_val_float.dval = temp; | 
 | #endif | 
 | 	} | 
 |       p[len] = saved_char;	/* restore the input stream */ | 
 |       if (num != 1) 		/* check scanf found ONLY a float ... */ | 
 | 	return ERROR; | 
 |       /* See if it has `f' or `l' suffix (float or long double).  */ | 
 |  | 
 |       c = tolower (p[len - 1]); | 
 |  | 
 |       if (c == 'f') | 
 | 	putithere->typed_val_float.type = builtin_type_float; | 
 |       else if (c == 'l') | 
 | 	putithere->typed_val_float.type = builtin_type_long_double; | 
 |       else if (isdigit (c) || c == '.') | 
 | 	putithere->typed_val_float.type = builtin_type_double; | 
 |       else | 
 | 	return ERROR; | 
 |  | 
 |       return FLOAT; | 
 |     } | 
 |  | 
 |   /* Handle base-switching prefixes 0x, 0t, 0d, 0 */ | 
 |   if (p[0] == '0') | 
 |     switch (p[1]) | 
 |       { | 
 |       case 'x': | 
 |       case 'X': | 
 | 	if (len >= 3) | 
 | 	  { | 
 | 	    p += 2; | 
 | 	    base = 16; | 
 | 	    len -= 2; | 
 | 	  } | 
 | 	break; | 
 |  | 
 |       case 't': | 
 |       case 'T': | 
 |       case 'd': | 
 |       case 'D': | 
 | 	if (len >= 3) | 
 | 	  { | 
 | 	    p += 2; | 
 | 	    base = 10; | 
 | 	    len -= 2; | 
 | 	  } | 
 | 	break; | 
 |  | 
 |       default: | 
 | 	base = 8; | 
 | 	break; | 
 |       } | 
 |  | 
 |   while (len-- > 0) | 
 |     { | 
 |       c = *p++; | 
 |       if (c >= 'A' && c <= 'Z') | 
 | 	c += 'a' - 'A'; | 
 |       if (c != 'l' && c != 'u') | 
 | 	n *= base; | 
 |       if (c >= '0' && c <= '9') | 
 | 	{ | 
 | 	  if (found_suffix) | 
 | 	    return ERROR; | 
 | 	  n += i = c - '0'; | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  if (base > 10 && c >= 'a' && c <= 'f') | 
 | 	    { | 
 | 	      if (found_suffix) | 
 | 		return ERROR; | 
 | 	      n += i = c - 'a' + 10; | 
 | 	    } | 
 | 	  else if (c == 'l') | 
 | 	    { | 
 | 	      ++long_p; | 
 | 	      found_suffix = 1; | 
 | 	    } | 
 | 	  else if (c == 'u') | 
 | 	    { | 
 | 	      unsigned_p = 1; | 
 | 	      found_suffix = 1; | 
 | 	    } | 
 | 	  else | 
 | 	    return ERROR;	/* Char not a digit */ | 
 | 	} | 
 |       if (i >= base) | 
 | 	return ERROR;		/* Invalid digit in this base */ | 
 |  | 
 |       /* Portably test for overflow (only works for nonzero values, so make | 
 | 	 a second check for zero).  FIXME: Can't we just make n and prevn | 
 | 	 unsigned and avoid this?  */ | 
 |       if (c != 'l' && c != 'u' && (prevn >= n) && n != 0) | 
 | 	unsigned_p = 1;		/* Try something unsigned */ | 
 |  | 
 |       /* Portably test for unsigned overflow. | 
 | 	 FIXME: This check is wrong; for example it doesn't find overflow | 
 | 	 on 0x123456789 when LONGEST is 32 bits.  */ | 
 |       if (c != 'l' && c != 'u' && n != 0) | 
 | 	{	 | 
 | 	  if ((unsigned_p && (ULONGEST) prevn >= (ULONGEST) n)) | 
 | 	    error ("Numeric constant too large."); | 
 | 	} | 
 |       prevn = n; | 
 |     } | 
 |  | 
 |   /* An integer constant is an int, a long, or a long long.  An L | 
 |      suffix forces it to be long; an LL suffix forces it to be long | 
 |      long.  If not forced to a larger size, it gets the first type of | 
 |      the above that it fits in.  To figure out whether it fits, we | 
 |      shift it right and see whether anything remains.  Note that we | 
 |      can't shift sizeof (LONGEST) * HOST_CHAR_BIT bits or more in one | 
 |      operation, because many compilers will warn about such a shift | 
 |      (which always produces a zero result).  Sometimes TARGET_INT_BIT | 
 |      or TARGET_LONG_BIT will be that big, sometimes not.  To deal with | 
 |      the case where it is we just always shift the value more than | 
 |      once, with fewer bits each time.  */ | 
 |  | 
 |   un = (ULONGEST)n >> 2; | 
 |   if (long_p == 0 | 
 |       && (un >> (TARGET_INT_BIT - 2)) == 0) | 
 |     { | 
 |       high_bit = ((ULONGEST)1) << (TARGET_INT_BIT-1); | 
 |  | 
 |       /* A large decimal (not hex or octal) constant (between INT_MAX | 
 | 	 and UINT_MAX) is a long or unsigned long, according to ANSI, | 
 | 	 never an unsigned int, but this code treats it as unsigned | 
 | 	 int.  This probably should be fixed.  GCC gives a warning on | 
 | 	 such constants.  */ | 
 |  | 
 |       unsigned_type = builtin_type_unsigned_int; | 
 |       signed_type = builtin_type_int; | 
 |     } | 
 |   else if (long_p <= 1 | 
 | 	   && (un >> (TARGET_LONG_BIT - 2)) == 0) | 
 |     { | 
 |       high_bit = ((ULONGEST)1) << (TARGET_LONG_BIT-1); | 
 |       unsigned_type = builtin_type_unsigned_long; | 
 |       signed_type = builtin_type_long; | 
 |     } | 
 |   else | 
 |     { | 
 |       int shift; | 
 |       if (sizeof (ULONGEST) * HOST_CHAR_BIT < TARGET_LONG_LONG_BIT) | 
 | 	/* A long long does not fit in a LONGEST.  */ | 
 | 	shift = (sizeof (ULONGEST) * HOST_CHAR_BIT - 1); | 
 |       else | 
 | 	shift = (TARGET_LONG_LONG_BIT - 1); | 
 |       high_bit = (ULONGEST) 1 << shift; | 
 |       unsigned_type = builtin_type_unsigned_long_long; | 
 |       signed_type = builtin_type_long_long; | 
 |     } | 
 |  | 
 |    putithere->typed_val_int.val = n; | 
 |  | 
 |    /* If the high bit of the worked out type is set then this number | 
 |       has to be unsigned. */ | 
 |  | 
 |    if (unsigned_p || (n & high_bit))  | 
 |      { | 
 |        putithere->typed_val_int.type = unsigned_type; | 
 |      } | 
 |    else  | 
 |      { | 
 |        putithere->typed_val_int.type = signed_type; | 
 |      } | 
 |  | 
 |    return INT; | 
 | } | 
 |  | 
 | struct token | 
 | { | 
 |   char *operator; | 
 |   int token; | 
 |   enum exp_opcode opcode; | 
 | }; | 
 |  | 
 | static const struct token tokentab3[] = | 
 |   { | 
 |     {">>=", ASSIGN_MODIFY, BINOP_RSH}, | 
 |     {"<<=", ASSIGN_MODIFY, BINOP_LSH} | 
 |   }; | 
 |  | 
 | static const 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_BITWISE_IOR}, | 
 |     {"&=", ASSIGN_MODIFY, BINOP_BITWISE_AND}, | 
 |     {"^=", ASSIGN_MODIFY, BINOP_BITWISE_XOR}, | 
 |     {"++", INCREMENT, BINOP_END}, | 
 |     {"--", DECREMENT, BINOP_END}, | 
 |     {"->", ARROW, BINOP_END}, | 
 |     {"&&", ANDAND, BINOP_END}, | 
 |     {"||", OROR, BINOP_END}, | 
 |     {"::", COLONCOLON, BINOP_END}, | 
 |     {"<<", LSH, BINOP_END}, | 
 |     {">>", RSH, BINOP_END}, | 
 |     {"==", EQUAL, BINOP_END}, | 
 |     {"!=", NOTEQUAL, BINOP_END}, | 
 |     {"<=", LEQ, BINOP_END}, | 
 |     {">=", GEQ, BINOP_END} | 
 |   }; | 
 |  | 
 | /* Read one token, getting characters through lexptr.  */ | 
 |  | 
 | static int | 
 | yylex () | 
 | { | 
 |   int c; | 
 |   int namelen; | 
 |   unsigned int i; | 
 |   char *tokstart; | 
 |   char *tokptr; | 
 |   int tempbufindex; | 
 |   static char *tempbuf; | 
 |   static int tempbufsize; | 
 |   struct symbol * sym_class = NULL; | 
 |   char * token_string = NULL; | 
 |   int class_prefix = 0; | 
 |   int unquoted_expr; | 
 |     | 
 |  retry: | 
 |  | 
 |   /* Check if this is a macro invocation that we need to expand.  */ | 
 |   if (! scanning_macro_expansion ()) | 
 |     { | 
 |       char *expanded = macro_expand_next (&lexptr, | 
 |                                           expression_macro_lookup_func, | 
 |                                           expression_macro_lookup_baton); | 
 |  | 
 |       if (expanded) | 
 |         scan_macro_expansion (expanded); | 
 |     } | 
 |  | 
 |   prev_lexptr = lexptr; | 
 |   unquoted_expr = 1; | 
 |  | 
 |   tokstart = lexptr; | 
 |   /* See if it is a special token of length 3.  */ | 
 |   for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++) | 
 |     if (STREQN (tokstart, tokentab3[i].operator, 3)) | 
 |       { | 
 | 	lexptr += 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 (STREQN (tokstart, tokentab2[i].operator, 2)) | 
 |       { | 
 | 	lexptr += 2; | 
 | 	yylval.opcode = tokentab2[i].opcode; | 
 | 	return tokentab2[i].token; | 
 |       } | 
 |  | 
 |   switch (c = *tokstart) | 
 |     { | 
 |     case 0: | 
 |       /* If we were just scanning the result of a macro expansion, | 
 |          then we need to resume scanning the original text. | 
 |          Otherwise, we were already scanning the original text, and | 
 |          we're really done.  */ | 
 |       if (scanning_macro_expansion ()) | 
 |         { | 
 |           finished_macro_expansion (); | 
 |           goto retry; | 
 |         } | 
 |       else | 
 |         return 0; | 
 |  | 
 |     case ' ': | 
 |     case '\t': | 
 |     case '\n': | 
 |       lexptr++; | 
 |       goto retry; | 
 |  | 
 |     case '\'': | 
 |       /* We either have a character constant ('0' or '\177' for example) | 
 | 	 or we have a quoted symbol reference ('foo(int,int)' in C++ | 
 | 	 for example). */ | 
 |       lexptr++; | 
 |       c = *lexptr++; | 
 |       if (c == '\\') | 
 | 	c = parse_escape (&lexptr); | 
 |       else if (c == '\'') | 
 | 	error ("Empty character constant."); | 
 |       else if (! host_char_to_target (c, &c)) | 
 |         { | 
 |           int toklen = lexptr - tokstart + 1; | 
 |           char *tok = alloca (toklen + 1); | 
 |           memcpy (tok, tokstart, toklen); | 
 |           tok[toklen] = '\0'; | 
 |           error ("There is no character corresponding to %s in the target " | 
 |                  "character set `%s'.", tok, target_charset ()); | 
 |         } | 
 |  | 
 |       yylval.typed_val_int.val = c; | 
 |       yylval.typed_val_int.type = builtin_type_char; | 
 |  | 
 |       c = *lexptr++; | 
 |       if (c != '\'') | 
 | 	{ | 
 | 	  namelen = skip_quoted (tokstart) - tokstart; | 
 | 	  if (namelen > 2) | 
 | 	    { | 
 | 	      lexptr = tokstart + namelen; | 
 |               unquoted_expr = 0; | 
 | 	      if (lexptr[-1] != '\'') | 
 | 		error ("Unmatched single quote."); | 
 | 	      namelen -= 2; | 
 | 	      tokstart++; | 
 | 	      goto tryname; | 
 | 	    } | 
 | 	  error ("Invalid character constant."); | 
 | 	} | 
 |       return INT; | 
 |  | 
 |     case '(': | 
 |       paren_depth++; | 
 |       lexptr++; | 
 |       return c; | 
 |  | 
 |     case ')': | 
 |       if (paren_depth == 0) | 
 | 	return 0; | 
 |       paren_depth--; | 
 |       lexptr++; | 
 |       return c; | 
 |  | 
 |     case ',': | 
 |       if (comma_terminates | 
 |           && paren_depth == 0 | 
 |           && ! scanning_macro_expansion ()) | 
 | 	return 0; | 
 |       lexptr++; | 
 |       return c; | 
 |  | 
 |     case '.': | 
 |       /* Might be a floating point number.  */ | 
 |       if (lexptr[1] < '0' || lexptr[1] > '9') | 
 | 	goto symbol;		/* Nope, must be a symbol. */ | 
 |       /* FALL THRU into number case.  */ | 
 |  | 
 |     case '0': | 
 |     case '1': | 
 |     case '2': | 
 |     case '3': | 
 |     case '4': | 
 |     case '5': | 
 |     case '6': | 
 |     case '7': | 
 |     case '8': | 
 |     case '9': | 
 |       { | 
 | 	/* It's a number.  */ | 
 | 	int got_dot = 0, got_e = 0, toktype; | 
 | 	register char *p = tokstart; | 
 | 	int hex = input_radix > 10; | 
 |  | 
 | 	if (c == '0' && (p[1] == 'x' || p[1] == 'X')) | 
 | 	  { | 
 | 	    p += 2; | 
 | 	    hex = 1; | 
 | 	  } | 
 | 	else if (c == '0' && (p[1]=='t' || p[1]=='T' || p[1]=='d' || p[1]=='D')) | 
 | 	  { | 
 | 	    p += 2; | 
 | 	    hex = 0; | 
 | 	  } | 
 |  | 
 | 	for (;; ++p) | 
 | 	  { | 
 | 	    /* This test includes !hex because 'e' is a valid hex digit | 
 | 	       and thus does not indicate a floating point number when | 
 | 	       the radix is hex.  */ | 
 | 	    if (!hex && !got_e && (*p == 'e' || *p == 'E')) | 
 | 	      got_dot = got_e = 1; | 
 | 	    /* This test does not include !hex, because a '.' always indicates | 
 | 	       a decimal floating point number regardless of the radix.  */ | 
 | 	    else if (!got_dot && *p == '.') | 
 | 	      got_dot = 1; | 
 | 	    else if (got_e && (p[-1] == 'e' || p[-1] == 'E') | 
 | 		     && (*p == '-' || *p == '+')) | 
 | 	      /* This is the sign of the exponent, not the end of the | 
 | 		 number.  */ | 
 | 	      continue; | 
 | 	    /* We will take any letters or digits.  parse_number will | 
 | 	       complain if past the radix, or if L or U are not final.  */ | 
 | 	    else if ((*p < '0' || *p > '9') | 
 | 		     && ((*p < 'a' || *p > 'z') | 
 | 				  && (*p < 'A' || *p > 'Z'))) | 
 | 	      break; | 
 | 	  } | 
 | 	toktype = parse_number (tokstart, p - tokstart, got_dot|got_e, &yylval); | 
 |         if (toktype == ERROR) | 
 | 	  { | 
 | 	    char *err_copy = (char *) alloca (p - tokstart + 1); | 
 |  | 
 | 	    memcpy (err_copy, tokstart, p - tokstart); | 
 | 	    err_copy[p - tokstart] = 0; | 
 | 	    error ("Invalid number \"%s\".", err_copy); | 
 | 	  } | 
 | 	lexptr = p; | 
 | 	return toktype; | 
 |       } | 
 |  | 
 |     case '+': | 
 |     case '-': | 
 |     case '*': | 
 |     case '/': | 
 |     case '%': | 
 |     case '|': | 
 |     case '&': | 
 |     case '^': | 
 |     case '~': | 
 |     case '!': | 
 |     case '@': | 
 |     case '<': | 
 |     case '>': | 
 |     case '[': | 
 |     case ']': | 
 |     case '?': | 
 |     case ':': | 
 |     case '=': | 
 |     case '{': | 
 |     case '}': | 
 |     symbol: | 
 |       lexptr++; | 
 |       return c; | 
 |  | 
 |     case '"': | 
 |  | 
 |       /* Build the gdb internal form of the input string in tempbuf, | 
 | 	 translating any standard C escape forms seen.  Note that the | 
 | 	 buffer is null byte terminated *only* for the convenience of | 
 | 	 debugging gdb itself and printing the buffer contents when | 
 | 	 the buffer contains no embedded nulls.  Gdb does not depend | 
 | 	 upon the buffer being null byte terminated, it uses the length | 
 | 	 string instead.  This allows gdb to handle C strings (as well | 
 | 	 as strings in other languages) with embedded null bytes */ | 
 |  | 
 |       tokptr = ++tokstart; | 
 |       tempbufindex = 0; | 
 |  | 
 |       do { | 
 |         char *char_start_pos = tokptr; | 
 |  | 
 | 	/* Grow the static temp buffer if necessary, including allocating | 
 | 	   the first one on demand. */ | 
 | 	if (tempbufindex + 1 >= tempbufsize) | 
 | 	  { | 
 | 	    tempbuf = (char *) realloc (tempbuf, tempbufsize += 64); | 
 | 	  } | 
 | 	switch (*tokptr) | 
 | 	  { | 
 | 	  case '\0': | 
 | 	  case '"': | 
 | 	    /* Do nothing, loop will terminate. */ | 
 | 	    break; | 
 | 	  case '\\': | 
 | 	    tokptr++; | 
 | 	    c = parse_escape (&tokptr); | 
 | 	    if (c == -1) | 
 | 	      { | 
 | 		continue; | 
 | 	      } | 
 | 	    tempbuf[tempbufindex++] = c; | 
 | 	    break; | 
 | 	  default: | 
 | 	    c = *tokptr++; | 
 |             if (! host_char_to_target (c, &c)) | 
 |               { | 
 |                 int len = tokptr - char_start_pos; | 
 |                 char *copy = alloca (len + 1); | 
 |                 memcpy (copy, char_start_pos, len); | 
 |                 copy[len] = '\0'; | 
 |  | 
 |                 error ("There is no character corresponding to `%s' " | 
 |                        "in the target character set `%s'.", | 
 |                        copy, target_charset ()); | 
 |               } | 
 |             tempbuf[tempbufindex++] = c; | 
 | 	    break; | 
 | 	  } | 
 |       } while ((*tokptr != '"') && (*tokptr != '\0')); | 
 |       if (*tokptr++ != '"') | 
 | 	{ | 
 | 	  error ("Unterminated string in expression."); | 
 | 	} | 
 |       tempbuf[tempbufindex] = '\0';	/* See note above */ | 
 |       yylval.sval.ptr = tempbuf; | 
 |       yylval.sval.length = tempbufindex; | 
 |       lexptr = tokptr; | 
 |       return (STRING); | 
 |     } | 
 |  | 
 |   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.  */ | 
 |   namelen = 0; | 
 |   for (c = tokstart[namelen]; | 
 |        (c == '_' || c == '$' || (c >= '0' && c <= '9') | 
 | 	|| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '<');) | 
 |     { | 
 |       /* Template parameter lists are part of the name. | 
 | 	 FIXME: This mishandles `print $a<4&&$a>3'.  */ | 
 |  | 
 |       if (c == '<') | 
 | 	{  | 
 |                /* Scan ahead to get rest of the template specification.  Note | 
 |                   that we look ahead only when the '<' adjoins non-whitespace | 
 |                   characters; for comparison expressions, e.g. "a < b > c", | 
 |                   there must be spaces before the '<', etc. */ | 
 |                 | 
 |                char * p = find_template_name_end (tokstart + namelen); | 
 |                if (p) | 
 |                  namelen = p - tokstart; | 
 |                break; | 
 | 	} | 
 |       c = tokstart[++namelen]; | 
 |     } | 
 |  | 
 |   /* The token "if" terminates the expression and is NOT removed from | 
 |      the input stream.  It doesn't count if it appears in the | 
 |      expansion of a macro.  */ | 
 |   if (namelen == 2 | 
 |       && tokstart[0] == 'i' | 
 |       && tokstart[1] == 'f' | 
 |       && ! scanning_macro_expansion ()) | 
 |     { | 
 |       return 0; | 
 |     } | 
 |  | 
 |   lexptr += namelen; | 
 |  | 
 |   tryname: | 
 |  | 
 |   /* Catch specific keywords.  Should be done with a data structure.  */ | 
 |   switch (namelen) | 
 |     { | 
 |     case 8: | 
 |       if (STREQN (tokstart, "unsigned", 8)) | 
 | 	return UNSIGNED; | 
 |       if (current_language->la_language == language_cplus | 
 | 	  && STREQN (tokstart, "template", 8)) | 
 | 	return TEMPLATE; | 
 |       if (STREQN (tokstart, "volatile", 8)) | 
 | 	return VOLATILE_KEYWORD; | 
 |       break; | 
 |     case 6: | 
 |       if (STREQN (tokstart, "struct", 6)) | 
 | 	return STRUCT; | 
 |       if (STREQN (tokstart, "signed", 6)) | 
 | 	return SIGNED_KEYWORD; | 
 |       if (STREQN (tokstart, "sizeof", 6))       | 
 | 	return SIZEOF; | 
 |       if (STREQN (tokstart, "double", 6))       | 
 | 	return DOUBLE_KEYWORD; | 
 |       break; | 
 |     case 5: | 
 |       if (current_language->la_language == language_cplus) | 
 |         { | 
 |           if (STREQN (tokstart, "false", 5)) | 
 |             return FALSEKEYWORD; | 
 |           if (STREQN (tokstart, "class", 5)) | 
 |             return CLASS; | 
 |         } | 
 |       if (STREQN (tokstart, "union", 5)) | 
 | 	return UNION; | 
 |       if (STREQN (tokstart, "short", 5)) | 
 | 	return SHORT; | 
 |       if (STREQN (tokstart, "const", 5)) | 
 | 	return CONST_KEYWORD; | 
 |       break; | 
 |     case 4: | 
 |       if (STREQN (tokstart, "enum", 4)) | 
 | 	return ENUM; | 
 |       if (STREQN (tokstart, "long", 4)) | 
 | 	return LONG; | 
 |       if (current_language->la_language == language_cplus) | 
 |           { | 
 |             if (STREQN (tokstart, "true", 4)) | 
 |               return TRUEKEYWORD; | 
 |           } | 
 |       break; | 
 |     case 3: | 
 |       if (STREQN (tokstart, "int", 3)) | 
 | 	return INT_KEYWORD; | 
 |       break; | 
 |     default: | 
 |       break; | 
 |     } | 
 |  | 
 |   yylval.sval.ptr = tokstart; | 
 |   yylval.sval.length = namelen; | 
 |  | 
 |   if (*tokstart == '$') | 
 |     { | 
 |       write_dollar_variable (yylval.sval); | 
 |       return VARIABLE; | 
 |     } | 
 |    | 
 |   /* Look ahead and see if we can consume more of the input | 
 |      string to get a reasonable class/namespace spec or a | 
 |      fully-qualified name.  This is a kludge to get around the | 
 |      HP aCC compiler's generation of symbol names with embedded | 
 |      colons for namespace and nested classes. */  | 
 |   if (unquoted_expr) | 
 |     { | 
 |       /* Only do it if not inside single quotes */  | 
 |       sym_class = parse_nested_classes_for_hpacc (yylval.sval.ptr, yylval.sval.length, | 
 |                                                   &token_string, &class_prefix, &lexptr); | 
 |       if (sym_class) | 
 |         { | 
 |           /* Replace the current token with the bigger one we found */  | 
 |           yylval.sval.ptr = token_string; | 
 |           yylval.sval.length = strlen (token_string); | 
 |         } | 
 |     } | 
 |    | 
 |   /* 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); | 
 |     struct symbol *sym; | 
 |     int is_a_field_of_this = 0; | 
 |     int hextype; | 
 |  | 
 |     sym = lookup_symbol (tmp, expression_context_block, | 
 | 			 VAR_NAMESPACE, | 
 | 			 current_language->la_language == language_cplus | 
 | 			 ? &is_a_field_of_this : (int *) NULL, | 
 | 			 (struct symtab **) NULL); | 
 |     /* Call lookup_symtab, not lookup_partial_symtab, in case there are | 
 |        no psymtabs (coff, xcoff, or some future change to blow away the | 
 |        psymtabs once once symbols are read).  */ | 
 |     if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) | 
 |       { | 
 | 	yylval.ssym.sym = sym; | 
 | 	yylval.ssym.is_a_field_of_this = is_a_field_of_this; | 
 | 	return BLOCKNAME; | 
 |       } | 
 |     else if (!sym) | 
 |       {				/* See if it's a file name. */ | 
 | 	struct symtab *symtab; | 
 |  | 
 | 	symtab = lookup_symtab (tmp); | 
 |  | 
 | 	if (symtab) | 
 | 	  { | 
 | 	    yylval.bval = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK); | 
 | 	    return FILENAME; | 
 | 	  } | 
 |       } | 
 |  | 
 |     if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF) | 
 |         { | 
 | #if 1 | 
 | 	  /* Despite the following flaw, we need to keep this code enabled. | 
 | 	     Because we can get called from check_stub_method, if we don't | 
 | 	     handle nested types then it screws many operations in any | 
 | 	     program which uses nested types.  */ | 
 | 	  /* In "A::x", if x is a member function of A and there happens | 
 | 	     to be a type (nested or not, since the stabs don't make that | 
 | 	     distinction) named x, then this code incorrectly thinks we | 
 | 	     are dealing with nested types rather than a member function.  */ | 
 |  | 
 | 	  char *p; | 
 | 	  char *namestart; | 
 | 	  struct symbol *best_sym; | 
 |  | 
 | 	  /* Look ahead to detect nested types.  This probably should be | 
 | 	     done in the grammar, but trying seemed to introduce a lot | 
 | 	     of shift/reduce and reduce/reduce conflicts.  It's possible | 
 | 	     that it could be done, though.  Or perhaps a non-grammar, but | 
 | 	     less ad hoc, approach would work well.  */ | 
 |  | 
 | 	  /* Since we do not currently have any way of distinguishing | 
 | 	     a nested type from a non-nested one (the stabs don't tell | 
 | 	     us whether a type is nested), we just ignore the | 
 | 	     containing type.  */ | 
 |  | 
 | 	  p = lexptr; | 
 | 	  best_sym = sym; | 
 | 	  while (1) | 
 | 	    { | 
 | 	      /* Skip whitespace.  */ | 
 | 	      while (*p == ' ' || *p == '\t' || *p == '\n') | 
 | 		++p; | 
 | 	      if (*p == ':' && p[1] == ':') | 
 | 		{ | 
 | 		  /* Skip the `::'.  */ | 
 | 		  p += 2; | 
 | 		  /* Skip whitespace.  */ | 
 | 		  while (*p == ' ' || *p == '\t' || *p == '\n') | 
 | 		    ++p; | 
 | 		  namestart = p; | 
 | 		  while (*p == '_' || *p == '$' || (*p >= '0' && *p <= '9') | 
 | 			 || (*p >= 'a' && *p <= 'z') | 
 | 			 || (*p >= 'A' && *p <= 'Z')) | 
 | 		    ++p; | 
 | 		  if (p != namestart) | 
 | 		    { | 
 | 		      struct symbol *cur_sym; | 
 | 		      /* As big as the whole rest of the expression, which is | 
 | 			 at least big enough.  */ | 
 | 		      char *ncopy = alloca (strlen (tmp)+strlen (namestart)+3); | 
 | 		      char *tmp1; | 
 |  | 
 | 		      tmp1 = ncopy; | 
 | 		      memcpy (tmp1, tmp, strlen (tmp)); | 
 | 		      tmp1 += strlen (tmp); | 
 | 		      memcpy (tmp1, "::", 2); | 
 | 		      tmp1 += 2; | 
 | 		      memcpy (tmp1, namestart, p - namestart); | 
 | 		      tmp1[p - namestart] = '\0'; | 
 | 		      cur_sym = lookup_symbol (ncopy, expression_context_block, | 
 | 					       VAR_NAMESPACE, (int *) NULL, | 
 | 					       (struct symtab **) NULL); | 
 | 		      if (cur_sym) | 
 | 			{ | 
 | 			  if (SYMBOL_CLASS (cur_sym) == LOC_TYPEDEF) | 
 | 			    { | 
 | 			      best_sym = cur_sym; | 
 | 			      lexptr = p; | 
 | 			    } | 
 | 			  else | 
 | 			    break; | 
 | 			} | 
 | 		      else | 
 | 			break; | 
 | 		    } | 
 | 		  else | 
 | 		    break; | 
 | 		} | 
 | 	      else | 
 | 		break; | 
 | 	    } | 
 |  | 
 | 	  yylval.tsym.type = SYMBOL_TYPE (best_sym); | 
 | #else /* not 0 */ | 
 | 	  yylval.tsym.type = SYMBOL_TYPE (sym); | 
 | #endif /* not 0 */ | 
 | 	  return TYPENAME; | 
 |         } | 
 |     if ((yylval.tsym.type = lookup_primitive_typename (tmp)) != 0) | 
 |       return TYPENAME; | 
 |  | 
 |     /* Input names that aren't symbols but ARE valid hex numbers, | 
 |        when the input radix permits them, can be names or numbers | 
 |        depending on the parse.  Note we support radixes > 16 here.  */ | 
 |     if (!sym &&  | 
 |         ((tokstart[0] >= 'a' && tokstart[0] < 'a' + input_radix - 10) || | 
 |          (tokstart[0] >= 'A' && tokstart[0] < 'A' + input_radix - 10))) | 
 |       { | 
 |  	YYSTYPE newlval;	/* Its value is ignored.  */ | 
 | 	hextype = parse_number (tokstart, namelen, 0, &newlval); | 
 | 	if (hextype == INT) | 
 | 	  { | 
 | 	    yylval.ssym.sym = sym; | 
 | 	    yylval.ssym.is_a_field_of_this = is_a_field_of_this; | 
 | 	    return NAME_OR_INT; | 
 | 	  } | 
 |       } | 
 |  | 
 |     /* Any other kind of symbol */ | 
 |     yylval.ssym.sym = sym; | 
 |     yylval.ssym.is_a_field_of_this = is_a_field_of_this; | 
 |     return NAME; | 
 |   } | 
 | } | 
 |  | 
 | void | 
 | yyerror (msg) | 
 |      char *msg; | 
 | { | 
 |   if (prev_lexptr) | 
 |     lexptr = prev_lexptr; | 
 |  | 
 |   error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr); | 
 | } |