BSD 4 release
[unix-history] / usr / src / cmd / pi / case.c
/* Copyright (c) 1979 Regents of the University of California */
static char sccsid[] = "@(#)case.c 1.1 8/27/80";
#include "whoami.h"
#include "0.h"
#include "tree.h"
#include "opcode.h"
/*
* The structure used to
* hold information about
* each case label.
*/
struct ct {
long clong;
int cline;
};
#ifdef OBJ
/*
* Caseop generates the
* pascal case statement code
*/
caseop(r)
int *r;
{
register struct nl *p;
register struct ct *ctab;
register *cs;
int *cl;
double low, high;
short *brtab;
char *brtab0;
char *csend;
int w, i, j, m, n;
int nr, goc;
goc = gocnt;
/*
* Obtain selector attributes:
* p type
* w width
* low lwb(p)
* high upb(p)
*/
p = rvalue((int *) r[2], NLNIL , RREQ );
if (p != NIL) {
if (isnta(p, "bcsi")) {
error("Case selectors cannot be %ss", nameof(p));
p = NIL;
} else {
cl = p;
if (p->class != RANGE)
cl = p->type;
if (cl == NIL)
p = NIL;
else {
w = width(p);
#ifdef DEBUG
if (hp21mx)
w = 2;
#endif
low = cl->range[0];
high = cl->range[1];
}
}
}
/*
* Count # of cases
*/
n = 0;
for (cl = r[3]; cl != NIL; cl = cl[2]) {
cs = cl[1];
if (cs == NIL)
continue;
for (cs = cs[2]; cs != NIL; cs = cs[2])
n++;
}
/*
* Allocate case table space
*/
ctab = i = malloc(n * sizeof *ctab);
if (i == -1) {
error("Ran out of memory (case)");
pexit(DIED);
}
/*
* Check the legality of the
* labels and count the number
* of good labels
*/
m = 0;
for (cl = r[3]; cl != NIL; cl = cl[2]) {
cs = cl[1];
if (cs == NIL)
continue;
line = cs[1];
for (cs = cs[2]; cs != NIL; cs = cs[2]) {
gconst(cs[1]);
if (p == NIL || con.ctype == NIL)
continue;
if (incompat(con.ctype, p, NIL )) {
cerror("Case label type clashed with case selector expression type");
continue;
}
if (con.crval < low || con.crval > high) {
error("Case label out of range");
continue;
}
ctab[m].clong = con.crval;
ctab[m].cline = line;
m++;
}
}
/*
* Check for duplicate labels
*/
for (i = 0; i < m; i++)
for (j = 0; j < m; j++)
if (ctab[i].clong == ctab[j].clong) {
if (i == j)
continue;
if (j < i)
break;
error("Multiply defined label in case, lines %d and %d", ctab[i].cline, ctab[j].cline);
}
/*
* Put out case operator and
* leave space for the
* branch table
*/
if (p != NIL) {
put(2, O_CASE1OP + (w >> 1), n);
brtab = brtab0 = lc;
putspace(n * 2);
put(1, O_CASEBEG);
for (i=0; i<m; i++)
put( 2 , O_CASE1 + (w >> 1), ctab[i].clong);
put(1, O_CASEEND);
}
csend = getlab();
put(2, O_TRA, csend);
/*
* Free the case
* table space.
*/
free(ctab);
/*
* Generate code for each
* statement. Patch branch
* table to beginning of each
* statement and follow each
* statement with a branch back
* to the TRA above.
*/
nr = 1;
for (cl = r[3]; cl != NIL; cl = cl[2]) {
cs = cl[1];
if (cs == NIL)
continue;
if (p != NIL)
for (cs = cs[2]; cs != NIL; cs = cs[2]) {
patchfil(brtab - 1, lc - brtab0, 1);
brtab++;
}
cs = cl[1];
putcnt();
level++;
statement(cs[3]);
nr &= noreach;
noreach = 0;
put(2, O_TRA, csend);
level--;
if (gotos[cbn])
ungoto();
}
/*
* Patch the termination branch
*/
patch(csend);
noreach = nr;
if (goc != gocnt)
putcnt();
}
#endif OBJ