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