1218885Sdim/*
2218885Sdim * Copyright (c) 1985 Sun Microsystems, Inc.
3218885Sdim * Copyright (c) 1980, 1993
4218885Sdim *	The Regents of the University of California.  All rights reserved.
5218885Sdim * All rights reserved.
6218885Sdim *
7218885Sdim * Redistribution and use in source and binary forms, with or without
8218885Sdim * modification, are permitted provided that the following conditions
9218885Sdim * are met:
10218885Sdim * 1. Redistributions of source code must retain the above copyright
11218885Sdim *    notice, this list of conditions and the following disclaimer.
12218885Sdim * 2. Redistributions in binary form must reproduce the above copyright
13218885Sdim *    notice, this list of conditions and the following disclaimer in the
14218885Sdim *    documentation and/or other materials provided with the distribution.
15218885Sdim * 3. All advertising materials mentioning features or use of this software
16218885Sdim *    must display the following acknowledgement:
17218885Sdim *	This product includes software developed by the University of
18218885Sdim *	California, Berkeley and its contributors.
19218885Sdim * 4. Neither the name of the University nor the names of its contributors
20218885Sdim *    may be used to endorse or promote products derived from this software
21218885Sdim *    without specific prior written permission.
22218885Sdim *
23218885Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24218885Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25218885Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26218885Sdim * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27218885Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28218885Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29218885Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30218885Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31218885Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32218885Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33218885Sdim * SUCH DAMAGE.
34218885Sdim */
35218885Sdim
36218885Sdim#if 0
37218885Sdim#ifndef lint
38218885Sdimstatic char sccsid[] = "@(#)lexi.c	8.1 (Berkeley) 6/6/93";
39218885Sdim#endif /* not lint */
40218885Sdim#endif
41218885Sdim#include <sys/cdefs.h>
42218885Sdim__FBSDID("$FreeBSD$");
43218885Sdim
44218885Sdim/*
45218885Sdim * Here we have the token scanner for indent.  It scans off one token and puts
46218885Sdim * it in the global variable "token".  It returns a code, indicating the type
47218885Sdim * of token scanned.
48218885Sdim */
49218885Sdim
50218885Sdim#include <err.h>
51218885Sdim#include <stdio.h>
52218885Sdim#include <ctype.h>
53218885Sdim#include <stdlib.h>
54218885Sdim#include <string.h>
55218885Sdim#include "indent_globs.h"
56218885Sdim#include "indent_codes.h"
57218885Sdim#include "indent.h"
58218885Sdim
59218885Sdim#define alphanum 1
60218885Sdim#define opchar 3
61218885Sdim
62218885Sdimstruct templ {
63218885Sdim    const char *rwd;
64218885Sdim    int         rwcode;
65218885Sdim};
66218885Sdim
67218885Sdimstruct templ specials[1000] =
68218885Sdim{
69218885Sdim    {"switch", 1},
70218885Sdim    {"case", 2},
71218885Sdim    {"break", 0},
72218885Sdim    {"struct", 3},
73218885Sdim    {"union", 3},
74218885Sdim    {"enum", 3},
75218885Sdim    {"default", 2},
76218885Sdim    {"int", 4},
77218885Sdim    {"char", 4},
78218885Sdim    {"float", 4},
79218885Sdim    {"double", 4},
80218885Sdim    {"long", 4},
81218885Sdim    {"short", 4},
82218885Sdim    {"typedef", 4},
83218885Sdim    {"unsigned", 4},
84218885Sdim    {"register", 4},
85218885Sdim    {"static", 4},
86218885Sdim    {"global", 4},
87218885Sdim    {"extern", 4},
88218885Sdim    {"void", 4},
89218885Sdim    {"const", 4},
90218885Sdim    {"volatile", 4},
91218885Sdim    {"goto", 0},
92218885Sdim    {"return", 0},
93218885Sdim    {"if", 5},
94218885Sdim    {"while", 5},
95218885Sdim    {"for", 5},
96218885Sdim    {"else", 6},
97218885Sdim    {"do", 6},
98218885Sdim    {"sizeof", 7},
99218885Sdim    {0, 0}
100218885Sdim};
101218885Sdim
102249423Sdimchar        chartype[128] =
103218885Sdim{				/* this is used to facilitate the decision of
104288943Sdim				 * what type (alphanumeric, operator) each
105218885Sdim				 * character is */
106218885Sdim    0, 0, 0, 0, 0, 0, 0, 0,
107314564Sdim    0, 0, 0, 0, 0, 0, 0, 0,
108314564Sdim    0, 0, 0, 0, 0, 0, 0, 0,
109321369Sdim    0, 0, 0, 0, 0, 0, 0, 0,
110218885Sdim    0, 3, 0, 0, 1, 3, 3, 0,
111314564Sdim    0, 0, 3, 3, 0, 3, 0, 3,
112314564Sdim    1, 1, 1, 1, 1, 1, 1, 1,
113218885Sdim    1, 1, 0, 0, 3, 3, 3, 3,
114218885Sdim    0, 1, 1, 1, 1, 1, 1, 1,
115218885Sdim    1, 1, 1, 1, 1, 1, 1, 1,
116218885Sdim    1, 1, 1, 1, 1, 1, 1, 1,
117218885Sdim    1, 1, 1, 0, 0, 0, 3, 1,
118218885Sdim    0, 1, 1, 1, 1, 1, 1, 1,
119218885Sdim    1, 1, 1, 1, 1, 1, 1, 1,
120218885Sdim    1, 1, 1, 1, 1, 1, 1, 1,
121218885Sdim    1, 1, 1, 0, 3, 0, 3, 0
122218885Sdim};
123218885Sdim
124218885Sdimint
125218885Sdimlexi(void)
126218885Sdim{
127218885Sdim    int         unary_delim;	/* this is set to 1 if the current token
128218885Sdim				 * forces a following operator to be unary */
129218885Sdim    static int  last_code;	/* the last token type returned */
130218885Sdim    static int  l_struct;	/* set to 1 if the last token was 'struct' */
131218885Sdim    int         code;		/* internal code to be returned */
132218885Sdim    char        qchar;		/* the delimiter character for a string */
133218885Sdim
134218885Sdim    e_token = s_token;		/* point to start of place to save token */
135218885Sdim    unary_delim = false;
136218885Sdim    ps.col_1 = ps.last_nl;	/* tell world that this token started in
137218885Sdim				 * column 1 iff the last thing scanned was nl */
138218885Sdim    ps.last_nl = false;
139218885Sdim
140218885Sdim    while (*buf_ptr == ' ' || *buf_ptr == '\t') {	/* get rid of blanks */
141218885Sdim	ps.col_1 = false;	/* leading blanks imply token is not in column
142218885Sdim				 * 1 */
143218885Sdim	if (++buf_ptr >= buf_end)
144218885Sdim	    fill_buffer();
145218885Sdim    }
146218885Sdim
147218885Sdim    /* Scan an alphanumeric token */
148218885Sdim    if (chartype[(int)*buf_ptr] == alphanum || (buf_ptr[0] == '.' && isdigit(buf_ptr[1]))) {
149218885Sdim	/*
150218885Sdim	 * we have a character or number
151218885Sdim	 */
152218885Sdim	const char *j;		/* used for searching thru list of
153218885Sdim				 *
154218885Sdim				 * reserved words */
155218885Sdim	struct templ *p;
156314564Sdim
157314564Sdim	if (isdigit(*buf_ptr) || (buf_ptr[0] == '.' && isdigit(buf_ptr[1]))) {
158314564Sdim	    int         seendot = 0,
159314564Sdim	                seenexp = 0,
160314564Sdim			seensfx = 0;
161218885Sdim	    if (*buf_ptr == '0' &&
162218885Sdim		    (buf_ptr[1] == 'x' || buf_ptr[1] == 'X')) {
163249423Sdim		*e_token++ = *buf_ptr++;
164249423Sdim		*e_token++ = *buf_ptr++;
165249423Sdim		while (isxdigit(*buf_ptr)) {
166249423Sdim		    CHECK_SIZE_TOKEN;
167249423Sdim		    *e_token++ = *buf_ptr++;
168249423Sdim		}
169249423Sdim	    }
170249423Sdim	    else
171249423Sdim		while (1) {
172249423Sdim		    if (*buf_ptr == '.') {
173249423Sdim			if (seendot)
174249423Sdim			    break;
175249423Sdim			else
176249423Sdim			    seendot++;
177249423Sdim		    }
178249423Sdim		    CHECK_SIZE_TOKEN;
179249423Sdim		    *e_token++ = *buf_ptr++;
180314564Sdim		    if (!isdigit(*buf_ptr) && *buf_ptr != '.') {
181314564Sdim			if ((*buf_ptr != 'E' && *buf_ptr != 'e') || seenexp)
182314564Sdim			    break;
183314564Sdim			else {
184249423Sdim			    seenexp++;
185249423Sdim			    seendot++;
186218885Sdim			    CHECK_SIZE_TOKEN;
187218885Sdim			    *e_token++ = *buf_ptr++;
188218885Sdim			    if (*buf_ptr == '+' || *buf_ptr == '-')
189218885Sdim				*e_token++ = *buf_ptr++;
190321369Sdim			}
191218885Sdim		    }
192218885Sdim		}
193218885Sdim	    while (1) {
194218885Sdim		if (!(seensfx & 1) &&
195218885Sdim			(*buf_ptr == 'U' || *buf_ptr == 'u')) {
196218885Sdim		    CHECK_SIZE_TOKEN;
197218885Sdim		    *e_token++ = *buf_ptr++;
198218885Sdim		    seensfx |= 1;
199218885Sdim		    continue;
200218885Sdim		}
201218885Sdim        	if (!(seensfx & 2) &&
202218885Sdim			(*buf_ptr == 'L' || *buf_ptr == 'l')) {
203218885Sdim		    CHECK_SIZE_TOKEN;
204218885Sdim		    if (buf_ptr[1] == buf_ptr[0])
205218885Sdim		        *e_token++ = *buf_ptr++;
206218885Sdim		    *e_token++ = *buf_ptr++;
207218885Sdim		    seensfx |= 2;
208218885Sdim		    continue;
209218885Sdim		}
210218885Sdim		break;
211218885Sdim	    }
212218885Sdim	}
213218885Sdim	else
214218885Sdim	    while (chartype[(int)*buf_ptr] == alphanum || *buf_ptr == BACKSLASH) {
215218885Sdim		/* fill_buffer() terminates buffer with newline */
216218885Sdim		if (*buf_ptr == BACKSLASH) {
217218885Sdim		    if (*(buf_ptr + 1) == '\n') {
218218885Sdim			buf_ptr += 2;
219218885Sdim			if (buf_ptr >= buf_end)
220218885Sdim			    fill_buffer();
221218885Sdim			} else
222218885Sdim			    break;
223218885Sdim		}
224218885Sdim		CHECK_SIZE_TOKEN;
225218885Sdim		/* copy it over */
226218885Sdim		*e_token++ = *buf_ptr++;
227218885Sdim		if (buf_ptr >= buf_end)
228218885Sdim		    fill_buffer();
229218885Sdim	    }
230218885Sdim	*e_token++ = '\0';
231218885Sdim	while (*buf_ptr == ' ' || *buf_ptr == '\t') {	/* get rid of blanks */
232218885Sdim	    if (++buf_ptr >= buf_end)
233218885Sdim		fill_buffer();
234218885Sdim	}
235218885Sdim	ps.its_a_keyword = false;
236218885Sdim	ps.sizeof_keyword = false;
237218885Sdim	if (l_struct && !ps.p_l_follow) {
238218885Sdim				/* if last token was 'struct' and we're not
239218885Sdim				 * in parentheses, then this token
240218885Sdim				 * should be treated as a declaration */
241218885Sdim	    l_struct = false;
242218885Sdim	    last_code = ident;
243218885Sdim	    ps.last_u_d = true;
244218885Sdim	    return (decl);
245218885Sdim	}
246218885Sdim	ps.last_u_d = l_struct;	/* Operator after identifier is binary
247218885Sdim				 * unless last token was 'struct' */
248218885Sdim	l_struct = false;
249218885Sdim	last_code = ident;	/* Remember that this is the code we will
250218885Sdim				 * return */
251218885Sdim
252218885Sdim	if (auto_typedefs) {
253218885Sdim	    const char *q = s_token;
254218885Sdim	    size_t q_len = strlen(q);
255218885Sdim	    /* Check if we have an "_t" in the end */
256218885Sdim	    if (q_len > 2 &&
257218885Sdim	        (strcmp(q + q_len - 2, "_t") == 0)) {
258218885Sdim	        ps.its_a_keyword = true;
259218885Sdim		ps.last_u_d = true;
260218885Sdim	        goto found_auto_typedef;
261218885Sdim	    }
262218885Sdim	}
263218885Sdim
264218885Sdim	/*
265218885Sdim	 * This loop will check if the token is a keyword.
266218885Sdim	 */
267218885Sdim	for (p = specials; (j = p->rwd) != 0; p++) {
268218885Sdim	    const char *q = s_token;	/* point at scanned token */
269218885Sdim	    if (*j++ != *q++ || *j++ != *q++)
270218885Sdim		continue;	/* This test depends on the fact that
271218885Sdim				 * identifiers are always at least 1 character
272218885Sdim				 * long (ie. the first two bytes of the
273218885Sdim				 * identifier are always meaningful) */
274218885Sdim	    if (q[-1] == 0)
275218885Sdim		break;		/* If its a one-character identifier */
276218885Sdim	    while (*q++ == *j)
277218885Sdim		if (*j++ == 0)
278218885Sdim		    goto found_keyword;	/* I wish that C had a multi-level
279218885Sdim					 * break... */
280218885Sdim	}
281218885Sdim	if (p->rwd) {		/* we have a keyword */
282218885Sdim    found_keyword:
283218885Sdim	    ps.its_a_keyword = true;
284218885Sdim	    ps.last_u_d = true;
285218885Sdim	    switch (p->rwcode) {
286218885Sdim	    case 1:		/* it is a switch */
287218885Sdim		return (swstmt);
288218885Sdim	    case 2:		/* a case or default */
289218885Sdim		return (casestmt);
290218885Sdim
291218885Sdim	    case 3:		/* a "struct" */
292218885Sdim		/*
293218885Sdim		 * Next time around, we will want to know that we have had a
294218885Sdim		 * 'struct'
295218885Sdim		 */
296218885Sdim		l_struct = true;
297218885Sdim		/* FALLTHROUGH */
298218885Sdim
299218885Sdim	    case 4:		/* one of the declaration keywords */
300218885Sdim	    found_auto_typedef:
301218885Sdim		if (ps.p_l_follow) {
302218885Sdim		    ps.cast_mask |= (1 << ps.p_l_follow) & ~ps.sizeof_mask;
303218885Sdim		    break;	/* inside parens: cast, param list or sizeof */
304218885Sdim		}
305218885Sdim		last_code = decl;
306218885Sdim		return (decl);
307218885Sdim
308218885Sdim	    case 5:		/* if, while, for */
309218885Sdim		return (sp_paren);
310218885Sdim
311218885Sdim	    case 6:		/* do, else */
312218885Sdim		return (sp_nparen);
313218885Sdim
314218885Sdim	    case 7:
315218885Sdim		ps.sizeof_keyword = true;
316218885Sdim	    default:		/* all others are treated like any other
317218885Sdim				 * identifier */
318218885Sdim		return (ident);
319218885Sdim	    }			/* end of switch */
320218885Sdim	}			/* end of if (found_it) */
321218885Sdim	if (*buf_ptr == '(' && ps.tos <= 1 && ps.ind_level == 0) {
322218885Sdim	    char *tp = buf_ptr;
323218885Sdim	    while (tp < buf_end)
324218885Sdim		if (*tp++ == ')' && (*tp == ';' || *tp == ','))
325218885Sdim		    goto not_proc;
326218885Sdim	    strncpy(ps.procname, token, sizeof ps.procname - 1);
327218885Sdim	    ps.in_parameter_declaration = 1;
328218885Sdim	    rparen_count = 1;
329218885Sdim    not_proc:;
330218885Sdim	}
331218885Sdim	/*
332218885Sdim	 * The following hack attempts to guess whether or not the current
333218885Sdim	 * token is in fact a declaration keyword -- one that has been
334218885Sdim	 * typedefd
335218885Sdim	 */
336218885Sdim	if (((*buf_ptr == '*' && buf_ptr[1] != '=') || isalpha(*buf_ptr) || *buf_ptr == '_')
337218885Sdim		&& !ps.p_l_follow
338218885Sdim	        && !ps.block_init
339218885Sdim		&& (ps.last_token == rparen || ps.last_token == semicolon ||
340218885Sdim		    ps.last_token == decl ||
341218885Sdim		    ps.last_token == lbrace || ps.last_token == rbrace)) {
342218885Sdim	    ps.its_a_keyword = true;
343218885Sdim	    ps.last_u_d = true;
344218885Sdim	    last_code = decl;
345218885Sdim	    return decl;
346218885Sdim	}
347218885Sdim	if (last_code == decl)	/* if this is a declared variable, then
348218885Sdim				 * following sign is unary */
349218885Sdim	    ps.last_u_d = true;	/* will make "int a -1" work */
350218885Sdim	last_code = ident;
351218885Sdim	return (ident);		/* the ident is not in the list */
352218885Sdim    }				/* end of procesing for alpanum character */
353218885Sdim
354218885Sdim    /* Scan a non-alphanumeric token */
355218885Sdim
356218885Sdim    *e_token++ = *buf_ptr;		/* if it is only a one-character token, it is
357218885Sdim				 * moved here */
358218885Sdim    *e_token = '\0';
359218885Sdim    if (++buf_ptr >= buf_end)
360218885Sdim	fill_buffer();
361218885Sdim
362218885Sdim    switch (*token) {
363218885Sdim    case '\n':
364218885Sdim	unary_delim = ps.last_u_d;
365218885Sdim	ps.last_nl = true;	/* remember that we just had a newline */
366218885Sdim	code = (had_eof ? 0 : newline);
367218885Sdim
368218885Sdim	/*
369218885Sdim	 * if data has been exhausted, the newline is a dummy, and we should
370218885Sdim	 * return code to stop
371218885Sdim	 */
372218885Sdim	break;
373218885Sdim
374218885Sdim    case '\'':			/* start of quoted character */
375218885Sdim    case '"':			/* start of string */
376218885Sdim	qchar = *token;
377218885Sdim	if (troff) {
378218885Sdim	    e_token[-1] = '`';
379218885Sdim	    if (qchar == '"')
380218885Sdim		*e_token++ = '`';
381218885Sdim	    e_token = chfont(&bodyf, &stringf, e_token);
382218885Sdim	}
383218885Sdim	do {			/* copy the string */
384218885Sdim	    while (1) {		/* move one character or [/<char>]<char> */
385218885Sdim		if (*buf_ptr == '\n') {
386218885Sdim		    diag2(1, "Unterminated literal");
387218885Sdim		    goto stop_lit;
388218885Sdim		}
389218885Sdim		CHECK_SIZE_TOKEN;	/* Only have to do this once in this loop,
390218885Sdim					 * since CHECK_SIZE guarantees that there
391218885Sdim					 * are at least 5 entries left */
392218885Sdim		*e_token = *buf_ptr++;
393218885Sdim		if (buf_ptr >= buf_end)
394218885Sdim		    fill_buffer();
395218885Sdim		if (*e_token == BACKSLASH) {	/* if escape, copy extra char */
396218885Sdim		    if (*buf_ptr == '\n')	/* check for escaped newline */
397218885Sdim			++line_no;
398218885Sdim		    if (troff) {
399218885Sdim			*++e_token = BACKSLASH;
400218885Sdim			if (*buf_ptr == BACKSLASH)
401218885Sdim			    *++e_token = BACKSLASH;
402218885Sdim		    }
403218885Sdim		    *++e_token = *buf_ptr++;
404218885Sdim		    ++e_token;	/* we must increment this again because we
405218885Sdim				 * copied two chars */
406218885Sdim		    if (buf_ptr >= buf_end)
407218885Sdim			fill_buffer();
408218885Sdim		}
409218885Sdim		else
410218885Sdim		    break;	/* we copied one character */
411218885Sdim	    }			/* end of while (1) */
412218885Sdim	} while (*e_token++ != qchar);
413218885Sdim	if (troff) {
414218885Sdim	    e_token = chfont(&stringf, &bodyf, e_token - 1);
415218885Sdim	    if (qchar == '"')
416218885Sdim		*e_token++ = '\'';
417218885Sdim	}
418218885Sdimstop_lit:
419218885Sdim	code = ident;
420218885Sdim	break;
421218885Sdim
422218885Sdim    case ('('):
423218885Sdim    case ('['):
424218885Sdim	unary_delim = true;
425218885Sdim	code = lparen;
426218885Sdim	break;
427218885Sdim
428218885Sdim    case (')'):
429218885Sdim    case (']'):
430218885Sdim	code = rparen;
431218885Sdim	break;
432218885Sdim
433218885Sdim    case '#':
434218885Sdim	unary_delim = ps.last_u_d;
435218885Sdim	code = preesc;
436218885Sdim	break;
437218885Sdim
438218885Sdim    case '?':
439218885Sdim	unary_delim = true;
440218885Sdim	code = question;
441218885Sdim	break;
442218885Sdim
443218885Sdim    case (':'):
444218885Sdim	code = colon;
445218885Sdim	unary_delim = true;
446218885Sdim	break;
447218885Sdim
448218885Sdim    case (';'):
449321369Sdim	unary_delim = true;
450218885Sdim	code = semicolon;
451218885Sdim	break;
452218885Sdim
453218885Sdim    case ('{'):
454218885Sdim	unary_delim = true;
455218885Sdim
456218885Sdim	/*
457218885Sdim	 * if (ps.in_or_st) ps.block_init = 1;
458218885Sdim	 */
459218885Sdim	/* ?	code = ps.block_init ? lparen : lbrace; */
460218885Sdim	code = lbrace;
461218885Sdim	break;
462218885Sdim
463218885Sdim    case ('}'):
464218885Sdim	unary_delim = true;
465321369Sdim	/* ?	code = ps.block_init ? rparen : rbrace; */
466321369Sdim	code = rbrace;
467218885Sdim	break;
468218885Sdim
469218885Sdim    case 014:			/* a form feed */
470218885Sdim	unary_delim = ps.last_u_d;
471218885Sdim	ps.last_nl = true;	/* remember this so we can set 'ps.col_1'
472218885Sdim				 * right */
473218885Sdim	code = form_feed;
474218885Sdim	break;
475218885Sdim
476218885Sdim    case (','):
477218885Sdim	unary_delim = true;
478218885Sdim	code = comma;
479218885Sdim	break;
480218885Sdim
481218885Sdim    case '.':
482218885Sdim	unary_delim = false;
483218885Sdim	code = period;
484218885Sdim	break;
485218885Sdim
486218885Sdim    case '-':
487218885Sdim    case '+':			/* check for -, +, --, ++ */
488218885Sdim	code = (ps.last_u_d ? unary_op : binary_op);
489218885Sdim	unary_delim = true;
490218885Sdim
491218885Sdim	if (*buf_ptr == token[0]) {
492218885Sdim	    /* check for doubled character */
493218885Sdim	    *e_token++ = *buf_ptr++;
494218885Sdim	    /* buffer overflow will be checked at end of loop */
495218885Sdim	    if (last_code == ident || last_code == rparen) {
496218885Sdim		code = (ps.last_u_d ? unary_op : postop);
497218885Sdim		/* check for following ++ or -- */
498218885Sdim		unary_delim = false;
499218885Sdim	    }
500314564Sdim	}
501218885Sdim	else if (*buf_ptr == '=')
502218885Sdim	    /* check for operator += */
503288943Sdim	    *e_token++ = *buf_ptr++;
504218885Sdim	else if (*buf_ptr == '>') {
505218885Sdim	    /* check for operator -> */
506218885Sdim	    *e_token++ = *buf_ptr++;
507218885Sdim	    if (!pointer_as_binop) {
508218885Sdim		unary_delim = false;
509218885Sdim		code = unary_op;
510218885Sdim		ps.want_blank = false;
511218885Sdim	    }
512218885Sdim	}
513218885Sdim	break;			/* buffer overflow will be checked at end of
514218885Sdim				 * switch */
515218885Sdim
516218885Sdim    case '=':
517218885Sdim	if (ps.in_or_st)
518218885Sdim	    ps.block_init = 1;
519218885Sdim#ifdef undef
520218885Sdim	if (chartype[*buf_ptr] == opchar) {	/* we have two char assignment */
521218885Sdim	    e_token[-1] = *buf_ptr++;
522218885Sdim	    if ((e_token[-1] == '<' || e_token[-1] == '>') && e_token[-1] == *buf_ptr)
523218885Sdim		*e_token++ = *buf_ptr++;
524218885Sdim	    *e_token++ = '=';	/* Flip =+ to += */
525218885Sdim	    *e_token = 0;
526218885Sdim	}
527218885Sdim#else
528218885Sdim	if (*buf_ptr == '=') {/* == */
529218885Sdim	    *e_token++ = '=';	/* Flip =+ to += */
530218885Sdim	    buf_ptr++;
531218885Sdim	    *e_token = 0;
532218885Sdim	}
533218885Sdim#endif
534218885Sdim	code = binary_op;
535218885Sdim	unary_delim = true;
536218885Sdim	break;
537218885Sdim	/* can drop thru!!! */
538218885Sdim
539218885Sdim    case '>':
540218885Sdim    case '<':
541218885Sdim    case '!':			/* ops like <, <<, <=, !=, etc */
542218885Sdim	if (*buf_ptr == '>' || *buf_ptr == '<' || *buf_ptr == '=') {
543218885Sdim	    *e_token++ = *buf_ptr;
544218885Sdim	    if (++buf_ptr >= buf_end)
545218885Sdim		fill_buffer();
546218885Sdim	}
547218885Sdim	if (*buf_ptr == '=')
548218885Sdim	    *e_token++ = *buf_ptr++;
549218885Sdim	code = (ps.last_u_d ? unary_op : binary_op);
550218885Sdim	unary_delim = true;
551218885Sdim	break;
552218885Sdim
553218885Sdim    default:
554218885Sdim	if (token[0] == '/' && *buf_ptr == '*') {
555218885Sdim	    /* it is start of comment */
556218885Sdim	    *e_token++ = '*';
557218885Sdim
558218885Sdim	    if (++buf_ptr >= buf_end)
559218885Sdim		fill_buffer();
560218885Sdim
561218885Sdim	    code = comment;
562218885Sdim	    unary_delim = ps.last_u_d;
563218885Sdim	    break;
564218885Sdim	}
565218885Sdim	while (*(e_token - 1) == *buf_ptr || *buf_ptr == '=') {
566218885Sdim	    /*
567218885Sdim	     * handle ||, &&, etc, and also things as in int *****i
568218885Sdim	     */
569218885Sdim	    *e_token++ = *buf_ptr;
570218885Sdim	    if (++buf_ptr >= buf_end)
571218885Sdim		fill_buffer();
572218885Sdim	}
573218885Sdim	code = (ps.last_u_d ? unary_op : binary_op);
574218885Sdim	unary_delim = true;
575218885Sdim
576218885Sdim
577218885Sdim    }				/* end of switch */
578218885Sdim    if (code != newline) {
579218885Sdim	l_struct = false;
580218885Sdim	last_code = code;
581218885Sdim    }
582218885Sdim    if (buf_ptr >= buf_end)	/* check for input buffer empty */
583218885Sdim	fill_buffer();
584218885Sdim    ps.last_u_d = unary_delim;
585218885Sdim    *e_token = '\0';		/* null terminate the token */
586218885Sdim    return (code);
587218885Sdim}
588218885Sdim
589218885Sdim/*
590218885Sdim * Add the given keyword to the keyword table, using val as the keyword type
591218885Sdim */
592218885Sdimvoid
593218885Sdimaddkey(char *key, int val)
594218885Sdim{
595218885Sdim    struct templ *p = specials;
596218885Sdim    while (p->rwd)
597218885Sdim	if (p->rwd[0] == key[0] && strcmp(p->rwd, key) == 0)
598218885Sdim	    return;
599218885Sdim	else
600218885Sdim	    p++;
601218885Sdim    if (p >= specials + sizeof specials / sizeof specials[0])
602218885Sdim	return;			/* For now, table overflows are silently
603218885Sdim				 * ignored */
604218885Sdim    p->rwd = key;
605218885Sdim    p->rwcode = val;
606218885Sdim    p[1].rwd = 0;
607218885Sdim    p[1].rwcode = 0;
608218885Sdim}
609218885Sdim