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 "types.h"
33
#include "read_types.h"
34
#include "analyser.h"
35
#include "check.h"
36
#include "de_types.h"
37
#include "de_capsule.h"
38
#include "file.h"
39
#include "high.h"
40
#include "names.h"
41
#include "node.h"
42
#include "read.h"
43
#include "read_cap.h"
44
#include "table.h"
45
#include "tdf.h"
46
#include "utility.h"
47
 
48
 
49
/*
50
    READ AN EXTERNAL NAME
51
 
52
    An external name representing an object of sort s is read from the
53
    input file.  If local is true this must just be an internal identifier.
54
*/
55
 
56
static construct *read_external
57
    PROTO_N ( ( s, local ) )
58
    PROTO_T ( sortname s X boolean local )
59
{
60
    construct *p ;
61
    node *e = null ;
62
    int estate = 0 ;
63
    position store ;
64
    allow_multibyte = 0 ;
65
 
66
    /* Read identifier */
67
    store_position ( &store ) ;
68
    read_word () ;
69
 
70
    /* Check for external name */
71
    if ( func_input ) {
72
	if ( word_type == INPUT_WORD ) {
73
	    if ( streq ( word, MAKE_STRING_EXTERN ) ) {
74
		estate = 1 ;
75
	    } else if ( streq ( word, MAKE_UNIQUE_EXTERN ) ) {
76
		estate = 2 ;
77
	    } else if ( streq ( word, MAKE_CHAIN_EXTERN ) ) {
78
		estate = 3 ;
79
	    }
80
	    if ( estate ) {
81
		read_word () ;
82
		if ( word_type != INPUT_OPEN ) {
83
		    /* Go back and treat as identifier */
84
		    estate = 0 ;
85
		    set_position ( &store ) ;
86
		    read_word () ;
87
		}
88
	    }
89
	}
90
    } else {
91
	if ( word_type == INPUT_OPEN ) {
92
	    read_word () ;
93
	    if ( word_type != INPUT_WORD ) {
94
		input_error ( "External expected" ) ;
95
		return ( null ) ;
96
	    }
97
	    if ( streq ( word, MAKE_STRING_EXTERN ) ) {
98
		estate = 1 ;
99
	    } else if ( streq ( word, MAKE_UNIQUE_EXTERN ) ) {
100
		estate = 2 ;
101
	    } else if ( streq ( word, MAKE_CHAIN_EXTERN ) ) {
102
		estate = 3 ;
103
	    } else {
104
		input_error ( "Illegal external, %s", word ) ;
105
		return ( null ) ;
106
	    }
107
	}
108
    }
109
 
110
    if ( estate ) {
111
	/* There is an external name */
112
	if ( local ) {
113
	    is_fatal = 0 ;
114
	    input_error ( "Can't have external name with local" ) ;
115
	}
116
	e = new_node () ;
117
	e->cons = &true_cons ;
118
	if ( estate == 1 ) {
119
	    e->son = read_node ( "$" ) ;
120
	} else if ( estate == 2 ) {
121
	    e->son = read_node ( "*[$]" ) ;
122
	} else {
123
	    e->son = read_node ( "$i" ) ;
124
	}
125
	read_word () ;
126
	if ( word_type != INPUT_CLOSE ) {
127
	    is_fatal = 0 ;
128
	    input_error ( "End of external construct expected" ) ;
129
	    looked_ahead = 1 ;
130
	}
131
	read_word () ;
132
	if ( func_input ) {
133
	    if ( word_type != INPUT_COMMA ) {
134
		is_fatal = 0 ;
135
		input_error ( "Comma expected" ) ;
136
		looked_ahead = 1 ;
137
	    }
138
	    read_word () ;
139
	}
140
    } else {
141
	/* There is no external name */
142
	if ( is_local_name ( word ) ) local = 1 ;
143
	if ( !local ) {
144
	    e = new_node () ;
145
	    e->cons = &false_cons ;
146
	}
147
    }
148
 
149
    /* Check internal name */
150
    if ( word_type != INPUT_WORD ) input_error ( "Identifier expected" ) ;
151
    p = search_var_hash ( word, s ) ;
152
    if ( p == null ) {
153
	/* New object */
154
	p = make_construct ( s ) ;
155
	p->name = string_copy_aux ( word ) ;
156
	p->ename = e ;
157
	IGNORE add_to_var_hash ( p, s ) ;
158
    } else {
159
	/* Existing object : check consistency */
160
	if ( local ) {
161
	    if ( p->ename ) {
162
		is_fatal = 0 ;
163
		input_error ( "Object %s previously declared global", word ) ;
164
	    }
165
	} else {
166
	    if ( p->ename ) {
167
		if ( e->son ) {
168
		    is_fatal = 0 ;
169
		    input_error ( "External name of object %s given twice",
170
				  word ) ;
171
		}
172
	    } else {
173
		is_fatal = 0 ;
174
		input_error ( "Object %s previously declared local", word ) ;
175
	    }
176
	}
177
    }
178
    allow_multibyte = 1 ;
179
    return ( p ) ;
180
}
181
 
182
 
183
/*
184
    READ AN ALIGNMENT TAG DECLARATION
185
 
186
    An alignment tag declaration is read from the input file.
187
*/
188
 
189
static void read_aldec
190
    PROTO_N ( ( local ) )
191
    PROTO_T ( boolean local )
192
{
193
    IGNORE read_external ( SORT_al_tag, local ) ;
194
    return ;
195
}
196
 
197
 
198
/*
199
    READ AN ALIGNMENT TAG DEFINITION
200
 
201
    An alignment tag definition is read from the input file.
202
*/
203
 
204
static void read_aldef
205
    PROTO_N ( ( local ) )
206
    PROTO_T ( boolean local )
207
{
208
    node *d ;
209
    construct *p = read_external ( SORT_al_tag, local ) ;
210
    al_tag_info *info = get_al_tag_info ( p ) ;
211
 
212
    /* Check comma */
213
    if ( func_input ) {
214
	read_word () ;
215
	if ( word_type != INPUT_COMMA ) {
216
	    is_fatal = 0 ;
217
	    input_error ( "Comma expected" ) ;
218
	    looked_ahead = 1 ;
219
	}
220
    }
221
 
222
    /* Read the definition (an alignment) */
223
    d = completion ( read_node ( "a" ) ) ;
224
    if ( info->def ) {
225
	if ( !eq_node ( info->def, d ) ) {
226
	    is_fatal = 0 ;
227
	    input_error ( "Alignment tag %s defined inconsistently",
228
			  p->name ) ;
229
	}
230
	free_node ( d ) ;
231
    } else {
232
	info->def = d ;
233
    }
234
    return ;
235
}
236
 
237
 
238
/*
239
    READ A TAG DECLARATION
240
 
241
    A tag declaration is read from the input file.  Whether it is a
242
    variable or an identity is indicated by the is_var flag.
243
*/
244
 
245
static void read_tagdec
246
    PROTO_N ( ( local, is_var ) )
247
    PROTO_T ( boolean local X int is_var )
248
{
249
    node *d ;
250
    construct *p = read_external ( SORT_tag, local ) ;
251
    tag_info *info = get_tag_info ( p ) ;
252
    set_tag_type ( p, is_var ) ;
253
 
254
    /* Check comma */
255
    if ( func_input ) {
256
	read_word () ;
257
	if ( word_type != INPUT_COMMA ) {
258
	    is_fatal = 0 ;
259
	    input_error ( "Comma expected" ) ;
260
	    looked_ahead = 1 ;
261
	}
262
    }
263
 
264
    /* Declaration = optional access + optional string + shape from 4.0 */
265
    d = completion ( read_node ( "?[u]?[X]S" ) ) ;
266
    info->var = ( boolean ) is_var ;
267
    if ( info->dec ) {
268
	if ( !eq_node ( info->dec, d ) ) {
269
	    is_fatal = 0 ;
270
	    input_error ( "Tag %s declared inconsistently", p->name ) ;
271
	}
272
	free_node ( d ) ;
273
    } else {
274
	info->dec = d ;
275
    }
276
    return ;
277
}
278
 
279
 
280
/*
281
    READ A TAG DEFINITION
282
 
283
    A tag definition is read from the input file.  Whether it is a
284
    variable or an identity is indicated by the is_var flag.
285
*/
286
 
287
static void read_tagdef
288
    PROTO_N ( ( local, is_var ) )
289
    PROTO_T ( boolean local X int is_var )
290
{
291
    node *d ;
292
    construct *p = read_external ( SORT_tag, local ) ;
293
    tag_info *info = get_tag_info ( p ) ;
294
 
295
    /* Set the tag type */
296
    if ( info->dec == null && !do_check ) {
297
	is_fatal = 0 ;
298
	input_error ( "Tag %s defined but not declared", word ) ;
299
    }
300
    set_tag_type ( p, is_var ) ;
301
 
302
    /* Check comma */
303
    if ( func_input ) {
304
	read_word () ;
305
	if ( word_type != INPUT_COMMA ) {
306
	    is_fatal = 0 ;
307
	    input_error ( "Comma expected" ) ;
308
	    looked_ahead = 1 ;
309
	}
310
    }
311
 
312
    /* Definition - signature added in 4.0 */
313
    d = completion ( read_node ( is_var ? "?[u]?[X]x" : "?[X]x" ) ) ;
314
    info->var = ( boolean ) is_var ;
315
    if ( info->def ) {
316
	if ( is_var == 2 ) {
317
	    node *dp = info->def ;
318
	    while ( dp->bro ) dp = dp->bro ;
319
	    dp->bro = d ;
320
	} else {
321
	    if ( !eq_node ( info->def, d ) ) {
322
		is_fatal = 0 ;
323
		input_error ( "Tag %s defined inconsistently", p->name ) ;
324
	    }
325
	    free_node ( d ) ;
326
	}
327
    } else {
328
	info->def = d ;
329
	if ( do_check ) check_tagdef ( p ) ;
330
    }
331
    return ;
332
}
333
 
334
 
335
/*
336
    READ A SORTNAME
337
 
338
    A sortname is read from the input file.
339
*/
340
 
341
static sortname read_sortname
342
    PROTO_Z ()
343
{
344
    sortname s ;
345
    if ( word_type != INPUT_WORD ) {
346
	is_fatal = 0 ;
347
	input_error ( "Sort name expected" ) ;
348
	return ( SORT_unknown ) ;
349
    }
350
    s = find_high_sort ( word ) ;
351
    if ( s == SORT_unknown ) {
352
	is_fatal = 0 ;
353
	input_error ( "Illegal sort name, %s", word ) ;
354
    } else {
355
	if ( s > SORT_max && s < SORT_no ) {
356
	    is_fatal = 0 ;
357
	    input_error ( "Bad sort name, %s", word ) ;
358
	}
359
    }
360
    return ( s ) ;
361
}
362
 
363
 
364
/*
365
    READ TOKEN SORT
366
 
367
    A token sort is read and the information is stored in info.  This
368
    can be a definition (with formal parameters) or a declaration
369
    (without) depending on the value of def.
370
*/
371
 
372
static void read_toksort
373
    PROTO_N ( ( info, def ) )
374
    PROTO_T ( tok_info *info X boolean def )
375
{
376
    /* Check comma */
377
    if ( func_input ) {
378
	read_word () ;
379
	if ( word_type != INPUT_COMMA ) {
380
	    is_fatal = 0 ;
381
	    input_error ( "Comma expected" ) ;
382
	    looked_ahead = 1 ;
383
	}
384
    }
385
 
386
    /* Initialize values */
387
    info->res = SORT_unknown ;
388
    info->args = null ;
389
    info->pars = null ;
390
    info->sig = null ;
391
 
392
    /* Read signature */
393
    info->sig = read_node ( "?[X]" ) ;
394
 
395
    /* Read argument sorts */
396
    read_word () ;
397
    if ( word_type == INPUT_OPEN ) {
398
	int no_args = 0 ;
399
	char arg_buff [100] ;
400
	char *a = arg_buff ;
401
	construct *cons_buff [100] ;
402
	construct **c = cons_buff ;
403
	while ( read_word (), word_type != INPUT_CLOSE ) {
404
	    sortname s = read_sortname () ;
405
	    if ( is_high ( s ) ) {
406
		sprint_high_sort ( a, s ) ;
407
		while ( *a ) a++ ;
408
	    } else {
409
		*( a++ ) = sort_letters [s] ;
410
	    }
411
	    if ( def ) {
412
		/* Read formal argument */
413
		construct *q ;
414
		read_word () ;
415
		if ( word_type != INPUT_WORD ) {
416
		    input_error ( "Token identifier expected" ) ;
417
		}
418
		q = search_var_hash ( word, SORT_token ) ;
419
		if ( q ) {
420
		    input_error ( "Token %s already declared", word ) ;
421
		}
422
		q = make_construct ( SORT_token ) ;
423
		q->name = string_copy_aux ( word ) ;
424
		IGNORE add_to_var_hash ( q, SORT_token ) ;
425
		set_token_sort ( q, s, ( char * ) null, ( node * ) null ) ;
426
		*( c++ ) = q ;
427
	    }
428
	    /* Check comma */
429
	    if ( func_input ) {
430
		read_word () ;
431
		if ( word_type == INPUT_CLOSE ) {
432
		    looked_ahead = 1 ;
433
		} else if ( word_type != INPUT_COMMA ) {
434
		    is_fatal = 0 ;
435
		    input_error ( "Comma or close bracket expected" ) ;
436
		    looked_ahead = 1 ;
437
		}
438
	    }
439
	    no_args++ ;
440
	}
441
	*a = 0 ;
442
	if ( *arg_buff ) {
443
	    /* Store argument string */
444
	    info->args = string_copy_aux ( arg_buff ) ;
445
	    if ( def ) {
446
		/* Store formal arguments */
447
		int i, n = no_args ;
448
		info->pars = alloc_nof ( construct *, n + 1 ) ;
449
		for ( i = 0 ; i < n ; i++ ) info->pars [i] = cons_buff [i] ;
450
		info->pars [n] = null ;
451
	    }
452
	}
453
	read_word () ;
454
	if ( func_input ) {
455
	    if ( word_type != INPUT_ARROW ) {
456
		is_fatal = 0 ;
457
		input_error ( "Arrow (->) expected" ) ;
458
		looked_ahead = 1 ;
459
	    }
460
	    read_word () ;
461
	}
462
    }
463
 
464
    /* Read result sort */
465
    info->res = read_sortname () ;
466
    if ( is_high ( info->res ) ) {
467
	input_error ( "Tokens cannot return high-level sorts" ) ;
468
    }
469
    return ;
470
}
471
 
472
 
473
/*
474
    READ A TOKEN DECLARATION
475
 
476
    A token declaration is read from the input file.
477
*/
478
 
479
static void read_tokdec
480
    PROTO_N ( ( local ) )
481
    PROTO_T ( boolean local )
482
{
483
    tok_info store ;
484
    construct *p = read_external ( SORT_token, local ) ;
485
    tok_info *info = get_tok_info ( p ) ;
486
 
487
    /* Get token sort */
488
    adjust_token ( p ) ;
489
    read_toksort ( &store, 0 ) ;
490
    info->dec = 1 ;
491
    set_token_sort ( p, store.res, store.args, store.sig ) ;
492
    return ;
493
}
494
 
495
 
496
/*
497
    READ A TOKEN DEFINITION
498
 
499
    A token definition is read from the input file.
500
*/
501
 
502
static void read_tokdef
503
    PROTO_N ( ( local ) )
504
    PROTO_T ( boolean local )
505
{
506
    node *d ;
507
    char buff [2] ;
508
    tok_info store ;
509
    construct *p = read_external ( SORT_token, local ) ;
510
    tok_info *info = get_tok_info ( p ) ;
511
    construct **old_pars = info->pars ;
512
 
513
    /* Get token sort */
514
    adjust_token ( p ) ;
515
    read_toksort ( &store, 1 ) ;
516
    info->dec = 1 ;
517
    info->pars = store.pars ;
518
    set_token_sort ( p, store.res, store.args, store.sig ) ;
519
 
520
    /* Check comma */
521
    if ( func_input ) {
522
	read_word () ;
523
	if ( word_type != INPUT_COMMA ) {
524
	    is_fatal = 0 ;
525
	    input_error ( "Comma expected" ) ;
526
	    looked_ahead = 1 ;
527
	}
528
    }
529
 
530
    /* Read the definition */
531
    buff [0] = sort_letters [ store.res ] ;
532
    buff [1] = 0 ;
533
    d = read_node ( buff ) ;
534
 
535
    /* Free formal parameters */
536
    if ( info->pars ) {
537
	construct **ps ;
538
	for ( ps = info->pars ; *ps ; ps++ ) {
539
	    remove_var_hash ( ( *ps )->name, SORT_token ) ;
540
	}
541
    }
542
 
543
    /* Check consistency */
544
    d = completion ( d ) ;
545
    if ( info->def ) {
546
	if ( !eq_node ( info->def, d ) ) {
547
	    is_fatal = 0 ;
548
	    input_error ( "Token %s defined inconsistently", p->name ) ;
549
	}
550
	free_node ( d ) ;
551
	info->pars = old_pars ;
552
    } else {
553
	info->def = d ;
554
    }
555
    return ;
556
}
557
 
558
 
559
/*
560
    READ A TOKEN SORT DEFINITION
561
 
562
    A token sort defintion is read from the input file.
563
*/
564
 
565
static void read_sortdef
566
    PROTO_N ( ( local ) )
567
    PROTO_T ( boolean local )
568
{
569
    char *nm ;
570
    tok_info store ;
571
 
572
    /* The local quantifier should not be used */
573
    if ( local ) {
574
	is_fatal = 0 ;
575
	input_error ( "Can't have local here" ) ;
576
    }
577
 
578
    /* Read the sort name */
579
    read_word () ;
580
    if ( word_type != INPUT_WORD ) input_error ( "Identifier expected" ) ;
581
    nm = string_copy_aux ( word ) ;
582
 
583
    /* Get sort definition */
584
    read_toksort ( &store, 0 ) ;
585
    set_high_sort ( nm, &store ) ;
586
    return ;
587
}
588
 
589
 
590
/*
591
    READ A SUBFILE
592
 
593
    A complete subfile is read.  ftype gives the type of the subfile :
594
 
595
    only the tokens should be read.
596
*/
597
 
598
static void sub_file
599
    PROTO_N ( ( ftype, ex ) )
600
    PROTO_T ( int ftype X int ex )
601
{
602
    position store ;
603
    boolean old_func_input = func_input ;
604
    char *old_name = input_file, *new_name ;
605
 
606
    /* Read the file name */
607
    allow_multibyte = 0 ;
608
    read_word () ;
609
    allow_multibyte = 1 ;
610
    if ( word_type != INPUT_STRING ) {
611
	is_fatal = 0 ;
612
	input_error ( "File name expected" ) ;
613
	return ;
614
    }
615
    new_name = string_copy_aux ( word ) ;
616
 
617
    /* Save the position in the existing file */
618
    store_position ( &store ) ;
619
 
620
    /* Read the subfile */
621
    text_input = ( boolean ) ( ftype == 0 ? 1 : 0 ) ;
622
    open_input ( new_name, 1 ) ;
623
    if ( ftype == 0 ) {
624
	read_capsule () ;
625
    } else {
626
	extract_tokdecs = ( boolean ) ex ;
627
	if ( ftype == 1 ) {
628
	    de_capsule () ;
629
	} else {
630
	    de_library () ;
631
	}
632
	extract_tokdecs = 0 ;
633
    }
634
 
635
    /* Restore the position in the old file */
636
    text_input = 1 ;
637
    open_input ( old_name, 1 ) ;
638
    set_position ( &store ) ;
639
    func_input = old_func_input ;
640
    return ;
641
}
642
 
643
 
644
/*
645
    READ A CAPSULE
646
 
647
    A complete capsule is read from the input file.
648
*/
649
 
650
void read_capsule
651
    PROTO_Z ()
652
{
653
    int starter ;
654
    read_word () ;
655
    if ( word_type == INPUT_OPEN ) {
656
	if ( func_input ) warning ( "Switching input form" ) ;
657
	func_input = 0 ;
658
	starter = INPUT_OPEN ;
659
    } else {
660
	if ( !func_input ) warning ( "Switching input form" ) ;
661
	func_input = 1 ;
662
	starter = INPUT_WORD ;
663
    }
664
    looked_ahead = 1 ;
665
 
666
    while ( read_word (), word_type == starter ) {
667
	char *cmd ;
668
	char *wtemp ;
669
	boolean local = 0 ;
670
	if ( !func_input ) {
671
	    read_word () ;
672
	    if ( word_type != INPUT_WORD ) {
673
		input_error ( "Construct name expected" ) ;
674
	    }
675
	}
676
 
677
	/* Check for the local qualifier */
678
	if ( streq ( word, LOCAL_DECL ) ) {
679
	    local = 1 ;
680
	    read_word () ;
681
	    if ( word_type != INPUT_WORD ) {
682
		input_error ( "Construct name expected" ) ;
683
	    }
684
	}
685
 
686
	/* For functional input, expect an open bracket */
687
	if ( func_input ) {
688
	    wtemp = temp_copy ( word ) ;
689
	    read_word () ;
690
	    if ( word_type != INPUT_OPEN ) {
691
		is_fatal = 0 ;
692
		input_error ( "Open bracket expected" ) ;
693
		looked_ahead = 1 ;
694
	    }
695
	} else {
696
	    wtemp = word ;
697
	}
698
 
699
	/* Macro to aid checking */
700
#define test_cmd( X, Y )\
701
	if ( streq ( wtemp, cmd = ( X ) ) ) {\
702
	    Y ;\
703
	} else
704
 
705
	/* Check on the various possible constructs */
706
	test_cmd ( MAKE_ALDEC, read_aldec ( local ) )
707
	test_cmd ( MAKE_ALDEF, read_aldef ( local ) )
708
	test_cmd ( MAKE_ID_TAGDEC, read_tagdec ( local, 0 ) )
709
	test_cmd ( MAKE_VAR_TAGDEC, read_tagdec ( local, 1 ) )
710
	test_cmd ( MAKE_ID_TAGDEF, read_tagdef ( local, 0 ) )
711
	test_cmd ( MAKE_VAR_TAGDEF, read_tagdef ( local, 1 ) )
712
	test_cmd ( MAKE_TOKDEC, read_tokdec ( local ) )
713
	test_cmd ( MAKE_TOKDEF, read_tokdef ( local ) )
714
	test_cmd ( COMMON_TAGDEC, read_tagdec ( local, 2 ) )
715
	test_cmd ( COMMON_TAGDEF, read_tagdef ( local, 2 ) )
716
	test_cmd ( MAKE_SORT, read_sortdef ( local ) )
717
 
718
	{
719
	    /* Include constructs */
720
	    if ( local ) {
721
		is_fatal = 0 ;
722
		input_error ( "Can't have local here" ) ;
723
	    }
724
	    test_cmd ( INCLUDE_TEXT, sub_file ( 0, 0 ) )
725
	    test_cmd ( INCLUDE_CODE, sub_file ( 1, 0 ) )
726
	    test_cmd ( USE_CODE, sub_file ( 1, 1 ) )
727
	    test_cmd ( INCLUDE_LIB, sub_file ( 2, 0 ) )
728
	    test_cmd ( USE_LIB, sub_file ( 2, 1 ) )
729
	    {
730
		/* Illegal construct */
731
		input_error ( "Illegal construct name, %s", wtemp ) ;
732
	    }
733
	}
734
 
735
	/* End of construct */
736
	read_word () ;
737
	if ( word_type != INPUT_CLOSE ) {
738
	    is_fatal = 0 ;
739
	    input_error ( "End of %s construct expected", cmd ) ;
740
	    looked_ahead = 1 ;
741
	}
742
	if ( func_input ) {
743
	    read_word () ;
744
	    if ( word_type != INPUT_SEMICOLON ) {
745
		is_fatal = 0 ;
746
		input_error ( "End of %s construct expected", cmd ) ;
747
		looked_ahead = 1 ;
748
	    }
749
	}
750
    }
751
    if ( word_type != INPUT_EOF ) {
752
	is_fatal = 0 ;
753
	input_error ( "Start of construct expected" ) ;
754
    }
755
    return ;
756
}