1 /* $NetBSD: emit1.c,v 1.18 2008/04/26 23:34:55 christos Exp $ */
4 * Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
5 * Copyright (c) 1994, 1995 Jochen Pohl
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Jochen Pohl for
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #if HAVE_NBTOOL_CONFIG_H
36 #include "nbtool_config.h"
39 #include <sys/cdefs.h>
40 #if defined(__RCSID) && !defined(lint)
41 __RCSID("$NetBSD: emit1.c,v 1.18 2008/04/26 23:34:55 christos Exp $");
48 static void outtt(sym_t
*, sym_t
*);
49 static void outfstrg(strg_t
*);
52 * Write type into the output buffer.
53 * The type is written as a sequence of substrings, each of which describes a
55 * a node is coded as follows:
59 * _Complex long double l X
70 * unsigned long long u Q
79 * (n arguments) F n arg1 arg2 ... argn
80 * (n arguments, ...) F n arg1 arg2 ... argn-1 E
81 * (a, b, c, ...) f n arg1 arg2 ...
82 * enum tag e T tag_or_typename
83 * struct tag s T tag_or_typename
84 * union tag u T tag_or_typename
86 * tag_or_typename 0 no tag or type name
88 * 2 n typename only type name
90 * spaces are only for better readability
91 * additionaly it is possible to prepend the characters 'c' (for const)
92 * and 'v' (for volatile)
102 if ((ts
= tp
->t_tspec
) == INT
&& tp
->t_isenum
)
105 case BOOL
: t
= 'B'; s
= '\0'; break;
106 case CHAR
: t
= 'C'; s
= '\0'; break;
107 case SCHAR
: t
= 'C'; s
= 's'; break;
108 case UCHAR
: t
= 'C'; s
= 'u'; break;
109 case SHORT
: t
= 'S'; s
= '\0'; break;
110 case USHORT
: t
= 'S'; s
= 'u'; break;
111 case INT
: t
= 'I'; s
= '\0'; break;
112 case UINT
: t
= 'I'; s
= 'u'; break;
113 case LONG
: t
= 'L'; s
= '\0'; break;
114 case ULONG
: t
= 'L'; s
= 'u'; break;
115 case QUAD
: t
= 'Q'; s
= '\0'; break;
116 case UQUAD
: t
= 'Q'; s
= 'u'; break;
117 case FLOAT
: t
= 'D'; s
= 's'; break;
118 case DOUBLE
: t
= 'D'; s
= '\0'; break;
119 case LDOUBLE
: t
= 'D'; s
= 'l'; break;
120 case VOID
: t
= 'V'; s
= '\0'; break;
121 case PTR
: t
= 'P'; s
= '\0'; break;
122 case ARRAY
: t
= 'A'; s
= '\0'; break;
123 case FUNC
: t
= 'F'; s
= '\0'; break;
124 case ENUM
: t
= 'T'; s
= 'e'; break;
125 case STRUCT
: t
= 'T'; s
= 's'; break;
126 case UNION
: t
= 'T'; s
= 'u'; break;
127 case FCOMPLEX
: t
= 'X'; s
= 's'; break;
128 case DCOMPLEX
: t
= 'X'; s
= '\0'; break;
129 case LCOMPLEX
: t
= 'X'; s
= 'l'; break;
142 } else if (ts
== ENUM
) {
143 outtt(tp
->t_enum
->etag
, tp
->t_enum
->etdef
);
144 } else if (ts
== STRUCT
|| ts
== UNION
) {
145 outtt(tp
->t_str
->stag
, tp
->t_str
->stdef
);
146 } else if (ts
== FUNC
&& tp
->t_proto
) {
148 for (arg
= tp
->t_args
; arg
!= NULL
; arg
= arg
->s_nxt
)
153 for (arg
= tp
->t_args
; arg
!= NULL
; arg
= arg
->s_nxt
)
154 outtype(arg
->s_type
);
164 * used for debugging output
166 * it uses its own output buffer for conversion
174 if (tob
.o_buf
== NULL
) {
176 tob
.o_buf
= tob
.o_nxt
= xmalloc(tob
.o_len
);
177 tob
.o_end
= tob
.o_buf
+ tob
.o_len
;
192 * write the name of a tag or typename
194 * if the tag is named, the name of the
195 * tag is written, otherwise, if a typename exists which
196 * refers to this tag, this typename is written
199 outtt(sym_t
*tag
, sym_t
*tdef
)
203 * 0 is no longer used.
205 if (tag
->s_name
!= unnamed
) {
207 outname(tag
->s_name
);
208 } else if (tdef
!= NULL
) {
210 outname(tdef
->s_name
);
213 outint(tag
->s_dpos
.p_line
);
215 outint(getfnid(tag
->s_dpos
.p_file
));
217 outint(tag
->s_dpos
.p_uniq
);
222 * write information about an global declared/defined symbol
223 * with storage class extern
225 * informations about function definitions are written in outfdef(),
229 outsym(sym_t
*sym
, scl_t sc
, def_t def
)
233 * Static function declarations must also be written to the output
234 * file. Compatibility of function declarations (for both static
235 * and extern functions) must be checked in lint2. Lint1 can't do
236 * this, especially not, if functions are declared at block level
237 * before their first declaration at level 0.
239 if (sc
!= EXTERN
&& !(sc
== STATIC
&& sym
->s_type
->t_tspec
== FUNC
))
246 * line number of .c source, 'd' for declaration, Id of current
247 * source (.c or .h), and line in current source.
249 outint(csrc_pos
.p_line
);
251 outint(getfnid(sym
->s_dpos
.p_file
));
253 outint(sym
->s_dpos
.p_line
);
263 /* tentative defined */
273 if (llibflg
&& def
!= DECL
) {
275 * mark it as used so we get no warnings from lint2 about
276 * unused symbols in libraries.
284 /* name of the symbol */
285 outname(sym
->s_name
);
287 /* renamed name of symbol, if necessary */
290 outname(sym
->s_rename
);
293 /* type of the symbol */
294 outtype(sym
->s_type
);
298 * write information about function definition
300 * this is also done for static functions so we are able to check if
301 * they are called with proper argument types
304 outfdef(sym_t
*fsym
, pos_t
*posp
, int rval
, int osdef
, sym_t
*args
)
309 /* reset the buffer */
313 * line number of .c source, 'd' for declaration, Id of current
314 * source (.c or .h), and line in current source
316 * we are already at the end of the function. If we are in the
317 * .c source, posp->p_line is correct, otherwise csrc_pos.p_line
318 * (for functions defined in header files).
320 if (posp
->p_file
== csrc_pos
.p_file
) {
321 outint(posp
->p_line
);
323 outint(csrc_pos
.p_line
);
326 outint(getfnid(posp
->p_file
));
328 outint(posp
->p_line
);
332 /* both SCANFLIKE and PRINTFLIKE imply VARARGS */
333 if (prflstrg
!= -1) {
335 } else if (scflstrg
!= -1) {
343 if (scflstrg
!= -1) {
347 if (prflstrg
!= -1) {
351 nvararg
= prflstrg
= scflstrg
= -1;
356 /* has return value */
361 * mark it as used so lint2 does not complain about
362 * unused symbols in libraries
367 /* old style function definition */
370 if (fsym
->s_scl
== STATIC
)
373 /* name of function */
374 outname(fsym
->s_name
);
376 /* renamed name of function, if necessary */
377 if (fsym
->s_rename
) {
379 outname(fsym
->s_rename
);
382 /* argument types and return value */
385 for (arg
= args
; arg
!= NULL
; arg
= arg
->s_nxt
)
389 for (arg
= args
; arg
!= NULL
; arg
= arg
->s_nxt
)
390 outtype(arg
->s_type
);
391 outtype(fsym
->s_type
->t_subt
);
393 outtype(fsym
->s_type
);
398 * write out all information necessary for lint2 to check function
401 * rvused is set if the return value is used (asigned to a variable)
402 * rvdisc is set if the return value is not used and not ignored
406 outcall(tnode_t
*tn
, int rvused
, int rvdisc
)
417 * line number of .c source, 'c' for function call, Id of current
418 * source (.c or .h), and line in current source
420 outint(csrc_pos
.p_line
);
422 outint(getfnid(curr_pos
.p_file
));
424 outint(curr_pos
.p_line
);
427 * flags; 'u' and 'i' must be last to make sure a letter
428 * is between the numeric argument of a flag and the name of
433 for (arg
= args
; arg
!= NULL
; arg
= arg
->tn_right
)
435 /* informations about arguments */
436 for (n
= 1; n
<= narg
; n
++) {
437 /* the last argument is the top one in the tree */
438 for (i
= narg
, arg
= args
; i
> n
; i
--, arg
= arg
->tn_right
)
441 if (arg
->tn_op
== CON
) {
442 if (isityp(t
= arg
->tn_type
->t_tspec
)) {
444 * XXX it would probably be better to
445 * explicitly test the sign
447 if ((q
= arg
->tn_val
->v_quad
) == 0) {
450 } else if (msb(q
, t
, 0) == 0) {
451 /* positive if casted to signed */
454 /* negative if casted to signed */
459 } else if (arg
->tn_op
== AMPER
&&
460 arg
->tn_left
->tn_op
== STRING
&&
461 arg
->tn_left
->tn_strg
->st_tspec
== CHAR
) {
462 /* constant string, write all format specifiers */
465 outfstrg(arg
->tn_left
->tn_strg
);
469 /* return value discarded/used/ignored */
470 outchar(rvdisc
? 'd' : (rvused
? 'u' : 'i'));
472 /* name of the called function */
473 outname(tn
->tn_left
->tn_left
->tn_sym
->s_name
);
475 /* types of arguments */
478 for (n
= 1; n
<= narg
; n
++) {
479 /* the last argument is the top one in the tree */
480 for (i
= narg
, arg
= args
; i
> n
; i
--, arg
= arg
->tn_right
)
482 outtype(arg
->tn_left
->tn_type
);
484 /* expected type of return value */
485 outtype(tn
->tn_type
);
489 * extracts potential format specifiers for printf() and scanf() and
490 * writes them, enclosed in "" and qouted if necessary, to the output buffer
493 outfstrg(strg_t
*strg
)
498 if (strg
->st_tspec
!= CHAR
)
499 LERROR("outfstrg()");
517 /* flags for printf and scanf and *-fieldwidth for printf */
518 while (c
!= '\0' && (c
== '-' || c
== '+' || c
== ' ' ||
519 c
== '#' || c
== '0' || c
== '*')) {
524 /* numeric field width */
525 while (c
!= '\0' && isdigit(c
)) {
530 /* precision for printf */
533 if ((c
= *cp
++) == '*') {
537 while (c
!= '\0' && isdigit(c
)) {
544 /* h, l, L and q flags fpr printf and scanf */
545 if (c
== 'h' || c
== 'l' || c
== 'L' || c
== 'q') {
551 * The last character. It is always written so we can detect
552 * invalid format specifiers.
559 * handle [ for scanf. [-] means that a minus sign
560 * was found at an undefined position.
568 while (c
!= '\0' && c
!= ']') {
570 if (!first
&& *cp
!= ']')
589 * writes a record if sym was used
598 * line number of .c source, 'u' for used, Id of current
599 * source (.c or .h), and line in current source
601 outint(csrc_pos
.p_line
);
603 outint(getfnid(curr_pos
.p_file
));
605 outint(curr_pos
.p_line
);
607 /* necessary to delimit both numbers */
610 /* Den Namen des Symbols ausgeben */
611 outname(sym
->s_name
);