/* * Copyright (c) 1980 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #ifndef lint static char sccsid[] = "@(#)p2put.c 5.3 (Berkeley) 6/21/85"; #endif not lint /* * functions to help pi put out * polish postfix binary portable c compiler intermediate code * thereby becoming the portable pascal compiler */ #include "whoami.h" #ifdef PC #include "0.h" #include "objfmt.h" #include #include "pc.h" #include "align.h" #include "tmps.h" /* * emits an ftext operator and a string to the pcstream */ puttext( string ) char *string; { int length = str4len( string ); if ( !CGENNING ) return; p2word( PCCM_TRIPLE( PCCF_FTEXT , length , 0 ) ); # ifdef DEBUG if ( opt( 'k' ) ) { fprintf( stdout , "PCCF_FTEXT | %3d | 0 " , length ); } # endif p2string( string ); } int str4len( string ) char *string; { return ( ( strlen( string ) + 3 ) / 4 ); } /* * put formatted text into a buffer for printing to the pcstream. * a call to putpflush actually puts out the text. * none of arg1 .. arg5 need be present. * and you can add more if you need them. */ /* VARARGS */ putprintf( format , incomplete , arg1 , arg2 , arg3 , arg4 , arg5 ) char *format; int incomplete; { static char ppbuffer[ BUFSIZ ]; static char *ppbufp = ppbuffer; if ( !CGENNING ) return; sprintf( ppbufp , format , arg1 , arg2 , arg3 , arg4 , arg5 ); ppbufp = &( ppbuffer[ strlen( ppbuffer ) ] ); if ( ppbufp >= &( ppbuffer[ BUFSIZ ] ) ) panic( "putprintf" ); if ( ! incomplete ) { puttext( ppbuffer ); ppbufp = ppbuffer; } } /* * emit a left bracket operator to pcstream * with function number, the maximum temp register, and total local bytes */ putlbracket(ftnno, sizesp) int ftnno; struct om *sizesp; { int maxtempreg; int alignedframesize; # ifdef vax maxtempreg = sizesp->curtmps.next_avail[REG_GENERAL]; # endif vax # ifdef mc68000 /* * this is how /lib/f1 wants it. */ maxtempreg = (sizesp->curtmps.next_avail[REG_ADDR] << 4) | (sizesp->curtmps.next_avail[REG_DATA]); # endif mc68000 alignedframesize = roundup((int)(BITSPERBYTE * -sizesp->curtmps.om_off), (long)(BITSPERBYTE * A_STACK)); p2word( PCCM_TRIPLE( PCCF_FLBRAC , maxtempreg , ftnno ) ); p2word(alignedframesize); # ifdef DEBUG if ( opt( 'k' ) ) { fprintf(stdout, "PCCF_FLBRAC | %3d | %d %d\n", maxtempreg, ftnno, alignedframesize); } # endif } /* * emit a right bracket operator * which for the binary interface * forces the stack allocate and register mask */ putrbracket( ftnno ) int ftnno; { p2word( PCCM_TRIPLE( PCCF_FRBRAC , 0 , ftnno ) ); # ifdef DEBUG if ( opt( 'k' ) ) { fprintf( stdout , "PCCF_FRBRAC | 0 | %d\n" , ftnno ); } # endif } /* * emit an eof operator */ puteof() { p2word( PCCF_FEOF ); # ifdef DEBUG if ( opt( 'k' ) ) { fprintf( stdout , "PCCF_FEOF\n" ); } # endif } /* * emit a dot operator, * with a source file line number and name * if line is negative, there was an error on that line, but who cares? */ putdot( filename , line ) char *filename; int line; { int length = str4len( filename ); if ( line < 0 ) { line = -line; } p2word( PCCM_TRIPLE( PCCF_FEXPR , length , line ) ); # ifdef DEBUG if ( opt( 'k' ) ) { fprintf( stdout , "PCCF_FEXPR | %3d | %d " , length , line ); } # endif p2string( filename ); } /* * put out a leaf node */ putleaf( op , lval , rval , type , name ) int op; int lval; int rval; int type; char *name; { if ( !CGENNING ) return; switch ( op ) { default: panic( "[putleaf]" ); case PCC_ICON: p2word( PCCM_TRIPLE( PCC_ICON , name != NIL , type ) ); p2word( lval ); # ifdef DEBUG if ( opt( 'k' ) ) { fprintf( stdout , "PCC_ICON | %3d | 0x%x " , name != NIL , type ); fprintf( stdout , "%d\n" , lval ); } # endif if ( name ) p2name( name ); break; case PCC_NAME: p2word( PCCM_TRIPLE( PCC_NAME , lval != 0 , type ) ); if ( lval ) p2word( lval ); # ifdef DEBUG if ( opt( 'k' ) ) { fprintf( stdout , "PCC_NAME | %3d | 0x%x " , lval != 0 , type ); if ( lval ) fprintf( stdout , "%d " , lval ); } # endif p2name( name ); break; case PCC_REG: p2word( PCCM_TRIPLE( PCC_REG , rval , type ) ); # ifdef DEBUG if ( opt( 'k' ) ) { fprintf( stdout , "PCC_REG | %3d | 0x%x\n" , rval , type ); } # endif break; } } /* * rvalues are just lvalues with indirection, except * special cases for registers and for named globals, * whose names are their rvalues. */ putRV( name , level , offset , other_flags , type ) char *name; int level; int offset; char other_flags; int type; { char extname[ BUFSIZ ]; char *printname; if ( !CGENNING ) return; if ( other_flags & NREGVAR ) { if ( ( offset < 0 ) || ( offset > P2FP ) ) { panic( "putRV regvar" ); } putleaf( PCC_REG , 0 , offset , type , (char *) 0 ); return; } if ( whereis( offset , other_flags ) == GLOBALVAR ) { if ( name != 0 ) { if ( name[0] != '_' ) { sprintf( extname , EXTFORMAT , name ); printname = extname; } else { printname = name; } putleaf( PCC_NAME , offset , 0 , type , printname ); return; } else { panic( "putRV no name" ); } } putLV( name , level , offset , other_flags , type ); putop( PCCOM_UNARY PCC_MUL , type ); } /* * put out an lvalue * given a level and offset * special case for * named globals, whose lvalues are just their names as constants. */ putLV( name , level , offset , other_flags , type ) char *name; int level; int offset; char other_flags; int type; { char extname[ BUFSIZ ]; char *printname; if ( !CGENNING ) return; if ( other_flags & NREGVAR ) { panic( "putLV regvar" ); } switch ( whereis( offset , other_flags ) ) { case GLOBALVAR: if ( ( name != 0 ) ) { if ( name[0] != '_' ) { sprintf( extname , EXTFORMAT , name ); printname = extname; } else { printname = name; } putleaf( PCC_ICON , offset , 0 , PCCM_ADDTYPE( type , PCCTM_PTR ) , printname ); return; } else { panic( "putLV no name" ); } case PARAMVAR: if ( level == cbn ) { putleaf( PCC_REG, 0, P2AP, PCCM_ADDTYPE( type , PCCTM_PTR ), (char *) 0 ); } else { putleaf( PCC_NAME , (level * sizeof(struct dispsave)) + AP_OFFSET , 0 , PCCTM_PTR | PCCT_CHAR , DISPLAYNAME ); parts[ level ] |= NONLOCALVAR; } putleaf( PCC_ICON , offset , 0 , PCCT_INT , (char *) 0 ); putop( PCC_PLUS , PCCTM_PTR | PCCT_CHAR ); break; case LOCALVAR: if ( level == cbn ) { putleaf( PCC_REG, 0, P2FP, PCCM_ADDTYPE( type , PCCTM_PTR ), (char *) 0 ); } else { putleaf( PCC_NAME , (level * sizeof(struct dispsave)) + FP_OFFSET , 0 , PCCTM_PTR | PCCT_CHAR , DISPLAYNAME ); parts[ level ] |= NONLOCALVAR; } putleaf( PCC_ICON , -offset , 0 , PCCT_INT , (char *) 0 ); putop( PCC_MINUS , PCCTM_PTR | PCCT_CHAR ); break; case NAMEDLOCALVAR: if ( level == cbn ) { putleaf( PCC_REG, 0, P2FP, PCCM_ADDTYPE( type , PCCTM_PTR ), (char *) 0 ); } else { putleaf( PCC_NAME , (level * sizeof(struct dispsave)) + FP_OFFSET , 0 , PCCTM_PTR | PCCT_CHAR , DISPLAYNAME ); parts[ level ] |= NONLOCALVAR; } putleaf( PCC_ICON , 0 , 0 , PCCT_INT , name ); putop( PCC_MINUS , PCCTM_PTR | PCCT_CHAR ); break; } return; } /* * put out a floating point constant leaf node * the constant is declared in aligned data space * and a PCC_NAME leaf put out for it */ putCON8( val ) double val; { char *label; char name[ BUFSIZ ]; if ( !CGENNING ) return; label = getlab(); putprintf( " .data" , 0 ); aligndot(A_DOUBLE); (void) putlab( label ); # ifdef vax putprintf( " .double 0d%.20e" , 0 , val ); # endif vax # ifdef mc68000 putprintf( " .long 0x%x,0x%x", 0, val); # endif mc68000 putprintf( " .text" , 0 ); sprintf( name , PREFIXFORMAT , LABELPREFIX , label ); putleaf( PCC_NAME , 0 , 0 , PCCT_DOUBLE , name ); } /* * put out either an lvalue or an rvalue for a constant string. * an lvalue (for assignment rhs's) is the name as a constant, * an rvalue (for parameters) is just the name. */ putCONG( string , length , required ) char *string; int length; int required; { char name[ BUFSIZ ]; char *label; char *cp; int pad; int others; if ( !CGENNING ) return; putprintf( " .data" , 0 ); aligndot(A_STRUCT); label = getlab(); (void) putlab( label ); cp = string; while ( *cp ) { putprintf( " .byte 0%o" , 1 , *cp ++ ); for ( others = 2 ; ( others <= 8 ) && *cp ; others ++ ) { putprintf( ",0%o" , 1 , *cp++ ); } putprintf( "" , 0 ); } pad = length - strlen( string ); while ( pad-- > 0 ) { putprintf( " .byte 0%o" , 1 , ' ' ); for ( others = 2 ; ( others <= 8 ) && ( pad-- > 0 ) ; others++ ) { putprintf( ",0%o" , 1 , ' ' ); } putprintf( "" , 0 ); } putprintf( " .byte 0" , 0 ); putprintf( " .text" , 0 ); sprintf( name , PREFIXFORMAT , LABELPREFIX , label ); if ( required == RREQ ) { putleaf( PCC_NAME , 0 , 0 , PCCTM_ARY | PCCT_CHAR , name ); } else { putleaf( PCC_ICON , 0 , 0 , PCCTM_PTR | PCCT_CHAR , name ); } } /* * map a pascal type to a c type * this would be tail recursive, but i unfolded it into a for (;;). * this is sort of like isa and lwidth * a note on the types used by the portable c compiler: * they are divided into a basic type (char, short, int, long, etc.) * and qualifications on those basic types (pointer, function, array). * the basic type is kept in the low 4 bits of the type descriptor, * and the qualifications are arranged in two bit chunks, with the * most significant on the right, * and the least significant on the left * e.g. int *foo(); * (a function returning a pointer to an integer) * is stored as * * so, we build types recursively * also, we know that /lib/f1 can only deal with 6 qualifications * so we stop the recursion there. this stops infinite type recursion * through mutually recursive pointer types. */ #define MAXQUALS 6 int p2type( np ) struct nl *np; { return typerecur( np , 0 ); } typerecur( np , quals ) struct nl *np; int quals; { if ( np == NIL || quals > MAXQUALS ) { return PCCT_UNDEF; } switch ( np -> class ) { case SCAL : case RANGE : case CRANGE : if ( np -> type == ( nl + TDOUBLE ) ) { return PCCT_DOUBLE; } switch ( bytes( np -> range[0] , np -> range[1] ) ) { case 1: return PCCT_CHAR; case 2: return PCCT_SHORT; case 4: return PCCT_INT; default: panic( "p2type int" ); /* NOTREACHED */ } case STR : return ( PCCTM_ARY | PCCT_CHAR ); case RECORD : case SET : return PCCT_STRTY; case FILET : return ( PCCTM_PTR | PCCT_STRTY ); case CONST : case VAR : case FIELD : return p2type( np -> type ); case TYPE : switch ( nloff( np ) ) { case TNIL : return ( PCCTM_PTR | PCCT_UNDEF ); case TSTR : return ( PCCTM_ARY | PCCT_CHAR ); case TSET : return PCCT_STRTY; default : return ( p2type( np -> type ) ); } case REF: case WITHPTR: case PTR : return PCCM_ADDTYPE( typerecur( np -> type , quals + 1 ) , PCCTM_PTR ); case ARRAY : return PCCM_ADDTYPE( typerecur( np -> type , quals + 1 ) , PCCTM_ARY ); case FUNC : /* * functions are really pointers to functions * which return their underlying type. */ return PCCM_ADDTYPE( PCCM_ADDTYPE( typerecur( np -> type , quals + 2 ) , PCCTM_FTN ) , PCCTM_PTR ); case PROC : /* * procedures are pointers to functions * which return integers (whether you look at them or not) */ return PCCM_ADDTYPE( PCCM_ADDTYPE( PCCT_INT , PCCTM_FTN ) , PCCTM_PTR ); case FFUNC : case FPROC : /* * formal procedures and functions are pointers * to structures which describe their environment. */ return ( PCCTM_PTR | PCCT_STRTY ); default : panic( "p2type" ); /* NOTREACHED */ } } /* * put a typed operator to the pcstream */ putop( op , type ) int op; int type; { extern char *p2opname(); if ( !CGENNING ) return; p2word( PCCM_TRIPLE( op , 0 , type ) ); # ifdef DEBUG if ( opt( 'k' ) ) { fprintf( stdout , "%s (%d) | 0 | 0x%x\n" , p2opname( op ) , op , type ); } # endif } /* * put out a structure operator (STASG, STARG, STCALL, UNARY STCALL ) * which looks just like a regular operator, only the size and * alignment go in the next consecutive words */ putstrop( op , type , size , alignment ) int op; int type; int size; int alignment; { extern char *p2opname(); if ( !CGENNING ) return; p2word( PCCM_TRIPLE( op , 0 , type ) ); p2word( size ); p2word( alignment ); # ifdef DEBUG if ( opt( 'k' ) ) { fprintf( stdout , "%s (%d) | 0 | 0x%x %d %d\n" , p2opname( op ) , op , type , size , alignment ); } # endif } /* * the string names of p2ops */ struct p2op { int op; char *name; }; static struct p2op p2opnames[] = { PCC_ERROR, "PCC_ERROR", PCC_NAME, "PCC_NAME", PCC_STRING, "PCC_STRING", PCC_ICON, "PCC_ICON", PCC_FCON, "PCC_FCON", PCC_PLUS, "PCC_PLUS", PCC_MINUS, "PCC_MINUS", PCC_UMINUS, "PCC_UMINUS", PCC_MUL, "PCC_MUL", PCC_DEREF, "PCC_DEREF", PCC_AND, "PCC_AND", PCC_ADDROF, "PCC_ADDROF", PCC_OR, "PCC_OR", PCC_ER, "PCC_ER", PCC_QUEST, "PCC_QUEST", PCC_COLON, "PCC_COLON", PCC_ANDAND, "PCC_ANDAND", PCC_OROR, "PCC_OROR", PCC_CM, "PCC_CM", PCC_ASSIGN, "PCC_ASSIGN", PCC_COMOP, "PCC_COMOP", PCC_DIV, "PCC_DIV", PCC_MOD, "PCC_MOD", PCC_LS, "PCC_LS", PCC_RS, "PCC_RS", PCC_DOT, "PCC_DOT", PCC_STREF, "PCC_STREF", PCC_CALL, "PCC_CALL", PCC_UCALL, "PCC_UCALL", PCC_FORTCALL, "PCC_FORTCALL", PCC_UFORTCALL, "PCC_UFORTCALL", PCC_NOT, "PCC_NOT", PCC_COMPL, "PCC_COMPL", PCC_INCR, "PCC_INCR", PCC_DECR, "PCC_DECR", PCC_EQ, "PCC_EQ", PCC_NE, "PCC_NE", PCC_LE, "PCC_LE", PCC_LT, "PCC_LT", PCC_GE, "PCC_GE", PCC_GT, "PCC_GT", PCC_ULE, "PCC_ULE", PCC_ULT, "PCC_ULT", PCC_UGE, "PCC_UGE", PCC_UGT, "PCC_UGT", PCC_REG, "PCC_REG", PCC_OREG, "PCC_OREG", PCC_CCODES, "PCC_CCODES", PCC_FREE, "PCC_FREE", PCC_STASG, "PCC_STASG", PCC_STARG, "PCC_STARG", PCC_STCALL, "PCC_STCALL", PCC_USTCALL, "PCC_USTCALL", PCC_FLD, "PCC_FLD", PCC_SCONV, "PCC_SCONV", PCC_PCONV, "PCC_PCONV", PCC_PMCONV, "PCC_PMCONV", PCC_PVCONV, "PCC_PVCONV", PCC_FORCE, "PCC_FORCE", PCC_CBRANCH, "PCC_CBRANCH", PCC_INIT, "PCC_INIT", PCC_CAST, "PCC_CAST", -1, "" }; char * p2opname( op ) register int op; { static char *p2map[PCC_MAXOP+1]; static bool mapready = FALSE; register struct p2op *pp; if ( mapready == FALSE ) { for ( pp = p2opnames; pp->op >= 0; pp++ ) p2map[ pp->op ] = pp->name; mapready = TRUE; } return ( p2map[ op ] ? p2map[ op ] : "unknown" ); } /* * low level routines */ /* * puts a long word on the pcstream */ p2word( word ) int word; { putw( word , pcstream ); } /* * put a length 0 mod 4 null padded string onto the pcstream */ p2string( string ) char *string; { int slen = strlen( string ); int wlen = ( slen + 3 ) / 4; int plen = ( wlen * 4 ) - slen; char *cp; int p; for ( cp = string ; *cp ; cp++ ) putc( *cp , pcstream ); for ( p = 1 ; p <= plen ; p++ ) putc( '\0' , pcstream ); # ifdef DEBUG if ( opt( 'k' ) ) { fprintf( stdout , "\"%s" , string ); for ( p = 1 ; p <= plen ; p++ ) fprintf( stdout , "\\0" ); fprintf( stdout , "\"\n" ); } # endif } /* * puts a name on the pcstream */ p2name( name ) char *name; { int pad; fprintf( pcstream , NAMEFORMAT , name ); pad = strlen( name ) % sizeof (long); for ( ; pad < sizeof (long) ; pad++ ) { putc( '\0' , pcstream ); } # ifdef DEBUG if ( opt( 'k' ) ) { fprintf( stdout , NAMEFORMAT , name ); pad = strlen( name ) % sizeof (long); for ( ; pad < sizeof (long) ; pad++ ) { fprintf( stdout , "\\0" ); } fprintf( stdout , "\n" ); } # endif } /* * put out a jump to a label */ putjbr( label ) long label; { printjbr( LABELPREFIX , label ); } /* * put out a jump to any kind of label */ printjbr( prefix , label ) char *prefix; long label; { # ifdef vax putprintf( " jbr " , 1 ); putprintf( PREFIXFORMAT , 0 , prefix , label ); # endif vax # ifdef mc68000 putprintf( " jra " , 1 ); putprintf( PREFIXFORMAT , 0 , prefix , label ); # endif mc68000 } /* * another version of put to catch calls to put */ /* VARARGS */ put() { panic("put()"); } #endif PC