Rewriting rules may be guarded with predicates to limit their applicability. In addition, the rhs of a rewrite rule is not limited to only a replacement expression: in general, any arbitrarily complex sequence of code may be used. For example, in the following set of rewriting rules we use guards to prevent undesirable replacements to be made during expression constant folding:
rewrite ConstantFolding { ADD (INT a, INT b): INT(a+b) | SUB (INT a, INT b): INT(a-b) | MUL (INT a, INT b): { int c = a * b; // silent overflow if (a == 0 || b == 0 || c / b == a) // no overflow? { rewrite(INT(c)); } else { cerr << "Overflow in multiply\n"; } } | DIV (INT a, INT b) | b == 0: { cerr << "Division by zero\n"; } | DIV (INT a, INT b): INT(a/b) | // etc... };