Subversion Repositories tendra.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
7 7u83 2
 * Copyright (c) 2002-2005 The TenDRA Project <http://www.tendra.org/>.
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *
8
 * 1. Redistributions of source code must retain the above copyright notice,
9
 *    this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright notice,
11
 *    this list of conditions and the following disclaimer in the documentation
12
 *    and/or other materials provided with the distribution.
13
 * 3. Neither the name of The TenDRA Project nor the names of its contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific, prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
18
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
21
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
 * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 *
29
 * $Id$
30
 */
31
/*
2 7u83 32
    		 Crown Copyright (c) 1997
7 7u83 33
 
2 7u83 34
    This TenDRA(r) Computer Program is subject to Copyright
35
    owned by the United Kingdom Secretary of State for Defence
36
    acting through the Defence Evaluation and Research Agency
37
    (DERA).  It is made available to Recipients with a
38
    royalty-free licence for its use, reproduction, transfer
39
    to other parties and amendment for any purpose not excluding
40
    product development provided that any such use et cetera
41
    shall be deemed to be acceptance of the following conditions:-
7 7u83 42
 
2 7u83 43
        (1) Its Recipients shall ensure that this Notice is
44
        reproduced upon any copies or amended versions of it;
7 7u83 45
 
2 7u83 46
        (2) Any amended version of it shall be clearly marked to
47
        show both the nature of and the organisation responsible
48
        for the relevant amendment or amendments;
7 7u83 49
 
2 7u83 50
        (3) Its onward transfer from a recipient to another
51
        party shall be deemed to be that party's acceptance of
52
        these conditions;
7 7u83 53
 
2 7u83 54
        (4) DERA gives no warranty or assurance as to its
55
        quality or suitability for any purpose and DERA accepts
56
        no liability whatsoever in relation to any use to which
57
        it may be put.
58
*/
59
 
60
 
61
#include "config.h"
62
#include "tdf.h"
63
#include "cons_ops.h"
64
#include "info_ops.h"
65
#include "link_ops.h"
66
#include "par_ops.h"
67
#include "sort_ops.h"
68
#include "error.h"
69
#include "input.h"
70
#include "xalloc.h"
71
 
72
 
73
/*
74
    ARRAY OF KNOWN SORT NAMES
75
 
76
    This table gives the mapping from sort names to sort codes.  Sorts
77
    not in this list, or with a sort code of zero, have sort codes
78
    automatically generated for them.
79
*/
80
 
81
static struct {
7 7u83 82
    char *name;
83
    int code;
84
} sort_names[] = {
2 7u83 85
    /* Built-in sorts */
86
    { "tdfint", 'i' },
87
    { "tdfstring", '$' },
88
    { "tdfident", '=' },
89
    { "tdfbool", 'j' },
90
    { "bitstream", '@' },
91
    { "bytestream", '#' },
92
 
93
    /* Basic sorts */
94
    { "access", 'u' },
95
    { "alignment", 'a' },
96
    { "al_tag", 'A' },
97
    { "bitfield_variety", 'B' },
98
    { "bool", 'b' },
99
    { "callees", 'q' },
100
    { "error_code", 'c' },
101
    { "error_treatment", 'e' },
102
    { "exp", 'x' },
103
    { "floating_variety", 'f' },
104
    { "label", 'l' },
105
    { "nat", 'n' },
106
    { "ntest", 'N' },
107
    { "procprops", 'P' },
108
    { "rounding_mode", 'r' },
109
    { "shape", 'S' },
110
    { "signed_nat", 's' },
111
    { "string", 'X' },
112
    { "tag", 't' },
113
    { "token", 'T' },
114
    { "transfer_mode", 'm' },
115
    { "variety", 'v' },
116
 
117
    /* Unit sorts */
118
    { "al_tagdef", 0 },
119
    { "diag_tagdef", 0 },
120
    { "external", 0 },
121
    { "sortname", '~' },
122
    { "tagdec", 0 },
123
    { "tagdef", 0 },
124
    { "tokdec", 0 },
125
    { "tokdef", 0 },
126
 
127
    /* Diagnostic and linkage sorts */
128
    { "diag_descriptor", 'D' },
129
    { "diag_tag", 'I' },
130
    { "diag_tq", 'g' },
131
    { "diag_type", 'd' },
132
    { "filename", 'Q' },
133
    { "linkinfo", 'L' },
134
    { "sourcemark", 'M' },
135
    { "version", 'V' },
136
 
137
    /* New diagnostic sorts */
138
    { "dg", 'G' },
139
    { "dg_accessibility", 'o' },
140
    { "dg_append", 'H' },
141
    { "dg_bound", 'w' },
142
    { "dg_classmem", 'z' },
143
    { "dg_class_base", 'y' },
144
    { "dg_compilation", 'C' },
145
    { "dg_dim", 'O' },
146
    { "dg_discrim", 'K' },
147
    { "dg_enum", 'E' },
148
    { "dg_field", 'R' },
149
    { "dg_filename", 'U' },
150
    { "dg_idname", 'Y' },
151
    { "dg_macro", 'Z' },
152
    { "dg_name", 'h' },
153
    { "dg_namelist", 'k' },
154
    { "dg_param", 'p' },
155
    { "dg_param_mode", 0 },
156
    { "dg_qualifier", 0 },
157
    { "dg_sourcepos", 'W' },
158
    { "dg_tag", 'J' },
159
    { "dg_type", 0 },
160
    { "dg_variant", 0 },
161
    { "dg_varpart", 0 },
162
    { "dg_virtuality", 0 }
7 7u83 163
};
2 7u83 164
 
165
#define NO_BUILTIN_SORTS	6
7 7u83 166
#define NO_SORTS		array_size(sort_names)
2 7u83 167
 
168
 
169
/*
170
    LIST OF ALL SORTS
171
 
172
    A list of all sorts (in alphabetical order) is maintained.
173
*/
174
 
7 7u83 175
static LIST(SORT)all_sorts = NULL_list(SORT);
2 7u83 176
 
177
 
178
/*
179
    DEFINE A SORT
180
 
181
    This routine defines the sort s to be info.
182
*/
183
 
7 7u83 184
static void
185
define_sort(SORT s, SORT_INFO info, int code)
2 7u83 186
{
7 7u83 187
    static int next_code = 1;
188
    SORT_INFO old = DEREF_info(sort_info(s));
189
    if (!IS_NULL_info(old)) {
190
	string nm = DEREF_string(sort_name(s));
191
	error(ERROR_SERIOUS, "Sort '%s' already defined", nm);
2 7u83 192
    }
7 7u83 193
    COPY_info(sort_info(s), info);
194
    if (code == 0) code = next_code++;
195
    COPY_int(sort_code(s), code);
196
    return;
2 7u83 197
}
198
 
199
 
200
/*
201
    FIND A SORT
202
 
203
    This routine looks up a sort named nm, creating it if it does not
204
    already exist if create is true.
205
*/
206
 
7 7u83 207
SORT
208
find_sort(string nm, int create)
2 7u83 209
{
7 7u83 210
    SORT s;
211
    string cnm;
212
    SORT_INFO info = NULL_info;
213
    LIST(SORT)p = all_sorts;
214
    LIST(SORT)q = NULL_list(SORT);
215
    while (!IS_NULL_list(p)) {
216
	int cmp;
217
	string n;
218
	s = DEREF_sort(HEAD_list(p));
219
	n = DEREF_string(sort_name(s));
220
	cmp = strcmp(n, nm);
221
	if (cmp == 0) return(s);
222
	if (cmp > 0) break;
223
	q = p;
224
	p = TAIL_list(p);
2 7u83 225
    }
7 7u83 226
    cnm = to_capitals(nm);
227
    MAKE_sort_basic(nm, cnm, NULL, NULL, 0, 0, 0, 0, info, s);
228
    if (!create) {
229
	error(ERROR_SERIOUS, "Sort '%s' not defined", nm);
230
	MAKE_info_builtin(nm, info);
231
	define_sort(s, info, 0);
2 7u83 232
    }
7 7u83 233
    CONS_sort(s, p, p);
234
    if (IS_NULL_list(q)) {
235
	all_sorts = p;
2 7u83 236
    } else {
7 7u83 237
	COPY_list(PTR_TAIL_list(q), p);
2 7u83 238
    }
7 7u83 239
    return(s);
2 7u83 240
}
241
 
242
 
243
/*
244
    MARK A CONSTRUCT AS USED
245
 
246
    This routine marks the parameter sorts of the constructs c with the
247
    value m.
248
*/
249
 
7 7u83 250
void
251
mark_construct(CONSTRUCT c, int m)
2 7u83 252
{
7 7u83 253
    if (!IS_NULL_cons(c)) {
254
	LIST(PARAMETER)p = DEREF_list(cons_pars(c));
255
	while (!IS_NULL_list(p)) {
256
	    PARAMETER a = DEREF_par(HEAD_list(p));
257
	    SORT s = DEREF_sort(par_type(a));
258
	    mark_sort(s, m);
259
	    p = TAIL_list(p);
2 7u83 260
	}
261
    }
7 7u83 262
    return;
2 7u83 263
}
264
 
265
 
266
/*
267
    MARK A SORT AS USED
268
 
269
    This routine marks the sort s and all its constructs with the value m.
270
*/
271
 
7 7u83 272
void
273
mark_sort(SORT s, int m)
2 7u83 274
{
7 7u83 275
    int mark = DEREF_int(sort_mark(s));
276
    if (mark != m) {
277
	SORT_INFO info = DEREF_info(sort_info(s));
278
	COPY_int(sort_mark(s), m);
279
	if (!IS_NULL_info(info)) {
280
	    switch (TAG_info(info)) {
281
		case info_basic_tag: {
282
		    LIST(CONSTRUCT)p;
283
		    p = DEREF_list(info_basic_cons(info));
284
		    while (!IS_NULL_list(p)) {
285
			CONSTRUCT c = DEREF_cons(HEAD_list(p));
286
			mark_construct(c, m);
287
			p = TAIL_list(p);
2 7u83 288
		    }
7 7u83 289
		    break;
2 7u83 290
		}
7 7u83 291
		case info_dummy_tag: {
292
		    CONSTRUCT c = DEREF_cons(info_dummy_cons(info));
293
		    mark_construct(c, m);
294
		    break;
2 7u83 295
		}
7 7u83 296
		case info_clist_tag:
297
		case info_slist_tag:
298
		case info_option_tag: {
299
		    SORT p = DEREF_sort(info_clist_etc_arg(info));
300
		    mark_sort(p, m);
301
		    break;
2 7u83 302
		}
303
	    }
304
	}
305
    }
7 7u83 306
    return;
2 7u83 307
}
308
 
309
 
310
/*
311
    MARK ALL SORTS AS USED
312
 
313
    This routine marks all sorts with the value m.
314
*/
315
 
7 7u83 316
void
317
mark_all_sorts(int m)
2 7u83 318
{
7 7u83 319
    LIST(SORT)p = all_sorts;
320
    while (!IS_NULL_list(p)) {
321
	SORT s = DEREF_sort(HEAD_list(p));
322
	COPY_int(sort_mark(s), m);
323
	p = TAIL_list(p);
2 7u83 324
    }
7 7u83 325
    return;
2 7u83 326
}
327
 
328
 
329
/*
330
    DOES A STRING HAVE A GIVEN ENDING?
331
 
332
    This routine checks whether the string s ends in the string e.  If so
333
    it returns a copy of s with this ending removed.  Otherwise it returns
334
    the null string.
335
*/
336
 
7 7u83 337
string
338
ends_in(string s, string e)
2 7u83 339
{
7 7u83 340
    unsigned n = (unsigned)strlen(s);
341
    unsigned m = (unsigned)strlen(e);
342
    if (n >= m) {
343
	unsigned d = n - m;
344
	if (streq(s + d, e)) {
345
	    s = xstrcpy(s);
346
	    s[d] = 0;
347
	    return(s);
2 7u83 348
	}
349
    }
7 7u83 350
    return(NULL);
2 7u83 351
}
352
 
353
 
354
/*
355
    CONVERT A STRING TO CAPITALS
356
 
357
    This routine returns a copy of the string s with all the lower case
358
    letters converted to upper case.
359
*/
360
 
7 7u83 361
string
362
to_capitals(string s)
2 7u83 363
{
7 7u83 364
    char c;
365
    string t;
366
    s = xstrcpy(s);
367
    t = s;
368
    while (c = *t, c != 0) {
369
	if (c >= 'a' && c <= 'z') {
370
	    *t = (char)('A' + (c - 'a'));
2 7u83 371
	}
7 7u83 372
	t++;
2 7u83 373
    }
7 7u83 374
    return(s);
2 7u83 375
}
376
 
377
 
378
/*
379
    DEFINE A BASIC SORT
380
 
381
    This routine defines the basic sort s to have b bits (extended if e
382
    is true) and constructs p.
383
*/
384
 
7 7u83 385
void
386
basic_sort(SORT s, unsigned b, unsigned e, LIST(CONSTRUCT)p)
2 7u83 387
{
7 7u83 388
    int code = 0;
389
    SORT_INFO info;
390
    string n = DEREF_string(sort_name(s));
391
    if (b == 0 && e == 0 && LENGTH_list(p) == 1) {
2 7u83 392
	/* Dummy sort */
7 7u83 393
	CONSTRUCT c = DEREF_cons(HEAD_list(p));
394
	MAKE_info_dummy(n, c, info);
395
	code = 'F';
2 7u83 396
    } else {
7 7u83 397
	int i;
398
	for (i = NO_BUILTIN_SORTS; i < NO_SORTS; i++) {
399
	    if (streq(n, sort_names[i].name)) {
400
		code = sort_names[i].code;
401
		break;
2 7u83 402
	    }
403
	}
7 7u83 404
	MAKE_info_basic(n, b, e, 0, p, NULL_cons, info);
2 7u83 405
    }
7 7u83 406
    define_sort(s, info, code);
407
    return;
2 7u83 408
}
409
 
410
 
411
/*
412
    CREATE A CONSTRUCT
413
 
414
    This routine creates a construct named nm with result sort s, parameter
415
    sorts p and encoding e.
416
*/
417
 
7 7u83 418
CONSTRUCT
419
make_construct(string nm, unsigned e, SORT s, LIST(PARAMETER)p)
2 7u83 420
{
7 7u83 421
    CONSTRUCT c;
422
    unsigned kind = KIND_simple;
423
    if (ends_in(nm, "_apply_token")) kind = KIND_token;
424
    if (ends_in(nm, "_cond")) kind = KIND_cond;
425
    MAKE_cons_basic(nm, e, s, p, kind, c);
426
    return(c);
2 7u83 427
}
428
 
429
 
430
/*
431
    DEFINE A COMPOUND SORT
432
 
433
    This routine defines the compound sort s with standard suffix suff
434
    and sort type tag.
435
*/
436
 
7 7u83 437
void
438
compound_sort(SORT s, string suff, unsigned tag, int code)
2 7u83 439
{
7 7u83 440
    string nm = DEREF_string(sort_name(s));
441
    string snm = ends_in(nm, suff);
442
    if (snm) {
443
	SORT_INFO info;
444
	SORT t = find_sort(snm, 1);
445
	MAKE_info_clist_etc(tag, nm, t, info);
446
	define_sort(s, info, code);
2 7u83 447
    } else {
7 7u83 448
	error(ERROR_SERIOUS, "Sort '%s' doesn't end in '%s'", nm, suff);
2 7u83 449
    }
7 7u83 450
    return;
2 7u83 451
}
452
 
453
 
454
/*
455
    FIND A CONSTRUCT
456
 
457
    This routine searches for a construct named c in the sort s.
458
*/
459
 
7 7u83 460
CONSTRUCT
461
find_construct(SORT s, string c)
2 7u83 462
{
7 7u83 463
    SORT_INFO info = DEREF_info(sort_info(s));
464
    if (!IS_NULL_info(info) && IS_info_basic(info)) {
465
	LIST(CONSTRUCT)p = DEREF_list(info_basic_cons(info));
466
	while (!IS_NULL_list(p)) {
467
	    CONSTRUCT a = DEREF_cons(HEAD_list(p));
468
	    string b = DEREF_string(cons_name(a));
469
	    if (streq(b, c)) return(a);
470
	    p = TAIL_list(p);
2 7u83 471
	}
472
    }
7 7u83 473
    return(NULL_cons);
2 7u83 474
}
475
 
476
 
477
/*
478
    SET A CONSTRUCT KIND
479
 
480
    This routine sets the kind of the construct c of sort s to be kind.
481
*/
482
 
7 7u83 483
void
484
set_special(SORT s, string c, unsigned kind)
2 7u83 485
{
7 7u83 486
    CONSTRUCT a = find_construct(s, c);
487
    if (!IS_NULL_cons(a)) {
488
	COPY_unsigned(cons_kind(a), kind);
2 7u83 489
    } else {
7 7u83 490
	string nm = DEREF_string(sort_name(s));
491
	error(ERROR_SERIOUS, "Can't find construct '%s' for sort '%s'",
492
		c, nm);
2 7u83 493
    }
7 7u83 494
    return;
2 7u83 495
}
496
 
497
 
498
/*
499
    FIND A CONSTRUCT OF A GIVEN KIND
500
 
501
    This routine searches for a construct of the sort s of the given kind.
502
*/
503
 
7 7u83 504
CONSTRUCT
505
get_special(SORT s, unsigned kind)
2 7u83 506
{
7 7u83 507
    SORT_INFO info = DEREF_info(sort_info(s));
508
    if (!IS_NULL_info(info) && IS_info_basic(info)) {
509
	LIST(CONSTRUCT)p = DEREF_list(info_basic_cons(info));
510
	while (!IS_NULL_list(p)) {
511
	    CONSTRUCT a = DEREF_cons(HEAD_list(p));
512
	    unsigned b = DEREF_unsigned(cons_kind(a));
513
	    if (b == kind) return(a);
514
	    p = TAIL_list(p);
2 7u83 515
	}
516
    }
7 7u83 517
    return(NULL_cons);
2 7u83 518
}
519
 
520
 
521
/*
522
    DEFINE THE BUILT-IN SORTS
523
 
524
    This routine defines the built-in sorts.
525
*/
526
 
7 7u83 527
void
528
builtin_sorts(void)
2 7u83 529
{
7 7u83 530
    int i;
531
    for (i = 0; i < NO_BUILTIN_SORTS; i++) {
532
	SORT_INFO info;
533
	char *nm = sort_names[i].name;
534
	SORT s = find_sort(nm, 1);
535
	MAKE_info_builtin(nm, info);
536
	define_sort(s, info, sort_names[i].code);
2 7u83 537
    }
7 7u83 538
    return;
2 7u83 539
}
540
 
541
 
542
/*
543
    CHECK THE LIST OF ALL SORTS
544
 
545
    This routine checks the list of all sorts for undefined sorts,
546
    returning the reordered list.
547
*/
548
 
7 7u83 549
LIST(SORT)
550
check_sorts(void)
2 7u83 551
{
7 7u83 552
    LIST(SORT)p = all_sorts;
553
    while (!IS_NULL_list(p)) {
554
	SORT s = DEREF_sort(HEAD_list(p));
555
	SORT_INFO info = DEREF_info(sort_info(s));
556
	if (IS_NULL_info(info)) {
557
	    string nm = DEREF_string(sort_name(s));
558
	    error(ERROR_SERIOUS, "Sort '%s' not defined", nm);
559
	    MAKE_info_builtin(nm, info);
560
	    define_sort(s, info, 0);
2 7u83 561
	}
7 7u83 562
	if (IS_info_basic(info)) {
563
	    unsigned m = 0;
564
	    LIST(CONSTRUCT)q = DEREF_list(info_basic_cons(info));
565
	    while (!IS_NULL_list(q)) {
566
		CONSTRUCT a = DEREF_cons(HEAD_list(q));
567
		unsigned n = DEREF_unsigned(cons_encode(a));
568
		if (n > m) m = n;
569
		q = TAIL_list(q);
2 7u83 570
	    }
7 7u83 571
	    COPY_unsigned(info_basic_max(info), m);
2 7u83 572
	}
7 7u83 573
	p = TAIL_list(p);
2 7u83 574
    }
7 7u83 575
    return(all_sorts);
2 7u83 576
}
577
 
578
 
579
/*
580
    FIND FOREIGN SORTS
581
 
582
    This routine finds all the foreign sorts.
583
*/
584
 
7 7u83 585
LIST(LINKAGE)
586
foreign_sorts(void)
2 7u83 587
{
7 7u83 588
    unsigned e = 0;
589
    LIST(SORT)p = all_sorts;
590
    LIST(LINKAGE)q = NULL_list(LINKAGE);
591
    LIST(PARAMETER)pars = NULL_list(PARAMETER);
592
    SORT t = find_sort("sortname", 0);
593
    SORT_INFO info = DEREF_info(sort_info(t));
594
    if (IS_info_basic(info)) {
595
	e = DEREF_unsigned(info_basic_max(info));
2 7u83 596
    }
7 7u83 597
    while (!IS_NULL_list(p)) {
598
	SORT s = DEREF_sort(HEAD_list(p));
599
	info = DEREF_info(sort_info(s));
600
	if (IS_info_basic(info)) {
601
	    string nm = DEREF_string(sort_name(s));
602
	    CONSTRUCT c = get_special(s, KIND_token);
603
	    if (!IS_NULL_cons(c)) {
2 7u83 604
		/* Sort can be tokenised */
7 7u83 605
		string snm = nm;
606
		if (streq(nm, "alignment")) {
607
		    snm = "alignment_sort";
2 7u83 608
		}
7 7u83 609
		c = find_construct(t, snm);
610
		if (IS_NULL_cons(c)) {
2 7u83 611
		    /* Doesn't have a sort name */
7 7u83 612
		    LINKAGE a;
613
		    if (streq(nm, "diag_type")) {
614
			snm = "diag_type";
615
		    } else if (streq(nm, "filename")) {
616
			snm = "~diag_file";
2 7u83 617
		    } else {
7 7u83 618
			snm = to_capitals(nm);
2 7u83 619
		    }
7 7u83 620
		    MAKE_cons_basic(snm, ++e, t, pars, KIND_foreign, c);
621
		    MAKE_link_basic(snm, s, a);
622
		    CONS_link(a, q, q);
2 7u83 623
		}
624
	    } else {
7 7u83 625
		MAKE_cons_basic(nm, ++e, t, pars, KIND_dummy, c);
2 7u83 626
	    }
7 7u83 627
	    COPY_cons(info_basic_sortname(info), c);
2 7u83 628
	}
7 7u83 629
	p = TAIL_list(p);
2 7u83 630
    }
7 7u83 631
    q = REVERSE_list(q);
632
    return(q);
2 7u83 633
}
634
 
635
 
636
/*
637
    FIND A PARAMETER
638
 
639
    This routine returns the nth parameter of the construct c.
640
*/
641
 
7 7u83 642
PARAMETER
643
find_param(CONSTRUCT c, unsigned n)
2 7u83 644
{
7 7u83 645
    LIST(PARAMETER)p = DEREF_list(cons_pars(c));
646
    while (n) {
647
	if (IS_NULL_list(p)) {
648
	    string nm = DEREF_string(cons_name(c));
649
	    error(ERROR_SERIOUS, "Bad parameter number for '%s'", nm);
650
	    return(NULL_par);
2 7u83 651
	}
7 7u83 652
	p = TAIL_list(p);
653
	n--;
2 7u83 654
    }
7 7u83 655
    return(DEREF_par(HEAD_list(p)));
2 7u83 656
}