Subversion Repositories tendra.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
7 7u83 2
 * Copyright (c) 2002-2006 The TenDRA Project <http://www.tendra.org/>.
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *
8
 * 1. Redistributions of source code must retain the above copyright notice,
9
 *    this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright notice,
11
 *    this list of conditions and the following disclaimer in the documentation
12
 *    and/or other materials provided with the distribution.
13
 * 3. Neither the name of The TenDRA Project nor the names of its contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific, prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
18
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
21
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
 * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 *
29
 * $Id$
30
 */
31
/*
2 7u83 32
    		 Crown Copyright (c) 1997
7 7u83 33
 
2 7u83 34
    This TenDRA(r) Computer Program is subject to Copyright
35
    owned by the United Kingdom Secretary of State for Defence
36
    acting through the Defence Evaluation and Research Agency
37
    (DERA).  It is made available to Recipients with a
38
    royalty-free licence for its use, reproduction, transfer
39
    to other parties and amendment for any purpose not excluding
40
    product development provided that any such use et cetera
41
    shall be deemed to be acceptance of the following conditions:-
7 7u83 42
 
2 7u83 43
        (1) Its Recipients shall ensure that this Notice is
44
        reproduced upon any copies or amended versions of it;
7 7u83 45
 
2 7u83 46
        (2) Any amended version of it shall be clearly marked to
47
        show both the nature of and the organisation responsible
48
        for the relevant amendment or amendments;
7 7u83 49
 
2 7u83 50
        (3) Its onward transfer from a recipient to another
51
        party shall be deemed to be that party's acceptance of
52
        these conditions;
7 7u83 53
 
2 7u83 54
        (4) DERA gives no warranty or assurance as to its
55
        quality or suitability for any purpose and DERA accepts
56
        no liability whatsoever in relation to any use to which
57
        it may be put.
58
*/
59
 
60
 
61
#include "config.h"
62
#include "c_types.h"
63
#include "exp_ops.h"
64
#include "hashid_ops.h"
65
#include "id_ops.h"
66
#include "member_ops.h"
67
#include "nspace_ops.h"
68
#include "error.h"
69
#include "catalog.h"
70
#include "basetype.h"
71
#include "dump.h"
72
#include "function.h"
73
#include "hash.h"
74
#include "label.h"
75
#include "namespace.h"
76
#include "statement.h"
77
#include "syntax.h"
78
 
79
 
80
/*
81
    LABEL NAMESPACE
82
 
83
    The labels in a function occupy a distinct namespace.  This is given by
84
    the following variable.
85
*/
86
 
7 7u83 87
NAMESPACE label_namespace = NULL_nspace;
2 7u83 88
 
89
 
90
/*
91
    LABEL USAGE VALUES
92
 
93
    The storage field of a label is used primarily to indicate whether that
94
    label has been used or defined.  However addition information is recorded
95
    using the following values, namely, whether the label is jumped to in
96
    an accessible portion of the program or reached by falling into it from
97
    the previous statement, and whether or not it is an unnamed label.
98
*/
99
 
100
#define dspec_goto		dspec_static
101
#define dspec_reached		dspec_extern
102
#define dspec_fall_thru		dspec_auto
103
#define dspec_anon		dspec_register
104
#define dspec_solve		dspec_mutable
105
#define dspec_scope		dspec_inline
106
 
107
 
108
/*
109
    CREATE A LABEL
110
 
111
    This routine creates a label named nm with usage information info.
112
*/
113
 
7 7u83 114
static IDENTIFIER
115
make_label(HASHID nm, DECL_SPEC info, int op)
2 7u83 116
{
7 7u83 117
	IDENTIFIER lab;
118
	NAMESPACE ns = label_namespace;
119
	MAKE_id_label(nm, info, ns, crt_loc, op, lab);
120
	return (lab);
2 7u83 121
}
122
 
123
 
124
/*
125
    BEGIN A LABELLED STATEMENT
126
 
127
    This routine begins the construction of a statement labelled by the
128
    label lab.  If lab is the null identifier then a unique identifier
129
    name is created.  op gives the type of label being defined (for example
130
    a break label, a case label or a normal identifier label).  If the
131
    label has already been defined then the null expression is returned.
132
    Although from the syntax a label is associated with a single body
133
    statement, the body of a labelled statement is actually all the
134
    remaining statements in the block.  That is:
135
 
136
			{
137
			    stmt1 ;
138
			    ...
139
			    label : body1 ;
140
			    body2 ;
141
			    ....
142
			}
143
 
144
    is transformed into:
145
 
146
			{
147
			    stmt1 ;
148
			    ...
149
			    label : {
150
				body1 ;
151
				body2 ;
152
				....
153
			    }
154
			}
155
 
156
    except that the introduced block does not establish a scope.
157
*/
158
 
7 7u83 159
EXP
160
begin_label_stmt(IDENTIFIER lab, int op)
2 7u83 161
{
7 7u83 162
	EXP e;
163
	EXP seq;
164
	HASHID nm;
165
	MEMBER mem;
166
	DECL_SPEC def_info = (dspec_defn | dspec_scope);
2 7u83 167
 
7 7u83 168
	/* Make up label name if necessary */
169
	if (IS_NULL_id(lab)) {
170
		nm = lookup_anon();
171
		def_info |= dspec_anon;
172
		if (op == lex_case || op == lex_default) {
173
			/* Mark case and default labels */
174
			def_info |= (dspec_used | dspec_goto);
175
		}
176
	} else {
177
		nm = DEREF_hashid(id_name(lab));
2 7u83 178
	}
179
 
7 7u83 180
	/* Check for fall through */
181
	if (!unreached_code) {
182
		def_info |= dspec_fall_thru;
183
	}
2 7u83 184
 
7 7u83 185
	/* Check if label has already been defined */
186
	mem = search_member(label_namespace, nm, 1);
187
	lab = DEREF_id(member_id(mem));
188
	if (!IS_NULL_id(lab)) {
189
		DECL_SPEC info = DEREF_dspec(id_storage(lab));
190
		if (info & dspec_defn) {
191
			/* Already defined */
192
			IDENTIFIER fn = crt_func_id;
193
			PTR(LOCATION) loc = id_loc(lab);
194
			report(crt_loc, ERR_stmt_label_redef(lab, fn, loc));
195
			return (NULL_exp);
196
		}
197
		/* Already used */
198
		info |= def_info;
199
		COPY_dspec(id_storage(lab), info);
200
		COPY_loc(id_loc(lab), crt_loc);
201
	} else {
202
		/* Not used or defined previously */
203
		lab = make_label(nm, def_info, op);
204
		COPY_id(member_id(mem), lab);
2 7u83 205
	}
7 7u83 206
	if (do_local && !IS_hashid_anon(nm)) {
207
		dump_declare(lab, &crt_loc, 1);
208
	}
2 7u83 209
 
7 7u83 210
	/* Create a labelled statement */
211
	seq = begin_compound_stmt(0);
212
	MAKE_exp_label_stmt(type_void, lab, seq, e);
213
	COPY_exp(exp_sequence_parent(seq), e);
214
	COPY_exp(id_label_stmt(lab), e);
215
	unreached_code = 0;
216
	unreached_last = 0;
217
	return (e);
2 7u83 218
}
219
 
220
 
221
/*
222
    COMPLETE A LABELLED STATEMENT
223
 
224
    This routine completes the construction of the labelled statement prev
225
    using the statement body.  It is also used to handle case and default
226
    statements.  If prev is the null expression, indicating any illegal
227
    label of some kind, then body is returned.  Otherwise body is added
228
    to the compound statement which is labelled.
229
*/
230
 
7 7u83 231
EXP
232
end_label_stmt(EXP prev, EXP body)
2 7u83 233
{
7 7u83 234
	EXP seq;
235
	IDENTIFIER lab;
236
	DECL_SPEC info;
237
	if (IS_NULL_exp(prev)) {
238
		return (body);
239
	}
2 7u83 240
 
7 7u83 241
	/* Mark end of label scope */
242
	lab = DEREF_id(exp_label_stmt_label(prev));
243
	info = DEREF_dspec(id_storage(lab));
244
	info &= ~dspec_scope;
245
	COPY_dspec(id_storage(lab), info);
2 7u83 246
 
7 7u83 247
	/* Check for consecutive labels */
248
	if (!IS_NULL_exp(body) && IS_exp_label_stmt(body)) {
249
		/* Two consecutive labels */
250
		IDENTIFIER blab = DEREF_id(exp_label_stmt_label(body));
251
		blab = DEREF_id(id_alias(blab));
252
		COPY_id(id_alias(lab), blab);
253
	}
2 7u83 254
 
7 7u83 255
	/* Assign to label body */
256
	seq = DEREF_exp(exp_label_stmt_body(prev));
257
	seq = add_compound_stmt(seq, body);
258
	COPY_exp(exp_label_stmt_body(prev), seq);
259
	return (prev);
2 7u83 260
}
261
 
262
 
263
/*
264
    CONSTRUCT A JUMP TO A LABEL
265
 
266
    This routine constructs a jump to the label lab (including break and
267
    continue statements).  join gives the smallest statement containing
268
    both the label and the jump.  This can only be filled in later for
269
    named labels.
270
*/
271
 
7 7u83 272
EXP
273
make_jump_stmt(IDENTIFIER lab, EXP join)
2 7u83 274
{
7 7u83 275
	DECL_SPEC info;
276
	EXP e = DEREF_exp(id_label_gotos(lab));
2 7u83 277
 
7 7u83 278
	/* Mark the label as used */
279
	info = DEREF_dspec(id_storage(lab));
280
	info |= (dspec_used | dspec_goto);
281
	if (!unreached_code) {
282
		info |= dspec_reached;
283
	}
284
	COPY_dspec(id_storage(lab), info);
2 7u83 285
 
7 7u83 286
	/* Construct the jump statement */
287
	if (IS_NULL_exp(join) && (info & dspec_scope)) {
288
		join = DEREF_exp(id_label_stmt(lab));
289
	}
290
	MAKE_exp_goto_stmt(type_bottom, lab, join, e, e);
291
	COPY_exp(id_label_gotos(lab), e);
292
	unreached_code = 1;
293
	unreached_last = 0;
294
	return (e);
2 7u83 295
}
296
 
297
 
298
/*
299
    CONSTRUCT A GOTO STATEMENT
300
 
301
    This routine constructs a goto statement where the destination label
302
    is given by lab.  Note that it is possible to use a label before it
303
    is defined.
304
*/
305
 
7 7u83 306
EXP
307
make_goto_stmt(IDENTIFIER lab)
2 7u83 308
{
7 7u83 309
	/* Look up existing label */
310
	EXP e;
311
	HASHID nm;
312
	MEMBER mem;
313
	if (IS_NULL_id(lab)) {
314
		nm = lookup_anon();
315
	} else {
316
		nm = DEREF_hashid(id_name(lab));
2 7u83 317
	}
7 7u83 318
	mem = search_member(label_namespace, nm, 1);
319
	lab = DEREF_id(member_id(mem));
320
	if (IS_NULL_id(lab)) {
321
		/* Create new label */
322
		DECL_SPEC info = (dspec_used | dspec_goto);
323
		lab = make_label(nm, info, lex_identifier);
324
		COPY_id(member_id(mem), lab);
325
	} else {
326
		DECL_SPEC info = DEREF_dspec(id_storage(lab));
327
		if (info & dspec_defn) {
328
			/* Backward jump */
329
			info |= dspec_reserve;
330
			COPY_dspec(id_storage(lab), info);
331
		}
332
	}
333
	if (do_local && do_usage && !IS_hashid_anon(nm)) {
334
		dump_use(lab, &crt_loc, 1);
335
	}
336
	e = make_jump_stmt(lab, NULL_exp);
337
	return (e);
2 7u83 338
}
339
 
340
 
341
/*
342
    POSTLUDE LABEL NAME
343
 
344
    This value gives the name associated with all postlude labels.  It is
345
    assigned when the first postlude label is created.
346
*/
347
 
7 7u83 348
static HASHID postlude_name = NULL_hashid;
2 7u83 349
 
350
 
351
/*
352
    CREATE A POSTLUDE LABEL
353
 
354
    This routine creates a label name for a postlude expression, that is
355
    to say an expression which will be called at the end of a function.
356
    At present this is only used in functions which do not return a value.
357
    A return statement within such a function is mapped onto a jump to
358
    the postlude label.
359
*/
360
 
7 7u83 361
IDENTIFIER
362
postlude_label(void)
2 7u83 363
{
7 7u83 364
	IDENTIFIER lab;
365
	HASHID nm = postlude_name;
366
	if (IS_NULL_hashid(nm)) {
367
		/* Assign postlude label name */
368
		nm = lookup_anon();
369
		postlude_name = nm;
370
	}
371
	lab = DEREF_id(hashid_id(nm));
372
	return (lab);
2 7u83 373
}
374
 
375
 
376
/*
377
    FIND A POSTLUDE LABEL
378
 
379
    This routine returns the postlude label associated with the current
380
    function or the null identifier if the function has no postlude.
381
*/
382
 
7 7u83 383
IDENTIFIER
384
find_postlude_label(void)
2 7u83 385
{
7 7u83 386
	HASHID nm = postlude_name;
387
	if (!IS_NULL_hashid(nm)) {
388
		MEMBER mem = search_member(label_namespace, nm, 0);
389
		if (!IS_NULL_member(mem)) {
390
			IDENTIFIER lab = DEREF_id(member_id(mem));
391
			return (lab);
392
		}
2 7u83 393
	}
7 7u83 394
	return (NULL_id);
2 7u83 395
}
396
 
397
 
398
/*
399
    HAS A LABELLED STATEMENT BEEN REACHED?
400
 
401
    This routine checks whether the label label has been reached using
402
    an explicit goto, break or continue statement in a reached portion of
403
    the program (when it returns 1) or by fall through from the previous
404
    statement (when it returns 2).
405
*/
406
 
7 7u83 407
int
408
used_label(IDENTIFIER lab)
2 7u83 409
{
7 7u83 410
	DECL_SPEC info = DEREF_dspec(id_storage(lab));
411
	if (info & dspec_reached) {
412
		return (1);
413
	}
414
	if (info & dspec_fall_thru) {
415
		return (2);
416
	}
417
	return (0);
2 7u83 418
}
419
 
420
 
421
/*
422
    CHECK ALL LABELS IN A FUNCTION
423
 
424
    This routine scans through all the labels defined in the current
425
    function searching for any which have been used but not defined.
426
    It returns the number of named labels defined.
427
*/
428
 
7 7u83 429
unsigned
430
check_labels(void)
2 7u83 431
{
432
    /* Scan through all labels */
7 7u83 433
    unsigned no_labs = 0;
434
    NAMESPACE ns = label_namespace;
435
    MEMBER mem = DEREF_member(nspace_last(ns));
436
    while (!IS_NULL_member(mem)) {
437
	LOCATION loc;
438
	IDENTIFIER lab = DEREF_id(member_id(mem));
439
	if (!IS_NULL_id(lab)) {
2 7u83 440
	    /* Check label information */
7 7u83 441
	    DECL_SPEC info = DEREF_dspec(id_storage(lab));
442
	    IDENTIFIER flab = DEREF_id(id_alias(lab));
443
	    if (!EQ_id(lab, flab)) {
2 7u83 444
		/* Deal with label aliases */
7 7u83 445
		DECL_SPEC finfo = DEREF_dspec(id_storage(flab));
446
		finfo |= (info & dspec_used);
447
		COPY_dspec(id_storage(flab), finfo);
2 7u83 448
	    }
7 7u83 449
	    if (info & dspec_anon) {
2 7u83 450
		/* Unnamed labels are ignored */
451
		/* EMPTY */
7 7u83 452
	    } else if (info & dspec_defn) {
2 7u83 453
		/* Defined labels */
7 7u83 454
		HASHID nm = DEREF_hashid(id_name(lab));
455
		if (!IS_hashid_anon(nm)) {
456
		    if (info & dspec_goto) {
2 7u83 457
			/* Label used and defined */
458
			/* EMPTY */
459
		    } else {
460
			/* Label defined but not used */
7 7u83 461
			IDENTIFIER fn = crt_func_id;
462
			DEREF_loc(id_loc(lab), loc);
463
			report(loc, ERR_stmt_label_unused(lab, fn));
2 7u83 464
		    }
7 7u83 465
		    if (info & (dspec_reached | dspec_fall_thru)) {
2 7u83 466
			/* Label reached */
467
			/* EMPTY */
468
		    } else {
469
			/* Label unreached */
7 7u83 470
			DEREF_loc(id_loc(lab), loc);
471
			report(loc, ERR_stmt_stmt_unreach());
2 7u83 472
		    }
473
		}
7 7u83 474
		no_labs++;
2 7u83 475
	    } else {
476
		/* Undefined labels */
7 7u83 477
		HASHID nm = DEREF_hashid(id_name(lab));
478
		if (!IS_hashid_anon(nm)) {
479
		    IDENTIFIER fn = crt_func_id;
480
		    DEREF_loc(id_loc(lab), loc);
481
		    report(loc, ERR_stmt_goto_undef(lab, fn));
2 7u83 482
		}
483
	    }
484
	}
485
 
486
	/* Check next label */
7 7u83 487
	mem = DEREF_member(member_next(mem));
2 7u83 488
    }
7 7u83 489
    return (no_labs);
2 7u83 490
}
491
 
492
 
493
/*
494
    FIND THE VALUE OF A CASE LABEL
495
 
496
    This routine determines the value associated with the case label lab.
497
*/
498
 
7 7u83 499
NAT
500
find_case_nat(IDENTIFIER lab)
2 7u83 501
{
7 7u83 502
	EXP e = DEREF_exp(id_label_gotos(lab));
503
	if (!IS_NULL_exp(e) && IS_exp_switch_stmt(e)) {
504
		LIST(NAT) p;
505
		LIST(IDENTIFIER) q;
506
		p = DEREF_list(exp_switch_stmt_cases(e));
507
		q = DEREF_list(exp_switch_stmt_case_labs(e));
508
		while (!IS_NULL_list(q)) {
509
			IDENTIFIER id = DEREF_id(HEAD_list(q));
510
			if (EQ_id(id, lab)) {
511
				NAT n = DEREF_nat(HEAD_list(p));
512
				return (n);
513
			}
514
			p = TAIL_list(p);
515
			q = TAIL_list(q);
516
		}
2 7u83 517
	}
7 7u83 518
	return (NULL_nat);
2 7u83 519
}
520
 
521
 
522
/*
523
    LISTS OF ALL SOLVE STATEMENTS AND TRY BLOCKS
524
 
525
    The list all_solve_stmts keeps track of all the solve statements in
526
    the current function.  Similarly all_try_blocks keeps track of all the
527
    try blocks.
528
*/
529
 
7 7u83 530
LIST(EXP) all_solve_stmts = NULL_list(EXP);
531
LIST(EXP) all_try_blocks = NULL_list(EXP);
2 7u83 532
 
533
 
534
/*
535
    CHECK JUMPED OVER STATEMENTS
536
 
537
    This routine checks whether a jump over the statement e to the label
538
    lab causes the initialisation of a variable to be bypassed or control
539
    to be transferred into an exception handler or another label body.
540
    The variable force is used to indicate whether an error should be
541
    reported.  It is 2 for a jump into the statement, 1 for a jump from
542
    one branch of a statement to another (for example, a handler to the
543
    body of a try block), and 0 otherwise.  The routine adds any variable
544
    or label which is jumped over, whether initialised or not, to the
545
    list ids.
546
*/
547
 
7 7u83 548
static LIST(IDENTIFIER)
549
jump_over_stmt(LIST(IDENTIFIER) ids, EXP e, IDENTIFIER lab, int force)
2 7u83 550
{
7 7u83 551
	switch (TAG_exp(e)) {
552
	case exp_decl_stmt_tag: {
553
		/* Jump into declaration body */
554
		IDENTIFIER id = DEREF_id(exp_decl_stmt_id(e));
555
		DECL_SPEC ds = DEREF_dspec(id_storage(id));
556
		if (ds & dspec_auto) {
557
			if (force == 2) {
558
				int init = 1;
559
				EXP d = DEREF_exp(id_variable_init(id));
560
				if (IS_NULL_exp(d) || IS_exp_null(d)) {
561
					if (ds & dspec_reserve) {
562
						/* Initialised in conditional */
563
						/* EMPTY */
564
					} else {
565
						/* No initialiser */
566
						init = 0;
567
					}
568
				}
569
				if (init) {
570
					/* Jump over initialiser */
571
					ERROR err;
572
					LOCATION loc;
573
					int op = DEREF_int(id_label_op(lab));
574
					if (op == lex_identifier) {
575
						err = ERR_stmt_dcl_bypass_lab(lab, id);
576
					} else if (op == lex_case) {
577
						NAT n = find_case_nat(lab);
578
						err = ERR_stmt_dcl_bypass_case(n, id);
579
					} else {
580
						err = ERR_stmt_dcl_bypass_default(id);
581
					}
582
					DEREF_loc(id_loc(id), loc);
583
					report(loc, err);
584
				}
2 7u83 585
			}
7 7u83 586
			CONS_id(id, ids, ids);
2 7u83 587
		}
7 7u83 588
		break;
2 7u83 589
	}
7 7u83 590
	case exp_if_stmt_tag: {
591
		/* Jump into if statement */
592
		IDENTIFIER lb = DEREF_id(exp_if_stmt_label(e));
593
		if (!IS_NULL_id(lb)) {
594
			CONS_id(lb, ids, ids);
595
		}
596
		break;
2 7u83 597
	}
7 7u83 598
	case exp_while_stmt_tag: {
599
		/* Jump into while loop */
600
		IDENTIFIER bk = DEREF_id(exp_while_stmt_break_lab(e));
601
		IDENTIFIER cn = DEREF_id(exp_while_stmt_cont_lab(e));
602
		IDENTIFIER lp = DEREF_id(exp_while_stmt_loop_lab(e));
603
		CONS_id(bk, ids, ids);
604
		CONS_id(cn, ids, ids);
605
		CONS_id(lp, ids, ids);
606
		break;
2 7u83 607
	}
7 7u83 608
	case exp_do_stmt_tag: {
609
		/* Jump into do loop */
610
		IDENTIFIER bk = DEREF_id(exp_do_stmt_break_lab(e));
611
		IDENTIFIER cn = DEREF_id(exp_do_stmt_cont_lab(e));
612
		IDENTIFIER lp = DEREF_id(exp_do_stmt_loop_lab(e));
613
		CONS_id(bk, ids, ids);
614
		CONS_id(cn, ids, ids);
615
		CONS_id(lp, ids, ids);
616
		break;
2 7u83 617
	}
7 7u83 618
	case exp_switch_stmt_tag: {
619
		/* Jump into switch statement */
620
		IDENTIFIER bk = DEREF_id(exp_switch_stmt_break_lab(e));
621
		CONS_id(bk, ids, ids);
622
		break;
2 7u83 623
	}
7 7u83 624
	case exp_solve_stmt_tag: {
625
		/* Jump into solve statement */
626
		LIST(IDENTIFIER) lbs;
627
		LIST(IDENTIFIER) vars;
628
		lbs = DEREF_list(exp_solve_stmt_labels(e));
629
		while (!IS_NULL_list(lbs)) {
630
			IDENTIFIER lb = DEREF_id(HEAD_list(lbs));
631
			CONS_id(lb, ids, ids);
632
			lbs = TAIL_list(lbs);
633
		}
634
		vars = DEREF_list(exp_solve_stmt_vars(e));
635
		while (!IS_NULL_list(vars)) {
636
			IDENTIFIER var = DEREF_id(HEAD_list(vars));
637
			CONS_id(var, ids, ids);
638
			vars = TAIL_list(vars);
639
		}
640
		break;
2 7u83 641
	}
7 7u83 642
	case exp_label_stmt_tag: {
643
		/* Jump into labelled block */
644
		IDENTIFIER lb = DEREF_id(exp_label_stmt_label(e));
645
		CONS_id(lb, ids, ids);
646
		break;
2 7u83 647
	}
7 7u83 648
	case exp_try_block_tag:
649
		/* Jump into try block */
650
		if (force != 0) {
651
			LOCATION loc;
652
			DEREF_loc(id_loc(lab), loc);
653
			report(loc, ERR_except_jump_into());
654
		}
655
		break;
656
	case exp_hash_if_tag:
657
		/* Jump into target dependent '#if' */
658
		if (force != 0) {
659
			LOCATION loc;
660
			DEREF_loc(id_loc(lab), loc);
661
			report(loc, ERR_cpp_cond_if_jump_into());
662
		}
663
		break;
664
	case exp_token_tag:
665
		/* Jump into statement token */
666
		if (force != 0) {
667
			LOCATION loc;
668
			DEREF_loc(id_loc(lab), loc);
669
			report(loc, ERR_token_stmt_jump());
670
		}
671
		break;
2 7u83 672
	}
7 7u83 673
	return (ids);
2 7u83 674
}
675
 
676
 
677
/*
678
    ADD AN IDENTIFIER TO A LIST
679
 
680
    This routine adds the identifier id to the start of the list p if it
681
    is not already a member.
682
*/
683
 
7 7u83 684
static LIST(IDENTIFIER)
685
add_id(IDENTIFIER id, LIST(IDENTIFIER) p)
2 7u83 686
{
7 7u83 687
	LIST(IDENTIFIER) q = p;
688
	while (!IS_NULL_list(q)) {
689
		IDENTIFIER qid = DEREF_id(HEAD_list(q));
690
		if (EQ_id(id, qid)) {
691
			return (p);
692
		}
693
		q = TAIL_list(q);
694
	}
695
	CONS_id(id, p, p);
696
	return (p);
2 7u83 697
}
698
 
699
 
700
/*
701
    EXTEND A SOLVE STATEMENT
702
 
703
    This routine extends the solve statement a by adding the label lab
704
    and the variables ids.
705
*/
706
 
7 7u83 707
static void
708
extend_solve_stmt(EXP a, IDENTIFIER lab, LIST(IDENTIFIER) ids)
2 7u83 709
{
7 7u83 710
	LIST(IDENTIFIER) vars = DEREF_list(exp_solve_stmt_vars(a));
711
	LIST(IDENTIFIER) labels = DEREF_list(exp_solve_stmt_labels(a));
712
	labels = add_id(lab, labels);
713
	while (!IS_NULL_list(ids)) {
714
		IDENTIFIER id = DEREF_id(HEAD_list(ids));
715
		if (IS_id_label(id)) {
716
			labels = add_id(id, labels);
717
		} else {
718
			vars = add_id(id, vars);
719
		}
720
		ids = TAIL_list(ids);
2 7u83 721
	}
7 7u83 722
	COPY_list(exp_solve_stmt_labels(a), labels);
723
	COPY_list(exp_solve_stmt_vars(a), vars);
724
	return;
2 7u83 725
}
726
 
727
 
728
/*
729
    CHECK FOR UNSTRUCTURED JUMPS
730
 
731
    The only instance where the mapping of a statement onto the
732
    corresponding TDF construct is non-trivial is for unstructured
733
    labels and gotos.  This routine scans the body of the current
734
    function, e, for such unstructured jumps and imposes some semblance
735
    of order on them.  The idea is to start with a labelled statement
736
    and to gradually expand the statement outwards until it contains all
737
    the goto statements for that label as substatements.  If this is the
738
    original labelled statement then no further action is required,
739
    otherwise the enclosing statement is further expanded to the
740
    enclosing block and the labelled statement is referenced from there.
741
    Jumps which bypass the initialisation of a variable or transfer
742
    control into an exception handler can also be detected during this
743
    process.
744
*/
745
 
7 7u83 746
EXP
747
solve_labels(EXP e)
2 7u83 748
{
7 7u83 749
    MEMBER mem = DEREF_member(nspace_last(label_namespace));
750
    while (!IS_NULL_member(mem)) {
751
	IDENTIFIER lab = DEREF_id(member_id(mem));
752
	if (!IS_NULL_id(lab)) {
753
	    DECL_SPEC info = DEREF_dspec(id_storage(lab));
754
	    if (info & dspec_anon) {
2 7u83 755
		/* Unnamed labels are ignored */
756
		/* EMPTY */
7 7u83 757
	    } else if (info & dspec_defn) {
2 7u83 758
		/* Only check defined labels */
7 7u83 759
		int solve = 0;
760
		EXP a = DEREF_exp(id_label_stmt(lab));
761
		EXP p = DEREF_exp(id_label_gotos(lab));
762
		LIST(IDENTIFIER) ids = NULL_list(IDENTIFIER);
763
		for (;;) {
2 7u83 764
		    /* Scan for enclosing statement */
7 7u83 765
		    EXP q = p;
766
		    int ok = 1;
767
		    while (!IS_NULL_exp(q) && IS_exp_goto_stmt(q)) {
2 7u83 768
			/* Check each goto statement */
7 7u83 769
			EXP b = q;
770
			PTR(EXP) pb = exp_goto_stmt_join(b);
771
			if (IS_NULL_exp(DEREF_exp(pb))) {
2 7u83 772
			    /* Join statement not yet assigned */
7 7u83 773
			    for (;;) {
774
				if (EQ_exp(a, b)) {
2 7u83 775
				    /* b is a sub-statement of a */
7 7u83 776
				    COPY_exp(pb, a);
777
				    break;
2 7u83 778
				}
7 7u83 779
				b = get_parent_stmt(b);
780
				if (IS_NULL_exp(b)) {
2 7u83 781
				    /* b is not a sub-statement of a */
7 7u83 782
				    ok = 0;
783
				    break;
2 7u83 784
				}
785
			    }
786
			}
7 7u83 787
			q = DEREF_exp(exp_goto_stmt_next(q));
2 7u83 788
		    }
789
 
790
		    /* Check whether a encloses all the jumps to lab */
7 7u83 791
		    if (ok) {
792
			int force = 1;
793
			while (!IS_exp_solve_stmt(a)) {
2 7u83 794
			    /* Scan to enclosing solve statement */
7 7u83 795
			    ids = jump_over_stmt(ids, a, lab, force);
796
			    a = get_parent_stmt(a);
797
			    if (IS_NULL_exp(a)) {
798
				    break;
799
			    }
800
			    force = 0;
2 7u83 801
			}
7 7u83 802
			break;
2 7u83 803
		    }
804
 
805
		    /* Some jump to lab is from outside a */
7 7u83 806
		    ids = jump_over_stmt(ids, a, lab, 2);
807
		    solve = 1;
2 7u83 808
 
809
		    /* Expand a to enclosing statement */
7 7u83 810
		    a = get_parent_stmt(a);
811
		    if (IS_NULL_exp(a)) {
2 7u83 812
			/* Can happen with statement tokens */
7 7u83 813
			a = e;
814
			break;
2 7u83 815
		    }
816
		}
817
 
818
		/* Deal with unstructured labels */
7 7u83 819
		if (solve) {
820
		    info |= dspec_solve;
821
		    COPY_dspec(id_storage(lab), info);
822
		    extend_solve_stmt(a, lab, ids);
2 7u83 823
		}
7 7u83 824
		DESTROY_list(ids, SIZE_id);
2 7u83 825
	    }
826
	}
7 7u83 827
	mem = DEREF_member(member_next(mem));
2 7u83 828
    }
7 7u83 829
    return (e);
2 7u83 830
}
831
 
832
 
833
/*
834
    CHECK A JUMP TO A CASE OR DEFAULT STATEMENT
835
 
836
    This routine checks whether the jump from the switch statement e to
837
    the case or default label lab bypasses the initialisation of a variable
838
    or jumps into an exception handler.  The previous labelled statement
839
    checked is passed in as prev.  If e is a sub-statement of prev then
840
    there is no need to check further.  The routine returns the labelled
841
    statement corresponding to lab.
842
*/
843
 
7 7u83 844
static EXP
845
solve_case(EXP e, IDENTIFIER lab, EXP prev)
2 7u83 846
{
7 7u83 847
	DECL_SPEC info = DEREF_dspec(id_storage(lab));
848
	if (info & dspec_defn) {
849
		EXP b = DEREF_exp(id_label_stmt(lab));
850
		EXP a = b;
851
		LIST(IDENTIFIER) ids = NULL_list(IDENTIFIER);
852
		while (!EQ_exp(a, e) && !EQ_exp(a, prev)) {
853
			ids = jump_over_stmt(ids, a, lab, 2);
854
			a = get_parent_stmt(a);
855
			if (IS_NULL_exp(a)) {
856
				break;
857
			}
858
		}
859
		if (!IS_NULL_list(ids)) {
860
			EXP s = DEREF_exp(exp_switch_stmt_body(e));
861
			extend_solve_stmt(s, lab, ids);
862
			DESTROY_list(ids, SIZE_id);
863
		}
864
		prev = b;
2 7u83 865
	} else {
7 7u83 866
		/* Case not defined */
867
		EXP a, b;
868
		LOCATION loc;
869
		int uc = unreached_code;
870
		IDENTIFIER flab = NULL_id;
871
		int op = DEREF_int(id_label_op(lab));
872
		DEREF_loc(id_loc(lab), loc);
873
		if (op == lex_case) {
874
			NAT n = find_case_nat(lab);
875
			report(loc, ERR_stmt_switch_case_not(n));
876
			flab = DEREF_id(exp_switch_stmt_default_lab(e));
877
		} else {
878
			report(loc, ERR_stmt_switch_default_not());
879
		}
880
		if (IS_NULL_id(flab)) {
881
			flab = DEREF_id(exp_switch_stmt_break_lab(e));
882
		}
883
		a = begin_label_stmt(lab, op);
884
		b = make_jump_stmt(flab, e);
885
		IGNORE end_label_stmt(a, b);
886
		unreached_code = uc;
2 7u83 887
	}
7 7u83 888
	return (prev);
2 7u83 889
}
890
 
891
 
892
/*
893
    CHECK A SWITCH STATEMENT
894
 
895
    This routine scans through the switch statement e for jumps which
896
    bypass the initialisation of a variable.
897
*/
898
 
7 7u83 899
EXP
900
solve_switch(EXP e)
2 7u83 901
{
7 7u83 902
	IDENTIFIER lab;
903
	EXP prev = NULL_exp;
904
	LIST(IDENTIFIER) cases;
905
	cases = DEREF_list(exp_switch_stmt_case_labs(e));
906
	while (!IS_NULL_list(cases)) {
907
		/* Check each case statement */
908
		lab = DEREF_id(HEAD_list(cases));
909
		prev = solve_case(e, lab, prev);
910
		cases = TAIL_list(cases);
911
	}
912
	lab = DEREF_id(exp_switch_stmt_default_lab(e));
913
	if (!IS_NULL_id(lab)) {
914
		/* Check any default statement */
915
		IGNORE solve_case(e, lab, prev);
916
	}
917
	return (e);
2 7u83 918
}
919
 
920
 
921
/*
922
    CONSTRUCT A LABEL FOR THE FOLLOWING STATEMENT
923
 
924
    This routine turns the list of statements following the position p
925
    in the block statement e into a labelled statement, returning the
926
    label created.  If p is the last statement in the block then the
927
    null identifier is returned.
928
*/
929
 
7 7u83 930
static IDENTIFIER
931
follow_label(EXP e, LIST(EXP) p)
2 7u83 932
{
7 7u83 933
	EXP a, b, c;
934
	DECL_SPEC ds;
935
	IDENTIFIER lab;
936
	LIST(EXP) r;
937
	LIST(EXP) q = TAIL_list(p);
938
	if (IS_NULL_list(q)) {
939
		return (NULL_id);
940
	}
2 7u83 941
 
7 7u83 942
	/* Examine following statement */
943
	a = DEREF_exp(HEAD_list(q));
944
	if (!IS_NULL_exp(a)) {
945
		unsigned tag = TAG_exp(a);
946
		if (tag == exp_location_tag) {
947
			a = DEREF_exp(exp_location_arg(a));
948
			if (!IS_NULL_exp(a)) {
949
				tag = TAG_exp(a);
950
			}
951
			if (tag == exp_label_stmt_tag) {
952
				/* Statement is already labelled */
953
				lab = DEREF_id(exp_label_stmt_label(a));
954
				return (lab);
955
			}
956
		}
2 7u83 957
	}
958
 
7 7u83 959
	/* Create new labelled statement */
960
	b = begin_label_stmt(NULL_id, lex_end);
961
	b = end_label_stmt(b, NULL_exp);
962
	set_parent_stmt(b, e);
963
	c = DEREF_exp(exp_label_stmt_body(b));
964
	r = DEREF_list(exp_sequence_first(c));
965
	IGNORE APPEND_list(r, q);
966
	while (!IS_NULL_list(q)) {
967
		a = DEREF_exp(HEAD_list(q));
968
		set_parent_stmt(a, b);
969
		q = TAIL_list(q);
970
	}
971
	COPY_list(PTR_TAIL_list(p), NULL_list(EXP));
972
	CONS_exp(b, NULL_list(EXP), q);
973
	IGNORE APPEND_list(p, q);
974
	lab = DEREF_id(exp_label_stmt_label(b));
975
	ds = DEREF_dspec(id_storage(lab));
976
	ds |= (dspec_goto | dspec_used);
977
	COPY_dspec(id_storage(lab), ds);
978
	return (lab);
2 7u83 979
}
980
 
981
 
982
/*
983
    FIND THE END OF A BRANCH OF A SOLVE STATEMENT
984
 
985
    This routine finds the end of the branch of the solve statement e
986
    given by the label lab.  This is a label which gives any immediately
987
    following code.
988
*/
989
 
7 7u83 990
static IDENTIFIER
991
end_solve_branch(IDENTIFIER lab, EXP e)
2 7u83 992
{
7 7u83 993
    EXP a;
994
    IDENTIFIER nlab;
995
    int op = DEREF_int(id_label_op(lab));
996
    switch (op) {
997
	case lex_continue:
998
	case lex_while:
999
	case lex_for:
1000
	case lex_do:
2 7u83 1001
	    /* Don't bother in these cases */
7 7u83 1002
	    return (NULL_id);
2 7u83 1003
    }
7 7u83 1004
    a = DEREF_exp(id_label_stmt(lab));
1005
    if (IS_NULL_exp(a)) {
2 7u83 1006
	/* Ignore undefined labels */
7 7u83 1007
	return (NULL_id);
2 7u83 1008
    }
7 7u83 1009
    nlab = DEREF_id(exp_label_stmt_next(a));
1010
    if (IS_NULL_id(nlab)) {
2 7u83 1011
	/* Scan up to enclosing block */
7 7u83 1012
	EXP b = a;
1013
	EXP c = DEREF_exp(exp_label_stmt_parent(b));
1014
	while (!EQ_exp(c, e) && !IS_NULL_exp(c)) {
1015
	    int again;
1016
	    EXP d = c;
2 7u83 1017
	    do {
7 7u83 1018
		again = 0;
1019
		switch (TAG_exp(d)) {
1020
		    case exp_sequence_tag: {
2 7u83 1021
			/* Found enclosing block */
7 7u83 1022
			LIST(EXP) q;
1023
			q = DEREF_list(exp_sequence_first(d));
1024
			q = TAIL_list(q);
1025
			while (!IS_NULL_list(q)) {
1026
			    EXP f = DEREF_exp(HEAD_list(q));
1027
			    if (!IS_NULL_exp(f)) {
1028
				if (IS_exp_location(f)) {
2 7u83 1029
				    /* Allow for location statements */
7 7u83 1030
				    f = DEREF_exp(exp_location_arg(f));
2 7u83 1031
				}
7 7u83 1032
				if (EQ_exp(f, b)) {
2 7u83 1033
				    /* Found labelled statement in block */
7 7u83 1034
				    nlab = follow_label(d, q);
1035
				    break;
2 7u83 1036
				}
1037
			    }
7 7u83 1038
			    q = TAIL_list(q);
2 7u83 1039
			}
7 7u83 1040
			break;
2 7u83 1041
		    }
7 7u83 1042
		    case exp_while_stmt_tag: {
2 7u83 1043
			/* Found enclosing while statement */
7 7u83 1044
			IDENTIFIER blab;
1045
			blab = DEREF_id(exp_while_stmt_break_lab(d));
1046
			if (!EQ_id(blab, lab)) {
1047
			    nlab = DEREF_id(exp_while_stmt_cont_lab(d));
2 7u83 1048
			}
7 7u83 1049
			break;
2 7u83 1050
		    }
7 7u83 1051
		    case exp_do_stmt_tag: {
2 7u83 1052
			/* Found enclosing do statement */
7 7u83 1053
			IDENTIFIER blab;
1054
			blab = DEREF_id(exp_do_stmt_break_lab(d));
1055
			if (!EQ_id(blab, lab)) {
1056
			    nlab = DEREF_id(exp_do_stmt_cont_lab(d));
2 7u83 1057
			}
7 7u83 1058
			break;
2 7u83 1059
		    }
7 7u83 1060
		    case exp_switch_stmt_tag:
2 7u83 1061
			/* Found enclosing switch statement */
7 7u83 1062
			nlab = DEREF_id(exp_switch_stmt_break_lab(d));
1063
			if (EQ_id(nlab, lab))nlab = NULL_id;
1064
			break;
1065
		    case exp_decl_stmt_tag:
2 7u83 1066
			/* Found enclosing declaration */
7 7u83 1067
			d = DEREF_exp(exp_decl_stmt_body(d));
1068
			if (!EQ_exp(d, b))again = 1;
1069
			break;
1070
		    case exp_label_stmt_tag:
2 7u83 1071
			/* Found enclosing label statement */
7 7u83 1072
			d = DEREF_exp(exp_label_stmt_body(d));
1073
			if (!EQ_exp(d, b))again = 1;
1074
			break;
2 7u83 1075
		}
7 7u83 1076
	    } while (again);
1077
	    if (!IS_NULL_id(nlab)) {
2 7u83 1078
		/* Label for next statement found */
7 7u83 1079
		nlab = DEREF_id(id_alias(nlab));
1080
		if (op == lex_break) {
2 7u83 1081
		    /* Alias break labels */
7 7u83 1082
		    COPY_id(id_alias(lab), nlab);
2 7u83 1083
		}
7 7u83 1084
		break;
2 7u83 1085
	    }
7 7u83 1086
	    b = c;
1087
	    c = get_parent_stmt(b);
2 7u83 1088
	}
1089
    }
7 7u83 1090
    COPY_id(exp_label_stmt_next(a), nlab);
1091
    return (nlab);
2 7u83 1092
}
1093
 
1094
 
1095
/*
1096
    END ALL SOLVE STATEMENTS
1097
 
1098
    This routine calls end_solve_branch for all the branches of all the
1099
    solve statements in the current function.
1100
*/
1101
 
7 7u83 1102
void
1103
end_solve_stmts(void)
2 7u83 1104
{
7 7u83 1105
    LIST(EXP) p = all_solve_stmts;
1106
    if (!IS_NULL_list(p)) {
1107
	while (!IS_NULL_list(p)) {
1108
	    int changed;
1109
	    LIST(IDENTIFIER) q0;
1110
	    EXP e = DEREF_exp(HEAD_list(p));
1111
	    q0 = DEREF_list(exp_solve_stmt_labels(e));
2 7u83 1112
	    do {
7 7u83 1113
		LIST(IDENTIFIER) q = q0;
1114
		changed = 0;
1115
		while (!IS_NULL_list(q)) {
1116
		    IDENTIFIER lab = DEREF_id(HEAD_list(q));
1117
		    IDENTIFIER nlab = end_solve_branch(lab, e);
1118
		    if (!IS_NULL_id(nlab)) {
2 7u83 1119
			/* Add new label to list */
7 7u83 1120
			LIST(IDENTIFIER) q1 = add_id(nlab, q0);
1121
			if (!EQ_list(q1, q0)) {
1122
			    q0 = q1;
1123
			    changed = 1;
2 7u83 1124
			}
1125
		    }
7 7u83 1126
		    q = TAIL_list(q);
2 7u83 1127
		}
7 7u83 1128
	    } while (changed);
1129
	    COPY_list(exp_solve_stmt_labels(e), q0);
1130
	    p = TAIL_list(p);
2 7u83 1131
	}
7 7u83 1132
	DESTROY_list(all_solve_stmts, SIZE_exp);
1133
	all_solve_stmts = NULL_list(EXP);
2 7u83 1134
    }
7 7u83 1135
    return;
2 7u83 1136
}