X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fc-exp.y;h=6d169405840beb7cb4073eaec2487a142bd68ace;hb=3e79cecf024acb3f5739ec19d6ebd331f08e80e8;hp=62ecbb0f6a2be09fda5550484bcb01a49f2fda1f;hpb=ba47c66add7b9bd51af6ca2e6f45529bb38b9dd3;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/c-exp.y b/gdb/c-exp.y index 62ecbb0f6a..6d16940584 100644 --- a/gdb/c-exp.y +++ b/gdb/c-exp.y @@ -1,5 +1,6 @@ /* YACC parser for C expressions, for GDB. - Copyright (C) 1986, 1989, 1990, 1991, 1993, 1994 + Copyright (C) 1986, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, + 1998, 1999, 2000, 2003, 2004, 2006, 2007, 2008 Free Software Foundation, Inc. This file is part of GDB. @@ -16,7 +17,8 @@ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ +Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ /* Parse a C expression from text in a string, and return the result as a struct expression pointer. @@ -38,7 +40,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ %{ #include "defs.h" -#include +#include "gdb_string.h" +#include #include "expression.h" #include "value.h" #include "parser-defs.h" @@ -47,6 +50,12 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #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" +#include "block.h" +#include "cp-support.h" +#include "dfp.h" + +#define parse_type builtin_type (parse_gdbarch) /* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc), as well as gratuitiously global symbol names, so we can have multiple @@ -56,7 +65,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ generators need to be fixed instead of adding those names to this list. */ #define yymaxdepth c_maxdepth -#define yyparse c_parse +#define yyparse c_parse_internal #define yylex c_lex #define yyerror c_error #define yylval c_lval @@ -84,19 +93,29 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #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 0 /* Default to no yydebug support */ +#define YYDEBUG 1 /* Default to yydebug support */ #endif -int -yyparse PARAMS ((void)); +#define YYFPRINTF parser_fprintf -static int -yylex PARAMS ((void)); +int yyparse (void); -void -yyerror PARAMS ((char *)); +static int yylex (void); + +void yyerror (char *); %} @@ -110,8 +129,15 @@ yyerror PARAMS ((char *)); struct { LONGEST val; struct type *type; - } typed_val; - double dval; + } typed_val_int; + struct { + DOUBLEST dval; + struct type *type; + } typed_val_float; + struct { + gdb_byte val[16]; + struct type *type; + } typed_val_decfloat; struct symbol *sym; struct type *tval; struct stoken sval; @@ -128,13 +154,12 @@ yyerror PARAMS ((char *)); %{ /* YYSTYPE gets defined by %union */ -static int -parse_number PARAMS ((char *, int, int, YYSTYPE *)); +static int parse_number (char *, int, int, YYSTYPE *); %} %type exp exp1 type_exp start variable qualified_name lcurly %type rcurly -%type type typebase +%type type typebase qualified_type %type nonempty_typelist /* %type block */ @@ -143,8 +168,9 @@ parse_number PARAMS ((char *, int, int, YYSTYPE *)); %type ptype %type array_mod -%token INT -%token FLOAT +%token INT +%token FLOAT +%token DECFLOAT /* Both NAME and TYPENAME tokens represent symbols in the input, and both convey their data as strings. @@ -156,6 +182,7 @@ parse_number PARAMS ((char *, int, int, YYSTYPE *)); %token STRING %token NAME /* BLOCKNAME defined below to give it higher precedence. */ +%token COMPLETE %token TYPENAME %type name %type name_not_typename @@ -174,15 +201,16 @@ parse_number PARAMS ((char *, int, int, YYSTYPE *)); /* 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 -%token LAST REGNAME +%token SIGNED_KEYWORD LONG SHORT INT_KEYWORD CONST_KEYWORD VOLATILE_KEYWORD DOUBLE_KEYWORD -%token VARIABLE +%token VARIABLE %token ASSIGN_MODIFY /* C++ */ -%token THIS +%token TRUEKEYWORD +%token FALSEKEYWORD + %left ',' %left ABOVE_COMMA @@ -202,6 +230,7 @@ parse_number PARAMS ((char *, int, int, YYSTYPE *)); %right UNARY INCREMENT DECREMENT %right ARROW '.' '[' '(' %token BLOCKNAME +%token FILENAME %type block %left COLONCOLON @@ -227,14 +256,20 @@ exp1 : exp /* 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_PLUS); } + ; + exp : '!' exp %prec UNARY { write_exp_elt_opcode (UNOP_LOGICAL_NOT); } ; @@ -269,6 +304,23 @@ exp : exp ARROW name write_exp_elt_opcode (STRUCTOP_PTR); } ; +exp : exp ARROW name COMPLETE + { mark_struct_expression (); + write_exp_elt_opcode (STRUCTOP_PTR); + write_exp_string ($3); + write_exp_elt_opcode (STRUCTOP_PTR); } + ; + +exp : exp ARROW COMPLETE + { struct stoken s; + mark_struct_expression (); + write_exp_elt_opcode (STRUCTOP_PTR); + s.ptr = ""; + s.length = 0; + write_exp_string (s); + 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 @@ -276,6 +328,7 @@ exp : exp ARROW qualified_name write_exp_elt_opcode (UNOP_ADDR); write_exp_elt_opcode (STRUCTOP_MPTR); } ; + exp : exp ARROW '*' exp { write_exp_elt_opcode (STRUCTOP_MPTR); } ; @@ -286,6 +339,23 @@ exp : exp '.' name write_exp_elt_opcode (STRUCTOP_STRUCT); } ; +exp : exp '.' name COMPLETE + { mark_struct_expression (); + write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_string ($3); + write_exp_elt_opcode (STRUCTOP_STRUCT); } + ; + +exp : exp '.' COMPLETE + { struct stoken s; + mark_struct_expression (); + write_exp_elt_opcode (STRUCTOP_STRUCT); + s.ptr = ""; + s.length = 0; + write_exp_string (s); + 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 @@ -456,8 +526,8 @@ 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.type); - write_exp_elt_longcst ((LONGEST)val.typed_val.val); + 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); } ; @@ -465,35 +535,29 @@ exp : NAME_OR_INT exp : FLOAT { write_exp_elt_opcode (OP_DOUBLE); - write_exp_elt_type (builtin_type_double); - write_exp_elt_dblcst ($1); + write_exp_elt_type ($1.type); + write_exp_elt_dblcst ($1.dval); write_exp_elt_opcode (OP_DOUBLE); } ; -exp : variable - ; - -exp : LAST - { write_exp_elt_opcode (OP_LAST); - write_exp_elt_longcst ((LONGEST) $1); - write_exp_elt_opcode (OP_LAST); } +exp : DECFLOAT + { write_exp_elt_opcode (OP_DECFLOAT); + write_exp_elt_type ($1.type); + write_exp_elt_decfloatcst ($1.val); + write_exp_elt_opcode (OP_DECFLOAT); } ; -exp : REGNAME - { write_exp_elt_opcode (OP_REGISTER); - write_exp_elt_longcst ((LONGEST) $1); - write_exp_elt_opcode (OP_REGISTER); } +exp : variable ; exp : VARIABLE - { write_exp_elt_opcode (OP_INTERNALVAR); - write_exp_elt_intern ($1); - write_exp_elt_opcode (OP_INTERNALVAR); } + /* Already written by write_dollar_variable. */ ; exp : SIZEOF '(' type ')' %prec UNARY { write_exp_elt_opcode (OP_LONG); - write_exp_elt_type (builtin_type_int); + write_exp_elt_type (parse_type->builtin_int); + CHECK_TYPEDEF ($3); write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3)); write_exp_elt_opcode (OP_LONG); } ; @@ -508,12 +572,12 @@ exp : STRING while (count-- > 0) { write_exp_elt_opcode (OP_LONG); - write_exp_elt_type (builtin_type_char); + write_exp_elt_type (parse_type->builtin_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_type (parse_type->builtin_char); write_exp_elt_longcst ((LONGEST)'\0'); write_exp_elt_opcode (OP_LONG); write_exp_elt_opcode (OP_ARRAY); @@ -523,36 +587,40 @@ exp : STRING ; /* C++. */ -exp : THIS - { write_exp_elt_opcode (OP_THIS); - write_exp_elt_opcode (OP_THIS); } +exp : TRUEKEYWORD + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (parse_type->builtin_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 (parse_type->builtin_bool); + write_exp_elt_longcst ((LONGEST) 0); + write_exp_elt_opcode (OP_LONG); } ; /* end of C++. */ block : BLOCKNAME { - if ($1.sym != 0) - $$ = SYMBOL_BLOCK_VALUE ($1.sym); + if ($1.sym) + $$ = SYMBOL_BLOCK_VALUE ($1.sym); else - { - struct symtab *tem = - lookup_symtab (copy_name ($1.stoken)); - if (tem) - $$ = BLOCKVECTOR_BLOCK - (BLOCKVECTOR (tem), STATIC_BLOCK); - else - error ("No file or function \"%s\".", - copy_name ($1.stoken)); - } + 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); + VAR_DOMAIN, (int *) NULL); if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK) error ("No function \"%s\" in specified context.", copy_name ($3)); @@ -562,8 +630,7 @@ block : block COLONCOLON name variable: block COLONCOLON name { struct symbol *sym; sym = lookup_symbol (copy_name ($3), $1, - VAR_NAMESPACE, (int *) NULL, - (struct symtab **) NULL); + VAR_DOMAIN, (int *) NULL); if (sym == 0) error ("No symbol \"%s\" in specified context.", copy_name ($3)); @@ -579,7 +646,8 @@ qualified_name: typebase COLONCOLON name { struct type *type = $1; if (TYPE_CODE (type) != TYPE_CODE_STRUCT - && TYPE_CODE (type) != TYPE_CODE_UNION) + && TYPE_CODE (type) != TYPE_CODE_UNION + && TYPE_CODE (type) != TYPE_CODE_NAMESPACE) error ("`%s' is not defined as an aggregate type.", TYPE_NAME (type)); @@ -593,19 +661,19 @@ qualified_name: typebase COLONCOLON name struct type *type = $1; struct stoken tmp_token; if (TYPE_CODE (type) != TYPE_CODE_STRUCT - && TYPE_CODE (type) != TYPE_CODE_UNION) + && TYPE_CODE (type) != TYPE_CODE_UNION + && TYPE_CODE (type) != TYPE_CODE_NAMESPACE) error ("`%s' is not defined as an aggregate type.", TYPE_NAME (type)); - if (!STREQ (type_name_no_tag (type), $4.ptr)) - error ("invalid destructor `%s::~%s'", - type_name_no_tag (type), $4.ptr); - 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); @@ -622,8 +690,7 @@ variable: qualified_name sym = lookup_symbol (name, (const struct block *) NULL, - VAR_NAMESPACE, (int *) NULL, - (struct symtab **) NULL); + VAR_DOMAIN, (int *) NULL); if (sym) { write_exp_elt_opcode (OP_VAR_VALUE); @@ -633,19 +700,13 @@ variable: qualified_name break; } - msymbol = lookup_minimal_symbol (name, - (struct objfile *) NULL); + msymbol = lookup_minimal_symbol (name, NULL, NULL); if (msymbol != NULL) - { - write_exp_msymbol (msymbol, - lookup_function_type (builtin_type_int), - builtin_type_int); - } + write_exp_msymbol (msymbol); + else if (!have_full_symbols () && !have_partial_symbols ()) + error ("No symbol table is loaded. Use the \"file\" command."); 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); + error ("No symbol \"%s\" in current context.", name); } ; @@ -687,16 +748,12 @@ variable: name_not_typename else { struct minimal_symbol *msymbol; - register char *arg = copy_name ($1.stoken); + char *arg = copy_name ($1.stoken); - msymbol = lookup_minimal_symbol (arg, - (struct objfile *) NULL); + msymbol = + lookup_minimal_symbol (arg, NULL, NULL); if (msymbol != NULL) - { - write_exp_msymbol (msymbol, - lookup_function_type (builtin_type_int), - builtin_type_int); - } + write_exp_msymbol (msymbol); else if (!have_full_symbols () && !have_partial_symbols ()) error ("No symbol table is loaded. Use the \"file\" command."); else @@ -706,21 +763,26 @@ variable: name_not_typename } ; +space_identifier : '@' NAME + { push_type_address_space (copy_name ($2.stoken)); + push_type (tp_space_identifier); + } + ; -ptype : typebase - /* "const" and "volatile" are curently ignored. A type qualifier - before the type is currently handled in the typebase rule. - The reason for recognizing these here (shift/reduce conflicts) - might be obsolete now that some pointer to member rules have - been deleted. */ - | typebase CONST_KEYWORD - | typebase VOLATILE_KEYWORD - | typebase abs_decl - { $$ = follow_types ($1); } - | typebase CONST_KEYWORD abs_decl - { $$ = follow_types ($1); } - | typebase VOLATILE_KEYWORD abs_decl - { $$ = follow_types ($1); } +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: '*' @@ -763,10 +825,10 @@ array_mod: '[' ']' func_mod: '(' ')' { $$ = 0; } | '(' nonempty_typelist ')' - { free ((PTR)$2); $$ = 0; } + { free ($2); $$ = 0; } ; -/* We used to try to recognize more pointer to member types here, but +/* We used to try to recognize 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) @@ -775,35 +837,67 @@ func_mod: '(' ')' 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; } + { $$ = parse_type->builtin_int; } | LONG - { $$ = builtin_type_long; } + { $$ = parse_type->builtin_long; } | SHORT - { $$ = builtin_type_short; } + { $$ = parse_type->builtin_short; } | LONG INT_KEYWORD - { $$ = builtin_type_long; } + { $$ = parse_type->builtin_long; } + | LONG SIGNED_KEYWORD INT_KEYWORD + { $$ = parse_type->builtin_long; } + | LONG SIGNED_KEYWORD + { $$ = parse_type->builtin_long; } + | SIGNED_KEYWORD LONG INT_KEYWORD + { $$ = parse_type->builtin_long; } | UNSIGNED LONG INT_KEYWORD - { $$ = builtin_type_unsigned_long; } + { $$ = parse_type->builtin_unsigned_long; } + | LONG UNSIGNED INT_KEYWORD + { $$ = parse_type->builtin_unsigned_long; } + | LONG UNSIGNED + { $$ = parse_type->builtin_unsigned_long; } | LONG LONG - { $$ = builtin_type_long_long; } + { $$ = parse_type->builtin_long_long; } | LONG LONG INT_KEYWORD - { $$ = builtin_type_long_long; } + { $$ = parse_type->builtin_long_long; } + | LONG LONG SIGNED_KEYWORD INT_KEYWORD + { $$ = parse_type->builtin_long_long; } + | LONG LONG SIGNED_KEYWORD + { $$ = parse_type->builtin_long_long; } + | SIGNED_KEYWORD LONG LONG + { $$ = parse_type->builtin_long_long; } + | SIGNED_KEYWORD LONG LONG INT_KEYWORD + { $$ = parse_type->builtin_long_long; } | UNSIGNED LONG LONG - { $$ = builtin_type_unsigned_long_long; } + { $$ = parse_type->builtin_unsigned_long_long; } | UNSIGNED LONG LONG INT_KEYWORD - { $$ = builtin_type_unsigned_long_long; } + { $$ = parse_type->builtin_unsigned_long_long; } + | LONG LONG UNSIGNED + { $$ = parse_type->builtin_unsigned_long_long; } + | LONG LONG UNSIGNED INT_KEYWORD + { $$ = parse_type->builtin_unsigned_long_long; } | SHORT INT_KEYWORD - { $$ = builtin_type_short; } + { $$ = parse_type->builtin_short; } + | SHORT SIGNED_KEYWORD INT_KEYWORD + { $$ = parse_type->builtin_short; } + | SHORT SIGNED_KEYWORD + { $$ = parse_type->builtin_short; } | UNSIGNED SHORT INT_KEYWORD - { $$ = builtin_type_unsigned_short; } + { $$ = parse_type->builtin_unsigned_short; } + | SHORT UNSIGNED + { $$ = parse_type->builtin_unsigned_short; } + | SHORT UNSIGNED INT_KEYWORD + { $$ = parse_type->builtin_unsigned_short; } + | DOUBLE_KEYWORD + { $$ = parse_type->builtin_double; } + | LONG DOUBLE_KEYWORD + { $$ = parse_type->builtin_long_double; } | STRUCT name { $$ = lookup_struct (copy_name ($2), expression_context_block); } @@ -819,20 +913,93 @@ typebase /* Implements (approximately): (type-qualifier)* type-specifier */ | UNSIGNED typename { $$ = lookup_unsigned_typename (TYPE_NAME($2.type)); } | UNSIGNED - { $$ = builtin_type_unsigned_int; } + { $$ = parse_type->builtin_unsigned_int; } | SIGNED_KEYWORD typename { $$ = lookup_signed_typename (TYPE_NAME($2.type)); } | SIGNED_KEYWORD - { $$ = builtin_type_int; } + { $$ = parse_type->builtin_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" and "volatile" are curently ignored. A type qualifier - after the type is handled in the ptype rule. I think these could - be too. */ - | CONST_KEYWORD typebase { $$ = $2; } - | VOLATILE_KEYWORD typebase { $$ = $2; } + | const_or_volatile_or_space_identifier_noopt typebase + { $$ = follow_types ($2); } + | typebase const_or_volatile_or_space_identifier_noopt + { $$ = follow_types ($1); } + | qualified_type + ; + +/* FIXME: carlton/2003-09-25: This next bit leads to lots of + reduce-reduce conflicts, because the parser doesn't know whether or + not to use qualified_name or qualified_type: the rules are + identical. If the parser is parsing 'A::B::x', then, when it sees + the second '::', it knows that the expression to the left of it has + to be a type, so it uses qualified_type. But if it is parsing just + 'A::B', then it doesn't have any way of knowing which rule to use, + so there's a reduce-reduce conflict; it picks qualified_name, since + that occurs earlier in this file than qualified_type. + + There's no good way to fix this with the grammar as it stands; as + far as I can tell, some of the problems arise from ambiguities that + GDB introduces ('start' can be either an expression or a type), but + some of it is inherent to the nature of C++ (you want to treat the + input "(FOO)" fairly differently depending on whether FOO is an + expression or a type, and if FOO is a complex expression, this can + be hard to determine at the right time). Fortunately, it works + pretty well in most cases. For example, if you do 'ptype A::B', + where A::B is a nested type, then the parser will mistakenly + misidentify it as an expression; but evaluate_subexp will get + called with 'noside' set to EVAL_AVOID_SIDE_EFFECTS, and everything + will work out anyways. But there are situations where the parser + will get confused: the most common one that I've run into is when + you want to do + + print *((A::B *) x)" + + where the parser doesn't realize that A::B has to be a type until + it hits the first right paren, at which point it's too late. (The + workaround is to type "print *(('A::B' *) x)" instead.) (And + another solution is to fix our symbol-handling code so that the + user never wants to type something like that in the first place, + because we get all the types right without the user's help!) + + Perhaps we could fix this by making the lexer smarter. Some of + this functionality used to be in the lexer, but in a way that + worked even less well than the current solution: that attempt + involved having the parser sometimes handle '::' and having the + lexer sometimes handle it, and without a clear division of + responsibility, it quickly degenerated into a big mess. Probably + the eventual correct solution will give more of a role to the lexer + (ideally via code that is shared between the lexer and + decode_line_1), but I'm not holding my breath waiting for somebody + to get around to cleaning this up... */ + +qualified_type: typebase COLONCOLON name + { + struct type *type = $1; + struct type *new_type; + char *ncopy = alloca ($3.length + 1); + + memcpy (ncopy, $3.ptr, $3.length); + ncopy[$3.length] = '\0'; + + if (TYPE_CODE (type) != TYPE_CODE_STRUCT + && TYPE_CODE (type) != TYPE_CODE_UNION + && TYPE_CODE (type) != TYPE_CODE_NAMESPACE) + error ("`%s' is not defined as an aggregate type.", + TYPE_NAME (type)); + + new_type = cp_lookup_nested_type (type, ncopy, + expression_context_block); + if (new_type == NULL) + error ("No type \"%s\" within class or namespace \"%s\".", + ncopy, TYPE_NAME (type)); + + $$ = new_type; + } ; typename: TYPENAME @@ -840,19 +1007,19 @@ typename: TYPENAME { $$.stoken.ptr = "int"; $$.stoken.length = 3; - $$.type = builtin_type_int; + $$.type = parse_type->builtin_int; } | LONG { $$.stoken.ptr = "long"; $$.stoken.length = 4; - $$.type = builtin_type_long; + $$.type = parse_type->builtin_long; } | SHORT { $$.stoken.ptr = "short"; $$.stoken.length = 5; - $$.type = builtin_type_short; + $$.type = parse_type->builtin_short; } ; @@ -869,6 +1036,25 @@ nonempty_typelist } ; +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; } @@ -896,20 +1082,20 @@ name_not_typename : NAME static int parse_number (p, len, parsed_float, putithere) - register char *p; - register int len; + char *p; + 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; - unsigned LONGEST un; + LONGEST n = 0; + LONGEST prevn = 0; + ULONGEST un; - register int i = 0; - register int c; - register int base = input_radix; + int i = 0; + int c; + int base = input_radix; int unsigned_p = 0; /* Number of "L" suffixes encountered. */ @@ -918,14 +1104,79 @@ parse_number (p, len, parsed_float, putithere) /* We have found a "L" or "U" suffix. */ int found_suffix = 0; - unsigned LONGEST high_bit; + 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. */ - putithere->dval = atof (p); + char *s; + int num; /* number of tokens scanned by scanf */ + char saved_char; + + /* If it ends at "df", "dd" or "dl", take it as type of decimal floating + point. Return DECFLOAT. */ + + if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'f') + { + p[len - 2] = '\0'; + putithere->typed_val_decfloat.type + = parse_type->builtin_decfloat; + decimal_from_string (putithere->typed_val_decfloat.val, 4, p); + p[len - 2] = 'd'; + return DECFLOAT; + } + + if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'd') + { + p[len - 2] = '\0'; + putithere->typed_val_decfloat.type + = parse_type->builtin_decdouble; + decimal_from_string (putithere->typed_val_decfloat.val, 8, p); + p[len - 2] = 'd'; + return DECFLOAT; + } + + if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'l') + { + p[len - 2] = '\0'; + putithere->typed_val_decfloat.type + = parse_type->builtin_declong; + decimal_from_string (putithere->typed_val_decfloat.val, 16, p); + p[len - 2] = 'd'; + return DECFLOAT; + } + + s = malloc (len); + saved_char = p[len]; + p[len] = 0; /* null-terminate the token */ + num = sscanf (p, "%" DOUBLEST_SCAN_FORMAT "%s", + &putithere->typed_val_float.dval, s); + p[len] = saved_char; /* restore the input stream */ + + if (num == 1) + putithere->typed_val_float.type = + parse_type->builtin_double; + + if (num == 2 ) + { + /* See if it has any float suffix: 'f' for float, 'l' for long + double. */ + if (!strcasecmp (s, "f")) + putithere->typed_val_float.type = + parse_type->builtin_float; + else if (!strcasecmp (s, "l")) + putithere->typed_val_float.type = + parse_type->builtin_long_double; + else + { + free (s); + return ERROR; + } + } + + free (s); return FLOAT; } @@ -1008,7 +1259,7 @@ parse_number (p, len, parsed_float, putithere) on 0x123456789 when LONGEST is 32 bits. */ if (c != 'l' && c != 'u' && n != 0) { - if ((unsigned_p && (unsigned LONGEST) prevn >= (unsigned LONGEST) n)) + if ((unsigned_p && (ULONGEST) prevn >= (ULONGEST) n)) error ("Numeric constant too large."); } prevn = n; @@ -1021,16 +1272,16 @@ parse_number (p, len, parsed_float, putithere) 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 + (which always produces a zero result). Sometimes gdbarch_int_bit + or gdbarch_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 = (unsigned LONGEST)n >> 2; + un = (ULONGEST)n >> 2; if (long_p == 0 - && (un >> (TARGET_INT_BIT - 2)) == 0) + && (un >> (gdbarch_int_bit (parse_gdbarch) - 2)) == 0) { - high_bit = ((unsigned LONGEST)1) << (TARGET_INT_BIT-1); + high_bit = ((ULONGEST)1) << (gdbarch_int_bit (parse_gdbarch) - 1); /* A large decimal (not hex or octal) constant (between INT_MAX and UINT_MAX) is a long or unsigned long, according to ANSI, @@ -1038,41 +1289,42 @@ parse_number (p, len, parsed_float, putithere) int. This probably should be fixed. GCC gives a warning on such constants. */ - unsigned_type = builtin_type_unsigned_int; - signed_type = builtin_type_int; + unsigned_type = parse_type->builtin_unsigned_int; + signed_type = parse_type->builtin_int; } else if (long_p <= 1 - && (un >> (TARGET_LONG_BIT - 2)) == 0) + && (un >> (gdbarch_long_bit (parse_gdbarch) - 2)) == 0) { - high_bit = ((unsigned LONGEST)1) << (TARGET_LONG_BIT-1); - unsigned_type = builtin_type_unsigned_long; - signed_type = builtin_type_long; + high_bit = ((ULONGEST)1) << (gdbarch_long_bit (parse_gdbarch) - 1); + unsigned_type = parse_type->builtin_unsigned_long; + signed_type = parse_type->builtin_long; } else { - high_bit = (((unsigned LONGEST)1) - << (TARGET_LONG_LONG_BIT - 32 - 1) - << 16 - << 16); - if (high_bit == 0) + int shift; + if (sizeof (ULONGEST) * HOST_CHAR_BIT + < gdbarch_long_long_bit (parse_gdbarch)) /* A long long does not fit in a LONGEST. */ - high_bit = (unsigned LONGEST)1 << sizeof (LONGEST) * HOST_CHAR_BIT - 1; - unsigned_type = builtin_type_unsigned_long_long; - signed_type = builtin_type_long_long; + shift = (sizeof (ULONGEST) * HOST_CHAR_BIT - 1); + else + shift = (gdbarch_long_long_bit (parse_gdbarch) - 1); + high_bit = (ULONGEST) 1 << shift; + unsigned_type = parse_type->builtin_unsigned_long_long; + signed_type = parse_type->builtin_long_long; } - putithere->typed_val.val = n; + 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.type = unsigned_type; + putithere->typed_val_int.type = unsigned_type; } else { - putithere->typed_val.type = signed_type; + putithere->typed_val_int.type = signed_type; } return INT; @@ -1115,6 +1367,16 @@ static const struct token tokentab2[] = {">=", GEQ, BINOP_END} }; +/* This is set if a NAME token appeared at the very end of the input + string, with no whitespace separating the name from the EOF. This + is used only when parsing to do field name completion. */ +static int saw_name_at_eof; + +/* This is set if the previously-returned token was a structure + operator -- either '.' or ARROW. This is used only when parsing to + do field name completion. */ +static int last_was_structop; + /* Read one token, getting characters through lexptr. */ static int @@ -1128,13 +1390,31 @@ yylex () int tempbufindex; static char *tempbuf; static int tempbufsize; - + char * token_string = NULL; + int class_prefix = 0; + int saw_structop = last_was_structop; + + last_was_structop = 0; + 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; + 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)) + if (strncmp (tokstart, tokentab3[i].operator, 3) == 0) { lexptr += 3; yylval.opcode = tokentab3[i].opcode; @@ -1143,17 +1423,38 @@ yylex () /* 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)) + if (strncmp (tokstart, tokentab2[i].operator, 2) == 0) { lexptr += 2; yylval.opcode = tokentab2[i].opcode; + if (in_parse_field && tokentab2[i].token == ARROW) + last_was_structop = 1; return tokentab2[i].token; } switch (c = *tokstart) { case 0: - return 0; + /* If we were just scanning the result of a macro expansion, + then we need to resume scanning the original text. + If we're parsing for field name completion, and the previous + token allows such completion, return a COMPLETE token. + Otherwise, we were already scanning the original text, and + we're really done. */ + if (scanning_macro_expansion ()) + { + finished_macro_expansion (); + goto retry; + } + else if (saw_name_at_eof) + { + saw_name_at_eof = 0; + return COMPLETE; + } + else if (saw_structop) + return COMPLETE; + else + return 0; case ' ': case '\t': @@ -1169,9 +1470,20 @@ yylex () 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.val = c; - yylval.typed_val.type = builtin_type_char; + yylval.typed_val_int.val = c; + yylval.typed_val_int.type = parse_type->builtin_char; c = *lexptr++; if (c != '\'') @@ -1203,7 +1515,9 @@ yylex () return c; case ',': - if (comma_terminates && paren_depth == 0) + if (comma_terminates + && paren_depth == 0 + && ! scanning_macro_expansion ()) return 0; lexptr++; return c; @@ -1211,7 +1525,11 @@ yylex () case '.': /* Might be a floating point number. */ if (lexptr[1] < '0' || lexptr[1] > '9') - goto symbol; /* Nope, must be a symbol. */ + { + if (in_parse_field) + last_was_structop = 1; + goto symbol; /* Nope, must be a symbol. */ + } /* FALL THRU into number case. */ case '0': @@ -1227,7 +1545,7 @@ yylex () { /* It's a number. */ int got_dot = 0, got_e = 0, toktype; - register char *p = tokstart; + char *p = tokstart; int hex = input_radix > 10; if (c == '0' && (p[1] == 'x' || p[1] == 'X')) @@ -1316,6 +1634,8 @@ yylex () 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) @@ -1338,7 +1658,19 @@ yylex () tempbuf[tempbufindex++] = c; break; default: - tempbuf[tempbufindex++] = *tokptr++; + 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')); @@ -1362,123 +1694,91 @@ yylex () namelen = 0; for (c = tokstart[namelen]; (c == '_' || c == '$' || (c >= '0' && c <= '9') - || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); - c = tokstart[++namelen]) - ; + || (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. */ - if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f') + /* 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; - /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1) - and $$digits (equivalent to $<-digits> if you could type that). - Make token type LAST, and put the number (the digits) in yylval. */ - tryname: - if (*tokstart == '$') - { - register int negate = 0; - c = 1; - /* Double dollar means negate the number and add -1 as well. - Thus $$ alone means -1. */ - if (namelen >= 2 && tokstart[1] == '$') - { - negate = 1; - c = 2; - } - if (c == namelen) - { - /* Just dollars (one or two) */ - yylval.lval = - negate; - return LAST; - } - /* Is the rest of the token digits? */ - for (; c < namelen; c++) - if (!(tokstart[c] >= '0' && tokstart[c] <= '9')) - break; - if (c == namelen) - { - yylval.lval = atoi (tokstart + 1 + negate); - if (negate) - yylval.lval = - yylval.lval; - return LAST; - } - } - - /* Handle tokens that refer to machine registers: - $ followed by a register name. */ - if (*tokstart == '$') { - for (c = 0; c < NUM_REGS; c++) - if (namelen - 1 == strlen (reg_names[c]) - && STREQN (tokstart + 1, reg_names[c], namelen - 1)) - { - yylval.lval = c; - return REGNAME; - } - for (c = 0; c < num_std_regs; c++) - if (namelen - 1 == strlen (std_regs[c].name) - && STREQN (tokstart + 1, std_regs[c].name, namelen - 1)) - { - yylval.lval = std_regs[c].regnum; - return REGNAME; - } - } /* Catch specific keywords. Should be done with a data structure. */ switch (namelen) { case 8: - if (STREQN (tokstart, "unsigned", 8)) + if (strncmp (tokstart, "unsigned", 8) == 0) return UNSIGNED; - if (current_language->la_language == language_cplus - && STREQN (tokstart, "template", 8)) + if (parse_language->la_language == language_cplus + && strncmp (tokstart, "template", 8) == 0) return TEMPLATE; - if (STREQN (tokstart, "volatile", 8)) + if (strncmp (tokstart, "volatile", 8) == 0) return VOLATILE_KEYWORD; break; case 6: - if (STREQN (tokstart, "struct", 6)) + if (strncmp (tokstart, "struct", 6) == 0) return STRUCT; - if (STREQN (tokstart, "signed", 6)) + if (strncmp (tokstart, "signed", 6) == 0) return SIGNED_KEYWORD; - if (STREQN (tokstart, "sizeof", 6)) + if (strncmp (tokstart, "sizeof", 6) == 0) return SIZEOF; + if (strncmp (tokstart, "double", 6) == 0) + return DOUBLE_KEYWORD; break; case 5: - if (current_language->la_language == language_cplus - && STREQN (tokstart, "class", 5)) - return CLASS; - if (STREQN (tokstart, "union", 5)) + if (parse_language->la_language == language_cplus) + { + if (strncmp (tokstart, "false", 5) == 0) + return FALSEKEYWORD; + if (strncmp (tokstart, "class", 5) == 0) + return CLASS; + } + if (strncmp (tokstart, "union", 5) == 0) return UNION; - if (STREQN (tokstart, "short", 5)) + if (strncmp (tokstart, "short", 5) == 0) return SHORT; - if (STREQN (tokstart, "const", 5)) + if (strncmp (tokstart, "const", 5) == 0) return CONST_KEYWORD; break; case 4: - if (STREQN (tokstart, "enum", 4)) + if (strncmp (tokstart, "enum", 4) == 0) return ENUM; - if (STREQN (tokstart, "long", 4)) + if (strncmp (tokstart, "long", 4) == 0) return LONG; - if (current_language->la_language == language_cplus - && STREQN (tokstart, "this", 4)) - { - static const char this_name[] = - { CPLUS_MARKER, 't', 'h', 'i', 's', '\0' }; - - if (lookup_symbol (this_name, expression_context_block, - VAR_NAMESPACE, (int *) NULL, - (struct symtab **) NULL)) - return THIS; - } + if (parse_language->la_language == language_cplus) + { + if (strncmp (tokstart, "true", 4) == 0) + return TRUEKEYWORD; + } break; case 3: - if (STREQN (tokstart, "int", 3)) + if (strncmp (tokstart, "int", 3) == 0) return INT_KEYWORD; break; default: @@ -1488,14 +1788,12 @@ yylex () yylval.sval.ptr = tokstart; yylval.sval.length = namelen; - /* Any other names starting in $ are debugger internal variables. */ - if (*tokstart == '$') { - yylval.ivar = lookup_internalvar (copy_name (yylval.sval) + 1); + write_dollar_variable (yylval.sval); return VARIABLE; } - + /* 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 @@ -1508,106 +1806,44 @@ yylex () 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); + VAR_DOMAIN, + parse_language->la_language == language_cplus + ? &is_a_field_of_this : (int *) 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) || - lookup_symtab (tmp)) + 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 *tmp = alloca (strlen (namestart)); - - memcpy (tmp, namestart, p - namestart); - tmp[p - namestart] = '\0'; - cur_sym = lookup_symbol (tmp, 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 */ + /* NOTE: carlton/2003-09-25: There used to be code here to + handle nested types. It didn't work very well. See the + comment before qualified_type for more info. */ yylval.tsym.type = SYMBOL_TYPE (sym); -#endif /* not 0 */ return TYPENAME; } - if ((yylval.tsym.type = lookup_primitive_typename (tmp)) != 0) - return TYPENAME; + yylval.tsym.type + = language_lookup_primitive_type_by_name (parse_language, + parse_gdbarch, tmp); + if (yylval.tsym.type != NULL) + return TYPENAME; /* Input names that aren't symbols but ARE valid hex numbers, when the input radix permits them, can be names or numbers @@ -1629,13 +1865,26 @@ yylex () /* Any other kind of symbol */ yylval.ssym.sym = sym; yylval.ssym.is_a_field_of_this = is_a_field_of_this; + if (in_parse_field && *lexptr == '\0') + saw_name_at_eof = 1; return NAME; } } +int +c_parse (void) +{ + last_was_structop = 0; + saw_name_at_eof = 0; + return yyparse (); +} + void yyerror (msg) char *msg; { - error (msg ? msg : "Invalid syntax in expression."); + if (prev_lexptr) + lexptr = prev_lexptr; + + error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr); }