1432 lines
36 KiB
C
1432 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 */
|