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