initial
[prop.git] / lib-src / automata / treegen.cc
blobee3f35c3fe502e5e824c71da8004a4caaceaa41e
1 ///////////////////////////////////////////////////////////////////////////////
2 // This file is generated automatically using Prop (version 2.3.3),
3 // last updated on Mar 30, 1997.
4 // The original source file is "treegen.pcc".
5 ///////////////////////////////////////////////////////////////////////////////
7 #line 1 "treegen.pcc"
8 //////////////////////////////////////////////////////////////////////////////
9 // NOTICE:
11 // ADLib, Prop and their related set of tools and documentation are in the
12 // public domain. The author(s) of this software reserve no copyrights on
13 // the source code and any code generated using the tools. You are encouraged
14 // to use ADLib and Prop to develop software, in both academic and commercial
15 // settings, and are welcomed to incorporate any part of ADLib and Prop into
16 // your programs.
18 // Although you are under no obligation to do so, we strongly recommend that
19 // you give away all software developed using our tools.
21 // We also ask that credit be given to us when ADLib and/or Prop are used in
22 // your programs, and that this notice be preserved intact in all the source
23 // code.
25 // This software is still under development and we welcome(read crave for)
26 // any suggestions and help from the users.
28 // Allen Leung
29 // 1994
30 //////////////////////////////////////////////////////////////////////////////
32 #include <assert.h>
33 #include <iostream.h>
34 #include <AD/automata/treegram.h> // tree grammar
35 #include <AD/automata/treegen.h> // tree automata compiler
36 #include <AD/contain/bitset.h> // bit set
37 #include <AD/hash/dchash.h> // direct chaining hash map
38 #include <AD/contain/vararray.h> // variable sized array
39 #include <AD/contain/slnklist.h> // linked list
40 #include <AD/memory/mempool.h> // memory pool
42 //////////////////////////////////////////////////////////////////////////////
43 // Make hidden types visible
44 //////////////////////////////////////////////////////////////////////////////
45 typedef TreeGrammar::TreeProduction TreeProduction;
46 typedef TreeGrammar::Functor Functor;
47 typedef TreeGrammar::Arity Arity;
48 typedef TreeGrammar::Variable Variable;
49 typedef TreeGrammar::State State;
50 typedef TreeGrammar::Rule Rule;
51 typedef TreeAutomaton::Equiv Equiv;
52 typedef SLinkList<State> StateList;
54 //////////////////////////////////////////////////////////////////////////////
55 // Class TreeGenerator represents the internals of the automata compiler.
56 // This stuff is completely hidden from the interface.
57 //////////////////////////////////////////////////////////////////////////////
58 class TreeGenerator {
60 TreeGenerator(const TreeGenerator&); // no copy constructor
61 void operator = (const TreeGenerator&); // no assignment
63 public:
65 ///////////////////////////////////////////////////////////////////////////
66 // Internal data structures
67 ///////////////////////////////////////////////////////////////////////////
69 TreeGen& treegen;
70 TreeGrammar& G; // the grammar
71 MemPool mem; // memory pool
72 BitSet ** ruleset_map; // non-terminal -> rule set
73 Rule * rule_map; // non-terminal -> rule set
74 DCHashTable<TreeTerm, Variable> non_terminals; // term -> non-terminals map
75 VarArray <TreeTerm> n_states; // non-terminals -> term map
76 DCHashTable<BitSet *, State> state_labels; // non-terminal set -> state mapping
77 DCHashTable<TreeTerm, BitSet *> delta; // term -> non-terminals mapping
78 VarArray <BitSet *> d_states; // state -> non-terminal set
79 VarArray <TreeTerm> d_terms; // state -> term map
80 BitSet *** proj; // projections
81 BitSet ** closure0; // transitive closure of each non-terminal
82 Variable max_non_terminal;
83 State number_of_states;
84 StateList *** representers;
86 ///////////////////////////////////////////////////////////////////////////
87 // Constructor
88 ///////////////////////////////////////////////////////////////////////////
89 TreeGenerator(TreeGen& gen, TreeGrammar& g) :
90 treegen(gen), G(g), mem(4096), non_terminals(1037),
91 state_labels(1037), delta(1037) {}
93 ///////////////////////////////////////////////////////////////////////////
94 // Methods to process various phases of the compilation.
95 ///////////////////////////////////////////////////////////////////////////
96 void assign_non_terminals ();
97 TreeTerm assign_non_terminal ( TreeTerm );
98 void compute_closures ();
99 void compute_projections ();
100 void compute_representers ();
101 void compute_initial_states ();
102 void compute_transitions ();
103 BitSet * compute_transition (BitSet *, TreeTerm, int, int, const BitSet&, State [], int []);
104 void compute_delta (BitSet *, TreeTerm, int, int, const State []);
105 void compute_accept_rules (State);
106 ostream& print_report (ostream&) const;
107 ostream& print_state (ostream&, State) const;
110 //////////////////////////////////////////////////////////////////////////////
111 // The following method is used to assign non-terminal symbols
112 // to each distinct term within the grammar
113 //////////////////////////////////////////////////////////////////////////////
114 void TreeGenerator::assign_non_terminals()
116 ///////////////////////////////////////////////////////////////////////////
117 // The grammar may already have user defined variable names.
118 // New non-terminals will have encodings right after these variables.
119 ///////////////////////////////////////////////////////////////////////////
120 max_non_terminal = G.max_variable() + 1;
121 non_terminals.insert(wild_term,0);
122 { for (Variable v = max_non_terminal - 1; v >= 0; v--)
123 n_states[v] = wild_term;
126 ///////////////////////////////////////////////////////////////////////////
127 // Traverse thru the grammar and compute the non-terminal numbers.
128 // The tree grammar *IS* destructively altered.
129 ///////////////////////////////////////////////////////////////////////////
130 { for (int i = G.size() - 1; i >= 0; i--)
131 G.update(i,assign_non_terminal( G[i].term ));
134 ///////////////////////////////////////////////////////////////////////////
135 // Compute the mapping from non-terminal -> accept rule
136 ///////////////////////////////////////////////////////////////////////////
137 ruleset_map = (BitSet **)mem.c_alloc(sizeof(BitSet *) * max_non_terminal);
138 rule_map = (Rule *) mem.c_alloc(sizeof(Rule) * max_non_terminal);
139 { int i;
140 for (i = max_non_terminal - 1; i >= 0; i--) rule_map[i] = -1;
141 for (i = G.size() - 1; i >= 0; i--) {
142 Variable v = non_terminals[G[i].term];
143 if (ruleset_map[v] == 0)
144 ruleset_map[v] = new (mem, max_non_terminal) BitSet;
145 ruleset_map[v]->add(i);
146 rule_map[v] = i;
151 //////////////////////////////////////////////////////////////////////////////
152 // Method to assign non-terminal numbers for a tree term. This is
153 // defined inductive as:
154 //////////////////////////////////////////////////////////////////////////////
155 TreeTerm TreeGenerator::assign_non_terminal( TreeTerm t )
157 ///////////////////////////////////////////////////////////////////////////
158 // Step (a) recursively fold the terms.
159 ///////////////////////////////////////////////////////////////////////////
161 #line 153 "treegen.pcc"
162 #line 163 "treegen.pcc"
164 if (t) {
165 switch (t->tag__) {
166 case a_TreeTerm::tag_tree_term: {
167 #line 160 "treegen.pcc"
169 for (int i = _tree_term(t)->_2 - 1; i >= 0; i--)
170 _tree_term(t)->_3[i] = assign_non_terminal(_tree_term(t)->_3[i]);
172 #line 163 "treegen.pcc"
173 } break;
174 case a_TreeTerm::tag_var_term: {
175 #line 155 "treegen.pcc"
176 // skip
178 #line 156 "treegen.pcc"
179 } break;
180 case a_TreeTerm::tag_and_term: {
181 #line 157 "treegen.pcc"
182 _and_term(t)->_1 = assign_non_terminal(_and_term(t)->_1); _and_term(t)->_2 = assign_non_terminal(_and_term(t)->_2);
184 #line 158 "treegen.pcc"
185 } break;
186 case a_TreeTerm::tag_or_term: {
187 #line 158 "treegen.pcc"
188 _or_term(t)->_1 = assign_non_terminal(_or_term(t)->_1); _or_term(t)->_2 = assign_non_terminal(_or_term(t)->_2);
190 #line 159 "treegen.pcc"
191 } break;
192 case a_TreeTerm::tag_not_term: {
193 #line 159 "treegen.pcc"
194 _not_term(t)->not_term = assign_non_terminal(_not_term(t)->not_term);
196 #line 160 "treegen.pcc"
197 } break;
198 default: {
199 #line 156 "treegen.pcc"
200 // skip
202 #line 157 "treegen.pcc"
203 } break;
205 } else {
206 #line 154 "treegen.pcc"
207 // skip
209 #line 155 "treegen.pcc"
212 #line 163 "treegen.pcc"
213 #line 163 "treegen.pcc"
216 ///////////////////////////////////////////////////////////////////////////
217 // Look it up from the ``non_terminal'' map.
218 ///////////////////////////////////////////////////////////////////////////
219 Ix p = non_terminals.lookup(t);
220 if (p == 0) { // not found!
221 ////////////////////////////////////////////////////////////////////////
222 // Step (b) if it is not found, assign a new non-terminal number.
223 // Notice that ``wild_term'' always gets the non-terminal number of 0.
224 ////////////////////////////////////////////////////////////////////////
225 Variable var;
227 #line 175 "treegen.pcc"
228 #line 179 "treegen.pcc"
230 if (t) {
231 switch (t->tag__) {
232 case a_TreeTerm::tag_var_term: {
233 #line 177 "treegen.pcc"
234 var = _var_term(t)->var_term;
236 #line 178 "treegen.pcc"
237 } break;
238 default: {
239 #line 178 "treegen.pcc"
240 var = max_non_terminal++;
242 #line 179 "treegen.pcc"
243 } break;
245 } else {
246 #line 176 "treegen.pcc"
247 var = 0;
249 #line 177 "treegen.pcc"
252 #line 179 "treegen.pcc"
253 #line 179 "treegen.pcc"
255 non_terminals.insert(t,var); // update map
256 n_states[var] = t; // update inverse map
257 } else {
258 t = non_terminals.key(p);
260 return t;
263 //////////////////////////////////////////////////////////////////////////////
264 // This is the method for computing transitive closure on a non-terminal
265 // set. Transitive closures apply in the presence of single reductions
266 // X -> Y
267 // or logical connectives:
268 // X -> Y and Z
269 // X -> Y or Z
271 // We don't support negation yet since it is anti-monotonic.
272 //////////////////////////////////////////////////////////////////////////////
273 void TreeGenerator::compute_closures()
275 ///////////////////////////////////////////////////////////////////////////
276 // Allocate the array closure0, which maps each non-terminal to
277 // its transitive closure. Closure set are allocated only if
278 // they are non-trivial (i.e. closure0[v] is something other than
279 // { 0, v }.
280 ///////////////////////////////////////////////////////////////////////////
281 closure0 = (BitSet**)mem.c_alloc(sizeof(BitSet*) * max_non_terminal);
283 ///////////////////////////////////////////////////////////////////////////
284 // Allocate closures for user defined non-terminals
285 ///////////////////////////////////////////////////////////////////////////
286 { for (Variable v = G.min_variable(); v <= G.max_variable(); v++) {
287 closure0[v] = new (mem, max_non_terminal) BitSet;
288 closure0[v]->add(0);
289 closure0[v]->add(v);
293 ///////////////////////////////////////////////////////////////////////////
294 // Now compute the transitive closure
295 ///////////////////////////////////////////////////////////////////////////
296 Bool changed;
297 BitSet& temp = *new(mem, max_non_terminal) BitSet; // temporary set buffer
298 do {
299 changed = false;
301 /////////////////////////////////////////////////////////////////////////
302 // Propagate closure information.
303 /////////////////////////////////////////////////////////////////////////
304 foreach (p, non_terminals) {
305 TreeTerm term = non_terminals.key(p);
306 Variable var = non_terminals.value(p);
308 /////////////////////////////////////////////////////////////////////
309 // Allocate a new closure set if necessary.
310 /////////////////////////////////////////////////////////////////////
312 #line 236 "treegen.pcc"
313 #line 243 "treegen.pcc"
315 if (term) {
316 switch (term->tag__) {
317 case a_TreeTerm::tag_tree_term:
318 case a_TreeTerm::tag_not_term:
319 case a_TreeTerm::tag_set_term: {
320 L1:;
321 #line 242 "treegen.pcc"
324 #line 243 "treegen.pcc"
325 } break;
326 default: {
327 if (
328 #line 237 "treegen.pcc"
329 (closure0[var] == 0)
330 #line 237 "treegen.pcc"
333 L2:;
334 #line 237 "treegen.pcc"
336 closure0[var] = new (mem, max_non_terminal) BitSet;
337 closure0[var]->add(0);
338 closure0[var]->add(var);
339 changed = true;
341 #line 242 "treegen.pcc"
342 } else {
343 goto L1; }
344 } break;
346 } else { goto L1; }
348 #line 243 "treegen.pcc"
349 #line 243 "treegen.pcc"
352 /////////////////////////////////////////////////////////////////////
353 // Propagate closures sets.
354 /////////////////////////////////////////////////////////////////////
356 #line 248 "treegen.pcc"
357 #line 266 "treegen.pcc"
359 if (term) {
360 switch (term->tag__) {
361 case a_TreeTerm::tag_var_term: {
362 if (
363 #line 259 "treegen.pcc"
364 (var != _var_term(term)->var_term)
365 #line 259 "treegen.pcc"
368 #line 259 "treegen.pcc"
370 if (closure0[_var_term(term)->var_term]) {
371 if (closure0[var]->Union_if_changed(*closure0[_var_term(term)->var_term])) changed = true;
372 } else {
373 if (closure0[var]->add_if_changed(_var_term(term)->var_term)) changed = true;
376 #line 265 "treegen.pcc"
377 } else {
379 L3:;
380 #line 265 "treegen.pcc"
381 // skip
383 #line 266 "treegen.pcc"
385 } break;
386 case a_TreeTerm::tag_and_term: {
387 #line 249 "treegen.pcc"
389 BitSet * s1 = closure0[ non_terminals[_and_term(term)->_1] ];
390 BitSet * s2 = closure0[ non_terminals[_and_term(term)->_2] ];
391 temp.Intersect(*s1,*s2);
392 if (closure0[var]->Union_if_changed(temp)) changed = true;
394 #line 254 "treegen.pcc"
395 } break;
396 case a_TreeTerm::tag_or_term: {
397 #line 254 "treegen.pcc"
399 BitSet * s1 = closure0[ non_terminals[_or_term(term)->_1] ];
400 BitSet * s2 = closure0[ non_terminals[_or_term(term)->_2] ];
401 if (closure0[var]->Union_if_changed(*s1)) changed = true;
402 if (closure0[var]->Union_if_changed(*s2)) changed = true;
404 #line 259 "treegen.pcc"
405 } break;
406 default: { goto L3; } break;
408 } else { goto L3; }
410 #line 266 "treegen.pcc"
411 #line 266 "treegen.pcc"
415 /////////////////////////////////////////////////////////////////////////
416 // Propagate closure information to user non-terminals
417 /////////////////////////////////////////////////////////////////////////
418 for (int i = G.size() - 1; i >= 0; i--) {
419 Variable v1 = G[i].var;
420 Variable v2 = non_terminals[G[i].term];
421 // cerr << "[" << v1 << " ";
422 // G.print_variable(cerr,v1) << " <= " << v2 << " ";
423 // G.print(cerr,G[i].term) << "]\n";
424 if (v1 == 0) continue;
425 if (closure0[v2]) {
426 if (closure0[v1]->Union_if_changed(*closure0[v2])) changed = true;
427 } else {
428 if (closure0[v1]->add_if_changed(v2)) changed = true;
431 } while (changed);
434 //////////////////////////////////////////////////////////////////////////////
435 // This is the method for computing projections.
436 // A projection on functor f and arity i (written as proj[f][i]) is
437 // the set of non-terminals that can appear in that position.
438 //////////////////////////////////////////////////////////////////////////////
439 void TreeGenerator::compute_projections()
441 ///////////////////////////////////////////////////////////////////////////
442 // Allocate the projection array.
443 ///////////////////////////////////////////////////////////////////////////
444 { proj = (BitSet***)mem.c_alloc(sizeof(BitSet**) * (G.max_functor() + 1));
445 for (Functor f = G.min_functor(); f <= G.max_functor(); f++) {
446 if (G.arity(f) == 0) continue;
447 proj[f] = (BitSet**)mem.c_alloc(sizeof(BitSet*) * G.arity(f));
448 for (int i = G.arity(f) - 1; i >= 0; i--) {
449 proj[f][i] = new (mem, max_non_terminal) BitSet;
450 proj[f][i]->add(0);
455 ///////////////////////////////////////////////////////////////////////////
456 // Compute the projections by going over the terms and
457 // looking up the non-terminals at each argument.
458 ///////////////////////////////////////////////////////////////////////////
459 { foreach (p, non_terminals) {
461 #line 314 "treegen.pcc"
462 #line 322 "treegen.pcc"
464 TreeTerm _V1 = non_terminals.key(p);
465 if (_V1) {
466 switch (_V1->tag__) {
467 case a_TreeTerm::tag_tree_term: {
468 #line 315 "treegen.pcc"
470 for (int i = _tree_term(_V1)->_2 - 1; i >= 0; i--) {
471 Variable v = non_terminals[ _tree_term(_V1)->_3[i] ];
472 if (closure0[v]) proj[_tree_term(_V1)->_1][i]->Union(*closure0[v]);
473 else proj[_tree_term(_V1)->_1][i]->add(v);
476 #line 321 "treegen.pcc"
477 } break;
478 default: {
479 L4:;
480 #line 321 "treegen.pcc"
481 // skip
483 #line 322 "treegen.pcc"
484 } break;
486 } else { goto L4; }
488 #line 322 "treegen.pcc"
489 #line 322 "treegen.pcc"
495 //////////////////////////////////////////////////////////////////////////////
496 // Method to allocate the representer state list for each functor at
497 // each arity. ``Representers'' are simply interesting states.
498 //////////////////////////////////////////////////////////////////////////////
499 void TreeGenerator::compute_representers()
500 { representers = (StateList***)mem.c_alloc(sizeof(StateList**) * (G.max_functor() + 1));
501 for (Functor f = G.min_functor(); f <= G.max_functor(); f++)
502 representers[f] =
503 (StateList**)mem.c_alloc(sizeof(StateList*) * G.arity(f));
506 //////////////////////////////////////////////////////////////////////////////
507 // Method to compute the accept rules of a state
508 //////////////////////////////////////////////////////////////////////////////
509 void TreeGenerator::compute_accept_rules (State s)
510 { register const BitSet& vars = *d_states[ s ];
511 register BitSet& rules = treegen.accept_rules(s);
512 register Rule min_rule = G.size();
513 register int v;
514 foreach_bit_fast(v,vars) {
515 Rule r = rule_map[v];
516 if (r >= 0 && r < min_rule) min_rule = r;
517 const BitSet * r_set = ruleset_map[v];
518 if (r_set) rules.Union(*r_set);
520 if (min_rule == G.size()) min_rule = -1;
521 treegen.set_accept1(s, min_rule);
524 //////////////////////////////////////////////////////////////////////////////
525 // Method to compute the initial states.
526 // These are the ``wildcard'' or no-information state, state 0.
527 // Followed by a state for each unit functor.
528 //////////////////////////////////////////////////////////////////////////////
529 void TreeGenerator::compute_initial_states()
531 ///////////////////////////////////////////////////////////////////////////
532 // Create the first state corresponding to the wildcard.
533 ///////////////////////////////////////////////////////////////////////////
534 number_of_states = 0;
535 { BitSet * state_zero = new (mem, max_non_terminal) BitSet;
536 state_zero->add (0);
537 state_labels.insert(state_zero, number_of_states);
538 d_states[ number_of_states ] = state_zero;
539 d_terms [ number_of_states ] = new(mem)
540 #line 371 "treegen.pcc"
541 TreeTerm_set_term
542 #line 371 "treegen.pcc"
543 (state_zero);
544 treegen.new_state(0);
545 compute_accept_rules(0);
546 number_of_states++;
549 ///////////////////////////////////////////////////////////////////////////
550 // Generate the rest of the terminal states formed by unit functors.
551 ///////////////////////////////////////////////////////////////////////////
552 { foreach (i, non_terminals) {
554 #line 381 "treegen.pcc"
555 #line 396 "treegen.pcc"
557 TreeTerm _V2 = non_terminals.key(i);
558 if (_V2) {
559 switch (_V2->tag__) {
560 case a_TreeTerm::tag_tree_term: {
561 switch (_tree_term(_V2)->_2) {
562 case 0: {
563 #line 382 "treegen.pcc"
564 // use terms with arity 0 only
565 BitSet * new_state = new (mem, max_non_terminal) BitSet;
566 Variable v = non_terminals.value(i);
567 new_state->add(0);
568 if (closure0[v]) new_state->Union(*closure0[v]);
569 else new_state->add(v);
570 state_labels.insert(new_state, number_of_states);
571 d_states[ number_of_states ] = new_state;
572 d_terms [ number_of_states ] =
573 #line 390 "treegen.pcc"
574 #line 390 "treegen.pcc"
575 new (mem) TreeTerm_set_term(new_state)
576 #line 390 "treegen.pcc"
577 #line 390 "treegen.pcc"
579 treegen.new_state(number_of_states);
580 treegen.add_delta(_tree_term(_V2)->_1,number_of_states);
581 compute_accept_rules(number_of_states);
582 number_of_states++;
584 #line 395 "treegen.pcc"
585 } break;
586 default: {
587 L5:;
588 #line 395 "treegen.pcc"
591 #line 396 "treegen.pcc"
594 } break;
595 default: { goto L5; } break;
597 } else { goto L5; }
599 #line 396 "treegen.pcc"
600 #line 396 "treegen.pcc"
606 //////////////////////////////////////////////////////////////////////////////
607 // Method to compute transitions.
608 //////////////////////////////////////////////////////////////////////////////
609 void TreeGenerator::compute_transitions()
611 ///////////////////////////////////////////////////////////////////////////
612 // Some temporary buffers used during this process.
613 ///////////////////////////////////////////////////////////////////////////
614 BitSet * projected [256]; // projected states of arity i
615 Bool is_relevant [256]; // is arity i relevant?
616 State inputs [256]; // input state of arity i
617 int equiv_class [256]; // equivalence class of above.
618 BitSet * T = 0; // current result non-terminal set
619 TreeTerm term = new_term(mem, 0, 255); // current term
621 { for (int i = G.max_arity() - 1; i >= 0; i--)
622 projected[i] = new (mem, max_non_terminal) BitSet;
625 ///////////////////////////////////////////////////////////////////////////
626 // Compute the transitions of the states. We'll start from state 0.
627 ///////////////////////////////////////////////////////////////////////////
628 for (State current = 0; current < number_of_states; current++) {
629 const BitSet& S = *d_states[current];
631 ////////////////////////////////////////////////////////////////////////
632 // Iterate over all the non-unit functors and compute their transition
633 // function on this new state ``current.''
634 ////////////////////////////////////////////////////////////////////////
635 for (Functor f = G.min_functor(); f <= G.max_functor(); f++) {
636 int n; // arity
637 if ((n = G.arity(f)) == 0) continue;
640 #line 434 "treegen.pcc"
641 #line 436 "treegen.pcc"
643 if (term) {
644 switch (term->tag__) {
645 case a_TreeTerm::tag_tree_term: {
646 #line 435 "treegen.pcc"
647 _tree_term(term)->_1 = f; _tree_term(term)->_2 = n;
648 #line 435 "treegen.pcc"
649 } break;
650 default: {
651 L6:;
652 #line 436 "treegen.pcc"
653 assert("bug");
654 #line 436 "treegen.pcc"
655 } break;
657 } else { goto L6; }
659 #line 437 "treegen.pcc"
660 #line 437 "treegen.pcc"
663 /////////////////////////////////////////////////////////////////////
664 // Compute the projections on the arguments.
665 // If the intersection of S with the ith projection is an old state T,
666 // then the transition with respect to arity ith must be the same
667 // as the state T.
668 /////////////////////////////////////////////////////////////////////
669 for (int i = n - 1; i >= 0; i--) {
670 projected[i]->Intersect(S, *proj[f][i]);
671 projected[i]->add(0);
672 Ix old = state_labels.lookup(projected[i]);
673 State mapped = current;
674 if (old && (mapped = state_labels.value(old)) < current) {
675 is_relevant[i] = false;
676 } else {
677 representers[f][i] = new (mem, mapped, representers[f][i]) StateList;
678 is_relevant[i] = true;
680 //////////////////////////////////////////////////////////////////
681 // Update the index map ``mu.''
682 //////////////////////////////////////////////////////////////////
683 treegen.add_mu(f,i,current,mapped);
686 /////////////////////////////////////////////////////////////////////
687 // Now compute the transition function of functor f with respect
688 // to the state ``current.'' Check only the arities that can
689 // produce new information. This is done by fixing all ``relevant''
690 // arities to state ``current'' and the rest to the rest of the
691 // representer states.
692 /////////////////////////////////////////////////////////////////////
693 for (int fix = n - 1; fix >= 0; fix--) {
694 if (! is_relevant[fix]) continue;
695 inputs [ fix ] = current;
696 equiv_class [ fix ] = treegen.index_map(f,fix,current);
697 T = compute_transition(T, term, 0, fix, *projected[fix], inputs, equiv_class);
703 //////////////////////////////////////////////////////////////////////////////
704 // Method to compute a set of transitions functions.
705 // We iterate over all the representer states.
706 //////////////////////////////////////////////////////////////////////////////
707 BitSet * TreeGenerator::compute_transition
708 ( BitSet * T, // temporary bitset
709 TreeTerm term, // temporary term
710 int i, // current arity to consider
711 int fixed, // the fixed arity
712 const BitSet& S, // input state of the fixed arity
713 State inputs[], // input states
714 int equiv [] // equiv class of above
717 if (i == fixed) i++; // skip the fixed arity.
719 #line 494 "treegen.pcc"
720 #line 552 "treegen.pcc"
722 if (term) {
723 switch (term->tag__) {
724 case a_TreeTerm::tag_tree_term: {
725 #line 496 "treegen.pcc"
727 if (i < _tree_term(term)->_2) {
728 ////////////////////////////////////////////////////////////////////////
729 // Try arity i == wildcard first
730 ////////////////////////////////////////////////////////////////////////
731 _tree_term(term)->_3[i] = wild_term;
732 inputs[i] = 0;
733 equiv [i] = 0;
734 T = compute_transition(T, term, i+1, fixed, S, inputs, equiv);
736 //////////////////////////////////////////////////////////////////////
737 // Try arity i == a representer state next.
738 ////////////////////////////////////////////////////////////////////////
739 for (StateList * r = representers[_tree_term(term)->_1][i]; r; r = r->tail) {
740 inputs[i] = r->head;
741 equiv [i] = treegen.index_map(_tree_term(term)->_1,i,r->head);
742 _tree_term(term)->_3[i] = d_terms[ r->head ];
743 T = compute_transition(T, term, i+1, fixed, S, inputs, equiv);
745 } else {
746 ////////////////////////////////////////////////////////////////////////
747 // Compute the non-terminal set corresponding to the new state.
748 ////////////////////////////////////////////////////////////////////////
749 if (T == 0) T = new (mem, max_non_terminal) BitSet;
750 else T->clear();
751 T->add(0);
752 int v;
753 foreach_bit_fast (v, S) {
754 _tree_term(term)->_3[ fixed ] = n_states[v];
755 compute_delta(T, term, 0, fixed, inputs);
758 ////////////////////////////////////////////////////////////////////////
759 // Now, lookup the new state to see if it is a new one.
760 // If so, create a new state.
761 ////////////////////////////////////////////////////////////////////////
762 Ix s;
763 State mapped;
764 if ((s = state_labels.lookup(T))) { // old state
765 mapped = state_labels.value(s);
766 } else { // new state
767 d_states[ number_of_states ] = T;
768 d_terms [ number_of_states ] = new(mem)
769 #line 538 "treegen.pcc"
770 TreeTerm_set_term
771 #line 538 "treegen.pcc"
772 (T);
773 state_labels.insert(T, number_of_states);
774 treegen.new_state(number_of_states);
775 compute_accept_rules(number_of_states);
776 T = 0;
777 mapped = number_of_states++;
780 ////////////////////////////////////////////////////////////////////////
781 // Update the delta table.
782 ////////////////////////////////////////////////////////////////////////
783 treegen.add_delta(_tree_term(term)->_1, equiv, mapped);
786 #line 551 "treegen.pcc"
787 } break;
788 default: {
789 L7:;
790 #line 552 "treegen.pcc"
791 assert("bug");
792 #line 552 "treegen.pcc"
793 } break;
795 } else { goto L7; }
797 #line 553 "treegen.pcc"
798 #line 553 "treegen.pcc"
800 return T;
803 //////////////////////////////////////////////////////////////////////////////
804 // Method to compute one delta function
805 //////////////////////////////////////////////////////////////////////////////
806 void TreeGenerator::compute_delta
807 ( BitSet * T, // temporary bitset
808 TreeTerm term, // temporary term
809 int i, // current arity to consider
810 int fixed, // the fixed arity
811 const State inputs[] // input states
813 { Bool first = i == 0;
814 if (i == fixed) i++;
815 Ix p;
817 if ((p = non_terminals.lookup(term))) {
818 ////////////////////////////////////////////////////////////////////////
819 // Found! use the info from the grammar.
820 ////////////////////////////////////////////////////////////////////////
821 Variable v = non_terminals.value(p);
822 if (closure0[v]) T->Union(*closure0[v]);
823 else T->add(v);
824 } else if ((p = delta.lookup(term))) {
825 ////////////////////////////////////////////////////////////////////////
826 // Found! use the info from the delta map.
827 ////////////////////////////////////////////////////////////////////////
828 T->Union(* delta.value(p));
829 } else {
830 ////////////////////////////////////////////////////////////////////////
831 // Split input state s into subcases and compute the union of all of
832 // them. Memorize individual cases into the map ``delta.''
833 ////////////////////////////////////////////////////////////////////////
835 #line 588 "treegen.pcc"
836 #line 612 "treegen.pcc"
838 if (term) {
839 switch (term->tag__) {
840 case a_TreeTerm::tag_tree_term: {
841 #line 590 "treegen.pcc"
843 if (i < _tree_term(term)->_2) {
844 const BitSet& U = *d_states[ inputs[i] ];
845 TreeTerm save = _tree_term(term)->_3[i];
846 BitSet * V;
847 if (first) V = T;
848 else { V = new (mem, max_non_terminal) BitSet; V->add(0); }
850 int v;
851 foreach_bit_fast (v, U) {
852 _tree_term(term)->_3 [i] = n_states[v];
853 compute_delta(V, term, i + 1, fixed, inputs);
855 _tree_term(term)->_3[i] = save;
857 if (! first) {
858 TreeTerm n_term = new_term(mem, _tree_term(term)->_1, _tree_term(term)->_2, _tree_term(term)->_3);
859 delta.insert(n_term,V);
860 T->Union(*V);
864 #line 611 "treegen.pcc"
865 } break;
866 default: {
867 L8:;
868 #line 612 "treegen.pcc"
869 assert ("bug");
870 #line 612 "treegen.pcc"
871 } break;
873 } else { goto L8; }
875 #line 613 "treegen.pcc"
876 #line 613 "treegen.pcc"
881 //////////////////////////////////////////////////////////////////////////////
882 // Method to print a report of the generated tables.
883 //////////////////////////////////////////////////////////////////////////////
884 ostream& TreeGenerator::print_report(ostream& log) const
886 ///////////////////////////////////////////////////////////////////////////
887 // (1) Print the item set.
888 ///////////////////////////////////////////////////////////////////////////
889 { log << "\nItems:\n";
890 for (Variable v = 0; v < max_non_terminal; v++) {
891 log << '{' << v << "}\t";
892 G.print(log, n_states[v]) << '\n';
896 ///////////////////////////////////////////////////////////////////////////
897 // (2) Print each state
898 ///////////////////////////////////////////////////////////////////////////
899 { log << "\nStates:\n";
900 for (State s = 0; s < number_of_states; s++) {
901 print_state(log,s);
904 return log;
907 //////////////////////////////////////////////////////////////////////////////
908 // Method to print a state
909 //////////////////////////////////////////////////////////////////////////////
910 ostream& TreeGenerator::print_state(ostream& log, State s) const
912 log << '<' << s << '>';
913 const BitSet& S = *d_states[s];
914 Variable v;
915 foreach_bit(v,S) G.print(log << '\t', n_states[v]) << '\n';
916 if (treegen.is_accept_state(s))
917 log << "\t[accept " << treegen.accept1_rule(s) << "]\n";
918 return log;
921 //////////////////////////////////////////////////////////////////////////////
922 // Client visible methods follow.
923 // All the work has been down by the class TreeGenerator.
924 // Class TreeGen simply ties things up together.
925 //////////////////////////////////////////////////////////////////////////////
927 //////////////////////////////////////////////////////////////////////////////
928 // Constructors and destructor of the class TreeGen.
929 //////////////////////////////////////////////////////////////////////////////
930 TreeGen:: TreeGen(Mem& m) : TreeAutomaton(m), impl(0) {}
931 TreeGen:: TreeGen(Mem& m, TreeGrammar& Gram)
932 : TreeAutomaton(m), impl(0) { compile(Gram); }
933 TreeGen::~TreeGen() { delete impl; }
935 //////////////////////////////////////////////////////////////////////////////
936 // This is the top level method to compile a tree grammar.
937 //////////////////////////////////////////////////////////////////////////////
938 void TreeGen::compile (TreeGrammar& Gram)
940 ///////////////////////////////////////////////////////////////////////////
941 // Let our superclass do its stuff first.
942 ///////////////////////////////////////////////////////////////////////////
943 Super::compile(Gram);
945 ///////////////////////////////////////////////////////////////////////////
946 // The internal representation is defined here.
947 ///////////////////////////////////////////////////////////////////////////
948 delete impl;
949 impl = new TreeGenerator(*this,Gram);
951 ///////////////////////////////////////////////////////////////////////////
952 // Now carry out the various steps.
953 ///////////////////////////////////////////////////////////////////////////
954 impl->assign_non_terminals(); // assign unique non-terminal names.
955 impl->compute_closures(); // compute transitive closures of non-terminals.
956 impl->compute_projections(); // compute the projections on functors.
957 impl->compute_representers(); // allocate the representor states.
958 impl->compute_initial_states(); // compute the initial states first.
959 impl->compute_transitions(); // compute the rest of the transitions.
962 //////////////////////////////////////////////////////////////////////////////
963 // Method to print a report of the generated tables.
964 //////////////////////////////////////////////////////////////////////////////
965 ostream& TreeGen::print_report(ostream& log) const
966 { Super::print_report(log);
967 if (impl) impl->print_report(log);
968 return log;
971 //////////////////////////////////////////////////////////////////////////////
972 // Method to print a state of the generated tables.
973 //////////////////////////////////////////////////////////////////////////////
974 ostream& TreeGen::print_state(ostream& log, State s) const
975 { if (impl) impl->print_state(log,s);
976 return log;
979 //////////////////////////////////////////////////////////////////////////////
980 // Algorithm name
981 //////////////////////////////////////////////////////////////////////////////
982 const char * TreeGen::algorithm() const { return "TreeGen"; }
983 #line 719 "treegen.pcc"
985 ------------------------------- Statistics -------------------------------
986 Merge matching rules = yes
987 Number of DFA nodes merged = 52
988 Number of ifs generated = 11
989 Number of switches generated = 10
990 Number of labels = 8
991 Number of gotos = 10
992 Adaptive matching = disabled
993 Fast string matching = disabled
994 Inline downcasts = disabled
995 --------------------------------------------------------------------------