home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / id-utils-3.2-src.tgz / tar.out / fsf / id-utils / libidu / scanners.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  30KB  |  1,213 lines

  1. /* scanners.c -- file & directory name manipulations
  2.    Copyright (C) 1986, 1995, 1996 Free Software Foundation, Inc.
  3.    Written by Greg McGary <gkm@gnu.ai.mit.edu>
  4.  
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 2, or (at your option)
  8.    any later version.
  9.  
  10.    This program is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.    GNU General Public License for more details.
  14.  
  15.    You should have received a copy of the GNU General Public License
  16.    along with this program; if not, write to the Free Software
  17.    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  18.  
  19. #include <config.h>
  20. #include <stdio.h>
  21. #include <ctype.h>
  22. #if HAVE_FCNTL_H
  23. # include <fcntl.h>
  24. #endif
  25. #include <getopt.h>
  26. #include "xstdlib.h"
  27. #include "xstddef.h"
  28. #include "xunistd.h"
  29. #include "xsysstat.h"
  30. #include "xstring.h"
  31. #include "xmalloc.h"
  32. #include "xnls.h"
  33. #include "error.h"
  34. #include "scanners.h"
  35. #include "tokflags.h"
  36.  
  37. #define DEBUG(args) /* printf args */
  38.  
  39. struct obstack lang_args_obstack;
  40. struct lang_args *lang_args_default = 0;
  41. struct lang_args *lang_args_list = 0;
  42. struct obstack tokens_obstack;
  43.  
  44. extern void usage __P((void));
  45. extern char *program_name;
  46.  
  47. /****************************************************************************/
  48.  
  49. struct lang_args **parse_language_map_file __P((char const *file_name, struct lang_args **next_ptr));
  50. char *read_language_map_file __P((char const *file_name));
  51. void tokenize_args_string __P((char *args_string, int *argcp, char ***argvp));
  52.  
  53. static struct token *get_token_c __P((FILE *in_FILE, void const *args, int *flags));
  54. static void *parse_args_c __P((char **argv, int argc));
  55. static void help_me_c __P((void));
  56.  
  57. static struct token *get_token_asm __P((FILE *in_FILE, void const *args, int *flags));
  58. static void *parse_args_asm __P((char **argv, int argc));
  59. static void help_me_asm __P((void));
  60.  
  61. static struct token *get_token_text __P((FILE *in_FILE, void const *args, int *flags));
  62. static void *parse_args_text __P((char **argv, int argc));
  63. static void help_me_text __P((void));
  64.  
  65. struct language languages_0[] =
  66. {
  67.   { "C", parse_args_c, get_token_c, help_me_c },
  68.   { "asm", parse_args_asm, get_token_asm, help_me_asm },
  69.   { "text", parse_args_text, get_token_text, help_me_text },
  70. };
  71. struct language const *languages_N = &languages_0[cardinalityof (languages_0)];
  72.  
  73. void
  74. language_help_me (void)
  75. {
  76.   struct language *lang;
  77.   for (lang = languages_0; lang < languages_N; lang++)
  78.     {
  79.       putchar ('\n');
  80.       (*lang->lg_help_me) ();
  81.     }
  82. }
  83.  
  84. void
  85. language_save_arg (char *arg)
  86. {
  87.   static char horizontal_space[] = " \t";
  88.   char *lang_name = strtok (arg, ":");
  89.   struct language *lang = get_language (lang_name);
  90.  
  91.   if (lang == 0)
  92.     {
  93.       error (0, 0, _("unrecognized language: `%s'"), lang_name);
  94.       usage ();
  95.     }
  96.   if (lang->lg_argc == 0)
  97.     lang->lg_argv[lang->lg_argc++] = program_name;
  98.   lang->lg_argv[lang->lg_argc++] = strtok (0, horizontal_space);
  99. }
  100.  
  101. void
  102. language_getopt (void)
  103. {
  104.   struct language *lang;
  105.  
  106.   for (lang = languages_0; lang < languages_N; lang++)
  107.     if (lang->lg_argc)
  108.       lang->lg_parse_args (lang->lg_argv, lang->lg_argc);
  109. }
  110.  
  111. struct language *
  112. get_language (char const *lang_name)
  113. {
  114.   struct language *lang;
  115.  
  116.   for (lang = languages_0; lang < languages_N; lang++)
  117.     if (strequ (lang_name, lang->lg_name))
  118.       {
  119.     DEBUG (("lang=%s", lang_name));
  120.     return lang;
  121.       }
  122.   DEBUG (("!lang=%s", lang_name));
  123.   return 0;
  124. }
  125.  
  126. /****************************************************************************/
  127.  
  128. int lang_args_index = 0;
  129.  
  130. void
  131. set_default_language (char const *lang_name)
  132. {
  133. }
  134.  
  135. void
  136. parse_language_map (char const *file_name)
  137. {
  138.   if (obstack_init (&lang_args_obstack) == 0)
  139.     error (1, 0, _("can't allocate language args obstack: memory exhausted"));
  140.   if (file_name == 0)
  141.     file_name = LANGUAGE_MAP_FILE;
  142.   parse_language_map_file (file_name, &lang_args_list);
  143. }
  144.  
  145. struct lang_args **
  146. parse_language_map_file (char const *file_name, struct lang_args **next_ptr)
  147. {
  148.   static char white_space[] = " \t\r\n\v\f";
  149.   static char horizontal_space[] = " \t";
  150.   static char vertical_space[] = "\r\n\v\f";
  151.   char *lang_map_buffer;
  152.   char *lmp;
  153.  
  154.   lmp = lang_map_buffer = read_language_map_file (file_name);
  155.   for (;;)
  156.     {
  157.       struct lang_args *new_args;
  158.       struct language const *lang;
  159.       int pattern_size;
  160.       char *lang_name;
  161.       int space;
  162.  
  163.       /* Skip leading white space and full-line comments */
  164.       while (*lmp)
  165.     {
  166.       lmp += strspn (lmp, white_space);
  167.       if (*lmp != '#')
  168.         break;
  169.       lmp += strcspn (lmp, vertical_space);
  170.     }
  171.       if (*lmp == '\0')
  172.     break;
  173.  
  174.       pattern_size = strcspn (lmp, white_space);
  175.       if (pattern_size == 3 && strnequ (lmp, "***", 3))
  176.     {
  177.       lmp += pattern_size;
  178.       lmp += strspn (lmp, horizontal_space);
  179.       if (isspace (*lmp))
  180.         next_ptr = parse_language_map_file (LANGUAGE_MAP_FILE, next_ptr);
  181.       else
  182.         {
  183.           char *end = lmp + strcspn (lmp, white_space);
  184.           *end = '\0';
  185.           next_ptr = parse_language_map_file (lmp, next_ptr);
  186.           lmp = end + 1;
  187.         }
  188.       continue;
  189.     }
  190.  
  191.       new_args = OBSTACK_ALLOC (&lang_args_obstack, struct lang_args, 1);
  192.       if (new_args == 0)
  193.     error (1, 0, _("can't allocate language args: memory exhausted"));
  194.       new_args->la_pattern = obstack_copy0 (&lang_args_obstack, lmp, pattern_size);
  195.       new_args->la_args_string = 0;
  196.       new_args->la_next = 0;
  197.       lmp += pattern_size;
  198.       lmp += strspn (lmp, horizontal_space);
  199.       if (isspace (*lmp))
  200.     {
  201.       error (0, 0, _("language name expected following `%s' in file `%s'"),
  202.          new_args->la_pattern, file_name);
  203.       obstack_free (&lang_args_obstack, new_args);
  204.       continue;
  205.     }
  206.       lang_name = lmp;
  207.       lmp += strcspn (lmp, white_space);
  208.       space = *lmp;
  209.       *lmp++ = '\0';
  210.       lmp += strspn (lmp, horizontal_space);
  211.       lang = new_args->la_language = get_language (lang_name);
  212.  
  213.       if (*lmp == '#')
  214.     lmp += strcspn (lmp, vertical_space);
  215.       else if (!isspace (*lmp) && (space == ' ' || space == '\t'))
  216.     {
  217.       int args_size = strcspn (lmp, vertical_space);
  218.       new_args->la_args_string = obstack_copy0 (&lang_args_obstack, lmp, args_size);
  219.       lmp += args_size;
  220.     }
  221.       new_args->la_args_digested = (lang
  222.                     ? lang->lg_parse_args (&new_args->la_args_string, 0)
  223.                     : 0);
  224.       if (pattern_size == 2 && strnequ (new_args->la_pattern, "**", 2))
  225.     {
  226.       if (lang_args_default)
  227.         {
  228.           obstack_free (&lang_args_obstack, new_args);
  229.           continue;
  230.         }
  231.       lang_args_default = new_args;
  232.       DEBUG ((", <default>"));
  233.     }
  234.       else
  235.     {
  236.       new_args->la_index = lang_args_index++;
  237.       *next_ptr = new_args;
  238.       next_ptr = &new_args->la_next;
  239.     }
  240.       DEBUG ((", pat=%s\n", new_args->la_pattern));
  241.     }
  242.   free (lang_map_buffer);
  243.   return next_ptr;
  244. }
  245.  
  246. char *
  247. read_language_map_file (char const *file_name)
  248. {
  249.   int map_fd;
  250.   char *lang_map_buffer;
  251.   struct stat st;
  252.   int bytes;
  253.  
  254.   map_fd = open (file_name, O_RDONLY);
  255.   if (map_fd < 0)
  256.     error (1, errno, _("can't open language map file `%s'"), file_name);
  257.   if (fstat (map_fd, &st) < 0)
  258.     error (1, errno, _("can't get size of map file `%s'"), file_name);
  259.  
  260.   lang_map_buffer = MALLOC (char, st.st_size + 2);
  261.   if (lang_map_buffer == 0)
  262.     error (1, 0, _("can't allocate language args: memory exhausted"));
  263.   lang_map_buffer[st.st_size] = '\n';
  264.   lang_map_buffer[st.st_size+1] = '\0';
  265.  
  266.   bytes = read (map_fd, lang_map_buffer, st.st_size);
  267.   if (bytes < 0)
  268.     error (1, errno, _("can't read language map file `%s'"), file_name);
  269.   /* FIXME: handle interrupted & partial reads */
  270.   if (bytes != st.st_size)
  271.     error (1, errno, _("can't read entire language map file `%s'"), file_name);
  272.  
  273.   close (map_fd);
  274.   return lang_map_buffer;
  275. }
  276.  
  277. /****************************************************************************/
  278.  
  279. void
  280. tokenize_args_string (char *args_string, int *argcp, char ***argvp)
  281. {
  282.   static char horizontal_space[] = " \t";
  283.   char **argv_0 = MALLOC (char *, strlen (args_string) / 2);
  284.   char **argv = argv_0;
  285.   char *arg;
  286.  
  287.   *argv++ = program_name;
  288.   arg = strtok (args_string, horizontal_space);
  289.   while (arg)
  290.     {
  291.       *argv++ = arg;
  292.       arg = strtok (0, horizontal_space);
  293.     }
  294.   *argcp = argv - argv_0;
  295.   *argvp = REALLOC (argv_0, char *, *argcp);
  296. }
  297.  
  298. static void
  299. set_ushort_ctype (unsigned short *ctype, char const *chars, int type)
  300. {
  301.   unsigned short *rct = &ctype[1];
  302.  
  303.   while (*chars)
  304.     rct[*chars++] |= type;
  305. }
  306.  
  307. static void
  308. clear_ushort_ctype (unsigned short *ctype, char const *chars, int type)
  309. {
  310.   unsigned short *rct = &ctype[1];
  311.  
  312.   while (*chars)
  313.     rct[*chars++] &= ~type;
  314. }
  315.  
  316. static void
  317. set_uchar_ctype (unsigned char *ctype, char const *chars, int type)
  318. {
  319.   unsigned char *rct = &ctype[1];
  320.  
  321.   while (*chars)
  322.     rct[*chars++] |= type;
  323. }
  324.  
  325. static void
  326. clear_uchar_ctype (unsigned char *ctype, char const *chars, int type)
  327. {
  328.   unsigned char *rct = &ctype[1];
  329.  
  330.   while (*chars)
  331.     rct[*chars++] &= ~type;
  332. }
  333.  
  334. /*************** C & C++ ****************************************************/
  335.  
  336. #define I1    0x0001        /* 1st char of an identifier [a-zA-Z_] */
  337. #define DG    0x0002        /* decimal digit [0-9] */
  338. #define NM    0x0004        /* extra chars in a hex or long number [a-fA-FxXlL] */
  339. #define C1    0x0008        /* C comment introduction char: / */
  340. #define C2    0x0010        /* C comment termination  char: * */
  341. #define Q1    0x0020        /* single quote: ' */
  342. #define Q2    0x0040        /* double quote: " */
  343. #define ES    0x0080        /* escape char: \ */
  344. #define NL    0x0100        /* newline: \n */
  345. #define EF    0x0200        /* EOF */
  346. #define SK    0x0400        /* Make these chars valid for names within strings */
  347. #define VH    0x0800        /* VHIL comment introduction char: # */
  348. #define WS    0x1000        /* White space characters */
  349.  
  350. /* character class membership macros: */
  351.  
  352. #define ISDIGIT(c)    ((rct)[c] & (DG))    /* digit */
  353. #define ISNUMBER(c)    ((rct)[c] & (DG|NM))    /* legal in a number */
  354. #define ISEOF(c)    ((rct)[c] & (EF))    /* EOF */
  355. #define ISID1ST(c)    ((rct)[c] & (I1))    /* 1st char of an identifier */
  356. #define ISIDREST(c)    ((rct)[c] & (I1|DG))    /* rest of an identifier */
  357. #define ISSTRKEEP(c)    ((rct)[c] & (I1|DG|SK))    /* keep contents of string */
  358. #define ISSPACE(c)    ((rct)[c] & (WS))    /* white space character */
  359.  
  360. /* The `BORING' classes should be skipped over until something
  361.    interesting comes along... */
  362.  
  363. #define ISBORING(c)    (!((rct)[c] & (EF|NL|I1|DG|Q1|Q2|C1|VH)))    /* fluff */
  364. #define ISCBORING(c)    (!((rct)[c] & (EF|C2)))    /* comment fluff */
  365. #define ISCCBORING(c)    (!((rct)[c] & (EF|NL)))    /* C++ // comment fluff */
  366. #define ISQ1BORING(c)    (!((rct)[c] & (EF|NL|Q1|ES)))    /* char const fluff */
  367. #define ISQ2BORING(c)    (!((rct)[c] & (EF|NL|Q2|ES)))    /* quoted str fluff */
  368.  
  369. static unsigned short ctype_c[257] =
  370. {
  371.   EF,
  372. /*      0       1       2       3       4       5       6       7   */
  373. /*    -----   -----   -----   -----   -----   -----   -----   ----- */
  374. /*000*/ 0,    0,    0,    0,    0,    0,    0,    0,
  375. /*010*/ 0,    0,    NL,    0,    0,    0,    0,    0,
  376. /*020*/ 0,    0,    0,    0,    0,    0,    0,    0,
  377. /*030*/ 0,    0,    0,    0,    0,    0,    0,    0,
  378. /*040*/ 0,    0,    Q2,    0,    0,    0,    0,    Q1,
  379. /*050*/ 0,    0,    C2,    0,    0,    0,    0,    C1,
  380. /*060*/ DG,    DG,    DG,    DG,    DG,    DG,    DG,    DG,
  381. /*070*/ DG,    DG,    0,    0,    0,    0,    0,    0,
  382. /*100*/ 0,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1,
  383. /*110*/ I1,    I1,    I1,    I1,    I1|NM,    I1,    I1,    I1,
  384. /*120*/ I1,    I1,    I1,    I1,    I1,    I1,    I1,    I1,
  385. /*130*/ I1|NM,    I1,    I1,    0,    ES,    0,    0,    I1,
  386. /*140*/ 0,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1,
  387. /*150*/ I1,    I1,    I1,    I1,    I1|NM,    I1,    I1,    I1,
  388. /*160*/ I1,    I1,    I1,    I1,    I1,    I1,    I1,    I1,
  389. /*170*/ I1|NM,    I1,    I1,    0,    0,    0,    0,    0,
  390.   /* FIXME: latin-1 */
  391. };
  392.  
  393. struct args_c
  394. {
  395.   int strip_underscore;
  396.   unsigned short *ctype;
  397. };
  398.  
  399. static struct args_c args_c = { 0, ctype_c };
  400.  
  401. static struct option const long_options_c[] =
  402. {
  403.   { "keep", required_argument, 0, 'k' },
  404.   { "ignore", required_argument, 0, 'i' },
  405.   { "strip-underscore", no_argument, 0, 'u' },
  406.   { 0 }
  407. };
  408.  
  409. static void
  410. help_me_c (void)
  411. {
  412.   printf (_("\
  413. C language:\n\
  414.   -k,--keep=CHARS        Allow CHARS in single-token strings, keep the result\n\
  415.   -i,--ignore=CHARS      Allow CHARS in single-token strings, toss the result\n\
  416.   -u,--strip-underscore  Strip a leading underscore from single-token strings\n\
  417. "));
  418. }
  419.  
  420. static void *
  421. parse_args_c (char **argv, int argc)
  422. {
  423.   char *tmp_string = 0;
  424.   struct args_c *args;
  425.  
  426.   if (argv == 0 || *argv == 0)
  427.     return &args_c;
  428.  
  429.   if (argc)
  430.     args = &args_c;
  431.   else
  432.     {
  433.       tmp_string = strdup (*argv);
  434.       tokenize_args_string (tmp_string, &argc, &argv);
  435.       args = MALLOC (struct args_c, 1);
  436.       args->strip_underscore = 0;
  437.       args->ctype = ctype_c;
  438.     }
  439.  
  440.   optind = 0;
  441.   for (;;)
  442.     {
  443.       int optc = getopt_long (argc, argv, "k:i:u",
  444.                   long_options_c, (int *) 0);
  445.       if (optc < 0)
  446.     break;
  447.       if ((optc == 'k' || optc == 'i') && args->ctype == ctype_c)
  448.     args->ctype = CLONE (ctype_c, unsigned short, cardinalityof (ctype_c));
  449.       switch (optc)
  450.     {
  451.     case 'k':
  452.       set_ushort_ctype (args->ctype, optarg, SK);
  453.       break;
  454.  
  455.     case 'i':
  456.       clear_ushort_ctype (args->ctype, optarg, SK);
  457.       break;
  458.  
  459.     case 'u':
  460.       args->strip_underscore = 1;
  461.       break;
  462.  
  463.     default:
  464.       usage ();
  465.     }
  466.     }
  467.   if (tmp_string)
  468.     {
  469.       free (argv);
  470.       free (tmp_string);
  471.     }
  472.   return args;
  473. }
  474.  
  475.  
  476. /* Grab the next identifier from the C source file.  This state
  477.    machine is built for speed, not elegance.  */
  478.  
  479. static struct token *
  480. get_token_c (FILE *in_FILE, void const *args, int *flags)
  481. {
  482. #define ARGS ((struct args_c const *) args)
  483.   static int new_line = 1;
  484.   unsigned short const *rct = &ARGS->ctype[1];
  485.   char id_0[BUFSIZ];
  486.   char *id = id_0;
  487.   int c;
  488.  
  489.   obstack_blank (&tokens_obstack, offsetof (struct token, tok_name));
  490.  
  491. top:
  492.   c = getc (in_FILE);
  493.   if (new_line)
  494.     {
  495.       new_line = 0;
  496.       if (c != '#')
  497.     goto next;
  498.       c = getc (in_FILE);
  499.       while (ISBORING (c))
  500.     c = getc (in_FILE);
  501.       if (!ISID1ST (c))
  502.     goto next;
  503.       id = id_0;
  504.       *id++ = c;
  505.       while (ISIDREST (c = getc (in_FILE)))
  506.     *id++ = c;
  507.       *id = '\0';
  508.       if (strequ (id_0, "include"))
  509.     {
  510.       while (c == ' ' || c == '\t')
  511.         c = getc (in_FILE);
  512.       if (c == '\n')
  513.         {
  514.           new_line = 1;
  515.           goto top;
  516.         }
  517.       id = id_0;
  518.       if (c == '"')
  519.         {
  520.           c = getc (in_FILE);
  521.           while (c != '\n' && c != EOF && c != '"')
  522.         {
  523.           *id++ = c;
  524.           c = getc (in_FILE);
  525.         }
  526.           *flags = TOK_STRING;
  527.         }
  528.       else if (c == '<')
  529.         {
  530.           c = getc (in_FILE);
  531.           while (c != '\n' && c != EOF && c != '>')
  532.         {
  533.           *id++ = c;
  534.           c = getc (in_FILE);
  535.         }
  536.           *flags = TOK_STRING;
  537.         }
  538.       else if (ISID1ST (c))
  539.         {
  540.           *id++ = c;
  541.           while (ISIDREST (c = getc (in_FILE)))
  542.         *id++ = c;
  543.           *flags = TOK_NAME;
  544.         }
  545.       else
  546.         {
  547.           while (c != '\n' && c != EOF)
  548.         c = getc (in_FILE);
  549.           new_line = 1;
  550.           goto top;
  551.         }
  552.       while (c != '\n' && c != EOF)
  553.         c = getc (in_FILE);
  554.       new_line = 1;
  555.       obstack_grow0 (&tokens_obstack, id_0, id - id_0);
  556.       return (struct token *) obstack_finish (&tokens_obstack);
  557.     }
  558.       if (strnequ (id_0, "if", 2)
  559.       || strequ (id_0, "define")
  560.       || strequ (id_0, "elif")    /* ansi C */
  561.       || strequ (id_0, "undef"))
  562.     goto next;
  563.       while ((c != '\n') && (c != EOF))
  564.     c = getc (in_FILE);
  565.       new_line = 1;
  566.       goto top;
  567.     }
  568.  
  569. next:
  570.   while (ISBORING (c))
  571.     c = getc (in_FILE);
  572.  
  573.   switch (c)
  574.     {
  575.     case '"':
  576.       id = id_0;
  577.       *id++ = c = getc (in_FILE);
  578.       for (;;)
  579.     {
  580.       while (ISQ2BORING (c))
  581.         *id++ = c = getc (in_FILE);
  582.       if (c == '\\')
  583.         {
  584.           *id++ = c = getc (in_FILE);
  585.           continue;
  586.         }
  587.       else if (c != '"')
  588.         goto next;
  589.       break;
  590.     }
  591.       *--id = '\0';
  592.       id = id_0;
  593.       while (ISSTRKEEP (*id))
  594.     id++;
  595.       if (*id || id == id_0)
  596.     {
  597.       c = getc (in_FILE);
  598.       goto next;
  599.     }
  600.       *flags = TOK_STRING;
  601.       if (ARGS->strip_underscore && id_0[0] == '_' && id_0[1])
  602.     obstack_grow0 (&tokens_obstack, id_0 + 1, id - id_0 - 1);
  603.       else
  604.     obstack_grow0 (&tokens_obstack, id_0, id - id_0);
  605.       return (struct token *) obstack_finish (&tokens_obstack);
  606.  
  607.     case '\'':
  608.       c = getc (in_FILE);
  609.       for (;;)
  610.     {
  611.       while (ISQ1BORING (c))
  612.         c = getc (in_FILE);
  613.       if (c == '\\')
  614.         {
  615.           c = getc (in_FILE);
  616.           continue;
  617.         }
  618.       else if (c == '\'')
  619.         c = getc (in_FILE);
  620.       goto next;
  621.     }
  622.  
  623.     case '/':
  624.       c = getc (in_FILE);
  625.       if (c == '/')
  626.     {            /* Cope with C++ comment */
  627.       while (ISCCBORING (c))
  628.         c = getc (in_FILE);
  629.       new_line = 1;
  630.       goto top;
  631.     }
  632.       else if (c != '*')
  633.     goto next;
  634.       c = getc (in_FILE);
  635.       for (;;)
  636.     {
  637.       while (ISCBORING (c))
  638.         c = getc (in_FILE);
  639.       c = getc (in_FILE);
  640.       if (c == '/')
  641.         {
  642.           c = getc (in_FILE);
  643.           goto next;
  644.         }
  645.       else if (ISEOF (c))
  646.         {
  647.           new_line = 1;
  648.           obstack_free (&tokens_obstack, obstack_finish (&tokens_obstack));
  649.           return 0;
  650.         }
  651.     }
  652.  
  653.     case '\n':
  654.       new_line = 1;
  655.       goto top;
  656.  
  657.     default:
  658.       if (ISEOF (c))
  659.     {
  660.       new_line = 1;
  661.       obstack_free (&tokens_obstack, obstack_finish (&tokens_obstack));
  662.       return 0;
  663.     }
  664.       id = id_0;
  665.       *id++ = c;
  666.       if (ISID1ST (c))
  667.     {
  668.       *flags = TOK_NAME;
  669.       while (ISIDREST (c = getc (in_FILE)))
  670.         *id++ = c;
  671.     }
  672.       else if (ISDIGIT (c))
  673.     {
  674.       *flags = TOK_NUMBER;
  675.       while (ISNUMBER (c = getc (in_FILE)))
  676.         *id++ = c;
  677.     }
  678.       else
  679.     {
  680.       if (isprint (c))
  681.         fprintf (stderr, _("junk: `%c'"), c);
  682.       else
  683.         fprintf (stderr, _("junk: `\\%03o'"), c);
  684.     }
  685.       ungetc (c, in_FILE);
  686.       *flags |= TOK_LITERAL;
  687.       obstack_grow0 (&tokens_obstack, id_0, id - id_0);
  688.       return (struct token *) obstack_finish (&tokens_obstack);
  689.     }
  690. #undef ARGS
  691. }
  692.  
  693. #undef I1
  694. #undef DG
  695. #undef NM
  696. #undef C1
  697. #undef C2
  698. #undef Q1
  699. #undef Q2
  700. #undef ES
  701. #undef NL
  702. #undef EF
  703. #undef SK
  704. #undef VH
  705. #undef WS
  706. #undef ISDIGIT
  707. #undef ISNUMBER
  708. #undef ISEOF
  709. #undef ISID1ST
  710. #undef ISIDREST
  711. #undef ISSTRKEEP
  712. #undef ISSPACE
  713. #undef ISBORING
  714. #undef ISCBORING
  715. #undef ISCCBORING
  716. #undef ISQ1BORING
  717. #undef ISQ2BORING
  718.  
  719. /*************** Assembly ***************************************************/
  720.  
  721. #define I1    0x01        /* 1st char of an identifier [a-zA-Z_] */
  722. #define NM    0x02        /* digit [0-9a-fA-FxX] */
  723. #define NL    0x04        /* newline: \n */
  724. #define CM    0x08        /* assembler comment char: usually # or | */
  725. #define IG    0x10        /* ignore `identifiers' with these chars in them */
  726. #define C1    0x20        /* C comment introduction char: / */
  727. #define C2    0x40        /* C comment termination  char: * */
  728. #define EF    0x80        /* EOF */
  729.  
  730. /* Assembly Language character classes */
  731. #define ISID1ST(c)    ((rct)[c] & (I1))
  732. #define ISIDREST(c)    ((rct)[c] & (I1|NM))
  733. #define ISNUMBER(c)    ((rct)[c] & (NM))
  734. #define ISEOF(c)    ((rct)[c] & (EF))
  735. #define ISCOMMENT(c)    ((rct)[c] & (CM))
  736. #define ISBORING(c)    (!((rct)[c] & (EF|NL|I1|NM|CM|C1)))
  737. #define ISCBORING(c)    (!((rct)[c] & (EF|NL)))
  738. #define ISCCBORING(c)    (!((rct)[c] & (EF|C2)))
  739. #define ISIGNORE(c)    ((rct)[c] & (IG))
  740.  
  741. static unsigned char ctype_asm[257] =
  742. {
  743.   EF,
  744. /*      0       1       2       3       4       5       6       7   */
  745. /*    -----   -----   -----   -----   -----   -----   -----   ----- */
  746. /*000*/ 0,    0,    0,    0,    0,    0,    0,    0,
  747. /*010*/ 0,    0,    NL,    0,    0,    0,    0,    0,
  748. /*020*/ 0,    0,    0,    0,    0,    0,    0,    0,
  749. /*030*/ 0,    0,    0,    0,    0,    0,    0,    0,
  750. /*040*/ 0,    0,    0,    0,    0,    0,    0,    0,
  751. /*050*/ 0,    0,    C2,    0,    0,    0,    0,    C1,
  752. /*060*/ NM,    NM,    NM,    NM,    NM,    NM,    NM,    NM,
  753. /*070*/ NM,    NM,    0,    0,    0,    0,    0,    0,
  754. /*100*/ 0,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1,
  755. /*110*/ I1,    I1,    I1,    I1,    I1|NM,    I1,    I1,    I1,
  756. /*120*/ I1,    I1,    I1,    I1,    I1,    I1,    I1,    I1,
  757. /*130*/ I1|NM,    I1,    I1,    0,    0,    0,    0,    I1,
  758. /*140*/ 0,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1,
  759. /*150*/ I1,    I1,    I1,    I1,    I1|NM,    I1,    I1,    I1,
  760. /*160*/ I1,    I1,    I1,    I1,    I1,    I1,    I1,    I1,
  761. /*170*/ I1|NM,    I1,    I1,    0,    0,    0,    0,    0,
  762.  
  763. };
  764.  
  765. struct args_asm
  766. {
  767.   int handle_cpp;
  768.   int strip_underscore;
  769.   unsigned char *ctype;
  770. };
  771.  
  772. static struct args_asm args_asm = { 1, 0, ctype_asm };
  773.  
  774. static struct option const long_options_asm[] =
  775. {
  776.   { "comment", required_argument, 0, 'c' },
  777.   { "keep", required_argument, 0, 'k' },
  778.   { "ignore", required_argument, 0, 'i' },
  779.   { "strip-underscore", no_argument, 0, 'u' },
  780.   { "no-cpp", no_argument, 0, 'p' },
  781.   { 0 }
  782. };
  783.  
  784. static void
  785. help_me_asm (void)
  786. {
  787.   printf (_("\
  788. Assembly language:\n\
  789.   -c,--comment=CHARS     Any of CHARS starts a comment until end-of-line\n\
  790.   -k,--keep=CHARS        Allow CHARS in tokens, and keep the result\n\
  791.   -i,--ignore=CHARS      Allow CHARS in tokens, and toss the result\n\
  792.   -u,--strip-underscore  Strip a leading underscore from tokens\n\
  793.   -n,--no-cpp            Don't handle C pre-processor directives\n\
  794. "));
  795. }
  796.  
  797. static void *
  798. parse_args_asm (char **argv, int argc)
  799. {
  800.   char *tmp_string = 0;
  801.   struct args_asm *args;
  802.  
  803.   if (argv == 0 || *argv == 0)
  804.     return &args_asm;
  805.  
  806.   if (argc)
  807.     args = &args_asm;
  808.   else
  809.     {
  810.       tmp_string = strdup (*argv);
  811.       tokenize_args_string (tmp_string, &argc, &argv);
  812.       args = MALLOC (struct args_asm, 1);
  813.       args->strip_underscore = 0;
  814.       args->ctype = ctype_asm;
  815.       args->handle_cpp = 1;
  816.     }
  817.  
  818.   optind = 0;
  819.   for (;;)
  820.     {
  821.       int optc = getopt_long (argc, argv, "c:k:i:un",
  822.                   long_options_asm, (int *) 0);
  823.       if (optc < 0)
  824.     break;
  825.       if ((optc == 'k' || optc == 'i' || optc == 'c')
  826.       && args->ctype == ctype_asm)
  827.     args->ctype = CLONE (ctype_asm, unsigned char, cardinalityof (ctype_asm));
  828.       switch (optc)
  829.     {
  830.     case 'c':
  831.       set_uchar_ctype (args->ctype, optarg, CM);
  832.       break;
  833.  
  834.     case 'k':
  835.       set_uchar_ctype (args->ctype, optarg, I1);
  836.       break;
  837.  
  838.     case 'i':
  839.       set_uchar_ctype (args->ctype, optarg, I1 | IG);
  840.       break;
  841.  
  842.     case 'u':
  843.       args->strip_underscore = 1;
  844.       break;
  845.  
  846.     case 'n':
  847.       args->handle_cpp = 0;
  848.       break;
  849.  
  850.     default:
  851.       usage ();
  852.     }
  853.     }
  854.   if (tmp_string)
  855.     {
  856.       free (argv);
  857.       free (tmp_string);
  858.     }
  859.   return args;
  860. }
  861.  
  862. /* Grab the next identifier the assembly language source file. This
  863.    state machine is built for speed, not elegance.  */
  864.  
  865. static struct token *
  866. get_token_asm (FILE *in_FILE, void const *args, int *flags)
  867. {
  868. #define ARGS ((struct args_asm const *) args)
  869.   static int new_line = 1;
  870.   unsigned char const *rct = &ARGS->ctype[1];
  871.   char id_0[BUFSIZ];
  872.   char *id = id_0;
  873.   int c;
  874.  
  875.   obstack_blank (&tokens_obstack, offsetof (struct token, tok_name));
  876.  
  877. top:
  878.   c = getc (in_FILE);
  879.   if (ARGS->handle_cpp > 0 && new_line)
  880.     {
  881.       new_line = 0;
  882.       if (c != '#')
  883.     goto next;
  884.       while (ISBORING (c))
  885.     c = getc (in_FILE);
  886.       if (!ISID1ST (c))
  887.     goto next;
  888.       id = id_0;
  889.       *id++ = c;
  890.       while (ISIDREST (c = getc (in_FILE)))
  891.     *id++ = c;
  892.       *id = '\0';
  893.       if (strequ (id_0, "include"))
  894.     {
  895.       while (c != '"' && c != '<')
  896.         c = getc (in_FILE);
  897.       id = id_0;
  898.       *id++ = c = getc (in_FILE);
  899.       while ((c = getc (in_FILE)) != '"' && c != '>')
  900.         *id++ = c;
  901.       *flags = TOK_STRING;
  902.       obstack_grow0 (&tokens_obstack, id_0, id - id_0);
  903.       return (struct token *) obstack_finish (&tokens_obstack);
  904.     }
  905.       if (strnequ (id_0, "if", 2)
  906.       || strequ (id_0, "define")
  907.       || strequ (id_0, "undef"))
  908.     goto next;
  909.       while (c != '\n')
  910.     c = getc (in_FILE);
  911.       new_line = 1;
  912.       goto top;
  913.     }
  914.  
  915. next:
  916.   while (ISBORING (c))
  917.     c = getc (in_FILE);
  918.  
  919.   if (ISCOMMENT (c))
  920.     {
  921.       while (ISCBORING (c))
  922.     c = getc (in_FILE);
  923.       new_line = 1;
  924.     }
  925.  
  926.   if (ISEOF (c))
  927.     {
  928.       new_line = 1;
  929.       obstack_free (&tokens_obstack, obstack_finish (&tokens_obstack));
  930.       return 0;
  931.     }
  932.  
  933.   if (c == '\n')
  934.     {
  935.       new_line = 1;
  936.       goto top;
  937.     }
  938.  
  939.   if (c == '/')
  940.     {
  941.       if ((c = getc (in_FILE)) != '*')
  942.     goto next;
  943.       c = getc (in_FILE);
  944.       for (;;)
  945.     {
  946.       while (ISCCBORING (c))
  947.         c = getc (in_FILE);
  948.       c = getc (in_FILE);
  949.       if (c == '/')
  950.         {
  951.           c = getc (in_FILE);
  952.           break;
  953.         }
  954.       else if (ISEOF (c))
  955.         {
  956.           new_line = 1;
  957.           obstack_free (&tokens_obstack, obstack_finish (&tokens_obstack));
  958.           return 0;
  959.         }
  960.     }
  961.       goto next;
  962.     }
  963.  
  964.   id = id_0;
  965.   if (ARGS->strip_underscore && c == '_' && !ISID1ST (c = getc (in_FILE)))
  966.     {
  967.       obstack_grow0 (&tokens_obstack, "_", 1);
  968.       return (struct token *) obstack_finish (&tokens_obstack);
  969.     }
  970.   *id++ = c;
  971.   if (ISID1ST (c))
  972.     {
  973.       *flags = TOK_NAME;
  974.       while (ISIDREST (c = getc (in_FILE)))
  975.     *id++ = c;
  976.     }
  977.   else if (ISNUMBER (c))
  978.     {
  979.       *flags = TOK_NUMBER;
  980.       while (ISNUMBER (c = getc (in_FILE)))
  981.     *id++ = c;
  982.     }
  983.   else
  984.     {
  985.       if (isprint (c))
  986.     fprintf (stderr, _("junk: `%c'"), c);
  987.       else
  988.     fprintf (stderr, _("junk: `\\%03o'"), c);
  989.       goto next;
  990.     }
  991.  
  992.   *id = '\0';
  993.   for (id = id_0; *id; id++)
  994.     if (ISIGNORE (*id))
  995.       goto next;
  996.   ungetc (c, in_FILE);
  997.   *flags |= TOK_LITERAL;
  998.   obstack_grow0 (&tokens_obstack, id_0, id - id_0);
  999.   return (struct token *) obstack_finish (&tokens_obstack);
  1000. #undef ARGS
  1001. }
  1002.  
  1003. #undef I1
  1004. #undef NM
  1005. #undef NL
  1006. #undef CM
  1007. #undef IG
  1008. #undef C1
  1009. #undef C2
  1010. #undef EF
  1011. #undef ISID1ST
  1012. #undef ISIDREST
  1013. #undef ISNUMBER
  1014. #undef ISEOF
  1015. #undef ISCOMMENT
  1016. #undef ISBORING
  1017. #undef ISCBORING
  1018. #undef ISCCBORING
  1019. #undef ISIGNORE
  1020.  
  1021. /*************** Text *******************************************************/
  1022.  
  1023. #define I1    0x01        /* 1st char of an identifier [a-zA-Z_] */
  1024. #define NM    0x02        /* digit [0-9a-fA-FxX] */
  1025. #define SQ    0x04        /* squeeze these out (.,',-) */
  1026. #define EF    0x80        /* EOF */
  1027.  
  1028. /* Text character classes */
  1029. #define ISID1ST(c)    ((rct)[c] & (I1))
  1030. #define ISIDREST(c)    ((rct)[c] & (I1|NM|SQ))
  1031. #define ISNUMBER(c)    ((rct)[c] & (NM))
  1032. #define ISEOF(c)    ((rct)[c] & (EF))
  1033. #define ISBORING(c)    (!((rct)[c] & (I1|NM|EF)))
  1034. #define ISIDSQUEEZE(c)    ((rct)[c] & (SQ))
  1035.  
  1036. static unsigned char ctype_text[257] =
  1037. {
  1038.   EF,
  1039. /*      0       1       2       3       4       5       6       7   */
  1040. /*    -----   -----   -----   -----   -----   -----   -----   ----- */
  1041. /*000*/ 0,    0,    0,    0,    0,    0,    0,    0,
  1042. /*010*/ 0,    0,    0,    0,    0,    0,    0,    0,
  1043. /*020*/ 0,    0,    0,    0,    0,    0,    0,    0,
  1044. /*030*/ 0,    0,    0,    0,    0,    0,    0,    0,
  1045. /*040*/ 0,    0,    0,    0,    0,    0,    0,    0,
  1046. /*050*/ 0,    0,    0,    0,    0,    0,    0,    0,
  1047. /*060*/ NM,    NM,    NM,    NM,    NM,    NM,    NM,    NM,
  1048. /*070*/ NM,    NM,    0,    0,    0,    0,    0,    0,
  1049. /*100*/ 0,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1,
  1050. /*110*/ I1,    I1,    I1,    I1,    I1|NM,    I1,    I1,    I1,
  1051. /*120*/ I1,    I1,    I1,    I1,    I1,    I1,    I1,    I1,
  1052. /*130*/ I1|NM,    I1,    I1,    0,    0,    0,    0,    I1,
  1053. /*140*/ 0,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1,
  1054. /*150*/ I1,    I1,    I1,    I1,    I1|NM,    I1,    I1,    I1,
  1055. /*160*/ I1,    I1,    I1,    I1,    I1,    I1,    I1,    I1,
  1056. /*170*/ I1|NM,    I1,    I1,    0,    0,    0,    0,    0,
  1057. /*200*/ 0,    0,    0,    0,    0,    0,    0,    0,
  1058. /*210*/ 0,    0,    0,    0,    0,    0,    0,    0,
  1059. /*220*/ 0,    0,    0,    0,    0,    0,    0,    0,
  1060. /*230*/ 0,    0,    0,    0,    0,    0,    0,    0,
  1061. /*240*/ 0,    0,    0,    0,    0,    0,    0,    0,
  1062. /*250*/ 0,    0,    0,    0,    0,    0,    0,    0,
  1063. /*260*/ 0,    0,    0,    0,    0,    0,    0,    0,
  1064. /*270*/ 0,    0,    0,    0,    0,    0,    0,    0,
  1065. /*300*/ I1,    I1,    I1,    I1,    I1,    I1,    I1,    I1,
  1066. /*310*/ I1,    I1,    I1,    I1,    I1,    I1,    I1,    I1,
  1067. /*320*/ I1,    I1,    I1,    I1,    I1,    I1,    I1,    0,
  1068. /*330*/ I1,    I1,    I1,    I1,    I1,    I1,    I1,    I1,
  1069. /*340*/ I1,    I1,    I1,    I1,    I1,    I1,    I1,    I1,
  1070. /*350*/ I1,    I1,    I1,    I1,    I1,    I1,    I1,    I1,
  1071. /*360*/ I1,    I1,    I1,    I1,    I1,    I1,    I1,    0,
  1072. /*370*/ I1,    I1,    I1,    I1,    I1,    I1,    I1,    I1,
  1073. };
  1074.  
  1075. struct args_text
  1076. {
  1077.   unsigned char *ctype;
  1078. };
  1079.  
  1080. static struct args_text args_text = { ctype_text };
  1081.  
  1082. static struct option const long_options_text[] =
  1083. {
  1084.   { "include", required_argument, 0, 'i' },
  1085.   { "exclude", required_argument, 0, 'x' },
  1086.   { 0 }
  1087. };
  1088.  
  1089. static void
  1090. help_me_text (void)
  1091. {
  1092.   printf (_("\
  1093. Text language:\n\
  1094.   -i,--include=CHAR-CLASS  Treat characters of CHAR-CLASS as token constituents\n\
  1095.   -x,--exclude=CHAR-CLASS  Treat characters of CHAR-CLASS as token delimiters\n\
  1096. "));
  1097. }
  1098.  
  1099. static void *
  1100. parse_args_text (char **argv, int argc)
  1101. {
  1102.   char *tmp_string = 0;
  1103.   struct args_text *args;
  1104.  
  1105.   if (argv == 0 || *argv == 0)
  1106.     return &args_text;
  1107.  
  1108.   if (argc)
  1109.     args = &args_text;
  1110.   else
  1111.     {
  1112.       tmp_string = strdup (*argv);
  1113.       tokenize_args_string (tmp_string, &argc, &argv);
  1114.       args = MALLOC (struct args_text, 1);
  1115.       args->ctype = ctype_text;
  1116.     }
  1117.  
  1118.   optind = 0;
  1119.   for (;;)
  1120.     {
  1121.       int optc = getopt_long (argc, argv, "i:x:",
  1122.                   long_options_text, (int *) 0);
  1123.       if (optc < 0)
  1124.     break;
  1125.       if ((optc == 'k' || optc == 'i') && args->ctype == ctype_text)
  1126.     args->ctype = CLONE (ctype_text, unsigned char, cardinalityof (ctype_text));
  1127.       switch (optc)
  1128.     {
  1129.     case 'i':
  1130.       set_uchar_ctype (args->ctype, optarg, I1);
  1131.       break;
  1132.  
  1133.     case 'x':
  1134.       clear_uchar_ctype (args->ctype, optarg, I1);
  1135.       break;
  1136.  
  1137.     default:
  1138.       usage ();
  1139.     }
  1140.     }
  1141.   if (tmp_string)
  1142.     {
  1143.       free (argv);
  1144.       free (tmp_string);
  1145.     }
  1146.   return args;
  1147. }
  1148.  
  1149. /* Grab the next identifier the text source file.  This state machine
  1150.    is built for speed, not elegance.  */
  1151.  
  1152. static struct token *
  1153. get_token_text (FILE *in_FILE, void const *args, int *flags)
  1154. {
  1155. #define ARGS ((struct args_text const *) args)
  1156.   static char id_0[BUFSIZ];
  1157.   unsigned char const *rct = &ARGS->ctype[1];
  1158.   int c;
  1159.   char *id = id_0;
  1160.  
  1161.   obstack_blank (&tokens_obstack, offsetof (struct token, tok_name));
  1162.  
  1163. top:
  1164.   c = getc (in_FILE);
  1165.   while (ISBORING (c))
  1166.     c = getc (in_FILE);
  1167.   if (ISEOF (c))
  1168.     {
  1169.       obstack_free (&tokens_obstack, obstack_finish (&tokens_obstack));
  1170.       return 0;
  1171.     }
  1172.   id = id_0;
  1173.   *id++ = c;
  1174.   if (ISID1ST (c))
  1175.     {
  1176.       *flags = TOK_NAME;
  1177.       while (ISIDREST (c = getc (in_FILE)))
  1178.     if (!ISIDSQUEEZE (c))
  1179.       *id++ = c;
  1180.     }
  1181.   else if (ISNUMBER (c))
  1182.     {
  1183.       *flags = TOK_NUMBER;
  1184.       while (ISNUMBER (c = getc (in_FILE)))
  1185.     *id++ = c;
  1186.     }
  1187.   else
  1188.     {
  1189.       if (isprint (c))
  1190.     fprintf (stderr, _("junk: `%c'"), c);
  1191.       else
  1192.     fprintf (stderr, _("junk: `\\%03o'"), c);
  1193.       goto top;
  1194.     }
  1195.  
  1196.   ungetc (c, in_FILE);
  1197.   *flags |= TOK_LITERAL;
  1198.   obstack_grow0 (&tokens_obstack, id_0, id - id_0);
  1199.   return (struct token *) obstack_finish (&tokens_obstack);
  1200. #undef ARGS
  1201. }
  1202.  
  1203. #undef I1
  1204. #undef NM
  1205. #undef SQ
  1206. #undef EF
  1207. #undef ISID1ST
  1208. #undef ISIDREST
  1209. #undef ISNUMBER
  1210. #undef ISEOF
  1211. #undef ISBORING
  1212. #undef ISIDSQUEEZE
  1213.