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