home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / icon / dos / src / icont / tlex.c < prev    next >
C/C++ Source or Header  |  1992-02-10  |  21KB  |  799 lines

  1. /*
  2.  * tlex.c -- the lexical analyzer.
  3.  */
  4.  
  5. #include "../h/gsupport.h"
  6. #include "tproto.h"
  7. #include "trans.h"
  8. #include "tlex.h"
  9. #include "tree.h"
  10. #include "token.h"
  11. #include <ctype.h>
  12.  
  13. #if MACINTOSH
  14. #if MPW
  15. #include <CursorCtl.h>
  16. #define CURSORINTERVAL 100
  17. #endif                    /* MPW */
  18. #endif                    /* MACINTOSH */
  19.  
  20. /*
  21.  * Prototypes.
  22.  */
  23.  
  24. hidden    int        ctlesc        Params((noargs));
  25. hidden    struct toktab   *findres    Params((noargs));
  26. hidden    struct toktab   *getident    Params((int ac,int *cc));
  27. hidden    struct toktab   *getnum        Params((int ac,int *cc));
  28. hidden    struct toktab   *getopr        Params((int ac,int *cc));
  29. hidden    struct toktab   *getstring    Params((int ac,int *cc));
  30. hidden    int        hexesc        Params((noargs));
  31. hidden    int        nextchar    Params((noargs));
  32. hidden    int        octesc        Params((int ac));
  33. hidden    int        setfilenm    Params((int c));
  34. hidden    int        setlineno    Params((noargs));
  35.  
  36. #define isletter(s)    (isupper(c) | islower(c))
  37.  
  38. #if EBCDIC
  39. extern char ToEBCDIC[256], FromEBCDIC[256];
  40. #endif                    /* EBCDIC */
  41.  
  42. #if !EBCDIC
  43. #define tonum(c)        (isdigit(c) ? (c - '0') : ((c & 037) + 9))
  44.  
  45. /*
  46.  * esctab - translates single-character escapes in string literals.
  47.  */
  48.  
  49. static char esctab[] = {
  50.    000,   001,   002,   003,   004,   005,   006,   007,   /* NUL-BEL */
  51.    010,   011,   012,   013,   014,   015,   016,   017,   /* BS -SI */
  52.    020,   021,   022,   023,   024,   025,   026,   027,   /* DLE-ETB */
  53.    030,   031,   032,   033,   034,   035,   036,   037,   /* CAN-US */
  54.    ' ',   '!',   '"',   '#',   '$',   '%',   '&',   '\'',  /* !"#$%&' */
  55.    '(',   ')',   '*',   '+',   ',',   '-',   '.',   '/',   /* ()*+,-./ */
  56.    000,   001,   002,   003,   004,   005,   006,   007,   /* 01234567 */
  57.    010,   011,   ':',   ';',   '<',   '=',   '>',   '?',   /* 89:;<=>? */
  58.    '@',   'A',   '\b',  'C',   0177,  033,   014,   'G',   /* @ABCDEFG */
  59.    'H',   'I',   'J',   'K',   '\n',  'M',  '\n',   'O',   /* HIJKLMNO */
  60.    'P',   'Q',   '\r',  'S',   '\t',  'U',   013,   'W',   /* PQRSTUVW */
  61.    'X',   'Y',   'Z',   '[',   '\\',  ']',   '^',   '_',   /* XYZ[\]^_ */
  62.    '`',   'a',   '\b',  'c',   0177,  033,   014,   'g',   /* `abcdefg */
  63.    'h',   'i',   'j',   'k',   '\n',  'm',   '\n',  'o',   /* hijklmno */
  64.    'p',   'q',   '\r',  's',   '\t',  'u',   013,   'w',   /* pqrstuvw */
  65.    'x',   'y',   'z',   '{',   '|',   '}',   '~',   0177,  /* xyz{|}~ */
  66.    0200,  0201,  0202,  0203,  0204,  0205,  0206,  0207,
  67.    0210,  0211,  0212,  0213,  0214,  0215,  0216,  0217,
  68.    0220,  0221,  0222,  0223,  0224,  0225,  0226,  0227,
  69.    0230,  0231,  0232,  0233,  0234,  0235,  0236,  0237,
  70.    0240,  0241,  0242,  0243,  0244,  0245,  0246,  0247,
  71.    0250,  0251,  0252,  0253,  0254,  0255,  0256,  0257,
  72.    0260,  0261,  0262,  0263,  0264,  0265,  0266,  0267,
  73.    0270,  0271,  0272,  0273,  0274,  0275,  0276,  0277,
  74.    0300,  0301,  0302,  0303,  0304,  0305,  0306,  0307,
  75.    0310,  0311,  0312,  0313,  0314,  0315,  0316,  0317,
  76.    0320,  0321,  0322,  0323,  0324,  0325,  0326,  0327,
  77.    0330,  0331,  0332,  0333,  0334,  0335,  0336,  0337,
  78.    0340,  0341,  0342,  0343,  0344,  0345,  0346,  0347,
  79.    0350,  0351,  0352,  0353,  0354,  0355,  0356,  0357,
  80.    0360,  0361,  0362,  0363,  0364,  0365,  0366,  0367,
  81.    0370,  0371,  0372,  0373,  0374,  0375,  0376,  0377,
  82.   };
  83. #else                                   /* !EBCDIC */
  84. /*
  85.  *  This is the EBCDIC table for handling escapes.
  86.  */
  87. static char esctab[] = {
  88.    0x00,  0x01,  0x02,  0x03,  0x04,  0x05,  0x06,  0x07,
  89.    0x08,  0x09,  0x0a,  0x0b,  0x0c,  0x0d,  0x0e,  0x0f,
  90.    0x10,  0x11,  0x12,  0x13,  0x14,  0x15,  0x16,  0x17,
  91.    0x18,  0x19,  0x1a,  0x1b,  0x1c,  0x1d,  0x1e,  0x1f,
  92.    0x20,  0x21,  0x22,  0x23,  0x24,  0x25,  0x26,  0x27,
  93.    0x28,  0x29,  0x2a,  0x2b,  0x2c,  0x2d,  0x2e,  0x2f,
  94.    0x30,  0x31,  0x32,  0x33,  0x34,  0x35,  0x36,  0x37,
  95.    0x38,  0x39,  0x3a,  0x3b,  0x3c,  0x3d,  0x3e,  0x3f,
  96.    ' ',   0x41,  0x42,  0x43,  0x44,  0x45,  0x46,  0x47,
  97.    0x48,  0x49,  0x4a,  0x4b,  0x4c,  0x4d,  0x4e,  0x4f,
  98.    0x50,  0x51,  0x52,  0x53,  0x54,  0x55,  0x56,  0x57,
  99.    0x58,  0x59,  0x5a,  0x5b,  0x5c,  0x5d,  0x5e,  0x5f,
  100.    0x60,  0x61,  0x62,  0x63,  0x64,  0x65,  0x66,  0x67,
  101.    0x68,  0x69,  0x6a,  0x6b,  0x6c,  0x6d,  0x6e,  0x6f,
  102.    0x70,  0x71,  0x72,  0x73,  0x74,  0x75,  0x76,  0x77,
  103.    0x78,  0x79,  0x7a,  0x7b,  0x7c,  0x7d,  0x7e,  0x7f,
  104.    0x80,  'a',   0x16,  'c',   0x07,  0x27,  0x0c,  'g',
  105.    'h',   'i',   0x8a,  0x8b,  0x8c,  0x8d,  0x8e,  0x8f,
  106.  
  107. #if EBCDIC == 2
  108.    0x90,  'j',   'k',   0x15,  'm',   0x15,  'o',   'p',
  109. #else                    /* EBCDIC == 2 */
  110.    0x90,  'j',   'k',   0x25,  'm',   0x15,  'o',   'p',
  111. #endif                    /* EBCDIC == 2 */
  112.  
  113.    'q',   0x0d,  0x9a,  0x9b,  0x9c,  0x9d,  0x9e,  0x9f,
  114.    0xa0,  0xa1,  's',   0x05,  'u',   0x0b,  'w',   'x',
  115.    'y',   'z',   0xaa,  0xab,  0xac,  0xad,  0xae,  0xaf,
  116.    0xb0,  0xb1,  0xb2,  0xb3,  0xb4,  0xb5,  0xb6,  0xb7,
  117.    0xb8,  0xb9,  0xba,  0xbb,  0xbc,  0xbd,  0xbe,  0xbf,
  118.    0xc0,  'A',   0x16,  'C',   0x07,  0x27,  0x0c,  'G',
  119.    'H',   'I',   0xca,  0xcb,  0xcc,  0xcd,  0xce,  0xcf,
  120.  
  121. #if EBCDIC == 2
  122.    0xd0,  'J',   'K',   0x15,  'M',   0x15,  'O',   'P',
  123. #else                    /* EBCDIC == 2 */
  124.    0xd0,  'J',   'K',   0x25,  'M',   0x15,  'O',   'P',
  125. #endif                    /* EBCDIC == 2 */
  126.  
  127.    'Q',   0x0d,  0xda,  0xdb,  0xdc,  0xdd,  0xde,  0xdf,
  128.    0xe0,  0xe1,  'S',   0x05,  'U',   0x0b,  'W',   'X',
  129.    'Y',   'Z',   0xea,  0xeb,  0xec,  0xed,  0xee,  0xef,
  130.    0,   1,   2,   3,     4,     5,     6,     7,
  131.    8,   9,   0xfa,   0xfb,  0xfc,  0xfd,  0xfe,  0xff,
  132.    };
  133. #endif                    /* !EBCDIC */
  134.  
  135. struct node tok_loc =
  136.    {0, NULL, 0, 0};    /* "model" node containing location of current token */
  137.  
  138. struct toktab dottok =
  139.    {".", DOT, Beginner};    /* token struct for DOT token */
  140.  
  141. /*
  142.  * yylex - find the next token in the input stream, and return its token
  143.  *  type and value to the parser.
  144.  *
  145.  * Variables of interest:
  146.  *
  147.  *  cc - character following last token.
  148.  *  comflag - set if in a comment.
  149.  *  nlflag - set if a newline was between the last token and the current token
  150.  *  lastend - set if the last token was an Ender.
  151.  *  lastval - when a semicolon is inserted and returned, lastval gets the
  152.  *   token value that would have been returned if the semicolon hadn't
  153.  *   been inserted.
  154.  */
  155.  
  156. static struct toktab *lasttok = NULL;
  157. static int lastend = 0;
  158. static int eofflag = 0;
  159. static int cc = '\n';
  160.  
  161. int yylex()
  162.    {
  163.    register struct toktab *t;
  164.    register int c;
  165.    int nlflag;
  166.    int comflag;
  167.    static nodeptr lastval;
  168.    static struct node semi_loc;
  169.  
  170.    if (lasttok != NULL) {
  171.       /*
  172.        * A semicolon was inserted and returned on the last call to yylex,
  173.        *  instead of going to the input, return lasttok and set the
  174.        *  appropriate variables.
  175.        */
  176.  
  177.       yylval = lastval;
  178.       tok_loc = *lastval;
  179.       t = lasttok;
  180.       goto ret;
  181.       }
  182.    nlflag = 0;
  183.    comflag = 0;
  184. loop:
  185.    c = cc;
  186.    /*
  187.     * Remember where a semicolon will go if we insert one.
  188.     */
  189.    semi_loc.n_file = tok_loc.n_file;
  190.    semi_loc.n_line = in_line;
  191.    semi_loc.n_col = incol;
  192.    /*
  193.     * Skip whitespace and comments and process #line directives.
  194.     */
  195.    while (c == Comment || isspace(c)) {
  196.       if (c == '\n') {
  197.          nlflag++;
  198.          c = NextChar;
  199.      if (c == Comment) {
  200.             /*
  201.          * Check for #line directive at start of line.
  202.              */
  203.             if (('l' == (c = NextChar)) &&
  204.                 ('i' == (c = NextChar)) &&
  205.                 ('n' == (c = NextChar)) &&
  206.                 ('e' == (c = NextChar))) {
  207.                c = setlineno();
  208.            while ((c == ' ') || (c == '\t'))
  209.           c = NextChar;
  210.                if (c != EOF && c != '\n')
  211.                   c = setfilenm(c);
  212.            }
  213.         while (c != EOF && c != '\n')
  214.                c = NextChar;
  215.         }
  216.          }
  217.       else {
  218.      if (c == Comment) {
  219.         while (c != EOF && c != '\n')
  220.                c = NextChar;
  221.         }
  222.          else {
  223.             c = NextChar;
  224.             }
  225.          }
  226.       }
  227.    /*
  228.     * A token is the next thing in the input.  Set token location to
  229.     *  the current line and column.
  230.     */
  231.    tok_loc.n_line = in_line;
  232.    tok_loc.n_col = incol;
  233.  
  234.    if (c == EOF) {
  235.       /*
  236.        * End of file has been reached.    Set eofflag, return T_Eof, and
  237.        *  set cc to EOF so that any subsequent scans also return T_Eof.
  238.        */
  239.       if (eofflag++) {
  240.      eofflag = 0;
  241.      cc = '\n';
  242.      yylval = NULL;
  243.      return 0;
  244.      }
  245.       cc = EOF;
  246.       t = T_Eof;
  247.       yylval = NULL;
  248.       goto ret;
  249.       }
  250.  
  251.    /*
  252.     * Look at current input character to determine what class of token
  253.     *  is next and take the appropriate action.  Note that the various
  254.     *  token gathering routines write a value into cc.
  255.     */
  256.    if (isalpha(c) || (c == '_')) {   /* gather ident or reserved word */
  257.       if ((t = getident(c, &cc)) == NULL)
  258.      goto loop;
  259.       }
  260.    else if (isdigit(c) || (c == '.')) {    /* gather numeric literal or "." */
  261.       if ((t = getnum(c, &cc)) == NULL)
  262.      goto loop;
  263.       }
  264.    else if (c == '"' || c == '\'') {    /* gather string or cset literal */
  265.       if ((t = getstring(c, &cc)) == NULL)
  266.      goto loop;
  267.       }
  268.    else {            /* gather longest legal operator */
  269.       if ((t = getopr(c, &cc)) == NULL)
  270.      goto loop;
  271.       yylval = OpNode(t->t_type);
  272.       }
  273.    if (nlflag && lastend && (t->t_flags & Beginner)) {
  274.       /*
  275.        * A newline was encountered between the current token and the last,
  276.        *  the last token was an Ender, and the current token is a Beginner.
  277.        *  Return a semicolon and save the current token in lastval.
  278.        */
  279.       lastval = yylval;
  280.       lasttok = t;
  281.       tok_loc = semi_loc;
  282.       yylval = OpNode(SEMICOL);
  283.       return SEMICOL;
  284.       }
  285. ret:
  286.    /*
  287.     * Clear lasttok, set lastend if the token being returned is an
  288.     *  Ender, and return the token.
  289.     */
  290.    lasttok = 0;
  291.    lastend = t->t_flags & Ender;
  292.    return (t->t_type);
  293.    }
  294.  
  295. #ifdef MultipleRuns
  296. /*
  297.  * yylexinit - initialize variables for multiple runs
  298.  */
  299. novalue yylexinit()
  300.    {
  301.    lasttok = NULL;
  302.    lastend = 0;
  303.    eofflag = 0;
  304.    cc = '\n';
  305.    }
  306.  
  307. #endif                    /* MultipleRuns */
  308. /*
  309.  * getident - gather an identifier beginning with ac.  The character
  310.  *  following identifier goes in cc.
  311.  */
  312.  
  313. static struct toktab *getident(ac, cc)
  314. int ac;
  315. int *cc;
  316.    {
  317.    register int c;
  318.    register char *p;
  319.    register struct toktab *t;
  320.  
  321.    c = ac;
  322.    p = strf;
  323.    /*
  324.     * Copy characters into string space until a non-alphanumeric character
  325.     *  is found.
  326.     */
  327.    do {
  328.       if (p >= stre)
  329.      tsyserr("out of string space");
  330.       *p++ = c;
  331.       c = NextChar;
  332.       } while (isalnum(c) || (c == '_'));
  333.    if (p >= stre)
  334.       tsyserr("out of string space");
  335.    *p++ = 0;
  336.    *cc = c;
  337.    /*
  338.     * If the identifier is a reserved word, make a ResNode for it and return
  339.     *  the token value.  Otherwise, install it with putid, make an
  340.     *  IdNode for it, and return.
  341.     */
  342.    if ((t = findres()) != NULL) {
  343.       yylval = ResNode(t->t_type);
  344.       return t;
  345.       }
  346.    else {
  347.       yylval = IdNode(putid((int)(p-strf)));
  348.       return (struct toktab *)T_Ident;
  349.       }
  350.    }
  351.  
  352. /*
  353.  * findres - if the string just copied into the string space by getident
  354.  *  is a reserved word, return a pointer to its entry in the token table.
  355.  *  Return NULL if the string isn't a reserved word.
  356.  */
  357.  
  358. static struct toktab *findres()
  359.    {
  360.    register struct toktab *t;
  361.    register char c, *p;
  362.  
  363.    p = strf;
  364.    c = *p;
  365.    if (!islower(c))
  366.       return NULL;
  367.    /*
  368.     * Point t at first reserved word that starts with c (if any).
  369.     */
  370.    if ((t = restab[c - 'a']) == NULL)
  371.       return NULL;
  372.    /*
  373.     * Search through reserved words, stopping when a match is found
  374.     *  or when the current reserved word doesn't start with c.
  375.     */
  376.    while (t->t_word[0] == c) {
  377.       if (strcmp(t->t_word, p) == 0)
  378.      return t;
  379.       t++;
  380.       }
  381.    return NULL;
  382.    }
  383.  
  384. /*
  385.  * getnum - gather a numeric literal starting with ac and put the
  386.  *  character following the literal into *cc.
  387.  *
  388.  * getnum also handles the "." operator, which is distinguished from
  389.  *  a numeric literal by what follows it.
  390.  */
  391.  
  392. static struct toktab *getnum(ac, cc)
  393. int ac;
  394. int *cc;
  395.    {
  396.    register int c, r, state;
  397.    char *p;
  398.    int realflag;
  399.  
  400.    p = strf;
  401.    c = ac;
  402.    if (c == '.') {
  403.       r = 0;
  404.       state = 7;
  405.       realflag = 1;
  406.       }
  407.    else { 
  408.       r = tonum(c);
  409.       state = 0;
  410.       realflag = 0;
  411.       }
  412.    for (;;) {
  413.       if (p >= stre)
  414.      tsyserr("out of string space");
  415.       *p++ = c;
  416.       c = NextChar;
  417.       switch (state) {
  418.      case 0:        /* integer part */
  419.         if (isdigit(c))        { r = r * 10 + tonum(c); continue; }
  420.         if (c == '.')           { state = 1; realflag++; continue; }
  421.         if (c == 'e' || c == 'E')  { state = 2; realflag++; continue; }
  422.         if (c == 'r' || c == 'R')  {
  423.            state = 5;
  424.            if (r < 2 || r > 36)
  425.           tfatal("invalid radix for integer literal", (char *)NULL);
  426.            continue;
  427.            }
  428.         break;
  429.      case 1:        /* fractional part */
  430.         if (isdigit(c))   continue;
  431.         if (c == 'e' || c == 'E')   { state = 2; continue; }
  432.         break;
  433.      case 2:        /* optional exponent sign */
  434.         if (c == '+' || c == '-') { state = 3; continue; }
  435.      case 3:        /* first digit after e, e+, or e- */
  436.         if (isdigit(c)) { state = 4; continue; }
  437.         tfatal("invalid real literal", (char *)NULL);
  438.         break;
  439.      case 4:        /* remaining digits after e */
  440.         if (isdigit(c))   continue;
  441.         break;
  442.      case 5:        /* first digit after r */
  443.         if ((isdigit(c) || isletter(c)) && tonum(c) < r)
  444.            { state = 6; continue; }
  445.         tfatal("invalid integer literal", (char *)NULL);
  446.         break;
  447.      case 6:        /* remaining digits after r */
  448.         if (isdigit(c) || isletter(c)) {
  449.            if (tonum(c) >= r) {    /* illegal digit for radix r */
  450.           tfatal("invalid digit in integer literal", (char *)NULL);
  451.           r = tonum('z');       /* prevent more messages */
  452.           }
  453.            continue;
  454.            }
  455.         break;
  456.      case 7:        /* token began with "." */
  457.         if (isdigit(c)) {
  458.            state = 1;        /* followed by digit is a real const */ 
  459.            continue;
  460.            }
  461.         *cc = c;            /* anything else is just a dot */
  462.         yylval = OpNode(DOT);
  463.         return &dottok;
  464.      }
  465.       break;
  466.       }
  467.    if (p >= stre)
  468.       tsyserr("out of string space");
  469.    *p++ = 0;
  470.    *cc = c;
  471.    if (realflag) {
  472.       yylval = RealNode(putid((int)(p-strf)));
  473.       return T_Real;
  474.       }
  475.    yylval = IntNode(putid((int)(p-strf)));
  476.    return T_Int;
  477.    }
  478.  
  479. /*
  480.  * getstring - gather a string literal starting with ac and place the
  481.  *  character following the literal in *cc.
  482.  */
  483.  
  484. static struct toktab *getstring(ac, cc)
  485. int ac;
  486. int *cc;
  487.    {
  488.    register int c, sc;
  489.    register char *p;
  490.    char *lc;
  491.    int len;
  492.  
  493.    sc = c = ac;
  494.    p = strf;
  495.    lc = 0;
  496.    while ((c = NextChar) != sc && c != '\n' && c != EOF) {
  497.    contin:
  498.       if (c == '_')
  499.      lc = p;
  500.       else if (!isspace(c))
  501.      lc = 0;
  502.       if (c == Escape) {
  503.      c = NextChar;
  504.  
  505. #ifdef VarTran
  506.      *p++ = Escape;
  507. #else                    /* VarTran */
  508.      if (isoctal(c))
  509.         c = octesc(c);
  510.      else if (c == 'x')
  511.         c = hexesc();
  512.      else if (c == '^')
  513.         c = ctlesc();
  514.      else
  515.         c = esctab[c];
  516. #endif                    /* VarTran */
  517.  
  518.      if (c == EOF)
  519.         goto noquote;
  520.      }
  521.       if (p >= stre)
  522.      tsyserr("out of string space");
  523.       *p++ = c;
  524.       }
  525.    if (p >= stre)
  526.       tsyserr("out of string space");
  527.    *p++ = 0;
  528.    if (c == sc)
  529.       *cc = ' ';
  530.    else {
  531.       if (c == '\n' && lc) {
  532.      p = lc;
  533.      while ((c = NextChar) != EOF && isspace(c)) ;
  534.      if (c != EOF)
  535.         goto contin;
  536.      }
  537. noquote:
  538.       tfatal("unclosed quote", (char *)NULL);
  539.       *cc = c;
  540.       }
  541.    if (ac == '"') {     /* a string literal */
  542.       len = p - strf;
  543.       yylval = StrNode(putid((int)len), len);
  544.       return T_String;
  545.       }
  546.    else {        /* a cset literal */
  547.       len = p - strf;
  548.       yylval = CsetNode(putid((int)len), len);
  549.       return T_Cset;
  550.       }
  551.    }
  552.  
  553. #ifndef VarTran
  554.  
  555. /*
  556.  * ctlesc - translate a control escape -- backslash followed by
  557.  *  caret and one character.
  558.  */
  559.  
  560. static int ctlesc()
  561.    {
  562.    register int c;
  563.  
  564.    c = NextChar;
  565.    if (c == EOF)
  566.       return EOF;
  567.  
  568. #if !EBCDIC
  569.    return (c & 037);
  570. #else                    /* !EBCDIC */
  571.    return ToEBCDIC[FromEBCDIC[c] & 037];
  572.                         /* ctrl-x in EBCDIC is the EBCDIC equivalent */
  573.                         /* to ASCII ctrl-x                           */
  574. #endif                    /* !EBCDIC */
  575.  
  576.    }
  577.  
  578. /*
  579.  * octesc - translate an octal escape -- backslash followed by
  580.  *  one, two, or three octal digits.
  581.  */
  582.  
  583. static int octesc(ac)
  584. int ac;
  585.    {
  586.    register int c, nc, i;
  587.  
  588.    c = 0;
  589.    nc = ac;
  590.    i = 1;
  591.    do {
  592.       c = (c << 3) | (nc - '0');
  593.       nc = NextChar;
  594.       if (nc == EOF)
  595.      return EOF;
  596.       } while (isoctal(nc) && i++ < 3);
  597.    PushChar(nc);
  598.  
  599. #if EBCDIC != 2
  600.    return (c & 0377);
  601. #else                    /* EBCDIC != 2 */
  602.    return ToEBCDIC[c & 0377];
  603. #endif                    /* EBCDIC != 2 */
  604.    }
  605.  
  606. /*
  607.  * hexesc - translate a hexadecimal escape -- backslash-x
  608.  *  followed by one or two hexadecimal digits.
  609.  */
  610.  
  611. static int hexesc()
  612.    {
  613.    register int c, nc, i;
  614.  
  615.    c = 0;
  616.    i = 0;
  617.    while (i++ < 2) {
  618.       nc = NextChar;
  619.       if (nc == EOF)
  620.      return EOF;
  621.       if (nc >= 'a' && nc <= 'f')
  622.      nc -= 'a' - 10;
  623.       else if (nc >= 'A' && nc <= 'F')
  624.      nc -= 'A' - 10;
  625.       else if (isdigit(nc))
  626.      nc -= '0';
  627.       else {
  628.      PushChar(nc);
  629.      break;
  630.      }
  631.       c = (c << 4) | nc;
  632.       }
  633.  
  634. #if EBCDIC != 2
  635.    return c;
  636. #else                    /* EBCDIC != 2 */
  637.    return ToEBCDIC[c];
  638. #endif                    /* EBCDIC != 2 */
  639.  
  640.    }
  641.  
  642. #endif                    /* VarTran */
  643.  
  644. /*
  645.  * getopr - find the longest legal operator and return a pointer
  646.  *  to its entry in the token table.
  647.  */
  648.  
  649. static struct toktab *getopr(ac, cc)
  650. int ac;
  651. int *cc;
  652.    {
  653.    register struct optab *state;
  654.    register char c, i;
  655.  
  656.    state = state0;
  657.    c = ac;
  658.    for (;;) {
  659.       while ((i = state->o_input) && c != i)
  660.      state++;
  661.       switch (state->o_action) {
  662.      case A_Goto:
  663.         state = (struct optab *) state->o_val;
  664.         c = NextChar;
  665.         continue;
  666.      case A_Error:
  667.         tfatal("invalid character", (char *)NULL);
  668.         *cc = ' ';
  669.         return NULL;
  670.      case A_Return:
  671.         *cc = c;
  672.         return (struct toktab *)(state->o_val);
  673.      case A_Immret:
  674.         *cc = ' ';
  675.         return (struct toktab *)(state->o_val);
  676.      }
  677.       }
  678.    }
  679.  
  680. /*
  681.  * setlineno - set line number from #line comment, return following char.
  682.  */
  683.  
  684. static int setlineno()
  685.    {
  686.    register int c;
  687.  
  688.    while ((c = NextChar) == ' ' || c == '\t')
  689.       ;
  690.    if (c < '0' || c > '9') {
  691.       tfatal("no line number in #line directive", "");
  692.       while (c != EOF && c != '\n')
  693.      c = NextChar;
  694.       return c;
  695.       }
  696.    in_line = 0;
  697.    while (c >= '0' && c <= '9') {
  698.       in_line = in_line * 10 + (c - '0');
  699.       c = NextChar;
  700.       }
  701.    return c;
  702.    }
  703.  
  704. /*
  705.  * setfilenm -    set file name from #line comment, return following char.
  706.  *
  707.  * Assigning to comfile here does not provide the fine-grained
  708.  * control over filenames required by a real macro processor.
  709.  * setloc() in tcode.c ought to be restored to its earlier form and
  710.  * the initialization of filenames fixed.
  711.  */
  712.  
  713. static int setfilenm(c)
  714. register int c;
  715.    {
  716.    extern char *comfile;
  717.    register char *p;
  718.  
  719.    while (c == ' ' || c == '\t')
  720.       c = NextChar;
  721.    if (c != '"') {
  722.       tfatal("'\"' missing from file name in #line directive", "");
  723.       while (c != EOF && c != '\n')
  724.      c = NextChar;
  725.       return c;
  726.       }
  727.    p = strf;
  728.    while ((c = NextChar) != '"' && c != EOF && c != '\n') {
  729.       if (p >= stre)
  730.      tsyserr("out of string space");
  731.       *p++ = c;
  732.       }
  733.    *p++ = '\0';
  734.    if (c == '"') {
  735.       tok_loc.n_file = putid((int)(p-strf));
  736.       return NextChar;
  737.       }
  738.    else {
  739.       tfatal("'\"' missing from file name in #line directive", "");
  740.       return c;
  741.       }
  742.    }
  743.  
  744. /*
  745.  * nextchar - return the next character in the input.
  746.  */
  747.  
  748. static int nextchar()
  749.    {
  750.    register int c;
  751.  
  752. #if MACINTOSH
  753. #if MPW
  754.    {
  755.    static short cursorcount = CURSORINTERVAL;
  756.    if (--cursorcount == 0) {
  757.       RotateCursor(0);
  758.       cursorcount = CURSORINTERVAL;
  759.       }
  760.    }
  761. #endif                    /* MPW */
  762. #endif                    /* MACINTOSH */
  763.  
  764.    if (c = peekc) {
  765.       peekc = 0;
  766.       return c;
  767.       }
  768.    c = getc(srcfile);
  769.    switch (c) {
  770.       case EOF:
  771.      if (incol) {
  772.         c = '\n';
  773.         in_line++;
  774.         incol = 0;
  775.         peekc = EOF;
  776.         break;
  777.         }
  778.      else {
  779.         in_line = 0;
  780.         incol = 0;
  781.         break;
  782.         }
  783.       case '\n':
  784.      in_line++;
  785.      incol = 0;
  786.      break;
  787.       case '\t':
  788.      incol = (incol | 7) + 1;
  789.      break;
  790.       case '\b':
  791.      if (incol)
  792.         incol--;
  793.      break;
  794.       default:
  795.      incol++;
  796.       }
  797.    return c;
  798.    }
  799.