+/* createRMW: Create a read-modify-write expression, using a */
+/* temporary variable if necessary to avoid duplicating */
+/* any side effects, for use in e.g. */
+/* foo()->count += 5; becomes */
+/* tmp = foo(); tmp->count = tmp->count + 5; */
+/*-----------------------------------------------------------------*/
+ast * createRMW (ast *target, unsigned op, ast *operand)
+{
+ ast *readval, *writeval;
+ ast *tempvar1 = NULL;
+ ast *tempvar2 = NULL;
+ ast *result;
+
+ if (!target || !operand) {
+ return NULL;
+ }
+
+ /* we need to create two copies of target: one to read from and
+ one to write to. but we need to do this without duplicating
+ any side effects that may be contained in the tree. */
+
+ if (IS_AST_OP(target)) {
+ /* if this is a dereference, put the referenced item in the temporary */
+ if (IS_DEREF_OP(target) || target->opval.op == PTR_OP) {
+ /* create a new temporary containing the item being dereferenced */
+ if (hasSEFcalls(target->left))
+ tempvar1 = replaceAstWithTemporary(&(target->left));
+ } else if (target->opval.op == '[') {
+ /* Array access is similar, but we have to avoid side effects in
+ both values [WIML: Why not transform a[b] to *(a+b) in parser?] */
+ if (hasSEFcalls(target->left))
+ tempvar1 = replaceAstWithTemporary(&(target->left));
+ if (hasSEFcalls(target->right))
+ tempvar2 = replaceAstWithTemporary(&(target->right));
+ } else {
+ /* we would have to handle '.', but it is not generated any more */
+ wassertl(target->opval.op != '.', "obsolete opcode in tree");
+
+ /* no other kinds of ASTs are lvalues and can contain side effects */
+ }
+ }
+
+ readval = target;
+ writeval = copyAst(target);
+
+ result = newNode('=', writeval, newNode(op, readval, operand));
+ if (tempvar2)
+ result = newNode(',', tempvar2, result);
+ if (tempvar1)
+ result = newNode(',', tempvar1, result);
+
+ return result;
+
+}
+
+/*-----------------------------------------------------------------*/
+/* hasSEFcalls - returns TRUE if tree has a function call, */
+/* inc/decrement, or other side effect */