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