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

  1.  
  2. #include <stddef.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include <errno.h>
  6. #include <ctype.h>
  7. #include "global.h"
  8.  
  9. #define IF_STACK_SIZE 10
  10. #define N_DIRS nelems(d_table)
  11. #define IF_STATE (if_sp[-1])
  12.  
  13. #define COND_FALSE    0
  14. #define COND_ELSE_SEEN    4
  15. #define COND_DONE_TRUE    8
  16.  
  17. /* a bundle of information about a preprocessor directive */
  18. typedef struct {
  19.   char *word;
  20.   int is_cond;
  21.   void (*handler) __PROTO((void));
  22. } Directive;
  23.  
  24. static int *if_stack, if_stack_size;
  25. int *if_sp;
  26.  
  27. extern void do_include __PROTO((void));
  28. extern void do_define __PROTO((void));
  29. extern void do_undefine __PROTO((void));
  30.  
  31. /* set up the conditional-compile stack */
  32. void cond_setup()
  33. {
  34.   if_sp = if_stack = (int *)mallok((if_stack_size = IF_STACK_SIZE) * sizeof (int));
  35.  
  36.   *if_sp++ = COND_TRUE;
  37. }
  38.  
  39. /*
  40.    endif_check() -- see if there are states left on the stack; each
  41.    corresponds to a missing #endif
  42. */
  43. void endif_check()
  44. {
  45.   int i;
  46.  
  47.   i = if_sp - if_stack - 1;
  48.   if (i) {
  49.     while (i--)
  50.       error("missing #endif");
  51.   }
  52. }
  53.  
  54. /* cond_shutdown() -- free the conditional-compile stack() */
  55. void cond_shutdown()
  56. {
  57.   free(if_stack);
  58. }
  59.  
  60. /* cond_push() -- push a conditional-compile state onto the stack */
  61. static void cond_push(s)
  62.   int s;
  63. {
  64.   if (if_sp - if_stack >= if_stack_size) {
  65.     ptrdiff_t dp;
  66.  
  67.     dp = if_sp - if_stack;
  68.     if_stack = reallok(if_stack, (if_stack_size *= 2) * sizeof (int));
  69.  
  70.     if_sp = if_stack + dp;
  71.   }
  72.   *if_sp++ = s;
  73. }
  74.  
  75. /* cond_pop() -- remove a conditional-compile state from the stack */
  76. static void cond_pop()
  77. {
  78.   if (if_sp - if_stack <= 1)
  79.     error("unmatched #endif");
  80.   else
  81.     if_sp--;
  82. }
  83.  
  84. /* do_if() -- handle an #if directive */
  85. static void do_if()
  86. {
  87.   cond_push(!cond_true()? COND_NESTED :
  88.         if_expr()? COND_TRUE | COND_DONE_TRUE :
  89.         COND_FALSE
  90.   );
  91. }
  92.  
  93. /* do_ifdef() -- handle an #ifdef directive */
  94. static void do_ifdef()
  95. {
  96.   TokenP T;
  97.  
  98.   T = _one_token();
  99.   if (T->type != ID)
  100.     error("argument \"%s\" to #ifdef is not an identifier", T->txt);
  101.   else {
  102.     cond_push(!cond_true()? COND_NESTED :
  103.           lookup(T->txt, T->hashval) ? COND_TRUE | COND_DONE_TRUE :
  104.           COND_FALSE
  105.     );
  106.   }
  107.   free_token(T);
  108.   T = _one_token();
  109.   if (T->type != EOL)
  110.     warning("garbage after #ifdef");
  111.   free_token(T);
  112. }
  113.  
  114. /* do_ifndef() -- handle an #ifndef directive */
  115. static void do_ifndef()
  116. {
  117.   TokenP T;
  118.  
  119.   T = _one_token();
  120.   if (T->type != ID)
  121.     error("argument \"%s\" to #ifndef is not an identifier", T->txt);
  122.   else {
  123.     cond_push(!cond_true()? COND_NESTED :
  124.           lookup(T->txt, T->hashval) ? COND_FALSE :
  125.           COND_TRUE | COND_DONE_TRUE
  126.     );
  127.   }
  128.   free_token(T);
  129.   T = _one_token();
  130.   if (T->type != EOL)
  131.     warning("garbage after #ifndef");
  132.   free_token(T);
  133. }
  134.  
  135. /* do_else() -- handle an #else directive */
  136. static void do_else()
  137. {
  138.   TokenP T;
  139.  
  140.   if (IF_STATE & COND_ELSE_SEEN)
  141.     error("#else after #else");
  142.   if (IF_STATE & COND_DONE_TRUE)
  143.     IF_STATE &= (~COND_TRUE);
  144.   else
  145.     IF_STATE |= (COND_TRUE | COND_DONE_TRUE);
  146.   T = _one_token();
  147.   if (T->type != EOL)
  148.     warning("garbage after #else");
  149.   free_token(T);
  150. }
  151.  
  152. /* do_elif() -- handle an #elif directive */
  153. static void do_elif()
  154. {
  155.   TokenP T;
  156.  
  157.   if (IF_STATE & COND_ELSE_SEEN)
  158.     error("#elif after #else");
  159.   if (IF_STATE & COND_DONE_TRUE)
  160.     IF_STATE &= (~COND_TRUE);
  161.   else if (if_expr())
  162.     IF_STATE |= (COND_TRUE | COND_DONE_TRUE);
  163.   else
  164.     IF_STATE &= (~COND_TRUE);
  165. }
  166.  
  167. /* do_endif() -- handle an #endif directive */
  168. static void do_endif()
  169. {
  170.   TokenP T;
  171.  
  172.   cond_pop();
  173.   T = _one_token();
  174.   if (T->type != EOL)
  175.     warning("garbage after #endif");
  176.   free_token(T);
  177. }
  178.  
  179. /* do_line() -- handle a #line directive */
  180. static void do_line()
  181. {
  182.   unsigned long ln;
  183.   TokenP Tn, Tf;
  184.   int l;
  185.  
  186.   _tokenize_line();
  187.   Tn = exp_token();
  188.   if (Tn->type != NUMBER) {
  189.     error("malformed number \"%s\" in #line directive", Tn->txt);
  190.     return;
  191.   }
  192.   Tf = exp_token();
  193.   if (Tf->type != STR_CON && Tf->type != EOL) {
  194.     error("malformed filename \"%s\" in #line directive", Tf->txt);
  195.     return;
  196.   }
  197.   if (Tf->type == STR_CON) {
  198.     l = strlen(Tf->txt) - 2;
  199.     free(cur_file);
  200.     cur_file = mallok(l);
  201.     strncpy(cur_file, Tf->txt + 1, l - 2);
  202.     cur_file[l] = '\0';
  203.     free_token(Tf);
  204.     Tf = exp_token();
  205.     if (Tf->type != EOL)
  206.       error("garbage after #line");
  207.     free_token(Tf);
  208.   }
  209.   this_line = next_line = Tn->val;
  210.   sync_line(0);
  211.   free_token(Tn);
  212. }
  213.  
  214. /* do_error() -- handle an #error directive */
  215. static void do_error()
  216. {
  217.   error("%s", rest_of_line());
  218. }
  219.  
  220. /* do_pragma() -- handle a #pragma directive */
  221. static void do_pragma()
  222. {
  223.   /* at the moment, we don't recognize any #pragma directives */
  224. }
  225.  
  226. /* do_nothing() -- handle a # directive */
  227. static void do_nothing()
  228. {
  229. }
  230.  
  231. /* blurbs on all the recognized preprocessor directives */
  232. Directive d_table[] =
  233. {
  234.   {"define", 0, do_define},
  235.   {"undef", 0, do_undefine},
  236.   {"include", 0, do_include},
  237.   {"if", 1, do_if},
  238.   {"ifdef", 1, do_ifdef},
  239.   {"ifndef", 1, do_ifndef},
  240.   {"else", 1, do_else},
  241.   {"elif", 1, do_elif},
  242.   {"endif", 1, do_endif},
  243.   {"line", 0, do_line},
  244.   {"error", 0, do_error},
  245.   {"pragma", 0, do_pragma},
  246.   {"", 0, do_nothing}
  247. };
  248.  
  249. /*
  250.    directive() -- perform the directive on the current input line
  251. */
  252. void directive()
  253. {
  254.   char *outline;
  255.   TokenP T;
  256.   int i;
  257.   Directive *d;
  258.  
  259.   T = _one_token();
  260.   if (T->type == EOL) {
  261.     free_token(T);
  262.     return;
  263.   }
  264.   for (i = 0, d = d_table; i < N_DIRS; i++, d++)
  265.     if (streq(T->txt, d->word))
  266.       break;
  267.   if (i == N_DIRS)
  268.     fatal("unrecognized preprocessor directive #%s", T->txt);
  269.   if (cond_true() || d->is_cond)
  270.     (*d->handler) ();
  271.   free_token(T);
  272.   flush_line();
  273. }
  274.