void goto_convertt::clean_expr( exprt &expr, goto_programt &dest, bool result_is_used) { // this cleans: // && || ?: comma (control-dependency) // function calls // object constructors like arrays, string constants, structs // ++ -- // compound assignments // compound literals if(!needs_cleaning(expr)) return; if(expr.id()==ID_and || expr.id()==ID_or) { // rewrite into ?: rewrite_boolean(expr); // recursive call clean_expr(expr, dest, result_is_used); return; } else if(expr.id()==ID_if) { // first clean condition clean_expr(to_if_expr(expr).cond(), dest, true); // possibly done now if(!needs_cleaning(to_if_expr(expr).true_case()) && !needs_cleaning(to_if_expr(expr).false_case())) return; // copy expression if_exprt if_expr=to_if_expr(expr); if(!if_expr.cond().is_boolean()) throw "first argument of `if' must be boolean, but got " +if_expr.cond().to_string(); const locationt location=expr.find_location(); // We do some constant-folding here, to mimic // what typical compilers do. { exprt tmp_cond=if_expr.cond(); simplify(tmp_cond, ns); if(tmp_cond.is_true()) { clean_expr(if_expr.true_case(), dest, result_is_used); expr=if_expr.true_case(); return; } else if(tmp_cond.is_false()) { clean_expr(if_expr.false_case(), dest, result_is_used); expr=if_expr.false_case(); return; } } goto_programt tmp_true; clean_expr(if_expr.true_case(), tmp_true, result_is_used); goto_programt tmp_false; clean_expr(if_expr.false_case(), tmp_false, result_is_used); if(result_is_used) { symbolt &new_symbol= new_tmp_symbol(expr.type(), "if_expr", dest, location); code_assignt assignment_true; assignment_true.lhs()=new_symbol.symbol_expr(); assignment_true.rhs()=if_expr.true_case(); assignment_true.location()=location; convert(assignment_true, tmp_true); code_assignt assignment_false; assignment_false.lhs()=new_symbol.symbol_expr(); assignment_false.rhs()=if_expr.false_case(); assignment_false.location()=location; convert(assignment_false, tmp_false); // overwrites expr expr=new_symbol.symbol_expr(); } else { // preserve the expressions for possible later checks if(if_expr.true_case().is_not_nil()) { code_expressiont code_expression(if_expr.true_case()); convert(code_expression, tmp_true); } if(if_expr.false_case().is_not_nil()) { code_expressiont code_expression(if_expr.false_case()); convert(code_expression, tmp_false); } expr=nil_exprt(); } // generate guard for argument side-effects generate_ifthenelse( if_expr.cond(), tmp_true, tmp_false, location, dest); return; } else if(expr.id()==ID_comma) { if(result_is_used) { exprt result; Forall_operands(it, expr) { bool last=(it==--expr.operands().end()); // special treatment for last one if(last) { result.swap(*it); clean_expr(result, dest, true); } else { clean_expr(*it, dest, false); // remember these for later checks if(it->is_not_nil()) convert(code_expressiont(*it), dest); } } expr.swap(result); } else // result not used {
void goto_convertt::clean_expr( exprt &expr, goto_programt &dest, bool result_is_used) { // this cleans: // && || ?: comma (control-dependency) // function calls // object constructors like arrays, string constants, structs // ++ -- // compound assignments if(!needs_cleaning(expr)) return; if(expr.id()==ID_and || expr.id()==ID_or) { // rewrite into ?: rewrite_boolean(expr); // recursive call clean_expr(expr, dest, result_is_used); return; } else if(expr.id()==ID_if) { if(expr.operands().size()!=3) throw "if takes three arguments"; if(!expr.op0().is_boolean()) throw "first argument of `if' must be boolean, but got " +expr.op0().to_string(); // first pull out condition -- we need to prevent // this getting destroyed by the side-effects in the other // operands make_temp_symbol(expr.op0(), "condition", dest); // now clean arguments goto_programt tmp_true, tmp_false; clean_expr(expr.op1(), tmp_true, result_is_used); clean_expr(expr.op2(), tmp_false, result_is_used); // generate guard for argument side-effects generate_ifthenelse( expr.op0(), tmp_true, tmp_false, expr.location(), dest); return; } else if(expr.id()==ID_comma) { exprt result; Forall_operands(it, expr) { bool last=(it==--expr.operands().end()); if(last) { result.swap(*it); clean_expr(result, dest, result_is_used); } else clean_expr(*it, dest, false); }