home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / INDENTSR.ZIP / LEXI.C < prev    next >
C/C++ Source or Header  |  1992-08-27  |  17KB  |  640 lines

  1. /*
  2.  * Copyright (c) 1985 Sun Microsystems, Inc.
  3.  * Copyright (c) 1980 The Regents of the University of California.
  4.  * Copyright (c) 1976 Board of Trustees of the University of Illinois.
  5.  * All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms are permitted
  8.  * provided that the above copyright notice and this paragraph are
  9.  * duplicated in all such forms and that any documentation,
  10.  * advertising materials, and other materials related to such
  11.  * distribution and use acknowledge that the software was developed
  12.  * by the University of California, Berkeley, the University of Illinois,
  13.  * Urbana, and Sun Microsystems, Inc.  The name of either University
  14.  * or Sun Microsystems may not be used to endorse or promote products
  15.  * derived from this software without specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
  17.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  18.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #ifndef lint
  22. static char sccsid[] = "@(#)lexi.c  5.11 (Berkeley) 88/09/15";
  23.  
  24. #endif                    /* not lint */
  25.  
  26. /*
  27.  * Here we have the token scanner for indent.  It scans off one token and puts
  28.  * it in the global variable "token".  It returns a code, indicating the type
  29.  * of token scanned.
  30.  */
  31.  
  32. #include "globals.h"
  33. #include "codes.h"
  34. #include <ctype.h>
  35.  
  36. #ifdef MSDOS                /* or OS/2 */
  37. #include <string.h>
  38. #endif
  39.  
  40. typedef enum char_type {
  41.     alphanum = 1,
  42.     opchar = 3,
  43.     colonchar = 4
  44. } char_type;
  45.  
  46. struct templ {
  47.     char *rwd;
  48.     int rwcode;
  49.     cplus_flag cplus;
  50. };
  51.  
  52. struct templ specials[100] =
  53. {
  54.     "switch", 1, c_and_cplus,
  55.     "case", 2, c_and_cplus,
  56.     "break", 0, c_and_cplus,
  57.     "struct", 3, c_and_cplus,
  58.     "union", 3, c_and_cplus,
  59.     "enum", 3, c_and_cplus,
  60.     "default", 2, c_and_cplus,
  61.     "int", 4, c_and_cplus,
  62.     "char", 4, c_and_cplus,
  63.     "float", 4, c_and_cplus,
  64.     "double", 4, c_and_cplus,
  65.     "long", 4, c_and_cplus,
  66.     "short", 4, c_and_cplus,
  67.     "typedef", 8, c_and_cplus,
  68.     "unsigned", 4, c_and_cplus,
  69.     "register", 4, c_and_cplus,
  70.     "static", 4, c_and_cplus,
  71.     "global", 4, c_and_cplus,
  72.     "extern", 4, c_and_cplus,
  73.     "void", 4, c_and_cplus,
  74.     "goto", 0, c_and_cplus,
  75.     "return", 0, c_and_cplus,
  76.     "if", 5, c_and_cplus,
  77.     "while", 5, c_and_cplus,
  78.     "for", 5, c_and_cplus,
  79.     "else", 6, c_and_cplus,
  80.     "do", 6, c_and_cplus,
  81.     "sizeof", 7, c_and_cplus,
  82.     "class", 3, cplus_only,
  83.     "public", 2, cplus_only,
  84.     "private", 2, cplus_only,
  85.     "protected", 2, cplus_only,
  86.     "volatile", 4, c_and_cplus,
  87.  
  88.     0, 0
  89. };
  90.  
  91. char chartype[128] =
  92. {                    /* this is used to facilitate the
  93.                      * decision of what type
  94.                      * (alphanumeric, operator) each
  95.                      * character is */
  96.     0, 0, 0, 0, 0, 0, 0, 0,
  97.     0, 0, 0, 0, 0, 0, 0, 0,
  98.     0, 0, 0, 0, 0, 0, 0, 0,
  99.     0, 0, 0, 0, 0, 0, 0, 0,
  100.     0, 3, 0, 0, 1, 3, 3, 0,
  101.     0, 0, 3, 3, 0, 3, 0, 3,
  102.     1, 1, 1, 1, 1, 1, 1, 1,
  103.     1, 1, 4, 0, 3, 3, 3, 3,
  104.     0, 1, 1, 1, 1, 1, 1, 1,
  105.     1, 1, 1, 1, 1, 1, 1, 1,
  106.     1, 1, 1, 1, 1, 1, 1, 1,
  107.     1, 1, 1, 0, 0, 0, 3, 1,
  108.     0, 1, 1, 1, 1, 1, 1, 1,
  109.     1, 1, 1, 1, 1, 1, 1, 1,
  110.     1, 1, 1, 1, 1, 1, 1, 1,
  111.     1, 1, 1, 0, 3, 0, 3, 0
  112. };
  113.  
  114.  
  115.  
  116. #ifdef ANSIC
  117. int 
  118. lexi(void)
  119. #else
  120. int 
  121. lexi()
  122. #endif
  123. {
  124.     register char *tok;            /* local pointer to next char in
  125.                      * token */
  126.     int unary_delim;            /* this is set to 1 if the current
  127.                      * token
  128.                      * 
  129.                      * forces a following operator to be
  130.                      * unary */
  131.     static int last_code;        /* the last token type returned */
  132.     static int l_struct;        /* set to 1 if the last token was
  133.                      * 'struct' */
  134.     static int l_struct_start;        /* set at struct, cleared at { or ; */
  135.     static int l_class;            /* in c++, class name coming next. */
  136.     int code;                /* internal code to be returned */
  137.     char qchar;                /* the delimiter character for a
  138.                      * string */
  139.  
  140.     tok = token;            /* point to start of place to save
  141.                      * token */
  142.     unary_delim = false;
  143.     ps.col_1 = ps.last_nl;        /* tell world that this token started
  144.                      * in column 1 iff the last thing
  145.                      * scanned was nl */
  146.     ps.last_nl = false;
  147.  
  148.     while (*buf_ptr == ' ' || *buf_ptr == '\t') {    /* get rid of blanks */
  149.     ps.col_1 = false;        /* leading blanks imply token is not
  150.                      * in column 1 */
  151.     if (++buf_ptr >= buf_end)
  152.         fill_buffer();
  153.     }
  154.  
  155.     /* Scan an alphanumeric token */
  156.     /* In c++, :: starting token is aok, as is ~ sometimes */
  157.     /* well, int x = ~y; will work oddly here */
  158.     if (((char_type) chartype[*buf_ptr] == alphanum || buf_ptr[0] == '.' && isdigit(buf_ptr[1])) ||
  159.     (cplus && buf_ptr[0] == ':' && buf_ptr[1] == ':') ||
  160.     (cplus && ps.in_decl && *buf_ptr == '~'
  161.         && (char_type) chartype[buf_ptr[1]] == alphanum)    /* destructors in
  162.                                  * classdefs */
  163.     ) {
  164.     /*
  165.      * we have a character or number
  166.      */
  167.     register char *j;        /* used for searching thru list of
  168.                      * 
  169.                      * reserved words */
  170.     register struct templ *p;
  171.  
  172.     if (isdigit(*buf_ptr) || buf_ptr[0] == '.' && isdigit(buf_ptr[1])) {
  173.         int seendot = 0, seenexp = 0;
  174.  
  175.         if (*buf_ptr == '0' &&
  176.         (buf_ptr[1] == 'x' || buf_ptr[1] == 'X')) {
  177.         *tok++ = *buf_ptr++;
  178.         *tok++ = *buf_ptr++;
  179.         while (isxdigit(*buf_ptr))
  180.             *tok++ = *buf_ptr++;
  181.         } else
  182.         while (1) {
  183.             if (*buf_ptr == '.')
  184.             if (seendot)
  185.                 break;
  186.             else
  187.                 seendot++;
  188.             *tok++ = *buf_ptr++;
  189.             if (!isdigit(*buf_ptr) && *buf_ptr != '.')
  190.             if ((*buf_ptr != 'E' && *buf_ptr != 'e') || seenexp)
  191.                 break;
  192.             else {
  193.                 seenexp++;
  194.                 seendot++;
  195.                 *tok++ = *buf_ptr++;
  196.                 if (*buf_ptr == '+' || *buf_ptr == '-')
  197.                 *tok++ = *buf_ptr++;
  198.             }
  199.         }
  200.         if (*buf_ptr == 'L' || *buf_ptr == 'l')
  201.         *tok++ = *buf_ptr++;
  202.     } else {
  203.         int first;
  204.  
  205.         first = 1;
  206.         while ((char_type) chartype[*buf_ptr] == alphanum ||
  207.         (buf_ptr[0] == ':' && buf_ptr[1] == ':' && cplus) ||
  208.         (cplus && first && buf_ptr[0] == '~')) {    /* copy it over */
  209.         int colonp;
  210.  
  211.         first = 0;
  212.         colonp = *buf_ptr == ':';
  213.         *tok++ = *buf_ptr++;
  214.         if (colonp) {
  215.             *tok++ = *buf_ptr++;
  216.             /* foo::~foo */
  217.             if (*buf_ptr == '~')
  218.             *tok++ = *buf_ptr++;
  219.             colonp = 0;
  220.         }
  221.         if (buf_ptr >= buf_end)
  222.             fill_buffer();
  223.         }
  224.     }
  225.     *tok++ = '\0';
  226.     while (*buf_ptr == ' ' || *buf_ptr == '\t') {    /* get rid of blanks */
  227.         if (++buf_ptr >= buf_end)
  228.         fill_buffer();
  229.     }
  230.     ps.its_a_keyword = false;
  231.     ps.sizeof_keyword = false;
  232.     if (l_struct) {            /* if last token was 'struct', then
  233.                      * this token should be treated as a
  234.                      * declaration */
  235.         if (l_class)
  236.         addkey(tok, 4);
  237.         l_class = false;
  238.         l_struct = false;
  239.         last_code = ident;
  240.         ps.last_u_d = true;
  241.         return (decl);
  242.     }
  243.     ps.last_u_d = false;        /* Operator after indentifier is
  244.                      * binary */
  245.     last_code = ident;        /* Remember that this is the code we
  246.                      * will return */
  247.  
  248.     /*
  249.      * This loop will check if the token is a keyword.
  250.      */
  251.     for (p = specials; (j = p->rwd) != 0; p++) {
  252.         tok = token;        /* point at scanned token */
  253.         if (*j++ != *tok++ || *j++ != *tok++)
  254.         continue;        /* This test depends on the fact that
  255.                      * identifiers are always at least 1
  256.                      * character long (ie. the first two
  257.                      * bytes of the identifier are always
  258.                      * meaningful) */
  259.         if (tok[-1] == 0)
  260.         break;            /* If its a one-character identifier */
  261.         while (*tok++ == *j)
  262.         if (*j++ == 0 &&
  263.             (p->cplus == c_and_cplus ||
  264.             (cplus && p->cplus == cplus_only) ||
  265.             (!cplus && p->cplus == c_only)))
  266.             goto found_keyword;    /* I wish that C had a multi-level
  267.                      * break... */
  268.     }
  269.     if (p->rwd) {            /* we have a keyword */
  270.     found_keyword:
  271.         ps.its_a_keyword = true;
  272.         ps.last_u_d = true;
  273.         switch (p->rwcode) {
  274.         case 1:            /* it is a switch */
  275.         return (swstmt);
  276.         case 2:            /* a case or default */
  277.         return (casestmt);
  278.  
  279.         case 3:            /* a "struct" */
  280.         if (ps.p_l_follow)
  281.             break;        /* inside parens: cast */
  282.         l_struct = true;
  283.         if (cplus)
  284.             l_struct_start = true;
  285.         /* automatically note keywords */
  286.         if (cplus && strcmp(tok, "class") == 0 ||
  287.             strcmp(tok, "struct") == 0 ||
  288.             strcmp(tok, "union") == 0 ||
  289.             strcmp(tok, "enum") == 0)
  290.             l_class = true;
  291.         /*
  292.          * Next time around, we will want to know that we have had a
  293.          * 'struct'
  294.          */
  295.         case 4:            /* one of the declaration keywords */
  296.         if (ps.p_l_follow) {
  297.             ps.cast_mask |= 1 << ps.p_l_follow;
  298.             break;        /* inside parens: cast */
  299.         }
  300.         last_code = decl;
  301.         return (decl);
  302.  
  303.         case 5:            /* if, while, for */
  304.         return (sp_paren);
  305.  
  306.         case 6:            /* do, else */
  307.         return (sp_nparen);
  308.  
  309.         case 7:
  310.         ps.sizeof_keyword = true;
  311.         return (ident);
  312.  
  313.         case 8:            /* typedef is a decl */
  314.         last_code = decl;
  315.         return (decl);
  316.  
  317.         default:            /* all others are treated like any
  318.                      * other identifier */
  319.         return (ident);
  320.         }                /* end of switch */
  321.     }                /* end of if (found_it) */
  322.     if (*buf_ptr == '(' && ps.tos <= 1 && ps.ind_level == 0) {
  323.         register char *tp = buf_ptr;
  324.  
  325.         while (tp < buf_end)
  326.         if (*tp++ == ')' && *tp == ';')
  327.             goto not_proc;
  328.         strncpy(ps.procname, token, sizeof ps.procname - 1);
  329.         ps.in_parameter_declaration = 1;
  330.     not_proc:;
  331.     }
  332.     /*
  333.      * The following hack attempts to guess whether or not the current
  334.      * token is in fact a declaration keyword -- one that has been
  335.      * typedefd
  336.      */
  337.     if (((*buf_ptr == '*' && buf_ptr[1] != '=') || isalpha(*buf_ptr) || *buf_ptr == '_')
  338.         && !ps.p_l_follow
  339.         && !ps.block_init
  340.         && (ps.last_token == rparen || ps.last_token == semicolon ||
  341.         ps.last_token == decl ||
  342.         ps.last_token == lbrace || ps.last_token == rbrace)) {
  343.         ps.its_a_keyword = true;
  344.         ps.last_u_d = true;
  345.         last_code = decl;
  346.         return decl;
  347.     }
  348.     if (last_code == decl)        /* if this is a declared variable,
  349.                      * then following sign is unary */
  350.         ps.last_u_d = true;        /* will make "int a -1" work */
  351.     last_code = ident;
  352.     return (ident);            /* the ident is not in the list */
  353.     }                    /* end of procesing for alpanum
  354.                      * character */
  355.     /* l l l l Scan a non-alphanumeric token */
  356.  
  357.     l_class = false;            /* struct { ain't defining a class. */
  358.     *tok++ = *buf_ptr;            /* if it is only a one-character
  359.                      * token, it is moved here */
  360.     *tok = '\0';
  361.     if (++buf_ptr >= buf_end)
  362.     fill_buffer();
  363.  
  364.     switch (*token) {
  365.     case '\n':
  366.     unary_delim = ps.last_u_d;
  367.     ps.last_nl = true;        /* remember that we just had a
  368.                      * newline */
  369.     code = (had_eof ? 0 : newline);
  370.  
  371.     /*
  372.      * if data has been exausted, the newline is a dummy, and we should
  373.      * return code to stop
  374.      */
  375.     break;
  376.  
  377.     case '\'':                /* start of quoted character */
  378.     case '"':                /* start of string */
  379.     qchar = *token;
  380.     if (troff) {
  381.         tok[-1] = '`';
  382.         if (qchar == '"')
  383.         *tok++ = '`';
  384.         tok = chfont(&bodyf, &stringf, tok);
  385.     }
  386.     do {                /* copy the string */
  387.         while (1) {            /* move one character or
  388.                      * [/<char>]<char> */
  389.         if (*buf_ptr == '\n') {
  390.             printf("%d: Unterminated literal\n", line_no);
  391.             goto stop_lit;
  392.         }
  393.         *tok = *buf_ptr++;
  394.         if (buf_ptr >= buf_end)
  395.             fill_buffer();
  396.         if (had_eof || ((tok - token) > (bufsize - 2))) {
  397.             printf("Unterminated literal\n");
  398.             ++tok;
  399.             goto stop_lit;
  400.             /* get outof literal copying loop */
  401.         }
  402.         if (*tok == BACKSLASH) {/* if escape, copy extra char */
  403.             if (*buf_ptr == '\n')    /* check for escaped newline */
  404.             ++line_no;
  405.             if (troff) {
  406.             *++tok = BACKSLASH;
  407.             if (*buf_ptr == BACKSLASH)
  408.                 *++tok = BACKSLASH;
  409.             }
  410.             *++tok = *buf_ptr++;
  411.             ++tok;        /* we must increment this again
  412.                      * because we copied two chars */
  413.             if (buf_ptr >= buf_end)
  414.             fill_buffer();
  415.         } else
  416.             break;        /* we copied one character */
  417.         }                /* end of while (1) */
  418.     } while (*tok++ != qchar);
  419.     if (troff) {
  420.         tok = chfont(&stringf, &bodyf, tok - 1);
  421.         if (qchar == '"')
  422.         *tok++ = '\'';
  423.     }
  424. stop_lit:
  425.     code = ident;
  426.     break;
  427.  
  428.     case ('('):
  429.     case ('['):
  430.     unary_delim = true;
  431.     code = lparen;
  432.     break;
  433.  
  434.     case (')'):
  435.     case (']'):
  436.     code = rparen;
  437.     break;
  438.  
  439.     case '#':
  440.     unary_delim = ps.last_u_d;
  441.     code = preesc;
  442.     break;
  443.  
  444.     case '?':
  445.     unary_delim = true;
  446.     code = question;
  447.     break;
  448.  
  449.     case (':'):
  450.     if (l_struct_start)
  451.         code = ident;
  452.     else
  453.         code = colon;
  454.     unary_delim = true;
  455.     break;
  456.  
  457.     case (';'):
  458.     l_struct_start = false;
  459.     unary_delim = true;
  460.     code = semicolon;
  461.     break;
  462.  
  463.     case ('{'):
  464.     l_struct_start = false;
  465.     unary_delim = true;
  466.  
  467.     /*
  468.      * if (ps.in_or_st) ps.block_init = 1;
  469.      */
  470.     /* ?    code = ps.block_init ? lparen : lbrace; */
  471.     code = lbrace;
  472.     break;
  473.  
  474.     case ('}'):
  475.     unary_delim = true;
  476.     /* ?    code = ps.block_init ? rparen : rbrace; */
  477.     code = rbrace;
  478.     break;
  479.  
  480.     case 014:                /* a form feed */
  481.     unary_delim = ps.last_u_d;
  482.     ps.last_nl = true;        /* remember this so we can set
  483.                      * 'ps.col_1' right */
  484.     code = form_feed;
  485.     break;
  486.  
  487.     case (','):
  488.     unary_delim = true;
  489.     code = comma;
  490.     break;
  491.  
  492.     case '.':
  493.     unary_delim = false;
  494.     code = period;
  495.     break;
  496.  
  497.     case '-':
  498.     case '+':                /* check for -, +, --, ++ */
  499.     code = (ps.last_u_d ? unary_op : binary_op);
  500.     unary_delim = true;
  501.  
  502.     if (*buf_ptr == token[0]) {
  503.         /* check for doubled character */
  504.         *tok++ = *buf_ptr++;
  505.         /* buffer overflow will be checked at end of loop */
  506.         if (last_code == ident || last_code == rparen) {
  507.         code = (ps.last_u_d ? unary_op : postop);
  508.         /* check for following ++ or -- */
  509.         unary_delim = false;
  510.         }
  511.     } else if (*buf_ptr == '=')
  512.         /* check for operator += */
  513.         *tok++ = *buf_ptr++;
  514.     else if (*buf_ptr == '>') {
  515.         /* check for operator -> */
  516.         *tok++ = *buf_ptr++;
  517.         if (!pointer_as_binop) {
  518.         unary_delim = false;
  519.         code = unary_op;
  520.         ps.want_blank = false;
  521.         }
  522.     }
  523.     break;                /* buffer overflow will be checked at
  524.                      * end of switch */
  525.  
  526.     case '=':
  527.     if (ps.in_or_st)
  528.         ps.block_init = 1;
  529. #ifdef undef
  530.     if (chartype[*buf_ptr] == opchar) {    /* we have two char
  531.                          * assignment */
  532.         tok[-1] = *buf_ptr++;
  533.         if ((tok[-1] == '<' || tok[-1] == '>') && tok[-1] == *buf_ptr)
  534.         *tok++ = *buf_ptr++;
  535.         *tok++ = '=';        /* Flip =+ to += */
  536.         *tok = 0;
  537.     }
  538. #else
  539.     if (*buf_ptr == '=') {        /* == */
  540.         *tok++ = '=';        /* Flip =+ to += */
  541.         buf_ptr++;
  542.         *tok = 0;
  543.     }
  544. #endif
  545.     code = binary_op;
  546.     unary_delim = true;
  547.     break;
  548.     /* can drop thru!!! */
  549.  
  550.     case '>':
  551.     case '<':
  552.     case '!':                /* ops like <, <<, <=, !=, etc */
  553.     if (*buf_ptr == '>' || *buf_ptr == '<' || *buf_ptr == '=') {
  554.         *tok++ = *buf_ptr;
  555.         if (++buf_ptr >= buf_end)
  556.         fill_buffer();
  557.     }
  558.     if (*buf_ptr == '=')
  559.         *tok++ = *buf_ptr++;
  560.     code = (ps.last_u_d ? unary_op : binary_op);
  561.     unary_delim = true;
  562.     break;
  563.  
  564.     default:
  565.     if (token[0] == '/' && *buf_ptr == '*') {
  566.         /* it is start of a C comment */
  567.         *tok++ = '*';
  568.  
  569.         if (++buf_ptr >= buf_end)
  570.         fill_buffer();
  571.  
  572.         code = comment;
  573.         unary_delim = ps.last_u_d;
  574.         break;
  575.     }
  576.     if (token[0] == '/' && *buf_ptr == '/') {
  577.         /* it is start of a C++ comment */
  578.         *tok++ = '/';
  579.  
  580.         if (++buf_ptr >= buf_end)
  581.         fill_buffer();
  582.  
  583.         code = cc_commnt;
  584.         ps.cc_comment++;
  585.         unary_delim = ps.last_u_d;
  586.         break;
  587.     }
  588.     while (*(tok - 1) == *buf_ptr || *buf_ptr == '=') {
  589.         /*
  590.          * handle ||, &&, etc, and also things as in int *****i
  591.          */
  592.         *tok++ = *buf_ptr;
  593.         if (++buf_ptr >= buf_end)
  594.         fill_buffer();
  595.     }
  596.     code = (ps.last_u_d ? unary_op : binary_op);
  597.     unary_delim = true;
  598.  
  599.  
  600.     }                    /* end of switch */
  601.     if (code != newline) {
  602.     l_struct = false;
  603.     last_code = code;
  604.     }
  605.     if (buf_ptr >= buf_end)        /* check for input buffer empty */
  606.     fill_buffer();
  607.     ps.last_u_d = unary_delim;
  608.     *tok = '\0';            /* null terminate the token */
  609.     return (code);
  610. };
  611.  
  612. /*
  613.  * Add the given keyword to the keyword table, using val as the keyword type
  614.  */
  615. #ifdef ANSIC
  616. void 
  617. addkey(char *key, int val)
  618. #else
  619. addkey(key, val)
  620.     char *key;
  621.  
  622. #endif
  623. {
  624.     register struct templ *p = specials;
  625.  
  626.     while (p->rwd)
  627.     if (p->rwd[0] == key[0] && strcmp(p->rwd, key) == 0)
  628.         return;
  629.     else
  630.         p++;
  631.     if (p >= specials + sizeof specials / sizeof specials[0])
  632.     return;                /* For now, table overflows are
  633.                      * silently ignored */
  634.     p->rwd = key;
  635.     p->rwcode = val;
  636.     p[1].rwd = 0;
  637.     p[1].rwcode = 0;
  638.     return;
  639. }
  640.