2 // Testing reference counting with the rewriting features.
3 // This test is created by modifying rewriting.pcc in this directory
10 // Define an algebraic datatype. Currently, rewriting can only be
11 // performed on datatypes(and not views) in Prop.
12 // If replacement is to be performed on a datatype, then it should
13 // be declared using the ``rewrite'' qualifier.
14 // We'll use garbage collection with rewriting.
16 datatype EXP :: traced rewrite = om
24 { inline void * operator new (size_t n)
25 { balance++; return new char [n]; }
26 inline void operator delete (void * c)
27 { balance--; delete [] ((char*)c); }
30 instantiate datatype EXP;
33 // Define a method that prints an expression. This is a simple
34 // inductive definition
36 ostream& operator << (ostream& f, EXP e)
38 om: { return f << "om"; }
39 | num i: { return f << i; }
40 | var v: { return f << v; }
41 | add(a,b): { return f << '(' << a << " + " << b << ')'; }
42 | sub(a,b): { return f << '(' << a << " - " << b << ')'; }
43 | mul(a,b): { return f << '(' << a << " * " << b << ')'; }
44 | div(a,b): { return f << '(' << a << " / " << b << ')'; }
49 // Define the interface to a ``rewriting class.'' A rewriting class
50 // is simply a C++ class with rewriting rules attached. In real programs
51 // this definition should be placed in some definition (i.e. .ph) files.
53 // In parenthesis, we must list all datatypes involved. Unlike
54 // simple pattern matching, rewriting can involve a set of mutually
55 // recursive (or mutually exclusive, if desired) datatype definitions.
56 // So in general this is a comma delimited list.
58 // In this example it involves only the datatype EXP.
60 rewrite class Simplify (EXP)
61 { // nothing here for now.
65 // Now we define the rewriting rules in the rewriting class Simplify. These
66 // rules should be placed in an implementation file (.pcc, .pC, .pc++ etc).
68 // In this brief sample class we have some rules that perform
69 // simple constant folding and strength reduction.
71 // Currently, all the rules for a rewrite class must be placed in
72 // the same rewrite construct. This will probably change in the future
73 // once I work out the details on incremental tree automata compilation.
76 add (num 0, x): rewrite(x);
77 | add (x, num 0): rewrite(x);
78 | sub (x, num 0): rewrite(x);
79 | mul (x, num 0): rewrite(num(0));
80 | mul (num 0, x): rewrite(num(0));
81 | mul (x, num 1): rewrite(x);
82 | mul (num 1, x): rewrite(x);
83 | mul (x, num 2): rewrite(add(x,x));
84 | mul (num 2, x): rewrite(add(x,x));
85 | div (x, num 1): rewrite(x);
86 | add (num x, num y): rewrite(num(x + y));
87 | sub (num x, num y): rewrite(num(x - y));
88 | mul (num x, num y): rewrite(num(x * y));
89 | div (num x, num y) where (y != 0): rewrite(num(x / y));
90 | div (_, num 0): { /* cout << "Division by zero!\n"; */ }
91 | div (zero as num 0, x): rewrite(zero);
95 // Now defines the function that uses all this stuff.
100 // Instantiate a rewriting class
105 for (int trials = 1; trials < 10000; trials++) {
107 // (0 + x * 2) / (1 * 5 + 1 * 3) / (0 / y);
109 t1 = div(div(add(num(0), mul(var('x'),num(2))),
110 add(mul(num(1), num(5)),mul(num(1),num(3)))),
111 div(num(0),var('y')));
115 // Rewrite the big term above.
117 // cout << "Before: " << term << '\n';
119 // cout << "After: " << term << '\n';
122 // Rewrite it again. It should have no effect since the term
123 // is already in normal form.
126 // cout << "Again (should have no effect): " << term << '\n';
129 // Rewrite some other term.
131 term2 = add(sub(num(3),num(3)), var('z'));
132 // cout << "Before: " << term2 << '\n';
134 // cout << "After: " << term2 << '\n';
140 cout << "Now performing some rewrites and generating some garbage.\n"
141 "This test is identical to the garbage collection test 'test_gc3'\n"
142 "except that reference counting is used. On all platforms\n"
143 "that I've tested reference counting is actually slower.\n"
148 cout << "Finished. Now cleaning up.\n"
149 "Balance = " << balance << '\n';
151 cerr << "Bug in reference counting!\n";