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