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