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