home *** CD-ROM | disk | FTP | other *** search
/ Dream 48 / Amiga_Dream_48.iso / Atari / c / cpp.zoo / src / define.c < prev    next >
C/C++ Source or Header  |  1993-06-03  |  4KB  |  206 lines

  1.  
  2. #include <string.h>
  3. #include "global.h"
  4.  
  5. /*
  6.    get_parms() -- return a list of the formal parameters in a macro
  7.    definition.  Return the number of parameters in |*n|.
  8. */
  9. static TokenP get_parms(n)
  10.   int *n;
  11. {
  12.   TokenP T, parms = NULL;
  13.  
  14.   for (*n = 0;;) {
  15.     T = token();
  16.     if (T->type == EOL)
  17.       goto oops;
  18.     if (T->type == RPAREN) {
  19.       if (*n == 0)
  20.     return NULL;
  21.       goto oops;
  22.     }
  23.     if (T->type != ID)
  24.       goto oops;
  25.     if (!parms)
  26.       parms = T;
  27.     else
  28.       parms->next = T;
  29.     (*n)++;
  30.     T = token();
  31.     switch (T->type) {
  32.     case COMMA:
  33.       free_token(T);
  34.       continue;
  35.     case RPAREN:
  36.       free_token(T);
  37.       return parms;
  38.     default:
  39.       free_token(T);
  40.       goto oops;
  41.     }
  42.   }
  43. oops:
  44.   error("syntax error in macro definition");
  45.   if (parms)
  46.     free_tlist(parms);
  47.   *n = -1;
  48.   return NULL;
  49. }
  50.  
  51. /*
  52.    macro_eq() -- determine if macro bodies |M1| and |M2| are equal, modulo
  53.    whitespace.  Currently unfinished.
  54. */
  55. int macro_eq(M1, M2)
  56.   Macro *M1, *M2;
  57. {
  58.   if (M1->flags != M2->flags || M1->nargs != M2->nargs)
  59.     return 0;
  60.   return 1;
  61. }
  62.  
  63. /*
  64.    is_parm() -- determine if Token |T| is one of the formal parameters of the
  65.    macro.  Return the "index" into the list of parameters, or -1 if there is
  66.    no match
  67. */
  68. static int is_parm(T, parms)
  69.   TokenP T, parms;
  70. {
  71.   int i;
  72.   register TokenP t;
  73.  
  74.   if (parms == NULL)
  75.     return -1;
  76.   for (i = 0, t = parms; t; i++, t = t->next) {
  77.     if (streq(T->txt, t->txt))
  78.       return i;
  79.   }
  80.   return -1;
  81. }
  82.  
  83. /* do_define() -- handle a #define directive */
  84. void do_define()
  85. {
  86.   TokenP K, L;
  87.   register TokenP T, pT;
  88.   Macro *M, *M1;
  89.   int i;
  90.   static Token head;
  91.  
  92.   _tokenize_line();
  93.   K = token();
  94.   if (K->type != ID) {
  95.     error("argument \"%s\" to #define is not an identifier", K->txt);
  96.     return;
  97.   }
  98.   M = (Macro *)mallok(sizeof (Macro));
  99.  
  100.   M->flags = 0;
  101.   T = token();
  102.   if (strlen(T->pre_ws) == 0 && T->type == LPAREN) {
  103.     /* a macro with arguments -- get the formal parameters */
  104.     free_token(T);
  105.     T = NULL;
  106.     M->flags |= HASARGS;
  107.     M->argnames = get_parms(&M->nargs);
  108.     if (M->nargs < 0) {
  109.       free_tlist(M->argnames);
  110.       free(M);
  111.       return;
  112.     }
  113.   } else {
  114.     M->nargs = 0;
  115.     M->argnames = NULL;
  116.     push_tlist(T);
  117.   }
  118.   L = &head;
  119.   head.next = NULL;
  120.   for (;;) {
  121.     T = token();
  122.     if (T->type == EOL)
  123.       break;
  124.     switch (T->type) {
  125.     case POUND:
  126.       free_token(T);
  127.       T = token();
  128.       if ((i = is_parm(T, M->argnames)) < 0) {
  129.     error("# not followed by macro parameter");
  130.     push_tlist(T);
  131.     break;
  132.       }
  133.       T->type = MACRO_ARG;
  134.       T->flags |= STRINGIZE_ME;
  135.       T->val = i;
  136.       L = L->next = T;
  137.       break;
  138.     case TOK_CAT:
  139.       free_token(T);
  140.       T = token();
  141.       if (L == &head || T->type == EOL) {
  142.     if (L == &head)
  143.       error("## at beginning of macro body");
  144.     if (T->type == EOL)
  145.       error("## at end of macro body");
  146.     push_tlist(T);
  147.     break;
  148.       }
  149.       L->flags |= CONCAT_NEXT;
  150.       L = L->next = T;
  151.       break;
  152.     case ID:
  153.       if ((i = is_parm(T, M->argnames)) >= 0) {
  154.     T->type = MACRO_ARG;
  155.     T->val = i;
  156.       }
  157.       L = L->next = T;
  158.       break;
  159.     default:
  160.       L = L->next = T;
  161.       break;
  162.     }
  163.   }
  164.   /* remove leading space from the resulting sequence */
  165.   T = head.next;
  166.   if (T)
  167.     *T->pre_ws = '\0';
  168.   M->m_text = head.next;
  169.  
  170.   /*
  171.      As per the Standard, a macro can only be re-#define'd with an identical
  172.      body, modulo whitespace.
  173.   */
  174.   if ((M1 = lookup(K->txt, K->hashval)) && !macro_eq(M, M1)) {
  175.     warning("non-identical redefine of \"%s\"", K->txt);
  176.     free_tlist(M->m_text);
  177.     free_tlist(M->argnames);
  178.     free(M);
  179.   } else {
  180.     hash_add(K->txt, K->hashval, M);
  181.   }
  182.   free_token(K);
  183. }
  184.  
  185. /* do_undefine() -- handle an #undef directive */
  186. void do_undefine()
  187. {
  188.   Macro *M;
  189.   TokenP T;
  190.  
  191.   T = token();
  192.   if (T->type != ID) {
  193.     error("argument \"%s\" to #undef is not an identifier", T->txt);
  194.     free_token(T);
  195.     return;
  196.   }
  197.   M = lookup(T->txt, T->hashval);
  198.   if (M && !(M->flags & MAGIC))
  199.     hash_remove(T->txt, T->hashval);
  200.   free_token(T);
  201.   T = token();
  202.   if (T->type != EOL)
  203.     warning("garbage after #undef");
  204.   free_token(T);
  205. }
  206.