home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / cproto.zip / cproto46 / semantic.c < prev    next >
C/C++ Source or Header  |  1998-01-18  |  31KB  |  1,226 lines

  1. /* $Id: semantic.c,v 4.5 1998/01/19 00:49:26 cthuang Exp $
  2.  *
  3.  * Semantic actions executed by the parser of the
  4.  * C function prototype generator.
  5.  */
  6. #include <stdio.h>
  7. #include "cproto.h"
  8. #include "semantic.h"
  9.  
  10. #if OPT_LINTLIBRARY
  11. static    int        put_parameter        ARGS((FILE *outf, Parameter *p, int name_only, int count, int commented));
  12. #define    putParameter(fp,p,f,n,c)        put_parameter(fp, p, f, n, c)
  13. #else
  14. static    int        put_parameter        ARGS((FILE *outf, Parameter *p, int commented));
  15. #define    putParameter(fp,p,f,n,c)        put_parameter(fp, p, c)
  16. #endif
  17.  
  18. static    char *        concat_string        ARGS((char *a, char *b));
  19. #if OPT_LINTLIBRARY
  20. static    char *        glue_strings        ARGS((char *a, char *b));
  21. #endif
  22. static    boolean        is_void_parameter    ARGS((Parameter *p));
  23. static    Parameter *    search_parameter_list    ARGS((ParameterList *params, char *name));
  24. static    void        put_param_list        ARGS((FILE *outf, Declarator *declarator, int commented));
  25. static    void        put_parameters        ARGS((FILE *outf, Declarator *declarator, int commented));
  26. static    void        put_func_declarator    ARGS((FILE *outf, Declarator *declarator, int commented));
  27. static    void        put_declarator        ARGS((FILE *outf, Declarator *declarator, int commented));
  28. static    void        put_decl_spec        ARGS((FILE *outf, DeclSpec *decl_spec));
  29. #if OPT_LINTLIBRARY
  30. static    void        put_llib_params        ARGS((Declarator *d, int c));
  31. #endif
  32. static    int        uses_varargs        ARGS((Declarator *declarator));
  33. static    void        check_void_param    ARGS((Declarator *declarator));
  34. static    void        set_param_decl_spec    ARGS((Declarator *declarator));
  35. static    void        put_param_decl        ARGS((Declarator *declarator, int commented));
  36.  
  37. /* Head function declarator in a prototype or function definition */
  38. static Declarator *func_declarator;
  39.  
  40. /* Role of the function declarator
  41.  * FUNC_PROTO if it is the declarator in a function prototype.
  42.  * FUNC_DEF if it is the declarator in a function definition.
  43.  */
  44. static int where;
  45.  
  46. /* Output format to use */
  47. static int format;
  48.  
  49. /* Function-parameter level, used to simplify logic that comments/suppresses
  50.  * function parameters in the output.
  51.  */
  52. static int nestedParams;
  53.  
  54. /* Initialize a new declaration specifier part.
  55.  */
  56. void
  57. new_decl_spec (decl_spec, text, offset, flags)
  58. DeclSpec *decl_spec;
  59. char *text;
  60. long offset;
  61. int flags;
  62. {
  63. #if OPT_LINTLIBRARY
  64.     if (lintLibrary()) {
  65.     if (!strcmp(text, "register"))
  66.         text = "";
  67.     }
  68. #endif
  69.     decl_spec->text = xstrdup(text);
  70.     decl_spec->begin = offset;
  71.     decl_spec->flags = flags;
  72. }
  73.  
  74. /* Free storage used by a declaration specifier part.
  75.  */
  76. void
  77. free_decl_spec (decl_spec)
  78. DeclSpec *decl_spec;
  79. {
  80.     free(decl_spec->text);
  81. }
  82.  
  83. /* Create a new string by joining two strings with a space between them.
  84.  * Return a pointer to the resultant string.
  85.  * If out of memory, output an error message and exit.
  86.  */
  87. static char *
  88. concat_string (a, b)
  89. char *a, *b;
  90. {
  91.     char *result;
  92.  
  93.     result = xmalloc(strlen(a) + strlen(b) + 2);
  94.     strcpy(result, a);
  95.     strcat(result, " ");
  96.     strcat(result, b);
  97.     return result;
  98. }
  99.  
  100. #if OPT_LINTLIBRARY
  101. static char *
  102. glue_strings (a, b)    /* concatenate w/o embedded blank */
  103. char *a, *b;
  104. {
  105.     char *result;
  106.  
  107.     result = xmalloc(strlen(a) + strlen(b) + 2);
  108.     strcpy(result, a);
  109.     strcat(result, b);
  110.     return result;
  111. }
  112. #endif
  113.  
  114. /* Append two declaration specifier parts together.
  115.  */
  116. void
  117. join_decl_specs (result, a, b)
  118. DeclSpec *result, *a, *b;
  119. {
  120.     result->text = concat_string(a->text, b->text);
  121.     result->flags = a->flags | b->flags;
  122.     result->begin = a->begin;
  123. }
  124.  
  125. /* Output an error message if the declaration specifier is an untagged
  126.  * struct, union or enum.
  127.  */
  128. void
  129. check_untagged (decl_spec)
  130. DeclSpec *decl_spec;
  131. {
  132.     if (strstr(decl_spec->text, "struct {}") != NULL) {
  133.     put_error();
  134.     fputs("untagged struct declaration\n", stderr);
  135.     } else if (strstr(decl_spec->text, "union {}") != NULL) {
  136.     put_error();
  137.     fputs("untagged union declaration\n", stderr);
  138.     } else if (strstr(decl_spec->text, "enum {}") != NULL) {
  139.     put_error();
  140.     fputs("untagged enum declaration\n", stderr);
  141.     }
  142. }
  143.  
  144. /* Allocate and initialize a declarator.
  145.  */
  146. Declarator *
  147. new_declarator (text, name, offset)
  148. char *text, *name;
  149. long offset;
  150. {
  151.     Declarator *d;
  152.  
  153.     d = NEW(Declarator);
  154.     d->text = xstrdup(text);
  155.     d->name = xstrdup(name);
  156.     d->begin = offset;
  157.     d->begin_comment = d->end_comment = 0;
  158.     d->func_def = FUNC_NONE;
  159.     new_ident_list(&d->params);
  160.     d->head = d;
  161.     d->func_stack = NULL;
  162.     d->pointer = FALSE;
  163.     return d;
  164. }
  165.  
  166. /* Free storage used by a declarator.
  167.  */
  168. void
  169. free_declarator (d)
  170. Declarator *d;
  171. {
  172.     free(d->text);
  173.     free(d->name);
  174.     free_param_list(&d->params);
  175.     if (d->func_stack != NULL)
  176.     free_declarator(d->func_stack);
  177.     free(d);
  178. }
  179.  
  180. /* Initialize a declarator list and add the given declarator to it.
  181.  */
  182. void
  183. new_decl_list (decl_list, declarator)
  184. DeclaratorList *decl_list;
  185. Declarator *declarator;
  186. {
  187.     decl_list->first = decl_list->last = declarator;
  188.     declarator->next = NULL;
  189. }
  190.  
  191. /* Free storage used by the declarators in the declarator list.
  192.  */
  193. void
  194. free_decl_list (decl_list)
  195. DeclaratorList *decl_list;
  196. {
  197.     Declarator *d, *next;
  198.  
  199.     d = decl_list->first;
  200.     while (d != NULL) {
  201.     next = d->next;
  202.     free_declarator(d);
  203.     d = next;
  204.     }
  205. }
  206.  
  207. /* Add the declarator to the declarator list.
  208.  */
  209. void
  210. add_decl_list (to, from, declarator)
  211. DeclaratorList *to, *from;
  212. Declarator *declarator;
  213. {
  214.     to->first = from->first;
  215.     from->last->next = declarator;
  216.     to->last = declarator;
  217.     to->last->next = NULL;
  218. }
  219.  
  220. /* Create a new parameter structure.
  221.  */
  222. Parameter *
  223. new_parameter (decl_spec, declarator)
  224. DeclSpec *decl_spec;
  225. Declarator *declarator;
  226. {
  227.     Parameter *param;
  228.     param = NEW(Parameter);
  229.  
  230.     if (decl_spec == NULL) {
  231.     new_decl_spec(¶m->decl_spec, "", 0L, DS_NONE);
  232.     } else {
  233.     param->decl_spec = *decl_spec;
  234.     }
  235.  
  236.     if (declarator == NULL) {
  237.     declarator = new_declarator("", "", 0L);
  238.     }
  239.     param->declarator = declarator;
  240.  
  241.     param->comment = NULL;
  242.     return param;
  243. }
  244.  
  245. /* Free the storage used by the parameter.
  246.  */
  247. void
  248. free_parameter (param)
  249. Parameter *param;
  250. {
  251.     free_decl_spec(¶m->decl_spec);
  252.     free_declarator(param->declarator);
  253.     if (param->comment != NULL)
  254.     free(param->comment);
  255.     free(param);
  256. }
  257.  
  258. /* Return TRUE if the parameter is void.
  259.  */
  260. static boolean
  261. is_void_parameter (p)
  262. Parameter *p;
  263. {
  264.     return p == NULL || (strcmp(p->decl_spec.text, "void") == 0 &&
  265.      p->declarator->text[0] == '\0');
  266. }
  267.  
  268. /* Initialize a list of function parameters.
  269.  */
  270. void
  271. new_param_list (param_list, param)
  272. ParameterList *param_list;
  273. Parameter *param;
  274. {
  275.     param_list->first = param_list->last = param;
  276.     param->next = NULL;
  277.  
  278.     param_list->begin_comment = param_list->end_comment = 0;
  279.     param_list->comment = NULL;
  280. }
  281.  
  282. /* Free storage used by the elements in the function parameter list.
  283.  */
  284. void
  285. free_param_list (param_list)
  286. ParameterList *param_list;
  287. {
  288.     Parameter *p, *next;
  289.  
  290.     p = param_list->first;
  291.     while (p != NULL) {
  292.     next = p->next;
  293.     free_parameter(p);
  294.     p = next;
  295.     }
  296.  
  297.     if (param_list->comment != NULL)
  298.     free(param_list->comment);
  299. }
  300.  
  301. /* Add the parameter to the function parameter list.
  302.  */
  303. void
  304. add_param_list (to, from, param)
  305. ParameterList *to, *from;
  306. Parameter *param;
  307. {
  308.     to->first = from->first;
  309.     from->last->next = param;
  310.     to->last = param;
  311.     param->next = NULL;
  312. }
  313.  
  314. /* Initialize an empty list of function parameter names.
  315.  */
  316. void
  317. new_ident_list (param_list)
  318. ParameterList *param_list;
  319. {
  320.     param_list->first = param_list->last = NULL;
  321.     param_list->begin_comment = param_list->end_comment = 0;
  322.     param_list->comment = NULL;
  323. }
  324.  
  325. /* Add an item to the list of function parameter declarations but set only
  326.  * the parameter name field.
  327.  */
  328. void
  329. add_ident_list (to, from, name)
  330. ParameterList *to, *from;
  331. char *name;
  332. {
  333.     Parameter *p;
  334.     Declarator *declarator;
  335.  
  336.     declarator = new_declarator(name, name, 0L);
  337.     p = new_parameter((DeclSpec *)0, declarator);
  338.  
  339.     to->first = from->first;
  340.     if (to->first == NULL) {
  341.     to->first = p;
  342.     } else {
  343.     from->last->next = p;
  344.     }
  345.     to->last = p;
  346.     p->next = NULL;
  347. }
  348.  
  349. /* Search the list of parameters for a matching parameter name.
  350.  * Return a pointer to the matching parameter or NULL if not found.
  351.  */
  352. static Parameter *
  353. search_parameter_list (params, name)
  354. ParameterList *params;
  355. char *name;
  356. {
  357.     Parameter *p;
  358.  
  359.     for (p = params->first; p != NULL; p = p->next) {
  360.     if (strcmp(p->declarator->name, name) == 0)
  361.         return p;
  362.     }
  363.     return (Parameter *)NULL;
  364. }
  365.  
  366. /* For each name in the declarator list <declarators>, set the declaration
  367.  * specifier part of the parameter in <params> having the same name.
  368.  * This is also where we promote formal parameters.  Parameters of type
  369.  * "char", "unsigned char", "short", or "unsigned short" are promoted to
  370.  * "int".  Parameters of type "float" are promoted to "double".
  371.  */
  372. void
  373. set_param_types (params, decl_spec, declarators)
  374. ParameterList *params;
  375. DeclSpec *decl_spec;
  376. DeclaratorList *declarators;
  377. {
  378.     Declarator *d;
  379.     Parameter *p;
  380.     char *decl_spec_text;
  381.  
  382.     for (d = declarators->first; d != NULL; d = d->next) {
  383.     /* Search the parameter list for a matching name. */
  384.     if ((p = search_parameter_list(params, d->name)) == NULL) {
  385.         put_error();
  386.         fprintf(stderr, "declared argument \"%s\" is missing\n", d->name);
  387.     } else {
  388.         decl_spec_text = decl_spec->text;
  389.         if (promote_param && strcmp(d->text, d->name) == 0) {
  390.         if (decl_spec->flags & (DS_CHAR | DS_SHORT))
  391.             decl_spec_text = "int";
  392.         else if (decl_spec->flags & DS_FLOAT)
  393.             decl_spec_text = "double";
  394.         }
  395.         free(p->decl_spec.text);
  396.         p->decl_spec.text = xstrdup(decl_spec_text);
  397.  
  398.         free_declarator(p->declarator);
  399.         p->declarator = d;
  400.     }
  401.     }
  402. }
  403.  
  404. /* Output a function parameter.
  405.  */
  406. static int
  407. put_parameter (outf, p,
  408. #if OPT_LINTLIBRARY
  409.     name_only, count,
  410. #endif
  411.     commented)
  412. FILE *outf;
  413. Parameter *p;
  414. #if OPT_LINTLIBRARY
  415. int    name_only;    /* nonzero if we only show the parameter name */
  416. int    count;        /* index in parameter list if we haven't names */
  417. #endif
  418. int    commented;    /* comment-delimiters already from higher level */
  419. {
  420.     char    *s;
  421.     char    gap = ' ';
  422.  
  423. #if OPT_LINTLIBRARY
  424.     if (name_only) {
  425.     s = p->declarator->name;
  426.     if (lintLibrary()) {
  427.         while (*s == '*')
  428.         s++;
  429.         if (*s == '\0' && !is_void_parameter(p))
  430.         s = supply_parm(count);
  431.     }
  432.     put_string(outf, s);    /* ... remainder of p->declarator.name */
  433.     return (TRUE);
  434.     }
  435. #endif
  436.  
  437.     s = p->decl_spec.text;
  438. #if OPT_LINTLIBRARY
  439.     if (lintLibrary()) {
  440.     if (is_void_parameter(p))
  441.         return (FALSE);
  442.     indent(outf);
  443.     if (knrLintLibrary() && !*s)
  444.         s = "int";
  445.     if (strlen(s) < 8)
  446.         gap = '\t';
  447.     }
  448. #endif
  449.  
  450.     put_string(outf, s);
  451.  
  452. #if OPT_LINTLIBRARY
  453.     if (lintLibrary()) {
  454.     char *t, *u;
  455.     s = p->declarator->text;
  456.     while (*s == '*')
  457.         s++;
  458.     if (*s == '\0') {
  459.         u = p->declarator->text;
  460.         p->declarator->text = glue_strings(u, supply_parm(count));
  461.         free(u);
  462.     } else if (p->declarator->name[0] == '\0') {
  463.         if ((t = strstr(s, "%s")) != 0) {
  464.         int parenthesized = FALSE;
  465.         Declarator *q;
  466.  
  467.         free(p->declarator->name);
  468.         p->declarator->name = xstrdup(supply_parm(count));
  469.  
  470.         for (q = p->declarator; q != 0; q = q->func_stack) {
  471.             if (q->func_def == FUNC_NONE) {
  472.             if (!strcmp(q->text, "(*)")) {
  473.                 char temp[20];
  474.                 sprintf(temp, "(*%s)", p->declarator->name);
  475.                 free(q->text);
  476.                 q->text = xstrdup(temp);
  477.                 parenthesized = TRUE;
  478.             } else {
  479.                 free(q->text);
  480.                 q->text = xstrdup(p->declarator->name);
  481.             }
  482.             break;
  483.             }
  484.         }
  485.         if (!parenthesized) {
  486.             if ((u = strchr(t, PAREN_L)) != 0) { /* e.g., "*%s()" */
  487.             t = p->declarator->text;
  488.             u = xmalloc(strlen(t) + 3);
  489.             (void)sprintf(u, "(%s)", t);
  490.             p->declarator->text = u;
  491.             free(t);
  492.             }
  493.         }
  494.         } else {    /* e.g., s is "[20]" for "char [20]" parameter */
  495.                 /* ...or something like "* const *" */
  496.         while (*s != '\0' && *s != SQUARE_L)
  497.             s++;
  498.         u = xstrdup(s);            /* the "[20]" */
  499.         *s = '\0';
  500.         if (s != p->declarator->text) {
  501.             s = glue_strings(p->declarator->text, supply_parm(count));
  502.         } else {
  503.             s = xstrdup(supply_parm(count));
  504.         }
  505.         p->declarator->text = glue_strings(s, u);
  506.         free(u);
  507.         free(s);
  508.         }
  509.     }
  510.     }
  511. #endif
  512.  
  513.     if (p->declarator->text[0] != '\0') {
  514.     if (strcmp(p->declarator->text, ELLIPSIS) == 0) {
  515.         put_string(outf, ELLIPSIS);
  516.     } else {
  517.         if (proto_style != PROTO_ABSTRACT || proto_comments
  518.          || where != FUNC_PROTO
  519.          || strcmp(p->declarator->text, p->declarator->name) != 0)
  520.         put_char(outf, gap);
  521.         put_declarator(outf, p->declarator, commented);
  522.     }
  523.     }
  524.     return (TRUE);
  525. }
  526.  
  527. /* Output a parameter list.
  528.  */
  529. static void
  530. put_param_list (outf, declarator, commented)
  531. FILE *outf;
  532. Declarator *declarator;
  533. int commented;
  534. {
  535. #if OPT_LINTLIBRARY
  536.     int count = 0;
  537. #endif
  538.     Parameter *p;
  539.     int f;
  540.     int hide_it = (where == FUNC_PROTO) && (proto_style == PROTO_TRADITIONAL);
  541.     int do_cmt = proto_comments && hide_it;
  542.  
  543.     p = declarator->params.first;
  544.     if (hide_it && !do_cmt) {
  545.     ;
  546.     } else if (is_void_parameter(p)) {
  547.     if (do_cmt) {
  548.         if (!commented)
  549.             put_string(outf, COMMENT_BEGIN);
  550.         put_string(outf, "void");
  551.         if (!commented)
  552.             put_string(outf, COMMENT_END);
  553.     } else if (!hide_it)
  554. #if OPT_LINTLIBRARY
  555.     if (!knrLintLibrary())
  556. #endif
  557.         put_string(outf, "void");
  558.     } else {
  559.     f = (declarator == func_declarator) ? format : FMT_OTHER;
  560.  
  561. #if OPT_LINTLIBRARY
  562.     if (where == FUNC_PROTO
  563.      && knrLintLibrary()
  564.      && (func_declarator != declarator)) {
  565.         do_cmt = TRUE;    /* patch: shouldn't have gotten here at all */
  566.     }
  567. #endif
  568.     if (where == FUNC_DEF && declarator->params.comment != NULL)
  569.         put_string(outf, declarator->params.comment);
  570.     else if (do_cmt && !commented)
  571.         put_string(outf, COMMENT_BEGIN);
  572.  
  573.     put_string(outf, fmt[f].first_param_prefix);
  574.     (void)putParameter(outf, p, knrLintLibrary(), ++count, commented);
  575.  
  576.     while (p->next != NULL) {
  577. #if OPT_LINTLIBRARY
  578.         if (lint_ellipsis(p->next))
  579.         break;
  580. #endif
  581.         put_char(outf, ',');
  582.         if (where == FUNC_DEF && p->comment != NULL)
  583.         put_string(outf, p->comment);
  584.  
  585.         p = p->next;
  586.         put_string(outf, fmt[f].middle_param_prefix);
  587.         (void)putParameter(outf, p, knrLintLibrary(), ++count, commented);
  588.     }
  589.     if (where == FUNC_DEF && p->comment != NULL)
  590.         put_string(outf, p->comment);
  591.     else if (do_cmt && !commented)
  592.         put_string(outf, COMMENT_END);
  593.  
  594.     put_string(outf, fmt[f].last_param_suffix);
  595.     }
  596. }
  597.  
  598. /* Output function parameters.
  599.  */
  600. static void
  601. put_parameters (outf, declarator, commented)
  602. FILE *outf;
  603. Declarator *declarator;
  604. int commented;
  605. {
  606.     Parameter *p;
  607.  
  608.     nestedParams++;
  609.     if (where == FUNC_DEF && func_style == FUNC_TRADITIONAL) {
  610.  
  611.     /* Output parameter name list for traditional function definition. */
  612.     p = declarator->params.first;
  613.  
  614.     /* Output parameter name list only for head function declarator. */
  615.     if (!is_void_parameter(p) && declarator == func_declarator) {
  616.         put_string(outf, fmt[format].first_param_prefix);
  617.         put_string(outf, p->declarator->name);
  618.         p = p->next;
  619.         while (p != NULL && strcmp(p->declarator->text, ELLIPSIS) != 0) {
  620.         put_char(outf, ',');
  621.         put_string(outf, fmt[format].middle_param_prefix);
  622.         put_string(outf, p->declarator->name);
  623.         p = p->next;
  624.         }
  625.         put_string(outf, fmt[format].last_param_suffix);
  626.     }
  627.     } else {
  628.  
  629.     /* Output parameter type list. */
  630.     if (where == FUNC_PROTO && proto_style == PROTO_TRADITIONAL &&
  631.      declarator == func_declarator) {
  632.         if (proto_comments) {
  633.         put_string(outf, COMMENT_BEGIN);
  634.         put_param_list(outf, declarator, TRUE);
  635.         put_string(outf, COMMENT_END);
  636.         }
  637.     } else if (func_style != FUNC_NONE || proto_style != PROTO_NONE) {
  638. #if OPT_LINTLIBRARY
  639.         if (!knrLintLibrary() || nestedParams <= 1)
  640. #endif
  641.             put_param_list(outf, declarator, commented);
  642.     }
  643.     }
  644.     nestedParams--;
  645. }
  646.  
  647. /* Output a function declarator.
  648.  */
  649. static void
  650. put_func_declarator (outf, declarator, commented)
  651. FILE *outf;
  652. Declarator *declarator;
  653. int commented;
  654. {
  655.     char *s, *t, *decl_text;
  656.     int f;
  657.     int saveNest = nestedParams;
  658.  
  659.     /* Output declarator text before function declarator place holder. */
  660.     if ((s = strstr(declarator->text, "%s")) == NULL)
  661.     return;
  662.     *s = '\0';
  663.     put_string(outf, declarator->text);
  664.  
  665.     /* Substitute place holder with function declarator. */
  666.     if (declarator->func_stack->func_def == FUNC_NONE) {
  667.  
  668.     decl_text = declarator->func_stack->text;
  669.     if (declarator->name[0] == '\0') {
  670.         put_string(outf, decl_text);
  671.     } else {
  672.         int star;
  673.  
  674.         /* Output the declarator text before the declarator name. */
  675.         if ((t = strstr(decl_text, declarator->name)) == NULL)
  676.         return;
  677.         *t = '\0';
  678.         star = ((t != decl_text) && (t[-1] == '*'));
  679.         put_string(outf, decl_text);
  680.         *t = declarator->name[0];
  681.  
  682.         /* Output the declarator prefix before the name. */
  683.         f = (declarator == func_declarator) ? format : FMT_OTHER;
  684.         if (strcmp(fmt[f].declarator_prefix, " ") != 0)
  685.         put_string(outf, fmt[f].declarator_prefix);
  686.  
  687.         /* Output the declarator name. */
  688.         if (where == FUNC_PROTO && proto_style == PROTO_ABSTRACT &&
  689.          declarator != func_declarator) {
  690.         if (proto_comments) {
  691.             if (star) put_char(outf, ' ');
  692.             put_string(outf, COMMENT_BEGIN);
  693.             put_string(outf, declarator->name);
  694.             put_string(outf, COMMENT_END);
  695.         }
  696.         } else {
  697.         put_string(outf, declarator->name);
  698.         }
  699.  
  700.         /* Output the remaining declarator text. */
  701.         put_string(outf, t + strlen(declarator->name));
  702.  
  703.         /* Output the declarator suffix. */
  704.         put_string(outf, fmt[f].declarator_suffix);
  705.     }
  706.     } else {
  707.     put_func_declarator(outf, declarator->func_stack, commented);
  708.     nestedParams = 2; /* e.g., "void (*signal(p1, p2))()" */
  709.     }
  710.     *s = '%';
  711.     s += 2;
  712.  
  713.     /* Output declarator text up to but before parameters place holder. */
  714.     if ((t = strstr(s, "()")) == NULL)
  715.     return;
  716.     *t = '\0';
  717.     put_string(outf, s);
  718.  
  719.     if (where == FUNC_PROTO
  720.      && (func_declarator == declarator
  721.       || func_declarator == declarator->head)
  722.      && proto_macro) {
  723.     fprintf(outf, " %s(", macro_name);
  724.     }
  725.  
  726.     /* Substitute place holder with function parameters. */
  727.     put_char(outf, *t++ = PAREN_L);
  728.     put_parameters(outf, declarator, commented);
  729.     put_string(outf, t);
  730.  
  731.     if (where == FUNC_PROTO
  732.      && (func_declarator == declarator
  733.       || func_declarator == declarator->head)
  734.      && proto_macro) {
  735.     put_char(outf, PAREN_R);
  736.     }
  737.     nestedParams = saveNest;
  738. }
  739.  
  740. /* Output a declarator.
  741.  */
  742. static void
  743. put_declarator (outf, declarator, commented)
  744. FILE *outf;
  745. Declarator *declarator;
  746. int commented;
  747. {
  748.     char *s;
  749.  
  750.     if (declarator->func_def == FUNC_NONE) {
  751.     if (where == FUNC_PROTO && proto_style == PROTO_ABSTRACT &&
  752.      declarator->name[0] != '\0') {
  753.         if ((s = strstr(declarator->text, declarator->name)) == NULL)
  754.         return;
  755.         *s = '\0';
  756.         if (proto_comments) {
  757.         fprintf(outf, "%s%s%s%s%s", declarator->text,
  758.          COMMENT_BEGIN, declarator->name, COMMENT_END,
  759.          s + strlen(declarator->name));
  760.         } else {
  761.         fprintf(outf, "%s%s", declarator->text,
  762.          s + strlen(declarator->name));
  763.         }
  764.         *s = declarator->name[0];
  765.     } else {
  766.         put_string(outf, declarator->text);
  767.     }
  768.     } else {
  769.     put_func_declarator(outf, declarator, commented);
  770.     }
  771. }
  772.  
  773. /* Output a declaration specifier for an external declaration.
  774.  */
  775. static void
  776. put_decl_spec (outf, decl_spec)
  777. FILE *outf;
  778. DeclSpec *decl_spec;
  779. {
  780.     /* An "extern func()" is legal, but we want to be explicit for lint libs */
  781. #if OPT_LINTLIBRARY
  782.     if (decl_spec->text[0] == '\0') {
  783.     free(decl_spec->text);
  784.         decl_spec->text = xstrdup("int");
  785.     }
  786. #endif
  787.     if (extern_out && !(decl_spec->flags & DS_STATIC) &&
  788.      strkey(decl_spec->text, "extern") == NULL)
  789.     put_padded(outf, "extern");
  790.     put_padded(outf, decl_spec->text);
  791. }
  792.  
  793. /* Output the list of parameters in K&R style, for lint-library
  794.  */
  795. #if OPT_LINTLIBRARY
  796. static void
  797. put_llib_params(declarator, commented)
  798. Declarator *declarator;
  799. int commented;
  800. {
  801.     Parameter *p;
  802.     int    count = 0;
  803.  
  804.     nestedParams++;
  805.     p = (declarator->func_stack->func_def != FUNC_NONE)
  806.         ? declarator->func_stack->params.first
  807.         : declarator->params.first;
  808.  
  809.     while (p != 0) {
  810.         if (lint_ellipsis(p))
  811.             break;
  812.         if (putParameter(stdout, p, FALSE, ++count, commented))
  813.             putchar(';');
  814.         p = p->next;
  815.     }
  816.     nestedParams--;
  817. }
  818. #endif
  819.  
  820. /* Generate variable declarations.
  821.  */
  822. void
  823. gen_declarations (decl_spec, decl_list)
  824. DeclSpec *decl_spec;        /* declaration specifier */
  825. DeclaratorList *decl_list;    /* list of declared variables */
  826. {
  827.     Declarator *d;
  828.     int    commented = FALSE;
  829.     int    saveNest = nestedParams;
  830.  
  831. #if OPT_LINTLIBRARY
  832.     boolean    defines = (strchr(decl_spec->text, CURL_L) != 0);
  833.     int        is_func;
  834.  
  835.     /* special treatment for -l, -T options */
  836.     if ((!variables_out && types_out && defines) || (decl_list == 0)) {
  837.     strcut(decl_spec->text, "static");
  838.     strcut(decl_spec->text, "extern");
  839.     fmt_library((decl_list == 0) ? 1 : 2);
  840.     if (decl_spec->text[0] != '\0') {
  841.         put_string(stdout, decl_spec->text);
  842.         put_string(stdout, ";\n");
  843.     }
  844.     return;
  845.     }
  846. #endif
  847.  
  848.     if (!variables_out || (decl_spec->flags & (DS_EXTERN|DS_JUNK))) {
  849. #if OPT_LINTLIBRARY
  850.     if (in_include >= extern_in)    /* -x option not set? */
  851. #endif
  852.         return;
  853. #if OPT_LINTLIBRARY
  854.     strcut(decl_spec->text, "extern");
  855. #endif
  856.     }
  857.     if (scope_out == SCOPE_EXTERN && (decl_spec->flags & DS_STATIC))
  858.     return;
  859.     if (scope_out == SCOPE_STATIC && !(decl_spec->flags & DS_STATIC))
  860.     return;
  861.  
  862.     check_untagged(decl_spec);
  863.     func_declarator = NULL;
  864.     where = FUNC_OTHER;
  865.     format = FMT_OTHER;
  866.     nestedParams = 0;
  867.  
  868.     for (d = decl_list->first; d != NULL; d = d->next) {
  869.     if (d->func_def == FUNC_NONE
  870.      || d->head->func_stack->pointer
  871. #if OPT_LINTLIBRARY
  872.      || (in_include < extern_in)
  873. #endif
  874.        ) {
  875. #if OPT_LINTLIBRARY
  876.         if (already_declared(d->name)) {
  877.         flush_varargs();
  878.         continue;
  879.         }
  880.  
  881.         /*
  882.          * Try to distinguish function declarations from function pointer
  883.          * declarations, so that we don't unintentionally emit lint-library
  884.          * arguments for function pointers.
  885.          */
  886.         is_func = is_actual_func(d);
  887.  
  888.         if (is_func) {
  889.         ellipsis_varargs(d);
  890.         } else {
  891.         nestedParams = 2;    /* disable params altogether */
  892.         if (types_out)
  893.             fmt_library(2);
  894.         }
  895.             if (lint_shadowed && lintLibrary())
  896.         printf("#undef %s\n", d->name);
  897. #endif
  898.         put_string(stdout, fmt[FMT_PROTO].decl_spec_prefix);
  899.         put_decl_spec(stdout, decl_spec);
  900.         put_declarator(stdout, d, commented);
  901. #if OPT_LINTLIBRARY
  902.         if (knrLintLibrary() && is_func)
  903.         put_llib_params(d, commented);
  904. #endif
  905.         put_body(stdout, decl_spec, d);
  906.         nestedParams = saveNest;
  907.     }
  908. #if OPT_LINTLIBRARY
  909.     flush_varargs();
  910. #endif
  911.     }
  912.     exitlike_func = FALSE;
  913. }
  914.  
  915. /* Return TRUE if the function uses varargs.
  916.  */
  917. static int
  918. uses_varargs (declarator)
  919. Declarator *declarator;
  920. {
  921.     Parameter *p;
  922.  
  923.     return (p = declarator->params.first) != NULL
  924.         && (p->next == NULL)
  925.     && (!strcmp(p->declarator->name, "va_alist"));
  926. }
  927.  
  928. /* If the parameter list is empty, then replace it with "void".
  929.  */
  930. static void
  931. check_void_param (declarator)
  932. Declarator *declarator;
  933. {
  934.     DeclSpec decl_spec;
  935.     Parameter *p;
  936.  
  937.     if (declarator->params.first == NULL) {
  938.     new_decl_spec(&decl_spec, "void", 0L, DS_NONE);
  939.     p = new_parameter(&decl_spec, (Declarator *)0);
  940.     new_param_list(&declarator->params, p);
  941.     }
  942. }
  943.  
  944. /* If a parameter name appears in the parameter list of a traditional style
  945.  * function definition but is not declared in the parameter declarations,
  946.  * then assign it the default type "int".
  947.  */
  948. static void
  949. set_param_decl_spec (declarator)
  950. Declarator *declarator;
  951. {
  952.     Parameter *p;
  953.  
  954.     for (p = declarator->params.first; p != NULL; p = p->next) {
  955.     if (p->decl_spec.text[0] == '\0' &&
  956.      strcmp(p->declarator->text, ELLIPSIS) != 0) {
  957.         free(p->decl_spec.text);
  958.         p->decl_spec.text = xstrdup("int");
  959.     }
  960.     }
  961. }
  962.  
  963. /* Generate a function prototype.
  964.  */
  965. void
  966. gen_prototype (decl_spec, declarator)
  967. DeclSpec *decl_spec;
  968. Declarator *declarator;
  969. {
  970.     Parameter *p;
  971.     int    commented = FALSE;
  972.  
  973.     if (proto_style == PROTO_NONE || (decl_spec->flags & DS_JUNK))
  974.     return;
  975.     if (scope_out == SCOPE_EXTERN && (decl_spec->flags & DS_STATIC))
  976.     return;
  977.     if (scope_out == SCOPE_STATIC && !(decl_spec->flags & DS_STATIC))
  978.     return;
  979.  
  980.     /*
  981.      * Trim pathological keywords (which are legal, but unnecessary) from the
  982.      * function and its parameters.
  983.      */
  984.     strcut(decl_spec->text, "extern");
  985.     for (p = declarator->params.first; p != NULL; p = p->next) {
  986.     strcut(p->decl_spec.text, "extern");
  987.     strcut(p->decl_spec.text, "auto");
  988.     }
  989.  
  990. #if OPT_LINTLIBRARY
  991.     if (lintLibrary())
  992.     ellipsis_varargs(declarator);
  993.     else if (types_out)
  994.     fmt_library(0);
  995. #endif
  996.  
  997.     func_declarator = declarator->head;
  998.     if (uses_varargs(func_declarator)) {
  999.     /* Generate a prototype for a function that uses varargs by replacing
  1000.      * the "va_alist" parameter with an empty parameter list.
  1001.      */
  1002.     free_param_list(&func_declarator->params);
  1003.     func_declarator->params.first = NULL;
  1004.     }
  1005.  
  1006.     check_void_param(func_declarator);
  1007.     set_param_decl_spec(func_declarator);
  1008.  
  1009.     where = FUNC_PROTO;
  1010.     format = FMT_PROTO;
  1011.     nestedParams = 0;
  1012.  
  1013. #if OPT_LINTLIBRARY
  1014.     if (lint_shadowed && lintLibrary())
  1015.     printf("#undef %s\n", declarator->name);
  1016. #endif
  1017.     put_string(stdout, fmt[format].decl_spec_prefix);
  1018.     put_decl_spec(stdout, decl_spec);
  1019.     put_func_declarator(stdout, declarator, commented);
  1020. #if OPT_LINTLIBRARY
  1021.     if (knrLintLibrary())
  1022.     put_llib_params(declarator, commented);
  1023. #endif
  1024.     put_body(stdout, decl_spec, declarator);
  1025. }
  1026.  
  1027. /* Generate a declarator for a function pointer declarator or prototype.
  1028.  */
  1029. void
  1030. gen_func_declarator (declarator)
  1031. Declarator *declarator;
  1032. {
  1033.     /* Go to the beginning of the function declarator in the temporary
  1034.      * file and overwrite it with the converted declarator.
  1035.      */
  1036.     fseek(cur_tmp_file(), declarator->begin, 0);
  1037.     func_declarator = NULL;
  1038.  
  1039.     where = FUNC_DEF;
  1040.     format = FMT_FUNC;
  1041.     nestedParams = 0;
  1042.  
  1043.     put_func_declarator(cur_tmp_file(), declarator, FALSE);
  1044.     cur_file_changed();
  1045. }
  1046.  
  1047. /* Output parameter declarations for old style function definition.
  1048.  */
  1049. static void
  1050. put_param_decl (declarator, commented)
  1051. Declarator *declarator;
  1052. int commented;
  1053. {
  1054. #if OPT_LINTLIBRARY
  1055.     int count = 0;
  1056. #endif
  1057.     Parameter *p;
  1058.  
  1059.     p = declarator->params.first;
  1060.     if (!is_void_parameter(p)) {
  1061.     fputc('\n', cur_tmp_file());
  1062.     (void)putParameter(cur_tmp_file(), p, knrLintLibrary(), ++count, commented);
  1063.     fputc(';', cur_tmp_file());
  1064.     if (p->comment != 0)
  1065.         fputs(p->comment, cur_tmp_file());
  1066.     p = p->next;
  1067.     while (p != NULL && strcmp(p->declarator->text, ELLIPSIS) != 0) {
  1068.         fputc('\n', cur_tmp_file());
  1069.         (void)putParameter(cur_tmp_file(), p, knrLintLibrary(), ++count, commented);
  1070.         fputc(';', cur_tmp_file());
  1071.         if (p->comment != 0)
  1072.         fputs(p->comment, cur_tmp_file());
  1073.         p = p->next;
  1074.     }
  1075.     }
  1076. }
  1077.  
  1078. /* Generate a function definition head.
  1079.  */
  1080. void
  1081. gen_func_definition (decl_spec, declarator)
  1082. DeclSpec *decl_spec;
  1083. Declarator *declarator;
  1084. {
  1085.     Parameter *p;
  1086.     ParameterList *params;
  1087.     char *comment = 0;
  1088.     int n;
  1089.     unsigned comment_len;
  1090.     long diff;
  1091.  
  1092.     /* Do nothing if the function is already defined in the desired style
  1093.      * or if the function uses varargs.
  1094.      */
  1095.     func_declarator = declarator->head;
  1096.     if (func_declarator->func_def == func_style ||
  1097.     uses_varargs(func_declarator))
  1098.     return;
  1099.  
  1100.     /* Save the text between the function head and the function body.
  1101.      * Read the temporary file from after the last ) or ; to the
  1102.      * end of the file.
  1103.      */
  1104.     if ((diff = (ftell(cur_tmp_file()) - cur_begin_comment())) > 0) {
  1105.     comment_len = (unsigned)diff;
  1106.     *(comment = xmalloc(comment_len)) = '\0';
  1107.     fseek(cur_tmp_file(), cur_begin_comment(), 0);
  1108.     fread(comment, sizeof(char), comment_len, cur_tmp_file());
  1109.     } else {
  1110.     comment_len = 0;
  1111.     }
  1112.  
  1113.     format = FMT_FUNC;
  1114.     nestedParams = 0;
  1115.  
  1116.     if (func_declarator->func_def == FUNC_TRADITIONAL
  1117.      || func_declarator->func_def == FUNC_BOTH) {
  1118.     /* Save the text before the parameter declarations. */
  1119.     params = &func_declarator->params;
  1120.     n = (int)(params->end_comment - params->begin_comment);
  1121.     if (n > 0) {
  1122.         *(params->comment = xmalloc((unsigned)(n+1))) = '\0';
  1123.         fseek(cur_tmp_file(), params->begin_comment, 0);
  1124.         fread(params->comment, sizeof(char), (size_t)n, cur_tmp_file());
  1125.         params->comment[n] = '\0';
  1126.         format = FMT_FUNC_COMMENT;
  1127.     }
  1128.  
  1129.     /* Get the parameter comments. */
  1130.     for (p = func_declarator->params.first; p != NULL; p = p->next) {
  1131.         n = (int)(p->declarator->end_comment - p->declarator->begin_comment);
  1132.         if (n > 0) {
  1133.             *(p->comment = xmalloc((unsigned)n+1)) = '\0';
  1134.             fseek(cur_tmp_file(), p->declarator->begin_comment, 0);
  1135.             fread(p->comment, sizeof(char), (size_t)n, cur_tmp_file());
  1136.             p->comment[n] = '\0';
  1137.             format = FMT_FUNC_COMMENT;
  1138.         }
  1139.     }
  1140.     }
  1141.  
  1142.     check_void_param(func_declarator);
  1143.     set_param_decl_spec(func_declarator);
  1144.  
  1145.     /* Go to the beginning of the function head in the temporary file
  1146.      * and overwrite it with the converted function head.
  1147.      */
  1148.     where = FUNC_DEF;
  1149.     fseek(cur_tmp_file(), decl_spec->begin, 0);
  1150.  
  1151.     if (func_style == FUNC_BOTH) {
  1152.     char *cur_func;
  1153.     unsigned func_len;
  1154.  
  1155.     /* Save the current function definition head. */
  1156.     if ((diff = (cur_begin_comment() - decl_spec->begin)) > 0) {
  1157.         func_len = (unsigned)diff;
  1158.         cur_func = xmalloc(func_len);
  1159.         fread(cur_func, sizeof(char), func_len, cur_tmp_file());
  1160.     } else {
  1161.         cur_func = 0;
  1162.         func_len = 0;
  1163.     }
  1164.  
  1165.     fseek(cur_tmp_file(), decl_spec->begin, 0);
  1166.     fprintf(cur_tmp_file(), "%s\n\n", func_directive);
  1167.  
  1168.     /* Output new style function definition head. */
  1169.     if (func_declarator->func_def == FUNC_ANSI) {
  1170.         if (cur_func != 0)
  1171.         fwrite(cur_func, sizeof(char), func_len, cur_tmp_file());
  1172.     } else {
  1173.         fputs(fmt[format].decl_spec_prefix, cur_tmp_file());
  1174.         fputs(decl_spec->text, cur_tmp_file());
  1175.         fputc(' ', cur_tmp_file());
  1176.  
  1177.         func_style = FUNC_ANSI;
  1178.         put_func_declarator(cur_tmp_file(), declarator, FALSE);
  1179.     }
  1180.     fputs("\n#else\n\n", cur_tmp_file());
  1181.  
  1182.     /* Output old style function definition head. */
  1183.     if (func_declarator->func_def == FUNC_TRADITIONAL
  1184.      || func_declarator->func_def == FUNC_BOTH) {
  1185.         if (cur_func != 0)
  1186.         fwrite(cur_func, sizeof(char), func_len, cur_tmp_file());
  1187.     } else {
  1188.         fputs(fmt[format].decl_spec_prefix, cur_tmp_file());
  1189.         fputs(decl_spec->text, cur_tmp_file());
  1190.         fputc(' ', cur_tmp_file());
  1191.  
  1192.         format = FMT_FUNC;
  1193.         func_style = FUNC_TRADITIONAL;
  1194.         put_func_declarator(cur_tmp_file(), declarator, FALSE);
  1195.         put_param_decl(func_declarator, FALSE);
  1196.     }
  1197.  
  1198.     fputs("\n#endif", cur_tmp_file());
  1199.     if (*comment != '\n')
  1200.         fputc('\n', cur_tmp_file());
  1201.     func_style = FUNC_BOTH;
  1202.  
  1203.     if (cur_func != 0)
  1204.         free(cur_func);
  1205.  
  1206.     } else {
  1207.     /* Output declarator specifiers. */
  1208.     fputs(fmt[format].decl_spec_prefix, cur_tmp_file());
  1209.     fputs(decl_spec->text, cur_tmp_file());
  1210.     fputc(' ', cur_tmp_file());
  1211.  
  1212.     /* Output function declarator. */
  1213.     put_func_declarator(cur_tmp_file(), declarator, FALSE);
  1214.     if (func_style == FUNC_TRADITIONAL)
  1215.         put_param_decl(func_declarator, FALSE);
  1216.     }
  1217.  
  1218.     /* Output text between function head and body. */
  1219.     if (comment != 0) {
  1220.     fwrite(comment, sizeof(char), comment_len, cur_tmp_file());
  1221.     free(comment);
  1222.     }
  1223.  
  1224.     cur_file_changed();
  1225. }
  1226.