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