home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3952 / unproto.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-02  |  19.0 KB  |  747 lines

  1. /*++
  2. /* NAME
  3. /*    unproto 1
  4. /* SUMMARY
  5. /*    ANSI C to old C converter
  6. /* PACKAGE
  7. /*    unproto
  8. /* SYNOPSIS
  9. /*    /lib/cpp ... | unproto
  10. /*
  11. /*    /somewhere/cpp ...
  12. /* DESCRIPTION
  13. /*    This document describes a filter that sits between the
  14. /*    C preprocessor (usually \fI/lib/cpp\fP) and the next C compiler
  15. /*    pass. It rewrites ANSI-C style function headers, function type
  16. /*    declarations, function pointer types, and function pointer casts
  17. /*    to old style. Other ANSI-isms are passed on without modification
  18. /*    (token pasting, pragmas, etcetera).
  19. /*
  20. /*    For maximal flexibility, the "cpp | unproto" pipeline can  be
  21. /*    packaged as an executable shell script named "/somewhere/cpp".
  22. /*    This script should then be specified to the C compiler as a 
  23. /*    non-default preprocessor.
  24. /*
  25. /*    The overhead of shell script interpretation can be avoided by
  26. /*    having the unprototyper itself open the pipe to the preprocessor.
  27. /*    In that case, the source should be compiled with the PIPE_THROUGH_CPP 
  28. /*    macro defined (usually as "/lib/cpp"), and the resulting binary 
  29. /*    should be installed as "/somewhere/cpp".
  30. /* SEE ALSO
  31. /* .ad
  32. /* .fi
  33. /*    cc(1), how to specify a non-default C preprocessor.
  34. /*
  35. /*    Some versions of the lint command are implemented as a shell
  36. /*    script. It should require only minor modification for integration
  37. /*    with the unprotoizer. Other versions of the lint command accept the same
  38. /*    command syntax as the C compiler for the specification of a non-default
  39. /*    preprocessor. Some research may be needed.
  40. /* DIAGNOSTICS
  41. /*    The progam will complain if it unexpectedly
  42. /*    reaches the end of input.
  43. /* BUGS
  44. /*    Should be run on preprocessed source only, i.e. after macro expansion.
  45. /*
  46. /*    Declarations of (whatever) are misunderstood and will result in
  47. /*    syntax errors.
  48. /* AUTHOR(S)
  49. /*    Wietse Venema (wietse@wzv.win.tue.nl)
  50. /*    Eindhoven University of Technology
  51. /*    Department of Mathematics and Computer Science
  52. /*    Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  53. /* LAST MODIFICATION
  54. /*    91/09/01 23:08:37
  55. /* VERSION/RELEASE
  56. /*    1.1
  57. /*--*/
  58.  
  59. static char unproto_sccsid[] = "@(#) unproto.c 1.1 91/09/01 23:08:37";
  60.  
  61. /* C library */
  62.  
  63. #include <stdio.h>
  64. #include <errno.h>
  65.  
  66. extern void exit();
  67. extern int optind;
  68. extern char *optarg;
  69. extern int getopt();
  70.  
  71. /* Application-specific stuff */
  72.  
  73. #include "vstring.h"
  74. #include "stdarg.h"
  75. #include "parse.h"
  76. #include "token.h"
  77.  
  78. /* Forward declarations. */
  79.  
  80. static struct token *dcl_flush();
  81. static void block_flush();
  82. static void block_dcls();
  83. static struct token *show_func_ptr_type();
  84. static struct token *show_struct_type();
  85. static void show_arg_name();
  86. static void show_type();
  87. static void pair_flush();
  88. static void check_cast();
  89.  
  90. #define    check_cast_flush(t)    (check_cast(t), tok_free(t))
  91.  
  92. #ifdef PIPE_THROUGH_CPP
  93. static int pipe_stdin_through_cpp();
  94. #endif
  95.  
  96. /* Disable debugging printfs while preserving side effects. */
  97.  
  98. #ifdef DEBUG
  99. #define    DPRINTF    printf
  100. #else
  101. #define    DPRINTF (void)
  102. #endif
  103.  
  104. /* An attempt to make some complicated expressions a bit more readable. */
  105.  
  106. #define    STREQ(x,y)        (*(x) == *(y) && !strcmp((x),(y)))
  107.  
  108. #define    LAST_ARG_AND_EQUAL(s,c)    ((s)->next == 0 && (s)->head \
  109.                 && ((s)->head == (s)->tail) \
  110.                 && (STREQ((s)->head->vstr->str, (c))))
  111.  
  112. #define    LIST_BEGINS_WITH_STAR(s) (s->head->head && s->head->head->tokno == '*')
  113.  
  114. #define    IS_FUNC_PTR_TYPE(s)    (s->tokno == TOK_LIST && s->next \
  115.                 && s->next->tokno == TOK_LIST \
  116.                 && LIST_BEGINS_WITH_STAR(s))
  117.  
  118. /* main - driver */
  119.  
  120. int     main(argc, argv)
  121. int     argc;
  122. char  **argv;
  123. {
  124.     register struct token *t;
  125.  
  126. #ifdef    PIPE_THROUGH_CPP            /* pipe through /lib/cpp */
  127.     int     cpp_status;
  128.     int     wait_pid;
  129.     int     cpp_pid;
  130.  
  131.     cpp_pid = pipe_stdin_through_cpp(argv);
  132. #endif
  133.  
  134.     while (t = tok_class(DO_WSPACE)) {
  135.     if (t = dcl_flush(t)) {            /* try declaration */
  136.         if (t->tokno == '{') {        /* examine rejected token */
  137.         block_flush(t);            /* body */
  138.         } else {
  139.         tok_flush(t);            /* other, recover */
  140.         }
  141.     }
  142.     }
  143.  
  144. #ifdef    PIPE_THROUGH_CPP            /* pipe through /lib/cpp */
  145.     while ((wait_pid = wait(&cpp_status)) != -1 && wait_pid != cpp_pid)
  146.      /* void */ ;
  147.     return (wait_pid != cpp_pid || cpp_status != 0);
  148. #else
  149.     return (0);
  150. #endif
  151. }
  152.  
  153. #ifdef    PIPE_THROUGH_CPP        /* pipe through /lib/cpp */
  154.  
  155. /* pipe_stdin_through_cpp - avoid shell script overhead */
  156.  
  157. static int pipe_stdin_through_cpp(argv)
  158. char  **argv;
  159. {
  160.     int     pipefds[2];
  161.     int     pid;
  162.     char  **cpptr = argv;
  163.  
  164.     /*
  165.      * This fix is mandatory for System V Release 2, but it should not harm
  166.      * elsewhere. With most UNIX implementations, the second non-option
  167.      * argument to /lib/cpp specifies the output file. If an output file
  168.      * other than stdout is specified, we must force /lib/cpp to write to
  169.      * stdout, and we must redirect our own standard output to the desired
  170.      * output file.
  171.      */
  172.  
  173.     /* Skip to first non-option argument, if any. */
  174.  
  175.     while (*++cpptr && **cpptr == '-' && *(*cpptr + 1))
  176.      /* void */ ;
  177.  
  178.     /* Take action if there is an output file name argument. */
  179.  
  180.     if (*cpptr && *++cpptr && (**cpptr != '-' || *(*cpptr + 1))) {
  181.  
  182.     /* Redirect our own standard output before we clobber the file name. */
  183.  
  184.     if (freopen(*cpptr, "w", stdout) == 0) {
  185.         perror(*cpptr);
  186.         exit(1);
  187.     }
  188.     /* Clobber the file name argument so that /lib/cpp writes to stdout */
  189.  
  190.     *cpptr = "-";
  191.     }
  192.     /* Set up the pipe that connects /lib/cpp to our standard input. */
  193.  
  194.     if (pipe(pipefds)) {
  195.     perror("pipe");
  196.     exit(1);
  197.     }
  198.     switch (pid = fork()) {
  199.     case -1:                    /* error */
  200.     perror("fork");
  201.     exit(1);
  202.     case 0:                    /* child */
  203.     close(pipefds[0]);
  204.     close(1);
  205.     if (dup(pipefds[1]) != 1)
  206.         error(1, "dup() problem");
  207.     close(pipefds[1]);
  208.     execv(PIPE_THROUGH_CPP, argv);
  209.     perror(PIPE_THROUGH_CPP);
  210.     exit(1);
  211.     default:                    /* parent */
  212.     close(pipefds[1]);
  213.     close(0);
  214.     if (dup(pipefds[0]) != 0)
  215.         error(1, "dup() problem");
  216.     close(pipefds[0]);
  217.     return (pid);
  218.     }
  219. }
  220.  
  221. #endif
  222.  
  223. /* error - report problem and optionally quit */
  224.  
  225. void    error(bailout, s)
  226. int     bailout;
  227. char   *s;
  228. {
  229.     fprintf(stderr, "%s\n", s);
  230.     if (bailout)
  231.     exit(1);
  232. }
  233.  
  234. /* header_flush - rewrite new-style function header to old style */
  235.  
  236. static void header_flush(t)
  237. register struct token *t;
  238. {
  239.     register struct token *s;
  240.  
  241.     /* Do argument names, but suppress void and rewrite trailing ... */
  242.  
  243.     if (LAST_ARG_AND_EQUAL(t->head, "void")) {
  244.     put_str("()\n");            /* no arguments */
  245.     } else {
  246.     for (s = t->head; s; s = s->next) {    /* foreach argument... */
  247.         if (LAST_ARG_AND_EQUAL(s, "...")) {
  248. #ifdef _VA_ALIST_                /* see ./stdarg.h */
  249.         put_ch(s->tokno);        /* ',' */
  250.         put_str(_VA_ALIST_);        /* varargs magic */
  251. #endif
  252.         } else {
  253.         put_ch(s->tokno);        /* opening '(' or ',' */
  254.         show_arg_name(s);        /* extract argument name */
  255.         }
  256.     }
  257.     put_str(")\n");                /* closing ')' */
  258.     }
  259.  
  260.     /* Do argument types, but suppress void and trailing ... */
  261.  
  262.     if (!LAST_ARG_AND_EQUAL(t->head, "void")) {
  263.     for (s = t->head; s; s = s->next) {    /* foreach argument... */
  264.         if (!LAST_ARG_AND_EQUAL(s, "...")) {
  265.         if (s->head != s->tail) {    /* really new-style argument? */
  266.             show_line_number();        /* fix line number */
  267.             show_type(s);        /* rewrite type info */
  268.             put_str(";\n");
  269.         }
  270.         }
  271.     }
  272.     }
  273.     tok_free(t);
  274.     show_line_number();                /* because '{' follows */
  275. }
  276.  
  277. /* show_arg_name - extract argument name from argument type info */
  278.  
  279. static void show_arg_name(s)
  280. register struct token *s;
  281. {
  282.     if (s->head) {
  283.     register struct token *p;
  284.     register struct token *t = 0;
  285.  
  286.     /* Find the last interesting item. */
  287.  
  288.     for (p = s->head; p; p = p->next) {
  289.         if (p->tokno == TOK_WORD) {
  290.         t = p;                /* remember last word */
  291.         } else if (IS_FUNC_PTR_TYPE(p)) {
  292.         t = p;                /* or function pointer */
  293.         p = p->next;
  294.         }
  295.     }
  296.  
  297.     /* Extract argument name from last interesting item. */
  298.  
  299.     if (t) {
  300.         if (t->tokno == TOK_LIST)
  301.         show_arg_name(t->head);        /* function pointer, recurse */
  302.         else
  303.         tok_show(t);            /* print last word */
  304.     }
  305.     }
  306. }
  307.  
  308. /* show_type - rewrite type to old-style syntax */
  309.  
  310. static void show_type(s)
  311. register struct token *s;
  312. {
  313.     register struct token *p;
  314.  
  315.     for (p = s->head; p; p = p->next) {
  316.     if (IS_FUNC_PTR_TYPE(p)) {
  317.         p = show_func_ptr_type(p);        /* function pointer type */
  318.     } else {
  319.         tok_show(p);            /* other */
  320.     }
  321.     }
  322. }
  323.  
  324. /* show_func_ptr_type - display function_pointer type using old-style syntax */
  325.  
  326. static struct token *show_func_ptr_type(t)
  327. struct token *t;
  328. {
  329.     register struct token *s;
  330.  
  331.     /*
  332.      * Rewrite (list1) (list2) to (list1) (). Only (list1) is given to us;
  333.      * the caller must have verified the presence of (list2). Account for the
  334.      * rare case that (list1) is a comma-separated list. That should be an
  335.      * error, but we do not want to waste any information.
  336.      */
  337.  
  338.     for (s = t->head; s; s = s->next) {
  339.     put_ch(s->tokno);            /* opening paren or ',' */
  340.     show_type(s);                /* recurse */
  341.     }
  342.     put_str(")()");                /* closing paren */
  343.     return (t->next);
  344. }
  345.  
  346. /* show_struct_type - display structured type, rewrite function-pointer types */
  347.  
  348. static struct token *show_struct_type(p)
  349. register struct token *p;
  350. {
  351.     tok_show(p);                /* opening brace */
  352.  
  353.     while (p->next) {                /* XXX cannot return 0 */
  354.     p = p->next;
  355.     if (IS_FUNC_PTR_TYPE(p)) {
  356.         p = show_func_ptr_type(p);        /* function-pointer member */
  357.     } else if (p->tokno == '{') {
  358.         p = show_struct_type(p);        /* recurse */
  359.     } else {
  360.         tok_show(p);            /* other */
  361.         if (p->tokno == '}') {
  362.         return (p);            /* done */
  363.         }
  364.     }
  365.     }
  366.     DPRINTF("/* missing '}' */");
  367.     return (p);
  368. }
  369.  
  370. /* is_func_ptr_cast - recognize function-pointer type cast */
  371.  
  372. static int is_func_ptr_cast(t)
  373. register struct token *t;
  374. {
  375.     register struct token *p;
  376.  
  377.     /*
  378.      * Examine superficial structure. Require (list1) (list2). Require that
  379.      * list1 begins with a star.
  380.      */
  381.  
  382.     if (!IS_FUNC_PTR_TYPE(t))
  383.     return (0);
  384.  
  385.     /*
  386.      * Make sure that there is no name in (list1). Do not worry about
  387.      * unexpected tokens, because the compiler will complain anyway.
  388.      */
  389.  
  390.     for (p = t->head->head; p; p = p->next) {
  391.     switch (p->tokno) {
  392.     case TOK_LIST:                /* recurse */
  393.         return (is_func_ptr_cast(p));
  394.     case TOK_WORD:                /* name in list */
  395.         return (0);
  396.     }
  397.     }
  398.     return (1);                    /* no name found */
  399. }
  400.  
  401. /* check_cast - display ()-delimited, comma-separated list */
  402.  
  403. static void check_cast(t)
  404. struct token *t;
  405. {
  406.     register struct token *s;
  407.     register struct token *p;
  408.  
  409.     /*
  410.      * Rewrite function-pointer types and function-pointer casts. Do not
  411.      * blindly rewrite (*list1)(list2) to (*list1)(). Function argument lists
  412.      * are about the only thing we can discard without provoking diagnostics
  413.      * from the compiler.
  414.      */
  415.  
  416.     for (s = t->head; s; s = s->next) {
  417.     put_ch(s->tokno);            /* opening paren or ',' */
  418.     for (p = s->head; p; p = p->next) {
  419.         switch (p->tokno) {
  420.         case TOK_LIST:
  421.         if (is_func_ptr_cast(p)) {    /* not: IS_FUNC_PTR_TYPE(p) */
  422.             p = show_func_ptr_type(p);    /* or we might take away */
  423.         } else {            /* function-call arguments */
  424.             check_cast(p);        /* recurse */
  425.         }
  426.         break;
  427.         case '{':
  428.         p = show_struct_type(p);    /* rewrite func. ptr. types */
  429.         break;
  430.         default:
  431.         tok_show(p);
  432.         break;
  433.         }
  434.     }
  435.     }
  436.     put_ch(')');                /* closing paren */
  437. }
  438.  
  439. /* block_dcls - on the fly rewrite decls/initializers at start of block */
  440.  
  441. static void block_dcls()
  442. {
  443.     register struct token *t;
  444.     register char *cp;
  445.  
  446.     /*
  447.      * Away from the top level, a declaration should be preceded by type or
  448.      * storage-class information. That is why inside blocks, structs and
  449.      * unions we insist on reading one word before passing the _next_ token
  450.      * to the dcl_flush() function.
  451.      * 
  452.      * Struct and union declarations look the same everywhere: we make an
  453.      * exception for these more regular constructs and pass the "struct" and
  454.      * "union" tokens to the type_dcl() function.
  455.      * 
  456.      * At present, this is the only place where we care about C keywords;
  457.      * therefore, keyword processing is not done in the tokenizer where it
  458.      * would slow down everything else, too.
  459.      */
  460.  
  461.     while (t = tok_class(DO_WSPACE)) {
  462.     switch (t->tokno) {
  463.     case TOK_WSPACE:            /* preserve white space */
  464.     case '\n':                /* preserve line count */
  465.         tok_flush(t);
  466.         break;
  467.     case TOK_WORD:                /* type declarations? */
  468.         cp = t->vstr->str;
  469.         /* Get rid of some keywords that can be followed by another word */
  470.         if (STREQ(cp, "return") == 0 && STREQ(cp, "do") == 0
  471.         && STREQ(cp, "sizeof") == 0) {
  472.         /* Special-case the "struct" and "union" keywords */
  473.         if (STREQ(cp, "struct") || STREQ(cp, "union")) {
  474.             t = dcl_flush(t);        /* the special regular case */
  475.         } else {
  476.             tok_flush(t);        /* advance to next token */
  477.             t = dcl_flush(tok_class(DO_WSPACE));
  478.         }
  479.         if (t == 0)            /* dcl_flush() succeeded */
  480.             break;
  481.         }
  482.         /* FALLTRHOUGH */
  483.     default:                /* end of declarations */
  484.         DPRINTF("/* end dcls */");
  485.         /* FALLTRHOUGH */
  486.     case '}':                /* ent of block */
  487.         tok_unget(t);
  488.         return;
  489.     }
  490.     }
  491. }
  492.  
  493. /* block_flush - rewrite struct, union or statement block on the fly */
  494.  
  495. static void block_flush(t)
  496. register struct token *t;
  497. {
  498.     static int count = 0;
  499.  
  500.     tok_flush(t);
  501.     DPRINTF("/*%d*/", ++count);
  502.  
  503.     /*
  504.      * Rewrite function pointer types in declarations and function pointer
  505.      * casts in initializers at start of block.
  506.      */
  507.  
  508.     block_dcls();
  509.  
  510.     /* Remainder of block: only rewrite function pointer casts. */
  511.  
  512.     while (t = tok_class(DO_WSPACE)) {
  513.     if (t->tokno == TOK_LIST) {
  514.         check_cast_flush(t);
  515.     } else if (t->tokno == '{') {
  516.         block_flush(t);
  517.     } else {
  518.         tok_flush(t);
  519.         if (t->tokno == '}') {
  520.         DPRINTF("/*%d*/", count--);
  521.         return;
  522.         }
  523.     }
  524.     }
  525.     DPRINTF("/* missing '}' */");
  526. }
  527.  
  528. /* pair_flush - on the fly rewrite casts in grouped stuff */
  529.  
  530. static void pair_flush(t, start, stop)
  531. register struct token *t;
  532. register int start;
  533. register int stop;
  534. {
  535.     tok_flush(t);
  536.  
  537.     while (t = tok_class(DO_WSPACE)) {
  538.     if (t->tokno == start) {        /* recurse */
  539.         pair_flush(t, start, stop);
  540.     } else if (t->tokno == TOK_LIST) {    /* expression or cast */
  541.         check_cast_flush(t);
  542.     } else {                /* other, copy */
  543.         tok_flush(t);
  544.         if (t->tokno == stop) {        /* done */
  545.         return;
  546.         }
  547.     }
  548.     }
  549.     DPRINTF("/* missing '%c' */", stop);
  550. }
  551.  
  552. /* initializer - on the fly rewrite casts in initializer */
  553.  
  554. static void initializer()
  555. {
  556.     register struct token *t;
  557.  
  558.     while (t = tok_class(DO_WSPACE)) {
  559.     switch (t->tokno) {
  560.     case ',':                /* list separator */
  561.     case ';':                /* list terminator */
  562.         tok_unget(t);
  563.         return;
  564.     case TOK_LIST:                /* expression or cast */
  565.         check_cast_flush(t);
  566.         break;
  567.     case '[':                /* array substript, may nest */
  568.         pair_flush(t, '[', ']');
  569.         break;
  570.     case '{':                /* structured data, may nest */
  571.         pair_flush(t, '{', '}');
  572.         break;
  573.     default:                /* other, just copy */
  574.         tok_flush(t);
  575.         break;
  576.     }
  577.     }
  578. }
  579.  
  580. /* func_ptr_dcl_flush - rewrite function pointer declaration */
  581.  
  582. static struct token *func_ptr_dcl_flush(list)
  583. register struct token *list;
  584. {
  585.     register struct token *t;
  586.  
  587.     /*
  588.      * Ignore blanks because they would be output earlier than the list that
  589.      * preceded them... Recover gracefully from syntax errors.
  590.      */
  591.  
  592.     while (t = tok_class(NO_WSPACE)) {
  593.     switch (t->tokno) {
  594.     case '\n':                /* preserve line count */
  595.         tok_flush(t);
  596.         break;
  597.     case TOK_LIST:
  598.         /* Function pointer type: (list1) (list2) -> (list1) () */
  599.         (void) show_func_ptr_type(list);    /* may be recursive */
  600.         tok_free(list);
  601.         tok_free(t);
  602.         return (0);
  603.     default:                /* not a declaration */
  604.         tok_unget(t);
  605.         return (list);
  606.     }
  607.     }
  608.  
  609.     /* Hit EOF; must be mistake, but do not waste any information. */
  610.  
  611.     return (list);
  612. }
  613.  
  614. /* function_dcl_flush - rewrite function { heading, type declaration } */
  615.  
  616. static struct token *function_dcl_flush(list)
  617. register struct token *list;
  618. {
  619.     register struct token *t;
  620.  
  621.     /*
  622.      * Ignore blanks because they would be output earlier than the list that
  623.      * preceded them...
  624.      */
  625.  
  626.     while (t = tok_class(NO_WSPACE)) {
  627.     switch (t->tokno) {
  628.     case '\n':
  629.         /* Preserve line count */
  630.         tok_flush(t);
  631.         break;
  632.     case '{':
  633.         /* Function heading: word (list) { -> old style heading */
  634.         header_flush(list);
  635.         tok_unget(t);
  636.         return (0);
  637.     case TOK_WORD:
  638.         /* Old-style function heading: word (list) word...{ */
  639.         tok_flush(list);
  640.         tok_unget(t);
  641.         return (0);
  642.     case TOK_LIST:
  643.         /* Function typedef? word (list1) (list) -> word (list1) () */
  644.         tok_flush(list);
  645.         put_str("()");
  646.         tok_free(t);
  647.         return (0);
  648.     case ',':
  649.     case ';':
  650.         /* Function type declaration: word (list) -> word () */
  651.         tok_free(list);
  652.         put_str("()");
  653.         tok_unget(t);
  654.         return (0);
  655.     default:
  656.         /* Something else, reject the list. */
  657.         tok_unget(t);
  658.         return (list);
  659.     }
  660.     }
  661.  
  662.     /* Hit EOF; must be mistake, but do not waste any information. */
  663.  
  664.     return (list);
  665. }
  666.  
  667. /* dcl_flush - parse declaration on the fly, return rejected token */
  668.  
  669. static struct token *dcl_flush(t)
  670. register struct token *t;
  671. {
  672.     register int got_word;
  673.  
  674.     /*
  675.      * Away from the top level, type or storage-class information is required
  676.      * for an (extern or forward) function type declaration or a variable
  677.      * declaration.
  678.      * 
  679.      * With our naive word-counting approach, this means that the caller should
  680.      * read one word before passing the next token to us. This is how we
  681.      * distinguish, for example, function declarations from function calls.
  682.      * 
  683.      * An exception are structs and unions, because they look the same at any
  684.      * level. The caller should give is the "struct" or "union" token.
  685.      */
  686.  
  687.     for (got_word = 0; t; t = tok_class(DO_WSPACE)) {
  688.     switch (t->tokno) {
  689.     case TOK_WSPACE:            /* advance past blanks */
  690.     case '\n':                /* advance past newline */
  691.     case '*':                /* indirection: keep trying */
  692.         tok_flush(t);
  693.         break;
  694.     case TOK_WORD:                /* word: keep trying */
  695.         got_word = 1;
  696.         tok_flush(t);
  697.         break;
  698.     default:
  699.  
  700.         /*
  701.          * Function pointer types can be preceded by zero or more words
  702.          * (at least one when not at the top level). Other stuff can be
  703.          * accepted only after we have seen at least one word (two words
  704.          * when not at the top level). See also the above comment on
  705.          * structs and unions.
  706.          */
  707.  
  708.         if (t->tokno == TOK_LIST && LIST_BEGINS_WITH_STAR(t)) {
  709.         if (t = func_ptr_dcl_flush(t)) {
  710.             return (t);            /* reject token */
  711.         } else {
  712.             got_word = 1;        /* for = and [ and , and ; */
  713.         }
  714.         } else if (got_word == 0) {
  715.         return (t);            /* reject token */
  716.         } else {
  717.         switch (t->tokno) {
  718.         case TOK_LIST:            /* function type */
  719.             if (t = function_dcl_flush(t))
  720.             return (t);        /* reject token */
  721.             break;
  722.         case '[':            /* dimension, does not nest */
  723.             pair_flush(t, '[', ']');
  724.             break;
  725.         case '=':            /* initializer follows */
  726.             tok_flush(t);
  727.             initializer();        /* rewrite casts */
  728.             break;
  729.         case '{':            /* struct, union, may nest */
  730.             block_flush(t);        /* use code for stmt blocks */
  731.             break;
  732.         case ',':            /* separator: keep trying */
  733.             got_word = 0;
  734.             tok_flush(t);
  735.             break;
  736.         case ';':            /* terminator: succeed */
  737.             tok_flush(t);
  738.             return (0);
  739.         default:            /* reject token */
  740.             return (t);
  741.         }
  742.         }
  743.     }
  744.     }
  745.     return (0);                    /* hit EOF */
  746. }
  747.