Subversion Repositories tendra.SVN

Rev

Rev 2 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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