⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ccgen1.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	CCGEN1.C - Generate code for parse-tree statement execution
**
**	(c) Copyright Ken Harrenstien 1989
**		All changes after v.198, 9-Mar-1988
**	(c) Copyright Ken Harrenstien, SRI International 1985, 1986
**		All changes after v.112, 8-Aug-1985
**
**	Original version (C) 1981  K. Chen
*/

#include "cc.h"
#include "ccgen.h"
#include <ctype.h>	/* isdigit */

/* Imported functions */
extern void vrfree(VREG *);
extern VREG *vrget(void);		/* CCREG */
extern void code_debugcall(NODE *);	/* CCDBUG */
extern NODE *ndeflr(int op, NODE *l, NODE *r);		/* CCSTMT */
extern VREG *genexpr(NODE *);		/* CCGEN2 for expressions */
extern void genxrelease(NODE *);	/* CCGEN2 for discarded expressions */
extern VREG *getmem(VREG *, TYPE *, int, int), 
	*stomem(VREG *, VREG *, INT, int);	/* CCGEN2 */
extern void gswitch(NODE *);		/* CCGSWI for switch statement */
extern void codlabel(SYMBOL *), codgolab(SYMBOL *);/*CCCODE for label output*/
extern SYMBOL *newlabel(void);	/* CCSYM */
extern INT sizetype(TYPE *);		/* CCSYM */
extern void outlab(SYMBOL *);		/* CCOUT */
extern void code0(int, VREG *, VREG *), code3(int, VREG *, SYMBOL *), 
	code4(int, VREG *, VREG *), code4s(int, VREG *, VREG *, int, INT), 
	code5(int, VREG *), code00(int, int, int),
	code6(int, VREG *, SYMBOL *), code8(int, VREG *, INT), 
	code13(int, VREG *, INT);
extern void relflush(VREG *), gboolean(NODE *, SYMBOL *, int), 
	flushcode(void), freelabel(SYMBOL *);
extern INT istrue(NODE *, NODE *);		/* CCEVAL */
extern int deadjump(void);		/* CCJSKP */
extern void killstack(void);	/* CCOPT */

extern void outepilog(SYMBOL *);	/* CCOUT */
extern VREG *gmuuo(NODE *);	/* CCGEN2 for imuuo key word; KAR 1/91 */

extern
void	    outiepilog (void);		/* FW 2A(52) */

/* Exported functions defined here */
void genstmt(NODE *);

/* Internal functions */
static void genadata(NODE *);
static void gdo(NODE *), gfor(NODE *), gif(NODE *), 
	gwhile(NODE *), greturn(NODE *);
static SYMBOL *gtoplab(void); 
static int labchk(NODE *);
static NODE *laststmt(NODE *);
#if 0
static void genadata();
static void gdo(), gfor(), gif(), gwhile(), greturn();
static SYMBOL *gtoplab();
static int labchk();
static NODE *laststmt();
#endif


/* ------------------------------------- */
/*      generate code for statement      */
/* ------------------------------------- */

extern void outstr();

void
genstmt(NODE *n)
{
    VREG	*muuo_ac;

    if (n == NULL) return;
    switch (n->Nop) {

    case N_STATEMENT:
	{ NODE *beg, *next;
	if (n->Nleft && n->Nleft->Nop == N_DATA) { /* Check for auto inits */
	    genadata(n->Nleft);		/* Yep, do them */
	    n = n->Nright;		/* then move on to real statements */
	}
	for(beg = n; n != NULL; n = n->Nright) {
	    if(n->Nop != N_STATEMENT)
		int_error("genstmt: bad stmt %N", n);
	    if(n->Nleft == NULL) continue;

	    /* Check out following stmt for possible optimizations */
	    if(n->Nright && (next = n->Nright->Nleft) != NULL && optgen) {
		switch(next->Nop) {

		/* Hack to encourage tail recursion */
		case Q_RETURN:			/* If next will be RETURN */
		    if(next->Nright == NULL) {	/* and has no return val */
			NODE *v;		/* Then try to optimize */
			if((v = laststmt(n->Nleft)) != NULL && v->Nop == N_FNCALL)
			    v->Nflag |= NF_RETEXPR;
		    }
		    break;

		/* If next stmt is a GOTO, ensure that any jumps
		 * within current stmt to end of stmt will
		 * instead go directly to object of the GOTO.
		 * Avoids jumping to jumps...
		 * We do a similar hack for BREAK and CONTINUE,
		 * which are similar to GOTOs except that their
		 * destination is kept in variables global to the
		 * code generation routines.
		 */
		case Q_CASE:	/* Not sure about this one yet */
		case N_LABEL:

		case Q_GOTO:
		    n->Nleft->Nendlab = next->Nxfsym;
		    break;
		case Q_BREAK:
		    n->Nleft->Nendlab = brklabel;
		    break;
		case Q_CONTINUE:
		    n->Nleft->Nendlab = looplabel;
		    break;
	        default:
	            ;	/* do nothing */
	    }	/* end of Nop switch */
	    }	/* end of next-stmt check */

	    /* Optimize label usage */
	    if(n->Nright == NULL 	/* If this is last stmt in list */
		&& optgen)
		n->Nleft->Nendlab = beg->Nendlab;	/* Copy from 1st */

	    genstmt(n->Nleft);
	}
	break;
	} /* end of N_STATEMENT case block */

    case Q_CASE:
	codlabel(n->Nxfsym);		/* send forward label */
	n->Nleft->Nendlab = n->Nendlab;	/* propagate end label */
	genstmt (n->Nleft);		/* finish rest of body */
	break;

    case N_LABEL:
	if (n->Nxfsym->Sname[0] == '%' && isdigit(n->Nxfsym->Sname[1]))
	    code_debugcall(n);
	else
	    codgolab(n->Nxfsym);		/* send goto label */
	n->Nleft->Nendlab = n->Nendlab;	/* propagate end label */
	genstmt(n->Nleft);		/* finish rest of body */
	break;

    case Q_BREAK:	code6(P_JRST, NULL, brklabel);	break;
    case Q_GOTO:	code6(P_JRST, NULL, n->Nxfsym);	break;
    case Q_CONTINUE:	code6(P_JRST, NULL, looplabel);	break;
    case Q_DO:		gdo(n);		break;
    case Q_FOR:		gfor(n);	break;
    case Q_IF:		gif(n);		break;
    case Q_RETURN:      greturn(n);	break;
    case Q_SWITCH:	gswitch(n);	break;
    case Q_WHILE:	gwhile(n);	break;

#if SYS_CSI	/* Added 1/91 for in-line monitor calls; KAR */
    case Q_MUUO:
	muuo_ac = gmuuo(n);
	vrfree(muuo_ac);
	break;
#endif

    case N_EXPRLIST:		/* Same as expression stmt */
    default:			/* None of above, assume expression stmt */
	genxrelease(n);		/* Generate it and flush any result */
	break;
    }
}

/* Hack for statement optimization.  Find last statement in list. */
static NODE *
laststmt(n)
NODE *n;
{
	while(n && n->Nop == N_STATEMENT) {
		while(n->Nright) n = n->Nright;
		n = n->Nleft;
	}
	return(n);
}

/* GENADATA - Generate auto data initializations
**	Should be called only for N_DATA nodes.
**
** Includes "gizlist" - Generate a struct/union/array constant.
**	This can only happen for brace-enclosed initializers.
** Node will be a N_IZLIST, with Ntype set to desired type of the
** constant.
** For the time being, our approach is to chicken out by just inventing
** a new internal label and returning that.  This label and the N_IZLIST
** are put together to form a N_LITIZ list and chained onto "litnodes"
** for eventual output as a static data literal.
*/
static void
genadata(n)
NODE *n;
{
    if (n->Nop != N_DATA) {
	int_error("genadata: node not N_DATA %N", n);
	return;
    }
#if SYS_CSI	/* Bliss-like reg linkage */
    if (Register_Id(n))		/* should never happen */
	int_error ("genadata: register var of non-arithmetic type");
#endif
    for (; n && n->Nop == N_DATA; n = n->Nright) {
	if (n->Nleft != NULL && n->Nleft->Nright != NULL) {

	    /* Have an N_IZ node with initializer, process it. */
	    if (n->Nleft->Nright->Nop == N_IZLIST) {
		/* A struct/union/array initializer! */
		SYMBOL *s = n->Nleft->Nleft->Nid;	/* Find ident */
		NODE *l = n->Nleft->Nright;	/* Point to N_IZLIST */
		TYPE *t = l->Ntype;		/* Find type of constant */
		VREG *ra, *r;

		/* Put izer node onto literal list for later emission */
		litnodes = ndeflr(N_LITIZ, l, litnodes);
		litnodes->Nendlab = newlabel();	/* Make label for it */

		/* Get the literal and store into auto var.  Note that the
		** type used is that of literal, not the ident, and it is
		** ignored except to find the size in words of the object.
		** This takes care of union objects, which only need to
		** init the first member (which may be smaller than some
		** other members).
		*/
		r = vrget();
		ra = vrget();
		code3(P_MOVE, r, litnodes->Nendlab);	/* Get lit's addr */
		r = getmem(r, t, 0, 0);			/* Get izer contents */
		code13(P_MOVE, ra, (s->Svalue+1)-stackoffset);	/* AUTO addr */
		r = stomem(r, ra, sizetype(t), 0);	/* Set up the store */
		relflush(r);				/* Done, flush reg */
		continue;
	    }

	    /* Normal case, izer not a brace-enclosed list.  Handle
	    ** by turning the N_IZ into a Q_ASGN expression.  Note the
	    ** C type of the expression needs to be set (from the Q_IDENT).
	    */
	    n->Nleft->Nop = Q_ASGN;	/* Turn N_IZ into Q_ASGN */
	    n->Nleft->Ntype = n->Nleft->Nleft->Ntype;	/* Set up type */
	    genxrelease(n->Nleft);	/* Generate code, ignore value */
	}
    }
}

/* ---------------------- */
/*	if statement      */
/* ---------------------- */
static void
gif(n)
NODE *n;
{
    SYMBOL *true, *false;
    NODE *nthen, *nelse, *body, *l;

    body = n->Nright;
    nthen = body->Nleft;
    nelse = body->Nright;
    l = n->Nleft;

    /* optimize if to a jump */
    if (nelse == NULL) {
	if (nthen == NULL) {		/* no body of either kind?? */
	    genxrelease(l);		/* yes, just produce condition */
	    return;			/* and return */
	} else if (optgen) switch (nthen->Nop) {
	case Q_BREAK:
	    l->Nendlab = n->Nendlab;
	    gboolean(l, brklabel, 1);
	    return;
	case Q_GOTO:
	    l->Nendlab = n->Nendlab;
	    gboolean(l, nthen->Nxfsym, 1);
	    return;
	case Q_CONTINUE:
	    l->Nendlab = n->Nendlab;
	    gboolean(l, looplabel, 1);
	    return;
	default:
	    ;	/* do nothing */
	}
    }

    /* Try to optimize when conditional expression is a constant.
    ** We have to be careful about flushing the then/else clauses because
    ** control could jump into them using either case or goto labels.
    ** Hence the labchk() to see whether the parse tree contains such labels...
    */
    if (l->Nop == N_ICONST && optgen) {		/* If cond is constant */
	if (l->Niconst && !labchk(nelse)) {	/* if (1) & "else" flushable */
	    if (nthen) {
		nthen->Nendlab = n->Nendlab;
		genstmt(nthen);
	    }
	    return;
	}
	if (!l->Niconst && !labchk(nthen)) {	/* if (0) & "then" flushable */
	    if (nelse) {
		nelse->Nendlab = n->Nendlab;
		genstmt(nelse);
	    }
	    return;
	}
    }

    /* do unoptimized if statement - first get exit label */
    true = ((n->Nendlab == NULL)? newlabel() : n->Nendlab);

    /* then emit code for test and clauses */
    if (nthen) {
	if (nelse == NULL) false = true;
	else switch (nelse->Nop) {
	case Q_GOTO:
	    false = nelse->Nxfsym;
	    nelse = NULL;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -