home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Archive / OS2_Archive_CD-ROM_Walnut_Creek_May_1992.iso / novell / progrmng / indent.zoo / lexi.c < prev    next >
C/C++ Source or Header  |  1989-10-30  |  15KB  |  593 lines

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