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