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

📄 ccgswi.c

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

#include "cc.h"
#include "ccgen.h"
#include <stdlib.h>	/* qsort */

/* Exported functions */
void gswitch(NODE *n);

/* Imported functions */
extern VREG *genexpr(NODE *);
extern void codlabel(SYMBOL *), codgolab(SYMBOL *);	/* CCCODE */
extern SYMBOL *newlabel(void);		/* CCSYM */
extern void genstmt(NODE *);			/* CCGEN1 */
extern void code00(int, int, int), code1(int, VREG *, INT), 
	code6(int, VREG *, SYMBOL *), code8(int, VREG *, INT), 
	code15(int, SYMBOL *, INT, VREG *), 
	code16(int, VREG *, SYMBOL *, VREG *), code17(INT);
extern void freelabel(SYMBOL *);
extern VREG *vrdget(void);
extern void vrfree (VREG *);
extern VREG *vrget(void);
extern void vrnarrow (VREG *);
extern int vrreal (VREG *);
extern int vrstoreal (VREG *, VREG *);
extern void vrufcreg(VREG *);

/* Internal functions */
struct lablist {		/* To hold labs for sorting */
    SYMBOL *label;		/* label itself */
    int caseval;		/* value to jump to label on */
};
static void casejump(VREG *a, struct lablist *b, INT c, struct lablist *d, 
	SYMBOL *e);
static INT countcases(NODE *a, struct lablist b[], SYMBOL **c, int d, int e);
static int labcomp(const void *, const void *),
	   unique(int a, struct lablist b[], int c, INT *d);

/*
** Generate code for switch statement
*/
void
gswitch (NODE *n)
{
    SYMBOL *saveb, *deflab;
    VREG *r;
    INT ncase;
    struct lablist caselab[MAXCASE];
    struct lablist ltable[MAXCASE];	/* Table for casejump to use */

    saveb = brklabel;			/* save old break label */
    brklabel = (n->Nendlab != NULL)? n->Nendlab : newlabel(); /* get new one */

    r = genexpr(n->Nleft);		/* r selects case */
    deflab = NULL;			/* assume no default */
#if 0
    ncase = countcases(n->Nxswlist, caselab, &deflab, 0, 1);
#else
    ncase = countcases (n->Nright, caselab, &deflab, 0, 1);
#endif

    /* at this point, ready to create jump tables */
    casejump(r, caselab, ncase, ltable, ((deflab)? deflab : brklabel));
    vrfree(r);				/* don't need register after this */
    if (n->Nright) {			/* if we have a body */
	n->Nright->Nendlab = brklabel;	/* remember where to exit to */
	genstmt(n->Nright);		/* make individual cases */
    }
    if (n->Nendlab == NULL) codlabel(brklabel); /* emit new break label */
    brklabel = saveb;			/* and restore old one */
}

#if 0
static INT
countcases(n, caselab, deflab, ncase, ismain)
NODE *n;
struct lablist caselab[];
SYMBOL **deflab;
{
    INT ncases = 0;
    SYMBOL **thelab;

    for (; n != NULL; n = n->Nright) {
      switch (n->Nop) {
	default:		/* Non-case node on switch list?? */
	    int_error("countcases: non-case %N", n);
	    return -1;

	case Q_CASE:
	    if (ncases >= MAXCASE) {
		int_error("countcases: %ld cases", (INT) ncases);
		return -1;
	    }
	    thelab = &caselab[ncases].label;
	    caselab[ncases++].caseval = n->Nxfint;
	    break;

	case Q_DEFAULT:
	    thelab = deflab;
	    break;

      }		/* end of switch */
	/*
	** Here when it was a case label or default.
	**
	** Before making a label for this one, we look for further cases
	** in the statement it is part of so that if we see a break, continue,
	** goto, label, or other case that becomes a label as the statement
	** that this is a label to, we can re-use the same label.
	** Otherwise, we turn this one into a LABEL node so that it
	** can be generated properly.
	*/
	if (optgen) {
	    if (n->Nleft) switch (n->Nleft->Nop) {
	    case N_LABEL:
	    case Q_GOTO:
	    case Q_CASE:
/* PROBLEM: Nxfsym hasn't yet been set for succeeding case labels!
 * this optimization will have to be a separate recursive routine.
 */
		*thelab = (n->Nxfsym = n->Nleft->Nxfsym);
		n->Nop = n->Nleft->Nop;	/* copy node across */
		n->Nleft = n->Nleft->Nleft;	/* so as not to dup label */
		return ncase;
	    case Q_BREAK:
/* PROBLEM: don't have ismain, can't know whether this break is
* the right one or not.  Parser may have to add level numbering.
*/
		if (!ismain) break;		/* only if still top level */
		*thelab = brklabel;		/* use break label */
		n->Nop = Q_BREAK;		/* propagate back */
		return ncase;
	    case Q_CONTINUE:
/* Same ismain problem as for break above. */
		if (!ismain) break;		/* only if still top level */
		*thelab = looplabel;	/* use loop label */
		n->Nop = Q_CONTINUE;		/* propagate back */
		return ncase;
	    }				/* end switch(n->Nleft->Nop) */
	}				/* end if(optimize) */

	/* didn't find other label, just make a new one */
	n->Nop = Q_CASE;		/* remember either case or default */
	n->Nxfsym = (*thelab = newlabel()); /* make label value */

    }		/* end of loop */
    return ncases;
}
#else /* Old stuff */
/*
** Find case labels and defaults
**
** These should have been collected together by casestmt(),
** but for now we go find them all again.  Rewrite me.
*/

static INT
countcases (n, caselab, deflab, ncase, ismain)
NODE *n;
struct lablist caselab[];
SYMBOL **deflab;
{
    INT val;
    SYMBOL **thelab;

    if (n == NULL) return ncase;

    while (1) {
	switch (n->Nop) {
	case N_STATEMENT:
	    for (; n != NULL; n = n->Nright)
		if (n->Nleft)
		    ncase = countcases(n->Nleft,caselab,deflab,ncase,ismain);
	    return ncase;
	case Q_IF:			/* yes, people really put cases */
	    n = n->Nright;		/* inside these things... */
	    ncase = countcases(n->Nright, caselab, deflab, ncase, ismain);
	case N_LABEL:
	    if ((n = n->Nleft) == NULL) return ncase; /* get body */
	    continue;

	case Q_DO:			/* these clear ismain */
	case Q_FOR:
	case Q_WHILE:
	    ismain = 0;			/* don't pass break up through here */
	    if ((n = n->Nleft) == NULL) return ncase; /* get body */
	    continue;			/* back up to try again */

	case Q_CASE:
	    val = n->Nxfint;
	    if (ncase >= MAXCASE) {
		int_error("countcases: %d cases", ncase);
		return 0;
	    }
	    thelab = &caselab[ncase].label;
	    caselab[ncase++].caseval = val;
	    break;

	case Q_DEFAULT:
	    thelab = deflab;
	    break;

	default:
	    return ncase;
	}
	break;				/* DEFAULT or CASE, break from loop */
    }

    /*
    ** Here when it was a case label or default.
    **
    ** Before making a label for this one, we look for further cases
    ** in the statement it is part of so that if we see a break, continue,
    ** goto, label, or other case that becomes a label as the statement
    ** that this is a label to, we can re-use the same label.
    ** Otherwise, we turn this one into a LABEL node so that it
    ** can be generated properly.
    */

    ncase = countcases(n->Nleft, caselab, deflab, ncase, ismain);
    if (optgen) {
	if (n->Nleft == NULL) {
#if 0
	/* What the HELL was this for??  It's completely wrong and makes
	** broken code!! --KLH
	*/
	    if (ismain) {
		n->Nop = Q_BREAK;	/* turn final null stmt into break */
		*thelab = brklabel;	/* remember where it goes */
		return ncase;
	    }
#endif
	} else switch (n->Nleft->Nop) {
	case N_LABEL:
	case Q_GOTO:
	case Q_CASE:
	    *thelab = (n->Nxfsym = n->Nleft->Nxfsym);
	    n->Nop = n->Nleft->Nop;	/* copy node across */
	    n->Nleft = n->Nleft->Nleft;	/* so as not to dup label */
	    return ncase;
	case Q_BREAK:
	    if (!ismain) break;		/* only if still top level */
	    *thelab = brklabel;		/* use break label */
	    n->Nop = Q_BREAK;		/* propagate back */
	    return ncase;
	case Q_CONTINUE:
	    if (!ismain) break;		/* only if still top level */
	    *thelab = looplabel;	/* use loop label */
	    n->Nop = Q_CONTINUE;		/* propagate back */
	    return ncase;
	default:
	    ;	/* do nothing */
	}				/* end switch(n->Nleft->Nop) */
    }					/* end if(optimize) */

    /* didn't find other label, just make a new one */
    n->Nop = Q_CASE;			/* remember either case or default */
    n->Nxfsym = (*thelab = newlabel()); /* make label value */
    return ncase;			/* say how many we got */

⌨️ 快捷键说明

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