private ProverFun procedure2ProverExpr(BoogieProcedure proc) {
    HashMap<Variable, ProverExpr> localbound = new HashMap<Variable, ProverExpr>();
    if (!usedFunctions.containsKey(proc)) {
      LinkedList<ProverType> args = new LinkedList<ProverType>();
      int idx = 0;
      for (Variable v : proc.getParameterList()) {
        ProverExpr arg = theoremProver.mkBoundVariable(idx++, type2ProverSort(v.getType()));
        args.add(arg.getType());
        localbound.put(v, arg);
      }

      ProverFun vcf = null;
      ProverType[] arr = args.toArray(new ProverType[args.size()]);
      if (proc.isPure()
          && proc.getRootBlock() != null
          && proc.getRootBlock().getStatements().size() == 1) {
        // TODO: this is a hack:
        // we assume that this case only occurs for prelude functions
        // which have only one statement
        // this will not work in any other case
        Statement stmt = proc.getRootBlock().getStatements().get(0);
        ProverExpr b = null;
        if (stmt instanceof ExpressionStatement) {
          ExpressionStatement es = (ExpressionStatement) stmt;
          b = expression2ProverExpr(es.getExpression(), localbound);
        } else {
          throw new RuntimeException("procedure2ProverExpr failed");
        }
        vcf = theoremProver.mkDefinedFunction(getProverFriendlyName(proc.getName()), arr, b);
      } else {
        vcf =
            theoremProver.mkUnintFunction(
                getProverFriendlyName(proc.getName()),
                arr,
                type2ProverSort(proc.getReturnVariable().getType()));

        // TODO: uninterpreted functions?
      }
      usedFunctions.put(proc, vcf);
    }
    return usedFunctions.get(proc);
  }
  private String z3_printSMT2Declarations() {
    StringBuilder sb = new StringBuilder();
    sb.append("(set-logic AUFLIA)\n\n");
    for (String s : z3_helperVars) {
      sb.append("(declare-fun ");
      sb.append(getProverFriendlyName(s));
      sb.append(" () Bool");
      sb.append(")\n");
    }

    for (Entry<Variable, ProverExpr> entry : usedVariable.entrySet()) {
      sb.append("(declare-fun ");
      sb.append(getProverFriendlyName(entry.getKey().getName()));
      sb.append(" () ");
      sb.append(z3_type2SMT2(entry.getKey().getType()));
      sb.append(")\n");
    }
    for (Entry<BoogieProcedure, ProverFun> entry : usedFunctions.entrySet()) {
      // distinguish between prelude functions that have exactly one
      // statement and are pure
      // and all the rest.
      if (proc.isPure()
          && proc.getRootBlock() != null
          && proc.getRootBlock().getStatements().size() == 1) {
        // TODO: for some reason this does not happen,
        // as princess already inlines those functions and they
        // are not added to the list of used functions.
        throw new RuntimeException("SMT2 Printer, unexpected prelude function");

      } else {
        sb.append("(declare-fun ");
        sb.append(getProverFriendlyName(entry.getKey().getName()));
        sb.append("( "); // now the params
        for (Variable param : entry.getKey().getParameterList()) {
          sb.append("(");
          sb.append(z3_type2SMT2(param.getType()));
          sb.append(") ");
        }
        sb.append(") "); // done with params
        // not the regular return value:
        if (entry.getKey().getReturnVariable() != null) {
          sb.append(z3_type2SMT2(entry.getKey().getReturnVariable().getType()));
          sb.append(" ");
        }
        // TODO: at this point, the SSA should have removed all
        // calls to non-pure functions already, so no need to
        // worry about exception handling

        sb.append(")\n");
      }
    }

    return sb.toString();
  }