X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fc-exp.y;h=845771c9b9678cd5d2fa6c54ece670288d198b13;hb=92981e24467c4247c8bf16780cac90b340c0a4c2;hp=cd4e8d0ae8df41a0cbc09ee8edc5b2b0d794e18d;hpb=fe898f56a1df2d8a610899df50e38d1590f3e57a;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/c-exp.y b/gdb/c-exp.y index cd4e8d0ae8..845771c9b9 100644 --- a/gdb/c-exp.y +++ b/gdb/c-exp.y @@ -1,23 +1,22 @@ /* YACC parser for C expressions, for GDB. - Copyright 1986, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, - 1998, 1999, 2000 + Copyright (C) 1986, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, + 1998, 1999, 2000, 2003, 2004, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. -This file is part of GDB. + 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 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 3 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. + 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. */ + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ /* Parse a C expression from text in a string, and return the result as a struct expression pointer. @@ -51,9 +50,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "objfiles.h" /* For have_full_symbols and have_partial_symbols */ #include "charset.h" #include "block.h" +#include "cp-support.h" +#include "dfp.h" +#include "gdb_assert.h" +#include "macroscope.h" -/* Flag indicating we're dealing with HP-compiled objects */ -extern int hp_som_som_object_present; +#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 @@ -63,7 +65,7 @@ extern int hp_som_som_object_present; 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 @@ -132,9 +134,14 @@ void yyerror (char *); 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; + struct typed_stoken tsval; struct ttype tsym; struct symtoken ssym; int voidval; @@ -142,6 +149,7 @@ void yyerror (char *); enum exp_opcode opcode; struct internalvar *ivar; + struct stoken_vector svec; struct type **tvec; int *ivec; } @@ -149,11 +157,12 @@ void yyerror (char *); %{ /* YYSTYPE gets defined by %union */ static int parse_number (char *, int, int, YYSTYPE *); +static struct stoken operator_stoken (const char *); %} %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 */ @@ -164,6 +173,7 @@ static int parse_number (char *, int, int, YYSTYPE *); %token INT %token FLOAT +%token DECFLOAT /* Both NAME and TYPENAME tokens represent symbols in the input, and both convey their data as strings. @@ -173,10 +183,13 @@ static int parse_number (char *, int, int, YYSTYPE *); Contexts where this distinction is not important can use the nonterminal "name", which matches either NAME or TYPENAME. */ -%token STRING +%token STRING +%token CHAR %token NAME /* BLOCKNAME defined below to give it higher precedence. */ +%token COMPLETE %token TYPENAME %type name +%type string_exp %type name_not_typename %type typename @@ -187,9 +200,13 @@ static int parse_number (char *, int, int, YYSTYPE *); %token NAME_OR_INT +%token OPERATOR %token STRUCT CLASS UNION ENUM SIZEOF UNSIGNED COLONCOLON %token TEMPLATE %token ERROR +%token NEW DELETE +%type operator +%token REINTERPRET_CAST DYNAMIC_CAST STATIC_CAST CONST_CAST /* Special type cases, put in to allow the parser to distinguish different legal basetypes. */ @@ -220,7 +237,7 @@ static int parse_number (char *, int, int, YYSTYPE *); %left '+' '-' %left '*' '/' '%' %right UNARY INCREMENT DECREMENT -%right ARROW '.' '[' '(' +%right ARROW ARROW_STAR '.' DOT_STAR '[' '(' %token BLOCKNAME %token FILENAME %type block @@ -258,6 +275,10 @@ 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); } ; @@ -292,6 +313,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 @@ -300,7 +338,7 @@ exp : exp ARROW qualified_name write_exp_elt_opcode (STRUCTOP_MPTR); } ; -exp : exp ARROW '*' exp +exp : exp ARROW_STAR exp { write_exp_elt_opcode (STRUCTOP_MPTR); } ; @@ -310,6 +348,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 @@ -318,7 +373,7 @@ exp : exp '.' qualified_name write_exp_elt_opcode (STRUCTOP_MEMBER); } ; -exp : exp '.' '*' exp +exp : exp DOT_STAR exp { write_exp_elt_opcode (STRUCTOP_MEMBER); } ; @@ -351,6 +406,18 @@ arglist : arglist ',' exp %prec ABOVE_COMMA { arglist_len++; } ; +exp : exp '(' nonempty_typelist ')' const_or_volatile + { int i; + write_exp_elt_opcode (TYPE_INSTANCE); + write_exp_elt_longcst ((LONGEST) $3[0]); + for (i = 0; i < $3[0]; ++i) + write_exp_elt_type ($3[i + 1]); + write_exp_elt_longcst((LONGEST) $3[0]); + write_exp_elt_opcode (TYPE_INSTANCE); + free ($3); + } + ; + rcurly : '}' { $$ = end_arglist () - 1; } ; @@ -476,6 +543,15 @@ exp : INT write_exp_elt_opcode (OP_LONG); } ; +exp : CHAR + { + struct stoken_vector vec; + vec.len = 1; + vec.tokens = &$1; + write_exp_string_vector ($1.type, &vec); + } + ; + exp : NAME_OR_INT { YYSTYPE val; parse_number ($1.stoken.ptr, $1.stoken.length, 0, &val); @@ -494,6 +570,13 @@ exp : FLOAT write_exp_elt_opcode (OP_DOUBLE); } ; +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 : variable ; @@ -503,47 +586,118 @@ exp : 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); } ; -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) +exp : REINTERPRET_CAST '<' type '>' '(' exp ')' %prec UNARY + { write_exp_elt_opcode (UNOP_REINTERPRET_CAST); + write_exp_elt_type ($3); + write_exp_elt_opcode (UNOP_REINTERPRET_CAST); } + ; + +exp : STATIC_CAST '<' type '>' '(' exp ')' %prec UNARY + { write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type ($3); + write_exp_elt_opcode (UNOP_CAST); } + ; + +exp : DYNAMIC_CAST '<' type '>' '(' exp ')' %prec UNARY + { write_exp_elt_opcode (UNOP_DYNAMIC_CAST); + write_exp_elt_type ($3); + write_exp_elt_opcode (UNOP_DYNAMIC_CAST); } + ; + +exp : CONST_CAST '<' type '>' '(' exp ')' %prec UNARY + { /* We could do more error checking here, but + it doesn't seem worthwhile. */ + write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type ($3); + write_exp_elt_opcode (UNOP_CAST); } + ; + +string_exp: + STRING + { + /* We copy the string here, and not in the + lexer, to guarantee that we do not leak a + string. Note that we follow the + NUL-termination convention of the + lexer. */ + struct typed_stoken *vec = XNEW (struct typed_stoken); + $$.len = 1; + $$.tokens = vec; + + vec->type = $1.type; + vec->length = $1.length; + vec->ptr = malloc ($1.length + 1); + memcpy (vec->ptr, $1.ptr, $1.length + 1); + } + + | string_exp STRING + { + /* Note that we NUL-terminate here, but just + for convenience. */ + char *p; + ++$$.len; + $$.tokens = realloc ($$.tokens, + $$.len * sizeof (struct typed_stoken)); + + p = malloc ($2.length + 1); + memcpy (p, $2.ptr, $2.length + 1); + + $$.tokens[$$.len - 1].type = $2.type; + $$.tokens[$$.len - 1].length = $2.length; + $$.tokens[$$.len - 1].ptr = p; + } + ; + +exp : string_exp + { + int i; + enum c_string_type type = C_STRING; + + for (i = 0; i < $1.len; ++i) { - 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); + switch ($1.tokens[i].type) + { + case C_STRING: + break; + case C_WIDE_STRING: + case C_STRING_16: + case C_STRING_32: + if (type != C_STRING + && type != $1.tokens[i].type) + error ("Undefined string concatenation."); + type = $1.tokens[i].type; + break; + default: + /* internal error */ + internal_error (__FILE__, __LINE__, + "unrecognized type in string concatenation"); + } } - 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); } + + write_exp_string_vector (type, &$1); + for (i = 0; i < $1.len; ++i) + free ($1.tokens[i].ptr); + free ($1.tokens); + } ; /* C++. */ exp : TRUEKEYWORD { write_exp_elt_opcode (OP_LONG); - write_exp_elt_type (builtin_type_bool); + 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 (builtin_type_bool); + write_exp_elt_type (parse_type->builtin_bool); write_exp_elt_longcst ((LONGEST) 0); write_exp_elt_opcode (OP_LONG); } ; @@ -567,8 +721,7 @@ block : BLOCKNAME 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)); @@ -578,8 +731,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)); @@ -594,8 +746,10 @@ variable: block COLONCOLON name qualified_name: typebase COLONCOLON name { struct type *type = $1; + CHECK_TYPEDEF (type); 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)); @@ -608,8 +762,10 @@ qualified_name: typebase COLONCOLON name { struct type *type = $1; struct stoken tmp_token; + CHECK_TYPEDEF (type); 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)); @@ -637,8 +793,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); @@ -650,16 +805,11 @@ variable: qualified_name 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); } ; @@ -670,9 +820,9 @@ variable: name_not_typename { if (symbol_read_needs_frame (sym)) { - if (innermost_block == 0 || - contained_in (block_found, - innermost_block)) + if (innermost_block == 0 + || contained_in (block_found, + innermost_block)) innermost_block = block_found; } @@ -689,8 +839,9 @@ variable: name_not_typename /* 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)) + 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); @@ -701,16 +852,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, 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 @@ -785,7 +932,7 @@ func_mod: '(' ')' { 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) @@ -794,71 +941,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 - { $$ = builtin_type_long; } + { $$ = parse_type->builtin_long; } | LONG SIGNED_KEYWORD - { $$ = builtin_type_long; } + { $$ = parse_type->builtin_long; } | SIGNED_KEYWORD LONG INT_KEYWORD - { $$ = builtin_type_long; } + { $$ = parse_type->builtin_long; } | UNSIGNED LONG INT_KEYWORD - { $$ = builtin_type_unsigned_long; } + { $$ = parse_type->builtin_unsigned_long; } | LONG UNSIGNED INT_KEYWORD - { $$ = builtin_type_unsigned_long; } + { $$ = parse_type->builtin_unsigned_long; } | LONG UNSIGNED - { $$ = builtin_type_unsigned_long; } + { $$ = 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 - { $$ = builtin_type_long_long; } + { $$ = parse_type->builtin_long_long; } | LONG LONG SIGNED_KEYWORD - { $$ = builtin_type_long_long; } + { $$ = parse_type->builtin_long_long; } | SIGNED_KEYWORD LONG LONG - { $$ = builtin_type_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 - { $$ = builtin_type_unsigned_long_long; } + { $$ = parse_type->builtin_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"); } + { $$ = parse_type->builtin_unsigned_long_long; } | SHORT INT_KEYWORD - { $$ = builtin_type_short; } + { $$ = parse_type->builtin_short; } | SHORT SIGNED_KEYWORD INT_KEYWORD - { $$ = builtin_type_short; } + { $$ = parse_type->builtin_short; } | SHORT SIGNED_KEYWORD - { $$ = builtin_type_short; } + { $$ = parse_type->builtin_short; } | UNSIGNED SHORT INT_KEYWORD - { $$ = builtin_type_unsigned_short; } + { $$ = parse_type->builtin_unsigned_short; } | SHORT UNSIGNED - { $$ = builtin_type_unsigned_short; } + { $$ = parse_type->builtin_unsigned_short; } | SHORT UNSIGNED INT_KEYWORD - { $$ = builtin_type_unsigned_short; } + { $$ = parse_type->builtin_unsigned_short; } | DOUBLE_KEYWORD - { $$ = builtin_type_double; } + { $$ = parse_type->builtin_double; } | LONG DOUBLE_KEYWORD - { $$ = builtin_type_long_double; } + { $$ = parse_type->builtin_long_double; } | STRUCT name { $$ = lookup_struct (copy_name ($2), expression_context_block); } @@ -872,13 +1015,17 @@ typebase /* Implements (approximately): (type-qualifier)* type-specifier */ { $$ = lookup_enum (copy_name ($2), expression_context_block); } | UNSIGNED typename - { $$ = lookup_unsigned_typename (TYPE_NAME($2.type)); } + { $$ = lookup_unsigned_typename (parse_language, + parse_gdbarch, + TYPE_NAME($2.type)); } | UNSIGNED - { $$ = builtin_type_unsigned_int; } + { $$ = parse_type->builtin_unsigned_int; } | SIGNED_KEYWORD typename - { $$ = lookup_signed_typename (TYPE_NAME($2.type)); } + { $$ = lookup_signed_typename (parse_language, + parse_gdbarch, + 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. */ @@ -890,6 +1037,77 @@ typebase /* Implements (approximately): (type-qualifier)* type-specifier */ { $$ = 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 @@ -897,19 +1115,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; } ; @@ -945,10 +1163,130 @@ const_or_volatile_noopt: const_and_volatile { push_type (tp_volatile); } ; +operator: OPERATOR NEW + { $$ = operator_stoken (" new"); } + | OPERATOR DELETE + { $$ = operator_stoken (" delete"); } + | OPERATOR NEW '[' ']' + { $$ = operator_stoken (" new[]"); } + | OPERATOR DELETE '[' ']' + { $$ = operator_stoken (" delete[]"); } + | OPERATOR '+' + { $$ = operator_stoken ("+"); } + | OPERATOR '-' + { $$ = operator_stoken ("-"); } + | OPERATOR '*' + { $$ = operator_stoken ("*"); } + | OPERATOR '/' + { $$ = operator_stoken ("/"); } + | OPERATOR '%' + { $$ = operator_stoken ("%"); } + | OPERATOR '^' + { $$ = operator_stoken ("^"); } + | OPERATOR '&' + { $$ = operator_stoken ("&"); } + | OPERATOR '|' + { $$ = operator_stoken ("|"); } + | OPERATOR '~' + { $$ = operator_stoken ("~"); } + | OPERATOR '!' + { $$ = operator_stoken ("!"); } + | OPERATOR '=' + { $$ = operator_stoken ("="); } + | OPERATOR '<' + { $$ = operator_stoken ("<"); } + | OPERATOR '>' + { $$ = operator_stoken (">"); } + | OPERATOR ASSIGN_MODIFY + { const char *op = "unknown"; + switch ($2) + { + case BINOP_RSH: + op = ">>="; + break; + case BINOP_LSH: + op = "<<="; + break; + case BINOP_ADD: + op = "+="; + break; + case BINOP_SUB: + op = "-="; + break; + case BINOP_MUL: + op = "*="; + break; + case BINOP_DIV: + op = "/="; + break; + case BINOP_REM: + op = "%="; + break; + case BINOP_BITWISE_IOR: + op = "|="; + break; + case BINOP_BITWISE_AND: + op = "&="; + break; + case BINOP_BITWISE_XOR: + op = "^="; + break; + default: + break; + } + + $$ = operator_stoken (op); + } + | OPERATOR LSH + { $$ = operator_stoken ("<<"); } + | OPERATOR RSH + { $$ = operator_stoken (">>"); } + | OPERATOR EQUAL + { $$ = operator_stoken ("=="); } + | OPERATOR NOTEQUAL + { $$ = operator_stoken ("!="); } + | OPERATOR LEQ + { $$ = operator_stoken ("<="); } + | OPERATOR GEQ + { $$ = operator_stoken (">="); } + | OPERATOR ANDAND + { $$ = operator_stoken ("&&"); } + | OPERATOR OROR + { $$ = operator_stoken ("||"); } + | OPERATOR INCREMENT + { $$ = operator_stoken ("++"); } + | OPERATOR DECREMENT + { $$ = operator_stoken ("--"); } + | OPERATOR ',' + { $$ = operator_stoken (","); } + | OPERATOR ARROW_STAR + { $$ = operator_stoken ("->*"); } + | OPERATOR ARROW + { $$ = operator_stoken ("->"); } + | OPERATOR '(' ')' + { $$ = operator_stoken ("()"); } + | OPERATOR '[' ']' + { $$ = operator_stoken ("[]"); } + | OPERATOR ptype + { char *name; + long length; + struct ui_file *buf = mem_fileopen (); + + c_print_type ($2, NULL, buf, -1, 0); + name = ui_file_xstrdup (buf, &length); + ui_file_delete (buf); + $$ = operator_stoken (name); + free (name); + } + ; + + + name : NAME { $$ = $1.stoken; } | BLOCKNAME { $$ = $1.stoken; } | TYPENAME { $$ = $1.stoken; } | NAME_OR_INT { $$ = $1.stoken; } + | operator { $$ = $1; } ; name_not_typename : NAME @@ -964,6 +1302,23 @@ name_not_typename : NAME %% +/* Returns a stoken of the operator name given by OP (which does not + include the string "operator"). */ +static struct stoken +operator_stoken (const char *op) +{ + static const char *operator_string = "operator"; + struct stoken st = { NULL, 0 }; + st.length = strlen (operator_string) + strlen (op); + st.ptr = malloc (st.length + 1); + strcpy (st.ptr, operator_string); + strcat (st.ptr, op); + + /* The toplevel (c_parse) will free the memory allocated here. */ + make_cleanup (free, st.ptr); + return st; +}; + /* 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. */ @@ -971,21 +1326,17 @@ name_not_typename : NAME /*** 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; +parse_number (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; + 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. */ @@ -1001,44 +1352,75 @@ parse_number (p, len, parsed_float, putithere) 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]; + char *s; + int num; /* number of tokens scanned by scanf */ + char saved_char; - 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 + /* 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') { -#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 - 2] = '\0'; + putithere->typed_val_decfloat.type + = parse_type->builtin_decfloat; + decimal_from_string (putithere->typed_val_decfloat.val, 4, + gdbarch_byte_order (parse_gdbarch), 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, + gdbarch_byte_order (parse_gdbarch), 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, + gdbarch_byte_order (parse_gdbarch), 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) /* 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; + 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; } @@ -1056,6 +1438,16 @@ parse_number (p, len, parsed_float, putithere) } break; + case 'b': + case 'B': + if (len >= 3) + { + p += 2; + base = 2; + len -= 2; + } + break; + case 't': case 'T': case 'd': @@ -1134,16 +1526,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 = (ULONGEST)n >> 2; if (long_p == 0 - && (un >> (TARGET_INT_BIT - 2)) == 0) + && (un >> (gdbarch_int_bit (parse_gdbarch) - 2)) == 0) { - high_bit = ((ULONGEST)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, @@ -1151,27 +1543,28 @@ 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 = ((ULONGEST)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 { int shift; - if (sizeof (ULONGEST) * HOST_CHAR_BIT < TARGET_LONG_LONG_BIT) + if (sizeof (ULONGEST) * HOST_CHAR_BIT + < gdbarch_long_long_bit (parse_gdbarch)) /* A long long does not fit in a LONGEST. */ shift = (sizeof (ULONGEST) * HOST_CHAR_BIT - 1); else - shift = (TARGET_LONG_LONG_BIT - 1); + shift = (gdbarch_long_long_bit (parse_gdbarch) - 1); high_bit = (ULONGEST) 1 << shift; - unsigned_type = builtin_type_unsigned_long_long; - signed_type = builtin_type_long_long; + unsigned_type = parse_type->builtin_unsigned_long_long; + signed_type = parse_type->builtin_long_long; } putithere->typed_val_int.val = n; @@ -1191,82 +1584,488 @@ parse_number (p, len, parsed_float, putithere) return INT; } +/* Temporary obstack used for holding strings. */ +static struct obstack tempbuf; +static int tempbuf_init; + +/* Parse a C escape sequence. The initial backslash of the sequence + is at (*PTR)[-1]. *PTR will be updated to point to just after the + last character of the sequence. If OUTPUT is not NULL, the + translated form of the escape sequence will be written there. If + OUTPUT is NULL, no output is written and the call will only affect + *PTR. If an escape sequence is expressed in target bytes, then the + entire sequence will simply be copied to OUTPUT. Return 1 if any + character was emitted, 0 otherwise. */ + +int +c_parse_escape (char **ptr, struct obstack *output) +{ + char *tokptr = *ptr; + int result = 1; + + /* Some escape sequences undergo character set conversion. Those we + translate here. */ + switch (*tokptr) + { + /* Hex escapes do not undergo character set conversion, so keep + the escape sequence for later. */ + case 'x': + if (output) + obstack_grow_str (output, "\\x"); + ++tokptr; + if (!isxdigit (*tokptr)) + error (_("\\x escape without a following hex digit")); + while (isxdigit (*tokptr)) + { + if (output) + obstack_1grow (output, *tokptr); + ++tokptr; + } + break; + + /* Octal escapes do not undergo character set conversion, so + keep the escape sequence for later. */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + int i; + if (output) + obstack_grow_str (output, "\\"); + for (i = 0; + i < 3 && isdigit (*tokptr) && *tokptr != '8' && *tokptr != '9'; + ++i) + { + if (output) + obstack_1grow (output, *tokptr); + ++tokptr; + } + } + break; + + /* We handle UCNs later. We could handle them here, but that + would mean a spurious error in the case where the UCN could + be converted to the target charset but not the host + charset. */ + case 'u': + case 'U': + { + char c = *tokptr; + int i, len = c == 'U' ? 8 : 4; + if (output) + { + obstack_1grow (output, '\\'); + obstack_1grow (output, *tokptr); + } + ++tokptr; + if (!isxdigit (*tokptr)) + error (_("\\%c escape without a following hex digit"), c); + for (i = 0; i < len && isxdigit (*tokptr); ++i) + { + if (output) + obstack_1grow (output, *tokptr); + ++tokptr; + } + } + break; + + /* We must pass backslash through so that it does not + cause quoting during the second expansion. */ + case '\\': + if (output) + obstack_grow_str (output, "\\\\"); + ++tokptr; + break; + + /* Escapes which undergo conversion. */ + case 'a': + if (output) + obstack_1grow (output, '\a'); + ++tokptr; + break; + case 'b': + if (output) + obstack_1grow (output, '\b'); + ++tokptr; + break; + case 'f': + if (output) + obstack_1grow (output, '\f'); + ++tokptr; + break; + case 'n': + if (output) + obstack_1grow (output, '\n'); + ++tokptr; + break; + case 'r': + if (output) + obstack_1grow (output, '\r'); + ++tokptr; + break; + case 't': + if (output) + obstack_1grow (output, '\t'); + ++tokptr; + break; + case 'v': + if (output) + obstack_1grow (output, '\v'); + ++tokptr; + break; + + /* GCC extension. */ + case 'e': + if (output) + obstack_1grow (output, HOST_ESCAPE_CHAR); + ++tokptr; + break; + + /* Backslash-newline expands to nothing at all. */ + case '\n': + ++tokptr; + result = 0; + break; + + /* A few escapes just expand to the character itself. */ + case '\'': + case '\"': + case '?': + /* GCC extensions. */ + case '(': + case '{': + case '[': + case '%': + /* Unrecognized escapes turn into the character itself. */ + default: + if (output) + obstack_1grow (output, *tokptr); + ++tokptr; + break; + } + *ptr = tokptr; + return result; +} + +/* Parse a string or character literal from TOKPTR. The string or + character may be wide or unicode. *OUTPTR is set to just after the + end of the literal in the input string. The resulting token is + stored in VALUE. This returns a token value, either STRING or + CHAR, depending on what was parsed. *HOST_CHARS is set to the + number of host characters in the literal. */ +static int +parse_string_or_char (char *tokptr, char **outptr, struct typed_stoken *value, + int *host_chars) +{ + int quote, i; + enum c_string_type type; + + /* Build the gdb internal form of the input string in tempbuf. 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 */ + + if (!tempbuf_init) + tempbuf_init = 1; + else + obstack_free (&tempbuf, NULL); + obstack_init (&tempbuf); + + /* Record the string type. */ + if (*tokptr == 'L') + { + type = C_WIDE_STRING; + ++tokptr; + } + else if (*tokptr == 'u') + { + type = C_STRING_16; + ++tokptr; + } + else if (*tokptr == 'U') + { + type = C_STRING_32; + ++tokptr; + } + else + type = C_STRING; + + /* Skip the quote. */ + quote = *tokptr; + if (quote == '\'') + type |= C_CHAR; + ++tokptr; + + *host_chars = 0; + + while (*tokptr) + { + char c = *tokptr; + if (c == '\\') + { + ++tokptr; + *host_chars += c_parse_escape (&tokptr, &tempbuf); + } + else if (c == quote) + break; + else + { + obstack_1grow (&tempbuf, c); + ++tokptr; + /* FIXME: this does the wrong thing with multi-byte host + characters. We could use mbrlen here, but that would + make "set host-charset" a bit less useful. */ + ++*host_chars; + } + } + + if (*tokptr != quote) + { + if (quote == '"') + error ("Unterminated string in expression."); + else + error ("Unmatched single quote."); + } + ++tokptr; + + value->type = type; + value->ptr = obstack_base (&tempbuf); + value->length = obstack_object_size (&tempbuf); + + *outptr = tokptr; + + return quote == '"' ? STRING : CHAR; +} + struct token { char *operator; int token; enum exp_opcode opcode; + int cxx_only; }; static const struct token tokentab3[] = { - {">>=", ASSIGN_MODIFY, BINOP_RSH}, - {"<<=", ASSIGN_MODIFY, BINOP_LSH} + {">>=", ASSIGN_MODIFY, BINOP_RSH, 0}, + {"<<=", ASSIGN_MODIFY, BINOP_LSH, 0}, + {"->*", ARROW_STAR, BINOP_END, 1} }; 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} + {"+=", ASSIGN_MODIFY, BINOP_ADD, 0}, + {"-=", ASSIGN_MODIFY, BINOP_SUB, 0}, + {"*=", ASSIGN_MODIFY, BINOP_MUL, 0}, + {"/=", ASSIGN_MODIFY, BINOP_DIV, 0}, + {"%=", ASSIGN_MODIFY, BINOP_REM, 0}, + {"|=", ASSIGN_MODIFY, BINOP_BITWISE_IOR, 0}, + {"&=", ASSIGN_MODIFY, BINOP_BITWISE_AND, 0}, + {"^=", ASSIGN_MODIFY, BINOP_BITWISE_XOR, 0}, + {"++", INCREMENT, BINOP_END, 0}, + {"--", DECREMENT, BINOP_END, 0}, + {"->", ARROW, BINOP_END, 0}, + {"&&", ANDAND, BINOP_END, 0}, + {"||", OROR, BINOP_END, 0}, + /* "::" is *not* only C++: gdb overrides its meaning in several + different ways, e.g., 'filename'::func, function::variable. */ + {"::", COLONCOLON, BINOP_END, 0}, + {"<<", LSH, BINOP_END, 0}, + {">>", RSH, BINOP_END, 0}, + {"==", EQUAL, BINOP_END, 0}, + {"!=", NOTEQUAL, BINOP_END, 0}, + {"<=", LEQ, BINOP_END, 0}, + {">=", GEQ, BINOP_END, 0}, + {".*", DOT_STAR, BINOP_END, 1} + }; + +/* Identifier-like tokens. */ +static const struct token ident_tokens[] = + { + {"unsigned", UNSIGNED, OP_NULL, 0}, + {"template", TEMPLATE, OP_NULL, 1}, + {"volatile", VOLATILE_KEYWORD, OP_NULL, 0}, + {"struct", STRUCT, OP_NULL, 0}, + {"signed", SIGNED_KEYWORD, OP_NULL, 0}, + {"sizeof", SIZEOF, OP_NULL, 0}, + {"double", DOUBLE_KEYWORD, OP_NULL, 0}, + {"false", FALSEKEYWORD, OP_NULL, 1}, + {"class", CLASS, OP_NULL, 1}, + {"union", UNION, OP_NULL, 0}, + {"short", SHORT, OP_NULL, 0}, + {"const", CONST_KEYWORD, OP_NULL, 0}, + {"enum", ENUM, OP_NULL, 0}, + {"long", LONG, OP_NULL, 0}, + {"true", TRUEKEYWORD, OP_NULL, 1}, + {"int", INT_KEYWORD, OP_NULL, 0}, + {"new", NEW, OP_NULL, 1}, + {"delete", DELETE, OP_NULL, 1}, + {"operator", OPERATOR, OP_NULL, 1}, + + {"and", ANDAND, BINOP_END, 1}, + {"and_eq", ASSIGN_MODIFY, BINOP_BITWISE_AND, 1}, + {"bitand", '&', OP_NULL, 1}, + {"bitor", '|', OP_NULL, 1}, + {"compl", '~', OP_NULL, 1}, + {"not", '!', OP_NULL, 1}, + {"not_eq", NOTEQUAL, BINOP_END, 1}, + {"or", OROR, BINOP_END, 1}, + {"or_eq", ASSIGN_MODIFY, BINOP_BITWISE_IOR, 1}, + {"xor", '^', OP_NULL, 1}, + {"xor_eq", ASSIGN_MODIFY, BINOP_BITWISE_XOR, 1}, + + {"const_cast", CONST_CAST, OP_NULL, 1 }, + {"dynamic_cast", DYNAMIC_CAST, OP_NULL, 1 }, + {"static_cast", STATIC_CAST, OP_NULL, 1 }, + {"reinterpret_cast", REINTERPRET_CAST, OP_NULL, 1 } }; +/* When we find that lexptr (the global var defined in parse.c) is + pointing at a macro invocation, we expand the invocation, and call + scan_macro_expansion to save the old lexptr here and point lexptr + into the expanded text. When we reach the end of that, we call + end_macro_expansion to pop back to the value we saved here. The + macro expansion code promises to return only fully-expanded text, + so we don't need to "push" more than one level. + + This is disgusting, of course. It would be cleaner to do all macro + expansion beforehand, and then hand that to lexptr. But we don't + really know where the expression ends. Remember, in a command like + + (gdb) break *ADDRESS if CONDITION + + we evaluate ADDRESS in the scope of the current frame, but we + evaluate CONDITION in the scope of the breakpoint's location. So + it's simply wrong to try to macro-expand the whole thing at once. */ +static char *macro_original_text; + +/* We save all intermediate macro expansions on this obstack for the + duration of a single parse. The expansion text may sometimes have + to live past the end of the expansion, due to yacc lookahead. + Rather than try to be clever about saving the data for a single + token, we simply keep it all and delete it after parsing has + completed. */ +static struct obstack expansion_obstack; + +static void +scan_macro_expansion (char *expansion) +{ + char *copy; + + /* We'd better not be trying to push the stack twice. */ + gdb_assert (! macro_original_text); + + /* Copy to the obstack, and then free the intermediate + expansion. */ + copy = obstack_copy0 (&expansion_obstack, expansion, strlen (expansion)); + xfree (expansion); + + /* Save the old lexptr value, so we can return to it when we're done + parsing the expanded text. */ + macro_original_text = lexptr; + lexptr = copy; +} + + +static int +scanning_macro_expansion (void) +{ + return macro_original_text != 0; +} + + +static void +finished_macro_expansion (void) +{ + /* There'd better be something to pop back to. */ + gdb_assert (macro_original_text); + + /* Pop back to the original text. */ + lexptr = macro_original_text; + macro_original_text = 0; +} + + +static void +scan_macro_cleanup (void *dummy) +{ + if (macro_original_text) + finished_macro_expansion (); + + obstack_free (&expansion_obstack, NULL); +} + +/* Return true iff the token represents a C++ cast operator. */ + +static int +is_cast_operator (const char *token, int len) +{ + return (! strncmp (token, "dynamic_cast", len) + || ! strncmp (token, "static_cast", len) + || ! strncmp (token, "reinterpret_cast", len) + || ! strncmp (token, "const_cast", len)); +} + +/* The scope used for macro expansion. */ +static struct macro_scope *expression_macro_scope; + +/* 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 -yylex () +yylex (void) { 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; - + int saw_structop = last_was_structop; + char *copy; + + 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); + standard_macro_lookup, + expression_macro_scope); 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)) + if (strncmp (tokstart, tokentab3[i].operator, 3) == 0) { + if (tokentab3[i].cxx_only + && parse_language->la_language != language_cplus) + break; + lexptr += 3; yylval.opcode = tokentab3[i].opcode; return tokentab3[i].token; @@ -1274,10 +2073,16 @@ 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) { + if (tokentab2[i].cxx_only + && parse_language->la_language != language_cplus) + break; + lexptr += 2; yylval.opcode = tokentab2[i].opcode; + if (in_parse_field && tokentab2[i].token == ARROW) + last_was_structop = 1; return tokentab2[i].token; } @@ -1286,6 +2091,8 @@ yylex () case 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 ()) @@ -1293,6 +2100,13 @@ yylex () 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; @@ -1302,52 +2116,13 @@ yylex () 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 '[': case '(': paren_depth++; lexptr++; return c; + case ']': case ')': if (paren_depth == 0) return 0; @@ -1366,7 +2141,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': @@ -1382,7 +2161,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')) @@ -1445,8 +2224,6 @@ yylex () case '@': case '<': case '>': - case '[': - case ']': case '?': case ':': case '=': @@ -1456,70 +2233,33 @@ yylex () lexptr++; return c; + case 'L': + case 'u': + case 'U': + if (tokstart[1] != '"' && tokstart[1] != '\'') + break; + /* Fall through. */ + case '\'': 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) + { + int host_len; + int result = parse_string_or_char (tokstart, &lexptr, &yylval.tsval, + &host_len); + if (result == CHAR) { - case '\0': - case '"': - /* Do nothing, loop will terminate. */ - break; - case '\\': - tokptr++; - c = parse_escape (&tokptr); - if (c == -1) + if (host_len == 0) + error ("Empty character constant."); + else if (host_len > 2 && c == '\'') { - continue; + ++tokstart; + namelen = lexptr - tokstart - 1; + goto tryname; } - 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; + else if (host_len > 1) + error ("Invalid character constant."); } - } 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); + return result; + } } if (!(c == '_' || c == '$' @@ -1537,16 +2277,19 @@ yylex () 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. */ + { + if (! is_cast_operator (tokstart, namelen)) + { + /* 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; + char * p = find_template_name_end (tokstart + namelen); + if (p) + namelen = p - tokstart; + } + break; } c = tokstart[++namelen]; } @@ -1562,109 +2305,66 @@ yylex () return 0; } + /* For the same reason (breakpoint conditions), "thread N" + terminates the expression. "thread" could be an identifier, but + an identifier is never followed by a number without intervening + punctuation. "task" is similar. Handle abbreviations of these, + similarly to breakpoint.c:find_condition_and_thread. */ + if (namelen >= 1 + && (strncmp (tokstart, "thread", namelen) == 0 + || strncmp (tokstart, "task", namelen) == 0) + && (tokstart[namelen] == ' ' || tokstart[namelen] == '\t') + && ! scanning_macro_expansion ()) + { + char *p = tokstart + namelen + 1; + while (*p == ' ' || *p == '\t') + p++; + if (*p >= '0' && *p <= '9') + 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; + /* Catch specific keywords. */ + copy = copy_name (yylval.sval); + for (i = 0; i < sizeof ident_tokens / sizeof ident_tokens[0]; i++) + if (strcmp (copy, ident_tokens[i].operator) == 0) + { + if (ident_tokens[i].cxx_only + && parse_language->la_language != language_cplus) + break; + + /* It is ok to always set this, even though we don't always + strictly need to. */ + yylval.opcode = ident_tokens[i].opcode; + return ident_tokens[i].token; + } + 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); + sym = lookup_symbol (copy, expression_context_block, + 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). */ @@ -1678,7 +2378,7 @@ yylex () { /* See if it's a file name. */ struct symtab *symtab; - symtab = lookup_symtab (tmp); + symtab = lookup_symtab (copy); if (symtab) { @@ -1689,103 +2389,24 @@ yylex () 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 */ + /* 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) + yylval.tsym.type + = language_lookup_primitive_type_by_name (parse_language, + parse_gdbarch, copy); + 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 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))) + 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); @@ -1800,13 +2421,50 @@ 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) +{ + int result; + struct cleanup *back_to = make_cleanup (free_current_contents, + &expression_macro_scope); + + /* Set up the scope for macro expansion. */ + expression_macro_scope = NULL; + + if (expression_context_block) + expression_macro_scope + = sal_macro_scope (find_pc_line (expression_context_pc, 0)); + else + expression_macro_scope = default_macro_scope (); + if (! expression_macro_scope) + expression_macro_scope = user_macro_scope (); + + /* Initialize macro expansion code. */ + obstack_init (&expansion_obstack); + gdb_assert (! macro_original_text); + make_cleanup (scan_macro_cleanup, 0); + + make_cleanup_restore_integer (&yydebug); + yydebug = parser_debug; + + /* Initialize some state used by the lexer. */ + last_was_structop = 0; + saw_name_at_eof = 0; + + result = yyparse (); + do_cleanups (back_to); + return result; +} + + void -yyerror (msg) - char *msg; +yyerror (char *msg) { if (prev_lexptr) lexptr = prev_lexptr;