1 /********************************************************************
2  * AUTHORS: Trevor Hansen
3  *
4  * BEGIN DATE: May, 2010
5  *
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12 
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 THE SOFTWARE.
23 ********************************************************************/
24 
25 #include "stp/Printer/SMTLIBPrinter.h"
26 #include "stp/Printer/printers.h"
27 
28 // Functions used by both the version1 and version2 STMLIB printers.
29 
30 namespace printer
31 {
32 using namespace stp;
33 using std::pair;
34 using std::endl;
35 
tolower(const char * name)36 static string tolower(const char* name)
37 {
38   string s(name);
39   for (size_t i = 0; i < s.size(); ++i)
40     s[i] = ::tolower(s[i]);
41   return s;
42 }
43 
44 // Map from ASTNodes to LetVars
45 THREAD_LOCAL stp::ASTNodeMap NodeLetVarMap;
46 
47 // This is a vector which stores the Node to LetVars pairs. It
48 // allows for sorted printing, as opposed to NodeLetVarMap
49 THREAD_LOCAL vector<pair<ASTNode, ASTNode>> NodeLetVarVec;
50 
51 // a partial Map from ASTNodes to LetVars. Needed in order to
52 // correctly print shared subterms inside the LET itself
53 THREAD_LOCAL stp::ASTNodeMap NodeLetVarMap1;
54 
55 // copied from Presentation Langauge printer.
56 ostream&
SMTLIB_Print(ostream & os,STPMgr * mgr,const ASTNode n,const int indentation,void (* SMTLIB1_Print1)(ostream &,const ASTNode,int,bool),bool smtlib1)57 SMTLIB_Print(ostream& os, STPMgr* mgr, const ASTNode n, const int indentation,
58              void (*SMTLIB1_Print1)(ostream&, const ASTNode, int, bool),
59              bool smtlib1)
60 {
61   // Clear the maps
62   NodeLetVarMap.clear();
63   NodeLetVarVec.clear();
64   NodeLetVarMap1.clear();
65 
66   // pass 1: letize the node
67   {
68     ASTNodeSet PLPrintNodeSet;
69     LetizeNode(n, PLPrintNodeSet, smtlib1, mgr);
70   }
71 
72   // pass 2:
73   //
74   // 2. print all the let variables and their counterpart expressions
75   // 2. as follows (LET var1 = expr1, var2 = expr2, ...
76   //
77   // 3. Then print the Node itself, replacing every occurence of
78   // 3. expr1 with var1, expr2 with var2, ...
79   // os << "(";
80   if (0 < NodeLetVarMap.size())
81   {
82     vector<pair<ASTNode, ASTNode>>::iterator it = NodeLetVarVec.begin();
83     const vector<pair<ASTNode, ASTNode>>::iterator itend = NodeLetVarVec.end();
84 
85     os << "(let (";
86     if (!smtlib1)
87       os << "(";
88     // print the let var first
89     SMTLIB1_Print1(os, it->first, indentation, false);
90     os << " ";
91     // print the expr
92     SMTLIB1_Print1(os, it->second, indentation, false);
93     os << " )";
94     if (!smtlib1)
95       os << ")";
96 
97     // update the second map for proper printing of LET
98     NodeLetVarMap1[it->second] = it->first;
99 
100     string closing = "";
101     for (it++; it != itend; it++)
102     {
103       os << " " << endl;
104       os << "(let (";
105       if (!smtlib1)
106         os << "(";
107       // print the let var first
108       SMTLIB1_Print1(os, it->first, indentation, false);
109       os << " ";
110       // print the expr
111       SMTLIB1_Print1(os, it->second, indentation, false);
112       os << ")";
113       if (!smtlib1)
114         os << ")";
115 
116       // update the second map for proper printing of LET
117       NodeLetVarMap1[it->second] = it->first;
118       closing += ")";
119     }
120     os << endl;
121     SMTLIB1_Print1(os, n, indentation, true);
122     os << closing;
123     os << " )  ";
124   }
125   else
126     SMTLIB1_Print1(os, n, indentation, false);
127 
128   os << endl;
129   return os;
130 }
131 
LetizeNode(const ASTNode & n,ASTNodeSet & PLPrintNodeSet,bool smtlib1,STPMgr * stp)132 void LetizeNode(const ASTNode& n, ASTNodeSet& PLPrintNodeSet, bool smtlib1,
133                 STPMgr* stp)
134 {
135   if (n.isAtom())
136     return;
137 
138   const ASTVec& c = n.GetChildren();
139   for (ASTVec::const_iterator it = c.begin(), itend = c.end(); it != itend;
140        it++)
141   {
142     const ASTNode& ccc = *it;
143     if (ccc.isAtom())
144       continue;
145 
146     if (PLPrintNodeSet.find(ccc) == PLPrintNodeSet.end())
147     {
148       // If branch: if *it is not in NodeSet then,
149       //
150       // 1. add it to NodeSet
151       //
152       // 2. Letize its childNodes
153       PLPrintNodeSet.insert(ccc);
154       LetizeNode(ccc, PLPrintNodeSet, smtlib1, stp);
155     }
156     else
157     {
158       // 0. Else branch: Node has been seen before
159       //
160       // 1. Check if the node has a corresponding letvar in the
161       // 1. NodeLetVarMap.
162       //
163       // 2. if no, then create a new var and add it to the
164       // 2. NodeLetVarMap
165       if ((!smtlib1 || ccc.GetType() == BITVECTOR_TYPE) &&
166           NodeLetVarMap.find(ccc) == NodeLetVarMap.end())
167       {
168         // Create a new symbol. Get some name. if it conflicts with a
169         // declared name, too bad.
170         int sz = NodeLetVarMap.size();
171         std::ostringstream oss;
172         oss << "?let_k_" << sz;
173 
174         ASTNode CurrentSymbol = stp->CreateSymbol(
175             oss.str().c_str(), n.GetIndexWidth(), n.GetValueWidth());
176         /* If for some reason the variable being created here is
177          * already declared by the user then the printed output will
178          * not be a legal input to the system. too bad. I refuse to
179          * check for this.  [Vijay is the author of this comment.]
180          */
181 
182         NodeLetVarMap[ccc] = CurrentSymbol;
183         std::pair<ASTNode, ASTNode> node_letvar_pair(CurrentSymbol, ccc);
184         NodeLetVarVec.push_back(node_letvar_pair);
185       }
186     }
187   }
188 }
189 
functionToSMTLIBName(const Kind k,bool smtlib1)190 string functionToSMTLIBName(const Kind k, bool smtlib1)
191 {
192   switch (k)
193   {
194     case IFF:
195       if (smtlib1)
196         return "iff";
197       else
198         return "=";
199     case IMPLIES:
200       if (smtlib1)
201         return "implies";
202       else
203         return "=>";
204     case AND:
205     case BVAND:
206     case BVNAND:
207     case BVNOR:
208     case BVOR:
209     case BVSGE:
210     case BVSGT:
211     case BVSLE:
212     case BVSLT:
213     case BVSUB:
214     case BVXOR:
215     case ITE:
216     case NAND:
217     case NOR:
218     case NOT:
219     case OR:
220     case XOR:
221     {
222       return tolower(_kind_names[k]);
223     }
224 
225     case BVCONCAT:
226       return "concat";
227     case BVDIV:
228       return "bvudiv";
229     case BVGT:
230       return "bvugt";
231     case BVGE:
232       return "bvuge";
233     case BVLE:
234       return "bvule";
235     case BVLEFTSHIFT:
236       return "bvshl";
237     case BVLT:
238       return "bvult";
239     case BVMOD:
240       return "bvurem";
241     case BVMULT:
242       return "bvmul";
243     case BVNOT:
244       return "bvnot";
245     case BVPLUS:
246       return "bvadd";
247     case BVRIGHTSHIFT:
248       return "bvlshr"; // logical
249     case BVSRSHIFT:
250       return "bvashr"; // arithmetic.
251     case BVUMINUS:
252       return "bvneg";
253     case EQ:
254       return "=";
255     case READ:
256       return "select";
257     case WRITE:
258       return "store";
259     case SBVDIV:
260       return "bvsdiv";
261     case SBVREM:
262       return "bvsrem";
263     case SBVMOD:
264       return "bvsmod";
265 
266     default:
267     {
268       std::cerr << "Unknown name when outputting:";
269       FatalError(_kind_names[k]);
270       return ""; // to quieten compiler/
271     }
272   }
273 }
274 }
275