1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642 |
- /* YACC parser for D expressions, for GDB.
- Copyright (C) 2014-2022 Free Software Foundation, Inc.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 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.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- /* This file is derived from c-exp.y, jv-exp.y. */
- /* Parse a D expression from text in a string,
- and return the result as a struct expression pointer.
- That structure contains arithmetic operations in reverse polish,
- with constants represented by operations that are followed by special data.
- See expression.h for the details of the format.
- What is important here is that it can be built up sequentially
- during the process of parsing; the lower levels of the tree always
- come first in the result.
- Note that malloc's and realloc's in this file are transformed to
- xmalloc and xrealloc respectively by the same sed command in the
- makefile that remaps any other malloc/realloc inserted by the parser
- generator. Doing this with #defines and trying to control the interaction
- with include files (<malloc.h> and <stdlib.h> for example) just became
- too messy, particularly when such includes can be inserted at random
- times by the parser generator. */
- %{
- #include "defs.h"
- #include <ctype.h>
- #include "expression.h"
- #include "value.h"
- #include "parser-defs.h"
- #include "language.h"
- #include "c-lang.h"
- #include "d-lang.h"
- #include "bfd.h" /* Required by objfiles.h. */
- #include "symfile.h" /* Required by objfiles.h. */
- #include "objfiles.h" /* For have_full_symbols and have_partial_symbols */
- #include "charset.h"
- #include "block.h"
- #include "type-stack.h"
- #include "expop.h"
- #define parse_type(ps) builtin_type (ps->gdbarch ())
- #define parse_d_type(ps) builtin_d_type (ps->gdbarch ())
- /* Remap normal yacc parser interface names (yyparse, yylex, yyerror,
- etc). */
- #define GDB_YY_REMAP_PREFIX d_
- #include "yy-remap.h"
- /* The state of the parser, used internally when we are parsing the
- expression. */
- static struct parser_state *pstate = NULL;
- /* The current type stack. */
- static struct type_stack *type_stack;
- int yyparse (void);
- static int yylex (void);
- static void yyerror (const char *);
- static int type_aggregate_p (struct type *);
- using namespace expr;
- %}
- /* Although the yacc "value" of an expression is not used,
- since the result is stored in the structure being created,
- other node types do have values. */
- %union
- {
- struct {
- LONGEST val;
- struct type *type;
- } typed_val_int;
- struct {
- gdb_byte val[16];
- struct type *type;
- } typed_val_float;
- struct symbol *sym;
- struct type *tval;
- struct typed_stoken tsval;
- struct stoken sval;
- struct ttype tsym;
- struct symtoken ssym;
- int ival;
- int voidval;
- enum exp_opcode opcode;
- struct stoken_vector svec;
- }
- %{
- /* YYSTYPE gets defined by %union */
- static int parse_number (struct parser_state *, const char *,
- int, int, YYSTYPE *);
- %}
- %token <sval> IDENTIFIER UNKNOWN_NAME
- %token <tsym> TYPENAME
- %token <voidval> COMPLETE
- /* A NAME_OR_INT is a symbol which is not known in the symbol table,
- but which would parse as a valid number in the current input radix.
- E.g. "c" when input_radix==16. Depending on the parse, it will be
- turned into a name or into a number. */
- %token <sval> NAME_OR_INT
- %token <typed_val_int> INTEGER_LITERAL
- %token <typed_val_float> FLOAT_LITERAL
- %token <tsval> CHARACTER_LITERAL
- %token <tsval> STRING_LITERAL
- %type <svec> StringExp
- %type <tval> BasicType TypeExp
- %type <sval> IdentifierExp
- %type <ival> ArrayLiteral
- %token ENTRY
- %token ERROR
- /* Keywords that have a constant value. */
- %token TRUE_KEYWORD FALSE_KEYWORD NULL_KEYWORD
- /* Class 'super' accessor. */
- %token SUPER_KEYWORD
- /* Properties. */
- %token CAST_KEYWORD SIZEOF_KEYWORD
- %token TYPEOF_KEYWORD TYPEID_KEYWORD
- %token INIT_KEYWORD
- /* Comparison keywords. */
- /* Type storage classes. */
- %token IMMUTABLE_KEYWORD CONST_KEYWORD SHARED_KEYWORD
- /* Non-scalar type keywords. */
- %token STRUCT_KEYWORD UNION_KEYWORD
- %token CLASS_KEYWORD INTERFACE_KEYWORD
- %token ENUM_KEYWORD TEMPLATE_KEYWORD
- %token DELEGATE_KEYWORD FUNCTION_KEYWORD
- %token <sval> DOLLAR_VARIABLE
- %token <opcode> ASSIGN_MODIFY
- %left ','
- %right '=' ASSIGN_MODIFY
- %right '?'
- %left OROR
- %left ANDAND
- %left '|'
- %left '^'
- %left '&'
- %left EQUAL NOTEQUAL '<' '>' LEQ GEQ
- %right LSH RSH
- %left '+' '-'
- %left '*' '/' '%'
- %right HATHAT
- %left IDENTITY NOTIDENTITY
- %right INCREMENT DECREMENT
- %right '.' '[' '('
- %token DOTDOT
- %%
- start :
- Expression
- | TypeExp
- ;
- /* Expressions, including the comma operator. */
- Expression:
- CommaExpression
- ;
- CommaExpression:
- AssignExpression
- | AssignExpression ',' CommaExpression
- { pstate->wrap2<comma_operation> (); }
- ;
- AssignExpression:
- ConditionalExpression
- | ConditionalExpression '=' AssignExpression
- { pstate->wrap2<assign_operation> (); }
- | ConditionalExpression ASSIGN_MODIFY AssignExpression
- {
- operation_up rhs = pstate->pop ();
- operation_up lhs = pstate->pop ();
- pstate->push_new<assign_modify_operation>
- ($2, std::move (lhs), std::move (rhs));
- }
- ;
- ConditionalExpression:
- OrOrExpression
- | OrOrExpression '?' Expression ':' ConditionalExpression
- {
- operation_up last = pstate->pop ();
- operation_up mid = pstate->pop ();
- operation_up first = pstate->pop ();
- pstate->push_new<ternop_cond_operation>
- (std::move (first), std::move (mid),
- std::move (last));
- }
- ;
- OrOrExpression:
- AndAndExpression
- | OrOrExpression OROR AndAndExpression
- { pstate->wrap2<logical_or_operation> (); }
- ;
- AndAndExpression:
- OrExpression
- | AndAndExpression ANDAND OrExpression
- { pstate->wrap2<logical_and_operation> (); }
- ;
- OrExpression:
- XorExpression
- | OrExpression '|' XorExpression
- { pstate->wrap2<bitwise_ior_operation> (); }
- ;
- XorExpression:
- AndExpression
- | XorExpression '^' AndExpression
- { pstate->wrap2<bitwise_xor_operation> (); }
- ;
- AndExpression:
- CmpExpression
- | AndExpression '&' CmpExpression
- { pstate->wrap2<bitwise_and_operation> (); }
- ;
- CmpExpression:
- ShiftExpression
- | EqualExpression
- | IdentityExpression
- | RelExpression
- ;
- EqualExpression:
- ShiftExpression EQUAL ShiftExpression
- { pstate->wrap2<equal_operation> (); }
- | ShiftExpression NOTEQUAL ShiftExpression
- { pstate->wrap2<notequal_operation> (); }
- ;
- IdentityExpression:
- ShiftExpression IDENTITY ShiftExpression
- { pstate->wrap2<equal_operation> (); }
- | ShiftExpression NOTIDENTITY ShiftExpression
- { pstate->wrap2<notequal_operation> (); }
- ;
- RelExpression:
- ShiftExpression '<' ShiftExpression
- { pstate->wrap2<less_operation> (); }
- | ShiftExpression LEQ ShiftExpression
- { pstate->wrap2<leq_operation> (); }
- | ShiftExpression '>' ShiftExpression
- { pstate->wrap2<gtr_operation> (); }
- | ShiftExpression GEQ ShiftExpression
- { pstate->wrap2<geq_operation> (); }
- ;
- ShiftExpression:
- AddExpression
- | ShiftExpression LSH AddExpression
- { pstate->wrap2<lsh_operation> (); }
- | ShiftExpression RSH AddExpression
- { pstate->wrap2<rsh_operation> (); }
- ;
- AddExpression:
- MulExpression
- | AddExpression '+' MulExpression
- { pstate->wrap2<add_operation> (); }
- | AddExpression '-' MulExpression
- { pstate->wrap2<sub_operation> (); }
- | AddExpression '~' MulExpression
- { pstate->wrap2<concat_operation> (); }
- ;
- MulExpression:
- UnaryExpression
- | MulExpression '*' UnaryExpression
- { pstate->wrap2<mul_operation> (); }
- | MulExpression '/' UnaryExpression
- { pstate->wrap2<div_operation> (); }
- | MulExpression '%' UnaryExpression
- { pstate->wrap2<rem_operation> (); }
- UnaryExpression:
- '&' UnaryExpression
- { pstate->wrap<unop_addr_operation> (); }
- | INCREMENT UnaryExpression
- { pstate->wrap<preinc_operation> (); }
- | DECREMENT UnaryExpression
- { pstate->wrap<predec_operation> (); }
- | '*' UnaryExpression
- { pstate->wrap<unop_ind_operation> (); }
- | '-' UnaryExpression
- { pstate->wrap<unary_neg_operation> (); }
- | '+' UnaryExpression
- { pstate->wrap<unary_plus_operation> (); }
- | '!' UnaryExpression
- { pstate->wrap<unary_logical_not_operation> (); }
- | '~' UnaryExpression
- { pstate->wrap<unary_complement_operation> (); }
- | TypeExp '.' SIZEOF_KEYWORD
- { pstate->wrap<unop_sizeof_operation> (); }
- | CastExpression
- | PowExpression
- ;
- CastExpression:
- CAST_KEYWORD '(' TypeExp ')' UnaryExpression
- { pstate->wrap2<unop_cast_type_operation> (); }
- /* C style cast is illegal D, but is still recognised in
- the grammar, so we keep this around for convenience. */
- | '(' TypeExp ')' UnaryExpression
- { pstate->wrap2<unop_cast_type_operation> (); }
- ;
- PowExpression:
- PostfixExpression
- | PostfixExpression HATHAT UnaryExpression
- { pstate->wrap2<exp_operation> (); }
- ;
- PostfixExpression:
- PrimaryExpression
- | PostfixExpression '.' COMPLETE
- {
- structop_base_operation *op
- = new structop_ptr_operation (pstate->pop (), "");
- pstate->mark_struct_expression (op);
- pstate->push (operation_up (op));
- }
- | PostfixExpression '.' IDENTIFIER
- {
- pstate->push_new<structop_operation>
- (pstate->pop (), copy_name ($3));
- }
- | PostfixExpression '.' IDENTIFIER COMPLETE
- {
- structop_base_operation *op
- = new structop_operation (pstate->pop (), copy_name ($3));
- pstate->mark_struct_expression (op);
- pstate->push (operation_up (op));
- }
- | PostfixExpression '.' SIZEOF_KEYWORD
- { pstate->wrap<unop_sizeof_operation> (); }
- | PostfixExpression INCREMENT
- { pstate->wrap<postinc_operation> (); }
- | PostfixExpression DECREMENT
- { pstate->wrap<postdec_operation> (); }
- | CallExpression
- | IndexExpression
- | SliceExpression
- ;
- ArgumentList:
- AssignExpression
- { pstate->arglist_len = 1; }
- | ArgumentList ',' AssignExpression
- { pstate->arglist_len++; }
- ;
- ArgumentList_opt:
- /* EMPTY */
- { pstate->arglist_len = 0; }
- | ArgumentList
- ;
- CallExpression:
- PostfixExpression '('
- { pstate->start_arglist (); }
- ArgumentList_opt ')'
- {
- std::vector<operation_up> args
- = pstate->pop_vector (pstate->end_arglist ());
- pstate->push_new<funcall_operation>
- (pstate->pop (), std::move (args));
- }
- ;
- IndexExpression:
- PostfixExpression '[' ArgumentList ']'
- { if (pstate->arglist_len > 0)
- {
- std::vector<operation_up> args
- = pstate->pop_vector (pstate->arglist_len);
- pstate->push_new<multi_subscript_operation>
- (pstate->pop (), std::move (args));
- }
- else
- pstate->wrap2<subscript_operation> ();
- }
- ;
- SliceExpression:
- PostfixExpression '[' ']'
- { /* Do nothing. */ }
- | PostfixExpression '[' AssignExpression DOTDOT AssignExpression ']'
- {
- operation_up last = pstate->pop ();
- operation_up mid = pstate->pop ();
- operation_up first = pstate->pop ();
- pstate->push_new<ternop_slice_operation>
- (std::move (first), std::move (mid),
- std::move (last));
- }
- ;
- PrimaryExpression:
- '(' Expression ')'
- { /* Do nothing. */ }
- | IdentifierExp
- { struct bound_minimal_symbol msymbol;
- std::string copy = copy_name ($1);
- struct field_of_this_result is_a_field_of_this;
- struct block_symbol sym;
- /* Handle VAR, which could be local or global. */
- sym = lookup_symbol (copy.c_str (),
- pstate->expression_context_block,
- VAR_DOMAIN, &is_a_field_of_this);
- if (sym.symbol && sym.symbol->aclass () != LOC_TYPEDEF)
- {
- if (symbol_read_needs_frame (sym.symbol))
- pstate->block_tracker->update (sym);
- pstate->push_new<var_value_operation> (sym);
- }
- else if (is_a_field_of_this.type != NULL)
- {
- /* It hangs off of `this'. Must not inadvertently convert from a
- method call to data ref. */
- pstate->block_tracker->update (sym);
- operation_up thisop
- = make_operation<op_this_operation> ();
- pstate->push_new<structop_ptr_operation>
- (std::move (thisop), std::move (copy));
- }
- else
- {
- /* Lookup foreign name in global static symbols. */
- msymbol = lookup_bound_minimal_symbol (copy.c_str ());
- if (msymbol.minsym != NULL)
- pstate->push_new<var_msym_value_operation> (msymbol);
- else if (!have_full_symbols () && !have_partial_symbols ())
- error (_("No symbol table is loaded. Use the \"file\" command"));
- else
- error (_("No symbol \"%s\" in current context."),
- copy.c_str ());
- }
- }
- | TypeExp '.' IdentifierExp
- { struct type *type = check_typedef ($1);
- /* Check if the qualified name is in the global
- context. However if the symbol has not already
- been resolved, it's not likely to be found. */
- if (type->code () == TYPE_CODE_MODULE)
- {
- struct block_symbol sym;
- const char *type_name = TYPE_SAFE_NAME (type);
- int type_name_len = strlen (type_name);
- std::string name
- = string_printf ("%.*s.%.*s",
- type_name_len, type_name,
- $3.length, $3.ptr);
- sym =
- lookup_symbol (name.c_str (),
- (const struct block *) NULL,
- VAR_DOMAIN, NULL);
- pstate->push_symbol (name.c_str (), sym);
- }
- else
- {
- /* Check if the qualified name resolves as a member
- of an aggregate or an enum type. */
- if (!type_aggregate_p (type))
- error (_("`%s' is not defined as an aggregate type."),
- TYPE_SAFE_NAME (type));
- pstate->push_new<scope_operation>
- (type, copy_name ($3));
- }
- }
- | DOLLAR_VARIABLE
- { pstate->push_dollar ($1); }
- | NAME_OR_INT
- { YYSTYPE val;
- parse_number (pstate, $1.ptr, $1.length, 0, &val);
- pstate->push_new<long_const_operation>
- (val.typed_val_int.type, val.typed_val_int.val); }
- | NULL_KEYWORD
- { struct type *type = parse_d_type (pstate)->builtin_void;
- type = lookup_pointer_type (type);
- pstate->push_new<long_const_operation> (type, 0); }
- | TRUE_KEYWORD
- { pstate->push_new<bool_operation> (true); }
- | FALSE_KEYWORD
- { pstate->push_new<bool_operation> (false); }
- | INTEGER_LITERAL
- { pstate->push_new<long_const_operation> ($1.type, $1.val); }
- | FLOAT_LITERAL
- {
- float_data data;
- std::copy (std::begin ($1.val), std::end ($1.val),
- std::begin (data));
- pstate->push_new<float_const_operation> ($1.type, data);
- }
- | CHARACTER_LITERAL
- { struct stoken_vector vec;
- vec.len = 1;
- vec.tokens = &$1;
- pstate->push_c_string (0, &vec); }
- | StringExp
- { int i;
- pstate->push_c_string (0, &$1);
- for (i = 0; i < $1.len; ++i)
- free ($1.tokens[i].ptr);
- free ($1.tokens); }
- | ArrayLiteral
- {
- std::vector<operation_up> args
- = pstate->pop_vector ($1);
- pstate->push_new<array_operation>
- (0, $1 - 1, std::move (args));
- }
- | TYPEOF_KEYWORD '(' Expression ')'
- { pstate->wrap<typeof_operation> (); }
- ;
- ArrayLiteral:
- '[' ArgumentList_opt ']'
- { $$ = pstate->arglist_len; }
- ;
- IdentifierExp:
- IDENTIFIER
- ;
- StringExp:
- STRING_LITERAL
- { /* 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 = (char *) malloc ($1.length + 1);
- memcpy (vec->ptr, $1.ptr, $1.length + 1);
- }
- | StringExp STRING_LITERAL
- { /* Note that we NUL-terminate here, but just
- for convenience. */
- char *p;
- ++$$.len;
- $$.tokens
- = XRESIZEVEC (struct typed_stoken, $$.tokens, $$.len);
- p = (char *) 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;
- }
- ;
- TypeExp:
- '(' TypeExp ')'
- { /* Do nothing. */ }
- | BasicType
- { pstate->push_new<type_operation> ($1); }
- | BasicType BasicType2
- { $$ = type_stack->follow_types ($1);
- pstate->push_new<type_operation> ($$);
- }
- ;
- BasicType2:
- '*'
- { type_stack->push (tp_pointer); }
- | '*' BasicType2
- { type_stack->push (tp_pointer); }
- | '[' INTEGER_LITERAL ']'
- { type_stack->push ($2.val);
- type_stack->push (tp_array); }
- | '[' INTEGER_LITERAL ']' BasicType2
- { type_stack->push ($2.val);
- type_stack->push (tp_array); }
- ;
- BasicType:
- TYPENAME
- { $$ = $1.type; }
- ;
- %%
- /* Return true if the type is aggregate-like. */
- static int
- type_aggregate_p (struct type *type)
- {
- return (type->code () == TYPE_CODE_STRUCT
- || type->code () == TYPE_CODE_UNION
- || type->code () == TYPE_CODE_MODULE
- || (type->code () == TYPE_CODE_ENUM
- && type->is_declared_class ()));
- }
- /* Take care of parsing a number (anything that starts with a digit).
- Set yylval and return the token type; update lexptr.
- LEN is the number of characters in it. */
- /*** Needs some error checking for the float case ***/
- static int
- parse_number (struct parser_state *ps, const char *p,
- int len, int parsed_float, YYSTYPE *putithere)
- {
- ULONGEST n = 0;
- ULONGEST prevn = 0;
- ULONGEST un;
- int i = 0;
- int c;
- int base = input_radix;
- int unsigned_p = 0;
- int long_p = 0;
- /* We have found a "L" or "U" suffix. */
- int found_suffix = 0;
- ULONGEST high_bit;
- struct type *signed_type;
- struct type *unsigned_type;
- if (parsed_float)
- {
- char *s, *sp;
- /* Strip out all embedded '_' before passing to parse_float. */
- s = (char *) alloca (len + 1);
- sp = s;
- while (len-- > 0)
- {
- if (*p != '_')
- *sp++ = *p;
- p++;
- }
- *sp = '\0';
- len = strlen (s);
- /* Check suffix for `i' , `fi' or `li' (idouble, ifloat or ireal). */
- if (len >= 1 && tolower (s[len - 1]) == 'i')
- {
- if (len >= 2 && tolower (s[len - 2]) == 'f')
- {
- putithere->typed_val_float.type
- = parse_d_type (ps)->builtin_ifloat;
- len -= 2;
- }
- else if (len >= 2 && tolower (s[len - 2]) == 'l')
- {
- putithere->typed_val_float.type
- = parse_d_type (ps)->builtin_ireal;
- len -= 2;
- }
- else
- {
- putithere->typed_val_float.type
- = parse_d_type (ps)->builtin_idouble;
- len -= 1;
- }
- }
- /* Check suffix for `f' or `l'' (float or real). */
- else if (len >= 1 && tolower (s[len - 1]) == 'f')
- {
- putithere->typed_val_float.type
- = parse_d_type (ps)->builtin_float;
- len -= 1;
- }
- else if (len >= 1 && tolower (s[len - 1]) == 'l')
- {
- putithere->typed_val_float.type
- = parse_d_type (ps)->builtin_real;
- len -= 1;
- }
- /* Default type if no suffix. */
- else
- {
- putithere->typed_val_float.type
- = parse_d_type (ps)->builtin_double;
- }
- if (!parse_float (s, len,
- putithere->typed_val_float.type,
- putithere->typed_val_float.val))
- return ERROR;
- return FLOAT_LITERAL;
- }
- /* Handle base-switching prefixes 0x, 0b, 0 */
- if (p[0] == '0')
- switch (p[1])
- {
- case 'x':
- case 'X':
- if (len >= 3)
- {
- p += 2;
- base = 16;
- len -= 2;
- }
- break;
- case 'b':
- case 'B':
- if (len >= 3)
- {
- p += 2;
- base = 2;
- len -= 2;
- }
- break;
- default:
- base = 8;
- break;
- }
- while (len-- > 0)
- {
- c = *p++;
- if (c == '_')
- continue; /* Ignore embedded '_'. */
- if (c >= 'A' && c <= 'Z')
- c += 'a' - 'A';
- if (c != 'l' && c != 'u')
- n *= base;
- if (c >= '0' && c <= '9')
- {
- if (found_suffix)
- return ERROR;
- n += i = c - '0';
- }
- else
- {
- if (base > 10 && c >= 'a' && c <= 'f')
- {
- if (found_suffix)
- return ERROR;
- n += i = c - 'a' + 10;
- }
- else if (c == 'l' && long_p == 0)
- {
- long_p = 1;
- found_suffix = 1;
- }
- else if (c == 'u' && unsigned_p == 0)
- {
- unsigned_p = 1;
- found_suffix = 1;
- }
- else
- return ERROR; /* Char not a digit */
- }
- if (i >= base)
- return ERROR; /* Invalid digit in this base. */
- /* Portably test for integer overflow. */
- if (c != 'l' && c != 'u')
- {
- ULONGEST n2 = prevn * base;
- if ((n2 / base != prevn) || (n2 + i < prevn))
- error (_("Numeric constant too large."));
- }
- prevn = n;
- }
- /* An integer constant is an int or a long. An L suffix forces it to
- be long, and a U suffix forces it to be unsigned. To figure out
- whether it fits, we shift it right and see whether anything remains.
- Note that we can't shift sizeof (LONGEST) * HOST_CHAR_BIT bits or
- more in one operation, because many compilers will warn about such a
- shift (which always produces a zero result). 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 >> 30) == 0)
- {
- high_bit = ((ULONGEST) 1) << 31;
- signed_type = parse_d_type (ps)->builtin_int;
- /* For decimal notation, keep the sign of the worked out type. */
- if (base == 10 && !unsigned_p)
- unsigned_type = parse_d_type (ps)->builtin_long;
- else
- unsigned_type = parse_d_type (ps)->builtin_uint;
- }
- else
- {
- int shift;
- if (sizeof (ULONGEST) * HOST_CHAR_BIT < 64)
- /* A long long does not fit in a LONGEST. */
- shift = (sizeof (ULONGEST) * HOST_CHAR_BIT - 1);
- else
- shift = 63;
- high_bit = (ULONGEST) 1 << shift;
- signed_type = parse_d_type (ps)->builtin_long;
- unsigned_type = parse_d_type (ps)->builtin_ulong;
- }
- putithere->typed_val_int.val = n;
- /* If the high bit of the worked out type is set then this number
- has to be unsigned_type. */
- if (unsigned_p || (n & high_bit))
- putithere->typed_val_int.type = unsigned_type;
- else
- putithere->typed_val_int.type = signed_type;
- return INTEGER_LITERAL;
- }
- /* Temporary obstack used for holding strings. */
- static struct obstack tempbuf;
- static int tempbuf_init;
- /* 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 (const char *tokptr, const char **outptr,
- struct typed_stoken *value, int *host_chars)
- {
- int quote;
- /* 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);
- /* Skip the quote. */
- quote = *tokptr;
- ++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 == '"' || quote == '`')
- error (_("Unterminated string in expression."));
- else
- error (_("Unmatched single quote."));
- }
- ++tokptr;
- /* FIXME: should instead use own language string_type enum
- and handle D-specific string suffixes here. */
- if (quote == '\'')
- value->type = C_CHAR;
- else
- value->type = C_STRING;
- value->ptr = (char *) obstack_base (&tempbuf);
- value->length = obstack_object_size (&tempbuf);
- *outptr = tokptr;
- return quote == '\'' ? CHARACTER_LITERAL : STRING_LITERAL;
- }
- struct token
- {
- const char *oper;
- int token;
- enum exp_opcode opcode;
- };
- static const struct token tokentab3[] =
- {
- {"^^=", ASSIGN_MODIFY, BINOP_EXP},
- {"<<=", ASSIGN_MODIFY, BINOP_LSH},
- {">>=", ASSIGN_MODIFY, BINOP_RSH},
- };
- 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, OP_NULL},
- {"--", DECREMENT, OP_NULL},
- {"&&", ANDAND, OP_NULL},
- {"||", OROR, OP_NULL},
- {"^^", HATHAT, OP_NULL},
- {"<<", LSH, OP_NULL},
- {">>", RSH, OP_NULL},
- {"==", EQUAL, OP_NULL},
- {"!=", NOTEQUAL, OP_NULL},
- {"<=", LEQ, OP_NULL},
- {">=", GEQ, OP_NULL},
- {"..", DOTDOT, OP_NULL},
- };
- /* Identifier-like tokens. */
- static const struct token ident_tokens[] =
- {
- {"is", IDENTITY, OP_NULL},
- {"!is", NOTIDENTITY, OP_NULL},
- {"cast", CAST_KEYWORD, OP_NULL},
- {"const", CONST_KEYWORD, OP_NULL},
- {"immutable", IMMUTABLE_KEYWORD, OP_NULL},
- {"shared", SHARED_KEYWORD, OP_NULL},
- {"super", SUPER_KEYWORD, OP_NULL},
- {"null", NULL_KEYWORD, OP_NULL},
- {"true", TRUE_KEYWORD, OP_NULL},
- {"false", FALSE_KEYWORD, OP_NULL},
- {"init", INIT_KEYWORD, OP_NULL},
- {"sizeof", SIZEOF_KEYWORD, OP_NULL},
- {"typeof", TYPEOF_KEYWORD, OP_NULL},
- {"typeid", TYPEID_KEYWORD, OP_NULL},
- {"delegate", DELEGATE_KEYWORD, OP_NULL},
- {"function", FUNCTION_KEYWORD, OP_NULL},
- {"struct", STRUCT_KEYWORD, OP_NULL},
- {"union", UNION_KEYWORD, OP_NULL},
- {"class", CLASS_KEYWORD, OP_NULL},
- {"interface", INTERFACE_KEYWORD, OP_NULL},
- {"enum", ENUM_KEYWORD, OP_NULL},
- {"template", TEMPLATE_KEYWORD, OP_NULL},
- };
- /* 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.
- This is used only when parsing to do field name completion. */
- static int last_was_structop;
- /* Depth of parentheses. */
- static int paren_depth;
- /* Read one token, getting characters through lexptr. */
- static int
- lex_one_token (struct parser_state *par_state)
- {
- int c;
- int namelen;
- const char *tokstart;
- int saw_structop = last_was_structop;
- last_was_structop = 0;
- retry:
- pstate->prev_lexptr = pstate->lexptr;
- tokstart = pstate->lexptr;
- /* See if it is a special token of length 3. */
- for (const auto &token : tokentab3)
- if (strncmp (tokstart, token.oper, 3) == 0)
- {
- pstate->lexptr += 3;
- yylval.opcode = token.opcode;
- return token.token;
- }
- /* See if it is a special token of length 2. */
- for (const auto &token : tokentab2)
- if (strncmp (tokstart, token.oper, 2) == 0)
- {
- pstate->lexptr += 2;
- yylval.opcode = token.opcode;
- return token.token;
- }
- switch (c = *tokstart)
- {
- case 0:
- /* 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 (saw_name_at_eof)
- {
- saw_name_at_eof = 0;
- return COMPLETE;
- }
- else if (saw_structop)
- return COMPLETE;
- else
- return 0;
- case ' ':
- case '\t':
- case '\n':
- pstate->lexptr++;
- goto retry;
- case '[':
- case '(':
- paren_depth++;
- pstate->lexptr++;
- return c;
- case ']':
- case ')':
- if (paren_depth == 0)
- return 0;
- paren_depth--;
- pstate->lexptr++;
- return c;
- case ',':
- if (pstate->comma_terminates && paren_depth == 0)
- return 0;
- pstate->lexptr++;
- return c;
- case '.':
- /* Might be a floating point number. */
- if (pstate->lexptr[1] < '0' || pstate->lexptr[1] > '9')
- {
- if (pstate->parse_completion)
- last_was_structop = 1;
- goto symbol; /* Nope, must be a symbol. */
- }
- /* FALL THRU. */
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- {
- /* It's a number. */
- int got_dot = 0, got_e = 0, toktype;
- const char *p = tokstart;
- int hex = input_radix > 10;
- if (c == '0' && (p[1] == 'x' || p[1] == 'X'))
- {
- p += 2;
- hex = 1;
- }
- for (;; ++p)
- {
- /* Hex exponents start with 'p', because 'e' is a valid hex
- digit and thus does not indicate a floating point number
- when the radix is hex. */
- if ((!hex && !got_e && tolower (p[0]) == 'e')
- || (hex && !got_e && tolower (p[0] == 'p')))
- got_dot = got_e = 1;
- /* A '.' always indicates a decimal floating point number
- regardless of the radix. If we have a '..' then its the
- end of the number and the beginning of a slice. */
- else if (!got_dot && (p[0] == '.' && p[1] != '.'))
- got_dot = 1;
- /* This is the sign of the exponent, not the end of the number. */
- else if (got_e && (tolower (p[-1]) == 'e' || tolower (p[-1]) == 'p')
- && (*p == '-' || *p == '+'))
- continue;
- /* We will take any letters or digits, ignoring any embedded '_'.
- parse_number will complain if past the radix, or if L or U are
- not final. */
- else if ((*p < '0' || *p > '9') && (*p != '_')
- && ((*p < 'a' || *p > 'z') && (*p < 'A' || *p > 'Z')))
- break;
- }
- toktype = parse_number (par_state, tokstart, p - tokstart,
- got_dot|got_e, &yylval);
- if (toktype == ERROR)
- {
- char *err_copy = (char *) alloca (p - tokstart + 1);
- memcpy (err_copy, tokstart, p - tokstart);
- err_copy[p - tokstart] = 0;
- error (_("Invalid number \"%s\"."), err_copy);
- }
- pstate->lexptr = p;
- return toktype;
- }
- case '@':
- {
- const char *p = &tokstart[1];
- size_t len = strlen ("entry");
- while (isspace (*p))
- p++;
- if (strncmp (p, "entry", len) == 0 && !isalnum (p[len])
- && p[len] != '_')
- {
- pstate->lexptr = &p[len];
- return ENTRY;
- }
- }
- /* FALLTHRU */
- case '+':
- case '-':
- case '*':
- case '/':
- case '%':
- case '|':
- case '&':
- case '^':
- case '~':
- case '!':
- case '<':
- case '>':
- case '?':
- case ':':
- case '=':
- case '{':
- case '}':
- symbol:
- pstate->lexptr++;
- return c;
- case '\'':
- case '"':
- case '`':
- {
- int host_len;
- int result = parse_string_or_char (tokstart, &pstate->lexptr,
- &yylval.tsval, &host_len);
- if (result == CHARACTER_LITERAL)
- {
- if (host_len == 0)
- error (_("Empty character constant."));
- else if (host_len > 2 && c == '\'')
- {
- ++tokstart;
- namelen = pstate->lexptr - tokstart - 1;
- goto tryname;
- }
- else if (host_len > 1)
- error (_("Invalid character constant."));
- }
- return result;
- }
- }
- if (!(c == '_' || c == '$'
- || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
- /* We must have come across a bad character (e.g. ';'). */
- error (_("Invalid character '%c' in expression"), c);
- /* It's a name. See how long it is. */
- namelen = 0;
- for (c = tokstart[namelen];
- (c == '_' || c == '$' || (c >= '0' && c <= '9')
- || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));)
- c = tokstart[++namelen];
- /* The token "if" terminates the expression and is NOT
- removed from the input stream. */
- if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f')
- 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'))
- {
- const char *p = tokstart + namelen + 1;
- while (*p == ' ' || *p == '\t')
- p++;
- if (*p >= '0' && *p <= '9')
- return 0;
- }
- pstate->lexptr += namelen;
- tryname:
- yylval.sval.ptr = tokstart;
- yylval.sval.length = namelen;
- /* Catch specific keywords. */
- std::string copy = copy_name (yylval.sval);
- for (const auto &token : ident_tokens)
- if (copy == token.oper)
- {
- /* It is ok to always set this, even though we don't always
- strictly need to. */
- yylval.opcode = token.opcode;
- return token.token;
- }
- if (*tokstart == '$')
- return DOLLAR_VARIABLE;
- yylval.tsym.type
- = language_lookup_primitive_type (par_state->language (),
- par_state->gdbarch (), copy.c_str ());
- 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 ((tokstart[0] >= 'a' && tokstart[0] < 'a' + input_radix - 10)
- || (tokstart[0] >= 'A' && tokstart[0] < 'A' + input_radix - 10))
- {
- YYSTYPE newlval; /* Its value is ignored. */
- int hextype = parse_number (par_state, tokstart, namelen, 0, &newlval);
- if (hextype == INTEGER_LITERAL)
- return NAME_OR_INT;
- }
- if (pstate->parse_completion && *pstate->lexptr == '\0')
- saw_name_at_eof = 1;
- return IDENTIFIER;
- }
- /* An object of this type is pushed on a FIFO by the "outer" lexer. */
- struct token_and_value
- {
- int token;
- YYSTYPE value;
- };
- /* A FIFO of tokens that have been read but not yet returned to the
- parser. */
- static std::vector<token_and_value> token_fifo;
- /* Non-zero if the lexer should return tokens from the FIFO. */
- static int popping;
- /* Temporary storage for yylex; this holds symbol names as they are
- built up. */
- static auto_obstack name_obstack;
- /* Classify an IDENTIFIER 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 parser_state *par_state, const struct block *block)
- {
- struct block_symbol sym;
- struct field_of_this_result is_a_field_of_this;
- std::string copy = copy_name (yylval.sval);
- sym = lookup_symbol (copy.c_str (), block, VAR_DOMAIN, &is_a_field_of_this);
- if (sym.symbol && sym.symbol->aclass () == LOC_TYPEDEF)
- {
- yylval.tsym.type = sym.symbol->type ();
- return TYPENAME;
- }
- else if (sym.symbol == NULL)
- {
- /* Look-up first for a module name, then a type. */
- sym = lookup_symbol (copy.c_str (), block, MODULE_DOMAIN, NULL);
- if (sym.symbol == NULL)
- sym = lookup_symbol (copy.c_str (), block, STRUCT_DOMAIN, NULL);
- if (sym.symbol != NULL)
- {
- yylval.tsym.type = sym.symbol->type ();
- return TYPENAME;
- }
- return UNKNOWN_NAME;
- }
- return IDENTIFIER;
- }
- /* Like classify_name, but used by the inner loop of the lexer, when a
- name might have already been seen. CONTEXT is the context type, or
- NULL if this is the first component of a name. */
- static int
- classify_inner_name (struct parser_state *par_state,
- const struct block *block, struct type *context)
- {
- struct type *type;
- if (context == NULL)
- return classify_name (par_state, block);
- type = check_typedef (context);
- if (!type_aggregate_p (type))
- return ERROR;
- std::string copy = copy_name (yylval.ssym.stoken);
- yylval.ssym.sym = d_lookup_nested_symbol (type, copy.c_str (), block);
- if (yylval.ssym.sym.symbol == NULL)
- return ERROR;
- if (yylval.ssym.sym.symbol->aclass () == LOC_TYPEDEF)
- {
- yylval.tsym.type = yylval.ssym.sym.symbol->type ();
- return TYPENAME;
- }
- return IDENTIFIER;
- }
- /* 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. */
- static int
- yylex (void)
- {
- token_and_value current;
- int last_was_dot;
- struct type *context_type = NULL;
- int last_to_examine, next_to_examine, checkpoint;
- const struct block *search_block;
- if (popping && !token_fifo.empty ())
- goto do_pop;
- popping = 0;
- /* Read the first token and decide what to do. */
- current.token = lex_one_token (pstate);
- if (current.token != IDENTIFIER && current.token != '.')
- return current.token;
- /* Read any sequence of alternating "." and identifier tokens into
- the token FIFO. */
- current.value = yylval;
- token_fifo.push_back (current);
- last_was_dot = current.token == '.';
- while (1)
- {
- current.token = lex_one_token (pstate);
- current.value = yylval;
- token_fifo.push_back (current);
- if ((last_was_dot && current.token != IDENTIFIER)
- || (!last_was_dot && current.token != '.'))
- break;
- last_was_dot = !last_was_dot;
- }
- popping = 1;
- /* We always read one extra token, so compute the number of tokens
- to examine accordingly. */
- last_to_examine = token_fifo.size () - 2;
- next_to_examine = 0;
- current = token_fifo[next_to_examine];
- ++next_to_examine;
- /* If we are not dealing with a typename, now is the time to find out. */
- if (current.token == IDENTIFIER)
- {
- yylval = current.value;
- current.token = classify_name (pstate, pstate->expression_context_block);
- current.value = yylval;
- }
- /* If the IDENTIFIER is not known, it could be a package symbol,
- first try building up a name until we find the qualified module. */
- if (current.token == UNKNOWN_NAME)
- {
- name_obstack.clear ();
- obstack_grow (&name_obstack, current.value.sval.ptr,
- current.value.sval.length);
- last_was_dot = 0;
- while (next_to_examine <= last_to_examine)
- {
- token_and_value next;
- next = token_fifo[next_to_examine];
- ++next_to_examine;
- if (next.token == IDENTIFIER && last_was_dot)
- {
- /* Update the partial name we are constructing. */
- obstack_grow_str (&name_obstack, ".");
- obstack_grow (&name_obstack, next.value.sval.ptr,
- next.value.sval.length);
- yylval.sval.ptr = (char *) obstack_base (&name_obstack);
- yylval.sval.length = obstack_object_size (&name_obstack);
- current.token = classify_name (pstate,
- pstate->expression_context_block);
- current.value = yylval;
- /* We keep going until we find a TYPENAME. */
- if (current.token == TYPENAME)
- {
- /* Install it as the first token in the FIFO. */
- token_fifo[0] = current;
- token_fifo.erase (token_fifo.begin () + 1,
- token_fifo.begin () + next_to_examine);
- break;
- }
- }
- else if (next.token == '.' && !last_was_dot)
- last_was_dot = 1;
- else
- {
- /* We've reached the end of the name. */
- break;
- }
- }
- /* Reset our current token back to the start, if we found nothing
- this means that we will just jump to do pop. */
- current = token_fifo[0];
- next_to_examine = 1;
- }
- if (current.token != TYPENAME && current.token != '.')
- goto do_pop;
- name_obstack.clear ();
- checkpoint = 0;
- if (current.token == '.')
- search_block = NULL;
- else
- {
- gdb_assert (current.token == TYPENAME);
- search_block = pstate->expression_context_block;
- obstack_grow (&name_obstack, current.value.sval.ptr,
- current.value.sval.length);
- context_type = current.value.tsym.type;
- checkpoint = 1;
- }
- last_was_dot = current.token == '.';
- while (next_to_examine <= last_to_examine)
- {
- token_and_value next;
- next = token_fifo[next_to_examine];
- ++next_to_examine;
- if (next.token == IDENTIFIER && last_was_dot)
- {
- int classification;
- yylval = next.value;
- classification = classify_inner_name (pstate, search_block,
- context_type);
- /* 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 && classification != IDENTIFIER)
- break;
- /* Accept up to this token. */
- checkpoint = next_to_examine;
- /* Update the partial name we are constructing. */
- if (context_type != NULL)
- {
- /* 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 = (char *) obstack_base (&name_obstack);
- yylval.sval.length = obstack_object_size (&name_obstack);
- current.value = yylval;
- current.token = classification;
- last_was_dot = 0;
- if (classification == IDENTIFIER)
- break;
- context_type = yylval.tsym.type;
- }
- else if (next.token == '.' && !last_was_dot)
- last_was_dot = 1;
- else
- {
- /* We've reached the end of the name. */
- break;
- }
- }
- /* If we have a replacement token, install it as the first token in
- the FIFO, and delete the other constituent tokens. */
- if (checkpoint > 0)
- {
- token_fifo[0] = current;
- if (checkpoint > 1)
- token_fifo.erase (token_fifo.begin () + 1,
- token_fifo.begin () + checkpoint);
- }
- do_pop:
- current = token_fifo[0];
- token_fifo.erase (token_fifo.begin ());
- yylval = current.value;
- return current.token;
- }
- int
- d_parse (struct parser_state *par_state)
- {
- /* Setting up the parser state. */
- scoped_restore pstate_restore = make_scoped_restore (&pstate);
- gdb_assert (par_state != NULL);
- pstate = par_state;
- scoped_restore restore_yydebug = make_scoped_restore (&yydebug,
- parser_debug);
- struct type_stack stack;
- scoped_restore restore_type_stack = make_scoped_restore (&type_stack,
- &stack);
- /* Initialize some state used by the lexer. */
- last_was_structop = 0;
- saw_name_at_eof = 0;
- paren_depth = 0;
- token_fifo.clear ();
- popping = 0;
- name_obstack.clear ();
- int result = yyparse ();
- if (!result)
- pstate->set_operation (pstate->pop ());
- return result;
- }
- static void
- yyerror (const char *msg)
- {
- if (pstate->prev_lexptr)
- pstate->lexptr = pstate->prev_lexptr;
- error (_("A %s in expression, near `%s'."), msg, pstate->lexptr);
- }
|