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-simp.c --- Rule simplification routines.
62
 *
63
 ** Author: Steve Folkes <smf@hermes.mod.uk>
64
 *
65
 *** Commentary:
66
 *
67
 * This file implements the SID elimination of identical rules routines.
68
 *
69
 * In order to optimise the elimination of identical rules the following is
70
 * done:
71
 *
72
 * 	- name flow through each rule is numbered, so that differences in
73
 *	  names do not affect the comparisons;
74
 *
75
 *	- alternatives are reordered so that they will appear in the same
76
 *	  order in identical rules;
77
 *
78
 *	- rules are placed in a hash table, so that identical rules will be in
79
 *	  the same slot in the table.
80
 *
81
 * The first two of these make comparisons between two rules quicker.  The
82
 * third reduces the number of comparisons that are made.
83
 *
84
 * One important thing to remember is that the hash value of a rule should not
85
 * depend upon the names of any rules that it calls.  If this was the case,
86
 * and one of the rules was replaced then it would be possible to have two
87
 * identical rules in different slots in the hash table!
88
 *
89
 * If two identical rules are found, one is substituted for the other.  If
90
 * one of the rules is a required rule, then it becomes the used rule.
91
 *
92
 *** Change Log:
93
 * $Log: rule-simp.c,v $
94
 * Revision 1.1.1.1  1998/01/17  15:57:47  release
95
 * First version to be checked into rolling release.
96
 *
97
 * Revision 1.2  1994/12/15  09:58:52  smf
98
 * Brought into line with OSSG C Coding Standards Document, as per
99
 * "CR94_178.sid+tld-update".
100
 *
101
 * Revision 1.1.1.1  1994/07/25  16:04:41  smf
102
 * Initial import of SID 1.8 non shared files.
103
 *
104
**/
105
 
106
/****************************************************************************/
107
 
108
#include "rule.h"
109
#include "action.h"
110
#include "basic.h"
111
#include "entry-list.h"
112
#include "name.h"
113
#include "type.h"
114
 
115
/*--------------------------------------------------------------------------*/
116
 
7 7u83 117
#define EQUALITY_TABLE_SIZE	(127)
2 7u83 118
 
119
/*--------------------------------------------------------------------------*/
120
 
121
typedef struct RuleSortListT {
122
    AltP			head;
123
    AltP		       *tail;
124
} RuleSortListT, *RuleSortListP;
125
 
126
typedef struct ReplaceClosureT {
127
    EntryP			from;
128
    EntryP			to;
129
} ReplaceClosureT, *ReplaceClosureP;
130
 
131
/*--------------------------------------------------------------------------*/
132
 
7 7u83 133
static RuleP		equality_table[EQUALITY_TABLE_SIZE];
2 7u83 134
 
135
/*--------------------------------------------------------------------------*/
136
 
137
static void
7 7u83 138
rule_sort_alts(RuleSortListP sort_list)
2 7u83 139
{
140
    AltP alt      = sort_list->head;
7 7u83 141
    AltP scan_alt = alt_next(alt);
2 7u83 142
 
143
    if (scan_alt) {
144
	RuleSortListT lower;
145
	RuleSortListT higher;
146
 
147
	lower.tail  = &(lower.head);
148
	higher.tail = &(higher.head);
7 7u83 149
	for (; scan_alt; scan_alt = alt_next(scan_alt)) {
150
	    if (alt_less_than(scan_alt, alt)) {
151
		*(lower.tail) = scan_alt;
152
		lower.tail     = alt_next_ref(scan_alt);
2 7u83 153
	    } else {
154
		*(higher.tail) = scan_alt;
7 7u83 155
		higher.tail    = alt_next_ref(scan_alt);
2 7u83 156
	    }
157
	}
7 7u83 158
	*(lower.tail) = NIL(AltP);
159
	*(higher.tail) = NIL(AltP);
2 7u83 160
	if (lower.head) {
7 7u83 161
	    rule_sort_alts(&lower);
2 7u83 162
	    sort_list->head = lower.head;
163
	    sort_list->tail = lower.tail;
164
	} else {
165
	    sort_list->tail = &(sort_list->head);
166
	}
167
	*(sort_list->tail) = alt;
7 7u83 168
	sort_list->tail    = alt_next_ref(alt);
2 7u83 169
	if (higher.head) {
7 7u83 170
	    rule_sort_alts(&higher);
2 7u83 171
	    *(sort_list->tail) = higher.head;
172
	    sort_list->tail    = higher.tail;
173
	}
7 7u83 174
	*(sort_list->tail) = NIL(AltP);
2 7u83 175
    }
176
}
177
 
178
static void
7 7u83 179
rule_reorder(RuleP rule)
2 7u83 180
{
181
    RuleSortListT sort_list;
182
 
7 7u83 183
    if ((sort_list.head = rule_alt_head(rule)) != NIL(AltP)) {
2 7u83 184
	sort_list.tail = rule->alt_tail;
7 7u83 185
	rule_sort_alts(&sort_list);
2 7u83 186
	rule->alt_head = sort_list.head;
187
	rule->alt_tail = sort_list.tail;
188
    }
189
}
190
 
191
static void
7 7u83 192
rule_hash_1(RuleP rule, EntryP predicate_id)
2 7u83 193
{
7 7u83 194
    unsigned hash_value = (unsigned)(rule_has_empty_alt(rule)? 3 : 0);
2 7u83 195
    AltP     alt;
196
 
7 7u83 197
    rule_renumber(rule, TRUE, predicate_id);
198
    rule_reorder(rule);
199
    for (alt = rule_alt_head(rule); alt; alt = alt_next(alt)) {
2 7u83 200
	ItemP item;
7 7u83 201
	KeyP  key = NIL(KeyP);
2 7u83 202
 
203
	hash_value += 5;
7 7u83 204
	for (item = alt_item_head(alt); item; item = item_next(item)) {
205
	    hash_value++;
206
	    if (!item_is_rule(item)) {
207
		key = entry_key(item_entry(item));
2 7u83 208
	    }
209
	}
210
	if (key) {
7 7u83 211
	    hash_value += key_hash_value(key);
2 7u83 212
	}
213
    }
214
    hash_value %= EQUALITY_TABLE_SIZE;
7 7u83 215
    rule_set_next_in_table(rule, equality_table[hash_value]);
216
    equality_table[hash_value] = rule;
2 7u83 217
}
218
 
219
static void
7 7u83 220
rule_hash_for_comparison(EntryP entry, GenericP gclosure)
2 7u83 221
{
7 7u83 222
    if (entry_is_rule(entry)) {
223
	RuleP  rule         = entry_get_rule(entry);
224
	EntryP predicate_id = (EntryP)gclosure;
2 7u83 225
 
7 7u83 226
	rule_hash_1(rule, predicate_id);
2 7u83 227
    }
228
}
229
 
230
static BoolT
7 7u83 231
rule_equal(RuleP rule1, RuleP rule2)
2 7u83 232
{
233
    AltP alt1;
234
    AltP alt2;
235
 
7 7u83 236
    if ((!types_equal_numbers(rule_param(rule1), rule_param(rule2))) ||
237
	(!types_equal_numbers(rule_result(rule1), rule_result(rule2))) ||
238
	(rule_has_empty_alt(rule1) != rule_has_empty_alt(rule2)) ||
239
	(!alt_equal(rule_get_handler(rule1), rule_get_handler(rule2))) ||
240
	(!non_local_list_is_empty(rule_non_locals(rule1))) ||
241
	(!non_local_list_is_empty(rule_non_locals(rule2)))) {
242
	return(FALSE);
2 7u83 243
    }
7 7u83 244
    for (alt1 = rule_alt_head(rule1), alt2 = rule_alt_head(rule2);
245
	 alt1 && alt2; alt1 = alt_next(alt1), alt2 = alt_next(alt2)) {
2 7u83 246
	ItemP item1;
247
	ItemP item2;
248
 
7 7u83 249
	for (item1 = alt_item_head(alt1), item2 = alt_item_head(alt2);
2 7u83 250
	     item1 && item2;
7 7u83 251
	     item1 = item_next(item1), item2 = item_next(item2)) {
252
	    if ((item_entry(item1) != item_entry(item2)) ||
253
		(!types_equal_numbers(item_param(item1), item_param(item2))) ||
254
		(!types_equal_numbers(item_result(item1),
255
				      item_result(item2)))) {
256
		return(FALSE);
2 7u83 257
	    }
258
	}
259
	if (item1 || item2) {
7 7u83 260
	    return(FALSE);
2 7u83 261
	}
262
    }
263
    if (alt1 || alt2) {
7 7u83 264
	return(FALSE);
2 7u83 265
    }
7 7u83 266
    return(TRUE);
2 7u83 267
}
268
 
269
static BoolT
7 7u83 270
rule_do_replacements_1(AltP alt, ReplaceClosureP closure)
2 7u83 271
{
272
    BoolT changed = FALSE;
273
    ItemP item;
274
 
7 7u83 275
    for (item = alt_item_head(alt); item; item = item_next(item)) {
276
	if (item_entry(item) == closure->from) {
277
	    item_set_entry(item, closure->to);
2 7u83 278
	    changed = TRUE;
279
	}
280
    }
7 7u83 281
    return(changed);
2 7u83 282
}
283
 
284
static void
7 7u83 285
rule_do_replacements(EntryP entry, GenericP gclosure)
2 7u83 286
{
7 7u83 287
    ReplaceClosureP closure = (ReplaceClosureP)gclosure;
2 7u83 288
 
7 7u83 289
    if (entry_is_rule(entry)) {
290
	RuleP rule    = entry_get_rule(entry);
2 7u83 291
	BoolT changed = FALSE;
292
	AltP  alt;
293
 
7 7u83 294
	if ((alt = rule_get_handler(rule)) != NIL(AltP)) {
295
	    if (rule_do_replacements_1(alt, closure)) {
2 7u83 296
		changed = TRUE;
297
	    }
298
	}
7 7u83 299
	for (alt = rule_alt_head(rule); alt; alt = alt_next(alt)) {
300
	    if (rule_do_replacements_1(alt, closure)) {
2 7u83 301
		changed = TRUE;
302
	    }
303
	}
304
	if (changed) {
7 7u83 305
	    rule_reorder(rule);
2 7u83 306
	}
307
    }
308
}
309
 
310
static BoolT
7 7u83 311
rule_remove_duplicates_1(RuleP *rule_ref, TableP table)
2 7u83 312
{
313
    BoolT did_remove = FALSE;
314
    RuleP rule;
315
 
7 7u83 316
    while ((rule = *rule_ref) != NIL(RuleP)) {
317
	RuleP *inner_rule_ref = rule_get_next_in_table_ref(rule);
2 7u83 318
	RuleP  inner_rule;
319
 
7 7u83 320
	while ((inner_rule = *inner_rule_ref) != NIL(RuleP)) {
321
	    if (rule_equal(rule, inner_rule)) {
2 7u83 322
		ReplaceClosureT closure;
323
 
7 7u83 324
		if (rule_is_required(inner_rule)) {
325
		    closure.from = rule_entry(rule);
326
		    closure.to   = rule_entry(inner_rule);
327
		    *rule_ref    = rule_get_next_in_table(rule);
2 7u83 328
		} else {
7 7u83 329
		    closure.from    = rule_entry(inner_rule);
330
		    closure.to      = rule_entry(rule);
331
		    *inner_rule_ref = rule_get_next_in_table(inner_rule);
2 7u83 332
		}
7 7u83 333
		table_iter(table, rule_do_replacements, (GenericP)&closure);
2 7u83 334
		did_remove = TRUE;
335
		if (rule != *rule_ref) {
336
		    goto removed_rule;
337
		}
338
	    } else {
7 7u83 339
		inner_rule_ref = rule_get_next_in_table_ref(inner_rule);
2 7u83 340
	    }
341
	}
7 7u83 342
	rule_ref = rule_get_next_in_table_ref(rule);
2 7u83 343
      removed_rule:;
344
    }
7 7u83 345
    return(did_remove);
2 7u83 346
}
347
 
348
/*--------------------------------------------------------------------------*/
349
 
350
void
7 7u83 351
rule_remove_duplicates(TableP table, EntryP predicate_id)
2 7u83 352
{
353
    BoolT    did_remove;
354
    unsigned i;
355
 
7 7u83 356
    for (i = 0; i < EQUALITY_TABLE_SIZE; i++) {
357
	equality_table[i] = NIL(RuleP);
2 7u83 358
    }
7 7u83 359
    table_iter(table, rule_hash_for_comparison, (GenericP)predicate_id);
2 7u83 360
    do {
361
	did_remove = FALSE;
7 7u83 362
	for (i = 0; i < EQUALITY_TABLE_SIZE; i++) {
363
	    if (rule_remove_duplicates_1(&(equality_table[i]), table)) {
2 7u83 364
		did_remove = TRUE;
365
	    }
366
	}
367
    } while (did_remove);
368
}
369
 
370
/*
371
 * Local variables(smf):
372
 * eval: (include::add-path-entry "../os-interface" "../library")
373
 * eval: (include::add-path-entry "../generated")
374
 * end:
375
**/