1 /* $NetBSD: C.c,v 1.18 2009/04/11 12:58:03 lukem Exp $ */
4 * Copyright (c) 1987, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
36 #include <sys/cdefs.h>
37 #if defined(__RCSID) && !defined(lint)
39 static char sccsid
[] = "@(#)C.c 8.4 (Berkeley) 4/2/94";
41 __RCSID("$NetBSD: C.c,v 1.18 2009/04/11 12:58:03 lukem Exp $");
52 static int func_entry(void);
53 static void hash_entry(void);
54 static void skip_string(int);
55 static int str_entry(int);
59 * read .c and .h files and call appropriate routines
64 int c
; /* current character */
65 int level
; /* brace level */
66 int token
; /* if reading a token */
67 int t_def
; /* if reading a typedef */
68 int t_level
; /* typedef's brace level */
69 char *sp
; /* buffer pointer */
70 char tok
[MAXTOKEN
]; /* token buffer */
72 lineftell
= ftell(inf
);
73 sp
= tok
; token
= t_def
= NO
; t_level
= -1; level
= 0; lineno
= 1;
74 while (GETC(!=, EOF
)) {
77 * Here's where it DOESN'T handle: {
84 * puts("hello, world");
92 * if level goes below zero, try and fix
93 * it, even though we've already messed up
102 * the above 3 cases are similar in that they
103 * are special characters that also end tokens.
105 endtok
: if (sp
> tok
) {
115 * We ignore quoted strings and character constants
120 (void)skip_string(c
);
124 * comments can be fun; note the state is unchanged after
125 * return, in case we found:
126 * "foo() XX comment XX { int bar; }"
132 } else if (c
== '/') {
136 (void)ungetc(c
, inf
);
140 /* hash marks flag #define's. */
149 * if we have a current token, parenthesis on
150 * level zero indicates a function.
154 while (c
!= EOF
&& iswhite(c
));
159 if (!level
&& token
) {
165 * grab the line immediately, we may
166 * already be wrong, for example,
174 pfnote(tok
, curline
);
181 * semi-colons indicate the end of a typedef; if we find a
182 * typedef we search for the next semi-colon of the same
183 * level as the typedef. Ignoring "structs", they are
184 * tricky, since you can find:
186 * "typedef long time_t;"
187 * "typedef unsigned int u_int;"
188 * "typedef unsigned int u_int [10];"
190 * If looking at a typedef, we save a copy of the last token
191 * found. Then, when we find the ';' we take the current
192 * token if it starts with a valid token name, else we take
193 * the one we saved. There's probably some reasonable
194 * alternative to this...
197 if (t_def
&& level
== t_level
) {
208 * store characters until one that can't be part of a token
209 * comes along; check the current token against certain
213 storec
: if (c
== EOF
)
220 /* no typedefs inside typedefs */
222 !memcmp(tok
, "typedef",8)) {
227 /* catch "typedef struct" */
228 if ((!t_def
|| t_level
<= level
)
229 && (!memcmp(tok
, "struct", 7)
230 || !memcmp(tok
, "union", 6)
231 || !memcmp(tok
, "enum", 5))) {
233 * get line immediately;
234 * may change before '{'
245 else if (sp
!= tok
|| begtoken(c
)) {
246 if (sp
< tok
+ sizeof tok
)
260 * handle a function reference
265 int c
; /* current character */
266 int level
= 0; /* for matching '()' */
267 static char attribute
[] = "__attribute__";
268 char maybe_attribute
[sizeof attribute
+ 1],
272 * Find the end of the assumed function declaration.
273 * Note that ANSI C functions can have type definitions so keep
274 * track of the parentheses nesting level.
276 while (GETC(!=, EOF
)) {
280 /* skip strings and character constants */
305 * we assume that the character after a function's right paren
306 * is a token character if it's a function and a non-token
307 * character if it's a declaration. Comments don't count...
309 for (anext
= maybe_attribute
;;) {
310 while (GETC(!=, EOF
) && iswhite(c
))
316 * Recognize the gnu __attribute__ extension, which would
317 * otherwise make the heuristic test DTWT
319 if (anext
== maybe_attribute
) {
326 if (anext
- maybe_attribute
327 < (ptrdiff_t)(sizeof attribute
- 1))
333 if (strcmp(maybe_attribute
, attribute
) == 0) {
334 (void)ungetc(c
, inf
);
340 if (intoken(c
) || c
== '{')
342 if (c
== '/' && GETC(==, '*'))
346 else { /* don't ever "read" '/' */
347 (void)ungetc(c
, inf
);
358 * handle a line starting with a '#'
363 int c
; /* character read */
364 int curline
; /* line started on */
365 char *sp
; /* buffer pointer */
366 char tok
[MAXTOKEN
]; /* storage buffer */
369 do if (GETC(==, EOF
))
371 while(c
!= '\n' && iswhite(c
));
373 for (sp
= tok
;;) { /* get next token */
378 if (sp
< tok
+ sizeof tok
)
381 if(sp
>= tok
+ sizeof tok
)
384 if (memcmp(tok
, "define", 6)) /* only interested in #define's */
386 for (;;) { /* this doesn't handle "#define \n" */
392 for (sp
= tok
;;) { /* get next token */
393 if(sp
< tok
+ sizeof tok
)
398 * this is where it DOESN'T handle
404 if(sp
>= tok
+ sizeof tok
)
407 if (dflag
|| c
== '(') { /* only want macros */
409 pfnote(tok
, curline
);
411 skip
: if (c
== '\n') { /* get rid of rest of define */
413 if (*(sp
- 1) != '\\')
416 (void)skip_key('\n');
421 * handle a struct, union or enum entry
424 str_entry(int c
/* current character */)
426 int curline
; /* line started on */
427 char *sp
; /* buffer pointer */
428 char tok
[LINE_MAX
]; /* storage buffer */
434 if (c
== '{') /* it was "struct {" */
436 for (sp
= tok
;;) { /* get next token */
444 case '{': /* it was "struct foo{" */
447 case '\n': /* it was "struct foo\n" */
450 default: /* probably "struct foo " */
451 while (GETC(!=, EOF
))
455 (void)ungetc(c
, inf
);
460 pfnote(tok
, curline
);
469 skip_comment(int commenttype
)
471 int c
; /* character read */
472 int star
; /* '*' flag */
474 for (star
= 0; GETC(!=, EOF
);)
476 /* comments don't nest, nor can they be escaped. */
481 if (commenttype
== '*' && star
)
485 if (commenttype
== '/') {
487 * we don't really parse C, so sometimes it
488 * is necessary to see the newline
503 * skip to the end of a string or character constant.
511 for (skip
= NO
; GETC(!=, EOF
); )
513 case '\\': /* a backslash escapes anything */
514 skip
= !skip
; /* we toggle in case it's "\\" */
520 if (c
== key
&& !skip
)
528 * skip to next char "key"
537 for (skip
= retval
= NO
; GETC(!=, EOF
);)
539 case '\\': /* a backslash escapes anything */
540 skip
= !skip
; /* we toggle in case it's "\\" */
542 case ';': /* special case for yacc; if one */
543 case '|': /* of these chars occurs, we may */
544 retval
= YES
; /* have moved out of the rule */
545 break; /* not used by C */
548 /* skip strings and character constants */
556 } else if (c
== '/') {
560 (void)ungetc(c
, inf
);
568 if (c
== key
&& !skip
)