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
/*** rule-lre.c --- Left recursion elimination routines.
62
 *
63
 ** Author: Steve Folkes <smf@hermes.mod.uk>
64
 *
65
 *** Commentary:
66
 *
67
 * This file implements the SID left recursion elimination routines.
68
 *
69
 * The generic cycle detection functions defined in the file ``rule.c'' are
70
 * used to find left cycles in the grammar (this is done by the function
71
 * ``grammar_remove_left_recursion'' in the file "grammar.c").  If the
72
 * functions find any such cycles, the function ``rule_remove_left_cycle'' is
73
 * called on the group of productions to remove the left recursion.  Left
74
 * recursion is transformed into right recursion in the manner described
75
 * below.
76
 *
77
 * Given a set of productions, expressed as
78
 *
79
 *	Ai = Aj Bji, Ci;
80
 *
81
 * this can be transformed into
82
 *
83
 *	Ai  = Cj Xji;
84
 *	Xij = Yij, Bik Xkj;
85
 *
86
 * Where the rules "Xij" are generated automatically, and Yij is the identity
87
 * operation if i = j, or an error otherwise.  The generated rule has the same
88
 * parameters and results, which are the results of "Ai" augmented with those
89
 * parameters of "Ai" that are used by "Bji".
90
 *
91
 * In order for the transform to work, all of the "Ai" must have the same
92
 * parameter and result types, and the same exception handler.  Also, the
93
 * initial call to "Aj" must take exactly the formals of "Ai" as parameters.
94
 * This is checked by the ``rule_check_cycle_types'' function, which also
95
 * ensures that names are consistent throughout all of the rules.  The
96
 * transform is performed by the function ``rule_left_cycle_general_case''.
97
 *
98
 * In addition to the general case, two special cases are looked for.  The
99
 * first of these transforms:
100
 *
101
 *	A = A B, $;
102
 *
103
 * into
104
 *
105
 *	A = B A, $;
106
 *
107
 * whilst the second transforms:
108
 *
109
 *	A = A C B, B;
110
 *
111
 * into
112
 *
113
 *	A = B X;
114
 *	X = C A;
115
 *
116
 * These special cases are handled by the ``rule_left_cycle_special_case''
117
 * function.
118
 *
119
 *** Change Log:
120
 * $Log: rule-lre.c,v $
121
 * Revision 1.1.1.1  1998/01/17  15:57:47  release
122
 * First version to be checked into rolling release.
123
 *
124
 * Revision 1.3  1995/02/10  16:29:42  smf
125
 * Fixed bugs "CR95_111.sid-inline-no-var-check" and "CR95_112.sid-lre-var-call".
126
 *
127
 * Revision 1.2  1994/12/15  09:58:41  smf
128
 * Brought into line with OSSG C Coding Standards Document, as per
129
 * "CR94_178.sid+tld-update".
130
 *
131
 * Revision 1.1.1.1  1994/07/25  16:04:39  smf
132
 * Initial import of SID 1.8 non shared files.
133
 *
134
**/
135
 
136
/****************************************************************************/
137
 
138
#include "rule.h"
139
#include "dstring.h"
140
#include "gen-errors.h"
141
 
142
/*--------------------------------------------------------------------------*/
143
 
144
typedef struct MatrixEntryT {
145
    AltP			alt;
146
    BoolT			inited;
147
    TypeTupleT			param;
148
} MatrixEntryT, *MatrixEntryP;
149
 
150
typedef struct VectorEntryT {
151
    BoolT			empty_alt;
152
    AltP			alt;
153
    BoolT			inited;
154
    TypeTupleT			param;
155
} VectorEntryT, *VectorEntryP;
156
 
157
/*--------------------------------------------------------------------------*/
158
 
159
static MatrixEntryP
7 7u83 160
rule_left_cycle_matrix(unsigned size)
2 7u83 161
{
7 7u83 162
    static MatrixEntryP array      = NIL(MatrixEntryP);
2 7u83 163
    static unsigned     array_size = 0;
164
    unsigned            i;
165
 
166
    if (size > array_size) {
7 7u83 167
	DEALLOCATE(array);
168
	array      = ALLOCATE_VECTOR(MatrixEntryT, size);
2 7u83 169
	array_size = size;
170
    }
7 7u83 171
    for (i = 0; i < size; i++) {
172
	array[i].alt    = NIL(AltP);
173
	array[i].inited = FALSE;
2 7u83 174
    }
7 7u83 175
    return(array);
2 7u83 176
}
177
 
178
static VectorEntryP
7 7u83 179
rule_left_cycle_vector(unsigned size)
2 7u83 180
{
7 7u83 181
    static VectorEntryP array      = NIL(VectorEntryP);
2 7u83 182
    static unsigned     array_size = 0;
183
    unsigned            i;
184
 
185
    if (size > array_size) {
7 7u83 186
	DEALLOCATE(array);
187
	array      = ALLOCATE_VECTOR(VectorEntryT, size);
2 7u83 188
	array_size = size;
189
    }
7 7u83 190
    for (i = 0; i < size; i++) {
191
	array[i].empty_alt = FALSE;
192
	array[i].alt       = NIL(AltP);
193
	array[i].inited    = FALSE;
2 7u83 194
    }
7 7u83 195
    return(array);
2 7u83 196
}
197
 
198
static void
7 7u83 199
rule_destroy_cycle_matrix(MatrixEntryP matrix, unsigned size)
2 7u83 200
{
201
    unsigned i;
202
 
7 7u83 203
    for (i = 0; i < size; i++) {
204
	if (matrix[i].inited) {
205
	    AltP alt = matrix[i].alt;
2 7u83 206
 
207
	    while (alt) {
7 7u83 208
		alt = alt_deallocate(alt);
2 7u83 209
	    }
7 7u83 210
	    types_destroy(&(matrix[i].param));
2 7u83 211
	}
212
    }
213
}
214
 
215
static void
7 7u83 216
rule_destroy_cycle_vector(VectorEntryP vector, unsigned size)
2 7u83 217
{
218
    unsigned i;
219
 
7 7u83 220
    for (i = 0; i < size; i++) {
221
	if (vector[i].inited) {
222
	    AltP alt = vector[i].alt;
2 7u83 223
 
224
	    while (alt) {
7 7u83 225
		alt = alt_deallocate(alt);
2 7u83 226
	    }
7 7u83 227
	    types_destroy(&(vector[i].param));
2 7u83 228
	}
229
    }
230
}
231
 
232
/*--------------------------------------------------------------------------*/
233
 
234
static ItemP
7 7u83 235
rule_find_suffix(ItemP rec_item, ItemP non_rec_item)
2 7u83 236
{
237
    ItemP    tmp_rec_item     = rec_item;
238
    ItemP    tmp_non_rec_item = non_rec_item;
239
    unsigned diff             = 0;
240
 
241
    while (tmp_rec_item && tmp_non_rec_item) {
7 7u83 242
	tmp_rec_item     = item_next(tmp_rec_item);
243
	tmp_non_rec_item = item_next(tmp_non_rec_item);
2 7u83 244
    }
245
    while (tmp_rec_item) {
7 7u83 246
	diff++;
247
	tmp_rec_item = item_next(tmp_rec_item);
2 7u83 248
    }
249
    if (diff == 0) {
7 7u83 250
	return(NIL(ItemP));
2 7u83 251
    }
252
    do {
7 7u83 253
	rec_item = item_next(rec_item);
254
    } while (--diff);
2 7u83 255
    tmp_rec_item     = rec_item;
256
    tmp_non_rec_item = non_rec_item;
257
    while (tmp_rec_item && tmp_non_rec_item) {
7 7u83 258
	if (item_entry(tmp_rec_item) != item_entry(tmp_non_rec_item)) {
259
	    return(NIL(ItemP));
2 7u83 260
	}
7 7u83 261
	tmp_rec_item     = item_next(tmp_rec_item);
262
	tmp_non_rec_item = item_next(tmp_non_rec_item);
2 7u83 263
    }
7 7u83 264
    ASSERT((tmp_rec_item == NIL(ItemP)) && (tmp_non_rec_item == NIL(ItemP)));
265
    return(rec_item);
2 7u83 266
}
267
 
268
static void
7 7u83 269
rule_renumber_item_list(ItemP item, TypeNTransP translator)
2 7u83 270
{
7 7u83 271
    ntrans_init(translator);
272
    for (; item; item = item_next(item)) {
273
	types_renumber(item_param(item), translator);
274
	types_renumber(item_result(item), translator);
2 7u83 275
    }
276
}
277
 
278
static BoolT
7 7u83 279
rule_compare_item_lists(ItemP rec_suffix, ItemP non_rec_item)
2 7u83 280
{
281
    while (rec_suffix) {
7 7u83 282
	ASSERT(non_rec_item);
283
	if (!((types_equal_numbers(item_param(rec_suffix),
284
				   item_param(non_rec_item))) &&
285
	      (types_equal_numbers(item_result(rec_suffix),
286
				   item_result(non_rec_item))))) {
287
	    return(FALSE);
2 7u83 288
	}
7 7u83 289
	rec_suffix   = item_next(rec_suffix);
290
	non_rec_item = item_next(non_rec_item);
2 7u83 291
    }
7 7u83 292
    ASSERT(non_rec_item == NIL(ItemP));
293
    return(TRUE);
2 7u83 294
}
295
 
296
static void
7 7u83 297
rule_left_cycle_special_case_2(RuleP rule, TableP table, AltP non_rec_alt,
298
			       AltP rec_alt, TypeTupleP param, ItemP rec_suffix)
2 7u83 299
{
7 7u83 300
    EntryP      entry    = table_add_generated_rule(table, TRUE);
301
    RuleP       new_rule = entry_get_rule(entry);
302
    ItemP       new_item = item_create(entry);
303
    ItemP       rec_item = alt_unlink_item_head(rec_alt);
304
    AltP        new_alt  = alt_create();
2 7u83 305
    AltP        handler;
306
    ItemP       item;
307
    TypeBTransT tmp_trans;
308
    TypeTupleT  result;
309
 
7 7u83 310
    rule_reinit(rule);
311
    alt_set_next(non_rec_alt, NIL(AltP));
312
    btrans_init(&tmp_trans);
313
    types_copy(&result, rule_result(rule));
314
    btrans_generate_names(&tmp_trans, &result, table);
315
    types_translate(&result, &tmp_trans);
316
    if ((handler = rule_get_handler(rule)) != NIL(AltP)) {
317
	ItemP handler_items = alt_item_head(handler);
2 7u83 318
 
7 7u83 319
	item_translate_list(handler_items, &tmp_trans);
2 7u83 320
    }
7 7u83 321
    btrans_destroy(&tmp_trans);
322
    types_assign(item_param(new_item), rule_result(rule));
323
    types_copy(item_result(new_item), &result);
324
    types_copy(rule_result(rule), &result);
325
    alt_add_item(non_rec_alt, new_item);
326
    rule_add_alt(rule, non_rec_alt);
327
    types_copy(rule_param(new_rule), item_result(rec_item));
328
    types_copy(rule_result(new_rule), &result);
329
   (void)item_deallocate(rec_item);
330
    while (item = alt_item_head(rec_alt), item != rec_suffix) {
331
	alt_add_item(new_alt, alt_unlink_item_head(rec_alt));
2 7u83 332
    }
7 7u83 333
   (void)alt_deallocate(rec_alt);
334
    new_item = item_create(rule_entry(rule));
2 7u83 335
    if (param) {
7 7u83 336
	types_assign(item_param(new_item), param);
2 7u83 337
    } else {
7 7u83 338
	types_copy(item_param(new_item), rule_param(new_rule));
2 7u83 339
    }
7 7u83 340
    types_assign(item_result(new_item), &result);
341
    alt_add_item(new_alt, new_item);
342
    rule_add_alt(new_rule, new_alt);
343
    if (types_equal_zero_tuple(rule_param(new_rule))) {
344
	rule_add_empty_alt(new_rule);
2 7u83 345
    } else {
7 7u83 346
	new_alt  = alt_create();
347
	new_item = item_create(table_add_rename(table));
348
	types_copy(item_param(new_item), rule_param(new_rule));
349
	types_copy(item_result(new_item), rule_result(new_rule));
350
	alt_add_item(new_alt, new_item);
351
	rule_add_alt(new_rule, new_alt);
2 7u83 352
    }
353
}
354
 
355
static BoolT
7 7u83 356
rule_left_cycle_special_case_1(RuleP rule, TableP table)
2 7u83 357
{
7 7u83 358
    AltP        rec_alt = rule_alt_head(rule);
2 7u83 359
    AltP        non_rec_alt;
360
    ItemP       rec_item;
361
    ItemP       rec_next;
362
    ItemP       rec_suffix;
363
    ItemP       non_rec_item;
364
    TypeTupleT  param;
365
    TypeNTransT rec_translator;
366
    TypeNTransT non_rec_translator;
367
 
7 7u83 368
    if (((non_rec_alt = alt_next(rec_alt)) == NIL(AltP)) ||
369
	(alt_next(non_rec_alt))) {
370
	return(FALSE);
2 7u83 371
    }
7 7u83 372
    if ((item_is_rule(non_rec_item = alt_item_head(non_rec_alt))) &&
373
	(entry_get_rule(item_entry(non_rec_item)) == rule)) {
2 7u83 374
	non_rec_alt  = rec_alt;
7 7u83 375
	rec_alt      = alt_next(rec_alt);
376
	non_rec_item = alt_item_head(non_rec_alt);
2 7u83 377
    }
7 7u83 378
    if ((item_is_rule(non_rec_item)) &&
379
	(entry_get_rule(item_entry(non_rec_item)) == rule)) {
380
	return(FALSE);
2 7u83 381
    }
7 7u83 382
    rec_item = alt_item_head(rec_alt);
383
    if (!((types_equal_names(rule_param(rule), item_param(rec_item))) &&
384
	  (types_equal(rule_param(rule), rule_result(rule))))) {
385
	return(FALSE);
2 7u83 386
    }
7 7u83 387
    rec_next = item_next(rec_item);
388
    if (item_names_used_in_list(rec_next, rule_param(rule))) {
389
	return(FALSE);
2 7u83 390
    }
7 7u83 391
    if ((rec_suffix = rule_find_suffix(rec_item, non_rec_item)) ==
392
	NIL(ItemP)) {
393
	return(FALSE);
2 7u83 394
    }
395
    if ((rec_suffix != rec_next) &&
7 7u83 396
	(item_names_used_in_list(rec_suffix, item_result(rec_item)))) {
397
	return(FALSE);
2 7u83 398
    }
7 7u83 399
    rule_renumber_item_list(non_rec_item, &non_rec_translator);
400
    rule_renumber_item_list(rec_suffix, &rec_translator);
401
    if (!rule_compare_item_lists(rec_suffix, non_rec_item)) {
402
	ntrans_destroy(&non_rec_translator);
403
	ntrans_destroy(&rec_translator);
404
	return(FALSE);
2 7u83 405
    }
406
    if (rec_suffix == rec_next) {
7 7u83 407
	ntrans_destroy(&non_rec_translator);
408
	ntrans_destroy(&rec_translator);
409
	rule_left_cycle_special_case_2(rule, table, non_rec_alt, rec_alt,
410
				       NIL(TypeTupleP), rec_suffix);
2 7u83 411
    } else {
7 7u83 412
	types_compute_param_from_trans(&param, &non_rec_translator,
413
				       &rec_translator, rule_param(rule));
414
	ntrans_destroy(&non_rec_translator);
415
	ntrans_destroy(&rec_translator);
416
	rule_left_cycle_special_case_2(rule, table, non_rec_alt, rec_alt,
417
				       &param, rec_suffix);
2 7u83 418
    }
7 7u83 419
    return(TRUE);
2 7u83 420
}
421
 
422
static BoolT
7 7u83 423
rule_left_cycle_special_case(RuleP rule, TableP table)
2 7u83 424
{
7 7u83 425
    if (rule_has_empty_alt(rule)) {
426
	AltP  alt = rule_alt_head(rule);
2 7u83 427
	ItemP item;
428
 
7 7u83 429
	if ((alt == NIL(AltP)) || (alt_next(alt) != NIL(AltP))) {
430
	    return(FALSE);
2 7u83 431
	}
7 7u83 432
	item = alt_unlink_item_head(alt);
433
	alt_add_item(alt, item);
434
	return(TRUE);
2 7u83 435
    } else {
7 7u83 436
	return(rule_left_cycle_special_case_1(rule, table));
2 7u83 437
    }
438
}
439
 
440
/*--------------------------------------------------------------------------*/
441
 
442
static BoolT
7 7u83 443
rule_check_non_locals(RuleP this_rule, RuleP rule_list, unsigned real_size)
2 7u83 444
{
7 7u83 445
    NStringP scope  = rule_maximum_scope(this_rule);
446
    unsigned length = nstring_length(scope);
2 7u83 447
    RuleP    rule;
448
 
7 7u83 449
    for (rule = rule_list; rule; rule = rule_get_next_in_reverse_dfs(rule)) {
450
	KeyP key = entry_key(rule_entry(rule));
2 7u83 451
 
7 7u83 452
	if ((rule != this_rule) && key_is_string(key)) {
453
	    NStringP string = key_get_string(key);
2 7u83 454
 
7 7u83 455
	    if (!(nstring_is_prefix(string, scope) ||
456
		  (nstring_is_prefix(scope, string) &&
457
		   ((nstring_length(string) + 2) == length)))) {
458
		E_out_of_scope_non_local(this_rule, rule, rule_list);
459
		return(FALSE);
2 7u83 460
	    }
461
	}
462
    }
7 7u83 463
    if (non_local_list_is_empty(rule_non_locals(this_rule)) ||
2 7u83 464
	(real_size == 1)) {
7 7u83 465
	return(TRUE);
2 7u83 466
    } else {
7 7u83 467
	E_left_recursion_nl_entry(this_rule, rule_list);
468
	return(FALSE);
2 7u83 469
    }
470
}
471
 
472
static BoolT
7 7u83 473
rule_check_alt_cycle_types(RuleP rule, RuleP rule_list, AltP alt,
474
			   BoolT need_check, TypeBTransP translator1,
475
			   TypeBTransP translator2, TableP table,
476
			   BoolP generate_ref)
2 7u83 477
{
7 7u83 478
    ItemP item = alt_item_head(alt);
2 7u83 479
 
7 7u83 480
    item_translate_list(item, translator1);
481
    if (item_is_rule(item)) {
482
	RuleP item_rule = entry_get_rule(item_entry(item));
2 7u83 483
 
7 7u83 484
	if (rule_get_cycle_index(item_rule) != 0) {
2 7u83 485
	    TypeTupleT result_intersect;
486
 
7 7u83 487
	    if (need_check && (!types_equal_names(rule_param(rule),
488
						  item_param(item)))) {
489
		btrans_destroy(translator1);
490
		btrans_destroy(translator2);
491
		E_left_recursion_name_mismatch(rule_list);
492
		return(FALSE);
2 7u83 493
	    }
494
/* If a result identifier is returned by the left recursive call, it is
495
 * necessary to rename that return value, and use an identity afterwards to
496
 * rename it.
497
 **/
7 7u83 498
	    types_init(&result_intersect);
499
	    types_compute_intersection(&result_intersect, rule_result(rule),
500
				       item_result(item));
501
	    if (!types_equal_zero_tuple(&result_intersect)) {
502
		EntryP      new_entry = table_add_rename(table);
503
		ItemP       new_item  = item_create(new_entry);
2 7u83 504
		TypeBTransT tmp_trans;
505
		TypeTupleT  tmp_tuple;
506
 
7 7u83 507
		btrans_init(&tmp_trans);
508
		types_copy(&tmp_tuple, &result_intersect);
509
		btrans_generate_names(&tmp_trans, &tmp_tuple, table);
510
		types_translate(&tmp_tuple, &tmp_trans);
511
		types_translate(item_result(item), &tmp_trans);
512
		btrans_destroy(&tmp_trans);
513
		types_assign(item_param(new_item), &tmp_tuple);
514
		types_assign(item_result(new_item), &result_intersect);
515
		item_set_next(new_item, item_next(item));
516
		item_set_next(item, new_item);
2 7u83 517
	    } else {
7 7u83 518
		types_destroy(&result_intersect);
2 7u83 519
	    }
520
	    if (*generate_ref) {
7 7u83 521
		btrans_generate_names(translator2, item_result(item), table);
2 7u83 522
		*generate_ref = FALSE;
523
	    } else {
7 7u83 524
		btrans_regenerate_names(translator2, item_result(item));
2 7u83 525
	    }
7 7u83 526
	    types_translate(item_result(item), translator2);
527
	    item_translate_list(item_next(item), translator2);
2 7u83 528
	}
529
    }
7 7u83 530
    return(TRUE);
2 7u83 531
}
532
 
533
static BoolT
7 7u83 534
rule_check_cycle_types(RuleP rule_list, EntryP predicate_id,
535
		       unsigned real_size, TableP table)
2 7u83 536
{
7 7u83 537
    TypeTupleP  param    = rule_param(rule_list);
538
    TypeTupleP  result   = rule_result(rule_list);
539
    AltP        handler  = rule_get_handler(rule_list);
2 7u83 540
    BoolT       generate = TRUE;
541
    RuleP       rule;
542
    TypeBTransT translator1;
543
    TypeBTransT translator2;
544
 
7 7u83 545
    rule_renumber(rule_list, TRUE, predicate_id);
546
    if (!rule_check_non_locals(rule_list, rule_list, real_size)) {
547
	return(FALSE);
2 7u83 548
    }
7 7u83 549
    for (rule = rule_get_next_in_reverse_dfs(rule_list); rule;
550
	 rule = rule_get_next_in_reverse_dfs(rule)) {
551
	if (!((types_equal(param, rule_param(rule))) &&
552
	      (types_equal(result, rule_result(rule))))) {
553
	    E_left_recursion_type_mismatch(rule_list);
554
	    return(FALSE);
2 7u83 555
	}
7 7u83 556
	rule_renumber(rule, TRUE, predicate_id);
557
	if (!alt_equal(handler, rule_get_handler(rule))) {
558
	    E_left_rec_handler_mismatch(rule_list);
559
	    return(FALSE);
2 7u83 560
	}
7 7u83 561
	if (!rule_check_non_locals(rule, rule_list, real_size)) {
562
	    return(FALSE);
2 7u83 563
	}
564
    }
7 7u83 565
    btrans_init(&translator1);
566
    btrans_init(&translator2);
567
    for (rule = rule_list; rule; rule = rule_get_next_in_reverse_dfs(rule)) {
2 7u83 568
	AltP alt;
569
 
570
	if (rule == rule_list) {
7 7u83 571
	    btrans_generate_names(&translator1, rule_param(rule), table);
2 7u83 572
	} else {
7 7u83 573
	    btrans_regenerate_names(&translator1, rule_param(rule));
2 7u83 574
	}
7 7u83 575
	types_translate(rule_param(rule), &translator1);
576
	if ((alt = rule_get_handler(rule)) != NIL(AltP)) {
577
	   (void)rule_check_alt_cycle_types(rule, rule_list, alt, FALSE,
578
					    &translator1, &translator2, table,
579
					    &generate);
2 7u83 580
	}
7 7u83 581
	for (alt = rule_alt_head(rule); alt; alt = alt_next(alt)) {
582
	    if (!rule_check_alt_cycle_types(rule, rule_list, alt, TRUE,
583
					    &translator1, &translator2, table,
584
					    &generate)) {
585
		return(FALSE);
2 7u83 586
	    }
587
	}
588
    }
7 7u83 589
    btrans_destroy(&translator1);
590
    btrans_destroy(&translator2);
591
    return(TRUE);
2 7u83 592
}
593
 
594
static void
7 7u83 595
rule_compute_param_subset(RuleP rule_list, TypeTupleP subset)
2 7u83 596
{
597
    RuleP rule;
598
 
7 7u83 599
    types_init(subset);
600
    for (rule = rule_list; rule; rule = rule_get_next_in_reverse_dfs(rule)) {
601
	TypeTupleP param = rule_param(rule);
2 7u83 602
	AltP       alt;
603
 
7 7u83 604
	for (alt = rule_alt_head(rule); alt; alt = alt_next(alt)) {
605
	    ItemP item = alt_item_head(alt);
2 7u83 606
 
7 7u83 607
	    if (item_is_rule(item)) {
608
		RuleP item_rule = entry_get_rule(item_entry(item));
2 7u83 609
 
7 7u83 610
		if (rule_get_cycle_index(item_rule) != 0) {
611
		    for (item = item_next(item); item;
612
			 item = item_next(item)) {
613
			types_compute_intersection(subset, param,
614
						   item_param(item));
2 7u83 615
		    }
616
		}
617
	    }
618
	}
619
    }
620
}
621
 
622
static void
7 7u83 623
rule_left_cycle_general_case_1(RuleP rule_list, unsigned size,
624
			       MatrixEntryP matrix, VectorEntryP vector,
625
			       TableP table, TypeTupleP gen_param,
626
			       TypeTupleP gen_result)
2 7u83 627
{
628
    unsigned    i               = 0;
629
    BoolT       generate        = TRUE;
630
    BoolT       generate_param  = TRUE;
631
    BoolT       generate_result = TRUE;
632
    RuleP       rule;
633
    TypeBTransT translator;
634
    TypeBTransT tmp_trans;
635
    TypeTupleT  dummy;
636
    TypeTupleT  param_subset;
637
 
7 7u83 638
    btrans_init(&translator);
639
    rule_compute_param_subset(rule_list, &param_subset);
640
    btrans_init(&tmp_trans);
641
    types_copy(&dummy, &param_subset);
642
    btrans_generate_names(&tmp_trans, &dummy, table);
643
    types_translate(&dummy, &tmp_trans);
644
    btrans_destroy(&tmp_trans);
2 7u83 645
    for (rule = rule_list; rule;
7 7u83 646
	 rule = rule_get_next_in_reverse_dfs(rule), i++) {
647
	AltP       alt = rule_alt_head(rule);
2 7u83 648
	AltP       handler;
649
	TypeTupleT old_result;
650
 
7 7u83 651
	types_copy(&old_result, rule_result(rule));
2 7u83 652
	if (generate) {
7 7u83 653
	    btrans_generate_names(&translator, rule_result(rule), table);
2 7u83 654
	    generate = FALSE;
655
	} else {
7 7u83 656
	    btrans_regenerate_names(&translator, rule_result(rule));
2 7u83 657
	}
7 7u83 658
	types_translate(rule_result(rule), &translator);
659
	if ((handler = rule_get_handler(rule)) != NIL(AltP)) {
660
	    ItemP handler_items = alt_item_head(handler);
2 7u83 661
 
7 7u83 662
	    item_translate_list(handler_items, &translator);
2 7u83 663
	}
7 7u83 664
	if (rule_has_empty_alt(rule)) {
665
	    vector[i].empty_alt = TRUE;
2 7u83 666
	}
667
	while (alt) {
7 7u83 668
	    ItemP    item    = alt_item_head(alt);
2 7u83 669
	    AltP     tmp_alt = alt;
670
	    RuleP    item_rule;
671
	    unsigned item_index;
672
 
7 7u83 673
	    alt = alt_next(alt);
674
	    if ((item_is_rule(item)) &&
675
		((item_rule = entry_get_rule(item_entry(item))),
676
		 ((item_index = rule_get_cycle_index(item_rule)) != 0))) {
677
		unsigned matrix_index = (size *(item_index - 1) + i);
2 7u83 678
 
7 7u83 679
		if (!(matrix[matrix_index].inited)) {
680
		    TypeTupleP param = &(matrix[matrix_index].param);
2 7u83 681
 
7 7u83 682
		    types_copy(param, &param_subset);
683
		    types_append_copy(param, &old_result);
684
		    matrix[matrix_index].inited = TRUE;
2 7u83 685
		}
686
		if (generate_param) {
7 7u83 687
		    ItemP item_head = alt_item_head(tmp_alt);
2 7u83 688
 
7 7u83 689
		    types_copy(gen_param, &param_subset);
690
		    types_append_copy(gen_param, item_result(item_head));
2 7u83 691
		    generate_param = FALSE;
692
		}
7 7u83 693
		(void)item_deallocate(alt_unlink_item_head(tmp_alt));
694
		alt_set_next(tmp_alt, matrix[matrix_index].alt);
695
		matrix[matrix_index].alt = tmp_alt;
2 7u83 696
	    } else {
7 7u83 697
		if (!(vector[i].inited)) {
698
		    TypeTupleP param = &(vector[i].param);
2 7u83 699
 
7 7u83 700
		    types_copy(param, &param_subset);
701
		    types_append_copy(param, &old_result);
702
		    vector[i].inited = TRUE;
2 7u83 703
		}
704
		if (generate_result) {
7 7u83 705
		    types_copy(gen_result, &dummy);
706
		    types_append_copy(gen_result, rule_result(rule));
2 7u83 707
		    generate_result = FALSE;
708
		}
7 7u83 709
		alt_set_next(tmp_alt, vector[i].alt);
710
		vector[i].alt = tmp_alt;
2 7u83 711
	    }
712
	}
7 7u83 713
	rule_reinit(rule);
714
	types_destroy(&old_result);
2 7u83 715
    }
7 7u83 716
    types_destroy(&param_subset);
717
    btrans_destroy(&translator);
2 7u83 718
}
719
 
720
static BoolT
7 7u83 721
rule_left_cycle_general_case_2(RuleP rule_list, unsigned size,
722
			       VectorEntryP vector)
2 7u83 723
{
724
    BoolT    not_found = TRUE;
725
    unsigned i;
726
 
7 7u83 727
    for (i = 0; i < size; i++) {
728
	if ((vector[i].empty_alt) || (vector[i].alt)) {
2 7u83 729
	    not_found = FALSE;
730
	}
731
    }
732
    if (not_found) {
7 7u83 733
	E_cycle_no_terminator(rule_list);
734
	return(FALSE);
2 7u83 735
    }
7 7u83 736
    return(TRUE);
2 7u83 737
}
738
 
739
static void
7 7u83 740
rule_left_cycle_general_case_3(RuleP rule, unsigned size, VectorEntryP vector,
741
			       TableP table, RuleP *new_rule_list_tail,
742
			       TypeTupleP param, TypeTupleP result)
2 7u83 743
{
744
    unsigned j;
745
 
7 7u83 746
    for (j = 0; j < size; j++) {
747
	EntryP entry    = table_add_generated_rule(table, TRUE);
748
	RuleP  new_rule = entry_get_rule(entry);
2 7u83 749
	AltP   alt;
750
 
7 7u83 751
	types_copy(rule_param(new_rule), param);
752
	types_copy(rule_result(new_rule), result);
2 7u83 753
	*new_rule_list_tail = new_rule;
7 7u83 754
	new_rule_list_tail  = rule_next_in_reverse_dfs_ref(new_rule);
755
	if (vector[j].empty_alt) {
756
	    AltP  new_alt  = alt_create();
757
	    ItemP new_item = item_create(entry);
2 7u83 758
 
7 7u83 759
	    types_copy(item_param(new_item), &(vector[j].param));
760
	    types_copy(item_result(new_item), result);
761
	    alt_add_item(new_alt, new_item);
762
	    rule_add_alt(rule, new_alt);
2 7u83 763
	}
7 7u83 764
	for (alt = vector[j].alt; alt; alt = alt_next(alt)) {
765
	    AltP  new_alt  = alt_duplicate(alt);
766
	    ItemP new_item = item_create(entry);
2 7u83 767
 
7 7u83 768
	    types_copy(item_param(new_item), &(vector[j].param));
769
	    types_copy(item_result(new_item), result);
770
	    alt_add_item(new_alt, new_item);
771
	    rule_add_alt(rule, new_alt);
2 7u83 772
	}
773
    }
774
}
775
 
776
static void
7 7u83 777
rule_left_cycle_general_case_4(RuleP new_rule_list, unsigned i, unsigned size,
778
			       MatrixEntryP matrix, TableP table)
2 7u83 779
{
780
    unsigned j;
781
    RuleP    rule;
782
 
783
    for (rule = new_rule_list, j = 0; j < size;
7 7u83 784
	 rule = rule_get_next_in_reverse_dfs(rule), j++) {
2 7u83 785
	RuleP    inner_rule;
786
	unsigned k = 0;
787
 
788
	if (i == j) {
7 7u83 789
	    if (types_equal_zero_tuple(rule_param(rule))) {
790
		rule_add_empty_alt(rule);
2 7u83 791
	    } else {
7 7u83 792
		AltP   new_alt  = alt_create();
793
		EntryP entry    = table_add_rename(table);
794
		ItemP  new_item = item_create(entry);
2 7u83 795
 
7 7u83 796
		types_copy(item_param(new_item), rule_param(rule));
797
		types_copy(item_result(new_item), rule_result(rule));
798
		alt_add_item(new_alt, new_item);
799
		rule_add_alt(rule, new_alt);
2 7u83 800
	    }
801
	}
802
	for (inner_rule = new_rule_list; inner_rule;
7 7u83 803
	     inner_rule = rule_get_next_in_reverse_dfs(inner_rule), k++) {
2 7u83 804
	    AltP alt;
805
 
7 7u83 806
	    for (alt = matrix[k].alt; alt; alt = alt_next(alt)) {
807
		AltP  new_alt  = alt_duplicate(alt);
808
		ItemP new_item = item_create(rule_entry(inner_rule));
2 7u83 809
 
7 7u83 810
		types_copy(item_param(new_item), &(matrix[k].param));
811
		types_copy(item_result(new_item), rule_result(rule));
812
		alt_add_item(new_alt, new_item);
813
		rule_add_alt(rule, new_alt);
2 7u83 814
	    }
815
	}
816
    }
817
}
818
 
819
static void
7 7u83 820
rule_left_cycle_general_case(RuleP rule_list, unsigned size, TableP table)
2 7u83 821
{
822
    unsigned     matrix_size = (size * size);
7 7u83 823
    MatrixEntryP matrix      = rule_left_cycle_matrix(matrix_size);
824
    VectorEntryP vector      = rule_left_cycle_vector(size);
2 7u83 825
    TypeTupleT   param;
826
    TypeTupleT   result;
827
 
7 7u83 828
    rule_left_cycle_general_case_1(rule_list, size, matrix, vector, table,
2 7u83 829
				    &param, &result);
7 7u83 830
    if (rule_left_cycle_general_case_2(rule_list, size, vector)) {
2 7u83 831
	unsigned i = 0;
832
	RuleP    rule;
833
 
834
	for (rule = rule_list; rule;
7 7u83 835
	     rule = rule_get_next_in_reverse_dfs(rule), i++) {
2 7u83 836
	    RuleP new_rule_list;
837
 
7 7u83 838
	    rule_left_cycle_general_case_3(rule, size, vector, table,
839
					   &new_rule_list, &param, &result);
840
	    rule_left_cycle_general_case_4(new_rule_list, i, size, matrix,
841
					   table);
2 7u83 842
	}
843
    }
7 7u83 844
    types_destroy(&param);
845
    types_destroy(&result);
846
    rule_destroy_cycle_matrix(matrix, matrix_size);
847
    rule_destroy_cycle_vector(vector, size);
2 7u83 848
}
849
 
850
/*--------------------------------------------------------------------------*/
851
 
852
void
7 7u83 853
rule_remove_left_cycle(RuleP rule_list, EntryP predicate_id, TableP table)
2 7u83 854
{
855
    unsigned size      = 0;
856
    unsigned real_size = 0;
857
    RuleP    rule;
858
 
7 7u83 859
    for (rule = rule_list; rule; rule = rule_get_next_in_reverse_dfs(rule)) {
860
	size++;
861
	if (key_is_string(entry_key(rule_entry(rule)))) {
862
	    real_size++;
2 7u83 863
	}
7 7u83 864
	rule_set_cycle_index(rule, size);
2 7u83 865
    }
7 7u83 866
    if (((size != 1) || (!rule_left_cycle_special_case(rule_list, table))) &&
867
	(rule_check_cycle_types(rule_list, predicate_id, real_size, table))) {
868
	rule_left_cycle_general_case(rule_list, size, table);
2 7u83 869
    }
7 7u83 870
    for (rule = rule_list; rule; rule = rule_get_next_in_reverse_dfs(rule)) {
871
	rule_reset_cycle_index(rule);
872
	rule_no_cycles(rule);
2 7u83 873
    }
874
}
875
 
876
/*
877
 * Local variables(smf):
878
 * eval: (include::add-path-entry "../os-interface" "../library")
879
 * eval: (include::add-path-entry "../generated")
880
 * end:
881
**/