home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v941.tgz / icon.v941src.tar / icon.v941src / src / preproc / preproc.c < prev    next >
C/C++ Source or Header  |  2001-12-12  |  28KB  |  992 lines

  1. /*
  2.  * The functions in this file handle preprocessing directives, macro
  3.  *  calls, and string concatenation.
  4.  */
  5. #include "../preproc/preproc.h"
  6. #include "../preproc/ptoken.h"
  7. #include "../preproc/pproto.h"
  8.  
  9. /*
  10.  * Prototypes for static functions.
  11.  */
  12. static void start_select (struct token *t);
  13. static void end_select   (struct token *t);
  14. static void incl_file    (struct token *t);
  15. static void define       (struct token *t);
  16. static int     expand       (struct token *t, struct macro *m);
  17. static void toks_to_str  (struct str_buf *sbuf, struct token *t);
  18.  
  19. /*
  20.  * start_select - handle #if, #ifdef, #ifndef
  21.  */
  22. static void start_select(t)
  23. struct token *t;
  24.    {
  25.    struct token *t1;
  26.    struct tok_lst *tlst;
  27.    int condition;
  28.    int nesting;
  29.  
  30.    /*
  31.     * determine if condition is true.
  32.     */
  33.    if (t->tok_id == PpIf)
  34.       condition = eval(t);  /* #if - evaluate expression */
  35.    else {
  36.       /*
  37.        * #ifdef or #ifndef - see if an identifier is defined.
  38.        */
  39.       t1 = NULL;
  40.       nxt_non_wh(&t1);
  41.       if (t1->tok_id != Identifier)
  42.          errt2(t1, "identifier must follow #", t->image);
  43.       condition = (m_lookup(t1) == NULL) ? 0 : 1;
  44.       if (t->tok_id == PpIfndef)
  45.          condition = !condition;
  46.       free_t(t1);
  47.       t1 = next_tok();
  48.       if (t1->tok_id != PpDirEnd)
  49.          errt2(t1, "expecting end of line following argument to #", t->image);
  50.       free_t(t1);
  51.       }
  52.  
  53.    /*
  54.     * look for the branch of the conditional inclusion to take or #endif.
  55.     */
  56.    nesting = 0;
  57.    while (!condition) {
  58.       t1 = next_tok();
  59.       if (t1 == NULL)
  60.         errt2(t, "no matching #endif for #", t->image);
  61.       switch (t1->tok_id) {
  62.          case PpIf:
  63.          case PpIfdef:
  64.          case PpIfndef:
  65.             /*
  66.              * Nested #if, #ifdef, or #ifndef in a branch of a conditional
  67.              *  that is being discarded. Contunue discarding until the
  68.              *  nesting level returns to 0.
  69.              */
  70.             ++nesting;
  71.             break;
  72.  
  73.          case PpEndif:
  74.             /*
  75.              * #endif found. See if this is this the end of a nested
  76.              *  conditional or the end of the conditional we are processing.
  77.              */
  78.             if (nesting > 0)
  79.               --nesting;
  80.             else {
  81.                /*
  82.                 * Discard any extraneous tokens on the end of the directive.
  83.                 */
  84.                while (t->tok_id != PpDirEnd) {
  85.                   free_t(t);
  86.                   t = next_tok();
  87.                   }
  88.                free_t(t);
  89.                free_t(t1);
  90.                return;
  91.                }
  92.             break;
  93.  
  94.          case PpElif:
  95.             /*
  96.              * #elif found. If this is not a nested conditional, see if
  97.              *   it has a true condition.
  98.              */
  99.             if (nesting == 0) {
  100.                free_t(t);
  101.                t = t1;
  102.                t1 = NULL;
  103.                condition = eval(t);
  104.                }
  105.             break;
  106.  
  107.          case PpElse:
  108.             /*
  109.              * #else found. If this is not a nested conditional, take
  110.              *  this branch.
  111.              */
  112.             if (nesting == 0) {
  113.                free_t(t);
  114.                t = t1;
  115.                t1 = next_tok();
  116.                /*
  117.                 * Discard any extraneous tokens on the end of the directive.
  118.                 */
  119.                while (t1->tok_id != PpDirEnd) {
  120.                   free_t(t1);
  121.                   t1 = next_tok();
  122.                   }
  123.                condition = 1;
  124.                }
  125.          }
  126.       free_t(t1);
  127.       }
  128.    tlst = new_t_lst(t);
  129.    tlst->next = src_stack->cond;
  130.    src_stack->cond = tlst;
  131.    }
  132.  
  133. /*
  134.  * end_select - handle #elif, #else, and #endif
  135.  */
  136. static void end_select(t)
  137. struct token *t;
  138.    {
  139.    struct tok_lst *tlst;
  140.    struct token *t1;
  141.    int nesting;
  142.  
  143.    /*
  144.     * Make sure we are processing conditional compilation and pop it
  145.     *  from the list of conditional nesting.
  146.     */
  147.    tlst = src_stack->cond;
  148.    if (tlst == NULL)
  149.       errt2(t, "invalid context for #", t->image);
  150.    src_stack->cond = tlst->next;
  151.    tlst->next = NULL;
  152.    free_t_lst(tlst);
  153.  
  154.    /*
  155.     * We are done with the selected branch for the conditional compilation.
  156.     *  Skip to the matching #endif (if we are not already there). Don't
  157.     *  be confused by nested conditionals.
  158.     */
  159.    nesting = 0;
  160.    t1 = copy_t(t);
  161.    while (t1->tok_id != PpEndif || nesting > 0) {
  162.       switch (t1->tok_id) {
  163.          case PpIf:
  164.          case PpIfdef:
  165.          case PpIfndef:
  166.             ++nesting;
  167.             break;
  168.  
  169.          case PpEndif:
  170.             --nesting;
  171.          }
  172.       free_t(t1);
  173.       t1 = next_tok();
  174.       if (t1 == NULL)
  175.         errt2(t, "no matching #endif for #", t->image);
  176.       }
  177.    free_t(t);
  178.  
  179.    /*
  180.     * Discard any extraneous tokens on the end of the #endif directive.
  181.     */
  182.    while (t1->tok_id != PpDirEnd) {
  183.       free_t(t1);
  184.       t1 = next_tok();
  185.       }
  186.    free_t(t1);
  187.    return;
  188.    }
  189.  
  190. /*
  191.  * incl_file - handle #include
  192.  */
  193. static void incl_file(t)
  194. struct token *t;
  195.    {
  196.    struct token *file_tok, *t1;
  197.    struct str_buf *sbuf;
  198.    char *s;
  199.    char *fname;
  200.    int line;
  201.  
  202.    file_tok = NULL;
  203.    advance_tok(&file_tok);
  204.  
  205.    /*
  206.     * Determine what form the head file name takes.
  207.     */
  208.    if (file_tok->tok_id != StrLit && file_tok->tok_id != PpHeader) {
  209.       /*
  210.        * see if macro expansion created a name of the form <...>
  211.        */
  212.       t1 = file_tok;
  213.       s = t1->image;
  214.       fname = t1->fname;
  215.       line = t1->line;
  216.       if (*s != '<')
  217.          errt1(t1, "invalid include file syntax");
  218.       ++s;
  219.  
  220.       /*
  221.        * Gather into a string buffer the characters from subsequent tokens
  222.        *  until the closing '>' is found, then create a "header" token
  223.        *  from it.
  224.        */
  225.       sbuf = get_sbuf();
  226.       while (*s != '>') {
  227.          while (*s != '\0' && *s != '>')
  228.             AppChar(*sbuf, *s++);
  229.          if (*s == '\0') {
  230.             switch (t1->tok_id) {
  231.                case StrLit:
  232.                case LStrLit:
  233.                   AppChar(*sbuf, '"');
  234.                   break;
  235.                case CharConst:
  236.                case LCharConst:
  237.                   AppChar(*sbuf, '\'');
  238.                   break;
  239.                }
  240.             free_t(t1);
  241.             t1 = interp_dir();
  242.             switch (t1->tok_id) {
  243.                case StrLit:
  244.                   AppChar(*sbuf, '"');
  245.                   break;
  246.                case LStrLit:
  247.                   AppChar(*sbuf, 'L');
  248.                   AppChar(*sbuf, '"');
  249.                   break;
  250.                case CharConst:
  251.                   AppChar(*sbuf, '\'');
  252.                   break;
  253.                case LCharConst:
  254.                   AppChar(*sbuf, 'L');
  255.                   AppChar(*sbuf, '\'');
  256.                   break;
  257.                case PpDirEnd:
  258.                   errt1(t1, "invalid include file syntax");
  259.                }
  260.             if (t1->tok_id == WhiteSpace)
  261.                AppChar(*sbuf, ' ');
  262.             else
  263.                s = t1->image;
  264.             }
  265.          }
  266.       if (*++s != '\0')
  267.          errt1(t1, "invalid include file syntax");
  268.       free_t(t1);
  269.       file_tok = new_token(PpHeader, str_install(sbuf), fname, line);
  270.       rel_sbuf(sbuf);
  271.       }
  272.  
  273.    t1 = interp_dir();
  274.    if (t1->tok_id != PpDirEnd)
  275.       errt1(t1, "invalid include file syntax");
  276.    free_t(t1);
  277.  
  278.    /*
  279.     * Add the file to the top of the token source stack.
  280.     */
  281.    if (file_tok->tok_id == StrLit)
  282.       include(t, file_tok->image, 0);
  283.    else
  284.       include(t, file_tok->image, 1);
  285.    free_t(file_tok);
  286.    free_t(t);
  287.    }
  288.  
  289. /*
  290.  * define - handle #define and #begdef
  291.  */
  292. static void define(t)
  293. struct token *t;
  294.    {
  295.    struct token *mname;   /* name of macro */
  296.    int category;      /* NoArgs for object-like macro, else number params */
  297.    int multi_line;
  298.    struct id_lst *prmlst; /* parameter list */
  299.    struct tok_lst *body;  /* replacement list */
  300.    struct token *t1;
  301.    struct id_lst **pilst;
  302.    struct tok_lst **ptlst;
  303.    int nesting;
  304.  
  305.    /*
  306.     * Get the macro name.
  307.     */
  308.    mname = NULL;
  309.    nxt_non_wh(&mname);
  310.    if (mname->tok_id != Identifier)
  311.       errt2(mname, "syntax error in #", t->image);
  312.  
  313.    /*
  314.     * Determine if this macro takes arguments.
  315.     */
  316.    prmlst = NULL;
  317.    t1 = next_tok();
  318.    if (t1->tok_id == '(') {
  319.       /*
  320.        * function like macro - gather parameter list
  321.        */
  322.       pilst = &prmlst;
  323.       nxt_non_wh(&t1);
  324.       if (t1->tok_id == Identifier) {
  325.          category = 1;
  326.          (*pilst) = new_id_lst(t1->image);
  327.          pilst = &(*pilst)->next;
  328.          nxt_non_wh(&t1);
  329.          while (t1->tok_id == ',') {
  330.             nxt_non_wh(&t1);
  331.             if (t1->tok_id != Identifier)
  332.                errt1(t1, "a parameter to a macro must be an identifier");
  333.             ++category;
  334.             (*pilst) = new_id_lst(t1->image);
  335.             pilst = &(*pilst)->next;
  336.             nxt_non_wh(&t1);
  337.             }
  338.          }
  339.       else
  340.          category = 0;
  341.       if (t1->tok_id != ')')
  342.          errt2(t1, "syntax error in #", t->image);
  343.       free_t(t1);
  344.       t1 = next_tok();
  345.       }
  346.    else
  347.       category = NoArgs; /* object-like macro */
  348.  
  349.    /*
  350.     * Gather the body of the macro.
  351.     */
  352.    body = NULL;
  353.    ptlst = &body;
  354.    if (t->tok_id == PpDefine) {  /* #define */
  355.       multi_line = 0;
  356.       /*
  357.        * strip leading white space
  358.        */
  359.       while (t1->tok_id == WhiteSpace) {
  360.          free_t(t1);
  361.          t1 = next_tok();
  362.          }
  363.  
  364.       while (t1->tok_id != PpDirEnd) {
  365.          /*
  366.           * Expansion of this type of macro does not trigger #line directives.
  367.           */
  368.          t1->flag &= ~LineChk;
  369.  
  370.          (*ptlst) = new_t_lst(t1);
  371.          ptlst = &(*ptlst)->next;
  372.          t1 = next_tok();
  373.          }
  374.       }
  375.    else {
  376.       /*
  377.        *  #begdef
  378.        */
  379.       multi_line = 1;
  380.       if (t1->tok_id != PpDirEnd)
  381.          errt1(t1, "expecting new-line at end of #begdef");
  382.       free_t(t1);
  383.  
  384.       /*
  385.        * Gather tokens until #enddef. Nested #begdef-#enddefs are put
  386.        *  in this macro and not processed until the macro is expanded.
  387.        */
  388.       nesting = 0;
  389.       t1 = next_tok();
  390.       while (t1 != NULL && (nesting > 0 || t1->tok_id != PpEnddef)) {
  391.          if (t1->tok_id == PpBegdef)
  392.             ++nesting;
  393.          else if (t1->tok_id == PpEnddef)
  394.             --nesting;
  395.          (*ptlst) = new_t_lst(t1);
  396.          ptlst = &(*ptlst)->next;
  397.          t1 = next_tok();
  398.          }
  399.       if (t1 == NULL)
  400.          errt1(t, "unexpected end-of-file in #begdef");
  401.       free_t(t1);
  402.       t1 = next_tok();
  403.       if (t1->tok_id != PpDirEnd)
  404.          errt1(t1, "expecting new-line at end of #enddef");
  405.       }
  406.    free_t(t1);
  407.    free_t(t);
  408.  
  409.    /*
  410.     * Install the macro in the macro symbol table.
  411.     */
  412.    m_install(mname, category, multi_line, prmlst, body);
  413.    free_t(mname);
  414.    }
  415.  
  416. /*
  417.  * expand - add expansion of macro to source stack.
  418.  */
  419. static int expand(t, m)
  420. struct token *t;
  421. struct macro *m;
  422.    {
  423.    struct token *t1 = NULL;
  424.    struct token *t2;
  425.    struct token *whsp = NULL;
  426.    union src_ref ref;
  427.    struct tok_lst **args, **exp_args;
  428.    struct tok_lst **tlp, **trail_whsp;
  429.    struct src *stack_sav;
  430.    int nparm;
  431.    int narg;
  432.    int paren_nest;
  433.    int line;
  434.    char *fname;
  435.  
  436.    ++m->ref_cnt;
  437.  
  438.    args = NULL;
  439.    exp_args = NULL;
  440.    if (m->category >= 0) {
  441.       /*
  442.        * This macro requires an argument list. Gather it, if there is one.
  443.        */
  444.       nparm = m->category;
  445.       narg = 0;
  446.       merge_whsp(&whsp, &t1, next_tok);
  447.       if (t1 == NULL || t1->tok_id != '(') {
  448.          /*
  449.           * There is no argument list. Do not expand the macro, just push
  450.           *  back the tokens we read ahead.
  451.           */
  452.          if (t1 != NULL)
  453.             src_stack->toks[src_stack->ntoks++] = t1;
  454.          if (whsp != NULL)
  455.             src_stack->toks[src_stack->ntoks++] = whsp;
  456.          --m->ref_cnt;
  457.          return 0;
  458.          }
  459.       free_t(whsp);
  460.  
  461.       /*
  462.        * See how many arguments we expect.
  463.        */
  464.       if (nparm == 0)
  465.          nxt_non_wh(&t1);
  466.       else {
  467.          /*
  468.           * Allocate an array for both raw and macro-expanded token lists
  469.           *  for the arguments.
  470.           */
  471.          args = alloc(nparm * sizeof(struct tok_lst *));
  472.          exp_args = alloc(nparm * sizeof(struct tok_lst *));
  473.  
  474.          /*
  475.           * Gather the tokens for each argument.
  476.           */
  477.          paren_nest = 0;
  478.          for ( ; narg < nparm && t1 != NULL && t1->tok_id != ')'; ++narg) {
  479.             /*
  480.              * Strip leading white space from the argument.
  481.              */
  482.             nxt_non_wh(&t1);
  483.             tlp = &args[narg];  /* location of raw token list for this arg */
  484.             *tlp = NULL;
  485.             trail_whsp = NULL;
  486.             /*
  487.              * Gather tokens for this argument.
  488.              */
  489.             while (t1 != NULL && (paren_nest > 0 || (t1->tok_id != ',' &&
  490.                  t1->tok_id != ')'))) {
  491.                if (t1->tok_id == '(')
  492.                   ++paren_nest;
  493.                if (t1->tok_id == ')')
  494.                   --paren_nest;
  495.                t1->flag &= ~LineChk;
  496.  
  497.                /*
  498.                 * Link this token into the list for the argument. If this
  499.                 *  might be trailing white space, remember where the pointer
  500.                 *  to it is so it can be discarded later.
  501.                 */
  502.                *tlp = new_t_lst(t1);
  503.                if (t1->tok_id == WhiteSpace) {
  504.                   if (trail_whsp == NULL)
  505.                      trail_whsp = tlp;
  506.                   }
  507.                else
  508.                   trail_whsp = NULL;
  509.                tlp = &(*tlp)->next;
  510.                t1 = next_tok();
  511.                }
  512.             /*
  513.              * strip trailing white space
  514.              */
  515.             if (trail_whsp != NULL) {
  516.                free_t_lst(*trail_whsp);
  517.                *trail_whsp = NULL;
  518.                }
  519.  
  520.             /*
  521.              * Create a macro expanded token list for the argument. This is
  522.              *  done by establishing a separate preprocessing context with
  523.              *  a new source stack. The current stack must be be saved and
  524.              *  restored.
  525.              */
  526.             tlp = &exp_args[narg]; /* location of expanded token list for arg */
  527.             *tlp = NULL;
  528.             if (src_stack->flag == CharSrc)
  529.                src_stack->u.cs->next_char = next_char; /* save state */
  530.             stack_sav = src_stack;
  531.             src_stack = &dummy;
  532.             ref.tlst = args[narg];
  533.             push_src(TokLst, &ref); /* initial stack is list of raw tokens */
  534.             /*
  535.              * Get macro expanded tokens.
  536.              */
  537.             for (t2 = interp_dir(); t2 != NULL; t2 = interp_dir()) {
  538.                *tlp = new_t_lst(t2);
  539.                tlp = &(*tlp)->next;
  540.                }
  541.             src_stack = stack_sav;
  542.             if (src_stack->flag == CharSrc) {
  543.                /*
  544.                 * Restore global state for tokenizing.
  545.                 */
  546.                first_char = src_stack->u.cs->char_buf;
  547.                next_char = src_stack->u.cs->next_char;
  548.                last_char = src_stack->u.cs->last_char;
  549.                }
  550.             }
  551.          }
  552.       if (t1 == NULL)
  553.          errt2(t, "unexpected end-of-file in call to macro ", t->image);
  554.       if (t1->tok_id != ')')
  555.          errt2(t1, "too many arguments for macro call to ", t->image);
  556.       if (narg < nparm)
  557.          errt2(t1, "too few arguments for macro call to ", t->image);
  558.       free_t(t1);
  559.       }
  560.  
  561.    ++m->recurse;
  562.    ref.me = new_me(m, args, exp_args);
  563.    push_src(MacExpand, &ref);
  564.    /*
  565.     * Don't loose generation of #line directive before regular
  566.     *  macros, if there should be one.
  567.     */
  568.    if (!m->multi_line && (t->flag & LineChk)) {
  569.       line = t->line;
  570.       fname = t->fname;
  571.       t1 = next_tok();
  572.       if (t1 != NULL) {
  573.          if (!(t1->flag & LineChk)) {
  574.             t1->flag |= LineChk;
  575.             t1->line = line;
  576.             t1->fname = fname;
  577.             }
  578.          src_stack->toks[src_stack->ntoks++] = t1;
  579.          }
  580.       }
  581.    return 1;
  582.    }
  583.  
  584. /*
  585.  * toks_to_str - put in a buffer the string image of tokens up to the end of
  586.  *    of a preprocessor directive.
  587.  */
  588. static void toks_to_str(sbuf, t)
  589. struct str_buf *sbuf;
  590. struct token *t;
  591.    {
  592.    char *s;
  593.  
  594.    while (t->tok_id != PpDirEnd) {
  595.       if (t->tok_id == WhiteSpace)
  596.          AppChar(*sbuf, ' ');
  597.       else {
  598.          if (t->tok_id == LCharConst || t->tok_id == LStrLit)
  599.             AppChar(*sbuf, 'L');
  600.          if (t->tok_id == CharConst || t->tok_id == LCharConst)
  601.             AppChar(*sbuf, '\'');
  602.          else if (t->tok_id == StrLit || t->tok_id == LStrLit)
  603.             AppChar(*sbuf, '"');
  604.          for (s = t->image; *s != '\0'; ++s)
  605.             AppChar(*sbuf, *s);
  606.          if (t->tok_id == CharConst || t->tok_id == LCharConst)
  607.             AppChar(*sbuf, '\'');
  608.          else if (t->tok_id == StrLit || t->tok_id == LStrLit)
  609.             AppChar(*sbuf, '"');
  610.          }
  611.       free_t(t);
  612.       t = next_tok();
  613.       }
  614.    free_t(t);
  615.    }
  616.  
  617. /*
  618.  * interp_dir - interpret preprocessing directives and recognize macro calls.
  619.  */
  620. struct token *interp_dir()
  621.    {
  622.    struct token *t, *t1;
  623.    struct macro *m;
  624.    struct str_buf *sbuf;
  625.    char *s;
  626.  
  627.    /*
  628.     * See if the caller pushed back any tokens
  629.     */
  630.    if (src_stack->ntoks > 0)
  631.       return src_stack->toks[--src_stack->ntoks];
  632.  
  633.    for (;;) {
  634.       t = next_tok();
  635.       if (t == NULL)
  636.           return NULL;
  637.  
  638.       switch (t->tok_id) {
  639.          case PpIf:          /* #if */
  640.          case PpIfdef:       /* #ifdef */
  641.          case PpIfndef:      /* #endif */
  642.             start_select(t);
  643.             break;
  644.  
  645.          case PpElif:        /* #elif */
  646.          case PpElse:        /* #else */
  647.          case PpEndif:       /* #endif */
  648.             end_select(t);
  649.             break;
  650.  
  651.          case PpInclude:     /* #include */
  652.             incl_file(t);
  653.             break;
  654.  
  655.          case PpDefine:      /* #define */
  656.          case PpBegdef:      /* #begdef */
  657.             define(t);
  658.             break;
  659.  
  660.          case PpEnddef:      /* #endif, but we have not seen an #begdef */
  661.             errt1(t, "invalid context for #enddef");
  662.  
  663.          case PpUndef:       /* #undef */
  664.             /*
  665.              * Get the identifier and delete it from the macro symbol table.
  666.              */
  667.             t1 = NULL;
  668.             nxt_non_wh(&t1);
  669.             if (t1->tok_id != Identifier)
  670.                errt1(t1, "#undef requires an identifier argument");
  671.             m_delete(t1);
  672.             free_t(t1);
  673.             t1 = next_tok();
  674.             if (t1->tok_id != PpDirEnd)
  675.                errt1(t1, "syntax error for #undef");
  676.             free_t(t1);
  677.             free_t(t);
  678.             break;
  679.  
  680.          case PpLine:        /* #line */
  681.             /* this directive is handled in next_tok() */
  682.             break;
  683.  
  684.          case PpError:       /* #error */
  685.             /*
  686.              * Create an error message out of the rest of the tokens
  687.              *  in this directive.
  688.              */
  689.             sbuf = get_sbuf();
  690.             t1 = NULL;
  691.             nxt_non_wh(&t1);
  692.             toks_to_str(sbuf, t1);
  693.             errt1(t, str_install(sbuf));
  694.             break;
  695.  
  696.          case PpPragma:       /* #pramga */
  697.          case PpSkip:
  698.             /*
  699.              * Ignore all pragmas and all non-ANSI directives that need not
  700.              *   be passed to the caller.
  701.              */
  702.             t1 = next_tok();
  703.             while (t1->tok_id != PpDirEnd) {
  704.                free_t(t1);
  705.                t1 = next_tok();
  706.                }
  707.             free_t(t);
  708.             free_t(t1);
  709.             break;
  710.  
  711.          case PpKeep:
  712.             /*
  713.              * This is a directive special to an application using
  714.              *  this preprocessor. Pass it on to the application.
  715.              */
  716.             sbuf = get_sbuf();
  717.             AppChar(*sbuf, '#');
  718.             for (s = t->image; *s != '\0'; ++s)
  719.                AppChar(*sbuf, *s);
  720.             toks_to_str(sbuf, next_tok());
  721.             t->image = str_install(sbuf);
  722.             rel_sbuf(sbuf);
  723.             return t;
  724.  
  725.          case PpNull:         /* # */
  726.             free_t(t);
  727.             free_t(next_tok());   /* must be PpDirEnd */
  728.             break;
  729.  
  730.          default:
  731.             /*
  732.              * This is not a directive, see if it is a macro name.
  733.              */
  734.             if (t->tok_id == Identifier && !(t->flag & NoExpand) &&
  735.                  (m = m_lookup(t)) != NULL) {
  736.                if (max_recurse < 0 || m->recurse < max_recurse) {
  737.                   if (expand(t, m))
  738.                      free_t(t);
  739.                   else
  740.                      return t;
  741.                   }
  742.                else {
  743.                   t->flag |= NoExpand;
  744.                   return t;
  745.                   }
  746.                }
  747.             else
  748.                return t; /* nothing special, just return it */
  749.          }
  750.       }
  751.    }
  752.  
  753.  
  754. /*
  755.  * See if compiler used to build the preprocessor recognizes '\a'
  756.  *  as the bell character.
  757.  */
  758. #if '\a' == Bell
  759.  
  760. #define TokSrc interp_dir
  761.  
  762. #else      /*  '\a' == Bell  */
  763.  
  764. #define TokSrc check_bell
  765.  
  766. /*
  767.  * fix_bell - replace \a characters which correct octal escape sequences.
  768.  */
  769. static char *fix_bell(s)
  770. register char *s;
  771.    {
  772.    struct str_buf *sbuf;
  773.  
  774.    sbuf = get_sbuf();
  775.    while (*s != '\0') {
  776.       AppChar(*sbuf, *s);
  777.       if (*s == '\\') {
  778.          ++s;
  779.          if (*s == 'a') {
  780.             AppChar(*sbuf, '0' + ((Bell >> 6) & 7));
  781.             AppChar(*sbuf, '0' + ((Bell >> 3) & 7));
  782.             AppChar(*sbuf, '0' + (Bell & 7));
  783.             }
  784.          else
  785.             AppChar(*sbuf, *s);
  786.          }
  787.       ++s;
  788.       }
  789.    s = str_install(sbuf);
  790.    rel_sbuf(sbuf);
  791.    return s;
  792.    }
  793.  
  794. /*
  795.  * check_bell - check for \a in character and string constants. This is only
  796.  *  used with compilers which don't give the standard interpretation to \a.
  797.  */
  798. static struct token *check_bell()
  799.    {
  800.    struct token *t;
  801.    register char *s;
  802.  
  803.    t = interp_dir();
  804.    if (t == NULL)
  805.       return NULL;
  806.    switch (t->tok_id) {
  807.       case StrLit:
  808.       case LStrLit:
  809.       case CharConst:
  810.       case LCharConst:
  811.          s = t->image;
  812.          while (*s != '\0') {
  813.            if (*s == '\\') {
  814.               if (*++s == 'a') {
  815.                  /*
  816.                   * There is at least one \a to replace.
  817.                   */
  818.                  t->image = fix_bell(t->image);
  819.                  break;
  820.                  }
  821.               }
  822.            ++s;
  823.            }
  824.       }
  825.    return t;
  826.    }
  827.  
  828. #endif     /*  '\a' == Bell  */
  829.  
  830. /*
  831.  * preproc - return the next fully preprocessed token.
  832.  */
  833. struct token *preproc()
  834.    {
  835.    struct token *t1, *whsp, *t2, *str;
  836.    struct str_buf *sbuf;
  837.    int i;
  838.    char *escape_seq;
  839.    char *s;
  840.    char hex_char;
  841.    int is_hex_char;
  842.  
  843.    t1 = TokSrc();
  844.    if (t1 == NULL)
  845.       return NULL;  /* end of file */
  846.  
  847.    /*
  848.     * Concatenate adjacent strings. There is a potential problem if the
  849.     *  first string ends in a octal or hex constant and the second string
  850.     *  starts with a corresponding digit. For example the strings "\12"
  851.     *  and  "7" should be concatenated to produce the 2 character string
  852.     *  "\0127" not the one character string "\127". When such a situation
  853.     *  arises, the last character of the first string is converted to a
  854.     *  canonical 3-digit octal form.
  855.     */
  856.    if (t1->tok_id == StrLit || t1->tok_id == LStrLit) {
  857.       /*
  858.        * See what the next non-white space token is, but don't discard any
  859.        *  white space yet.
  860.        */
  861.       whsp = NULL;
  862.       merge_whsp(&whsp, &t2, TokSrc);
  863.       if (t2 != NULL && (t2->tok_id == StrLit || t2->tok_id == LStrLit)) {
  864.          /*
  865.           * There are at least two adjacent string literals, concatenate them.
  866.           */
  867.          sbuf = get_sbuf();
  868.          str = copy_t(t1);
  869.          while (t2 != NULL && (t2->tok_id == StrLit || t2->tok_id == LStrLit)) {
  870.             s = t1->image;
  871.             while (*s != '\0') {
  872.                if (*s == '\\') {
  873.                   AppChar(*sbuf, *s);
  874.                   ++s;
  875.                   if (*s == 'x') {
  876.                      /*
  877.                       * Hex escape sequence.
  878.                       */
  879.                      hex_char = 0;
  880.                      escape_seq = s;
  881.                      ++s;
  882.                      is_hex_char = 1;
  883.                      while (is_hex_char) {
  884.                         if (*s >= '0' && *s <= '9')
  885.                            hex_char = (hex_char << 4) | (*s - '0');
  886.                         else switch (*s) {
  887.                            case 'a': case 'A':
  888.                               hex_char = (hex_char << 4) | 10;
  889.                               break;
  890.                            case 'b': case 'B':
  891.                               hex_char = (hex_char << 4) | 11;
  892.                               break;
  893.                            case 'c': case 'C':
  894.                               hex_char = (hex_char << 4) | 12;
  895.                               break;
  896.                            case 'd': case 'D':
  897.                               hex_char = (hex_char << 4) | 13;
  898.                               break;
  899.                            case 'e': case 'E':
  900.                               hex_char = (hex_char << 4) | 14;
  901.                               break;
  902.                            case 'f': case 'F':
  903.                               hex_char = (hex_char << 4) | 15;
  904.                               break;
  905.                            default: is_hex_char = 0;
  906.                            }
  907.                         if (is_hex_char)
  908.                            ++s;
  909.                         }
  910.                      /*
  911.                       * If this escape sequence is at the end of the
  912.                       *  string and the next string starts with a
  913.                       *  hex digit, use the canonical form, otherwise
  914.                       *  use it as is.
  915.                       */
  916.                      if (*s == '\0' && isxdigit(t2->image[0])) {
  917.                         AppChar(*sbuf, ((hex_char >> 6) & 03) + '0');
  918.                         AppChar(*sbuf, ((hex_char >> 3) & 07) + '0');
  919.                         AppChar(*sbuf, (hex_char        & 07) + '0');
  920.                         }
  921.                      else
  922.                         while (escape_seq != s)
  923.                            AppChar(*sbuf, *escape_seq++);
  924.                      }
  925.                   else if (*s >= '0' && *s <= '7') {
  926.                      /*
  927.                       * Octal escape sequence.
  928.                       */
  929.                      escape_seq = s;
  930.                      i = 1;
  931.                      while (i <= 3 && *s >= '0' && *s <= '7') {
  932.                         ++i;
  933.                         ++s;
  934.                         }
  935.                      /*
  936.                       * If this escape sequence is at the end of the
  937.                       *  string and the next string starts with an
  938.                       *  octal digit, extend it to 3 digits, otherwise
  939.                       *  use it as is.
  940.                       */
  941.                      if (*s == '\0' && t2->image[0] >= '0' &&
  942.                            t2->image[0] <= '7' && i <= 3) {
  943.                         AppChar(*sbuf, '0');
  944.                         if (i <= 2)
  945.                            AppChar(*sbuf, '0');
  946.                         }
  947.                      while (escape_seq != s)
  948.                         AppChar(*sbuf, *escape_seq++);
  949.                      }
  950.                   }
  951.                else {
  952.                   /*
  953.                    * Not an escape sequence, just copy the character to the
  954.                    *  buffer.
  955.                    */
  956.                   AppChar(*sbuf, *s);
  957.                   ++s;
  958.                   }
  959.                }
  960.             free_t(t1);
  961.             t1 = t2;
  962.  
  963.             /*
  964.              * Get the next non-white space token, saving any skipped
  965.              *  white space.
  966.              */
  967.             merge_whsp(&whsp, &t2, TokSrc);
  968.             }
  969.  
  970.          /*
  971.           * Copy the image of the last token into the buffer, creating
  972.           *  the image for the concatenated token.
  973.           */
  974.          for (s = t1->image; *s != '\0'; ++s)
  975.             AppChar(*sbuf, *s);
  976.          str->image = str_install(sbuf);
  977.          free_t(t1);
  978.          t1 = str;
  979.          rel_sbuf(sbuf);
  980.          }
  981.  
  982.       /*
  983.        * Push back any look-ahead tokens.
  984.        */
  985.       if (t2 != NULL)
  986.          src_stack->toks[src_stack->ntoks++] = t2;
  987.       if (whsp != NULL)
  988.          src_stack->toks[src_stack->ntoks++] = whsp;
  989.       }
  990.    return t1;
  991.    }
  992.