1431 lines
		
	
	
	
		
			36 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1431 lines
		
	
	
	
		
			36 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /****************************************************************
 | |
| Copyright 1990, 1991 by AT&T Bell Laboratories and Bellcore.
 | |
| 
 | |
| Permission to use, copy, modify, and distribute this software
 | |
| and its documentation for any purpose and without fee is hereby
 | |
| granted, provided that the above copyright notice appear in all
 | |
| copies and that both that the copyright notice and this
 | |
| permission notice and warranty disclaimer appear in supporting
 | |
| documentation, and that the names of AT&T Bell Laboratories or
 | |
| Bellcore or any of their entities not be used in advertising or
 | |
| publicity pertaining to distribution of the software without
 | |
| specific, written prior permission.
 | |
| 
 | |
| AT&T and Bellcore disclaim all warranties with regard to this
 | |
| software, including all implied warranties of merchantability
 | |
| and fitness.  In no event shall AT&T or Bellcore be liable for
 | |
| any special, indirect or consequential damages or any damages
 | |
| whatsoever resulting from loss of use, data or profits, whether
 | |
| in an action of contract, negligence or other tortious action,
 | |
| arising out of or in connection with the use or performance of
 | |
| this software.
 | |
| ****************************************************************/
 | |
| 
 | |
| #include "defs.h"
 | |
| #include "names.h"
 | |
| #include "output.h"
 | |
| 
 | |
| #ifndef TRUE
 | |
| #define TRUE 1
 | |
| #endif
 | |
| #ifndef FALSE
 | |
| #define FALSE 0
 | |
| #endif
 | |
| 
 | |
| char _assoc_table[] = { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
 | |
| 
 | |
| /* Opcode table -- This array is indexed by the OP_____ macros defined in
 | |
|    defines.h; these macros are expected to be adjacent integers, so that
 | |
|    this table is as small as possible. */
 | |
| 
 | |
| table_entry opcode_table[] = {
 | |
| 				{ 0, 0, NULL },
 | |
| 	/* OPPLUS 1 */		{ BINARY_OP, 12, "%l + %r" },
 | |
| 	/* OPMINUS 2 */		{ BINARY_OP, 12, "%l - %r" },
 | |
| 	/* OPSTAR 3 */		{ BINARY_OP, 13, "%l * %r" },
 | |
| 	/* OPSLASH 4 */		{ BINARY_OP, 13, "%l / %r" },
 | |
| 	/* OPPOWER 5 */		{ BINARY_OP,  0, "power (%l, %r)" },
 | |
| 	/* OPNEG 6 */		{ UNARY_OP,  14, "-%l" },
 | |
| 	/* OPOR 7 */		{ BINARY_OP,  4, "%l || %r" },
 | |
| 	/* OPAND 8 */		{ BINARY_OP,  5, "%l && %r" },
 | |
| 	/* OPEQV 9 */		{ BINARY_OP,  9, "%l == %r" },
 | |
| 	/* OPNEQV 10 */		{ BINARY_OP,  9, "%l != %r" },
 | |
| 	/* OPNOT 11 */		{ UNARY_OP,  14, "! %l" },
 | |
| 	/* OPCONCAT 12 */	{ BINARY_OP,  0, "concat (%l, %r)" },
 | |
| 	/* OPLT 13 */		{ BINARY_OP, 10, "%l < %r" },
 | |
| 	/* OPEQ 14 */		{ BINARY_OP,  9, "%l == %r" },
 | |
| 	/* OPGT 15 */		{ BINARY_OP, 10, "%l > %r" },
 | |
| 	/* OPLE 16 */		{ BINARY_OP, 10, "%l <= %r" },
 | |
| 	/* OPNE 17 */		{ BINARY_OP,  9, "%l != %r" },
 | |
| 	/* OPGE 18 */		{ BINARY_OP, 10, "%l >= %r" },
 | |
| 	/* OPCALL 19 */		{ BINARY_OP, 15, SPECIAL_FMT },
 | |
| 	/* OPCCALL 20 */	{ BINARY_OP, 15, SPECIAL_FMT },
 | |
| 
 | |
| /* Left hand side of an assignment cannot have outermost parens */
 | |
| 
 | |
| 	/* OPASSIGN 21 */	{ BINARY_OP,  2, "%l = %r" },
 | |
| 	/* OPPLUSEQ 22 */	{ BINARY_OP,  2, "%l += %r" },
 | |
| 	/* OPSTAREQ 23 */	{ BINARY_OP,  2, "%l *= %r" },
 | |
| 	/* OPCONV 24 */		{ BINARY_OP, 14, "%l" },
 | |
| 	/* OPLSHIFT 25 */	{ BINARY_OP, 11, "%l << %r" },
 | |
| 	/* OPMOD 26 */		{ BINARY_OP, 13, "%l %% %r" },
 | |
| 	/* OPCOMMA 27 */	{ BINARY_OP,  1, "%l, %r" },
 | |
| 
 | |
| /* Don't want to nest the colon operator in parens */
 | |
| 
 | |
| 	/* OPQUEST 28 */	{ BINARY_OP, 3, "%l ? %r" },
 | |
| 	/* OPCOLON 29 */	{ BINARY_OP, 3, "%l : %r" },
 | |
| 	/* OPABS 30 */		{ UNARY_OP,  0, "abs(%l)" },
 | |
| 	/* OPMIN 31 */		{ BINARY_OP,   0, SPECIAL_FMT },
 | |
| 	/* OPMAX 32 */		{ BINARY_OP,   0, SPECIAL_FMT },
 | |
| 	/* OPADDR 33 */		{ UNARY_OP, 14, "&%l" },
 | |
| 
 | |
| 	/* OPCOMMA_ARG 34 */	{ BINARY_OP, 15, SPECIAL_FMT },
 | |
| 	/* OPBITOR 35 */	{ BINARY_OP,  6, "%l | %r" },
 | |
| 	/* OPBITAND 36 */	{ BINARY_OP,  8, "%l & %r" },
 | |
| 	/* OPBITXOR 37 */	{ BINARY_OP,  7, "%l ^ %r" },
 | |
| 	/* OPBITNOT 38 */	{ UNARY_OP,  14, "~ %l" },
 | |
| 	/* OPRSHIFT 39 */	{ BINARY_OP, 11, "%l >> %r" },
 | |
| 
 | |
| /* This isn't quite right -- it doesn't handle arrays, for instance */
 | |
| 
 | |
| 	/* OPWHATSIN 40 */	{ UNARY_OP,  14, "*%l" },
 | |
| 	/* OPMINUSEQ 41 */	{ BINARY_OP,  2, "%l -= %r" },
 | |
| 	/* OPSLASHEQ 42 */	{ BINARY_OP,  2, "%l /= %r" },
 | |
| 	/* OPMODEQ 43 */	{ BINARY_OP,  2, "%l %%= %r" },
 | |
| 	/* OPLSHIFTEQ 44 */	{ BINARY_OP,  2, "%l <<= %r" },
 | |
| 	/* OPRSHIFTEQ 45 */	{ BINARY_OP,  2, "%l >>= %r" },
 | |
| 	/* OPBITANDEQ 46 */	{ BINARY_OP,  2, "%l &= %r" },
 | |
| 	/* OPBITXOREQ 47 */	{ BINARY_OP,  2, "%l ^= %r" },
 | |
| 	/* OPBITOREQ 48 */	{ BINARY_OP,  2, "%l |= %r" },
 | |
| 	/* OPPREINC 49 */	{ UNARY_OP,  14, "++%l" },
 | |
| 	/* OPPREDEC 50 */	{ UNARY_OP,  14, "--%l" },
 | |
| 	/* OPDOT 51 */		{ BINARY_OP, 15, "%l.%r" },
 | |
| 	/* OPARROW 52 */	{ BINARY_OP, 15, "%l -> %r"},
 | |
| 	/* OPNEG1 53 */		{ UNARY_OP,  14, "-%l" },
 | |
| 	/* OPDMIN 54 */		{ BINARY_OP, 0, "dmin(%l,%r)" },
 | |
| 	/* OPDMAX 55 */		{ BINARY_OP, 0, "dmax(%l,%r)" },
 | |
| 	/* OPASSIGNI 56 */	{ BINARY_OP,  2, "%l = &%r" },
 | |
| 	/* OPIDENTITY 57 */	{ UNARY_OP, 15, "%l" },
 | |
| 	/* OPCHARCAST 58 */	{ UNARY_OP, 14, "(char *)&%l" },
 | |
| 	/* OPDABS 59 */		{ UNARY_OP, 0, "dabs(%l)" },
 | |
| 	/* OPMIN2 60 */		{ BINARY_OP,   0, "min(%l,%r)" },
 | |
| 	/* OPMAX2 61 */		{ BINARY_OP,   0, "max(%l,%r)" },
 | |
| 
 | |
| /* kludge to imitate (under forcedouble) f77's bizarre treatement of OPNEG... */
 | |
| 
 | |
| 	/* OPNEG KLUDGE */	{ UNARY_OP,  14, "-(doublereal)%l" }
 | |
| }; /* opcode_table */
 | |
| 
 | |
| #define OPNEG_KLUDGE (sizeof(opcode_table)/sizeof(table_entry) - 1)
 | |
| 
 | |
| static char opeqable[sizeof(opcode_table)/sizeof(table_entry)];
 | |
| 
 | |
| 
 | |
| static void output_prim ();
 | |
| static void output_unary (), output_binary (), output_arg_list ();
 | |
| static void output_list (), output_literal ();
 | |
| 
 | |
| 
 | |
| void expr_out (fp, e)
 | |
| FILE *fp;
 | |
| expptr e;
 | |
| {
 | |
|     if (e == (expptr) NULL)
 | |
| 	return;
 | |
| 
 | |
|     switch (e -> tag) {
 | |
| 	case TNAME:	out_name (fp, (struct Nameblock *) e);
 | |
| 			return;
 | |
| 
 | |
| 	case TCONST:	out_const(fp, &e->constblock);
 | |
| 			goto end_out;
 | |
| 	case TEXPR:
 | |
| 	    		break;
 | |
| 
 | |
| 	case TADDR:	out_addr (fp, &(e -> addrblock));
 | |
| 			goto end_out;
 | |
| 
 | |
| 	case TPRIM:	warn ("expr_out: got TPRIM");
 | |
| 			output_prim (fp, &(e -> primblock));
 | |
| 			return;
 | |
| 
 | |
| 	case TLIST:	output_list (fp, &(e -> listblock));
 | |
|  end_out:		frexpr(e);
 | |
| 			return;
 | |
| 
 | |
| 	case TIMPLDO:	err ("expr_out: got TIMPLDO");
 | |
| 			return;
 | |
| 
 | |
| 	case TERROR:
 | |
| 	default:
 | |
| 			erri ("expr_out: bad tag '%d'", e -> tag);
 | |
|     } /* switch */
 | |
| 
 | |
| /* Now we know that the tag is TEXPR */
 | |
| 
 | |
| /* Optimize on simple expressions, such as "a = a + b" ==> "a += b" */
 | |
| 
 | |
|     if (e -> exprblock.opcode == OPASSIGN && e -> exprblock.rightp &&
 | |
| 	e -> exprblock.rightp -> tag == TEXPR) {
 | |
| 	int opcode;
 | |
| 
 | |
| 	opcode = e -> exprblock.rightp -> exprblock.opcode;
 | |
| 
 | |
| 	if (opeqable[opcode]) {
 | |
| 	    expptr leftp, rightp;
 | |
| 
 | |
| 	    if ((leftp = e -> exprblock.leftp) &&
 | |
| 		(rightp = e -> exprblock.rightp -> exprblock.leftp)) {
 | |
| 
 | |
| 		if (same_ident (leftp, rightp)) {
 | |
| 		    expptr temp = e -> exprblock.rightp;
 | |
| 
 | |
| 		    e -> exprblock.opcode = op_assign(opcode);
 | |
| 
 | |
| 		    e -> exprblock.rightp = temp -> exprblock.rightp;
 | |
| 		    temp->exprblock.rightp = 0;
 | |
| 		    frexpr(temp);
 | |
| 		} /* if same_ident (leftp, rightp) */
 | |
| 	    } /* if leftp && rightp */
 | |
| 	} /* if opcode == OPPLUS || */
 | |
|     } /* if e -> exprblock.opcode == OPASSIGN */
 | |
| 
 | |
| 
 | |
| /* Optimize on increment or decrement by 1 */
 | |
| 
 | |
|     {
 | |
| 	int opcode = e -> exprblock.opcode;
 | |
| 	expptr leftp = e -> exprblock.leftp;
 | |
| 	expptr rightp = e -> exprblock.rightp;
 | |
| 
 | |
| 	if (leftp && rightp && (leftp -> headblock.vstg == STGARG ||
 | |
| 		ISINT (leftp -> headblock.vtype)) &&
 | |
| 		(opcode == OPPLUSEQ || opcode == OPMINUSEQ) &&
 | |
| 		ISINT (rightp -> headblock.vtype) &&
 | |
| 		ISICON (e -> exprblock.rightp) &&
 | |
| 		(ISONE (e -> exprblock.rightp) ||
 | |
| 		e -> exprblock.rightp -> constblock.Const.ci == -1)) {
 | |
| 
 | |
| /* Allow for the '-1' constant value */
 | |
| 
 | |
| 	    if (!ISONE (e -> exprblock.rightp))
 | |
| 		opcode = (opcode == OPPLUSEQ) ? OPMINUSEQ : OPPLUSEQ;
 | |
| 
 | |
| /* replace the existing opcode */
 | |
| 
 | |
| 	    if (opcode == OPPLUSEQ)
 | |
| 		e -> exprblock.opcode = OPPREINC;
 | |
| 	    else
 | |
| 		e -> exprblock.opcode = OPPREDEC;
 | |
| 
 | |
| /* Free up storage used by the right hand side */
 | |
| 
 | |
| 	    frexpr (e -> exprblock.rightp);
 | |
| 	    e->exprblock.rightp = 0;
 | |
| 	} /* if opcode == OPPLUS */
 | |
|     } /* block */
 | |
| 
 | |
| 
 | |
|     if (is_unary_op (e -> exprblock.opcode))
 | |
| 	output_unary (fp, &(e -> exprblock));
 | |
|     else if (is_binary_op (e -> exprblock.opcode))
 | |
| 	output_binary (fp, &(e -> exprblock));
 | |
|     else
 | |
| 	erri ("expr_out: bad opcode '%d'", (int) e -> exprblock.opcode);
 | |
| 
 | |
|     free((char *)e);
 | |
| 
 | |
| } /* expr_out */
 | |
| 
 | |
| 
 | |
| void out_and_free_statement (outfile, expr)
 | |
| FILE *outfile;
 | |
| expptr expr;
 | |
| {
 | |
|     if (expr)
 | |
| 	expr_out (outfile, expr);
 | |
| 
 | |
|     nice_printf (outfile, ";\n");
 | |
| } /* out_and_free_statement */
 | |
| 
 | |
| 
 | |
| 
 | |
| int same_ident (left, right)
 | |
| expptr left, right;
 | |
| {
 | |
|     if (!left || !right)
 | |
| 	return 0;
 | |
| 
 | |
|     if (left -> tag == TNAME && right -> tag == TNAME && left == right)
 | |
| 	return 1;
 | |
| 
 | |
|     if (left -> tag == TADDR && right -> tag == TADDR &&
 | |
| 	    left -> addrblock.uname_tag == right -> addrblock.uname_tag)
 | |
| 	switch (left -> addrblock.uname_tag) {
 | |
| 	    case UNAM_NAME:
 | |
| 
 | |
| /* Check for array subscripts */
 | |
| 
 | |
| 		if (left -> addrblock.user.name -> vdim ||
 | |
| 			right -> addrblock.user.name -> vdim)
 | |
| 		    if (left -> addrblock.user.name !=
 | |
| 			    right -> addrblock.user.name ||
 | |
| 			    !same_expr (left -> addrblock.memoffset,
 | |
| 			    right -> addrblock.memoffset))
 | |
| 			return 0;
 | |
| 
 | |
| 		return same_ident ((expptr) (left -> addrblock.user.name),
 | |
| 			(expptr) right -> addrblock.user.name);
 | |
| 	    case UNAM_IDENT:
 | |
| 		return strcmp(left->addrblock.user.ident,
 | |
| 				right->addrblock.user.ident) == 0;
 | |
| 	    case UNAM_CHARP:
 | |
| 		return strcmp(left->addrblock.user.Charp,
 | |
| 				right->addrblock.user.Charp) == 0;
 | |
| 	    default:
 | |
| 	        return 0;
 | |
| 	} /* switch */
 | |
| 
 | |
|     if (left->tag == TEXPR && left->exprblock.opcode == OPWHATSIN
 | |
| 	&& right->tag == TEXPR && right->exprblock.opcode == OPWHATSIN)
 | |
| 		return same_ident(left->exprblock.leftp,
 | |
| 				 right->exprblock.leftp);
 | |
| 
 | |
|     return 0;
 | |
| } /* same_ident */
 | |
| 
 | |
|  static int
 | |
| samefpconst(c1, c2, n)
 | |
|  register Constp c1, c2;
 | |
|  register int n;
 | |
| {
 | |
| 	char *s1, *s2;
 | |
| 	if (!c1->vstg && !c2->vstg)
 | |
| 		return c1->Const.cd[n] == c2->Const.cd[n];
 | |
| 	s1 = c1->vstg ? c1->Const.cds[n] : dtos(c1->Const.cd[n]);
 | |
| 	s2 = c2->vstg ? c2->Const.cds[n] : dtos(c2->Const.cd[n]);
 | |
| 	return !strcmp(s1, s2);
 | |
| 	}
 | |
| 
 | |
|  static int
 | |
| sameconst(c1, c2)
 | |
|  register Constp c1, c2;
 | |
| {
 | |
| 	switch(c1->vtype) {
 | |
| 		case TYCOMPLEX:
 | |
| 		case TYDCOMPLEX:
 | |
| 			if (!samefpconst(c1,c2,1))
 | |
| 				return 0;
 | |
| 		case TYREAL:
 | |
| 		case TYDREAL:
 | |
| 			return samefpconst(c1,c2,0);
 | |
| 		case TYCHAR:
 | |
| 			return c1->Const.ccp1.blanks == c2->Const.ccp1.blanks
 | |
| 			    &&	   c1->vleng->constblock.Const.ci
 | |
| 				== c2->vleng->constblock.Const.ci
 | |
| 			    && !memcmp(c1->Const.ccp, c2->Const.ccp,
 | |
| 					(int)c1->vleng->constblock.Const.ci);
 | |
| 		case TYSHORT:
 | |
| 		case TYINT:
 | |
| 		case TYLOGICAL:
 | |
| 			return c1->Const.ci == c2->Const.ci;
 | |
| 		}
 | |
| 	err("unexpected type in sameconst");
 | |
| 	return 0;
 | |
| 	}
 | |
| 
 | |
| /* same_expr -- Returns true only if   e1 and e2   match.  This is
 | |
|    somewhat pessimistic, but can afford to be because it's just used to
 | |
|    optimize on the assignment operators (+=, -=, etc). */
 | |
| 
 | |
| int same_expr (e1, e2)
 | |
| expptr e1, e2;
 | |
| {
 | |
|     if (!e1 || !e2)
 | |
| 	return !e1 && !e2;
 | |
| 
 | |
|     if (e1 -> tag != e2 -> tag || e1 -> headblock.vtype != e2 -> headblock.vtype)
 | |
| 	return 0;
 | |
| 
 | |
|     switch (e1 -> tag) {
 | |
|         case TEXPR:
 | |
| 	    if (e1 -> exprblock.opcode != e2 -> exprblock.opcode)
 | |
| 		return 0;
 | |
| 
 | |
| 	    return same_expr (e1 -> exprblock.leftp, e2 -> exprblock.leftp) &&
 | |
| 		   same_expr (e1 -> exprblock.rightp, e2 -> exprblock.rightp);
 | |
| 	case TNAME:
 | |
| 	case TADDR:
 | |
| 	    return same_ident (e1, e2);
 | |
| 	case TCONST:
 | |
| 	    return sameconst(&e1->constblock, &e2->constblock);
 | |
| 	default:
 | |
| 	    return 0;
 | |
|     } /* switch */
 | |
| } /* same_expr */
 | |
| 
 | |
| 
 | |
| 
 | |
| void out_name (fp, namep)
 | |
|  FILE *fp;
 | |
|  Namep namep;
 | |
| {
 | |
|     extern int usedefsforcommon;
 | |
|     Extsym *comm;
 | |
| 
 | |
|     if (namep == NULL)
 | |
| 	return;
 | |
| 
 | |
| /* DON'T want to use oneof_stg() here; need to find the right common name
 | |
|    */
 | |
| 
 | |
|     if (namep->vstg == STGCOMMON && !namep->vcommequiv && !usedefsforcommon) {
 | |
| 	comm = &extsymtab[namep->vardesc.varno];
 | |
| 	extern_out(fp, comm);
 | |
| 	nice_printf(fp, "%d.", comm->curno);
 | |
|     } /* if namep -> vstg == STGCOMMON */
 | |
| 
 | |
|     if (namep->vprocclass == PTHISPROC && namep->vtype != TYSUBR)
 | |
| 	nice_printf(fp, xretslot[namep->vtype]->user.ident);
 | |
|     else
 | |
| 	nice_printf (fp, "%s", namep->cvarname);
 | |
| } /* out_name */
 | |
| 
 | |
| 
 | |
| static char *Longfmt = "%ld";
 | |
| 
 | |
| #define cpd(n) cp->vstg ? cp->Const.cds[n] : dtos(cp->Const.cd[n])
 | |
| 
 | |
| void out_const(fp, cp)
 | |
|  FILE *fp;
 | |
|  register Constp cp;
 | |
| {
 | |
|     static char real_buf[50], imag_buf[50];
 | |
|     unsigned int k;
 | |
|     int type = cp->vtype;
 | |
| 
 | |
|     switch (type) {
 | |
|         case TYSHORT:
 | |
| 	    nice_printf (fp, "%ld", cp->Const.ci);	/* don't cast ci! */
 | |
| 	    break;
 | |
| 	case TYLONG:
 | |
| 	    nice_printf (fp, Longfmt, cp->Const.ci);	/* don't cast ci! */
 | |
| 	    break;
 | |
| 	case TYREAL:
 | |
| 	    nice_printf(fp, "%s", flconst(real_buf, cpd(0)));
 | |
| 	    break;
 | |
| 	case TYDREAL:
 | |
| 	    nice_printf(fp, "%s", cpd(0));
 | |
| 	    break;
 | |
| 	case TYCOMPLEX:
 | |
| 	    nice_printf(fp, cm_fmt_string, flconst(real_buf, cpd(0)),
 | |
| 			flconst(imag_buf, cpd(1)));
 | |
| 	    break;
 | |
| 	case TYDCOMPLEX:
 | |
| 	    nice_printf(fp, dcm_fmt_string, cpd(0), cpd(1));
 | |
| 	    break;
 | |
| 	case TYLOGICAL:
 | |
| 	    nice_printf (fp, "%s", cp->Const.ci ? "TRUE_" : "FALSE_");
 | |
| 	    break;
 | |
| 	case TYCHAR: {
 | |
| 	    char *c = cp->Const.ccp, *ce;
 | |
| 
 | |
| 	    if (c == NULL) {
 | |
| 		nice_printf (fp, "\"\"");
 | |
| 		break;
 | |
| 	    } /* if c == NULL */
 | |
| 
 | |
| 	    nice_printf (fp, "\"");
 | |
| 	    ce = c + cp->vleng->constblock.Const.ci;
 | |
| 	    while(c < ce) {
 | |
| 		k = *(unsigned char *)c++;
 | |
| 		nice_printf(fp, str_fmt[k], k);
 | |
| 		}
 | |
| 	    for(k = cp->Const.ccp1.blanks; k > 0; k--)
 | |
| 		nice_printf(fp, " ");
 | |
| 	    nice_printf (fp, "\"");
 | |
| 	    break;
 | |
| 	} /* case TYCHAR */
 | |
| 	default:
 | |
| 	    erri ("out_const:  bad type '%d'", (int) type);
 | |
| 	    break;
 | |
|     } /* switch */
 | |
| 
 | |
| } /* out_const */
 | |
| #undef cpd
 | |
| 
 | |
| 
 | |
| /* out_addr -- this routine isn't local because it is called by the
 | |
|    system-generated identifier printing routines */
 | |
| 
 | |
| void out_addr (fp, addrp)
 | |
| FILE *fp;
 | |
| struct Addrblock *addrp;
 | |
| {
 | |
| 	extern Extsym *extsymtab;
 | |
| 	int was_array = 0;
 | |
| 	char *s;
 | |
| 
 | |
| 
 | |
| 	if (addrp == NULL)
 | |
| 		return;
 | |
| 	if (doin_setbound
 | |
| 			&& addrp->vstg == STGARG
 | |
| 			&& addrp->vtype != TYCHAR
 | |
| 			&& ISICON(addrp->memoffset)
 | |
| 			&& !addrp->memoffset->constblock.Const.ci)
 | |
| 		nice_printf(fp, "*");
 | |
| 
 | |
| 	switch (addrp -> uname_tag) {
 | |
| 	    case UNAM_NAME:
 | |
| 		out_name (fp, addrp -> user.name);
 | |
| 		break;
 | |
| 	    case UNAM_IDENT:
 | |
| 		if (*(s = addrp->user.ident) == ' ') {
 | |
| 			if (multitype)
 | |
| 				nice_printf(fp, "%s",
 | |
| 					xretslot[addrp->vtype]->user.ident);
 | |
| 			else
 | |
| 				nice_printf(fp, "%s", s+1);
 | |
| 			}
 | |
| 		else {
 | |
| 			nice_printf(fp, "%s", s);
 | |
| 			}
 | |
| 		break;
 | |
| 	    case UNAM_CHARP:
 | |
| 		nice_printf(fp, "%s", addrp->user.Charp);
 | |
| 		break;
 | |
| 	    case UNAM_EXTERN:
 | |
| 		extern_out (fp, &extsymtab[addrp -> memno]);
 | |
| 		break;
 | |
| 	    case UNAM_CONST:
 | |
| 		switch(addrp->vstg) {
 | |
| 			case STGCONST:
 | |
| 				out_const(fp, (Constp)addrp);
 | |
| 				break;
 | |
| 			case STGMEMNO:
 | |
| 				output_literal (fp, (int)addrp->memno,
 | |
| 					(Constp)addrp);
 | |
| 				break;
 | |
| 			default:
 | |
| 			Fatal("unexpected vstg in out_addr");
 | |
| 			}
 | |
| 		break;
 | |
| 	    case UNAM_UNKNOWN:
 | |
| 	    default:
 | |
| 		nice_printf (fp, "Unknown Addrp");
 | |
| 		break;
 | |
| 	} /* switch */
 | |
| 
 | |
| /* It's okay to just throw in the brackets here because they have a
 | |
|    precedence level of 15, the highest value.  */
 | |
| 
 | |
|     if ((addrp->uname_tag == UNAM_NAME && addrp->user.name->vdim
 | |
| 			|| addrp->ntempelt > 1 || addrp->isarray)
 | |
| 	&& addrp->vtype != TYCHAR) {
 | |
| 	expptr offset;
 | |
| 
 | |
| 	was_array = 1;
 | |
| 
 | |
| 	offset = addrp -> memoffset;
 | |
| 	addrp->memoffset = 0;
 | |
| 	if (ONEOF(addrp->vstg, M(STGCOMMON)|M(STGEQUIV)) &&
 | |
| 		addrp -> uname_tag == UNAM_NAME)
 | |
| 	    offset = mkexpr (OPMINUS, offset, mkintcon (
 | |
| 		    addrp -> user.name -> voffset));
 | |
| 
 | |
| 	nice_printf (fp, "[");
 | |
| 
 | |
| 	offset = mkexpr (OPSLASH, offset,
 | |
| 		ICON (typesize[addrp -> vtype] * (addrp -> Field ? 2 : 1)));
 | |
| 	expr_out (fp, offset);
 | |
| 	nice_printf (fp, "]");
 | |
| 	}
 | |
| 
 | |
| /* Check for structure field reference */
 | |
| 
 | |
|     if (addrp -> Field && addrp -> uname_tag != UNAM_CONST &&
 | |
| 	    addrp -> uname_tag != UNAM_UNKNOWN) {
 | |
| 	if (oneof_stg((addrp -> uname_tag == UNAM_NAME ? addrp -> user.name :
 | |
| 		(Namep) NULL), addrp -> vstg, M(STGARG)|M(STGEQUIV))
 | |
| 		&& !was_array && (addrp->vclass != CLPROC || !multitype))
 | |
| 	    nice_printf (fp, "->%s", addrp -> Field);
 | |
| 	else
 | |
| 	    nice_printf (fp, ".%s", addrp -> Field);
 | |
|     } /* if */
 | |
| 
 | |
| /* Check for character subscripting */
 | |
| 
 | |
|     if (addrp->vtype == TYCHAR &&
 | |
| 	    (addrp->vclass != CLPROC || addrp->uname_tag == UNAM_NAME
 | |
| 			&& addrp->user.name->vprocclass == PTHISPROC) &&
 | |
| 	    addrp -> memoffset &&
 | |
| 	    (addrp -> uname_tag != UNAM_NAME ||
 | |
| 	     addrp -> user.name -> vtype == TYCHAR) &&
 | |
| 	    (!ISICON (addrp -> memoffset) ||
 | |
| 	     (addrp -> memoffset -> constblock.Const.ci))) {
 | |
| 
 | |
| 	int use_paren = 0;
 | |
| 	expptr e = addrp -> memoffset;
 | |
| 
 | |
| 	if (!e)
 | |
| 		return;
 | |
| 	addrp->memoffset = 0;
 | |
| 
 | |
| 	if (ONEOF(addrp->vstg, M(STGCOMMON)|M(STGEQUIV))
 | |
| 	 && addrp -> uname_tag == UNAM_NAME) {
 | |
| 	    e = mkexpr (OPMINUS, e, mkintcon (addrp -> user.name -> voffset));
 | |
| 
 | |
| /* mkexpr will simplify it to zero if possible */
 | |
| 	    if (e->tag == TCONST && e->constblock.Const.ci == 0)
 | |
| 		return;
 | |
| 	} /* if addrp -> vstg == STGCOMMON */
 | |
| 
 | |
| /* In the worst case, parentheses might be needed OUTSIDE the expression,
 | |
|    too.  But since I think this subscripting can only appear as a
 | |
|    parameter in a procedure call, I don't think outside parens will ever
 | |
|    be needed.  INSIDE parens are handled below */
 | |
| 
 | |
| 	nice_printf (fp, " + ");
 | |
| 	if (e -> tag == TEXPR) {
 | |
| 	    int arg_prec = op_precedence (e -> exprblock.opcode);
 | |
| 	    int prec = op_precedence (OPPLUS);
 | |
| 	    use_paren = arg_prec && (arg_prec < prec || (arg_prec == prec &&
 | |
| 		    is_left_assoc (OPPLUS)));
 | |
| 	} /* if e -> tag == TEXPR */
 | |
| 	if (use_paren) nice_printf (fp, "(");
 | |
| 	expr_out (fp, e);
 | |
| 	if (use_paren) nice_printf (fp, ")");
 | |
|     } /* if */
 | |
| } /* out_addr */
 | |
| 
 | |
| 
 | |
| static void output_literal (fp, memno, cp)
 | |
|  FILE *fp;
 | |
|  int memno;
 | |
|  Constp cp;
 | |
| {
 | |
|     struct Literal *litp, *lastlit;
 | |
|     extern char *lit_name ();
 | |
| 
 | |
|     lastlit = litpool + nliterals;
 | |
| 
 | |
|     for (litp = litpool; litp < lastlit; litp++) {
 | |
| 	if (litp -> litnum == memno)
 | |
| 	    break;
 | |
|     } /* for litp */
 | |
| 
 | |
|     if (litp >= lastlit)
 | |
| 	out_const (fp, cp);
 | |
|     else {
 | |
| 	nice_printf (fp, "%s", lit_name (litp));
 | |
| 	litp->lituse++;
 | |
| 	}
 | |
| } /* output_literal */
 | |
| 
 | |
| 
 | |
| static void output_prim (fp, primp)
 | |
| FILE *fp;
 | |
| struct Primblock *primp;
 | |
| {
 | |
|     if (primp == NULL)
 | |
| 	return;
 | |
| 
 | |
|     out_name (fp, primp -> namep);
 | |
|     if (primp -> argsp)
 | |
| 	output_arg_list (fp, primp -> argsp);
 | |
| 
 | |
|     if (primp -> fcharp != (expptr) NULL || primp -> lcharp != (expptr) NULL)
 | |
| 	nice_printf (fp, "Sorry, no substrings yet");
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| static void output_arg_list (fp, listp)
 | |
| FILE *fp;
 | |
| struct Listblock *listp;
 | |
| {
 | |
|     chainp arg_list;
 | |
| 
 | |
|     if (listp == (struct Listblock *) NULL || listp -> listp == (chainp) NULL)
 | |
| 	return;
 | |
| 
 | |
|     nice_printf (fp, "(");
 | |
| 
 | |
|     for (arg_list = listp -> listp; arg_list; arg_list = arg_list -> nextp) {
 | |
| 	expr_out (fp, (expptr) arg_list -> datap);
 | |
| 	if (arg_list -> nextp != (chainp) NULL)
 | |
| 
 | |
| /* Might want to add a hook in here to accomodate the style setting which
 | |
|    wants spaces after commas */
 | |
| 
 | |
| 	    nice_printf (fp, ",");
 | |
|     } /* for arg_list */
 | |
| 
 | |
|     nice_printf (fp, ")");
 | |
| } /* output_arg_list */
 | |
| 
 | |
| 
 | |
| 
 | |
| static void output_unary (fp, e)
 | |
| FILE *fp;
 | |
| struct Exprblock *e;
 | |
| {
 | |
|     if (e == NULL)
 | |
| 	return;
 | |
| 
 | |
|     switch (e -> opcode) {
 | |
|         case OPNEG:
 | |
| 		if (e->vtype == TYREAL && forcedouble) {
 | |
| 			e->opcode = OPNEG_KLUDGE;
 | |
| 			output_binary(fp,e);
 | |
| 			e->opcode = OPNEG;
 | |
| 			break;
 | |
| 			}
 | |
| 	case OPNEG1:
 | |
| 	case OPNOT:
 | |
| 	case OPABS:
 | |
| 	case OPBITNOT:
 | |
| 	case OPWHATSIN:
 | |
| 	case OPPREINC:
 | |
| 	case OPPREDEC:
 | |
| 	case OPADDR:
 | |
| 	case OPIDENTITY:
 | |
| 	case OPCHARCAST:
 | |
| 	case OPDABS:
 | |
| 	    output_binary (fp, e);
 | |
| 	    break;
 | |
| 	case OPCALL:
 | |
| 	case OPCCALL:
 | |
| 	    nice_printf (fp, "Sorry, no OPCALL yet");
 | |
| 	    break;
 | |
| 	default:
 | |
| 	    erri ("output_unary: bad opcode", (int) e -> opcode);
 | |
| 	    break;
 | |
|     } /* switch */
 | |
| } /* output_unary */
 | |
| 
 | |
| 
 | |
|  static char *
 | |
| findconst(m)
 | |
|  register long m;
 | |
| {
 | |
| 	register struct Literal *litp, *litpe;
 | |
| 
 | |
| 	litp = litpool;
 | |
| 	for(litpe = litp + nliterals; litp < litpe; litp++)
 | |
| 		if (litp->litnum ==  m)
 | |
| 			return litp->cds[0];
 | |
| 	Fatal("findconst failure!");
 | |
| 	return 0;
 | |
| 	}
 | |
| 
 | |
|  static int
 | |
| opconv_fudge(fp,e)
 | |
|  FILE *fp;
 | |
|  struct Exprblock *e;
 | |
| {
 | |
| 	/* special handling for ichar and character*1 */
 | |
| 	register expptr lp = e->leftp;
 | |
| 	register union Expression *Offset;
 | |
| 	register char *cp;
 | |
| 	int lt = lp->headblock.vtype;
 | |
| 	char buf[8];
 | |
| 	unsigned int k;
 | |
| 	Namep np;
 | |
| 
 | |
| 	if (lp->addrblock.vtype == TYCHAR) {
 | |
| 		switch(lp->tag) {
 | |
| 			case TNAME:
 | |
| 				nice_printf(fp, "*");
 | |
| 				out_name(fp, (Namep)lp);
 | |
| 				return 1;
 | |
| 			case TCONST:
 | |
|  tconst:
 | |
| 				cp = lp->constblock.Const.ccp;
 | |
|  tconst1:
 | |
| 				k = *(unsigned char *)cp;
 | |
| 				sprintf(buf, chr_fmt[k], k);
 | |
| 				nice_printf(fp, "'%s'", buf);
 | |
| 				return 1;
 | |
| 			case TADDR:
 | |
| 				switch(lp->addrblock.vstg) {
 | |
| 				    case STGMEMNO:
 | |
| 					cp = findconst(lp->addrblock.memno);
 | |
| 					goto tconst1;
 | |
| 				    case STGCONST:
 | |
| 					goto tconst;
 | |
| 				    }
 | |
| 				lt = lp->addrblock.vtype = tyint;
 | |
| 				Offset = lp->addrblock.memoffset;
 | |
| 				if (lp->addrblock.uname_tag == UNAM_NAME) {
 | |
| 					np = lp->addrblock.user.name;
 | |
| 					if (ONEOF(np->vstg,
 | |
| 					    M(STGCOMMON)|M(STGEQUIV)))
 | |
| 						Offset = mkexpr(OPMINUS, Offset,
 | |
| 							ICON(np->voffset));
 | |
| 					}
 | |
| 				lp->addrblock.memoffset = Offset ?
 | |
| 					mkexpr(OPSTAR, Offset,
 | |
| 						ICON(typesize[tyint]))
 | |
| 					: ICON(0);
 | |
| 				lp->addrblock.isarray = 1;
 | |
| 				/* STGCOMMON or STGEQUIV would cause */
 | |
| 				/* voffset to be added in a second time */
 | |
| 				lp->addrblock.vstg = STGUNKNOWN;
 | |
| 				break;
 | |
| 			default:
 | |
| 				badtag("opconv_fudge", lp->tag);
 | |
| 			}
 | |
| 		}
 | |
| 	if (lt != e->vtype)
 | |
| 		nice_printf(fp, "(%s) ",
 | |
| 			c_type_decl(e->vtype, 0));
 | |
| 	return 0;
 | |
| 	}
 | |
| 
 | |
| 
 | |
| static void output_binary (fp, e)
 | |
| FILE *fp;
 | |
| struct Exprblock *e;
 | |
| {
 | |
|     char *format;
 | |
|     extern table_entry opcode_table[];
 | |
|     int prec;
 | |
| 
 | |
|     if (e == NULL || e -> tag != TEXPR)
 | |
| 	return;
 | |
| 
 | |
| /* Instead of writing a huge switch, I've incorporated the output format
 | |
|    into a table.  Things like "%l" and "%r" stand for the left and
 | |
|    right subexpressions.  This should allow both prefix and infix
 | |
|    functions to be specified (e.g. "(%l * %r", "z_div (%l, %r").  Of
 | |
|    course, I should REALLY think out the ramifications of writing out
 | |
|    straight text, as opposed to some intermediate format, which could
 | |
|    figure out and optimize on the the number of required blanks (we don't
 | |
|    want "x - (-y)" to become "x --y", for example).  Special cases (such as
 | |
|    incomplete implementations) could still be implemented as part of the
 | |
|    switch, they will just have some dummy value instead of the string
 | |
|    pattern.  Another difficulty is the fact that the complex functions
 | |
|    will differ from the integer and real ones */
 | |
| 
 | |
| /* Handle a special case.  We don't want to output "x + - 4", or "y - - 3"
 | |
| */
 | |
|     if ((e -> opcode == OPPLUS || e -> opcode == OPMINUS) &&
 | |
| 	    e -> rightp && e -> rightp -> tag == TCONST &&
 | |
| 	    isnegative_const (&(e -> rightp -> constblock)) &&
 | |
| 	    is_negatable (&(e -> rightp -> constblock))) {
 | |
| 
 | |
| 	e -> opcode = (e -> opcode == OPPLUS) ? OPMINUS : OPPLUS;
 | |
| 	negate_const (&(e -> rightp -> constblock));
 | |
|     } /* if e -> opcode == PLUS or MINUS */
 | |
| 
 | |
|     prec = op_precedence (e -> opcode);
 | |
|     format = op_format (e -> opcode);
 | |
| 
 | |
|     if (format != SPECIAL_FMT) {
 | |
| 	while (*format) {
 | |
| 	    if (*format == '%') {
 | |
| 		int arg_prec, use_paren = 0;
 | |
| 		expptr lp, rp;
 | |
| 
 | |
| 		switch (*(format + 1)) {
 | |
| 		    case 'l':
 | |
| 			lp = e->leftp;
 | |
| 			if (lp && lp->tag == TEXPR) {
 | |
| 			    arg_prec = op_precedence(lp->exprblock.opcode);
 | |
| 
 | |
| 			    use_paren = arg_prec &&
 | |
| 			        (arg_prec < prec || (arg_prec == prec &&
 | |
| 				    is_right_assoc (prec)));
 | |
| 			} /* if e -> leftp */
 | |
| 			if (e->opcode == OPCONV && opconv_fudge(fp,e))
 | |
| 				break;
 | |
| 			if (use_paren)
 | |
| 			    nice_printf (fp, "(");
 | |
| 		        expr_out(fp, lp);
 | |
| 			if (use_paren)
 | |
| 			    nice_printf (fp, ")");
 | |
| 		        break;
 | |
| 		    case 'r':
 | |
| 			rp = e->rightp;
 | |
| 			if (rp && rp->tag == TEXPR) {
 | |
| 			    arg_prec = op_precedence(rp->exprblock.opcode);
 | |
| 
 | |
| 			    use_paren = arg_prec &&
 | |
| 			        (arg_prec < prec || (arg_prec == prec &&
 | |
| 				    is_left_assoc (prec)));
 | |
| 			    use_paren = use_paren ||
 | |
| 				(rp->exprblock.opcode == OPNEG
 | |
| 				&& prec >= op_precedence(OPMINUS));
 | |
| 			} /* if e -> rightp */
 | |
| 			if (use_paren)
 | |
| 			    nice_printf (fp, "(");
 | |
| 		        expr_out(fp, rp);
 | |
| 			if (use_paren)
 | |
| 			    nice_printf (fp, ")");
 | |
| 		        break;
 | |
| 		    case '\0':
 | |
| 		    case '%':
 | |
| 		        nice_printf (fp, "%%");
 | |
| 		        break;
 | |
| 		    default:
 | |
| 		        erri ("output_binary: format err: '%%%c' illegal",
 | |
| 				(int) *(format + 1));
 | |
| 		        break;
 | |
| 		} /* switch */
 | |
| 		format += 2;
 | |
| 	    } else
 | |
| 		nice_printf (fp, "%c", *format++);
 | |
| 	} /* while *format */
 | |
|     } else {
 | |
| 
 | |
| /* Handle Special cases of formatting */
 | |
| 
 | |
| 	switch (e -> opcode) {
 | |
| 		case OPCCALL:
 | |
| 		case OPCALL:
 | |
| 			out_call (fp, (int) e -> opcode, e -> vtype,
 | |
| 					e -> vleng, e -> leftp, e -> rightp);
 | |
| 			break;
 | |
| 
 | |
| 		case OPCOMMA_ARG:
 | |
| 			doin_setbound = 1;
 | |
| 			nice_printf(fp, "(");
 | |
| 			expr_out(fp, e->leftp);
 | |
| 			nice_printf(fp, ", &");
 | |
| 			doin_setbound = 0;
 | |
| 			expr_out(fp, e->rightp);
 | |
| 			nice_printf(fp, ")");
 | |
| 			break;
 | |
| 
 | |
| 		case OPADDR:
 | |
| 		default:
 | |
| 	        	nice_printf (fp, "Sorry, can't format OPCODE '%d'",
 | |
| 				e -> opcode);
 | |
| 	        	break;
 | |
| 		}
 | |
| 
 | |
|     } /* else */
 | |
| } /* output_binary */
 | |
| 
 | |
| 
 | |
| out_call (outfile, op, ftype, len, name, args)
 | |
| FILE *outfile;
 | |
| int op, ftype;
 | |
| expptr len, name, args;
 | |
| {
 | |
|     chainp arglist;		/* Pointer to any actual arguments */
 | |
|     chainp cp;			/* Iterator over argument lists */
 | |
|     Addrp ret_val = (Addrp) NULL;
 | |
| 				/* Function return value buffer, if any is
 | |
| 				   required */
 | |
|     int byvalue;		/* True iff we're calling a C library
 | |
| 				   routine */
 | |
|     int done_once;		/* Used for writing commas to   outfile   */
 | |
|     int narg, t;
 | |
|     register expptr q;
 | |
|     long L;
 | |
|     Argtypes *at;
 | |
|     Atype *A;
 | |
|     Namep np;
 | |
|     extern int forcereal;
 | |
| 
 | |
| /* Don't use addresses if we're calling a C function */
 | |
| 
 | |
|     byvalue = op == OPCCALL;
 | |
| 
 | |
|     if (args)
 | |
| 	arglist = args -> listblock.listp;
 | |
|     else
 | |
| 	arglist = CHNULL;
 | |
| 
 | |
| /* If this is a CHARACTER function, the first argument is the result */
 | |
| 
 | |
|     if (ftype == TYCHAR)
 | |
| 	if (ISICON (len)) {
 | |
| 	    ret_val = (Addrp) (arglist -> datap);
 | |
| 	    arglist = arglist -> nextp;
 | |
| 	} else {
 | |
| 	    err ("adjustable character function");
 | |
| 	    return;
 | |
| 	} /* else */
 | |
| 
 | |
| /* If this is a COMPLEX function, the first argument is the result */
 | |
| 
 | |
|     else if (ISCOMPLEX (ftype)) {
 | |
| 	ret_val = (Addrp) (arglist -> datap);
 | |
| 	arglist = arglist -> nextp;
 | |
|     } /* if ISCOMPLEX */
 | |
| 
 | |
| /* Now we can actually start to write out the function invocation */
 | |
| 
 | |
|     if (ftype == TYREAL && forcereal)
 | |
| 	nice_printf(outfile, "(real)");
 | |
|     if (name -> tag == TEXPR && name -> exprblock.opcode == OPWHATSIN) {
 | |
| 	nice_printf (outfile, "(");
 | |
| 	np = (Namep)name->exprblock.leftp; /*expr_out will free name */
 | |
| 	expr_out (outfile, name);
 | |
| 	nice_printf (outfile, ")");
 | |
| 	}
 | |
|     else {
 | |
| 	np = (Namep)name;
 | |
| 	expr_out(outfile, name);
 | |
| 	}
 | |
| 
 | |
|     /* prepare to cast procedure parameters -- set A if we know how */
 | |
| 
 | |
|     A = np->tag == TNAME && (at = np->arginfo) && at->nargs > 0
 | |
| 	? at->atypes : 0;
 | |
| 
 | |
|     nice_printf(outfile, "(");
 | |
| 
 | |
|     if (ret_val) {
 | |
| 	if (ISCOMPLEX (ftype))
 | |
| 	    nice_printf (outfile, "&");
 | |
| 	expr_out (outfile, (expptr) ret_val);
 | |
| 
 | |
| /* The length of the result of a character function is the second argument */
 | |
| /* It should be in place from putcall(), so we won't touch it explicitly */
 | |
| 
 | |
|     } /* if ret_val */
 | |
|     done_once = ret_val ? TRUE : FALSE;
 | |
| 
 | |
| /* Now run through the named arguments */
 | |
| 
 | |
|     narg = -1;
 | |
|     for (cp = arglist; cp; cp = cp -> nextp, done_once = TRUE) {
 | |
| 
 | |
| 	if (done_once)
 | |
| 	    nice_printf (outfile, ", ");
 | |
| 	narg++;
 | |
| 
 | |
| 	if (!( q = (expptr)cp->datap) )
 | |
| 		continue;
 | |
| 
 | |
| 	if (q->tag == TADDR) {
 | |
| 		if (q->addrblock.vtype > TYERROR) {
 | |
| 			/* I/O block */
 | |
| 			nice_printf(outfile, "&%s", q->addrblock.user.ident);
 | |
| 			continue;
 | |
| 			}
 | |
| 		if (!byvalue && q->addrblock.isarray
 | |
| 		&& q->addrblock.vtype != TYCHAR
 | |
| 		&& q->addrblock.memoffset->tag == TCONST) {
 | |
| 
 | |
| 			/* check for 0 offset -- after */
 | |
| 			/* correcting for equivalence. */
 | |
| 			L = q->addrblock.memoffset->constblock.Const.ci;
 | |
| 			if (ONEOF(q->addrblock.vstg, M(STGCOMMON)|M(STGEQUIV))
 | |
| 					&& q->addrblock.uname_tag == UNAM_NAME)
 | |
| 				L -= q->addrblock.user.name->voffset;
 | |
| 			if (L)
 | |
| 				goto skip_deref;
 | |
| 
 | |
| 			/* &x[0] == x */
 | |
| 			/* This also prevents &sizeof(doublereal)[0] */
 | |
| 			switch(q->addrblock.uname_tag) {
 | |
| 			    case UNAM_NAME:
 | |
| 				out_name(outfile, q->addrblock.user.name);
 | |
| 				continue;
 | |
| 			    case UNAM_IDENT:
 | |
| 				nice_printf(outfile, "%s",
 | |
| 					q->addrblock.user.ident);
 | |
| 				continue;
 | |
| 			    case UNAM_CHARP:
 | |
| 				nice_printf(outfile, "%s",
 | |
| 					q->addrblock.user.Charp);
 | |
| 				continue;
 | |
| 			    case UNAM_EXTERN:
 | |
| 				extern_out(outfile,
 | |
| 					&extsymtab[q->addrblock.memno]);
 | |
| 				continue;
 | |
| 			    }
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| /* Skip over the dereferencing operator generated only for the
 | |
|    intermediate file */
 | |
|  skip_deref:
 | |
| 	if (q -> tag == TEXPR && q -> exprblock.opcode == OPWHATSIN)
 | |
| 	    q = q -> exprblock.leftp;
 | |
| 
 | |
| 	if (q->headblock.vclass == CLPROC
 | |
| 			&& Castargs
 | |
| 			&& (q->tag != TNAME
 | |
| 				|| q->nameblock.vprocclass != PTHISPROC))
 | |
| 		{
 | |
| 		if (A && (t = A[narg].type) >= 200)
 | |
| 			t %= 100;
 | |
| 		else {
 | |
| 			t = q->headblock.vtype;
 | |
| 			if (q->tag == TNAME && q->nameblock.vimpltype)
 | |
| 				t = TYUNKNOWN;
 | |
| 			}
 | |
| 		nice_printf(outfile, "(%s)", usedcasts[t] = casttypes[t]);
 | |
| 		}
 | |
| 
 | |
| 	if ((q -> tag == TADDR || q-> tag == TNAME) &&
 | |
| 		(byvalue || q -> headblock.vstg != STGREG)) {
 | |
| 	    if (q -> headblock.vtype != TYCHAR)
 | |
| 	      if (byvalue) {
 | |
| 
 | |
| 		if (q -> tag == TADDR &&
 | |
| 			q -> addrblock.uname_tag == UNAM_NAME &&
 | |
| 			! q -> addrblock.user.name -> vdim &&
 | |
| 			oneof_stg(q -> addrblock.user.name, q -> addrblock.vstg,
 | |
| 					M(STGARG)|M(STGEQUIV)) &&
 | |
| 			! ISCOMPLEX(q->addrblock.user.name->vtype))
 | |
| 		    nice_printf (outfile, "*");
 | |
| 		else if (q -> tag == TNAME
 | |
| 			&& oneof_stg(&q->nameblock, q -> nameblock.vstg,
 | |
| 				M(STGARG)|M(STGEQUIV))
 | |
| 			&& !(q -> nameblock.vdim))
 | |
| 		    nice_printf (outfile, "*");
 | |
| 
 | |
| 	      } else {
 | |
| 		expptr memoffset;
 | |
| 
 | |
| 		if (q->tag == TADDR &&
 | |
| 			!ONEOF (q -> addrblock.vstg, M(STGEXT)|M(STGLENG))
 | |
| 			&& (
 | |
| 			ONEOF(q->addrblock.vstg,
 | |
| 				M(STGCOMMON)|M(STGEQUIV)|M(STGMEMNO))
 | |
| 			|| ((memoffset = q->addrblock.memoffset)
 | |
| 				&& (!ISICON(memoffset)
 | |
| 				|| memoffset->constblock.Const.ci)))
 | |
| 			|| ONEOF(q->addrblock.vstg,
 | |
| 					M(STGINIT)|M(STGAUTO)|M(STGBSS))
 | |
| 				&& !q->addrblock.isarray)
 | |
| 		    nice_printf (outfile, "&");
 | |
| 		else if (q -> tag == TNAME
 | |
| 			&& !oneof_stg(&q->nameblock, q -> nameblock.vstg,
 | |
| 				M(STGARG)|M(STGEXT)|M(STGEQUIV)))
 | |
| 		    nice_printf (outfile, "&");
 | |
| 	    } /* else */
 | |
| 
 | |
| 	    expr_out (outfile, q);
 | |
| 	} /* if q -> tag == TADDR || q -> tag == TNAME */
 | |
| 
 | |
| /* Might be a Constant expression, e.g. string length, character constants */
 | |
| 
 | |
| 	else if (q -> tag == TCONST) {
 | |
| 	    if (tyioint == TYLONG)
 | |
| 	   	Longfmt = "%ldL";
 | |
| 	    out_const(outfile, &q->constblock);
 | |
| 	    Longfmt = "%ld";
 | |
| 	    }
 | |
| 
 | |
| /* Must be some other kind of expression, or register var, or constant.
 | |
|    In particular, this is likely to be a temporary variable assignment
 | |
|    which was generated in p1put_call */
 | |
| 
 | |
| 	else if (!ISCOMPLEX (q -> headblock.vtype) && !ISCHAR (q)){
 | |
| 	    int use_paren = q -> tag == TEXPR &&
 | |
| 		    op_precedence (q -> exprblock.opcode) <=
 | |
| 		    op_precedence (OPCOMMA);
 | |
| 
 | |
| 	    if (use_paren) nice_printf (outfile, "(");
 | |
| 	    expr_out (outfile, q);
 | |
| 	    if (use_paren) nice_printf (outfile, ")");
 | |
| 	} /* if !ISCOMPLEX */
 | |
| 	else
 | |
| 	    err ("out_call:  unknown parameter");
 | |
| 
 | |
|     } /* for (cp = arglist */
 | |
| 
 | |
|     if (arglist)
 | |
| 	frchain (&arglist);
 | |
| 
 | |
|     nice_printf (outfile, ")");
 | |
| 
 | |
| } /* out_call */
 | |
| 
 | |
| 
 | |
|  char *
 | |
| flconst(buf, x)
 | |
|  char *buf, *x;
 | |
| {
 | |
| 	sprintf(buf, fl_fmt_string, x);
 | |
| 	return buf;
 | |
| 	}
 | |
| 
 | |
|  char *
 | |
| dtos(x)
 | |
|  double x;
 | |
| {
 | |
| 	static char buf[64];
 | |
| 	sprintf(buf, db_fmt_string, x);
 | |
| 	return buf;
 | |
| 	}
 | |
| 
 | |
| char tr_tab[Table_size];
 | |
| 
 | |
| /* out_init -- Initialize the data structures used by the routines in
 | |
|    output.c.  These structures include the output format to be used for
 | |
|    Float, Double, Complex, and Double Complex constants. */
 | |
| 
 | |
| void out_init ()
 | |
| {
 | |
|     extern int tab_size;
 | |
|     register char *s;
 | |
| 
 | |
|     s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+-.";
 | |
|     while(*s)
 | |
| 	tr_tab[*s++] = 3;
 | |
|     tr_tab['>'] = 1;
 | |
| 
 | |
| 	opeqable[OPPLUS] = 1;
 | |
| 	opeqable[OPMINUS] = 1;
 | |
| 	opeqable[OPSTAR] = 1;
 | |
| 	opeqable[OPSLASH] = 1;
 | |
| 	opeqable[OPMOD] = 1;
 | |
| 	opeqable[OPLSHIFT] = 1;
 | |
| 	opeqable[OPBITAND] = 1;
 | |
| 	opeqable[OPBITXOR] = 1;
 | |
| 	opeqable[OPBITOR ] = 1;
 | |
| 
 | |
| 
 | |
| /* Set the output format for both types of floating point constants */
 | |
| 
 | |
|     if (fl_fmt_string == NULL || *fl_fmt_string == '\0')
 | |
| 	fl_fmt_string = Ansi == 1 ? "%sf" : "(float)%s";
 | |
| 
 | |
|     if (db_fmt_string == NULL || *db_fmt_string == '\0')
 | |
| 	db_fmt_string = "%.17g";
 | |
| 
 | |
| /* Set the output format for both types of complex constants.  They will
 | |
|    have string parameters rather than float or double so that the decimal
 | |
|    point may be added to the strings generated by the {db,fl}_fmt_string
 | |
|    formats above */
 | |
| 
 | |
|     if (cm_fmt_string == NULL || *cm_fmt_string == '\0') {
 | |
| 	cm_fmt_string = "{%s,%s}";
 | |
|     } /* if cm_fmt_string == NULL */
 | |
| 
 | |
|     if (dcm_fmt_string == NULL || *dcm_fmt_string == '\0') {
 | |
| 	dcm_fmt_string = "{%s,%s}";
 | |
|     } /* if dcm_fmt_string == NULL */
 | |
| 
 | |
|     tab_size = 4;
 | |
| } /* out_init */
 | |
| 
 | |
| 
 | |
| void extern_out (fp, extsym)
 | |
| FILE *fp;
 | |
| Extsym *extsym;
 | |
| {
 | |
|     if (extsym == (Extsym *) NULL)
 | |
| 	return;
 | |
| 
 | |
|     nice_printf (fp, "%s", extsym->cextname);
 | |
| 
 | |
| } /* extern_out */
 | |
| 
 | |
| 
 | |
| 
 | |
| static void output_list (fp, listp)
 | |
| FILE *fp;
 | |
| struct Listblock *listp;
 | |
| {
 | |
|     int did_one = 0;
 | |
|     chainp elts;
 | |
| 
 | |
|     nice_printf (fp, "(");
 | |
|     if (listp)
 | |
| 	for (elts = listp -> listp; elts; elts = elts -> nextp) {
 | |
| 	    if (elts -> datap) {
 | |
| 		if (did_one)
 | |
| 		    nice_printf (fp, ", ");
 | |
| 		expr_out (fp, (expptr) elts -> datap);
 | |
| 		did_one = 1;
 | |
| 	    } /* if elts -> datap */
 | |
| 	} /* for elts */
 | |
|     nice_printf (fp, ")");
 | |
| } /* output_list */
 | |
| 
 | |
| 
 | |
| void out_asgoto (outfile, expr)
 | |
| FILE *outfile;
 | |
| expptr expr;
 | |
| {
 | |
|     char *user_label();
 | |
|     chainp value;
 | |
|     Namep namep;
 | |
|     int k;
 | |
| 
 | |
|     if (expr == (expptr) NULL) {
 | |
| 	err ("out_asgoto:  NULL variable expr");
 | |
| 	return;
 | |
|     } /* if expr */
 | |
| 
 | |
|     nice_printf (outfile, Ansi ? "switch (" : "switch ((int)"); /*)*/
 | |
|     expr_out (outfile, expr);
 | |
|     nice_printf (outfile, ") {\n");
 | |
|     next_tab (outfile);
 | |
| 
 | |
| /* The initial addrp value will be stored as a namep pointer */
 | |
| 
 | |
|     switch(expr->tag) {
 | |
| 	case TNAME:
 | |
| 		/* local variable */
 | |
| 		namep = &expr->nameblock;
 | |
| 		break;
 | |
| 	case TEXPR:
 | |
| 		if (expr->exprblock.opcode == OPWHATSIN
 | |
| 		 && expr->exprblock.leftp->tag == TNAME)
 | |
| 			/* argument */
 | |
| 			namep = &expr->exprblock.leftp->nameblock;
 | |
| 		else
 | |
| 			goto bad;
 | |
| 		break;
 | |
| 	case TADDR:
 | |
| 		if (expr->addrblock.uname_tag == UNAM_NAME) {
 | |
| 			/* initialized local variable */
 | |
| 			namep = expr->addrblock.user.name;
 | |
| 			break;
 | |
| 			}
 | |
| 	default:
 | |
|  bad:
 | |
| 		err("out_asgoto:  bad expr");
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
|     for(k = 0, value = namep -> varxptr.assigned_values; value;
 | |
| 	    value = value->nextp, k++) {
 | |
| 	nice_printf (outfile, "case %d: goto %s;\n", k,
 | |
| 		user_label((long)value->datap));
 | |
|     } /* for value */
 | |
|     prev_tab (outfile);
 | |
| 
 | |
|     nice_printf (outfile, "}\n");
 | |
| } /* out_asgoto */
 | |
| 
 | |
| void out_if (outfile, expr)
 | |
| FILE *outfile;
 | |
| expptr expr;
 | |
| {
 | |
|     nice_printf (outfile, "if (");
 | |
|     expr_out (outfile, expr);
 | |
|     nice_printf (outfile, ") {\n");
 | |
|     next_tab (outfile);
 | |
| } /* out_if */
 | |
| 
 | |
|  static void
 | |
| output_rbrace(outfile, s)
 | |
|  FILE *outfile;
 | |
|  char *s;
 | |
| {
 | |
| 	extern int last_was_label;
 | |
| 	register char *fmt;
 | |
| 
 | |
| 	if (last_was_label) {
 | |
| 		last_was_label = 0;
 | |
| 		fmt = ";%s";
 | |
| 		}
 | |
| 	else
 | |
| 		fmt = "%s";
 | |
| 	nice_printf(outfile, fmt, s);
 | |
| 	}
 | |
| 
 | |
| void out_else (outfile)
 | |
| FILE *outfile;
 | |
| {
 | |
|     prev_tab (outfile);
 | |
|     output_rbrace(outfile, "} else {\n");
 | |
|     next_tab (outfile);
 | |
| } /* out_else */
 | |
| 
 | |
| void elif_out (outfile, expr)
 | |
| FILE *outfile;
 | |
| expptr expr;
 | |
| {
 | |
|     prev_tab (outfile);
 | |
|     output_rbrace(outfile, "} else ");
 | |
|     out_if (outfile, expr);
 | |
| } /* elif_out */
 | |
| 
 | |
| void endif_out (outfile)
 | |
| FILE *outfile;
 | |
| {
 | |
|     prev_tab (outfile);
 | |
|     output_rbrace(outfile, "}\n");
 | |
| } /* endif_out */
 | |
| 
 | |
| void end_else_out (outfile)
 | |
| FILE *outfile;
 | |
| {
 | |
|     prev_tab (outfile);
 | |
|     output_rbrace(outfile, "}\n");
 | |
| } /* end_else_out */
 | |
| 
 | |
| 
 | |
| 
 | |
| void compgoto_out (outfile, index, labels)
 | |
| FILE *outfile;
 | |
| expptr index, labels;
 | |
| {
 | |
|     char *s1, *s2;
 | |
| 
 | |
|     if (index == ENULL)
 | |
| 	err ("compgoto_out:  null index for computed goto");
 | |
|     else if (labels && labels -> tag != TLIST)
 | |
| 	erri ("compgoto_out:  expected label list, got tag '%d'",
 | |
| 		labels -> tag);
 | |
|     else {
 | |
| 	extern char *user_label ();
 | |
| 	chainp elts;
 | |
| 	int i = 1;
 | |
| 
 | |
| 	s2 = /*(*/ ") {\n"; /*}*/
 | |
| 	if (Ansi)
 | |
| 		s1 = "switch ("; /*)*/
 | |
| 	else if (index->tag == TNAME || index->tag == TEXPR
 | |
| 				&& index->exprblock.opcode == OPWHATSIN)
 | |
| 		s1 = "switch ((int)"; /*)*/
 | |
| 	else {
 | |
| 		s1 = "switch ((int)(";
 | |
| 		s2 = ")) {\n"; /*}*/
 | |
| 		}
 | |
| 	nice_printf(outfile, s1);
 | |
| 	expr_out (outfile, index);
 | |
| 	nice_printf (outfile, s2);
 | |
| 	next_tab (outfile);
 | |
| 
 | |
| 	for (elts = labels -> listblock.listp; elts; elts = elts -> nextp, i++) {
 | |
| 	    if (elts -> datap) {
 | |
| 		if (ISICON(((expptr) (elts -> datap))))
 | |
| 		    nice_printf (outfile, "case %d:  goto %s;\n", i,
 | |
| 			user_label(((expptr)(elts->datap))->constblock.Const.ci));
 | |
| 		else
 | |
| 		    err ("compgoto_out:  bad label in label list");
 | |
| 	    } /* if (elts -> datap) */
 | |
| 	} /* for elts */
 | |
| 	prev_tab (outfile);
 | |
| 	nice_printf (outfile, /*{*/ "}\n");
 | |
|     } /* else */
 | |
| } /* compgoto_out */
 | |
| 
 | |
| 
 | |
| void out_for (outfile, init, test, inc)
 | |
| FILE *outfile;
 | |
| expptr init, test, inc;
 | |
| {
 | |
|     nice_printf (outfile, "for (");
 | |
|     expr_out (outfile, init);
 | |
|     nice_printf (outfile, "; ");
 | |
|     expr_out (outfile, test);
 | |
|     nice_printf (outfile, "; ");
 | |
|     expr_out (outfile, inc);
 | |
|     nice_printf (outfile, ") {\n");
 | |
|     next_tab (outfile);
 | |
| } /* out_for */
 | |
| 
 | |
| 
 | |
| void out_end_for (outfile)
 | |
| FILE *outfile;
 | |
| {
 | |
|     prev_tab (outfile);
 | |
|     nice_printf (outfile, "}\n");
 | |
| } /* out_end_for */
 |