home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
files
/
language
/
sozobon2
/
gsub.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-23
|
10KB
|
541 lines
/* Copyright (c) 1988 by Sozobon, Limited. Author: Johann Ruegg
*
* Permission is granted to anyone to use this software for any purpose
* on any computer system, and to redistribute it freely, with the
* following restrictions:
* 1) No charge may be made other than reasonable charges for reproduction.
* 2) Modified versions must be clearly marked as such.
* 3) The authors are not responsible for any harmful consequences
* of using this software, even if they result from defects in it.
*
* gsub.c
*
* Various code generation subroutines
* Includes generation of switches and
* conversion of type lists to simple type,size.
*/
#include <stdio.h>
#include "param.h"
#include "bstok.h"
#include "tytok.h"
#include "flags.h"
#include "nodes.h"
#include "gen.h"
#define isimmed(np) ((np)->g_flags & IMMEDID)
#define isareg(np) ((np)->g_token == REGVAR && (np)->g_rno >= AREG)
extern cctest;
extern xflags[];
#define debug xflags['s'-'a']
gen_brt(np, lbl)
NODEP np;
{
p2_expr(&np);
mustty(np, R_SCALAR);
br_sub(np, 0, lbl);
}
gen_brf(np, lbl)
NODEP np;
{
p2_expr(&np);
mustty(np, R_SCALAR);
br_sub(np, 1, lbl);
}
br_sub(np, rev, lbl)
NODEP np;
{
int i;
switch (np->e_token) {
case DOUBLE '&':
br_split(np, lbl, rev);
return;
case DOUBLE '|':
br_split(np, lbl, 2+rev);
return;
}
genx(np, FORCC);
i = cctest;
if (i) {
if (rev)
/* reverse truth */
i = (i&1) ? i+1 : i-1;
out_b(i, lbl);
}
}
br_split(np, lbl, n)
NODEP np;
{
int nlbl;
if (n == 0 || n == 3)
nlbl = new_lbl();
else
nlbl = lbl;
br_sub(np->n_left, n<2, nlbl);
br_sub(np->n_right, n&1, lbl);
freeunit(np);
if (nlbl != lbl)
def_lbl(nlbl);
}
/* generate switch
np - list of nodes with value,label pairs (sorted)
dlbl - default label or -1
*/
#undef min
#undef max
gen_switch(np, odlbl)
NODEP np;
{
int n,min,max;
int dlbl;
register NODEP p;
if (debug) {
printf("gs %d ", odlbl);
printnode(np);
}
/* if no default, make one! */
if (odlbl < 0)
dlbl = new_lbl();
else
dlbl = odlbl;
n = 0;
for (p=np; p; p=p->n_next) {
if (n == 0)
min = max = p->c_casev;
else
max = p->c_casev;
n++;
}
if (n <= C_SIMPLE)
simple_sw(np,odlbl);
else if (n >= max/C_RATIO - min/C_RATIO)
table_sw(np,dlbl,min,max);
else {
half_sw(np,dlbl,max/2+min/2,n);
goto out; /* free already done */
}
freenode(np);
out:
if (odlbl < 0)
def_lbl(dlbl);
}
/* simple if-else type switch
dlbl may be -1 -> fall through
does not free np
*/
simple_sw(np, dlbl)
register NODEP np;
{
while (np) {
out_d0cmp(np->c_casev);
out_b(B_EQ, np->c_casel);
np = np->n_next;
}
if (dlbl >= 0)
out_br(dlbl);
}
/* use table switch
dlbl is not -1
does not free np
*/
table_sw(np, dlbl, min, max)
NODEP np;
{
out_d0cmp(min);
out_b(B_LT, dlbl);
out_d0cmp(max);
out_b(B_GT, dlbl);
if (min)
out_d0sub(min);
out_tsw();
while (np) {
while (min < np->c_casev) {
out_tlbl(dlbl);
min++;
}
out_tlbl(np->c_casel);
min++;
np = np->n_next;
}
}
/* cut switch in half (by value)
dlbl is not -1
will free np
*/
half_sw(np, dlbl, cut, n)
NODEP np;
{
register NODEP p, last;
int nlo, nhi;
int l1;
for (p=np; p->c_casev < cut; p = p->n_next)
last = p;
/* we KNOW both pieces are non-NULL ! */
last->n_next = NULL;
last = p;
nlo = 0;
nhi = 0;
for (p=np; p; p=p->n_next)
nlo++;
nhi = n - nlo;
if (nhi == 1) { /* switch hi and low */
p = np;
np = last;
last = p;
nlo = 1;
nhi = n-1;
}
if (nlo == 1) { /* also nhi == 1 */
out_d0cmp(np->c_casev);
out_b(B_EQ, np->c_casel);
freenode(np);
gen_switch(last, dlbl);
return;
}
l1 = new_lbl();
out_d0cmp(cut);
out_b(B_GE, l1);
gen_switch(np, dlbl);
def_lbl(l1);
gen_switch(last, dlbl);
}
istempa(np)
register NODEP np;
{
if (np->g_token == OREG && istemp(np->g_rno))
return 1;
return 0;
}
char chunkch[] = {0, 'b', 'w', 0, 'l'};
strasn(np)
NODEP np;
{
int r;
long count, i;
int chunk, l;
char buf[40];
int lisa, risa, rissp;
int useloop;
if (np->g_ty != ET_A)
return 0;
count = np->g_bsize;
chunk = np->g_sz;
if (count == 1) {
return 0;
}
useloop = count > 3;
lisa = istempa(np->n_left);
risa = istempa(np->n_right);
rissp = (np->n_right->g_token == PUSHER);
if (lisa)
r = np->n_left->g_rno;
else
r = ralloc(AREG); /* R0 */
indir(np, r);
np->g_offs = -(count*chunk);
if (risa)
np->g_r1 = np->n_right->g_rno;
else if (rissp)
np->g_r1 = AREG+7;
else
tempr(np, AREG); /* R1 */
if (useloop)
tempr(np, 0); /* R2 */
if (!lisa || np->n_left->g_offs)
addcode(np, "\tlea\t<A,R0\n");
if (!(risa||rissp) || np->n_right->g_offs)
addcode(np, "\tlea\t>A,R1\n");
if (useloop) {
sprintf(buf, "\tmove.w\t#%d,R2\n", (int)(count-1));
addcode(np, buf);
l = new_lbl();
sprintf(buf, "'L%d:\tmove.%c\t(R1)+,(R0)+\n",l,chunkch[chunk]);
addcode(np, buf);
sprintf(buf, "\tdbra\tR2,'L%d\n", l);
addcode(np, buf);
} else for (i=0; i<count; i++) {
sprintf(buf, "\tmove.%c\t(R1)+,(R0)+\n", chunkch[chunk]);
addcode(np, buf);
}
if (chunk == 1 && count & 1 && rissp)
addcode(np, "\tmove.b\t(sp)+,R2\n");
return 1;
}
strret(np)
NODEP np;
{
extern funstrl;
strsub(np, funstrl);
}
strpush(np)
NODEP np;
{
return strsub(np, 0);
}
strxpush(np)
NODEP np;
{
strsub(np, -1);
}
strsub(np, tolbl)
register NODEP np;
{
long count, i;
int chunk, l;
char buf[40];
char *frstr;
register NODEP tp;
int useloop;
count = np->g_bsize;
chunk = np->g_sz;
if (chunk == 1 && count & 1 && tolbl <= 0)
count++;
useloop = count > 3;
if (useloop && np->g_r2 == -1)
np->g_r2 = ralloc(0);
/* set up 'from' address */
if (np->g_token == OREG && istemp(np->g_rno)) {
frstr = "R0";
if (np->g_offs)
addcode(np, "\tlea\tA,R0\n");
} else if (tolbl == -1 && (tp = np->n_left) &&
tp->g_token == OREG && istemp(tp->g_rno) &&
tp->g_offs == 0) {
frstr = "R1";
np->g_r1 = tp->g_rno;
} else {
frstr = "R1";
if (np->g_r1 == -1)
np->g_r1 = ralloc(AREG);
if (tolbl == -1)
addcode(np, "\tlea\t<A,R1\n");
else
addcode(np, "\tlea\tA,R1\n");
}
/* set up 'to' address */
if (tolbl > 0) {
sprintf(buf, "\tmove.l\t#'L%d,H\n", tolbl);
addcode(np, buf);
} else {
sprintf(buf, "\tsub\t#%d,sp\n", (int)(count*chunk));
addcode(np, buf);
addcode(np, "\tmove.l\tsp,H\n");
}
/* generate copy loop */
if (useloop) {
sprintf(buf, "\tmove.w\t#%d,R2\n", (int)(count-1));
addcode(np, buf);
l = new_lbl();
sprintf(buf, "'L%d:\tmove.%c\t(%s)+,(H)+\n", l, chunkch[chunk],
frstr);
addcode(np, buf);
sprintf(buf, "\tdbra\tR2,'L%d\n", l);
addcode(np, buf);
} else for (i=0; i<count; i++) {
sprintf(buf, "\tmove.%c\t(%s)+,(H)+\n", chunkch[chunk],
frstr);
addcode(np, buf);
}
return count*chunk;
}
specasn(np, flags)
NODEP np;
{
NODEP lp = np->n_left, rp = np->n_right;
int r;
if (rp->g_token == ICON && isimmed(rp)) {
rinherit(np);
if (rp->g_offs == 0)
addcode(np, isareg(lp) ? "\tsub.S\t<A,<A\n"
: "\tclr.S\t<A\n");
else
addcode(np, "\tmove.S\t>A,<A\n");
return 1;
}
if (rp->g_token == OREG && isimmed(rp)) {
rp->g_flags &= ~IMMEDID;
if (isareg(lp)) {
inherit(np);
addcode(np, "\tlea\t>A,A\n");
} else if (rp->g_offs == 0) {
retreg(np, rp->g_rno);
addcode(np, "\tmove.l\tA,<A\n");
} else {
if (istemp(rp->g_rno))
r = rp->g_rno;
else
r = ralloc(AREG);
retreg(np, r);
addcode(np, "\tlea\t>A,A\n");
addcode(np, "\tmove.l\tA,<A\n");
}
return 1;
}
return 0;
}
untype(np)
register NODEP np;
{
if (np == NULL || np->n_tptr == NULL) {
printf("? NULL untype ");
return;
}
switch (np->e_type) {
case E_BIN:
untype(np->n_right);
/* fall through */
case E_UNARY:
if (np->e_token == '.' && np->e_fldw) {
np->g_fldw = np->e_fldw;
np->g_fldo = np->e_fldo;
} else
np->g_fldw = 0;
untype(np->n_left);
}
get_tyinf(np);
if ((np->n_flags & N_COPYT) == 0)
freenode(np->n_tptr);
np->n_tptr = NULL; /* is g_code */
np->g_betw = NULL;
}
static char bty[] = {
ET_U, ET_U, ET_S, ET_S, ET_U, ET_S, ET_S, ET_F, ET_F, 0
};
static char bsz[] = {
SIZE_C, SIZE_L, SIZE_L, SIZE_S, SIZE_U,
SIZE_I, SIZE_C, SIZE_F, SIZE_D, 0
};
get_tyinf(np)
register NODEP np;
{
NODEP tp = np->n_tptr;
int n;
long offs;
offs = np->e_offs;
/* inherit name,token,left,right,nmx from common
and token, flags, type, sc from enode */
switch (tp->t_token) {
case K_STRUCT:
case K_UNION:
np->g_ty = ET_A;
/* determine copy chunk size and number of chunks */
if (tp->t_aln & 1) {
if (tp->t_size & 1)
fatal("aligned struct with odd size");
if (tp->t_size & 2) {
np->g_bsize = tp->t_size >> 1;
np->g_sz = 2;
} else {
np->g_bsize = tp->t_size >> 2;
np->g_sz = 4;
}
} else {
np->g_bsize = tp->t_size;
np->g_sz = 1;
}
break;
case '(':
break;
case STAR:
np->g_ty = ET_U;
np->g_sz = SIZE_P;
break;
default:
n = tp->t_token-FIRST_BAS;
np->g_ty = bty[n];
np->g_sz = bsz[n];
}
np->g_offs = offs; /* different place */
}
addcode(np, s)
register NODEP np;
char *s;
{
NODEP tp;
int i, c;
while (np->g_code)
np = np->g_code;
tp = allocnode();
np->g_code = tp;
np->n_flags &= ~N_COPYT;
i = strlen(s);
if (i < NMXSIZE) { /* fits in one */
strcpy(tp->n_name, s);
return;
}
/* need to split it */
i = NMXSIZE-1;
c = s[i-1];
if (c == '<' || c == '>' || (c>='A' && c<='Z')) /* special */
i--;
strncpy(tp->n_name, s, i);
tp->n_name[i] = 0;
addcode(tp, &s[i]);
}