X-Git-Url: https://repo.jachan.dev/binutils.git/blobdiff_plain/379a77b5484ba0d8f29983175acb2b968f56785a..cc80f267162ba7f1cab2fcf605270a3510cf010b:/gdb/c-exp.y diff --git a/gdb/c-exp.y b/gdb/c-exp.y index 688c060ef2..e912657754 100644 --- a/gdb/c-exp.y +++ b/gdb/c-exp.y @@ -1,7 +1,6 @@ /* YACC parser for C expressions, for GDB. - Copyright (C) 1986, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, - 1998, 1999, 2000, 2003, 2004, 2006, 2007, 2008, 2009 - Free Software Foundation, Inc. + Copyright (C) 1986, 1989-2000, 2003-2004, 2006-2012 Free Software + Foundation, Inc. This file is part of GDB. @@ -104,6 +103,12 @@ #define yygindex c_yygindex #define yytable c_yytable #define yycheck c_yycheck +#define yyss c_yyss +#define yysslim c_yysslim +#define yyssp c_yyssp +#define yystacksize c_yystacksize +#define yyvs c_yyvs +#define yyvsp c_yyvsp #ifndef YYDEBUG #define YYDEBUG 1 /* Default to yydebug support */ @@ -157,11 +162,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 qualified_type +%type type typebase %type nonempty_typelist /* %type block */ @@ -185,6 +191,7 @@ static int parse_number (char *, int, int, YYSTYPE *); %token STRING %token CHAR %token NAME /* BLOCKNAME defined below to give it higher precedence. */ +%token UNKNOWN_CPP_NAME %token COMPLETE %token TYPENAME %type name @@ -199,15 +206,20 @@ 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 +%token ENTRY /* Special type cases, put in to allow the parser to distinguish different legal basetypes. */ %token SIGNED_KEYWORD LONG SHORT INT_KEYWORD CONST_KEYWORD VOLATILE_KEYWORD DOUBLE_KEYWORD -%token VARIABLE +%token VARIABLE %token ASSIGN_MODIFY @@ -232,7 +244,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 @@ -333,7 +345,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); } ; @@ -368,7 +380,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); } ; @@ -386,6 +398,29 @@ exp : exp '(' write_exp_elt_opcode (OP_FUNCALL); } ; +exp : UNKNOWN_CPP_NAME '(' + { + /* This could potentially be a an argument defined + lookup function (Koenig). */ + write_exp_elt_opcode (OP_ADL_FUNC); + write_exp_elt_block (expression_context_block); + write_exp_elt_sym (NULL); /* Placeholder. */ + write_exp_string ($1.stoken); + write_exp_elt_opcode (OP_ADL_FUNC); + + /* This is to save the value of arglist_len + being accumulated by an outer function call. */ + + start_arglist (); + } + arglist ')' %prec ARROW + { + write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst ((LONGEST) end_arglist ()); + write_exp_elt_opcode (OP_FUNCALL); + } + ; + lcurly : '{' { start_arglist (); } ; @@ -401,6 +436,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; } ; @@ -564,17 +611,47 @@ exp : variable ; exp : VARIABLE - /* Already written by write_dollar_variable. */ + { + write_dollar_variable ($1); + } ; exp : SIZEOF '(' type ')' %prec UNARY { write_exp_elt_opcode (OP_LONG); - write_exp_elt_type (parse_type->builtin_int); + write_exp_elt_type (lookup_signed_typename + (parse_language, parse_gdbarch, + "int")); CHECK_TYPEDEF ($3); write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3)); write_exp_elt_opcode (OP_LONG); } ; +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 { @@ -627,7 +704,7 @@ exp : string_exp case C_STRING_32: if (type != C_STRING && type != $1.tokens[i].type) - error ("Undefined string concatenation."); + error (_("Undefined string concatenation.")); type = $1.tokens[i].type; break; default: @@ -666,7 +743,7 @@ block : BLOCKNAME if ($1.sym) $$ = SYMBOL_BLOCK_VALUE ($1.sym); else - error ("No file or function \"%s\".", + error (_("No file or function \"%s\"."), copy_name ($1.stoken)); } | FILENAME @@ -680,18 +757,40 @@ block : block COLONCOLON name = lookup_symbol (copy_name ($3), $1, VAR_DOMAIN, (int *) NULL); if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK) - error ("No function \"%s\" in specified context.", + error (_("No function \"%s\" in specified context."), copy_name ($3)); $$ = SYMBOL_BLOCK_VALUE (tem); } ; +variable: name_not_typename ENTRY + { struct symbol *sym = $1.sym; + + if (sym == NULL || !SYMBOL_IS_ARGUMENT (sym) + || !symbol_read_needs_frame (sym)) + error (_("@entry can be used only for function " + "parameters, not for \"%s\""), + copy_name ($1.stoken)); + + write_exp_elt_opcode (OP_VAR_ENTRY_VALUE); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_ENTRY_VALUE); + } + ; + variable: block COLONCOLON name { struct symbol *sym; sym = lookup_symbol (copy_name ($3), $1, VAR_DOMAIN, (int *) NULL); if (sym == 0) - error ("No symbol \"%s\" in specified context.", + error (_("No symbol \"%s\" in specified context."), copy_name ($3)); + if (symbol_read_needs_frame (sym)) + { + if (innermost_block == 0 + || contained_in (block_found, + innermost_block)) + innermost_block = block_found; + } write_exp_elt_opcode (OP_VAR_VALUE); /* block_found is set by lookup_symbol. */ @@ -700,13 +799,14 @@ variable: block COLONCOLON name write_exp_elt_opcode (OP_VAR_VALUE); } ; -qualified_name: typebase COLONCOLON name +qualified_name: TYPENAME COLONCOLON name { - struct type *type = $1; + struct type *type = $1.type; + CHECK_TYPEDEF (type); 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.", + error (_("`%s' is not defined as an aggregate type."), TYPE_NAME (type)); write_exp_elt_opcode (OP_SCOPE); @@ -714,14 +814,15 @@ qualified_name: typebase COLONCOLON name write_exp_string ($3); write_exp_elt_opcode (OP_SCOPE); } - | typebase COLONCOLON '~' name + | TYPENAME COLONCOLON '~' name { - struct type *type = $1; + struct type *type = $1.type; 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_NAMESPACE) - error ("`%s' is not defined as an aggregate type.", + error (_("`%s' is not defined as an aggregate type."), TYPE_NAME (type)); tmp_token.ptr = (char*) alloca ($4.length + 2); @@ -731,18 +832,25 @@ qualified_name: typebase COLONCOLON name tmp_token.ptr[tmp_token.length] = 0; /* Check for valid destructor name. */ - destructor_name_p (tmp_token.ptr, type); + destructor_name_p (tmp_token.ptr, $1.type); write_exp_elt_opcode (OP_SCOPE); write_exp_elt_type (type); write_exp_string (tmp_token); write_exp_elt_opcode (OP_SCOPE); } + | TYPENAME COLONCOLON name COLONCOLON name + { + char *copy = copy_name ($3); + error (_("No type \"%s\" within class " + "or namespace \"%s\"."), + copy, TYPE_NAME ($1.type)); + } ; variable: qualified_name - | COLONCOLON name + | COLONCOLON name_not_typename { - char *name = copy_name ($2); + char *name = copy_name ($2.stoken); struct symbol *sym; struct minimal_symbol *msymbol; @@ -762,9 +870,9 @@ variable: qualified_name if (msymbol != NULL) write_exp_msymbol (msymbol); else if (!have_full_symbols () && !have_partial_symbols ()) - error ("No symbol table is loaded. Use the \"file\" command."); + 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); } ; @@ -775,9 +883,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; } @@ -794,8 +902,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); @@ -813,9 +922,9 @@ variable: name_not_typename if (msymbol != NULL) write_exp_msymbol (msymbol); else if (!have_full_symbols () && !have_partial_symbols ()) - error ("No symbol table is loaded. Use the \"file\" command."); + error (_("No symbol table is loaded. Use the \"file\" command.")); else - error ("No symbol \"%s\" in current context.", + error (_("No symbol \"%s\" in current context."), copy_name ($1.stoken)); } } @@ -901,61 +1010,117 @@ typebase /* Implements (approximately): (type-qualifier)* type-specifier */ : TYPENAME { $$ = $1.type; } | INT_KEYWORD - { $$ = parse_type->builtin_int; } + { $$ = lookup_signed_typename (parse_language, + parse_gdbarch, + "int"); } | LONG - { $$ = parse_type->builtin_long; } + { $$ = lookup_signed_typename (parse_language, + parse_gdbarch, + "long"); } | SHORT - { $$ = parse_type->builtin_short; } + { $$ = lookup_signed_typename (parse_language, + parse_gdbarch, + "short"); } | LONG INT_KEYWORD - { $$ = parse_type->builtin_long; } + { $$ = lookup_signed_typename (parse_language, + parse_gdbarch, + "long"); } | LONG SIGNED_KEYWORD INT_KEYWORD - { $$ = parse_type->builtin_long; } + { $$ = lookup_signed_typename (parse_language, + parse_gdbarch, + "long"); } | LONG SIGNED_KEYWORD - { $$ = parse_type->builtin_long; } + { $$ = lookup_signed_typename (parse_language, + parse_gdbarch, + "long"); } | SIGNED_KEYWORD LONG INT_KEYWORD - { $$ = parse_type->builtin_long; } + { $$ = lookup_signed_typename (parse_language, + parse_gdbarch, + "long"); } | UNSIGNED LONG INT_KEYWORD - { $$ = parse_type->builtin_unsigned_long; } + { $$ = lookup_unsigned_typename (parse_language, + parse_gdbarch, + "long"); } | LONG UNSIGNED INT_KEYWORD - { $$ = parse_type->builtin_unsigned_long; } + { $$ = lookup_unsigned_typename (parse_language, + parse_gdbarch, + "long"); } | LONG UNSIGNED - { $$ = parse_type->builtin_unsigned_long; } + { $$ = lookup_unsigned_typename (parse_language, + parse_gdbarch, + "long"); } | LONG LONG - { $$ = parse_type->builtin_long_long; } + { $$ = lookup_signed_typename (parse_language, + parse_gdbarch, + "long long"); } | LONG LONG INT_KEYWORD - { $$ = parse_type->builtin_long_long; } + { $$ = lookup_signed_typename (parse_language, + parse_gdbarch, + "long long"); } | LONG LONG SIGNED_KEYWORD INT_KEYWORD - { $$ = parse_type->builtin_long_long; } + { $$ = lookup_signed_typename (parse_language, + parse_gdbarch, + "long long"); } | LONG LONG SIGNED_KEYWORD - { $$ = parse_type->builtin_long_long; } + { $$ = lookup_signed_typename (parse_language, + parse_gdbarch, + "long long"); } | SIGNED_KEYWORD LONG LONG - { $$ = parse_type->builtin_long_long; } + { $$ = lookup_signed_typename (parse_language, + parse_gdbarch, + "long long"); } | SIGNED_KEYWORD LONG LONG INT_KEYWORD - { $$ = parse_type->builtin_long_long; } + { $$ = lookup_signed_typename (parse_language, + parse_gdbarch, + "long long"); } | UNSIGNED LONG LONG - { $$ = parse_type->builtin_unsigned_long_long; } + { $$ = lookup_unsigned_typename (parse_language, + parse_gdbarch, + "long long"); } | UNSIGNED LONG LONG INT_KEYWORD - { $$ = parse_type->builtin_unsigned_long_long; } + { $$ = lookup_unsigned_typename (parse_language, + parse_gdbarch, + "long long"); } | LONG LONG UNSIGNED - { $$ = parse_type->builtin_unsigned_long_long; } + { $$ = lookup_unsigned_typename (parse_language, + parse_gdbarch, + "long long"); } | LONG LONG UNSIGNED INT_KEYWORD - { $$ = parse_type->builtin_unsigned_long_long; } + { $$ = lookup_unsigned_typename (parse_language, + parse_gdbarch, + "long long"); } | SHORT INT_KEYWORD - { $$ = parse_type->builtin_short; } + { $$ = lookup_signed_typename (parse_language, + parse_gdbarch, + "short"); } | SHORT SIGNED_KEYWORD INT_KEYWORD - { $$ = parse_type->builtin_short; } + { $$ = lookup_signed_typename (parse_language, + parse_gdbarch, + "short"); } | SHORT SIGNED_KEYWORD - { $$ = parse_type->builtin_short; } + { $$ = lookup_signed_typename (parse_language, + parse_gdbarch, + "short"); } | UNSIGNED SHORT INT_KEYWORD - { $$ = parse_type->builtin_unsigned_short; } + { $$ = lookup_unsigned_typename (parse_language, + parse_gdbarch, + "short"); } | SHORT UNSIGNED - { $$ = parse_type->builtin_unsigned_short; } + { $$ = lookup_unsigned_typename (parse_language, + parse_gdbarch, + "short"); } | SHORT UNSIGNED INT_KEYWORD - { $$ = parse_type->builtin_unsigned_short; } + { $$ = lookup_unsigned_typename (parse_language, + parse_gdbarch, + "short"); } | DOUBLE_KEYWORD - { $$ = parse_type->builtin_double; } + { $$ = lookup_typename (parse_language, parse_gdbarch, + "double", (struct block *) NULL, + 0); } | LONG DOUBLE_KEYWORD - { $$ = parse_type->builtin_long_double; } + { $$ = lookup_typename (parse_language, parse_gdbarch, + "long double", + (struct block *) NULL, 0); } | STRUCT name { $$ = lookup_struct (copy_name ($2), expression_context_block); } @@ -969,13 +1134,21 @@ 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 - { $$ = parse_type->builtin_unsigned_int; } + { $$ = lookup_unsigned_typename (parse_language, + parse_gdbarch, + "int"); } | SIGNED_KEYWORD typename - { $$ = lookup_signed_typename (TYPE_NAME($2.type)); } + { $$ = lookup_signed_typename (parse_language, + parse_gdbarch, + TYPE_NAME($2.type)); } | SIGNED_KEYWORD - { $$ = parse_type->builtin_int; } + { $$ = lookup_signed_typename (parse_language, + parse_gdbarch, + "int"); } /* It appears that this rule for templates is never reduced; template recognition happens by lookahead in the token processing code in yylex. */ @@ -987,77 +1160,6 @@ 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 @@ -1065,19 +1167,25 @@ typename: TYPENAME { $$.stoken.ptr = "int"; $$.stoken.length = 3; - $$.type = parse_type->builtin_int; + $$.type = lookup_signed_typename (parse_language, + parse_gdbarch, + "int"); } | LONG { $$.stoken.ptr = "long"; $$.stoken.length = 4; - $$.type = parse_type->builtin_long; + $$.type = lookup_signed_typename (parse_language, + parse_gdbarch, + "long"); } | SHORT { $$.stoken.ptr = "short"; $$.stoken.length = 5; - $$.type = parse_type->builtin_short; + $$.type = lookup_signed_typename (parse_language, + parse_gdbarch, + "short"); } ; @@ -1113,10 +1221,131 @@ 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; } + | UNKNOWN_CPP_NAME { $$ = $1.stoken; } + | operator { $$ = $1; } ; name_not_typename : NAME @@ -1128,10 +1357,36 @@ name_not_typename : NAME context where only a name could occur, this might be useful. | NAME_OR_INT */ + | operator + { + $$.stoken = $1; + $$.sym = lookup_symbol ($1.ptr, + expression_context_block, + VAR_DOMAIN, + &$$.is_a_field_of_this); + } + | UNKNOWN_CPP_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. */ @@ -1139,11 +1394,7 @@ name_not_typename : NAME /*** Needs some error checking for the float case ***/ static int -parse_number (p, len, parsed_float, putithere) - char *p; - 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. */ @@ -1168,11 +1419,6 @@ parse_number (p, len, parsed_float, putithere) if (parsed_float) { - /* It's a float since it contains a point or an exponent. */ - 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. */ @@ -1181,7 +1427,8 @@ parse_number (p, len, parsed_float, putithere) p[len - 2] = '\0'; putithere->typed_val_decfloat.type = parse_type->builtin_decfloat; - decimal_from_string (putithere->typed_val_decfloat.val, 4, p); + decimal_from_string (putithere->typed_val_decfloat.val, 4, + gdbarch_byte_order (parse_gdbarch), p); p[len - 2] = 'd'; return DECFLOAT; } @@ -1191,7 +1438,8 @@ parse_number (p, len, parsed_float, putithere) p[len - 2] = '\0'; putithere->typed_val_decfloat.type = parse_type->builtin_decdouble; - decimal_from_string (putithere->typed_val_decfloat.val, 8, p); + decimal_from_string (putithere->typed_val_decfloat.val, 8, + gdbarch_byte_order (parse_gdbarch), p); p[len - 2] = 'd'; return DECFLOAT; } @@ -1201,40 +1449,16 @@ parse_number (p, len, parsed_float, putithere) p[len - 2] = '\0'; putithere->typed_val_decfloat.type = parse_type->builtin_declong; - decimal_from_string (putithere->typed_val_decfloat.val, 16, p); + 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) - 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); + if (! parse_c_float (parse_gdbarch, p, len, + &putithere->typed_val_float.dval, + &putithere->typed_val_float.type)) + return ERROR; return FLOAT; } @@ -1252,6 +1476,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': @@ -1318,7 +1552,7 @@ parse_number (p, len, parsed_float, putithere) if (c != 'l' && c != 'u' && n != 0) { if ((unsigned_p && (ULONGEST) prevn >= (ULONGEST) n)) - error ("Numeric constant too large."); + error (_("Numeric constant too large.")); } prevn = n; } @@ -1437,14 +1671,19 @@ c_parse_escape (char **ptr, struct obstack *output) case '5': case '6': case '7': - if (output) - obstack_grow_str (output, "\\"); - while (isdigit (*tokptr) && *tokptr != '8' && *tokptr != '9') - { - if (output) - obstack_1grow (output, *tokptr); - ++tokptr; - } + { + 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 @@ -1561,7 +1800,7 @@ static int parse_string_or_char (char *tokptr, char **outptr, struct typed_stoken *value, int *host_chars) { - int quote, i; + int quote; enum c_string_type type; /* Build the gdb internal form of the input string in tempbuf. Note @@ -1630,9 +1869,9 @@ parse_string_or_char (char *tokptr, char **outptr, struct typed_stoken *value, if (*tokptr != quote) { if (quote == '"') - error ("Unterminated string in expression."); + error (_("Unterminated string in expression.")); else - error ("Unmatched single quote."); + error (_("Unmatched single quote.")); } ++tokptr; @@ -1656,7 +1895,8 @@ struct token static const struct token tokentab3[] = { {">>=", ASSIGN_MODIFY, BINOP_RSH, 0}, - {"<<=", ASSIGN_MODIFY, BINOP_LSH, 0} + {"<<=", ASSIGN_MODIFY, BINOP_LSH, 0}, + {"->*", ARROW_STAR, BINOP_END, 1} }; static const struct token tokentab2[] = @@ -1674,13 +1914,16 @@ static const struct token tokentab2[] = {"->", 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} + {">=", GEQ, BINOP_END, 0}, + {".*", DOT_STAR, BINOP_END, 1} }; /* Identifier-like tokens. */ @@ -1702,6 +1945,9 @@ static const struct token ident_tokens[] = {"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}, @@ -1713,7 +1959,12 @@ static const struct token ident_tokens[] = {"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} + {"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 @@ -1791,6 +2042,16 @@ scan_macro_cleanup (void *dummy) 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; @@ -1808,7 +2069,7 @@ static int last_was_structop; /* Read one token, getting characters through lexptr. */ static int -yylex () +lex_one_token (void) { int c; int namelen; @@ -1839,6 +2100,10 @@ yylex () for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++) 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; @@ -1848,6 +2113,10 @@ yylex () for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++) 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) @@ -1974,12 +2243,27 @@ yylex () memcpy (err_copy, tokstart, p - tokstart); err_copy[p - tokstart] = 0; - error ("Invalid number \"%s\".", err_copy); + error (_("Invalid number \"%s\"."), err_copy); } lexptr = p; return toktype; } + case '@': + { + char *p = &tokstart[1]; + size_t len = strlen ("entry"); + + while (isspace (*p)) + p++; + if (strncmp (p, "entry", len) == 0 && !isalnum (p[len]) + && p[len] != '_') + { + lexptr = &p[len]; + return ENTRY; + } + } + /* FALLTHRU */ case '+': case '-': case '*': @@ -1990,7 +2274,6 @@ yylex () case '^': case '~': case '!': - case '@': case '<': case '>': case '?': @@ -2017,7 +2300,7 @@ yylex () if (result == CHAR) { if (host_len == 0) - error ("Empty character constant."); + error (_("Empty character constant.")); else if (host_len > 2 && c == '\'') { ++tokstart; @@ -2025,7 +2308,7 @@ yylex () goto tryname; } else if (host_len > 1) - error ("Invalid character constant."); + error (_("Invalid character constant.")); } return result; } @@ -2034,7 +2317,7 @@ yylex () if (!(c == '_' || c == '$' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) /* We must have come across a bad character (e.g. ';'). */ - error ("Invalid character '%c' in expression.", c); + error (_("Invalid character '%c' in expression."), c); /* It's a name. See how long it is. */ namelen = 0; @@ -2046,16 +2329,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]; } @@ -2071,6 +2357,24 @@ 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: @@ -2094,85 +2398,256 @@ yylex () } if (*tokstart == '$') + return VARIABLE; + + if (in_parse_field && *lexptr == '\0') + saw_name_at_eof = 1; + return NAME; +} + +/* An object of this type is pushed on a FIFO by the "outer" lexer. */ +typedef struct +{ + int token; + YYSTYPE value; +} token_and_value; + +DEF_VEC_O (token_and_value); + +/* A FIFO of tokens that have been read but not yet returned to the + parser. */ +static VEC (token_and_value) *token_fifo; + +/* Non-zero if the lexer should return tokens from the FIFO. */ +static int popping; + +/* Temporary storage for c_lex; this holds symbol names as they are + built up. */ +static struct obstack name_obstack; + +/* Classify a NAME token. The contents of the token are in `yylval'. + Updates yylval and returns the new token type. BLOCK is the block + in which lookups start; this can be NULL to mean the global + scope. */ +static int +classify_name (struct block *block) +{ + struct symbol *sym; + char *copy; + int is_a_field_of_this = 0; + + copy = copy_name (yylval.sval); + + sym = lookup_symbol (copy, block, VAR_DOMAIN, + parse_language->la_language == language_cplus + ? &is_a_field_of_this : (int *) NULL); + + if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) { - write_dollar_variable (yylval.sval); - return VARIABLE; + yylval.ssym.sym = sym; + yylval.ssym.is_a_field_of_this = is_a_field_of_this; + return BLOCKNAME; } - - /* 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. */ - { - struct symbol *sym; - int is_a_field_of_this = 0; - int hextype; - - 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). */ - 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 (copy); + else if (!sym) + { + /* See if it's a file name. */ + struct symtab *symtab; - if (symtab) - { - yylval.bval = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK); - return FILENAME; - } - } + symtab = lookup_symtab (copy); + if (symtab) + { + yylval.bval = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK); + return FILENAME; + } + } - if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF) - { - /* 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); - return TYPENAME; - } - yylval.tsym.type - = language_lookup_primitive_type_by_name (parse_language, - parse_gdbarch, copy); - if (yylval.tsym.type != NULL) + if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF) + { + yylval.tsym.type = SYMBOL_TYPE (sym); return TYPENAME; + } - /* Input names that aren't symbols but ARE valid hex numbers, - when the input radix permits them, can be names or numbers - depending on the parse. Note we support radixes > 16 here. */ - if (!sym && - ((tokstart[0] >= 'a' && tokstart[0] < 'a' + input_radix - 10) || - (tokstart[0] >= 'A' && tokstart[0] < 'A' + input_radix - 10))) - { - YYSTYPE newlval; /* Its value is ignored. */ - hextype = parse_number (tokstart, namelen, 0, &newlval); - if (hextype == INT) - { - yylval.ssym.sym = sym; - yylval.ssym.is_a_field_of_this = is_a_field_of_this; - return NAME_OR_INT; - } - } + 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 + && ((copy[0] >= 'a' && copy[0] < 'a' + input_radix - 10) + || (copy[0] >= 'A' && copy[0] < 'A' + input_radix - 10))) + { + YYSTYPE newlval; /* Its value is ignored. */ + int hextype = parse_number (copy, yylval.sval.length, 0, &newlval); + if (hextype == INT) + { + yylval.ssym.sym = sym; + yylval.ssym.is_a_field_of_this = is_a_field_of_this; + return NAME_OR_INT; + } + } + + /* Any other kind of symbol */ + yylval.ssym.sym = sym; + yylval.ssym.is_a_field_of_this = is_a_field_of_this; + + if (sym == NULL + && parse_language->la_language == language_cplus + && !is_a_field_of_this + && !lookup_minimal_symbol (copy, NULL, NULL)) + return UNKNOWN_CPP_NAME; + + return NAME; +} + +/* Like classify_name, but used by the inner loop of the lexer, when a + name might have already been seen. FIRST_NAME is true if the token + in `yylval' is the first component of a name, false otherwise. If + this function returns NAME, it might not have updated `yylval'. + This is ok because the caller only cares about TYPENAME. */ +static int +classify_inner_name (struct block *block, int first_name) +{ + struct type *type, *new_type; + char *copy; + + if (first_name) + return classify_name (block); - /* 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; + type = check_typedef (yylval.tsym.type); + if (TYPE_CODE (type) != TYPE_CODE_STRUCT + && TYPE_CODE (type) != TYPE_CODE_UNION + && TYPE_CODE (type) != TYPE_CODE_NAMESPACE) + /* We know the caller won't expect us to update yylval. */ return NAME; - } + + copy = copy_name (yylval.tsym.stoken); + new_type = cp_lookup_nested_type (yylval.tsym.type, copy, block); + + if (new_type == NULL) + /* We know the caller won't expect us to update yylval. */ + return NAME; + + yylval.tsym.type = new_type; + return TYPENAME; +} + +/* The outer level of a two-level lexer. This calls the inner lexer + to return tokens. It then either returns these tokens, or + aggregates them into a larger token. This lets us work around a + problem in our parsing approach, where the parser could not + distinguish between qualified names and qualified types at the + right point. + + This approach is still not ideal, because it mishandles template + types. See the comment in lex_one_token for an example. However, + this is still an improvement over the earlier approach, and will + suffice until we move to better parsing technology. */ +static int +yylex (void) +{ + token_and_value current; + int first_was_coloncolon, last_was_coloncolon, first_iter; + + if (popping && !VEC_empty (token_and_value, token_fifo)) + { + token_and_value tv = *VEC_index (token_and_value, token_fifo, 0); + VEC_ordered_remove (token_and_value, token_fifo, 0); + yylval = tv.value; + return tv.token; + } + popping = 0; + + current.token = lex_one_token (); + if (current.token == NAME) + current.token = classify_name (expression_context_block); + if (parse_language->la_language != language_cplus + || (current.token != TYPENAME && current.token != COLONCOLON)) + return current.token; + + first_was_coloncolon = current.token == COLONCOLON; + last_was_coloncolon = first_was_coloncolon; + obstack_free (&name_obstack, obstack_base (&name_obstack)); + if (!last_was_coloncolon) + obstack_grow (&name_obstack, yylval.sval.ptr, yylval.sval.length); + current.value = yylval; + first_iter = 1; + while (1) + { + token_and_value next; + + next.token = lex_one_token (); + next.value = yylval; + + if (next.token == NAME && last_was_coloncolon) + { + int classification; + + classification = classify_inner_name (first_was_coloncolon + ? NULL + : expression_context_block, + first_iter); + /* We keep going until we either run out of names, or until + we have a qualified name which is not a type. */ + if (classification != TYPENAME) + { + /* Push the final component and leave the loop. */ + VEC_safe_push (token_and_value, token_fifo, &next); + break; + } + + /* Update the partial name we are constructing. */ + if (!first_iter) + { + /* We don't want to put a leading "::" into the name. */ + obstack_grow_str (&name_obstack, "::"); + } + obstack_grow (&name_obstack, next.value.sval.ptr, + next.value.sval.length); + + yylval.sval.ptr = obstack_base (&name_obstack); + yylval.sval.length = obstack_object_size (&name_obstack); + current.value = yylval; + current.token = classification; + + last_was_coloncolon = 0; + } + else if (next.token == COLONCOLON && !last_was_coloncolon) + last_was_coloncolon = 1; + else + { + /* We've reached the end of the name. */ + VEC_safe_push (token_and_value, token_fifo, &next); + break; + } + + first_iter = 0; + } + + popping = 1; + + /* If we ended with a "::", insert it too. */ + if (last_was_coloncolon) + { + token_and_value cc; + memset (&cc, 0, sizeof (token_and_value)); + if (first_was_coloncolon && first_iter) + { + yylval = cc.value; + return COLONCOLON; + } + cc.token = COLONCOLON; + VEC_safe_insert (token_and_value, token_fifo, 0, &cc); + } + + yylval = current.value; + yylval.sval.ptr = obstack_copy0 (&expansion_obstack, + yylval.sval.ptr, + yylval.sval.length); + return current.token; } int @@ -2198,10 +2673,18 @@ c_parse (void) 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; + VEC_free (token_and_value, token_fifo); + popping = 0; + obstack_init (&name_obstack); + make_cleanup_obstack_free (&name_obstack); + result = yyparse (); do_cleanups (back_to); return result; @@ -2209,11 +2692,10 @@ c_parse (void) void -yyerror (msg) - char *msg; +yyerror (char *msg) { if (prev_lexptr) lexptr = prev_lexptr; - error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr); + error (_("A %s in expression, near `%s'."), (msg ? msg : "error"), lexptr); }