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