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 / bldtok.c next >
C/C++ Source or Header  |  2001-12-12  |  21KB  |  767 lines

  1. /*
  2.  * This file contains routines for building tokens out of characters from a
  3.  *  "character source". This source is the top element on the source stack.
  4.  */
  5. #include "../preproc/preproc.h"
  6. #include "../preproc/ptoken.h"
  7.  
  8. /*
  9.  * Prototypes for static functions.
  10.  */
  11. static int           pp_tok_id  (char *s);
  12. static struct token *chck_wh_sp (struct char_src *cs);
  13. static struct token *pp_number  (void);
  14. static struct token *char_str   (int delim, int tok_id);
  15. static struct token *hdr_tok    (int delim, int tok_id, struct char_src *cs);
  16.  
  17. int whsp_image = NoSpelling;    /* indicate what is in white space tokens */
  18. struct token *zero_tok;         /* token for literal 0 */
  19. struct token *one_tok;          /* token for literal 1 */
  20.  
  21. #include "../preproc/pproto.h"
  22.  
  23. /*
  24.  * IsWhSp(c) - true if c is a white space character.
  25.  */
  26. #define IsWhSp(c) (c == ' ' || c == '\n' || c == '\t' || c == '\v' || c == '\f')
  27.  
  28. /*
  29.  * AdvChar() - advance to next character from buffer, filling the buffer
  30.  *   if needed.
  31.  */
  32. #define AdvChar() \
  33.    if (++next_char == last_char) \
  34.       fill_cbuf();
  35.  
  36. static int line;                   /* current line number */
  37. static char *fname;                /* current file name */
  38. static struct str_buf tknize_sbuf; /* string buffer */
  39.  
  40. /*
  41.  * List of preprocessing directives and the corresponding token ids.
  42.  */
  43. static struct rsrvd_wrd pp_rsrvd[] = {
  44.    PPDirectives
  45.    {"if",      PpIf},
  46.    {"else",    PpElse},
  47.    {"ifdef",   PpIfdef},
  48.    {"ifndef",  PpIfndef},
  49.    {"elif",    PpElif},
  50.    {"endif",   PpEndif},
  51.    {"include", PpInclude},
  52.    {"define",  PpDefine},
  53.    {"undef",   PpUndef},
  54.    {"begdef",  PpBegdef},
  55.    {"enddef",  PpEnddef},
  56.    {"line",    PpLine},
  57.    {"error",   PpError},
  58.    {"pragma",  PpPragma},
  59.    {NULL, Invalid}};
  60.  
  61. /*
  62.  * init_tok - initialize tokenizer.
  63.  */
  64. void init_tok()
  65.    {
  66.    struct rsrvd_wrd *rw;
  67.    static int first_time = 1;
  68.  
  69.    if (first_time) {
  70.       first_time = 0;
  71.       init_sbuf(&tknize_sbuf); /* initialize string buffer */
  72.       /*
  73.        * install reserved words into the string table
  74.        */
  75.       for (rw = pp_rsrvd; rw->s != NULL; ++rw)
  76.          rw->s = spec_str(rw->s);
  77.  
  78.       zero_tok = new_token(PpNumber, spec_str("0"), "", 0);
  79.       one_tok = new_token(PpNumber, spec_str("1"), "", 0);
  80.       }
  81.    }
  82.  
  83. /*
  84.  * pp_tok_id - see if s in the name of a preprocessing directive.
  85.  */
  86. static int pp_tok_id(s)
  87. char *s;
  88.    {
  89.    struct rsrvd_wrd *rw;
  90.  
  91.    for (rw = pp_rsrvd; rw->s != NULL && rw->s != s; ++rw)
  92.       ;
  93.    return rw->tok_id;
  94.    }
  95.  
  96. /*
  97.  * chk_eq_sign - look ahead to next character to see if it is an equal sign.
  98.  *  It is used for processing -D options.
  99.  */
  100. int chk_eq_sign()
  101.    {
  102.    if (*next_char == '=') {
  103.       AdvChar();
  104.       return 1;
  105.       }
  106.    else
  107.       return 0;
  108.    }
  109.  
  110. /*
  111.  * chck_wh_sp - If the input is at white space, construct a white space token
  112.  *  and return it, otherwise return NULL. This function also helps keeps track
  113.  *  of preprocessor directive boundaries.
  114.  */
  115. static struct token *chck_wh_sp(cs)
  116. struct char_src *cs;
  117.    {
  118.    register int c1, c2;
  119.    struct token *t;
  120.    int tok_id;
  121.  
  122.    /*
  123.     * See if we are at white space or a comment.
  124.     */
  125.    c1 = *next_char;
  126.    if (!IsWhSp(c1) && (c1 != '/' || next_char[1] != '*'))
  127.       return NULL;
  128.  
  129.    /*
  130.     * Fine the line number of the current character in the line number
  131.     *  buffer, and correct it if we have encountered any #line directives.
  132.     */
  133.    line = cs->line_buf[next_char - first_char] + cs->line_adj;
  134.    if (c1 == '\n')
  135.       --line;      /* a new-line really belongs to the previous line */
  136.  
  137.    tok_id = WhiteSpace;
  138.    for (;;) {
  139.       if (IsWhSp(c1)) {
  140.          /*
  141.           * The next character is a white space. If we are retaining the
  142.           *  image of the white space in the token, copy the character to
  143.           *  the string buffer. If we are in the midst of a preprocessor
  144.           *  directive and find a new-line, indicate the end of the
  145.           *  the directive.
  146.           */
  147.          AdvChar();
  148.          if (whsp_image != NoSpelling)
  149.             AppChar(tknize_sbuf, c1);
  150.          if (c1 == '\n') {
  151.             if (cs->dir_state == Within)
  152.                tok_id = PpDirEnd;
  153.             cs->dir_state = CanStart;
  154.             if (tok_id == PpDirEnd)
  155.                break;
  156.             }
  157.          }
  158.       else if (c1 == '/' && next_char[1] == '*') {
  159.          /*
  160.           * Start of comment. If we are retaining the image of comments,
  161.           *  copy the characters into the string buffer.
  162.           */
  163.          if (whsp_image == FullImage) {
  164.             AppChar(tknize_sbuf, '/');
  165.             AppChar(tknize_sbuf, '*');
  166.             }
  167.          AdvChar();
  168.          AdvChar();
  169.  
  170.          /*
  171.           * Look for the end of the comment.
  172.           */
  173.          c1 = *next_char;
  174.          c2 = next_char[1];
  175.          while (c1 != '*' || c2 != '/') {
  176.             if (c1 == EOF)
  177.                 errfl1(fname, line, "eof encountered in comment");
  178.             AdvChar();
  179.             if (whsp_image == FullImage)
  180.                AppChar(tknize_sbuf, c1);
  181.             c1 = c2;
  182.             c2 = next_char[1];
  183.             }
  184.  
  185.          /*
  186.           * Determine if we are retaining the image of a comment, replacing
  187.           *  a comment by one space character, or ignoring comments.
  188.           */
  189.          if (whsp_image == FullImage) {
  190.             AppChar(tknize_sbuf, '*');
  191.             AppChar(tknize_sbuf, '/');
  192.             }
  193.          else if (whsp_image == NoComment)
  194.             AppChar(tknize_sbuf, ' ');
  195.          AdvChar();
  196.          AdvChar();
  197.          }
  198.       else
  199.          break;         /* end of white space */
  200.       c1 = *next_char;
  201.       }
  202.  
  203.    /*
  204.     * If we are not retaining the image of white space, replace it all
  205.     *  with one space character.
  206.     */
  207.    if (whsp_image == NoSpelling)
  208.       AppChar(tknize_sbuf, ' ');
  209.  
  210.    t = new_token(tok_id, str_install(&tknize_sbuf), fname, line);
  211.  
  212.    /*
  213.     * Look ahead to see if a ## operator is next.
  214.     */
  215.    if (*next_char == '#' && next_char[1] == '#')
  216.       if (tok_id == PpDirEnd)
  217.          errt1(t, "## expressions must not cross directive boundaries");
  218.       else {
  219.          /*
  220.           * Discard white space before a ## operator.
  221.           */
  222.          free_t(t);
  223.          return NULL;
  224.          }
  225.    return t;
  226.    }
  227.  
  228. /*
  229.  * pp_number - Create a token for a preprocessing number (See ANSI C Standard
  230.  *  for the syntax of such a number).
  231.  */
  232. static struct token *pp_number()
  233.    {
  234.    register int c;
  235.  
  236.    c = *next_char;
  237.    for (;;) {
  238.       if (c == 'e' || c == 'E') {
  239.          AppChar(tknize_sbuf, c);
  240.          AdvChar();
  241.          c = *next_char;
  242.          if (c == '+' || c == '-') {
  243.             AppChar(tknize_sbuf, c);
  244.             AdvChar();
  245.             c = *next_char;
  246.             }
  247.          }
  248.       else if (isdigit(c) || c == '.' || islower(c) || isupper(c) || c == '_') {
  249.          AppChar(tknize_sbuf, c);
  250.          AdvChar();
  251.          c = *next_char;
  252.          }
  253.       else {
  254.          return new_token(PpNumber, str_install(&tknize_sbuf), fname, line);
  255.          }
  256.       }
  257.    }
  258.  
  259. /*
  260.  * char_str - construct a token for a character constant or string literal.
  261.  */
  262. static struct token *char_str(delim, tok_id)
  263. int delim;
  264. int tok_id;
  265.    {
  266.    register int c;
  267.  
  268.    for (c = *next_char; c != EOF && c != '\n' &&  c != delim; c = *next_char) {
  269.       AppChar(tknize_sbuf, c);
  270.       if (c == '\\') {
  271.          c = next_char[1];
  272.          if (c == EOF || c == '\n')
  273.             break;
  274.          else {
  275.             AppChar(tknize_sbuf, c);
  276.             AdvChar();
  277.             }
  278.          }
  279.       AdvChar();
  280.       }
  281.    if (c == EOF)
  282.       errfl1(fname, line, "End-of-file encountered within a literal");
  283.    if (c == '\n')
  284.       errfl1(fname, line, "New-line encountered within a literal");
  285.    AdvChar();
  286.    return new_token(tok_id, str_install(&tknize_sbuf), fname, line);
  287.    }
  288.  
  289. /*
  290.  * hdr_tok - create a token for an #include header. The delimiter may be
  291.  *  > or ".
  292.  */
  293. static struct token *hdr_tok(delim, tok_id, cs)
  294. int delim;
  295. int tok_id;
  296. struct char_src *cs;
  297.    {
  298.    register int c;
  299.  
  300.    line = cs->line_buf[next_char - first_char] + cs->line_adj;
  301.    AdvChar();
  302.  
  303.    for (c = *next_char; c != delim; c = *next_char) {
  304.       if (c == EOF)
  305.          errfl1(fname, line,
  306.             "End-of-file encountered within a header name");
  307.       if (c == '\n')
  308.          errfl1(fname, line,
  309.             "New-line encountered within a header name");
  310.       AppChar(tknize_sbuf, c);
  311.       AdvChar();
  312.       }
  313.    AdvChar();
  314.    return new_token(tok_id, str_install(&tknize_sbuf), fname, line);
  315.    }
  316.  
  317. /*
  318.  * tokenize - return the next token from the character source on the top
  319.  *  of the source stack.
  320.  */
  321. struct token *tokenize()
  322.    {
  323.    struct char_src *cs;
  324.    struct token *t1, *t2;
  325.    register int c;
  326.    int tok_id;
  327.  
  328.  
  329.    cs = src_stack->u.cs;
  330.  
  331.    /*
  332.     * Check to see if the last call left a token from a look ahead.
  333.     */
  334.    if (cs->tok_sav != NULL) {
  335.       t1 = cs->tok_sav;
  336.       cs->tok_sav = NULL;
  337.       return t1;
  338.       }
  339.  
  340.    if (*next_char == EOF)
  341.       return NULL;
  342.  
  343.    /*
  344.     * Find the current line number and file name for the character
  345.     *  source and check for white space.
  346.     */
  347.    line = cs->line_buf[next_char - first_char] + cs->line_adj;
  348.    fname = cs->fname;
  349.    if ((t1 = chck_wh_sp(cs)) != NULL)
  350.        return t1;
  351.  
  352.    c = *next_char;  /* look at next character */
  353.    AdvChar();
  354.  
  355.    /*
  356.     * If the last thing we saw in this character source was white space
  357.     *  containing a new-line, then we must look for the start of a
  358.     *  preprocessing directive.
  359.     */
  360.    if (cs->dir_state == CanStart) {
  361.       cs->dir_state = Reset;
  362.       if  (c == '#' && *next_char != '#') {
  363.          /*
  364.           * Assume we are within a preprocessing directive and check
  365.           *  for white space to discard.
  366.           */
  367.          cs->dir_state = Within;
  368.          if ((t1 = chck_wh_sp(cs)) != NULL)
  369.             if (t1->tok_id == PpDirEnd) {
  370.                /*
  371.                 * We found a new-line, this is a null preprocessor directive.
  372.                 */
  373.                cs->tok_sav = t1;
  374.                AppChar(tknize_sbuf, '#');
  375.                return new_token(PpNull, str_install(&tknize_sbuf), fname, line);
  376.                }
  377.             else
  378.                free_t(t1);  /* discard white space */
  379.          c = *next_char;
  380.          if (islower(c) || isupper(c) || c == '_') {
  381.             /*
  382.              * Tokenize the identifier following the #
  383.              */
  384.             t1 = tokenize();
  385.             if ((tok_id = pp_tok_id(t1->image)) == Invalid) {
  386.                /*
  387.                 * We have a stringizing operation, not a preprocessing
  388.                 *  directive.
  389.                 */
  390.                cs->dir_state = Reset;
  391.                cs->tok_sav = t1;
  392.                AppChar(tknize_sbuf, '#');
  393.                return new_token('#', str_install(&tknize_sbuf), fname, line);
  394.                }
  395.             else {
  396.                t1->tok_id = tok_id;
  397.                if (tok_id == PpInclude) {
  398.                   /*
  399.                    * A header name has to be tokenized specially. Find
  400.                    *  it, then save the token.
  401.                    */
  402.                   if ((t2 = chck_wh_sp(cs)) != NULL)
  403.                      if (t2->tok_id == PpDirEnd)
  404.                         errt1(t2, "file name missing from #include");
  405.                      else
  406.                         free_t(t2);
  407.                   c = *next_char;
  408.                   if (c == '"')
  409.                      cs->tok_sav = hdr_tok('"', StrLit, cs);
  410.                   else if (c == '<')
  411.                      cs->tok_sav = hdr_tok('>', PpHeader, cs);
  412.                   }
  413.                /*
  414.                 * Return the token indicating the kind of preprocessor
  415.                 *  directive we have started.
  416.                 */
  417.                return t1;
  418.                }
  419.             }
  420.          else
  421.             errfl1(fname, line,
  422.                "# must be followed by an identifier or keyword");
  423.          }
  424.       }
  425.  
  426.    /*
  427.     * Check for literals containing wide characters.
  428.     */
  429.    if (c == 'L') {
  430.       if (*next_char == '\'') {
  431.          AdvChar();
  432.          t1 = char_str('\'', LCharConst);
  433.          if (t1->image[0] == '\0')
  434.             errt1(t1, "invalid character constant");
  435.          return t1;
  436.          }
  437.       else if (*next_char == '"') {
  438.          AdvChar();
  439.          return char_str('"', LStrLit);
  440.          }
  441.       }
  442.  
  443.    /*
  444.     * Check for identifier.
  445.     */
  446.    if (islower(c) || isupper(c) || c == '_') {
  447.       AppChar(tknize_sbuf, c);
  448.       c = *next_char;
  449.       while (islower(c) || isupper(c) || isdigit(c) || c == '_') {
  450.          AppChar(tknize_sbuf, c);
  451.          AdvChar();
  452.          c = *next_char;
  453.          }
  454.       return new_token(Identifier, str_install(&tknize_sbuf), fname, line);
  455.      }
  456.  
  457.    /*
  458.     * Check for number.
  459.     */
  460.    if (isdigit(c)) {
  461.       AppChar(tknize_sbuf, c);
  462.       return pp_number();
  463.       }
  464.  
  465.    /*
  466.     * Check for character constant.
  467.     */
  468.    if (c == '\'') {
  469.       t1 = char_str(c, CharConst);
  470.       if (t1->image[0] == '\0')
  471.          errt1(t1, "invalid character constant");
  472.       return t1;
  473.       }
  474.  
  475.    /*
  476.     * Check for string constant.
  477.     */
  478.    if (c == '"')
  479.       return char_str(c, StrLit);
  480.  
  481.    /*
  482.     * Check for operators and punctuation. Anything that does not fit these
  483.     *  categories is a single character token.
  484.     */
  485.    AppChar(tknize_sbuf, c);
  486.    switch (c) {
  487.       case '.':
  488.          c = *next_char;
  489.          if (isdigit(c)) {
  490.             /*
  491.              * Number
  492.              */
  493.             AppChar(tknize_sbuf, c);
  494.             AdvChar();
  495.             return pp_number();
  496.             }
  497.          else if (c == '.' && next_char[1] == '.') {
  498.             /*
  499.              *  ...
  500.              */
  501.             AdvChar();
  502.             AdvChar();
  503.             AppChar(tknize_sbuf, '.');
  504.             AppChar(tknize_sbuf, '.');
  505.             return new_token(Ellipsis, str_install(&tknize_sbuf), fname, line);
  506.             }
  507.          else
  508.             return new_token('.', str_install(&tknize_sbuf), fname, line);
  509.  
  510.       case '+':
  511.          c = *next_char;
  512.          if (c == '+') {
  513.             /*
  514.              *  ++
  515.              */
  516.             AppChar(tknize_sbuf, '+');
  517.             AdvChar();
  518.             return new_token(Incr, str_install(&tknize_sbuf), fname, line);
  519.             }
  520.          else if (c == '=') {
  521.             /*
  522.              *  +=
  523.              */
  524.             AppChar(tknize_sbuf, '=');
  525.             AdvChar();
  526.             return new_token(PlusAsgn, str_install(&tknize_sbuf), fname, line);
  527.             }
  528.          else
  529.             return new_token('+', str_install(&tknize_sbuf), fname, line);
  530.  
  531.       case '-':
  532.          c = *next_char;
  533.          if (c == '>') {
  534.             /*
  535.              *  ->
  536.              */
  537.             AppChar(tknize_sbuf, '>');
  538.             AdvChar();
  539.             return new_token(Arrow, str_install(&tknize_sbuf), fname, line);
  540.             }
  541.          else if (c == '-') {
  542.             /*
  543.              *  --
  544.              */
  545.             AppChar(tknize_sbuf, '-');
  546.             AdvChar();
  547.             return new_token(Decr, str_install(&tknize_sbuf), fname, line);
  548.             }
  549.          else if (c == '=') {
  550.             /*
  551.              *  -=
  552.              */
  553.             AppChar(tknize_sbuf, '=');
  554.             AdvChar();
  555.             return new_token(MinusAsgn, str_install(&tknize_sbuf), fname,
  556.                line);
  557.             }
  558.          else
  559.             return new_token('-', str_install(&tknize_sbuf), fname, line);
  560.  
  561.       case '<':
  562.          c = *next_char;
  563.          if (c == '<') {
  564.             AppChar(tknize_sbuf, '<');
  565.             AdvChar();
  566.             if (*next_char == '=') {
  567.                /*
  568.                 *  <<=
  569.                 */
  570.                AppChar(tknize_sbuf, '=');
  571.                AdvChar();
  572.                return new_token(LShftAsgn, str_install(&tknize_sbuf), fname,
  573.                   line);
  574.                }
  575.             else
  576.                /*
  577.                 *  <<
  578.                 */
  579.                return new_token(LShft, str_install(&tknize_sbuf), fname, line);
  580.             }
  581.          else if (c == '=') {
  582.             /*
  583.              *  <=
  584.              */
  585.             AppChar(tknize_sbuf, '=');
  586.             AdvChar();
  587.             return new_token(Leq, str_install(&tknize_sbuf), fname, line);
  588.             }
  589.          else
  590.             return new_token('<', str_install(&tknize_sbuf), fname, line);
  591.  
  592.       case '>':
  593.          c = *next_char;
  594.          if (c == '>') {
  595.             AppChar(tknize_sbuf, '>');
  596.             AdvChar();
  597.             if (*next_char == '=') {
  598.                /*
  599.                 *  >>=
  600.                 */
  601.                AppChar(tknize_sbuf, '=');
  602.                AdvChar();
  603.                return new_token(RShftAsgn, str_install(&tknize_sbuf), fname,
  604.                   line);
  605.                }
  606.             else
  607.                /*
  608.                 *  >>
  609.                 */
  610.                return new_token(RShft, str_install(&tknize_sbuf), fname, line);
  611.             }
  612.          else if (c == '=') {
  613.             /*
  614.              *  >=
  615.              */
  616.             AppChar(tknize_sbuf, '=');
  617.             AdvChar();
  618.             return new_token(Geq, str_install(&tknize_sbuf), fname, line);
  619.             }
  620.          else
  621.             return new_token('>', str_install(&tknize_sbuf), fname, line);
  622.  
  623.       case '=':
  624.          if (*next_char == '=') {
  625.             /*
  626.              *  ==
  627.              */
  628.             AppChar(tknize_sbuf, '=');
  629.             AdvChar();
  630.             return new_token(TokEqual, str_install(&tknize_sbuf), fname, line);
  631.             }
  632.          else
  633.             return new_token('=', str_install(&tknize_sbuf), fname, line);
  634.  
  635.       case '!':
  636.          if (*next_char == '=') {
  637.             /*
  638.              *  !=
  639.              */
  640.             AppChar(tknize_sbuf, '=');
  641.             AdvChar();
  642.             return new_token(Neq, str_install(&tknize_sbuf), fname, line);
  643.             }
  644.          else
  645.             return new_token('!', str_install(&tknize_sbuf), fname, line);
  646.  
  647.       case '&':
  648.          c = *next_char;
  649.          if (c == '&') {
  650.             /*
  651.              *  &&
  652.              */
  653.             AppChar(tknize_sbuf, '&');
  654.             AdvChar();
  655.             return new_token(And, str_install(&tknize_sbuf), fname, line);
  656.             }
  657.          else if (c == '=') {
  658.             /*
  659.              *  &=
  660.              */
  661.             AppChar(tknize_sbuf, '=');
  662.             AdvChar();
  663.             return new_token(AndAsgn, str_install(&tknize_sbuf), fname, line);
  664.             }
  665.          else
  666.             return new_token('&', str_install(&tknize_sbuf), fname, line);
  667.  
  668.       case '|':
  669.          c = *next_char;
  670.          if (c == '|') {
  671.             /*
  672.              *  ||
  673.              */
  674.             AppChar(tknize_sbuf, '|');
  675.             AdvChar();
  676.             return new_token(Or, str_install(&tknize_sbuf), fname, line);
  677.             }
  678.          else if (c == '=') {
  679.             /*
  680.              *  |=
  681.              */
  682.             AppChar(tknize_sbuf, '=');
  683.             AdvChar();
  684.             return new_token(OrAsgn, str_install(&tknize_sbuf), fname, line);
  685.             }
  686.          else
  687.             return new_token('|', str_install(&tknize_sbuf), fname, line);
  688.  
  689.       case '*':
  690.          if (*next_char == '=') {
  691.             /*
  692.              *  *=
  693.              */
  694.             AppChar(tknize_sbuf, '=');
  695.             AdvChar();
  696.             return new_token(MultAsgn, str_install(&tknize_sbuf), fname, line);
  697.             }
  698.          else
  699.             return new_token('*', str_install(&tknize_sbuf), fname, line);
  700.  
  701.       case '/':
  702.          if (*next_char == '=') {
  703.             /*
  704.              *  /=
  705.              */
  706.             AppChar(tknize_sbuf, '=');
  707.             AdvChar();
  708.             return new_token(DivAsgn, str_install(&tknize_sbuf), fname, line);
  709.             }
  710.          else
  711.             return new_token('/', str_install(&tknize_sbuf), fname, line);
  712.  
  713.       case '%':
  714.          if (*next_char == '=') {
  715.             /*
  716.              *  &=
  717.              */
  718.             AppChar(tknize_sbuf, '=');
  719.             AdvChar();
  720.             return new_token(ModAsgn, str_install(&tknize_sbuf), fname, line);
  721.             }
  722.          else
  723.             return new_token('%', str_install(&tknize_sbuf), fname, line);
  724.  
  725.       case '^':
  726.          if (*next_char == '=') {
  727.             /*
  728.              *  ^=
  729.              */
  730.             AppChar(tknize_sbuf, '=');
  731.             AdvChar();
  732.             return new_token(XorAsgn, str_install(&tknize_sbuf), fname, line);
  733.             }
  734.          else
  735.             return new_token('^', str_install(&tknize_sbuf), fname, line);
  736.  
  737.       case '#':
  738.          /*
  739.           * Token pasting or stringizing operator.
  740.           */
  741.          if (*next_char == '#') {
  742.             /*
  743.              *  ##
  744.              */
  745.             AppChar(tknize_sbuf, '#');
  746.             AdvChar();
  747.             t1 =  new_token(PpPaste, str_install(&tknize_sbuf), fname, line);
  748.             }
  749.          else
  750.             t1 = new_token('#', str_install(&tknize_sbuf), fname, line);
  751.  
  752.          /*
  753.           * The operand must be in the same preprocessing directive.
  754.           */
  755.          if ((t2 = chck_wh_sp(cs)) != NULL)
  756.             if (t2->tok_id == PpDirEnd)
  757.               errt2(t2, t1->image,
  758.                " preprocessing expression must not cross directive boundary");
  759.             else
  760.                free_t(t2);
  761.          return t1;
  762.  
  763.       default:
  764.          return new_token(c, str_install(&tknize_sbuf), fname, line);
  765.       }
  766.    }
  767.