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

📄 ccgen.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	CCGEN.C - Generate code for parse-tree data declarations
**
**	(c) Copyright Ken Harrenstien 1989
**		All changes after v.221, 25-Apr-1988
**	(c) Copyright Ken Harrenstien, SRI International 1985, 1986
**		All changes after v.84, 8-Aug-1985
**
**	Original version (C) 1981  K. Chen
*/

#include "cc.h"
#include "ccgen.h"
#include "ccchar.h"
#include <string.h>

/* Imported (external) functions used herein */
extern void ridlsym(SYMBOL *);				/* CCSYM */
extern SYMBOL *newlabel(void);
extern void freelabel(SYMBOL *);
extern INT sizearray(TYPE *), sizetype(TYPE *);		/* CCSYM */
extern int elembsize(TYPE *);
extern void code5(int, VREG *), 
	code6(int, VREG *, SYMBOL *), codemdx(int, int, SYMBOL *, INT, int), 
        code00 (int, int, int), code12 (int, VREG *, INT),
	code8(int, VREG *, INT), flushcode(void);	/* CCCODE */
extern VREG *vrget(void);
extern void genstmt(NODE *);
extern void genxrelease(NODE *);
extern void				/* CCOUT */
	outmidef(SYMBOL *), outmiref(SYMBOL *), outid(char *), 
	outptr(SYMBOL *, int, INT), outscon(char *, int, int), 
	outlab(SYMBOL *), outnum(INT), outnl(void), 
	outstr(char *);
extern int				/* CCOUT */
	outflt(int, INT *, int), codeseg(void), dataseg(void), prevseg(int);
extern void vrinit(void);			/* CCREG.C */
extern void vrendchk (void);
extern void vrfree (VREG *);

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

#if SYS_CSI		
extern void outpghdr(void), outprolog(SYMBOL *);		/* CCOUT */
#endif

/* Exported functions defined here */
void gencode(NODE *n);		/* Called by CC mainline */

/* Internal Functions */
static void inicode(void), 
	    endcode(void), 
	    gendata(NODE *), 
	    genfunct(NODE *), 
	    gliterals(void), 
	    giz(NODE *, TYPE *, SYMBOL *), 
	    gizword(NODE *, TYPE *, SYMBOL *), 
	    giznull(TYPE *), 
	    gizexpr(NODE *, TYPE *);
static int  gizptr(NODE *); 
static INT  gizconst(NODE *);

static void gizlist(NODE *, TYPE *, SYMBOL *);
static void gizbytes(NODE *, TYPE *, SYMBOL *, int);
static void bytbeg(int), 
	    wdalign(void), 
	    outval(long), 
	    outbyte(long, int), 
	    outzbs(INT), 
	    outzwds(INT);
static INT  bytend(void);
#if 0
static void inicode(), endcode(), gendata(), genfunct(), gliterals();
static void giz(), gizword(), giznull(), gizexpr();
static int gizptr(), gizconst();

static void gizlist();
static void gizbytes();
static void bytbeg(), wdalign(), outval(), outbyte(),
	outzbs(), outzwds();
static INT bytend();
#endif

/* OUT data emission vars. */
static int bsiz;	/* 0 if in word mode, else byte size in bits */
static int bpw;		/* # bytes per word */
static int bpos;	/* P of last byte deposited (TGSIZ_WORD at beg of wd)*/
static INT savlct;	/* Saved loc ctr at start of byte mode */
static INT locctr;	/* Location counter (only for tracking # wds output) */

/* GENCODE - Generate code/data from parse-tree node
*/
void
gencode(NODE *n)
{
    if (n)				/* Ignore null stmts/defs */
	switch (n->Nop) {
	    case N_DATA:
		if (!nerrors) gendata(n); 	/* Generate data definition */
		break;
	    case N_FUNCTION:
		if (!nerrors) genfunct(n);	/* Generate function instrs */
		ridlsym((SYMBOL *)NULL);	/* Flush any local symbols */
		break;
	    default:
		int_error("gencode: bad node %N", n);
 	}
}

/*
 * genfunct ()
 *
 * - Generate machine instruction code for function
 */

static
void
genfunct (NODE* n)
    {
    extern
    int		_word_cnt;	/* KAR-2/91, from CCOUT # wds in function */
    int		i;
    VREG*	r;


    isr = 0;

    if (n->Nleft->Nright)		/* Any local-scope static data defs? */
	gendata(n->Nleft->Nright);	/* Yes, generate them first */

    codeseg ();				/* Ensure in code segment */
    inicode ();				/* Start making code */

    if (mlist)
	{
	/* Emit definitions for register variables. */

	for (i = 0; i < _reg_count; i++)
	    {
	    putc ('\t', out);
	    outid (Reg_Id[i]->Sname);
	    putc ('=', out);
	    outnum (i + r_maxnopreserve + 1); /* FW 2A(47) */
	    putc ('\n', out);
	    }
	}

    outmidef(n->Nleft->Nleft->Nid);	/* Output function label */

    if (curfn != n->Nleft->Nleft->Nid)
	int_error("Bad funct Nid \"%S\"", n->Nleft->Nleft->Nid);

    if (n->Nleft->Nleft->Nid->Sflags & TF_INTERRUPT)
	{				/* FW 2A(52) */
	isr = 1;
	outiprolog ();
	}

    if (profbliss)			/* for BLISS profiler */
	outprolog (curfn);		/* added 09/15/89 by MVS */

    if (n->Nreg <= R_PRESERVE_COUNT)	/* Reg linkage */
	{
        for (i = 0; i < n->Nreg;  i++)
	    {
	    /* Push preserved registers for all functions except main () */   

	    if (!fn_main)
		{	
		code00 (P_PUSH, R_SP, i + r_maxnopreserve + 1); /* FW 2A(47) */
	        ++stackoffset;
	        oline++;
	        }
		
	    /* Initialize all reg parameters (often optimized away later) */

	    if (Reg_Id[i]->Sclass == SC_RARG)
	        {
		r_preserve = i + r_maxnopreserve + 1; /* FW 2A(47) */
		r = vrget();

		/* ex:  MOVE argc,-1(SP) */

		code12(P_MOVE, r, -(Reg_Id[i]->Svalue) - stackoffset);
		vrfree(r);
	        }
	    }
	}
    
    if (maxauto)
	{				/* If any auto vars, */
	code8(P_ADJSP, VR_SP, maxauto);	/* make room for them on stack */
	stackoffset += maxauto;		/* and remember stack bumped */
        }

    genstmt (n->Nright);		/* Generate code for body */
    endcode ();				/* Wrap up code */

    if (vrbfun) 
	fprintf (outmsgs, "%d words\n", _word_cnt);

    _word_cnt = 0;

    if (mlist && (oline > HDR_LINES))
	outpghdr();
}

/* INICODE - Common code generation inits
*/
static void
inicode(void)
{
    previous = NULL;
    litstrings = NULL;
    litnodes = NULL;
    looplabel = brklabel = NULL;
    stackoffset = maxcode = mincode = 0;
    vrinit();
}

/* ENDCODE - Common code generation wrap-ups
*/

static void
endcode(void)
{
    flushcode();	/* Flush out peephole buffer */
    gliterals();	/* Generate any accumulated literals */
    vrendchk();		/* Check to make sure no regs active */
}

/* GENDATA - Generate data definitions
**
** This routine is only called to process static-extent data definitions
** of global or local scope, as opposed to local-extent (automatic) defs
** which are generated by genadata() in CCGEN1.
** Note that the Ntype of the symbol's Q_IDENT node is never examined here;
** the symbol's Stype is used instead.  They are identical except for
** array and function names, when the Ntype is "pointer to <Stype>".
*/

static void
gendata(NODE *n)
{
    NODE *var;
    SYMBOL *s;

    for (; n != NULL; n = n->Nright) {
	if (n->Nop != N_DATA) {
	    int_error("gendata: bad N_DATA %N", n);
	    break;
	}
	if ((var = n->Nleft) != NULL) {	/* For each item on N_DATA list */
	    TYPE *t;
	    if (var->Nop != N_IZ) {
		int_error("gendata: bad datum %N", n);
		break;
	    }
	    s = var->Nleft->Nid;		/* get symbol */
	    for (t = s->Stype; t->Tspec == TS_ARRAY; t = t->Tsubt)
		 ; /* Get to bottom of array */
	    if (!tisanyvolat(t) && tisconst(t))	/* If obj can be pure, */
		codeseg();			/* put it in pure code seg */
	    else dataseg();			/* Else ensure in data seg */
	    outmidef(s);			/* make label for variable */
	    giz(var->Nright, s->Stype, s);	/* do the initialization */
	}
    }
    gliterals();		/* Put literals into code (pure) segment */
}

/* GLITERALS - Emit all accumulated literals
**	Forces use of code segment as literals are expected to be pure,
**	although this is not mandatory.
*/
static void
gliterals(void)
{
    if (litstrings || litnodes) {		
	codeseg();
	flushcode();			/* Make sure all code forced out */
    }
    /* Do node literals first since they may generate more string literals! */
    while (litnodes != NULL) {
	outlab(litnodes->Nendlab);	/* Emit internal label */
	giz(litnodes->Nleft, litnodes->Nleft->Ntype, litnodes->Nendlab);
	freelabel(litnodes->Nendlab);
	litnodes = litnodes->Nright;
    }
    while (litstrings != NULL) {	/* Output literal strings */
	outlab(litstrings->Nsclab);	/* Emit generated label */
	freelabel(litstrings->Nsclab);	/* and then can free it. */
	outtab();			/* spaced out from string. */
	outscon(litstrings->Nsconst,	/* Output string literal, */
		    litstrings->Nsclen,	/* this long */
		    elembsize(litstrings->Ntype));	/* of this bytesize. */
	outnl();				/* End with final newline */
	litstrings = litstrings->Nscnext;	/* chain through list */
    }
}

/* GIZ - Generate initialization value for an object
*/
static void
giz(NODE *n, TYPE *t, SYMBOL *s)
{
    if (n == NULL) {
	giznull(t);	/* nothing there, just make block */
	return;
    }

    switch (t->Tspec) {
    case TS_ARRAY:
    case TS_STRUCT:
    case TS_UNION:
	gizlist(n, t, s);
	return;

    default:				/* initializing simple object */
	gizword(n, t, s);		/* make just one or two words */
	return;
    }
}

/* GIZWORD - emit initialization for a simple var (not array or structure)
**	This closely follows the nisconst() routine in CCDECL which
**	checked for legality while parsing.
*/
static void
gizword(NODE *n, TYPE *t, SYMBOL *s)
{
    if (n->Nop == N_IZLIST) {		/* something in brackets? */
	if (n->Nright != NULL)		/* no more than one allowed */
	    int_error("gizword: izer mismatch for %S %N", s, n);
	gizword(n->Nleft, t, s);	/* Just use inner part */
    } else
	if (!gizconst(n))		/* Try new stuff.  If not constant, */
	    gizexpr(n, t);		/* sigh, make at runtime. */
}

/* GIZCONST - Returns true if expression is an allowable initializer constant,
**	with appropriate code generated.  Otherwise, caller must generate.
*/
/* Return value indicates something about the type of constant: */
#define CT_NOTCON 0	/* not a constant, caller must generate. */
#define CT_CON	1	/* definitely a constant (arith, or a cast pointer) */
#define CT_ADDR	2	/* address of some kind */
#define CT_FUNC	3	/* function address (cannot add or sub from this) */

static struct pointerval {
	SYMBOL *pv_id;		/* Identifier (if any) */
	INT pv_off;		/* Offset from identifier (words or bytes) */
	int pv_bsize;		/* Byte size of pointer (0 = word) */
} pv;

static INT
gizconst(NODE *e)
{
    INT res;

    switch(e->Nop) {

	case N_ICONST:
	    if (tisbyte(e->Ntype)) {	/* Special handling for byte vals */
		res = e->Niconst & ((1<<tbitsize(e->Ntype))-1);	/* Mask off */
		res <<= (TGSIZ_WORD % tbitsize(e->Ntype));	/* Shift */
		outval(res);
		return CT_CON;
	    }
	    /* Normal word value, drop through */
	case N_PCONST:
#if __MSDOS__
	    if (e->Ntype->Tflag & TF_UNSIGN)
		unsign_int = 1;	   /* used in outnum() called by outval() */
	    outval(e->Niconst);		/* Just emit integer constant */
	    unsign_int = 0;
#else    
	    outval(e->Niconst);		/* Just emit integer constant */
#endif
	    return CT_CON;		/* Say simple constant generated */

	case N_FCONST:			/* Invoke rtn from CCOUT */
	    locctr += outflt(e->Ntype->Tspec, (INT *)&e->Nfconst, 0);
	    return CT_CON;		/* Say simple constant generated */


	/* Only the most likely cast conversions are supported here,
	** the others aren't common enough to be worth the
	** extra trouble.
	*/
	case N_CAST:
	    if (e->Ncast == CAST_NONE)
		return gizconst(e->Nleft); /*Most trivial cast just pass on */
	    else if (e->Ncast != CAST_PT_PT)
		return CT_NOTCON;	/* Not a constant */
	    /* Drop through to check for ptr (most likely cast) */

	default:
	    if (e->Ntype->Tspec == TS_PTR) {	/* Is this a pointer? */
		pv.pv_id = NULL;		/* Initialize arg struct */
		pv.pv_off = pv.pv_bsize = 0;
		if ((res = gizptr(e)) != 0) {	/* Fill in the struct */
		    /* Won, output pointer word. */
		    outtab();			/* Won, output it. */
		    outptr(pv.pv_id, pv.pv_bsize, pv.pv_off);
		    outnl();
		    ++locctr;
		    return res;
		}
	    }
    }
    return CT_NOTCON;		/* Must generate instructions */
}

/* GIZPTR - auxiliary for GIZCONST */
static int
gizptr(NODE *n)
{
    INT addoff, off;
    int i;
    TYPE *t;

    switch (n->Nop) {
	case N_CAST:
	    switch ((int) n->Ncast) {
		case CAST_PT_PT:	/* Only ptr-ptr supported */
		    i = gizptr(n->Nleft);	/* Get values for operand */
		    if (i == CT_FUNC		/* Function addr?  If so, */
		      && n->Ntype->Tspec == TS_PTR	/* and converting to */
		      && n->Ntype->Tsubt->Tspec == TS_FUNCT)	/* same, */
			return CT_FUNC;		/* No further conv needed! */

		    if (i != 2)		/* Only normal addrs allowed now */
			return CT_NOTCON;

		    /* First see whether a conversion is actually needed */
		    i = elembsize(n->Ntype);	/* Desired bytesize of ptr */
		    if (i == 0) {		/* Casting to (void *)? */
			if (tischarpointer(n->Nleft->Ntype)) /* from (char*)?*/
			    return CT_ADDR;	/* Yes, no change */
			i = TGSIZ_CHAR;		/* Else cvt to this bsize */
		    } else if (!elembsize(n->Nleft->Ntype)) { /* fm (void*)? */
			if (tischarpointer(n->Ntype))	      /* to (char*)?*/
			    return CT_ADDR;	/* Yes, no change */
		    }
		    if (i >= TGSIZ_WORD) i = 0;
		    if (i == pv.pv_bsize)	/* If already OK, */
			return CT_ADDR;		/* just return success */

		    /* Different sizes.  Check to see if boundaries match.
		    ** This takes care of 9<->18 bit conversions
		    ** (as well as any others)
		    */
		    if (i && pv.pv_bsize) {	/* Both are byte ptrs? */
			if (pv.pv_bsize < i && (i%pv.pv_bsize == 0)) {
			    pv.pv_off /= (i/pv.pv_bsize);
			    pv.pv_bsize = i;
			    return CT_ADDR;
			}
			if (i < pv.pv_bsize && (pv.pv_bsize%i == 0)) {
			    pv.pv_off *= (pv.pv_bsize/i);
			    pv.pv_bsize = i;
			    return CT_ADDR;
			}
		    }

		    /* Odd sizes.  First must always cvt to a word pointer */
		    if (pv.pv_bsize) {
			pv.pv_off /= (TGSIZ_WORD/pv.pv_bsize);
			pv.pv_bsize = 0;
		    }
		    /* Casting to byte ptr of some kind? */
		    if (i && (i < TGSIZ_WORD)) {
			pv.pv_off *= (TGSIZ_WORD/i);
			pv.pv_bsize = i;
		    }
		    return CT_ADDR;

		default:		/* Only ptr-to-ptr supported for now */
		    break;
	    }
	    return CT_NOTCON;


	case N_SCONST:
	    pv.pv_id = n->Nsclab = newlabel();	/* Get fwd lab for later use */
	    n->Nscnext = litstrings;	/* Link on string stack */
	    litstrings = n;		/* Now on stack */
	    pv.pv_bsize = elembsize(n->Ntype);	/* Set bsize */
	    return CT_ADDR;			/* Say address generated */

	case Q_IDENT:
		/* Identifier.  See documentation for Q_IDENT in cctoks.h
		** for explanation of this method of testing.
		*/
	    pv.pv_id = n->Nid;			/* Remember it */
	    switch (n->Nid->Stype->Tspec) {

⌨️ 快捷键说明

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