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