home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / c / c2man-2.0pl33.lha / c2man-2.0 / semantic.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-14  |  16.3 KB  |  703 lines

  1. /* $Id: semantic.c,v 2.0.1.12 1994/01/07 07:05:05 greyham Exp $
  2.  *
  3.  * C manual page generator
  4.  * These routines implement the semantic actions executed by the yacc parser.
  5.  */
  6. #include "c2man.h"
  7.  
  8. #include <ctype.h>
  9. #include "semantic.h"
  10. #include "enum.h"
  11. #include "manpage.h"
  12. #include "strconcat.h"
  13. #include "output.h"
  14.  
  15. /* Return TRUE if the given identifier is really a typedef name.
  16.  * Search the symbol table for the identifier.
  17.  */
  18. boolean
  19. is_typedef_name (name)
  20. char *name;
  21. {
  22.     return (boolean)(find_symbol(typedef_names, name) != NULL);
  23. }
  24.  
  25. /* Initialize a new declaration specifier part.
  26.  */
  27. void
  28. new_decl_spec (decl_spec, text, flags)
  29. DeclSpec *decl_spec;
  30. char *text;
  31. int flags;
  32. {
  33.     decl_spec->text = text ? strduplicate(text) : NULL;
  34.     decl_spec->flags = flags;
  35.     decl_spec->enum_list = NULL;
  36. }
  37.  
  38. /* Free storage used by a declaration specifier part.
  39.  */
  40. void
  41. free_decl_spec (decl_spec)
  42. DeclSpec *decl_spec;
  43. {
  44.     safe_free(decl_spec->text);    /* could be an ellipsis you know */
  45. }
  46.  
  47. /* Initialize a new declaration specifier part, including an enum part.
  48.  */
  49. void
  50. new_enum_decl_spec (decl_spec, text, flags, enum_list)
  51. DeclSpec *decl_spec;
  52. char *text;
  53. int flags;
  54. EnumeratorList *enum_list;
  55. {
  56.     decl_spec->text = text;
  57.     decl_spec->flags = flags;
  58.     decl_spec->enum_list = enum_list;
  59. }
  60.  
  61. /* Initialize a new declaration specifier part, but don't strdup the text. */
  62. void
  63. dyn_decl_spec (decl_spec, text, flags)
  64. DeclSpec *decl_spec;
  65. char *text;
  66. unsigned int flags;
  67. {
  68.     decl_spec->text = text;
  69.     decl_spec->flags = flags;
  70.     decl_spec->enum_list = NULL;
  71. }
  72.  
  73. /* Append two declaration specifier parts together.
  74.  */
  75. void
  76. join_decl_specs (result, a, b)
  77. DeclSpec *result, *a, *b;
  78. {
  79.     if (a->text)
  80.     {
  81.     if (b->text)
  82.     {
  83.         result->text = strconcat(a->text, " ", b->text, NULLCP);
  84.         free(a->text);
  85.         free(b->text);
  86.     }
  87.     else
  88.         result->text = a->text;
  89.     }
  90.     else
  91.     result->text = b->text;
  92.     
  93.     result->flags = a->flags | b->flags;
  94.     
  95.     /* only one of the decl specs should have an enum list! */
  96.     result->enum_list = a->enum_list ? a->enum_list : b->enum_list;
  97. }
  98.  
  99. /* Allocate and initialize a declarator. */
  100. Declarator *
  101. new_declarator (text, name)
  102. char *name, *text;
  103. {
  104.     Declarator *d;
  105.  
  106.     d = (Declarator *)safe_malloc(sizeof(Declarator));
  107.     d->text = text;
  108.     d->name = name;
  109.     d->type = DECL_SIMPLE;
  110.     d->comment = NULL;
  111.     new_ident_list(&d->params);
  112.     d->head = d;
  113.     d->func_stack = NULL;
  114.     return d;
  115. }
  116.  
  117. /* Free storage used by a declarator.
  118.  */
  119. void
  120. free_declarator (d)
  121. Declarator *d;
  122. {
  123. #ifdef DEBUG
  124.     fprintf(stderr,"free_declarator: decl = %lx, name = %s, text = %s\n",
  125.     (long)d, d->name?d->name:"NULL", d->text?d->text:"NULL");
  126. #endif
  127.     safe_free(d->name);    /* could be an ellipsis (ie: no name) */
  128.     safe_free(d->text);    /* ellipsis is marked by no text too */
  129.     safe_free(d->comment);
  130.     free_param_list(&(d->params));
  131.     if (d->func_stack != NULL)
  132.     free_declarator(d->func_stack);
  133.     free(d);
  134. }
  135.  
  136. /* add a comment to the last declarator in the list */
  137. int
  138. comment_last_decl(list, comment)
  139. DeclaratorList *list;
  140. char *comment;
  141. {
  142.     if (list->last->comment)
  143.     {
  144.     declarator_error(list->last);
  145.     free(comment);
  146.     return 0;
  147.     }
  148.     else
  149.     list->last->comment = comment;
  150.     return 1;
  151. }
  152.  
  153. /* Initialize a declarator list and add the given declarator to it.
  154.  */
  155. void
  156. new_decl_list (decl_list, declarator)
  157. DeclaratorList *decl_list;
  158. Declarator *declarator;
  159. {
  160.     decl_list->first = decl_list->last = declarator;
  161.     declarator->next = NULL;
  162. }
  163.  
  164. /* Free storage used by the declarators in the declarator list.
  165.  */
  166. void
  167. free_decl_list (decl_list)
  168. DeclaratorList *decl_list;
  169. {
  170.     Declarator *d, *next;
  171. #ifdef DEBUG
  172.     fprintf(stderr,"free_decl_list: decl_list = %lx, first = %lx\n",
  173.         (long)decl_list, (long)decl_list->first);
  174. #endif
  175.     d = decl_list->first;
  176.     while (d != NULL) {
  177.     next = d->next;
  178.     free_declarator(d);
  179.     d = next;
  180.     }
  181. }
  182.  
  183. /* Add the declarator to the declarator list.
  184.  */
  185. void
  186. add_decl_list (to, from, declarator)
  187. DeclaratorList *to, *from;
  188. Declarator *declarator;
  189. {
  190.     to->first = from->first;
  191.     from->last->next = declarator;
  192.     to->last = declarator;
  193.     to->last->next = NULL;
  194. }
  195.  
  196. /* Initialize the parameter structure.
  197.  */
  198. void
  199. new_parameter (param, decl_spec, declarator, comment_before, comment_after)
  200. Parameter *param;        /* pointer to structure to be initialized */
  201. DeclSpec *decl_spec;        /* declaration specifier structure */
  202. Declarator *declarator;        /* declarator structure */
  203. char *comment_before;        /* comment before the param */
  204. char *comment_after;        /* comment after the param */
  205. {
  206.  
  207.     if (decl_spec == NULL) {
  208.     new_decl_spec(&(param->decl_spec), NULLCP, DS_JUNK);
  209.     } else {
  210.     param->decl_spec = *decl_spec;
  211.     }
  212.  
  213.     if (declarator == NULL) {
  214.     declarator = new_declarator(NULLCP, NULLCP);
  215.     }
  216.     param->declarator = declarator;
  217.  
  218.     if (comment_before && comment_after)
  219.     {
  220.     parameter_error(param);
  221.     free(comment_after);    /* comment_before will go in Parameter */
  222.     }
  223.  
  224.     param->declarator->comment =
  225.             comment_before ? comment_before : comment_after;
  226.     param->suppress = FALSE;
  227.     param->duplicate = FALSE;
  228. }
  229.  
  230. /* Free the storage used by the parameter.
  231.  */
  232. void
  233. free_parameter (param)
  234. Parameter *param;
  235. {
  236.     free_decl_spec(&(param->decl_spec));
  237.     free_declarator(param->declarator);
  238. }
  239.  
  240. /* add a comment to the last parameter in the list */
  241. int
  242. comment_last_parameter(list, comment)
  243. ParameterList *list;
  244. char *comment;
  245. {
  246.     if (list->last == NULL)
  247.     {
  248.     yyerror("comment '%s' applies to non-existent parameter", comment);
  249.     free(comment);
  250.     return 0;
  251.     }
  252.  
  253.     if (list->last->declarator->comment)
  254.     {
  255.     parameter_error(list->last);
  256.     free(comment);
  257.     return 0;
  258.     }
  259.     else
  260.     list->last->declarator->comment = comment;
  261.     return 1;
  262. }
  263.  
  264. /* Initialize a list of function parameters.
  265.  */
  266. void
  267. new_param_list (param_list, param)
  268. ParameterList *param_list;
  269. Parameter *param;
  270. {
  271.     Parameter *p;
  272.  
  273.     p = (Parameter *)safe_malloc((unsigned)sizeof(Parameter));
  274.     *p = *param;
  275.     
  276.     param_list->first = param_list->last = p;
  277.     p->next = NULL;
  278. }
  279.  
  280. /* Free storage used by the elements in the function parameter list.
  281.  */
  282. void
  283. free_param_list (param_list)
  284. ParameterList *param_list;
  285. {
  286.     Parameter *p, *next;
  287.  
  288.     p = param_list->first;
  289.     while (p != NULL) {
  290.     next = p->next;
  291.     free_parameter(p);
  292.     free(p);
  293.     p = next;
  294.     }
  295. }
  296.  
  297. /* Add the function parameter declaration to the list.
  298.  */
  299. void
  300. add_param_list (to, from, param)
  301. ParameterList *to, *from;
  302. Parameter *param;
  303. {
  304.     Parameter *p;
  305.  
  306.     p = (Parameter *)safe_malloc((unsigned)sizeof(Parameter));
  307.     *p = *param;
  308.  
  309.     to->first = from->first;
  310.     from->last->next = p;
  311.     to->last = p;
  312.     p->next = NULL;
  313. }
  314.  
  315. /* Initialize an empty list of function parameter names.
  316.  */
  317. void
  318. new_ident_list (param_list)
  319. ParameterList *param_list;
  320. {
  321.     param_list->first = param_list->last = NULL;
  322. }
  323.  
  324. /* Add an item to the list of function parameter declarations but set only
  325.  * the parameter name field and the comments.
  326.  */
  327. void
  328. add_ident_list (to, from, ident)
  329. ParameterList *to, *from;
  330. Identifier *ident;
  331. {
  332.     Parameter *p;
  333.     Declarator *declarator;
  334.  
  335.     p = (Parameter *)safe_malloc(sizeof(Parameter));
  336.     declarator = new_declarator(ident->name, strduplicate(ident->name));
  337.     new_parameter(p, (DeclSpec *)NULL, declarator, ident->comment_before,
  338.                             ident->comment_after);
  339.  
  340.     to->first = from->first;
  341.     if (to->first == NULL) {
  342.     to->first = p;
  343.     } else {
  344.     from->last->next = p;
  345.     }
  346.     to->last = p;
  347.     p->next = NULL;
  348. }
  349.  
  350. /* Search the list of parameters for a matching parameter name.
  351.  * Return a pointer to the matching parameter or NULL if not found.
  352.  */
  353. static Parameter *
  354. search_parameter_list (params, name)
  355. ParameterList *params;
  356. char *name;
  357. {
  358.     Parameter *p;
  359.  
  360.     for (p = params->first; p != NULL; p = p->next) {
  361.     if (p->declarator->name && strcmp(p->declarator->name, name) == 0)
  362.         return p;
  363.     }
  364.     return (Parameter *)NULL;
  365. }
  366.  
  367. /* This routine is called to generate function prototypes from traditional
  368.  * style function definitions.  For each parameter name in the declarator
  369.  * list, find the matching parameter name in the parameter list and set
  370.  * that parameter's declaration specifier.
  371.  * This is also where we promote formal parameters.  Parameters of type
  372.  * "char", "unsigned char", "short", or "unsigned short" get promoted to
  373.  * "int".  Parameters of type "float" are promoted to "double".
  374.  */
  375. void
  376. set_param_types (params, decl_spec, declarators, comment, eolcomment)
  377. ParameterList *params;
  378. DeclSpec *decl_spec;
  379. DeclaratorList *declarators;
  380. char *comment;
  381. char *eolcomment;
  382. {
  383.     Declarator *d;
  384.     Parameter *p;
  385.  
  386.     if (comment && eolcomment)
  387.     {
  388.     yyerror("parameter declaration has multiple comments");
  389.     return;
  390.     }
  391.  
  392.     if (!comment)    comment = eolcomment;
  393.     
  394.     for (d = declarators->first; d != NULL; d = d->next) {
  395.     /* Search the parameter list for a matching name. */
  396.     if ((p = search_parameter_list(params, d->name)) == NULL) {
  397.         output_error();
  398.         fprintf(stderr, "declared argument \"%s\" is missing\n", d->name);
  399.     } else {
  400.         char *decl_spec_text = decl_spec->text;
  401.         if (promote_param && strcmp(d->text, d->name) == 0) {
  402.         if (decl_spec->flags & (DS_CHAR | DS_SHORT))
  403.             decl_spec_text = "int";
  404.         else if (decl_spec->flags & DS_FLOAT)
  405.             decl_spec_text = "double";
  406.         }
  407.         safe_free(p->decl_spec.text);   /* there shouldn't be one, but...*/
  408.         p->decl_spec.text = strduplicate(decl_spec_text);
  409.         if (p->decl_spec.flags != decl_spec->flags)
  410.         {
  411.         if (p->decl_spec.flags & DS_JUNK)
  412.             p->decl_spec.flags = decl_spec->flags;
  413.         else
  414.             parameter_error(p);
  415.         }
  416.         if (p->decl_spec.enum_list != decl_spec->enum_list)
  417.         {
  418.         if (p->decl_spec.enum_list == NULL)
  419.             p->decl_spec.enum_list = decl_spec->enum_list;
  420.         else
  421.             parameter_error(p);
  422.         }
  423.  
  424.         free_declarator(p->declarator);
  425.         p->declarator = d;
  426.  
  427.         if (comment)
  428.         {
  429.         if (p->declarator->comment)
  430.             parameter_error(p);
  431.         else
  432.             p->declarator->comment = strduplicate(comment);
  433.         }
  434.     }
  435.     }
  436.  
  437.     free_decl_spec(decl_spec);
  438.     safe_free(comment);
  439. }
  440.  
  441. /* Output a declaration specifier for an external declaration.
  442.  */
  443. void
  444. output_decl_spec (decl_spec)
  445. DeclSpec *decl_spec;
  446. {
  447.     output->text(decl_spec->text);
  448. }
  449.  
  450. static void
  451. output_parameters _((Declarator *d, boolean format));
  452.  
  453. /* does a function have any parameters?
  454.  * This accounts for both fn() and fn(void)
  455.  */
  456. boolean has_parameters(d)
  457. const Declarator *d;
  458. {
  459.     Parameter *first = d->head->params.first;
  460.  
  461.     return (first != NULL &&
  462.        (first->declarator->text != NULL ||
  463.         strcmp(first->decl_spec.text, "void")));
  464. }
  465.  
  466. /* output a declarator name, stripping leading underscores if necessary */
  467. void output_decl_text(text, keep_underscores)
  468. char *text;
  469. boolean keep_underscores;
  470. {
  471.     if (!keep_underscores)
  472.     {
  473.     /* skip leading stuff before the actual name */
  474.     while (*text && *text != '_' && !isalnum(*text))
  475.         output->character(*text++);
  476.     while (text[0] == '_' && text[1])    text++;
  477.     }
  478.     output->text(text);
  479. }
  480.  
  481. /* Output a function declarator.
  482.  */
  483. static void
  484. output_func_declarator (declarator, format)
  485. Declarator *declarator;
  486. boolean format;
  487. {
  488.     char *s, *t, *decl_text;
  489.  
  490.     /* Output declarator text before function declarator place holder. */
  491.     if ((s = strstr(declarator->text, "%s")) == NULL)
  492.     return;
  493.     *s = '\0';
  494.     output->text(declarator->text);
  495.  
  496.     /* Substitute place holder with function declarator. */
  497.     if (!is_function_declarator(declarator->func_stack)) {
  498.  
  499.     decl_text = declarator->func_stack->text;
  500.     if (declarator->name == NULL || declarator->name[0] == '\0') {
  501.         output->text(decl_text);
  502.     } else {
  503.  
  504.         /* Output the declarator text before the declarator name. */
  505.         if ((t = strstr(decl_text, declarator->name)) == NULL)
  506.         return;
  507.         *t = '\0';
  508.         output->text(decl_text);
  509.         *t = declarator->name[0];
  510.  
  511.         if (format && strcmp(declarator_prefix, " ") != 0)
  512.         output_format_string(declarator_prefix);
  513.  
  514.         /* Output the declarator name. */
  515.         output_decl_text(declarator->name, format);
  516.  
  517.         /* Output the remaining declarator text. */
  518.         output->text(t + strlen(declarator->name));
  519.  
  520.         /* Output the declarator suffix. */
  521.         if (format) output_format_string(declarator_suffix);
  522.     }
  523.     } else {
  524.     output_func_declarator(declarator->func_stack,format);
  525.     }
  526.     *s = '%';
  527.     s += 2;
  528.  
  529.     /* Output declarator text up to but before parameters place holder. */
  530.     if ((t = strstr(s, "()")) == NULL)
  531.     return;
  532.     *t = '\0';
  533.     output->text(s);
  534.  
  535.     /* Substitute place holder with function parameters. */
  536.     output->character(*t++ = '(');
  537.     output_parameters(declarator, format);
  538.     output->text(t);
  539. }
  540.  
  541. /* Output a declarator.
  542.  */
  543. void
  544. output_declarator (d, format)
  545. Declarator *d;
  546. boolean format;
  547. {
  548.     if (d->func_stack) {
  549.     output_func_declarator(d, format);
  550.     } else {
  551.     output_decl_text(d->text, format);
  552.     }
  553. }
  554.  
  555. /* Output a function parameter.
  556.  */
  557. void
  558. output_parameter (p)
  559. Parameter *p;
  560. {
  561.     if (p->decl_spec.text)
  562.     output->text(p->decl_spec.text);
  563.     else
  564.     /* Check for parameter names with no declaration specifiers.  This
  565.      * happens when a parameter name appears in the identifier list of a
  566.      * function definition but does not appear in the parameter declaration
  567.      * part.  The default type in this cause is "int".
  568.      */
  569.     if (p->declarator->text && strcmp(p->declarator->text, "...") != 0)
  570.     output->text("int ");
  571.  
  572.     /* not all parameters must have declarators: might be a prototype */
  573.     if (p->declarator->text) {
  574.     if (p->decl_spec.text)
  575.         output->character(' ');
  576.     /* don't format parameters; keep it all on one line */
  577.     output_declarator(p->declarator, FALSE);
  578.     }
  579. }
  580.  
  581. /* Output the list of function parameters.
  582.  */
  583. static void
  584. output_parameters (d, format)
  585. Declarator *d;
  586. boolean format;
  587. {
  588.     if (has_parameters(d)) {
  589.         Parameter *p = d->params.first;
  590.     if (format) output_format_string(first_param_prefix);
  591.     output_parameter(p);
  592.     p = p->next;
  593.     while (p != NULL) {
  594.         output->character(',');
  595.         if (format) output_format_string(middle_param_prefix);
  596.         output_parameter(p);
  597.         p = p->next;
  598.     }
  599.     if (format) output_format_string(last_param_suffix);
  600.     }
  601.     else
  602.     output->text("void");
  603. }
  604.  
  605. /* remember variable and function declarations. */
  606. int
  607. remember_declarations (comment, decl_spec, decl_list, eolcomment)
  608. char *comment;            /* comment before */
  609. DeclSpec *decl_spec;        /* declaration specifier */
  610. DeclaratorList *decl_list;    /* list of declared variables */
  611. char *eolcomment;        /* eol comment after */
  612. {
  613.     Declarator *d, *next;
  614.     int ret = 1;
  615.     
  616.     /* attach EOL comment to last one in list */
  617.     if (eolcomment)
  618.     {
  619.     Declarator *attach;
  620.  
  621.     /* if it's a function, attach it to the last parameter */
  622.     if (is_function_declarator(decl_list->last) &&
  623.         decl_list->last->head->params.last)
  624.         attach = decl_list->last->head->params.last->declarator;
  625.     else
  626.         attach = decl_list->last;
  627.         
  628.     if (attach->comment)
  629.     {
  630.         declarator_error(attach);
  631.         free(eolcomment);
  632.         ret = 0;
  633.     }
  634.     else
  635.         attach->comment = eolcomment;
  636.     }
  637.     
  638.     /* special case of a single declarator handled efficiently */
  639.     if (decl_list->first && decl_list->first->next == NULL)
  640.     {
  641.     d = decl_list->first;
  642.     /* free the declarator comment if it isn't going to get used */
  643.     if (comment)
  644.         safe_free(d->comment);
  645.     else
  646.         comment = d->comment;
  647.  
  648.     /* and nuke it from the declarator so free_declarator won't free it
  649.      * (since safe_free will do that) if new_manual_page decides to throw
  650.      * it away.
  651.      */
  652.     d->comment = NULL;
  653.  
  654.     new_manual_page(comment, decl_spec, d);
  655.     }
  656.     else
  657.     {
  658.     for (d = decl_list->first; d != NULL; d = next)
  659.     {
  660.         DeclSpec spec_copy;
  661.         char *comment_copy;
  662.  
  663.         next = d->next;
  664. #ifdef DEBUG
  665.         fprintf(stderr,
  666.         "remember_declarations: text=%s name=%s\ncomment: %s\n",
  667.             d->text,d->name, comment ? comment : "NULL");
  668. #endif
  669.         spec_copy = *decl_spec;
  670.         spec_copy.text = strduplicate(decl_spec->text);
  671.         comment_copy = d->comment ? d->comment :
  672.                     (comment ? strduplicate(comment) : NULL);
  673.         d->comment = NULL;
  674.         new_manual_page(comment_copy, &spec_copy,d);
  675.     }
  676.  
  677.     /* free 'em up */
  678.     free_decl_spec(decl_spec);
  679.     safe_free(comment);
  680.     }
  681.  
  682.     return ret;
  683. }
  684.  
  685. void parameter_error(param)
  686. Parameter *param;
  687. {
  688.     yyerror("parameter '%s' has multiple comments", param->declarator->name);
  689. }
  690.  
  691. void declarator_error(decl)
  692. Declarator *decl;
  693. {
  694.     yyerror("declarator '%s' has multiple comments", decl->name);
  695. }
  696.  
  697. /* is a declarator for a function? (as opposed to a variable) */
  698. boolean is_function_declarator(decl)
  699. const Declarator *decl;
  700. {
  701.     return decl->type == DECL_FUNCTION || decl->type == DECL_FUNCDEF;
  702. }
  703.