📄 ccgswi.c
字号:
/* 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 + -