3 * Implementation of GiNaC's light-weight expression handles. */
6 * GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
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.
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.
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
33 #include "relational.h"
34 #include "input_lexer.h"
46 // non-virtual functions in this class
51 /** Print expression to stream. The formatting of the output is determined
52 * by the kind of print_context object that is passed. Possible formattings
53 * include ginsh-parsable output (the default), tree-like output for
54 * debugging, and C++ source.
55 * @see print_context */
56 void ex::print(const print_context & c, unsigned level) const
61 /** Little wrapper arount print to be called within a debugger. */
62 void ex::dbgprint() const
67 /** Little wrapper arount printtree to be called within a debugger. */
68 void ex::dbgprinttree() const
73 ex ex::expand(unsigned options) const
75 if (options == 0 && (bp->flags & status_flags::expanded)) // The "expanded" flag only covers the standard options; someone might want to re-expand with different options
78 return bp->expand(options);
81 /** Compute partial derivative of an expression.
83 * @param s symbol by which the expression is derived
84 * @param nth order of derivative (default 1)
85 * @return partial derivative as a new expression */
86 ex ex::diff(const symbol & s, unsigned nth) const
91 return bp->diff(s, nth);
94 /** Check whether expression matches a specified pattern. */
95 bool ex::match(const ex & pattern) const
98 return bp->match(pattern, repl_lst);
101 /** Find all occurrences of a pattern. The found matches are appended to
102 * the "found" list. If the expression itself matches the pattern, the
103 * children are not further examined. This function returns true when any
104 * matches were found. */
105 bool ex::find(const ex & pattern, lst & found) const
107 if (match(pattern)) {
113 bool any_found = false;
114 for (size_t i=0; i<nops(); i++)
115 if (op(i).find(pattern, found))
120 /** Traverse expression tree with given visitor, preorder traversal. */
121 void ex::traverse_preorder(visitor & v) const
126 for (size_t i = 0; i < n; ++i)
127 op(i).traverse_preorder(v);
130 /** Traverse expression tree with given visitor, postorder traversal. */
131 void ex::traverse_postorder(visitor & v) const
134 for (size_t i = 0; i < n; ++i)
135 op(i).traverse_postorder(v);
140 /** Return modifyable operand/member at position i. */
141 ex & ex::let_op(size_t i)
144 return bp->let_op(i);
147 ex & ex::operator[](const ex & index)
153 ex & ex::operator[](size_t i)
159 /** Left hand side of relational expression. */
162 if (!is_a<relational>(*this))
163 throw std::runtime_error("ex::lhs(): not a relation");
167 /** Right hand side of relational expression. */
170 if (!is_a<relational>(*this))
171 throw std::runtime_error("ex::rhs(): not a relation");
177 /** Make this ex writable (if more than one ex handle the same basic) by
178 * unlinking the object and creating an unshared copy of it. */
179 void ex::makewriteable()
181 GINAC_ASSERT(bp->flags & status_flags::dynallocated);
183 GINAC_ASSERT(bp->refcount == 1);
186 /** Helper function for the ex-from-basic constructor. This is where GiNaC's
187 * automatic evaluator and memory management are implemented.
188 * @see ex::ex(const basic &) */
189 ptr<basic> ex::construct_from_basic(const basic & other)
191 if (!(other.flags & status_flags::evaluated)) {
193 // The object is not yet evaluated, so call eval() to evaluate
194 // the top level. This will return either
195 // a) the original object with status_flags::evaluated set (when the
196 // eval() implementation calls hold())
198 // b) a different expression.
200 // eval() returns an ex, not a basic&, so this will go through
201 // construct_from_basic() a second time. In case a) we end up in
202 // the "else" branch below. In case b) we end up here again and
203 // apply eval() once more. The recursion stops when eval() calls
204 // hold() or returns an object that already has its "evaluated"
205 // flag set, such as a symbol or a numeric.
206 const ex & tmpex = other.eval(1);
208 // Eventually, the eval() recursion goes through the "else" branch
209 // below, which assures that the object pointed to by tmpex.bp is
210 // allocated on the heap (either it was already on the heap or it
211 // is a heap-allocated duplicate of another object).
212 GINAC_ASSERT(tmpex.bp->flags & status_flags::dynallocated);
214 // If the original object is not referenced but heap-allocated,
215 // it means that eval() hit case b) above. The original object is
216 // no longer needed (it evaluated into something different), so we
217 // delete it (because nobody else will).
218 if ((other.refcount==0) && (other.flags & status_flags::dynallocated))
219 delete &other; // yes, you can apply delete to a const pointer
221 // We can't return a basic& here because the tmpex is destroyed as
222 // soon as we leave the function, which would deallocate the
228 // The easy case: making an "ex" out of an evaluated object.
229 if (other.flags & status_flags::dynallocated) {
231 // The object is already heap-allocated, so we can just make
232 // another reference to it.
233 return ptr<basic>(const_cast<basic &>(other));
237 // The object is not heap-allocated, so we create a duplicate
239 basic *bp = other.duplicate();
240 bp->setflag(status_flags::dynallocated);
241 GINAC_ASSERT(bp->refcount == 0);
247 basic & ex::construct_from_int(int i)
249 switch (i) { // prefer flyweights over new objects
251 return const_cast<numeric &>(_num_12);
253 return const_cast<numeric &>(_num_11);
255 return const_cast<numeric &>(_num_10);
257 return const_cast<numeric &>(_num_9);
259 return const_cast<numeric &>(_num_8);
261 return const_cast<numeric &>(_num_7);
263 return const_cast<numeric &>(_num_6);
265 return const_cast<numeric &>(_num_5);
267 return const_cast<numeric &>(_num_4);
269 return const_cast<numeric &>(_num_3);
271 return const_cast<numeric &>(_num_2);
273 return const_cast<numeric &>(_num_1);
275 return const_cast<numeric &>(_num0);
277 return const_cast<numeric &>(_num1);
279 return const_cast<numeric &>(_num2);
281 return const_cast<numeric &>(_num3);
283 return const_cast<numeric &>(_num4);
285 return const_cast<numeric &>(_num5);
287 return const_cast<numeric &>(_num6);
289 return const_cast<numeric &>(_num7);
291 return const_cast<numeric &>(_num8);
293 return const_cast<numeric &>(_num9);
295 return const_cast<numeric &>(_num10);
297 return const_cast<numeric &>(_num11);
299 return const_cast<numeric &>(_num12);
301 basic *bp = new numeric(i);
302 bp->setflag(status_flags::dynallocated);
303 GINAC_ASSERT(bp->refcount == 0);
308 basic & ex::construct_from_uint(unsigned int i)
310 switch (i) { // prefer flyweights over new objects
312 return const_cast<numeric &>(_num0);
314 return const_cast<numeric &>(_num1);
316 return const_cast<numeric &>(_num2);
318 return const_cast<numeric &>(_num3);
320 return const_cast<numeric &>(_num4);
322 return const_cast<numeric &>(_num5);
324 return const_cast<numeric &>(_num6);
326 return const_cast<numeric &>(_num7);
328 return const_cast<numeric &>(_num8);
330 return const_cast<numeric &>(_num9);
332 return const_cast<numeric &>(_num10);
334 return const_cast<numeric &>(_num11);
336 return const_cast<numeric &>(_num12);
338 basic *bp = new numeric(i);
339 bp->setflag(status_flags::dynallocated);
340 GINAC_ASSERT(bp->refcount == 0);
345 basic & ex::construct_from_long(long i)
347 switch (i) { // prefer flyweights over new objects
349 return const_cast<numeric &>(_num_12);
351 return const_cast<numeric &>(_num_11);
353 return const_cast<numeric &>(_num_10);
355 return const_cast<numeric &>(_num_9);
357 return const_cast<numeric &>(_num_8);
359 return const_cast<numeric &>(_num_7);
361 return const_cast<numeric &>(_num_6);
363 return const_cast<numeric &>(_num_5);
365 return const_cast<numeric &>(_num_4);
367 return const_cast<numeric &>(_num_3);
369 return const_cast<numeric &>(_num_2);
371 return const_cast<numeric &>(_num_1);
373 return const_cast<numeric &>(_num0);
375 return const_cast<numeric &>(_num1);
377 return const_cast<numeric &>(_num2);
379 return const_cast<numeric &>(_num3);
381 return const_cast<numeric &>(_num4);
383 return const_cast<numeric &>(_num5);
385 return const_cast<numeric &>(_num6);
387 return const_cast<numeric &>(_num7);
389 return const_cast<numeric &>(_num8);
391 return const_cast<numeric &>(_num9);
393 return const_cast<numeric &>(_num10);
395 return const_cast<numeric &>(_num11);
397 return const_cast<numeric &>(_num12);
399 basic *bp = new numeric(i);
400 bp->setflag(status_flags::dynallocated);
401 GINAC_ASSERT(bp->refcount == 0);
406 basic & ex::construct_from_ulong(unsigned long i)
408 switch (i) { // prefer flyweights over new objects
410 return const_cast<numeric &>(_num0);
412 return const_cast<numeric &>(_num1);
414 return const_cast<numeric &>(_num2);
416 return const_cast<numeric &>(_num3);
418 return const_cast<numeric &>(_num4);
420 return const_cast<numeric &>(_num5);
422 return const_cast<numeric &>(_num6);
424 return const_cast<numeric &>(_num7);
426 return const_cast<numeric &>(_num8);
428 return const_cast<numeric &>(_num9);
430 return const_cast<numeric &>(_num10);
432 return const_cast<numeric &>(_num11);
434 return const_cast<numeric &>(_num12);
436 basic *bp = new numeric(i);
437 bp->setflag(status_flags::dynallocated);
438 GINAC_ASSERT(bp->refcount == 0);
443 basic & ex::construct_from_double(double d)
445 basic *bp = new numeric(d);
446 bp->setflag(status_flags::dynallocated);
447 GINAC_ASSERT(bp->refcount == 0);
451 ptr<basic> ex::construct_from_string_and_lst(const std::string &s, const ex &l)
454 set_lexer_symbols(l);
455 ginac_yyrestart(NULL);
457 throw (std::runtime_error(get_parser_error()));
463 // static member variables
469 // functions which are not member functions