expr_stream.cpp

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  * \file expr_stream.cpp
00004  * 
00005  * Author: Sergey Berezin
00006  * 
00007  * Created: Mon Jun 16 13:57:29 2003
00008  *
00009  * <hr>
00010  * Copyright (C) 2003 by the Board of Trustees of Leland Stanford
00011  * Junior University and by New York University. 
00012  *
00013  * License to use, copy, modify, sell and/or distribute this software
00014  * and its documentation for any purpose is hereby granted without
00015  * royalty, subject to the terms and conditions defined in the \ref
00016  * LICENSE file provided with this distribution.  In particular:
00017  *
00018  * - The above copyright notice and this permission notice must appear
00019  * in all copies of the software and related documentation.
00020  *
00021  * - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES,
00022  * EXPRESSED OR IMPLIED.  USE IT AT YOUR OWN RISK.
00023  * 
00024  * <hr>
00025  * 
00026  */
00027 /*****************************************************************************/
00028 
00029 #include "pretty_printer.h"
00030 #include "expr_stream.h"
00031 
00032 //TODO: get rid of dependence on theory_arith
00033 #include "theory_arith.h"
00034 
00035 using namespace std;
00036 
00037 namespace CVCL {
00038 
00039   ExprStream::ExprStream(ExprManager *em)
00040     : d_em(em), d_os(&cout), d_depth(em->printDepth()), d_currDepth(0),
00041       d_lang(em->getOutputLang()),
00042       d_indent(em->withIndentation()), d_col(em->indent()),
00043       d_lineWidth(em->lineWidth()), d_indentReg(0), d_beginningOfLine(false),
00044       d_dag(em->dagPrinting()), d_dagBuilt(false), d_idCounter(0),
00045       d_nodag(false) {
00046     d_indentStack.push_back(d_em->indent());
00047     d_indentLast = d_indentStack.size();
00048     d_dagPtr.push_back(0);
00049     d_lastDagSize=d_dagPtr.size();
00050   }
00051 
00052   //! Generating unique names in DAG expr
00053   string ExprStream::newName() {
00054     ostringstream name;
00055     name << "cvcl_" << d_idCounter++;
00056     return name.str();
00057   }
00058 
00059   static bool isTrivialExpr(const Expr& e) {
00060     switch (e.getKind()) {
00061       // These need to be trivial for correct handling of smt-lib translation.
00062       case CONSTDEF:
00063         if (e.arity() == 2) {
00064           return isTrivialExpr(e[1]);
00065         }
00066         return false;
00067       case RATIONAL_EXPR:
00068       case PLUS:
00069       case MINUS:
00070       case UMINUS:
00071       case MULT:
00072       case DIVIDE:
00073         return true;
00074     }
00075     return (e.arity()==0 && !e.isClosure());
00076   }
00077 
00078   //! Traverse the Expr, collect shared subexpressions in d_dagMap
00079   void ExprStream::collectShared(const Expr& e, ExprMap<bool>& cache) {
00080     // If seen before, and it's not something trivial, add to d_dagMap
00081     if(!isTrivialExpr(e) && cache.count(e) > 0) {
00082       if(d_dagMap.count(e) == 0) {
00083         string s(newName());
00084         if (d_lang == SMTLIB_LANG) {
00085           Type type(e.getType());
00086           if (type.isBool()) {
00087             s = "$" + s;
00088           }
00089           else {
00090             s = "?" + s;
00091           }
00092         }
00093         d_dagMap[e] = s;
00094         d_newDagMap[e] = s;
00095         d_dagStack.push_back(e);
00096       }
00097       return;
00098     }
00099     cache[e] = true;
00100     for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i)
00101       collectShared(*i, cache);
00102     d_dagBuilt = true;
00103   }
00104 
00105   //! Wrap e into the top-level LET ... IN header from the dagMap
00106   /*! 
00107    * We rely on the fact that d_dagMap is ordered by the Expr creation
00108    * order, so earlier expressions cannot depend on later ones.
00109    */
00110   Expr ExprStream::addLetHeader(const Expr& e) {
00111     ExprManager* em = e.getEM();
00112     if(d_newDagMap.size() == 0) return e;
00113     vector<Expr> decls;
00114     for(ExprMap<string>::iterator i=d_newDagMap.begin(),
00115           iend=d_newDagMap.end(); i!=iend; ++i) {
00116       Expr var(em->newVarExpr((*i).second));
00117       if(((*i).first).isType())
00118         decls.push_back(Expr(LETDECL, var, em->newLeafExpr(TYPE),
00119                              (*i).first));
00120       else
00121         decls.push_back(Expr(LETDECL, var, (*i).first));
00122     }
00123     d_newDagMap.clear();
00124     return Expr(LET, Expr(LETDECLS, decls), e);
00125   }
00126 
00127   void ExprStream::popIndent() {
00128     DebugAssert(d_indentStack.size() > 0
00129                 && d_indentStack.size() > d_indentLast,
00130                 "ExprStream::popIndent(): popped too much: "
00131                 "stack size = "+int2string(d_indentStack.size())
00132                 +", indentLast = "+int2string(d_indentLast));
00133     if(d_indentStack.size() > 0 && d_indentStack.size() > d_indentLast)
00134       d_indentStack.pop_back();
00135   }
00136 
00137   //! Reset indentation to what it was at this level
00138   void ExprStream::resetIndent() {
00139     while(d_indentStack.size() > d_indentLast)
00140       d_indentStack.pop_back();
00141   }
00142 
00143 
00144   void ExprStream::pushDag() {
00145     d_dagBuilt = false;
00146     d_dagPtr.push_back(d_dagStack.size());
00147   }
00148 
00149   void ExprStream::popDag() {
00150     DebugAssert(d_dagPtr.size() > d_lastDagSize,
00151                 "ExprStream::popDag: popping more than pushed");
00152     DebugAssert(d_lastDagSize > 0, "ExprStream::popDag: this cannot happen!");
00153     if(d_dagPtr.size() > d_lastDagSize) {
00154       size_t size(d_dagPtr.back());
00155       d_dagPtr.pop_back();
00156       while(d_dagStack.size() > size) {
00157         d_dagMap.erase(d_dagStack.back());
00158         d_dagStack.pop_back();
00159       }
00160       d_newDagMap.clear();
00161     }
00162   }
00163 
00164   void ExprStream::resetDag() {
00165     while(d_dagPtr.size() > d_lastDagSize) popDag();
00166   }
00167 
00168   /*! \defgroup ExprStream_Op Overloaded operator<< 
00169    * \ingroup PrettyPrinting
00170    * @{
00171    */
00172   //! Use manipulators which are functions over ExprStream&
00173   ExprStream& operator<<(ExprStream& os,
00174                          ExprStream& (*manip)(ExprStream&)) {
00175     return (*manip)(os);
00176   }
00177 
00178   //! Print Expr
00179   ExprStream& operator<<(ExprStream& os, const Expr& e) {
00180     Expr saveParent = os.d_parent;
00181     //os << "Printing in expr_stream";
00182     // If the max print depth is reached, print "..."
00183     if(os.d_depth >= 0 && os.d_currDepth > os.d_depth) return os << "...";
00184     Expr e2(e);
00185     // KLUDGE: don't LET-ify commands like ASSERT, QUERY, TRANSFORM
00186     switch(e.getKind()) {
00187     case QUERY:
00188     case ASSERT:
00189     case TRANSFORM:
00190     case TYPE:
00191     case CONST:
00192       os.d_nodag = true;
00193       break;
00194     default: break;
00195     }
00196     // Check cache for DAG printing
00197     if(os.d_dag && !os.d_nodag) {
00198       if(os.d_dagBuilt) {
00199         ExprMap<string>::iterator i(os.d_dagMap.find(e));
00200         if(i != os.d_dagMap.end()) {
00201           ostringstream ss;
00202           ss << (*i).second;
00203           return os << ss.str();
00204         }
00205       } else {
00206         // We are at the top level; build dagMap and print LET header
00207         ExprMap<bool> cache;
00208         os.collectShared(e, cache);
00209         e2 = os.addLetHeader(e);
00210       }
00211     }
00212     os.d_nodag=false;
00213 
00214     // Increase the depth before the (possibly) recursive call
00215     os.d_currDepth++;
00216     // Save the indentation stack position and register
00217     int indentLast = os.d_indentLast;
00218     int reg = os.d_indentReg;
00219     size_t lastDagSize = os.d_lastDagSize;
00220 
00221     os.d_indentLast = os.d_indentStack.size();
00222     os.d_lastDagSize = os.d_dagPtr.size();
00223 
00224     os.d_parent = os.d_current;
00225     os.d_current = e;
00226 
00227     PrettyPrinter* pp = os.d_em->getPrinter();
00228     // If no pretty-printer, or the language is AST, print the AST
00229     if(pp == NULL || os.d_lang == AST_LANG) e2.printAST(os);
00230     // Otherwise simply call the pretty-printer
00231     else pp->print(os, e2);
00232     // Restore the depth after the (possibly) recursive call
00233     os.d_currDepth--;
00234     os.d_current = os.d_parent;
00235     os.d_parent = saveParent;
00236 
00237     // Restore the indentation stack and register
00238     os.resetIndent();
00239     os.resetDag();
00240     os.d_indentLast = indentLast;
00241     os.d_indentReg = reg;
00242     os.d_lastDagSize = lastDagSize;
00243     return os;
00244   }
00245 
00246   //! Print Type
00247   ExprStream& operator<<(ExprStream& os, const Type& t) {
00248     return os << t.getExpr();
00249   }
00250 
00251 
00252   //! Print string
00253   /*! This is where all the indentation is happening.
00254 
00255   The algorithm for determining whether to go to the next line is the
00256   following:
00257   
00258   - If the new d_col does not exceed d_lineWidth/2 or current
00259     indentation, don't bother.
00260   
00261   - If the difference between the new d_col and the current
00262     indentation is less than d_lineWidth/4, don't bother either, so
00263     that we don't get lots of very short lines clumped to the right
00264     side.
00265 
00266   - Similarly, if the difference between the old d_col and the current
00267     indentation is less than d_lineWidth/6, keep the same line.
00268     Otherwise, for long atomic strings, we may get useless line breaks.
00269   
00270   - Otherwise, go to the next line.
00271   */
00272   ExprStream& operator<<(ExprStream& os, const string& s) {
00273     // Save the old position
00274     int oldCol(os.d_col);
00275     // The new position after printing s
00276     os.d_col += s.size();
00277     if(os.d_indent) {
00278       // Current indentation position
00279       int n(os.d_indentStack.size()? os.d_indentStack.back() : 0);
00280       // See if we need to go to the next line before printing.
00281       if(2*os.d_col > os.d_lineWidth && 4*(os.d_col - n) > os.d_lineWidth
00282          && 6*(oldCol - n) > os.d_lineWidth) {
00283         os << endl;
00284         // Recompute the new column
00285         os.d_col += s.size();
00286       }
00287     }
00288     *os.d_os << s;
00289     os.d_beginningOfLine = false;
00290     return os;
00291   }
00292 
00293   //! Print char* string
00294   ExprStream& operator<<(ExprStream& os, const char* s) {
00295     return os << string(s);
00296   }
00297 
00298   //! Print Rational
00299   ExprStream& operator<<(ExprStream& os, const Rational& r) {
00300     ostringstream ss;
00301     ss << r;
00302     return os << ss.str();
00303   }
00304 
00305   //! Print int
00306   ExprStream& operator<<(ExprStream& os, int i) {
00307     ostringstream ss;
00308     ss << i;
00309     return os << ss.str();
00310   }
00311   /*! @} */ // End of group ExprStream_Op
00312 
00313   /*! \defgroup ExprStream_Manip Manipulators 
00314    * \ingroup PrettyPrinting
00315    * @{
00316    */
00317 
00318   //! Set the indentation to the current position
00319   ExprStream& push(ExprStream& os) { os.pushIndent(); return os; }
00320 
00321   //! Restore the indentation
00322   ExprStream& pop(ExprStream& os) { os.popIndent(); return os; }
00323   //! Remember the current indentation and pop to the previous position
00324   /*! There is only one register to save the previous position.  If
00325     you use popSave() more than once, only the latest position can be
00326     restored with pushRestore(). */
00327   ExprStream& popSave(ExprStream& os) {
00328     os.d_indentReg = os.d_indentStack.size() ? os.d_indentStack.back() : 0;
00329     os.popIndent();
00330     return os;
00331   }
00332   //! Set the indentation to the position saved by popSave()
00333   /*! There is only one register to save the previous position.  Using
00334     pushRestore() several times will set intendation to the same
00335     position. */
00336   ExprStream& pushRestore(ExprStream& os) {
00337     os.pushIndent(os.d_indentReg);
00338     return os;
00339   }
00340   //! Reset the indentation to the default at this level
00341   ExprStream& reset(ExprStream& os) { os.resetIndent(); return os; }
00342   //! Insert a single white space separator
00343   /*! It is preferred to use 'space' rather than a string of spaces
00344     (" ") because ExprStream needs to delete extra white space if it
00345     decides to end the line.  If you use strings for spaces, you'll
00346     mess up the indentation. */
00347   ExprStream& space(ExprStream& os) {
00348     // Prevent " " to carry to the next line
00349     if(!os.d_beginningOfLine) os << push << " " << pop;
00350     return os;
00351   }
00352 
00353   ExprStream& nodag(ExprStream& os) {
00354     os.d_nodag = true;
00355     return os;
00356   }
00357 
00358   ExprStream& pushdag(ExprStream& os) { os.pushDag(); return os; }
00359 
00360   ExprStream& popdag(ExprStream& os) { os.popDag(); return os; }
00361 
00362   /*! @} */ // End of group ExprStream_Manip
00363 
00364 } // End of namespace CVCL
00365 
00366 namespace std {
00367 
00368   //! Print the end-of-line
00369   /*! 
00370    * The new line will not necessarily start at column 0 because of
00371    * indentation.
00372    * \ingroup ExprStream_Manip 
00373    */
00374   CVCL::ExprStream& endl(CVCL::ExprStream& os) {
00375     if(os.d_indent) {
00376       // Current indentation
00377       int n(os.d_indentStack.size()? os.d_indentStack.back() : 0);
00378       // Create a string of n white spaces
00379       string spaces(n, ' ');
00380       (*os.d_os) << endl << spaces;
00381       os.d_col = n;
00382     } else {
00383       (*os.d_os) << endl;
00384       os.d_col = 0;
00385     }
00386     os.d_beginningOfLine = true;
00387     return os;
00388   }
00389 }

Generated on Thu Apr 13 16:57:31 2006 for CVC Lite by  doxygen 1.4.4