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