home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / browser2.zip / lex.c < prev    next >
C/C++ Source or Header  |  1995-02-17  |  31KB  |  1,228 lines

  1. /* EMACS CLASS BROWSER FOR C++.
  2.    Copyright (C) 1993-95
  3.    Gerd Moellmann (mmann@ibm.net, CIS:100025,3303)
  4.  
  5.    $Id: lex.c,v 3.1 1995/02/17 18:20:24 mmann Exp $
  6.  
  7.    This file may be made part of GNU Emacs at the option of the FSF.
  8.  
  9.    This code is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY.  No author or distributor
  11.    accepts responsibility to anyone for the consequences of using it
  12.    or for whether it serves any particular purpose or works at all,
  13.    unless he says so in writing.  Refer to the GNU Emacs General Public
  14.    License for full details.
  15.  
  16.    Everyone is granted permission to copy, modify and redistribute
  17.    this code, but only under the conditions described in the
  18.    GNU Emacs General Public License.   A copy of this license is
  19.    supposed to have been given to you along with GNU Emacs so you
  20.    can know your rights and responsibilities.  It should be in a
  21.    file named COPYING.  Among other things, the copyright notice
  22.    and this notice must be preserved on all copies. */
  23.  
  24. #ifdef __IBMC__
  25. #include <io.h>
  26. #endif
  27. #include <fcntl.h>
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <stdarg.h>
  33. #include <string.h>
  34. #include <ctype.h>
  35. #include <assert.h>
  36. #include "br-rev.el"
  37. #include "lex.h"
  38.  
  39. #define USAGE "\
  40. EBROWSE v%s\n\
  41. %s\n\
  42. Usage: ebrowse [options] {files}\n\
  43. Options:\n\
  44. -a         append output\n\
  45. -e<file>    call from Emacs\n\
  46. -f        do not do expensive friends processing\n\
  47. -i<file>     read file names from file\n\
  48. -m#         set minimum regexp length\n\
  49. -M#         set maximum regexp length\n\
  50. -n        include nested classes\n\
  51. -o<file>    set output file name\n\
  52. -r<file>    write regular expressions to file\n\
  53. -s         don't record structs and unions\n\
  54. -v         be verbose\n\
  55. -V        be very verbose\n\
  56. -x         record regular expressions\n\
  57. "
  58.  
  59. #define MAX_STRING_LENGTH       1024
  60. #define HASH_SIZE               1001
  61.  
  62. char    yytext[MAX_STRING_LENGTH];
  63. char*   yytext_end = &yytext[MAX_STRING_LENGTH];
  64. int     yyin;
  65. FILE*   yyout;
  66. int    regexp_file;
  67. unsigned yyline;
  68. int     allow_cpp_comments = 1;
  69. long    long_val;
  70. char*   filename;
  71. char*    regexp_filename;
  72.  
  73. /* Three character class vectors. */
  74. char    is_ident[255];
  75. char    is_digit[255];
  76. char    is_white[255];
  77.  
  78. /* Commond line flags. */
  79. int     f_costly_friends = 1;
  80. int     f_append = 0;
  81. int     f_verbose = 0;
  82. int     f_very_verbose = 0;
  83. int     f_structs = 1;
  84. int     f_regexps = 0;
  85. int    f_emacs = 0;
  86. int    f_nested_classes = 0;
  87.  
  88. int     min_regexp = MIN_REGEXP;
  89. int     max_regexp = MAX_REGEXP;
  90.  
  91. unsigned carriage_returns;
  92. char* inbuffer;
  93. char* in;
  94.  
  95. struct kw
  96. {
  97.   char* name;
  98.   struct kw* next;
  99.   int tk;
  100. }
  101. * kw_hash_table[HASH_SIZE];
  102.  
  103. void
  104. yyerror (char* format, ...)
  105. {
  106.   va_list args;
  107.   va_start (args, format);
  108.   printf ("%s:%d: ", filename, yyline);
  109.   vprintf (format, args);
  110.   putchar ('\n');
  111.   va_end (args);
  112. }
  113.  
  114. #ifdef PROTOTYPES
  115. static void kw_insert (char* name, int tk);
  116. static struct kw* kw_lookup (char* name);
  117. static void re_init_lex (void);
  118. static void init_lex (void);
  119. static void usage (void);
  120. static void process_file (char* file);
  121. static void process_stdin (void);
  122. #ifdef __GNUC__
  123. extern char** glob_filename (char* path);
  124. #endif
  125. #else
  126. #ifdef __GNUC__
  127. extern char** glob_filename ();
  128. #endif
  129. #endif
  130.  
  131. static void
  132. kw_insert (name, tk)
  133.      char* name;
  134.      int tk;
  135. {
  136.   char* s;
  137.   unsigned h = 0;
  138.   struct kw* k = (struct kw*) xmalloc (sizeof *k);
  139.  
  140.   for (s = name; *s; ++s)
  141.     h = (h << 1) ^ *s;
  142.  
  143.   h %= HASH_SIZE;
  144.   k->name = name;
  145.   k->tk = tk;
  146.   k->next = kw_hash_table[h];
  147.   kw_hash_table[h] = k;
  148. }
  149.  
  150. static struct kw*
  151. kw_lookup (name)
  152.      char* name;
  153. {
  154.   char* s;
  155.   unsigned h = 0;
  156.   struct kw* k;
  157.  
  158.   for (s = name; *s; ++s)
  159.     h = (h << 1) ^ *s;
  160.  
  161.   h %= HASH_SIZE;
  162.  
  163.   for (k = kw_hash_table[h]; k; k = k->next)
  164.     if (!strcmp (k->name, name))
  165.       break;
  166.  
  167.   return k;
  168. }
  169.  
  170. static void
  171. re_init_lex ()
  172. {
  173.   in = inbuffer;
  174. #if MSDOS || OS2
  175.   carriage_returns = 0;
  176. #endif
  177.   yyline = 1;
  178. }
  179.  
  180. void
  181. init_lex ()
  182. {
  183.   int i;
  184.  
  185.   inbuffer = in = (char*) malloc (INBUFFER_SIZE+1);
  186.   yyline = 1;
  187.  
  188.   for (i = 0; i < sizeof is_ident; ++i)
  189.     {
  190.       if (i == '_' || isalnum (i))
  191.         is_ident[i] = 1;
  192.  
  193.       if (i >= '0' && i <= '9')
  194.         is_digit[i] = 1;
  195.  
  196.       if (i == ' ' || i == '\t' || i == '\f' || i == '\v')
  197.         is_white[i] = 1;
  198.     }
  199.  
  200.   kw_insert ("asm", ASM);
  201.   kw_insert ("auto", AUTO);
  202.   kw_insert ("break", BREAK);
  203.   kw_insert ("case", CASE);
  204.   kw_insert ("catch", CATCH);
  205.   kw_insert ("char", CHAR);
  206.   kw_insert ("class", CLASS);
  207.   kw_insert ("const", CONST);
  208.   kw_insert ("continue", CONTINUE);
  209.   kw_insert ("default", DEFAULT);
  210.   kw_insert ("delete", DELETE);
  211.   kw_insert ("do", DO);
  212.   kw_insert ("double", DOUBLE);
  213.   kw_insert ("else", ELSE);
  214.   kw_insert ("enum", ENUM);
  215.   kw_insert ("extern", EXTERN);
  216.   kw_insert ("float", FLOAT);
  217.   kw_insert ("for", FOR);
  218.   kw_insert ("friend", FRIEND);
  219.   kw_insert ("goto", GOTO);
  220.   kw_insert ("if", IF);
  221.   kw_insert ("inline", INLINE);
  222.   kw_insert ("int", INT);
  223.   kw_insert ("long", LONG);
  224.   kw_insert ("new", NEW);
  225.   kw_insert ("operator", OPERATOR);
  226.   kw_insert ("private", PRIVATE);
  227.   kw_insert ("protected", PROTECTED);
  228.   kw_insert ("public", PUBLIC);
  229.   kw_insert ("register", REGISTER);
  230.   kw_insert ("return", RETURN);
  231.   kw_insert ("short", SHORT);
  232.   kw_insert ("signed", SIGNED);
  233.   kw_insert ("sizeof", SIZEOF);
  234.   kw_insert ("static", STATIC);
  235.   kw_insert ("struct", STRUCT);
  236.   kw_insert ("switch", SWITCH);
  237.   kw_insert ("template", TEMPLATE);
  238.   kw_insert ("this", THIS);
  239.   kw_insert ("throw", THROW);
  240.   kw_insert ("try", TRY);
  241.   kw_insert ("typedef", TYPEDEF);
  242.   kw_insert ("union", UNION);
  243.   kw_insert ("unsigned", UNSIGNED);
  244.   kw_insert ("virtual", VIRTUAL);
  245.   kw_insert ("void", VOID);
  246.   kw_insert ("volatile", VOLATILE);
  247.   kw_insert ("while", WHILE);
  248. }
  249.  
  250. #define get(c)          (c = *in++)
  251. #define unget(c)        --in
  252. #undef EOF
  253. #define EOF             0
  254.  
  255. int
  256. yylex ()
  257. {
  258.   int c;
  259.   char end_char;
  260.   char* p;
  261.  
  262.   for (;;)
  263.     {
  264.       while (is_white[get (c)])
  265.         ;
  266.  
  267.       switch (c)
  268.         {
  269.         case '\n':
  270.           /* Newlines */
  271.           ++yyline;
  272.           break;
  273.  
  274.     case '\r':
  275. #if MSDOS || OS2
  276.       ++carriage_returns;
  277. #endif
  278.       break;
  279.  
  280.         case EOF:
  281.           /* End of file */
  282.           return 0;
  283.  
  284.         case '\\':
  285.           get (c);
  286. #if MSDOS || OS2
  287.       if (c == '\r')
  288.         {
  289.           get (c);
  290.           ++carriage_returns;
  291.         }
  292. #endif
  293.           break;
  294.  
  295.         case '"':
  296.         case '\'':
  297.           /* String and character constants */
  298.           p = yytext;
  299.           end_char = c;
  300.  
  301.           while (get (c) != EOF && c != end_char)
  302.             {
  303.               switch (c)
  304.                 {
  305.                 case '\\':
  306.                   /* Escape sequences. */
  307.                   if (get (c) == EOF)
  308.                     {
  309.                       if (end_char == '\'')
  310.                         yyerror ("EOF in character constant");
  311.                       else
  312.                         yyerror ("EOF in string constant");
  313.               goto end_string;
  314.                     }
  315.                   else switch (c)
  316.                     {
  317. #if MSDOS || OS2
  318.             case '\r':
  319.               get (c);
  320.               ++carriage_returns;
  321.               break;
  322. #endif
  323.  
  324.             case '\n':
  325.               break;
  326.                     case 'a':
  327.                       *p++ = '\a';
  328.                       break;
  329.                     case 'b':
  330.                       *p++ = '\b';
  331.                       break;
  332.                     case 'f':
  333.                       *p++ = '\f';
  334.                       break;
  335.                     case 'n':
  336.                       *p++ = '\n';
  337.                       break;
  338.                     case 'r':
  339.                       *p++ = '\r';
  340.                       break;
  341.                     case 't':
  342.                       *p++ = '\t';
  343.                       break;
  344.                     case 'v':
  345.                       *p++ = '\v';
  346.                       break;
  347.  
  348.                     case 'x':
  349.                       {
  350.                         /* Hexadecimal escape sequence. */
  351.                         int i, v;
  352.                         for (i = v = 0; i < 2; ++i)
  353.                           {
  354.                             get (c);
  355.  
  356.                             if (c >= '0' && c <= '7')
  357.                               v = 16 * v + c - '0';
  358.                             else if (c >= 'a' && c <= 'f')
  359.                               v = 16 * v + c - 'a' + 10;
  360.                             else if (c >= 'A' && c <= 'F')
  361.                               v = 16 * v + c - 'A' + 10;
  362.                             else
  363.                               {
  364.                                 unget (c);
  365.                                 break;
  366.                               }
  367.                           }
  368.                         *p = v;
  369.                       }
  370.                       break;
  371.  
  372.                     case '0':
  373.                       {
  374.                         /* Octal escape sequence. */
  375.                         int i, v;
  376.                         for (i = v = 0; i < 3; ++i)
  377.                           {
  378.                             get (c);
  379.  
  380.                             if (c >= '0' && c <= '7')
  381.                               v = 8 * v + c - '0';
  382.                             else
  383.                               {
  384.                                 unget (c);
  385.                                 break;
  386.                               }
  387.                           }
  388.                         *p = v;
  389.                       }
  390.                       break;
  391.  
  392.                     default:
  393.                       *p++ = c;
  394.                       break;
  395.                     }
  396.                   break;
  397.  
  398.                 case '\n':
  399.                   if (end_char == '\'')
  400.                     yyerror ("newline in character constant");
  401.                   else
  402.                     yyerror ("newline in string constant");
  403.                   ++yyline;
  404.           goto end_string;
  405.  
  406.                 default:
  407.                   *p++ = c;
  408.                   break;
  409.                 }
  410.             }
  411.  
  412.     end_string:
  413.           if (p > yytext_end)
  414.             {
  415.               yyerror ("string constant overflow");
  416.               exit (1);
  417.             }
  418.  
  419.           return end_char == '\'' ? CCHAR : CSTRING;
  420.  
  421.         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
  422.         case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
  423.         case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
  424.         case 'v': case 'w': case 'x': case 'y': case 'z':
  425.         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
  426.         case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
  427.         case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
  428.         case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_':
  429.           {
  430.             /* Identifier and keywords. */
  431.             unsigned hash;
  432.             struct kw* k;
  433.  
  434.             p = yytext;
  435.             *p++ = hash = c;
  436.  
  437.             while (is_ident[get (*p)])
  438.               hash = (hash << 1) ^ *p++;
  439.  
  440.             unget (*p);
  441.             *p = 0;
  442.  
  443.             for (k = kw_hash_table[hash % HASH_SIZE]; k; k = k->next)
  444.               if (!strcmp (k->name, yytext))
  445.                 return k->tk;
  446.  
  447.             return IDENT;
  448.           }
  449.  
  450.         case '/':
  451.           /* C and C++ comments, '/' and '/=' */
  452.           switch (get (c))
  453.             {
  454.             case '*':
  455.               while (get (c) != EOF)
  456.                 {
  457.                   switch (c)
  458.                     {
  459.                     case '*':
  460.                       if (get (c) == '/')
  461.                         goto comment_end;
  462.                       unget (c);
  463.                       break;
  464.                     case '\\':
  465.                       get (c);
  466.                       break;
  467.                     case '\n':
  468.                       ++yyline;
  469.                       break;
  470. #if MSDOS || OS2
  471.             case '\r':
  472.               ++carriage_returns;
  473.               break;
  474. #endif
  475.                     }
  476.                 }
  477.             comment_end:;
  478.               break;
  479.  
  480.             case '=':
  481.               return DIVASGN;
  482.  
  483.             case '/':
  484.               if (allow_cpp_comments)
  485.                 {
  486.                   while (get (c) != EOF && c != '\n')
  487.                     ;
  488.                   ++yyline;
  489.                   break;
  490.                 }
  491.  
  492.             default:
  493.               unget (c);
  494.               return '/';
  495.             }
  496.           break;
  497.  
  498.         case '+':
  499.           if (get (c) == '+')
  500.             return INC;
  501.           else if (c == '=')
  502.             return ADDASGN;
  503.           unget (c);
  504.           return '+';
  505.  
  506.         case '-':
  507.           switch (get (c))
  508.             {
  509.             case '-':
  510.               return DEC;
  511.             case '>':
  512.               if (get (c) == '*')
  513.                 return ARROWSTAR;
  514.               unget (c);
  515.               return ARROW;
  516.             case '=':
  517.               return SUBASGN;
  518.             }
  519.           unget (c);
  520.           return '-';
  521.  
  522.         case '*':
  523.           if (get (c) == '=')
  524.             return MULASGN;
  525.           unget (c);
  526.           return '*';
  527.  
  528.         case '%':
  529.           if (get (c) == '=')
  530.             return MODASGN;
  531.           unget (c);
  532.           return '%';
  533.  
  534.         case '|':
  535.           if (get (c) == '|')
  536.             return LOR;
  537.           else if (c == '=')
  538.             return ORASGN;
  539.           unget (c);
  540.           return '|';
  541.  
  542.         case '&':
  543.           if (get (c) == '&')
  544.             return LAND;
  545.           else if (c == '=')
  546.             return ANDASGN;
  547.           unget (c);
  548.           return '&';
  549.  
  550.         case '^':
  551.           if (get (c) == '=')
  552.             return XORASGN;
  553.           unget (c);
  554.           return '^';
  555.  
  556.         case '.':
  557.           if (get (c) == '*')
  558.             return POINTSTAR;
  559.           else if (c == '.')
  560.             {
  561.               if (get (c) != '.')
  562.                 yyerror ("invalid token '..' ('...' assumed)");
  563.               unget (c);
  564.               return ELLIPSIS;
  565.             }
  566.           else if (! is_digit[c])
  567.             {
  568.               unget (c);
  569.               return '.';
  570.             }
  571.  
  572.           goto mantissa;
  573.  
  574.         case ':':
  575.           if (get (c) == ':')
  576.             return DCOLON;
  577.           unget (c);
  578.           return ':';
  579.  
  580.         case '=':
  581.           if (get (c) == '=')
  582.             return EQ;
  583.           unget (c);
  584.           return '=';
  585.  
  586.         case '!':
  587.           if (get (c) == '=')
  588.             return NE;
  589.           unget (c);
  590.           return '!';
  591.  
  592.         case '<':
  593.           switch (get (c))
  594.             {
  595.             case '=':
  596.               return LE;
  597.             case '<':
  598.               if (get (c) == '=')
  599.                 return LSHIFTASGN;
  600.               unget (c);
  601.               return LSHIFT;
  602.             }
  603.           unget (c);
  604.           return '<';
  605.  
  606.         case '>':
  607.           switch (get (c))
  608.             {
  609.             case '=':
  610.               return GE;
  611.             case '>':
  612.               if (get (c) == '=')
  613.                 return RSHIFTASGN;
  614.               unget (c);
  615.               return RSHIFT;
  616.             }
  617.           unget (c);
  618.           return '>';
  619.  
  620.         case '#':
  621.           while (get (c) != EOF && c != '\n')
  622.             if (c == '\\')
  623.               {
  624. #if MSDOS || OS2
  625.                 get (c);        /* for \r */
  626.         if (c == '\r')
  627.           get (c);
  628. #else
  629.                 get (c);
  630. #endif
  631.               }
  632.  
  633.       if (c == EOF)
  634.         return 0;
  635.  
  636.           ++yyline;
  637.           break;
  638.  
  639.         case '(': case ')': case '[': case ']': case '{': case '}':
  640.         case ';': case ',': case '?': case '~':
  641.           return c;
  642.  
  643.         case '0':
  644.           long_val = 0;
  645.  
  646.           if (get (c) == 'x' || c == 'X')
  647.             {
  648.               while (get (c) != EOF)
  649.                 {
  650.                   if (is_digit[c])
  651.                     long_val = long_val * 16 + c - '0';
  652.                   else if (c >= 'a' && c <= 'f')
  653.                     long_val = long_val * 16 + c - 'a' + 10;
  654.                   else if (c >= 'A' && c <= 'F')
  655.                     long_val = long_val * 16 + c - 'A' + 10;
  656.                   else
  657.                     break;
  658.                 }
  659.  
  660.               goto int_suffixes;
  661.             }
  662.           else if (c == '.')
  663.             goto mantissa;
  664.  
  665.           while (c >= '0' && c <= '7')
  666.             {
  667.               long_val = long_val << 3 + c - '0';
  668.               get (c);
  669.             }
  670.  
  671.         int_suffixes:
  672.           /* Integer suffixes */
  673.           while (c == 'l' || c == 'L' || c == 'u' || c == 'U')
  674.             get (c);
  675.           unget (c);
  676.           return CINT;
  677.  
  678.         case '1': case '2': case '3': case '4': case '5': case '6':
  679.         case '7': case '8': case '9':
  680.           /* Integer or floating constant, part before '.' */
  681.           long_val = c - '0';
  682.  
  683.           while (get (c) != EOF && is_digit[c])
  684.             long_val = 10 * long_val + c - '0';
  685.  
  686.           if (c != '.')
  687.             goto int_suffixes;
  688.  
  689.         mantissa:
  690.           /* Digits following '.' */
  691.           while (is_digit[c])
  692.             get (c);
  693.  
  694.           /* Optional exponent */
  695.           if (c == 'E' || c == 'e')
  696.             {
  697.               if (get (c) == '-' || c == '+')
  698.                 get (c);
  699.  
  700.               while (is_digit[c])
  701.                 get (c);
  702.             }
  703.  
  704.           /* Optional type suffixes */
  705.           while (c == 'f' || c == 'F' || c == 'l' || c == 'L')
  706.             get (c);
  707.  
  708.           return CFLOAT;
  709.  
  710.         default:
  711. #if 0
  712.           yyerror ("illegal character '%c'", c);
  713. #endif
  714.           break;
  715.         }
  716.     }
  717. }
  718.  
  719. char*
  720. line_start ()
  721. {
  722.   char* p;
  723.   char* s;
  724.   char* t;
  725.   static char buffer[MAX_REGEXP];
  726.   static char* end_buf = &buffer[MAX_REGEXP] - 1;
  727.  
  728.   if (!f_regexps)
  729.     return NULL;
  730.  
  731.   for (p = in - 1; p > inbuffer && *p != '\n'; --p)
  732.     ;
  733.  
  734.   if (*p == '\n')
  735.     {
  736.       while (in - p < MIN_REGEXP && p > inbuffer)
  737.         {
  738.           /* Line probably not significant enough */
  739.           for (--p; p >= inbuffer && *p != '\n'; --p)
  740.             ;
  741.         }
  742.       if (*p == '\n')
  743.         ++p;
  744.     }
  745.  
  746.   /* Copy from end to make sure significant portions are included.
  747.      This implies that in the browser a regular expressino of the
  748.      form `^.*{regexp}' has to be used. */
  749.  
  750.   for (s = end_buf-1, t = in; s > buffer && t > p;)
  751.     {
  752.       *--s = *--t;
  753.  
  754.       if (*s == '"')
  755.         *--s = '\\';
  756. #ifdef OS2
  757.       else if (*s == '\r')
  758.         ++s;
  759. #endif
  760.     }
  761.  
  762.   *(end_buf-1) = 0;
  763.   return s;
  764. }
  765.  
  766. unsigned
  767. buffer_pos ()
  768. {
  769. #if MSDOS || OS2
  770.   return in - inbuffer - carriage_returns;
  771. #else
  772.   return in - inbuffer;
  773. #endif
  774. }
  775.  
  776. char*
  777. token_string (t)
  778.      unsigned t;
  779. {
  780.   static char b[3];
  781.  
  782.   switch (t)
  783.     {
  784.     case CSTRING:               return "string constant";
  785.     case CCHAR:                 return "char constant";
  786.     case CINT:                  return "int constant";
  787.     case CFLOAT:                return "floating constant";
  788.     case ELLIPSIS:              return "...";
  789.     case LSHIFTASGN:            return "<<=";
  790.     case RSHIFTASGN:            return ">>=";
  791.     case ARROWSTAR:             return "->*";
  792.     case IDENT:                 return "identifier";
  793.     case DIVASGN:        return "/=";
  794.     case INC:            return "++";
  795.     case ADDASGN:        return "+=";
  796.     case DEC:            return "--";
  797.     case ARROW:            return "->";
  798.     case SUBASGN:        return "-=";
  799.     case MULASGN:        return "*=";
  800.     case MODASGN:        return "%=";
  801.     case LOR:            return "||";
  802.     case ORASGN:        return "|=";
  803.     case LAND:            return "&&";
  804.     case ANDASGN:        return "&=";
  805.     case XORASGN:        return "^=";
  806.     case POINTSTAR:        return ".*";
  807.     case DCOLON:        return "::";
  808.     case EQ:            return "==";
  809.     case NE:            return "!=";
  810.     case LE:            return "<=";
  811.     case LSHIFT:        return "<<";
  812.     case GE:            return ">=";
  813.     case RSHIFT:        return ">>";
  814.     case ASM:                   return "asm";
  815.     case AUTO:                  return "auto";
  816.     case BREAK:                 return "break";
  817.     case CASE:                  return "case";
  818.     case CATCH:                 return "catch";
  819.     case CHAR:                  return "char";
  820.     case CLASS:                 return "class";
  821.     case CONST:                 return "const";
  822.     case CONTINUE:              return "continue";
  823.     case DEFAULT:               return "default";
  824.     case DELETE:                return "delete";
  825.     case DO:                    return "do";
  826.     case DOUBLE:                return "double";
  827.     case ELSE:                  return "else";
  828.     case ENUM:                  return "enum";
  829.     case EXTERN:                return "extern";
  830.     case FLOAT:                 return "float";
  831.     case FOR:                   return "for";
  832.     case FRIEND:                return "friend";
  833.     case GOTO:                  return "goto";
  834.     case IF:                    return "if";
  835.     case INLINE:                return "inline";
  836.     case INT:                   return "int";
  837.     case LONG:                  return "long";
  838.     case NEW:                   return "new";
  839.     case OPERATOR:              return "operator";
  840.     case PRIVATE:               return "private";
  841.     case PROTECTED:             return "protected";
  842.     case PUBLIC:                return "public";
  843.     case REGISTER:              return "register";
  844.     case RETURN:                return "return";
  845.     case SHORT:                 return "short";
  846.     case SIGNED:                return "signed";
  847.     case SIZEOF:                return "sizeof";
  848.     case STATIC:                return "static";
  849.     case STRUCT:                return "struct";
  850.     case SWITCH:                return "switch";
  851.     case TEMPLATE:              return "template";
  852.     case THIS:                  return "this";
  853.     case THROW:                 return "throw";
  854.     case TRY:                   return "try";
  855.     case TYPEDEF:               return "typedef";
  856.     case UNION:                 return "union";
  857.     case UNSIGNED:              return "unsigned";
  858.     case VIRTUAL:               return "virtual";
  859.     case VOID:                  return "void";
  860.     case VOLATILE:              return "volatile";
  861.     case WHILE:                 return "while";
  862.     case YYEOF:                 return "EOF";
  863.     }
  864.  
  865.   assert (t < 255);
  866.   b[0] = t;
  867.   b[1] = 0;
  868.   return b;
  869. }
  870.  
  871. static void
  872. usage ()
  873. {
  874.   char buffer[50];
  875.   char* rev = buffer;
  876.   char* s;
  877.  
  878.   for (s = strcpy (buffer, revision); *s; ++s)
  879.     {
  880.       if (*s == '$')
  881.     *s = '\0';
  882.       else if (*s == ':')
  883.     {
  884.       do ++s; while (*s == ' ');
  885.       rev = s;
  886.     }
  887.     }
  888.  
  889.   printf (USAGE, rev, copyright);
  890.   exit (1);
  891. }
  892.  
  893. void
  894. process_file (file)
  895.      char* file;
  896. {
  897.   char* s;
  898.   unsigned n;
  899.  
  900.   /* Record in FILENAME the current file name. */
  901.   filename = dupstr (file);
  902.  
  903.   /* Convert backslashes in paths to forward slashes.
  904.      This is only needed if the Emacs used is not prepared
  905.      to handle backslashes properly (e.g. DJ Emacs under
  906.      MSDOS. */
  907. #ifdef CONVERT_BACKSLASH
  908. #ifdef MSDOS
  909.   strlwr (filename);
  910. #endif
  911.   for (s = filename; *s; ++s)
  912.     if (*s == '\\')
  913.       *s = '/';
  914. #endif
  915.  
  916.   /* Give a progress indication if needed. */
  917.   if (f_very_verbose)
  918.     {
  919.       puts (filename);
  920.       fflush (stdout);
  921.     }
  922.   else if (f_verbose)
  923.     {
  924.       putchar ('.');
  925.       fflush (stdout);
  926.     }
  927.  
  928.   /* Reinitialize scanner and parser. */
  929.   re_init_lex ();
  930.   re_init_parse ();
  931.  
  932.   /* Read input file into input buffer and parse it. */
  933.   if ((yyin = open (filename, O_RDONLY | O_BINARY)) == -1)
  934.     {
  935.       yyerror ("cannot open");
  936.       return;
  937.     }
  938.  
  939.   if ((n = read (yyin, inbuffer, INBUFFER_SIZE)) == INBUFFER_SIZE)
  940.     yyerror ("file too big, only %u bytes will be processed.", n);
  941.  
  942.   inbuffer[n] = 0;
  943.   yyparse ();
  944.   close (yyin);
  945. }
  946.  
  947. void
  948. process_stdin ()
  949. {
  950.   unsigned n;
  951.   yyin = fileno (stdin);
  952.  
  953.   if ((n = read (yyin, inbuffer, INBUFFER_SIZE)) == INBUFFER_SIZE)
  954.     yyerror ("file too big, only %u bytes will be processed.", n);
  955.  
  956.   inbuffer[n] = 0;
  957.   re_init_lex ();
  958.   re_init_parse ();
  959.   yyparse ();
  960. }
  961.  
  962. main (argc, argv)
  963.      int argc;
  964.      char** argv;
  965. {
  966.   int i;
  967.   unsigned n;
  968.   int any_inputfiles = 0;
  969.   static char out_filename[255] = DEFAULT_OUTFILE;
  970.   static char* input_filenames[MAX_INPUTFILES];
  971.   static int n_input_files;
  972.   static char b[255];
  973.  
  974. #if defined __GNUC__ && OS2
  975.   _wildcard (&argc, &argv);
  976. #endif
  977.  
  978.   filename = "command line";
  979.  
  980.   /* stdout is not a constant under IBM C Set++ 2.1 so it
  981.      cannot be an initializer in global scope (would you believe
  982.      that?) */
  983.   yyout = stdout;
  984.  
  985.   if (argc < 2)
  986.     usage ();
  987.  
  988.   /* Get command line switches. */
  989.   for (i = 1; i < argc; ++i)
  990.     {
  991.       if (*argv[i] == '-')
  992.         {
  993.           int j;
  994.  
  995.           for (j = 1; argv[i][j]; ++j)
  996.             {
  997.               switch (argv[i][j])
  998.                 {
  999.         case 'n':
  1000.           f_nested_classes = 1;
  1001.           break;
  1002.  
  1003.         case 'e':
  1004.           f_emacs = 1;
  1005.           if (argv[i][j+1])
  1006.             {
  1007.               filename = &argv[i][j+1];
  1008.               goto next_argv;
  1009.             }
  1010.                   else if (i < argc - 1)
  1011.                     {
  1012.                       argv[i] = NULL;
  1013.                       filename = argv[++i];
  1014.                       goto next_argv;
  1015.                     }
  1016.                   else
  1017.                     usage ();
  1018.           break;
  1019.  
  1020.         case 'x':
  1021.           f_regexps = 1;
  1022.                   break;
  1023.  
  1024.           /* Do not record regular expressions/ write regexps
  1025.              to file (and insert positions instead of strings
  1026.              into Lisp structures). */
  1027.  
  1028.                 case 'r':
  1029.           if (argv[i][j+1])
  1030.             {
  1031.               regexp_filename = &argv[i][j+1];
  1032.               goto next_argv;
  1033.             }
  1034.           else if (i < argc - 1)
  1035.             {
  1036.               argv[i] = NULL;
  1037.                       regexp_filename = argv[++i];
  1038.                       goto next_argv;
  1039.             }
  1040.           else
  1041.             usage ();
  1042.                   break;
  1043.  
  1044.                 case 'i':
  1045.                   /* read file names from input file. */
  1046.                   if (argv[i][j+1])
  1047.                     {
  1048.                       input_filenames[n_input_files++] =
  1049.                         dupstr (&argv[i][j+1]);
  1050.                       goto next_argv;
  1051.                     }
  1052.                   else if (i < argc - 1)
  1053.                     {
  1054.                       argv[i] = NULL;
  1055.                       input_filenames[n_input_files++] = dupstr (argv[++i]);
  1056.                       goto next_argv;
  1057.                     }
  1058.                   else
  1059.                     usage ();
  1060.                   break;
  1061.  
  1062.                 case 'a':
  1063.                   /* Append to output file */
  1064.                   f_append = 1;
  1065.                   break;
  1066.  
  1067.                 case 'f':
  1068.                   f_costly_friends = 0;
  1069.                   break;
  1070.  
  1071.                 case 's':
  1072.                   f_structs = 0;
  1073.                   break;
  1074.  
  1075.                 case 'v':
  1076.                   f_verbose = 1;
  1077.                   break;
  1078.  
  1079.         case 'V':
  1080.           f_verbose = 1;
  1081.           f_very_verbose = 1;
  1082.           break;
  1083.  
  1084.                 case 'o':
  1085.                   if (argv[i][j+1])
  1086.                     {
  1087.                       strcpy (out_filename, &argv[i][j+1]);
  1088.                       goto next_argv;
  1089.                     }
  1090.                   else if (i < argc - 1)
  1091.                     {
  1092.                       argv[i] = NULL;
  1093.                       strcpy (out_filename, argv[++i]);
  1094.                       goto next_argv;
  1095.                     }
  1096.                   else
  1097.                     usage ();
  1098.                   break;
  1099.  
  1100.                 case 'm':
  1101.                 case 'M':
  1102.                   {
  1103.                     int v;
  1104.                     char option = argv[i][j];
  1105.  
  1106.                     if (argv[i][j+1])
  1107.                       v = atoi (&argv[i][j+1]);
  1108.                     else if (i < argc - 1)
  1109.                       {
  1110.                         argv[i] = NULL;
  1111.                         v = atoi (argv[++i]);
  1112.                       }
  1113.                     else
  1114.                       usage ();
  1115.  
  1116.                     if (option == 'm')
  1117.                       min_regexp = v;
  1118.                     else
  1119.                       max_regexp = v;
  1120.  
  1121.                     goto next_argv;
  1122.                   }
  1123.                       
  1124.                 default:
  1125.                   usage ();
  1126.                   break;
  1127.                 }
  1128.             }
  1129.  
  1130.         next_argv:;
  1131.  
  1132.           if (n_input_files == MAX_INPUTFILES)
  1133.             {
  1134.               yyerror ("too many input files specified");
  1135.               exit (1);
  1136.             }
  1137.  
  1138.           argv[i] = NULL;
  1139.         }
  1140.     }
  1141.  
  1142.   init_lex ();
  1143.   init_sym ();
  1144.  
  1145.   if (f_emacs)
  1146.     {
  1147.       process_stdin ();
  1148.       dump_roots (stdout);
  1149.       exit (0);
  1150.     }
  1151.  
  1152.   /* Open output file */
  1153.  
  1154.   if (*out_filename)
  1155.     if (0 == (yyout = fopen (out_filename, f_append ? "a" : "w")))
  1156.       {
  1157.         yyerror ("cannot open output file %s", out_filename);
  1158.         exit (1);
  1159.       }
  1160.  
  1161.   /* Open regular expression output file, if any. */
  1162.  
  1163.   if (regexp_filename)
  1164.     if (-1 == (regexp_file = open (regexp_filename,
  1165.                    O_WRONLY | O_BINARY | O_CREAT)))
  1166.       {
  1167.     yyerror ("cannot open regexp output file `%s'", regexp_filename);
  1168.     exit (1);
  1169.       }
  1170.  
  1171.   /* Process input files given on command line. For GNU use globbing
  1172.      on the remaining files. */
  1173.  
  1174.   for (i = 1; i < argc; ++i)
  1175.     if (argv[i])
  1176.       {
  1177.     process_file (argv[i]);
  1178.     any_inputfiles = 1;
  1179.       }
  1180.  
  1181.   /* Process files given on stdin if no files specified */
  1182.  
  1183.   if (!any_inputfiles && !input_filenames[0])
  1184.     {
  1185.       while (fgets (b, sizeof b - 1, stdin))
  1186.     {
  1187.       b[strlen (b)-1] = 0;
  1188.       process_file (b);
  1189.     }
  1190.     }
  1191.   else
  1192.     {
  1193.       /* Process files from input files. */
  1194.  
  1195.       for (i = 0; input_filenames[i]; ++i)
  1196.     {
  1197.       FILE* fp = fopen (input_filenames[i], "r");
  1198.       
  1199.       if (!fp)
  1200.         yyerror ("cannot open input file `%s'", input_filenames[i]);
  1201.       else
  1202.         {
  1203.           while (fgets (b, sizeof b - 1, fp))
  1204.         {
  1205.           b[strlen (b)-1] = 0;
  1206.           process_file (b);
  1207.         }
  1208.           
  1209.           fclose (fp);
  1210.         }
  1211.     }
  1212.     }
  1213.  
  1214.   /* Print results */
  1215.   dump_roots (yyout);
  1216.  
  1217.   if (f_verbose || f_very_verbose)
  1218.     printf ("\ntotal allocated = %ld bytes\n", total_allocated);
  1219.  
  1220.   if (yyout != stdout)
  1221.     fclose (yyout);
  1222.  
  1223.   if (regexp_file > 0)
  1224.     close (regexp_file);
  1225.  
  1226.   return 0;
  1227. }
  1228.