Line data Source code
1 : /*-
2 : * Copyright (c) 1985 Sun Microsystems, Inc.
3 : * Copyright (c) 1980, 1993
4 : * The Regents of the University of California. All rights reserved.
5 : * All rights reserved.
6 : *
7 : * Redistribution and use in source and binary forms, with or without
8 : * modification, are permitted provided that the following conditions
9 : * are met:
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * 2. Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in the
14 : * documentation and/or other materials provided with the distribution.
15 : * 3. Neither the name of the University nor the names of its contributors
16 : * may be used to endorse or promote products derived from this software
17 : * without specific prior written permission.
18 : *
19 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 : * SUCH DAMAGE.
30 : */
31 :
32 : #if 0
33 : #ifndef lint
34 : static char sccsid[] = "@(#)lexi.c 8.1 (Berkeley) 6/6/93";
35 : #endif /* not lint */
36 : #endif
37 :
38 : #include "c.h"
39 :
40 : /*
41 : * Here we have the token scanner for indent. It scans off one token and puts
42 : * it in the global variable "token". It returns a code, indicating the type
43 : * of token scanned.
44 : */
45 :
46 : #include <err.h>
47 : #include <stdio.h>
48 : #include <ctype.h>
49 : #include <stdlib.h>
50 : #include <string.h>
51 : #include "indent_globs.h"
52 : #include "indent_codes.h"
53 : #include "indent.h"
54 :
55 : #define alphanum 1
56 : #ifdef undef
57 : #define opchar 3
58 : #endif
59 :
60 : struct templ {
61 : const char *rwd;
62 : int rwcode;
63 : };
64 :
65 : /*
66 : * This table has to be sorted alphabetically, because it'll be used in binary
67 : * search. For the same reason, string must be the first thing in struct templ.
68 : */
69 : struct templ specials[] =
70 : {
71 : {"_Bool", 4},
72 : {"_Complex", 4},
73 : {"_Imaginary", 4},
74 : {"auto", 10},
75 : {"bool", 4},
76 : {"break", 9},
77 : {"case", 8},
78 : {"char", 4},
79 : {"complex", 4},
80 : {"const", 4},
81 : {"continue", 12},
82 : {"default", 8},
83 : {"do", 6},
84 : {"double", 4},
85 : {"else", 6},
86 : {"enum", 3},
87 : {"extern", 10},
88 : {"float", 4},
89 : {"for", 5},
90 : {"global", 4},
91 : {"goto", 9},
92 : {"if", 5},
93 : {"imaginary", 4},
94 : {"inline", 12},
95 : {"int", 4},
96 : {"long", 4},
97 : {"offsetof", 1},
98 : {"register", 10},
99 : {"restrict", 12},
100 : {"return", 9},
101 : {"short", 4},
102 : {"signed", 4},
103 : {"sizeof", 2},
104 : {"static", 10},
105 : {"struct", 3},
106 : {"switch", 7},
107 : {"typedef", 11},
108 : {"union", 3},
109 : {"unsigned", 4},
110 : {"void", 4},
111 : {"volatile", 4},
112 : {"while", 5}
113 : };
114 :
115 : const char **typenames;
116 : int typename_count;
117 : int typename_top = -1;
118 :
119 : char chartype[128] =
120 : { /* this is used to facilitate the decision of
121 : * what type (alphanumeric, operator) each
122 : * character is */
123 : 0, 0, 0, 0, 0, 0, 0, 0,
124 : 0, 0, 0, 0, 0, 0, 0, 0,
125 : 0, 0, 0, 0, 0, 0, 0, 0,
126 : 0, 0, 0, 0, 0, 0, 0, 0,
127 : 0, 3, 0, 0, 1, 3, 3, 0,
128 : 0, 0, 3, 3, 0, 3, 0, 3,
129 : 1, 1, 1, 1, 1, 1, 1, 1,
130 : 1, 1, 0, 0, 3, 3, 3, 3,
131 : 0, 1, 1, 1, 1, 1, 1, 1,
132 : 1, 1, 1, 1, 1, 1, 1, 1,
133 : 1, 1, 1, 1, 1, 1, 1, 1,
134 : 1, 1, 1, 0, 0, 0, 3, 1,
135 : 0, 1, 1, 1, 1, 1, 1, 1,
136 : 1, 1, 1, 1, 1, 1, 1, 1,
137 : 1, 1, 1, 1, 1, 1, 1, 1,
138 : 1, 1, 1, 0, 3, 0, 3, 0
139 : };
140 :
141 : static int
142 2271 : strcmp_type(const void *e1, const void *e2)
143 : {
144 2271 : return (strcmp(e1, *(const char * const *)e2));
145 : }
146 :
147 : /*
148 : * Decide whether "foo(..." is a function definition or declaration.
149 : *
150 : * At call, we are looking at the '('. Look ahead to find the first
151 : * '{', ';' or ',' that is not within parentheses or comments; then
152 : * it's a definition if we found '{', otherwise a declaration.
153 : * Note that this rule is fooled by K&R-style parameter declarations,
154 : * but telling the difference between those and function attributes
155 : * seems like more trouble than it's worth. This code could also be
156 : * fooled by mismatched parens or apparent comment starts within string
157 : * literals, but that seems unlikely in the context it's used in.
158 : */
159 : static int
160 32 : is_func_definition(char *tp)
161 : {
162 32 : int paren_depth = 0;
163 32 : int in_comment = false;
164 32 : int in_slash_comment = false;
165 32 : int lastc = 0;
166 :
167 : /* We may need to look past the end of the current buffer. */
168 32 : lookahead_reset();
169 636 : for (;;) {
170 : int c;
171 :
172 : /* Fetch next character. */
173 668 : if (tp < buf_end)
174 362 : c = *tp++;
175 : else {
176 306 : c = lookahead();
177 306 : if (c == EOF)
178 0 : break;
179 : }
180 : /* Handle comments. */
181 668 : if (in_comment) {
182 0 : if (lastc == '*' && c == '/')
183 0 : in_comment = false;
184 668 : } else if (lastc == '/' && c == '*' && !in_slash_comment)
185 0 : in_comment = true;
186 668 : else if (in_slash_comment) {
187 0 : if (c == '\n')
188 0 : in_slash_comment = false;
189 668 : } else if (lastc == '/' && c == '/')
190 0 : in_slash_comment = true;
191 : /* Count nested parens properly. */
192 668 : else if (c == '(')
193 37 : paren_depth++;
194 631 : else if (c == ')') {
195 37 : paren_depth--;
196 : /*
197 : * If we find unbalanced parens, we must have started inside a
198 : * declaration.
199 : */
200 37 : if (paren_depth < 0)
201 0 : return false;
202 594 : } else if (paren_depth == 0) {
203 : /* We are outside any parentheses or comments. */
204 99 : if (c == '{')
205 28 : return true;
206 71 : else if (c == ';' || c == ',')
207 4 : return false;
208 : }
209 636 : lastc = c;
210 : }
211 : /* Hit EOF --- for lack of anything better, assume "not a definition". */
212 0 : return false;
213 : }
214 :
215 : int
216 1340 : lexi(struct parser_state *state)
217 : {
218 : int unary_delim; /* this is set to 1 if the current token
219 : * forces a following operator to be unary */
220 : int code; /* internal code to be returned */
221 : char qchar; /* the delimiter character for a string */
222 :
223 1340 : e_token = s_token; /* point to start of place to save token */
224 1340 : unary_delim = false;
225 1340 : state->col_1 = state->last_nl; /* tell world that this token started
226 : * in column 1 iff the last thing
227 : * scanned was a newline */
228 1340 : state->last_nl = false;
229 :
230 3130 : while (*buf_ptr == ' ' || *buf_ptr == '\t') { /* get rid of blanks */
231 450 : state->col_1 = false; /* leading blanks imply token is not in column
232 : * 1 */
233 450 : if (++buf_ptr >= buf_end)
234 21 : fill_buffer();
235 : }
236 :
237 : /* Scan an alphanumeric token */
238 1340 : if (chartype[*buf_ptr & 127] == alphanum ||
239 911 : (buf_ptr[0] == '.' && isdigit((unsigned char)buf_ptr[1]))) {
240 : /*
241 : * we have a character or number
242 : */
243 : struct templ *p;
244 :
245 432 : if (isdigit((unsigned char)*buf_ptr) ||
246 435 : (buf_ptr[0] == '.' && isdigit((unsigned char)buf_ptr[1]))) {
247 55 : int seendot = 0,
248 55 : seenexp = 0,
249 55 : seensfx = 0;
250 :
251 : /*
252 : * base 2, base 8, base 16:
253 : */
254 66 : if (buf_ptr[0] == '0' && buf_ptr[1] != '.') {
255 : int len;
256 :
257 11 : if (buf_ptr[1] == 'b' || buf_ptr[1] == 'B')
258 2 : len = strspn(buf_ptr + 2, "01") + 2;
259 9 : else if (buf_ptr[1] == 'x' || buf_ptr[1] == 'X')
260 2 : len = strspn(buf_ptr + 2, "0123456789ABCDEFabcdef") + 2;
261 : else
262 7 : len = strspn(buf_ptr + 1, "012345678") + 1;
263 11 : if (len > 0) {
264 11 : CHECK_SIZE_TOKEN(len);
265 11 : memcpy(e_token, buf_ptr, len);
266 11 : e_token += len;
267 11 : buf_ptr += len;
268 : }
269 : else
270 0 : diag2(1, "Unterminated literal");
271 : }
272 : else /* base 10: */
273 : while (1) {
274 62 : if (*buf_ptr == '.') {
275 7 : if (seendot)
276 0 : break;
277 : else
278 7 : seendot++;
279 : }
280 62 : CHECK_SIZE_TOKEN(3);
281 62 : *e_token++ = *buf_ptr++;
282 62 : if (!isdigit((unsigned char)*buf_ptr) && *buf_ptr != '.') {
283 44 : if ((*buf_ptr != 'E' && *buf_ptr != 'e') || seenexp)
284 : break;
285 : else {
286 0 : seenexp++;
287 0 : seendot++;
288 0 : *e_token++ = *buf_ptr++;
289 0 : if (*buf_ptr == '+' || *buf_ptr == '-')
290 0 : *e_token++ = *buf_ptr++;
291 : }
292 : }
293 : }
294 :
295 : while (1) {
296 69 : CHECK_SIZE_TOKEN(2);
297 69 : if (!(seensfx & 1) && (*buf_ptr == 'U' || *buf_ptr == 'u')) {
298 6 : *e_token++ = *buf_ptr++;
299 6 : seensfx |= 1;
300 6 : continue;
301 : }
302 63 : if (!(seensfx & 2) && (strchr("fFlL", *buf_ptr) != NULL)) {
303 8 : if (buf_ptr[1] == buf_ptr[0])
304 0 : *e_token++ = *buf_ptr++;
305 8 : *e_token++ = *buf_ptr++;
306 8 : seensfx |= 2;
307 8 : continue;
308 : }
309 55 : break;
310 : }
311 : }
312 : else
313 2457 : while (chartype[*buf_ptr & 127] == alphanum || *buf_ptr == BACKSLASH) {
314 : /* fill_buffer() terminates buffer with newline */
315 1703 : if (*buf_ptr == BACKSLASH) {
316 0 : if (*(buf_ptr + 1) == '\n') {
317 0 : buf_ptr += 2;
318 0 : if (buf_ptr >= buf_end)
319 0 : fill_buffer();
320 : } else
321 0 : break;
322 : }
323 1703 : CHECK_SIZE_TOKEN(1);
324 : /* copy it over */
325 1703 : *e_token++ = *buf_ptr++;
326 1703 : if (buf_ptr >= buf_end)
327 0 : fill_buffer();
328 : }
329 432 : *e_token = '\0';
330 :
331 432 : if (s_token[0] == 'L' && s_token[1] == '\0' &&
332 2 : (*buf_ptr == '"' || *buf_ptr == '\''))
333 2 : return (strpfx);
334 :
335 1081 : while (*buf_ptr == ' ' || *buf_ptr == '\t') { /* get rid of blanks */
336 221 : if (++buf_ptr >= buf_end)
337 16 : fill_buffer();
338 : }
339 430 : state->keyword = 0;
340 430 : if (state->last_token == structure && !state->p_l_follow) {
341 : /* if last token was 'struct' and we're not
342 : * in parentheses, then this token
343 : * should be treated as a declaration */
344 6 : state->last_u_d = true;
345 6 : return (decl);
346 : }
347 : /*
348 : * Operator after identifier is binary unless last token was 'struct'
349 : */
350 424 : state->last_u_d = (state->last_token == structure);
351 :
352 424 : p = bsearch(s_token,
353 : specials,
354 : sizeof(specials) / sizeof(specials[0]),
355 : sizeof(specials[0]),
356 : strcmp_type);
357 424 : if (p == NULL) { /* not a special keyword... */
358 : char *u;
359 :
360 : /* ... so maybe a type_t or a typedef */
361 256 : if ((auto_typedefs && ((u = strrchr(s_token, '_')) != NULL) &&
362 303 : strcmp(u, "_t") == 0) || (typename_top >= 0 &&
363 47 : bsearch(s_token, typenames, typename_top + 1,
364 : sizeof(typenames[0]), strcmp_type))) {
365 4 : state->keyword = 4; /* a type name */
366 4 : if (state->last_token != period && state->last_token != unary_op)
367 2 : state->last_u_d = true;
368 4 : goto found_typename;
369 : }
370 : } else { /* we have a keyword */
371 168 : state->keyword = p->rwcode;
372 168 : state->last_u_d = true;
373 168 : switch (p->rwcode) {
374 1 : case 7: /* it is a switch */
375 1 : return (swstmt);
376 2 : case 8: /* a case or default */
377 2 : return (casestmt);
378 :
379 : case 3: /* a "struct" */
380 : /* FALLTHROUGH */
381 : case 4: /* one of the declaration keywords */
382 129 : found_typename:
383 129 : if (state->p_l_follow) {
384 : /* inside parens: cast, param list, offsetof or sizeof */
385 47 : state->cast_mask |= (1 << state->p_l_follow) & ~state->not_cast_mask;
386 : }
387 129 : if (state->last_token == period || state->last_token == unary_op) {
388 2 : state->keyword = 0;
389 2 : break;
390 : }
391 127 : if (p != NULL && p->rwcode == 3)
392 19 : return (structure);
393 108 : if (state->p_l_follow)
394 37 : break;
395 71 : return (decl);
396 :
397 12 : case 5: /* if, while, for */
398 12 : return (sp_paren);
399 :
400 7 : case 6: /* do, else */
401 7 : return (sp_nparen);
402 :
403 10 : case 10: /* storage class specifier */
404 10 : return (storage);
405 :
406 6 : case 11: /* typedef */
407 6 : return (type_def);
408 :
409 5 : default: /* all others are treated like any other
410 : * identifier */
411 5 : return (ident);
412 : } /* end of switch */
413 : } /* end of if (found_it) */
414 291 : if (*buf_ptr == '(' && state->tos <= 1 && state->ind_level == 0 &&
415 34 : state->in_parameter_declaration == 0 && state->block_init == 0) {
416 32 : if (is_func_definition(buf_ptr)) {
417 28 : strncpy(state->procname, token, sizeof state->procname - 1);
418 28 : if (state->in_decl)
419 27 : state->in_parameter_declaration = 1;
420 28 : return (funcname);
421 : }
422 : }
423 : /*
424 : * The following hack attempts to guess whether or not the current
425 : * token is in fact a declaration keyword -- one that has been
426 : * typedefd
427 : */
428 259 : else if (!state->p_l_follow && !state->block_init &&
429 100 : !state->in_stmt &&
430 24 : ((*buf_ptr == '*' && buf_ptr[1] != '=') ||
431 21 : isalpha((unsigned char)*buf_ptr)) &&
432 6 : (state->last_token == semicolon || state->last_token == lbrace ||
433 0 : state->last_token == rbrace)) {
434 6 : state->keyword = 4; /* a type name */
435 6 : state->last_u_d = true;
436 6 : return decl;
437 : }
438 257 : if (state->last_token == decl) /* if this is a declared variable,
439 : * then following sign is unary */
440 39 : state->last_u_d = true; /* will make "int a -1" work */
441 257 : return (ident); /* the ident is not in the list */
442 : } /* end of processing for alphanum character */
443 :
444 : /* Scan a non-alphanumeric token */
445 :
446 908 : CHECK_SIZE_TOKEN(3); /* things like "<<=" */
447 908 : *e_token++ = *buf_ptr; /* if it is only a one-character token, it is
448 : * moved here */
449 908 : *e_token = '\0';
450 908 : if (++buf_ptr >= buf_end)
451 301 : fill_buffer();
452 :
453 908 : switch (*token) {
454 345 : case '\n':
455 345 : unary_delim = state->last_u_d;
456 345 : state->last_nl = true; /* remember that we just had a newline */
457 345 : code = (had_eof ? 0 : newline);
458 :
459 : /*
460 : * if data has been exhausted, the newline is a dummy, and we should
461 : * return code to stop
462 : */
463 345 : break;
464 :
465 2 : case '\'': /* start of quoted character */
466 : case '"': /* start of string */
467 2 : qchar = *token;
468 : do { /* copy the string */
469 : while (1) { /* move one character or [/<char>]<char> */
470 7 : if (*buf_ptr == '\n') {
471 0 : diag2(1, "Unterminated literal");
472 0 : goto stop_lit;
473 : }
474 7 : CHECK_SIZE_TOKEN(2);
475 7 : *e_token = *buf_ptr++;
476 7 : if (buf_ptr >= buf_end)
477 0 : fill_buffer();
478 7 : if (*e_token == BACKSLASH) { /* if escape, copy extra char */
479 0 : if (*buf_ptr == '\n') /* check for escaped newline */
480 0 : ++line_no;
481 0 : *++e_token = *buf_ptr++;
482 0 : ++e_token; /* we must increment this again because we
483 : * copied two chars */
484 0 : if (buf_ptr >= buf_end)
485 0 : fill_buffer();
486 : }
487 : else
488 7 : break; /* we copied one character */
489 : } /* end of while (1) */
490 7 : } while (*e_token++ != qchar);
491 2 : stop_lit:
492 2 : code = ident;
493 2 : break;
494 :
495 78 : case ('('):
496 : case ('['):
497 78 : unary_delim = true;
498 78 : code = lparen;
499 78 : break;
500 :
501 78 : case (')'):
502 : case (']'):
503 78 : code = rparen;
504 78 : break;
505 :
506 11 : case '#':
507 11 : unary_delim = state->last_u_d;
508 11 : code = preesc;
509 11 : break;
510 :
511 0 : case '?':
512 0 : unary_delim = true;
513 0 : code = question;
514 0 : break;
515 :
516 5 : case (':'):
517 5 : code = colon;
518 5 : unary_delim = true;
519 5 : break;
520 :
521 75 : case (';'):
522 75 : unary_delim = true;
523 75 : code = semicolon;
524 75 : break;
525 :
526 58 : case ('{'):
527 58 : unary_delim = true;
528 :
529 : /*
530 : * if (state->in_or_st) state->block_init = 1;
531 : */
532 : /* ? code = state->block_init ? lparen : lbrace; */
533 58 : code = lbrace;
534 58 : break;
535 :
536 42 : case ('}'):
537 42 : unary_delim = true;
538 : /* ? code = state->block_init ? rparen : rbrace; */
539 42 : code = rbrace;
540 42 : break;
541 :
542 0 : case 014: /* a form feed */
543 0 : unary_delim = state->last_u_d;
544 0 : state->last_nl = true; /* remember this so we can set 'state->col_1'
545 : * right */
546 0 : code = form_feed;
547 0 : break;
548 :
549 56 : case (','):
550 56 : unary_delim = true;
551 56 : code = comma;
552 56 : break;
553 :
554 6 : case '.':
555 6 : unary_delim = false;
556 6 : code = period;
557 6 : break;
558 :
559 6 : case '-':
560 : case '+': /* check for -, +, --, ++ */
561 6 : code = (state->last_u_d ? unary_op : binary_op);
562 6 : unary_delim = true;
563 :
564 6 : if (*buf_ptr == token[0]) {
565 : /* check for doubled character */
566 0 : *e_token++ = *buf_ptr++;
567 : /* buffer overflow will be checked at end of loop */
568 0 : if (state->last_token == ident || state->last_token == rparen) {
569 0 : code = (state->last_u_d ? unary_op : postop);
570 : /* check for following ++ or -- */
571 0 : unary_delim = false;
572 : }
573 : }
574 6 : else if (*buf_ptr == '=')
575 : /* check for operator += */
576 0 : *e_token++ = *buf_ptr++;
577 6 : else if (*buf_ptr == '>') {
578 : /* check for operator -> */
579 2 : *e_token++ = *buf_ptr++;
580 2 : unary_delim = false;
581 2 : code = unary_op;
582 2 : state->want_blank = false;
583 : }
584 6 : break; /* buffer overflow will be checked at end of
585 : * switch */
586 :
587 28 : case '=':
588 28 : if (state->in_or_st)
589 25 : state->block_init = 1;
590 : #ifdef undef
591 : if (chartype[*buf_ptr & 127] == opchar) { /* we have two char assignment */
592 : e_token[-1] = *buf_ptr++;
593 : if ((e_token[-1] == '<' || e_token[-1] == '>') && e_token[-1] == *buf_ptr)
594 : *e_token++ = *buf_ptr++;
595 : *e_token++ = '='; /* Flip =+ to += */
596 : *e_token = 0;
597 : }
598 : #else
599 28 : if (*buf_ptr == '=') {/* == */
600 0 : *e_token++ = '='; /* Flip =+ to += */
601 0 : buf_ptr++;
602 0 : *e_token = 0;
603 : }
604 : #endif
605 28 : code = binary_op;
606 28 : unary_delim = true;
607 28 : break;
608 : /* can drop thru!!! */
609 :
610 4 : case '>':
611 : case '<':
612 : case '!': /* ops like <, <<, <=, !=, etc */
613 4 : if (*buf_ptr == '>' || *buf_ptr == '<' || *buf_ptr == '=') {
614 4 : *e_token++ = *buf_ptr;
615 4 : if (++buf_ptr >= buf_end)
616 0 : fill_buffer();
617 : }
618 4 : if (*buf_ptr == '=')
619 0 : *e_token++ = *buf_ptr++;
620 4 : code = (state->last_u_d ? unary_op : binary_op);
621 4 : unary_delim = true;
622 4 : break;
623 :
624 46 : case '*':
625 46 : unary_delim = true;
626 46 : if (!state->last_u_d) {
627 6 : if (*buf_ptr == '=')
628 0 : *e_token++ = *buf_ptr++;
629 6 : code = binary_op;
630 6 : break;
631 : }
632 91 : while (*buf_ptr == '*' || isspace((unsigned char)*buf_ptr)) {
633 11 : if (*buf_ptr == '*') {
634 3 : CHECK_SIZE_TOKEN(1);
635 3 : *e_token++ = *buf_ptr;
636 : }
637 11 : if (++buf_ptr >= buf_end)
638 2 : fill_buffer();
639 : }
640 40 : code = unary_op;
641 40 : break;
642 :
643 68 : default:
644 68 : if (token[0] == '/' && *buf_ptr == '*') {
645 : /* it is start of comment */
646 67 : *e_token++ = '*';
647 :
648 67 : if (++buf_ptr >= buf_end)
649 0 : fill_buffer();
650 :
651 67 : code = comment;
652 67 : unary_delim = state->last_u_d;
653 67 : break;
654 : }
655 2 : while (*(e_token - 1) == *buf_ptr || *buf_ptr == '=') {
656 : /*
657 : * handle ||, &&, etc, and also things as in int *****i
658 : */
659 0 : CHECK_SIZE_TOKEN(1);
660 0 : *e_token++ = *buf_ptr;
661 0 : if (++buf_ptr >= buf_end)
662 0 : fill_buffer();
663 : }
664 1 : code = (state->last_u_d ? unary_op : binary_op);
665 1 : unary_delim = true;
666 :
667 :
668 : } /* end of switch */
669 908 : if (buf_ptr >= buf_end) /* check for input buffer empty */
670 0 : fill_buffer();
671 908 : state->last_u_d = unary_delim;
672 908 : CHECK_SIZE_TOKEN(1);
673 908 : *e_token = '\0'; /* null terminate the token */
674 908 : return (code);
675 : }
676 :
677 : void
678 19 : alloc_typenames(void)
679 : {
680 :
681 19 : typenames = (const char **)malloc(sizeof(typenames[0]) *
682 19 : (typename_count = 16));
683 19 : if (typenames == NULL)
684 0 : err(1, NULL);
685 19 : }
686 :
687 : void
688 3 : add_typename(const char *key)
689 : {
690 : int comparison;
691 : const char *copy;
692 :
693 3 : if (typename_top + 1 >= typename_count) {
694 0 : typenames = realloc((void *)typenames,
695 0 : sizeof(typenames[0]) * (typename_count *= 2));
696 0 : if (typenames == NULL)
697 0 : err(1, NULL);
698 : }
699 3 : if (typename_top == -1)
700 2 : typenames[++typename_top] = copy = strdup(key);
701 1 : else if ((comparison = strcmp(key, typenames[typename_top])) >= 0) {
702 : /* take advantage of sorted input */
703 0 : if (comparison == 0) /* remove duplicates */
704 0 : return;
705 0 : typenames[++typename_top] = copy = strdup(key);
706 : }
707 : else {
708 : int p;
709 :
710 1 : for (p = 0; (comparison = strcmp(key, typenames[p])) > 0; p++)
711 : /* find place for the new key */;
712 1 : if (comparison == 0) /* remove duplicates */
713 0 : return;
714 1 : memmove(&typenames[p + 1], &typenames[p],
715 1 : sizeof(typenames[0]) * (++typename_top - p));
716 1 : typenames[p] = copy = strdup(key);
717 : }
718 :
719 3 : if (copy == NULL)
720 0 : err(1, NULL);
721 : }
|