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 "version.h"
33
#include "c_types.h"
34
#include "exp_ops.h"
35
#include "type_ops.h"
36
#include "error.h"
37
#include "tdf.h"
38
#include "allocate.h"
39
#include "basetype.h"
40
#include "capsule.h"
41
#include "chktype.h"
42
#include "compile.h"
43
#include "destroy.h"
44
#include "diag.h"
45
#include "encode.h"
46
#include "exception.h"
47
#include "exp.h"
48
#include "init.h"
49
#include "inttype.h"
50
#include "shape.h"
51
#include "statement.h"
52
#include "stmt.h"
53
#include "struct.h"
54
#include "syntax.h"
55
#include "throw.h"
56
#include "tok.h"
57
#include "typeid.h"
58
#include "ustring.h"
59
#if TDF_OUTPUT
60
 
61
 
62
/*
63
    ENCODE THE ADDRESS OF A DESTRUCTOR
64
 
65
    This routine adds the address of the destructor function corresponding
66
    to d to the bitstream bs.
67
*/
68
 
69
BITSTREAM *enc_destr_func
70
    PROTO_N ( ( bs, d ) )
71
    PROTO_T ( BITSTREAM *bs X EXP d )
72
{
73
    if ( !IS_NULL_exp ( d ) ) {
74
	EXP f ;
75
	while ( IS_exp_nof ( d ) ) {
76
	    d = DEREF_exp ( exp_nof_pad ( d ) ) ;
77
	}
78
	f = DEREF_exp ( exp_destr_call ( d ) ) ;
79
	if ( IS_exp_func_id ( f ) ) {
80
	    ulong n ;
81
	    IDENTIFIER fn = DEREF_id ( exp_func_id_id ( f ) ) ;
82
	    IGNORE capsule_id ( fn, VAR_tag ) ;
83
	    n = unit_no ( bs, fn, VAR_tag, 0 ) ;
84
	    ENC_obtain_tag ( bs ) ;
85
	    ENC_make_tag ( bs, n ) ;
86
	    return ( bs ) ;
87
	}
88
    }
89
    ENC_make_null_proc ( bs ) ;
90
    return ( bs ) ;
91
}
92
 
93
 
94
/*
95
    EXCEPTION HANDLING ROUTINES
96
 
97
    The exception handling routines are only included in the C++ producer.
98
*/
99
 
100
#if LANGUAGE_CPP
101
 
102
 
103
/*
104
    ENCODE A CATCH STATEMENT
105
 
106
    This routine adds the start of a catch statement to the bitstream bs.
107
    It checks whether the type t can handle the current exception.  If
108
    the label lab is given then catching the exception causes a jump to
109
    lab.  Otherwise the handler body, consisting of seq statements,
110
    followed by the code if the exception is not caught, needs to be
111
    added later.
112
*/
113
 
114
static BITSTREAM *enc_catch
115
    PROTO_N ( ( bs, t, lab, seq ) )
116
    PROTO_T ( BITSTREAM *bs X TYPE t X ulong lab X unsigned seq )
117
{
118
    BITSTREAM *ts ;
119
    NTEST tst = ntest_eq ;
120
    if ( lab == LINK_NONE ) {
121
	/* Create label if necessary */
122
	lab = unit_no ( bs, NULL_id, VAR_label, 1 ) ;
123
	ENC_conditional ( bs ) ;
124
	ENC_make_label ( bs, lab ) ;
125
	ENC_SEQUENCE ( bs, seq ) ;
126
	tst = ntest_not_eq ;
127
    }
128
    ENC_integer_test ( bs ) ;
129
    ENC_OFF ( bs ) ;
130
    bs = enc_ntest ( bs, tst ) ;
131
    ENC_make_label ( bs, lab ) ;
132
    bs = enc_special ( bs, TOK_except_catch ) ;
133
    ts = start_bitstream ( NIL ( FILE ), bs->link ) ;
134
    ts = enc_rtti_type ( ts, t, lex_typeid ) ;
135
    bs = enc_bitstream ( bs, ts ) ;
136
    bs = enc_make_int ( bs, type_sint, 0 ) ;
137
    return ( bs ) ;
138
}
139
 
140
 
141
/*
142
    ENCODE THE START OF A TRY BLOCK
143
 
144
    This routine adds the start of a try block to the bitstream bs.  seq
145
    gives the number of statements to follow.
146
*/
147
 
148
BITSTREAM *enc_try_start
149
    PROTO_N ( ( bs, pn, seq ) )
150
    PROTO_T ( BITSTREAM *bs X ulong *pn X unsigned seq )
151
{
152
    ulong n ;
153
    ulong lab ;
154
    BITSTREAM *ts ;
155
 
156
    /* Must be in a function definition */
157
    if ( in_dynamic_init ) output_init = 1 ;
158
 
159
    /* Encode the try block jump buffer */
160
    n = unit_no ( bs, NULL_id, VAR_tag, 1 ) ;
161
    ENC_variable ( bs ) ;
162
    bs = enc_access ( bs, crt_func_access ) ;
163
    ENC_make_tag ( bs, n ) ;
164
    ENC_make_value ( bs ) ;
165
    bs = enc_special ( bs, TOK_try_type ) ;
166
    *pn = n ;
167
 
168
    /* Encode the try block label */
169
    lab = unit_no ( bs, NULL_id, VAR_label, 1 ) ;
170
    ENC_conditional ( bs ) ;
171
    ENC_make_label ( bs, lab ) ;
172
 
173
    /* Encode the try block body */
174
    ENC_SEQUENCE ( bs, seq ) ;
175
    bs = enc_special ( bs, TOK_try_begin ) ;
176
    ts = start_bitstream ( NIL ( FILE ), bs->link ) ;
177
    ENC_obtain_tag ( ts ) ;
178
    ENC_make_tag ( ts, n ) ;
179
    ENC_current_env ( ts ) ;
180
    ENC_make_local_lv ( ts ) ;
181
    ENC_make_label ( ts, lab ) ;
182
    bs = enc_bitstream ( bs, ts ) ;
183
    return ( bs ) ;
184
}
185
 
186
 
187
/*
188
    ENCODE THE END OF A TRY BLOCK
189
 
190
    This routine adds the end of the current try block to the bitstream bs.
191
*/
192
 
193
BITSTREAM *enc_try_end
194
    PROTO_N ( ( bs, n ) )
195
    PROTO_T ( BITSTREAM *bs X ulong n )
196
{
197
    BITSTREAM *ts ;
198
    bs = enc_special ( bs, TOK_try_end ) ;
199
    ts = start_bitstream ( NIL ( FILE ), bs->link ) ;
200
    ENC_obtain_tag ( ts ) ;
201
    ENC_make_tag ( ts, n ) ;
202
    bs = enc_bitstream ( bs, ts ) ;
203
    return ( bs ) ;
204
}
205
 
206
 
207
/*
208
    ENCODE A TRY BLOCK
209
 
210
    This routine adds the try block e to the bitstream bs.
211
*/
212
 
213
BITSTREAM *enc_try
214
    PROTO_N ( ( bs, e ) )
215
    PROTO_T ( BITSTREAM *bs X EXP e )
216
{
217
    int uc ;
218
    ulong ex ;
219
    unsigned seq ;
220
    EXP a = DEREF_exp ( exp_try_block_body ( e ) ) ;
221
    LIST ( EXP ) p = DEREF_list ( exp_try_block_handlers ( e ) ) ;
222
    LIST ( TYPE ) q = DEREF_list ( exp_try_block_htypes ( e ) ) ;
223
    EXP c = DEREF_exp ( exp_try_block_ellipsis ( e ) ) ;
224
 
225
    /* Ignore handlers if exception handling disabled */
226
    if ( !output_except ) {
227
	bs = enc_stmt ( bs, a ) ;
228
	return ( bs ) ;
229
    }
230
 
231
    /* Encode the try block */
232
    no_destructors++ ;
233
    if ( output_new_diag ) {
234
	seq = 2 ;
235
    } else {
236
	seq = stmt_length ( a ) + 1 ;
237
    }
238
    bs = enc_try_start ( bs, &ex, seq ) ;
239
    COPY_ulong ( exp_try_block_no ( e ), ex ) ;
240
    if ( output_new_diag ) {
241
	BITSTREAM *ts = enc_diag_begin ( &bs ) ;
242
	ts = enc_stmt ( ts, a ) ;
243
	bs = enc_diag_end ( bs, ts, e, 1 ) ;
244
    } else {
245
	bs = enc_compound_stmt ( bs, a ) ;
246
    }
247
    bs = enc_try_end ( bs, ex ) ;
248
    uc = unreached_code ;
249
 
250
    /* Encode the handlers */
251
    while ( !IS_NULL_list ( p ) ) {
252
	EXP b = DEREF_exp ( HEAD_list ( p ) ) ;
253
	TYPE t = DEREF_type ( HEAD_list ( q ) ) ;
254
	unreached_code = 0 ;
255
	if ( !output_new_diag ) {
256
	    b = DEREF_exp ( exp_handler_body ( b ) ) ;
257
	}
258
	seq = stmt_length ( b ) + 1 ;
259
	bs = enc_catch ( bs, t, LINK_NONE, seq ) ;
260
	bs = enc_compound_stmt ( bs, b ) ;
261
	bs = enc_special ( bs, TOK_except_end ) ;
262
	if ( !unreached_code ) uc = 0 ;
263
	q = TAIL_list ( q ) ;
264
	p = TAIL_list ( p ) ;
265
    }
266
 
267
    /* Encode the default handler */
268
    unreached_code = 0 ;
269
    if ( IS_exp_handler ( c ) ) {
270
	if ( !output_new_diag ) {
271
	    c = DEREF_exp ( exp_handler_body ( c ) ) ;
272
	}
273
	seq = stmt_length ( c ) ;
274
	if ( seq ) {
275
	    ENC_SEQUENCE ( bs, seq ) ;
276
	    bs = enc_compound_stmt ( bs, c ) ;
277
	}
278
	bs = enc_special ( bs, TOK_except_end ) ;
279
    } else {
280
	/* Re-throw current exception */
281
	bs = enc_exp ( bs, c ) ;
282
    }
283
    if ( !unreached_code ) uc = 0 ;
284
    unreached_code = uc ;
285
    no_destructors-- ;
286
    return ( bs ) ;
287
}
288
 
289
 
290
/*
291
    RETHROW THE CURRENT EXCEPTION
292
 
293
    This routine adds the expression 'throw' to the bitstream bs.
294
*/
295
 
296
BITSTREAM *enc_rethrow
297
    PROTO_N ( ( bs ) )
298
    PROTO_T ( BITSTREAM *bs )
299
{
300
    if ( output_except ) {
301
	bs = enc_special ( bs, TOK_except_rethrow ) ;
302
    } else {
303
	BITSTREAM *ts ;
304
	bs = enc_special ( bs, TOK_except_bad ) ;
305
	ts = start_bitstream ( NIL ( FILE ), bs->link ) ;
306
	ts = enc_make_snat ( ts, 0 ) ;
307
	bs = enc_bitstream ( bs, ts ) ;
308
    }
309
    unreached_code = 1 ;
310
    return ( bs ) ;
311
}
312
 
313
 
314
/*
315
    ENCODE A THROW EXPRESSION
316
 
317
    This routine adds the expression 'throw a' to the bitstream bs.  If
318
    a is the null expression then the current exception is rethrown.  b
319
    and d give the size and destructor for the exception type.
320
*/
321
 
322
BITSTREAM *enc_throw
323
    PROTO_N ( ( bs, a, b, d ) )
324
    PROTO_T ( BITSTREAM *bs X EXP a X EXP b X EXP d )
325
{
326
    if ( !IS_NULL_exp ( a ) && output_except ) {
327
	/* Set up variable */
328
	EXP c ;
329
	BITSTREAM *ts, *us ;
330
	TYPE t = DEREF_type ( exp_type ( a ) ) ;
331
	ulong n = unit_no ( bs, NULL_id, VAR_tag, 1 ) ;
332
	ENC_variable ( bs ) ;
333
	bs = enc_access ( bs, dspec_none ) ;
334
	ENC_make_tag ( bs, n ) ;
335
	MAKE_exp_dummy ( t, NULL_exp, n, NULL_off, 2, c ) ;
336
 
337
	/* Allocate space for exception value */
338
	bs = enc_special ( bs, TOK_from_ptr_void ) ;
339
	ts = start_bitstream ( NIL ( FILE ), bs->link ) ;
340
	ts = enc_alignment ( ts, t ) ;
341
	ts = enc_special ( ts, TOK_except_alloc ) ;
342
	us = start_bitstream ( NIL ( FILE ), ts->link ) ;
343
	us = enc_exp ( us, b ) ;
344
	ts = enc_bitstream ( ts, us ) ;
345
	bs = enc_bitstream ( bs, ts ) ;
346
 
347
	/* Assign exception value */
348
	ENC_SEQ_SMALL ( bs, 1 ) ;
349
	bs = enc_init_tag ( bs, n, NULL_off, 1, t, a, NULL_exp, 0 ) ;
350
 
351
	/* Throw the exception */
352
	bs = enc_special ( bs, TOK_except_throw ) ;
353
	ts = start_bitstream ( NIL ( FILE ), bs->link ) ;
354
	ts = enc_special ( ts, TOK_to_ptr_void ) ;
355
	us = start_bitstream ( NIL ( FILE ), ts->link ) ;
356
	us = enc_alignment ( us, t ) ;
357
	us = enc_exp ( us, c ) ;
358
	ts = enc_bitstream ( ts, us ) ;
359
	ts = enc_rtti_type ( ts, t, lex_typeid ) ;
360
	ts = enc_destr_func ( ts, d ) ;
361
	bs = enc_bitstream ( bs, ts ) ;
362
	unreached_code = 1 ;
363
	free_exp ( c, 1 ) ;
364
 
365
    } else {
366
	/* Rethrow the current exception */
367
	bs = enc_rethrow ( bs ) ;
368
    }
369
    return ( bs ) ;
370
}
371
 
372
 
373
/*
374
    ENCODE A CAUGHT EXPRESSION
375
 
376
    This routine adds the initialiser for an exception handler variable
377
    of type t to the bitstream bs.  This is obtained by casting the
378
    current exception value to a pointer to t.
379
*/
380
 
381
BITSTREAM *enc_thrown
382
    PROTO_N ( ( bs, t ) )
383
    PROTO_T ( BITSTREAM *bs X TYPE t )
384
{
385
    BITSTREAM *ts = start_bitstream ( NIL ( FILE ), bs->link ) ;
386
    bs = enc_special ( bs, TOK_from_ptr_void ) ;
387
    ts = enc_alignment ( ts, t ) ;
388
    ts = enc_special ( ts, TOK_except_value ) ;
389
    bs = enc_bitstream ( bs, ts ) ;
390
    return ( bs ) ;
391
}
392
 
393
 
394
/*
395
    EXCEPTION SPECIFICATION FLAG
396
 
397
    This flag is set to true if the current function has an exception
398
    specification.
399
*/
400
 
401
int in_exception_spec = 0 ;
402
 
403
 
404
/*
405
    ENCODE THE START OF A FUNCTION EXCEPTION HANDLER
406
 
407
    This routine is called at the start of a function definition declared
408
    with a non-trivial exception specification.  It sets up a try block
409
    enclosing the complete function body.
410
*/
411
 
412
BITSTREAM *enc_try_func
413
    PROTO_N ( ( bs, a ) )
414
    PROTO_T ( BITSTREAM *bs X EXP a )
415
{
416
    if ( !IS_NULL_exp ( a ) ) {
417
	/* Declare counter variable */
418
	EXP b = sizeof_init ( a, type_sint ) ;
419
	ulong n = unit_no ( bs, NULL_id, VAR_tag, 1 ) ;
420
	ENC_variable ( bs ) ;
421
	bs = enc_access ( bs, crt_func_access ) ;
422
	ENC_make_tag ( bs, n ) ;
423
	bs = enc_exp ( bs, b ) ;
424
	free_exp ( b, 1 ) ;
425
	last_params [ DUMMY_count ] = n ;
426
    }
427
    no_destructors++ ;
428
    in_exception_spec++ ;
429
    ENC_SEQ_SMALL ( bs, 1 ) ;
430
    bs = enc_try_start ( bs, last_params + DUMMY_catch, ( unsigned ) 1 ) ;
431
    return ( bs ) ;
432
}
433
 
434
 
435
/*
436
    BAD EXCEPTION TYPE
437
 
438
    This type represents the standard class 'std::bad_exception' which has
439
    a special meaning within exception specifications.
440
*/
441
 
442
static TYPE bad_except = NULL_type ;
443
 
444
 
445
/*
446
    ENCODE THE END OF A FUNCTION EXCEPTION HANDLER
447
 
448
    This routine is called at the end of a function definition declared
449
    with the set of exceptions p.  It sets up a list of exception handlers
450
    for each element of p which re-throw the current exception.  If the
451
    exception remains uncaught then the bad exception token is called
452
    (which calls unexpected).
453
*/
454
 
455
BITSTREAM *enc_catch_func
456
    PROTO_N ( ( bs, p, a ) )
457
    PROTO_T ( BITSTREAM *bs X LIST ( TYPE ) p X EXP a )
458
{
459
    int rethrow = 0 ;
460
    bs = enc_try_end ( bs, last_params [ DUMMY_catch ] ) ;
461
    if ( !IS_NULL_exp ( a ) ) {
462
	ENC_SEQ_SMALL ( bs, 1 ) ;
463
	bs = enc_exp ( bs, a ) ;
464
    }
465
    if ( EQ_list ( p, univ_type_set ) ) {
466
	/* Can throw any exception */
467
	rethrow = 1 ;
468
    } else {
469
	BITSTREAM *ts ;
470
	int have_bad = 0 ;
471
	if ( !IS_NULL_list ( p ) ) {
472
	    /* Check list of exceptions */
473
	    unsigned n = 0 ;
474
	    LIST ( TYPE ) q = p ;
475
	    while ( !IS_NULL_list ( q ) ) {
476
		TYPE t = DEREF_type ( HEAD_list ( q ) ) ;
477
		if ( !IS_NULL_type ( t ) ) n++ ;
478
		q = TAIL_list ( q ) ;
479
	    }
480
	    if ( n ) {
481
		ulong lab ;
482
		TYPE s = bad_except ;
483
		if ( IS_NULL_type ( s ) ) {
484
		    s = find_std_type ( "bad_exception", 1, 0 ) ;
485
		    s = exception_type ( s, 0 ) ;
486
		    bad_except = s ;
487
		}
488
		lab = unit_no ( bs, NULL_id, VAR_label, 1 ) ;
489
		ENC_conditional ( bs ) ;
490
		ENC_make_label ( bs, lab ) ;
491
		ENC_SEQUENCE ( bs, n ) ;
492
		while ( !IS_NULL_list ( p ) ) {
493
		    TYPE t = DEREF_type ( HEAD_list ( p ) ) ;
494
		    if ( !IS_NULL_type ( t ) ) {
495
			t = exception_type ( t, 0 ) ;
496
			if ( eq_type ( t, s ) ) have_bad = 1 ;
497
			bs = enc_catch ( bs, t, lab, ( unsigned ) 0 ) ;
498
		    }
499
		    p = TAIL_list ( p ) ;
500
		}
501
		rethrow = 1 ;
502
	    }
503
	}
504
	bs = enc_special ( bs, TOK_except_bad ) ;
505
	ts = start_bitstream ( NIL ( FILE ), bs->link ) ;
506
	ts = enc_make_snat ( ts, have_bad ) ;
507
	bs = enc_bitstream ( bs, ts ) ;
508
    }
509
    if ( rethrow ) {
510
	/* Re-throw the current exception */
511
	bs = enc_special ( bs, TOK_except_rethrow ) ;
512
	unreached_code = 1 ;
513
    }
514
    in_exception_spec-- ;
515
    no_destructors-- ;
516
    UNUSED ( a ) ;
517
    return ( bs ) ;
518
}
519
 
520
 
521
#endif /* LANGUAGE_CPP */
522
#endif /* TDF_OUTPUT */