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

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