1 | /*****************************************************************************/ |
2 | /* */ |
3 | /* swstmt.c */ |
4 | /* */ |
5 | /* Parse the switch statement */ |
6 | /* */ |
7 | /* */ |
8 | /* */ |
9 | /* (C) 1998-2008 Ullrich von Bassewitz */ |
10 | /* Roemerstrasse 52 */ |
11 | /* D-70794 Filderstadt */ |
12 | /* EMail: uz@cc65.org */ |
13 | /* */ |
14 | /* */ |
15 | /* This software is provided 'as-is', without any expressed or implied */ |
16 | /* warranty. In no event will the authors be held liable for any damages */ |
17 | /* arising from the use of this software. */ |
18 | /* */ |
19 | /* Permission is granted to anyone to use this software for any purpose, */ |
20 | /* including commercial applications, and to alter it and redistribute it */ |
21 | /* freely, subject to the following restrictions: */ |
22 | /* */ |
23 | /* 1. The origin of this software must not be misrepresented; you must not */ |
24 | /* claim that you wrote the original software. If you use this software */ |
25 | /* in a product, an acknowledgment in the product documentation would be */ |
26 | /* appreciated but is not required. */ |
27 | /* 2. Altered source versions must be plainly marked as such, and must not */ |
28 | /* be misrepresented as being the original software. */ |
29 | /* 3. This notice may not be removed or altered from any source */ |
30 | /* distribution. */ |
31 | /* */ |
32 | /*****************************************************************************/ |
33 | |
34 | |
35 | |
36 | #include <limits.h> |
37 | |
38 | /* common */ |
39 | #include "coll.h" |
40 | #include "xmalloc.h" |
41 | |
42 | /* cc65 */ |
43 | #include "asmcode.h" |
44 | #include "asmlabel.h" |
45 | #include "casenode.h" |
46 | #include "codegen.h" |
47 | #include "datatype.h" |
48 | #include "error.h" |
49 | #include "expr.h" |
50 | #include "global.h" |
51 | #include "loop.h" |
52 | #include "scanner.h" |
53 | #include "stmt.h" |
54 | #include "swstmt.h" |
55 | |
56 | |
57 | |
58 | /*****************************************************************************/ |
59 | /* Data */ |
60 | /*****************************************************************************/ |
61 | |
62 | |
63 | |
64 | typedef struct SwitchCtrl SwitchCtrl; |
65 | struct SwitchCtrl { |
66 | Collection* Nodes; /* CaseNode tree */ |
67 | TypeCode ExprType; /* Basic switch expression type */ |
68 | unsigned Depth; /* Number of bytes the selector type has */ |
69 | unsigned DefaultLabel; /* Label for the default branch */ |
70 | |
71 | |
72 | |
73 | }; |
74 | |
75 | /* Pointer to current switch control struct */ |
76 | static SwitchCtrl* Switch = 0; |
77 | |
78 | |
79 | |
80 | /*****************************************************************************/ |
81 | /* Code */ |
82 | /*****************************************************************************/ |
83 | |
84 | |
85 | |
86 | void SwitchStatement (void) |
87 | /* Handle a switch statement for chars with a cmp cascade for the selector */ |
88 | { |
89 | ExprDesc SwitchExpr; /* Switch statement expression */ |
90 | CodeMark CaseCodeStart; /* Start of code marker */ |
91 | CodeMark SwitchCodeStart;/* Start of switch code */ |
92 | CodeMark SwitchCodeEnd; /* End of switch code */ |
93 | unsigned ExitLabel; /* Exit label */ |
94 | unsigned SwitchCodeLabel;/* Label for the switch code */ |
95 | int HaveBreak = 0; /* True if the last statement had a break */ |
96 | int RCurlyBrace; /* True if last token is right curly brace */ |
97 | SwitchCtrl* OldSwitch; /* Pointer to old switch control data */ |
98 | SwitchCtrl SwitchData; /* New switch data */ |
99 | |
100 | |
101 | /* Eat the "switch" token */ |
102 | NextToken (); |
103 | |
104 | /* Read the switch expression and load it into the primary. It must have |
105 | ** integer type. |
106 | */ |
107 | ConsumeLParen (); |
108 | Expression0 (&SwitchExpr); |
109 | if (!IsClassInt (SwitchExpr.Type)) { |
110 | Error ("Switch quantity is not an integer" ); |
111 | /* To avoid any compiler errors, make the expression a valid int */ |
112 | ED_MakeConstAbsInt (&SwitchExpr, 1); |
113 | } |
114 | ConsumeRParen (); |
115 | |
116 | /* Add a jump to the switch code. This jump is usually unnecessary, |
117 | ** because the switch code will moved up just behind the switch |
118 | ** expression. However, in rare cases, there's a label at the end of |
119 | ** the switch expression. This label will not get moved, so the code |
120 | ** jumps around the switch code, and after moving the switch code, |
121 | ** things look really weird. If we add a jump here, we will never have |
122 | ** a label attached to the current code position, and the jump itself |
123 | ** will get removed by the optimizer if it is unnecessary. |
124 | */ |
125 | SwitchCodeLabel = GetLocalLabel (); |
126 | g_jump (SwitchCodeLabel); |
127 | |
128 | /* Remember the current code position. We will move the switch code |
129 | ** to this position later. |
130 | */ |
131 | GetCodePos (&CaseCodeStart); |
132 | |
133 | /* Setup the control structure, save the old and activate the new one */ |
134 | SwitchData.Nodes = NewCollection (); |
135 | SwitchData.ExprType = UnqualifiedType (SwitchExpr.Type[0].C); |
136 | SwitchData.Depth = SizeOf (SwitchExpr.Type); |
137 | SwitchData.DefaultLabel = 0; |
138 | OldSwitch = Switch; |
139 | Switch = &SwitchData; |
140 | |
141 | /* Get the exit label for the switch statement */ |
142 | ExitLabel = GetLocalLabel (); |
143 | |
144 | /* Create a loop so we may use break. */ |
145 | AddLoop (ExitLabel, 0); |
146 | |
147 | /* Parse the following statement, which may actually be a compound |
148 | ** statement if there is a curly brace at the current input position |
149 | */ |
150 | HaveBreak = Statement (&RCurlyBrace); |
151 | |
152 | /* Check if we had any labels */ |
153 | if (CollCount (SwitchData.Nodes) == 0 && SwitchData.DefaultLabel == 0) { |
154 | Warning ("No case labels" ); |
155 | } |
156 | |
157 | /* If the last statement did not have a break, we may have an open |
158 | ** label (maybe from an if or similar). Emitting code and then moving |
159 | ** this code to the top will also move the label to the top which is |
160 | ** wrong. So if the last statement did not have a break (which would |
161 | ** carry the label), add a jump to the exit. If it is useless, the |
162 | ** optimizer will remove it later. |
163 | */ |
164 | if (!HaveBreak) { |
165 | g_jump (ExitLabel); |
166 | } |
167 | |
168 | /* Remember the current position */ |
169 | GetCodePos (&SwitchCodeStart); |
170 | |
171 | /* Output the switch code label */ |
172 | g_defcodelabel (SwitchCodeLabel); |
173 | |
174 | /* Generate code */ |
175 | if (SwitchData.DefaultLabel == 0) { |
176 | /* No default label, use switch exit */ |
177 | SwitchData.DefaultLabel = ExitLabel; |
178 | } |
179 | g_switch (SwitchData.Nodes, SwitchData.DefaultLabel, SwitchData.Depth); |
180 | |
181 | /* Move the code to the front */ |
182 | GetCodePos (&SwitchCodeEnd); |
183 | MoveCode (&SwitchCodeStart, &SwitchCodeEnd, &CaseCodeStart); |
184 | |
185 | /* Define the exit label */ |
186 | g_defcodelabel (ExitLabel); |
187 | |
188 | /* Exit the loop */ |
189 | DelLoop (); |
190 | |
191 | /* Switch back to the enclosing switch statement if any */ |
192 | Switch = OldSwitch; |
193 | |
194 | /* Free the case value tree */ |
195 | FreeCaseNodeColl (SwitchData.Nodes); |
196 | |
197 | /* If the case statement was terminated by a closing curly |
198 | ** brace, skip it now. |
199 | */ |
200 | if (RCurlyBrace) { |
201 | NextToken (); |
202 | } |
203 | } |
204 | |
205 | |
206 | |
207 | void CaseLabel (void) |
208 | /* Handle a case sabel */ |
209 | { |
210 | ExprDesc CaseExpr; /* Case label expression */ |
211 | long Val; /* Case label value */ |
212 | unsigned CodeLabel; /* Code label for this case */ |
213 | |
214 | |
215 | /* Skip the "case" token */ |
216 | NextToken (); |
217 | |
218 | /* Read the selector expression */ |
219 | ConstAbsIntExpr (hie1, &CaseExpr); |
220 | Val = CaseExpr.IVal; |
221 | |
222 | /* Now check if we're inside a switch statement */ |
223 | if (Switch != 0) { |
224 | |
225 | /* Check the range of the expression */ |
226 | switch (Switch->ExprType) { |
227 | |
228 | case T_SCHAR: |
229 | /* Signed char */ |
230 | if (Val < -128 || Val > 127) { |
231 | Error ("Range error" ); |
232 | } |
233 | break; |
234 | |
235 | case T_UCHAR: |
236 | if (Val < 0 || Val > 255) { |
237 | Error ("Range error" ); |
238 | } |
239 | break; |
240 | |
241 | case T_SHORT: |
242 | case T_INT: |
243 | if (Val < -32768 || Val > 32767) { |
244 | Error ("Range error" ); |
245 | } |
246 | break; |
247 | |
248 | case T_USHORT: |
249 | case T_UINT: |
250 | if (Val < 0 || Val > 65535) { |
251 | Error ("Range error" ); |
252 | } |
253 | break; |
254 | |
255 | case T_LONG: |
256 | case T_ULONG: |
257 | break; |
258 | |
259 | default: |
260 | Internal ("Invalid type: %06lX" , Switch->ExprType); |
261 | } |
262 | |
263 | /* Insert the case selector into the selector table */ |
264 | CodeLabel = InsertCaseValue (Switch->Nodes, Val, Switch->Depth); |
265 | |
266 | /* Define this label */ |
267 | g_defcodelabel (CodeLabel); |
268 | |
269 | } else { |
270 | |
271 | /* case keyword outside a switch statement */ |
272 | Error ("Case label not within a switch statement" ); |
273 | |
274 | } |
275 | |
276 | /* Skip the colon */ |
277 | ConsumeColon (); |
278 | } |
279 | |
280 | |
281 | |
282 | void DefaultLabel (void) |
283 | /* Handle a default label */ |
284 | { |
285 | /* Default case */ |
286 | NextToken (); |
287 | |
288 | /* Now check if we're inside a switch statement */ |
289 | if (Switch != 0) { |
290 | |
291 | /* Check if we do already have a default branch */ |
292 | if (Switch->DefaultLabel == 0) { |
293 | |
294 | /* Generate and emit the default label */ |
295 | Switch->DefaultLabel = GetLocalLabel (); |
296 | g_defcodelabel (Switch->DefaultLabel); |
297 | |
298 | } else { |
299 | /* We had the default label already */ |
300 | Error ("Multiple default labels in one switch" ); |
301 | } |
302 | |
303 | } else { |
304 | |
305 | /* case keyword outside a switch statement */ |
306 | Error ("'default' label not within a switch statement" ); |
307 | |
308 | } |
309 | |
310 | /* Skip the colon */ |
311 | ConsumeColon (); |
312 | } |
313 | |