1 ///////////////////////////////////////////////////////////////////////////////
2 // This file is generated automatically using Prop (version 2.3.6),
3 // last updated on Nov 2, 1999.
4 // The original source file is "matchgen.pcc".
5 ///////////////////////////////////////////////////////////////////////////////
8 ///////////////////////////////////////////////////////////////////////////////
10 // This file implements the backend for pattern matching,
11 // string matching, and lexical scanning constructs. C++ code is
12 // emitted in this file.
14 ///////////////////////////////////////////////////////////////////////////////
19 #include <AD/contain/bitset.h>
20 #include <AD/automata/lexergen.h>
21 #include <AD/strings/charesc.h>
22 #include <AD/memory/mempool.h>
23 #include <AD/sort/heapsort.h>
24 #include <AD/sort/heapsrt2.h>
35 ///////////////////////////////////////////////////////////////////////////////
37 // Class to mark the current rule.
39 ///////////////////////////////////////////////////////////////////////////////
40 MarkCurrentRule::MarkCurrentRule(MatchRule
& c
, MatchRule n
)
41 : current_rule(c
), old_rule(c
) { c
= n
; }
42 MarkCurrentRule::~MarkCurrentRule() { current_rule
= old_rule
; }
44 ///////////////////////////////////////////////////////////////////////////////
46 // Method to extract the line number of the current rule
48 ///////////////////////////////////////////////////////////////////////////////
49 int MatchCompiler::current_rule_line() const
50 { if (current_rule
== 0) bug("MatchCompiler::current_rule_line()\n");
51 return current_rule
->begin_line
;
54 ///////////////////////////////////////////////////////////////////////////////
56 // Method to extract the text of the current rule
58 ///////////////////////////////////////////////////////////////////////////////
59 const char * MatchCompiler::current_rule_text() const
60 { if (current_rule
== 0) bug("MatchCompiler::current_rule_text()\n");
62 std::ostrstream
stream(buffer
,sizeof(buffer
));
63 std::ostream
& s
= stream
;
64 s
<< current_rule
<< std::ends
;
65 buffer
[sizeof(buffer
)-1] = '\0';
66 return make_quoted_string(buffer
);
69 ///////////////////////////////////////////////////////////////////////////////
73 ///////////////////////////////////////////////////////////////////////////////
74 HashTable
* current_index_map
= 0;
75 Bool merge_match
= true; // should we merge the DFAs?
76 Id current_failure
= 0; // jump label for failure
78 ///////////////////////////////////////////////////////////////////////////////
80 // Is the expression simple?
82 ///////////////////////////////////////////////////////////////////////////////
83 Bool
is_simple_exp (Exp exp
)
85 #line 77 "matchgen.pcc"
86 #line 80 "matchgen.pcc"
91 case a_Exp::tag_MARKEDexp
: {
92 #line 79 "matchgen.pcc"
93 exp
= ((Exp_MARKEDexp
*)exp
)->_2
;
94 #line 79 "matchgen.pcc"
96 case a_Exp::tag_LITERALexp
:
97 case a_Exp::tag_IDexp
: {
98 #line 78 "matchgen.pcc"
100 #line 78 "matchgen.pcc"
104 #line 80 "matchgen.pcc"
106 #line 80 "matchgen.pcc"
112 #line 81 "matchgen.pcc"
113 #line 81 "matchgen.pcc"
118 ///////////////////////////////////////////////////////////////////////////////
120 // Generate match variable bindings for complex match expressions.
122 ///////////////////////////////////////////////////////////////////////////////
123 void compute_match_variables(MatchExps exps
)
124 { static LabelGen
vars("_V");
125 for_each (MatchExp
, me
, exps
)
127 #line 93 "matchgen.pcc"
128 #line 96 "matchgen.pcc"
131 #line 94 "matchgen.pcc"
132 ((me
->_2
== 0) && (! is_simple_exp(me
->_1
)))
133 #line 94 "matchgen.pcc"
136 #line 95 "matchgen.pcc"
137 me
->_2
= vars
.new_label();
138 #line 95 "matchgen.pcc"
141 #line 96 "matchgen.pcc"
143 #line 96 "matchgen.pcc"
146 #line 97 "matchgen.pcc"
147 #line 97 "matchgen.pcc"
152 ///////////////////////////////////////////////////////////////////////////////
154 // Generate pattern matching code from a match dag
156 ///////////////////////////////////////////////////////////////////////////////
157 void MatchCompiler::gen(Match mt
, MatchOptions match_options
, Ty match_ty
)
159 if (mt
== FAILmatch
) {
160 if (current_failure
) pr ("%? goto %s; ", current_failure
);
164 // check for duplicates
165 if (mt
->label
) { pr ("%? goto %s; ", mt
->label
); gotos
++; return; }
166 if (mt
->shared
> 1) { goto_labels
++;
167 pr ("%^%s:; ", mt
->label
= labels
.new_label()); }
169 #line 117 "matchgen.pcc"
170 #line 190 "matchgen.pcc"
174 case a_Match::tag_SUCCESSmatch
: {
175 #line 120 "matchgen.pcc"
176 MarkCurrentRule
mark(current_rule
,((Match_SUCCESSmatch
*)mt
)->_2
); pr ("%&", ((Match_SUCCESSmatch
*)mt
)->_2
->_5
);
177 #line 120 "matchgen.pcc"
179 case a_Match::tag_SUCCESSESmatch
: {
180 #line 125 "matchgen.pcc"
181 if (current_options
& MATCHwithtreecost
)
182 gen_treecost_match(FAILmatch
,((Match_SUCCESSESmatch
*)mt
)->_2
,((Match_SUCCESSESmatch
*)mt
)->_3
);
184 gen_success_match(((Match_SUCCESSESmatch
*)mt
)->_1
,((Match_SUCCESSESmatch
*)mt
)->_2
,((Match_SUCCESSESmatch
*)mt
)->_3
);
186 #line 129 "matchgen.pcc"
188 case a_Match::tag_COSTmatch
: {
189 #line 121 "matchgen.pcc"
190 gen_cost_success_match(((Match_COSTmatch
*)mt
)->_1
,((Match_COSTmatch
*)mt
)->_3
,((Match_COSTmatch
*)mt
)->_4
);
191 #line 121 "matchgen.pcc"
193 case a_Match::tag_GUARDmatch
: {
194 #line 132 "matchgen.pcc"
195 ifs
++; pr ("%^if (%E) {%+%^%m%-%?} else {%+%^%m%-%?}\n",((Match_GUARDmatch
*)mt
)->_1
,((Match_GUARDmatch
*)mt
)->_2
,((Match_GUARDmatch
*)mt
)->_3
);
196 #line 132 "matchgen.pcc"
198 case a_Match::tag_LITERALmatch
: {
199 switch (((Match_LITERALmatch
*)mt
)->_3
[0]->tag__
) {
200 case a_Literal::tag_REGEXPlit
: {
201 #line 185 "matchgen.pcc"
202 if (options
.generate_report
) open_logfile() << mt
<< '\n';
203 gen_regexp_match(((Match_LITERALmatch
*)mt
)->_2
,((Match_LITERALmatch
*)mt
)->_4
,((Match_LITERALmatch
*)mt
)->_3
,((Match_LITERALmatch
*)mt
)->_5
,((Match_LITERALmatch
*)mt
)->_6
,match_options
,match_ty
);
205 #line 187 "matchgen.pcc"
207 case a_Literal::tag_QUARKlit
: {
208 #line 189 "matchgen.pcc"
209 gen_quark_match(((Match_LITERALmatch
*)mt
)->_2
,((Match_LITERALmatch
*)mt
)->_4
,((Match_LITERALmatch
*)mt
)->_3
,((Match_LITERALmatch
*)mt
)->_5
,((Match_LITERALmatch
*)mt
)->_6
,match_options
);
210 #line 189 "matchgen.pcc"
212 case a_Literal::tag_BIGINTlit
: {
214 #line 190 "matchgen.pcc"
216 #line 190 "matchgen.pcc"
218 case a_Literal::tag_REALlit
:
219 case a_Literal::tag_STRINGlit
: {
220 #line 183 "matchgen.pcc"
221 gen_binary_search_on_literals(((Match_LITERALmatch
*)mt
)->_2
,((Match_LITERALmatch
*)mt
)->_4
,((Match_LITERALmatch
*)mt
)->_3
,((Match_LITERALmatch
*)mt
)->_5
,((Match_LITERALmatch
*)mt
)->_6
);
222 #line 183 "matchgen.pcc"
225 #line 158 "matchgen.pcc"
228 #line 159 "matchgen.pcc"
229 #line 161 "matchgen.pcc"
231 Literal _V1
= ((Match_LITERALmatch
*)mt
)->_3
[0];
232 switch (_V1
->tag__
) {
233 case a_Literal::tag_BOOLlit
: {
234 #line 160 "matchgen.pcc"
236 #line 160 "matchgen.pcc"
239 #line 161 "matchgen.pcc"
241 #line 161 "matchgen.pcc"
245 #line 162 "matchgen.pcc"
246 #line 162 "matchgen.pcc"
249 pr ("%^switch (%e) {\n%+", ((Match_LITERALmatch
*)mt
)->_2
);
250 for (int i
= 0; i
< ((Match_LITERALmatch
*)mt
)->_4
; ) {
252 for (j
= i
+1; j
< ((Match_LITERALmatch
*)mt
)->_4
; j
++) if (((Match_LITERALmatch
*)mt
)->_5
[i
] != ((Match_LITERALmatch
*)mt
)->_5
[j
]) break;
254 if (is_boolean
&& j
== ((Match_LITERALmatch
*)mt
)->_4
&& ((Match_LITERALmatch
*)mt
)->_4
== 2) {
255 pr ("%^default:"); i
= ((Match_LITERALmatch
*)mt
)->_4
;
257 for ( ; i
< j
; i
++) {
258 pr ("%^case %l:", ((Match_LITERALmatch
*)mt
)->_3
[i
]);
259 if (i
!= j
- 1) pr ("\n");
262 pr(" {%+%m%-%?} break;\n", ((Match_LITERALmatch
*)mt
)->_5
[k
]);
264 if (! is_boolean
|| ((Match_LITERALmatch
*)mt
)->_4
< 2) pr ("%^default: {%+%m%-%?}", ((Match_LITERALmatch
*)mt
)->_6
);
267 #line 181 "matchgen.pcc"
271 case a_Match::tag_RANGEmatch
: {
272 #line 130 "matchgen.pcc"
273 gen_range_match(((Match_RANGEmatch
*)mt
)->_1
,((Match_RANGEmatch
*)mt
)->_2
,((Match_RANGEmatch
*)mt
)->_3
,((Match_RANGEmatch
*)mt
)->_4
,((Match_RANGEmatch
*)mt
)->_5
,((Match_RANGEmatch
*)mt
)->_6
,mt
);
274 #line 130 "matchgen.pcc"
276 case a_Match::tag_CONSmatch
: {
277 if (((Match_CONSmatch
*)mt
)->_4
) {
278 switch (((Match_CONSmatch
*)mt
)->_4
->tag__
) {
279 case a_Ty::tag_TYCONty
: {
280 if (boxed(((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)) {
281 switch (((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
->tag__
) {
282 case a_TyCon::tag_DATATYPEtycon
: {
284 #line 135 "matchgen.pcc"
285 (((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->qualifiers
& QUALview
)
286 #line 135 "matchgen.pcc"
289 #line 136 "matchgen.pcc"
290 gen_view_match (((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->id
, ((Match_CONSmatch
*)mt
)->_2
, ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->view_match
, ((Match_CONSmatch
*)mt
)->_5
, ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->terms
, ((Match_CONSmatch
*)mt
)->_6
, ((Match_CONSmatch
*)mt
)->_7
,
291 ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->opt
, ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->qualifiers
& QUALextensible
);
292 #line 137 "matchgen.pcc"
295 switch (((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->arg
) {
297 #line 140 "matchgen.pcc"
298 gen_switch (((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->id
, ((Match_CONSmatch
*)mt
)->_2
, ((Match_CONSmatch
*)mt
)->_3
, ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->unit
, ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->terms
, ((Match_CONSmatch
*)mt
)->_6
, ((Match_CONSmatch
*)mt
)->_7
, mt
->shared
,
299 false, false, ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->opt
, ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->qualifiers
& QUALextensible
);
300 #line 141 "matchgen.pcc"
303 switch (((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->unit
) {
305 #line 144 "matchgen.pcc"
306 gen_switch (((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->id
, ((Match_CONSmatch
*)mt
)->_2
, ((Match_CONSmatch
*)mt
)->_3
, ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->arg
, ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->terms
, ((Match_CONSmatch
*)mt
)->_6
, ((Match_CONSmatch
*)mt
)->_7
, mt
->shared
,
307 false, true, ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->opt
, ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->qualifiers
& QUALextensible
);
308 #line 145 "matchgen.pcc"
311 #line 148 "matchgen.pcc"
313 pr ((((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->unit
> 1 ? "%^if (boxed(%e)) {%+" : "%^if (%e) {%+"), ((Match_CONSmatch
*)mt
)->_2
);
314 gen_switch (((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->id
, ((Match_CONSmatch
*)mt
)->_2
, ((Match_CONSmatch
*)mt
)->_3
, ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->arg
, ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->terms
+ ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->unit
, ((Match_CONSmatch
*)mt
)->_6
+ ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->unit
, ((Match_CONSmatch
*)mt
)->_7
, mt
->shared
,
315 true, true, ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->opt
, ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->qualifiers
& QUALextensible
);
316 pr ("%-%?} else {%+");
317 gen_switch (((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->id
, ((Match_CONSmatch
*)mt
)->_2
, ((Match_CONSmatch
*)mt
)->_3
, ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->unit
, ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->terms
, ((Match_CONSmatch
*)mt
)->_6
, ((Match_CONSmatch
*)mt
)->_7
, mt
->shared
,
318 true, false, ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->opt
, ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)((Match_CONSmatch
*)mt
)->_4
)->_1
)->qualifiers
& QUALextensible
);
321 #line 156 "matchgen.pcc"
328 default: { goto L3
; } break;
332 default: { goto L3
; } break;
336 case a_Match::tag_TREECOSTmatch
: {
337 #line 122 "matchgen.pcc"
338 gen_treecost_match(((Match_TREECOSTmatch
*)mt
)->_1
,((Match_TREECOSTmatch
*)mt
)->_2
,((Match_TREECOSTmatch
*)mt
)->_3
);
339 #line 122 "matchgen.pcc"
341 case a_Match::tag_TREELABELmatch
: {
342 #line 123 "matchgen.pcc"
343 gen_treelabel_match(((Match_TREELABELmatch
*)mt
)->_1
,((Match_TREELABELmatch
*)mt
)->_2
,((Match_TREELABELmatch
*)mt
)->_3
,((Match_TREELABELmatch
*)mt
)->_4
);
344 #line 123 "matchgen.pcc"
346 default: { goto L3
; } break;
354 #line 191 "matchgen.pcc"
355 #line 191 "matchgen.pcc"
359 ///////////////////////////////////////////////////////////////////////////////
361 // Method to generate a bitmap of all the successful matching rules.
363 ///////////////////////////////////////////////////////////////////////////////
364 void MatchCompiler::gen_success_match(int n
, const BitSet
* set
, MatchRules
)
365 { pr ("%^{%+ static const unsigned char matched_set__[%i] =\n%^{ %+",
368 for(int i
= 0; i
< (n
+ 7) / 8; i
++) {
369 if (i
> 0) pr (", ");
370 if (i
!= 0 && (i
% 8) == 0) pr ("%^");
371 pr ("%i ", (int)set
->byte(i
));
374 "%^m__ = matched_set__;\n"
379 ///////////////////////////////////////////////////////////////////////////////
381 // Method to generate code for cost minimalization.
383 ///////////////////////////////////////////////////////////////////////////////
384 void MatchCompiler::gen_cost_success_match(int n
, const BitSet
* set
,
388 #line 222 "matchgen.pcc"
389 #line 237 "matchgen.pcc"
393 #line 224 "matchgen.pcc"
396 #line 225 "matchgen.pcc"
397 #line 232 "matchgen.pcc"
399 MatchRule _V2
= rules
->_1
;
400 #line 227 "matchgen.pcc"
402 #line 227 "matchgen.pcc"
403 #line 231 "matchgen.pcc"
412 #line 231 "matchgen.pcc"
413 #line 231 "matchgen.pcc"
416 #line 232 "matchgen.pcc"
418 #line 233 "matchgen.pcc"
419 #line 233 "matchgen.pcc"
425 #line 237 "matchgen.pcc"
430 #line 238 "matchgen.pcc"
431 #line 238 "matchgen.pcc"
435 ///////////////////////////////////////////////////////////////////////////////
437 // Method to generate a switch statement for pattern matching.
438 // This method is responsible for generating optimized code for a one-level
439 // match using C++'s "switch" statement.
441 ///////////////////////////////////////////////////////////////////////////////
442 void MatchCompiler::gen_switch
443 (Id id
, Exp e
, Ty ty
, int n
, Cons terms
[], Match m
[], Match def
, int shared
,
444 Bool variant
, Bool boxed
, TyOpt optimizations
, Bool is_refutable
)
446 if (n
== 1) { // only one arm
448 } else if (n
== 2) { // two arms, use "if"
450 merges
++; if (m
[0] != FAILmatch
) m
[0]->shared
-= shared
; gen(m
[0]);
455 if (optimizations
& OPTtaggedpointer
)
456 { prefix
= "untagp("; suffix
= ")"; }
458 { prefix
= ""; suffix
= "->tag__"; }
459 } else { prefix
= suffix
= ""; }
461 pr ("%^if (%s%e%s) {%+%^%m%-%?} else {%+%^%m%-%?}\n",
462 prefix
, e
, suffix
, m
[1], m
[0]);
465 /////////////////////////////////////////////////////////////////////////
466 // The following is the general case for handling n-ary branches.
467 /////////////////////////////////////////////////////////////////////////
470 /////////////////////////////////////////////////////////////////////////
471 // If all n branches are the same, eliminate the match
472 /////////////////////////////////////////////////////////////////////////
473 for (i
= n
- 1; i
> 0; i
--) if (m
[i
] != m
[i
-1]) break;
474 if (i
== 0) { if (m
[0] != FAILmatch
) m
[0]->shared
-= (n
-1) * shared
;
475 merges
++; gen(m
[0]); return;
481 /////////////////////////////////////////////////////////////////////////
482 // Generate the "switch" expression.
483 /////////////////////////////////////////////////////////////////////////
485 if (optimizations
& OPTtaggedpointer
)
486 { prefix
= "untagp("; suffix
= ")"; }
488 { prefix
= ""; suffix
= "->tag__"; }
491 { prefix
= "(int)"; suffix
= ""; }
493 { prefix
= suffix
= ""; }
495 pr ("%^switch (%s%e%s) {\n%+", prefix
, e
, suffix
);
497 /////////////////////////////////////////////////////////////////////////
498 // Partition the arms of the matches into alternatives with the
499 // same actions. Sort the partitions in increasing sizes.
500 /////////////////////////////////////////////////////////////////////////
502 { Cons term
; Match action
; int tag
; };
503 struct MatchPartition
504 { int count
; Conses terms
; Match action
; int first_tag
; };
505 ConsMatch
* sorted
= (ConsMatch
*)mem_pool
.c_alloc
506 (sizeof(ConsMatch
) * n
);
507 MatchPartition
* parts
= (MatchPartition
*)mem_pool
.c_alloc
508 (sizeof(MatchPartition
) * n
);
509 int number_of_parts
= 0;
510 { for (i
= 0; i
< n
; i
++)
511 { sorted
[i
].term
= terms
[i
];
512 sorted
[i
].action
= m
[i
];
513 if (terms
[i
] != NOcons
) sorted
[i
].tag
= terms
[i
]->tag
;
516 // sort branches according the actions
517 heapSort(ConsMatch
, sorted
, n
,
518 (key
.action
< sorted
[i
].action
||
519 key
.action
== sorted
[i
].action
&&
520 key
.tag
< sorted
[i
].tag
));
522 // partition each branch by action
523 for (i
= n
- 1; i
>= 0; i
--)
524 { if (i
== n
-1 || sorted
[i
].action
!= sorted
[i
+1].action
)
525 { parts
[number_of_parts
].terms
=
526 #line 331 "matchgen.pcc"
527 #line 331 "matchgen.pcc"
528 list_1_(sorted
[i
].term
)
529 #line 331 "matchgen.pcc"
530 #line 331 "matchgen.pcc"
532 parts
[number_of_parts
].action
= sorted
[i
].action
;
533 parts
[number_of_parts
].count
= 1;
534 parts
[number_of_parts
].first_tag
= sorted
[i
].tag
;
537 parts
[number_of_parts
-1].terms
=
539 #line 338 "matchgen.pcc"
540 #line 338 "matchgen.pcc"
541 list_1_(sorted
[i
].term
,parts
[(number_of_parts
- 1)].terms
)
542 #line 338 "matchgen.pcc"
543 #line 338 "matchgen.pcc"
545 parts
[number_of_parts
-1].count
++;
546 if (parts
[number_of_parts
-1].first_tag
> sorted
[i
].tag
)
547 parts
[number_of_parts
-1].first_tag
= sorted
[i
].tag
;
551 // Sort partitions in order of frequency; so that
552 // the most frequent case becomes the "default" inside
553 // the "switch" statement.
554 heapSort(MatchPartition
, parts
, number_of_parts
,
555 (key
.count
< parts
[i
].count
||
556 key
.count
== parts
[i
].count
&&
557 key
.first_tag
< parts
[i
].first_tag
));
560 /////////////////////////////////////////////////////////////////////////
561 // Generate the arms of the "switch".
562 // We try to combine the arms that are the same together into
563 // one rule to help the compiler.
564 /////////////////////////////////////////////////////////////////////////
565 for (i
= 0; i
< number_of_parts
; i
++)
566 { if (i
== number_of_parts
- 1) {
569 Conses tags
= parts
[i
].terms
;
571 #line 364 "matchgen.pcc"
572 #line 369 "matchgen.pcc"
576 #line 366 "matchgen.pcc"
577 pr ("%^case %*:", tags
->_1
, false);
579 #line 367 "matchgen.pcc"
580 #line 367 "matchgen.pcc"
582 #line 367 "matchgen.pcc"
583 #line 367 "matchgen.pcc"
587 #line 369 "matchgen.pcc"
592 #line 370 "matchgen.pcc"
593 #line 370 "matchgen.pcc"
596 if (parts
[i
].action
!= FAILmatch
)
597 parts
[i
].action
->shared
-= (parts
[i
].count
- 1) * shared
;
598 pr (" {%+%?%m%?} break;\n%-", parts
[i
].action
);
605 ///////////////////////////////////////////////////////////////////////////////
607 // Generate binary search for testing literals
609 ///////////////////////////////////////////////////////////////////////////////
610 void MatchCompiler::gen_binary_search_on_literals
611 (Exp e
, int n
, Literal l
[], Match m
[], Match d
)
613 /////////////////////////////////////////////////////////////////////////
614 // Generate linear tests for simple literal tests.
615 /////////////////////////////////////////////////////////////////////////
616 for (int i
= 0; i
< n
; i
++) {
618 if (i
> 0) pr("%^else "); else pr ("%^");
619 pr ("if (%=(%e,%l)) {%m}\n",l
[i
], e
, l
[i
], m
[i
]);
621 if (d
!= FAILmatch
) pr ("%^else {%m}\n", d
);
622 else if (current_failure
) pr ("%^else goto %s;\n", current_failure
);
624 /////////////////////////////////////////////////////////////////////////
625 // Generate binary search for tests containing many alternatives.
626 /////////////////////////////////////////////////////////////////////////
629 pr ("%^if (%<(%e,%l)) {\n%+", l
[k
], e
, l
[k
]);
630 gen_binary_search_on_literals(e
,k
,l
,m
,d
);
631 pr ("%-%^} else {\n%+");
632 gen_binary_search_on_literals(e
,n
-k
,l
+k
,m
+k
,d
);
637 ///////////////////////////////////////////////////////////////////////////////
639 // Generate range matching
641 ///////////////////////////////////////////////////////////////////////////////
642 void MatchCompiler::gen_range_match
643 (Pos pos
, Exp e
, int lo
, int hi
, Match a
, Match b
, Match m
)
646 pr ("%^switch (%e) {%+",e
);
648 #line 423 "matchgen.pcc"
649 #line 425 "matchgen.pcc"
654 case a_Match::tag_RANGEmatch
: {
656 #line 424 "matchgen.pcc"
657 ((((Match_RANGEmatch
*)m
)->_3
== ((Match_RANGEmatch
*)m
)->_4
) && pos_equal(pos
,((Match_RANGEmatch
*)m
)->_1
))
658 #line 424 "matchgen.pcc"
661 #line 425 "matchgen.pcc"
662 pr ("%^case %i: {%+%m%-%?} break;", ((Match_RANGEmatch
*)m
)->_3
, ((Match_RANGEmatch
*)m
)->_5
); m
= ((Match_RANGEmatch
*)m
)->_6
;
663 #line 425 "matchgen.pcc"
667 default: { goto L6
; } break;
673 #line 426 "matchgen.pcc"
674 #line 426 "matchgen.pcc"
676 pr ("%^default: {%+%m%-%?}"
682 pr ("%^if (%e <= %i) {%+%^%m%-%?} else {%+%^%m%-%?}\n",e
,hi
,a
,b
);
683 } else if (hi
== INT_MAX
) {
684 pr ("%^if (%e >= %i) {%+%^%m%-%?} else {%+%^%m%-%?}\n",e
,lo
,a
,b
);
686 pr ("%^if (%i <= %e && %e <= %i) {%+%^%m%-%?} else {%+%^%m%-%?}\n",
692 ///////////////////////////////////////////////////////////////////////////////
694 // Generate view matching
696 ///////////////////////////////////////////////////////////////////////////////
697 void MatchCompiler::gen_view_match
698 (Id id
, Exp e
, Exp view_match
, int n
, Cons terms
[], Match m
[], Match d
,
699 TyOpt opt
, TyQual qual
)
700 { if (view_match
!= NOexp
)
702 pr ("%^switch (%e) {%+", subst(view_match
,&e
));
703 for (int i
= 0; i
< n
; i
++)
704 { pr ("%^case %e: {%+%m%-%?} break;", terms
[i
]->view_predicate
, m
[i
]);
709 for (i
= 0; i
< n
; i
++)
711 for (j
= i
+ 1; j
< n
; j
++) if (m
[i
] != m
[j
]) break;
713 Exp predicate_fun
= terms
[i
]->view_predicate
;
714 Exp predicate
= subst(predicate_fun
,&e
);
716 pr("%^%sif (%e) {%+%^%m%-%?} ",
717 (i
> 0 ? "else " : ""), predicate
, m
[i
]);
720 pr ("%^%s{%+%^%m%-%?}\n", (i
> 0 ? "else " : ""), m
[i
]);
724 ///////////////////////////////////////////////////////////////////////////////
726 // Generate regular expression matching as a DFA.
728 ///////////////////////////////////////////////////////////////////////////////
729 void MatchCompiler::gen_regexp_match
730 (Exp e
, int n
, Literal l
[], Match m
[], Match d
,
731 MatchOptions options
, Ty match_ty
)
733 const char ** regexps
= (const char **)mem_pool
[n
* sizeof(const char *)];
734 const char ** contexts
= 0;
736 ////////////////////////////////////////////////////////////////////////////
737 // If we have a match type, locate the set of contexts.
738 ////////////////////////////////////////////////////////////////////////////
739 if (options
& MATCHscanner
)
741 #line 491 "matchgen.pcc"
742 #line 505 "matchgen.pcc"
744 Ty _V4
= deref_all(match_ty
);
746 switch (_V4
->tag__
) {
747 case a_Ty::tag_TYCONty
: {
748 if (boxed(((Ty_TYCONty
*)_V4
)->_1
)) {
749 switch (((Ty_TYCONty
*)_V4
)->_1
->tag__
) {
750 case a_TyCon::tag_DATATYPEtycon
: {
751 #line 494 "matchgen.pcc"
752 contexts
= (const char **)mem_pool
[(((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)_V4
)->_1
)->unit
+1)*sizeof(const char *)];
753 if (((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)_V4
)->_1
)->unit
<= 1)
754 msg("%L%wdatatype has less than 2 unit constructors for contexts");
755 for (int i
= 1; i
< ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)_V4
)->_1
)->unit
; i
++)
757 #line 498 "matchgen.pcc"
758 #line 501 "matchgen.pcc"
760 Cons _V5
= ((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)_V4
)->_1
)->terms
[i
];
762 #line 499 "matchgen.pcc"
763 contexts
[i
-1] = _V5
->name
;
764 #line 499 "matchgen.pcc"
767 #line 501 "matchgen.pcc"
768 #line 501 "matchgen.pcc"
771 contexts
[((TyCon_DATATYPEtycon
*)((Ty_TYCONty
*)_V4
)->_1
)->unit
-1] = 0;
773 #line 504 "matchgen.pcc"
777 #line 505 "matchgen.pcc"
778 error ("%Lillegal context type: %T\n", match_ty
);
779 #line 505 "matchgen.pcc"
784 default: { goto L7
; } break;
788 #line 506 "matchgen.pcc"
789 #line 506 "matchgen.pcc"
793 ////////////////////////////////////////////////////////////////////////////
794 // Allocate a regexp array
795 ////////////////////////////////////////////////////////////////////////////
796 for (int i
= 0; i
< n
; i
++)
798 #line 513 "matchgen.pcc"
799 #line 520 "matchgen.pcc"
802 switch (_V6
->tag__
) {
803 case a_Literal::tag_REGEXPlit
: {
804 #line 515 "matchgen.pcc"
805 int len
= strlen(((Literal_REGEXPlit
*)_V6
)->REGEXPlit
);
806 char * regexp
= str_pool(((Literal_REGEXPlit
*)_V6
)->REGEXPlit
+1,len
-1);
807 regexp
[len
-2] = '\0';
810 #line 519 "matchgen.pcc"
813 #line 520 "matchgen.pcc"
814 bug("gen_regexp_match");
815 #line 520 "matchgen.pcc"
819 #line 521 "matchgen.pcc"
820 #line 521 "matchgen.pcc"
824 int opt
= LexerGen::None
;
825 if (options
& MATCHscanner
)
826 { opt
|= LexerGen::Backtracking
;
827 debug_msg("%Lgenerating backtracking scanner\n");
829 if (options
& MATCHcaseinsensitive
) opt
|= LexerGen::CaseInsensitive
;
831 lexerGen
.compile(n
, regexps
, contexts
, 255, opt
);
833 if (! lexerGen
.ok()) {
834 error ("%L%s in: %l\n", lexerGen
.error_message(), l
[lexerGen
.bad()]);
836 /////////////////////////////////////////////////////////////////////////
837 // Generate the action code
838 /////////////////////////////////////////////////////////////////////////
839 Id id
= vars
.new_label();
841 lexerGen
.gen_code(*output
, id
);
843 pr ("%^static const RegexMatch %s"
849 "%^ %s_equiv_classes );\n",
850 id
, id
, id
, id
, id
, id
, id
);
851 Id rule_binding
= "";
852 if (options
& MATCHlexemepat
)
853 { pr ("%^int rule__;");
854 rule_binding
= "rule__ = ";
856 if (options
& MATCHscanner
) {
857 pr ("%^const char * next;\n"
858 "%^switch(%s%s.MatchText(RegexMatch::start_state,%e,next)) {%+",
859 rule_binding
, id
, e
);
861 pr ("%^switch(%s%s.MatchText(%e)) {%+", rule_binding
, id
, e
);
863 for (int i
= 0; i
< n
; i
++)
864 pr ("%^case %i: {%+%m%-%?} break;", i
+1, m
[i
]);
865 pr ("%^default: {%+%m%-%?}", d
);
869 /////////////////////////////////////////////////////////////////////////
871 /////////////////////////////////////////////////////////////////////////
872 if (::options
.generate_report
) lexerGen
.print_report(open_logfile());
876 ///////////////////////////////////////////////////////////////////////////////
878 // Generate quark pattern matching
880 ///////////////////////////////////////////////////////////////////////////////
881 void MatchCompiler::gen_quark_match
882 (Exp e
, int n
, Literal l
[], Match m
[], Match d
, MatchOptions options
)
883 { for (int i
= 0; i
< n
; i
++)
885 pr ("%^%sif (%e == %l) {%+%^%m%-%?} ",
886 (i
> 0 ? "else " : ""), e
, l
[i
], m
[i
]);
888 pr ("%^%s{%+%^%m%-%?}\n", (n
> 0 ? "else " : ""), d
);
891 ///////////////////////////////////////////////////////////////////////////////
893 // Method to translate and merge a set of patterns
895 ///////////////////////////////////////////////////////////////////////////////
896 Match
MatchCompiler::trans_merge
897 (int n
, MatchRules rules
, int match_options
, Cost
* costs
)
898 { Match m
= FAILmatch
;
900 for_each(MatchRule
, r
, rules
)
902 #line 601 "matchgen.pcc"
903 #line 621 "matchgen.pcc"
905 #line 603 "matchgen.pcc"
906 if (! r
->is_chain_rule
)
908 if (match_options
& (MATCHall
| MATCHwithcost
)) {
909 BitSet
* set
= new (mem_pool
,n
) BitSet
;
911 if (costs
&& ! (match_options
& MATCHwithtreecost
))
912 rhs
= COSTmatch(n
,costs
,set
,rules
);
914 rhs
= SUCCESSESmatch(n
,set
,rules
);
916 r
->used
= false; rhs
= SUCCESSmatch(rule_no
,r
);
918 if (r
->_3
!= NOexp
) rhs
= GUARDmatch(r
->_3
,rhs
,FAILmatch
);
919 rhs
= trans(r
->_2
, POSzero
, false, rhs
, FAILmatch
);
920 debug_msg("%r => %M\n", r
, rhs
);
925 #line 621 "matchgen.pcc"
927 #line 622 "matchgen.pcc"
928 #line 622 "matchgen.pcc"
934 ///////////////////////////////////////////////////////////////////////////////
936 // Method to translate but do not merge a set of patterns.
937 // Use Wadler's algorithm.
939 ///////////////////////////////////////////////////////////////////////////////
940 Match
MatchCompiler::trans_no_merge
941 (int n
, int rule_no
, MatchRules rules
, int match_options
, Cost
* costs
)
944 #line 636 "matchgen.pcc"
945 #line 636 "matchgen.pcc"
947 #line 636 "matchgen.pcc"
948 #line 636 "matchgen.pcc"
952 #line 638 "matchgen.pcc"
953 #line 653 "matchgen.pcc"
955 MatchRule _V7
= rules
->_1
;
956 #line 640 "matchgen.pcc"
958 if (match_options
& (MATCHall
| MATCHwithcost
)) {
959 BitSet
* set
= new (mem_pool
,n
) BitSet
;
961 if (costs
) rhs
= COSTmatch(n
,costs
,set
,rules
);
962 else rhs
= SUCCESSESmatch(n
,set
,rules
);
964 _V7
->used
= false; rhs
= SUCCESSmatch(rule_no
,_V7
);
967 trans_no_merge(n
, rule_no
+1, rules
->_2
, match_options
, costs
);
968 if (_V7
->_3
!= NOexp
) rhs
= GUARDmatch(_V7
->_3
,rhs
,no
);
969 return trans(_V7
->_2
, POSzero
, false, rhs
, no
);
971 #line 653 "matchgen.pcc"
973 #line 654 "matchgen.pcc"
974 #line 654 "matchgen.pcc"
979 ///////////////////////////////////////////////////////////////////////////////
981 // Instrument the matching code if tracing is on
983 ///////////////////////////////////////////////////////////////////////////////
984 void MatchCompiler::instrument_trace(MatchRules rules
)
985 { for_each(MatchRule
, r
, rules
)
987 #line 665 "matchgen.pcc"
988 #line 682 "matchgen.pcc"
990 #line 667 "matchgen.pcc"
992 std::ostrstream
stream(buffer
, sizeof(buffer
));
993 std::ostream
& s
= stream
;
997 #line 672 "matchgen.pcc"
998 #line 672 "matchgen.pcc"
999 list_1_(EXPdecl(APPexp(IDexp("PROP_TRACE"),TUPLEexp(list_1_(LITERALexp(STRINGlit(make_quoted_string(buffer
))),list_1_(LITERALexp(STRINGlit(make_quoted_string(r
->file_name
))),list_1_(LITERALexp(INTlit(r
->begin_line
)))))))),list_1_(OPAQUEdecl(";"),r
->_5
))
1000 #line 681 "matchgen.pcc"
1001 #line 681 "matchgen.pcc"
1004 #line 682 "matchgen.pcc"
1006 #line 683 "matchgen.pcc"
1007 #line 683 "matchgen.pcc"
1012 ///////////////////////////////////////////////////////////////////////////////
1014 // Compute the match dag from a set of pattern matching rules.
1016 ///////////////////////////////////////////////////////////////////////////////
1017 Match
MatchCompiler::match_of
1018 (int n
, MatchRules rules
, MatchOptions match_options
)
1021 ////////////////////////////////////////////////////////////////////////////
1022 // Save the last index map.
1023 ////////////////////////////////////////////////////////////////////////////
1024 HashTable
* last_index_map
= current_index_map
;
1026 ////////////////////////////////////////////////////////////////////////////
1027 // Create index map for this pattern set if necessary.
1028 ////////////////////////////////////////////////////////////////////////////
1029 if (options
.adaptive_matching
) {
1030 debug_msg("Creating index map\n");
1031 current_index_map
= new HashTable(pos_hash
, pos_equal
, 129);
1032 indexing(rules
, *current_index_map
);
1033 debug_msg("Finished indexing\n");
1035 current_index_map
= 0;
1038 ////////////////////////////////////////////////////////////////////////////
1039 // If tracing is on, instrument the code.
1040 ////////////////////////////////////////////////////////////////////////////
1041 if (options
.trace
&& (match_options
& MATCHnotrace
) == 0)
1042 instrument_trace(rules
);
1044 ////////////////////////////////////////////////////////////////////////////
1045 // Make a cost vector if cost minimization is in effect
1046 ////////////////////////////////////////////////////////////////////////////
1047 Cost
* cost_vector
= 0;
1048 if (match_options
& MATCHwithintcost
)
1049 { cost_vector
= (Cost
*)mem_pool
[n
* sizeof(Cost
)];
1051 for_each(MatchRule
, r
, rules
)
1053 #line 727 "matchgen.pcc"
1054 #line 728 "matchgen.pcc"
1056 #line 728 "matchgen.pcc"
1057 cost_vector
[i
] = r
->_4
; i
++;
1058 #line 728 "matchgen.pcc"
1060 #line 728 "matchgen.pcc"
1061 #line 728 "matchgen.pcc"
1066 ////////////////////////////////////////////////////////////////////////////
1067 // Translate each pattern into a matching tree and merge them together.
1068 ////////////////////////////////////////////////////////////////////////////
1070 m
= trans_merge(n
, rules
, match_options
, cost_vector
);
1072 m
= trans_no_merge(n
, 0, rules
, match_options
, cost_vector
);
1074 m
= make_dag (m
, match_options
, rules
);
1075 debug_msg("Matching DFA: %M\n", m
);
1077 ////////////////////////////////////////////////////////////////////////////
1079 ////////////////////////////////////////////////////////////////////////////
1080 // BUG 3/6/97: Always check for selectability!!!
1081 if (true || (match_options
& MATCHnocheck
) == 0) {
1082 if (match_options
& (MATCHall
| MATCHwithcost
)) {
1083 BitSet
* may_match
= new (mem_pool
,n
) BitSet
;
1084 matchables(m
,*may_match
);
1086 for_each (MatchRule
, r
, rules
)
1087 { if (! may_match
->contains(i
) && ! r
->is_chain_rule
)
1088 error("%!this rule is never selected: %r\n", r
->loc(), r
);
1092 { for_each (MatchRule
,r
,rules
)
1094 error ("%!this rule is never used: %r\n", r
->loc(), r
);
1100 ////////////////////////////////////////////////////////////////////////////
1101 // Clean up the index map
1102 ////////////////////////////////////////////////////////////////////////////
1103 if (current_index_map
) delete current_index_map
;
1104 current_index_map
= last_index_map
;
1108 ///////////////////////////////////////////////////////////////////////////////
1110 // Returns true if the set of rules involve cost expressions.
1112 ///////////////////////////////////////////////////////////////////////////////
1113 int involve_cost(MatchRules rules
)
1114 { int options
= MATCHnone
;
1115 for_each(MatchRule
, r
, rules
)
1117 #line 782 "matchgen.pcc"
1118 #line 788 "matchgen.pcc"
1121 if (untagp(r
->_4
)) {
1123 #line 784 "matchgen.pcc"
1124 options
|= MATCHwithcost
| MATCHwithintcost
;
1125 #line 784 "matchgen.pcc"
1128 #line 786 "matchgen.pcc"
1129 options
|= MATCHwithcost
| MATCHwithexpcost
;
1130 #line 786 "matchgen.pcc"
1134 #line 788 "matchgen.pcc"
1135 #line 788 "matchgen.pcc"
1141 ///////////////////////////////////////////////////////////////////////////////
1143 // Method to check for refutable set of rules and print out
1144 // warning/error messages.
1146 ///////////////////////////////////////////////////////////////////////////////
1147 static Bool check_refutable
1148 (Match m
, MatchRules rules
, MatchOptions match_options
)
1149 { Bool is_refutable
= refutable(m
); // error checking
1150 if (! (match_options
& MATCHnocheck
) &&
1151 ! (match_options
& MATCHwhile
) && is_refutable
) {
1152 msg ("%!%wpatterns are not exhaustive:\n", rules
->_1
->loc());
1153 for_each(MatchRule
,r
,rules
) msg("%!\t%r\n", r
->loc(), r
);
1155 return is_refutable
;
1158 ///////////////////////////////////////////////////////////////////////////////
1160 // Compile a match/matchall statement.
1162 ///////////////////////////////////////////////////////////////////////////////
1163 void MatchCompiler::gen_match_stmt
1164 (MatchExps exps
, MatchRules rules
, MatchOptions match_options
, Ty match_ty
)
1165 { MemPoolMark marker
= mem_pool
.getMark(); // set heap marker
1166 int n
= length(rules
);
1167 Ty pattern_tys
= type_match_rules(rules
); // type inference
1168 Id save_failure
= current_failure
;
1169 current_failure
= 0;
1170 MatchOptions save
= current_options
;
1171 current_options
= match_options
;
1173 if (pattern_tys
!= NOty
) {
1175 if (match_options
& MATCHwhile
) {
1176 pr ("%^for (;;) {%+"); current_failure
= labels
.new_label();
1179 // check for cost expressions
1180 int cost_opts
= involve_cost(rules
);
1181 if (cost_opts
& MATCHwithcost
) {
1182 if (match_options
& MATCHall
)
1183 if (! (match_options
& MATCHwithtreecost
))
1184 msg ("%L%wmatching costs are ignored.\n");
1186 match_options
|= cost_opts
;
1189 Match m
= match_of(n
, rules
, match_options
); // compile patterns
1190 Bool is_refutable
= check_refutable(m
, rules
, match_options
);
1192 // prefix code for matchall
1193 if ((match_options
& (MATCHall
| MATCHwithcost
)) &&
1194 ! (match_options
& MATCHwithtreecost
))
1195 pr ("%^const unsigned char * m__%s;\n", (is_refutable
? " = 0" : ""));
1197 gen_match_variables(exps
, pattern_tys
);
1198 gen(m
, match_options
, match_ty
);
1200 // suffix code for cost minimization
1201 if (! (match_options
& MATCHwithtreecost
))
1202 { if (match_options
& MATCHwithexpcost
)
1203 gen_match_cost_minimization(n
, m
, rules
, is_refutable
);
1205 // suffix code for matchall
1206 else if (match_options
& MATCHall
)
1207 gen_matchall_suffix(n
, m
, rules
, is_refutable
);
1210 if (match_options
& MATCHwhile
)
1212 if (is_refutable
) pr("%^%s:;", current_failure
);
1216 mem_pool
.setMark(marker
); // release all memory used
1217 current_failure
= save_failure
;
1218 current_options
= save
;
1221 ///////////////////////////////////////////////////////////////////////////////
1223 // Generate suffix code for a matchall statement.
1224 // The suffix code goes thru the bitmap and select all rule with
1227 ///////////////////////////////////////////////////////////////////////////////
1228 void MatchCompiler::gen_matchall_suffix
1229 (int n
, Match m
, MatchRules rules
, Bool is_refutable
)
1230 { int index
= 0; int bit
= 0;
1231 const BitSet
& always_match
= always_matchables(m
,n
);
1232 if (is_refutable
) { ifs
++; pr ("%^if (m__) {%+"); }
1234 for_each (MatchRule
, r
, rules
)
1236 #line 887 "matchgen.pcc"
1237 #line 898 "matchgen.pcc"
1239 #line 889 "matchgen.pcc"
1240 if (! always_match
.contains(index
* 8 + bit
)) {
1242 pr ("%^if (m__[%i] & %i) ", index
, 1 << bit
);
1246 MarkCurrentRule
mark(current_rule
,r
);
1247 pr ("{%+%&%-%?}\n", r
->_5
);
1248 if (++bit
== 8) { bit
= 0; index
++; }
1250 #line 898 "matchgen.pcc"
1252 #line 899 "matchgen.pcc"
1253 #line 899 "matchgen.pcc"
1256 if (is_refutable
) pr ("%-%^}");
1259 ///////////////////////////////////////////////////////////////////////////////
1261 // Generate suffix code for a match statement with cost minimization.
1262 // The bitmap selected with determine which cost function to execute.
1263 // When all the appropriate cost functions are executed, we choose the
1264 // matched rule with the lowest cost. Ties are broken by the lexical
1265 // order of the rules.
1267 ///////////////////////////////////////////////////////////////////////////////
1268 void MatchCompiler::gen_match_cost_minimization
1269 (int n
, Match m
, MatchRules rules
, Bool is_refutable
)
1271 const BitSet
& always_match
= always_matchables(m
,n
);
1274 "%^int tmp_cost__, cost__ = %i, rule__ = -1;", MAX_COST
);
1275 if (is_refutable
) { ifs
++; pr ("%^if (m__) {%+"); }
1277 for_each (MatchRule
, r
, rules
)
1279 if (! always_match
.contains(index
* 8 + bit
)) {
1281 pr ("if (m__[%i] & %i) ", index
, 1 << bit
);
1283 int rule_no
= index
* 8 + bit
;
1285 #line 929 "matchgen.pcc"
1286 #line 937 "matchgen.pcc"
1289 if (untagp(r
->_4
)) {
1291 #line 937 "matchgen.pcc"
1292 pr ("if (cost__ > %i) { cost__ = %i; rule__ = %i; }", ((Cost_INTcost
*)derefp(r
->_4
))->INTcost
, ((Cost_INTcost
*)derefp(r
->_4
))->INTcost
, rule_no
);
1293 #line 937 "matchgen.pcc"
1296 #line 931 "matchgen.pcc"
1297 pr ("if ((tmp_cost__ = %e) < cost__) { cost__ = tmp_cost__; rule_ = %i; }",
1298 ((Cost_EXPcost
*)r
->_4
)->_1
, rule_no
);
1300 #line 933 "matchgen.pcc"
1303 #line 935 "matchgen.pcc"
1304 pr ("{ rule__ = %i; break; }", rule_no
);
1305 #line 935 "matchgen.pcc"
1308 #line 938 "matchgen.pcc"
1309 #line 938 "matchgen.pcc"
1311 if (++bit
== 8) { bit
= 0; index
++; }
1314 if (is_refutable
) pr ("%-%^}");
1315 pr ("%-%^} while (0);"
1316 "%^switch (rule__) {%+");
1318 for_each(MatchRule
, r
, rules
)
1320 #line 947 "matchgen.pcc"
1321 #line 952 "matchgen.pcc"
1323 #line 949 "matchgen.pcc"
1324 MarkCurrentRule
mark(current_rule
,r
);
1325 pr ("%^case %i: {%+%&%-%?} break;", i
, r
->_5
);
1328 #line 952 "matchgen.pcc"
1330 #line 953 "matchgen.pcc"
1331 #line 953 "matchgen.pcc"
1338 ///////////////////////////////////////////////////////////////////////////////
1340 // Generate code that binds match variables.
1342 ///////////////////////////////////////////////////////////////////////////////
1343 void MatchCompiler::gen_match_variables(MatchExps es
, Ty ty
)
1345 if (length(es
) > 1) {
1347 #line 967 "matchgen.pcc"
1348 #line 969 "matchgen.pcc"
1352 switch (_V8
->tag__
) {
1353 case a_Ty::tag_TYCONty
: {
1354 if (boxed(((Ty_TYCONty
*)_V8
)->_1
)) {
1356 #line 969 "matchgen.pcc"
1357 bug("gen_match_variables()");
1358 #line 969 "matchgen.pcc"
1360 switch ((int)((Ty_TYCONty
*)_V8
)->_1
) {
1361 case ((int)TUPLEtycon
): {
1362 #line 968 "matchgen.pcc"
1363 tys
= ((Ty_TYCONty
*)_V8
)->_2
;
1364 #line 968 "matchgen.pcc"
1366 default: { goto L8
; } break;
1370 default: { goto L8
; } break;
1374 #line 970 "matchgen.pcc"
1375 #line 970 "matchgen.pcc"
1379 #line 972 "matchgen.pcc"
1380 #line 972 "matchgen.pcc"
1382 #line 972 "matchgen.pcc"
1383 #line 972 "matchgen.pcc"
1386 for ( ; es
&& tys
; es
= es
->_2
, tys
= tys
->_2
) {
1388 #line 975 "matchgen.pcc"
1389 #line 982 "matchgen.pcc"
1391 MatchExp _V9
= es
->_1
;
1393 #line 976 "matchgen.pcc"
1395 #line 976 "matchgen.pcc"
1398 #line 977 "matchgen.pcc"
1399 if (! is_ground(tys
->_1
))
1400 error ("%!missing type info in expression %e : %T\n",
1401 _V9
->loc(), _V9
->_1
, tys
->_1
);
1402 pr ("%^%t = %e;\n", tys
->_1
, _V9
->_2
, _V9
->_1
);
1404 #line 981 "matchgen.pcc"
1407 #line 982 "matchgen.pcc"
1409 #line 982 "matchgen.pcc"
1412 #line 983 "matchgen.pcc"
1413 #line 983 "matchgen.pcc"
1418 ///////////////////////////////////////////////////////////////////////////////
1420 // Generate code for a set of function definitions.
1422 ///////////////////////////////////////////////////////////////////////////////
1423 void MatchCompiler::gen_fun_def (FunDefs fundefs
)
1424 { // Generate the prototype first (to deal with recursive definitions).
1425 MemPoolMark marker
= mem_pool
.getMark(); // set heap marker
1426 { for_each (FunDef
, f
, fundefs
)
1428 #line 996 "matchgen.pcc"
1429 #line 1009 "matchgen.pcc"
1431 #line 998 "matchgen.pcc"
1432 f
->_2
= type_match_rules(f
->_4
);
1434 std::ostrstream
b(buf
,sizeof(buf
));
1435 std::ostream
& s
= b
;
1436 s
<< f
->_1
<< std::ends
;
1437 Ty ret_ty
= f
->_3
== NOty
? void_ty
: f
->_3
;
1439 ret_ty
, buf
, f
->_2
, "1", TYformal
);
1440 if (! is_ground(f
->_2
))
1441 error ("%!missing type info in function %q %T\n",
1442 f
->loc(), f
->_1
, f
->_2
);
1444 #line 1009 "matchgen.pcc"
1446 #line 1010 "matchgen.pcc"
1447 #line 1010 "matchgen.pcc"
1452 // Then generate the body of the functions.
1453 { for_each (FunDef
, f
, fundefs
)
1455 #line 1016 "matchgen.pcc"
1456 #line 1030 "matchgen.pcc"
1458 #line 1018 "matchgen.pcc"
1459 int n
= length(f
->_4
);
1460 Match m
= match_of(n
, f
->_4
, MATCHnone
);
1461 check_refutable(m
, f
->_4
, MATCHnone
);
1462 Ty ret_ty
= f
->_3
== NOty
? void_ty
: f
->_3
;
1464 std::ostrstream
b(buf
,sizeof(buf
));
1465 std::ostream
& s
= b
;
1466 s
<< f
->_1
<< std::ends
;
1467 pr ("%^%t %b\n{\n%+",
1468 ret_ty
, buf
, f
->_2
, "1", TYformal
);
1472 #line 1030 "matchgen.pcc"
1474 #line 1031 "matchgen.pcc"
1475 #line 1031 "matchgen.pcc"
1479 mem_pool
.setMark(marker
); // release all memory used
1481 #line 1036 "matchgen.pcc"
1483 ------------------------------- Statistics -------------------------------
1484 Merge matching rules = yes
1485 Number of DFA nodes merged = 147
1486 Number of ifs generated = 23
1487 Number of switches generated = 14
1488 Number of labels = 4
1489 Number of gotos = 12
1490 Adaptive matching = enabled
1491 Fast string matching = disabled
1492 Inline downcasts = enabled
1493 --------------------------------------------------------------------------