1 /* Copyright (c) 1979 Regents of the University of California */ 2 3 #ifndef lint 4 static char sccsid[] = "@(#)p2put.c 2.2 03/20/85"; 5 #endif 6 7 /* 8 * functions to help pi put out 9 * polish postfix binary portable c compiler intermediate code 10 * thereby becoming the portable pascal compiler 11 */ 12 13 #include "whoami.h" 14 #ifdef PC 15 #include "0.h" 16 #include "objfmt.h" 17 #include <pcc.h> 18 #include "pc.h" 19 #include "align.h" 20 #include "tmps.h" 21 22 /* 23 * emits an ftext operator and a string to the pcstream 24 */ 25 puttext( string ) 26 char *string; 27 { 28 int length = str4len( string ); 29 30 if ( !CGENNING ) 31 return; 32 p2word( PCCM_TRIPLE( PCCF_FTEXT , length , 0 ) ); 33 # ifdef DEBUG 34 if ( opt( 'k' ) ) { 35 fprintf( stdout , "PCCF_FTEXT | %3d | 0 " , length ); 36 } 37 # endif 38 p2string( string ); 39 } 40 41 int 42 str4len( string ) 43 char *string; 44 { 45 46 return ( ( strlen( string ) + 3 ) / 4 ); 47 } 48 49 /* 50 * put formatted text into a buffer for printing to the pcstream. 51 * a call to putpflush actually puts out the text. 52 * none of arg1 .. arg5 need be present. 53 * and you can add more if you need them. 54 */ 55 /* VARARGS */ 56 putprintf( format , incomplete , arg1 , arg2 , arg3 , arg4 , arg5 ) 57 char *format; 58 int incomplete; 59 { 60 static char ppbuffer[ BUFSIZ ]; 61 static char *ppbufp = ppbuffer; 62 63 if ( !CGENNING ) 64 return; 65 sprintf( ppbufp , format , arg1 , arg2 , arg3 , arg4 , arg5 ); 66 ppbufp = &( ppbuffer[ strlen( ppbuffer ) ] ); 67 if ( ppbufp >= &( ppbuffer[ BUFSIZ ] ) ) 68 panic( "putprintf" ); 69 if ( ! incomplete ) { 70 puttext( ppbuffer ); 71 ppbufp = ppbuffer; 72 } 73 } 74 75 /* 76 * emit a left bracket operator to pcstream 77 * with function number, the maximum temp register, and total local bytes 78 */ 79 putlbracket(ftnno, sizesp) 80 int ftnno; 81 struct om *sizesp; 82 { 83 int maxtempreg; 84 int alignedframesize; 85 86 # ifdef vax 87 maxtempreg = sizesp->curtmps.next_avail[REG_GENERAL]; 88 # endif vax 89 # ifdef mc68000 90 /* 91 * this is how /lib/f1 wants it. 92 */ 93 maxtempreg = (sizesp->curtmps.next_avail[REG_ADDR] << 4) 94 | (sizesp->curtmps.next_avail[REG_DATA]); 95 # endif mc68000 96 alignedframesize = roundup((int)(BITSPERBYTE * -sizesp->curtmps.om_off), 97 (long)(BITSPERBYTE * A_STACK)); 98 p2word( PCCM_TRIPLE( PCCF_FLBRAC , maxtempreg , ftnno ) ); 99 p2word(alignedframesize); 100 # ifdef DEBUG 101 if ( opt( 'k' ) ) { 102 fprintf(stdout, "PCCF_FLBRAC | %3d | %d %d\n", 103 maxtempreg, ftnno, alignedframesize); 104 } 105 # endif 106 } 107 108 /* 109 * emit a right bracket operator 110 * which for the binary interface 111 * forces the stack allocate and register mask 112 */ 113 putrbracket( ftnno ) 114 int ftnno; 115 { 116 117 p2word( PCCM_TRIPLE( PCCF_FRBRAC , 0 , ftnno ) ); 118 # ifdef DEBUG 119 if ( opt( 'k' ) ) { 120 fprintf( stdout , "PCCF_FRBRAC | 0 | %d\n" , ftnno ); 121 } 122 # endif 123 } 124 125 /* 126 * emit an eof operator 127 */ 128 puteof() 129 { 130 131 p2word( PCCF_FEOF ); 132 # ifdef DEBUG 133 if ( opt( 'k' ) ) { 134 fprintf( stdout , "PCCF_FEOF\n" ); 135 } 136 # endif 137 } 138 139 /* 140 * emit a dot operator, 141 * with a source file line number and name 142 * if line is negative, there was an error on that line, but who cares? 143 */ 144 putdot( filename , line ) 145 char *filename; 146 int line; 147 { 148 int length = str4len( filename ); 149 150 if ( line < 0 ) { 151 line = -line; 152 } 153 p2word( PCCM_TRIPLE( PCCF_FEXPR , length , line ) ); 154 # ifdef DEBUG 155 if ( opt( 'k' ) ) { 156 fprintf( stdout , "PCCF_FEXPR | %3d | %d " , length , line ); 157 } 158 # endif 159 p2string( filename ); 160 } 161 162 /* 163 * put out a leaf node 164 */ 165 putleaf( op , lval , rval , type , name ) 166 int op; 167 int lval; 168 int rval; 169 int type; 170 char *name; 171 { 172 if ( !CGENNING ) 173 return; 174 switch ( op ) { 175 default: 176 panic( "[putleaf]" ); 177 case PCC_ICON: 178 p2word( PCCM_TRIPLE( PCC_ICON , name != NIL , type ) ); 179 p2word( lval ); 180 # ifdef DEBUG 181 if ( opt( 'k' ) ) { 182 fprintf( stdout , "PCC_ICON | %3d | 0x%x " 183 , name != NIL , type ); 184 fprintf( stdout , "%d\n" , lval ); 185 } 186 # endif 187 if ( name ) 188 p2name( name ); 189 break; 190 case PCC_NAME: 191 p2word( PCCM_TRIPLE( PCC_NAME , lval != 0 , type ) ); 192 if ( lval ) 193 p2word( lval ); 194 # ifdef DEBUG 195 if ( opt( 'k' ) ) { 196 fprintf( stdout , "PCC_NAME | %3d | 0x%x " 197 , lval != 0 , type ); 198 if ( lval ) 199 fprintf( stdout , "%d " , lval ); 200 } 201 # endif 202 p2name( name ); 203 break; 204 case PCC_REG: 205 p2word( PCCM_TRIPLE( PCC_REG , rval , type ) ); 206 # ifdef DEBUG 207 if ( opt( 'k' ) ) { 208 fprintf( stdout , "PCC_REG | %3d | 0x%x\n" , 209 rval , type ); 210 } 211 # endif 212 break; 213 } 214 } 215 216 /* 217 * rvalues are just lvalues with indirection, except 218 * special cases for registers and for named globals, 219 * whose names are their rvalues. 220 */ 221 putRV( name , level , offset , other_flags , type ) 222 char *name; 223 int level; 224 int offset; 225 char other_flags; 226 int type; 227 { 228 char extname[ BUFSIZ ]; 229 char *printname; 230 231 if ( !CGENNING ) 232 return; 233 if ( other_flags & NREGVAR ) { 234 if ( ( offset < 0 ) || ( offset > P2FP ) ) { 235 panic( "putRV regvar" ); 236 } 237 putleaf( PCC_REG , 0 , offset , type , (char *) 0 ); 238 return; 239 } 240 if ( whereis( offset , other_flags ) == GLOBALVAR ) { 241 if ( name != 0 ) { 242 if ( name[0] != '_' ) { 243 sprintf( extname , EXTFORMAT , name ); 244 printname = extname; 245 } else { 246 printname = name; 247 } 248 putleaf( PCC_NAME , offset , 0 , type , printname ); 249 return; 250 } else { 251 panic( "putRV no name" ); 252 } 253 } 254 putLV( name , level , offset , other_flags , type ); 255 putop( PCCOM_UNARY PCC_MUL , type ); 256 } 257 258 /* 259 * put out an lvalue 260 * given a level and offset 261 * special case for 262 * named globals, whose lvalues are just their names as constants. 263 */ 264 putLV( name , level , offset , other_flags , type ) 265 char *name; 266 int level; 267 int offset; 268 char other_flags; 269 int type; 270 { 271 char extname[ BUFSIZ ]; 272 char *printname; 273 274 if ( !CGENNING ) 275 return; 276 if ( other_flags & NREGVAR ) { 277 panic( "putLV regvar" ); 278 } 279 switch ( whereis( offset , other_flags ) ) { 280 case GLOBALVAR: 281 if ( ( name != 0 ) ) { 282 if ( name[0] != '_' ) { 283 sprintf( extname , EXTFORMAT , name ); 284 printname = extname; 285 } else { 286 printname = name; 287 } 288 putleaf( PCC_ICON , offset , 0 , PCCM_ADDTYPE( type , PCCTM_PTR ) 289 , printname ); 290 return; 291 } else { 292 panic( "putLV no name" ); 293 } 294 case PARAMVAR: 295 if ( level == cbn ) { 296 putleaf( PCC_REG, 0, P2AP, PCCM_ADDTYPE( type , PCCTM_PTR ), (char *) 0 ); 297 } else { 298 putleaf( PCC_NAME , (level * sizeof(struct dispsave)) + AP_OFFSET 299 , 0 , PCCTM_PTR | PCCT_CHAR , DISPLAYNAME ); 300 parts[ level ] |= NONLOCALVAR; 301 } 302 putleaf( PCC_ICON , offset , 0 , PCCT_INT , (char *) 0 ); 303 putop( PCC_PLUS , PCCTM_PTR | PCCT_CHAR ); 304 break; 305 case LOCALVAR: 306 if ( level == cbn ) { 307 putleaf( PCC_REG, 0, P2FP, PCCM_ADDTYPE( type , PCCTM_PTR ), (char *) 0 ); 308 } else { 309 putleaf( PCC_NAME , (level * sizeof(struct dispsave)) + FP_OFFSET 310 , 0 , PCCTM_PTR | PCCT_CHAR , DISPLAYNAME ); 311 parts[ level ] |= NONLOCALVAR; 312 } 313 putleaf( PCC_ICON , -offset , 0 , PCCT_INT , (char *) 0 ); 314 putop( PCC_MINUS , PCCTM_PTR | PCCT_CHAR ); 315 break; 316 case NAMEDLOCALVAR: 317 if ( level == cbn ) { 318 putleaf( PCC_REG, 0, P2FP, PCCM_ADDTYPE( type , PCCTM_PTR ), (char *) 0 ); 319 } else { 320 putleaf( PCC_NAME , (level * sizeof(struct dispsave)) + FP_OFFSET 321 , 0 , PCCTM_PTR | PCCT_CHAR , DISPLAYNAME ); 322 parts[ level ] |= NONLOCALVAR; 323 } 324 putleaf( PCC_ICON , 0 , 0 , PCCT_INT , name ); 325 putop( PCC_MINUS , PCCTM_PTR | PCCT_CHAR ); 326 break; 327 } 328 return; 329 } 330 331 /* 332 * put out a floating point constant leaf node 333 * the constant is declared in aligned data space 334 * and a PCC_NAME leaf put out for it 335 */ 336 putCON8( val ) 337 double val; 338 { 339 char *label; 340 char name[ BUFSIZ ]; 341 342 if ( !CGENNING ) 343 return; 344 label = getlab(); 345 putprintf( " .data" , 0 ); 346 aligndot(A_DOUBLE); 347 (void) putlab( label ); 348 # ifdef vax 349 putprintf( " .double 0d%.20e" , 0 , val ); 350 # endif vax 351 # ifdef mc68000 352 putprintf( " .long 0x%x,0x%x", 0, val); 353 # endif mc68000 354 putprintf( " .text" , 0 ); 355 sprintf( name , PREFIXFORMAT , LABELPREFIX , label ); 356 putleaf( PCC_NAME , 0 , 0 , PCCT_DOUBLE , name ); 357 } 358 359 /* 360 * put out either an lvalue or an rvalue for a constant string. 361 * an lvalue (for assignment rhs's) is the name as a constant, 362 * an rvalue (for parameters) is just the name. 363 */ 364 putCONG( string , length , required ) 365 char *string; 366 int length; 367 int required; 368 { 369 char name[ BUFSIZ ]; 370 char *label; 371 char *cp; 372 int pad; 373 int others; 374 375 if ( !CGENNING ) 376 return; 377 putprintf( " .data" , 0 ); 378 aligndot(A_STRUCT); 379 label = getlab(); 380 (void) putlab( label ); 381 cp = string; 382 while ( *cp ) { 383 putprintf( " .byte 0%o" , 1 , *cp ++ ); 384 for ( others = 2 ; ( others <= 8 ) && *cp ; others ++ ) { 385 putprintf( ",0%o" , 1 , *cp++ ); 386 } 387 putprintf( "" , 0 ); 388 } 389 pad = length - strlen( string ); 390 while ( pad-- > 0 ) { 391 putprintf( " .byte 0%o" , 1 , ' ' ); 392 for ( others = 2 ; ( others <= 8 ) && ( pad-- > 0 ) ; others++ ) { 393 putprintf( ",0%o" , 1 , ' ' ); 394 } 395 putprintf( "" , 0 ); 396 } 397 putprintf( " .byte 0" , 0 ); 398 putprintf( " .text" , 0 ); 399 sprintf( name , PREFIXFORMAT , LABELPREFIX , label ); 400 if ( required == RREQ ) { 401 putleaf( PCC_NAME , 0 , 0 , PCCTM_ARY | PCCT_CHAR , name ); 402 } else { 403 putleaf( PCC_ICON , 0 , 0 , PCCTM_PTR | PCCT_CHAR , name ); 404 } 405 } 406 407 /* 408 * map a pascal type to a c type 409 * this would be tail recursive, but i unfolded it into a for (;;). 410 * this is sort of like isa and lwidth 411 * a note on the types used by the portable c compiler: 412 * they are divided into a basic type (char, short, int, long, etc.) 413 * and qualifications on those basic types (pointer, function, array). 414 * the basic type is kept in the low 4 bits of the type descriptor, 415 * and the qualifications are arranged in two bit chunks, with the 416 * most significant on the right, 417 * and the least significant on the left 418 * e.g. int *foo(); 419 * (a function returning a pointer to an integer) 420 * is stored as 421 * <ptr><ftn><int> 422 * so, we build types recursively 423 * also, we know that /lib/f1 can only deal with 6 qualifications 424 * so we stop the recursion there. this stops infinite type recursion 425 * through mutually recursive pointer types. 426 */ 427 #define MAXQUALS 6 428 int 429 p2type( np ) 430 struct nl *np; 431 { 432 433 return typerecur( np , 0 ); 434 } 435 typerecur( np , quals ) 436 struct nl *np; 437 int quals; 438 { 439 440 if ( np == NIL || quals > MAXQUALS ) { 441 return PCCT_UNDEF; 442 } 443 switch ( np -> class ) { 444 case SCAL : 445 case RANGE : 446 case CRANGE : 447 if ( np -> type == ( nl + TDOUBLE ) ) { 448 return PCCT_DOUBLE; 449 } 450 switch ( bytes( np -> range[0] , np -> range[1] ) ) { 451 case 1: 452 return PCCT_CHAR; 453 case 2: 454 return PCCT_SHORT; 455 case 4: 456 return PCCT_INT; 457 default: 458 panic( "p2type int" ); 459 /* NOTREACHED */ 460 } 461 case STR : 462 return ( PCCTM_ARY | PCCT_CHAR ); 463 case RECORD : 464 case SET : 465 return PCCT_STRTY; 466 case FILET : 467 return ( PCCTM_PTR | PCCT_STRTY ); 468 case CONST : 469 case VAR : 470 case FIELD : 471 return p2type( np -> type ); 472 case TYPE : 473 switch ( nloff( np ) ) { 474 case TNIL : 475 return ( PCCTM_PTR | PCCT_UNDEF ); 476 case TSTR : 477 return ( PCCTM_ARY | PCCT_CHAR ); 478 case TSET : 479 return PCCT_STRTY; 480 default : 481 return ( p2type( np -> type ) ); 482 } 483 case REF: 484 case WITHPTR: 485 case PTR : 486 return PCCM_ADDTYPE( typerecur( np -> type , quals + 1 ) , PCCTM_PTR ); 487 case ARRAY : 488 return PCCM_ADDTYPE( typerecur( np -> type , quals + 1 ) , PCCTM_ARY ); 489 case FUNC : 490 /* 491 * functions are really pointers to functions 492 * which return their underlying type. 493 */ 494 return PCCM_ADDTYPE( PCCM_ADDTYPE( typerecur( np -> type , quals + 2 ) , 495 PCCTM_FTN ) , PCCTM_PTR ); 496 case PROC : 497 /* 498 * procedures are pointers to functions 499 * which return integers (whether you look at them or not) 500 */ 501 return PCCM_ADDTYPE( PCCM_ADDTYPE( PCCT_INT , PCCTM_FTN ) , PCCTM_PTR ); 502 case FFUNC : 503 case FPROC : 504 /* 505 * formal procedures and functions are pointers 506 * to structures which describe their environment. 507 */ 508 return ( PCCTM_PTR | PCCT_STRTY ); 509 default : 510 panic( "p2type" ); 511 /* NOTREACHED */ 512 } 513 } 514 515 /* 516 * put a typed operator to the pcstream 517 */ 518 putop( op , type ) 519 int op; 520 int type; 521 { 522 extern char *p2opname(); 523 524 if ( !CGENNING ) 525 return; 526 p2word( PCCM_TRIPLE( op , 0 , type ) ); 527 # ifdef DEBUG 528 if ( opt( 'k' ) ) { 529 fprintf( stdout , "%s (%d) | 0 | 0x%x\n" 530 , p2opname( op ) , op , type ); 531 } 532 # endif 533 } 534 535 /* 536 * put out a structure operator (STASG, STARG, STCALL, UNARY STCALL ) 537 * which looks just like a regular operator, only the size and 538 * alignment go in the next consecutive words 539 */ 540 putstrop( op , type , size , alignment ) 541 int op; 542 int type; 543 int size; 544 int alignment; 545 { 546 extern char *p2opname(); 547 548 if ( !CGENNING ) 549 return; 550 p2word( PCCM_TRIPLE( op , 0 , type ) ); 551 p2word( size ); 552 p2word( alignment ); 553 # ifdef DEBUG 554 if ( opt( 'k' ) ) { 555 fprintf( stdout , "%s (%d) | 0 | 0x%x %d %d\n" 556 , p2opname( op ) , op , type , size , alignment ); 557 } 558 # endif 559 } 560 561 /* 562 * the string names of p2ops 563 */ 564 565 struct p2op { 566 int op; 567 char *name; 568 }; 569 570 static struct p2op p2opnames[] = { 571 PCC_ERROR, "PCC_ERROR", 572 PCC_NAME, "PCC_NAME", 573 PCC_STRING, "PCC_STRING", 574 PCC_ICON, "PCC_ICON", 575 PCC_FCON, "PCC_FCON", 576 PCC_PLUS, "PCC_PLUS", 577 PCC_MINUS, "PCC_MINUS", 578 PCC_UMINUS, "PCC_UMINUS", 579 PCC_MUL, "PCC_MUL", 580 PCC_DEREF, "PCC_DEREF", 581 PCC_AND, "PCC_AND", 582 PCC_ADDROF, "PCC_ADDROF", 583 PCC_OR, "PCC_OR", 584 PCC_ER, "PCC_ER", 585 PCC_QUEST, "PCC_QUEST", 586 PCC_COLON, "PCC_COLON", 587 PCC_ANDAND, "PCC_ANDAND", 588 PCC_OROR, "PCC_OROR", 589 PCC_CM, "PCC_CM", 590 PCC_ASSIGN, "PCC_ASSIGN", 591 PCC_COMOP, "PCC_COMOP", 592 PCC_DIV, "PCC_DIV", 593 PCC_MOD, "PCC_MOD", 594 PCC_LS, "PCC_LS", 595 PCC_RS, "PCC_RS", 596 PCC_DOT, "PCC_DOT", 597 PCC_STREF, "PCC_STREF", 598 PCC_CALL, "PCC_CALL", 599 PCC_UCALL, "PCC_UCALL", 600 PCC_FORTCALL, "PCC_FORTCALL", 601 PCC_UFORTCALL, "PCC_UFORTCALL", 602 PCC_NOT, "PCC_NOT", 603 PCC_COMPL, "PCC_COMPL", 604 PCC_INCR, "PCC_INCR", 605 PCC_DECR, "PCC_DECR", 606 PCC_EQ, "PCC_EQ", 607 PCC_NE, "PCC_NE", 608 PCC_LE, "PCC_LE", 609 PCC_LT, "PCC_LT", 610 PCC_GE, "PCC_GE", 611 PCC_GT, "PCC_GT", 612 PCC_ULE, "PCC_ULE", 613 PCC_ULT, "PCC_ULT", 614 PCC_UGE, "PCC_UGE", 615 PCC_UGT, "PCC_UGT", 616 PCC_REG, "PCC_REG", 617 PCC_OREG, "PCC_OREG", 618 PCC_CCODES, "PCC_CCODES", 619 PCC_FREE, "PCC_FREE", 620 PCC_STASG, "PCC_STASG", 621 PCC_STARG, "PCC_STARG", 622 PCC_STCALL, "PCC_STCALL", 623 PCC_USTCALL, "PCC_USTCALL", 624 PCC_FLD, "PCC_FLD", 625 PCC_SCONV, "PCC_SCONV", 626 PCC_PCONV, "PCC_PCONV", 627 PCC_PMCONV, "PCC_PMCONV", 628 PCC_PVCONV, "PCC_PVCONV", 629 PCC_FORCE, "PCC_FORCE", 630 PCC_CBRANCH, "PCC_CBRANCH", 631 PCC_INIT, "PCC_INIT", 632 PCC_CAST, "PCC_CAST", 633 -1, "" 634 }; 635 636 char * 637 p2opname( op ) 638 register int op; 639 { 640 static char *p2map[PCC_MAXOP+1]; 641 static bool mapready = FALSE; 642 register struct p2op *pp; 643 644 if ( mapready == FALSE ) { 645 for ( pp = p2opnames; pp->op >= 0; pp++ ) 646 p2map[ pp->op ] = pp->name; 647 mapready = TRUE; 648 } 649 return ( p2map[ op ] ? p2map[ op ] : "unknown" ); 650 } 651 652 /* 653 * low level routines 654 */ 655 656 /* 657 * puts a long word on the pcstream 658 */ 659 p2word( word ) 660 int word; 661 { 662 663 putw( word , pcstream ); 664 } 665 666 /* 667 * put a length 0 mod 4 null padded string onto the pcstream 668 */ 669 p2string( string ) 670 char *string; 671 { 672 int slen = strlen( string ); 673 int wlen = ( slen + 3 ) / 4; 674 int plen = ( wlen * 4 ) - slen; 675 char *cp; 676 int p; 677 678 for ( cp = string ; *cp ; cp++ ) 679 putc( *cp , pcstream ); 680 for ( p = 1 ; p <= plen ; p++ ) 681 putc( '\0' , pcstream ); 682 # ifdef DEBUG 683 if ( opt( 'k' ) ) { 684 fprintf( stdout , "\"%s" , string ); 685 for ( p = 1 ; p <= plen ; p++ ) 686 fprintf( stdout , "\\0" ); 687 fprintf( stdout , "\"\n" ); 688 } 689 # endif 690 } 691 692 /* 693 * puts a name on the pcstream 694 */ 695 p2name( name ) 696 char *name; 697 { 698 int pad; 699 700 fprintf( pcstream , NAMEFORMAT , name ); 701 pad = strlen( name ) % sizeof (long); 702 for ( ; pad < sizeof (long) ; pad++ ) { 703 putc( '\0' , pcstream ); 704 } 705 # ifdef DEBUG 706 if ( opt( 'k' ) ) { 707 fprintf( stdout , NAMEFORMAT , name ); 708 pad = strlen( name ) % sizeof (long); 709 for ( ; pad < sizeof (long) ; pad++ ) { 710 fprintf( stdout , "\\0" ); 711 } 712 fprintf( stdout , "\n" ); 713 } 714 # endif 715 } 716 717 /* 718 * put out a jump to a label 719 */ 720 putjbr( label ) 721 long label; 722 { 723 724 printjbr( LABELPREFIX , label ); 725 } 726 727 /* 728 * put out a jump to any kind of label 729 */ 730 printjbr( prefix , label ) 731 char *prefix; 732 long label; 733 { 734 735 # ifdef vax 736 putprintf( " jbr " , 1 ); 737 putprintf( PREFIXFORMAT , 0 , prefix , label ); 738 # endif vax 739 # ifdef mc68000 740 putprintf( " jra " , 1 ); 741 putprintf( PREFIXFORMAT , 0 , prefix , label ); 742 # endif mc68000 743 } 744 745 /* 746 * another version of put to catch calls to put 747 */ 748 /* VARARGS */ 749 put() 750 { 751 752 panic("put()"); 753 } 754 755 #endif PC 756