#ifndef around namespace GiNaC { }
[ginac.git] / ginac / printcsrc.cpp
1 /** @file printcsrc.cpp
2  *
3  *  The methods .printcsrc() are responsible for C-source output of
4  *  objects.  All related helper-functions go in here as well. */
5
6 /*
7  *  GiNaC Copyright (C) 1999 Johannes Gutenberg University Mainz, Germany
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include <iostream>
25
26 #include "basic.h"
27 #include "ex.h"
28 #include "add.h"
29 #include "constant.h"
30 #include "expairseq.h"
31 #include "indexed.h"
32 #include "inifcns.h"
33 #include "mul.h"
34 #include "ncmul.h"
35 #include "numeric.h"
36 #include "power.h"
37 #include "relational.h"
38 #include "series.h"
39 #include "symbol.h"
40 #include "debugmsg.h"
41
42 #ifndef NO_GINAC_NAMESPACE
43 namespace GiNaC {
44 #endif // ndef NO_GINAC_NAMESPACE
45
46 /** Print expression as a C++ statement. The output looks like
47  *  "<type> <var_name> = <expression>;". The "type" parameter has an effect
48  *  on how number literals are printed.
49  *
50  *  @param os output stream
51  *  @param type variable type (one of the csrc_types)
52  *  @param var_name variable name to be printed */
53 void ex::printcsrc(ostream & os, unsigned type, const char *var_name) const
54 {
55     debugmsg("ex print csrc", LOGLEVEL_PRINT);
56     GINAC_ASSERT(bp!=0);
57         switch (type) {
58                 case csrc_types::ctype_float:
59                         os << "float ";
60                         break;
61                 case csrc_types::ctype_double:
62                         os << "double ";
63                         break;
64                 case csrc_types::ctype_cl_N:
65                         os << "cl_N ";
66                         break;
67         }
68     os << var_name << " = ";
69     bp->printcsrc(os, type, 0);
70     os << ";\n";
71 }
72
73 void basic::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
74 {
75     debugmsg("basic print csrc", LOGLEVEL_PRINT);
76 }
77
78 void numeric::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
79 {
80     debugmsg("numeric print csrc", LOGLEVEL_PRINT);
81         ios::fmtflags oldflags = os.flags();
82         os.setf(ios::scientific);
83     if (is_rational() && !is_integer()) {
84         if (compare(numZERO()) > 0) {
85             os << "(";
86                         if (type == csrc_types::ctype_cl_N)
87                                 os << "cl_F(\"" << numer().evalf() << "\")";
88                         else
89                     os << numer().to_double();
90         } else {
91             os << "-(";
92                         if (type == csrc_types::ctype_cl_N)
93                                 os << "cl_F(\"" << -numer().evalf() << "\")";
94                         else
95                     os << -numer().to_double();
96         }
97         os << "/";
98                 if (type == csrc_types::ctype_cl_N)
99                         os << "cl_F(\"" << denom().evalf() << "\")";
100                 else
101                 os << denom().to_double();
102         os << ")";
103     } else {
104                 if (type == csrc_types::ctype_cl_N)
105                         os << "cl_F(\"" << evalf() << "\")";
106                 else
107                 os << to_double();
108         }
109         os.flags(oldflags);
110 }
111
112 void symbol::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
113 {
114     debugmsg("symbol print csrc", LOGLEVEL_PRINT);
115     os << name;
116 }
117
118 void constant::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
119 {
120     debugmsg("constant print csrc",LOGLEVEL_PRINT);
121     os << name;
122 }
123
124 static void print_sym_pow(ostream & os, unsigned type, const symbol &x, int exp)
125 {
126     // Optimal output of integer powers of symbols to aid compiler CSE
127     if (exp == 1) {
128         x.printcsrc(os, type, 0);
129     } else if (exp == 2) {
130         x.printcsrc(os, type, 0);
131         os << "*";
132         x.printcsrc(os, type, 0);
133     } else if (exp & 1) {
134         x.printcsrc(os, 0);
135         os << "*";
136         print_sym_pow(os, type, x, exp-1);
137     } else {
138         os << "(";
139         print_sym_pow(os, type, x, exp >> 1);
140         os << ")*(";
141         print_sym_pow(os, type, x, exp >> 1);
142         os << ")";
143     }
144 }
145
146 void power::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
147 {
148     debugmsg("power print csrc", LOGLEVEL_PRINT);
149
150         // Integer powers of symbols are printed in a special, optimized way
151     if (exponent.info(info_flags::integer) &&
152         (is_ex_exactly_of_type(basis, symbol) ||
153          is_ex_exactly_of_type(basis, constant))) {
154         int exp = ex_to_numeric(exponent).to_int();
155         if (exp > 0)
156             os << "(";
157         else {
158             exp = -exp;
159                         if (type == csrc_types::ctype_cl_N)
160                                 os << "recip(";
161                         else
162                     os << "1.0/(";
163         }
164         print_sym_pow(os, type, static_cast<const symbol &>(*basis.bp), exp);
165         os << ")";
166
167         // <expr>^-1 is printed as "1.0/<expr>" or with the recip() function of CLN
168     } else if (exponent.compare(numMINUSONE()) == 0) {
169                 if (type == csrc_types::ctype_cl_N)
170                         os << "recip(";
171                 else
172                 os << "1.0/(";
173         basis.bp->printcsrc(os, type, 0);
174                 os << ")";
175
176         // Otherwise, use the pow() or expt() (CLN) functions
177     } else {
178                 if (type == csrc_types::ctype_cl_N)
179                         os << "expt(";
180                 else
181                 os << "pow(";
182         basis.bp->printcsrc(os, type, 0);
183         os << ",";
184         exponent.bp->printcsrc(os, type, 0);
185         os << ")";
186     }
187 }
188
189 void add::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
190 {
191     debugmsg("add print csrc", LOGLEVEL_PRINT);
192     if (precedence <= upper_precedence)
193         os << "(";
194
195         // Print arguments, separated by "+"
196     epvector::const_iterator it = seq.begin();
197     epvector::const_iterator itend = seq.end();
198     while (it != itend) {
199
200                 // If the coefficient is -1, it is replaced by a single minus sign
201         if (it->coeff.compare(numONE()) == 0) {
202                 it->rest.bp->printcsrc(os, type, precedence);
203         } else if (it->coeff.compare(numMINUSONE()) == 0) {
204             os << "-";
205                 it->rest.bp->printcsrc(os, type, precedence);
206                 } else if (ex_to_numeric(it->coeff).numer().compare(numONE()) == 0) {
207                 it->rest.bp->printcsrc(os, type, precedence);
208                         os << "/";
209             ex_to_numeric(it->coeff).denom().printcsrc(os, type, precedence);
210                 } else if (ex_to_numeric(it->coeff).numer().compare(numMINUSONE()) == 0) {
211                         os << "-";
212                 it->rest.bp->printcsrc(os, type, precedence);
213                         os << "/";
214             ex_to_numeric(it->coeff).denom().printcsrc(os, type, precedence);
215                 } else {
216             it->coeff.bp->printcsrc(os, type, precedence);
217             os << "*";
218                 it->rest.bp->printcsrc(os, type, precedence);
219         }
220
221                 // Separator is "+", except it the following expression would have a leading minus sign
222         it++;
223         if (it != itend && !(it->coeff.compare(numZERO()) < 0 || (it->coeff.compare(numONE()) == 0 && is_ex_exactly_of_type(it->rest, numeric) && it->rest.compare(numZERO()) < 0)))
224             os << "+";
225     }
226     
227     if (!overall_coeff.is_equal(exZERO())) {
228         if (overall_coeff > 0) os << '+';
229         overall_coeff.bp->printcsrc(os,type,precedence);
230     }
231     
232     if (precedence <= upper_precedence)
233         os << ")";
234 }
235
236 void mul::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
237 {
238     debugmsg("mul print csrc", LOGLEVEL_PRINT);
239     if (precedence <= upper_precedence)
240         os << "(";
241
242     if (!overall_coeff.is_equal(exONE())) {
243         overall_coeff.bp->printcsrc(os,type,precedence);
244         os << "*";
245     }
246     
247         // Print arguments, separated by "*" or "/"
248     epvector::const_iterator it = seq.begin();
249     epvector::const_iterator itend = seq.end();
250     while (it != itend) {
251
252                 // If the first argument is a negative integer power, it gets printed as "1.0/<expr>"
253         if (it == seq.begin() && ex_to_numeric(it->coeff).is_integer() && it->coeff.compare(numZERO()) < 0) {
254                         if (type == csrc_types::ctype_cl_N)
255                                 os << "recip(";
256                         else
257                     os << "1.0/";
258                 }
259
260                 // If the exponent is 1 or -1, it is left out
261         if (it->coeff.compare(exONE()) == 0 || it->coeff.compare(numMINUSONE()) == 0)
262             it->rest.bp->printcsrc(os, type, precedence);
263         else
264             // outer parens around ex needed for broken gcc-2.95 parser:
265             (ex(power(it->rest, abs(ex_to_numeric(it->coeff))))).bp->printcsrc(os, type, upper_precedence);
266
267                 // Separator is "/" for negative integer powers, "*" otherwise
268         it++;
269         if (it != itend) {
270             if (ex_to_numeric(it->coeff).is_integer() && it->coeff.compare(numZERO()) < 0)
271                 os << "/";
272             else
273                 os << "*";
274         }
275     }
276     if (precedence <= upper_precedence)
277         os << ")";
278 }
279
280 void ncmul::printcsrc(ostream & os, unsigned upper_precedence) const
281 {
282     debugmsg("ncmul print csrc",LOGLEVEL_PRINT);
283     exvector::const_iterator it;
284     exvector::const_iterator itend = seq.end()-1;
285     os << "ncmul(";
286     for (it=seq.begin(); it!=itend; ++it) {
287         (*it).bp->printcsrc(os,precedence);
288         os << ",";
289     }
290     (*it).bp->printcsrc(os,precedence);
291     os << ")";
292 }
293
294 void relational::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
295 {
296     debugmsg("relational print csrc", LOGLEVEL_PRINT);
297     if (precedence<=upper_precedence)
298                 os << "(";
299
300         // Print left-hand expression
301     lh.bp->printcsrc(os, type, precedence);
302
303         // Print relational operator
304     switch (o) {
305             case equal:
306                 os << "==";
307                 break;
308             case not_equal:
309                 os << "!=";
310                 break;
311             case less:
312                 os << "<";
313                 break;
314             case less_or_equal:
315                 os << "<=";
316                 break;
317             case greater:
318                 os << ">";
319                 break;
320             case greater_or_equal:
321                 os << ">=";
322                 break;
323             default:
324                 os << "(INVALID RELATIONAL OPERATOR)";
325                         break;
326     }
327
328         // Print right-hand operator
329     rh.bp->printcsrc(os, type, precedence);
330
331     if (precedence <= upper_precedence)
332                 os << ")";
333 }
334
335 #ifndef NO_GINAC_NAMESPACE
336 } // namespace GiNaC
337 #endif // ndef NO_GINAC_NAMESPACE