1 /* $NetBSD: emit1.c,v 1.5 1996/12/22 11:31:06 cgd Exp $ */ 2 3 /* 4 * Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved. 5 * Copyright (c) 1994, 1995 Jochen Pohl 6 * All Rights Reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 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 19 * The NetBSD Project. 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. 22 * 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. 33 */ 34 35 #ifndef lint 36 static char rcsid[] = "$NetBSD: emit1.c,v 1.5 1996/12/22 11:31:06 cgd Exp $"; 37 #endif 38 39 #include <ctype.h> 40 41 #include "lint1.h" 42 43 static void outtt __P((sym_t *, sym_t *)); 44 static void outfstrg __P((strg_t *)); 45 46 /* 47 * Write type into the output buffer. 48 * The type is written as a sequence of substrings, each of which describes a 49 * node of type type_t 50 * a node is coded as follows: 51 * char C 52 * signed char s C 53 * unsigned char u C 54 * short S 55 * unsigned short u S 56 * int I 57 * unsigned int u I 58 * long L 59 * unsigned long u L 60 * long long Q 61 * unsigned long long u Q 62 * float s D 63 * double D 64 * long double l D 65 * void V 66 * * P 67 * [n] A n 68 * () F 69 * (void) F 0 70 * (n arguments) F n arg1 arg2 ... argn 71 * (n arguments, ...) F n arg1 arg2 ... argn-1 E 72 * (a, b, c, ...) f n arg1 arg2 ... 73 * enum tag e T tag_or_typename 74 * struct tag s T tag_or_typename 75 * union tag u T tag_or_typename 76 * 77 * tag_or_typename 0 no tag or type name 78 * 1 n tag Tag 79 * 2 n typename only type name 80 * 81 * spaces are only for better readability 82 * additionaly it is possible to prepend the characters 'c' (for const) 83 * and 'v' (for volatile) 84 */ 85 void 86 outtype(tp) 87 type_t *tp; 88 { 89 int t, s, na; 90 sym_t *arg; 91 tspec_t ts; 92 93 while (tp != NULL) { 94 if ((ts = tp->t_tspec) == INT && tp->t_isenum) 95 ts = ENUM; 96 switch (ts) { 97 case CHAR: t = 'C'; s = '\0'; break; 98 case SCHAR: t = 'C'; s = 's'; break; 99 case UCHAR: t = 'C'; s = 'u'; break; 100 case SHORT: t = 'S'; s = '\0'; break; 101 case USHORT: t = 'S'; s = 'u'; break; 102 case INT: t = 'I'; s = '\0'; break; 103 case UINT: t = 'I'; s = 'u'; break; 104 case LONG: t = 'L'; s = '\0'; break; 105 case ULONG: t = 'L'; s = 'u'; break; 106 case QUAD: t = 'Q'; s = '\0'; break; 107 case UQUAD: t = 'Q'; s = 'u'; break; 108 case FLOAT: t = 'D'; s = 's'; break; 109 case DOUBLE: t = 'D'; s = '\0'; break; 110 case LDOUBLE: t = 'D'; s = 'l'; break; 111 case VOID: t = 'V'; s = '\0'; break; 112 case PTR: t = 'P'; s = '\0'; break; 113 case ARRAY: t = 'A'; s = '\0'; break; 114 case FUNC: t = 'F'; s = '\0'; break; 115 case ENUM: t = 'T'; s = 'e'; break; 116 case STRUCT: t = 'T'; s = 's'; break; 117 case UNION: t = 'T'; s = 'u'; break; 118 default: 119 lerror("outtyp() 1"); 120 } 121 if (tp->t_const) 122 outchar('c'); 123 if (tp->t_volatile) 124 outchar('v'); 125 if (s != '\0') 126 outchar(s); 127 outchar(t); 128 if (ts == ARRAY) { 129 outint(tp->t_dim); 130 } else if (ts == ENUM) { 131 outtt(tp->t_enum->etag, tp->t_enum->etdef); 132 } else if (ts == STRUCT || ts == UNION) { 133 outtt(tp->t_str->stag, tp->t_str->stdef); 134 } else if (ts == FUNC && tp->t_proto) { 135 na = 0; 136 for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt) 137 na++; 138 if (tp->t_vararg) 139 na++; 140 outint(na); 141 for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt) 142 outtype(arg->s_type); 143 if (tp->t_vararg) 144 outchar('E'); 145 } 146 tp = tp->t_subt; 147 } 148 } 149 150 /* 151 * type to string 152 * used for debugging output 153 * 154 * it uses its own output buffer for conversion 155 */ 156 const char * 157 ttos(tp) 158 type_t *tp; 159 { 160 static ob_t tob; 161 ob_t tmp; 162 163 if (tob.o_buf == NULL) { 164 tob.o_len = 64; 165 tob.o_buf = tob.o_nxt = xmalloc(tob.o_len); 166 tob.o_end = tob.o_buf + tob.o_len; 167 } 168 169 tmp = ob; 170 ob = tob; 171 ob.o_nxt = ob.o_buf; 172 outtype(tp); 173 outchar('\0'); 174 tob = ob; 175 ob = tmp; 176 177 return (tob.o_buf); 178 } 179 180 /* 181 * write the name of a tag or typename 182 * 183 * if the tag is named, the name of the 184 * tag is written, otherwise, if a typename exists which 185 * refers to this tag, this typename is written 186 */ 187 static void 188 outtt(tag, tdef) 189 sym_t *tag, *tdef; 190 { 191 192 /* 193 * 0 is no longer used. 194 */ 195 if (tag->s_name != unnamed) { 196 outint(1); 197 outname(tag->s_name); 198 } else if (tdef != NULL) { 199 outint(2); 200 outname(tdef->s_name); 201 } else { 202 outint(3); 203 outint(tag->s_dpos.p_line); 204 outchar('.'); 205 outint(getfnid(tag->s_dpos.p_file)); 206 outchar('.'); 207 outint(tag->s_dpos.p_uniq); 208 } 209 } 210 211 /* 212 * write information about an global declared/defined symbol 213 * with storage class extern 214 * 215 * informations about function definitions are written in outfdef(), 216 * not here 217 */ 218 void 219 outsym(sym, sc, def) 220 sym_t *sym; 221 scl_t sc; 222 def_t def; 223 { 224 /* 225 * Static function declarations must also be written to the output 226 * file. Compatibility of function declarations (for both static 227 * and extern functions) must be checked in lint2. Lint1 can't do 228 * this, especially not, if functions are declared at block level 229 * before their first declaration at level 0. 230 */ 231 if (sc != EXTERN && !(sc == STATIC && sym->s_type->t_tspec == FUNC)) 232 return; 233 234 /* reset buffer */ 235 outclr(); 236 237 /* 238 * line number of .c source, 'd' for declaration, Id of current 239 * source (.c or .h), and line in current source. 240 */ 241 outint(csrc_pos.p_line); 242 outchar('d'); 243 outint(getfnid(sym->s_dpos.p_file)); 244 outchar('.'); 245 outint(sym->s_dpos.p_line); 246 247 /* flags */ 248 249 switch (def) { 250 case DEF: 251 /* defined */ 252 outchar('d'); 253 break; 254 case TDEF: 255 /* tentative defined */ 256 outchar('t'); 257 break; 258 case DECL: 259 /* declared */ 260 outchar('e'); 261 break; 262 default: 263 lerror("outsym() 2"); 264 } 265 if (llibflg && def != DECL) { 266 /* 267 * mark it as used so we get no warnings from lint2 about 268 * unused symbols in libraries. 269 */ 270 outchar('u'); 271 } 272 273 if (sc == STATIC) 274 outchar('s'); 275 276 /* name of the symbol */ 277 outname(sym->s_name); 278 279 /* type of the symbol */ 280 outtype(sym->s_type); 281 } 282 283 /* 284 * write information about function definition 285 * 286 * this is also done for static functions so we are able to check if 287 * they are called with proper argument types 288 */ 289 void 290 outfdef(fsym, posp, rval, osdef, args) 291 sym_t *fsym, *args; 292 pos_t *posp; 293 int rval, osdef; 294 { 295 int narg; 296 sym_t *arg; 297 298 /* reset the buffer */ 299 outclr(); 300 301 /* 302 * line number of .c source, 'd' for declaration, Id of current 303 * source (.c or .h), and line in current source 304 * 305 * we are already at the end of the function. If we are in the 306 * .c source, posp->p_line is correct, otherwise csrc_pos.p_line 307 * (for functions defined in header files). 308 */ 309 if (posp->p_file == csrc_pos.p_file) { 310 outint(posp->p_line); 311 } else { 312 outint(csrc_pos.p_line); 313 } 314 outchar('d'); 315 outint(getfnid(posp->p_file)); 316 outchar('.'); 317 outint(posp->p_line); 318 319 /* flags */ 320 321 /* both SCANFLIKE and PRINTFLIKE imply VARARGS */ 322 if (prflstrg != -1) { 323 nvararg = prflstrg; 324 } else if (scflstrg != -1) { 325 nvararg = scflstrg; 326 } 327 328 if (nvararg != -1) { 329 outchar('v'); 330 outint(nvararg); 331 } 332 if (scflstrg != -1) { 333 outchar('S'); 334 outint(scflstrg); 335 } 336 if (prflstrg != -1) { 337 outchar('P'); 338 outint(prflstrg); 339 } 340 nvararg = prflstrg = scflstrg = -1; 341 342 outchar('d'); 343 344 if (rval) 345 /* has return value */ 346 outchar('r'); 347 348 if (llibflg) 349 /* 350 * mark it as used so lint2 does not complain about 351 * unused symbols in libraries 352 */ 353 outchar('u'); 354 355 if (osdef) 356 /* old style function definition */ 357 outchar('o'); 358 359 if (fsym->s_scl == STATIC) 360 outchar('s'); 361 362 /* name of function */ 363 outname(fsym->s_name); 364 365 /* argument types and return value */ 366 if (osdef) { 367 narg = 0; 368 for (arg = args; arg != NULL; arg = arg->s_nxt) 369 narg++; 370 outchar('f'); 371 outint(narg); 372 for (arg = args; arg != NULL; arg = arg->s_nxt) 373 outtype(arg->s_type); 374 outtype(fsym->s_type->t_subt); 375 } else { 376 outtype(fsym->s_type); 377 } 378 } 379 380 /* 381 * write out all information necessary for lint2 to check function 382 * calls 383 * 384 * rvused is set if the return value is used (asigned to a variable) 385 * rvdisc is set if the return value is not used and not ignored 386 * (casted to void) 387 */ 388 void 389 outcall(tn, rvused, rvdisc) 390 tnode_t *tn; 391 int rvused, rvdisc; 392 { 393 tnode_t *args, *arg; 394 int narg, n, i; 395 quad_t q; 396 tspec_t t; 397 398 /* reset buffer */ 399 outclr(); 400 401 /* 402 * line number of .c source, 'c' for function call, Id of current 403 * source (.c or .h), and line in current source 404 */ 405 outint(csrc_pos.p_line); 406 outchar('c'); 407 outint(getfnid(curr_pos.p_file)); 408 outchar('.'); 409 outint(curr_pos.p_line); 410 411 /* 412 * flags; 'u' and 'i' must be last to make sure a letter 413 * is between the numeric argument of a flag and the name of 414 * the function 415 */ 416 narg = 0; 417 args = tn->tn_right; 418 for (arg = args; arg != NULL; arg = arg->tn_right) 419 narg++; 420 /* informations about arguments */ 421 for (n = 1; n <= narg; n++) { 422 /* the last argument is the top one in the tree */ 423 for (i = narg, arg = args; i > n; i--, arg = arg->tn_right) ; 424 arg = arg->tn_left; 425 if (arg->tn_op == CON) { 426 if (isityp(t = arg->tn_type->t_tspec)) { 427 /* 428 * XXX it would probably be better to 429 * explizitly test the sign 430 */ 431 if ((q = arg->tn_val->v_quad) == 0) { 432 /* zero constant */ 433 outchar('z'); 434 } else if (msb(q, t, 0) == 0) { 435 /* positive if casted to signed */ 436 outchar('p'); 437 } else { 438 /* negative if casted to signed */ 439 outchar('n'); 440 } 441 outint(n); 442 } 443 } else if (arg->tn_op == AMPER && 444 arg->tn_left->tn_op == STRING && 445 arg->tn_left->tn_strg->st_tspec == CHAR) { 446 /* constant string, write all format specifiers */ 447 outchar('s'); 448 outint(n); 449 outfstrg(arg->tn_left->tn_strg); 450 } 451 452 } 453 /* return value discarded/used/ignored */ 454 outchar(rvdisc ? 'd' : (rvused ? 'u' : 'i')); 455 456 /* name of the called function */ 457 outname(tn->tn_left->tn_left->tn_sym->s_name); 458 459 /* types of arguments */ 460 outchar('f'); 461 outint(narg); 462 for (n = 1; n <= narg; n++) { 463 /* the last argument is the top one in the tree */ 464 for (i = narg, arg = args; i > n; i--, arg = arg->tn_right) ; 465 outtype(arg->tn_left->tn_type); 466 } 467 /* expected type of return value */ 468 outtype(tn->tn_type); 469 } 470 471 /* 472 * extracts potential format specifiers for printf() and scanf() and 473 * writes them, enclosed in "" and qouted if necessary, to the output buffer 474 */ 475 static void 476 outfstrg(strg) 477 strg_t *strg; 478 { 479 int c, oc, first; 480 u_char *cp; 481 482 if (strg->st_tspec != CHAR) 483 lerror("outfstrg() 1"); 484 485 cp = strg->st_cp; 486 487 outchar('"'); 488 489 c = *cp++; 490 491 while (c != '\0') { 492 493 if (c != '%') { 494 c = *cp++; 495 continue; 496 } 497 498 outqchar('%'); 499 c = *cp++; 500 501 /* flags for printf and scanf and *-fieldwidth for printf */ 502 while (c != '\0' && (c == '-' || c == '+' || c == ' ' || 503 c == '#' || c == '0' || c == '*')) { 504 outqchar(c); 505 c = *cp++; 506 } 507 508 /* numeric field width */ 509 while (c != '\0' && isdigit(c)) { 510 outqchar(c); 511 c = *cp++; 512 } 513 514 /* precision for printf */ 515 if (c == '.') { 516 outqchar(c); 517 if ((c = *cp++) == '*') { 518 outqchar(c); 519 c = *cp++; 520 } else { 521 while (c != '\0' && isdigit(c)) { 522 outqchar(c); 523 c = *cp++; 524 } 525 } 526 } 527 528 /* h, l, L and q flags fpr printf and scanf */ 529 if (c == 'h' || c == 'l' || c == 'L' || c == 'q') { 530 outqchar(c); 531 c = *cp++; 532 } 533 534 /* 535 * The last character. It is always written so we can detect 536 * invalid format specifiers. 537 */ 538 if (c != '\0') { 539 outqchar(c); 540 oc = c; 541 c = *cp++; 542 /* 543 * handle [ for scanf. [-] means that a minus sign 544 * was found at an undefined position. 545 */ 546 if (oc == '[') { 547 if (c == '^') 548 c = *cp++; 549 if (c == ']') 550 c = *cp++; 551 first = 1; 552 while (c != '\0' && c != ']') { 553 if (c == '-') { 554 if (!first && *cp != ']') 555 outqchar(c); 556 } 557 first = 0; 558 c = *cp++; 559 } 560 if (c == ']') { 561 outqchar(c); 562 c = *cp++; 563 } 564 } 565 } 566 567 } 568 569 outchar('"'); 570 } 571 572 /* 573 * writes a record if sym was used 574 */ 575 void 576 outusg(sym) 577 sym_t *sym; 578 { 579 /* reset buffer */ 580 outclr(); 581 582 /* 583 * line number of .c source, 'u' for used, Id of current 584 * source (.c or .h), and line in current source 585 */ 586 outint(csrc_pos.p_line); 587 outchar('u'); 588 outint(getfnid(curr_pos.p_file)); 589 outchar('.'); 590 outint(curr_pos.p_line); 591 592 /* necessary to delimit both numbers */ 593 outchar('x'); 594 595 /* Den Namen des Symbols ausgeben */ 596 outname(sym->s_name); 597 } 598