Subversion Repositories tendra.SVN

Rev

Rev 2 | Rev 6 | 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 "object.h"
33
#include "hash.h"
34
#include "name.h"
35
#include "type.h"
36
#include "print.h"
37
#include "utility.h"
38
 
39
 
40
/*
41
    COPYRIGHT MESSAGE
42
 
43
    These variables give the file containing the copyright message, and,
44
    after the first time it is processed, the message text.
45
*/
46
 
47
char *copyright = null ;
48
static char *copyright_text = null ;
49
 
50
 
51
/*
52
    OUTPUT MACROS
53
 
54
    These macros are used as convenient shorthands for various print
55
    routines.
56
*/
57
 
58
#define OUT		IGNORE fprintf
59
#define OUTC( X, Y )	IGNORE fputc ( Y, X )
60
#define OUTS( X, Y )	IGNORE fputs ( Y, X )
61
 
62
 
63
/*
64
    OUTPUT TRICKS
65
 
66
    A number of minor tricks are required in the headers, mostly due to
67
    library building problems.
68
*/
69
 
70
static boolean weak_proto = 0 ;
71
#define enum_hack	"__enum_"
72
#define is_hidden( X )	strneq ( X, HIDDEN_NAME, HIDDEN_LEN )
73
 
74
 
75
/*
76
    OUTPUT FILE
77
 
78
    These variables hold information about the current output file.
79
*/
80
 
81
static info *crt_info = null ;
82
static int column = 0 ;
83
 
84
 
85
/*
86
    DOES A TYPE HAVE A TAIL COMPONENT?
87
 
88
    This routine checks whether the type t has an array, bitfield or
89
    function component.
90
*/
91
 
92
static int is_tailed_type
93
    PROTO_N ( ( t ) )
94
    PROTO_T ( type *t )
95
{
96
    if ( t ) {
97
	switch ( t->id ) {
98
	    case TYPE_ARRAY :
99
	    case TYPE_BITFIELD :
100
	    case TYPE_PROC : {
101
		return ( 1 ) ;
102
	    }
103
	}
104
    }
105
    return ( 0 ) ;
106
}
107
 
108
 
109
/*
110
    PRINT THE HEAD OF A TYPE
111
 
112
    This routine prints the head of the type t, that is to say the base type
113
    and the pointer components, to the file output.
114
*/
115
 
116
static int print_head
117
    PROTO_N ( ( output, t, sp, tok ) )
118
    PROTO_T ( FILE *output X type *t X int sp X int tok )
119
{
120
    if ( t == null ) return ( sp ) ;
121
    switch ( t->id ) {
122
	case TYPE_VOID :
123
	case TYPE_INT :
124
	case TYPE_SIGNED :
125
	case TYPE_UNSIGNED :
126
	case TYPE_FLOAT :
127
	case TYPE_ARITH :
128
	case TYPE_SCALAR :
129
	case TYPE_STRUCT :
130
	case TYPE_UNION :
131
	case TYPE_ENUM :
132
	case TYPE_GENERIC :
133
	case TYPE_DEFINED :
134
	case TYPE_PROMOTE : {
135
	    OUTS ( output, t->u.obj->name ) ;
136
	    sp = 1 ;
137
	    break ;
138
	}
139
	case TYPE_STRUCT_TAG : {
140
	    OUT ( output, "struct %s", t->u.obj->name ) ;
141
	    sp = 1 ;
142
	    break ;
143
	}
144
	case TYPE_UNION_TAG : {
145
	    OUT ( output, "union %s", t->u.obj->name ) ;
146
	    sp = 1 ;
147
	    break ;
148
	}
149
	case TYPE_ENUM_TAG : {
150
	    if ( tok ) {
151
		OUT ( output, "%s%s", enum_hack, t->u.obj->name ) ;
152
	    } else {
153
		OUT ( output, "enum %s", t->u.obj->name ) ;
154
	    }
155
	    sp = 1 ;
156
	    break ;
157
	}
158
	case TYPE_LVALUE : {
159
	    OUTS ( output, "lvalue " ) ;
160
	    if ( tok ) OUTS ( output, ": " ) ;
161
	    sp = print_head ( output, t->u.subtype, 0, tok ) ;
162
	    break ;
163
	}
164
	case TYPE_QUALIFIER : {
165
	    OUT ( output, "%s ", t->v.str ) ;
166
	    sp = print_head ( output, t->u.subtype, 0, tok ) ;
167
	    break ;
168
	}
169
	case TYPE_RVALUE : {
170
	    if ( tok ) OUTS ( output, "rvalue : " ) ;
171
	    sp = print_head ( output, t->u.subtype, 0, tok ) ;
172
	    break ;
173
	}
174
	case TYPE_PTR : {
175
	    type *s = t->u.subtype ;
176
	    char *q = t->v.str ;
177
	    sp = print_head ( output, s, sp, tok ) ;
178
	    if ( sp ) OUTC ( output, ' ' ) ;
179
	    if ( is_tailed_type ( s ) ) {
180
		OUTS ( output, "( *" ) ;
181
	    } else {
182
		OUTS ( output, "*" ) ;
183
	    }
184
	    sp = 0 ;
185
	    if ( q ) {
186
		OUT ( output, " %s", q ) ;
187
		sp = 1 ;
188
	    }
189
	    break ;
190
	}
191
	case TYPE_ARRAY :
192
	case TYPE_BITFIELD :
193
	case TYPE_PROC : {
194
	    sp = print_head ( output, t->u.subtype, sp, tok ) ;
195
	    break ;
196
	}
197
	default : {
198
	    /* Unknown types */
199
	    error ( ERR_INTERNAL, "Unknown type identifier, '%d'", t->id ) ;
200
	    break ;
201
	}
202
    }
203
    return ( sp ) ;
204
}
205
 
206
 
207
/*
208
    PRINT THE TAIL OF A TYPE
209
 
210
    This routine prints the tail of the type t, that is to say the array,
211
    bitfield and function components, to the file output.
212
*/
213
 
214
static void print_tail
215
    PROTO_N ( ( output, t, tok ) )
216
    PROTO_T ( FILE *output X type *t X int tok )
217
{
218
    if ( t == null ) return ;
219
    switch ( t->id ) {
220
	case TYPE_LVALUE :
221
	case TYPE_RVALUE :
222
	case TYPE_QUALIFIER : {
223
	    print_tail ( output, t->u.subtype, tok ) ;
224
	    break ;
225
	}
226
	case TYPE_PTR : {
227
	    type *s = t->u.subtype ;
228
	    if ( is_tailed_type ( s ) ) {
229
		OUTS ( output, " )" ) ;
230
	    }
231
	    print_tail ( output, s, tok ) ;
232
	    break ;
233
	}
234
	case TYPE_ARRAY : {
235
	    OUT ( output, " [%s]", t->v.str ) ;
236
	    print_tail ( output, t->u.subtype, tok ) ;
237
	    break ;
238
	}
239
	case TYPE_BITFIELD : {
240
	    if ( tok ) {
241
		OUT ( output, " %% %s", t->v.str ) ;
242
	    } else {
243
		OUT ( output, " : %s", t->v.str ) ;
244
	    }
245
	    print_tail ( output, t->u.subtype, tok ) ;
246
	    break ;
247
	}
248
	case TYPE_PROC : {
249
	    type *s = t->v.next ;
250
	    if ( s ) {
251
		OUTS ( output, " ( " ) ;
252
		while ( s ) {
253
		    print_type ( output, s->u.subtype, null_str, tok ) ;
254
		    s = s->v.next ;
255
		    if ( s ) OUTS ( output, ", " ) ;
256
		}
257
		OUTS ( output, " )" ) ;
258
	    } else {
259
		OUTS ( output, " ()" ) ;
260
	    }
261
	    print_tail ( output, t->u.subtype, tok ) ;
262
	    break ;
263
	}
264
    }
265
    return ;
266
}
267
 
268
 
269
/*
270
    PRINT A TYPE
271
 
272
    This routine prints the object nm of type t to the file output.
273
*/
274
 
275
void print_type
276
    PROTO_N ( ( output, t, nm, tok ) )
277
    PROTO_T ( FILE *output X type *t X char *nm X int tok )
278
{
279
    if ( t ) {
280
	int sp = print_head ( output, t, 0, tok ) ;
281
	if ( nm ) {
282
	    if ( sp ) OUTC ( output, ' ' ) ;
283
	    OUTS ( output, nm ) ;
284
	}
285
	print_tail ( output, t, tok ) ;
286
    }
287
    return ;
288
}
289
 
290
 
291
/*
292
    PRINT A STRUCT OR UNION DEFINITION
293
 
294
    This routine prints the specification for a structure or union type,
295
    t, with internal name nm and external name tnm, to output.
296
*/
297
 
298
static void print_struct_defn
299
    PROTO_N ( ( output, t, nm, tnm, d ) )
300
    PROTO_T ( FILE *output X type *t X char *nm X char *tnm X int d )
301
{
302
    char *tok, *tag ;
303
    object *q = t->v.obj2 ;
304
    boolean show_token = 1, show_interface = 1 ;
305
    boolean show_ignore = 1, show_defn = 1 ;
306
 
307
    /* Find the token type */
308
    switch ( t->id ) EXHAUSTIVE {
309
	case TYPE_STRUCT : tok = "STRUCT" ; tag = "" ; break ;
310
	case TYPE_STRUCT_TAG : tok = "STRUCT" ; tag = "TAG " ; break ;
311
	case TYPE_UNION : tok = "UNION" ; tag = "" ; break ;
312
	case TYPE_UNION_TAG : tok = "UNION" ; tag = "TAG " ; break ;
313
    }
314
 
315
    /* Deal with undefined tokens immediately */
316
    if ( q == null ) {
317
	OUT ( output, "#pragma token %s %s%s # %s\n", tok, tag, nm, tnm ) ;
318
	return ;
319
    }
320
 
321
    /* Deal with the various definition cases */
322
    switch ( t->state ) {
323
	case 0 : {
324
	    /* Definition is immediate */
325
	    if ( is_hidden ( nm ) ) {
326
		show_token = 0 ;
327
		show_interface = 0 ;
328
		show_ignore = 0 ;
329
	    }
330
	    break ;
331
	}
332
	case 1 : {
333
	    /* Definition is elsewhere */
334
	    show_interface = 0 ;
335
	    show_ignore = 0 ;
336
	    show_defn = 0 ;
337
	    t->state = 2 ;
338
	    break ;
339
	}
340
	case 2 : {
341
	    /* Declaration was earlier in file */
342
	    show_token = 0 ;
343
	    t->state = 0 ;
344
	    break ;
345
	}
346
	case 3 : {
347
	    /* Declaration was in another file */
348
	    if ( d ) {
349
		show_token = 0 ;
350
		show_interface = 0 ;
351
		t->state = 1 ;
352
	    } else {
353
		show_interface = 0 ;
354
		show_ignore = 0 ;
355
		show_defn = 0 ;
356
		t->state = 2 ;
357
	    }
358
	    break ;
359
	}
360
    }
361
 
362
    /* Print the token if necessary */
363
    if ( show_token ) {
364
	OUT ( output, "#pragma token %s %s%s # %s\n", tok, tag, nm, tnm ) ;
365
    }
366
 
367
    /* Print the interface statement */
368
    if ( show_interface ) {
369
	char *b = BUILDING_MACRO ;
370
	OUT ( output, "#ifdef %s\n", b ) ;
371
	OUT ( output, "#pragma interface %s%s\n", tag, nm ) ;
372
	OUT ( output, "#else /* %s */\n", b ) ;
373
    }
374
 
375
    /* Print the ignore statement */
376
    if ( show_ignore ) {
377
	if ( !show_interface ) {
378
	    char *b = BUILDING_MACRO ;
379
	    OUT ( output, "#ifndef %s\n", b ) ;
380
	}
381
	OUT ( output, "#pragma ignore %s%s\n", tag, nm ) ;
382
    }
383
 
384
    /* Print the type definition */
385
    if ( show_defn ) {
386
	tok = ( tok [0] == 'S' ? "struct" : "union" ) ;
387
	if ( *tag ) {
388
	    OUT ( output, "%s %s {\n", tok, nm ) ;
389
	} else {
390
	    OUT ( output, "typedef %s {\n", tok ) ;
391
	}
392
	while ( q ) {
393
	    field *f = q->u.u_obj->u.u_field ;
394
	    OUTS ( output, "    " ) ;
395
	    print_type ( output, f->ftype, f->fname, 0 ) ;
396
	    OUTS ( output, " ;\n" ) ;
397
	    q = q->next ;
398
	}
399
	if ( *tag ) {
400
	    OUTS ( output, "} ;\n" ) ;
401
	} else {
402
	    OUT ( output, "} %s ;\n", nm ) ;
403
	}
404
    }
405
 
406
    /* Print the final #endif */
407
    if ( show_interface || show_ignore ) {
408
	char *b = BUILDING_MACRO ;
409
	OUT ( output, "#endif /* %s */\n", b ) ;
410
    }
411
    return ;
412
}
413
 
414
 
415
/*
416
    PRINT A TOKENISED TYPE
417
 
418
    This routine is the special case of print_token which deals with
419
    tokenised types.
420
*/
421
 
422
static void print_token_type
423
    PROTO_N ( ( output, p, tnm ) )
424
    PROTO_T ( FILE *output X object *p X char *tnm )
425
{
426
    char *tok = "TYPE" ;
427
    char *nm = p->name ;
428
    type *t = p->u.u_type ;
429
    int i = t->id ;
430
    switch ( i ) {
431
 
432
	case TYPE_DEFINED : {
433
	    /* Defined types */
434
	    char *tm, *sp ;
435
	    type *s = t->v.next ;
436
	    char *b = BUILDING_MACRO ;
437
	    if ( s == type_bottom ) {
438
		sp = "bottom" ;
439
	    } else if ( s == type_printf ) {
440
		sp = "... printf" ;
441
	    } else if ( s == type_scanf ) {
442
		sp = "... scanf" ;
443
	    } else {
444
		OUTS ( output, "typedef " ) ;
445
		print_type ( output, s, nm, 0 ) ;
446
		OUTS ( output, " ;\n" ) ;
447
		break ;
448
	    }
449
	    /* Allow for special types */
450
	    tm = "__TenDRA__" ;
451
	    OUT ( output, "#ifndef %s\n", b ) ;
452
	    OUT ( output, "#ifdef %s\n", tm ) ;
453
	    OUT ( output, "#pragma TenDRA type %s for %s\n", nm, sp ) ;
454
	    OUT ( output, "#else /* %s */\n", tm ) ;
455
	    OUT ( output, "typedef %s %s ;\n", s->u.obj->name, nm ) ;
456
	    OUT ( output, "#endif /* %s */\n", tm ) ;
457
	    OUT ( output, "#else /* %s */\n", b ) ;
458
	    OUT ( output, "typedef %s %s ;\n", s->u.obj->name, nm ) ;
459
	    OUT ( output, "#endif /* %s */\n", b ) ;
460
	    break ;
461
	}
462
 
463
	case TYPE_INT : tok = "VARIETY" ; goto generic_lab ;
464
	case TYPE_SIGNED : tok = "VARIETY signed" ; goto generic_lab ;
465
	case TYPE_UNSIGNED : tok = "VARIETY unsigned" ; goto generic_lab ;
466
	case TYPE_FLOAT : tok = "FLOAT" ; goto generic_lab ;
467
	case TYPE_ARITH : tok = "ARITHMETIC" ; goto generic_lab ;
468
	case TYPE_SCALAR : tok = "SCALAR" ; goto generic_lab ;
469
 
470
	case TYPE_GENERIC :
471
	generic_lab : {
472
	    /* Generic types */
473
	    OUT ( output, "#pragma token %s %s # %s\n", tok, nm, tnm ) ;
474
	    break ;
475
	}
476
 
477
	case TYPE_PROMOTE : {
478
	    /* Promotion types */
479
	    char *pt = t->v.next->u.obj->name ;
480
	    OUT ( output, "#pragma token VARIETY %s # %s\n", nm, tnm ) ;
481
	    OUT ( output, "#pragma promote %s : %s\n", pt, nm ) ;
482
	    break ;
483
	}
484
 
485
	case TYPE_STRUCT :
486
	case TYPE_STRUCT_TAG :
487
	case TYPE_UNION :
488
	case TYPE_UNION_TAG : {
489
	    /* Structure or union types */
490
	    print_struct_defn ( output, t, nm, tnm, 0 ) ;
491
	    break ;
492
	}
493
 
494
	case TYPE_ENUM :
495
	case TYPE_ENUM_TAG : {
496
	    /* Enumeration types are a complete hack */
497
	    char *b = BUILDING_MACRO ;
498
	    boolean tagged = ( boolean ) ( i == TYPE_ENUM ? 0 : 1 ) ;
499
	    object *q = t->v.obj2 ;
500
	    OUT ( output, "#ifndef %s\n", b ) ;
501
 
502
	    /* Print the enumeration type */
503
	    if ( tagged ) {
504
		OUT ( output, "typedef enum %s {", nm ) ;
505
	    } else {
506
		OUTS ( output, "typedef enum {" ) ;
507
	    }
508
 
509
	    /* Print the enumeration elements */
510
	    while ( q ) {
511
		object *r = q->u.u_obj ;
512
		char *v = r->u.u_str ;
513
		if ( v && v [0] ) {
514
		    OUT ( output, "\n    %s = %s", r->name, v ) ;
515
		} else {
516
		    OUT ( output, "\n    %s", r->name ) ;
517
		}
518
		q = q->next ;
519
		if ( q ) OUTC ( output, ',' ) ;
520
	    }
521
 
522
	    /* Print the end of the enumeration type */
523
	    if ( tagged ) {
524
		IGNORE sprintf ( buffer, "%s%s", enum_hack, nm ) ;
525
		OUT ( output, "\n} %s ;\n", buffer ) ;
526
	    } else {
527
		OUT ( output, "\n} %s ;\n", nm ) ;
528
	    }
529
 
530
	    /* Print the hacked library building version */
531
	    OUT ( output, "#else /* %s */\n", b ) ;
532
	    if ( tagged ) {
533
		OUT ( output, "typedef int %s ;\n", buffer ) ;
534
	    } else {
535
		OUT ( output, "#pragma token VARIETY %s # %s\n", nm, tnm ) ;
536
		OUT ( output, "#pragma promote %s : %s\n", nm, nm ) ;
537
		OUT ( output, "#pragma interface %s\n", nm ) ;
538
	    }
539
	    OUT ( output, "#endif /* %s */\n", b ) ;
540
	    break ;
541
	}
542
 
543
	default : {
544
	    /* Other types */
545
	    error ( ERR_INTERNAL, "Unknown type identifier, '%d'\n", i ) ;
546
	    break ;
547
	}
548
    }
549
    return ;
550
}
551
 
552
 
553
/*
554
    PRINT A TOKEN
555
 
556
    This routine prints the object p, representing the token tnm, to the
557
    file output.
558
*/
559
 
560
static void print_token
561
    PROTO_N ( ( output, p, tnm ) )
562
    PROTO_T ( FILE *output X object *p X char *tnm )
563
{
564
    char *nm = p->name ;
565
    switch ( p->objtype ) {
566
 
567
	case OBJ_CONST :
568
	case OBJ_EXP : {
569
	    /* Constants and expressions */
570
	    type *t = p->u.u_type ;
571
	    OUTS ( output, "#pragma token EXP " ) ;
572
	    if ( p->objtype == OBJ_CONST && t->id == TYPE_RVALUE ) {
573
		OUTS ( output, "const : " ) ;
574
		t = t->u.subtype ;
575
	    }
576
	    print_type ( output, t, null_str, 1 ) ;
577
	    OUT ( output, " : %s # %s\n", nm, tnm ) ;
578
	    break ;
579
	}
580
 
581
	case OBJ_EXTERN : {
582
	    /* External expressions */
583
	    type *t = p->u.u_type ;
584
	    if ( t->id == TYPE_LVALUE ) t = t->u.subtype ;
585
	    OUTS ( output, "extern " ) ;
586
	    print_type ( output, t, nm, 0 ) ;
587
	    OUTS ( output, " ;\n" ) ;
588
	    break ;
589
	}
590
 
591
	case OBJ_WEAK : {
592
	    /* Weak prototype declarations */
593
	    int sp ;
594
	    char *w = WEAK_PROTO ;
595
	    type *t = p->u.u_type ;
596
	    if ( !weak_proto ) {
597
		char *b = BUILDING_MACRO ;
598
		OUT ( output, "#ifndef %s\n", w ) ;
599
		OUT ( output, "#ifndef %s\n", b ) ;
600
		OUT ( output, "#pragma TenDRA keyword %s_KEY for weak\n", w ) ;
601
		OUT ( output, "#define %s( A )\t%s_KEY A\n", w, w ) ;
602
		OUT ( output, "#else /* %s */\n", b ) ;
603
		OUT ( output, "#define %s( A )\t()\n", w ) ;
604
		OUT ( output, "#endif /* %s */\n", b ) ;
605
		OUT ( output, "#endif /* %s */\n\n", w ) ;
606
		weak_proto = 1 ;
607
	    }
608
	    OUTS ( output, "extern " ) ;
609
	    sp = print_head ( output, t, 0, 0 ) ;
610
	    if ( sp ) OUTC ( output, ' ' ) ;
611
	    OUT ( output, "%s %s (", nm, w ) ;
612
	    print_tail ( output, t, 0 ) ;
613
	    OUTS ( output, " ) ;\n" ) ;
614
	    break ;
615
	}
616
 
617
	case OBJ_DEFINE : {
618
	    /* Macro definitions */
619
	    char *s = p->u.u_str ;
620
	    OUT ( output, "#define %s%s\n", nm, s ) ;
621
	    break ;
622
	}
623
 
624
	case OBJ_FIELD : {
625
	    /* Field selectors */
626
	    field *f = p->u.u_field ;
627
	    OUTS ( output, "#pragma token MEMBER " ) ;
628
	    print_type ( output, f->ftype, null_str, 1 ) ;
629
	    OUTS ( output, " : " ) ;
630
	    print_type ( output, f->stype, null_str, 1 ) ;
631
	    OUT ( output, " : %s # %s\n", f->fname, tnm ) ;
632
	    break ;
633
	}
634
 
635
	case OBJ_FUNC : {
636
	    /* Functions */
637
	    type *t = p->u.u_type ;
638
	    OUTS ( output, "#pragma token FUNC " ) ;
639
	    print_type ( output, t, null_str, 1 ) ;
640
	    OUT ( output, " : %s # %s\n", nm, tnm ) ;
641
	    break ;
642
	}
643
 
644
	case OBJ_MACRO : {
645
	    /* Macros */
646
	    type *t = p->u.u_type ;
647
	    type *s = t->v.next ;
648
	    OUTS ( output, "#pragma token PROC ( " ) ;
649
	    /* Print the macro arguments */
650
	    while ( s && s != type_none  ) {
651
		OUTS ( output, "EXP " ) ;
652
		print_type ( output, s->u.subtype, null_str, 1 ) ;
653
		s = s->v.next ;
654
		OUTS ( output, ( s ? " : , " : " : " ) ) ;
655
	    }
656
	    /* Print the macro result */
657
	    OUTS ( output, ") EXP " ) ;
658
	    print_type ( output, t->u.subtype, null_str, 1 ) ;
659
	    OUT ( output, " : %s # %s\n", nm, tnm ) ;
660
	    break ;
661
	}
662
 
663
	case OBJ_NAT : {
664
	    /* Nats */
665
	    OUT ( output, "#pragma token NAT %s # %s\n", nm, tnm ) ;
666
	    break ;
667
	}
668
 
669
	case OBJ_STATEMENT : {
670
	    /* Statements */
671
	    type *t = p->u.u_type ;
672
	    if ( t != null ) {
673
		/* Statements with arguments */
674
		type *s = t->v.next ;
675
		OUTS ( output, "#pragma token PROC ( " ) ;
676
		while ( s && s != type_none ) {
677
		    OUTS ( output, "EXP " ) ;
678
		    print_type ( output, s->u.subtype, null_str, 1 ) ;
679
		    s = s->v.next ;
680
		    OUTS ( output, ( s ? " : , " : " : " ) ) ;
681
		}
682
		OUT ( output, ") STATEMENT %s # %s\n", nm, tnm ) ;
683
	    } else {
684
		/* Statements with no arguments */
685
		OUT ( output, "#pragma token STATEMENT %s # %s\n", nm, tnm ) ;
686
	    }
687
	    break ;
688
	}
689
 
690
	case OBJ_TOKEN : {
691
	    /* Tokens */
692
	    char *s = p->u.u_str ;
693
	    OUT ( output, "#pragma token %s %s # %s\n", s, nm, tnm ) ;
694
	    break ;
695
	}
696
 
697
	case OBJ_TYPE : {
698
	    /* Types */
699
	    print_token_type ( output, p, tnm ) ;
700
	    break ;
701
	}
702
 
703
	default : {
704
	    /* Unknown objects */
705
	    error ( ERR_INTERNAL, "Unknown object type, '%d'", p->objtype ) ;
706
	    break ;
707
	}
708
    }
709
    return ;
710
}
711
 
712
 
713
/*
714
    TYPE REPRESENTING AN IF STATEMENT
715
 
716
    All if, else and endif statements are stored and simplified prior to
717
    output.  The ifcmd structure is used to represent the commands, with
718
    the dir field giving the command type and the nm field the associated
719
    expression.
720
*/
721
 
722
typedef struct {
723
    int dir ;
724
    char *nm ;
725
} ifcmd ;
726
 
727
 
728
/*
729
    PRINT A NUMBER OF IF STATEMENTS
730
 
731
    This routine outputs the list of if statements, ifs, to the file
732
    output.
733
*/
734
 
735
static void print_ifs
736
    PROTO_N ( ( output, ifs ) )
737
    PROTO_T ( FILE *output X ifcmd *ifs )
738
{
739
    ifcmd *p ;
740
    boolean changed ;
741
 
742
    /* Simplify the list of statements */
743
    do {
744
	ifcmd *q = null ;
745
	changed = 0 ;
746
	for ( p = ifs ; p->dir != CMD_END ; p++ ) {
747
	    int d = p->dir ;
748
	    if ( d != CMD_NONE ) {
749
		if ( q && q->dir != CMD_NONE ) {
750
		    int e = q->dir ;
751
		    if ( d == CMD_ENDIF ) {
752
			if ( e == CMD_ELSE ) {
753
			    /* else + endif -> endif */
754
			    q->dir = CMD_NONE ;
755
			    changed = 1 ;
756
			} else if ( e != CMD_ENDIF ) {
757
			    /* if + endif -> nothing */
758
			    p->dir = CMD_NONE ;
759
			    q->dir = CMD_NONE ;
760
			    changed = 1 ;
761
			}
762
		    }
763
		    if ( d == CMD_ELSE ) {
764
			if ( e == CMD_IFDEF ) {
765
			    /* ifdef + else -> ifndef */
766
			    p->dir = CMD_IFNDEF ;
767
			    q->dir = CMD_NONE ;
768
			    changed = 1 ;
769
			} else if ( e == CMD_IFDEF ) {
770
			    /* ifndef + else -> ifdef */
771
			    p->dir = CMD_IFDEF ;
772
			    q->dir = CMD_NONE ;
773
			    changed = 1 ;
774
			}
775
		    }
776
		}
777
		q = p ;
778
	    }
779
	}
780
    } while ( changed ) ;
781
 
782
    /* Print the result */
783
    if ( column ) OUTC ( output, '\n' ) ;
784
    for ( p = ifs ; p->dir != CMD_END ; p++ ) {
785
	switch ( p->dir ) {
786
	    case CMD_IF : {
787
		OUT ( output, "#if %s\n", p->nm ) ;
788
		break ;
789
	    }
790
	    case CMD_IFDEF : {
791
		OUT ( output, "#ifdef %s\n", p->nm ) ;
792
		break ;
793
	    }
794
	    case CMD_IFNDEF : {
795
		OUT ( output, "#ifndef %s\n", p->nm ) ;
796
		break ;
797
	    }
798
	    case CMD_ELSE : {
799
		OUT ( output, "#else /* %s */\n", p->nm ) ;
800
		break ;
801
	    }
802
	    case CMD_ENDIF : {
803
		OUT ( output, "#endif /* %s */\n", p->nm ) ;
804
		break ;
805
	    }
806
	}
807
    }
808
    column = 0 ;
809
    ifs [0].dir = CMD_END ;
810
    return ;
811
}
812
 
813
 
814
/*
815
    PRINT AN INTERFACE ITEM
816
 
817
    This routine prints an interface statement for the object p to the
818
    file output.
819
*/
820
 
821
static void print_interface
822
    PROTO_N ( ( output, p, ifs ) )
823
    PROTO_T ( FILE *output X object *p X ifcmd *ifs )
824
{
825
    char *nm = p->name ;
826
    switch ( p->objtype ) {
827
 
828
	case OBJ_CONST :
829
	case OBJ_EXP :
830
	case OBJ_MACRO :
831
	case OBJ_NAT :
832
	case OBJ_STATEMENT :
833
	case OBJ_TOKEN : {
834
	    /* Simple tokens are easy */
835
	    break ;
836
	}
837
 
838
	case OBJ_EXTERN :
839
	case OBJ_WEAK : {
840
	    /* Deal with externals */
841
	    nm = null ;
842
	    break ;
843
	}
844
 
845
	case OBJ_FIELD : {
846
	    /* Deal with fields */
847
	    field *f = p->u.u_field ;
848
	    switch ( f->stype->id ) {
849
		case TYPE_STRUCT_TAG :
850
		case TYPE_UNION_TAG : {
851
		    /* Tagged types require some attention */
852
		    IGNORE sprintf ( buffer, "TAG %s", nm ) ;
853
		    nm = buffer ;
854
		    break ;
855
		}
856
	    }
857
	    break ;
858
	}
859
 
860
	case OBJ_FUNC : {
861
	    /* Functions containing ... are not actually tokens */
862
	    type *t = p->u.u_type->v.next ;
863
	    while ( t != null ) {
864
		if ( t->u.subtype == type_ellipsis ) {
865
		    nm = null ;
866
		    break ;
867
		}
868
		t = t->v.next ;
869
	    }
870
	    break ;
871
	}
872
 
873
	case OBJ_DEFINE : {
874
	    /* Macro definitions are not tokens */
875
	    nm = null ;
876
	    break ;
877
	}
878
 
879
	case OBJ_TYPE : {
880
	    /* Deal with types */
881
	    type *t = p->u.u_type ;
882
	    switch ( t->id ) {
883
		case TYPE_STRUCT_TAG :
884
		case TYPE_UNION_TAG : {
885
		    /* Tagged types require some attention */
886
		    IGNORE sprintf ( buffer, "TAG %s", nm ) ;
887
		    nm = buffer ;
888
		    goto type_struct_lab ;
889
		}
890
		case TYPE_STRUCT :
891
		case TYPE_UNION :
892
		type_struct_lab : {
893
		    /* Some structures and unions are not tokens */
894
		    if ( t->v.obj2 ) {
895
			if ( t->state == 2 ) {
896
			    t->state = 3 ;
897
			} else {
898
			    nm = null ;
899
			}
900
		    }
901
		    break ;
902
		}
903
		case TYPE_DEFINED : {
904
		    /* Type definitions are not tokens */
905
		    nm = null ;
906
		    break ;
907
		}
908
		case TYPE_ENUM :
909
		case TYPE_ENUM_TAG : {
910
		    /* Enumeration types are not tokens */
911
		    nm = null ;
912
		    break ;
913
		}
914
	    }
915
	    break ;
916
	}
917
 
918
	default : {
919
	    /* Unknown objects */
920
	    error ( ERR_INTERNAL, "Unknown object type, '%d'", p->objtype ) ;
921
	    nm = null ;
922
	    break ;
923
	}
924
    }
925
 
926
    /* Print the interface statement */
927
    if ( nm ) {
928
	int n = ( int ) strlen ( nm ) + 1 ;
929
	if ( ifs [0].dir != CMD_END ) print_ifs ( output, ifs ) ;
930
	if ( column + n >= 60 ) {
931
	    OUTC ( output, '\n' ) ;
932
	    column = 0 ;
933
	}
934
	if ( column == 0 ) OUTS ( output, "#pragma interface" ) ;
935
	OUTC ( output, ' ' ) ;
936
	OUTS ( output, nm ) ;
937
	column += n ;
938
    }
939
    return ;
940
}
941
 
942
 
943
/*
944
    PRINT AN INCLUDED FILE
945
*/
946
 
947
static void print_include
948
    PROTO_N ( ( output, nm, on ) )
949
    PROTO_T ( FILE *output X char *nm X int on )
950
{
951
    object *p ;
952
    if ( nm == null ) return ;
953
    IGNORE sprintf ( buffer, "%s[%s]", crt_info->src, nm ) ;
954
    if ( search_hash ( files, buffer, no_version ) ) return ;
955
    p = make_object ( string_copy ( buffer ), OBJ_FILE ) ;
956
    p->u.u_file = null ;
957
    IGNORE add_hash ( files, p, no_version ) ;
958
    if ( on ) OUT ( output, "#include <%s>\n", nm ) ;
959
    return ;
960
}
961
 
962
 
963
/*
964
    PRINT AN OBJECT
965
 
966
    This routine prints the list of objects input to the file output, the
967
    form of the information to be printed being indicated by pass.
968
*/
969
 
970
static void print_object
971
    PROTO_N ( ( output, input, pass ) )
972
    PROTO_T ( FILE *output X object *input X int pass )
973
{
974
    object *p ;
975
    ifcmd ifs [100] ;
976
    ifs [0].dir = CMD_END ;
977
    for ( p = input ; p != null ; p = p->next ) {
978
	char *nm = p->name ;
979
	switch ( p->objtype ) {
980
 
981
	    case OBJ_IF	 : {
982
		/* If statements etc. */
983
		if ( pass != 1 ) {
984
		    int i = 0 ;
985
		    while ( ifs [i].dir != CMD_END ) i++ ;
986
		    ifs [i].dir = p->u.u_num ;
987
		    ifs [i].nm = p->name ;
988
		    ifs [ i + 1 ].dir = CMD_END ;
989
		    if ( i >= 90 ) print_ifs ( output, ifs ) ;
990
		}
991
		break ;
992
	    }
993
 
994
	    case OBJ_IMPLEMENT :
995
	    case OBJ_USE : {
996
		/* Inclusion statements */
997
		if ( pass < 2 && nm [ pass ] == '1' ) {
998
		    object *q = p->u.u_obj ;
999
		    info *i = q->u.u_info ;
1000
		    char *b = BUILDING_MACRO ;
1001
		    if ( streq ( i->api, LOCAL_API ) ) break ;
1002
		    if ( ifs [0].dir != CMD_END ) print_ifs ( output, ifs ) ;
1003
		    if ( pass == 0 ) {
1004
			char *f ;
1005
			char *dir ;
1006
			char *m = i->protect ;
1007
			int n = output_incl_len ;
1008
			if ( nm [2] == 'G' ) {
1009
			    OUT ( output, "#ifndef %s\n", b ) ;
1010
			    dir = "#pragma extend interface [%s]\n" ;
1011
			    OUT ( output, dir, i->file ) ;
1012
			    OUT ( output, "#else /* %s */\n", b ) ;
1013
			    m = "" ;
1014
			}
1015
			if ( *m ) OUT ( output, "#ifndef %s\n", m ) ;
1016
			if ( local_input ) {
1017
			    f = i->incl + n ;
1018
			    dir = "#pragma extend interface <../%s>\n" ;
1019
			} else {
1020
			    f = relative ( crt_info->incl, i->incl, n ) ;
1021
			    dir = "#pragma extend interface \"%s\"\n" ;
1022
			}
1023
			OUT ( output, dir, f ) ;
1024
			if ( *m ) OUT ( output, "#endif /* %s */\n", m ) ;
1025
			if ( nm [2] == 'G' ) {
1026
			    OUT ( output, "#endif /* %s */\n", b ) ;
1027
			}
1028
		    } else {
1029
			print_include ( output, i->file, 1 ) ;
1030
		    }
1031
		}
1032
		break ;
1033
	    }
1034
 
1035
	    case OBJ_SET : {
1036
		/* Subsets */
1037
		object *q = p->u.u_obj ;
1038
		info *i = q->u.u_info ;
1039
		if ( streq ( i->api, LOCAL_API ) ) {
1040
		    if ( ifs [0].dir != CMD_END ) print_ifs ( output, ifs ) ;
1041
		    print_object ( output, i->elements, pass ) ;
1042
		} else {
1043
		    if ( pass < 2 ) {
1044
			if ( ifs [0].dir != CMD_END ) {
1045
			    print_ifs ( output, ifs ) ;
1046
			}
1047
			print_set ( p, pass ) ;
1048
		    }
1049
		}
1050
		break ;
1051
	    }
1052
 
1053
	    case OBJ_TEXT_INCL : {
1054
		/* Include file quoted text */
1055
		if ( pass == 0 ) {
1056
		    if ( ifs [0].dir != CMD_END ) print_ifs ( output, ifs ) ;
1057
		    OUTS ( output, nm ) ;
1058
		    OUTC ( output, '\n' ) ;
1059
		}
1060
		break ;
1061
	    }
1062
 
1063
	    case OBJ_TEXT_SRC : {
1064
		/* Source file quoted text */
1065
		if ( pass == 1 ) {
1066
		    if ( ifs [0].dir != CMD_END ) print_ifs ( output, ifs ) ;
1067
		    OUTS ( output, nm ) ;
1068
		    OUTC ( output, '\n' ) ;
1069
		}
1070
		break ;
1071
	    }
1072
 
1073
	    case OBJ_TOKEN : {
1074
		/* Tokenised objects */
1075
		if ( pass == 0 ) {
1076
		    if ( ifs [0].dir != CMD_END ) print_ifs ( output, ifs ) ;
1077
		    print_token ( output, p->u.u_obj, nm ) ;
1078
		} else if ( pass == 2 ) {
1079
		    print_interface ( output, p->u.u_obj, ifs ) ;
1080
		}
1081
		break ;
1082
	    }
1083
 
1084
	    case OBJ_TYPE : {
1085
		/* Definition of previously declared type */
1086
		if ( pass == 0 ) {
1087
		    type *t = p->u.u_type ;
1088
		    char *tnm = t->u.obj->name ;
1089
		    print_struct_defn ( output, t, tnm, tnm, 1 ) ;
1090
		}
1091
		break ;
1092
	    }
1093
 
1094
	    default : {
1095
		/* Unknown objects */
1096
		char *err = "Unknown object type, '%d'" ;
1097
		error ( ERR_INTERNAL, err, p->objtype ) ;
1098
		break ;
1099
	    }
1100
	}
1101
    }
1102
    if ( ifs [0].dir != CMD_END ) print_ifs ( output, ifs ) ;
1103
    return ;
1104
}
1105
 
1106
 
1107
/*
1108
    SCAN AN OBJECT
1109
 
1110
    This routine scans the object input, calling print_set on any subsets.
1111
*/
1112
 
1113
static void scan_object
1114
    PROTO_N ( ( input, pass ) )
1115
    PROTO_T ( object *input X int pass )
1116
{
1117
    object *p ;
1118
    for ( p = input ; p != null ; p = p->next ) {
1119
	if ( p->objtype == OBJ_SET ) {
1120
	    object *q = p->u.u_obj ;
1121
	    info *i = q->u.u_info ;
1122
	    if ( streq ( i->api, LOCAL_API ) ) {
1123
		scan_object ( i->elements, pass ) ;
1124
	    } else {
1125
		if ( pass < 2 ) print_set ( p, pass ) ;
1126
	    }
1127
	}
1128
    }
1129
    return ;
1130
}
1131
 
1132
 
1133
/*
1134
    PRINT A SET
1135
 
1136
    This routine prints the set of objects given by input.  The form of the
1137
    output is indicated by pass.
1138
*/
1139
 
1140
void print_set
1141
    PROTO_N ( ( input, pass ) )
1142
    PROTO_T ( object *input X int pass )
1143
{
1144
    char *nm ;
1145
    time_t t1, t2 ;
1146
    FILE *output = null ;
1147
    object *ss = input->u.u_obj ;
1148
    info *i = ss->u.u_info ;
1149
    column = 0 ;
1150
 
1151
    if ( streq ( i->api, LOCAL_API ) ) {
1152
	/* Local files go to the standard output */
1153
	if ( pass != 0 ) return ;
1154
	nm = "stdout" ;
1155
	output = stdout ;
1156
	t1 = ( time_t ) 0 ;
1157
	t2 = ( time_t ) 0 ;
1158
    } else {
1159
	nm = ( pass ? i->src : i->incl ) ;
1160
	if ( nm == null || ( restrict_use && i->implemented == 0 ) ) {
1161
	    scan_object ( i->elements, 1 ) ;
1162
	    return ;
1163
	}
1164
	if ( pass == 1 && i->tokens == 0 ) {
1165
	    if ( verbose > 1 ) {
1166
		error ( ERR_INFO, "%s is not required ...", nm ) ;
1167
	    }
1168
	    scan_object ( i->elements, 1 ) ;
1169
	    return ;
1170
	}
1171
	t1 = i->age ;
1172
	if ( progdate > t1 ) t1 = progdate ;
1173
	t2 = date_stamp ( nm ) ;
1174
    }
1175
 
1176
    if ( ( t1 && t1 < t2 ) && !force_output ) {
1177
	/* Output file is up to date */
1178
	object *q ;
1179
	if ( verbose > 1 ) error ( ERR_INFO, "%s is up to date ...", nm ) ;
1180
	q = make_object ( nm, OBJ_FILE ) ;
1181
	q->u.u_file = null ;
1182
	IGNORE add_hash ( files, q, no_version ) ;
1183
	for ( q = i->elements ; q != null ; q = q->next ) {
1184
	    if ( q->objtype == OBJ_SET ) print_set ( q, pass ) ;
1185
	}
1186
    } else {
1187
	/* Output file needs updating */
1188
	object *q = null ;
1189
	info *old_info = crt_info ;
1190
	int old_column = column ;
1191
	boolean old_weak_proto = weak_proto ;
1192
	weak_proto = 0 ;
1193
 
1194
	/* Open output file */
1195
	if ( output == null ) {
1196
	    create_dir ( nm ) ;
1197
	    if ( verbose ) error ( ERR_INFO, "Creating %s ...", nm ) ;
1198
	    check_name ( nm ) ;
1199
	    q = make_object ( nm, OBJ_FILE ) ;
1200
	    q->u.u_file = null ;
1201
	    IGNORE add_hash ( files, q, no_version ) ;
1202
	    output = fopen ( nm, "w" ) ;
1203
	    q->u.u_file = output ;
1204
	    if ( output == null ) {
1205
		error ( ERR_SERIOUS, "Can't open output file, %s", nm ) ;
1206
		return ;
1207
	    }
1208
	}
1209
 
1210
	crt_info = i ;
1211
	if ( pass == 0 ) {
1212
	    /* Include output file */
1213
	    char *m = i->protect ;
1214
	    char *v = i->version ;
1215
 
1216
	    /* Print the copyright message */
1217
	    if ( copyright ) {
1218
		if ( copyright_text == null ) {
1219
		    FILE *f = fopen ( copyright, "r" ) ;
1220
		    if ( f == null ) {
1221
			char *err = "Can't open copyright file, %s" ;
1222
			error ( ERR_SERIOUS, err, copyright ) ;
1223
			copyright_text = "" ;
1224
		    } else {
1225
			int c, j = 0 ;
1226
			while ( c = getc ( f ), c != EOF ) {
1227
			    buffer [j] = ( char ) c ;
1228
			    if ( ++j >= buffsize ) {
1229
				error ( ERR_SERIOUS, "Copyright too long" ) ;
1230
				break ;
1231
			    }
1232
			}
1233
			buffer [j] = 0 ;
1234
			copyright_text = string_copy ( buffer ) ;
1235
			IGNORE fclose ( f ) ;
1236
		    }
1237
		}
1238
		OUTS ( output, copyright_text ) ;
1239
	    }
1240
 
1241
	    /* Find the version number */
1242
	    if ( v == null && i->subset ) {
1243
		char *a = subset_name ( i->api, i->file, null_str ) ;
1244
		object *ap = make_subset ( a ) ;
1245
		v = ap->u.u_info->version ;
1246
	    }
1247
	    if ( v == null && i->file ) {
1248
		char *a = subset_name ( i->api, null_str, null_str ) ;
1249
		object *ap = make_subset ( a ) ;
1250
		v = ap->u.u_info->version ;
1251
	    }
1252
 
1253
	    /* Print the file header */
1254
	    OUTS ( output, "/*\n    AUTOMATICALLY GENERATED BY " ) ;
1255
	    OUT ( output, "%s %s\n", progname, progvers ) ;
1256
	    OUT ( output, "    API SUBSET: %s", ss->name ) ;
1257
	    if ( v ) OUT ( output, " (VERSION %s)", v ) ;
1258
	    OUTS ( output, "\n*/\n\n" ) ;
1259
 
1260
	    /* Print the file body */
1261
	    if ( *m ) {
1262
		OUT ( output, "#ifndef %s\n", m ) ;
1263
		OUT ( output, "#define %s\n\n", m ) ;
1264
	    }
1265
	    if ( i->elements ) {
1266
		boolean is_cpplus = 0 ;
1267
		if ( i->linkage ) {
1268
		    if ( streq ( i->linkage, "C++" ) ) {
1269
			OUT ( output, "extern \"%s\" {\n\n", i->linkage ) ;
1270
			is_cpplus = 1 ;
1271
		    } else {
1272
			OUT ( output, "#ifdef __cplusplus\n" ) ;
1273
			OUT ( output, "extern \"%s\" {\n", i->linkage ) ;
1274
			OUT ( output, "#endif\n\n" ) ;
1275
		    }
1276
		}
1277
		if ( i->nspace ) {
1278
		    if ( is_cpplus ) {
1279
			OUT ( output, "namespace %s {\n\n", i->nspace ) ;
1280
		    } else {
1281
			OUT ( output, "#ifdef __cplusplus\n" ) ;
1282
			OUT ( output, "namespace %s {\n", i->nspace ) ;
1283
			OUT ( output, "#endif\n\n" ) ;
1284
		    }
1285
		}
1286
		if ( i->block ) {
1287
		    char *dir ;
1288
		    dir = "#pragma TenDRA declaration block %s begin\n\n" ;
1289
		    OUT ( output, dir, i->block ) ;
1290
		}
1291
		print_object ( output, i->elements, 0 ) ;
1292
		if ( i->tokens ) OUTC ( output, '\n' ) ;
1293
		print_object ( output, i->elements, 2 ) ;
1294
		if ( column ) OUTC ( output, '\n' ) ;
1295
		if ( i->block ) {
1296
		    char *dir ;
1297
		    dir = "\n#pragma TenDRA declaration block end\n" ;
1298
		    OUT ( output, dir ) ;
1299
		}
1300
		if ( i->nspace ) {
1301
		    if ( is_cpplus ) {
1302
			OUT ( output, "\n}\n" ) ;
1303
		    } else {
1304
			OUT ( output, "\n#ifdef __cplusplus\n" ) ;
1305
			OUT ( output, "}\n" ) ;
1306
			OUT ( output, "#endif\n" ) ;
1307
		    }
1308
		}
1309
		if ( i->linkage ) {
1310
		    if ( is_cpplus ) {
1311
			OUT ( output, "\n}\n" ) ;
1312
		    } else {
1313
			OUT ( output, "\n#ifdef __cplusplus\n" ) ;
1314
			OUT ( output, "}\n" ) ;
1315
			OUT ( output, "#endif\n" ) ;
1316
		    }
1317
		}
1318
	    }
1319
	    if ( *m ) OUT ( output, "\n#endif /* %s */\n", m ) ;
1320
 
1321
	} else {
1322
	    /* Source output file */
1323
	    if ( i->method == null ) {
1324
		char *m, *s ;
1325
		char *w1, *w2 ;
1326
		int n = output_incl_len ;
1327
		m = macro_name ( DEFINE_PREFIX, i->api, i->file, i->subset ) ;
1328
		w1 = macro_name ( WRONG_PREFIX, i->api, null_str, null_str ) ;
1329
		w2 = macro_name ( WRONG_PREFIX, i->api, i->file, i->subset ) ;
1330
		s = i->incl + n ;
1331
		OUTS ( output, "/* AUTOMATICALLY GENERATED BY " ) ;
1332
		OUT ( output, "%s %s */\n", progname, progvers ) ;
1333
		OUT ( output, "#ifndef %s\n", w1 ) ;
1334
		OUT ( output, "#ifndef %s\n", w2 ) ;
1335
		OUT ( output, "#if #include ( %s )\n", i->file ) ;
1336
		OUT ( output, "#define %s\n", m ) ;
1337
		print_include ( output, i->file, 0 ) ;
1338
		print_object ( output, i->elements, 1 ) ;
1339
		OUT ( output, "#include <%s>\n", i->file ) ;
1340
		OUT ( output, "#endif\n" ) ;
1341
		OUT ( output, "#endif\n\n" ) ;
1342
		OUT ( output, "#ifndef %s\n", m ) ;
1343
		OUT ( output, "#pragma TenDRA no token definition allow\n" ) ;
1344
		OUT ( output, "#endif\n" ) ;
1345
		OUT ( output, "#pragma implement interface <../%s>\n", s ) ;
1346
		OUT ( output, "#endif\n" ) ;
1347
	    } else {
1348
		print_object ( output, i->elements, 1 ) ;
1349
	    }
1350
	}
1351
 
1352
	/* End the output */
1353
	IGNORE fclose ( output ) ;
1354
	if ( q ) q->u.u_file = null ;
1355
	crt_info = old_info ;
1356
	column = old_column ;
1357
	weak_proto = old_weak_proto ;
1358
    }
1359
    return ;
1360
}