12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515 |
- /* YACC parser for C expressions, for GDB.
- Copyright (C) 1986-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/>. */
- /* Parse a C expression from text in a string,
- and return the result as a struct expression pointer.
- That structure contains arithmetic operations in reverse polish,
- with constants represented by operations that are followed by special data.
- See expression.h for the details of the format.
- What is important here is that it can be built up sequentially
- during the process of parsing; the lower levels of the tree always
- come first in the result.
- Note that malloc's and realloc's in this file are transformed to
- xmalloc and xrealloc respectively by the same sed command in the
- makefile that remaps any other malloc/realloc inserted by the parser
- generator. Doing this with #defines and trying to control the interaction
- with include files (<malloc.h> and <stdlib.h> for example) just became
- too messy, particularly when such includes can be inserted at random
- times by the parser generator. */
- %{
- #include "defs.h"
- #include <ctype.h>
- #include "expression.h"
- #include "value.h"
- #include "parser-defs.h"
- #include "language.h"
- #include "c-lang.h"
- #include "c-support.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 "cp-support.h"
- #include "macroscope.h"
- #include "objc-lang.h"
- #include "typeprint.h"
- #include "cp-abi.h"
- #include "type-stack.h"
- #include "target-float.h"
- #include "c-exp.h"
- #define parse_type(ps) builtin_type (ps->gdbarch ())
- /* Remap normal yacc parser interface names (yyparse, yylex, yyerror,
- etc). */
- #define GDB_YY_REMAP_PREFIX c_
- #include "yy-remap.h"
- /* The state of the parser, used internally when we are parsing the
- expression. */
- static struct parser_state *pstate = NULL;
- /* Data that must be held for the duration of a parse. */
- struct c_parse_state
- {
- /* These are used to hold type lists and type stacks that are
- allocated during the parse. */
- std::vector<std::unique_ptr<std::vector<struct type *>>> type_lists;
- std::vector<std::unique_ptr<struct type_stack>> type_stacks;
- /* Storage for some strings allocated during the parse. */
- std::vector<gdb::unique_xmalloc_ptr<char>> strings;
- /* 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. */
- const char *macro_original_text = nullptr;
- /* 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. */
- auto_obstack expansion_obstack;
- /* The type stack. */
- struct type_stack type_stack;
- };
- /* This is set and cleared in c_parse. */
- static struct c_parse_state *cpstate;
- 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
- {
- LONGEST lval;
- struct {
- LONGEST val;
- struct type *type;
- } typed_val_int;
- struct {
- gdb_byte val[16];
- struct type *type;
- } typed_val_float;
- struct type *tval;
- struct stoken sval;
- struct typed_stoken tsval;
- struct ttype tsym;
- struct symtoken ssym;
- int voidval;
- const struct block *bval;
- enum exp_opcode opcode;
- struct stoken_vector svec;
- std::vector<struct type *> *tvec;
- struct type_stack *type_stack;
- struct objc_class_str theclass;
- }
- %{
- /* YYSTYPE gets defined by %union */
- static int parse_number (struct parser_state *par_state,
- const char *, int, int, YYSTYPE *);
- static struct stoken operator_stoken (const char *);
- static struct stoken typename_stoken (const char *);
- static void check_parameter_typelist (std::vector<struct type *> *);
- #if defined(YYBISON) && YYBISON < 30800
- static void c_print_token (FILE *file, int type, YYSTYPE value);
- #define YYPRINT(FILE, TYPE, VALUE) c_print_token (FILE, TYPE, VALUE)
- #endif
- %}
- %type <voidval> exp exp1 type_exp start variable qualified_name lcurly function_method
- %type <lval> rcurly
- %type <tval> type typebase scalar_type
- %type <tvec> nonempty_typelist func_mod parameter_typelist
- /* %type <bval> block */
- /* Fancy type parsing. */
- %type <tval> ptype
- %type <lval> array_mod
- %type <tval> conversion_type_id
- %type <type_stack> ptr_operator_ts abs_decl direct_abs_decl
- %token <typed_val_int> INT COMPLEX_INT
- %token <typed_val_float> FLOAT COMPLEX_FLOAT
- /* Both NAME and TYPENAME tokens represent symbols in the input,
- and both convey their data as strings.
- But a TYPENAME is a string that happens to be defined as a typedef
- or builtin type name (such as int or char)
- and a NAME is any other symbol.
- Contexts where this distinction is not important can use the
- nonterminal "name", which matches either NAME or TYPENAME. */
- %token <tsval> STRING
- %token <sval> NSSTRING /* ObjC Foundation "NSString" literal */
- %token SELECTOR /* ObjC "@selector" pseudo-operator */
- %token <tsval> CHAR
- %token <ssym> NAME /* BLOCKNAME defined below to give it higher precedence. */
- %token <ssym> UNKNOWN_CPP_NAME
- %token <voidval> COMPLETE
- %token <tsym> TYPENAME
- %token <theclass> CLASSNAME /* ObjC Class name */
- %type <sval> name field_name
- %type <svec> string_exp
- %type <ssym> name_not_typename
- %type <tsym> type_name
- /* This is like a '[' token, but is only generated when parsing
- Objective C. This lets us reuse the same parser without
- erroneously parsing ObjC-specific expressions in C. */
- %token OBJC_LBRAC
- /* A NAME_OR_INT is a symbol which is not known in the symbol table,
- but which would parse as a valid number in the current input radix.
- E.g. "c" when input_radix==16. Depending on the parse, it will be
- turned into a name or into a number. */
- %token <ssym> NAME_OR_INT
- %token OPERATOR
- %token STRUCT CLASS UNION ENUM SIZEOF ALIGNOF UNSIGNED COLONCOLON
- %token TEMPLATE
- %token ERROR
- %token NEW DELETE
- %type <sval> oper
- %token REINTERPRET_CAST DYNAMIC_CAST STATIC_CAST CONST_CAST
- %token ENTRY
- %token TYPEOF
- %token DECLTYPE
- %token TYPEID
- /* 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 RESTRICT ATOMIC
- %token FLOAT_KEYWORD COMPLEX
- %token <sval> DOLLAR_VARIABLE
- %token <opcode> ASSIGN_MODIFY
- /* C++ */
- %token TRUEKEYWORD
- %token FALSEKEYWORD
- %left ','
- %left ABOVE_COMMA
- %right '=' ASSIGN_MODIFY
- %right '?'
- %left OROR
- %left ANDAND
- %left '|'
- %left '^'
- %left '&'
- %left EQUAL NOTEQUAL
- %left '<' '>' LEQ GEQ
- %left LSH RSH
- %left '@'
- %left '+' '-'
- %left '*' '/' '%'
- %right UNARY INCREMENT DECREMENT
- %right ARROW ARROW_STAR '.' DOT_STAR '[' OBJC_LBRAC '('
- %token <ssym> BLOCKNAME
- %token <bval> FILENAME
- %type <bval> block
- %left COLONCOLON
- %token DOTDOTDOT
- %%
- start : exp1
- | type_exp
- ;
- type_exp: type
- {
- pstate->push_new<type_operation> ($1);
- }
- | TYPEOF '(' exp ')'
- {
- pstate->wrap<typeof_operation> ();
- }
- | TYPEOF '(' type ')'
- {
- pstate->push_new<type_operation> ($3);
- }
- | DECLTYPE '(' exp ')'
- {
- pstate->wrap<decltype_operation> ();
- }
- ;
- /* Expressions, including the comma operator. */
- exp1 : exp
- | exp1 ',' exp
- { pstate->wrap2<comma_operation> (); }
- ;
- /* Expressions, not including the comma operator. */
- exp : '*' exp %prec UNARY
- { pstate->wrap<unop_ind_operation> (); }
- ;
- exp : '&' exp %prec UNARY
- { pstate->wrap<unop_addr_operation> (); }
- ;
- exp : '-' exp %prec UNARY
- { pstate->wrap<unary_neg_operation> (); }
- ;
- exp : '+' exp %prec UNARY
- { pstate->wrap<unary_plus_operation> (); }
- ;
- exp : '!' exp %prec UNARY
- {
- if (pstate->language ()->la_language
- == language_opencl)
- pstate->wrap<opencl_not_operation> ();
- else
- pstate->wrap<unary_logical_not_operation> ();
- }
- ;
- exp : '~' exp %prec UNARY
- { pstate->wrap<unary_complement_operation> (); }
- ;
- exp : INCREMENT exp %prec UNARY
- { pstate->wrap<preinc_operation> (); }
- ;
- exp : DECREMENT exp %prec UNARY
- { pstate->wrap<predec_operation> (); }
- ;
- exp : exp INCREMENT %prec UNARY
- { pstate->wrap<postinc_operation> (); }
- ;
- exp : exp DECREMENT %prec UNARY
- { pstate->wrap<postdec_operation> (); }
- ;
- exp : TYPEID '(' exp ')' %prec UNARY
- { pstate->wrap<typeid_operation> (); }
- ;
- exp : TYPEID '(' type_exp ')' %prec UNARY
- { pstate->wrap<typeid_operation> (); }
- ;
- exp : SIZEOF exp %prec UNARY
- { pstate->wrap<unop_sizeof_operation> (); }
- ;
- exp : ALIGNOF '(' type_exp ')' %prec UNARY
- { pstate->wrap<unop_alignof_operation> (); }
- ;
- exp : exp ARROW field_name
- {
- pstate->push_new<structop_ptr_operation>
- (pstate->pop (), copy_name ($3));
- }
- ;
- exp : exp ARROW field_name COMPLETE
- {
- structop_base_operation *op
- = new structop_ptr_operation (pstate->pop (),
- copy_name ($3));
- pstate->mark_struct_expression (op);
- pstate->push (operation_up (op));
- }
- ;
- exp : exp ARROW COMPLETE
- {
- structop_base_operation *op
- = new structop_ptr_operation (pstate->pop (), "");
- pstate->mark_struct_expression (op);
- pstate->push (operation_up (op));
- }
- ;
- exp : exp ARROW '~' name
- {
- pstate->push_new<structop_ptr_operation>
- (pstate->pop (), "~" + copy_name ($4));
- }
- ;
- exp : exp ARROW '~' name COMPLETE
- {
- structop_base_operation *op
- = new structop_ptr_operation (pstate->pop (),
- "~" + copy_name ($4));
- pstate->mark_struct_expression (op);
- pstate->push (operation_up (op));
- }
- ;
- exp : exp ARROW qualified_name
- { /* exp->type::name becomes exp->*(&type::name) */
- /* Note: this doesn't work if name is a
- static member! FIXME */
- pstate->wrap<unop_addr_operation> ();
- pstate->wrap2<structop_mptr_operation> (); }
- ;
- exp : exp ARROW_STAR exp
- { pstate->wrap2<structop_mptr_operation> (); }
- ;
- exp : exp '.' field_name
- {
- if (pstate->language ()->la_language
- == language_opencl)
- pstate->push_new<opencl_structop_operation>
- (pstate->pop (), copy_name ($3));
- else
- pstate->push_new<structop_operation>
- (pstate->pop (), copy_name ($3));
- }
- ;
- exp : exp '.' field_name COMPLETE
- {
- structop_base_operation *op
- = new structop_operation (pstate->pop (),
- copy_name ($3));
- pstate->mark_struct_expression (op);
- pstate->push (operation_up (op));
- }
- ;
- exp : exp '.' COMPLETE
- {
- structop_base_operation *op
- = new structop_operation (pstate->pop (), "");
- pstate->mark_struct_expression (op);
- pstate->push (operation_up (op));
- }
- ;
- exp : exp '.' '~' name
- {
- pstate->push_new<structop_operation>
- (pstate->pop (), "~" + copy_name ($4));
- }
- ;
- exp : exp '.' '~' name COMPLETE
- {
- structop_base_operation *op
- = new structop_operation (pstate->pop (),
- "~" + copy_name ($4));
- pstate->mark_struct_expression (op);
- pstate->push (operation_up (op));
- }
- ;
- exp : exp '.' qualified_name
- { /* exp.type::name becomes exp.*(&type::name) */
- /* Note: this doesn't work if name is a
- static member! FIXME */
- pstate->wrap<unop_addr_operation> ();
- pstate->wrap2<structop_member_operation> (); }
- ;
- exp : exp DOT_STAR exp
- { pstate->wrap2<structop_member_operation> (); }
- ;
- exp : exp '[' exp1 ']'
- { pstate->wrap2<subscript_operation> (); }
- ;
- exp : exp OBJC_LBRAC exp1 ']'
- { pstate->wrap2<subscript_operation> (); }
- ;
- /*
- * The rules below parse ObjC message calls of the form:
- * '[' target selector {':' argument}* ']'
- */
- exp : OBJC_LBRAC TYPENAME
- {
- CORE_ADDR theclass;
- std::string copy = copy_name ($2.stoken);
- theclass = lookup_objc_class (pstate->gdbarch (),
- copy.c_str ());
- if (theclass == 0)
- error (_("%s is not an ObjC Class"),
- copy.c_str ());
- pstate->push_new<long_const_operation>
- (parse_type (pstate)->builtin_int,
- (LONGEST) theclass);
- start_msglist();
- }
- msglist ']'
- { end_msglist (pstate); }
- ;
- exp : OBJC_LBRAC CLASSNAME
- {
- pstate->push_new<long_const_operation>
- (parse_type (pstate)->builtin_int,
- (LONGEST) $2.theclass);
- start_msglist();
- }
- msglist ']'
- { end_msglist (pstate); }
- ;
- exp : OBJC_LBRAC exp
- { start_msglist(); }
- msglist ']'
- { end_msglist (pstate); }
- ;
- msglist : name
- { add_msglist(&$1, 0); }
- | msgarglist
- ;
- msgarglist : msgarg
- | msgarglist msgarg
- ;
- msgarg : name ':' exp
- { add_msglist(&$1, 1); }
- | ':' exp /* Unnamed arg. */
- { add_msglist(0, 1); }
- | ',' exp /* Variable number of args. */
- { add_msglist(0, 0); }
- ;
- exp : exp '('
- /* This is to save the value of arglist_len
- being accumulated by an outer function call. */
- { pstate->start_arglist (); }
- arglist ')' %prec ARROW
- {
- std::vector<operation_up> args
- = pstate->pop_vector (pstate->end_arglist ());
- pstate->push_new<funcall_operation>
- (pstate->pop (), std::move (args));
- }
- ;
- /* This is here to disambiguate with the production for
- "func()::static_var" further below, which uses
- function_method_void. */
- exp : exp '(' ')' %prec ARROW
- {
- pstate->push_new<funcall_operation>
- (pstate->pop (), std::vector<operation_up> ());
- }
- ;
- exp : UNKNOWN_CPP_NAME '('
- {
- /* This could potentially be a an argument defined
- lookup function (Koenig). */
- /* This is to save the value of arglist_len
- being accumulated by an outer function call. */
- pstate->start_arglist ();
- }
- arglist ')' %prec ARROW
- {
- std::vector<operation_up> args
- = pstate->pop_vector (pstate->end_arglist ());
- pstate->push_new<adl_func_operation>
- (copy_name ($1.stoken),
- pstate->expression_context_block,
- std::move (args));
- }
- ;
- lcurly : '{'
- { pstate->start_arglist (); }
- ;
- arglist :
- ;
- arglist : exp
- { pstate->arglist_len = 1; }
- ;
- arglist : arglist ',' exp %prec ABOVE_COMMA
- { pstate->arglist_len++; }
- ;
- function_method: exp '(' parameter_typelist ')' const_or_volatile
- {
- std::vector<struct type *> *type_list = $3;
- /* Save the const/volatile qualifiers as
- recorded by the const_or_volatile
- production's actions. */
- type_instance_flags flags
- = (cpstate->type_stack
- .follow_type_instance_flags ());
- pstate->push_new<type_instance_operation>
- (flags, std::move (*type_list),
- pstate->pop ());
- }
- ;
- function_method_void: exp '(' ')' const_or_volatile
- {
- type_instance_flags flags
- = (cpstate->type_stack
- .follow_type_instance_flags ());
- pstate->push_new<type_instance_operation>
- (flags, std::vector<type *> (), pstate->pop ());
- }
- ;
- exp : function_method
- ;
- /* Normally we must interpret "func()" as a function call, instead of
- a type. The user needs to write func(void) to disambiguate.
- However, in the "func()::static_var" case, there's no
- ambiguity. */
- function_method_void_or_typelist: function_method
- | function_method_void
- ;
- exp : function_method_void_or_typelist COLONCOLON name
- {
- pstate->push_new<func_static_var_operation>
- (pstate->pop (), copy_name ($3));
- }
- ;
- rcurly : '}'
- { $$ = pstate->end_arglist () - 1; }
- ;
- exp : lcurly arglist rcurly %prec ARROW
- {
- std::vector<operation_up> args
- = pstate->pop_vector ($3 + 1);
- pstate->push_new<array_operation> (0, $3,
- std::move (args));
- }
- ;
- exp : lcurly type_exp rcurly exp %prec UNARY
- { pstate->wrap2<unop_memval_type_operation> (); }
- ;
- exp : '(' type_exp ')' exp %prec UNARY
- {
- if (pstate->language ()->la_language
- == language_opencl)
- pstate->wrap2<opencl_cast_type_operation> ();
- else
- pstate->wrap2<unop_cast_type_operation> ();
- }
- ;
- exp : '(' exp1 ')'
- { }
- ;
- /* Binary operators in order of decreasing precedence. */
- exp : exp '@' exp
- { pstate->wrap2<repeat_operation> (); }
- ;
- exp : exp '*' exp
- { pstate->wrap2<mul_operation> (); }
- ;
- exp : exp '/' exp
- { pstate->wrap2<div_operation> (); }
- ;
- exp : exp '%' exp
- { pstate->wrap2<rem_operation> (); }
- ;
- exp : exp '+' exp
- { pstate->wrap2<add_operation> (); }
- ;
- exp : exp '-' exp
- { pstate->wrap2<sub_operation> (); }
- ;
- exp : exp LSH exp
- { pstate->wrap2<lsh_operation> (); }
- ;
- exp : exp RSH exp
- { pstate->wrap2<rsh_operation> (); }
- ;
- exp : exp EQUAL exp
- {
- if (pstate->language ()->la_language
- == language_opencl)
- pstate->wrap2<opencl_equal_operation> ();
- else
- pstate->wrap2<equal_operation> ();
- }
- ;
- exp : exp NOTEQUAL exp
- {
- if (pstate->language ()->la_language
- == language_opencl)
- pstate->wrap2<opencl_notequal_operation> ();
- else
- pstate->wrap2<notequal_operation> ();
- }
- ;
- exp : exp LEQ exp
- {
- if (pstate->language ()->la_language
- == language_opencl)
- pstate->wrap2<opencl_leq_operation> ();
- else
- pstate->wrap2<leq_operation> ();
- }
- ;
- exp : exp GEQ exp
- {
- if (pstate->language ()->la_language
- == language_opencl)
- pstate->wrap2<opencl_geq_operation> ();
- else
- pstate->wrap2<geq_operation> ();
- }
- ;
- exp : exp '<' exp
- {
- if (pstate->language ()->la_language
- == language_opencl)
- pstate->wrap2<opencl_less_operation> ();
- else
- pstate->wrap2<less_operation> ();
- }
- ;
- exp : exp '>' exp
- {
- if (pstate->language ()->la_language
- == language_opencl)
- pstate->wrap2<opencl_gtr_operation> ();
- else
- pstate->wrap2<gtr_operation> ();
- }
- ;
- exp : exp '&' exp
- { pstate->wrap2<bitwise_and_operation> (); }
- ;
- exp : exp '^' exp
- { pstate->wrap2<bitwise_xor_operation> (); }
- ;
- exp : exp '|' exp
- { pstate->wrap2<bitwise_ior_operation> (); }
- ;
- exp : exp ANDAND exp
- {
- if (pstate->language ()->la_language
- == language_opencl)
- {
- operation_up rhs = pstate->pop ();
- operation_up lhs = pstate->pop ();
- pstate->push_new<opencl_logical_binop_operation>
- (BINOP_LOGICAL_AND, std::move (lhs),
- std::move (rhs));
- }
- else
- pstate->wrap2<logical_and_operation> ();
- }
- ;
- exp : exp OROR exp
- {
- if (pstate->language ()->la_language
- == language_opencl)
- {
- operation_up rhs = pstate->pop ();
- operation_up lhs = pstate->pop ();
- pstate->push_new<opencl_logical_binop_operation>
- (BINOP_LOGICAL_OR, std::move (lhs),
- std::move (rhs));
- }
- else
- pstate->wrap2<logical_or_operation> ();
- }
- ;
- exp : exp '?' exp ':' exp %prec '?'
- {
- operation_up last = pstate->pop ();
- operation_up mid = pstate->pop ();
- operation_up first = pstate->pop ();
- if (pstate->language ()->la_language
- == language_opencl)
- pstate->push_new<opencl_ternop_cond_operation>
- (std::move (first), std::move (mid),
- std::move (last));
- else
- pstate->push_new<ternop_cond_operation>
- (std::move (first), std::move (mid),
- std::move (last));
- }
- ;
- exp : exp '=' exp
- {
- if (pstate->language ()->la_language
- == language_opencl)
- pstate->wrap2<opencl_assign_operation> ();
- else
- pstate->wrap2<assign_operation> ();
- }
- ;
- exp : exp ASSIGN_MODIFY exp
- {
- operation_up rhs = pstate->pop ();
- operation_up lhs = pstate->pop ();
- pstate->push_new<assign_modify_operation>
- ($2, std::move (lhs), std::move (rhs));
- }
- ;
- exp : INT
- {
- pstate->push_new<long_const_operation>
- ($1.type, $1.val);
- }
- ;
- exp : COMPLEX_INT
- {
- operation_up real
- = (make_operation<long_const_operation>
- (TYPE_TARGET_TYPE ($1.type), 0));
- operation_up imag
- = (make_operation<long_const_operation>
- (TYPE_TARGET_TYPE ($1.type), $1.val));
- pstate->push_new<complex_operation>
- (std::move (real), std::move (imag), $1.type);
- }
- ;
- exp : CHAR
- {
- struct stoken_vector vec;
- vec.len = 1;
- vec.tokens = &$1;
- pstate->push_c_string ($1.type, &vec);
- }
- ;
- exp : NAME_OR_INT
- { YYSTYPE val;
- parse_number (pstate, $1.stoken.ptr,
- $1.stoken.length, 0, &val);
- pstate->push_new<long_const_operation>
- (val.typed_val_int.type,
- val.typed_val_int.val);
- }
- ;
- exp : FLOAT
- {
- 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);
- }
- ;
- exp : COMPLEX_FLOAT
- {
- struct type *underlying
- = TYPE_TARGET_TYPE ($1.type);
- float_data val;
- target_float_from_host_double (val.data (),
- underlying, 0);
- operation_up real
- = (make_operation<float_const_operation>
- (underlying, val));
- std::copy (std::begin ($1.val), std::end ($1.val),
- std::begin (val));
- operation_up imag
- = (make_operation<float_const_operation>
- (underlying, val));
- pstate->push_new<complex_operation>
- (std::move (real), std::move (imag),
- $1.type);
- }
- ;
- exp : variable
- ;
- exp : DOLLAR_VARIABLE
- {
- pstate->push_dollar ($1);
- }
- ;
- exp : SELECTOR '(' name ')'
- {
- pstate->push_new<objc_selector_operation>
- (copy_name ($3));
- }
- ;
- exp : SIZEOF '(' type ')' %prec UNARY
- { struct type *type = $3;
- struct type *int_type
- = lookup_signed_typename (pstate->language (),
- "int");
- type = check_typedef (type);
- /* $5.3.3/2 of the C++ Standard (n3290 draft)
- says of sizeof: "When applied to a reference
- or a reference type, the result is the size of
- the referenced type." */
- if (TYPE_IS_REFERENCE (type))
- type = check_typedef (TYPE_TARGET_TYPE (type));
- pstate->push_new<long_const_operation>
- (int_type, TYPE_LENGTH (type));
- }
- ;
- exp : REINTERPRET_CAST '<' type_exp '>' '(' exp ')' %prec UNARY
- { pstate->wrap2<reinterpret_cast_operation> (); }
- ;
- exp : STATIC_CAST '<' type_exp '>' '(' exp ')' %prec UNARY
- { pstate->wrap2<unop_cast_type_operation> (); }
- ;
- exp : DYNAMIC_CAST '<' type_exp '>' '(' exp ')' %prec UNARY
- { pstate->wrap2<dynamic_cast_operation> (); }
- ;
- exp : CONST_CAST '<' type_exp '>' '(' exp ')' %prec UNARY
- { /* We could do more error checking here, but
- it doesn't seem worthwhile. */
- pstate->wrap2<unop_cast_type_operation> (); }
- ;
- 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 = (char *) 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 = 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;
- }
- ;
- exp : string_exp
- {
- int i;
- c_string_type type = C_STRING;
- for (i = 0; i < $1.len; ++i)
- {
- 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 = (enum c_string_type_values) $1.tokens[i].type;
- break;
- default:
- /* internal error */
- internal_error (__FILE__, __LINE__,
- "unrecognized type in string concatenation");
- }
- }
- pstate->push_c_string (type, &$1);
- for (i = 0; i < $1.len; ++i)
- free ($1.tokens[i].ptr);
- free ($1.tokens);
- }
- ;
- exp : NSSTRING /* ObjC NextStep NSString constant
- * of the form '@' '"' string '"'.
- */
- {
- pstate->push_new<objc_nsstring_operation>
- (copy_name ($1));
- }
- ;
- /* C++. */
- exp : TRUEKEYWORD
- { pstate->push_new<long_const_operation>
- (parse_type (pstate)->builtin_bool, 1);
- }
- ;
- exp : FALSEKEYWORD
- { pstate->push_new<long_const_operation>
- (parse_type (pstate)->builtin_bool, 0);
- }
- ;
- /* end of C++. */
- block : BLOCKNAME
- {
- if ($1.sym.symbol)
- $$ = SYMBOL_BLOCK_VALUE ($1.sym.symbol);
- else
- error (_("No file or function \"%s\"."),
- copy_name ($1.stoken).c_str ());
- }
- | FILENAME
- {
- $$ = $1;
- }
- ;
- block : block COLONCOLON name
- {
- std::string copy = copy_name ($3);
- struct symbol *tem
- = lookup_symbol (copy.c_str (), $1,
- VAR_DOMAIN, NULL).symbol;
- if (!tem || tem->aclass () != LOC_BLOCK)
- error (_("No function \"%s\" in specified context."),
- copy.c_str ());
- $$ = SYMBOL_BLOCK_VALUE (tem); }
- ;
- variable: name_not_typename ENTRY
- { struct symbol *sym = $1.sym.symbol;
- if (sym == NULL || !sym->is_argument ()
- || !symbol_read_needs_frame (sym))
- error (_("@entry can be used only for function "
- "parameters, not for \"%s\""),
- copy_name ($1.stoken).c_str ());
- pstate->push_new<var_entry_value_operation> (sym);
- }
- ;
- variable: block COLONCOLON name
- {
- std::string copy = copy_name ($3);
- struct block_symbol sym
- = lookup_symbol (copy.c_str (), $1,
- VAR_DOMAIN, NULL);
- if (sym.symbol == 0)
- error (_("No symbol \"%s\" in specified context."),
- copy.c_str ());
- if (symbol_read_needs_frame (sym.symbol))
- pstate->block_tracker->update (sym);
- pstate->push_new<var_value_operation> (sym);
- }
- ;
- qualified_name: TYPENAME COLONCOLON name
- {
- struct type *type = $1.type;
- type = check_typedef (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));
- }
- | TYPENAME COLONCOLON '~' name
- {
- struct type *type = $1.type;
- type = check_typedef (type);
- if (!type_aggregate_p (type))
- error (_("`%s' is not defined as an aggregate type."),
- TYPE_SAFE_NAME (type));
- std::string name = "~" + std::string ($4.ptr,
- $4.length);
- /* Check for valid destructor name. */
- destructor_name_p (name.c_str (), $1.type);
- pstate->push_new<scope_operation> (type,
- std::move (name));
- }
- | TYPENAME COLONCOLON name COLONCOLON name
- {
- std::string copy = copy_name ($3);
- error (_("No type \"%s\" within class "
- "or namespace \"%s\"."),
- copy.c_str (), TYPE_SAFE_NAME ($1.type));
- }
- ;
- variable: qualified_name
- | COLONCOLON name_not_typename
- {
- std::string name = copy_name ($2.stoken);
- struct block_symbol sym
- = lookup_symbol (name.c_str (),
- (const struct block *) NULL,
- VAR_DOMAIN, NULL);
- pstate->push_symbol (name.c_str (), sym);
- }
- ;
- variable: name_not_typename
- { struct block_symbol sym = $1.sym;
- if (sym.symbol)
- {
- if (symbol_read_needs_frame (sym.symbol))
- pstate->block_tracker->update (sym);
- /* If we found a function, see if it's
- an ifunc resolver that has the same
- address as the ifunc symbol itself.
- If so, prefer the ifunc symbol. */
- bound_minimal_symbol resolver
- = find_gnu_ifunc (sym.symbol);
- if (resolver.minsym != NULL)
- pstate->push_new<var_msym_value_operation>
- (resolver);
- else
- pstate->push_new<var_value_operation> (sym);
- }
- else if ($1.is_a_field_of_this)
- {
- /* C++: it hangs off of `this'. Must
- not inadvertently convert from a method call
- to data ref. */
- pstate->block_tracker->update (sym);
- operation_up thisop
- = make_operation<op_this_operation> ();
- pstate->push_new<structop_ptr_operation>
- (std::move (thisop), copy_name ($1.stoken));
- }
- else
- {
- std::string arg = copy_name ($1.stoken);
- bound_minimal_symbol msymbol
- = lookup_bound_minimal_symbol (arg.c_str ());
- if (msymbol.minsym == NULL)
- {
- 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."),
- arg.c_str ());
- }
- /* This minsym might be an alias for
- another function. See if we can find
- the debug symbol for the target, and
- if so, use it instead, since it has
- return type / prototype info. This
- is important for example for "p
- *__errno_location()". */
- symbol *alias_target
- = ((msymbol.minsym->type != mst_text_gnu_ifunc
- && msymbol.minsym->type != mst_data_gnu_ifunc)
- ? find_function_alias_target (msymbol)
- : NULL);
- if (alias_target != NULL)
- {
- block_symbol bsym { alias_target,
- SYMBOL_BLOCK_VALUE (alias_target) };
- pstate->push_new<var_value_operation> (bsym);
- }
- else
- pstate->push_new<var_msym_value_operation>
- (msymbol);
- }
- }
- ;
- const_or_volatile: const_or_volatile_noopt
- |
- ;
- single_qualifier:
- CONST_KEYWORD
- { cpstate->type_stack.insert (tp_const); }
- | VOLATILE_KEYWORD
- { cpstate->type_stack.insert (tp_volatile); }
- | ATOMIC
- { cpstate->type_stack.insert (tp_atomic); }
- | RESTRICT
- { cpstate->type_stack.insert (tp_restrict); }
- | '@' NAME
- {
- cpstate->type_stack.insert (pstate,
- copy_name ($2.stoken).c_str ());
- }
- | '@' UNKNOWN_CPP_NAME
- {
- cpstate->type_stack.insert (pstate,
- copy_name ($2.stoken).c_str ());
- }
- ;
- qualifier_seq_noopt:
- single_qualifier
- | qualifier_seq_noopt single_qualifier
- ;
- qualifier_seq:
- qualifier_seq_noopt
- |
- ;
- ptr_operator:
- ptr_operator '*'
- { cpstate->type_stack.insert (tp_pointer); }
- qualifier_seq
- | '*'
- { cpstate->type_stack.insert (tp_pointer); }
- qualifier_seq
- | '&'
- { cpstate->type_stack.insert (tp_reference); }
- | '&' ptr_operator
- { cpstate->type_stack.insert (tp_reference); }
- | ANDAND
- { cpstate->type_stack.insert (tp_rvalue_reference); }
- | ANDAND ptr_operator
- { cpstate->type_stack.insert (tp_rvalue_reference); }
- ;
- ptr_operator_ts: ptr_operator
- {
- $$ = cpstate->type_stack.create ();
- cpstate->type_stacks.emplace_back ($$);
- }
- ;
- abs_decl: ptr_operator_ts direct_abs_decl
- { $$ = $2->append ($1); }
- | ptr_operator_ts
- | direct_abs_decl
- ;
- direct_abs_decl: '(' abs_decl ')'
- { $$ = $2; }
- | direct_abs_decl array_mod
- {
- cpstate->type_stack.push ($1);
- cpstate->type_stack.push ($2);
- cpstate->type_stack.push (tp_array);
- $$ = cpstate->type_stack.create ();
- cpstate->type_stacks.emplace_back ($$);
- }
- | array_mod
- {
- cpstate->type_stack.push ($1);
- cpstate->type_stack.push (tp_array);
- $$ = cpstate->type_stack.create ();
- cpstate->type_stacks.emplace_back ($$);
- }
- | direct_abs_decl func_mod
- {
- cpstate->type_stack.push ($1);
- cpstate->type_stack.push ($2);
- $$ = cpstate->type_stack.create ();
- cpstate->type_stacks.emplace_back ($$);
- }
- | func_mod
- {
- cpstate->type_stack.push ($1);
- $$ = cpstate->type_stack.create ();
- cpstate->type_stacks.emplace_back ($$);
- }
- ;
- array_mod: '[' ']'
- { $$ = -1; }
- | OBJC_LBRAC ']'
- { $$ = -1; }
- | '[' INT ']'
- { $$ = $2.val; }
- | OBJC_LBRAC INT ']'
- { $$ = $2.val; }
- ;
- func_mod: '(' ')'
- {
- $$ = new std::vector<struct type *>;
- cpstate->type_lists.emplace_back ($$);
- }
- | '(' parameter_typelist ')'
- { $$ = $2; }
- ;
- /* 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)
- is a function type but
- int (foo::bar::baz::bizzle::*)
- is a pointer to member type. Stroustrup loses again! */
- type : ptype
- ;
- /* A helper production that recognizes scalar types that can validly
- be used with _Complex. */
- scalar_type:
- INT_KEYWORD
- { $$ = lookup_signed_typename (pstate->language (),
- "int"); }
- | LONG
- { $$ = lookup_signed_typename (pstate->language (),
- "long"); }
- | SHORT
- { $$ = lookup_signed_typename (pstate->language (),
- "short"); }
- | LONG INT_KEYWORD
- { $$ = lookup_signed_typename (pstate->language (),
- "long"); }
- | LONG SIGNED_KEYWORD INT_KEYWORD
- { $$ = lookup_signed_typename (pstate->language (),
- "long"); }
- | LONG SIGNED_KEYWORD
- { $$ = lookup_signed_typename (pstate->language (),
- "long"); }
- | SIGNED_KEYWORD LONG INT_KEYWORD
- { $$ = lookup_signed_typename (pstate->language (),
- "long"); }
- | UNSIGNED LONG INT_KEYWORD
- { $$ = lookup_unsigned_typename (pstate->language (),
- "long"); }
- | LONG UNSIGNED INT_KEYWORD
- { $$ = lookup_unsigned_typename (pstate->language (),
- "long"); }
- | LONG UNSIGNED
- { $$ = lookup_unsigned_typename (pstate->language (),
- "long"); }
- | LONG LONG
- { $$ = lookup_signed_typename (pstate->language (),
- "long long"); }
- | LONG LONG INT_KEYWORD
- { $$ = lookup_signed_typename (pstate->language (),
- "long long"); }
- | LONG LONG SIGNED_KEYWORD INT_KEYWORD
- { $$ = lookup_signed_typename (pstate->language (),
- "long long"); }
- | LONG LONG SIGNED_KEYWORD
- { $$ = lookup_signed_typename (pstate->language (),
- "long long"); }
- | SIGNED_KEYWORD LONG LONG
- { $$ = lookup_signed_typename (pstate->language (),
- "long long"); }
- | SIGNED_KEYWORD LONG LONG INT_KEYWORD
- { $$ = lookup_signed_typename (pstate->language (),
- "long long"); }
- | UNSIGNED LONG LONG
- { $$ = lookup_unsigned_typename (pstate->language (),
- "long long"); }
- | UNSIGNED LONG LONG INT_KEYWORD
- { $$ = lookup_unsigned_typename (pstate->language (),
- "long long"); }
- | LONG LONG UNSIGNED
- { $$ = lookup_unsigned_typename (pstate->language (),
- "long long"); }
- | LONG LONG UNSIGNED INT_KEYWORD
- { $$ = lookup_unsigned_typename (pstate->language (),
- "long long"); }
- | SHORT INT_KEYWORD
- { $$ = lookup_signed_typename (pstate->language (),
- "short"); }
- | SHORT SIGNED_KEYWORD INT_KEYWORD
- { $$ = lookup_signed_typename (pstate->language (),
- "short"); }
- | SHORT SIGNED_KEYWORD
- { $$ = lookup_signed_typename (pstate->language (),
- "short"); }
- | UNSIGNED SHORT INT_KEYWORD
- { $$ = lookup_unsigned_typename (pstate->language (),
- "short"); }
- | SHORT UNSIGNED
- { $$ = lookup_unsigned_typename (pstate->language (),
- "short"); }
- | SHORT UNSIGNED INT_KEYWORD
- { $$ = lookup_unsigned_typename (pstate->language (),
- "short"); }
- | DOUBLE_KEYWORD
- { $$ = lookup_typename (pstate->language (),
- "double",
- NULL,
- 0); }
- | FLOAT_KEYWORD
- { $$ = lookup_typename (pstate->language (),
- "float",
- NULL,
- 0); }
- | LONG DOUBLE_KEYWORD
- { $$ = lookup_typename (pstate->language (),
- "long double",
- NULL,
- 0); }
- | UNSIGNED type_name
- { $$ = lookup_unsigned_typename (pstate->language (),
- $2.type->name ()); }
- | UNSIGNED
- { $$ = lookup_unsigned_typename (pstate->language (),
- "int"); }
- | SIGNED_KEYWORD type_name
- { $$ = lookup_signed_typename (pstate->language (),
- $2.type->name ()); }
- | SIGNED_KEYWORD
- { $$ = lookup_signed_typename (pstate->language (),
- "int"); }
- ;
- /* Implements (approximately): (type-qualifier)* type-specifier.
- When type-specifier is only ever a single word, like 'float' then these
- arrive as pre-built TYPENAME tokens thanks to the classify_name
- function. However, when a type-specifier can contain multiple words,
- for example 'double' can appear as just 'double' or 'long double', and
- similarly 'long' can appear as just 'long' or in 'long double', then
- these type-specifiers are parsed into their own tokens in the function
- lex_one_token and the ident_tokens array. These separate tokens are all
- recognised here. */
- typebase
- : TYPENAME
- { $$ = $1.type; }
- | scalar_type
- { $$ = $1; }
- | COMPLEX scalar_type
- {
- $$ = init_complex_type (nullptr, $2);
- }
- | STRUCT name
- { $$
- = lookup_struct (copy_name ($2).c_str (),
- pstate->expression_context_block);
- }
- | STRUCT COMPLETE
- {
- pstate->mark_completion_tag (TYPE_CODE_STRUCT,
- "", 0);
- $$ = NULL;
- }
- | STRUCT name COMPLETE
- {
- pstate->mark_completion_tag (TYPE_CODE_STRUCT,
- $2.ptr, $2.length);
- $$ = NULL;
- }
- | CLASS name
- { $$ = lookup_struct
- (copy_name ($2).c_str (),
- pstate->expression_context_block);
- }
- | CLASS COMPLETE
- {
- pstate->mark_completion_tag (TYPE_CODE_STRUCT,
- "", 0);
- $$ = NULL;
- }
- | CLASS name COMPLETE
- {
- pstate->mark_completion_tag (TYPE_CODE_STRUCT,
- $2.ptr, $2.length);
- $$ = NULL;
- }
- | UNION name
- { $$
- = lookup_union (copy_name ($2).c_str (),
- pstate->expression_context_block);
- }
- | UNION COMPLETE
- {
- pstate->mark_completion_tag (TYPE_CODE_UNION,
- "", 0);
- $$ = NULL;
- }
- | UNION name COMPLETE
- {
- pstate->mark_completion_tag (TYPE_CODE_UNION,
- $2.ptr, $2.length);
- $$ = NULL;
- }
- | ENUM name
- { $$ = lookup_enum (copy_name ($2).c_str (),
- pstate->expression_context_block);
- }
- | ENUM COMPLETE
- {
- pstate->mark_completion_tag (TYPE_CODE_ENUM, "", 0);
- $$ = NULL;
- }
- | ENUM name COMPLETE
- {
- pstate->mark_completion_tag (TYPE_CODE_ENUM, $2.ptr,
- $2.length);
- $$ = NULL;
- }
- /* It appears that this rule for templates is never
- reduced; template recognition happens by lookahead
- in the token processing code in yylex. */
- | TEMPLATE name '<' type '>'
- { $$ = lookup_template_type
- (copy_name($2).c_str (), $4,
- pstate->expression_context_block);
- }
- | qualifier_seq_noopt typebase
- { $$ = cpstate->type_stack.follow_types ($2); }
- | typebase qualifier_seq_noopt
- { $$ = cpstate->type_stack.follow_types ($1); }
- ;
- type_name: TYPENAME
- | INT_KEYWORD
- {
- $$.stoken.ptr = "int";
- $$.stoken.length = 3;
- $$.type = lookup_signed_typename (pstate->language (),
- "int");
- }
- | LONG
- {
- $$.stoken.ptr = "long";
- $$.stoken.length = 4;
- $$.type = lookup_signed_typename (pstate->language (),
- "long");
- }
- | SHORT
- {
- $$.stoken.ptr = "short";
- $$.stoken.length = 5;
- $$.type = lookup_signed_typename (pstate->language (),
- "short");
- }
- ;
- parameter_typelist:
- nonempty_typelist
- { check_parameter_typelist ($1); }
- | nonempty_typelist ',' DOTDOTDOT
- {
- $1->push_back (NULL);
- check_parameter_typelist ($1);
- $$ = $1;
- }
- ;
- nonempty_typelist
- : type
- {
- std::vector<struct type *> *typelist
- = new std::vector<struct type *>;
- cpstate->type_lists.emplace_back (typelist);
- typelist->push_back ($1);
- $$ = typelist;
- }
- | nonempty_typelist ',' type
- {
- $1->push_back ($3);
- $$ = $1;
- }
- ;
- ptype : typebase
- | ptype abs_decl
- {
- cpstate->type_stack.push ($2);
- $$ = cpstate->type_stack.follow_types ($1);
- }
- ;
- conversion_type_id: typebase conversion_declarator
- { $$ = cpstate->type_stack.follow_types ($1); }
- ;
- conversion_declarator: /* Nothing. */
- | ptr_operator conversion_declarator
- ;
- const_and_volatile: CONST_KEYWORD VOLATILE_KEYWORD
- | VOLATILE_KEYWORD CONST_KEYWORD
- ;
- const_or_volatile_noopt: const_and_volatile
- { cpstate->type_stack.insert (tp_const);
- cpstate->type_stack.insert (tp_volatile);
- }
- | CONST_KEYWORD
- { cpstate->type_stack.insert (tp_const); }
- | VOLATILE_KEYWORD
- { cpstate->type_stack.insert (tp_volatile); }
- ;
- oper: OPERATOR NEW
- { $$ = operator_stoken (" new"); }
- | OPERATOR DELETE
- { $$ = operator_stoken (" delete"); }
- | OPERATOR NEW '[' ']'
- { $$ = operator_stoken (" new[]"); }
- | OPERATOR DELETE '[' ']'
- { $$ = operator_stoken (" delete[]"); }
- | OPERATOR NEW OBJC_LBRAC ']'
- { $$ = operator_stoken (" new[]"); }
- | OPERATOR DELETE OBJC_LBRAC ']'
- { $$ = 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 OBJC_LBRAC ']'
- { $$ = operator_stoken ("[]"); }
- | OPERATOR conversion_type_id
- {
- string_file buf;
- c_print_type ($2, NULL, &buf, -1, 0,
- &type_print_raw_options);
- std::string name = buf.release ();
- /* This also needs canonicalization. */
- gdb::unique_xmalloc_ptr<char> canon
- = cp_canonicalize_string (name.c_str ());
- if (canon != nullptr)
- name = canon.get ();
- $$ = operator_stoken ((" " + name).c_str ());
- }
- ;
- /* This rule exists in order to allow some tokens that would not normally
- match the 'name' rule to appear as fields within a struct. The example
- that initially motivated this was the RISC-V target which models the
- floating point registers as a union with fields called 'float' and
- 'double'. */
- field_name
- : name
- | DOUBLE_KEYWORD { $$ = typename_stoken ("double"); }
- | FLOAT_KEYWORD { $$ = typename_stoken ("float"); }
- | INT_KEYWORD { $$ = typename_stoken ("int"); }
- | LONG { $$ = typename_stoken ("long"); }
- | SHORT { $$ = typename_stoken ("short"); }
- | SIGNED_KEYWORD { $$ = typename_stoken ("signed"); }
- | UNSIGNED { $$ = typename_stoken ("unsigned"); }
- ;
- name : NAME { $$ = $1.stoken; }
- | BLOCKNAME { $$ = $1.stoken; }
- | TYPENAME { $$ = $1.stoken; }
- | NAME_OR_INT { $$ = $1.stoken; }
- | UNKNOWN_CPP_NAME { $$ = $1.stoken; }
- | oper { $$ = $1; }
- ;
- name_not_typename : NAME
- | BLOCKNAME
- /* These would be useful if name_not_typename was useful, but it is just
- a fake for "variable", so these cause reduce/reduce conflicts because
- the parser can't tell whether NAME_OR_INT is a name_not_typename (=variable,
- =exp) or just an exp. If name_not_typename was ever used in an lvalue
- context where only a name could occur, this might be useful.
- | NAME_OR_INT
- */
- | oper
- {
- struct field_of_this_result is_a_field_of_this;
- $$.stoken = $1;
- $$.sym
- = lookup_symbol ($1.ptr,
- pstate->expression_context_block,
- VAR_DOMAIN,
- &is_a_field_of_this);
- $$.is_a_field_of_this
- = is_a_field_of_this.type != NULL;
- }
- | 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)
- {
- struct stoken st = { NULL, 0 };
- char *buf;
- st.length = CP_OPERATOR_LEN + strlen (op);
- buf = (char *) malloc (st.length + 1);
- strcpy (buf, CP_OPERATOR_STR);
- strcat (buf, op);
- st.ptr = buf;
- /* The toplevel (c_parse) will free the memory allocated here. */
- cpstate->strings.emplace_back (buf);
- return st;
- };
- /* Returns a stoken of the type named TYPE. */
- static struct stoken
- typename_stoken (const char *type)
- {
- struct stoken st = { type, 0 };
- st.length = strlen (type);
- return st;
- };
- /* 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_NAMESPACE
- || (type->code () == TYPE_CODE_ENUM
- && type->is_declared_class ()));
- }
- /* Validate a parameter typelist. */
- static void
- check_parameter_typelist (std::vector<struct type *> *params)
- {
- struct type *type;
- int ix;
- for (ix = 0; ix < params->size (); ++ix)
- {
- type = (*params)[ix];
- if (type != NULL && check_typedef (type)->code () == TYPE_CODE_VOID)
- {
- if (ix == 0)
- {
- if (params->size () == 1)
- {
- /* Ok. */
- break;
- }
- error (_("parameter types following 'void'"));
- }
- else
- error (_("'void' invalid as parameter type"));
- }
- }
- }
- /* 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 *par_state,
- const char *buf, 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;
- /* Number of "L" suffixes encountered. */
- int long_p = 0;
- /* Imaginary number. */
- bool imaginary_p = false;
- /* We have found a "L" or "U" (or "i") suffix. */
- int found_suffix = 0;
- ULONGEST high_bit;
- struct type *signed_type;
- struct type *unsigned_type;
- char *p;
- p = (char *) alloca (len);
- memcpy (p, buf, len);
- if (parsed_float)
- {
- if (len >= 1 && p[len - 1] == 'i')
- {
- imaginary_p = true;
- --len;
- }
- /* Handle suffixes for decimal floating-point: "df", "dd" or "dl". */
- if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'f')
- {
- putithere->typed_val_float.type
- = parse_type (par_state)->builtin_decfloat;
- len -= 2;
- }
- else if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'd')
- {
- putithere->typed_val_float.type
- = parse_type (par_state)->builtin_decdouble;
- len -= 2;
- }
- else if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'l')
- {
- putithere->typed_val_float.type
- = parse_type (par_state)->builtin_declong;
- len -= 2;
- }
- /* Handle suffixes: 'f' for float, 'l' for long double. */
- else if (len >= 1 && TOLOWER (p[len - 1]) == 'f')
- {
- putithere->typed_val_float.type
- = parse_type (par_state)->builtin_float;
- len -= 1;
- }
- else if (len >= 1 && TOLOWER (p[len - 1]) == 'l')
- {
- putithere->typed_val_float.type
- = parse_type (par_state)->builtin_long_double;
- len -= 1;
- }
- /* Default type for floating-point literals is double. */
- else
- {
- putithere->typed_val_float.type
- = parse_type (par_state)->builtin_double;
- }
- if (!parse_float (p, len,
- putithere->typed_val_float.type,
- putithere->typed_val_float.val))
- return ERROR;
- if (imaginary_p)
- putithere->typed_val_float.type
- = init_complex_type (nullptr, putithere->typed_val_float.type);
- return imaginary_p ? COMPLEX_FLOAT : FLOAT;
- }
- /* Handle base-switching prefixes 0x, 0t, 0d, 0 */
- if (p[0] == '0' && len > 1)
- 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;
- case 't':
- case 'T':
- case 'd':
- case 'D':
- if (len >= 3)
- {
- p += 2;
- base = 10;
- len -= 2;
- }
- break;
- default:
- base = 8;
- break;
- }
- while (len-- > 0)
- {
- c = *p++;
- if (c >= 'A' && c <= 'Z')
- c += 'a' - 'A';
- if (c != 'l' && c != 'u' && c != 'i')
- n *= base;
- if (c >= '0' && c <= '9')
- {
- if (found_suffix)
- return ERROR;
- n += i = c - '0';
- }
- else
- {
- if (base > 10 && c >= 'a' && c <= 'f')
- {
- if (found_suffix)
- return ERROR;
- n += i = c - 'a' + 10;
- }
- else if (c == 'l')
- {
- ++long_p;
- found_suffix = 1;
- }
- else if (c == 'u')
- {
- unsigned_p = 1;
- found_suffix = 1;
- }
- else if (c == 'i')
- {
- imaginary_p = true;
- found_suffix = 1;
- }
- else
- return ERROR; /* Char not a digit */
- }
- if (i >= base)
- return ERROR; /* Invalid digit in this base */
- /* Portably test for overflow (only works for nonzero values, so make
- a second check for zero). FIXME: Can't we just make n and prevn
- unsigned and avoid this? */
- if (c != 'l' && c != 'u' && c != 'i' && (prevn >= n) && n != 0)
- unsigned_p = 1; /* Try something unsigned */
- /* Portably test for unsigned overflow.
- FIXME: This check is wrong; for example it doesn't find overflow
- on 0x123456789 when LONGEST is 32 bits. */
- if (c != 'l' && c != 'u' && c != 'i' && n != 0)
- {
- if (unsigned_p && prevn >= n)
- error (_("Numeric constant too large."));
- }
- prevn = n;
- }
- /* An integer constant is an int, a long, or a long long. An L
- suffix forces it to be long; an LL suffix forces it to be long
- long. If not forced to a larger size, it gets the first type of
- the above that it fits in. To figure out whether it fits, we
- shift it right and see whether anything remains. Note that we
- can't shift sizeof (LONGEST) * HOST_CHAR_BIT bits or more in one
- operation, because many compilers will warn about such a shift
- (which always produces a zero result). Sometimes 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 = n >> 2;
- if (long_p == 0
- && (un >> (gdbarch_int_bit (par_state->gdbarch ()) - 2)) == 0)
- {
- high_bit
- = ((ULONGEST)1) << (gdbarch_int_bit (par_state->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,
- never an unsigned int, but this code treats it as unsigned
- int. This probably should be fixed. GCC gives a warning on
- such constants. */
- unsigned_type = parse_type (par_state)->builtin_unsigned_int;
- signed_type = parse_type (par_state)->builtin_int;
- }
- else if (long_p <= 1
- && (un >> (gdbarch_long_bit (par_state->gdbarch ()) - 2)) == 0)
- {
- high_bit
- = ((ULONGEST)1) << (gdbarch_long_bit (par_state->gdbarch ()) - 1);
- unsigned_type = parse_type (par_state)->builtin_unsigned_long;
- signed_type = parse_type (par_state)->builtin_long;
- }
- else
- {
- int shift;
- if (sizeof (ULONGEST) * HOST_CHAR_BIT
- < gdbarch_long_long_bit (par_state->gdbarch ()))
- /* A long long does not fit in a LONGEST. */
- shift = (sizeof (ULONGEST) * HOST_CHAR_BIT - 1);
- else
- shift = (gdbarch_long_long_bit (par_state->gdbarch ()) - 1);
- high_bit = (ULONGEST) 1 << shift;
- unsigned_type = parse_type (par_state)->builtin_unsigned_long_long;
- signed_type = parse_type (par_state)->builtin_long_long;
- }
- putithere->typed_val_int.val = n;
- /* If the high bit of the worked out type is set then this number
- has to be unsigned. */
- if (unsigned_p || (n & high_bit))
- {
- putithere->typed_val_int.type = unsigned_type;
- }
- else
- {
- putithere->typed_val_int.type = signed_type;
- }
- if (imaginary_p)
- putithere->typed_val_int.type
- = init_complex_type (nullptr, putithere->typed_val_int.type);
- return imaginary_p ? COMPLEX_INT : 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 (const char **ptr, struct obstack *output)
- {
- const 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 (const char *tokptr, const char **outptr,
- struct typed_stoken *value, int *host_chars)
- {
- int quote;
- c_string_type type;
- int is_objc = 0;
- /* 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 if (*tokptr == '@')
- {
- /* An Objective C string. */
- is_objc = 1;
- type = C_STRING;
- ++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 = (char *) obstack_base (&tempbuf);
- value->length = obstack_object_size (&tempbuf);
- *outptr = tokptr;
- return quote == '"' ? (is_objc ? NSSTRING : STRING) : CHAR;
- }
- /* This is used to associate some attributes with a token. */
- enum token_flag
- {
- /* If this bit is set, the token is C++-only. */
- FLAG_CXX = 1,
- /* If this bit is set, the token is C-only. */
- FLAG_C = 2,
- /* If this bit is set, the token is conditional: if there is a
- symbol of the same name, then the token is a symbol; otherwise,
- the token is a keyword. */
- FLAG_SHADOW = 4
- };
- DEF_ENUM_FLAGS_TYPE (enum token_flag, token_flags);
- struct token
- {
- const char *oper;
- int token;
- enum exp_opcode opcode;
- token_flags flags;
- };
- static const struct token tokentab3[] =
- {
- {">>=", ASSIGN_MODIFY, BINOP_RSH, 0},
- {"<<=", ASSIGN_MODIFY, BINOP_LSH, 0},
- {"->*", ARROW_STAR, OP_NULL, FLAG_CXX},
- {"...", DOTDOTDOT, OP_NULL, 0}
- };
- static const struct token tokentab2[] =
- {
- {"+=", 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, OP_NULL, 0},
- {"--", DECREMENT, OP_NULL, 0},
- {"->", ARROW, OP_NULL, 0},
- {"&&", ANDAND, OP_NULL, 0},
- {"||", OROR, OP_NULL, 0},
- /* "::" is *not* only C++: gdb overrides its meaning in several
- different ways, e.g., 'filename'::func, function::variable. */
- {"::", COLONCOLON, OP_NULL, 0},
- {"<<", LSH, OP_NULL, 0},
- {">>", RSH, OP_NULL, 0},
- {"==", EQUAL, OP_NULL, 0},
- {"!=", NOTEQUAL, OP_NULL, 0},
- {"<=", LEQ, OP_NULL, 0},
- {">=", GEQ, OP_NULL, 0},
- {".*", DOT_STAR, OP_NULL, FLAG_CXX}
- };
- /* Identifier-like tokens. Only type-specifiers than can appear in
- multi-word type names (for example 'double' can appear in 'long
- double') need to be listed here. type-specifiers that are only ever
- single word (like 'char') are handled by the classify_name function. */
- static const struct token ident_tokens[] =
- {
- {"unsigned", UNSIGNED, OP_NULL, 0},
- {"template", TEMPLATE, OP_NULL, FLAG_CXX},
- {"volatile", VOLATILE_KEYWORD, OP_NULL, 0},
- {"struct", STRUCT, OP_NULL, 0},
- {"signed", SIGNED_KEYWORD, OP_NULL, 0},
- {"sizeof", SIZEOF, OP_NULL, 0},
- {"_Alignof", ALIGNOF, OP_NULL, 0},
- {"alignof", ALIGNOF, OP_NULL, FLAG_CXX},
- {"double", DOUBLE_KEYWORD, OP_NULL, 0},
- {"float", FLOAT_KEYWORD, OP_NULL, 0},
- {"false", FALSEKEYWORD, OP_NULL, FLAG_CXX},
- {"class", CLASS, OP_NULL, FLAG_CXX},
- {"union", UNION, OP_NULL, 0},
- {"short", SHORT, OP_NULL, 0},
- {"const", CONST_KEYWORD, OP_NULL, 0},
- {"restrict", RESTRICT, OP_NULL, FLAG_C | FLAG_SHADOW},
- {"__restrict__", RESTRICT, OP_NULL, 0},
- {"__restrict", RESTRICT, OP_NULL, 0},
- {"_Atomic", ATOMIC, OP_NULL, 0},
- {"enum", ENUM, OP_NULL, 0},
- {"long", LONG, OP_NULL, 0},
- {"_Complex", COMPLEX, OP_NULL, 0},
- {"__complex__", COMPLEX, OP_NULL, 0},
- {"true", TRUEKEYWORD, OP_NULL, FLAG_CXX},
- {"int", INT_KEYWORD, OP_NULL, 0},
- {"new", NEW, OP_NULL, FLAG_CXX},
- {"delete", DELETE, OP_NULL, FLAG_CXX},
- {"operator", OPERATOR, OP_NULL, FLAG_CXX},
- {"and", ANDAND, OP_NULL, FLAG_CXX},
- {"and_eq", ASSIGN_MODIFY, BINOP_BITWISE_AND, FLAG_CXX},
- {"bitand", '&', OP_NULL, FLAG_CXX},
- {"bitor", '|', OP_NULL, FLAG_CXX},
- {"compl", '~', OP_NULL, FLAG_CXX},
- {"not", '!', OP_NULL, FLAG_CXX},
- {"not_eq", NOTEQUAL, OP_NULL, FLAG_CXX},
- {"or", OROR, OP_NULL, FLAG_CXX},
- {"or_eq", ASSIGN_MODIFY, BINOP_BITWISE_IOR, FLAG_CXX},
- {"xor", '^', OP_NULL, FLAG_CXX},
- {"xor_eq", ASSIGN_MODIFY, BINOP_BITWISE_XOR, FLAG_CXX},
- {"const_cast", CONST_CAST, OP_NULL, FLAG_CXX },
- {"dynamic_cast", DYNAMIC_CAST, OP_NULL, FLAG_CXX },
- {"static_cast", STATIC_CAST, OP_NULL, FLAG_CXX },
- {"reinterpret_cast", REINTERPRET_CAST, OP_NULL, FLAG_CXX },
- {"__typeof__", TYPEOF, OP_TYPEOF, 0 },
- {"__typeof", TYPEOF, OP_TYPEOF, 0 },
- {"typeof", TYPEOF, OP_TYPEOF, FLAG_SHADOW },
- {"__decltype", DECLTYPE, OP_DECLTYPE, FLAG_CXX },
- {"decltype", DECLTYPE, OP_DECLTYPE, FLAG_CXX | FLAG_SHADOW },
- {"typeid", TYPEID, OP_TYPEID, FLAG_CXX}
- };
- static void
- scan_macro_expansion (const char *expansion)
- {
- /* We'd better not be trying to push the stack twice. */
- gdb_assert (! cpstate->macro_original_text);
- /* Copy to the obstack. */
- const char *copy = obstack_strdup (&cpstate->expansion_obstack, expansion);
- /* Save the old lexptr value, so we can return to it when we're done
- parsing the expanded text. */
- cpstate->macro_original_text = pstate->lexptr;
- pstate->lexptr = copy;
- }
- static int
- scanning_macro_expansion (void)
- {
- return cpstate->macro_original_text != 0;
- }
- static void
- finished_macro_expansion (void)
- {
- /* There'd better be something to pop back to. */
- gdb_assert (cpstate->macro_original_text);
- /* Pop back to the original text. */
- pstate->lexptr = cpstate->macro_original_text;
- cpstate->macro_original_text = 0;
- }
- /* 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. */
- static bool 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, bool *is_quoted_name)
- {
- int c;
- int namelen;
- const char *tokstart;
- bool saw_structop = last_was_structop;
- last_was_structop = false;
- *is_quoted_name = false;
- retry:
- /* Check if this is a macro invocation that we need to expand. */
- if (! scanning_macro_expansion ())
- {
- gdb::unique_xmalloc_ptr<char> expanded
- = macro_expand_next (&pstate->lexptr, *expression_macro_scope);
- if (expanded != nullptr)
- scan_macro_expansion (expanded.get ());
- }
- 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)
- {
- if ((token.flags & FLAG_CXX) != 0
- && par_state->language ()->la_language != language_cplus)
- break;
- gdb_assert ((token.flags & FLAG_C) == 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)
- {
- if ((token.flags & FLAG_CXX) != 0
- && par_state->language ()->la_language != language_cplus)
- break;
- gdb_assert ((token.flags & FLAG_C) == 0);
- pstate->lexptr += 2;
- yylval.opcode = token.opcode;
- if (token.token == ARROW)
- last_was_structop = 1;
- return token.token;
- }
- switch (c = *tokstart)
- {
- case 0:
- /* If we were just scanning the result of a macro expansion,
- then we need to resume scanning the original text.
- If we're parsing for field name completion, and the previous
- token allows such completion, return a COMPLETE token.
- Otherwise, we were already scanning the original text, and
- we're really done. */
- if (scanning_macro_expansion ())
- {
- finished_macro_expansion ();
- goto retry;
- }
- else if (saw_name_at_eof)
- {
- saw_name_at_eof = 0;
- return COMPLETE;
- }
- else if (par_state->parse_completion && saw_structop)
- return COMPLETE;
- else
- return 0;
- case ' ':
- case '\t':
- case '\n':
- pstate->lexptr++;
- goto retry;
- case '[':
- case '(':
- paren_depth++;
- pstate->lexptr++;
- if (par_state->language ()->la_language == language_objc
- && c == '[')
- return OBJC_LBRAC;
- return c;
- case ']':
- case ')':
- if (paren_depth == 0)
- return 0;
- paren_depth--;
- pstate->lexptr++;
- return c;
- case ',':
- if (pstate->comma_terminates
- && paren_depth == 0
- && ! scanning_macro_expansion ())
- return 0;
- pstate->lexptr++;
- return c;
- case '.':
- /* Might be a floating point number. */
- if (pstate->lexptr[1] < '0' || pstate->lexptr[1] > '9')
- {
- last_was_structop = true;
- 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, got_p = 0, toktype;
- const char *p = tokstart;
- int hex = input_radix > 10;
- if (c == '0' && (p[1] == 'x' || p[1] == 'X'))
- {
- p += 2;
- hex = 1;
- }
- else if (c == '0' && (p[1]=='t' || p[1]=='T' || p[1]=='d' || p[1]=='D'))
- {
- p += 2;
- hex = 0;
- }
- for (;; ++p)
- {
- /* This test includes !hex because 'e' is a valid hex digit
- and thus does not indicate a floating point number when
- the radix is hex. */
- if (!hex && !got_e && !got_p && (*p == 'e' || *p == 'E'))
- got_dot = got_e = 1;
- else if (!got_e && !got_p && (*p == 'p' || *p == 'P'))
- got_dot = got_p = 1;
- /* This test does not include !hex, because a '.' always indicates
- a decimal floating point number regardless of the radix. */
- else if (!got_dot && *p == '.')
- got_dot = 1;
- else if (((got_e && (p[-1] == 'e' || p[-1] == 'E'))
- || (got_p && (p[-1] == 'p' || p[-1] == 'P')))
- && (*p == '-' || *p == '+'))
- /* This is the sign of the exponent, not the end of the
- number. */
- continue;
- /* We will take any letters or digits. parse_number will
- complain if past the radix, or if L or U are not final. */
- else if ((*p < '0' || *p > '9')
- && ((*p < 'a' || *p > 'z')
- && (*p < 'A' || *p > 'Z')))
- break;
- }
- toktype = parse_number (par_state, tokstart, p - tokstart,
- got_dot | got_e | got_p, &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];
- if (par_state->language ()->la_language == language_objc)
- {
- size_t len = strlen ("selector");
- if (strncmp (p, "selector", len) == 0
- && (p[len] == '\0' || ISSPACE (p[len])))
- {
- pstate->lexptr = p + len;
- return SELECTOR;
- }
- else if (*p == '"')
- goto parse_string;
- }
- while (ISSPACE (*p))
- p++;
- size_t len = strlen ("entry");
- if (strncmp (p, "entry", len) == 0 && !c_ident_is_alnum (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 'L':
- case 'u':
- case 'U':
- if (tokstart[1] != '"' && tokstart[1] != '\'')
- break;
- /* Fall through. */
- case '\'':
- case '"':
- parse_string:
- {
- int host_len;
- int result = parse_string_or_char (tokstart, &pstate->lexptr,
- &yylval.tsval, &host_len);
- if (result == CHAR)
- {
- if (host_len == 0)
- error (_("Empty character constant."));
- else if (host_len > 2 && c == '\'')
- {
- ++tokstart;
- namelen = pstate->lexptr - tokstart - 1;
- *is_quoted_name = true;
- goto tryname;
- }
- else if (host_len > 1)
- error (_("Invalid character constant."));
- }
- return result;
- }
- }
- if (!(c == '_' || c == '$' || c_ident_is_alpha (c)))
- /* 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_ident_is_alnum (c) || c == '<');)
- {
- /* Template parameter lists are part of the name.
- FIXME: This mishandles `print $a<4&&$a>3'. */
- if (c == '<')
- {
- 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. */
- const char *p = find_template_name_end (tokstart + namelen);
- if (p)
- namelen = p - tokstart;
- }
- break;
- }
- c = tokstart[++namelen];
- }
- /* The token "if" terminates the expression and is NOT removed from
- the input stream. It doesn't count if it appears in the
- expansion of a macro. */
- if (namelen == 2
- && tokstart[0] == 'i'
- && tokstart[1] == 'f'
- && ! scanning_macro_expansion ())
- {
- return 0;
- }
- /* 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 ())
- {
- 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)
- {
- if ((token.flags & FLAG_CXX) != 0
- && par_state->language ()->la_language != language_cplus)
- break;
- if ((token.flags & FLAG_C) != 0
- && par_state->language ()->la_language != language_c
- && par_state->language ()->la_language != language_objc)
- break;
- if ((token.flags & FLAG_SHADOW) != 0)
- {
- struct field_of_this_result is_a_field_of_this;
- if (lookup_symbol (copy.c_str (),
- pstate->expression_context_block,
- VAR_DOMAIN,
- (par_state->language ()->la_language
- == language_cplus ? &is_a_field_of_this
- : NULL)).symbol
- != NULL)
- {
- /* The keyword is shadowed. */
- break;
- }
- }
- /* 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;
- if (pstate->parse_completion && *pstate->lexptr == '\0')
- saw_name_at_eof = 1;
- yylval.ssym.stoken = yylval.sval;
- yylval.ssym.sym.symbol = NULL;
- yylval.ssym.sym.block = NULL;
- yylval.ssym.is_a_field_of_this = 0;
- return NAME;
- }
- /* 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 c_lex; this holds symbol names as they are
- built up. */
- static auto_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.
- IS_QUOTED_NAME is non-zero if the name token was originally quoted
- in single quotes. IS_AFTER_STRUCTOP is true if this name follows
- a structure operator -- either '.' or ARROW */
- static int
- classify_name (struct parser_state *par_state, const struct block *block,
- bool is_quoted_name, bool is_after_structop)
- {
- struct block_symbol bsym;
- struct field_of_this_result is_a_field_of_this;
- std::string copy = copy_name (yylval.sval);
- /* Initialize this in case we *don't* use it in this call; that way
- we can refer to it unconditionally below. */
- memset (&is_a_field_of_this, 0, sizeof (is_a_field_of_this));
- bsym = lookup_symbol (copy.c_str (), block, VAR_DOMAIN,
- par_state->language ()->name_of_this ()
- ? &is_a_field_of_this : NULL);
- if (bsym.symbol && bsym.symbol->aclass () == LOC_BLOCK)
- {
- yylval.ssym.sym = bsym;
- yylval.ssym.is_a_field_of_this = is_a_field_of_this.type != NULL;
- return BLOCKNAME;
- }
- else if (!bsym.symbol)
- {
- /* If we found a field of 'this', we might have erroneously
- found a constructor where we wanted a type name. Handle this
- case by noticing that we found a constructor and then look up
- the type tag instead. */
- if (is_a_field_of_this.type != NULL
- && is_a_field_of_this.fn_field != NULL
- && TYPE_FN_FIELD_CONSTRUCTOR (is_a_field_of_this.fn_field->fn_fields,
- 0))
- {
- struct field_of_this_result inner_is_a_field_of_this;
- bsym = lookup_symbol (copy.c_str (), block, STRUCT_DOMAIN,
- &inner_is_a_field_of_this);
- if (bsym.symbol != NULL)
- {
- yylval.tsym.type = bsym.symbol->type ();
- return TYPENAME;
- }
- }
- /* If we found a field on the "this" object, or we are looking
- up a field on a struct, then we want to prefer it over a
- filename. However, if the name was quoted, then it is better
- to check for a filename or a block, since this is the only
- way the user has of requiring the extension to be used. */
- if ((is_a_field_of_this.type == NULL && !is_after_structop)
- || is_quoted_name)
- {
- /* See if it's a file name. */
- struct symtab *symtab;
- symtab = lookup_symtab (copy.c_str ());
- if (symtab)
- {
- yylval.bval
- = BLOCKVECTOR_BLOCK (symtab->compunit ()->blockvector (),
- STATIC_BLOCK);
- return FILENAME;
- }
- }
- }
- if (bsym.symbol && bsym.symbol->aclass () == LOC_TYPEDEF)
- {
- yylval.tsym.type = bsym.symbol->type ();
- return TYPENAME;
- }
- /* See if it's an ObjC classname. */
- if (par_state->language ()->la_language == language_objc && !bsym.symbol)
- {
- CORE_ADDR Class = lookup_objc_class (par_state->gdbarch (),
- copy.c_str ());
- if (Class)
- {
- struct symbol *sym;
- yylval.theclass.theclass = Class;
- sym = lookup_struct_typedef (copy.c_str (),
- par_state->expression_context_block, 1);
- if (sym)
- yylval.theclass.type = sym->type ();
- return CLASSNAME;
- }
- }
- /* 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 (!bsym.symbol
- && ((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 (par_state, copy.c_str (), yylval.sval.length,
- 0, &newlval);
- if (hextype == INT)
- {
- yylval.ssym.sym = bsym;
- yylval.ssym.is_a_field_of_this = is_a_field_of_this.type != NULL;
- return NAME_OR_INT;
- }
- }
- /* Any other kind of symbol */
- yylval.ssym.sym = bsym;
- yylval.ssym.is_a_field_of_this = is_a_field_of_this.type != NULL;
- if (bsym.symbol == NULL
- && par_state->language ()->la_language == language_cplus
- && is_a_field_of_this.type == NULL
- && lookup_minimal_symbol (copy.c_str (), NULL, NULL).minsym == 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. 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, false, false);
- type = check_typedef (context);
- if (!type_aggregate_p (type))
- return ERROR;
- std::string copy = copy_name (yylval.ssym.stoken);
- /* N.B. We assume the symbol can only be in VAR_DOMAIN. */
- yylval.ssym.sym = cp_lookup_nested_symbol (type, copy.c_str (), block,
- VAR_DOMAIN);
- /* If no symbol was found, search for a matching base class named
- COPY. This will allow users to enter qualified names of class members
- relative to the `this' pointer. */
- if (yylval.ssym.sym.symbol == NULL)
- {
- struct type *base_type = cp_find_type_baseclass_by_name (type,
- copy.c_str ());
- if (base_type != NULL)
- {
- yylval.tsym.type = base_type;
- return TYPENAME;
- }
- return ERROR;
- }
- switch (yylval.ssym.sym.symbol->aclass ())
- {
- case LOC_BLOCK:
- case LOC_LABEL:
- /* cp_lookup_nested_symbol might have accidentally found a constructor
- named COPY when we really wanted a base class of the same name.
- Double-check this case by looking for a base class. */
- {
- struct type *base_type
- = cp_find_type_baseclass_by_name (type, copy.c_str ());
- if (base_type != NULL)
- {
- yylval.tsym.type = base_type;
- return TYPENAME;
- }
- }
- return ERROR;
- case LOC_TYPEDEF:
- yylval.tsym.type = yylval.ssym.sym.symbol->type ();
- return TYPENAME;
- default:
- return NAME;
- }
- internal_error (__FILE__, __LINE__, _("not reached"));
- }
- /* 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;
- struct type *context_type = NULL;
- int last_to_examine, next_to_examine, checkpoint;
- const struct block *search_block;
- bool is_quoted_name, last_lex_was_structop;
- if (popping && !token_fifo.empty ())
- goto do_pop;
- popping = 0;
- last_lex_was_structop = last_was_structop;
- /* Read the first token and decide what to do. Most of the
- subsequent code is C++-only; but also depends on seeing a "::" or
- name-like token. */
- current.token = lex_one_token (pstate, &is_quoted_name);
- if (current.token == NAME)
- current.token = classify_name (pstate, pstate->expression_context_block,
- is_quoted_name, last_lex_was_structop);
- if (pstate->language ()->la_language != language_cplus
- || (current.token != TYPENAME && current.token != COLONCOLON
- && current.token != FILENAME))
- return current.token;
- /* Read any sequence of alternating "::" and name-like tokens into
- the token FIFO. */
- current.value = yylval;
- token_fifo.push_back (current);
- last_was_coloncolon = current.token == COLONCOLON;
- while (1)
- {
- bool ignore;
- /* We ignore quoted names other than the very first one.
- Subsequent ones do not have any special meaning. */
- current.token = lex_one_token (pstate, &ignore);
- current.value = yylval;
- token_fifo.push_back (current);
- if ((last_was_coloncolon && current.token != NAME)
- || (!last_was_coloncolon && current.token != COLONCOLON))
- break;
- last_was_coloncolon = !last_was_coloncolon;
- }
- 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;
- name_obstack.clear ();
- checkpoint = 0;
- if (current.token == FILENAME)
- search_block = current.value.bval;
- else if (current.token == COLONCOLON)
- 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;
- }
- first_was_coloncolon = current.token == COLONCOLON;
- last_was_coloncolon = first_was_coloncolon;
- while (next_to_examine <= last_to_examine)
- {
- token_and_value next;
- next = token_fifo[next_to_examine];
- ++next_to_examine;
- if (next.token == NAME && last_was_coloncolon)
- {
- 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 != NAME)
- 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 = (const char *) obstack_base (&name_obstack);
- yylval.sval.length = obstack_object_size (&name_obstack);
- current.value = yylval;
- current.token = classification;
- last_was_coloncolon = 0;
- if (classification == NAME)
- break;
- context_type = yylval.tsym.type;
- }
- else if (next.token == COLONCOLON && !last_was_coloncolon)
- last_was_coloncolon = 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)
- {
- current.value.sval.ptr
- = obstack_strndup (&cpstate->expansion_obstack,
- current.value.sval.ptr,
- current.value.sval.length);
- 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
- c_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;
- c_parse_state cstate;
- scoped_restore cstate_restore = make_scoped_restore (&cpstate, &cstate);
- gdb::unique_xmalloc_ptr<struct macro_scope> macro_scope;
- if (par_state->expression_context_block)
- macro_scope
- = sal_macro_scope (find_pc_line (par_state->expression_context_pc, 0));
- else
- macro_scope = default_macro_scope ();
- if (! macro_scope)
- macro_scope = user_macro_scope ();
- scoped_restore restore_macro_scope
- = make_scoped_restore (&expression_macro_scope, macro_scope.get ());
- scoped_restore restore_yydebug = make_scoped_restore (&yydebug,
- parser_debug);
- /* Initialize some state used by the lexer. */
- last_was_structop = false;
- 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;
- }
- #if defined(YYBISON) && YYBISON < 30800
- /* This is called via the YYPRINT macro when parser debugging is
- enabled. It prints a token's value. */
- static void
- c_print_token (FILE *file, int type, YYSTYPE value)
- {
- switch (type)
- {
- case INT:
- parser_fprintf (file, "typed_val_int<%s, %s>",
- TYPE_SAFE_NAME (value.typed_val_int.type),
- pulongest (value.typed_val_int.val));
- break;
- case CHAR:
- case STRING:
- {
- char *copy = (char *) alloca (value.tsval.length + 1);
- memcpy (copy, value.tsval.ptr, value.tsval.length);
- copy[value.tsval.length] = '\0';
- parser_fprintf (file, "tsval<type=%d, %s>", value.tsval.type, copy);
- }
- break;
- case NSSTRING:
- case DOLLAR_VARIABLE:
- parser_fprintf (file, "sval<%s>", copy_name (value.sval).c_str ());
- break;
- case TYPENAME:
- parser_fprintf (file, "tsym<type=%s, name=%s>",
- TYPE_SAFE_NAME (value.tsym.type),
- copy_name (value.tsym.stoken).c_str ());
- break;
- case NAME:
- case UNKNOWN_CPP_NAME:
- case NAME_OR_INT:
- case BLOCKNAME:
- parser_fprintf (file, "ssym<name=%s, sym=%s, field_of_this=%d>",
- copy_name (value.ssym.stoken).c_str (),
- (value.ssym.sym.symbol == NULL
- ? "(null)" : value.ssym.sym.symbol->print_name ()),
- value.ssym.is_a_field_of_this);
- break;
- case FILENAME:
- parser_fprintf (file, "bval<%s>", host_address_to_string (value.bval));
- break;
- }
- }
- #endif
- 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);
- }
|