1 /********************************************************************
2  * AUTHORS: Trevor Hansen, Vijay Ganesh
3  *
4  * BEGIN DATE: July, 2009
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 #include <cassert>
28 #include <cctype>
29 
30 // Outputs in the SMTLIB1 format. If you want something that can be parsed by
31 // other tools call
32 // SMTLIB_PrintBack(). SMTLIB_Print() prints just an expression.
33 // Wierdly is seems that only terms, not formulas can be LETized.
34 
35 // NB: This code doesn't include the substitution map. So if you've already
36 // simplified
37 // the graph, then solving what this prints out wont necessarily give you a
38 // model.
39 
40 namespace printer
41 {
42 using std::string;
43 using std::endl;
44 using namespace stp;
45 
46 void SMTLIB1_Print1(ostream& os, const stp::ASTNode n, int indentation,
47                     bool letize);
48 void printSMTLIB1VarDeclsToStream(ASTNodeSet& symbols, ostream& os);
49 
SMTLIB1_PrintBack(ostream & os,const ASTNode & n,STPMgr * mgr)50 void SMTLIB1_PrintBack(ostream& os, const ASTNode& n, STPMgr* mgr)
51 {
52   os << "(" << endl;
53   os << "benchmark blah" << endl;
54   if (containsArrayOps(n, mgr))
55     os << ":logic QF_AUFBV" << endl;
56   else
57     os << ":logic QF_BV" << endl;
58 
59   if (input_status == TO_BE_SATISFIABLE)
60   {
61     os << ":status sat" << endl;
62   }
63   else if (input_status == TO_BE_UNSATISFIABLE)
64   {
65     os << ":status unsat" << endl;
66   }
67   else
68     os << ":status unknown" << endl;
69 
70   ASTNodeSet visited, symbols;
71   buildListOfSymbols(n, visited, symbols);
72   printSMTLIB1VarDeclsToStream(symbols, os);
73   os << ":formula ";
74   SMTLIB_Print(os, mgr, n, 0, &SMTLIB1_Print1, true);
75   os << ")" << endl;
76 }
77 
printSMTLIB1VarDeclsToStream(ASTNodeSet & symbols,ostream & os)78 void printSMTLIB1VarDeclsToStream(ASTNodeSet& symbols, ostream& os)
79 {
80   for (ASTNodeSet::const_iterator i = symbols.begin(), iend = symbols.end();
81        i != iend; i++)
82   {
83     const stp::ASTNode& a = *i;
84 
85     // Should be a symbol.
86     assert(a.GetKind() == SYMBOL);
87 
88     switch (a.GetType())
89     {
90       case stp::BITVECTOR_TYPE:
91 
92         os << ":extrafuns (( ";
93         a.nodeprint(os);
94         os << " BitVec[" << a.GetValueWidth() << "]";
95         os << " ))" << endl;
96         break;
97       case stp::ARRAY_TYPE:
98         os << ":extrafuns (( ";
99         a.nodeprint(os);
100         os << " Array[" << a.GetIndexWidth();
101         os << ":" << a.GetValueWidth() << "] ))" << endl;
102         break;
103       case stp::BOOLEAN_TYPE:
104         os << ":extrapreds (( ";
105         a.nodeprint(os);
106         os << "))" << endl;
107         break;
108       default:
109         stp::FatalError("printVarDeclsToStream: Unsupported type", a);
110         break;
111     }
112   }
113 } // printVarDeclsToStream
114 
outputBitVec(const ASTNode n,ostream & os)115 void outputBitVec(const ASTNode n, ostream& os)
116 {
117   const Kind k = n.GetKind();
118   const ASTVec& c = n.GetChildren();
119   ASTNode op;
120 
121   if (BITVECTOR == k)
122   {
123     op = c[0];
124   }
125   else if (BVCONST == k)
126   {
127     op = n;
128   }
129   else
130     FatalError("nsadfsdaf2");
131 
132   // CONSTANTBV::BitVector_to_Dec returns a signed representation by default.
133   // Prepend with zero to convert to unsigned.
134 
135   os << "bv";
136   CBV zero = CONSTANTBV::BitVector_Create(1, true);
137   CBV unsign = CONSTANTBV::BitVector_Concat(zero, op.GetBVConst());
138   unsigned char* str = CONSTANTBV::BitVector_to_Dec(unsign);
139   CONSTANTBV::BitVector_Destroy(unsign);
140   CONSTANTBV::BitVector_Destroy(zero);
141   os << str << "[" << op.GetValueWidth() << "]";
142   CONSTANTBV::BitVector_Dispose(str);
143 }
144 
SMTLIB1_Print1(ostream & os,const ASTNode n,int indentation,bool letize)145 void SMTLIB1_Print1(ostream& os, const ASTNode n, int indentation, bool letize)
146 {
147   // os << spaces(indentation);
148   // os << endl << spaces(indentation);
149   if (!n.IsDefined())
150   {
151     FatalError("<undefined>");
152     return;
153   }
154 
155   // if this node is present in the letvar Map, then print the letvar
156   // this is to print letvars for shared subterms inside the printing
157   // of "(LET v0 = term1, v1=term1@term2,...
158   if ((NodeLetVarMap1.find(n) != NodeLetVarMap1.end()) && !letize)
159   {
160     SMTLIB1_Print1(os, (NodeLetVarMap1[n]), indentation, letize);
161     return;
162   }
163 
164   // this is to print letvars for shared subterms inside the actual
165   // term to be printed
166   if ((NodeLetVarMap.find(n) != NodeLetVarMap.end()) && letize)
167   {
168     SMTLIB1_Print1(os, (NodeLetVarMap[n]), indentation, letize);
169     return;
170   }
171 
172   // otherwise print it normally
173   const Kind kind = n.GetKind();
174   const ASTVec& c = n.GetChildren();
175   switch (kind)
176   {
177     case BITVECTOR:
178     case BVCONST:
179       outputBitVec(n, os);
180       break;
181     case SYMBOL:
182       n.nodeprint(os);
183       break;
184     case FALSE:
185       os << "false";
186       break;
187     case NAND: // No NAND, NOR in smtlib format.
188     case NOR:
189       assert(c.size() == 2);
190       os << "("
191          << "not ";
192       if (NAND == kind)
193         os << "("
194            << "and ";
195       else
196         os << "("
197            << "or ";
198       SMTLIB1_Print1(os, c[0], 0, letize);
199       os << " ";
200       SMTLIB1_Print1(os, c[1], 0, letize);
201       os << "))";
202       break;
203     case TRUE:
204       os << "true";
205       break;
206     case BVSX:
207     case BVZX:
208     {
209       unsigned int amount = c[1].GetUnsignedConst();
210       if (BVZX == kind)
211         os << "(zero_extend[";
212       else
213         os << "(sign_extend[";
214 
215       os << (amount - c[0].GetValueWidth()) << "]";
216       SMTLIB1_Print1(os, c[0], indentation, letize);
217       os << ")";
218     }
219     break;
220     case BVEXTRACT:
221     {
222       unsigned int upper = c[1].GetUnsignedConst();
223       unsigned int lower = c[2].GetUnsignedConst();
224       assert(upper >= lower);
225       os << "(extract[" << upper << ":" << lower << "] ";
226       SMTLIB1_Print1(os, c[0], indentation, letize);
227       os << ")";
228     }
229     break;
230     default:
231     {
232       if ((kind == AND || kind == OR || kind == XOR) && n.Degree() == 1)
233       {
234         FatalError("Wrong number of arguments to operation (must be >1).", n);
235       }
236 
237       // SMT-LIB only allows these functions to have two parameters.
238       if ((kind == AND || kind == OR || kind == XOR || BVPLUS == kind ||
239            kind == BVOR || kind == BVAND) &&
240           n.Degree() > 2)
241       {
242         string close = "";
243 
244         for (long int i = 0; i < (long int)c.size() - 1; i++)
245         {
246           os << "(" << functionToSMTLIBName(kind, true);
247           os << " ";
248           SMTLIB1_Print1(os, c[i], 0, letize);
249           os << " ";
250           close += ")";
251         }
252         SMTLIB1_Print1(os, c[c.size() - 1], 0, letize);
253         os << close;
254       }
255       else
256       {
257         os << "(" << functionToSMTLIBName(kind, true);
258 
259         ASTVec::const_iterator iend = c.end();
260         for (ASTVec::const_iterator i = c.begin(); i != iend; i++)
261         {
262           os << " ";
263           SMTLIB1_Print1(os, *i, 0, letize);
264         }
265 
266         os << ")";
267       }
268     }
269   }
270 }
271 }
272