1 ///////////////////////////////////////////////////////////////////////////////
3 // This file implements the tree rewriting/tree parsing compiler.
4 // This is used to implement the rewrite class/rewrite constructs of Prop.
6 ///////////////////////////////////////////////////////////////////////////////
9 #include <AD/automata/treegram.ph>
10 #include <AD/automata/treegen.h>
11 #include <AD/rewrite/burs_gen.h>
12 #include <AD/strings/quark.h>
16 #include "matchcom.ph"
24 ///////////////////////////////////////////////////////////////////////////////
26 // Constructor and destructor of the rewriting compiler.
28 ///////////////////////////////////////////////////////////////////////////////
29 RewritingCompiler::RewritingCompiler(ostream& f)
30 : CodeGen(f), MatchCompiler(f), rewriters(#[]) {}
31 RewritingCompiler::~RewritingCompiler() {}
33 ///////////////////////////////////////////////////////////////////////////////
35 // Import some type definitions from the tree grammar and hash table
38 ///////////////////////////////////////////////////////////////////////////////
39 typedef TreeGrammar::TreeProduction TreeProduction;
40 typedef TreeGrammar::Cost TreeCost;
41 typedef HashTable::Key Key;
42 typedef HashTable::Value Value;
44 ///////////////////////////////////////////////////////////////////////////////
46 // Method to generate the inference for a rewrite class.
48 ///////////////////////////////////////////////////////////////////////////////
49 void DatatypeCompiler::gen_rewrite_class
50 (Id class_name, Protocols protocols, TyQual qual)
51 { Bool is_app = qual & QUALapplicative;
53 "%^%s(const %s&); // no copy constructor"
54 "%^void operator = (const %s&); // no assignment"
56 "%^struct %s_StateRec * stack__, * stack_top__;",
57 class_name, class_name, class_name, class_name
61 "%^%s reduce(int, int&, int);"
62 "%^%s reduce(char, int&, int);"
63 "%^%s reduce(const char *, int&, int);"
64 "%^%s reduce(Quark, int&, int);"
65 "%^%s reduce(double, int&, int);"
66 "%n#ifdef PROP_BOOL_IS_IMPLEMENTED"
67 "%^%s reduce(bool, int&, int);"
69 (is_app ? "int " : "void"),
70 (is_app ? "char " : "void"),
71 (is_app ? "const char *" : "void"),
72 (is_app ? "Quark " : "void"),
73 (is_app ? "double " : "void"),
74 (is_app ? "bool " : "void")
77 Bool gen_traversal = qual & QUALtreeparser;
79 { for_each (Protocol, p, protocols)
81 { PROTOCOL { ty, syn = ! NOty ... }:
82 { gen_traversal = true;
89 { for_each (Protocol, p, protocols)
91 { PROTOCOL { ty, syn ... }:
92 { Ty t = is_app ? ty : mkrefty(ty);
93 Ty r = is_app ? ty : void_ty;
94 pr("%^ %t reduce(%t, int&, int);"
95 "%^inline virtual %t operator () (%t) { int s; %sreduce(redex,s,0); }",
98 (is_app ? "return " : "")
101 pr("%^ %t traverse(%t);",
102 (syn == NOty ? void_ty : syn), "", ty, "redex");
109 pr ("%-%^private:%+");
112 ///////////////////////////////////////////////////////////////////////////////
114 // Method to generate literals matching code.
116 ///////////////////////////////////////////////////////////////////////////////
117 void RewritingCompiler::gen_bottomup_literal
118 ( Id rewrite_class, // name of the rewrite class
119 TyQual qual, // type qualifiers
120 Ty ty, // type of literal
121 FunctorMap& F // functor map
123 { Bool is_app = qual & QUALapplicative;
124 pr ("%^inline %t %s::reduce(%t, int& s__, int r__)"
126 (is_app ? ty : void_ty), "",
127 rewrite_class, ty, "redex");
129 Exp selector = IDexp("redex");
130 MatchExps exps = #[ MATCHexp(selector,0) ];
131 MatchRules rules = #[];
133 // Translate patterns into matching rules.
134 foreach_entry (e, F.literal_map)
135 { Literal l = (Literal)F.literal_map.key(e);
136 if (type_of(l) == ty)
137 { Functor f = (Functor)F.literal_map.value(e);
138 Pat pat = LITERALpat(l);
139 pat->selector = selector;
140 MatchRule r = MATCHrule(0,pat,NOexp,NOcost,
141 #[ SETSTATEdecl(F.tree_gen->go(f)) ]);
145 #[ MATCHrule(0,WILDpat(), NOexp, NOcost, #[SETSTATEdecl(0)])];
146 rules = #[ r ... rules ];
150 // Compile the matching code.
151 if (rules != #[]) gen_match_stmt(exps,rules,MATCHnotrace);
152 else pr ("%^s__ = 0;");
154 if (is_app) pr ("%^return redex;");
158 ///////////////////////////////////////////////////////////////////////////////
160 // Method to generate the bottom up traversal code for one constructor.
162 ///////////////////////////////////////////////////////////////////////////////
163 static void gen_one_traversal
164 (RewritingCompiler& C, FunctorMap& F, Id id,
165 TyQual qual, Functor f, Cons cons, int arity, Ty datatype_ty)
166 { Bool is_app = qual & QUALapplicative;
167 const TreeAutomaton& treeGen = *F.tree_gen;
168 Bool is_array_con = is_array_constructor(cons->name);
169 Ty ty = component_ty(datatype_ty, cons);
170 Exp e = select(IDexp("redex"),cons);
172 Bool is_record = false;
174 // generate temporaries
175 int n = arity < 0 ? arity_of(ty) : arity;
176 { for (int j = 0; j < n; j++) C.pr("%^int s%i__;\n",j); }
178 // Optimize out singletons
179 Bool is_singleton = true;
180 { for (int i = n - 1; i >= 0; i--)
181 if (treeGen.index_range(f,i) > 1) is_singleton = false;
184 // Generate code to traversal the components and tally up the
185 // costs of the subcomponents.
186 if (is_app) C.pr("%^redex = %S%+", cons->name);
188 { NOty: { if (is_app) C.pr ("%-;\n"); }
189 | TYCONty(TUPLEtycon, tys):
191 if (is_app) C.pr("(");
192 for(i = 0, ts = tys; i < n && ts; i++, ts = ts->_2)
193 { if (F.is_known_type(ts->_1))
194 { C.pr ("%^reduce(%e, s%i__, r__)%s\n",
195 DOTexp(e,index_of(i+1)), i,
196 (is_app ? (i != n - 1 ? "," : "") : ";")
200 C.pr ("%^(s%i__ = 0, %e)%s // %T\n",
201 i, DOTexp(e,index_of(i+1)),
202 (i != n - 1 ? "," : ""), ts->_1);
204 C.pr ("%^s%i__ = 0; // %T\n", i, ts->_1);
207 if (is_app) C.pr("%-%^);\n");
209 | TYCONty(RECORDtycon (labs,_), tys):
210 { int i; Tys ts; Ids l;
213 if (is_app) C.pr("(");
214 for (l = labs, ts = tys, i = 0; l && ts; l = l->_2, ts = ts->_2, i++)
215 { if (F.is_known_type(ts->_1))
216 { C.pr ("%^reduce(%e, s%i__, r__)%s\n", DOTexp(e,l->_1), i,
217 (is_app ? (i != n - 1 ? "," : "") : ";"));
221 C.pr ("%^(s%i__ = 0, %e)%s // %T\n",
223 (i != n - 1 ? "," : ""), ts->_1);
225 C.pr ("%^s%i__ = 0; // %T\n", i, ts->_1);
229 if (is_app) C.pr("%-%^);\n");
232 { if (is_app) C.pr("(");
234 { if (F.is_known_type(ty))
235 { for (int i = 0; i < arity; i++)
236 { C.pr ("%^reduce(%e(%i), s%i__, r__)%s\n",
237 DOTexp(e,"at"), i, i,
238 (is_app ? (i != n - 1 ? "," : "") : ";"));
241 { for (int i = 0; i < arity; i++)
242 { C.pr ("%^(s_%i__ = 0, %e(%i))%s// %T\n",
243 i, DOTexp(e,"at"), i,
244 (is_app ? (i != n - 1 ? "," : "") : ";"), ty);
248 { if (F.is_known_type(ty))
249 { C.pr ("%^reduce(%e, s0__, r__)%s\n", e, (is_app ? "" : ";"));
252 C.pr ("%^(s0__ = 0, %e) // %T\n", e, ty);
254 C.pr ("%^s0__ = 0; // %T\n", ty);
257 if (is_app) C.pr("%-%^);\n");
261 // Generate code to compute the new state.
262 if (treeGen.arity_of(f) == 0 && ty != NOty) C.pr ("%?s__ = 0;");
263 else if (is_singleton) C.pr ("%?s__ = %i;", treeGen.go(f));
265 C.pr ("%^s__ = %s_theta_%i", id, f);
266 for (int i = 0, j = 0; i < n; i++)
267 { if (is_record && ! relevant[i]) continue;
268 if (treeGen.index_range(f,i) == 1)
270 else if (F.use_compression)
271 C.pr ("[%s_check[%i + s%i__] == %i ? %s_next[%i + s%i__] : 0]",
272 id, treeGen.compressed_offset(f,j), j,
273 treeGen.compressed_index(f,j),
274 id, treeGen.compressed_offset(f,j), j);
276 C.pr ("[%s_mu_%i_%i[s%i__]]", id, f, j, j);
283 ///////////////////////////////////////////////////////////////////////////////
285 // Method to generate the bottom up traversal code.
287 ///////////////////////////////////////////////////////////////////////////////
288 static void gen_traversal
289 (RewritingCompiler& C, FunctorMap& F, Id id,
290 TyQual qual, Functor f, Cons cons, Ty this_ty)
291 { if (is_array_constructor(cons->name))
292 { Exp vec_exp = select(IDexp("redex"),cons);
293 Exp len_exp = DOTexp(vec_exp,"len()");
294 Exp array_exp = DOTexp(vec_exp,"at");
295 Bool is_app = qual & QUALapplicative;
297 // switch on the length of the vector
298 C.pr("%^switch (%e) {%+\n", len_exp);
300 // generate traversals with specific lengths
301 foreach_entry (i, F.vector_map)
302 { VectorId vec_id = (VectorId)F.vector_map.key(i);
303 Functor fnct = (Functor)F.vector_map.value(i);
304 if (vec_id->cons == cons && ty_equal(vec_id->ty, this_ty))
305 { C.pr("%^case %i: {%+", vec_id->arity);
306 gen_one_traversal(C,F,id,qual,fnct,cons,vec_id->arity,this_ty);
307 C.pr("%-%^} break;");
311 // generate traversals of other lengths
312 C.pr("%^default: {%+");
313 C.pr ("%^int s0__;");
315 C.pr("%^%t args_[256];", this_ty, "");
316 C.pr("%^for(int _i_ = 0; _i_ < %e; _i_++)"
317 "%^{ %sreduce(%e(_i_), s0__, r__); }\n",
318 len_exp, (is_app ? "args_[_i_] = " : ""), array_exp);
320 C.pr("%^redex = %S(%e,args_);\n", mangle(cons->name), len_exp);
324 { gen_one_traversal(C,F,id,qual,f,cons,-1,this_ty);
328 ///////////////////////////////////////////////////////////////////////////////
330 // Method to generate one set of traversals
332 ///////////////////////////////////////////////////////////////////////////////
334 (RewritingCompiler& C, FunctorMap& F, Id rewrite_class, Functor f,
335 int n, Cons terms[], int opt, TyQual qual, Ty this_ty)
336 { Bool is_boxed = terms[0]->ty != NOty;
338 if (opt & OPTtaggedpointer) { prefix = "untagp("; suffix = ")"; }
339 else if (is_boxed) { prefix = ""; suffix = "->untag()"; }
340 else { prefix = suffix = ""; }
342 gen_traversal(C, F, rewrite_class, qual, f, terms[0], this_ty);
344 C.pr ("%^if (%sredex%s) {%+", prefix, suffix);
345 gen_traversal(C, F, rewrite_class, qual, f+1, terms[1], this_ty);
346 C.pr ("%-%^} else {%+");
347 gen_traversal(C, F, rewrite_class, qual, f, terms[0], this_ty);
350 C.pr ("%^switch ((int)%sredex%s) {%+", prefix, suffix);
351 for (int i = 0; i < n; i++)
352 { C.pr ((i == n - 1 ? "%^default: { %+" : "%^case %*: { %+"),
353 terms[i], #[], false);
354 gen_traversal(C, F, rewrite_class, qual, f + i, terms[i], this_ty);
361 ///////////////////////////////////////////////////////////////////////////////
363 // Method to generate action code for a datatype rewrite.
365 ///////////////////////////////////////////////////////////////////////////////
366 static void gen_action(RewritingCompiler& C, FunctorMap& F, Id id, Ty ty)
368 HashTable::Entry * e = F.rule_map.lookup(ty);
370 const TreeAutomaton& treeGen = *F.tree_gen;
372 // Check whether this subset of rules contains guards or
374 MatchRules rules = (MatchRules)F.rule_map.value(e);
375 Bool has_guard = false;
376 Bool has_cost_exp = false;
377 { for_each (MatchRule, r, rules)
379 { MATCHrule(_,_,guard,cost,_):
380 { if (guard != NOexp) has_guard = true;
382 { EXPcost _: { has_cost_exp = true; }
390 if (has_cost_exp || F.has_syn_attrib || F.gen_traversal)
391 C.pr("%^Rule rule__ = -1;");
394 // Case when there are cost minimization to perform.
395 C.pr ("%^const unsigned char * a__ = %s_accept[s__];"
396 "%^Cost cost__ = infinite_cost, tmp_cost__;"
400 // Generate guard and cost minimization code.
401 for_each (MatchRule, r, rules)
403 { MATCHrule(_,_,guard,cost,action):
404 { int rule_no = r->rule_number;
405 C.pr ("%^if (a__[%i] & %i)%+%^",
406 (rule_no / 8), 1 << (rule_no & 7));
407 if (guard != NOexp) C.pr("if (%e) ", guard);
409 { NOcost: // if no cost is used, assume cost of zero
410 { C.pr("{ cost__ = 0; rule__ = %i; }", rule_no); }
411 | INTcost i: // a constant integer cost
412 { C.pr("if (%i < cost__)"
413 "%+%^{ cost__ = %i; rule__ = %i; }%-",
415 | EXPcost (e,_): // a cost expression
416 { C.pr("if ((tmp_cost__ = %e) < cost__)"
417 "%+%^{ cost__ = tmp_cost__; rule__ = %i; }%-",
425 // Update the new cost
426 C.pr ("%-%^} while (0);");
428 if (! F.gen_traversal)
429 { C.pr ("%^switch (rule__) {%+");
431 // Gererate all the actions.
432 { for_each (MatchRule, r, rules)
434 { MATCHrule(_,_,_,_,action):
435 { C.pr ("%^case %i: {%+%&%-%?} break;", r->rule_number, action); }
443 // Case when all the costs are zero.
445 // If we have a guard then generate code that performs
446 // state to accept rule decoding at runtime.
447 // Otherwise, perform the decoding at compile time.
449 C.pr("%^const Rule * o__ = %s_accept_vector + %s_accept_base[s__];"
451 "%^switch (*o__) {%+", id, id);
452 } else if (F.gen_traversal) {
453 C.pr("%^rule__ = %s_accept1[s__];",id);
455 C.pr("%^switch (s__) {%+");
458 // Now emit all the action code.
459 if (! F.gen_traversal || has_guard)
460 { for_each (MatchRule, r, rules)
462 { MATCHrule(_,_,guard,_,action):
464 C.pr("%^case %i: ", r->rule_number);
466 int rule_no = r->rule_number;
468 for (int s = treeGen.number_of_states() - 1; s >= 0; s--)
469 if (treeGen.accept1_rule(s) == rule_no)
470 { C.pr ("%^case %i: ", s); used = true; }
471 if (! used) continue;
473 if (guard != NOexp) C.pr ("if (%e)%^", guard);
475 C.pr ("rule__ = %i;", r->rule_number);
477 C.pr ("%+{%&}%-", action);
479 C.pr ("%^else { ++o__; goto accept__; }");
490 ///////////////////////////////////////////////////////////////////////////////
492 // Method to generate datatype rewriting code.
494 ///////////////////////////////////////////////////////////////////////////////
495 void RewritingCompiler::gen_bottomup_datatype
496 ( Id rewrite_class, // name of the rewrite class
497 TyQual qual, // type qualifiers
498 Ty ty, // type of datatype
499 FunctorMap& F // functor map
501 { Bool is_app = qual & QUALapplicative;
502 Ty arg_ty = is_app ? ty : mkrefty( ty );
503 Ty ret_ty = is_app ? ty : void_ty;
504 pr ("%^%t %s::reduce(%t, int& s__, int r__)"
506 "%^replacement__:%+",
507 ret_ty, "", rewrite_class, arg_ty, "redex");
510 (Used::replacement || F.has_syn_attrib || F.gen_traversal) &&
511 has_qual(QUALrewritable,ty) &&
512 boxed_variants(ty) > 0;
517 { TYCONty(DATATYPEtycon { opt ... }, _) | opt & OPTtaggedpointer:
518 { redex = "derefp(redex)"; }
519 | _: { redex = "redex"; }
522 // generate code to cut short replacement.
524 pr ("%^if (r__ && boxed(redex) && %s->has_rewrite_state())"
525 "%^{ s__ = %s->get_rewrite_state(); return%s; }",
526 redex, redex, (is_app ? " redex" : ""));
528 // if we have cost or synthesized attribute then allocate a new
531 pr ("%^%s_StateRec * t__ = "
532 "%^ (%s_StateRec *)mem[sizeof(%s_StateRec)];",
533 F.class_name, F.class_name, F.class_name);
535 Functor f = (Functor)F.type_map[ty];
537 // Generate code for bottom up traversal and state computation.
539 { TYCONty(DATATYPEtycon { unit, arg, terms, opt ... }, _):
540 { int arity = unit + arg;
541 Bool fast_encoding = false;
542 int first_state = F.tree_gen->go(f);
545 for (j = arity - 1; j >= 0; j--)
546 if (first_state + j != F.tree_gen->go(f+j)) break;
547 fast_encoding = j < 0;
551 pr ("%^s__ = redex + %i;", F.tree_gen->go(f));
554 gen_traversals(*this, F, rewrite_class, f, unit, terms, opt, qual, ty);
555 } else if (unit == 0) {
556 gen_traversals(*this, F, rewrite_class, f, arg, terms, opt, qual, ty);
558 pr ("%^if (%s(redex)) {%+", (unit > 1 ? "boxed" : ""));
559 gen_traversals(*this, F, rewrite_class, f + unit, arg, terms + unit, opt, qual, ty);
560 pr ("%-%^} else {%+");
561 gen_traversals(*this, F, rewrite_class, f, unit, terms, opt, qual, ty);
569 // Generate code for rewriting actions
570 gen_action(*this, F, rewrite_class, ty);
572 // if (F.has_cost) pr ("%^t__->cost = cost__;");
574 // Generate code to cache the current state.
576 pr ("%^if (boxed(redex)) {%+"
577 "%^%s->set_rewrite_state(s__);", redex);
578 if (F.gen_traversal) pr ("%^%s->set_rewrite_rule(rule__);", redex);
582 if (is_app) pr ("%^return redex;");
586 ///////////////////////////////////////////////////////////////////////////////
588 // Method to generate the tree automaton tables.
590 ///////////////////////////////////////////////////////////////////////////////
592 (Id id, RewritingCompiler& C, const TreeGrammar& G, FunctorMap& F)
593 { ostream& out = C.pr("");
595 if (F.gen_traversal) {
596 // Emit the accept state tables.
597 F.tree_gen->gen_accept1(out,id) << '\n';
600 if (F.has_cost_exp) {
601 // Emit the bitmap table if we have cost expressions.
602 F.tree_gen->gen_bitmap_accept(out,id) << '\n';
605 // Emit the base/check accept state table also if we have guards.
606 F.tree_gen->gen_accept(out,id) << '\n';
609 // Elided in the new accept table scheme
610 // if (F.has_guard) {
611 // // Generate a function that looks for the next accept rule given
612 // // the current state and the current rule. This function is called
613 // // when the current guard fails.
614 // C.pr("%^static int %s_next_rule(register int s, register int r)"
615 // "%^{ register const unsigned char * mask = %s_accept[s];"
616 // "%^ while (++r < %i && (mask[r/8] & (1 << (r & 7))) == 0);"
622 // Emit the theta tables
623 { for (Functor f = G.min_functor(); f <= G.max_functor(); f++)
624 { if (G.arity(f) > 0) {
625 C.pr ("%^static const TreeTables::State %s_theta_%i", id, f);
626 F.tree_gen->gen_delta(out,f);
632 if (F.use_compression) {
633 // Emit the compressed index map.
634 F.tree_gen->gen_compressed_index(out,id) << '\n';
635 // C.pr ("%^inline int %s_go (int s, int offset)"
636 // "%^{ return %s_check[offset] == s ? %s_next[offset] : 0; }\n\n",
639 // Emit the index maps for each arity of each functor.
640 { for (Functor f = G.min_functor(); f <= G.max_functor(); f++)
641 for (int i = 0; i < G.arity(f); i++)
642 { C.pr ("%^static const TreeTables::State %s_mu_%i_%i", id, f, i);
643 F.tree_gen->gen_index(out,f,i);
650 ///////////////////////////////////////////////////////////////////////////////
652 // Generate the state record type.
654 ///////////////////////////////////////////////////////////////////////////////
655 static void gen_state_record
656 ( RewritingCompiler& C, FunctorMap& F,
657 Id class_name, Protocols protocols, MatchRules rules)
659 C.pr ("%^%/%^// State record for rewrite class %s%^%/"
660 "%^struct %s_StateRec {%+", class_name, class_name);
662 C.pr ("%^BURS::Rule rule; // reduction rule"
663 "%^BURS::State state; // current state",
666 // Generate the cost vector
668 { C.pr ("%^BURS::Cost cost__[%i];", F.type_map.size());
671 // Map from rewrite type to type of synthesized attribute.
672 if (F.has_syn_attrib) {
673 HashTable syn_map (ty_hash, ty_equal);
674 { for_each (Protocol, p, protocols)
676 { PROTOCOL { ty, syn = syn as ! NOty ... }:
677 { syn_map.insert(ty, syn); }
685 // Generate the inherited attributes for each rule that needs
688 for_each (MatchRule, r, rules)
690 HashTable::Entry * e = syn_map.lookup(ty);
692 Ty syn_ty = (Ty)syn_map.value(e);
693 C.pr ("%^%t;", syn_ty, index_of(i));
704 C.pr ("%^%s_StateRec * kids[%i]; // children", class_name, F.max_arity);
709 ///////////////////////////////////////////////////////////////////////////////
711 // Generate a traversal function for one pattern.
713 ///////////////////////////////////////////////////////////////////////////////
714 int RewritingCompiler::gen_pattern_traversal(FunctorMap& F, Pat pat, int i)
716 { NOpat || LITERALpat _ || CONSpat _ || CONTEXTpat _ ||
718 | ASpat(_,p,_,_): { i = gen_pattern_traversal(F,p,i); }
719 | TYPEDpat(p,_): { i = gen_pattern_traversal(F,p,i); }
720 | MARKEDpat(_,p): { i = gen_pattern_traversal(F,p,i); }
721 | GUARDpat(p,_): { i = gen_pattern_traversal(F,p,i); }
722 | APPpat (_,p): { i = gen_pattern_traversal(F,p,i); }
723 | IDpat _ || WILDpat _:
724 { if (F.is_rewritable_type(pat->ty)) {
725 Protocol proto = (Protocol)F.protocols[pat->ty];
726 if (! has_qual(QUALrewritable,deref_all(pat->ty)))
727 { error ("%Ldatatype %T must be rewritable\n", pat->ty);
730 { PROTOCOL { syn = NOty ... }:
731 { pr("%^traverse(%e);", pat->selector); }
732 | PROTOCOL { syn ... }:
733 { pr("%^%t _%i__ = traverse(%e);", syn, "", i, pat->selector); }
738 | ARRAYpat(ps,_): { for_each(Pat, p, ps) i = gen_pattern_traversal(F,p,i);}
739 | TUPLEpat ps: { for_each(Pat, p, ps) i = gen_pattern_traversal(F,p,i); }
740 | EXTUPLEpat ps: { for_each(Pat, p, ps) i = gen_pattern_traversal(F,p,i); }
741 | RECORDpat (labPs,_):
742 { for_each (LabPat, p, labPs) i = gen_pattern_traversal(F,p.pat,i); }
743 | LISTpat { head, tail ... }:
744 { for_each (Pat, p, head) i = gen_pattern_traversal(F,p,i);
745 i = gen_pattern_traversal(F,tail,i);
747 | VECTORpat { array, elements, len ... }:
748 { for_each (Pat, p, elements) i = gen_pattern_traversal(F,p,i);
749 i = gen_pattern_traversal(F,array,i);
750 i = gen_pattern_traversal(F,len,i);
752 | _: { bug("RewritingCompiler::gen_pattern_traversal: %p", pat); }
757 ///////////////////////////////////////////////////////////////////////////////
759 // Method to generate an attribute evaluation traversal routine for
760 // a datatype. This is the second pass of the algorithm. We assume
761 // that the tree has already been properly labeled.
763 ///////////////////////////////////////////////////////////////////////////////
764 void RewritingCompiler::gen_datatype_traversal (FunctorMap& F, Ty ty)
765 { HashTable::Entry * e = F.rule_map.lookup(ty);
767 { MatchRules rules = (MatchRules)F.rule_map.value(e);
768 Functor f = (Functor)F.type_map[ty];
771 // Check the protocol of this datatype
772 Protocol proto = (Protocol)F.protocols[ty];
774 { PROTOCOL { syn = NOty ... }: { syn_ty = void_ty; }
775 | PROTOCOL { syn ... }: { syn_ty = syn; }
778 // The name and protocol of this traversal function
779 pr("%^%t %s::traverse(%t)"
781 syn_ty, "", F.class_name, ty, "redex"
784 if (syn_ty != void_ty) pr ("%^%t;", syn_ty, "__");
786 // The name and protocol of this traversal function
788 { TYCONty(DATATYPEtycon { unit = 0, arg, opt ... }, _):
789 { Id redex_var = (opt & OPTtaggedpointer) ? "derefp(redex)" : "redex";
790 pr("%^int r__ = %s->get_rewrite_rule();", redex_var); }
791 | TYCONty(DATATYPEtycon { unit, arg, opt ... }, _):
792 { Id table_name = vars.new_label();
793 Id redex_var = (opt & OPTtaggedpointer) ? "derefp(redex)" : "redex";
795 { pr("%^static const Rule %s[] = { ",table_name);
796 for (int i = 0; i < unit; i++)
797 { pr ("%i", F.tree_gen->accept1_rule(F.tree_gen->go(f+i)));
798 if (i != unit - 1) pr (", ");
801 pr("%^int r__ = boxed(redex) ? %s->get_rewrite_rule() : %s[int(%s)];",
802 redex_var, table_name, redex_var);
804 pr("%^int r__ = boxed(redex) ? %s->get_rewrite_rule() : %i;",
805 redex_var, F.tree_gen->accept1_rule(F.tree_gen->go(f)));
807 | _: { bug("RewritingCompiler::gen_datatype_traversal()"); }
811 pr ("%^switch (r__) {%+");
813 for_each(MatchRule, r, rules)
815 { MATCHrule(_,pat,_,_,action):
816 { pr ("%^case %i: {%+", r->rule_number);
817 gen_pattern_traversal(F,pat,0);
818 pr ("%^%&} break;%-", action);
825 if (syn_ty != void_ty) pr ("%^return __;");
830 ///////////////////////////////////////////////////////////////////////////////
832 // Top level method to compile a set of rewrite rules.
834 ///////////////////////////////////////////////////////////////////////////////
835 void RewritingCompiler::gen_rewrite(Id rewrite_class, MatchRules rules)
837 MemPoolMark marker = mem_pool.getMark(); // get a memory pool marker
838 int N = length(rules); // number of rules
839 FunctorMap F(N,rewrite_class); // the functor encoding map.
840 int last_errors = errors;
841 Protocols protocols = lookup_rewrite_class(rewrite_class);
843 // Encodes and enters all protocols.
844 { for_each (Protocol, p, protocols)
846 { PROTOCOL { ty, syn ... }:
847 { F.encode(ty); F.protocols.insert(ty,p);
848 if (syn != NOty) F.has_syn_attrib = true;
855 if (PropOptions::trace) instrument_trace(rules);
857 // Type checking, then partition rules by type and encode the patterns.
858 F.partition_rules (rules);
860 // Checks for missing protocols.
861 foreach_entry (e, F.type_map)
862 { Ty ty = (Ty)F.type_map.key(e);
863 if (! F.protocols.contains(ty))
864 error ("%Lmissing type %T in the protocols of rewrite class %s\n",
868 if (errors == last_errors)
872 TreeProduction * productions
873 = (TreeProduction *)mem_pool.c_alloc(sizeof(TreeProduction) * N);
875 = (Id *)mem_pool.c_alloc(sizeof(Id) * F.functors);
877 = (Id *)mem_pool.c_alloc(sizeof(Id) * (F.variables + N + 4));
878 TyQual qual = TyQual(rewrite_qual.lookup(rewrite_class)->v);
879 F.gen_traversal = (qual & QUALtreeparser) || F.has_syn_attrib;
881 // translate patterns into terms
883 for_each (MatchRule, r, rules)
885 { MATCHrule(lhs,pat,guard,cost,_):
886 { int rule_no = lhs ? Variable(F.var_map.lookup(lhs)->v) : 0;
888 match (cost) // extract cost
889 { NOcost: { cst = TreeTables::zero_cost; }
890 | INTcost c: { cst = c;
891 if (c != 0) F.has_cost = true;
893 | EXPcost _: { cst = TreeTables::zero_cost;
894 F.has_cost_exp = true;
897 productions[i] = TreeProduction(rule_no,F.trans(pat),cst);
898 if (guard != NOexp) F.has_guard = true;
905 F.compute_names (functor_names, variable_names);
907 // compile the tree grammar
908 G.compile (N, productions, functor_names, variable_names,
909 0, F.functors - 1, 0);
911 if (qual & QUALtopdown)
912 gen_topdown (rewrite_class,rules,N,protocols,F,qual,
913 G,functor_names,variable_names);
915 gen_bottomup(rewrite_class,rules,N,protocols,F,qual,
916 G,functor_names,variable_names);
918 mem_pool.setMark(marker); // reset the memory pool to reclaim memory
921 ///////////////////////////////////////////////////////////////////////////////
923 // Generate code for bottom-up rewriting.
925 ///////////////////////////////////////////////////////////////////////////////
926 void RewritingCompiler::gen_bottomup( Id rewrite_class,
937 // Create a new memory pool
938 MemPool my_pool(4096);
940 // allocate a new tree automata compiler
941 debug_msg("[Compiling %i rewriting rules for class %s]\n",
943 if (PropOptions::burs || F.has_cost)
944 F.tree_gen = new BURS_Gen (my_pool);
946 F.tree_gen = new TreeGen (my_pool);
948 // compile the tree automata
949 F.tree_gen->compile (G);
950 debug_msg("[Compressing index maps for class %s]\n", rewrite_class);
951 F.tree_gen->compile_compression_index();
952 debug_msg("[Done]\n");
954 // check for compression rate
955 double shrinkage = F.tree_gen->compression_rate();
956 if (shrinkage <= 0.3 || F.tree_gen->number_of_states() <= 40) {
957 F.use_compression = false;
960 // Generate the state record type.
961 gen_state_record(*this, F, rewrite_class, protocols, rules);
963 // generate the tables
964 generate_tables(rewrite_class, *this, G, F);
966 // Choose whether to build an isomorphic parse tree or
967 // using the semantic value stack (or neither)
968 if (F.has_cost) { F.iso_tree = true; }
969 if (F.has_syn_attrib) { F.use_stack = true; }
970 print_semantic_stack = F.use_stack;
972 // generate the matching code for literals
973 gen_bottomup_literal(rewrite_class, qual, integer_ty, F);
974 gen_bottomup_literal(rewrite_class, qual, character_ty, F);
975 gen_bottomup_literal(rewrite_class, qual, real_ty, F);
976 gen_bottomup_literal(rewrite_class, qual, string_ty, F);
977 gen_bottomup_literal(rewrite_class, qual, quark_ty, F);
978 pr ("%n#ifdef PROP_BOOL_IS_IMPLEMENTED\n");
979 gen_bottomup_literal(rewrite_class, qual, bool_ty, F);
982 // generate the matching code for datatypes
983 { foreach_entry(e, F.type_map)
984 { Ty ty = (Ty)F.type_map.key(e);
985 gen_bottomup_datatype(rewrite_class, qual, ty, F);
987 gen_datatype_traversal(F, ty);
991 // print report if necessary
992 if (PropOptions::generate_report) F.print_report(open_logfile());