Pristine Ack-5.5
[Ack-5.5.git] / lang / cem / cemcom / switch.c
1 /*
2  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
3  * See the copyright notice in the ACK home directory, in the file "Copyright".
4  */
5 /* $Id: switch.c,v 3.26 1994/06/24 12:06:27 ceriel Exp $ */
6 /*      S W I T C H - S T A T E M E N T  A D M I N I S T R A T I O N    */
7
8 #include        "lint.h"
9 #include        "nofloat.h"
10 #ifndef LINT
11 #include        <em.h>
12 #else
13 #include        "l_em.h"
14 #endif  /* LINT */
15 #include        "debug.h"
16 #include        "botch_free.h"
17 #include        <alloc.h>
18 #include        "density.h"
19 #include        "Lpars.h"
20 #include        "idf.h"
21 #include        "label.h"
22 #include        "arith.h"
23 #include        "switch.h"
24 #include        "code.h"
25 #include        "assert.h"
26 #include        "expr.h"
27 #include        "type.h"
28 #include        "noRoption.h"
29
30 extern char options[];
31 int density = DENSITY;
32
33 compact(nr, low, up)
34         arith low, up;
35 {
36         /*      Careful! up - low might not fit in an arith. And then,
37                 the test "up-low < 0" might also not work to detect this
38                 situation! Or is this just a bug in the M68020/M68000?
39         */
40         arith diff = up - low;
41
42         return (nr == 0 || (diff >= 0 && diff / nr <= (density - 1)));
43 }
44
45 static struct switch_hdr *switch_stack = 0;
46
47 /* (EB 86.05.20) The following rules hold for switch statements:
48         - the expression E in "switch(E)" is cast to 'int' (RM 9.7)
49         - the expression E in "case E:" must be 'int' (RM 9.7)
50         - the values in the CSA/CSB tables are words (EM 7.4)
51         For simplicity, we suppose int_size == word_size.
52 */
53
54 code_startswitch(expp)
55         struct expr **expp;
56 {
57         /*      Check the expression, stack a new case header and
58                 fill in the necessary fields.
59         */
60         register label l_table = text_label();
61         register label l_break = text_label();
62         register struct switch_hdr *sh = new_switch_hdr();
63         int fund = any2arith(expp, SWITCH);     /* INT, LONG or DOUBLE */
64         
65         switch (fund) {
66         case LONG:
67 #ifndef NOROPTION
68                 if (options['R'])
69                         warning("long in switch (cast to int)");
70 #endif
71                 int2int(expp, int_type);
72                 break;
73 #ifndef NOFLOAT
74         case DOUBLE:
75                 error("float/double in switch");
76                 erroneous2int(expp);
77                 break;
78 #endif /* NOFLOAT */
79         }
80         stack_stmt(l_break, NO_LABEL);
81         sh->sh_break = l_break;
82         sh->sh_default = 0;
83         sh->sh_table = l_table;
84         sh->sh_nrofentries = 0;
85         sh->sh_type = (*expp)->ex_type; /* the expression switched      */
86         sh->sh_lowerbd = sh->sh_upperbd = (arith)0;     /* immaterial ??? */
87         sh->sh_entries = (struct case_entry *) 0; /* case-entry list    */
88         sh->sh_expr = *expp;
89 #ifdef LINT
90         code_expr(sh->sh_expr, RVAL, TRUE, NO_LABEL, NO_LABEL);
91 #endif
92         sh->next = switch_stack;        /* push onto switch-stack       */
93         switch_stack = sh;
94         C_bra(l_table);                 /* goto start of switch_table   */
95 }
96
97 code_endswitch()
98 {
99         register struct switch_hdr *sh = switch_stack;
100         register label tablabel;
101         register struct case_entry *ce;
102
103         if (sh->sh_default == 0)        /* no default occurred yet */
104                 sh->sh_default = sh->sh_break;
105         C_bra(sh->sh_break);            /* skip the switch table now    */
106         C_df_ilb(sh->sh_table);         /* switch table entry           */
107         /* evaluate the switch expr.    */
108 #ifndef LINT
109         code_expr(sh->sh_expr, RVAL, TRUE, NO_LABEL, NO_LABEL);
110 #endif
111         tablabel = data_label();        /* the rom must have a label    */
112         C_df_dlb(tablabel);
113         C_rom_ilb(sh->sh_default);
114         if (compact(sh->sh_nrofentries, sh->sh_lowerbd, sh->sh_upperbd)) {
115                 /* CSA */
116                 register arith val;
117
118                 C_rom_cst(sh->sh_lowerbd);
119                 C_rom_cst(sh->sh_upperbd - sh->sh_lowerbd);
120                 ce = sh->sh_entries;
121                 if (sh->sh_nrofentries)
122                     for (val = sh->sh_lowerbd; val <= sh->sh_upperbd; val++) {
123                         ASSERT(ce);
124                         if (val == ce->ce_value) {
125                                 C_rom_ilb(ce->ce_label);
126                                 ce = ce->next;
127                         }
128                         else
129                                 C_rom_ilb(sh->sh_default);
130                 }
131                 C_lae_dlb(tablabel, (arith)0); /* perform the switch    */
132                 C_csa(sh->sh_type->tp_size);
133         }
134         else { /* CSB */
135                 C_rom_cst((arith)sh->sh_nrofentries);
136                 for (ce = sh->sh_entries; ce; ce = ce->next) {
137                         /* generate the entries: value + prog.label     */
138                         C_rom_cst(ce->ce_value);
139                         C_rom_ilb(ce->ce_label);
140                 }
141                 C_lae_dlb(tablabel, (arith)0); /* perform the switch    */
142                 C_csb(sh->sh_type->tp_size);
143         }
144         C_df_ilb(sh->sh_break);
145         switch_stack = sh->next;        /* unstack the switch descriptor */
146         for (ce = sh->sh_entries; ce;) { /* free allocated switch structure */
147                 register struct case_entry *tmp = ce->next;
148
149                 free_case_entry(ce);
150                 ce = tmp;
151         }
152         free_switch_hdr(sh);
153         unstack_stmt();
154 }
155
156 code_case(expr)
157         struct expr *expr;
158 {
159         register arith val;
160         register struct case_entry *ce;
161         register struct switch_hdr *sh = switch_stack;
162         
163         ASSERT(is_cp_cst(expr));
164         if (sh == 0) {
165                 error("case statement not in switch");
166                 return;
167         }
168         if (expr->ex_flags & EX_ERROR) /* is probably 0 anyway */
169                 return;
170         ch7cast(&expr, CASE, sh->sh_type);
171         ce = new_case_entry();
172         C_df_ilb(ce->ce_label = text_label());
173         ce->ce_value = val = expr->VL_VALUE;
174         if (sh->sh_entries == 0) { /* first case entry  */
175                 ce->next = (struct case_entry *) 0;
176                 sh->sh_entries = ce;
177                 sh->sh_lowerbd = sh->sh_upperbd = val;
178                 sh->sh_nrofentries = 1;
179         }
180         else { /* second etc. case entry; put ce into proper place */
181                 register struct case_entry *c1 = sh->sh_entries, *c2 = 0;
182                 
183                 if (val < sh->sh_lowerbd)
184                         sh->sh_lowerbd = val;
185                 else
186                 if (val > sh->sh_upperbd)
187                         sh->sh_upperbd = val;
188                 while (c1 && c1->ce_value < ce->ce_value) {
189                         c2 = c1;
190                         c1 = c1->next;
191                 }
192                 /*      At this point three cases are possible:
193                         1: c1 != 0 && c2 != 0: insert ce somewhere in the middle
194                         2: c1 != 0 && c2 == 0: insert ce right after the head
195                         3: c1 == 0 && c2 != 0: append ce to last element
196                         The case c1 == 0 && c2 == 0 cannot occur, since
197                         the list is guaranteed to be non-empty.
198                 */
199                 if (c1) {
200                         if (c1->ce_value == ce->ce_value) {
201                                 error("multiple case entry for value %ld",
202                                         ce->ce_value);
203                                 free_case_entry(ce);
204                                 return;
205                         }
206                         if (c2) {
207                                 ce->next = c2->next;
208                                 c2->next = ce;
209                         }
210                         else {
211                                 ce->next = sh->sh_entries;
212                                 sh->sh_entries = ce;
213                         }
214                 }
215                 else {
216                         ASSERT(c2);
217                         ce->next = (struct case_entry *) 0;
218                         c2->next = ce;
219                 }
220                 (sh->sh_nrofentries)++;
221         }
222 }
223
224 code_default()
225 {
226         register struct switch_hdr *sh = switch_stack;
227
228         if (sh == 0) {
229                 error("default statement not in switch");
230                 return;
231         }
232         if (sh->sh_default != 0) {
233                 error("multiple entry for default in switch");
234                 return;
235         }
236
237         C_df_ilb(sh->sh_default = text_label());
238 }