home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / cpm / cpm68k / utils.lbr / LEXI.CQ / LEXI.C
Encoding:
Text File  |  1986-05-22  |  11.3 KB  |  459 lines

  1. #
  2. /*
  3.  
  4.               Copyright (C) 1976
  5.                 by the
  6.               Board of Trustees
  7.                 of the
  8.             University of Illinois
  9.  
  10.              All rights reserved
  11.  
  12.  
  13. NAME:
  14.     lexi
  15.  
  16. FUNCTION:
  17.     This is the token scanner for indent
  18.  
  19. ALGORITHM:
  20.     1) Strip off intervening blanks and/or tabs.
  21.     2) If it is an alphanumeric token, move it to the token buffer "token".
  22.        Check if it is a special reserved word that indent will want to
  23.        know about.
  24.     3) Non-alphanumeric tokens are handled with a big switch statement.  A
  25.        flag is kept to remember if the last token was a "unary delimiter",
  26.        which forces a following operator to be unary as opposed to binary.
  27.  
  28. PARAMETERS:
  29.     None
  30.  
  31. RETURNS:
  32.     An integer code indicating the type of token scanned.
  33.  
  34. GLOBALS:
  35.     buf_ptr =
  36.     had_eof
  37.     last_u_d =    Set to true iff this token is a "unary delimiter"
  38.  
  39. CALLS:
  40.     fill_buffer
  41.     printf (lib)
  42.  
  43. CALLED BY:
  44.     main
  45.  
  46. NOTES:
  47.     Start of comment is passed back so that the comment can be scanned by
  48.     pr_comment.
  49.  
  50.     Strings and character literals are returned just like identifiers.
  51.  
  52. HISTORY:
  53.     initial coding     November 1976    D A Willcox of CAC
  54.     1/7/77        D A Willcox of CAC    Fix to provide proper handling
  55.                         of "int a -1;"
  56.  
  57. */
  58.  
  59. /* Here we have the token scanner for indent.  It scans off one token and
  60.    puts it in the global variable "token".  It returns a code, indicating the
  61.    type of token scanned. */
  62.  
  63. #include "indntglo.h";
  64. #include "indntcod.h";
  65.  
  66.  
  67.  
  68. #define alphanum 1
  69. #define opchar 3
  70.  
  71. struct templ {
  72.     char   *rwd;
  73.     int     rwcode;
  74. };
  75.  
  76. struct templ    specials[] =
  77. {
  78.     "switch", 1,
  79.     "case", 2,
  80.     "struct", 3,
  81.     "default", 2,
  82.     "int", 4,
  83.     "char", 4,
  84.     "float", 4,
  85.     "double", 4,
  86.     "long", 4,
  87.     "short", 4,
  88.     "typdef", 4,
  89.     "unsigned", 4,
  90.     "register", 4,
  91.     "static", 4,
  92.     "global", 4,
  93.     "extern", 4,
  94.     "if", 5,
  95.     "while", 5,
  96.     "for", 5,
  97.     "else", 6,
  98.     "do", 6,
  99.     "sizeof", 0,
  100.     0, 0
  101. };
  102.  
  103. char    chartype[128] =
  104. {           /* this is used to facilitate the decision of what type
  105.               (alphanumeric, operator) each character is */
  106.     0, 0, 0, 0, 0, 0, 0, 0,
  107.     0, 0, 0, 0, 0, 0, 0, 0,
  108.     0, 0, 0, 0, 0, 0, 0, 0,
  109.     0, 0, 0, 0, 0, 0, 0, 0,
  110.     0, 3, 0, 0, 1, 3, 3, 0,
  111.     0, 0, 3, 3, 0, 3, 3, 3,
  112.     1, 1, 1, 1, 1, 1, 1, 1,
  113.     1, 1, 0, 0, 3, 3, 3, 3,
  114.     0, 1, 1, 1, 1, 1, 1, 1,
  115.     1, 1, 1, 1, 1, 1, 1, 1,
  116.     1, 1, 1, 1, 1, 1, 1, 1,
  117.     1, 1, 1, 0, 0, 0, 3, 1,
  118.     0, 1, 1, 1, 1, 1, 1, 1,
  119.     1, 1, 1, 1, 1, 1, 1, 1,
  120.     1, 1, 1, 1, 1, 1, 1, 1,
  121.     1, 1, 1, 0, 3, 0, 3, 0
  122. };
  123.  
  124. int     last_nl = true;
  125.  /* this is true if the last thing scanned was a newline */
  126.  
  127.  
  128.  
  129. int     lexi () {
  130.     register char  *tok;
  131.  /* local pointer to next char in token */
  132.     register int    i;
  133.  /* local loop counter */
  134.     register char  *j;
  135.  /* used for searching thru list of reserved words */
  136.     int     unary_delim;
  137.  /* this is set to 1 if the current token forces a following operator to be
  138.     unary */
  139.     static int  last_code;
  140.  /* the last token type returned */
  141.     static int  l_struct;
  142.  /* set to 1 if the last token was 'struct' */
  143.     int     found_it;
  144.     int     code;  /* internal code to be returned */
  145.     char    qchar; /* the delimiter character for a string */
  146.  
  147.     tok = token;           /* point to start of place to save token */
  148.     unary_delim = false;
  149.     col_1 = last_nl;           /* tell world that this token started in column
  150.                       1 iff the last thing scanned was nl */
  151.     last_nl = false;
  152.  
  153.     while (*buf_ptr == ' ' || *buf_ptr == '\t') {
  154.     /* get rid of blanks */
  155.     col_1 = false;           /* leading blanks imply token is not in column 1
  156.                       */
  157.     if (++buf_ptr >= buf_end)
  158.         fill_buffer ();
  159.     }
  160.  
  161. /*----------------------------------------------------------*\ 
  162. |    Scan an alphanumeric token
  163. \*----------------------------------------------------------*/
  164.  
  165.     if (chartype[*buf_ptr & 0177] == alphanum) {
  166.     register char c;
  167.     /* we have a character or number */
  168.     while (chartype[c = *buf_ptr & 0177] == alphanum
  169.      || c=='-' && tok[-1]=='e' && ('0'<=token[0]||token[0]<='9')) {
  170.     /* copy it over */
  171.         *tok++ = *buf_ptr++;
  172.         if (buf_ptr >= buf_end)
  173.         fill_buffer ();
  174.     }
  175.  
  176.     *tok++ = '\0';
  177.  
  178.     if (l_struct) {           /* if last token was 'struct', then this token
  179.                       should be treated as a declaration */
  180.         l_struct = false;
  181.         last_code = ident;
  182.         last_u_d = true;
  183.         return (decl);
  184.     }
  185.  
  186.     last_u_d = false;      /* operator after indentifier is binary */
  187.  
  188.     for (i = 0; specials[i].rwd != 0; ++i) {
  189.     /* this loop will check if the token is a keyword.  if so, a following
  190.        operator is unary */
  191.         last_code = ident; /* remember that this is the code we will return
  192.                       */
  193.         j = specials[i].rwd;
  194.     /* point at ith reserved word */
  195.         tok = token;       /* point at scanned toekn */
  196.         found_it = true;   /* set to false if not found */
  197.         do {
  198.         if (*tok++ != *j) {
  199.             found_it = false;
  200.             break;
  201.         }
  202.         } while (*j++);
  203.  
  204.         if (found_it) {    /* we have a keyword */
  205.         last_u_d = true;
  206.         switch (specials[i].rwcode) {
  207.             case 1:    /* it is a switch */
  208.             return (swstmt);
  209.             case 2:    /* a case or default */
  210.             return (casestmt);
  211.  
  212.             case 3:    /* a "struct" */
  213.             l_struct = true;
  214.             /* Next time around, we will want to know that we have had
  215.                a 'struct' */
  216.             case 4:    /* one of the declaration keywords */
  217.             if(p_l_follow) break;    /* inside parens: cast */
  218.             last_code = decl;
  219.             return (decl);
  220.  
  221.             case 5:    /* if, while, for */
  222.             return (sp_paren);
  223.  
  224.             case 6:    /* do, else */
  225.             return (sp_nparen);
  226.  
  227.             default:   /* all others are treated like any other
  228.                       identifier */
  229.             return (ident);
  230.         }           /* end of switch */
  231.         }               /* end of if (found_it) */
  232.  
  233.     }
  234.  
  235.     if (last_code == decl) /* if this is a declared variable, then
  236.                       following sign is unary */
  237.         last_u_d = true;   /* will make "int a -1" work */
  238.     last_code = ident;
  239.     return (ident);           /* the ident is not in the list */
  240.     }                   /* end of procesing for alpanum character */
  241.  
  242.  
  243.  
  244. /*----------------------------------------------------------*\ 
  245. |   Scan a non-alphanumeric token
  246. \*----------------------------------------------------------*/
  247.  
  248.     *tok++ = *buf_ptr;           /* if it is only a one-character token, it is
  249.                       moved here */
  250.     *tok = '\0';
  251.     if (++buf_ptr >= buf_end)
  252.     fill_buffer ();
  253.  
  254.     switch (*token) {
  255.     case '\n': 
  256.         unary_delim = last_u_d;
  257.         last_nl = true;    /* remember that we just had a newline */
  258.         code = (had_eof ? 0 : newline);
  259.     /* if data has been exausted, the newline is a dummy, and we should
  260.        return code to stop */
  261.         break;
  262.  
  263.     case '\'':            /* start of quoted character */
  264.         qchar = '\'';      /* remember final delimiter */
  265.         goto copy_lit;     /* and go to common literal code */
  266.  
  267.     case '"':            /* start of string */
  268.         qchar = '"';
  269.  
  270.     copy_lit: 
  271.         do {           /* copy the string */
  272.         while (1) {    /* move one character or [/<char>]<char> */
  273.             if (*buf_ptr == '\n') {
  274.             /* check for unterminated literal */
  275.             printf ("%d: Unterminated literal\n", line_no);
  276.             goto stop_lit;
  277.             /* Don't copy any more */
  278.             }
  279.  
  280.             *tok = *buf_ptr++;
  281.             if (buf_ptr >= buf_end)
  282.             fill_buffer ();
  283.             if (had_eof || ((tok - token) > (bufsize - 2))) {
  284.             printf ("Unterminated literal\n");
  285.             ++tok;
  286.             goto stop_lit;
  287.             /* get outof literal copying loop */
  288.             }
  289.  
  290.             if (*tok == '\\') {
  291.             /* if escape, copy extra char */
  292.             if (*buf_ptr == '\n')
  293.                    /* check for escaped newline */
  294.                 ++line_no;
  295.             *(++tok) = *buf_ptr++;
  296.             ++tok; /* we must increment this again because we
  297.                       copied two chars */
  298.             if (buf_ptr >= buf_end)
  299.                 fill_buffer ();
  300.             }
  301.             else
  302.             break; /* we copied one character */
  303.         }           /* end of while (1) */
  304.         } while (*tok++ != qchar);
  305.  
  306.     stop_lit: 
  307.         code = ident;
  308.         break;
  309.  
  310.     case ('('): 
  311.     case ('['): 
  312.         unary_delim = true;
  313.         code = lparen;
  314.         break;
  315.  
  316.     case (')'): 
  317.     case (']'): 
  318.         code = rparen;
  319.         break;
  320.  
  321.     case '#': 
  322.         unary_delim = last_u_d;
  323.         code = preesc;
  324.         break;
  325.  
  326.     case '?': 
  327.         unary_delim = true;
  328.         code = question;
  329.         break;
  330.  
  331.     case (':'): 
  332.         code = colon;
  333.         unary_delim = true;
  334.         break;
  335.  
  336.     case (';'): 
  337.         unary_delim = true;
  338.         code = semicolon;
  339.         break;
  340.  
  341.     case ('{'): 
  342.         unary_delim = true;
  343.         code = lbrace;
  344.         break;
  345.  
  346.     case ('}'): 
  347.         unary_delim = true;
  348.         code = rbrace;
  349.         break;
  350.  
  351.     case 014:            /* a form feed */
  352.         unary_delim = last_u_d;
  353.         last_nl = true;    /* remember this so we can set 'col_1' right */
  354.         code = form_feed;
  355.         break;
  356.  
  357.     case (','): 
  358.         unary_delim = true;
  359.         code = comma;
  360.         break;
  361.  
  362.     case '.': 
  363.         unary_delim = false;
  364.         code = period;
  365.         break;
  366.  
  367.     case '-': 
  368.     case '+':            /* check for -, +, --, ++ */
  369.         code = (last_u_d ? unary_op : binary_op);
  370.         unary_delim = true;
  371.  
  372.         if (*buf_ptr == token[0]) {
  373.         /* check for doubled character */
  374.         *tok++ = *buf_ptr++;
  375.         /* buffer overflow will be checked at end of loop */
  376.         if (last_code == ident || last_code == rparen) {
  377.             code = (last_u_d ? unary_op : postop);
  378.         /* check for following ++ or -- */
  379.             unary_delim = false;
  380.         }
  381.         }
  382.         else
  383.         if (*buf_ptr == '>' || *buf_ptr == '=')
  384.                    /* check for operator -> or += */
  385.             *tok++ = *buf_ptr++;
  386.     /* buffer overflow will be checked at end of switch */
  387.  
  388.         break;
  389.  
  390.     case '=': 
  391.         if (chartype[*buf_ptr] == opchar) {
  392.         /* we have two char assignment */
  393.         *tok++ = *buf_ptr;
  394.         /* move second character */
  395.         if (++buf_ptr >= buf_end)
  396.             fill_buffer ();
  397.         }
  398.  
  399.         code = binary_op;
  400.         unary_delim = true;
  401.         if (token[1] != '<' && token[1] != '>')
  402.                    /* check for possible 3 char operator */
  403.         break;
  404.     /* can drop thru!!! */
  405.  
  406.     case '>': 
  407.     case '<': 
  408.     case '!':            /* ops like <, <<, <=, !=, etc */
  409.         if (*buf_ptr == '>' || *buf_ptr == '<' || *buf_ptr == '=') {
  410.         *tok++ = *buf_ptr;
  411.         if (++buf_ptr >= buf_end)
  412.             fill_buffer ();
  413.         }
  414.  
  415.         if (*buf_ptr == '=')
  416.          *tok++ = *buf_ptr++;
  417.         code = (last_u_d ? unary_op : binary_op);
  418.         unary_delim = true;
  419.         break;
  420.  
  421.     default: 
  422.         if (token[0] == '/' && *buf_ptr == '*') {
  423.         /* it is start of comment */
  424.         *tok++ = '*';
  425.  
  426.         if (++buf_ptr >= buf_end)
  427.             fill_buffer ();
  428.  
  429.         code = comment;
  430.         unary_delim = last_u_d;
  431.         break;
  432.         }
  433.  
  434.         while (*(tok - 1) == *buf_ptr || *buf_ptr=='=') {
  435.         /* handle ||, &&, etc, and also things as in int *****i */
  436.         *tok++ = *buf_ptr;
  437.         if (++buf_ptr >= buf_end)
  438.             fill_buffer ();
  439.         }
  440.  
  441.  
  442.         code = (last_u_d ? unary_op : binary_op);
  443.         unary_delim = true;
  444.  
  445.  
  446.     }                   /* end of switch */
  447.  
  448.     if (code != newline) {
  449.     l_struct = false;
  450.     last_code = code;
  451.     }
  452.  
  453.     if (buf_ptr >= buf_end)    /* check for input buffer empty */
  454.     fill_buffer ();
  455.     last_u_d = unary_delim;
  456.     *tok = '\0';           /* null terminate the token */
  457.     return (code);
  458. };
  459.