1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991 |
- /* ebrowse.c --- parsing files for the ebrowse C++ browser
- Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
- Free Software Foundation, Inc.
- This file is part of GNU Emacs.
- GNU Emacs is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- GNU Emacs is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <stdio.h>
- #ifdef HAVE_STDLIB_H
- #include <stdlib.h>
- #endif
- #ifdef HAVE_STRING_H
- #include <string.h>
- #endif
- #include <ctype.h>
- #include <assert.h>
- #include "getopt.h"
- /* The SunOS compiler doesn't have SEEK_END. */
- #ifndef SEEK_END
- #define SEEK_END 2
- #endif
- /* Conditionalize function prototypes. */
- #ifdef PROTOTYPES /* From config.h. */
- #define P_(x) x
- #else
- #define P_(x) ()
- #endif
- /* Value is non-zero if strings X and Y compare equal. */
- #define streq(X, Y) (*(X) == *(Y) && strcmp ((X) + 1, (Y) + 1) == 0)
- /* The ubiquitous `max' and `min' macros. */
- #ifndef max
- #define max(X, Y) ((X) > (Y) ? (X) : (Y))
- #define min(X, Y) ((X) < (Y) ? (X) : (Y))
- #endif
- /* Files are read in chunks of this number of bytes. */
- #define READ_CHUNK_SIZE (100 * 1024)
- /* The character used as a separator in path lists (like $PATH). */
- #if defined(__MSDOS__)
- #define PATH_LIST_SEPARATOR ';'
- #define FILENAME_EQ(X,Y) (strcasecmp(X,Y) == 0)
- #else
- #if defined(WINDOWSNT)
- #define PATH_LIST_SEPARATOR ';'
- #define FILENAME_EQ(X,Y) (stricmp(X,Y) == 0)
- #else
- #define PATH_LIST_SEPARATOR ':'
- #define FILENAME_EQ(X,Y) (streq(X,Y))
- #endif
- #endif
- /* The default output file name. */
- #define DEFAULT_OUTFILE "BROWSE"
- /* A version string written to the output file. Change this whenever
- the structure of the output file changes. */
- #define EBROWSE_FILE_VERSION "ebrowse 5.0"
- /* The output file consists of a tree of Lisp objects, with major
- nodes built out of Lisp structures. These are the heads of the
- Lisp structs with symbols identifying their type. */
- #define TREE_HEADER_STRUCT "[ebrowse-hs "
- #define TREE_STRUCT "[ebrowse-ts "
- #define MEMBER_STRUCT "[ebrowse-ms "
- #define BROWSE_STRUCT "[ebrowse-bs "
- #define CLASS_STRUCT "[ebrowse-cs "
- /* The name of the symbol table entry for global functions, variables,
- defines etc. This name also appears in the browser display. */
- #define GLOBALS_NAME "*Globals*"
- /* Token definitions. */
- enum token
- {
- YYEOF = 0, /* end of file */
- CSTRING = 256, /* string constant */
- CCHAR, /* character constant */
- CINT, /* integral constant */
- CFLOAT, /* real constant */
- ELLIPSIS, /* ... */
- LSHIFTASGN, /* <<= */
- RSHIFTASGN, /* >>= */
- ARROWSTAR, /* ->* */
- IDENT, /* identifier */
- DIVASGN, /* /= */
- INC, /* ++ */
- ADDASGN, /* += */
- DEC, /* -- */
- ARROW, /* -> */
- SUBASGN, /* -= */
- MULASGN, /* *= */
- MODASGN, /* %= */
- LOR, /* || */
- ORASGN, /* |= */
- LAND, /* && */
- ANDASGN, /* &= */
- XORASGN, /* ^= */
- POINTSTAR, /* .* */
- DCOLON, /* :: */
- EQ, /* == */
- NE, /* != */
- LE, /* <= */
- LSHIFT, /* << */
- GE, /* >= */
- RSHIFT, /* >> */
- /* Keywords. The undef's are there because these
- three symbols are very likely to be defined somewhere. */
- #undef BOOL
- #undef TRUE
- #undef FALSE
- ASM, /* asm */
- AUTO, /* auto */
- BREAK, /* break */
- CASE, /* case */
- CATCH, /* catch */
- CHAR, /* char */
- CLASS, /* class */
- CONST, /* const */
- CONTINUE, /* continue */
- DEFAULT, /* default */
- DELETE, /* delete */
- DO, /* do */
- DOUBLE, /* double */
- ELSE, /* else */
- ENUM, /* enum */
- EXTERN, /* extern */
- FLOAT, /* float */
- FOR, /* for */
- FRIEND, /* friend */
- GOTO, /* goto */
- IF, /* if */
- T_INLINE, /* inline */
- INT, /* int */
- LONG, /* long */
- NEW, /* new */
- OPERATOR, /* operator */
- PRIVATE, /* private */
- PROTECTED, /* protected */
- PUBLIC, /* public */
- REGISTER, /* register */
- RETURN, /* return */
- SHORT, /* short */
- SIGNED, /* signed */
- SIZEOF, /* sizeof */
- STATIC, /* static */
- STRUCT, /* struct */
- SWITCH, /* switch */
- TEMPLATE, /* template */
- THIS, /* this */
- THROW, /* throw */
- TRY, /* try */
- TYPEDEF, /* typedef */
- UNION, /* union */
- UNSIGNED, /* unsigned */
- VIRTUAL, /* virtual */
- VOID, /* void */
- VOLATILE, /* volatile */
- WHILE, /* while */
- MUTABLE, /* mutable */
- BOOL, /* bool */
- TRUE, /* true */
- FALSE, /* false */
- SIGNATURE, /* signature (GNU extension) */
- NAMESPACE, /* namespace */
- EXPLICIT, /* explicit */
- TYPENAME, /* typename */
- CONST_CAST, /* const_cast */
- DYNAMIC_CAST, /* dynamic_cast */
- REINTERPRET_CAST, /* reinterpret_cast */
- STATIC_CAST, /* static_cast */
- TYPEID, /* typeid */
- USING, /* using */
- WCHAR /* wchar_t */
- };
- /* Storage classes, in a wider sense. */
- enum sc
- {
- SC_UNKNOWN,
- SC_MEMBER, /* Is an instance member. */
- SC_STATIC, /* Is static member. */
- SC_FRIEND, /* Is friend function. */
- SC_TYPE /* Is a type definition. */
- };
- /* Member visibility. */
- enum visibility
- {
- V_PUBLIC,
- V_PROTECTED,
- V_PRIVATE
- };
- /* Member flags. */
- #define F_VIRTUAL 1 /* Is virtual function. */
- #define F_INLINE 2 /* Is inline function. */
- #define F_CONST 4 /* Is const. */
- #define F_PURE 8 /* Is pure virtual function. */
- #define F_MUTABLE 16 /* Is mutable. */
- #define F_TEMPLATE 32 /* Is a template. */
- #define F_EXPLICIT 64 /* Is explicit constructor. */
- #define F_THROW 128 /* Has a throw specification. */
- #define F_EXTERNC 256 /* Is declared extern "C". */
- #define F_DEFINE 512 /* Is a #define. */
- /* Two macros to set and test a bit in an int. */
- #define SET_FLAG(F, FLAG) ((F) |= (FLAG))
- #define HAS_FLAG(F, FLAG) (((F) & (FLAG)) != 0)
- /* Structure describing a class member. */
- struct member
- {
- struct member *next; /* Next in list of members. */
- struct member *anext; /* Collision chain in member_table. */
- struct member **list; /* Pointer to list in class. */
- unsigned param_hash; /* Hash value for parameter types. */
- int vis; /* Visibility (public, ...). */
- int flags; /* See F_* above. */
- char *regexp; /* Matching regular expression. */
- char *filename; /* Don't free this shared string. */
- int pos; /* Buffer position of occurrence. */
- char *def_regexp; /* Regular expression matching definition. */
- char *def_filename; /* File name of definition. */
- int def_pos; /* Buffer position of definition. */
- char name[1]; /* Member name. */
- };
- /* Structures of this type are used to connect class structures with
- their super and subclasses. */
- struct link
- {
- struct sym *sym; /* The super or subclass. */
- struct link *next; /* Next in list or NULL. */
- };
- /* Structure used to record namespace aliases. */
- struct alias
- {
- struct alias *next; /* Next in list. */
- struct sym *namesp; /* Namespace in which defined. */
- struct link *aliasee; /* List of aliased namespaces (A::B::C...). */
- char name[1]; /* Alias name. */
- };
- /* The structure used to describe a class in the symbol table,
- or a namespace in all_namespaces. */
- struct sym
- {
- int flags; /* Is class a template class?. */
- unsigned char visited; /* Used to find circles. */
- struct sym *next; /* Hash collision list. */
- struct link *subs; /* List of subclasses. */
- struct link *supers; /* List of superclasses. */
- struct member *vars; /* List of instance variables. */
- struct member *fns; /* List of instance functions. */
- struct member *static_vars; /* List of static variables. */
- struct member *static_fns; /* List of static functions. */
- struct member *friends; /* List of friend functions. */
- struct member *types; /* List of local types. */
- char *regexp; /* Matching regular expression. */
- int pos; /* Buffer position. */
- char *filename; /* File in which it can be found. */
- char *sfilename; /* File in which members can be found. */
- struct sym *namesp; /* Namespace in which defined. . */
- char name[1]; /* Name of the class. */
- };
- /* Experimental: Print info for `--position-info'. We print
- '(CLASS-NAME SCOPE MEMBER-NAME). */
- #define P_DEFN 1
- #define P_DECL 2
- int info_where;
- struct sym *info_cls = NULL;
- struct member *info_member = NULL;
- /* Experimental. For option `--position-info', the buffer position we
- are interested in. When this position is reached, print out
- information about what we know about that point. */
- int info_position = -1;
- /* Command line options structure for getopt_long. */
- struct option options[] =
- {
- {"append", no_argument, NULL, 'a'},
- {"files", required_argument, NULL, 'f'},
- {"help", no_argument, NULL, -2},
- {"min-regexp-length", required_argument, NULL, 'm'},
- {"max-regexp-length", required_argument, NULL, 'M'},
- {"no-nested-classes", no_argument, NULL, 'n'},
- {"no-regexps", no_argument, NULL, 'x'},
- {"no-structs-or-unions", no_argument, NULL, 's'},
- {"output-file", required_argument, NULL, 'o'},
- {"position-info", required_argument, NULL, 'p'},
- {"search-path", required_argument, NULL, 'I'},
- {"verbose", no_argument, NULL, 'v'},
- {"version", no_argument, NULL, -3},
- {"very-verbose", no_argument, NULL, 'V'},
- {NULL, 0, NULL, 0}
- };
- /* Semantic values of tokens. Set by yylex.. */
- unsigned yyival; /* Set for token CINT. */
- char *yytext; /* Set for token IDENT. */
- char *yytext_end;
- /* Output file. */
- FILE *yyout;
- /* Current line number. */
- int yyline;
- /* The name of the current input file. */
- char *filename;
- /* Three character class vectors, and macros to test membership
- of characters. */
- char is_ident[255];
- char is_digit[255];
- char is_white[255];
- #define IDENTP(C) is_ident[(unsigned char) (C)]
- #define DIGITP(C) is_digit[(unsigned char) (C)]
- #define WHITEP(C) is_white[(unsigned char) (C)]
- /* Command line flags. */
- int f_append;
- int f_verbose;
- int f_very_verbose;
- int f_structs = 1;
- int f_regexps = 1;
- int f_nested_classes = 1;
- /* Maximum and minimum lengths of regular expressions matching a
- member, class etc., for writing them to the output file. These are
- overridable from the command line. */
- int min_regexp = 5;
- int max_regexp = 50;
- /* Input buffer. */
- char *inbuffer;
- char *in;
- int inbuffer_size;
- /* Return the current buffer position in the input file. */
- #define BUFFER_POS() (in - inbuffer)
- /* If current lookahead is CSTRING, the following points to the
- first character in the string constant. Used for recognizing
- extern "C". */
- char *string_start;
- /* The size of the hash tables for classes.and members. Should be
- prime. */
- #define TABLE_SIZE 1001
- /* The hash table for class symbols. */
- struct sym *class_table[TABLE_SIZE];
- /* Hash table containing all member structures. This is generally
- faster for member lookup than traversing the member lists of a
- `struct sym'. */
- struct member *member_table[TABLE_SIZE];
- /* Hash table for namespace aliases */
- struct alias *namespace_alias_table[TABLE_SIZE];
- /* The special class symbol used to hold global functions,
- variables etc. */
- struct sym *global_symbols;
- /* The current namespace. */
- struct sym *current_namespace;
- /* The list of all known namespaces. */
- struct sym *all_namespaces;
- /* Stack of namespaces we're currently nested in, during the parse. */
- struct sym **namespace_stack;
- int namespace_stack_size;
- int namespace_sp;
- /* The current lookahead token. */
- int tk = -1;
- /* Structure describing a keyword. */
- struct kw
- {
- char *name; /* Spelling. */
- int tk; /* Token value. */
- struct kw *next; /* Next in collision chain. */
- };
- /* Keywords are lookup up in a hash table of their own. */
- #define KEYWORD_TABLE_SIZE 1001
- struct kw *keyword_table[KEYWORD_TABLE_SIZE];
- /* Search path. */
- struct search_path
- {
- char *path;
- struct search_path *next;
- };
- struct search_path *search_path;
- struct search_path *search_path_tail;
- /* Function prototypes. */
- int yylex P_ ((void));
- void yyparse P_ ((void));
- void re_init_parser P_ ((void));
- char *token_string P_ ((int));
- char *matching_regexp P_ ((void));
- void init_sym P_ ((void));
- struct sym *add_sym P_ ((char *, struct sym *));
- void add_link P_ ((struct sym *, struct sym *));
- void add_member_defn P_ ((struct sym *, char *, char *,
- int, unsigned, int, int, int));
- void add_member_decl P_ ((struct sym *, char *, char *, int,
- unsigned, int, int, int, int));
- void dump_roots P_ ((FILE *));
- void *xmalloc P_ ((int));
- void xfree P_ ((void *));
- void add_global_defn P_ ((char *, char *, int, unsigned, int, int, int));
- void add_global_decl P_ ((char *, char *, int, unsigned, int, int, int));
- void add_define P_ ((char *, char *, int));
- void mark_inherited_virtual P_ ((void));
- void leave_namespace P_ ((void));
- void enter_namespace P_ ((char *));
- void register_namespace_alias P_ ((char *, struct link *));
- void insert_keyword P_ ((char *, int));
- void re_init_scanner P_ ((void));
- void init_scanner P_ ((void));
- void usage P_ ((int));
- void version P_ ((void));
- void process_file P_ ((char *));
- void add_search_path P_ ((char *));
- FILE *open_file P_ ((char *));
- int process_pp_line P_ ((void));
- int dump_members P_ ((FILE *, struct member *));
- void dump_sym P_ ((FILE *, struct sym *));
- int dump_tree P_ ((FILE *, struct sym *));
- struct member *find_member P_ ((struct sym *, char *, int, int, unsigned));
- struct member *add_member P_ ((struct sym *, char *, int, int, unsigned));
- void mark_virtual P_ ((struct sym *));
- void mark_virtual P_ ((struct sym *));
- struct sym *make_namespace P_ ((char *, struct sym *));
- char *sym_scope P_ ((struct sym *));
- char *sym_scope_1 P_ ((struct sym *));
- int skip_to P_ ((int));
- void skip_matching P_ ((void));
- void member P_ ((struct sym *, int));
- void class_body P_ ((struct sym *, int));
- void class_definition P_ ((struct sym *, int, int, int));
- void declaration P_ ((int));
- unsigned parm_list P_ ((int *));
- char *operator_name P_ ((int *));
- struct sym *parse_classname P_ ((void));
- struct sym *parse_qualified_ident_or_type P_ ((char **));
- void parse_qualified_param_ident_or_type P_ ((char **));
- int globals P_ ((int));
- void yyerror P_ ((char *, char *));
- void usage P_ ((int)) NO_RETURN;
- void version P_ (()) NO_RETURN;
- /***********************************************************************
- Utilities
- ***********************************************************************/
- /* Print an error in a printf-like style with the current input file
- name and line number. */
- void
- yyerror (format, s)
- char *format, *s;
- {
- fprintf (stderr, "%s:%d: ", filename, yyline);
- fprintf (stderr, format, s);
- putc ('\n', stderr);
- }
- /* Like malloc but print an error and exit if not enough memory is
- available. */
- void *
- xmalloc (nbytes)
- int nbytes;
- {
- void *p = malloc (nbytes);
- if (p == NULL)
- {
- yyerror ("out of memory", NULL);
- exit (EXIT_FAILURE);
- }
- return p;
- }
- /* Like realloc but print an error and exit if out of memory. */
- void *
- xrealloc (p, sz)
- void *p;
- int sz;
- {
- p = realloc (p, sz);
- if (p == NULL)
- {
- yyerror ("out of memory", NULL);
- exit (EXIT_FAILURE);
- }
- return p;
- }
- /* Like strdup, but print an error and exit if not enough memory is
- available.. If S is null, return null. */
- char *
- xstrdup (s)
- char *s;
- {
- if (s)
- s = strcpy (xmalloc (strlen (s) + 1), s);
- return s;
- }
- /***********************************************************************
- Symbols
- ***********************************************************************/
- /* Initialize the symbol table. This currently only sets up the
- special symbol for globals (`*Globals*'). */
- void
- init_sym ()
- {
- global_symbols = add_sym (GLOBALS_NAME, NULL);
- }
- /* Add a symbol for class NAME to the symbol table. NESTED_IN_CLASS
- is the class in which class NAME was found. If it is null,
- this means the scope of NAME is the current namespace.
- If a symbol for NAME already exists, return that. Otherwise
- create a new symbol and set it to default values. */
- struct sym *
- add_sym (name, nested_in_class)
- char *name;
- struct sym *nested_in_class;
- {
- struct sym *sym;
- unsigned h;
- char *s;
- struct sym *scope = nested_in_class ? nested_in_class : current_namespace;
- for (s = name, h = 0; *s; ++s)
- h = (h << 1) ^ *s;
- h %= TABLE_SIZE;
- for (sym = class_table[h]; sym; sym = sym->next)
- if (streq (name, sym->name)
- && ((!sym->namesp && !scope)
- || (sym->namesp && scope
- && streq (sym->namesp->name, scope->name))))
- break;
- if (sym == NULL)
- {
- if (f_very_verbose)
- {
- putchar ('\t');
- puts (name);
- }
- sym = (struct sym *) xmalloc (sizeof *sym + strlen (name));
- bzero (sym, sizeof *sym);
- strcpy (sym->name, name);
- sym->namesp = scope;
- sym->next = class_table[h];
- class_table[h] = sym;
- }
- return sym;
- }
- /* Add links between superclass SUPER and subclass SUB. */
- void
- add_link (super, sub)
- struct sym *super, *sub;
- {
- struct link *lnk, *lnk2, *p, *prev;
- /* See if a link already exists. */
- for (p = super->subs, prev = NULL;
- p && strcmp (sub->name, p->sym->name) > 0;
- prev = p, p = p->next)
- ;
- /* Avoid duplicates. */
- if (p == NULL || p->sym != sub)
- {
- lnk = (struct link *) xmalloc (sizeof *lnk);
- lnk2 = (struct link *) xmalloc (sizeof *lnk2);
- lnk->sym = sub;
- lnk->next = p;
- if (prev)
- prev->next = lnk;
- else
- super->subs = lnk;
- lnk2->sym = super;
- lnk2->next = sub->supers;
- sub->supers = lnk2;
- }
- }
- /* Find in class CLS member NAME.
- VAR non-zero means look for a member variable; otherwise a function
- is searched. SC specifies what kind of member is searched---a
- static, or per-instance member etc. HASH is a hash code for the
- parameter types of functions. Value is a pointer to the member
- found or null if not found. */
- struct member *
- find_member (cls, name, var, sc, hash)
- struct sym *cls;
- char *name;
- int var, sc;
- unsigned hash;
- {
- struct member **list;
- struct member *p;
- unsigned name_hash = 0;
- char *s;
- int i;
- switch (sc)
- {
- case SC_FRIEND:
- list = &cls->friends;
- break;
- case SC_TYPE:
- list = &cls->types;
- break;
- case SC_STATIC:
- list = var ? &cls->static_vars : &cls->static_fns;
- break;
- default:
- list = var ? &cls->vars : &cls->fns;
- break;
- }
- for (s = name; *s; ++s)
- name_hash = (name_hash << 1) ^ *s;
- i = name_hash % TABLE_SIZE;
- for (p = member_table[i]; p; p = p->anext)
- if (p->list == list && p->param_hash == hash && streq (name, p->name))
- break;
- return p;
- }
- /* Add to class CLS information for the declaration of member NAME.
- REGEXP is a regexp matching the declaration, if non-null. POS is
- the position in the source where the declaration is found. HASH is
- a hash code for the parameter list of the member, if it's a
- function. VAR non-zero means member is a variable or type. SC
- specifies the type of member (instance member, static, ...). VIS
- is the member's visibility (public, protected, private). FLAGS is
- a bit set giving additional information about the member (see the
- F_* defines). */
- void
- add_member_decl (cls, name, regexp, pos, hash, var, sc, vis, flags)
- struct sym *cls;
- char *name;
- char *regexp;
- int pos;
- unsigned hash;
- int var;
- int sc;
- int vis;
- int flags;
- {
- struct member *m;
- m = find_member (cls, name, var, sc, hash);
- if (m == NULL)
- m = add_member (cls, name, var, sc, hash);
- /* Have we seen a new filename? If so record that. */
- if (!cls->filename || !FILENAME_EQ (cls->filename, filename))
- m->filename = filename;
- m->regexp = regexp;
- m->pos = pos;
- m->flags = flags;
- switch (vis)
- {
- case PRIVATE:
- m->vis = V_PRIVATE;
- break;
- case PROTECTED:
- m->vis = V_PROTECTED;
- break;
- case PUBLIC:
- m->vis = V_PUBLIC;
- break;
- }
- info_where = P_DECL;
- info_cls = cls;
- info_member = m;
- }
- /* Add to class CLS information for the definition of member NAME.
- REGEXP is a regexp matching the declaration, if non-null. POS is
- the position in the source where the declaration is found. HASH is
- a hash code for the parameter list of the member, if it's a
- function. VAR non-zero means member is a variable or type. SC
- specifies the type of member (instance member, static, ...). VIS
- is the member's visibility (public, protected, private). FLAGS is
- a bit set giving additional information about the member (see the
- F_* defines). */
- void
- add_member_defn (cls, name, regexp, pos, hash, var, sc, flags)
- struct sym *cls;
- char *name;
- char *regexp;
- int pos;
- unsigned hash;
- int var;
- int sc;
- int flags;
- {
- struct member *m;
- if (sc == SC_UNKNOWN)
- {
- m = find_member (cls, name, var, SC_MEMBER, hash);
- if (m == NULL)
- {
- m = find_member (cls, name, var, SC_STATIC, hash);
- if (m == NULL)
- m = add_member (cls, name, var, sc, hash);
- }
- }
- else
- {
- m = find_member (cls, name, var, sc, hash);
- if (m == NULL)
- m = add_member (cls, name, var, sc, hash);
- }
- if (!cls->sfilename)
- cls->sfilename = filename;
- if (!FILENAME_EQ (cls->sfilename, filename))
- m->def_filename = filename;
- m->def_regexp = regexp;
- m->def_pos = pos;
- m->flags |= flags;
- info_where = P_DEFN;
- info_cls = cls;
- info_member = m;
- }
- /* Add a symbol for a define named NAME to the symbol table.
- REGEXP is a regular expression matching the define in the source,
- if it is non-null. POS is the position in the file. */
- void
- add_define (name, regexp, pos)
- char *name, *regexp;
- int pos;
- {
- add_global_defn (name, regexp, pos, 0, 1, SC_FRIEND, F_DEFINE);
- add_global_decl (name, regexp, pos, 0, 1, SC_FRIEND, F_DEFINE);
- }
- /* Add information for the global definition of NAME.
- REGEXP is a regexp matching the declaration, if non-null. POS is
- the position in the source where the declaration is found. HASH is
- a hash code for the parameter list of the member, if it's a
- function. VAR non-zero means member is a variable or type. SC
- specifies the type of member (instance member, static, ...). VIS
- is the member's visibility (public, protected, private). FLAGS is
- a bit set giving additional information about the member (see the
- F_* defines). */
- void
- add_global_defn (name, regexp, pos, hash, var, sc, flags)
- char *name, *regexp;
- int pos;
- unsigned hash;
- int var;
- int sc;
- int flags;
- {
- int i;
- struct sym *sym;
- /* Try to find out for which classes a function is a friend, and add
- what we know about it to them. */
- if (!var)
- for (i = 0; i < TABLE_SIZE; ++i)
- for (sym = class_table[i]; sym; sym = sym->next)
- if (sym != global_symbols && sym->friends)
- if (find_member (sym, name, 0, SC_FRIEND, hash))
- add_member_defn (sym, name, regexp, pos, hash, 0,
- SC_FRIEND, flags);
- /* Add to global symbols. */
- add_member_defn (global_symbols, name, regexp, pos, hash, var, sc, flags);
- }
- /* Add information for the global declaration of NAME.
- REGEXP is a regexp matching the declaration, if non-null. POS is
- the position in the source where the declaration is found. HASH is
- a hash code for the parameter list of the member, if it's a
- function. VAR non-zero means member is a variable or type. SC
- specifies the type of member (instance member, static, ...). VIS
- is the member's visibility (public, protected, private). FLAGS is
- a bit set giving additional information about the member (see the
- F_* defines). */
- void
- add_global_decl (name, regexp, pos, hash, var, sc, flags)
- char *name, *regexp;
- int pos;
- unsigned hash;
- int var;
- int sc;
- int flags;
- {
- /* Add declaration only if not already declared. Header files must
- be processed before source files for this to have the right effect.
- I do not want to handle implicit declarations at the moment. */
- struct member *m;
- struct member *found;
- m = found = find_member (global_symbols, name, var, sc, hash);
- if (m == NULL)
- m = add_member (global_symbols, name, var, sc, hash);
- /* Definition already seen => probably last declaration implicit.
- Override. This means that declarations must always be added to
- the symbol table before definitions. */
- if (!found)
- {
- if (!global_symbols->filename
- || !FILENAME_EQ (global_symbols->filename, filename))
- m->filename = filename;
- m->regexp = regexp;
- m->pos = pos;
- m->vis = V_PUBLIC;
- m->flags = flags;
- info_where = P_DECL;
- info_cls = global_symbols;
- info_member = m;
- }
- }
- /* Add a symbol for member NAME to class CLS.
- VAR non-zero means it's a variable. SC specifies the kind of
- member. HASH is a hash code for the parameter types of a function.
- Value is a pointer to the member's structure. */
- struct member *
- add_member (cls, name, var, sc, hash)
- struct sym *cls;
- char *name;
- int var;
- int sc;
- unsigned hash;
- {
- struct member *m = (struct member *) xmalloc (sizeof *m + strlen (name));
- struct member **list;
- struct member *p;
- struct member *prev;
- unsigned name_hash = 0;
- int i;
- char *s;
- strcpy (m->name, name);
- m->param_hash = hash;
- m->vis = 0;
- m->flags = 0;
- m->regexp = NULL;
- m->filename = NULL;
- m->pos = 0;
- m->def_regexp = NULL;
- m->def_filename = NULL;
- m->def_pos = 0;
- assert (cls != NULL);
- switch (sc)
- {
- case SC_FRIEND:
- list = &cls->friends;
- break;
- case SC_TYPE:
- list = &cls->types;
- break;
- case SC_STATIC:
- list = var ? &cls->static_vars : &cls->static_fns;
- break;
- default:
- list = var ? &cls->vars : &cls->fns;
- break;
- }
- for (s = name; *s; ++s)
- name_hash = (name_hash << 1) ^ *s;
- i = name_hash % TABLE_SIZE;
- m->anext = member_table[i];
- member_table[i] = m;
- m->list = list;
- /* Keep the member list sorted. It's cheaper to do it here than to
- sort them in Lisp. */
- for (prev = NULL, p = *list;
- p && strcmp (name, p->name) > 0;
- prev = p, p = p->next)
- ;
- m->next = p;
- if (prev)
- prev->next = m;
- else
- *list = m;
- return m;
- }
- /* Given the root R of a class tree, step through all subclasses
- recursively, marking functions as virtual that are declared virtual
- in base classes. */
- void
- mark_virtual (r)
- struct sym *r;
- {
- struct link *p;
- struct member *m, *m2;
- for (p = r->subs; p; p = p->next)
- {
- for (m = r->fns; m; m = m->next)
- if (HAS_FLAG (m->flags, F_VIRTUAL))
- {
- for (m2 = p->sym->fns; m2; m2 = m2->next)
- if (m->param_hash == m2->param_hash && streq (m->name, m2->name))
- SET_FLAG (m2->flags, F_VIRTUAL);
- }
- mark_virtual (p->sym);
- }
- }
- /* For all roots of the class tree, mark functions as virtual that
- are virtual because of a virtual declaration in a base class. */
- void
- mark_inherited_virtual ()
- {
- struct sym *r;
- int i;
- for (i = 0; i < TABLE_SIZE; ++i)
- for (r = class_table[i]; r; r = r->next)
- if (r->supers == NULL)
- mark_virtual (r);
- }
- /* Create and return a symbol for a namespace with name NAME. */
- struct sym *
- make_namespace (name, context)
- char *name;
- struct sym *context;
- {
- struct sym *s = (struct sym *) xmalloc (sizeof *s + strlen (name));
- bzero (s, sizeof *s);
- strcpy (s->name, name);
- s->next = all_namespaces;
- s->namesp = context;
- all_namespaces = s;
- return s;
- }
- /* Find the symbol for namespace NAME. If not found, retrun NULL */
- struct sym *
- check_namespace (name, context)
- char *name;
- struct sym *context;
- {
- struct sym *p = NULL;
- for (p = all_namespaces; p; p = p->next)
- {
- if (streq (p->name, name) && (p->namesp == context))
- break;
- }
- return p;
- }
- /* Find the symbol for namespace NAME. If not found, add a new symbol
- for NAME to all_namespaces. */
- struct sym *
- find_namespace (name, context)
- char *name;
- struct sym *context;
- {
- struct sym *p = check_namespace (name, context);
- if (p == NULL)
- p = make_namespace (name, context);
- return p;
- }
- /* Find namespace alias with name NAME. If not found return NULL. */
- struct link *
- check_namespace_alias (name)
- char *name;
- {
- struct link *p = NULL;
- struct alias *al;
- unsigned h;
- char *s;
- for (s = name, h = 0; *s; ++s)
- h = (h << 1) ^ *s;
- h %= TABLE_SIZE;
- for (al = namespace_alias_table[h]; al; al = al->next)
- if (streq (name, al->name) && (al->namesp == current_namespace))
- {
- p = al->aliasee;
- break;
- }
- return p;
- }
- /* Register the name NEW_NAME as an alias for namespace list OLD_NAME. */
- void
- register_namespace_alias (new_name, old_name)
- char *new_name;
- struct link *old_name;
- {
- unsigned h;
- char *s;
- struct alias *al;
- for (s = new_name, h = 0; *s; ++s)
- h = (h << 1) ^ *s;
- h %= TABLE_SIZE;
- /* Is it already in the table of aliases? */
- for (al = namespace_alias_table[h]; al; al = al->next)
- if (streq (new_name, al->name) && (al->namesp == current_namespace))
- return;
- al = (struct alias *) xmalloc (sizeof *al + strlen (new_name));
- strcpy (al->name, new_name);
- al->next = namespace_alias_table[h];
- al->namesp = current_namespace;
- al->aliasee = old_name;
- namespace_alias_table[h] = al;
- }
- /* Enter namespace with name NAME. */
- void
- enter_namespace (name)
- char *name;
- {
- struct sym *p = find_namespace (name, current_namespace);
- if (namespace_sp == namespace_stack_size)
- {
- int size = max (10, 2 * namespace_stack_size);
- namespace_stack
- = (struct sym **) xrealloc ((void *)namespace_stack,
- size * sizeof *namespace_stack);
- namespace_stack_size = size;
- }
- namespace_stack[namespace_sp++] = current_namespace;
- current_namespace = p;
- }
- /* Leave the current namespace. */
- void
- leave_namespace ()
- {
- assert (namespace_sp > 0);
- current_namespace = namespace_stack[--namespace_sp];
- }
- /***********************************************************************
- Writing the Output File
- ***********************************************************************/
- /* Write string S to the output file FP in a Lisp-readable form.
- If S is null, write out `()'. */
- #define PUTSTR(s, fp) \
- do { \
- if (!s) \
- { \
- putc ('(', fp); \
- putc (')', fp); \
- putc (' ', fp); \
- } \
- else \
- { \
- putc ('"', fp); \
- fputs (s, fp); \
- putc ('"', fp); \
- putc (' ', fp); \
- } \
- } while (0)
- /* A dynamically allocated buffer for constructing a scope name. */
- char *scope_buffer;
- int scope_buffer_size;
- int scope_buffer_len;
- /* Make sure scope_buffer has enough room to add LEN chars to it. */
- void
- ensure_scope_buffer_room (len)
- int len;
- {
- if (scope_buffer_len + len >= scope_buffer_size)
- {
- int new_size = max (2 * scope_buffer_size, scope_buffer_len + len);
- scope_buffer = (char *) xrealloc (scope_buffer, new_size);
- scope_buffer_size = new_size;
- }
- }
- /* Recursively add the scope names of symbol P and the scopes of its
- namespaces to scope_buffer. Value is a pointer to the complete
- scope name constructed. */
- char *
- sym_scope_1 (p)
- struct sym *p;
- {
- int len;
- if (p->namesp)
- sym_scope_1 (p->namesp);
- if (*scope_buffer)
- {
- ensure_scope_buffer_room (3);
- strcat (scope_buffer, "::");
- scope_buffer_len += 2;
- }
- len = strlen (p->name);
- ensure_scope_buffer_room (len + 1);
- strcat (scope_buffer, p->name);
- scope_buffer_len += len;
- if (HAS_FLAG (p->flags, F_TEMPLATE))
- {
- ensure_scope_buffer_room (3);
- strcat (scope_buffer, "<>");
- scope_buffer_len += 2;
- }
- return scope_buffer;
- }
- /* Return the scope of symbol P in printed representation, i.e.
- as it would appear in a C*+ source file. */
- char *
- sym_scope (p)
- struct sym *p;
- {
- if (!scope_buffer)
- {
- scope_buffer_size = 1024;
- scope_buffer = (char *) xmalloc (scope_buffer_size);
- }
- *scope_buffer = '\0';
- scope_buffer_len = 0;
- if (p->namesp)
- sym_scope_1 (p->namesp);
- return scope_buffer;
- }
- /* Dump the list of members M to file FP. Value is the length of the
- list. */
- int
- dump_members (fp, m)
- FILE *fp;
- struct member *m;
- {
- int n;
- putc ('(', fp);
- for (n = 0; m; m = m->next, ++n)
- {
- fputs (MEMBER_STRUCT, fp);
- PUTSTR (m->name, fp);
- PUTSTR (NULL, fp); /* FIXME? scope for globals */
- fprintf (fp, "%u ", (unsigned) m->flags);
- PUTSTR (m->filename, fp);
- PUTSTR (m->regexp, fp);
- fprintf (fp, "%u ", (unsigned) m->pos);
- fprintf (fp, "%u ", (unsigned) m->vis);
- putc (' ', fp);
- PUTSTR (m->def_filename, fp);
- PUTSTR (m->def_regexp, fp);
- fprintf (fp, "%u", (unsigned) m->def_pos);
- putc (']', fp);
- putc ('\n', fp);
- }
- putc (')', fp);
- putc ('\n', fp);
- return n;
- }
- /* Dump class ROOT to stream FP. */
- void
- dump_sym (fp, root)
- FILE *fp;
- struct sym *root;
- {
- fputs (CLASS_STRUCT, fp);
- PUTSTR (root->name, fp);
- /* Print scope, if any. */
- if (root->namesp)
- PUTSTR (sym_scope (root), fp);
- else
- PUTSTR (NULL, fp);
- /* Print flags. */
- fprintf (fp, "%u", root->flags);
- PUTSTR (root->filename, fp);
- PUTSTR (root->regexp, fp);
- fprintf (fp, "%u", (unsigned) root->pos);
- PUTSTR (root->sfilename, fp);
- putc (']', fp);
- putc ('\n', fp);
- }
- /* Dump class ROOT and its subclasses to file FP. Value is the
- number of classes written. */
- int
- dump_tree (fp, root)
- FILE *fp;
- struct sym *root;
- {
- struct link *lk;
- unsigned n = 0;
- dump_sym (fp, root);
- if (f_verbose)
- {
- putchar ('+');
- fflush (stdout);
- }
- putc ('(', fp);
- for (lk = root->subs; lk; lk = lk->next)
- {
- fputs (TREE_STRUCT, fp);
- n += dump_tree (fp, lk->sym);
- putc (']', fp);
- }
- putc (')', fp);
- dump_members (fp, root->vars);
- n += dump_members (fp, root->fns);
- dump_members (fp, root->static_vars);
- n += dump_members (fp, root->static_fns);
- n += dump_members (fp, root->friends);
- dump_members (fp, root->types);
- /* Superclasses. */
- putc ('(', fp);
- putc (')', fp);
- /* Mark slot. */
- putc ('(', fp);
- putc (')', fp);
- putc ('\n', fp);
- return n;
- }
- /* Dump the entire class tree to file FP. */
- void
- dump_roots (fp)
- FILE *fp;
- {
- int i, n = 0;
- struct sym *r;
- /* Output file header containing version string, command line
- options etc. */
- if (!f_append)
- {
- fputs (TREE_HEADER_STRUCT, fp);
- PUTSTR (EBROWSE_FILE_VERSION, fp);
- putc ('\"', fp);
- if (!f_structs)
- fputs (" -s", fp);
- if (f_regexps)
- fputs (" -x", fp);
- putc ('\"', fp);
- fputs (" ()", fp);
- fputs (" ()", fp);
- putc (']', fp);
- }
- /* Mark functions as virtual that are so because of functions
- declared virtual in base classes. */
- mark_inherited_virtual ();
- /* Dump the roots of the graph. */
- for (i = 0; i < TABLE_SIZE; ++i)
- for (r = class_table[i]; r; r = r->next)
- if (!r->supers)
- {
- fputs (TREE_STRUCT, fp);
- n += dump_tree (fp, r);
- putc (']', fp);
- }
- if (f_verbose)
- putchar ('\n');
- }
- /***********************************************************************
- Scanner
- ***********************************************************************/
- #ifdef DEBUG
- #define INCREMENT_LINENO \
- do { \
- if (f_very_verbose) \
- { \
- ++yyline; \
- printf ("%d:\n", yyline); \
- } \
- else \
- ++yyline; \
- } while (0)
- #else
- #define INCREMENT_LINENO ++yyline
- #endif
- /* Define two macros for accessing the input buffer (current input
- file). GET(C) sets C to the next input character and advances the
- input pointer. UNGET retracts the input pointer. */
- #define GET(C) ((C) = *in++)
- #define UNGET() (--in)
- /* Process a preprocessor line. Value is the next character from the
- input buffer not consumed. */
- int
- process_pp_line ()
- {
- int in_comment = 0, in_string = 0;
- int c;
- char *p = yytext;
- /* Skip over white space. The `#' has been consumed already. */
- while (WHITEP (GET (c)))
- ;
- /* Read the preprocessor command (if any). */
- while (IDENTP (c))
- {
- *p++ = c;
- GET (c);
- }
- /* Is it a `define'? */
- *p = '\0';
- if (*yytext && streq (yytext, "define"))
- {
- p = yytext;
- while (WHITEP (c))
- GET (c);
- while (IDENTP (c))
- {
- *p++ = c;
- GET (c);
- }
- *p = '\0';
- if (*yytext)
- {
- char *regexp = matching_regexp ();
- int pos = BUFFER_POS ();
- add_define (yytext, regexp, pos);
- }
- }
- while (c && (c != '\n' || in_comment || in_string))
- {
- if (c == '\\')
- GET (c);
- else if (c == '/' && !in_comment)
- {
- if (GET (c) == '*')
- in_comment = 1;
- }
- else if (c == '*' && in_comment)
- {
- if (GET (c) == '/')
- in_comment = 0;
- }
- else if (c == '"')
- in_string = !in_string;
- if (c == '\n')
- INCREMENT_LINENO;
- GET (c);
- }
- return c;
- }
- /* Value is the next token from the input buffer. */
- int
- yylex ()
- {
- int c;
- char end_char;
- char *p;
- for (;;)
- {
- while (WHITEP (GET (c)))
- ;
- switch (c)
- {
- case '\n':
- INCREMENT_LINENO;
- break;
- case '\r':
- break;
- case 0:
- /* End of file. */
- return YYEOF;
- case '\\':
- GET (c);
- break;
- case '"':
- case '\'':
- /* String and character constants. */
- end_char = c;
- string_start = in;
- while (GET (c) && c != end_char)
- {
- switch (c)
- {
- case '\\':
- /* Escape sequences. */
- if (!GET (c))
- {
- if (end_char == '\'')
- yyerror ("EOF in character constant", NULL);
- else
- yyerror ("EOF in string constant", NULL);
- goto end_string;
- }
- else switch (c)
- {
- case '\n':
- INCREMENT_LINENO;
- case 'a':
- case 'b':
- case 'f':
- case 'n':
- case 'r':
- case 't':
- case 'v':
- break;
- case 'x':
- {
- /* Hexadecimal escape sequence. */
- int i;
- for (i = 0; i < 2; ++i)
- {
- GET (c);
- if (c >= '0' && c <= '7')
- ;
- else if (c >= 'a' && c <= 'f')
- ;
- else if (c >= 'A' && c <= 'F')
- ;
- else
- {
- UNGET ();
- break;
- }
- }
- }
- break;
- case '0':
- {
- /* Octal escape sequence. */
- int i;
- for (i = 0; i < 3; ++i)
- {
- GET (c);
- if (c >= '0' && c <= '7')
- ;
- else
- {
- UNGET ();
- break;
- }
- }
- }
- break;
- default:
- break;
- }
- break;
- case '\n':
- if (end_char == '\'')
- yyerror ("newline in character constant", NULL);
- else
- yyerror ("newline in string constant", NULL);
- INCREMENT_LINENO;
- break;
- default:
- break;
- }
- }
- end_string:
- return end_char == '\'' ? CCHAR : CSTRING;
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
- case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
- case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
- case 'v': case 'w': case 'x': case 'y': case 'z':
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
- case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
- case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
- case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_':
- {
- /* Identifier and keywords. */
- unsigned hash;
- struct kw *k;
- p = yytext;
- *p++ = hash = c;
- while (IDENTP (GET (*p)))
- {
- hash = (hash << 1) ^ *p++;
- if (p == yytext_end - 1)
- {
- int size = yytext_end - yytext;
- yytext = (char *) xrealloc (yytext, 2 * size);
- yytext_end = yytext + 2 * size;
- p = yytext + size - 1;
- }
- }
- UNGET ();
- *p = 0;
- for (k = keyword_table[hash % KEYWORD_TABLE_SIZE]; k; k = k->next)
- if (streq (k->name, yytext))
- return k->tk;
- return IDENT;
- }
- case '/':
- /* C and C++ comments, '/' and '/='. */
- switch (GET (c))
- {
- case '*':
- while (GET (c))
- {
- switch (c)
- {
- case '*':
- if (GET (c) == '/')
- goto comment_end;
- UNGET ();
- break;
- case '\\':
- GET (c);
- break;
- case '\n':
- INCREMENT_LINENO;
- break;
- }
- }
- comment_end:;
- break;
- case '=':
- return DIVASGN;
- case '/':
- while (GET (c) && c != '\n')
- ;
- INCREMENT_LINENO;
- break;
- default:
- UNGET ();
- return '/';
- }
- break;
- case '+':
- if (GET (c) == '+')
- return INC;
- else if (c == '=')
- return ADDASGN;
- UNGET ();
- return '+';
- case '-':
- switch (GET (c))
- {
- case '-':
- return DEC;
- case '>':
- if (GET (c) == '*')
- return ARROWSTAR;
- UNGET ();
- return ARROW;
- case '=':
- return SUBASGN;
- }
- UNGET ();
- return '-';
- case '*':
- if (GET (c) == '=')
- return MULASGN;
- UNGET ();
- return '*';
- case '%':
- if (GET (c) == '=')
- return MODASGN;
- UNGET ();
- return '%';
- case '|':
- if (GET (c) == '|')
- return LOR;
- else if (c == '=')
- return ORASGN;
- UNGET ();
- return '|';
- case '&':
- if (GET (c) == '&')
- return LAND;
- else if (c == '=')
- return ANDASGN;
- UNGET ();
- return '&';
- case '^':
- if (GET (c) == '=')
- return XORASGN;
- UNGET ();
- return '^';
- case '.':
- if (GET (c) == '*')
- return POINTSTAR;
- else if (c == '.')
- {
- if (GET (c) != '.')
- yyerror ("invalid token '..' ('...' assumed)", NULL);
- UNGET ();
- return ELLIPSIS;
- }
- else if (!DIGITP (c))
- {
- UNGET ();
- return '.';
- }
- goto mantissa;
- case ':':
- if (GET (c) == ':')
- return DCOLON;
- UNGET ();
- return ':';
- case '=':
- if (GET (c) == '=')
- return EQ;
- UNGET ();
- return '=';
- case '!':
- if (GET (c) == '=')
- return NE;
- UNGET ();
- return '!';
- case '<':
- switch (GET (c))
- {
- case '=':
- return LE;
- case '<':
- if (GET (c) == '=')
- return LSHIFTASGN;
- UNGET ();
- return LSHIFT;
- }
- UNGET ();
- return '<';
- case '>':
- switch (GET (c))
- {
- case '=':
- return GE;
- case '>':
- if (GET (c) == '=')
- return RSHIFTASGN;
- UNGET ();
- return RSHIFT;
- }
- UNGET ();
- return '>';
- case '#':
- c = process_pp_line ();
- if (c == 0)
- return YYEOF;
- break;
- case '(': case ')': case '[': case ']': case '{': case '}':
- case ';': case ',': case '?': case '~':
- return c;
- case '0':
- yyival = 0;
- if (GET (c) == 'x' || c == 'X')
- {
- while (GET (c))
- {
- if (DIGITP (c))
- yyival = yyival * 16 + c - '0';
- else if (c >= 'a' && c <= 'f')
- yyival = yyival * 16 + c - 'a' + 10;
- else if (c >= 'A' && c <= 'F')
- yyival = yyival * 16 + c - 'A' + 10;
- else
- break;
- }
- goto int_suffixes;
- }
- else if (c == '.')
- goto mantissa;
- while (c >= '0' && c <= '7')
- {
- yyival = (yyival << 3) + c - '0';
- GET (c);
- }
- int_suffixes:
- /* Integer suffixes. */
- while (isalpha (c))
- GET (c);
- UNGET ();
- return CINT;
- case '1': case '2': case '3': case '4': case '5': case '6':
- case '7': case '8': case '9':
- /* Integer or floating constant, part before '.'. */
- yyival = c - '0';
- while (GET (c) && DIGITP (c))
- yyival = 10 * yyival + c - '0';
- if (c != '.')
- goto int_suffixes;
- mantissa:
- /* Digits following '.'. */
- while (DIGITP (c))
- GET (c);
- /* Optional exponent. */
- if (c == 'E' || c == 'e')
- {
- if (GET (c) == '-' || c == '+')
- GET (c);
- while (DIGITP (c))
- GET (c);
- }
- /* Optional type suffixes. */
- while (isalpha (c))
- GET (c);
- UNGET ();
- return CFLOAT;
- default:
- break;
- }
- }
- }
- /* Actually local to matching_regexp. These variables must be in
- global scope for the case that `static' get's defined away. */
- static char *matching_regexp_buffer, *matching_regexp_end_buf;
- /* Value is the string from the start of the line to the current
- position in the input buffer, or maybe a bit more if that string is
- shorter than min_regexp. */
- char *
- matching_regexp ()
- {
- char *p;
- char *s;
- char *t;
- if (!f_regexps)
- return NULL;
- if (matching_regexp_buffer == NULL)
- {
- matching_regexp_buffer = (char *) xmalloc (max_regexp);
- matching_regexp_end_buf = &matching_regexp_buffer[max_regexp] - 1;
- }
- /* Scan back to previous newline of buffer start. */
- for (p = in - 1; p > inbuffer && *p != '\n'; --p)
- ;
- if (*p == '\n')
- {
- while (in - p < min_regexp && p > inbuffer)
- {
- /* Line probably not significant enough */
- for (--p; p > inbuffer && *p != '\n'; --p)
- ;
- }
- if (*p == '\n')
- ++p;
- }
- /* Copy from end to make sure significant portions are included.
- This implies that in the browser a regular expressing of the form
- `^.*{regexp}' has to be used. */
- for (s = matching_regexp_end_buf - 1, t = in;
- s > matching_regexp_buffer && t > p;)
- {
- *--s = *--t;
- if (*s == '"' || *s == '\\')
- *--s = '\\';
- }
- *(matching_regexp_end_buf - 1) = '\0';
- return xstrdup (s);
- }
- /* Return a printable representation of token T. */
- char *
- token_string (t)
- int t;
- {
- static char b[3];
- switch (t)
- {
- case CSTRING: return "string constant";
- case CCHAR: return "char constant";
- case CINT: return "int constant";
- case CFLOAT: return "floating constant";
- case ELLIPSIS: return "...";
- case LSHIFTASGN: return "<<=";
- case RSHIFTASGN: return ">>=";
- case ARROWSTAR: return "->*";
- case IDENT: return "identifier";
- case DIVASGN: return "/=";
- case INC: return "++";
- case ADDASGN: return "+=";
- case DEC: return "--";
- case ARROW: return "->";
- case SUBASGN: return "-=";
- case MULASGN: return "*=";
- case MODASGN: return "%=";
- case LOR: return "||";
- case ORASGN: return "|=";
- case LAND: return "&&";
- case ANDASGN: return "&=";
- case XORASGN: return "^=";
- case POINTSTAR: return ".*";
- case DCOLON: return "::";
- case EQ: return "==";
- case NE: return "!=";
- case LE: return "<=";
- case LSHIFT: return "<<";
- case GE: return ">=";
- case RSHIFT: return ">>";
- case ASM: return "asm";
- case AUTO: return "auto";
- case BREAK: return "break";
- case CASE: return "case";
- case CATCH: return "catch";
- case CHAR: return "char";
- case CLASS: return "class";
- case CONST: return "const";
- case CONTINUE: return "continue";
- case DEFAULT: return "default";
- case DELETE: return "delete";
- case DO: return "do";
- case DOUBLE: return "double";
- case ELSE: return "else";
- case ENUM: return "enum";
- case EXTERN: return "extern";
- case FLOAT: return "float";
- case FOR: return "for";
- case FRIEND: return "friend";
- case GOTO: return "goto";
- case IF: return "if";
- case T_INLINE: return "inline";
- case INT: return "int";
- case LONG: return "long";
- case NEW: return "new";
- case OPERATOR: return "operator";
- case PRIVATE: return "private";
- case PROTECTED: return "protected";
- case PUBLIC: return "public";
- case REGISTER: return "register";
- case RETURN: return "return";
- case SHORT: return "short";
- case SIGNED: return "signed";
- case SIZEOF: return "sizeof";
- case STATIC: return "static";
- case STRUCT: return "struct";
- case SWITCH: return "switch";
- case TEMPLATE: return "template";
- case THIS: return "this";
- case THROW: return "throw";
- case TRY: return "try";
- case TYPEDEF: return "typedef";
- case UNION: return "union";
- case UNSIGNED: return "unsigned";
- case VIRTUAL: return "virtual";
- case VOID: return "void";
- case VOLATILE: return "volatile";
- case WHILE: return "while";
- case MUTABLE: return "mutable";
- case BOOL: return "bool";
- case TRUE: return "true";
- case FALSE: return "false";
- case SIGNATURE: return "signature";
- case NAMESPACE: return "namespace";
- case EXPLICIT: return "explicit";
- case TYPENAME: return "typename";
- case CONST_CAST: return "const_cast";
- case DYNAMIC_CAST: return "dynamic_cast";
- case REINTERPRET_CAST: return "reinterpret_cast";
- case STATIC_CAST: return "static_cast";
- case TYPEID: return "typeid";
- case USING: return "using";
- case WCHAR: return "wchar_t";
- case YYEOF: return "EOF";
- default:
- if (t < 255)
- {
- b[0] = t;
- b[1] = '\0';
- return b;
- }
- else
- return "???";
- }
- }
- /* Reinitialize the scanner for a new input file. */
- void
- re_init_scanner ()
- {
- in = inbuffer;
- yyline = 1;
- if (yytext == NULL)
- {
- int size = 256;
- yytext = (char *) xmalloc (size * sizeof *yytext);
- yytext_end = yytext + size;
- }
- }
- /* Insert a keyword NAME with token value TK into the keyword hash
- table. */
- void
- insert_keyword (name, tk)
- char *name;
- int tk;
- {
- char *s;
- unsigned h = 0;
- struct kw *k = (struct kw *) xmalloc (sizeof *k);
- for (s = name; *s; ++s)
- h = (h << 1) ^ *s;
- h %= KEYWORD_TABLE_SIZE;
- k->name = name;
- k->tk = tk;
- k->next = keyword_table[h];
- keyword_table[h] = k;
- }
- /* Initialize the scanner for the first file. This sets up the
- character class vectors and fills the keyword hash table. */
- void
- init_scanner ()
- {
- int i;
- /* Allocate the input buffer */
- inbuffer_size = READ_CHUNK_SIZE + 1;
- inbuffer = in = (char *) xmalloc (inbuffer_size);
- yyline = 1;
- /* Set up character class vectors. */
- for (i = 0; i < sizeof is_ident; ++i)
- {
- if (i == '_' || isalnum (i))
- is_ident[i] = 1;
- if (i >= '0' && i <= '9')
- is_digit[i] = 1;
- if (i == ' ' || i == '\t' || i == '\f' || i == '\v')
- is_white[i] = 1;
- }
- /* Fill keyword hash table. */
- insert_keyword ("and", LAND);
- insert_keyword ("and_eq", ANDASGN);
- insert_keyword ("asm", ASM);
- insert_keyword ("auto", AUTO);
- insert_keyword ("bitand", '&');
- insert_keyword ("bitor", '|');
- insert_keyword ("bool", BOOL);
- insert_keyword ("break", BREAK);
- insert_keyword ("case", CASE);
- insert_keyword ("catch", CATCH);
- insert_keyword ("char", CHAR);
- insert_keyword ("class", CLASS);
- insert_keyword ("compl", '~');
- insert_keyword ("const", CONST);
- insert_keyword ("const_cast", CONST_CAST);
- insert_keyword ("continue", CONTINUE);
- insert_keyword ("default", DEFAULT);
- insert_keyword ("delete", DELETE);
- insert_keyword ("do", DO);
- insert_keyword ("double", DOUBLE);
- insert_keyword ("dynamic_cast", DYNAMIC_CAST);
- insert_keyword ("else", ELSE);
- insert_keyword ("enum", ENUM);
- insert_keyword ("explicit", EXPLICIT);
- insert_keyword ("extern", EXTERN);
- insert_keyword ("false", FALSE);
- insert_keyword ("float", FLOAT);
- insert_keyword ("for", FOR);
- insert_keyword ("friend", FRIEND);
- insert_keyword ("goto", GOTO);
- insert_keyword ("if", IF);
- insert_keyword ("inline", T_INLINE);
- insert_keyword ("int", INT);
- insert_keyword ("long", LONG);
- insert_keyword ("mutable", MUTABLE);
- insert_keyword ("namespace", NAMESPACE);
- insert_keyword ("new", NEW);
- insert_keyword ("not", '!');
- insert_keyword ("not_eq", NE);
- insert_keyword ("operator", OPERATOR);
- insert_keyword ("or", LOR);
- insert_keyword ("or_eq", ORASGN);
- insert_keyword ("private", PRIVATE);
- insert_keyword ("protected", PROTECTED);
- insert_keyword ("public", PUBLIC);
- insert_keyword ("register", REGISTER);
- insert_keyword ("reinterpret_cast", REINTERPRET_CAST);
- insert_keyword ("return", RETURN);
- insert_keyword ("short", SHORT);
- insert_keyword ("signed", SIGNED);
- insert_keyword ("sizeof", SIZEOF);
- insert_keyword ("static", STATIC);
- insert_keyword ("static_cast", STATIC_CAST);
- insert_keyword ("struct", STRUCT);
- insert_keyword ("switch", SWITCH);
- insert_keyword ("template", TEMPLATE);
- insert_keyword ("this", THIS);
- insert_keyword ("throw", THROW);
- insert_keyword ("true", TRUE);
- insert_keyword ("try", TRY);
- insert_keyword ("typedef", TYPEDEF);
- insert_keyword ("typeid", TYPEID);
- insert_keyword ("typename", TYPENAME);
- insert_keyword ("union", UNION);
- insert_keyword ("unsigned", UNSIGNED);
- insert_keyword ("using", USING);
- insert_keyword ("virtual", VIRTUAL);
- insert_keyword ("void", VOID);
- insert_keyword ("volatile", VOLATILE);
- insert_keyword ("wchar_t", WCHAR);
- insert_keyword ("while", WHILE);
- insert_keyword ("xor", '^');
- insert_keyword ("xor_eq", XORASGN);
- }
- /***********************************************************************
- Parser
- ***********************************************************************/
- /* Match the current lookahead token and set it to the next token. */
- #define MATCH() (tk = yylex ())
- /* Return the lookahead token. If current lookahead token is cleared,
- read a new token. */
- #define LA1 (tk == -1 ? (tk = yylex ()) : tk)
- /* Is the current lookahead equal to the token T? */
- #define LOOKING_AT(T) (tk == (T))
- /* Is the current lookahead one of T1 or T2? */
- #define LOOKING_AT2(T1, T2) (tk == (T1) || tk == (T2))
- /* Is the current lookahead one of T1, T2 or T3? */
- #define LOOKING_AT3(T1, T2, T3) (tk == (T1) || tk == (T2) || tk == (T3))
- /* Is the current lookahead one of T1...T4? */
- #define LOOKING_AT4(T1, T2, T3, T4) \
- (tk == (T1) || tk == (T2) || tk == (T3) || tk == (T4))
- /* Match token T if current lookahead is T. */
- #define MATCH_IF(T) if (LOOKING_AT (T)) MATCH (); else ((void) 0)
- /* Skip to matching token if current token is T. */
- #define SKIP_MATCHING_IF(T) \
- if (LOOKING_AT (T)) skip_matching (); else ((void) 0)
- /* Skip forward until a given token TOKEN or YYEOF is seen and return
- the current lookahead token after skipping. */
- int
- skip_to (token)
- int token;
- {
- while (!LOOKING_AT2 (YYEOF, token))
- MATCH ();
- return tk;
- }
- /* Skip over pairs of tokens (parentheses, square brackets,
- angle brackets, curly brackets) matching the current lookahead. */
- void
- skip_matching ()
- {
- int open, close, n;
- switch (open = LA1)
- {
- case '{':
- close = '}';
- break;
- case '(':
- close = ')';
- break;
- case '<':
- close = '>';
- break;
- case '[':
- close = ']';
- break;
- default:
- abort ();
- }
- for (n = 0;;)
- {
- if (LOOKING_AT (open))
- ++n;
- else if (LOOKING_AT (close))
- --n;
- else if (LOOKING_AT (YYEOF))
- break;
- MATCH ();
- if (n == 0)
- break;
- }
- }
- void
- skip_initializer ()
- {
- for (;;)
- {
- switch (LA1)
- {
- case ';':
- case ',':
- case YYEOF:
- return;
- case '{':
- case '[':
- case '(':
- skip_matching ();
- break;
- default:
- MATCH ();
- break;
- }
- }
- }
- /* Build qualified namespace alias (A::B::c) and return it. */
- struct link *
- match_qualified_namespace_alias ()
- {
- struct link *head = NULL;
- struct link *cur = NULL;
- struct link *tmp = NULL;
- for (;;)
- {
- MATCH ();
- switch (LA1)
- {
- case IDENT:
- tmp = (struct link *) xmalloc (sizeof *cur);
- tmp->sym = find_namespace (yytext, cur);
- tmp->next = NULL;
- if (head)
- {
- cur = cur->next = tmp;
- }
- else
- {
- head = cur = tmp;
- }
- break;
- case DCOLON:
- /* Just skip */
- break;
- default:
- return head;
- break;
- }
- }
- }
- /* Re-initialize the parser by resetting the lookahead token. */
- void
- re_init_parser ()
- {
- tk = -1;
- }
- /* Parse a parameter list, including the const-specifier,
- pure-specifier, and throw-list that may follow a parameter list.
- Return in FLAGS what was seen following the parameter list.
- Returns a hash code for the parameter types. This value is used to
- distinguish between overloaded functions. */
- unsigned
- parm_list (flags)
- int *flags;
- {
- unsigned hash = 0;
- int type_seen = 0;
- while (!LOOKING_AT2 (YYEOF, ')'))
- {
- switch (LA1)
- {
- /* Skip over grouping parens or parameter lists in parameter
- declarations. */
- case '(':
- skip_matching ();
- break;
- /* Next parameter. */
- case ',':
- MATCH ();
- type_seen = 0;
- break;
- /* Ignore the scope part of types, if any. This is because
- some types need scopes when defined outside of a class body,
- and don't need them inside the class body. This means that
- we have to look for the last IDENT in a sequence of
- IDENT::IDENT::... */
- case IDENT:
- if (!type_seen)
- {
- char *last_id;
- unsigned ident_type_hash = 0;
- parse_qualified_param_ident_or_type (&last_id);
- if (last_id)
- {
- /* LAST_ID null means something like `X::*'. */
- for (; *last_id; ++last_id)
- ident_type_hash = (ident_type_hash << 1) ^ *last_id;
- hash = (hash << 1) ^ ident_type_hash;
- type_seen = 1;
- }
- }
- else
- MATCH ();
- break;
- case VOID:
- /* This distinction is made to make `func (void)' equivalent
- to `func ()'. */
- type_seen = 1;
- MATCH ();
- if (!LOOKING_AT (')'))
- hash = (hash << 1) ^ VOID;
- break;
- case BOOL: case CHAR: case CLASS: case CONST:
- case DOUBLE: case ENUM: case FLOAT: case INT:
- case LONG: case SHORT: case SIGNED: case STRUCT:
- case UNION: case UNSIGNED: case VOLATILE: case WCHAR:
- case ELLIPSIS:
- type_seen = 1;
- hash = (hash << 1) ^ LA1;
- MATCH ();
- break;
- case '*': case '&': case '[': case ']':
- hash = (hash << 1) ^ LA1;
- MATCH ();
- break;
- default:
- MATCH ();
- break;
- }
- }
- if (LOOKING_AT (')'))
- {
- MATCH ();
- if (LOOKING_AT (CONST))
- {
- /* We can overload the same function on `const' */
- hash = (hash << 1) ^ CONST;
- SET_FLAG (*flags, F_CONST);
- MATCH ();
- }
- if (LOOKING_AT (THROW))
- {
- MATCH ();
- SKIP_MATCHING_IF ('(');
- SET_FLAG (*flags, F_THROW);
- }
- if (LOOKING_AT ('='))
- {
- MATCH ();
- if (LOOKING_AT (CINT) && yyival == 0)
- {
- MATCH ();
- SET_FLAG (*flags, F_PURE);
- }
- }
- }
- return hash;
- }
- /* Print position info to stdout. */
- void
- print_info ()
- {
- if (info_position >= 0 && BUFFER_POS () <= info_position)
- if (info_cls)
- printf ("(\"%s\" \"%s\" \"%s\" %d)\n",
- info_cls->name, sym_scope (info_cls),
- info_member->name, info_where);
- }
- /* Parse a member declaration within the class body of CLS. VIS is
- the access specifier for the member (private, protected,
- public). */
- void
- member (cls, vis)
- struct sym *cls;
- int vis;
- {
- char *id = NULL;
- int sc = SC_MEMBER;
- char *regexp = NULL;
- int pos;
- int is_constructor;
- int anonymous = 0;
- int flags = 0;
- int class_tag;
- int type_seen = 0;
- int paren_seen = 0;
- unsigned hash = 0;
- int tilde = 0;
- while (!LOOKING_AT4 (';', '{', '}', YYEOF))
- {
- switch (LA1)
- {
- default:
- MATCH ();
- break;
- /* A function or class may follow. */
- case TEMPLATE:
- MATCH();
- SET_FLAG (flags, F_TEMPLATE);
- /* Skip over template argument list */
- SKIP_MATCHING_IF ('<');
- break;
- case EXPLICIT:
- SET_FLAG (flags, F_EXPLICIT);
- goto typeseen;
- case MUTABLE:
- SET_FLAG (flags, F_MUTABLE);
- goto typeseen;
- case T_INLINE:
- SET_FLAG (flags, F_INLINE);
- goto typeseen;
- case VIRTUAL:
- SET_FLAG (flags, F_VIRTUAL);
- goto typeseen;
- case '[':
- skip_matching ();
- break;
- case ENUM:
- sc = SC_TYPE;
- goto typeseen;
- case TYPEDEF:
- sc = SC_TYPE;
- goto typeseen;
- case FRIEND:
- sc = SC_FRIEND;
- goto typeseen;
- case STATIC:
- sc = SC_STATIC;
- goto typeseen;
- case '~':
- tilde = 1;
- MATCH ();
- break;
- case IDENT:
- /* Remember IDENTS seen so far. Among these will be the member
- name. */
- id = (char *) xrealloc (id, strlen (yytext) + 2);
- if (tilde)
- {
- *id = '~';
- strcpy (id + 1, yytext);
- }
- else
- strcpy (id, yytext);
- MATCH ();
- break;
- case OPERATOR:
- {
- char *s = operator_name (&sc);
- id = (char *) xrealloc (id, strlen (s) + 1);
- strcpy (id, s);
- }
- break;
- case '(':
- /* Most probably the beginning of a parameter list. */
- MATCH ();
- paren_seen = 1;
- if (id && cls)
- {
- if (!(is_constructor = streq (id, cls->name)))
- regexp = matching_regexp ();
- }
- else
- is_constructor = 0;
- pos = BUFFER_POS ();
- hash = parm_list (&flags);
- if (is_constructor)
- regexp = matching_regexp ();
- if (id && cls != NULL)
- add_member_decl (cls, id, regexp, pos, hash, 0, sc, vis, flags);
- while (!LOOKING_AT3 (';', '{', YYEOF))
- MATCH ();
- if (LOOKING_AT ('{') && id && cls)
- add_member_defn (cls, id, regexp, pos, hash, 0, sc, flags);
- free (id);
- id = NULL;
- sc = SC_MEMBER;
- break;
- case STRUCT: case UNION: case CLASS:
- /* Nested class */
- class_tag = LA1;
- type_seen = 1;
- MATCH ();
- anonymous = 1;
- /* More than one ident here to allow for MS-DOS specialties
- like `_export class' etc. The last IDENT seen counts
- as the class name. */
- while (!LOOKING_AT4 (YYEOF, ';', ':', '{'))
- {
- if (LOOKING_AT (IDENT))
- anonymous = 0;
- MATCH ();
- }
- if (LOOKING_AT2 (':', '{'))
- class_definition (anonymous ? NULL : cls, class_tag, flags, 1);
- else
- skip_to (';');
- break;
- case INT: case CHAR: case LONG: case UNSIGNED:
- case SIGNED: case CONST: case DOUBLE: case VOID:
- case SHORT: case VOLATILE: case BOOL: case WCHAR:
- case TYPENAME:
- typeseen:
- type_seen = 1;
- MATCH ();
- break;
- }
- }
- if (LOOKING_AT (';'))
- {
- /* The end of a member variable, a friend declaration or an access
- declaration. We don't want to add friend classes as members. */
- if (id && sc != SC_FRIEND && cls)
- {
- regexp = matching_regexp ();
- pos = BUFFER_POS ();
- if (cls != NULL)
- {
- if (type_seen || !paren_seen)
- add_member_decl (cls, id, regexp, pos, 0, 1, sc, vis, 0);
- else
- add_member_decl (cls, id, regexp, pos, hash, 0, sc, vis, 0);
- }
- }
- MATCH ();
- print_info ();
- }
- else if (LOOKING_AT ('{'))
- {
- /* A named enum. */
- if (sc == SC_TYPE && id && cls)
- {
- regexp = matching_regexp ();
- pos = BUFFER_POS ();
- if (cls != NULL)
- {
- add_member_decl (cls, id, regexp, pos, 0, 1, sc, vis, 0);
- add_member_defn (cls, id, regexp, pos, 0, 1, sc, 0);
- }
- }
- skip_matching ();
- print_info ();
- }
- free (id);
- }
- /* Parse the body of class CLS. TAG is the tag of the class (struct,
- union, class). */
- void
- class_body (cls, tag)
- struct sym *cls;
- int tag;
- {
- int vis = tag == CLASS ? PRIVATE : PUBLIC;
- int temp;
- while (!LOOKING_AT2 (YYEOF, '}'))
- {
- switch (LA1)
- {
- case PRIVATE: case PROTECTED: case PUBLIC:
- temp = LA1;
- MATCH ();
- if (LOOKING_AT (':'))
- {
- vis = temp;
- MATCH ();
- }
- else
- {
- /* Probably conditional compilation for inheritance list.
- We don't known whether there comes more of this.
- This is only a crude fix that works most of the time. */
- do
- {
- MATCH ();
- }
- while (LOOKING_AT2 (IDENT, ',')
- || LOOKING_AT3 (PUBLIC, PROTECTED, PRIVATE));
- }
- break;
- case TYPENAME:
- case USING:
- skip_to (';');
- break;
- /* Try to synchronize */
- case CHAR: case CLASS: case CONST:
- case DOUBLE: case ENUM: case FLOAT: case INT:
- case LONG: case SHORT: case SIGNED: case STRUCT:
- case UNION: case UNSIGNED: case VOID: case VOLATILE:
- case TYPEDEF: case STATIC: case T_INLINE: case FRIEND:
- case VIRTUAL: case TEMPLATE: case IDENT: case '~':
- case BOOL: case WCHAR: case EXPLICIT: case MUTABLE:
- member (cls, vis);
- break;
- default:
- MATCH ();
- break;
- }
- }
- }
- /* Parse a qualified identifier. Current lookahead is IDENT. A
- qualified ident has the form `X<..>::Y<...>::T<...>. Returns a
- symbol for that class. */
- struct sym *
- parse_classname ()
- {
- struct sym *last_class = NULL;
- while (LOOKING_AT (IDENT))
- {
- last_class = add_sym (yytext, last_class);
- MATCH ();
- if (LOOKING_AT ('<'))
- {
- skip_matching ();
- SET_FLAG (last_class->flags, F_TEMPLATE);
- }
- if (!LOOKING_AT (DCOLON))
- break;
- MATCH ();
- }
- return last_class;
- }
- /* Parse an operator name. Add the `static' flag to *SC if an
- implicitly static operator has been parsed. Value is a pointer to
- a static buffer holding the constructed operator name string. */
- char *
- operator_name (sc)
- int *sc;
- {
- static int id_size = 0;
- static char *id = NULL;
- char *s;
- int len;
- MATCH ();
- if (LOOKING_AT2 (NEW, DELETE))
- {
- /* `new' and `delete' are implicitly static. */
- if (*sc != SC_FRIEND)
- *sc = SC_STATIC;
- s = token_string (LA1);
- MATCH ();
- len = strlen (s) + 10;
- if (len > id_size)
- {
- int new_size = max (len, 2 * id_size);
- id = (char *) xrealloc (id, new_size);
- id_size = new_size;
- }
- strcpy (id, s);
- /* Vector new or delete? */
- if (LOOKING_AT ('['))
- {
- strcat (id, "[");
- MATCH ();
- if (LOOKING_AT (']'))
- {
- strcat (id, "]");
- MATCH ();
- }
- }
- }
- else
- {
- int tokens_matched = 0;
- len = 20;
- if (len > id_size)
- {
- int new_size = max (len, 2 * id_size);
- id = (char *) xrealloc (id, new_size);
- id_size = new_size;
- }
- strcpy (id, "operator");
- /* Beware access declarations of the form "X::f;" Beware of
- `operator () ()'. Yet another difficulty is found in
- GCC 2.95's STL: `operator == __STL_NULL_TMPL_ARGS (...'. */
- while (!(LOOKING_AT ('(') && tokens_matched)
- && !LOOKING_AT2 (';', YYEOF))
- {
- s = token_string (LA1);
- len += strlen (s) + 2;
- if (len > id_size)
- {
- int new_size = max (len, 2 * id_size);
- id = (char *) xrealloc (id, new_size);
- id_size = new_size;
- }
- if (*s != ')' && *s != ']')
- strcat (id, " ");
- strcat (id, s);
- MATCH ();
- /* If this is a simple operator like `+', stop now. */
- if (!isalpha ((unsigned char) *s) && *s != '(' && *s != '[')
- break;
- ++tokens_matched;
- }
- }
- return id;
- }
- /* This one consumes the last IDENT of a qualified member name like
- `X::Y::z'. This IDENT is returned in LAST_ID. Value is the
- symbol structure for the ident. */
- struct sym *
- parse_qualified_ident_or_type (last_id)
- char **last_id;
- {
- struct sym *cls = NULL;
- char *id = NULL;
- size_t id_size = 0;
- int enter = 0;
- while (LOOKING_AT (IDENT))
- {
- int len = strlen (yytext) + 1;
- if (len > id_size)
- {
- id = (char *) xrealloc (id, len);
- id_size = len;
- }
- strcpy (id, yytext);
- *last_id = id;
- MATCH ();
- SKIP_MATCHING_IF ('<');
- if (LOOKING_AT (DCOLON))
- {
- struct sym *pcn = NULL;
- struct link *pna = check_namespace_alias (id);
- if (pna)
- {
- do
- {
- enter_namespace (pna->sym->name);
- enter++;
- pna = pna->next;
- }
- while (pna);
- }
- else if ((pcn = check_namespace (id, current_namespace)))
- {
- enter_namespace (pcn->name);
- enter++;
- }
- else
- cls = add_sym (id, cls);
- *last_id = NULL;
- free (id);
- id = NULL;
- id_size = 0;
- MATCH ();
- }
- else
- break;
- }
- while (enter--)
- leave_namespace();
- return cls;
- }
- /* This one consumes the last IDENT of a qualified member name like
- `X::Y::z'. This IDENT is returned in LAST_ID. Value is the
- symbol structure for the ident. */
- void
- parse_qualified_param_ident_or_type (last_id)
- char **last_id;
- {
- struct sym *cls = NULL;
- static char *id = NULL;
- static int id_size = 0;
- while (LOOKING_AT (IDENT))
- {
- int len = strlen (yytext) + 1;
- if (len > id_size)
- {
- id = (char *) xrealloc (id, len);
- id_size = len;
- }
- strcpy (id, yytext);
- *last_id = id;
- MATCH ();
- SKIP_MATCHING_IF ('<');
- if (LOOKING_AT (DCOLON))
- {
- cls = add_sym (id, cls);
- *last_id = NULL;
- MATCH ();
- }
- else
- break;
- }
- }
- /* Parse a class definition.
- CONTAINING is the class containing the class being parsed or null.
- This may also be null if NESTED != 0 if the containing class is
- anonymous. TAG is the tag of the class (struct, union, class).
- NESTED is non-zero if we are parsing a nested class.
- Current lookahead is the class name. */
- void
- class_definition (containing, tag, flags, nested)
- struct sym *containing;
- int tag;
- int flags;
- int nested;
- {
- struct sym *current;
- struct sym *base_class;
- /* Set CURRENT to null if no entry has to be made for the class
- parsed. This is the case for certain command line flag
- settings. */
- if ((tag != CLASS && !f_structs) || (nested && !f_nested_classes))
- current = NULL;
- else
- {
- current = add_sym (yytext, containing);
- current->pos = BUFFER_POS ();
- current->regexp = matching_regexp ();
- current->filename = filename;
- current->flags = flags;
- }
- /* If at ':', base class list follows. */
- if (LOOKING_AT (':'))
- {
- int done = 0;
- MATCH ();
- while (!done)
- {
- switch (LA1)
- {
- case VIRTUAL: case PUBLIC: case PROTECTED: case PRIVATE:
- MATCH ();
- break;
- case IDENT:
- base_class = parse_classname ();
- if (base_class && current && base_class != current)
- add_link (base_class, current);
- break;
- /* The `,' between base classes or the end of the base
- class list. Add the previously found base class.
- It's done this way to skip over sequences of
- `A::B::C' until we reach the end.
- FIXME: it is now possible to handle `class X : public B::X'
- because we have enough information. */
- case ',':
- MATCH ();
- break;
- default:
- /* A syntax error, possibly due to preprocessor constructs
- like
- #ifdef SOMETHING
- class A : public B
- #else
- class A : private B.
- MATCH until we see something like `;' or `{'. */
- while (!LOOKING_AT3 (';', YYEOF, '{'))
- MATCH ();
- done = 1;
- case '{':
- done = 1;
- break;
- }
- }
- }
- /* Parse the class body if there is one. */
- if (LOOKING_AT ('{'))
- {
- if (tag != CLASS && !f_structs)
- skip_matching ();
- else
- {
- MATCH ();
- class_body (current, tag);
- if (LOOKING_AT ('}'))
- {
- MATCH ();
- if (LOOKING_AT (';') && !nested)
- MATCH ();
- }
- }
- }
- }
- /* Add to class *CLS information for the declaration of variable or
- type *ID. If *CLS is null, this means a global declaration. SC is
- the storage class of *ID. FLAGS is a bit set giving additional
- information about the member (see the F_* defines). */
- void
- add_declarator (cls, id, flags, sc)
- struct sym **cls;
- char **id;
- int flags, sc;
- {
- if (LOOKING_AT2 (';', ','))
- {
- /* The end of a member variable or of an access declaration
- `X::f'. To distinguish between them we have to know whether
- type information has been seen. */
- if (*id)
- {
- char *regexp = matching_regexp ();
- int pos = BUFFER_POS ();
- if (*cls)
- add_member_defn (*cls, *id, regexp, pos, 0, 1, SC_UNKNOWN, flags);
- else
- add_global_defn (*id, regexp, pos, 0, 1, sc, flags);
- }
- MATCH ();
- print_info ();
- }
- else if (LOOKING_AT ('{'))
- {
- if (sc == SC_TYPE && *id)
- {
- /* A named enumeration. */
- char *regexp = matching_regexp ();
- int pos = BUFFER_POS ();
- add_global_defn (*id, regexp, pos, 0, 1, sc, flags);
- }
- skip_matching ();
- print_info ();
- }
- free (*id);
- *id = NULL;
- *cls = NULL;
- }
- /* Parse a declaration. */
- void
- declaration (flags)
- int flags;
- {
- char *id = NULL;
- struct sym *cls = NULL;
- char *regexp = NULL;
- int pos = 0;
- unsigned hash = 0;
- int is_constructor;
- int sc = 0;
- while (!LOOKING_AT3 (';', '{', YYEOF))
- {
- switch (LA1)
- {
- default:
- MATCH ();
- break;
- case '[':
- skip_matching ();
- break;
- case ENUM:
- case TYPEDEF:
- sc = SC_TYPE;
- MATCH ();
- break;
- case STATIC:
- sc = SC_STATIC;
- MATCH ();
- break;
- case INT: case CHAR: case LONG: case UNSIGNED:
- case SIGNED: case CONST: case DOUBLE: case VOID:
- case SHORT: case VOLATILE: case BOOL: case WCHAR:
- MATCH ();
- break;
- case CLASS: case STRUCT: case UNION:
- /* This is for the case `STARTWRAP class X : ...' or
- `declare (X, Y)\n class A : ...'. */
- if (id)
- {
- free (id);
- return;
- }
- case '=':
- /* Assumed to be the start of an initialization in this
- context. */
- skip_initializer ();
- break;
- case ',':
- add_declarator (&cls, &id, flags, sc);
- break;
- case OPERATOR:
- {
- char *s = operator_name (&sc);
- id = (char *) xrealloc (id, strlen (s) + 1);
- strcpy (id, s);
- }
- break;
- case T_INLINE:
- SET_FLAG (flags, F_INLINE);
- MATCH ();
- break;
- case '~':
- MATCH ();
- if (LOOKING_AT (IDENT))
- {
- id = (char *) xrealloc (id, strlen (yytext) + 2);
- *id = '~';
- strcpy (id + 1, yytext);
- MATCH ();
- }
- break;
- case IDENT:
- cls = parse_qualified_ident_or_type (&id);
- break;
- case '(':
- /* Most probably the beginning of a parameter list. */
- if (cls)
- {
- MATCH ();
- if (id && cls)
- {
- if (!(is_constructor = streq (id, cls->name)))
- regexp = matching_regexp ();
- }
- else
- is_constructor = 0;
- pos = BUFFER_POS ();
- hash = parm_list (&flags);
- if (is_constructor)
- regexp = matching_regexp ();
- if (id && cls)
- add_member_defn (cls, id, regexp, pos, hash, 0,
- SC_UNKNOWN, flags);
- }
- else
- {
- /* This may be a C functions, but also a macro
- call of the form `declare (A, B)' --- such macros
- can be found in some class libraries. */
- MATCH ();
- if (id)
- {
- regexp = matching_regexp ();
- pos = BUFFER_POS ();
- hash = parm_list (&flags);
- add_global_decl (id, regexp, pos, hash, 0, sc, flags);
- }
- /* This is for the case that the function really is
- a macro with no `;' following it. If a CLASS directly
- follows, we would miss it otherwise. */
- if (LOOKING_AT3 (CLASS, STRUCT, UNION))
- return;
- }
- while (!LOOKING_AT3 (';', '{', YYEOF))
- MATCH ();
- if (!cls && id && LOOKING_AT ('{'))
- add_global_defn (id, regexp, pos, hash, 0, sc, flags);
- free (id);
- id = NULL;
- break;
- }
- }
- add_declarator (&cls, &id, flags, sc);
- }
- /* Parse a list of top-level declarations/definitions. START_FLAGS
- says in which context we are parsing. If it is F_EXTERNC, we are
- parsing in an `extern "C"' block. Value is 1 if EOF is reached, 0
- otherwise. */
- int
- globals (start_flags)
- int start_flags;
- {
- int anonymous;
- int class_tk;
- int flags = start_flags;
- for (;;)
- {
- char *prev_in = in;
- switch (LA1)
- {
- case NAMESPACE:
- {
- MATCH ();
- if (LOOKING_AT (IDENT))
- {
- char *namespace_name = xstrdup (yytext);
- MATCH ();
- if (LOOKING_AT ('='))
- {
- struct link *qna = match_qualified_namespace_alias ();
- if (qna)
- register_namespace_alias (namespace_name, qna);
- if (skip_to (';') == ';')
- MATCH ();
- }
- else if (LOOKING_AT ('{'))
- {
- MATCH ();
- enter_namespace (namespace_name);
- globals (0);
- leave_namespace ();
- MATCH_IF ('}');
- }
- free (namespace_name);
- }
- }
- break;
- case EXTERN:
- MATCH ();
- if (LOOKING_AT (CSTRING) && *string_start == 'C'
- && *(string_start + 1) == '"')
- {
- /* This is `extern "C"'. */
- MATCH ();
- if (LOOKING_AT ('{'))
- {
- MATCH ();
- globals (F_EXTERNC);
- MATCH_IF ('}');
- }
- else
- SET_FLAG (flags, F_EXTERNC);
- }
- break;
- case TEMPLATE:
- MATCH ();
- SKIP_MATCHING_IF ('<');
- SET_FLAG (flags, F_TEMPLATE);
- break;
- case CLASS: case STRUCT: case UNION:
- class_tk = LA1;
- MATCH ();
- anonymous = 1;
- /* More than one ident here to allow for MS-DOS and OS/2
- specialties like `far', `_Export' etc. Some C++ libs
- have constructs like `_OS_DLLIMPORT(_OS_CLIENT)' in front
- of the class name. */
- while (!LOOKING_AT4 (YYEOF, ';', ':', '{'))
- {
- if (LOOKING_AT (IDENT))
- anonymous = 0;
- MATCH ();
- }
- /* Don't add anonymous unions. */
- if (LOOKING_AT2 (':', '{') && !anonymous)
- class_definition (NULL, class_tk, flags, 0);
- else
- {
- if (skip_to (';') == ';')
- MATCH ();
- }
- flags = start_flags;
- break;
- case YYEOF:
- return 1;
- case '}':
- return 0;
- default:
- declaration (flags);
- flags = start_flags;
- break;
- }
- if (prev_in == in)
- yyerror ("parse error", NULL);
- }
- }
- /* Parse the current input file. */
- void
- yyparse ()
- {
- while (globals (0) == 0)
- MATCH_IF ('}');
- }
- /***********************************************************************
- Main Program
- ***********************************************************************/
- /* Add the list of paths PATH_LIST to the current search path for
- input files. */
- void
- add_search_path (path_list)
- char *path_list;
- {
- while (*path_list)
- {
- char *start = path_list;
- struct search_path *p;
- while (*path_list && *path_list != PATH_LIST_SEPARATOR)
- ++path_list;
- p = (struct search_path *) xmalloc (sizeof *p);
- p->path = (char *) xmalloc (path_list - start + 1);
- memcpy (p->path, start, path_list - start);
- p->path[path_list - start] = '\0';
- p->next = NULL;
- if (search_path_tail)
- {
- search_path_tail->next = p;
- search_path_tail = p;
- }
- else
- search_path = search_path_tail = p;
- while (*path_list == PATH_LIST_SEPARATOR)
- ++path_list;
- }
- }
- /* Open FILE and return a file handle for it, or -1 if FILE cannot be
- opened. Try to find FILE in search_path first, then try the
- unchanged file name. */
- FILE *
- open_file (file)
- char *file;
- {
- FILE *fp = NULL;
- static char *buffer;
- static int buffer_size;
- struct search_path *path;
- int flen = strlen (file) + 1; /* +1 for the slash */
- filename = xstrdup (file);
- for (path = search_path; path && fp == NULL; path = path->next)
- {
- int len = strlen (path->path) + flen;
- if (len + 1 >= buffer_size)
- {
- buffer_size = max (len + 1, 2 * buffer_size);
- buffer = (char *) xrealloc (buffer, buffer_size);
- }
- strcpy (buffer, path->path);
- strcat (buffer, "/");
- strcat (buffer, file);
- fp = fopen (buffer, "r");
- }
- /* Try the original file name. */
- if (fp == NULL)
- fp = fopen (file, "r");
- if (fp == NULL)
- yyerror ("cannot open", NULL);
- return fp;
- }
- /* Display usage information and exit program. */
- #define USAGE "\
- Usage: ebrowse [options] {files}\n\
- \n\
- -a, --append append output to existing file\n\
- -f, --files=FILES read input file names from FILE\n\
- -I, --search-path=LIST set search path for input files\n\
- -m, --min-regexp-length=N set minimum regexp length to N\n\
- -M, --max-regexp-length=N set maximum regexp length to N\n\
- -n, --no-nested-classes exclude nested classes\n\
- -o, --output-file=FILE set output file name to FILE\n\
- -p, --position-info print info about position in file\n\
- -s, --no-structs-or-unions don't record structs or unions\n\
- -v, --verbose be verbose\n\
- -V, --very-verbose be very verbose\n\
- -x, --no-regexps don't record regular expressions\n\
- --help display this help\n\
- --version display version info\n\
- "
- void
- usage (error)
- int error;
- {
- puts (USAGE);
- exit (error ? EXIT_FAILURE : EXIT_SUCCESS);
- }
- /* Display version and copyright info. The VERSION macro is set
- from the Makefile and contains the Emacs version. */
- #ifndef VERSION
- # define VERSION "21"
- #endif
- void
- version ()
- {
- /* Makes it easier to update automatically. */
- char emacs_copyright[] = "Copyright (C) 2010 Free Software Foundation, Inc.";
- printf ("ebrowse %s\n", VERSION);
- puts (emacs_copyright);
- puts ("This program is distributed under the same terms as Emacs.");
- exit (EXIT_SUCCESS);
- }
- /* Parse one input file FILE, adding classes and members to the symbol
- table. */
- void
- process_file (file)
- char *file;
- {
- FILE *fp;
- fp = open_file (file);
- if (fp)
- {
- int nread, nbytes;
- /* Give a progress indication if needed. */
- if (f_very_verbose)
- {
- puts (filename);
- fflush (stdout);
- }
- else if (f_verbose)
- {
- putchar ('.');
- fflush (stdout);
- }
- /* Read file to inbuffer. */
- for (nread = 0;;)
- {
- if (nread + READ_CHUNK_SIZE >= inbuffer_size)
- {
- inbuffer_size = nread + READ_CHUNK_SIZE + 1;
- inbuffer = (char *) xrealloc (inbuffer, inbuffer_size);
- }
- nbytes = fread (inbuffer + nread, 1, READ_CHUNK_SIZE, fp);
- if (nbytes <= 0)
- break;
- nread += nbytes;
- }
- if (nread < 0)
- nread = 0;
- inbuffer[nread] = '\0';
- /* Reinitialize scanner and parser for the new input file. */
- re_init_scanner ();
- re_init_parser ();
- /* Parse it and close the file. */
- yyparse ();
- fclose (fp);
- }
- }
- /* Read a line from stream FP and return a pointer to a static buffer
- containing its contents without the terminating newline. Value
- is null when EOF is reached. */
- char *
- read_line (fp)
- FILE *fp;
- {
- static char *buffer;
- static int buffer_size;
- int i = 0, c;
- while ((c = getc (fp)) != EOF && c != '\n')
- {
- if (i >= buffer_size)
- {
- buffer_size = max (100, buffer_size * 2);
- buffer = (char *) xrealloc (buffer, buffer_size);
- }
- buffer[i++] = c;
- }
- if (c == EOF && i == 0)
- return NULL;
- if (i == buffer_size)
- {
- buffer_size = max (100, buffer_size * 2);
- buffer = (char *) xrealloc (buffer, buffer_size);
- }
- buffer[i] = '\0';
- if (i > 0 && buffer[i - 1] == '\r')
- buffer[i - 1] = '\0';
- return buffer;
- }
- /* Main entry point. */
- int
- main (argc, argv)
- int argc;
- char **argv;
- {
- int i;
- int any_inputfiles = 0;
- static char *out_filename = DEFAULT_OUTFILE;
- static char **input_filenames = NULL;
- static int input_filenames_size = 0;
- static int n_input_files;
- filename = "command line";
- yyout = stdout;
- while ((i = getopt_long (argc, argv, "af:I:m:M:no:p:svVx",
- options, NULL)) != EOF)
- {
- switch (i)
- {
- /* Experimental. */
- case 'p':
- info_position = atoi (optarg);
- break;
- case 'n':
- f_nested_classes = 0;
- break;
- case 'x':
- f_regexps = 0;
- break;
- /* Add the name of a file containing more input files. */
- case 'f':
- if (n_input_files == input_filenames_size)
- {
- input_filenames_size = max (10, 2 * input_filenames_size);
- input_filenames = (char **) xrealloc ((void *)input_filenames,
- input_filenames_size);
- }
- input_filenames[n_input_files++] = xstrdup (optarg);
- break;
- /* Append new output to output file instead of truncating it. */
- case 'a':
- f_append = 1;
- break;
- /* Include structs in the output */
- case 's':
- f_structs = 0;
- break;
- /* Be verbose (give a progress indication). */
- case 'v':
- f_verbose = 1;
- break;
- /* Be very verbose (print file names as they are processed). */
- case 'V':
- f_verbose = 1;
- f_very_verbose = 1;
- break;
- /* Change the name of the output file. */
- case 'o':
- out_filename = optarg;
- break;
- /* Set minimum length for regular expression strings
- when recorded in the output file. */
- case 'm':
- min_regexp = atoi (optarg);
- break;
- /* Set maximum length for regular expression strings
- when recorded in the output file. */
- case 'M':
- max_regexp = atoi (optarg);
- break;
- /* Add to search path. */
- case 'I':
- add_search_path (optarg);
- break;
- /* Display help */
- case -2:
- usage (0);
- break;
- case -3:
- version ();
- break;
- }
- }
- /* Call init_scanner after command line flags have been processed to be
- able to add keywords depending on command line (not yet
- implemented). */
- init_scanner ();
- init_sym ();
- /* Open output file */
- if (*out_filename)
- {
- if (f_append)
- {
- /* Check that the file to append to exists, and is not
- empty. More specifically, it should be a valid file
- produced by a previous run of ebrowse, but that's too
- difficult to check. */
- FILE *fp;
- int rc;
- fp = fopen (out_filename, "r");
- if (fp == NULL)
- {
- yyerror ("file `%s' must exist for --append", out_filename);
- exit (EXIT_FAILURE);
- }
- rc = fseek (fp, 0, SEEK_END);
- if (rc == -1)
- {
- yyerror ("error seeking in file `%s'", out_filename);
- exit (EXIT_FAILURE);
- }
- rc = ftell (fp);
- if (rc == -1)
- {
- yyerror ("error getting size of file `%s'", out_filename);
- exit (EXIT_FAILURE);
- }
-
- else if (rc == 0)
- {
- yyerror ("file `%s' is empty", out_filename);
- /* It may be ok to use an empty file for appending.
- exit (EXIT_FAILURE); */
- }
- fclose (fp);
- }
- yyout = fopen (out_filename, f_append ? "a" : "w");
- if (yyout == NULL)
- {
- yyerror ("cannot open output file `%s'", out_filename);
- exit (EXIT_FAILURE);
- }
- }
- /* Process input files specified on the command line. */
- while (optind < argc)
- {
- process_file (argv[optind++]);
- any_inputfiles = 1;
- }
- /* Process files given on stdin if no files specified. */
- if (!any_inputfiles && n_input_files == 0)
- {
- char *file;
- while ((file = read_line (stdin)) != NULL)
- process_file (file);
- }
- else
- {
- /* Process files from `--files=FILE'. Every line in FILE names
- one input file to process. */
- for (i = 0; i < n_input_files; ++i)
- {
- FILE *fp = fopen (input_filenames[i], "r");
- if (fp == NULL)
- yyerror ("cannot open input file `%s'", input_filenames[i]);
- else
- {
- char *file;
- while ((file = read_line (fp)) != NULL)
- process_file (file);
- fclose (fp);
- }
- }
- }
- /* Write output file. */
- dump_roots (yyout);
- /* Close output file. */
- if (yyout != stdout)
- fclose (yyout);
- return EXIT_SUCCESS;
- }
- /* arch-tag: fc03b4bc-91a9-4c3d-b3b9-12a77fa86dd8
- (do not change this comment) */
- /* ebrowse.c ends here */
|