Added package with the documentation and the examples
[lwc.git] / statement.c
blob30bc85ba4dad94db4b72526931a88238bc6a7f22
1 #include "global.h"
3 #define BLOCK_START_MAYTHROW(X) \
4 CLEAR_MAYTHROW; int pos = get_stream_pos (X); SAVE_VAR (did_unwind, false);
5 #define BLOCK_END_MAYTHROW(X) \
6 if (TEST_MAYTHROW && did_unwind) { wipeout_unwind (X, pos); } RESTOR_VAR (did_unwind);
8 NormPtr statement (OUTSTREAM, NormPtr);
10 static NormPtr parenth_expression (OUTSTREAM o, NormPtr p)
12 exprret E;
13 if (CODE [p++] != '(')
14 parse_error (p, "missing '(' after reserved keyword");
15 p = parse_expression (p, &E, NORMAL_EXPR);
16 if (!E.ok) parse_error (p, "compilation stops here");
17 if (CODE [p++] != ')')
18 parse_error (p, "missing ')' after reserved keyword");
19 outprintf (o, '(', ISTR (E.newExpr), ')', -1);
20 free (E.newExpr);
21 return p;
24 static NormPtr __asm___statement (OUTSTREAM o, NormPtr p)
26 NormPtr p2 = p;
27 if (CODE [p] == RESERVED_volatile)
28 ++p;
29 if (CODE [p++] != '(')
30 parse_error (p, "__asm__ '('");
31 p = skip_parenthesis (p);
32 if (CODE [p++] != ';')
33 parse_error (p, "missing ';' after __asm__");
34 outprintf (o, RESERVED___asm__, NSTRNEXT, CODE + p2, p - p2, ';', - 1);
35 return p;
38 static NormPtr if_statement (OUTSTREAM o, NormPtr p)
40 output_itoken (o, RESERVED_if);
41 p = statement (o, parenth_expression (o, p));
42 // oh my god. this must be the horrible if-else ambiguity!
43 if (CODE [p] == RESERVED_else) {
44 output_itoken (o, RESERVED_else);
45 p = statement (o, p + 1);
47 return p;
50 /* general statmenent at catchpoint which may catch longbreak/longcontinue */
51 static NormPtr loop_body_statement (OUTSTREAM o, NormPtr p, int cp)
53 Token lbrk, lcnt;
54 OUTSTREAM t = new_stream ();
56 add_catchpoint (cp);
57 p = statement (t, p);
58 rmv_catchpoint (&lbrk, &lcnt);
60 if (lcnt || lbrk) output_itoken (o, '{');
61 concate_streams (o, t);
62 if (lcnt) outprintf (o, lcnt, ':', lbrk ? BLANKT : ';', -1);
63 if (lbrk) outprintf (o, RESERVED_continue, ';', lbrk, ':', RESERVED_break, ';', -1);
64 if (lcnt || lbrk) output_itoken (o, '}');
66 return p;
69 static struct {
70 OUTSTREAM caselabels;
71 Token addr1, dflt, base, array;
72 } cl, nocl;
74 static NormPtr switch_statement (OUTSTREAM o, NormPtr p)
76 bool dcl;
77 /* Feature: switch (declaration) */
78 if (dcl = CODE [p] == '(' && is_dcl_start (CODE [p + 1]) && CODE [p + 2] != '.') {
79 NormPtr p2;
80 p = skip_parenthesis (p2 = p + 1) - 1;
81 CODE [p] = ';';
82 open_local_scope ();
83 output_itoken (o, '{');
84 local_declaration (o, p2);
85 CODE [p++] = ')';
86 outprintf (o, RESERVED_switch, '(', recent_obj (), ')', -1);
87 /* ^^^^^^^^^^^^^^^^^^^^^^^ */
88 } else {
89 output_itoken (o, RESERVED_switch);
90 p = parenth_expression (o, p);
93 /* Feature: gather switch label addresses */
94 SAVE_VAR (cl, nocl);
95 if (CODE [p] == ':') {
96 if (!syntax_pattern (p, ':', VERIFY_symbol, ',', VERIFY_symbol, '[', ']', -1))
97 parse_error (p, "The syntax is 'switch () : name1, name2 []'");
98 outprintf (cl.caselabels = new_stream (), RESERVED_static, RESERVED_const,
99 RESERVED_int, cl.array = CODE [p + 3], '[', ']', '=', '{', -1);
100 cl.base = CODE [p + 1];
101 p += 6;
103 /* :::::::::::::::::::::::::::::::::::::: */
105 p = loop_body_statement (o, p, 1);
107 if (dcl) {
108 close_local_scope ();
109 output_itoken (o, '}');
112 /* make label addresses */
113 if (cl.caselabels) {
114 Token *dcl = combine_output (cl.caselabels), v = cl.dflt ?: cl.addr1;
115 int i;
116 for (i = 0; dcl [i] != -1; i++)
117 if (dcl [i] == RESERVED_0) dcl [i] = v;
118 outprintf (o, ISTR (dcl), '}', ';', RESERVED_static, RESERVED_void,
119 '*', cl.base, '=', ANDAND, v, ';', -1);
120 enter_local_obj (cl.array, typeID_intP);
121 enter_local_obj (cl.base, typeID_voidP);
122 free (dcl);
124 RESTOR_VAR (cl);
125 /* :::::::::::::::::::: */
127 return p;
130 static NormPtr do_statement (OUTSTREAM o, NormPtr p)
132 OUTSTREAM S = new_stream ();
134 p = loop_body_statement (S, p, 2);
136 if (CODE [p] == RESERVED_while) {
137 output_itoken (o, RESERVED_do);
138 concate_streams (o, S);
139 output_itoken (o, RESERVED_while);
140 p = parenth_expression (o, p + 1);
141 if (CODE [p++] != ';')
142 parse_error (p, "this is special. You need a ';'");
143 output_itoken (o, ';');
144 /* Feature: do without while */
145 } else {
146 outprintf (o, RESERVED_for, '(', ';', ';', ')', '{', - 1);
147 concate_streams (o, S);
148 outprintf (o, RESERVED_break, ';', '}', - 1);
150 /* ^^^^^^^^^^^^^^^^^^^^^^^^^ */
152 return p;
155 static NormPtr for_statement (OUTSTREAM o, NormPtr p)
157 bool first_dcl;
158 exprret E1, E2, E3;
160 if (CODE [p++] != '(')
161 parse_error (p, "for '('");
162 /* Feature: first part may be declaration */
163 if (first_dcl = is_dcl_start (CODE [p])) {
164 output_itoken (o, '{');
165 open_local_scope ();
166 p = local_declaration (o, p) - 1;
167 (E1.newExpr = mallocint (1)) [0] = -1;
168 E1.ok = true;
169 } else p = parse_expression (p, &E1, NORMAL_EXPR);
170 if (CODE [p++] != ';')
171 parse_error (p, "for (';'");
172 p = parse_expression (p, &E2, NORMAL_EXPR);
173 if (CODE [p++] != ';')
174 parse_error (p, "for (;';'");
175 p = parse_expression (p, &E3, NORMAL_EXPR);
176 if (CODE [p++] != ')')
177 parse_error (p, "for (;';')");
178 if (!(E1.ok && E2.ok && E3.ok))
179 parse_error (p, "compilation halted at for()");
180 outprintf (o, RESERVED_for, '(', ISTR (E1.newExpr), ';',
181 ISTR (E2.newExpr), ';', ISTR (E3.newExpr), ')', -1);
182 free (E1.newExpr);
183 free (E2.newExpr);
184 free (E3.newExpr);
186 p = loop_body_statement (o, p, 2);
188 if (first_dcl) {
189 close_local_scope ();
190 output_itoken (o, '}');
192 return p;
195 static NormPtr while_statement (OUTSTREAM o, NormPtr p)
197 output_itoken (o, RESERVED_while);
198 p = loop_body_statement (o, parenth_expression (o, p), 2);
199 return p;
202 static NormPtr return_statement (OUTSTREAM o, NormPtr p)
204 exprret E;
205 bool he;
206 p = parse_expression_retconv (p, &E, return_typeID, NORMAL_EXPR);
207 if (!E.ok) return p + 1;
209 /* Feature: a 'return;' in destructors, returns this */
210 if (!(he = E.newExpr [0] != -1) && (he = objective.isdtor))
211 sintprintf (frealloc (&E.newExpr, 2), RESERVED_this, -1);
213 /* Feature: before return, call internal destruction */
214 if (objective.isdtor && idtor (objective.class)) {
215 Token *t = mallocint (intlen (E.newExpr) + 7);
216 sintprintf (t, idtor (objective.class), '(', RESERVED_this, ')', ',',
217 ISTR (E.newExpr), -1);
218 free (E.newExpr);
219 E.newExpr = t;
222 /* Feature: destructors for all locals */
223 if (func_has_dtors ()) {
224 outprintf (o, '{', -1);
225 if (he) outprintf (o, RESERVED___typeof__, '(', ISTR (E.newExpr), ')',
226 internal_identifier1 (), '=', ISTR (E.newExpr), ';', -1);
227 gen_all_destructors (o);
228 outprintf (o, RESERVED_return, he ? internal_identifier1 () : BLANKT, ';', '}', -1);
229 } else
230 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
231 outprintf (o, RESERVED_return, ISTR (E.newExpr), ';', -1);
232 free (E.newExpr);
233 if (CODE [p] != ';')
234 parse_error (p, "expecting ';' after return");
235 return p + 1;
238 static NormPtr case_statement (OUTSTREAM o, NormPtr p)
240 static int uniq;
241 Token v = 0;
242 exprret E;
243 output_itoken (o, RESERVED_case);
244 p = parse_expression (p, &E, NORMAL_EXPR);
245 if (E.ok) outprintf (o, ISTR (E.newExpr), -1);
247 /* gather labels */
248 if (cl.caselabels) {
249 v = toktokcat (RESERVED_case, E.newExpr [1] != -1 ?
250 internal_identifiern (uniq++) : E.newExpr [0]);
251 if (!cl.addr1) cl.addr1 = v;
252 outprintf (cl.caselabels, '[', ISTR (E.newExpr), ']', '=',
253 ANDAND, v, '-', ANDAND, RESERVED_0, ',', -1);
256 free (E.newExpr);
257 /* extension '...' in case */
258 if (CODE [p] == ELLIPSIS) {
259 if (v) parse_error (p, "Can't gather labels for '...' case");
260 p = parse_expression (p, &E, NORMAL_EXPR);
261 if (E.ok) {
262 outprintf (o, ELLIPSIS, ISTR (E.newExpr), -1);
263 free (E.newExpr);
266 if (CODE [p] != ':') parse_error (p, "case ':' error");
267 output_itoken (o, ':');
268 /* label equiv */
269 if (v) outprintf (o, v, ':', -1);
270 return p + 1;
273 static NormPtr expression_statement (OUTSTREAM o, NormPtr p)
275 exprret E;
276 p = parse_expression (p, &E, NORMAL_EXPR);
277 if (CODE [p++] != ';') parse_error (p, "expression';'");
278 if (E.ok) {
279 outprintf (o, ISTR (E.newExpr), ';', -1);
280 free (E.newExpr);
282 return p;
285 static inline bool is_declaration (NormPtr p)
287 return is_dcl_start (CODE [p]) && !(ISSYMBOL (CODE [p]) && CODE [p + 1] == '.');
290 #ifdef DEBUG
291 bool special_debug;
292 #endif
294 NormPtr compound_statement (OUTSTREAM o, NormPtr p)
296 bool noend = false;
298 #ifdef DEBUG
299 SAVE_VAR (special_debug, CODE [p] == RESERVED_0);
300 if (CODE [p] == RESERVED_0) ++p;
301 #endif
302 BLOCK_START_MAYTHROW (o);
303 open_local_scope ();
304 output_itoken (o, '{');
305 while (CODE [p] != '}') {
306 noend = in4 (CODE [p], RESERVED_return, RESERVED_break,
307 RESERVED_continue, RESERVED_goto);
308 p = is_declaration (p) ? local_declaration (o, p) : statement (o, p);
310 /* Feature: destructors of local objects */
311 if (scope_has_dtors () && !noend)
312 gen_auto_destruction (o, !may_throw);
313 /* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */
314 output_itoken (o, '}');
315 close_local_scope ();
316 BLOCK_END_MAYTHROW (o);
317 #ifdef DEBUG
318 RESTOR_VAR (special_debug);
319 #endif
320 return p + 1;
323 static NormPtr jump_statement (OUTSTREAM o, NormPtr p, Token t)
325 int cont = t == RESERVED_continue ? 2 : 1;
326 bool bhd;
328 /* Feature: break 2; */
329 int break_n = ISVALUE (CODE [p]) ? eval_int (CODE [p++]) : 1;
330 /* ^^^^^^^^^^^^^^^^^ */
332 if (CODE [p] != ';')
333 parse_error (p, "break/continue ';'");
335 /* Feature: destructors of local objects */
336 if ((bhd = break_has_dtors (cont)) || break_n != 1) {
337 Token lbl;
339 if (bhd) output_itoken (o, '{');
340 if (lbl = gen_break_destructors (o, cont, break_n))
341 outprintf (o, RESERVED_goto, lbl, ';', -1);
342 else outprintf (o, t, ';', -1);
343 if (bhd) output_itoken (o, '}');
344 } else
345 /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
346 outprintf (o, t, ';', -1);
347 return p + 1;
350 static NormPtr goto_statement (OUTSTREAM o, NormPtr p)
352 /* GNUC: computed goto */
353 if (CODE [p] == '*') {
354 outprintf (o, RESERVED_goto, '*', -1);
355 return expression_statement (o, p + 1);
357 /* Feature: goto (...) ? l1 : l2 */
358 if (CODE [p] == '(' && CODE [skip_parenthesis (p + 1)] == '?') {
359 outprintf (o, '{', RESERVED_if, -1);
360 p = parenth_expression (o, p);
361 syntax_pattern (p, '?', VERIFY_symbol, ':', VERIFY_symbol, ';', -1);
362 outprintf (o, RESERVED_goto, CODE [p + 1], ';',
363 RESERVED_goto, CODE [p + 3], ';', '}', -1);
364 return p + 4;
367 if (!ISSYMBOL (CODE [p]) || CODE [p + 1] != ';')
368 parse_error (p, "'goto label;' only");
369 outprintf (o, RESERVED_goto, CODE [p], ';', -1);
370 return p + 2;
373 NormPtr statement (OUTSTREAM o, NormPtr p)
375 Token t = CODE [p++];
377 if (ISSYMBOL (t) && CODE [p] == ':') {
378 outprintf (o, t, CODE [p++], -1);
379 return CODE [p] == '}' ? p : statement (o, p);
382 switch (t) {
383 case '{': return compound_statement (o, p);
384 case RESERVED_case: return case_statement (o, p);
385 case RESERVED_return: return return_statement (o, p);
386 case RESERVED_while: return while_statement (o, p);
387 case RESERVED_for: return for_statement (o, p);
388 case RESERVED_do: return do_statement (o, p);
389 case RESERVED_switch: return switch_statement (o, p);
390 case RESERVED_if: return if_statement (o, p);
391 case RESERVED_else: parse_error (p, "else without if");
392 case RESERVED_throw: return throw_statement (o, p);
393 case RESERVED_try: return try_statement (o, p);
394 case RESERVED___on_throw__:
395 return on_throw_statement (o, p);
396 case RESERVED___asm__: return __asm___statement (o, p);
397 case RESERVED_continue:
398 case RESERVED_break: return jump_statement (o, p, t);
399 case RESERVED_goto: return goto_statement (o, p);
400 default: return expression_statement (o, p - 1);
401 case ';':
402 output_itoken (o, ';');
403 return p;
404 case RESERVED_default:
405 if (CODE [p] != ':') parse_error (p, "default:");
406 outprintf (o, RESERVED_default, ':', -1);
407 if (cl.caselabels) {
408 cl.dflt = tokstrcat (RESERVED_default, "_label");
409 outprintf (o, cl.dflt, ':', -1);
411 return p + 1;
415 /* This is a compound statement inside an expression */
416 Token *rewrite_compound_statement (Token *t)
418 OUTSTREAM o = new_stream ();
420 SAVE_VAR (CODE, t);
421 SAVE_VAR (last_location, 0);
423 output_itoken (o, '(');
424 compound_statement (o, 0);
425 output_itoken (o, ')');
427 RESTOR_VAR (CODE);
428 RESTOR_VAR (last_location);
430 return combine_output (o);