/* Copyright (c) 1980 Regents of the University of California */
static char sccsid
[] = "@(#)pccaseop.c 1.4 10/8/80";
* and the rest of the file
* its constant label, line number (for errors), and location label.
* the P2FORCE operator puts its operand into a register.
* these to keep from thinking of it as r0 all over.
* given a tree for a case statement, generate code for it.
* this computes the expression into a register,
* puts down the code for each of the cases,
* and then decides how to do the case switching.
* [3] list of cased statements:
* [2] list of constant labels
* find out the type of the case expression
* even if the expression has errors (exprtype == NIL), continue.
exprtype
= rvalue( (int *) tcase
[2] , NIL
, RREQ
);
if ( isnta( exprtype
, "bcsi" ) ) {
error("Case selectors cannot be %ss" , nameof( exprtype
) );
if ( exprtype
-> class != RANGE
) {
rangetype
= exprtype
-> type
;
if ( rangetype
== NIL
) {
low
= rangetype
-> range
[0];
high
= rangetype
-> range
[1];
* put expression into a register
* save its c-type and jump to the code to do the switch.
putop( P2FORCE
, P2INT
);
putdot( filename
, line
);
exprctype
= p2type( exprtype
);
* count the number of cases
* and allocate table for cases, lines, and labels
* default case goes in ctab[0].
for ( cstatlp
= tcase
[3] ; cstatlp
!= NIL
; cstatlp
= cstatlp
[2] ) {
for ( casep
= cstatp
[2] ; casep
!= NIL
; casep
= casep
[2] ) {
ctab
= (struct ct
*) malloc( count
* sizeof( struct ct
) );
if ( ctab
== (struct ct
*) 0 ) {
error("Ran out of memory (case)");
* pick up default label and label for after case statement.
ctab
[0].clabel
= getlab();
* generate code for each case
* filling in ctab for each.
* nr is for error if no case falls out bottom.
for ( cstatlp
= tcase
[3] ; cstatlp
!= NIL
; cstatlp
= cstatlp
[2] ) {
for ( casep
= cstatp
[2] ; casep
!= NIL
; casep
= casep
[2] ) {
if( exprtype
== NIL
|| con
.ctype
== NIL
) {
if ( incompat( con
.ctype
, exprtype
, NIL
) ) {
cerror("Case label type clashed with case selector expression type");
if ( con
.crval
< low
|| con
.crval
> high
) {
error("Case label out of range");
ctab
[ count
].cconst
= con
.crval
;
ctab
[ count
].cline
= line
;
ctab
[ count
].clabel
= label
;
* default action is to call error
putlab( ctab
[0].clabel
);
putleaf( P2ICON
, 0 , 0 , ADDTYPE( P2FTN
| P2INT
, P2PTR
) , "_ERROR" );
putleaf( P2ICON
, ECASE
, 0 , P2INT
, 0 );
putleaf( P2REG
, FORCENUMBER
, 0 , P2INT
, 0 );
putop( P2LISTOP
, P2INT
);
putdot( filename
, line
);
qsort( &ctab
[1] , count
, sizeof (struct ct
) , casecmp
);
for ( ctp
= &ctab
[1] ; ctp
< &ctab
[ count
] ; ctp
++ ) {
if ( ctp
[0].cconst
== ctp
[1].cconst
) {
error("Multiply defined label in case, lines %d and %d" ,
ctp
[0].cline
, ctp
[1].cline
);
* choose a switch algorithm and implement it:
* direct switch >= 1/3 full and >= 4 cases.
* binary switch not direct switch and > 8 cases.
* ifthenelse not direct or binary switch.
if ( ctab
[ count
].cconst
- ctab
[1].cconst
< 3 * count
&& count
>= 4 ) {
directsw( ctab
, count
);
} else if ( count
> 8 ) {
binarysw( ctab
, count
);
int fromlabel
= getlab();
putprintf( " casel %s,$%d,$%d" , 0 , FORCENAME
,
ctab
[1].cconst
, ctab
[ count
].cconst
- ctab
[1].cconst
);
if ( j
== ctab
[ i
].cconst
) {
putprintf( " .word " , 1 );
putprintf( PREFIXFORMAT
, 1 , LABELPREFIX
, ctab
[ i
].clabel
);
putprintf( PREFIXFORMAT
, 0 , LABELPREFIX
, fromlabel
);
putprintf( " .word " , 1 );
putprintf( PREFIXFORMAT
, 1 , LABELPREFIX
, ctab
[ 0 ].clabel
);
putprintf( PREFIXFORMAT
, 0 , LABELPREFIX
, fromlabel
);
putjbr( ctab
[0].clabel
);
* special case out default label and start recursion.
bsrecur( ctab
[0].clabel
, &ctab
[0] , count
);
* recursive log( count ) search.
bsrecur( deflabel
, ctab
, count
)
putprintf( " jbr L%d" , 0 , deflabel
);
} else if ( count
== 1 ) {
putprintf( " cmpl %s,$%d" , 0 , FORCENAME
, ctab
[1].cconst
);
putprintf( " jeql L%d" , 0 , ctab
[1].clabel
);
putprintf( " jbr L%d" , 0 , deflabel
);
int half
= ( count
+ 1 ) / 2;
putprintf( " cmpl %s,$%d" , 0 , FORCENAME
, ctab
[ half
].cconst
);
putprintf( " jgtr L%d" , 0 , gtrlabel
);
putprintf( " jeql L%d" , 0 , ctab
[ half
].clabel
);
bsrecur( deflabel
, &ctab
[0] , half
- 1 );
putprintf( "L%d:" , 0 , gtrlabel
);
bsrecur( deflabel
, &ctab
[ half
] , count
- half
);
for ( i
= 1 ; i
<= count
; i
++ ) {
putprintf( " cmpl %s,$%d" , 0 , FORCENAME
, ctab
[ i
].cconst
);
putprintf( " jeql L%d" , 0 , ctab
[ i
].clabel
);
putprintf( " jbr L%d" , 0 , ctab
[0].clabel
);
if ( this -> cconst
< that
-> cconst
) {
} else if ( this -> cconst
> that
-> cconst
) {