home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume26 / unproto / part01 / tok_io.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-07  |  9.8 KB  |  465 lines

  1. /*++
  2. /* NAME
  3. /*    tok_io 3
  4. /* SUMMARY
  5. /*    token I/O
  6. /* PACKAGE
  7. /*    unproto
  8. /* SYNOPSIS
  9. /*    #include "token.h"
  10. /*
  11. /*    struct token *tok_get(skip_flag)
  12. /*    int skip_flag;
  13. /*
  14. /*    void tok_unget(t)
  15. /*    struct token *t;
  16. /*
  17. /*    void tok_flush(t)
  18. /*    struct token *t;
  19. /*
  20. /*    void tok_show(t)
  21. /*    struct token *t;
  22. /*
  23. /*    void put_str(s)
  24. /*    char *s;
  25. /*
  26. /*    void put_ch(c)
  27. /*    int c;
  28. /*
  29. /*    void show_line_control()
  30. /*
  31. /*    char curr_path[];
  32. /*    int curr_line;
  33. /* DESCRIPTION
  34. /*    These functions read from stdin and write to stdout. The
  35. /*    output functions maintain some memory so that two successive
  36. /*    words will always be separated by white space.
  37. /*
  38. /*    The input routines eliminate backslash-newline from the input.
  39. /*
  40. /*    tok_get() reads the next token from standard input. It returns
  41. /*    a null pointer when the end of input is reached. If the skip_flag
  42. /*    argument is nonzero, white space (except newline) will be skipped.
  43. /*
  44. /*    tok_unget() implements a limited amount of token push back.
  45. /*
  46. /*    tok_show() displays the contents of a (possibly composite) token
  47. /*    on the standard output.
  48. /*
  49. /*    tok_flush() displays the contents of a (possibly composite) token
  50. /*    on the standard output and makes it available for re-use.
  51. /*
  52. /*    put_str() writes a null-terminated string to standard output.
  53. /*
  54. /*    put_ch() writes one character to standard output.
  55. /*
  56. /*    show_line_control() displays the line number of the next line
  57. /*    to be written to standard output, in a format suitable for the C
  58. /*    compiler parser phase.
  59. /*
  60. /*    The curr_path[] and curr_line variables contain the input file name and 
  61. /*    line number of the most recently read token.
  62. /* BUGS
  63. /*    The tokenizer is just good enough for the unproto filter.
  64. /*    As a benefit, it is quite fast.
  65. /* AUTHOR(S)
  66. /*    Wietse Venema
  67. /*    Eindhoven University of Technology
  68. /*    Department of Mathematics and Computer Science
  69. /*    Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  70. /* LAST MODIFICATION
  71. /*    91/11/30 21:10:26
  72. /* VERSION/RELEASE
  73. /*    1.2
  74. /*--*/
  75.  
  76. static char io_sccsid[] = "@(#) tok_io.c 1.2 91/11/30 21:10:26";
  77.  
  78. /* C library */
  79.  
  80. #include <stdio.h>
  81. #include <ctype.h>
  82.  
  83. extern char *strchr();
  84. extern char *malloc();
  85. extern char *realloc();
  86. extern char *strcpy();
  87.  
  88. /* Application-specific stuff */
  89.  
  90. #include "token.h"
  91. #include "vstring.h"
  92. #include "error.h"
  93.  
  94. /* Stuff to keep track of original source file name and position */
  95.  
  96. char    curr_path[BUFSIZ];        /* current file name */
  97. int     curr_line = 0;            /* # of last read line */
  98.  
  99. /* Forward declarations */
  100.  
  101. static void read_quoted();
  102. static void read_comment();
  103.  
  104. /* Buffered i/o stuff */
  105.  
  106. static struct vstring *buf = 0;        /* read-ahead buffer */
  107. static char *bp = "";            /* buffer position */
  108.  
  109. #ifdef DEBUG
  110. #define    INITBUF    1            /* small initial buffer size */
  111. #else
  112. #define    INITBUF BUFSIZ            /* reasonable initial buffer size */
  113. #endif
  114.  
  115. #define    input()        (*bp ? *bp++ : next_line())
  116. #define    unput(c)    (*--bp = (c))
  117.  
  118. #define    TOK_BUFSIZE    5        /* token push-back buffer size */
  119.  
  120. static struct token *tok_buf[TOK_BUFSIZE];
  121. static int tok_bufpos = 0;
  122.  
  123. /* Type of last token sent to output, for pretty printing */
  124.  
  125. static int last_tok = 0;
  126.  
  127. /* Directives that should be ignored. */
  128.  
  129. #ifdef IGNORE_DIRECTIVES
  130.  
  131. static char *ignore_directives[] = {
  132.     IGNORE_DIRECTIVES,
  133.     0,
  134. };
  135.  
  136. #endif
  137.  
  138. /* Modified string and ctype stuff. */
  139.  
  140. #define    STREQUAL(x,y)    (*(x) == *(y) && strcmp((x),(y)) == 0)
  141.  
  142. #define    ISALNUM(c)    (isalnum(c) || (c) == '_')
  143. #define    ISALPHA(c)    (isalpha(c) || (c) == '_')
  144. #define    ISSPACE(c)    (isspace(c) && c != '\n')
  145. #define    ISDOT(c)    (c == '.')
  146.  
  147. /* Collect all characters that satisfy one condition */
  148.  
  149. #define    COLLECT(v,c,cond) { \
  150.                 register struct vstring *vs = v; \
  151.                 register char *cp = vs->str; \
  152.                 *cp++ = c; \
  153.                 for (;;) { \
  154.                     if ((c = input()) == 0) { \
  155.                     break; \
  156.                     } else if (cond) { \
  157.                     if (VS_ADDCH(vs, cp, c) == 0) \
  158.                         error(1, "out of memory"); \
  159.                     } else { \
  160.                     unput(c); \
  161.                     break; \
  162.                     } \
  163.                 } \
  164.                 *cp = 0; \
  165.                 }
  166.  
  167. /* do_control - parse control line, uses tok_get() */
  168.  
  169. static int do_control()
  170. {
  171.     struct token *t1;
  172.     struct token *t2;
  173.     int     pass_thru = 1;        /* 0 = ignore, 1 = output */
  174.  
  175.     (void) input();                /* skip the hash */
  176.  
  177.     if (t1 = tok_get(NO_WSPACE)) {
  178.     switch (t1->tokno) {
  179.  
  180.         /*
  181.          * In case of line number control, the remainder of the line has
  182.          * the format: linenumber "pathname".
  183.          */
  184.     case TOK_NUMBER:
  185.         if (t2 = tok_get(NO_WSPACE)) {
  186.         if (t2->tokno == '"') {
  187.             curr_line = atoi(t1->vstr->str) - 1;
  188.             strcpy(curr_path, t2->vstr->str);
  189.         }
  190.         tok_free(t2);
  191.         }
  192.         break;
  193.  
  194. #ifdef IGNORE_DIRECTIVES
  195.     case TOK_WORD:
  196.         /* Optionally ignore other #directives, such as #pragma. */
  197.         {
  198.         char  **cpp;
  199.         char   *cp = t1->vstr->str;
  200.  
  201.         for (cpp = ignore_directives; *cpp; cpp++) {
  202.             if (STREQUAL(cp, *cpp)) {
  203.             pass_thru = 0;
  204.             break;
  205.             }
  206.         }
  207.         }
  208.         break;
  209. #endif
  210.     }
  211.     tok_free(t1);
  212.     }
  213.     return (pass_thru);
  214. }
  215.  
  216. /* next_line - read one logical line, handle #control */
  217.  
  218. static int next_line()
  219. {
  220.     register int c;
  221.     register char *cp;
  222.  
  223.     /* Allocate buffer upon first entry */
  224.  
  225.     if (buf == 0)
  226.     buf = vs_alloc(INITBUF);
  227.  
  228.     for (;;) {
  229.     cp = buf->str;
  230.  
  231.     /* Account for EOF and line continuations */
  232.  
  233.     while ((c = getchar()) != EOF) {
  234.         if (VS_ADDCH(buf, cp, c) == 0)    /* store character */
  235.         error(1, "out of memory");
  236.         if (c == '\n') {            /* real end of line */
  237.         curr_line++;
  238.         break;
  239.         } else if (c == '\\') {
  240.         if ((c = getchar()) == EOF) {    /* XXX strip backslash-EOF */
  241.             break;
  242.         } else if (c == '\n') {        /* strip backslash-newline */
  243.             curr_line++;
  244.             put_ch('\n');        /* preserve line count */
  245.             cp--;            /* un-store backslash */
  246.         } else {
  247.             ungetc(c, stdin);        /* keep backslash-other */
  248.         }
  249.         }
  250.     }
  251.     *cp = 0;
  252.     bp = buf->str;
  253.  
  254.     /* Account for EOF and #control */
  255.  
  256.     switch (bp[0]) {
  257.     case 0:                    /* EOF */
  258.         return (0);
  259.     case '#':                /* control */
  260.         if (do_control())
  261.         fputs(buf->str, stdout);    /* pass through */
  262.         else
  263.         putchar('\n');            /* filter out */
  264.         break;
  265.     default:                /* non-control */
  266.         return (input());
  267.     }
  268.     }
  269. }
  270.  
  271. /* tok_unget - push back one token */
  272.  
  273. void    tok_unget(t)
  274. register struct token *t;
  275. {
  276.     if (tok_bufpos >= TOK_BUFSIZE)
  277.     error(1, "too much pushback");
  278.     tok_buf[tok_bufpos++] = t;
  279. }
  280.  
  281. /* tok_get - get next token */
  282.  
  283. struct token *tok_get(skip_flag)
  284. int     skip_flag;
  285. {
  286.     register struct token *t;
  287.     register int c;
  288.     int     d;
  289.  
  290.     /* Use push-back token, if any. */
  291.  
  292.     if (tok_bufpos) {
  293.     t = tok_buf[--tok_bufpos];
  294.     return (t);
  295.     }
  296.  
  297.     /*
  298.      * Get one from the pool and fill it in. The loop is here in case we
  299.      * should skip white-space tokens, which happens in a minority of all
  300.      * cases.
  301.      */
  302.  
  303.     t = tok_alloc();
  304.  
  305.     for (;;) {
  306.     if ((c = input()) == 0) {
  307.         tok_free(t);
  308.         return (0);
  309.     } else if (!isascii(c)) {
  310.         t->vstr->str[0] = c;
  311.         t->vstr->str[1] = 0;
  312.         t->tokno = TOK_OTHER;
  313.         return (t);
  314.     } else if (c == '"' || c == '\'') {
  315.         read_quoted(t, c);
  316.         t->tokno = c;
  317.         return (t);
  318.     } else if (ISALPHA(c)) {
  319.         COLLECT(t->vstr, c, ISALNUM(c));
  320.         t->tokno = TOK_WORD;
  321.         return (t);
  322.     } else if (isdigit(c)) {
  323.         COLLECT(t->vstr, c, isdigit(c));
  324.         t->tokno = TOK_NUMBER;
  325.         return (t);
  326.     } else if (ISSPACE(c)) {
  327.         COLLECT(t->vstr, c, ISSPACE(c));
  328.         if (skip_flag)
  329.         continue;
  330.         t->tokno = TOK_WSPACE;
  331.         return (t);
  332.     } else if (ISDOT(c)) {
  333.         COLLECT(t->vstr, c, ISDOT(c));
  334.         t->tokno = TOK_OTHER;
  335.         return (t);
  336.     } else {
  337.         t->vstr->str[0] = c;
  338.         if (c == '/') {
  339.         if ((d = input()) == '*') {
  340.             t->vstr->str[1] = d;    /* comment */
  341.             read_comment(t->vstr);
  342.             if (skip_flag)
  343.             continue;
  344.             t->tokno = TOK_WSPACE;
  345.             return (t);
  346.         } else {
  347.             unput(d);
  348.         }
  349.         }
  350.         t->vstr->str[1] = 0;
  351.         t->tokno = c;
  352.         return (t);
  353.     }
  354.     }
  355. }
  356.  
  357. /* read_qouted - read string or character literal */
  358.  
  359. static void read_quoted(t, ch)
  360. register struct token *t;
  361. int     ch;
  362. {
  363.     register char *cp = t->vstr->str;
  364.     register int c;
  365.  
  366.     *cp++ = ch;
  367.  
  368.     while (c = input()) {
  369.     if (c == '\n') {            /* newline in string */
  370.         unput(c);
  371.         break;
  372.     }
  373.     if (VS_ADDCH(t->vstr, cp, c) == 0)    /* store character */
  374.         error(1, "out of memory");
  375.     if (c == ch)                /* end of string */
  376.         break;
  377.     if (c == '\\')                /* eat next character */
  378.         if ((c = input()) != 0 && VS_ADDCH(t->vstr, cp, c) == 0)
  379.         error(1, "out of memory");
  380.     }
  381.     *cp = 0;
  382.     return;
  383. }
  384.  
  385. /* read_comment - stuff a whole comment into one huge token */
  386.  
  387. static void read_comment(vs)
  388. register struct vstring *vs;
  389. {
  390.     register char *cp = vs->str + 2;    /* skip slash star */
  391.     register int c;
  392.     register int d;
  393.  
  394.     while (c = input()) {
  395.     if (VS_ADDCH(vs, cp, c) == 0)
  396.         error(1, "out of memory");
  397.     if (c == '*') {
  398.         if ((d = input()) == '/') {
  399.         if (VS_ADDCH(vs, cp, d) == 0)
  400.             error(1, "out of memory");
  401.         break;
  402.         } else {
  403.         unput(d);
  404.         }
  405.     }
  406.     }
  407.     *cp = 0;
  408. }
  409.  
  410. /* put_str - output a string */
  411.  
  412. void    put_str(s)
  413. char   *s;
  414. {
  415.     fputs(s, stdout);
  416.     last_tok = s[0];                /* XXX */
  417. #ifdef DEBUG
  418.     fflush(stdout);
  419. #endif
  420. }
  421.  
  422. /* put_ch - put character */
  423.  
  424. void    put_ch(c)
  425. int     c;
  426. {
  427.     last_tok = putchar(c);
  428. #ifdef DEBUG
  429.     fflush(stdout);
  430. #endif
  431. }
  432.  
  433. /* tok_show - output (possibly composite) token */
  434.  
  435. void    tok_show(t)
  436. struct token *t;
  437. {
  438.     register struct token *p;
  439.     register struct token *s;
  440.  
  441.     switch (t->tokno) {
  442.     case TOK_LIST:
  443.     for (s = t->head; s; s = s->next) {
  444.         put_ch(s->tokno);            /* opening paren or ',' */
  445.         for (p = s->head; p; p = p->next)
  446.         tok_show(p);
  447.     }
  448.     put_ch(')');                /* closing paren */
  449.     break;
  450.     case TOK_WORD:
  451.     if (ISALPHA(last_tok))
  452.         putchar(' ');
  453.     /* FALLTRHOUGH */
  454.     default:
  455.     fputs(t->vstr->str, stdout);        /* token contents */
  456.     last_tok = t->vstr->str[0];
  457. #ifdef DEBUG
  458.     fflush(stdout);
  459. #endif
  460.     if (t->head)                /* trailing blanks */
  461.             for (p = t->head; p; p = p->next)
  462.                 tok_show(p);
  463.     }
  464. }
  465.