/**
  * Flatten an expression with respect to an associative operator: for example the expression (a+b)
  * + (c+d) becomes list(a,b,c,d), with the list in canonical order (sorted by hashCode)
  *
  * @param list a list provided by the caller to contain the result
  * @return the list of expressions
  */
 private List flattenExpression(List list) {
   if (operand0 instanceof BinaryExpression
       && ((BinaryExpression) operand0).operator == operator) {
     ((BinaryExpression) operand0).flattenExpression(list);
   } else {
     int h = operand0.hashCode();
     list.add(operand0);
     int i = list.size() - 1;
     while (i > 0 && h > list.get(i - 1).hashCode()) {
       list.set(i, list.get(i - 1));
       list.set(i - 1, operand0);
       i--;
     }
   }
   if (operand1 instanceof BinaryExpression
       && ((BinaryExpression) operand1).operator == operator) {
     ((BinaryExpression) operand1).flattenExpression(list);
   } else {
     int h = operand1.hashCode();
     list.add(operand1);
     int i = list.size() - 1;
     while (i > 0 && h > list.get(i - 1).hashCode()) {
       list.set(i, list.get(i - 1));
       list.set(i - 1, operand1);
       i--;
     }
   }
   return list;
 }
 /** Is this expression the same as another expression? */
 public boolean equals(Object other) {
   if (other instanceof BinaryExpression) {
     BinaryExpression b = (BinaryExpression) other;
     if (operator == b.operator) {
       if (operand0.equals(b.operand0) && operand1.equals(b.operand1)) {
         return true;
       }
       if (isCommutative(operator) && operand0.equals(b.operand1) && operand1.equals(b.operand0)) {
         return true;
       }
       if (isAssociative(operator)
           && pairwiseEqual(
               flattenExpression(new ArrayList(4)), b.flattenExpression(new ArrayList(4)))) {
         return true;
       }
     }
     if (isInverse(operator, b.operator)
         && operand0.equals(b.operand1)
         && operand1.equals(b.operand0)) {
       return true;
     }
   }
   return false;
 }