Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – tendra.SVN – Blame – /branches/tendra5/src/tools/tnc/read.c – Rev 2

Subversion Repositories tendra.SVN

Rev

Go to most recent revision | Details | 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 "high.h"
37
#include "names.h"
38
#include "node.h"
39
#include "read.h"
40
#include "shape.h"
41
#include "table.h"
42
#include "tdf.h"
43
#include "utility.h"
44
 
45
 
46
/*
47
    ARE MULTIBYTE STRINGS ALLOWED
48
 
49
    This flag is true to indicate that multibyte strings (other than
50
    8 bits per character) are allowed.
51
*/
52
 
53
boolean allow_multibyte = 1 ;
54
 
55
 
56
/*
57
    READ A TOKEN APPLICATION
58
 
59
    A token application of sort s is read and appended to p.
60
*/
61
 
62
void read_token
63
    PROTO_N ( ( p, s ) )
64
    PROTO_T ( node *p X sortname s )
65
{
66
    char *ra ;
67
    char *wtemp ;
68
    sortname rs ;
69
    construct *v ;
70
    tok_info *info ;
71
    boolean in_brackets = 0 ;
72
 
73
    /* Check bracket (1) */
74
    read_word () ;
75
    if ( !func_input && word_type == INPUT_OPEN ) {
76
	in_brackets = 1 ;
77
	read_word () ;
78
    }
79
 
80
    /* Read token identifier */
81
    if ( word_type != INPUT_WORD ) {
82
	input_error ( "Token identifier expected" ) ;
83
	return ;
84
    }
85
 
86
    /* Check bracket (2) */
87
    if ( func_input ) {
88
	wtemp = temp_copy ( word ) ;
89
	read_word () ;
90
	if ( word_type == INPUT_OPEN ) {
91
	    in_brackets = 1 ;
92
	} else {
93
	    looked_ahead = 1 ;
94
	}
95
    } else {
96
	wtemp = word ;
97
    }
98
 
99
    /* Look up token */
100
    v = search_var_hash ( wtemp, SORT_token ) ;
101
    if ( v == null ) {
102
	input_error ( "Token %s not declared", wtemp ) ;
103
	return ;
104
    }
105
    info = get_tok_info ( v ) ;
106
    rs = info->res ;
107
    ra = info->args ;
108
    if ( rs == SORT_unknown ) {
109
	input_error ( "Token %s not declared", wtemp ) ;
110
	return ;
111
    }
112
    if ( is_high ( rs ) ) {
113
	high_sort *h = high_sorts + high_no ( rs ) ;
114
	rs = h->res ;
115
	ra = find_decode_string ( h ) ;
116
    }
117
    if ( rs != s ) {
118
	input_error ( "Token %s returns %s, not %s", wtemp,
119
		      sort_name ( rs ), sort_name ( s ) ) ;
120
	return ;
121
    }
122
    adjust_token ( v ) ;
123
 
124
    /* Decode arguments */
125
    p->son = new_node () ;
126
    p->son->cons = v ;
127
    if ( ra ) p->son->son = read_node ( ra ) ;
128
 
129
    /* Check end */
130
    if ( in_brackets ) {
131
	read_word () ;
132
	if ( word_type != INPUT_CLOSE ) {
133
	    is_fatal = 0 ;
134
	    input_error ( "End of token %s construct expected", v->name ) ;
135
	    looked_ahead = 1 ;
136
	}
137
    } else {
138
	if ( p->son->son ) {
139
	    is_fatal = 0 ;
140
	    input_error ( "Token %s construct should be in brackets",
141
			  v->name ) ;
142
	}
143
    }
144
    if ( do_check ) IGNORE set_token_args ( info->pars, p->son->son, 0 ) ;
145
    return ;
146
}
147
 
148
 
149
/*
150
    READ A TOKEN NAME
151
 
152
    This routine reads a token name (as opposed to a token application).
153
    The token should have sort s.
154
*/
155
 
156
static node *read_token_name
157
    PROTO_N ( ( s ) )
158
    PROTO_T ( sortname s )
159
{
160
    node *p ;
161
    boolean ok = 0 ;
162
    construct *v ;
163
    high_sort *h ;
164
    tok_info *info ;
165
 
166
    /* Read token identifier */
167
    read_word () ;
168
    if ( word_type != INPUT_WORD ) {
169
	input_error ( "Token identifier expected" ) ;
170
	return ( null ) ;
171
    }
172
 
173
    /* Look up token */
174
    v = search_var_hash ( word, SORT_token ) ;
175
    if ( v == null ) {
176
	input_error ( "Token %s not declared", word ) ;
177
	return ( null ) ;
178
    }
179
    info = get_tok_info ( v ) ;
180
 
181
    /* Check consistency */
182
    h = high_sorts + high_no ( s ) ;
183
    if ( h->res == info->res ) {
184
	if ( info->args == null ) {
185
	    if ( h->no_args == 0 ) ok = 1 ;
186
	} else if ( h->no_args ) {
187
	    char *ha = find_decode_string ( h ) ;
188
	    if ( streq ( info->args, ha ) ) ok = 1 ;
189
	}
190
    } else if ( h->id == info->res ) {
191
	if ( info->args == null ) ok = 1 ;
192
    }
193
    if ( !ok ) {
194
	input_error ( "Token %s has incorrect sort", v->name ) ;
195
    }
196
 
197
    /* Return the construct */
198
    p = new_node () ;
199
    p->cons = v ;
200
    if ( !text_output ) {
201
	p->son = new_node () ;
202
	p->son->cons = &token_cons ;
203
    }
204
    return ( p ) ;
205
}
206
 
207
 
208
/*
209
    FIND BASIC CONSTRUCT FOR A VARIABLE SORT
210
 
211
    This routine returns the construct for turning an identifier into
212
    an object of sort s.
213
*/
214
 
215
static long make_obj
216
    PROTO_N ( ( s ) )
217
    PROTO_T ( sortname s )
218
{
219
    long mk = -1 ;
220
    switch ( s ) {
221
	case SORT_al_tag : mk = ENC_make_al_tag ; break ;
222
	case SORT_label : mk = ENC_make_label ; break ;
223
	case SORT_tag : mk = ENC_make_tag ; break ;
224
    }
225
    return ( mk ) ;
226
}
227
 
228
 
229
/*
230
    IS A VARIABLE SORT A USE OR AN INTRODUCTION?
231
 
232
    This flag is true to indicate that the tag (or whatever) being read
233
    is a new one being introduced rather than an old one being used.
234
    The flag intro_tag_var is set to indicate that any tag so introduced
235
    is a variable.  The flag intro_visible is set to true whenever the
236
    visible access specifier is read.
237
*/
238
 
239
static boolean intro_var = 0 ;
240
static boolean intro_tag_var = 0 ;
241
boolean intro_visible = 0 ;
242
 
243
 
244
/*
245
    SEARCH FOR A VARIABLE SORT
246
 
247
    This routine initializes, if appropriate, and returns the construct
248
    corresponding to the object named nm of sort s.
249
*/
250
 
251
static construct *search_var_sort
252
    PROTO_N ( ( nm, s ) )
253
    PROTO_T ( char *nm X sortname s )
254
{
255
    construct *v = search_var_hash ( nm, s ) ;
256
    if ( intro_var ) {
257
	if ( v == null ) {
258
	    v = make_construct ( s ) ;
259
	    v->name = string_copy_aux ( nm ) ;
260
	    /* Don't add to hash table yet */
261
	    if ( s == SORT_tag ) {
262
		tag_info *info = get_tag_info ( v ) ;
263
		info->var = intro_tag_var ;
264
		info->vis = intro_visible ;
265
		intro_visible = 0 ;
266
	    }
267
	} else {
268
	    input_error ( "%s %s already in scope", sort_name ( s ), nm ) ;
269
	}
270
    } else {
271
	if ( v == null ) {
272
	    if ( !dont_check ) {
273
		is_fatal = 0 ;
274
		input_error ( "%s %s not in scope", sort_name ( s ), nm ) ;
275
	    }
276
	    v = make_construct ( s ) ;
277
	    v->name = string_copy_aux ( nm ) ;
278
	    IGNORE add_to_var_hash ( v, s ) ;
279
	}
280
    }
281
    return ( v ) ;
282
}
283
 
284
 
285
/*
286
    READ A VARIABLE SORT
287
 
288
    An identifier representing a construct of sort s is read.
289
*/
290
 
291
node *read_var_sort
292
    PROTO_N ( ( s ) )
293
    PROTO_T ( sortname s )
294
{
295
    node *p ;
296
    construct *v ;
297
    read_word () ;
298
    if ( word_type != INPUT_WORD ) {
299
	input_error ( "%s identifier expected", sort_name ( s ) ) ;
300
    }
301
    v = search_var_sort ( word, s ) ;
302
    p = new_node () ;
303
    p->cons = v ;
304
    return ( p ) ;
305
}
306
 
307
 
308
/*
309
    READ A SEQUENCE EXPRESSION
310
 
311
    A sequence expression is read.  This is tricky because it is a list
312
    of exps followed by an exp, which may be read as a list of exps.
313
*/
314
 
315
void read_seq_node
316
    PROTO_N ( ( p ) )
317
    PROTO_T ( node *p )
318
{
319
    node *q = read_node ( "*[x]?[x]" ) ;
320
    if ( q->bro->son ) {
321
	node *r = q->bro->son ;
322
	q->bro = r ;
323
	p->son = q ;
324
	return ;
325
    }
326
    q->bro = null ;
327
    if ( q->cons->encoding == 0 ) {
328
	is_fatal = 0 ;
329
	input_error ( "exp expected" ) ;
330
	return ;
331
    }
332
    ( q->cons->encoding )-- ;
333
    p->son = q ;
334
    q = q->son ;
335
    if ( q->bro == null ) {
336
	p->son->son = null ;
337
	p->son->bro = q ;
338
    } else {
339
	while ( q->bro->bro ) q = q->bro ;
340
	p->son->bro = q->bro ;
341
	q->bro = null ;
342
    }
343
    return ;
344
}
345
 
346
 
347
/*
348
    READ SORT INDICATED BY A SINGLE DECODE LETTER
349
 
350
    An object with sort given by the decode letter str is read.  If the next
351
    object is not of this sort then either an error is flagged (if strict
352
    is true) or null is returned.
353
*/
354
 
355
static node *read_node_aux
356
    PROTO_N ( ( str, strict ) )
357
    PROTO_T ( char *str X int strict )
358
{
359
    sortname s ;
360
    char *wtemp ;
361
    node *p, *ps ;
362
    construct *cons ;
363
    read_func fn = null ;
364
    boolean in_brackets = 0 ;
365
 
366
    /* Find the corresponding sort name */
367
    if ( str [1] == '&' ) {
368
	/* Introduced variable */
369
	intro_var = 1 ;
370
	intro_tag_var = 1 ;
371
    } else if ( str [1] == '^' ) {
372
	/* Introduced identity */
373
	intro_var = 1 ;
374
	intro_tag_var = 0 ;
375
    }
376
    switch ( str [0] ) {
377
	case 'i' : {
378
	    s = SORT_tdfint ;
379
	    break ;
380
	}
381
	case 'j' : {
382
	    s = SORT_tdfbool ;
383
	    break ;
384
	}
385
	case '$' : {
386
	    s = SORT_tdfstring ;
387
	    break ;
388
	}
389
	case 'F' : {
390
	    s = SORT_unknown ;
391
	    break ;
392
	}
393
	default : {
394
	    s = find_sort ( str [0] ) ;
395
	    fn = sort_read [s] ;
396
	    break ;
397
	}
398
    }
399
 
400
    /* Read the next word */
401
    read_word () ;
402
 
403
    /* Check for blanks */
404
    if ( word_type == INPUT_BLANK && !strict ) {
405
	word_type = INPUT_BLANK_FIRST ;
406
	return ( null ) ;
407
    }
408
 
409
    /* Check for bars */
410
    if ( word_type == INPUT_BAR && !strict ) {
411
	word_type = INPUT_BAR_FIRST ;
412
	return ( null ) ;
413
    }
414
 
415
    /* Deal with strings */
416
    if ( s == SORT_tdfstring ) {
417
	if ( word_type == INPUT_STRING ) {
418
	    p = new_node () ;
419
	    p->cons = new_construct () ;
420
	    p->cons->sortnum = SORT_tdfstring ;
421
	    p->cons->encoding = word_length ;
422
	    p->cons->name = string_copy ( word, ( int ) word_length ) ;
423
	    p->cons->next = null ;
424
	    return ( p ) ;
425
	} else {
426
	    boolean is_multibyte = 0 ;
427
	    if ( func_input ) {
428
		if ( word_type == INPUT_WORD ) {
429
		    if ( streq ( word, MAKE_STRING ) ) {
430
			read_word () ;
431
			if ( word_type == INPUT_OPEN ) is_multibyte = 1 ;
432
		    }
433
		}
434
	    } else {
435
		if ( word_type == INPUT_OPEN ) {
436
		    read_word () ;
437
		    if ( word_type == INPUT_WORD ) {
438
			if ( streq ( word, MAKE_STRING ) ) is_multibyte = 1 ;
439
		    }
440
		}
441
	    }
442
	    if ( is_multibyte ) {
443
		if ( !allow_multibyte ) {
444
		    input_error ( "Multibyte strings not allowed here" ) ;
445
		}
446
		p = new_node () ;
447
		p->cons = &string_cons ;
448
		p->son = read_node ( "i*[i]" ) ;
449
		read_word () ;
450
		if ( word_type != INPUT_CLOSE ) {
451
		    input_error ( "End of multibyte string expected" ) ;
452
		}
453
		return ( p ) ;
454
	    }
455
	}
456
	if ( strict ) input_error ( "String expected" ) ;
457
	return ( null ) ;
458
    }
459
 
460
    /* Deal with numbers */
461
    if ( word_type == INPUT_NUMBER ) {
462
	boolean negate = 0 ;
463
	if ( *word == '-' ) {
464
	    word++ ;
465
	    negate = 1 ;
466
	}
467
	p = new_node () ;
468
	p->cons = new_construct () ;
469
	if ( fits_ulong ( word, 1 ) ) {
470
	    p->cons->sortnum = SORT_small_tdfint ;
471
	    p->cons->encoding = ( long ) octal_to_ulong ( word ) ;
472
	} else {
473
	    p->cons->sortnum = SORT_tdfint ;
474
	    p->cons->name = string_copy_aux ( word ) ;
475
	}
476
 
477
	switch ( s ) {
478
	    case SORT_tdfint : {
479
		if ( negate ) {
480
		    is_fatal = 0 ;
481
		    input_error ( "Negative nat" ) ;
482
		}
483
		return ( p ) ;
484
	    }
485
	    case SORT_tdfbool : {
486
		node *q = new_node () ;
487
		q->cons = ( negate ? &true_cons : &false_cons ) ;
488
		q->bro = p ;
489
		return ( q ) ;
490
	    }
491
	    case SORT_nat : {
492
		node *q = new_node () ;
493
		if ( negate ) {
494
		    is_fatal = 0 ;
495
		    input_error ( "Negative nat" ) ;
496
		}
497
		q->cons = cons_no ( SORT_nat, ENC_make_nat ) ;
498
		q->son = p ;
499
		return ( q ) ;
500
	    }
501
	    case SORT_signed_nat : {
502
		node *q = new_node () ;
503
		q->cons = cons_no ( SORT_signed_nat, ENC_make_signed_nat ) ;
504
		q->son = new_node () ;
505
		q->son->cons = ( negate ? &true_cons : &false_cons ) ;
506
		q->son->bro = p ;
507
		return ( q ) ;
508
	    }
509
	    default : {
510
		if ( strict ) input_error ( "%s expected", sort_name ( s ) ) ;
511
		return ( null ) ;
512
	    }
513
	}
514
    }
515
 
516
    /* Deal with strings */
517
    if ( word_type == INPUT_STRING ) {
518
	if ( s == SORT_string ) {
519
	    node *q ;
520
	    p = new_node () ;
521
	    p->cons = new_construct () ;
522
	    p->cons->sortnum = SORT_tdfstring ;
523
	    p->cons->encoding = word_length ;
524
	    p->cons->name = string_copy ( word, ( int ) word_length ) ;
525
	    p->cons->next = null ;
526
	    q = new_node () ;
527
	    q->cons = cons_no ( SORT_string, ENC_make_string ) ;
528
	    q->son = p ;
529
	    return ( q ) ;
530
	}
531
    }
532
 
533
    /* That was the last chance for numbers */
534
    if ( fn == null ) {
535
	if ( strict ) input_error ( "Number expected" ) ;
536
	return ( null ) ;
537
    }
538
 
539
    /* Check for brackets (1) */
540
    if ( !func_input && word_type == INPUT_OPEN ) {
541
	in_brackets = 1 ;
542
	read_word () ;
543
    }
544
 
545
    /* The next word should be the identifier */
546
    if ( word_type != INPUT_WORD ) {
547
	if ( strict ) input_error ( "%s expected", sort_name ( s ) ) ;
548
	return ( null ) ;
549
    }
550
 
551
    /* Check for brackets (2) */
552
    if ( func_input ) {
553
	wtemp = temp_copy ( word ) ;
554
	read_word () ;
555
	if ( word_type == INPUT_OPEN ) {
556
	    in_brackets = 1 ;
557
	} else {
558
	    looked_ahead = 1 ;
559
	}
560
    } else {
561
	wtemp = word ;
562
    }
563
 
564
    if ( s == SORT_string && streq ( word, MAKE_STRING ) ) {
565
	node *q ;
566
	p = new_node () ;
567
	p->cons = &string_cons ;
568
	p->son = read_node ( "i*[i]" ) ;
569
	read_word () ;
570
	if ( word_type != INPUT_CLOSE ) {
571
	    input_error ( "End of multibyte string expected" ) ;
572
	}
573
	q = new_node () ;
574
	q->cons = cons_no ( SORT_string, ENC_make_string ) ;
575
	q->son = p ;
576
	return ( q ) ;
577
    }
578
 
579
    /* Look up construct */
580
    cons = search_cons_hash ( wtemp, s ) ;
581
    if ( cons ) {
582
	p = fn ( cons->encoding ) ;
583
	ps = p->son ;
584
    } else {
585
	boolean do_check_tag = 0 ;
586
	if ( !in_brackets && ( s == SORT_al_tag || s == SORT_label ||
587
			       s == SORT_tag ) ) {
588
	    do_check_tag = 1 ;
589
	}
590
	/* Look up token */
591
	cons = search_var_hash ( wtemp, SORT_token ) ;
592
	if ( cons ) {
593
	    tok_info *info = get_tok_info ( cons ) ;
594
	    sortname rs = info->res ;
595
	    char *ra = info->args ;
596
	    if ( rs == SORT_unknown ) {
597
		if ( do_check_tag ) goto check_lab ;
598
		input_error ( "Token %s not declared", wtemp ) ;
599
	    }
600
	    if ( is_high ( rs ) ) {
601
		high_sort *h = high_sorts + high_no ( rs ) ;
602
		rs = h->res ;
603
		ra = find_decode_string ( h ) ;
604
	    }
605
	    if ( rs != s ) {
606
		if ( do_check_tag ) goto check_lab ;
607
		if ( !strict ) return ( null ) ;
608
		input_error ( "Token %s returns %s, not %s", wtemp,
609
			      sort_name ( rs ), sort_name ( s ) ) ;
610
	    }
611
	    adjust_token ( cons ) ;
612
	    p = new_node () ;
613
	    p->cons = cons_no ( s, sort_tokens [s] ) ;
614
	    p->son = new_node () ;
615
	    p->son->cons = cons ;
616
	    if ( ra ) p->son->son = read_node ( ra ) ;
617
	    ps = p->son->son ;
618
	    if ( do_check ) {
619
		IGNORE set_token_args ( info->pars, p->son->son, 0 ) ;
620
		if ( s == SORT_exp ) check_exp ( p ) ;
621
	    }
622
	} else {
623
	    /* Look up label, tag etc */
624
	    if ( do_check_tag ) {
625
		check_lab : cons = search_var_sort ( wtemp, s ) ;
626
	    }
627
	    if ( cons ) {
628
		long mk = make_obj ( s ) ;
629
		p = new_node () ;
630
		p->cons = cons_no ( s, mk ) ;
631
		p->son = new_node () ;
632
		p->son->cons = cons ;
633
		ps = null ;
634
	    } else {
635
		if ( strict ) {
636
		    input_error ( "Illegal %s, %s", sort_name ( s ), wtemp ) ;
637
		}
638
		return ( null ) ;
639
	    }
640
	}
641
    }
642
 
643
    /* Check end of construct */
644
    if ( in_brackets ) {
645
	read_word () ;
646
	if ( word_type != INPUT_CLOSE ) {
647
	    is_fatal = 0 ;
648
	    input_error ( "End of %s construct expected", cons->name ) ;
649
	    looked_ahead = 1 ;
650
	}
651
    } else {
652
	if ( ps ) {
653
	    is_fatal = 0 ;
654
	    input_error ( "%s construct should be in brackets", cons->name ) ;
655
	}
656
    }
657
    return ( p ) ;
658
}
659
 
660
 
661
/*
662
    BRING VARIABLES INTO AND OUT OF SCOPE
663
 
664
    The tags, labels etc introduced in p are brought into (if end is
665
    false) or out of (if end is true) scope.  This only works because
666
    all the constructs which introduce these variables are of a fairly
667
    simple form.
668
*/
669
 
670
static void adjust_scope
671
    PROTO_N ( ( p, end ) )
672
    PROTO_T ( node *p X int end )
673
{
674
    node *p0 = p ;
675
    while ( p ) {
676
	construct *v = p->cons ;
677
	sortname s = v->sortnum ;
678
	switch ( s ) {
679
 
680
	    case SORT_repeat :
681
	    case SORT_option : {
682
		/* Scan repeated and optional arguments */
683
		if ( p->son ) adjust_scope ( p->son, end ) ;
684
		break ;
685
	    }
686
 
687
	    case SORT_al_tag :
688
	    case SORT_label :
689
	    case SORT_tag : {
690
		/* Variable found - adjust scope */
691
		if ( v->encoding == make_obj ( s ) ) {
692
		    construct *u = p->son->cons ;
693
		    if ( end ) {
694
			if ( s == SORT_tag ) {
695
			    /* Visible tags aren't removed */
696
			    tag_info *info = get_tag_info ( u ) ;
697
			    if ( info->vis ) break ;
698
			}
699
			remove_var_hash ( u->name, s ) ;
700
		    } else {
701
			if ( add_to_var_hash ( u, s ) ) {
702
			    input_error ( "%s %s already in scope",
703
					  sort_name ( s ), u->name ) ;
704
			}
705
			if ( do_check && s == SORT_tag ) {
706
			    /* Fill in shape of tag */
707
			    node *ts ;
708
			    node *p1 = p->bro ;
709
			    tag_info *info = get_tag_info ( u ) ;
710
			    if ( p1 && p1->cons->sortnum == SORT_exp ) {
711
				/* identity and variable have "t&x" */
712
				ts = p1->shape ;
713
			    } else if ( p0->cons->sortnum == SORT_shape ) {
714
				/* make_proc etc have "S?[u]t&" */
715
				ts = copy_node ( p0 ) ;
716
			    } else {
717
				/* don't know about other constructs */
718
				ts = null ;
719
			    }
720
			    /* Declaration = ?[u]?[X]S from 4.0 */
721
			    info->dec = new_node () ;
722
			    info->dec->cons = &false_cons ;
723
			    info->dec->bro = new_node () ;
724
			    info->dec->bro->cons = &false_cons ;
725
			    info->dec->bro->bro = ts ;
726
			}
727
		    }
728
		}
729
		break ;
730
	    }
731
	}
732
	p = p->bro ;
733
    }
734
    return ;
735
}
736
 
737
 
738
/*
739
    CHECK FOR COMMA OR CLOSE BRACKET
740
 
741
    The next word should be a comma, which is stepped over, or a close
742
    bracket.
743
*/
744
 
745
static void check_comma
746
    PROTO_Z ()
747
{
748
    read_word () ;
749
    if ( word_type == INPUT_COMMA ) {
750
	read_word () ;
751
	looked_ahead = 1 ;
752
	if ( word_type == INPUT_CLOSE ) {
753
	    is_fatal = 0 ;
754
	    input_error ( "Badly placed comma" ) ;
755
	}
756
	return ;
757
    }
758
    if ( word_type != INPUT_CLOSE ) {
759
	is_fatal = 0 ;
760
	input_error ( "Comma or close bracket expected" ) ;
761
    }
762
    looked_ahead = 1 ;
763
    return ;
764
}
765
 
766
 
767
/*
768
    READ SORTS GIVEN BY A STRING OF DECODE LETTERS
769
 
770
    A node corresponding to the decode string str is read from the
771
    input file.
772
*/
773
 
774
node *read_node
775
    PROTO_N ( ( str ) )
776
    PROTO_T ( char *str )
777
{
778
    char c ;
779
    position store ;
780
    node *p, *q = null, *qe = null ;
781
    while ( c = *str, ( c != 0 && c != ']' ) ) {
782
	switch ( c ) {
783
 
784
	    case '{' : {
785
		/* Start of scope */
786
		adjust_scope ( q, 0 ) ;
787
		p = null ;
788
		break ;
789
	    }
790
 
791
	    case '}' : {
792
		/* End of scope */
793
		adjust_scope ( q, 1 ) ;
794
		p = null ;
795
		break ;
796
	    }
797
 
798
	    case '[' :
799
	    case '|' :
800
	    case '&' :
801
	    case '^' : {
802
		/* Ignore these cases */
803
		p = null ;
804
		break ;
805
	    }
806
 
807
	    case '*' :
808
	    case '!' : {
809
		/* Repeats */
810
		char cr ;
811
		char *sr ;
812
		long n = 0 ;
813
		int opt = 0 ;
814
		node *pe = null, *pr ;
815
		str += 2 ;
816
		cr = *str ;
817
		sr = str ;
818
		if ( cr == '?' ) {
819
		    /* Allow for lists of options */
820
		    opt = 1 ;
821
		    str += 2 ;
822
		    cr = *str ;
823
		    sr = skip_text ( str ) ;
824
		}
825
		if ( cr == '*' || cr == '!' ) {
826
		    input_error ( "Sorry, lists of lists not implemented" ) ;
827
		} else if ( cr == '?' ) {
828
		    input_error ( "Sorry, lists of options not implemented" ) ;
829
		}
830
		p = new_node () ;
831
		p->cons = new_construct () ;
832
		p->cons->sortnum = SORT_repeat ;
833
		do {
834
		    store_position ( &store ) ;
835
		    pr = read_node_aux ( sr, 0 ) ;
836
		    if ( pr || ( opt && word_type == INPUT_BLANK_FIRST ) ) {
837
			if ( func_input ) check_comma () ;
838
			if ( opt ) {
839
			    /* Allow for optionals */
840
			    node *pt = pr ;
841
			    if ( pt && str [1] != ']' ) {
842
				pt->bro = read_node ( str + 1 ) ;
843
			    }
844
			    pr = new_node () ;
845
			    pr->cons = &optional_cons ;
846
			    pr->son = pt ;
847
			}
848
			if ( sr [1] != ']' ) {
849
			    pr->bro = read_node ( sr + 1 ) ;
850
			}
851
			if ( pe == null ) {
852
			    p->son = pr ;
853
			} else {
854
			    pe->bro = pr ;
855
			}
856
			pe = pr ;
857
			while ( pe->bro ) pe = pe->bro ;
858
			n++ ;
859
		    } else {
860
			if ( word_type == INPUT_BAR_FIRST ) {
861
			    if ( func_input ) check_comma () ;
862
			} else if ( c == '!' && n == 0 &&
863
				    word_type == INPUT_BLANK_FIRST ) {
864
			    if ( func_input ) check_comma () ;
865
			} else {
866
			    set_position ( &store ) ;
867
			}
868
		    }
869
		} while ( pr ) ;
870
		p->cons->encoding = n ;
871
		if ( opt ) sr++ ;
872
		str = skip_text ( sr ) ;
873
		if ( c == '!' ) {
874
		    /* Optional repeats */
875
		    node *pt = p ;
876
		    p = new_node () ;
877
		    p->cons = &optional_cons ;
878
		    if ( n ) p->son = pt ;
879
		}
880
		break ;
881
	    }
882
 
883
	    case '?' : {
884
		/* Optionals */
885
		node *po ;
886
		char co ;
887
		str += 2 ;
888
		co = *str ;
889
		if ( co == '*' || co == '!' ) {
890
		    input_error ( "Sorry, optional lists not implemented" ) ;
891
		} else if ( co == '?' ) {
892
		    input_error ( "Sorry, optional options not implemented" ) ;
893
		}
894
		intro_visible = 0 ;
895
		store_position ( &store ) ;
896
		po = read_node_aux ( str, 0 ) ;
897
		if ( po ) {
898
		    if ( func_input ) check_comma () ;
899
		    if ( str [1] != ']' ) {
900
			po->bro = read_node ( str + 1 ) ;
901
		    }
902
		} else {
903
		    if ( word_type == INPUT_BLANK_FIRST ) {
904
			if ( func_input ) check_comma () ;
905
		    } else {
906
			set_position ( &store ) ;
907
		    }
908
		}
909
		p = new_node () ;
910
		p->cons = &optional_cons ;
911
		p->son = po ;
912
		str = skip_text ( str ) ;
913
		break ;
914
	    }
915
 
916
	    case '@' : {
917
		/* Conditionals */
918
		str += 2 ;
919
		p = new_node () ;
920
		p->cons = &bytestream_cons ;
921
		p->son = read_node ( str ) ;
922
		str = skip_text ( str ) ;
923
		break ;
924
	    }
925
 
926
	    case 'T' : {
927
		/* Tokens */
928
		sortname sn ;
929
		str = find_sortname ( str, &sn ) ;
930
		p = read_token_name ( sn ) ;
931
		break ;
932
	    }
933
 
934
	    default : {
935
		/* Simple sort */
936
		p = read_node_aux ( str, 1 ) ;
937
		if ( func_input ) check_comma () ;
938
		break ;
939
	    }
940
	}
941
	if ( p ) {
942
	    if ( qe == null ) {
943
		q = p ;
944
	    } else {
945
		qe->bro = p ;
946
	    }
947
	    qe = p ;
948
	    while ( qe->bro ) qe = qe->bro ;
949
	    intro_var = 0 ;
950
	}
951
	str++ ;
952
    }
953
    return ( q ) ;
954
}