expr_stream.h

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  * \file expr_stream.h
00004  * 
00005  * Author: Sergey Berezin
00006  * 
00007  * Created: Mon Jun 16 10:59:18 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  * Declaration of class ExprStream, an output stream to pretty-print
00027  * Expr in various nice output formats (presentation/internal/other
00028  * languages, outo-indentation, bounded depth printing, DAG-ified
00029  * printing, etc, etc...).
00030  * 
00031  * This stream is most useful for the decision procedure designer when
00032  * writing a pretty-printer (Theory::print() method).  ExprStream
00033  * carries information about the current output language, and all the
00034  * indentation and depth pretty-printing is done automagically by the
00035  * operator<<().
00036  * 
00037  */
00038 /*****************************************************************************/
00039 
00040 #ifndef _CVC_lite__expr_stream_h_
00041 #define _CVC_lite__expr_stream_h_
00042 
00043 #include "expr.h"
00044 
00045 namespace CVCL {
00046   class ExprStream;
00047 }
00048 
00049 namespace std {
00050   CVCL::ExprStream& endl(CVCL::ExprStream& os);
00051 }
00052 
00053 namespace CVCL {
00054   
00055   /*! \defgroup PrettyPrinting Pretty-printing related classes and methods
00056    * \ingroup BuildingBlocks
00057    * If you are writing a theory-specific pretty-printer, please read
00058    * carefully all the documentation about class ExprStream and its
00059    * manipulators.
00060    * 
00061    * @{
00062    */
00063 
00064   //! Pretty-printing output stream for Expr.  READ THE DOCS BEFORE USING!
00065   /*! Use this class as a standard ostream for Expr, string, int,
00066     Rational, manipulators like endl, and it will do the expected
00067     thing.  Additionally, it has methods to access the current
00068     printing flags.
00069     
00070     In order for the indentation engine to work correctly, you must
00071     use the manipulators properly.
00072 
00073     Never use "\\n" in a string; always use endl manipulator, which
00074     knows about indentation and will do the right thing.
00075 
00076     Always assume that the object you are printing may start printing
00077     on a new line from the current indentation position.  Therefore,
00078     no string should start with an empty space (otherwise parts of
00079     your expression will be mis-indented).  If you need a white space
00080     separator, or an operator surrounded by spaces, like os << " = ",
00081     use os << space << "= " instead.  The 'space' manipulator adds one
00082     white space only if it's not at the beginning of a newly indented
00083     line.  Think of it as a logical white-space separator with
00084     intelligent behavior, rather than a stupid hard space like " ".
00085 
00086     Indentation can be set to the current position with os << push,
00087     and restored to the previous with os << pop.  You do not need to
00088     restore it before exiting your print function, ExprStream knows
00089     how to restore it automatically.  For example, you can write:
00090 
00091     os << "(" << push << e[0] << space << "+ " << e[1] << push << ")";
00092 
00093     to print (PLUS a b) as "(a + b)".  Notice the second 'push' before
00094     the closing paren.  This is intentional (not a typo), and prevents
00095     the paren ")" from jumping to the next line by itself.  ExprStream
00096     will not go to the next line if the current position is too close
00097     to the indentation, since this will not give the expression a
00098     better look.
00099 
00100     The indentation level is not restored in this example, and that is
00101     fine, ExprStream will take care of that.
00102 
00103     For complex expressions like IF-THEN-ELSE, you may want to
00104     remember the indentation to which you want to return later.  You
00105     can save the current indentation position with os << popSave, and
00106     restore it later with os << pushRestore.  These manipulators are
00107     similar to pop and push, but 'pushRestore' will set the new
00108     indentation level to the one popped by the last popSave instead of
00109     the current one.  At the moment, there is only one register for
00110     saving an indentation position, so multiple pushRestore will not
00111     work as you would expect (maybe this should be fixed?..).
00112 
00113     For concrete examples, see TheoryCore::print() and
00114     TheoryArith::print().
00115     
00116   */
00117   class ExprStream {
00118   private:
00119     ExprManager* d_em; //!< The ExprManager to use
00120     std::ostream* d_os; //!< The ostream to print into
00121     int d_depth; //!< Printing only upto this depth; -1 == unlimited
00122     int d_currDepth; //!< Current depth of Expr
00123     InputLanguage d_lang; //!< Output language
00124     bool d_indent; //!< Whether to print with indentations
00125     int d_col; //!< Current column in a line
00126     int d_lineWidth; //!< Try to format/indent for this line width
00127     //! Indentation stack
00128     /*! The user code can set the indentation to the current d_col by
00129       pushing the new value on the stack.  This value is popped
00130       automatically when returning from the recursive call. */
00131     std::vector<int> d_indentStack;
00132     //! The lowest position of the indent stack the user can pop
00133     size_t d_indentLast;
00134     //! Indentation register for popSave() and pushRestore()
00135     int d_indentReg;
00136     //! Whether it is a beginning of line (for eating up extra spaces)
00137     bool d_beginningOfLine;
00138     bool d_dag; //!< Print Expr as a DAG
00139     //! Mapping subexpressions to names for DAG printing
00140     ExprMap<std::string> d_dagMap;
00141     //! New subexpressions not yet printed in a LET header
00142     ExprMap<std::string> d_newDagMap;
00143     //! Stack of shared subexpressions (same as in d_dagMap)
00144     std::vector<Expr> d_dagStack;
00145     //! Stack of pointers to d_dagStack for pushing/popping shared subexprs
00146     std::vector<size_t> d_dagPtr;
00147     //! The smallest size of d_dagPtr the user can `popDag'
00148     size_t d_lastDagSize;
00149     //! Flag whether the dagMap is already built
00150     bool d_dagBuilt;
00151     //! Counter for generating unique LET var names
00152     int d_idCounter;
00153     //! nodag() manipulator has been applied
00154     bool d_nodag;
00155     //! Parent of current expr being printed
00156     Expr d_parent;
00157     //! Current expr being printed
00158     Expr d_current;
00159     //! Generating unique names in DAG expr
00160     std::string newName();
00161     //! Traverse the Expr, collect shared subexpressions in d_dagMap
00162     void collectShared(const Expr& e, ExprMap<bool>& cache);
00163     //! Wrap e into the top-level LET ... IN header from the dagMap
00164     Expr addLetHeader(const Expr& e);
00165   public:
00166     //! Default constructor
00167     ExprStream(ExprManager *em);
00168     //! Destructor
00169     ~ExprStream() { }
00170     //! Set a new output stream
00171     /*! Note, that there is no method to access the ostream.  This is
00172       done on purpose, so that DP designers had to use only ExprStream
00173       to print everything in their versions of Theory::print(). */
00174     void os(std::ostream& os) { d_os = &os; }
00175     //! Get the current output language
00176     InputLanguage lang() const { return d_lang; }
00177     //! Set the output language
00178     void lang(InputLanguage l) { d_lang = l; }
00179     //! Get the printing depth
00180     int depth() const { return d_depth; }
00181     //! Set the printing depth
00182     void depth(int d) { d_depth = d; }
00183     //! Set the line width
00184     void lineWidth(int w) { d_lineWidth = w; }
00185     //! Set the DAG flag
00186     void dagFlag(bool flag = true) { d_dag = flag; }
00187     //! Set the indentation to the current column
00188     /*! The value will be restorted automatically after the DP print()
00189       function returns */
00190     void pushIndent() { d_indentStack.push_back(d_col); }
00191     //! Set the indentation to the given absolute position
00192     /*! The value will be restorted automatically after the DP print()
00193       function returns */
00194     void pushIndent(int pos) { d_indentStack.push_back(pos); }
00195     //! Restore the indentation (user cannot pop more than pushed)
00196     void popIndent();
00197     //! Reset indentation to what it was at this level
00198     void resetIndent();
00199     //! Return the current column position
00200     int column() const { return d_col; }
00201     //! Recompute shared subexpression for the next Expr
00202     void pushDag();
00203     //! Delete shared subexpressions previously added with pushdag
00204     void popDag();
00205     //! Reset the DAG to what it was at this level
00206     void resetDag();
00207     //! Get parent of current expr being printed
00208     const Expr& getParent() { return d_parent; }
00209 
00210     // The printing action
00211 
00212     //! Use manipulators which are functions over ExprStream&
00213     friend ExprStream& operator<<(ExprStream& os,
00214                                   ExprStream& (*manip)(ExprStream&));
00215     //! Print Expr
00216     friend ExprStream& operator<<(ExprStream& os, const Expr& e);
00217     //! Print Type
00218     friend ExprStream& operator<<(ExprStream& os, const Type& t);
00219     //! Print string
00220     friend ExprStream& operator<<(ExprStream& os, const std::string& s);
00221     //! Print char* string
00222     friend ExprStream& operator<<(ExprStream& os, const char* s);
00223     //! Print Rational
00224     friend ExprStream& operator<<(ExprStream& os, const Rational& r);
00225     //! Print int
00226     friend ExprStream& operator<<(ExprStream& os, int i);
00227 
00228     //! Set the indentation to the current position
00229     friend ExprStream& push(ExprStream& os);
00230     //! Restore the indentation to the previous position
00231     friend ExprStream& pop(ExprStream& os);
00232     //! Remember the current indentation and pop to the previous position
00233     friend ExprStream& popSave(ExprStream& os);
00234     //! Set the indentation to the position saved by popSave()
00235     friend ExprStream& pushRestore(ExprStream& os);
00236     //! Reset the indentation to the default at this level
00237     friend ExprStream& reset(ExprStream& os);
00238     //! Insert a single white space separator
00239     /*! It is preferred to use 'space' rather than a string of spaces
00240       (" ") because ExprStream needs to delete extra white space if it
00241       decides to end the line.  If you use strings for spaces, you'll
00242       mess up the indentation. */
00243     friend ExprStream& space(ExprStream& os);
00244     //! Print the next top-level expression node without DAG-ifying
00245     /*! 
00246      * DAG-printing will resume for the children of the node.  This is
00247      * useful when printing definitions in the header of a DAGified
00248      * LET expressions: defs have names, but must be printed expanded.
00249      */
00250     friend ExprStream& nodag(ExprStream& os);
00251     //! Recompute shared subexpression for the next Expr
00252     /*!
00253      * For some constructs with bound variables (notably,
00254      * quantifiers), shared subexpressions are not computed, because
00255      * they cannot be defined outside the scope of bound variables.
00256      * If this manipulator is applied before an expression within the
00257      * scope of bound vars, these internal subexpressions will then be
00258      * computed.
00259      */
00260     friend ExprStream& pushdag(ExprStream& os);
00261     //! Delete shared subexpressions previously added with pushdag
00262     /*!
00263      * Similar to push/pop, shared subexpressions are automatically
00264      * deleted upon a return from a recursive call, so popdag is not
00265      * necessary after a pushdag in theory-specific print() functions.
00266      * Also, you cannot pop more than you pushed an the current
00267      * recursion level.
00268      */
00269     friend ExprStream& popdag(ExprStream& os);
00270     //! Print the end-of-line
00271     /*! The new line will not necessarily start at column 0 because of
00272       indentation. 
00273     
00274       The name endl will be introduced in namespace std, otherwise
00275       CVCL::endl would overshadow std::endl, wreaking havoc...
00276     */
00277     friend ExprStream& std::endl(ExprStream& os);
00278   }; // end of class ExprStream
00279 
00280   /*! @} */ // End of group PrettyPrinting
00281 
00282 } // End of namespace CVCL
00283 
00284 /*
00285 namespace std {
00286   CVCL::ExprStream& endl(CVCL::ExprStream& os);
00287 }
00288 */
00289 
00290 #endif

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