root/lib-src/ebrowse.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. streq
  2. filename_eq
  3. set_flag
  4. has_flag
  5. yyerror
  6. xmalloc
  7. xrealloc
  8. xstrdup
  9. init_sym
  10. add_sym
  11. add_link
  12. find_member
  13. add_member_decl
  14. add_member_defn
  15. add_define
  16. add_global_defn
  17. add_global_decl
  18. add_member
  19. mark_virtual
  20. mark_inherited_virtual
  21. make_namespace
  22. check_namespace
  23. find_namespace
  24. check_namespace_alias
  25. register_namespace_alias
  26. enter_namespace
  27. leave_namespace
  28. putstr
  29. ensure_scope_buffer_room
  30. sym_scope_1
  31. sym_scope
  32. dump_members
  33. dump_sym
  34. dump_tree
  35. dump_roots
  36. process_pp_line
  37. yylex
  38. matching_regexp
  39. token_string
  40. re_init_scanner
  41. insert_keyword
  42. init_scanner
  43. skip_to
  44. skip_matching
  45. skip_initializer
  46. match_qualified_namespace_alias
  47. re_init_parser
  48. parm_list
  49. print_info
  50. member
  51. class_body
  52. parse_classname
  53. operator_name
  54. parse_qualified_ident_or_type
  55. parse_qualified_param_ident_or_type
  56. class_definition
  57. add_declarator
  58. declaration
  59. globals
  60. yyparse
  61. add_search_path
  62. open_file
  63. usage
  64. version
  65. process_file
  66. read_line
  67. main

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

/* [<][>][^][v][top][bottom][index][help] */