ebrowse.c 92 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845
  1. /* ebrowse.c --- parsing files for the ebrowse C++ browser
  2. Copyright (C) 1992-2015 Free Software Foundation, Inc.
  3. This file is part of GNU Emacs.
  4. GNU Emacs is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. GNU Emacs is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
  14. #include <config.h>
  15. #include <stddef.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <ctype.h>
  20. #include <assert.h>
  21. #include <getopt.h>
  22. /* The SunOS compiler doesn't have SEEK_END. */
  23. #ifndef SEEK_END
  24. #define SEEK_END 2
  25. #endif
  26. #include <min-max.h>
  27. /* Files are read in chunks of this number of bytes. */
  28. enum { READ_CHUNK_SIZE = 100 * 1024 };
  29. /* Value is true if strings X and Y compare equal. */
  30. static bool
  31. streq (char const *x, char const *y)
  32. {
  33. return strcmp (x, y) == 0;
  34. }
  35. static bool
  36. filename_eq (char const *x, char const *y)
  37. {
  38. #ifdef __MSDOS__
  39. return strcasecmp (x, y) == 0;
  40. #elif defined WINDOWSNT
  41. return stricmp (x, y) == 0;
  42. #else
  43. return streq (x, y);
  44. #endif
  45. }
  46. /* The default output file name. */
  47. #define DEFAULT_OUTFILE "BROWSE"
  48. /* A version string written to the output file. Change this whenever
  49. the structure of the output file changes. */
  50. #define EBROWSE_FILE_VERSION "ebrowse 5.0"
  51. /* The output file consists of a tree of Lisp objects, with major
  52. nodes built out of Lisp structures. These are the heads of the
  53. Lisp structs with symbols identifying their type. */
  54. #define TREE_HEADER_STRUCT "[ebrowse-hs "
  55. #define TREE_STRUCT "[ebrowse-ts "
  56. #define MEMBER_STRUCT "[ebrowse-ms "
  57. #define CLASS_STRUCT "[ebrowse-cs "
  58. /* The name of the symbol table entry for global functions, variables,
  59. defines etc. This name also appears in the browser display. */
  60. #define GLOBALS_NAME "*Globals*"
  61. /* Token definitions. */
  62. enum token
  63. {
  64. YYEOF = 0, /* end of file */
  65. CSTRING = 256, /* string constant */
  66. CCHAR, /* character constant */
  67. CINT, /* integral constant */
  68. CFLOAT, /* real constant */
  69. ELLIPSIS, /* ... */
  70. LSHIFTASGN, /* <<= */
  71. RSHIFTASGN, /* >>= */
  72. ARROWSTAR, /* ->* */
  73. IDENT, /* identifier */
  74. DIVASGN, /* /= */
  75. INC, /* ++ */
  76. ADDASGN, /* += */
  77. DEC, /* -- */
  78. ARROW, /* -> */
  79. SUBASGN, /* -= */
  80. MULASGN, /* *= */
  81. MODASGN, /* %= */
  82. LOR, /* || */
  83. ORASGN, /* |= */
  84. LAND, /* && */
  85. ANDASGN, /* &= */
  86. XORASGN, /* ^= */
  87. POINTSTAR, /* .* */
  88. DCOLON, /* :: */
  89. EQ, /* == */
  90. NE, /* != */
  91. LE, /* <= */
  92. LSHIFT, /* << */
  93. GE, /* >= */
  94. RSHIFT, /* >> */
  95. /* Keywords. The undef's are there because these
  96. three symbols are very likely to be defined somewhere. */
  97. #undef BOOL
  98. #undef TRUE
  99. #undef FALSE
  100. ASM, /* asm */
  101. AUTO, /* auto */
  102. BREAK, /* break */
  103. CASE, /* case */
  104. CATCH, /* catch */
  105. CHAR, /* char */
  106. CLASS, /* class */
  107. CONST, /* const */
  108. CONTINUE, /* continue */
  109. DEFAULT, /* default */
  110. DELETE, /* delete */
  111. DO, /* do */
  112. DOUBLE, /* double */
  113. ELSE, /* else */
  114. ENUM, /* enum */
  115. EXTERN, /* extern */
  116. FLOAT, /* float */
  117. FOR, /* for */
  118. FRIEND, /* friend */
  119. GOTO, /* goto */
  120. IF, /* if */
  121. T_INLINE, /* inline */
  122. INT, /* int */
  123. LONG, /* long */
  124. NEW, /* new */
  125. OPERATOR, /* operator */
  126. PRIVATE, /* private */
  127. PROTECTED, /* protected */
  128. PUBLIC, /* public */
  129. REGISTER, /* register */
  130. RETURN, /* return */
  131. SHORT, /* short */
  132. SIGNED, /* signed */
  133. SIZEOF, /* sizeof */
  134. STATIC, /* static */
  135. STRUCT, /* struct */
  136. SWITCH, /* switch */
  137. TEMPLATE, /* template */
  138. THIS, /* this */
  139. THROW, /* throw */
  140. TRY, /* try */
  141. TYPEDEF, /* typedef */
  142. UNION, /* union */
  143. UNSIGNED, /* unsigned */
  144. VIRTUAL, /* virtual */
  145. VOID, /* void */
  146. VOLATILE, /* volatile */
  147. WHILE, /* while */
  148. MUTABLE, /* mutable */
  149. BOOL, /* bool */
  150. TRUE, /* true */
  151. FALSE, /* false */
  152. SIGNATURE, /* signature (GNU extension) */
  153. NAMESPACE, /* namespace */
  154. EXPLICIT, /* explicit */
  155. TYPENAME, /* typename */
  156. CONST_CAST, /* const_cast */
  157. DYNAMIC_CAST, /* dynamic_cast */
  158. REINTERPRET_CAST, /* reinterpret_cast */
  159. STATIC_CAST, /* static_cast */
  160. TYPEID, /* typeid */
  161. USING, /* using */
  162. WCHAR /* wchar_t */
  163. };
  164. /* Storage classes, in a wider sense. */
  165. enum sc
  166. {
  167. SC_UNKNOWN,
  168. SC_MEMBER, /* Is an instance member. */
  169. SC_STATIC, /* Is static member. */
  170. SC_FRIEND, /* Is friend function. */
  171. SC_TYPE /* Is a type definition. */
  172. };
  173. /* Member visibility. */
  174. enum visibility
  175. {
  176. V_PUBLIC,
  177. V_PROTECTED,
  178. V_PRIVATE
  179. };
  180. /* Member flags. */
  181. #define F_VIRTUAL 1 /* Is virtual function. */
  182. #define F_INLINE 2 /* Is inline function. */
  183. #define F_CONST 4 /* Is const. */
  184. #define F_PURE 8 /* Is pure virtual function. */
  185. #define F_MUTABLE 16 /* Is mutable. */
  186. #define F_TEMPLATE 32 /* Is a template. */
  187. #define F_EXPLICIT 64 /* Is explicit constructor. */
  188. #define F_THROW 128 /* Has a throw specification. */
  189. #define F_EXTERNC 256 /* Is declared extern "C". */
  190. #define F_DEFINE 512 /* Is a #define. */
  191. /* Set and test a bit in an int. */
  192. static void
  193. set_flag (int *f, int flag)
  194. {
  195. *f |= flag;
  196. }
  197. static bool
  198. has_flag (int f, int flag)
  199. {
  200. return (f & flag) != 0;
  201. }
  202. /* Structure describing a class member. */
  203. struct member
  204. {
  205. struct member *next; /* Next in list of members. */
  206. struct member *anext; /* Collision chain in member_table. */
  207. struct member **list; /* Pointer to list in class. */
  208. unsigned param_hash; /* Hash value for parameter types. */
  209. int vis; /* Visibility (public, ...). */
  210. int flags; /* See F_* above. */
  211. char *regexp; /* Matching regular expression. */
  212. const char *filename; /* Don't free this shared string. */
  213. int pos; /* Buffer position of occurrence. */
  214. char *def_regexp; /* Regular expression matching definition. */
  215. const char *def_filename; /* File name of definition. */
  216. int def_pos; /* Buffer position of definition. */
  217. char name[FLEXIBLE_ARRAY_MEMBER]; /* Member name. */
  218. };
  219. /* Structures of this type are used to connect class structures with
  220. their super and subclasses. */
  221. struct link
  222. {
  223. struct sym *sym; /* The super or subclass. */
  224. struct link *next; /* Next in list or NULL. */
  225. };
  226. /* Structure used to record namespace aliases. */
  227. struct alias
  228. {
  229. struct alias *next; /* Next in list. */
  230. struct sym *namesp; /* Namespace in which defined. */
  231. struct link *aliasee; /* List of aliased namespaces (A::B::C...). */
  232. char name[FLEXIBLE_ARRAY_MEMBER]; /* Alias name. */
  233. };
  234. /* The structure used to describe a class in the symbol table,
  235. or a namespace in all_namespaces. */
  236. struct sym
  237. {
  238. int flags; /* Is class a template class?. */
  239. unsigned char visited; /* Used to find circles. */
  240. struct sym *next; /* Hash collision list. */
  241. struct link *subs; /* List of subclasses. */
  242. struct link *supers; /* List of superclasses. */
  243. struct member *vars; /* List of instance variables. */
  244. struct member *fns; /* List of instance functions. */
  245. struct member *static_vars; /* List of static variables. */
  246. struct member *static_fns; /* List of static functions. */
  247. struct member *friends; /* List of friend functions. */
  248. struct member *types; /* List of local types. */
  249. char *regexp; /* Matching regular expression. */
  250. int pos; /* Buffer position. */
  251. const char *filename; /* File in which it can be found. */
  252. const char *sfilename; /* File in which members can be found. */
  253. struct sym *namesp; /* Namespace in which defined. . */
  254. char name[FLEXIBLE_ARRAY_MEMBER]; /* Name of the class. */
  255. };
  256. /* Experimental: Print info for `--position-info'. We print
  257. '(CLASS-NAME SCOPE MEMBER-NAME). */
  258. #define P_DEFN 1
  259. #define P_DECL 2
  260. int info_where;
  261. struct sym *info_cls = NULL;
  262. struct member *info_member = NULL;
  263. /* Experimental. For option `--position-info', the buffer position we
  264. are interested in. When this position is reached, print out
  265. information about what we know about that point. */
  266. int info_position = -1;
  267. /* Command line options structure for getopt_long. */
  268. struct option options[] =
  269. {
  270. {"append", no_argument, NULL, 'a'},
  271. {"files", required_argument, NULL, 'f'},
  272. {"help", no_argument, NULL, -2},
  273. {"min-regexp-length", required_argument, NULL, 'm'},
  274. {"max-regexp-length", required_argument, NULL, 'M'},
  275. {"no-nested-classes", no_argument, NULL, 'n'},
  276. {"no-regexps", no_argument, NULL, 'x'},
  277. {"no-structs-or-unions", no_argument, NULL, 's'},
  278. {"output-file", required_argument, NULL, 'o'},
  279. {"position-info", required_argument, NULL, 'p'},
  280. {"search-path", required_argument, NULL, 'I'},
  281. {"verbose", no_argument, NULL, 'v'},
  282. {"version", no_argument, NULL, -3},
  283. {"very-verbose", no_argument, NULL, 'V'},
  284. {NULL, 0, NULL, 0}
  285. };
  286. /* Semantic values of tokens. Set by yylex.. */
  287. unsigned yyival; /* Set for token CINT. */
  288. char *yytext; /* Set for token IDENT. */
  289. char *yytext_end;
  290. /* Output file. */
  291. FILE *yyout;
  292. /* Current line number. */
  293. int yyline;
  294. /* The name of the current input file. */
  295. const char *filename;
  296. /* Three character class vectors, and macros to test membership
  297. of characters. */
  298. char is_ident[255];
  299. char is_digit[255];
  300. char is_white[255];
  301. #define IDENTP(C) is_ident[(unsigned char) (C)]
  302. #define DIGITP(C) is_digit[(unsigned char) (C)]
  303. #define WHITEP(C) is_white[(unsigned char) (C)]
  304. /* Command line flags. */
  305. int f_append;
  306. int f_verbose;
  307. int f_very_verbose;
  308. int f_structs = 1;
  309. int f_regexps = 1;
  310. int f_nested_classes = 1;
  311. /* Maximum and minimum lengths of regular expressions matching a
  312. member, class etc., for writing them to the output file. These are
  313. overridable from the command line. */
  314. int min_regexp = 5;
  315. int max_regexp = 50;
  316. /* Input buffer. */
  317. char *inbuffer;
  318. char *in;
  319. size_t inbuffer_size;
  320. /* Return the current buffer position in the input file. */
  321. #define BUFFER_POS() (in - inbuffer)
  322. /* If current lookahead is CSTRING, the following points to the
  323. first character in the string constant. Used for recognizing
  324. extern "C". */
  325. char *string_start;
  326. /* The size of the hash tables for classes.and members. Should be
  327. prime. */
  328. #define TABLE_SIZE 1001
  329. /* The hash table for class symbols. */
  330. struct sym *class_table[TABLE_SIZE];
  331. /* Hash table containing all member structures. This is generally
  332. faster for member lookup than traversing the member lists of a
  333. `struct sym'. */
  334. struct member *member_table[TABLE_SIZE];
  335. /* Hash table for namespace aliases */
  336. struct alias *namespace_alias_table[TABLE_SIZE];
  337. /* The special class symbol used to hold global functions,
  338. variables etc. */
  339. struct sym *global_symbols;
  340. /* The current namespace. */
  341. struct sym *current_namespace;
  342. /* The list of all known namespaces. */
  343. struct sym *all_namespaces;
  344. /* Stack of namespaces we're currently nested in, during the parse. */
  345. struct sym **namespace_stack;
  346. int namespace_stack_size;
  347. int namespace_sp;
  348. /* The current lookahead token. */
  349. int tk = -1;
  350. /* Structure describing a keyword. */
  351. struct kw
  352. {
  353. const char *name; /* Spelling. */
  354. int tk; /* Token value. */
  355. struct kw *next; /* Next in collision chain. */
  356. };
  357. /* Keywords are lookup up in a hash table of their own. */
  358. #define KEYWORD_TABLE_SIZE 1001
  359. struct kw *keyword_table[KEYWORD_TABLE_SIZE];
  360. /* Search path. */
  361. struct search_path
  362. {
  363. char *path;
  364. struct search_path *next;
  365. };
  366. struct search_path *search_path;
  367. struct search_path *search_path_tail;
  368. /* Function prototypes. */
  369. static char *matching_regexp (void);
  370. static struct sym *add_sym (const char *, struct sym *);
  371. static void add_global_defn (char *, char *, int, unsigned, int, int, int);
  372. static void add_global_decl (char *, char *, int, unsigned, int, int, int);
  373. static struct member *add_member (struct sym *, char *, int, int, unsigned);
  374. static void class_definition (struct sym *, int, int, int);
  375. static char *operator_name (int *);
  376. static void parse_qualified_param_ident_or_type (char **);
  377. /***********************************************************************
  378. Utilities
  379. ***********************************************************************/
  380. /* Print an error in a printf-like style with the current input file
  381. name and line number. */
  382. static void
  383. yyerror (const char *format, const char *s)
  384. {
  385. fprintf (stderr, "%s:%d: ", filename, yyline);
  386. fprintf (stderr, format, s);
  387. putc ('\n', stderr);
  388. }
  389. /* Like malloc but print an error and exit if not enough memory is
  390. available. */
  391. static void *
  392. xmalloc (size_t nbytes)
  393. {
  394. void *p = malloc (nbytes);
  395. if (p == NULL)
  396. {
  397. yyerror ("out of memory", NULL);
  398. exit (EXIT_FAILURE);
  399. }
  400. return p;
  401. }
  402. /* Like realloc but print an error and exit if out of memory. */
  403. static void *
  404. xrealloc (void *p, size_t sz)
  405. {
  406. p = realloc (p, sz);
  407. if (p == NULL)
  408. {
  409. yyerror ("out of memory", NULL);
  410. exit (EXIT_FAILURE);
  411. }
  412. return p;
  413. }
  414. /* Like strdup, but print an error and exit if not enough memory is
  415. available.. If S is null, return null. */
  416. static char *
  417. xstrdup (char *s)
  418. {
  419. if (s)
  420. return strcpy (xmalloc (strlen (s) + 1), s);
  421. return s;
  422. }
  423. /***********************************************************************
  424. Symbols
  425. ***********************************************************************/
  426. /* Initialize the symbol table. This currently only sets up the
  427. special symbol for globals (`*Globals*'). */
  428. static void
  429. init_sym (void)
  430. {
  431. global_symbols = add_sym (GLOBALS_NAME, NULL);
  432. }
  433. /* Add a symbol for class NAME to the symbol table. NESTED_IN_CLASS
  434. is the class in which class NAME was found. If it is null,
  435. this means the scope of NAME is the current namespace.
  436. If a symbol for NAME already exists, return that. Otherwise
  437. create a new symbol and set it to default values. */
  438. static struct sym *
  439. add_sym (const char *name, struct sym *nested_in_class)
  440. {
  441. struct sym *sym;
  442. unsigned h;
  443. const char *s;
  444. struct sym *scope = nested_in_class ? nested_in_class : current_namespace;
  445. for (s = name, h = 0; *s; ++s)
  446. h = (h << 1) ^ *s;
  447. h %= TABLE_SIZE;
  448. for (sym = class_table[h]; sym; sym = sym->next)
  449. if (streq (name, sym->name)
  450. && ((!sym->namesp && !scope)
  451. || (sym->namesp && scope
  452. && streq (sym->namesp->name, scope->name))))
  453. break;
  454. if (sym == NULL)
  455. {
  456. if (f_very_verbose)
  457. {
  458. putchar ('\t');
  459. puts (name);
  460. }
  461. sym = xmalloc (offsetof (struct sym, name) + strlen (name) + 1);
  462. memset (sym, 0, offsetof (struct sym, name));
  463. strcpy (sym->name, name);
  464. sym->namesp = scope;
  465. sym->next = class_table[h];
  466. class_table[h] = sym;
  467. }
  468. return sym;
  469. }
  470. /* Add links between superclass SUPER and subclass SUB. */
  471. static void
  472. add_link (struct sym *super, struct sym *sub)
  473. {
  474. struct link *lnk, *lnk2, *p, *prev;
  475. /* See if a link already exists. */
  476. for (p = super->subs, prev = NULL;
  477. p && strcmp (sub->name, p->sym->name) > 0;
  478. prev = p, p = p->next)
  479. ;
  480. /* Avoid duplicates. */
  481. if (p == NULL || p->sym != sub)
  482. {
  483. lnk = (struct link *) xmalloc (sizeof *lnk);
  484. lnk2 = (struct link *) xmalloc (sizeof *lnk2);
  485. lnk->sym = sub;
  486. lnk->next = p;
  487. if (prev)
  488. prev->next = lnk;
  489. else
  490. super->subs = lnk;
  491. lnk2->sym = super;
  492. lnk2->next = sub->supers;
  493. sub->supers = lnk2;
  494. }
  495. }
  496. /* Find in class CLS member NAME.
  497. VAR non-zero means look for a member variable; otherwise a function
  498. is searched. SC specifies what kind of member is searched---a
  499. static, or per-instance member etc. HASH is a hash code for the
  500. parameter types of functions. Value is a pointer to the member
  501. found or null if not found. */
  502. static struct member *
  503. find_member (struct sym *cls, char *name, int var, int sc, unsigned int hash)
  504. {
  505. struct member **list;
  506. struct member *p;
  507. unsigned name_hash = 0;
  508. char *s;
  509. int i;
  510. switch (sc)
  511. {
  512. case SC_FRIEND:
  513. list = &cls->friends;
  514. break;
  515. case SC_TYPE:
  516. list = &cls->types;
  517. break;
  518. case SC_STATIC:
  519. list = var ? &cls->static_vars : &cls->static_fns;
  520. break;
  521. default:
  522. list = var ? &cls->vars : &cls->fns;
  523. break;
  524. }
  525. for (s = name; *s; ++s)
  526. name_hash = (name_hash << 1) ^ *s;
  527. i = name_hash % TABLE_SIZE;
  528. for (p = member_table[i]; p; p = p->anext)
  529. if (p->list == list && p->param_hash == hash && streq (name, p->name))
  530. break;
  531. return p;
  532. }
  533. /* Add to class CLS information for the declaration of member NAME.
  534. REGEXP is a regexp matching the declaration, if non-null. POS is
  535. the position in the source where the declaration is found. HASH is
  536. a hash code for the parameter list of the member, if it's a
  537. function. VAR non-zero means member is a variable or type. SC
  538. specifies the type of member (instance member, static, ...). VIS
  539. is the member's visibility (public, protected, private). FLAGS is
  540. a bit set giving additional information about the member (see the
  541. F_* defines). */
  542. static void
  543. add_member_decl (struct sym *cls, char *name, char *regexp, int pos, unsigned int hash, int var, int sc, int vis, int flags)
  544. {
  545. struct member *m;
  546. m = find_member (cls, name, var, sc, hash);
  547. if (m == NULL)
  548. m = add_member (cls, name, var, sc, hash);
  549. /* Have we seen a new filename? If so record that. */
  550. if (!cls->filename || !filename_eq (cls->filename, filename))
  551. m->filename = filename;
  552. m->regexp = regexp;
  553. m->pos = pos;
  554. m->flags = flags;
  555. switch (vis)
  556. {
  557. case PRIVATE:
  558. m->vis = V_PRIVATE;
  559. break;
  560. case PROTECTED:
  561. m->vis = V_PROTECTED;
  562. break;
  563. case PUBLIC:
  564. m->vis = V_PUBLIC;
  565. break;
  566. }
  567. info_where = P_DECL;
  568. info_cls = cls;
  569. info_member = m;
  570. }
  571. /* Add to class CLS information for the definition of member NAME.
  572. REGEXP is a regexp matching the declaration, if non-null. POS is
  573. the position in the source where the declaration is found. HASH is
  574. a hash code for the parameter list of the member, if it's a
  575. function. VAR non-zero means member is a variable or type. SC
  576. specifies the type of member (instance member, static, ...). VIS
  577. is the member's visibility (public, protected, private). FLAGS is
  578. a bit set giving additional information about the member (see the
  579. F_* defines). */
  580. static void
  581. add_member_defn (struct sym *cls, char *name, char *regexp, int pos, unsigned int hash, int var, int sc, int flags)
  582. {
  583. struct member *m;
  584. if (sc == SC_UNKNOWN)
  585. {
  586. m = find_member (cls, name, var, SC_MEMBER, hash);
  587. if (m == NULL)
  588. {
  589. m = find_member (cls, name, var, SC_STATIC, hash);
  590. if (m == NULL)
  591. m = add_member (cls, name, var, sc, hash);
  592. }
  593. }
  594. else
  595. {
  596. m = find_member (cls, name, var, sc, hash);
  597. if (m == NULL)
  598. m = add_member (cls, name, var, sc, hash);
  599. }
  600. if (!cls->sfilename)
  601. cls->sfilename = filename;
  602. if (!filename_eq (cls->sfilename, filename))
  603. m->def_filename = filename;
  604. m->def_regexp = regexp;
  605. m->def_pos = pos;
  606. m->flags |= flags;
  607. info_where = P_DEFN;
  608. info_cls = cls;
  609. info_member = m;
  610. }
  611. /* Add a symbol for a define named NAME to the symbol table.
  612. REGEXP is a regular expression matching the define in the source,
  613. if it is non-null. POS is the position in the file. */
  614. static void
  615. add_define (char *name, char *regexp, int pos)
  616. {
  617. add_global_defn (name, regexp, pos, 0, 1, SC_FRIEND, F_DEFINE);
  618. add_global_decl (name, regexp, pos, 0, 1, SC_FRIEND, F_DEFINE);
  619. }
  620. /* Add information for the global definition of NAME.
  621. REGEXP is a regexp matching the declaration, if non-null. POS is
  622. the position in the source where the declaration is found. HASH is
  623. a hash code for the parameter list of the member, if it's a
  624. function. VAR non-zero means member is a variable or type. SC
  625. specifies the type of member (instance member, static, ...). VIS
  626. is the member's visibility (public, protected, private). FLAGS is
  627. a bit set giving additional information about the member (see the
  628. F_* defines). */
  629. static void
  630. add_global_defn (char *name, char *regexp, int pos, unsigned int hash, int var, int sc, int flags)
  631. {
  632. int i;
  633. struct sym *sym;
  634. /* Try to find out for which classes a function is a friend, and add
  635. what we know about it to them. */
  636. if (!var)
  637. for (i = 0; i < TABLE_SIZE; ++i)
  638. for (sym = class_table[i]; sym; sym = sym->next)
  639. if (sym != global_symbols && sym->friends)
  640. if (find_member (sym, name, 0, SC_FRIEND, hash))
  641. add_member_defn (sym, name, regexp, pos, hash, 0,
  642. SC_FRIEND, flags);
  643. /* Add to global symbols. */
  644. add_member_defn (global_symbols, name, regexp, pos, hash, var, sc, flags);
  645. }
  646. /* Add information for the global declaration of NAME.
  647. REGEXP is a regexp matching the declaration, if non-null. POS is
  648. the position in the source where the declaration is found. HASH is
  649. a hash code for the parameter list of the member, if it's a
  650. function. VAR non-zero means member is a variable or type. SC
  651. specifies the type of member (instance member, static, ...). VIS
  652. is the member's visibility (public, protected, private). FLAGS is
  653. a bit set giving additional information about the member (see the
  654. F_* defines). */
  655. static void
  656. add_global_decl (char *name, char *regexp, int pos, unsigned int hash, int var, int sc, int flags)
  657. {
  658. /* Add declaration only if not already declared. Header files must
  659. be processed before source files for this to have the right effect.
  660. I do not want to handle implicit declarations at the moment. */
  661. struct member *m;
  662. struct member *found;
  663. m = found = find_member (global_symbols, name, var, sc, hash);
  664. if (m == NULL)
  665. m = add_member (global_symbols, name, var, sc, hash);
  666. /* Definition already seen => probably last declaration implicit.
  667. Override. This means that declarations must always be added to
  668. the symbol table before definitions. */
  669. if (!found)
  670. {
  671. if (!global_symbols->filename
  672. || !filename_eq (global_symbols->filename, filename))
  673. m->filename = filename;
  674. m->regexp = regexp;
  675. m->pos = pos;
  676. m->vis = V_PUBLIC;
  677. m->flags = flags;
  678. info_where = P_DECL;
  679. info_cls = global_symbols;
  680. info_member = m;
  681. }
  682. }
  683. /* Add a symbol for member NAME to class CLS.
  684. VAR non-zero means it's a variable. SC specifies the kind of
  685. member. HASH is a hash code for the parameter types of a function.
  686. Value is a pointer to the member's structure. */
  687. static struct member *
  688. add_member (struct sym *cls, char *name, int var, int sc, unsigned int hash)
  689. {
  690. struct member *m = xmalloc (offsetof (struct member, name)
  691. + strlen (name) + 1);
  692. struct member **list;
  693. struct member *p;
  694. struct member *prev;
  695. unsigned name_hash = 0;
  696. int i;
  697. char *s;
  698. strcpy (m->name, name);
  699. m->param_hash = hash;
  700. m->vis = 0;
  701. m->flags = 0;
  702. m->regexp = NULL;
  703. m->filename = NULL;
  704. m->pos = 0;
  705. m->def_regexp = NULL;
  706. m->def_filename = NULL;
  707. m->def_pos = 0;
  708. assert (cls != NULL);
  709. switch (sc)
  710. {
  711. case SC_FRIEND:
  712. list = &cls->friends;
  713. break;
  714. case SC_TYPE:
  715. list = &cls->types;
  716. break;
  717. case SC_STATIC:
  718. list = var ? &cls->static_vars : &cls->static_fns;
  719. break;
  720. default:
  721. list = var ? &cls->vars : &cls->fns;
  722. break;
  723. }
  724. for (s = name; *s; ++s)
  725. name_hash = (name_hash << 1) ^ *s;
  726. i = name_hash % TABLE_SIZE;
  727. m->anext = member_table[i];
  728. member_table[i] = m;
  729. m->list = list;
  730. /* Keep the member list sorted. It's cheaper to do it here than to
  731. sort them in Lisp. */
  732. for (prev = NULL, p = *list;
  733. p && strcmp (name, p->name) > 0;
  734. prev = p, p = p->next)
  735. ;
  736. m->next = p;
  737. if (prev)
  738. prev->next = m;
  739. else
  740. *list = m;
  741. return m;
  742. }
  743. /* Given the root R of a class tree, step through all subclasses
  744. recursively, marking functions as virtual that are declared virtual
  745. in base classes. */
  746. static void
  747. mark_virtual (struct sym *r)
  748. {
  749. struct link *p;
  750. struct member *m, *m2;
  751. for (p = r->subs; p; p = p->next)
  752. {
  753. for (m = r->fns; m; m = m->next)
  754. if (has_flag (m->flags, F_VIRTUAL))
  755. {
  756. for (m2 = p->sym->fns; m2; m2 = m2->next)
  757. if (m->param_hash == m2->param_hash && streq (m->name, m2->name))
  758. set_flag (&m2->flags, F_VIRTUAL);
  759. }
  760. mark_virtual (p->sym);
  761. }
  762. }
  763. /* For all roots of the class tree, mark functions as virtual that
  764. are virtual because of a virtual declaration in a base class. */
  765. static void
  766. mark_inherited_virtual (void)
  767. {
  768. struct sym *r;
  769. int i;
  770. for (i = 0; i < TABLE_SIZE; ++i)
  771. for (r = class_table[i]; r; r = r->next)
  772. if (r->supers == NULL)
  773. mark_virtual (r);
  774. }
  775. /* Create and return a symbol for a namespace with name NAME. */
  776. static struct sym *
  777. make_namespace (char *name, struct sym *context)
  778. {
  779. struct sym *s = xmalloc (offsetof (struct sym, name) + strlen (name) + 1);
  780. memset (s, 0, offsetof (struct sym, name));
  781. strcpy (s->name, name);
  782. s->next = all_namespaces;
  783. s->namesp = context;
  784. all_namespaces = s;
  785. return s;
  786. }
  787. /* Find the symbol for namespace NAME. If not found, return NULL */
  788. static struct sym *
  789. check_namespace (char *name, struct sym *context)
  790. {
  791. struct sym *p = NULL;
  792. for (p = all_namespaces; p; p = p->next)
  793. {
  794. if (streq (p->name, name) && (p->namesp == context))
  795. break;
  796. }
  797. return p;
  798. }
  799. /* Find the symbol for namespace NAME. If not found, add a new symbol
  800. for NAME to all_namespaces. */
  801. static struct sym *
  802. find_namespace (char *name, struct sym *context)
  803. {
  804. struct sym *p = check_namespace (name, context);
  805. if (p == NULL)
  806. p = make_namespace (name, context);
  807. return p;
  808. }
  809. /* Find namespace alias with name NAME. If not found return NULL. */
  810. static struct link *
  811. check_namespace_alias (char *name)
  812. {
  813. struct link *p = NULL;
  814. struct alias *al;
  815. unsigned h;
  816. char *s;
  817. for (s = name, h = 0; *s; ++s)
  818. h = (h << 1) ^ *s;
  819. h %= TABLE_SIZE;
  820. for (al = namespace_alias_table[h]; al; al = al->next)
  821. if (streq (name, al->name) && (al->namesp == current_namespace))
  822. {
  823. p = al->aliasee;
  824. break;
  825. }
  826. return p;
  827. }
  828. /* Register the name NEW_NAME as an alias for namespace list OLD_NAME. */
  829. static void
  830. register_namespace_alias (char *new_name, struct link *old_name)
  831. {
  832. unsigned h;
  833. char *s;
  834. struct alias *al;
  835. for (s = new_name, h = 0; *s; ++s)
  836. h = (h << 1) ^ *s;
  837. h %= TABLE_SIZE;
  838. /* Is it already in the table of aliases? */
  839. for (al = namespace_alias_table[h]; al; al = al->next)
  840. if (streq (new_name, al->name) && (al->namesp == current_namespace))
  841. return;
  842. al = xmalloc (offsetof (struct alias, name) + strlen (new_name) + 1);
  843. strcpy (al->name, new_name);
  844. al->next = namespace_alias_table[h];
  845. al->namesp = current_namespace;
  846. al->aliasee = old_name;
  847. namespace_alias_table[h] = al;
  848. }
  849. /* Enter namespace with name NAME. */
  850. static void
  851. enter_namespace (char *name)
  852. {
  853. struct sym *p = find_namespace (name, current_namespace);
  854. if (namespace_sp == namespace_stack_size)
  855. {
  856. int size = max (10, 2 * namespace_stack_size);
  857. namespace_stack
  858. = (struct sym **) xrealloc ((void *)namespace_stack,
  859. size * sizeof *namespace_stack);
  860. namespace_stack_size = size;
  861. }
  862. namespace_stack[namespace_sp++] = current_namespace;
  863. current_namespace = p;
  864. }
  865. /* Leave the current namespace. */
  866. static void
  867. leave_namespace (void)
  868. {
  869. assert (namespace_sp > 0);
  870. current_namespace = namespace_stack[--namespace_sp];
  871. }
  872. /***********************************************************************
  873. Writing the Output File
  874. ***********************************************************************/
  875. /* Write string S to the output file FP in a Lisp-readable form.
  876. If S is null, write out `()'. */
  877. static void
  878. putstr (const char *s, FILE *fp)
  879. {
  880. if (!s)
  881. {
  882. putc ('(', fp);
  883. putc (')', fp);
  884. putc (' ', fp);
  885. }
  886. else
  887. {
  888. putc ('"', fp);
  889. fputs (s, fp);
  890. putc ('"', fp);
  891. putc (' ', fp);
  892. }
  893. }
  894. /* A dynamically allocated buffer for constructing a scope name. */
  895. char *scope_buffer;
  896. int scope_buffer_size;
  897. int scope_buffer_len;
  898. /* Make sure scope_buffer has enough room to add LEN chars to it. */
  899. static void
  900. ensure_scope_buffer_room (int len)
  901. {
  902. if (scope_buffer_len + len >= scope_buffer_size)
  903. {
  904. int new_size = max (2 * scope_buffer_size, scope_buffer_len + len);
  905. scope_buffer = (char *) xrealloc (scope_buffer, new_size);
  906. scope_buffer_size = new_size;
  907. }
  908. }
  909. /* Recursively add the scope names of symbol P and the scopes of its
  910. namespaces to scope_buffer. Value is a pointer to the complete
  911. scope name constructed. */
  912. static char *
  913. sym_scope_1 (struct sym *p)
  914. {
  915. int len;
  916. if (p->namesp)
  917. sym_scope_1 (p->namesp);
  918. if (*scope_buffer)
  919. {
  920. ensure_scope_buffer_room (3);
  921. strcpy (scope_buffer + scope_buffer_len, "::");
  922. scope_buffer_len += 2;
  923. }
  924. len = strlen (p->name);
  925. ensure_scope_buffer_room (len + 1);
  926. strcpy (scope_buffer + scope_buffer_len, p->name);
  927. scope_buffer_len += len;
  928. if (has_flag (p->flags, F_TEMPLATE))
  929. {
  930. ensure_scope_buffer_room (3);
  931. strcpy (scope_buffer + scope_buffer_len, "<>");
  932. scope_buffer_len += 2;
  933. }
  934. return scope_buffer;
  935. }
  936. /* Return the scope of symbol P in printed representation, i.e.
  937. as it would appear in a C*+ source file. */
  938. static char *
  939. sym_scope (struct sym *p)
  940. {
  941. if (!scope_buffer)
  942. {
  943. scope_buffer_size = 1024;
  944. scope_buffer = (char *) xmalloc (scope_buffer_size);
  945. }
  946. *scope_buffer = '\0';
  947. scope_buffer_len = 0;
  948. if (p->namesp)
  949. sym_scope_1 (p->namesp);
  950. return scope_buffer;
  951. }
  952. /* Dump the list of members M to file FP. Value is the length of the
  953. list. */
  954. static int
  955. dump_members (FILE *fp, struct member *m)
  956. {
  957. int n;
  958. putc ('(', fp);
  959. for (n = 0; m; m = m->next, ++n)
  960. {
  961. fputs (MEMBER_STRUCT, fp);
  962. putstr (m->name, fp);
  963. putstr (NULL, fp); /* FIXME? scope for globals */
  964. fprintf (fp, "%u ", (unsigned) m->flags);
  965. putstr (m->filename, fp);
  966. putstr (m->regexp, fp);
  967. fprintf (fp, "%u ", (unsigned) m->pos);
  968. fprintf (fp, "%u ", (unsigned) m->vis);
  969. putc (' ', fp);
  970. putstr (m->def_filename, fp);
  971. putstr (m->def_regexp, fp);
  972. fprintf (fp, "%u", (unsigned) m->def_pos);
  973. putc (']', fp);
  974. putc ('\n', fp);
  975. }
  976. putc (')', fp);
  977. putc ('\n', fp);
  978. return n;
  979. }
  980. /* Dump class ROOT to stream FP. */
  981. static void
  982. dump_sym (FILE *fp, struct sym *root)
  983. {
  984. fputs (CLASS_STRUCT, fp);
  985. putstr (root->name, fp);
  986. /* Print scope, if any. */
  987. if (root->namesp)
  988. putstr (sym_scope (root), fp);
  989. else
  990. putstr (NULL, fp);
  991. /* Print flags. */
  992. fprintf (fp, "%d", root->flags);
  993. putstr (root->filename, fp);
  994. putstr (root->regexp, fp);
  995. fprintf (fp, "%u", (unsigned) root->pos);
  996. putstr (root->sfilename, fp);
  997. putc (']', fp);
  998. putc ('\n', fp);
  999. }
  1000. /* Dump class ROOT and its subclasses to file FP. Value is the
  1001. number of classes written. */
  1002. static int
  1003. dump_tree (FILE *fp, struct sym *root)
  1004. {
  1005. struct link *lk;
  1006. unsigned n = 0;
  1007. dump_sym (fp, root);
  1008. if (f_verbose)
  1009. {
  1010. putchar ('+');
  1011. fflush (stdout);
  1012. }
  1013. putc ('(', fp);
  1014. for (lk = root->subs; lk; lk = lk->next)
  1015. {
  1016. fputs (TREE_STRUCT, fp);
  1017. n += dump_tree (fp, lk->sym);
  1018. putc (']', fp);
  1019. }
  1020. putc (')', fp);
  1021. dump_members (fp, root->vars);
  1022. n += dump_members (fp, root->fns);
  1023. dump_members (fp, root->static_vars);
  1024. n += dump_members (fp, root->static_fns);
  1025. n += dump_members (fp, root->friends);
  1026. dump_members (fp, root->types);
  1027. /* Superclasses. */
  1028. putc ('(', fp);
  1029. putc (')', fp);
  1030. /* Mark slot. */
  1031. putc ('(', fp);
  1032. putc (')', fp);
  1033. putc ('\n', fp);
  1034. return n;
  1035. }
  1036. /* Dump the entire class tree to file FP. */
  1037. static void
  1038. dump_roots (FILE *fp)
  1039. {
  1040. int i, n = 0;
  1041. struct sym *r;
  1042. /* Output file header containing version string, command line
  1043. options etc. */
  1044. if (!f_append)
  1045. {
  1046. fputs (TREE_HEADER_STRUCT, fp);
  1047. putstr (EBROWSE_FILE_VERSION, fp);
  1048. putc ('\"', fp);
  1049. if (!f_structs)
  1050. fputs (" -s", fp);
  1051. if (f_regexps)
  1052. fputs (" -x", fp);
  1053. putc ('\"', fp);
  1054. fputs (" ()", fp);
  1055. fputs (" ()", fp);
  1056. putc (']', fp);
  1057. }
  1058. /* Mark functions as virtual that are so because of functions
  1059. declared virtual in base classes. */
  1060. mark_inherited_virtual ();
  1061. /* Dump the roots of the graph. */
  1062. for (i = 0; i < TABLE_SIZE; ++i)
  1063. for (r = class_table[i]; r; r = r->next)
  1064. if (!r->supers)
  1065. {
  1066. fputs (TREE_STRUCT, fp);
  1067. n += dump_tree (fp, r);
  1068. putc (']', fp);
  1069. }
  1070. if (f_verbose)
  1071. putchar ('\n');
  1072. }
  1073. /***********************************************************************
  1074. Scanner
  1075. ***********************************************************************/
  1076. #ifdef DEBUG
  1077. #define INCREMENT_LINENO \
  1078. do { \
  1079. if (f_very_verbose) \
  1080. { \
  1081. ++yyline; \
  1082. printf ("%d:\n", yyline); \
  1083. } \
  1084. else \
  1085. ++yyline; \
  1086. } while (0)
  1087. #else
  1088. #define INCREMENT_LINENO ++yyline
  1089. #endif
  1090. /* Define two macros for accessing the input buffer (current input
  1091. file). GET(C) sets C to the next input character and advances the
  1092. input pointer. UNGET retracts the input pointer. */
  1093. #define GET(C) ((C) = *in++)
  1094. #define UNGET() (--in)
  1095. /* Process a preprocessor line. Value is the next character from the
  1096. input buffer not consumed. */
  1097. static int
  1098. process_pp_line (void)
  1099. {
  1100. int in_comment = 0, in_string = 0;
  1101. int c;
  1102. char *p = yytext;
  1103. /* Skip over white space. The `#' has been consumed already. */
  1104. while (WHITEP (GET (c)))
  1105. ;
  1106. /* Read the preprocessor command (if any). */
  1107. while (IDENTP (c))
  1108. {
  1109. *p++ = c;
  1110. GET (c);
  1111. }
  1112. /* Is it a `define'? */
  1113. *p = '\0';
  1114. if (*yytext && streq (yytext, "define"))
  1115. {
  1116. p = yytext;
  1117. while (WHITEP (c))
  1118. GET (c);
  1119. while (IDENTP (c))
  1120. {
  1121. *p++ = c;
  1122. GET (c);
  1123. }
  1124. *p = '\0';
  1125. if (*yytext)
  1126. {
  1127. char *regexp = matching_regexp ();
  1128. int pos = BUFFER_POS ();
  1129. add_define (yytext, regexp, pos);
  1130. }
  1131. }
  1132. while (c && (c != '\n' || in_comment || in_string))
  1133. {
  1134. if (c == '\\')
  1135. GET (c);
  1136. else if (c == '/' && !in_comment)
  1137. {
  1138. if (GET (c) == '*')
  1139. in_comment = 1;
  1140. }
  1141. else if (c == '*' && in_comment)
  1142. {
  1143. if (GET (c) == '/')
  1144. in_comment = 0;
  1145. }
  1146. else if (c == '"')
  1147. in_string = !in_string;
  1148. if (c == '\n')
  1149. INCREMENT_LINENO;
  1150. GET (c);
  1151. }
  1152. return c;
  1153. }
  1154. /* Value is the next token from the input buffer. */
  1155. static int
  1156. yylex (void)
  1157. {
  1158. int c;
  1159. char end_char;
  1160. char *p;
  1161. for (;;)
  1162. {
  1163. while (WHITEP (GET (c)))
  1164. ;
  1165. switch (c)
  1166. {
  1167. case '\n':
  1168. INCREMENT_LINENO;
  1169. break;
  1170. case '\r':
  1171. break;
  1172. case 0:
  1173. /* End of file. */
  1174. return YYEOF;
  1175. case '\\':
  1176. GET (c);
  1177. break;
  1178. case '"':
  1179. case '\'':
  1180. /* String and character constants. */
  1181. end_char = c;
  1182. string_start = in;
  1183. while (GET (c) && c != end_char)
  1184. {
  1185. switch (c)
  1186. {
  1187. case '\\':
  1188. /* Escape sequences. */
  1189. if (!GET (c))
  1190. {
  1191. if (end_char == '\'')
  1192. yyerror ("EOF in character constant", NULL);
  1193. else
  1194. yyerror ("EOF in string constant", NULL);
  1195. goto end_string;
  1196. }
  1197. else switch (c)
  1198. {
  1199. case '\n':
  1200. INCREMENT_LINENO;
  1201. case 'a':
  1202. case 'b':
  1203. case 'f':
  1204. case 'n':
  1205. case 'r':
  1206. case 't':
  1207. case 'v':
  1208. break;
  1209. case 'x':
  1210. {
  1211. /* Hexadecimal escape sequence. */
  1212. int i;
  1213. for (i = 0; i < 2; ++i)
  1214. {
  1215. GET (c);
  1216. if (c >= '0' && c <= '7')
  1217. ;
  1218. else if (c >= 'a' && c <= 'f')
  1219. ;
  1220. else if (c >= 'A' && c <= 'F')
  1221. ;
  1222. else
  1223. {
  1224. UNGET ();
  1225. break;
  1226. }
  1227. }
  1228. }
  1229. break;
  1230. case '0':
  1231. {
  1232. /* Octal escape sequence. */
  1233. int i;
  1234. for (i = 0; i < 3; ++i)
  1235. {
  1236. GET (c);
  1237. if (c >= '0' && c <= '7')
  1238. ;
  1239. else
  1240. {
  1241. UNGET ();
  1242. break;
  1243. }
  1244. }
  1245. }
  1246. break;
  1247. default:
  1248. break;
  1249. }
  1250. break;
  1251. case '\n':
  1252. if (end_char == '\'')
  1253. yyerror ("newline in character constant", NULL);
  1254. else
  1255. yyerror ("newline in string constant", NULL);
  1256. INCREMENT_LINENO;
  1257. break;
  1258. default:
  1259. break;
  1260. }
  1261. }
  1262. end_string:
  1263. return end_char == '\'' ? CCHAR : CSTRING;
  1264. case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
  1265. case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
  1266. case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
  1267. case 'v': case 'w': case 'x': case 'y': case 'z':
  1268. case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
  1269. case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
  1270. case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
  1271. case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_':
  1272. {
  1273. /* Identifier and keywords. */
  1274. unsigned hash;
  1275. struct kw *k;
  1276. p = yytext;
  1277. *p++ = hash = c;
  1278. while (IDENTP (GET (*p)))
  1279. {
  1280. hash = (hash << 1) ^ *p++;
  1281. if (p == yytext_end - 1)
  1282. {
  1283. int size = yytext_end - yytext;
  1284. yytext = (char *) xrealloc (yytext, 2 * size);
  1285. yytext_end = yytext + 2 * size;
  1286. p = yytext + size - 1;
  1287. }
  1288. }
  1289. UNGET ();
  1290. *p = 0;
  1291. for (k = keyword_table[hash % KEYWORD_TABLE_SIZE]; k; k = k->next)
  1292. if (streq (k->name, yytext))
  1293. return k->tk;
  1294. return IDENT;
  1295. }
  1296. case '/':
  1297. /* C and C++ comments, '/' and '/='. */
  1298. switch (GET (c))
  1299. {
  1300. case '*':
  1301. while (GET (c))
  1302. {
  1303. switch (c)
  1304. {
  1305. case '*':
  1306. if (GET (c) == '/')
  1307. goto comment_end;
  1308. UNGET ();
  1309. break;
  1310. case '\\':
  1311. GET (c);
  1312. break;
  1313. case '\n':
  1314. INCREMENT_LINENO;
  1315. break;
  1316. }
  1317. }
  1318. comment_end:;
  1319. break;
  1320. case '=':
  1321. return DIVASGN;
  1322. case '/':
  1323. while (GET (c) && c != '\n')
  1324. ;
  1325. /* Don't try to read past the end of the input buffer if
  1326. the file ends in a C++ comment without a newline. */
  1327. if (c == 0)
  1328. return YYEOF;
  1329. INCREMENT_LINENO;
  1330. break;
  1331. default:
  1332. UNGET ();
  1333. return '/';
  1334. }
  1335. break;
  1336. case '+':
  1337. if (GET (c) == '+')
  1338. return INC;
  1339. else if (c == '=')
  1340. return ADDASGN;
  1341. UNGET ();
  1342. return '+';
  1343. case '-':
  1344. switch (GET (c))
  1345. {
  1346. case '-':
  1347. return DEC;
  1348. case '>':
  1349. if (GET (c) == '*')
  1350. return ARROWSTAR;
  1351. UNGET ();
  1352. return ARROW;
  1353. case '=':
  1354. return SUBASGN;
  1355. }
  1356. UNGET ();
  1357. return '-';
  1358. case '*':
  1359. if (GET (c) == '=')
  1360. return MULASGN;
  1361. UNGET ();
  1362. return '*';
  1363. case '%':
  1364. if (GET (c) == '=')
  1365. return MODASGN;
  1366. UNGET ();
  1367. return '%';
  1368. case '|':
  1369. if (GET (c) == '|')
  1370. return LOR;
  1371. else if (c == '=')
  1372. return ORASGN;
  1373. UNGET ();
  1374. return '|';
  1375. case '&':
  1376. if (GET (c) == '&')
  1377. return LAND;
  1378. else if (c == '=')
  1379. return ANDASGN;
  1380. UNGET ();
  1381. return '&';
  1382. case '^':
  1383. if (GET (c) == '=')
  1384. return XORASGN;
  1385. UNGET ();
  1386. return '^';
  1387. case '.':
  1388. if (GET (c) == '*')
  1389. return POINTSTAR;
  1390. else if (c == '.')
  1391. {
  1392. if (GET (c) != '.')
  1393. yyerror ("invalid token '..' ('...' assumed)", NULL);
  1394. UNGET ();
  1395. return ELLIPSIS;
  1396. }
  1397. else if (!DIGITP (c))
  1398. {
  1399. UNGET ();
  1400. return '.';
  1401. }
  1402. goto mantissa;
  1403. case ':':
  1404. if (GET (c) == ':')
  1405. return DCOLON;
  1406. UNGET ();
  1407. return ':';
  1408. case '=':
  1409. if (GET (c) == '=')
  1410. return EQ;
  1411. UNGET ();
  1412. return '=';
  1413. case '!':
  1414. if (GET (c) == '=')
  1415. return NE;
  1416. UNGET ();
  1417. return '!';
  1418. case '<':
  1419. switch (GET (c))
  1420. {
  1421. case '=':
  1422. return LE;
  1423. case '<':
  1424. if (GET (c) == '=')
  1425. return LSHIFTASGN;
  1426. UNGET ();
  1427. return LSHIFT;
  1428. }
  1429. UNGET ();
  1430. return '<';
  1431. case '>':
  1432. switch (GET (c))
  1433. {
  1434. case '=':
  1435. return GE;
  1436. case '>':
  1437. if (GET (c) == '=')
  1438. return RSHIFTASGN;
  1439. UNGET ();
  1440. return RSHIFT;
  1441. }
  1442. UNGET ();
  1443. return '>';
  1444. case '#':
  1445. c = process_pp_line ();
  1446. if (c == 0)
  1447. return YYEOF;
  1448. break;
  1449. case '(': case ')': case '[': case ']': case '{': case '}':
  1450. case ';': case ',': case '?': case '~':
  1451. return c;
  1452. case '0':
  1453. yyival = 0;
  1454. if (GET (c) == 'x' || c == 'X')
  1455. {
  1456. while (GET (c))
  1457. {
  1458. if (DIGITP (c))
  1459. yyival = yyival * 16 + c - '0';
  1460. else if (c >= 'a' && c <= 'f')
  1461. yyival = yyival * 16 + c - 'a' + 10;
  1462. else if (c >= 'A' && c <= 'F')
  1463. yyival = yyival * 16 + c - 'A' + 10;
  1464. else
  1465. break;
  1466. }
  1467. goto int_suffixes;
  1468. }
  1469. else if (c == '.')
  1470. goto mantissa;
  1471. while (c >= '0' && c <= '7')
  1472. {
  1473. yyival = (yyival << 3) + c - '0';
  1474. GET (c);
  1475. }
  1476. int_suffixes:
  1477. /* Integer suffixes. */
  1478. while (isalpha (c))
  1479. GET (c);
  1480. UNGET ();
  1481. return CINT;
  1482. case '1': case '2': case '3': case '4': case '5': case '6':
  1483. case '7': case '8': case '9':
  1484. /* Integer or floating constant, part before '.'. */
  1485. yyival = c - '0';
  1486. while (GET (c) && DIGITP (c))
  1487. yyival = 10 * yyival + c - '0';
  1488. if (c != '.')
  1489. goto int_suffixes;
  1490. mantissa:
  1491. /* Digits following '.'. */
  1492. while (DIGITP (c))
  1493. GET (c);
  1494. /* Optional exponent. */
  1495. if (c == 'E' || c == 'e')
  1496. {
  1497. if (GET (c) == '-' || c == '+')
  1498. GET (c);
  1499. while (DIGITP (c))
  1500. GET (c);
  1501. }
  1502. /* Optional type suffixes. */
  1503. while (isalpha (c))
  1504. GET (c);
  1505. UNGET ();
  1506. return CFLOAT;
  1507. default:
  1508. break;
  1509. }
  1510. }
  1511. }
  1512. /* Actually local to matching_regexp. These variables must be in
  1513. global scope for the case that `static' get's defined away. */
  1514. static char *matching_regexp_buffer, *matching_regexp_end_buf;
  1515. /* Value is the string from the start of the line to the current
  1516. position in the input buffer, or maybe a bit more if that string is
  1517. shorter than min_regexp. */
  1518. static char *
  1519. matching_regexp (void)
  1520. {
  1521. char *p;
  1522. char *s;
  1523. char *t;
  1524. if (!f_regexps)
  1525. return NULL;
  1526. if (matching_regexp_buffer == NULL)
  1527. {
  1528. matching_regexp_buffer = (char *) xmalloc (max_regexp);
  1529. matching_regexp_end_buf = &matching_regexp_buffer[max_regexp] - 1;
  1530. }
  1531. /* Scan back to previous newline of buffer start. */
  1532. for (p = in - 1; p > inbuffer && *p != '\n'; --p)
  1533. ;
  1534. if (*p == '\n')
  1535. {
  1536. while (in - p < min_regexp && p > inbuffer)
  1537. {
  1538. /* Line probably not significant enough */
  1539. for (--p; p > inbuffer && *p != '\n'; --p)
  1540. ;
  1541. }
  1542. if (*p == '\n')
  1543. ++p;
  1544. }
  1545. /* Copy from end to make sure significant portions are included.
  1546. This implies that in the browser a regular expressing of the form
  1547. `^.*{regexp}' has to be used. */
  1548. for (s = matching_regexp_end_buf - 1, t = in;
  1549. s > matching_regexp_buffer && t > p;)
  1550. {
  1551. *--s = *--t;
  1552. if (*s == '"' || *s == '\\')
  1553. *--s = '\\';
  1554. }
  1555. *(matching_regexp_end_buf - 1) = '\0';
  1556. return xstrdup (s);
  1557. }
  1558. /* Return a printable representation of token T. */
  1559. static const char *
  1560. token_string (int t)
  1561. {
  1562. static char b[3];
  1563. switch (t)
  1564. {
  1565. case CSTRING: return "string constant";
  1566. case CCHAR: return "char constant";
  1567. case CINT: return "int constant";
  1568. case CFLOAT: return "floating constant";
  1569. case ELLIPSIS: return "...";
  1570. case LSHIFTASGN: return "<<=";
  1571. case RSHIFTASGN: return ">>=";
  1572. case ARROWSTAR: return "->*";
  1573. case IDENT: return "identifier";
  1574. case DIVASGN: return "/=";
  1575. case INC: return "++";
  1576. case ADDASGN: return "+=";
  1577. case DEC: return "--";
  1578. case ARROW: return "->";
  1579. case SUBASGN: return "-=";
  1580. case MULASGN: return "*=";
  1581. case MODASGN: return "%=";
  1582. case LOR: return "||";
  1583. case ORASGN: return "|=";
  1584. case LAND: return "&&";
  1585. case ANDASGN: return "&=";
  1586. case XORASGN: return "^=";
  1587. case POINTSTAR: return ".*";
  1588. case DCOLON: return "::";
  1589. case EQ: return "==";
  1590. case NE: return "!=";
  1591. case LE: return "<=";
  1592. case LSHIFT: return "<<";
  1593. case GE: return ">=";
  1594. case RSHIFT: return ">>";
  1595. case ASM: return "asm";
  1596. case AUTO: return "auto";
  1597. case BREAK: return "break";
  1598. case CASE: return "case";
  1599. case CATCH: return "catch";
  1600. case CHAR: return "char";
  1601. case CLASS: return "class";
  1602. case CONST: return "const";
  1603. case CONTINUE: return "continue";
  1604. case DEFAULT: return "default";
  1605. case DELETE: return "delete";
  1606. case DO: return "do";
  1607. case DOUBLE: return "double";
  1608. case ELSE: return "else";
  1609. case ENUM: return "enum";
  1610. case EXTERN: return "extern";
  1611. case FLOAT: return "float";
  1612. case FOR: return "for";
  1613. case FRIEND: return "friend";
  1614. case GOTO: return "goto";
  1615. case IF: return "if";
  1616. case T_INLINE: return "inline";
  1617. case INT: return "int";
  1618. case LONG: return "long";
  1619. case NEW: return "new";
  1620. case OPERATOR: return "operator";
  1621. case PRIVATE: return "private";
  1622. case PROTECTED: return "protected";
  1623. case PUBLIC: return "public";
  1624. case REGISTER: return "register";
  1625. case RETURN: return "return";
  1626. case SHORT: return "short";
  1627. case SIGNED: return "signed";
  1628. case SIZEOF: return "sizeof";
  1629. case STATIC: return "static";
  1630. case STRUCT: return "struct";
  1631. case SWITCH: return "switch";
  1632. case TEMPLATE: return "template";
  1633. case THIS: return "this";
  1634. case THROW: return "throw";
  1635. case TRY: return "try";
  1636. case TYPEDEF: return "typedef";
  1637. case UNION: return "union";
  1638. case UNSIGNED: return "unsigned";
  1639. case VIRTUAL: return "virtual";
  1640. case VOID: return "void";
  1641. case VOLATILE: return "volatile";
  1642. case WHILE: return "while";
  1643. case MUTABLE: return "mutable";
  1644. case BOOL: return "bool";
  1645. case TRUE: return "true";
  1646. case FALSE: return "false";
  1647. case SIGNATURE: return "signature";
  1648. case NAMESPACE: return "namespace";
  1649. case EXPLICIT: return "explicit";
  1650. case TYPENAME: return "typename";
  1651. case CONST_CAST: return "const_cast";
  1652. case DYNAMIC_CAST: return "dynamic_cast";
  1653. case REINTERPRET_CAST: return "reinterpret_cast";
  1654. case STATIC_CAST: return "static_cast";
  1655. case TYPEID: return "typeid";
  1656. case USING: return "using";
  1657. case WCHAR: return "wchar_t";
  1658. case YYEOF: return "EOF";
  1659. default:
  1660. if (t < 255)
  1661. {
  1662. b[0] = t;
  1663. b[1] = '\0';
  1664. return b;
  1665. }
  1666. else
  1667. return "???";
  1668. }
  1669. }
  1670. /* Reinitialize the scanner for a new input file. */
  1671. static void
  1672. re_init_scanner (void)
  1673. {
  1674. in = inbuffer;
  1675. yyline = 1;
  1676. if (yytext == NULL)
  1677. {
  1678. int size = 256;
  1679. yytext = (char *) xmalloc (size * sizeof *yytext);
  1680. yytext_end = yytext + size;
  1681. }
  1682. }
  1683. /* Insert a keyword NAME with token value TKV into the keyword hash
  1684. table. */
  1685. static void
  1686. insert_keyword (const char *name, int tkv)
  1687. {
  1688. const char *s;
  1689. unsigned h = 0;
  1690. struct kw *k = (struct kw *) xmalloc (sizeof *k);
  1691. for (s = name; *s; ++s)
  1692. h = (h << 1) ^ *s;
  1693. h %= KEYWORD_TABLE_SIZE;
  1694. k->name = name;
  1695. k->tk = tkv;
  1696. k->next = keyword_table[h];
  1697. keyword_table[h] = k;
  1698. }
  1699. /* Initialize the scanner for the first file. This sets up the
  1700. character class vectors and fills the keyword hash table. */
  1701. static void
  1702. init_scanner (void)
  1703. {
  1704. int i;
  1705. /* Allocate the input buffer */
  1706. inbuffer_size = READ_CHUNK_SIZE + 1;
  1707. inbuffer = in = (char *) xmalloc (inbuffer_size);
  1708. yyline = 1;
  1709. /* Set up character class vectors. */
  1710. for (i = 0; i < sizeof is_ident; ++i)
  1711. {
  1712. if (i == '_' || isalnum (i))
  1713. is_ident[i] = 1;
  1714. if (i >= '0' && i <= '9')
  1715. is_digit[i] = 1;
  1716. if (i == ' ' || i == '\t' || i == '\f' || i == '\v')
  1717. is_white[i] = 1;
  1718. }
  1719. /* Fill keyword hash table. */
  1720. insert_keyword ("and", LAND);
  1721. insert_keyword ("and_eq", ANDASGN);
  1722. insert_keyword ("asm", ASM);
  1723. insert_keyword ("auto", AUTO);
  1724. insert_keyword ("bitand", '&');
  1725. insert_keyword ("bitor", '|');
  1726. insert_keyword ("bool", BOOL);
  1727. insert_keyword ("break", BREAK);
  1728. insert_keyword ("case", CASE);
  1729. insert_keyword ("catch", CATCH);
  1730. insert_keyword ("char", CHAR);
  1731. insert_keyword ("class", CLASS);
  1732. insert_keyword ("compl", '~');
  1733. insert_keyword ("const", CONST);
  1734. insert_keyword ("const_cast", CONST_CAST);
  1735. insert_keyword ("continue", CONTINUE);
  1736. insert_keyword ("default", DEFAULT);
  1737. insert_keyword ("delete", DELETE);
  1738. insert_keyword ("do", DO);
  1739. insert_keyword ("double", DOUBLE);
  1740. insert_keyword ("dynamic_cast", DYNAMIC_CAST);
  1741. insert_keyword ("else", ELSE);
  1742. insert_keyword ("enum", ENUM);
  1743. insert_keyword ("explicit", EXPLICIT);
  1744. insert_keyword ("extern", EXTERN);
  1745. insert_keyword ("false", FALSE);
  1746. insert_keyword ("float", FLOAT);
  1747. insert_keyword ("for", FOR);
  1748. insert_keyword ("friend", FRIEND);
  1749. insert_keyword ("goto", GOTO);
  1750. insert_keyword ("if", IF);
  1751. insert_keyword ("inline", T_INLINE);
  1752. insert_keyword ("int", INT);
  1753. insert_keyword ("long", LONG);
  1754. insert_keyword ("mutable", MUTABLE);
  1755. insert_keyword ("namespace", NAMESPACE);
  1756. insert_keyword ("new", NEW);
  1757. insert_keyword ("not", '!');
  1758. insert_keyword ("not_eq", NE);
  1759. insert_keyword ("operator", OPERATOR);
  1760. insert_keyword ("or", LOR);
  1761. insert_keyword ("or_eq", ORASGN);
  1762. insert_keyword ("private", PRIVATE);
  1763. insert_keyword ("protected", PROTECTED);
  1764. insert_keyword ("public", PUBLIC);
  1765. insert_keyword ("register", REGISTER);
  1766. insert_keyword ("reinterpret_cast", REINTERPRET_CAST);
  1767. insert_keyword ("return", RETURN);
  1768. insert_keyword ("short", SHORT);
  1769. insert_keyword ("signed", SIGNED);
  1770. insert_keyword ("sizeof", SIZEOF);
  1771. insert_keyword ("static", STATIC);
  1772. insert_keyword ("static_cast", STATIC_CAST);
  1773. insert_keyword ("struct", STRUCT);
  1774. insert_keyword ("switch", SWITCH);
  1775. insert_keyword ("template", TEMPLATE);
  1776. insert_keyword ("this", THIS);
  1777. insert_keyword ("throw", THROW);
  1778. insert_keyword ("true", TRUE);
  1779. insert_keyword ("try", TRY);
  1780. insert_keyword ("typedef", TYPEDEF);
  1781. insert_keyword ("typeid", TYPEID);
  1782. insert_keyword ("typename", TYPENAME);
  1783. insert_keyword ("union", UNION);
  1784. insert_keyword ("unsigned", UNSIGNED);
  1785. insert_keyword ("using", USING);
  1786. insert_keyword ("virtual", VIRTUAL);
  1787. insert_keyword ("void", VOID);
  1788. insert_keyword ("volatile", VOLATILE);
  1789. insert_keyword ("wchar_t", WCHAR);
  1790. insert_keyword ("while", WHILE);
  1791. insert_keyword ("xor", '^');
  1792. insert_keyword ("xor_eq", XORASGN);
  1793. }
  1794. /***********************************************************************
  1795. Parser
  1796. ***********************************************************************/
  1797. /* Match the current lookahead token and set it to the next token. */
  1798. #define MATCH() (tk = yylex ())
  1799. /* Return the lookahead token. If current lookahead token is cleared,
  1800. read a new token. */
  1801. #define LA1 (tk == -1 ? (tk = yylex ()) : tk)
  1802. /* Is the current lookahead equal to the token T? */
  1803. #define LOOKING_AT(T) (tk == (T))
  1804. /* Is the current lookahead one of T1 or T2? */
  1805. #define LOOKING_AT2(T1, T2) (tk == (T1) || tk == (T2))
  1806. /* Is the current lookahead one of T1, T2 or T3? */
  1807. #define LOOKING_AT3(T1, T2, T3) (tk == (T1) || tk == (T2) || tk == (T3))
  1808. /* Is the current lookahead one of T1...T4? */
  1809. #define LOOKING_AT4(T1, T2, T3, T4) \
  1810. (tk == (T1) || tk == (T2) || tk == (T3) || tk == (T4))
  1811. /* Match token T if current lookahead is T. */
  1812. #define MATCH_IF(T) if (LOOKING_AT (T)) MATCH (); else ((void) 0)
  1813. /* Skip to matching token if current token is T. */
  1814. #define SKIP_MATCHING_IF(T) \
  1815. if (LOOKING_AT (T)) skip_matching (); else ((void) 0)
  1816. /* Skip forward until a given token TOKEN or YYEOF is seen and return
  1817. the current lookahead token after skipping. */
  1818. static int
  1819. skip_to (int token)
  1820. {
  1821. while (!LOOKING_AT2 (YYEOF, token))
  1822. MATCH ();
  1823. return tk;
  1824. }
  1825. /* Skip over pairs of tokens (parentheses, square brackets,
  1826. angle brackets, curly brackets) matching the current lookahead. */
  1827. static void
  1828. skip_matching (void)
  1829. {
  1830. int open, close, n;
  1831. switch (open = LA1)
  1832. {
  1833. case '{':
  1834. close = '}';
  1835. break;
  1836. case '(':
  1837. close = ')';
  1838. break;
  1839. case '<':
  1840. close = '>';
  1841. break;
  1842. case '[':
  1843. close = ']';
  1844. break;
  1845. default:
  1846. abort ();
  1847. }
  1848. for (n = 0;;)
  1849. {
  1850. if (LOOKING_AT (open))
  1851. ++n;
  1852. else if (LOOKING_AT (close))
  1853. --n;
  1854. else if (LOOKING_AT (YYEOF))
  1855. break;
  1856. MATCH ();
  1857. if (n == 0)
  1858. break;
  1859. }
  1860. }
  1861. static void
  1862. skip_initializer (void)
  1863. {
  1864. for (;;)
  1865. {
  1866. switch (LA1)
  1867. {
  1868. case ';':
  1869. case ',':
  1870. case YYEOF:
  1871. return;
  1872. case '{':
  1873. case '[':
  1874. case '(':
  1875. skip_matching ();
  1876. break;
  1877. default:
  1878. MATCH ();
  1879. break;
  1880. }
  1881. }
  1882. }
  1883. /* Build qualified namespace alias (A::B::c) and return it. */
  1884. static struct link *
  1885. match_qualified_namespace_alias (void)
  1886. {
  1887. struct link *head = NULL;
  1888. struct link *cur = NULL;
  1889. struct link *tmp = NULL;
  1890. for (;;)
  1891. {
  1892. MATCH ();
  1893. switch (LA1)
  1894. {
  1895. case IDENT:
  1896. tmp = (struct link *) xmalloc (sizeof *cur);
  1897. tmp->sym = find_namespace (yytext, cur ? cur->sym : NULL);
  1898. tmp->next = NULL;
  1899. if (head)
  1900. {
  1901. cur = cur->next = tmp;
  1902. }
  1903. else
  1904. {
  1905. head = cur = tmp;
  1906. }
  1907. break;
  1908. case DCOLON:
  1909. /* Just skip */
  1910. break;
  1911. default:
  1912. return head;
  1913. break;
  1914. }
  1915. }
  1916. }
  1917. /* Re-initialize the parser by resetting the lookahead token. */
  1918. static void
  1919. re_init_parser (void)
  1920. {
  1921. tk = -1;
  1922. }
  1923. /* Parse a parameter list, including the const-specifier,
  1924. pure-specifier, and throw-list that may follow a parameter list.
  1925. Return in FLAGS what was seen following the parameter list.
  1926. Returns a hash code for the parameter types. This value is used to
  1927. distinguish between overloaded functions. */
  1928. static unsigned
  1929. parm_list (int *flags)
  1930. {
  1931. unsigned hash = 0;
  1932. int type_seen = 0;
  1933. while (!LOOKING_AT2 (YYEOF, ')'))
  1934. {
  1935. switch (LA1)
  1936. {
  1937. /* Skip over grouping parens or parameter lists in parameter
  1938. declarations. */
  1939. case '(':
  1940. skip_matching ();
  1941. break;
  1942. /* Next parameter. */
  1943. case ',':
  1944. MATCH ();
  1945. type_seen = 0;
  1946. break;
  1947. /* Ignore the scope part of types, if any. This is because
  1948. some types need scopes when defined outside of a class body,
  1949. and don't need them inside the class body. This means that
  1950. we have to look for the last IDENT in a sequence of
  1951. IDENT::IDENT::... */
  1952. case IDENT:
  1953. if (!type_seen)
  1954. {
  1955. char *last_id;
  1956. unsigned ident_type_hash = 0;
  1957. parse_qualified_param_ident_or_type (&last_id);
  1958. if (last_id)
  1959. {
  1960. /* LAST_ID null means something like `X::*'. */
  1961. for (; *last_id; ++last_id)
  1962. ident_type_hash = (ident_type_hash << 1) ^ *last_id;
  1963. hash = (hash << 1) ^ ident_type_hash;
  1964. type_seen = 1;
  1965. }
  1966. }
  1967. else
  1968. MATCH ();
  1969. break;
  1970. case VOID:
  1971. /* This distinction is made to make `func (void)' equivalent
  1972. to `func ()'. */
  1973. type_seen = 1;
  1974. MATCH ();
  1975. if (!LOOKING_AT (')'))
  1976. hash = (hash << 1) ^ VOID;
  1977. break;
  1978. case BOOL: case CHAR: case CLASS: case CONST:
  1979. case DOUBLE: case ENUM: case FLOAT: case INT:
  1980. case LONG: case SHORT: case SIGNED: case STRUCT:
  1981. case UNION: case UNSIGNED: case VOLATILE: case WCHAR:
  1982. case ELLIPSIS:
  1983. type_seen = 1;
  1984. hash = (hash << 1) ^ LA1;
  1985. MATCH ();
  1986. break;
  1987. case '*': case '&': case '[': case ']':
  1988. hash = (hash << 1) ^ LA1;
  1989. MATCH ();
  1990. break;
  1991. default:
  1992. MATCH ();
  1993. break;
  1994. }
  1995. }
  1996. if (LOOKING_AT (')'))
  1997. {
  1998. MATCH ();
  1999. if (LOOKING_AT (CONST))
  2000. {
  2001. /* We can overload the same function on `const' */
  2002. hash = (hash << 1) ^ CONST;
  2003. set_flag (flags, F_CONST);
  2004. MATCH ();
  2005. }
  2006. if (LOOKING_AT (THROW))
  2007. {
  2008. MATCH ();
  2009. SKIP_MATCHING_IF ('(');
  2010. set_flag (flags, F_THROW);
  2011. }
  2012. if (LOOKING_AT ('='))
  2013. {
  2014. MATCH ();
  2015. if (LOOKING_AT (CINT) && yyival == 0)
  2016. {
  2017. MATCH ();
  2018. set_flag (flags, F_PURE);
  2019. }
  2020. }
  2021. }
  2022. return hash;
  2023. }
  2024. /* Print position info to stdout. */
  2025. static void
  2026. print_info (void)
  2027. {
  2028. if (info_position >= 0 && BUFFER_POS () <= info_position)
  2029. if (info_cls)
  2030. printf ("(\"%s\" \"%s\" \"%s\" %d)\n",
  2031. info_cls->name, sym_scope (info_cls),
  2032. info_member->name, info_where);
  2033. }
  2034. /* Parse a member declaration within the class body of CLS. VIS is
  2035. the access specifier for the member (private, protected,
  2036. public). */
  2037. static void
  2038. member (struct sym *cls, int vis)
  2039. {
  2040. char *id = NULL;
  2041. int sc = SC_MEMBER;
  2042. char *regexp = NULL;
  2043. int pos;
  2044. int is_constructor;
  2045. int anonymous = 0;
  2046. int flags = 0;
  2047. int class_tag;
  2048. int type_seen = 0;
  2049. int paren_seen = 0;
  2050. unsigned hash = 0;
  2051. int tilde = 0;
  2052. while (!LOOKING_AT4 (';', '{', '}', YYEOF))
  2053. {
  2054. switch (LA1)
  2055. {
  2056. default:
  2057. MATCH ();
  2058. break;
  2059. /* A function or class may follow. */
  2060. case TEMPLATE:
  2061. MATCH ();
  2062. set_flag (&flags, F_TEMPLATE);
  2063. /* Skip over template argument list */
  2064. SKIP_MATCHING_IF ('<');
  2065. break;
  2066. case EXPLICIT:
  2067. set_flag (&flags, F_EXPLICIT);
  2068. goto typeseen;
  2069. case MUTABLE:
  2070. set_flag (&flags, F_MUTABLE);
  2071. goto typeseen;
  2072. case T_INLINE:
  2073. set_flag (&flags, F_INLINE);
  2074. goto typeseen;
  2075. case VIRTUAL:
  2076. set_flag (&flags, F_VIRTUAL);
  2077. goto typeseen;
  2078. case '[':
  2079. skip_matching ();
  2080. break;
  2081. case ENUM:
  2082. sc = SC_TYPE;
  2083. goto typeseen;
  2084. case TYPEDEF:
  2085. sc = SC_TYPE;
  2086. goto typeseen;
  2087. case FRIEND:
  2088. sc = SC_FRIEND;
  2089. goto typeseen;
  2090. case STATIC:
  2091. sc = SC_STATIC;
  2092. goto typeseen;
  2093. case '~':
  2094. tilde = 1;
  2095. MATCH ();
  2096. break;
  2097. case IDENT:
  2098. /* Remember IDENTS seen so far. Among these will be the member
  2099. name. */
  2100. id = (char *) xrealloc (id, strlen (yytext) + 2);
  2101. if (tilde)
  2102. {
  2103. *id = '~';
  2104. strcpy (id + 1, yytext);
  2105. }
  2106. else
  2107. strcpy (id, yytext);
  2108. MATCH ();
  2109. break;
  2110. case OPERATOR:
  2111. {
  2112. char *s = operator_name (&sc);
  2113. id = (char *) xrealloc (id, strlen (s) + 1);
  2114. strcpy (id, s);
  2115. }
  2116. break;
  2117. case '(':
  2118. /* Most probably the beginning of a parameter list. */
  2119. MATCH ();
  2120. paren_seen = 1;
  2121. if (id && cls)
  2122. {
  2123. if (!(is_constructor = streq (id, cls->name)))
  2124. regexp = matching_regexp ();
  2125. }
  2126. else
  2127. is_constructor = 0;
  2128. pos = BUFFER_POS ();
  2129. hash = parm_list (&flags);
  2130. if (is_constructor)
  2131. regexp = matching_regexp ();
  2132. if (id && cls != NULL)
  2133. add_member_decl (cls, id, regexp, pos, hash, 0, sc, vis, flags);
  2134. while (!LOOKING_AT3 (';', '{', YYEOF))
  2135. MATCH ();
  2136. if (LOOKING_AT ('{') && id && cls)
  2137. add_member_defn (cls, id, regexp, pos, hash, 0, sc, flags);
  2138. free (id);
  2139. id = NULL;
  2140. sc = SC_MEMBER;
  2141. break;
  2142. case STRUCT: case UNION: case CLASS:
  2143. /* Nested class */
  2144. class_tag = LA1;
  2145. type_seen = 1;
  2146. MATCH ();
  2147. anonymous = 1;
  2148. /* More than one ident here to allow for MS-DOS specialties
  2149. like `_export class' etc. The last IDENT seen counts
  2150. as the class name. */
  2151. while (!LOOKING_AT4 (YYEOF, ';', ':', '{'))
  2152. {
  2153. if (LOOKING_AT (IDENT))
  2154. anonymous = 0;
  2155. MATCH ();
  2156. }
  2157. if (LOOKING_AT2 (':', '{'))
  2158. class_definition (anonymous ? NULL : cls, class_tag, flags, 1);
  2159. else
  2160. skip_to (';');
  2161. break;
  2162. case INT: case CHAR: case LONG: case UNSIGNED:
  2163. case SIGNED: case CONST: case DOUBLE: case VOID:
  2164. case SHORT: case VOLATILE: case BOOL: case WCHAR:
  2165. case TYPENAME:
  2166. typeseen:
  2167. type_seen = 1;
  2168. MATCH ();
  2169. break;
  2170. }
  2171. }
  2172. if (LOOKING_AT (';'))
  2173. {
  2174. /* The end of a member variable, a friend declaration or an access
  2175. declaration. We don't want to add friend classes as members. */
  2176. if (id && sc != SC_FRIEND && cls)
  2177. {
  2178. regexp = matching_regexp ();
  2179. pos = BUFFER_POS ();
  2180. if (cls != NULL)
  2181. {
  2182. if (type_seen || !paren_seen)
  2183. add_member_decl (cls, id, regexp, pos, 0, 1, sc, vis, 0);
  2184. else
  2185. add_member_decl (cls, id, regexp, pos, hash, 0, sc, vis, 0);
  2186. }
  2187. }
  2188. MATCH ();
  2189. print_info ();
  2190. }
  2191. else if (LOOKING_AT ('{'))
  2192. {
  2193. /* A named enum. */
  2194. if (sc == SC_TYPE && id && cls)
  2195. {
  2196. regexp = matching_regexp ();
  2197. pos = BUFFER_POS ();
  2198. if (cls != NULL)
  2199. {
  2200. add_member_decl (cls, id, regexp, pos, 0, 1, sc, vis, 0);
  2201. add_member_defn (cls, id, regexp, pos, 0, 1, sc, 0);
  2202. }
  2203. }
  2204. skip_matching ();
  2205. print_info ();
  2206. }
  2207. free (id);
  2208. }
  2209. /* Parse the body of class CLS. TAG is the tag of the class (struct,
  2210. union, class). */
  2211. static void
  2212. class_body (struct sym *cls, int tag)
  2213. {
  2214. int vis = tag == CLASS ? PRIVATE : PUBLIC;
  2215. int temp;
  2216. while (!LOOKING_AT2 (YYEOF, '}'))
  2217. {
  2218. switch (LA1)
  2219. {
  2220. case PRIVATE: case PROTECTED: case PUBLIC:
  2221. temp = LA1;
  2222. MATCH ();
  2223. if (LOOKING_AT (':'))
  2224. {
  2225. vis = temp;
  2226. MATCH ();
  2227. }
  2228. else
  2229. {
  2230. /* Probably conditional compilation for inheritance list.
  2231. We don't known whether there comes more of this.
  2232. This is only a crude fix that works most of the time. */
  2233. do
  2234. {
  2235. MATCH ();
  2236. }
  2237. while (LOOKING_AT2 (IDENT, ',')
  2238. || LOOKING_AT3 (PUBLIC, PROTECTED, PRIVATE));
  2239. }
  2240. break;
  2241. case TYPENAME:
  2242. case USING:
  2243. skip_to (';');
  2244. break;
  2245. /* Try to synchronize */
  2246. case CHAR: case CLASS: case CONST:
  2247. case DOUBLE: case ENUM: case FLOAT: case INT:
  2248. case LONG: case SHORT: case SIGNED: case STRUCT:
  2249. case UNION: case UNSIGNED: case VOID: case VOLATILE:
  2250. case TYPEDEF: case STATIC: case T_INLINE: case FRIEND:
  2251. case VIRTUAL: case TEMPLATE: case IDENT: case '~':
  2252. case BOOL: case WCHAR: case EXPLICIT: case MUTABLE:
  2253. member (cls, vis);
  2254. break;
  2255. default:
  2256. MATCH ();
  2257. break;
  2258. }
  2259. }
  2260. }
  2261. /* Parse a qualified identifier. Current lookahead is IDENT. A
  2262. qualified ident has the form `X<..>::Y<...>::T<...>. Returns a
  2263. symbol for that class. */
  2264. static struct sym *
  2265. parse_classname (void)
  2266. {
  2267. struct sym *last_class = NULL;
  2268. while (LOOKING_AT (IDENT))
  2269. {
  2270. last_class = add_sym (yytext, last_class);
  2271. MATCH ();
  2272. if (LOOKING_AT ('<'))
  2273. {
  2274. skip_matching ();
  2275. set_flag (&last_class->flags, F_TEMPLATE);
  2276. }
  2277. if (!LOOKING_AT (DCOLON))
  2278. break;
  2279. MATCH ();
  2280. }
  2281. return last_class;
  2282. }
  2283. /* Parse an operator name. Add the `static' flag to *SC if an
  2284. implicitly static operator has been parsed. Value is a pointer to
  2285. a static buffer holding the constructed operator name string. */
  2286. static char *
  2287. operator_name (int *sc)
  2288. {
  2289. static size_t id_size = 0;
  2290. static char *id = NULL;
  2291. const char *s;
  2292. size_t len;
  2293. MATCH ();
  2294. if (LOOKING_AT2 (NEW, DELETE))
  2295. {
  2296. /* `new' and `delete' are implicitly static. */
  2297. if (*sc != SC_FRIEND)
  2298. *sc = SC_STATIC;
  2299. s = token_string (LA1);
  2300. MATCH ();
  2301. ptrdiff_t slen = strlen (s);
  2302. len = slen + 10;
  2303. if (len > id_size)
  2304. {
  2305. size_t new_size = max (len, 2 * id_size);
  2306. id = (char *) xrealloc (id, new_size);
  2307. id_size = new_size;
  2308. }
  2309. char *z = stpcpy (id, s);
  2310. /* Vector new or delete? */
  2311. if (LOOKING_AT ('['))
  2312. {
  2313. z = stpcpy (z, "[");
  2314. MATCH ();
  2315. if (LOOKING_AT (']'))
  2316. {
  2317. strcpy (z, "]");
  2318. MATCH ();
  2319. }
  2320. }
  2321. }
  2322. else
  2323. {
  2324. size_t tokens_matched = 0;
  2325. len = 20;
  2326. if (len > id_size)
  2327. {
  2328. int new_size = max (len, 2 * id_size);
  2329. id = (char *) xrealloc (id, new_size);
  2330. id_size = new_size;
  2331. }
  2332. char *z = stpcpy (id, "operator");
  2333. /* Beware access declarations of the form "X::f;" Beware of
  2334. `operator () ()'. Yet another difficulty is found in
  2335. GCC 2.95's STL: `operator == __STL_NULL_TMPL_ARGS (...'. */
  2336. while (!(LOOKING_AT ('(') && tokens_matched)
  2337. && !LOOKING_AT2 (';', YYEOF))
  2338. {
  2339. s = token_string (LA1);
  2340. len += strlen (s) + 2;
  2341. if (len > id_size)
  2342. {
  2343. ptrdiff_t idlen = z - id;
  2344. size_t new_size = max (len, 2 * id_size);
  2345. id = (char *) xrealloc (id, new_size);
  2346. id_size = new_size;
  2347. z = id + idlen;
  2348. }
  2349. if (*s != ')' && *s != ']')
  2350. *z++ = ' ';
  2351. z = stpcpy (z, s);
  2352. MATCH ();
  2353. /* If this is a simple operator like `+', stop now. */
  2354. if (!isalpha ((unsigned char) *s) && *s != '(' && *s != '[')
  2355. break;
  2356. ++tokens_matched;
  2357. }
  2358. }
  2359. return id;
  2360. }
  2361. /* This one consumes the last IDENT of a qualified member name like
  2362. `X::Y::z'. This IDENT is returned in LAST_ID. Value is the
  2363. symbol structure for the ident. */
  2364. static struct sym *
  2365. parse_qualified_ident_or_type (char **last_id)
  2366. {
  2367. struct sym *cls = NULL;
  2368. char *id = NULL;
  2369. size_t id_size = 0;
  2370. int enter = 0;
  2371. while (LOOKING_AT (IDENT))
  2372. {
  2373. int len = strlen (yytext) + 1;
  2374. if (len > id_size)
  2375. {
  2376. id = (char *) xrealloc (id, len);
  2377. id_size = len;
  2378. }
  2379. strcpy (id, yytext);
  2380. *last_id = id;
  2381. MATCH ();
  2382. SKIP_MATCHING_IF ('<');
  2383. if (LOOKING_AT (DCOLON))
  2384. {
  2385. struct sym *pcn = NULL;
  2386. struct link *pna = check_namespace_alias (id);
  2387. if (pna)
  2388. {
  2389. do
  2390. {
  2391. enter_namespace (pna->sym->name);
  2392. enter++;
  2393. pna = pna->next;
  2394. }
  2395. while (pna);
  2396. }
  2397. else if ((pcn = check_namespace (id, current_namespace)))
  2398. {
  2399. enter_namespace (pcn->name);
  2400. enter++;
  2401. }
  2402. else
  2403. cls = add_sym (id, cls);
  2404. *last_id = NULL;
  2405. free (id);
  2406. id = NULL;
  2407. id_size = 0;
  2408. MATCH ();
  2409. }
  2410. else
  2411. break;
  2412. }
  2413. while (enter--)
  2414. leave_namespace ();
  2415. return cls;
  2416. }
  2417. /* This one consumes the last IDENT of a qualified member name like
  2418. `X::Y::z'. This IDENT is returned in LAST_ID. Value is the
  2419. symbol structure for the ident. */
  2420. static void
  2421. parse_qualified_param_ident_or_type (char **last_id)
  2422. {
  2423. struct sym *cls = NULL;
  2424. static char *id = NULL;
  2425. static int id_size = 0;
  2426. assert (LOOKING_AT (IDENT));
  2427. do
  2428. {
  2429. int len = strlen (yytext) + 1;
  2430. if (len > id_size)
  2431. {
  2432. id = (char *) xrealloc (id, len);
  2433. id_size = len;
  2434. }
  2435. strcpy (id, yytext);
  2436. *last_id = id;
  2437. MATCH ();
  2438. SKIP_MATCHING_IF ('<');
  2439. if (LOOKING_AT (DCOLON))
  2440. {
  2441. cls = add_sym (id, cls);
  2442. *last_id = NULL;
  2443. MATCH ();
  2444. }
  2445. else
  2446. break;
  2447. }
  2448. while (LOOKING_AT (IDENT));
  2449. }
  2450. /* Parse a class definition.
  2451. CONTAINING is the class containing the class being parsed or null.
  2452. This may also be null if NESTED != 0 if the containing class is
  2453. anonymous. TAG is the tag of the class (struct, union, class).
  2454. NESTED is non-zero if we are parsing a nested class.
  2455. Current lookahead is the class name. */
  2456. static void
  2457. class_definition (struct sym *containing, int tag, int flags, int nested)
  2458. {
  2459. struct sym *current;
  2460. struct sym *base_class;
  2461. /* Set CURRENT to null if no entry has to be made for the class
  2462. parsed. This is the case for certain command line flag
  2463. settings. */
  2464. if ((tag != CLASS && !f_structs) || (nested && !f_nested_classes))
  2465. current = NULL;
  2466. else
  2467. {
  2468. current = add_sym (yytext, containing);
  2469. current->pos = BUFFER_POS ();
  2470. current->regexp = matching_regexp ();
  2471. current->filename = filename;
  2472. current->flags = flags;
  2473. }
  2474. /* If at ':', base class list follows. */
  2475. if (LOOKING_AT (':'))
  2476. {
  2477. int done = 0;
  2478. MATCH ();
  2479. while (!done)
  2480. {
  2481. switch (LA1)
  2482. {
  2483. case VIRTUAL: case PUBLIC: case PROTECTED: case PRIVATE:
  2484. MATCH ();
  2485. break;
  2486. case IDENT:
  2487. base_class = parse_classname ();
  2488. if (base_class && current && base_class != current)
  2489. add_link (base_class, current);
  2490. break;
  2491. /* The `,' between base classes or the end of the base
  2492. class list. Add the previously found base class.
  2493. It's done this way to skip over sequences of
  2494. `A::B::C' until we reach the end.
  2495. FIXME: it is now possible to handle `class X : public B::X'
  2496. because we have enough information. */
  2497. case ',':
  2498. MATCH ();
  2499. break;
  2500. default:
  2501. /* A syntax error, possibly due to preprocessor constructs
  2502. like
  2503. #ifdef SOMETHING
  2504. class A : public B
  2505. #else
  2506. class A : private B.
  2507. MATCH until we see something like `;' or `{'. */
  2508. while (!LOOKING_AT3 (';', YYEOF, '{'))
  2509. MATCH ();
  2510. done = 1;
  2511. case '{':
  2512. done = 1;
  2513. break;
  2514. }
  2515. }
  2516. }
  2517. /* Parse the class body if there is one. */
  2518. if (LOOKING_AT ('{'))
  2519. {
  2520. if (tag != CLASS && !f_structs)
  2521. skip_matching ();
  2522. else
  2523. {
  2524. MATCH ();
  2525. class_body (current, tag);
  2526. if (LOOKING_AT ('}'))
  2527. {
  2528. MATCH ();
  2529. if (LOOKING_AT (';') && !nested)
  2530. MATCH ();
  2531. }
  2532. }
  2533. }
  2534. }
  2535. /* Add to class *CLS information for the declaration of variable or
  2536. type *ID. If *CLS is null, this means a global declaration. SC is
  2537. the storage class of *ID. FLAGS is a bit set giving additional
  2538. information about the member (see the F_* defines). */
  2539. static void
  2540. add_declarator (struct sym **cls, char **id, int flags, int sc)
  2541. {
  2542. if (LOOKING_AT2 (';', ','))
  2543. {
  2544. /* The end of a member variable or of an access declaration
  2545. `X::f'. To distinguish between them we have to know whether
  2546. type information has been seen. */
  2547. if (*id)
  2548. {
  2549. char *regexp = matching_regexp ();
  2550. int pos = BUFFER_POS ();
  2551. if (*cls)
  2552. add_member_defn (*cls, *id, regexp, pos, 0, 1, SC_UNKNOWN, flags);
  2553. else
  2554. add_global_defn (*id, regexp, pos, 0, 1, sc, flags);
  2555. }
  2556. MATCH ();
  2557. print_info ();
  2558. }
  2559. else if (LOOKING_AT ('{'))
  2560. {
  2561. if (sc == SC_TYPE && *id)
  2562. {
  2563. /* A named enumeration. */
  2564. char *regexp = matching_regexp ();
  2565. int pos = BUFFER_POS ();
  2566. add_global_defn (*id, regexp, pos, 0, 1, sc, flags);
  2567. }
  2568. skip_matching ();
  2569. print_info ();
  2570. }
  2571. free (*id);
  2572. *id = NULL;
  2573. *cls = NULL;
  2574. }
  2575. /* Parse a declaration. */
  2576. static void
  2577. declaration (int flags)
  2578. {
  2579. char *id = NULL;
  2580. struct sym *cls = NULL;
  2581. char *regexp = NULL;
  2582. int pos = 0;
  2583. unsigned hash = 0;
  2584. int is_constructor;
  2585. int sc = 0;
  2586. while (!LOOKING_AT3 (';', '{', YYEOF))
  2587. {
  2588. switch (LA1)
  2589. {
  2590. default:
  2591. MATCH ();
  2592. break;
  2593. case '[':
  2594. skip_matching ();
  2595. break;
  2596. case ENUM:
  2597. case TYPEDEF:
  2598. sc = SC_TYPE;
  2599. MATCH ();
  2600. break;
  2601. case STATIC:
  2602. sc = SC_STATIC;
  2603. MATCH ();
  2604. break;
  2605. case INT: case CHAR: case LONG: case UNSIGNED:
  2606. case SIGNED: case CONST: case DOUBLE: case VOID:
  2607. case SHORT: case VOLATILE: case BOOL: case WCHAR:
  2608. MATCH ();
  2609. break;
  2610. case CLASS: case STRUCT: case UNION:
  2611. /* This is for the case `STARTWRAP class X : ...' or
  2612. `declare (X, Y)\n class A : ...'. */
  2613. if (id)
  2614. {
  2615. free (id);
  2616. return;
  2617. }
  2618. case '=':
  2619. /* Assumed to be the start of an initialization in this
  2620. context. */
  2621. skip_initializer ();
  2622. break;
  2623. case ',':
  2624. add_declarator (&cls, &id, flags, sc);
  2625. break;
  2626. case OPERATOR:
  2627. {
  2628. char *s = operator_name (&sc);
  2629. id = (char *) xrealloc (id, strlen (s) + 1);
  2630. strcpy (id, s);
  2631. }
  2632. break;
  2633. case T_INLINE:
  2634. set_flag (&flags, F_INLINE);
  2635. MATCH ();
  2636. break;
  2637. case '~':
  2638. MATCH ();
  2639. if (LOOKING_AT (IDENT))
  2640. {
  2641. id = (char *) xrealloc (id, strlen (yytext) + 2);
  2642. *id = '~';
  2643. strcpy (id + 1, yytext);
  2644. MATCH ();
  2645. }
  2646. break;
  2647. case IDENT:
  2648. cls = parse_qualified_ident_or_type (&id);
  2649. break;
  2650. case '(':
  2651. /* Most probably the beginning of a parameter list. */
  2652. if (cls)
  2653. {
  2654. MATCH ();
  2655. if (id && cls)
  2656. {
  2657. if (!(is_constructor = streq (id, cls->name)))
  2658. regexp = matching_regexp ();
  2659. }
  2660. else
  2661. is_constructor = 0;
  2662. pos = BUFFER_POS ();
  2663. hash = parm_list (&flags);
  2664. if (is_constructor)
  2665. regexp = matching_regexp ();
  2666. if (id && cls)
  2667. add_member_defn (cls, id, regexp, pos, hash, 0,
  2668. SC_UNKNOWN, flags);
  2669. }
  2670. else
  2671. {
  2672. /* This may be a C functions, but also a macro
  2673. call of the form `declare (A, B)' --- such macros
  2674. can be found in some class libraries. */
  2675. MATCH ();
  2676. if (id)
  2677. {
  2678. regexp = matching_regexp ();
  2679. pos = BUFFER_POS ();
  2680. hash = parm_list (&flags);
  2681. add_global_decl (id, regexp, pos, hash, 0, sc, flags);
  2682. }
  2683. /* This is for the case that the function really is
  2684. a macro with no `;' following it. If a CLASS directly
  2685. follows, we would miss it otherwise. */
  2686. if (LOOKING_AT3 (CLASS, STRUCT, UNION))
  2687. return;
  2688. }
  2689. while (!LOOKING_AT3 (';', '{', YYEOF))
  2690. MATCH ();
  2691. if (!cls && id && LOOKING_AT ('{'))
  2692. add_global_defn (id, regexp, pos, hash, 0, sc, flags);
  2693. free (id);
  2694. id = NULL;
  2695. break;
  2696. }
  2697. }
  2698. add_declarator (&cls, &id, flags, sc);
  2699. }
  2700. /* Parse a list of top-level declarations/definitions. START_FLAGS
  2701. says in which context we are parsing. If it is F_EXTERNC, we are
  2702. parsing in an `extern "C"' block. Value is 1 if EOF is reached, 0
  2703. otherwise. */
  2704. static int
  2705. globals (int start_flags)
  2706. {
  2707. int anonymous;
  2708. int class_tk;
  2709. int flags = start_flags;
  2710. for (;;)
  2711. {
  2712. char *prev_in = in;
  2713. switch (LA1)
  2714. {
  2715. case NAMESPACE:
  2716. {
  2717. MATCH ();
  2718. if (LOOKING_AT (IDENT))
  2719. {
  2720. char *namespace_name = xstrdup (yytext);
  2721. MATCH ();
  2722. if (LOOKING_AT ('='))
  2723. {
  2724. struct link *qna = match_qualified_namespace_alias ();
  2725. if (qna)
  2726. register_namespace_alias (namespace_name, qna);
  2727. if (skip_to (';') == ';')
  2728. MATCH ();
  2729. }
  2730. else if (LOOKING_AT ('{'))
  2731. {
  2732. MATCH ();
  2733. enter_namespace (namespace_name);
  2734. globals (0);
  2735. leave_namespace ();
  2736. MATCH_IF ('}');
  2737. }
  2738. free (namespace_name);
  2739. }
  2740. }
  2741. break;
  2742. case EXTERN:
  2743. MATCH ();
  2744. if (LOOKING_AT (CSTRING) && *string_start == 'C'
  2745. && *(string_start + 1) == '"')
  2746. {
  2747. /* This is `extern "C"'. */
  2748. MATCH ();
  2749. if (LOOKING_AT ('{'))
  2750. {
  2751. MATCH ();
  2752. globals (F_EXTERNC);
  2753. MATCH_IF ('}');
  2754. }
  2755. else
  2756. set_flag (&flags, F_EXTERNC);
  2757. }
  2758. break;
  2759. case TEMPLATE:
  2760. MATCH ();
  2761. SKIP_MATCHING_IF ('<');
  2762. set_flag (&flags, F_TEMPLATE);
  2763. break;
  2764. case CLASS: case STRUCT: case UNION:
  2765. class_tk = LA1;
  2766. MATCH ();
  2767. anonymous = 1;
  2768. /* More than one ident here to allow for MS-DOS and OS/2
  2769. specialties like `far', `_Export' etc. Some C++ libs
  2770. have constructs like `_OS_DLLIMPORT(_OS_CLIENT)' in front
  2771. of the class name. */
  2772. while (!LOOKING_AT4 (YYEOF, ';', ':', '{'))
  2773. {
  2774. if (LOOKING_AT (IDENT))
  2775. anonymous = 0;
  2776. MATCH ();
  2777. }
  2778. /* Don't add anonymous unions. */
  2779. if (LOOKING_AT2 (':', '{') && !anonymous)
  2780. class_definition (NULL, class_tk, flags, 0);
  2781. else
  2782. {
  2783. if (skip_to (';') == ';')
  2784. MATCH ();
  2785. }
  2786. flags = start_flags;
  2787. break;
  2788. case YYEOF:
  2789. return 1;
  2790. case '}':
  2791. return 0;
  2792. default:
  2793. declaration (flags);
  2794. flags = start_flags;
  2795. break;
  2796. }
  2797. if (prev_in == in)
  2798. yyerror ("parse error", NULL);
  2799. }
  2800. }
  2801. /* Parse the current input file. */
  2802. static void
  2803. yyparse (void)
  2804. {
  2805. while (globals (0) == 0)
  2806. MATCH_IF ('}');
  2807. }
  2808. /***********************************************************************
  2809. Main Program
  2810. ***********************************************************************/
  2811. /* Add the list of paths PATH_LIST to the current search path for
  2812. input files. */
  2813. static void
  2814. add_search_path (char *path_list)
  2815. {
  2816. while (*path_list)
  2817. {
  2818. char *start = path_list;
  2819. struct search_path *p;
  2820. while (*path_list && *path_list != SEPCHAR)
  2821. ++path_list;
  2822. p = (struct search_path *) xmalloc (sizeof *p);
  2823. p->path = (char *) xmalloc (path_list - start + 1);
  2824. memcpy (p->path, start, path_list - start);
  2825. p->path[path_list - start] = '\0';
  2826. p->next = NULL;
  2827. if (search_path_tail)
  2828. {
  2829. search_path_tail->next = p;
  2830. search_path_tail = p;
  2831. }
  2832. else
  2833. search_path = search_path_tail = p;
  2834. while (*path_list == SEPCHAR)
  2835. ++path_list;
  2836. }
  2837. }
  2838. /* Open FILE and return a file handle for it, or -1 if FILE cannot be
  2839. opened. Try to find FILE in search_path first, then try the
  2840. unchanged file name. */
  2841. static FILE *
  2842. open_file (char *file)
  2843. {
  2844. FILE *fp = NULL;
  2845. static char *buffer;
  2846. static int buffer_size;
  2847. struct search_path *path;
  2848. int flen = strlen (file) + 1; /* +1 for the slash */
  2849. filename = xstrdup (file);
  2850. for (path = search_path; path && fp == NULL; path = path->next)
  2851. {
  2852. int len = strlen (path->path) + flen;
  2853. if (len + 1 >= buffer_size)
  2854. {
  2855. buffer_size = max (len + 1, 2 * buffer_size);
  2856. buffer = (char *) xrealloc (buffer, buffer_size);
  2857. }
  2858. char *z = stpcpy (buffer, path->path);
  2859. *z++ = '/';
  2860. strcpy (z, file);
  2861. fp = fopen (buffer, "r");
  2862. }
  2863. /* Try the original file name. */
  2864. if (fp == NULL)
  2865. fp = fopen (file, "r");
  2866. if (fp == NULL)
  2867. yyerror ("cannot open", NULL);
  2868. return fp;
  2869. }
  2870. /* Display usage information and exit program. */
  2871. static char const *const usage_message[] =
  2872. {
  2873. "\
  2874. Usage: ebrowse [options] {files}\n\
  2875. \n\
  2876. -a, --append append output to existing file\n\
  2877. -f, --files=FILES read input file names from FILE\n\
  2878. -I, --search-path=LIST set search path for input files\n\
  2879. -m, --min-regexp-length=N set minimum regexp length to N\n\
  2880. -M, --max-regexp-length=N set maximum regexp length to N\n\
  2881. ",
  2882. "\
  2883. -n, --no-nested-classes exclude nested classes\n\
  2884. -o, --output-file=FILE set output file name to FILE\n\
  2885. -p, --position-info print info about position in file\n\
  2886. -s, --no-structs-or-unions don't record structs or unions\n\
  2887. -v, --verbose be verbose\n\
  2888. -V, --very-verbose be very verbose\n\
  2889. -x, --no-regexps don't record regular expressions\n\
  2890. --help display this help\n\
  2891. --version display version info\n\
  2892. \n\
  2893. "
  2894. };
  2895. static _Noreturn void
  2896. usage (int error)
  2897. {
  2898. int i;
  2899. for (i = 0; i < sizeof usage_message / sizeof *usage_message; i++)
  2900. fputs (usage_message[i], stdout);
  2901. exit (error ? EXIT_FAILURE : EXIT_SUCCESS);
  2902. }
  2903. /* Display version and copyright info. The VERSION macro is set
  2904. from config.h and contains the Emacs version. */
  2905. #ifndef VERSION
  2906. # define VERSION "21"
  2907. #endif
  2908. static _Noreturn void
  2909. version (void)
  2910. {
  2911. char emacs_copyright[] = COPYRIGHT;
  2912. printf ("ebrowse %s\n", VERSION);
  2913. puts (emacs_copyright);
  2914. puts ("This program is distributed under the same terms as Emacs.");
  2915. exit (EXIT_SUCCESS);
  2916. }
  2917. /* Parse one input file FILE, adding classes and members to the symbol
  2918. table. */
  2919. static void
  2920. process_file (char *file)
  2921. {
  2922. FILE *fp;
  2923. fp = open_file (file);
  2924. if (fp)
  2925. {
  2926. size_t nread, nbytes;
  2927. /* Give a progress indication if needed. */
  2928. if (f_very_verbose)
  2929. {
  2930. puts (filename);
  2931. fflush (stdout);
  2932. }
  2933. else if (f_verbose)
  2934. {
  2935. putchar ('.');
  2936. fflush (stdout);
  2937. }
  2938. /* Read file to inbuffer. */
  2939. for (nread = 0;;)
  2940. {
  2941. if (nread + READ_CHUNK_SIZE >= inbuffer_size)
  2942. {
  2943. inbuffer_size = nread + READ_CHUNK_SIZE + 1;
  2944. inbuffer = (char *) xrealloc (inbuffer, inbuffer_size);
  2945. }
  2946. nbytes = fread (inbuffer + nread, 1, READ_CHUNK_SIZE, fp);
  2947. if (nbytes == 0)
  2948. break;
  2949. nread += nbytes;
  2950. }
  2951. inbuffer[nread] = '\0';
  2952. /* Reinitialize scanner and parser for the new input file. */
  2953. re_init_scanner ();
  2954. re_init_parser ();
  2955. /* Parse it and close the file. */
  2956. yyparse ();
  2957. fclose (fp);
  2958. }
  2959. }
  2960. /* Read a line from stream FP and return a pointer to a static buffer
  2961. containing its contents without the terminating newline. Value
  2962. is null when EOF is reached. */
  2963. static char *
  2964. read_line (FILE *fp)
  2965. {
  2966. static char *buffer;
  2967. static int buffer_size;
  2968. int i = 0, c;
  2969. while ((c = getc (fp)) != EOF && c != '\n')
  2970. {
  2971. if (i >= buffer_size)
  2972. {
  2973. buffer_size = max (100, buffer_size * 2);
  2974. buffer = (char *) xrealloc (buffer, buffer_size);
  2975. }
  2976. buffer[i++] = c;
  2977. }
  2978. if (c == EOF && i == 0)
  2979. return NULL;
  2980. if (i == buffer_size)
  2981. {
  2982. buffer_size = max (100, buffer_size * 2);
  2983. buffer = (char *) xrealloc (buffer, buffer_size);
  2984. }
  2985. buffer[i] = '\0';
  2986. if (i > 0 && buffer[i - 1] == '\r')
  2987. buffer[i - 1] = '\0';
  2988. return buffer;
  2989. }
  2990. /* Main entry point. */
  2991. int
  2992. main (int argc, char **argv)
  2993. {
  2994. int i;
  2995. int any_inputfiles = 0;
  2996. static const char *out_filename = DEFAULT_OUTFILE;
  2997. static char **input_filenames = NULL;
  2998. static int input_filenames_size = 0;
  2999. static int n_input_files;
  3000. filename = "command line";
  3001. yyout = stdout;
  3002. while ((i = getopt_long (argc, argv, "af:I:m:M:no:p:svVx",
  3003. options, NULL)) != EOF)
  3004. {
  3005. switch (i)
  3006. {
  3007. /* Experimental. */
  3008. case 'p':
  3009. info_position = atoi (optarg);
  3010. break;
  3011. case 'n':
  3012. f_nested_classes = 0;
  3013. break;
  3014. case 'x':
  3015. f_regexps = 0;
  3016. break;
  3017. /* Add the name of a file containing more input files. */
  3018. case 'f':
  3019. if (n_input_files == input_filenames_size)
  3020. {
  3021. input_filenames_size = max (10, 2 * input_filenames_size);
  3022. input_filenames = (char **) xrealloc ((void *)input_filenames,
  3023. input_filenames_size);
  3024. }
  3025. input_filenames[n_input_files++] = xstrdup (optarg);
  3026. break;
  3027. /* Append new output to output file instead of truncating it. */
  3028. case 'a':
  3029. f_append = 1;
  3030. break;
  3031. /* Include structs in the output */
  3032. case 's':
  3033. f_structs = 0;
  3034. break;
  3035. /* Be verbose (give a progress indication). */
  3036. case 'v':
  3037. f_verbose = 1;
  3038. break;
  3039. /* Be very verbose (print file names as they are processed). */
  3040. case 'V':
  3041. f_verbose = 1;
  3042. f_very_verbose = 1;
  3043. break;
  3044. /* Change the name of the output file. */
  3045. case 'o':
  3046. out_filename = optarg;
  3047. break;
  3048. /* Set minimum length for regular expression strings
  3049. when recorded in the output file. */
  3050. case 'm':
  3051. min_regexp = atoi (optarg);
  3052. break;
  3053. /* Set maximum length for regular expression strings
  3054. when recorded in the output file. */
  3055. case 'M':
  3056. max_regexp = atoi (optarg);
  3057. break;
  3058. /* Add to search path. */
  3059. case 'I':
  3060. add_search_path (optarg);
  3061. break;
  3062. /* Display help */
  3063. case -2:
  3064. usage (0);
  3065. break;
  3066. case -3:
  3067. version ();
  3068. break;
  3069. }
  3070. }
  3071. /* Call init_scanner after command line flags have been processed to be
  3072. able to add keywords depending on command line (not yet
  3073. implemented). */
  3074. init_scanner ();
  3075. init_sym ();
  3076. /* Open output file */
  3077. if (*out_filename)
  3078. {
  3079. if (f_append)
  3080. {
  3081. /* Check that the file to append to exists, and is not
  3082. empty. More specifically, it should be a valid file
  3083. produced by a previous run of ebrowse, but that's too
  3084. difficult to check. */
  3085. FILE *fp;
  3086. int rc;
  3087. fp = fopen (out_filename, "r");
  3088. if (fp == NULL)
  3089. {
  3090. yyerror ("file '%s' must exist for --append", out_filename);
  3091. exit (EXIT_FAILURE);
  3092. }
  3093. rc = fseek (fp, 0, SEEK_END);
  3094. if (rc == -1)
  3095. {
  3096. yyerror ("error seeking in file '%s'", out_filename);
  3097. exit (EXIT_FAILURE);
  3098. }
  3099. rc = ftell (fp);
  3100. if (rc == -1)
  3101. {
  3102. yyerror ("error getting size of file '%s'", out_filename);
  3103. exit (EXIT_FAILURE);
  3104. }
  3105. else if (rc == 0)
  3106. {
  3107. yyerror ("file '%s' is empty", out_filename);
  3108. /* It may be ok to use an empty file for appending.
  3109. exit (EXIT_FAILURE); */
  3110. }
  3111. fclose (fp);
  3112. }
  3113. yyout = fopen (out_filename, f_append ? "a" : "w");
  3114. if (yyout == NULL)
  3115. {
  3116. yyerror ("cannot open output file '%s'", out_filename);
  3117. exit (EXIT_FAILURE);
  3118. }
  3119. }
  3120. /* Process input files specified on the command line. */
  3121. while (optind < argc)
  3122. {
  3123. process_file (argv[optind++]);
  3124. any_inputfiles = 1;
  3125. }
  3126. /* Process files given on stdin if no files specified. */
  3127. if (!any_inputfiles && n_input_files == 0)
  3128. {
  3129. char *file;
  3130. while ((file = read_line (stdin)) != NULL)
  3131. process_file (file);
  3132. }
  3133. else
  3134. {
  3135. /* Process files from `--files=FILE'. Every line in FILE names
  3136. one input file to process. */
  3137. for (i = 0; i < n_input_files; ++i)
  3138. {
  3139. FILE *fp = fopen (input_filenames[i], "r");
  3140. if (fp == NULL)
  3141. yyerror ("cannot open input file '%s'", input_filenames[i]);
  3142. else
  3143. {
  3144. char *file;
  3145. while ((file = read_line (fp)) != NULL)
  3146. process_file (file);
  3147. fclose (fp);
  3148. }
  3149. }
  3150. }
  3151. /* Write output file. */
  3152. dump_roots (yyout);
  3153. /* Close output file. */
  3154. if (yyout != stdout)
  3155. fclose (yyout);
  3156. return EXIT_SUCCESS;
  3157. }
  3158. /* ebrowse.c ends here */