1 ///////////////////////////////////////////////////////////////////////////////
3 // This file implements the backend for pattern matching,
4 // string matching, and lexical scanning constructs. C++ code is
5 // emitted in this file.
7 ///////////////////////////////////////////////////////////////////////////////
11 #include <strstream.h>
12 #include <AD/contain/bitset.h>
13 #include <AD/automata/lexergen.h>
14 #include <AD/strings/charesc.h>
15 #include <AD/memory/mempool.h>
16 #include <AD/sort/heapsort.h>
17 #include <AD/sort/heapsrt2.h>
20 #include "matchcom.ph"
28 ///////////////////////////////////////////////////////////////////////////////
30 // Class to mark the current rule.
32 ///////////////////////////////////////////////////////////////////////////////
33 MarkCurrentRule::MarkCurrentRule(MatchRule& c, MatchRule n)
34 : current_rule(c), old_rule(c) { c = n; }
35 MarkCurrentRule::~MarkCurrentRule() { current_rule = old_rule; }
37 ///////////////////////////////////////////////////////////////////////////////
39 // Method to extract the line number of the current rule
41 ///////////////////////////////////////////////////////////////////////////////
42 int MatchCompiler::current_rule_line() const
43 { if (current_rule == 0) bug("MatchCompiler::current_rule_line()\n");
44 return current_rule->begin_line;
47 ///////////////////////////////////////////////////////////////////////////////
49 // Method to extract the text of the current rule
51 ///////////////////////////////////////////////////////////////////////////////
52 const char * MatchCompiler::current_rule_text() const
53 { if (current_rule == 0) bug("MatchCompiler::current_rule_text()\n");
55 ostrstream stream(buffer,sizeof(buffer));
56 std::ostream& s = stream;
57 s << current_rule << ends;
58 buffer[sizeof(buffer)-1] = '\0';
59 return make_quoted_string(buffer);
62 ///////////////////////////////////////////////////////////////////////////////
66 ///////////////////////////////////////////////////////////////////////////////
67 HashTable * current_index_map = 0;
68 Bool merge_match = true; // should we merge the DFAs?
69 Id current_failure = 0; // jump label for failure
71 ///////////////////////////////////////////////////////////////////////////////
73 // Is the expression simple?
75 ///////////////////////////////////////////////////////////////////////////////
76 Bool is_simple_exp (Exp exp)
78 { IDexp _ || LITERALexp _: { return true; }
79 | MARKEDexp(_,e): { exp = e; }
80 | _: { return false; }
85 ///////////////////////////////////////////////////////////////////////////////
87 // Generate match variable bindings for complex match expressions.
89 ///////////////////////////////////////////////////////////////////////////////
90 void compute_match_variables(MatchExps exps)
91 { static LabelGen vars("_V");
92 for_each (MatchExp, me, exps)
94 { MATCHexp(e,mv) | mv == 0 && ! is_simple_exp(e):
95 { mv = vars.new_label(); }
101 ///////////////////////////////////////////////////////////////////////////////
103 // Generate pattern matching code from a match dag
105 ///////////////////////////////////////////////////////////////////////////////
106 void MatchCompiler::gen(Match mt, MatchOptions match_options, Ty match_ty)
108 if (mt == FAILmatch) {
109 if (current_failure) pr ("%? goto %s; ", current_failure);
113 // check for duplicates
114 if (mt->label) { pr ("%? goto %s; ", mt->label); gotos++; return; }
115 if (mt->shared > 1) { goto_labels++;
116 pr ("%^%s:; ", mt->label = labels.new_label()); }
119 | SUCCESSmatch(_, r as MATCHrule(_,_,_,_,decls)):
120 { MarkCurrentRule mark(current_rule,r); pr ("%&", decls); }
121 | COSTmatch(n,_,set,rules): { gen_cost_success_match(n,set,rules); }
122 | TREECOSTmatch(m,set,rules): { gen_treecost_match(m,set,rules); }
123 | TREELABELmatch(m,t1,t2,i): { gen_treelabel_match(m,t1,t2,i); }
124 | SUCCESSESmatch (n,set,rules):
125 { if (current_options & MATCHwithtreecost)
126 gen_treecost_match(FAILmatch,set,rules);
128 gen_success_match(n,set,rules);
130 | RANGEmatch(pos,e,lo,hi,a,b): { gen_range_match(pos,e,lo,hi,a,b,mt); }
131 | GUARDmatch (e,a,b):
132 { ifs++; pr ("%^if (%E) {%+%^%m%-%?} else {%+%^%m%-%?}\n",e,a,b); }
134 DATATYPEty({ view_match, id, terms, qualifiers, opt ... },_),n,m,d)
135 | qualifiers & QUALview:
136 { gen_view_match (id, e, view_match, n, terms, m, d,
137 opt, qualifiers & QUALextensible); }
139 DATATYPEty({ id, unit, arg = 0, terms, qualifiers, opt ... },_),n,m,d):
140 { gen_switch (id, e, ty, unit, terms, m, d, mt->shared,
141 false, false, opt, qualifiers & QUALextensible); }
143 DATATYPEty({ id, unit = 0, arg, terms, qualifiers, opt ... },_),n,m,d):
144 { gen_switch (id, e, ty, arg, terms, m, d, mt->shared,
145 false, true, opt, qualifiers & QUALextensible); }
147 DATATYPEty({ id, unit, arg, terms, opt, qualifiers ... },_),n,m,d):
149 pr ((unit > 1 ? "%^if (boxed(%e)) {%+" : "%^if (%e) {%+"), e);
150 gen_switch (id, e, ty, arg, terms + unit, m + unit, d, mt->shared,
151 true, true, opt, qualifiers & QUALextensible);
152 pr ("%-%?} else {%+");
153 gen_switch (id, e, ty, unit, terms, m, d, mt->shared,
154 true, false, opt, qualifiers & QUALextensible);
157 | LITERALmatch(_,e,l as [BOOLlit _ || INTlit _ || CHARlit _], n, a, b):
160 { BOOLlit _: { is_boolean = true; }
161 | _: { is_boolean = false; }
164 pr ("%^switch (%e) {\n%+", e);
165 for (int i = 0; i < n; ) {
167 for (j = i+1; j < n; j++) if (a[i] != a[j]) break;
169 if (is_boolean && j == n && n == 2) {
170 pr ("%^default:"); i = n;
172 for ( ; i < j; i++) {
173 pr ("%^case %l:", l[i]);
174 if (i != j - 1) pr ("\n");
177 pr(" {%+%m%-%?} break;\n", a[k]);
179 if (! is_boolean || n < 2) pr ("%^default: {%+%m%-%?}", b);
182 | LITERALmatch(_,e,l as [REALlit _ || STRINGlit _], n, a, b):
183 { gen_binary_search_on_literals(e,n,l,a,b); }
184 | LITERALmatch(_,e,l as [REGEXPlit _], n, a, b):
185 { if (options.generate_report) open_logfile() << mt << '\n';
186 gen_regexp_match(e,n,l,a,b,match_options,match_ty);
188 | LITERALmatch(_,e,l as [QUARKlit _], n, a, b):
189 { gen_quark_match(e,n,l,a,b,match_options); }
190 | _: { bug ("gen(Match)"); }
194 ///////////////////////////////////////////////////////////////////////////////
196 // Method to generate a bitmap of all the successful matching rules.
198 ///////////////////////////////////////////////////////////////////////////////
199 void MatchCompiler::gen_success_match(int n, const BitSet * set, MatchRules)
200 { pr ("%^{%+ static const unsigned char matched_set__[%i] =\n%^{ %+",
203 for(int i = 0; i < (n + 7) / 8; i++) {
204 if (i > 0) pr (", ");
205 if (i != 0 && (i % 8) == 0) pr ("%^");
206 pr ("%i ", (int)set->byte(i));
209 "%^m__ = matched_set__;\n"
214 ///////////////////////////////////////////////////////////////////////////////
216 // Method to generate code for cost minimalization.
218 ///////////////////////////////////////////////////////////////////////////////
219 void MatchCompiler::gen_cost_success_match(int n, const BitSet * set,
224 { if ((*set)[rule_no])
226 { MATCHrule (_,_,_,cost,_):
241 ///////////////////////////////////////////////////////////////////////////////
243 // Method to generate a switch statement for pattern matching.
244 // This method is responsible for generating optimized code for a one-level
245 // match using C++'s "switch" statement.
247 ///////////////////////////////////////////////////////////////////////////////
248 void MatchCompiler::gen_switch
249 (Id id, Exp e, Ty ty, int n, Cons terms[], Match m[], Match def, int shared,
250 Bool variant, Bool boxed, TyOpt optimizations, Bool is_refutable)
252 if (n == 1) { // only one arm
254 } else if (n == 2) { // two arms, use "if"
256 merges++; if (m[0] != FAILmatch) m[0]->shared -= shared; gen(m[0]);
261 if (optimizations & OPTtaggedpointer)
262 { prefix = "untagp("; suffix = ")"; }
264 { prefix = ""; suffix = "->tag__"; }
265 } else { prefix = suffix = ""; }
267 pr ("%^if (%s%e%s) {%+%^%m%-%?} else {%+%^%m%-%?}\n",
268 prefix, e, suffix, m[1], m[0]);
271 /////////////////////////////////////////////////////////////////////////
272 // The following is the general case for handling n-ary branches.
273 /////////////////////////////////////////////////////////////////////////
276 /////////////////////////////////////////////////////////////////////////
277 // If all n branches are the same, eliminate the match
278 /////////////////////////////////////////////////////////////////////////
279 for (i = n - 1; i > 0; i--) if (m[i] != m[i-1]) break;
280 if (i == 0) { if (m[0] != FAILmatch) m[0]->shared -= (n-1) * shared;
281 merges++; gen(m[0]); return;
287 /////////////////////////////////////////////////////////////////////////
288 // Generate the "switch" expression.
289 /////////////////////////////////////////////////////////////////////////
291 if (optimizations & OPTtaggedpointer)
292 { prefix = "untagp("; suffix = ")"; }
294 { prefix = ""; suffix = "->tag__"; }
297 { prefix = "(int)"; suffix = ""; }
299 { prefix = suffix = ""; }
301 pr ("%^switch (%s%e%s) {\n%+", prefix, e, suffix);
303 /////////////////////////////////////////////////////////////////////////
304 // Partition the arms of the matches into alternatives with the
305 // same actions. Sort the partitions in increasing sizes.
306 /////////////////////////////////////////////////////////////////////////
308 { Cons term; Match action; int tag; };
309 struct MatchPartition
310 { int count; Conses terms; Match action; int first_tag; };
311 ConsMatch * sorted = (ConsMatch *)mem_pool.c_alloc
312 (sizeof(ConsMatch) * n);
313 MatchPartition * parts = (MatchPartition *)mem_pool.c_alloc
314 (sizeof(MatchPartition) * n);
315 int number_of_parts = 0;
316 { for (i = 0; i < n; i++)
317 { sorted[i].term = terms[i];
318 sorted[i].action = m[i];
319 if (terms[i] != NOcons) sorted[i].tag = terms[i]->tag;
322 // sort branches according the actions
323 heapSort(ConsMatch, sorted, n,
324 (key.action < sorted[i].action ||
325 key.action == sorted[i].action &&
326 key.tag < sorted[i].tag));
328 // partition each branch by action
329 for (i = n - 1; i >= 0; i--)
330 { if (i == n-1 || sorted[i].action != sorted[i+1].action)
331 { parts[number_of_parts].terms = #[sorted[i].term];
332 parts[number_of_parts].action = sorted[i].action;
333 parts[number_of_parts].count = 1;
334 parts[number_of_parts].first_tag = sorted[i].tag;
337 parts[number_of_parts-1].terms =
338 #[sorted[i].term ... parts[number_of_parts-1].terms];
339 parts[number_of_parts-1].count++;
340 if (parts[number_of_parts-1].first_tag > sorted[i].tag)
341 parts[number_of_parts-1].first_tag = sorted[i].tag;
345 // Sort partitions in order of frequency; so that
346 // the most frequent case becomes the "default" inside
347 // the "switch" statement.
348 heapSort(MatchPartition, parts, number_of_parts,
349 (key.count < parts[i].count ||
350 key.count == parts[i].count &&
351 key.first_tag < parts[i].first_tag));
354 /////////////////////////////////////////////////////////////////////////
355 // Generate the arms of the "switch".
356 // We try to combine the arms that are the same together into
357 // one rule to help the compiler.
358 /////////////////////////////////////////////////////////////////////////
359 for (i = 0; i < number_of_parts; i++)
360 { if (i == number_of_parts - 1) {
363 Conses tags = parts[i].terms;
366 { pr ("%^case %*:", one, false);
367 if (rest != #[]) pr ("\n");
372 if (parts[i].action != FAILmatch)
373 parts[i].action->shared -= (parts[i].count - 1) * shared;
374 pr (" {%+%?%m%?} break;\n%-", parts[i].action);
381 ///////////////////////////////////////////////////////////////////////////////
383 // Generate binary search for testing literals
385 ///////////////////////////////////////////////////////////////////////////////
386 void MatchCompiler::gen_binary_search_on_literals
387 (Exp e, int n, Literal l[], Match m[], Match d)
389 /////////////////////////////////////////////////////////////////////////
390 // Generate linear tests for simple literal tests.
391 /////////////////////////////////////////////////////////////////////////
392 for (int i = 0; i < n; i++) {
394 if (i > 0) pr("%^else "); else pr ("%^");
395 pr ("if (%=(%e,%l)) {%m}\n",l[i], e, l[i], m[i]);
397 if (d != FAILmatch) pr ("%^else {%m}\n", d);
398 else if (current_failure) pr ("%^else goto %s;\n", current_failure);
400 /////////////////////////////////////////////////////////////////////////
401 // Generate binary search for tests containing many alternatives.
402 /////////////////////////////////////////////////////////////////////////
405 pr ("%^if (%<(%e,%l)) {\n%+", l[k], e, l[k]);
406 gen_binary_search_on_literals(e,k,l,m,d);
407 pr ("%-%^} else {\n%+");
408 gen_binary_search_on_literals(e,n-k,l+k,m+k,d);
413 ///////////////////////////////////////////////////////////////////////////////
415 // Generate range matching
417 ///////////////////////////////////////////////////////////////////////////////
418 void MatchCompiler::gen_range_match
419 (Pos pos, Exp e, int lo, int hi, Match a, Match b, Match m)
422 pr ("%^switch (%e) {%+",e);
424 { RANGEmatch (p, e, low, high, a, b) | low == high && pos_equal(pos,p):
425 { pr ("%^case %i: {%+%m%-%?} break;", low, a); m = b; }
427 pr ("%^default: {%+%m%-%?}"
433 pr ("%^if (%e <= %i) {%+%^%m%-%?} else {%+%^%m%-%?}\n",e,hi,a,b);
434 } else if (hi == INT_MAX) {
435 pr ("%^if (%e >= %i) {%+%^%m%-%?} else {%+%^%m%-%?}\n",e,lo,a,b);
437 pr ("%^if (%i <= %e && %e <= %i) {%+%^%m%-%?} else {%+%^%m%-%?}\n",
443 ///////////////////////////////////////////////////////////////////////////////
445 // Generate view matching
447 ///////////////////////////////////////////////////////////////////////////////
448 void MatchCompiler::gen_view_match
449 (Id id, Exp e, Exp view_match, int n, Cons terms [], Match m[], Match d,
450 TyOpt opt, TyQual qual)
451 { if (view_match != NOexp)
453 pr ("%^switch (%e) {%+", subst(view_match,&e));
454 for (int i = 0; i < n; i++)
455 { pr ("%^case %e: {%+%m%-%?} break;", terms[i]->view_predicate, m[i]);
460 for (i = 0; i < n; i++)
462 for (j = i + 1; j < n; j++) if (m[i] != m[j]) break;
464 Exp predicate_fun = terms[i]->view_predicate;
465 Exp predicate = subst(predicate_fun,&e);
467 pr("%^%sif (%e) {%+%^%m%-%?} ",
468 (i > 0 ? "else " : ""), predicate, m[i]);
471 pr ("%^%s{%+%^%m%-%?}\n", (i > 0 ? "else " : ""), m[i]);
475 ///////////////////////////////////////////////////////////////////////////////
477 // Generate regular expression matching as a DFA.
479 ///////////////////////////////////////////////////////////////////////////////
480 void MatchCompiler::gen_regexp_match
481 (Exp e, int n, Literal l[], Match m[], Match d,
482 MatchOptions options, Ty match_ty)
484 const char ** regexps = (const char **)mem_pool[n * sizeof(const char *)];
485 const char ** contexts = 0;
487 ////////////////////////////////////////////////////////////////////////////
488 // If we have a match type, locate the set of contexts.
489 ////////////////////////////////////////////////////////////////////////////
490 if (options & MATCHscanner)
491 { match (deref_all(match_ty))
493 | DATATYPEty({ terms, unit ... },_):
494 { contexts = (const char **)mem_pool[(unit+1)*sizeof(const char *)];
496 msg("%L%wdatatype has less than 2 unit constructors for contexts");
497 for (int i = 1; i < unit; i++)
499 { ONEcons { name ... }: { contexts[i-1] = name; }
503 contexts[unit-1] = 0;
505 | _: { error ("%Lillegal context type: %T\n", match_ty); }
509 ////////////////////////////////////////////////////////////////////////////
510 // Allocate a regexp array
511 ////////////////////////////////////////////////////////////////////////////
512 for (int i = 0; i < n; i++)
515 { int len = strlen(re);
516 char * regexp = str_pool(re+1,len-1);
517 regexp[len-2] = '\0';
520 | _: { bug("gen_regexp_match"); }
524 int opt = LexerGen::None;
525 if (options & MATCHscanner)
526 { opt |= LexerGen::Backtracking;
527 debug_msg("%Lgenerating backtracking scanner\n");
529 if (options & MATCHcaseinsensitive) opt |= LexerGen::CaseInsensitive;
531 lexerGen.compile(n, regexps, contexts, 255, opt);
533 if (! lexerGen.ok()) {
534 error ("%L%s in: %l\n", lexerGen.error_message(), l[lexerGen.bad()]);
536 /////////////////////////////////////////////////////////////////////////
537 // Generate the action code
538 /////////////////////////////////////////////////////////////////////////
539 Id id = vars.new_label();
541 lexerGen.gen_code(*output, id);
543 pr ("%^static const RegexMatch %s"
549 "%^ %s_equiv_classes );\n",
550 id, id, id, id, id, id, id);
551 Id rule_binding = "";
552 if (options & MATCHlexemepat)
553 { pr ("%^int rule__;");
554 rule_binding = "rule__ = ";
556 if (options & MATCHscanner) {
557 pr ("%^const char * next;\n"
558 "%^switch(%s%s.MatchText(RegexMatch::start_state,%e,next)) {%+",
559 rule_binding, id, e);
561 pr ("%^switch(%s%s.MatchText(%e)) {%+", rule_binding, id, e);
563 for (int i = 0; i < n; i++)
564 pr ("%^case %i: {%+%m%-%?} break;", i+1, m[i]);
565 pr ("%^default: {%+%m%-%?}", d);
569 /////////////////////////////////////////////////////////////////////////
571 /////////////////////////////////////////////////////////////////////////
572 if (::options.generate_report) lexerGen.print_report(open_logfile());
576 ///////////////////////////////////////////////////////////////////////////////
578 // Generate quark pattern matching
580 ///////////////////////////////////////////////////////////////////////////////
581 void MatchCompiler::gen_quark_match
582 (Exp e, int n, Literal l[], Match m[], Match d, MatchOptions options)
583 { for (int i = 0; i < n; i++)
585 pr ("%^%sif (%e == %l) {%+%^%m%-%?} ",
586 (i > 0 ? "else " : ""), e, l[i], m[i]);
588 pr ("%^%s{%+%^%m%-%?}\n", (n > 0 ? "else " : ""), d);
591 ///////////////////////////////////////////////////////////////////////////////
593 // Method to translate and merge a set of patterns
595 ///////////////////////////////////////////////////////////////////////////////
596 Match MatchCompiler::trans_merge
597 (int n, MatchRules rules, int match_options, Cost * costs)
598 { Match m = FAILmatch;
600 for_each(MatchRule, r, rules)
602 { MATCHrule(_, pat, guard, cost, decls):
603 { if (! r->is_chain_rule)
605 if (match_options & (MATCHall | MATCHwithcost)) {
606 BitSet * set = new (mem_pool,n) BitSet;
608 if (costs && ! (match_options & MATCHwithtreecost))
609 rhs = COSTmatch(n,costs,set,rules);
611 rhs = SUCCESSESmatch(n,set,rules);
613 r->used = false; rhs = SUCCESSmatch(rule_no,r);
615 if (guard != NOexp) rhs = GUARDmatch(guard,rhs,FAILmatch);
616 rhs = trans(pat, POSzero, false, rhs, FAILmatch);
617 debug_msg("%r => %M\n", r, rhs);
627 ///////////////////////////////////////////////////////////////////////////////
629 // Method to translate but do not merge a set of patterns.
630 // Use Wadler's algorithm.
632 ///////////////////////////////////////////////////////////////////////////////
633 Match MatchCompiler::trans_no_merge
634 (int n, int rule_no, MatchRules rules, int match_options, Cost * costs)
636 if (rules == #[]) return FAILmatch;
639 { r as MATCHrule(_, pat, guard, cost, decls):
641 if (match_options & (MATCHall | MATCHwithcost)) {
642 BitSet * set = new (mem_pool,n) BitSet;
644 if (costs) rhs = COSTmatch(n,costs,set,rules);
645 else rhs = SUCCESSESmatch(n,set,rules);
647 r->used = false; rhs = SUCCESSmatch(rule_no,r);
650 trans_no_merge(n, rule_no+1, rules->#2, match_options, costs);
651 if (guard != NOexp) rhs = GUARDmatch(guard,rhs,no);
652 return trans(pat, POSzero, false, rhs, no);
658 ///////////////////////////////////////////////////////////////////////////////
660 // Instrument the matching code if tracing is on
662 ///////////////////////////////////////////////////////////////////////////////
663 void MatchCompiler::instrument_trace(MatchRules rules)
664 { for_each(MatchRule, r, rules)
666 { MATCHrule(id,pat,guard,cost,action):
668 ostrstream stream(buffer, sizeof(buffer));
669 std::ostream& s = stream;
673 APPexp(IDexp("PROP_TRACE"),
675 LITERALexp(STRINGlit(make_quoted_string(buffer))),
676 LITERALexp(STRINGlit(make_quoted_string(r->file_name))),
677 LITERALexp(INTlit(r->begin_line))
687 ///////////////////////////////////////////////////////////////////////////////
689 // Compute the match dag from a set of pattern matching rules.
691 ///////////////////////////////////////////////////////////////////////////////
692 Match MatchCompiler::match_of
693 (int n, MatchRules rules, MatchOptions match_options)
696 ////////////////////////////////////////////////////////////////////////////
697 // Save the last index map.
698 ////////////////////////////////////////////////////////////////////////////
699 HashTable * last_index_map = current_index_map;
701 ////////////////////////////////////////////////////////////////////////////
702 // Create index map for this pattern set if necessary.
703 ////////////////////////////////////////////////////////////////////////////
704 if (options.adaptive_matching) {
705 debug_msg("Creating index map\n");
706 current_index_map = new HashTable(pos_hash, pos_equal, 129);
707 indexing(rules, *current_index_map);
708 debug_msg("Finished indexing\n");
710 current_index_map = 0;
713 ////////////////////////////////////////////////////////////////////////////
714 // If tracing is on, instrument the code.
715 ////////////////////////////////////////////////////////////////////////////
716 if (options.trace && (match_options & MATCHnotrace) == 0)
717 instrument_trace(rules);
719 ////////////////////////////////////////////////////////////////////////////
720 // Make a cost vector if cost minimization is in effect
721 ////////////////////////////////////////////////////////////////////////////
722 Cost * cost_vector = 0;
723 if (match_options & MATCHwithintcost)
724 { cost_vector = (Cost*)mem_pool[n * sizeof(Cost)];
726 for_each(MatchRule, r, rules)
728 { MATCHrule(_,_,_,cost,_): { cost_vector[i] = cost; i++; } }
732 ////////////////////////////////////////////////////////////////////////////
733 // Translate each pattern into a matching tree and merge them together.
734 ////////////////////////////////////////////////////////////////////////////
736 m = trans_merge(n, rules, match_options, cost_vector);
738 m = trans_no_merge(n, 0, rules, match_options, cost_vector);
740 m = make_dag (m, match_options, rules);
741 debug_msg("Matching DFA: %M\n", m);
743 ////////////////////////////////////////////////////////////////////////////
745 ////////////////////////////////////////////////////////////////////////////
746 // BUG 3/6/97: Always check for selectability!!!
747 if (true || (match_options & MATCHnocheck) == 0) {
748 if (match_options & (MATCHall | MATCHwithcost)) {
749 BitSet * may_match = new (mem_pool,n) BitSet;
750 matchables(m,*may_match);
752 for_each (MatchRule, r, rules)
753 { if (! may_match->contains(i) && ! r->is_chain_rule)
754 error("%!this rule is never selected: %r\n", r->loc(), r);
758 { for_each (MatchRule,r,rules)
760 error ("%!this rule is never used: %r\n", r->loc(), r);
766 ////////////////////////////////////////////////////////////////////////////
767 // Clean up the index map
768 ////////////////////////////////////////////////////////////////////////////
769 if (current_index_map) delete current_index_map;
770 current_index_map = last_index_map;
774 ///////////////////////////////////////////////////////////////////////////////
776 // Returns true if the set of rules involve cost expressions.
778 ///////////////////////////////////////////////////////////////////////////////
779 int involve_cost(MatchRules rules)
780 { int options = MATCHnone;
781 for_each(MatchRule, r, rules)
783 { MATCHrule(_,_,_,INTcost _, _):
784 { options |= MATCHwithcost | MATCHwithintcost; }
785 | MATCHrule(_,_,_,EXPcost _, _):
786 { options |= MATCHwithcost | MATCHwithexpcost; }
793 ///////////////////////////////////////////////////////////////////////////////
795 // Method to check for refutable set of rules and print out
796 // warning/error messages.
798 ///////////////////////////////////////////////////////////////////////////////
799 static Bool check_refutable
800 (Match m, MatchRules rules, MatchOptions match_options)
801 { Bool is_refutable = refutable(m); // error checking
802 if (! (match_options & MATCHnocheck) &&
803 ! (match_options & MATCHwhile) && is_refutable) {
804 msg ("%!%wpatterns are not exhaustive:\n", rules->#1->loc());
805 for_each(MatchRule,r,rules) msg("%!\t%r\n", r->loc(), r);
810 ///////////////////////////////////////////////////////////////////////////////
812 // Compile a match/matchall statement.
814 ///////////////////////////////////////////////////////////////////////////////
815 void MatchCompiler::gen_match_stmt
816 (MatchExps exps, MatchRules rules, MatchOptions match_options, Ty match_ty)
817 { MemPoolMark marker = mem_pool.getMark(); // set heap marker
818 int n = length(rules);
819 Ty pattern_tys = type_match_rules(rules); // type inference
820 Id save_failure = current_failure;
822 MatchOptions save = current_options;
823 current_options = match_options;
825 if (pattern_tys != NOty) {
827 if (match_options & MATCHwhile) {
828 pr ("%^for (;;) {%+"); current_failure = labels.new_label();
831 // check for cost expressions
832 int cost_opts = involve_cost(rules);
833 if (cost_opts & MATCHwithcost) {
834 if (match_options & MATCHall)
835 if (! (match_options & MATCHwithtreecost))
836 msg ("%L%wmatching costs are ignored.\n");
838 match_options |= cost_opts;
841 Match m = match_of(n, rules, match_options); // compile patterns
842 Bool is_refutable = check_refutable(m, rules, match_options);
844 // prefix code for matchall
845 if ((match_options & (MATCHall | MATCHwithcost)) &&
846 ! (match_options & MATCHwithtreecost))
847 pr ("%^const unsigned char * m__%s;\n", (is_refutable ? " = 0" : ""));
849 gen_match_variables(exps, pattern_tys);
850 gen(m, match_options, match_ty);
852 // suffix code for cost minimization
853 if (! (match_options & MATCHwithtreecost))
854 { if (match_options & MATCHwithexpcost)
855 gen_match_cost_minimization(n, m, rules, is_refutable);
857 // suffix code for matchall
858 else if (match_options & MATCHall)
859 gen_matchall_suffix(n, m, rules, is_refutable);
862 if (match_options & MATCHwhile)
864 if (is_refutable) pr("%^%s:;", current_failure);
868 mem_pool.setMark(marker); // release all memory used
869 current_failure = save_failure;
870 current_options = save;
873 ///////////////////////////////////////////////////////////////////////////////
875 // Generate suffix code for a matchall statement.
876 // The suffix code goes thru the bitmap and select all rule with
879 ///////////////////////////////////////////////////////////////////////////////
880 void MatchCompiler::gen_matchall_suffix
881 (int n, Match m, MatchRules rules, Bool is_refutable)
882 { int index = 0; int bit = 0;
883 const BitSet& always_match = always_matchables(m,n);
884 if (is_refutable) { ifs++; pr ("%^if (m__) {%+"); }
886 for_each (MatchRule, r, rules)
888 { MATCHrule(_,_,_,_,action):
889 { if (! always_match.contains(index * 8 + bit)) {
891 pr ("%^if (m__[%i] & %i) ", index, 1 << bit);
895 MarkCurrentRule mark(current_rule,r);
896 pr ("{%+%&%-%?}\n", action);
897 if (++bit == 8) { bit = 0; index++; }
901 if (is_refutable) pr ("%-%^}");
904 ///////////////////////////////////////////////////////////////////////////////
906 // Generate suffix code for a match statement with cost minimization.
907 // The bitmap selected with determine which cost function to execute.
908 // When all the appropriate cost functions are executed, we choose the
909 // matched rule with the lowest cost. Ties are broken by the lexical
910 // order of the rules.
912 ///////////////////////////////////////////////////////////////////////////////
913 void MatchCompiler::gen_match_cost_minimization
914 (int n, Match m, MatchRules rules, Bool is_refutable)
916 const BitSet& always_match = always_matchables(m,n);
919 "%^int tmp_cost__, cost__ = %i, rule__ = -1;", MAX_COST);
920 if (is_refutable) { ifs++; pr ("%^if (m__) {%+"); }
922 for_each (MatchRule, r, rules)
924 if (! always_match.contains(index * 8 + bit)) {
926 pr ("if (m__[%i] & %i) ", index, 1 << bit);
928 int rule_no = index * 8 + bit;
930 { MATCHrule (_,_,_,EXPcost(e,_),_):
931 { pr ("if ((tmp_cost__ = %e) < cost__) { cost__ = tmp_cost__; rule_ = %i; }",
934 | MATCHrule (_,_,_,NOcost,_):
935 { pr ("{ rule__ = %i; break; }", rule_no); }
936 | MATCHrule (_,_,_,INTcost c,_):
937 { pr ("if (cost__ > %i) { cost__ = %i; rule__ = %i; }", c, c, rule_no); }
939 if (++bit == 8) { bit = 0; index++; }
942 if (is_refutable) pr ("%-%^}");
943 pr ("%-%^} while (0);"
944 "%^switch (rule__) {%+");
946 for_each(MatchRule, r, rules)
948 { MATCHrule (_,_,_,cost,action):
949 { MarkCurrentRule mark(current_rule,r);
950 pr ("%^case %i: {%+%&%-%?} break;", i, action);
959 ///////////////////////////////////////////////////////////////////////////////
961 // Generate code that binds match variables.
963 ///////////////////////////////////////////////////////////////////////////////
964 void MatchCompiler::gen_match_variables(MatchExps es, Ty ty)
966 if (length(es) > 1) {
968 { TUPLEty ts: { tys = ts; }
969 | _: { bug("gen_match_variables()"); }
974 for ( ; es && tys; es = es->#2, tys = tys->#2) {
976 { me as MATCHexp(e,mv) | mv != 0:
977 { if (! is_ground(tys->#1))
978 error ("%!missing type info in expression %e : %T\n",
979 me->loc(), e, tys->#1);
980 pr ("%^%t = %e;\n", tys->#1, mv, e);
987 ///////////////////////////////////////////////////////////////////////////////
989 // Generate code for a set of function definitions.
991 ///////////////////////////////////////////////////////////////////////////////
992 void MatchCompiler::gen_fun_def (FunDefs fundefs)
993 { // Generate the prototype first (to deal with recursive definitions).
994 MemPoolMark marker = mem_pool.getMark(); // set heap marker
995 { for_each (FunDef, f, fundefs)
997 { FUNdef(id, arg_ty, return_ty, rules):
998 { arg_ty = type_match_rules(rules);
1000 std::ostrstream b(buf,sizeof(buf));
1001 std::ostream& s = b;
1002 s << id << std::ends;
1003 Ty ret_ty = return_ty == NOty ? void_ty : return_ty;
1005 ret_ty, buf, arg_ty, "1", TYformal);
1006 if (! is_ground(arg_ty))
1007 error ("%!missing type info in function %q %T\n",
1008 f->loc(), id, arg_ty);
1014 // Then generate the body of the functions.
1015 { for_each (FunDef, f, fundefs)
1017 { FUNdef(id, arg_ty, return_ty, rules):
1018 { int n = length(rules);
1019 Match m = match_of(n, rules, MATCHnone);
1020 check_refutable(m, rules, MATCHnone);
1021 Ty ret_ty = return_ty == NOty ? void_ty : return_ty;
1023 std::ostrstream b(buf,sizeof(buf));
1024 std::ostream& s = b;
1025 s << id << std::ends;
1026 pr ("%^%t %b\n{\n%+",
1027 ret_ty, buf, arg_ty, "1", TYformal);
1034 mem_pool.setMark(marker); // release all memory used