1 /* expr.cc -- part of aamath
2  *
3  * This program is copyright (C) 2005 Mauro Persano, and is free
4  * software which is freely distributable under the terms of the
5  * GNU public license, included as the file COPYING in this
6  * distribution.  It is NOT public domain software, and any
7  * redistribution not permitted by the GNU General Public License is
8  * expressly forbidden without prior written permission from
9  * the author.
10  *
11  */
12 
13 #include <stdio.h>
14 #include <string.h>
15 #include <assert.h>
16 #include "canvas.h"
17 #include "expr.h"
18 
19 static Integer ZERO("0");
20 
21 extern bool big_radicals;
22 
23 static inline int
max(int a,int b)24 max(int a, int b)
25 {
26 	return a > b ? a : b;
27 }
28 
29 static inline int
min(int a,int b)30 min(int a, int b)
31 {
32 	return a < b ? a : b;
33 }
34 
35 //
36 //	E x p r e s s i o n
37 //
38 
Expression(ExpressionType type_)39 Expression::Expression(ExpressionType type_)
40 : expr_type(type_)
41 { }
42 
~Expression()43 Expression::~Expression()
44 { }
45 
46 ExpressionType
get_expr_type() const47 Expression::get_expr_type() const
48 {
49 	return expr_type;
50 }
51 
52 
53 //
54 //	C o n s t a n t
55 //
56 
Constant(ConstantType type_)57 Constant::Constant(ConstantType type_)
58 : Expression(ET_Constant)
59 , const_type(type_)
60 { }
61 
~Constant()62 Constant::~Constant()
63 { }
64 
65 ConstantType
get_const_type() const66 Constant::get_const_type() const
67 {
68 	return const_type;
69 }
70 
71 bool
need_parens() const72 Constant::need_parens() const
73 {
74 	return false;
75 }
76 
77 bool
is_constant() const78 Constant::is_constant() const
79 {
80 	return true;
81 }
82 
83 bool
accept_expn() const84 Constant::accept_expn() const
85 {
86 	return false;
87 }
88 
89 void
set_expn(Expression * expn_)90 Constant::set_expn(Expression *expn_)
91 {
92 	assert(0);
93 }
94 
95 
Integer(char * value_)96 Integer::Integer(char *value_)
97 : Constant(CT_Integer)
98 , value(value_)
99 { }
100 
~Integer()101 Integer::~Integer()
102 { }
103 
104 CanvasPtr
render() const105 Integer::render() const
106 {
107 	CanvasPtr c;
108 
109 	c->paste_string(value, 0, 0);
110 
111 	return c;
112 }
113 
Real(char * value_)114 Real::Real(char *value_)
115 : Constant(CT_Real)
116 , value(value_)
117 { }
118 
~Real()119 Real::~Real()
120 { }
121 
122 CanvasPtr
render() const123 Real::render() const
124 {
125 	CanvasPtr c;
126 
127 	c->paste_string(value, 0, 0);
128 
129 	return c;
130 }
131 
132 
Ellipsis()133 Ellipsis::Ellipsis()
134 : Constant(CT_Ellipsis)
135 { }
136 
~Ellipsis()137 Ellipsis::~Ellipsis()
138 { }
139 
140 CanvasPtr
render() const141 Ellipsis::render() const
142 {
143 	CanvasPtr c;
144 
145 	c->paste_string("...", 0, 0);
146 
147 	return c;
148 }
149 
Infinity()150 Infinity::Infinity()
151 : Constant(CT_Infinity)
152 { }
153 
~Infinity()154 Infinity::~Infinity()
155 { }
156 
157 CanvasPtr
render() const158 Infinity::render() const
159 {
160 	CanvasPtr c;
161 
162 	c->paste_string("oo", 0, 0);
163 
164 	return c;
165 }
166 
Pi()167 Pi::Pi()
168 : Constant(CT_Pi)
169 , expn(NULL)
170 { }
171 
~Pi()172 Pi::~Pi()
173 {
174 	if (expn != NULL)
175 		delete expn;
176 }
177 
178 bool
accept_expn() const179 Pi::accept_expn() const
180 {
181 	return expn == NULL;
182 }
183 
184 void
set_expn(Expression * expn_)185 Pi::set_expn(Expression *expn_)
186 {
187 	assert(expn == NULL);
188 
189 	expn = expn_;
190 }
191 
192 CanvasPtr
render() const193 Pi::render() const
194 {
195 	CanvasPtr c;
196 
197 	c->paste_string("__", -1, 0);
198 	c->paste_string("||", 0, 0);
199 
200 	if (expn != NULL)
201 		c->paste(*(expn->render()), -1, 2, Canvas::VA_Top);
202 
203 	return c;
204 }
205 
Nabla()206 Nabla::Nabla()
207 : Constant(CT_Nabla)
208 , expn(NULL)
209 { }
210 
~Nabla()211 Nabla::~Nabla()
212 {
213 	if (expn != NULL)
214 		delete expn;
215 }
216 
217 bool
accept_expn() const218 Nabla::accept_expn() const
219 {
220 	return expn == NULL;
221 }
222 
223 void
set_expn(Expression * expn_)224 Nabla::set_expn(Expression *expn_)
225 {
226 	assert(expn == NULL);
227 
228 	expn = expn_;
229 }
230 
231 CanvasPtr
render() const232 Nabla::render() const
233 {
234 	CanvasPtr c;
235 
236 	c->paste_string("__", -1, 0);
237 	c->paste_string("\\/", 0, 0);
238 
239 	if (expn != NULL)
240 		c->paste(*(expn->render()), -1, 2, Canvas::VA_Top);
241 
242 	return c;
243 }
244 
245 //
246 //	V a r i a b l e
247 //
248 
Symbol(char * name_)249 Symbol::Symbol(char *name_)
250 : Expression(ET_Symbol)
251 , name(name_)
252 , subscr(NULL)
253 , expn(NULL)
254 , num_ticks(0)
255 , is_conj(false)
256 , has_bar(false)
257 { }
258 
~Symbol()259 Symbol::~Symbol()
260 {
261 	if (subscr != NULL)
262 		delete subscr;
263 
264 	if (expn != NULL)
265 		delete expn;
266 }
267 
268 bool
need_parens() const269 Symbol::need_parens() const
270 {
271 	return false;
272 }
273 
274 bool
is_constant() const275 Symbol::is_constant() const
276 {
277 	return false;
278 }
279 
280 bool
accept_expn() const281 Symbol::accept_expn() const
282 {
283 	return expn == NULL;
284 }
285 
286 CanvasPtr
render() const287 Symbol::render() const
288 {
289 	CanvasPtr canvas;
290 
291 	canvas->paste_string(name, 0, 0);
292 
293 	int c = name.length();
294 
295 	if (has_bar) {
296 		for (int i = 0; i < c; i++)
297 			(*canvas)[-1][i] = '_';
298 	}
299 
300 	if (subscr != NULL)
301 		canvas->paste(*(subscr->render()), 1, c, Canvas::VA_Bottom);
302 
303 	for (int i = 0; i < num_ticks; i++)
304 		(*canvas)[0][c + i] = '\'';
305 
306 	if (is_conj) {
307 		(*canvas)[-1][c] = '*';
308 		++c;
309 	}
310 
311 	if (expn != NULL)
312 		canvas->paste(*(expn->render()), -1, c, Canvas::VA_Top);
313 
314 	return canvas;
315 }
316 
317 void
set_subscr(Expression * subscr_)318 Symbol::set_subscr(Expression *subscr_)
319 {
320 	assert(subscr == NULL);
321 
322 	subscr = subscr_;
323 }
324 
325 bool
has_subscr() const326 Symbol::has_subscr() const
327 {
328 	return subscr != NULL;
329 }
330 
331 void
set_expn(Expression * expn_)332 Symbol::set_expn(Expression *expn_)
333 {
334 	assert(expn == NULL);
335 
336 	expn = expn_;
337 }
338 
339 bool
has_expn() const340 Symbol::has_expn() const
341 {
342 	return expn != NULL;
343 }
344 
345 void
add_tick()346 Symbol::add_tick()
347 {
348 	++num_ticks;
349 }
350 
351 void
set_conj(bool is_conj_)352 Symbol::set_conj(bool is_conj_)
353 {
354 	is_conj = is_conj_;
355 }
356 
357 
358 void
switch_conj()359 Symbol::switch_conj()
360 {
361 	is_conj = !is_conj;
362 }
363 
364 bool
get_conj() const365 Symbol::get_conj() const
366 {
367 	return is_conj;
368 }
369 
370 void
set_bar()371 Symbol::set_bar()
372 {
373 	has_bar = true;
374 }
375 
376 bool
get_bar() const377 Symbol::get_bar() const
378 {
379 	return has_bar;
380 }
381 
382 //
383 //	U n a r y O p
384 //
385 
UnaryOp(UnaryOpType type_,Expression * down_)386 UnaryOp::UnaryOp(UnaryOpType type_, Expression *down_)
387 : Expression(ET_UnaryOp)
388 , unop_type(type_)
389 , down(down_)
390 { }
391 
~UnaryOp()392 UnaryOp::~UnaryOp()
393 {
394 	delete down;
395 }
396 
397 UnaryOpType
get_unop_type() const398 UnaryOp::get_unop_type() const
399 {
400 	return unop_type;
401 }
402 
403 bool
is_constant() const404 UnaryOp::is_constant() const
405 {
406 	return down->is_constant();
407 }
408 
409 bool
accept_expn() const410 UnaryOp::accept_expn() const
411 {
412 	return false;
413 }
414 
415 void
set_expn(Expression * expn_)416 UnaryOp::set_expn(Expression *expn_)
417 {
418 	assert(0);
419 }
420 
Neg(Expression * down_)421 Neg::Neg(Expression *down_)
422 : UnaryOp(UT_Neg, down_)
423 { }
424 
~Neg()425 Neg::~Neg()
426 { }
427 
428 CanvasPtr
render() const429 Neg::render() const
430 {
431 	CanvasPtr canvas_down = down->render();
432 
433 	CanvasPtr canvas;
434 
435 	(*canvas)[0][0] = '-';
436 
437 	canvas->paste_with_parens(*canvas_down, 0,
438 	  down->get_expr_type() == ET_Constant ||
439 	  down->get_expr_type() == ET_Symbol ? 1 : 2,
440 	  down->need_parens());
441 
442 	return canvas;
443 }
444 
445 bool
need_parens() const446 Neg::need_parens() const
447 {
448 	return true;
449 }
450 
Sqrt(Expression * down_)451 Sqrt::Sqrt(Expression *down_)
452 : UnaryOp(UT_Sqrt, down_)
453 { }
454 
~Sqrt()455 Sqrt::~Sqrt()
456 { }
457 
458 CanvasPtr
render() const459 Sqrt::render() const
460 {
461 	CanvasPtr canvas_down = down->render();
462 
463 	Size size_down = canvas_down->size();
464 
465 	CanvasPtr canvas;
466 
467 	(*canvas)[size_down.descent][0] = '\\';
468 
469 	int c;
470 
471 	if (big_radicals) {
472 		c = size_down.rows + 1;
473 
474 		for (int i = 0; i < size_down.rows; i++)
475 			(*canvas)[size_down.descent - i][1 + i] = '/';
476 	} else {
477 		c = 2;
478 
479 		for (int i = 0; i < size_down.rows; i++)
480 			(*canvas)[-size_down.ascent + i][1] = '|';
481 	}
482 
483 	canvas->paste(*canvas_down, 0, c);
484 
485 	for (int i = 0; i < size_down.cols; i++)
486 		(*canvas)[-size_down.ascent - 1][c + i] = '_';
487 
488 	return canvas;
489 }
490 
491 bool
need_parens() const492 Sqrt::need_parens() const
493 {
494 	return false;
495 }
496 
Fact(Expression * down_)497 Fact::Fact(Expression *down_)
498 : UnaryOp(UT_Fact, down_)
499 { }
500 
~Fact()501 Fact::~Fact()
502 { }
503 
504 CanvasPtr
render() const505 Fact::render() const
506 {
507 	CanvasPtr canvas_down = down->render();
508 
509 	Size size_down = canvas_down->size();
510 
511 	bool parens = down->get_expr_type() != ET_Constant &&
512 	  down->get_expr_type() != ET_Symbol;
513 
514 	CanvasPtr canvas;
515 
516 	canvas->paste_with_parens(*canvas_down, 0, 0, parens);
517 
518 	(*canvas)[0][size_down.cols + (parens ? 2 : 0)] = '!';
519 
520 	return canvas;
521 }
522 
523 
524 bool
need_parens() const525 Fact::need_parens() const
526 {
527 	return false;
528 }
529 
Conj(Expression * down_)530 Conj::Conj(Expression *down_)
531 : UnaryOp(UT_Conj, down_)
532 { }
533 
~Conj()534 Conj::~Conj()
535 { }
536 
537 CanvasPtr
render() const538 Conj::render() const
539 {
540 	CanvasPtr canvas_down = down->render();
541 
542 	Size size_down = canvas_down->size();
543 
544 	bool parens = (down->get_expr_type() != ET_Constant &&
545 	  down->get_expr_type() != ET_Symbol)
546 	  || (down->get_expr_type() == ET_Symbol &&
547 	  dynamic_cast<Symbol *>(down)->has_expn() == true);
548 
549 	CanvasPtr canvas;
550 
551 	canvas->paste_with_parens(*canvas_down, 0, 0, parens);
552 
553 	(*canvas)[-1][size_down.cols + (parens ? 2 : 0)] = '*';
554 
555 	return canvas;
556 }
557 
558 bool
need_parens() const559 Conj::need_parens() const
560 {
561 	return false;
562 }
563 
Bar(Expression * down_)564 Bar::Bar(Expression *down_)
565 : UnaryOp(UT_Bar, down_)
566 { }
567 
~Bar()568 Bar::~Bar()
569 { }
570 
571 CanvasPtr
render() const572 Bar::render() const
573 {
574 	CanvasPtr canvas_down = down->render();
575 
576 	Size size_down = canvas_down->size();
577 
578 	CanvasPtr canvas;
579 
580 	canvas->paste(*canvas_down, 0, 0);
581 
582 	for (int i = 0; i < size_down.cols; i++)
583 		(*canvas)[-size_down.ascent - 1][i] = '_';
584 
585 	return canvas;
586 }
587 
588 bool
need_parens() const589 Bar::need_parens() const
590 {
591 	return false;
592 }
593 
Abs(Expression * down_)594 Abs::Abs(Expression *down_)
595 : UnaryOp(UT_Abs, down_)
596 { }
597 
~Abs()598 Abs::~Abs()
599 { }
600 
601 CanvasPtr
render() const602 Abs::render() const
603 {
604 	CanvasPtr canvas_down = down->render();
605 
606 	Size size_down = canvas_down->size();
607 
608 	CanvasPtr canvas;
609 
610 	canvas->paste(*canvas_down, 0, 1);
611 
612 	for (int i = 0; i < size_down.rows; i++)
613 		(*canvas)[-size_down.ascent + i][0] =
614 		(*canvas)[-size_down.ascent + i][size_down.cols + 1] = '|';
615 
616 	return canvas;
617 }
618 
619 bool
need_parens() const620 Abs::need_parens() const
621 {
622 	return false;
623 }
624 
625 
626 //
627 //	B i n a r y O p
628 //
629 
BinaryOp(BinaryOpType type_,Expression * left_,Expression * right_)630 BinaryOp::BinaryOp(BinaryOpType type_, Expression *left_, Expression *right_)
631 : Expression(ET_BinaryOp)
632 , binop_type(type_)
633 , left(left_)
634 , right(right_)
635 { }
636 
~BinaryOp()637 BinaryOp::~BinaryOp()
638 {
639 	delete left;
640 	delete right;
641 }
642 
643 BinaryOpType
get_binop_type() const644 BinaryOp::get_binop_type() const
645 {
646 	return binop_type;
647 }
648 
649 bool
is_constant() const650 BinaryOp::is_constant() const
651 {
652 	return left->is_constant() && right->is_constant();
653 }
654 
655 bool
accept_expn() const656 BinaryOp::accept_expn() const
657 {
658 	return false;
659 }
660 
661 void
set_expn(Expression * expn_)662 BinaryOp::set_expn(Expression *expn_)
663 {
664 	assert(0);
665 }
666 
SimpleBinaryOp(BinaryOpType type_,Expression * left_,Expression * right_)667 SimpleBinaryOp::SimpleBinaryOp(BinaryOpType type_, Expression *left_, Expression *right_)
668 : BinaryOp(type_, left_, right_)
669 { }
670 
~SimpleBinaryOp()671 SimpleBinaryOp::~SimpleBinaryOp()
672 { }
673 
674 CanvasPtr
render() const675 SimpleBinaryOp::render() const
676 {
677 	CanvasPtr canvas_left = left->render();
678 
679 	Size size_left = canvas_left->size();
680 
681 	CanvasPtr canvas;
682 
683 	canvas->paste(*canvas_left, 0, 0);
684 
685 	(*canvas)[0][size_left.cols + 1] = symbol();
686 
687 	canvas->paste(*(right->render()), 0, size_left.cols + 3);
688 
689 	return canvas;
690 }
691 
692 bool
need_parens() const693 SimpleBinaryOp::need_parens() const
694 {
695 	return true;
696 }
697 
Add(Expression * left_,Expression * right_)698 Add::Add(Expression *left_, Expression *right_)
699 : SimpleBinaryOp(BT_Add, left_, right_)
700 { }
701 
~Add()702 Add::~Add()
703 { }
704 
705 char
symbol() const706 Add::symbol() const
707 {
708 	return '+';
709 }
710 
Sub(Expression * left_,Expression * right_)711 Sub::Sub(Expression *left_, Expression *right_)
712 : SimpleBinaryOp(BT_Sub, left_, right_)
713 { }
714 
~Sub()715 Sub::~Sub()
716 { }
717 
718 CanvasPtr
render() const719 Sub::render() const
720 {
721 	CanvasPtr canvas_left = left->render();
722 	Size size_left = canvas_left->size();
723 
724 	CanvasPtr canvas;
725 
726 	canvas->paste(*canvas_left, 0, 0);
727 
728 	(*canvas)[0][size_left.cols + 1] = '-';
729 
730 	canvas->paste_with_parens(*(right->render()), 0, size_left.cols + 3,
731 	  right->need_parens());
732 
733 	return canvas;
734 }
735 
736 char
symbol() const737 Sub::symbol() const
738 {
739 	return '-';
740 }
741 
Equal(Expression * left_,Expression * right_)742 Equal::Equal(Expression *left_, Expression *right_)
743 : SimpleBinaryOp(BT_Equal, left_, right_)
744 { }
745 
~Equal()746 Equal::~Equal()
747 { }
748 
749 char
symbol() const750 Equal::symbol() const
751 {
752 	return '=';
753 }
754 
Less(Expression * left_,Expression * right_)755 Less::Less(Expression *left_, Expression *right_)
756 : SimpleBinaryOp(BT_Less, left_, right_)
757 { }
758 
~Less()759 Less::~Less()
760 { }
761 
762 char
symbol() const763 Less::symbol() const
764 {
765 	return '<';
766 }
767 
Greater(Expression * left_,Expression * right_)768 Greater::Greater(Expression *left_, Expression *right_)
769 : SimpleBinaryOp(BT_Greater, left_, right_)
770 { }
771 
~Greater()772 Greater::~Greater()
773 { }
774 
775 char
symbol() const776 Greater::symbol() const
777 {
778 	return '>';
779 }
780 
GreaterOrEqual(Expression * left_,Expression * right_)781 GreaterOrEqual::GreaterOrEqual(Expression *left_, Expression *right_)
782 : BinaryOp(BT_GreaterOrEqual, left_, right_)
783 { }
784 
~GreaterOrEqual()785 GreaterOrEqual::~GreaterOrEqual()
786 { }
787 
788 CanvasPtr
render() const789 GreaterOrEqual::render() const
790 {
791 	CanvasPtr canvas_left = left->render();
792 	Size size_left = canvas_left->size();
793 
794 	CanvasPtr canvas;
795 
796 	canvas->paste(*canvas_left, 0, 0);
797 
798 	(*canvas)[0][size_left.cols + 1] = '>';
799 	(*canvas)[1][size_left.cols + 1] = '-';
800 
801 	canvas->paste_with_parens(*(right->render()), 0, size_left.cols + 3,
802 	  right->need_parens());
803 
804 	return canvas;
805 }
806 
807 bool
need_parens() const808 GreaterOrEqual::need_parens() const
809 {
810 	return false;
811 }
812 
LessOrEqual(Expression * left_,Expression * right_)813 LessOrEqual::LessOrEqual(Expression *left_, Expression *right_)
814 : BinaryOp(BT_LessOrEqual, left_, right_)
815 { }
816 
~LessOrEqual()817 LessOrEqual::~LessOrEqual()
818 { }
819 
820 CanvasPtr
render() const821 LessOrEqual::render() const
822 {
823 	CanvasPtr canvas_left = left->render();
824 	Size size_left = canvas_left->size();
825 
826 	CanvasPtr canvas;
827 
828 	canvas->paste(*canvas_left, 0, 0);
829 
830 	(*canvas)[0][size_left.cols + 1] = '<';
831 	(*canvas)[1][size_left.cols + 1] = '-';
832 
833 	canvas->paste_with_parens(*(right->render()), 0, size_left.cols + 3,
834 	  right->need_parens());
835 
836 	return canvas;
837 }
838 
839 bool
need_parens() const840 LessOrEqual::need_parens() const
841 {
842 	return false;
843 }
844 
Mul(Expression * left_,Expression * right_)845 Mul::Mul(Expression *left_, Expression *right_)
846 : BinaryOp(BT_Mul, left_, right_)
847 { }
848 
~Mul()849 Mul::~Mul()
850 { }
851 
852 CanvasPtr
render() const853 Mul::render() const
854 {
855 	CanvasPtr canvas_left = left->render();
856 	Size size_left = canvas_left->size();
857 
858 	CanvasPtr canvas;
859 
860 	canvas->paste_with_parens(*canvas_left, 0, 0, left->need_parens());
861 
862 	int c = size_left.cols + (left->need_parens() ? 3 : 1);
863 
864 	canvas->paste_with_parens(*(right->render()), 0, c,
865 	  right->need_parens());
866 
867 	return canvas;
868 }
869 
870 bool
need_parens() const871 Mul::need_parens() const
872 {
873 	return false;
874 }
875 
Div(Expression * left_,Expression * right_)876 Div::Div(Expression *left_, Expression *right_)
877 : BinaryOp(BT_Div, left_, right_)
878 { }
879 
~Div()880 Div::~Div()
881 { }
882 
883 CanvasPtr
render() const884 Div::render() const
885 {
886 	CanvasPtr canvas_left = left->render();
887 	Size size_left = canvas_left->size();
888 
889 	CanvasPtr canvas_right = right->render();
890 	Size size_right = canvas_right->size();
891 
892 	int cols = max(size_left.cols, size_right.cols);
893 
894 	CanvasPtr canvas;
895 
896 	canvas->paste(*canvas_left, -1, cols/2 - size_left.cols/2,
897 	  Canvas::VA_Top);
898 
899 	for (int i = 0; i < cols; i++)
900 		(*canvas)[0][i] = '-';
901 
902 	canvas->paste(*canvas_right, 1, cols/2 - size_right.cols/2,
903 	  Canvas::VA_Bottom);
904 
905 	return canvas;
906 }
907 
908 bool
need_parens() const909 Div::need_parens() const
910 {
911 	return false;
912 }
913 
Pow(Expression * left_,Expression * right_)914 Pow::Pow(Expression *left_, Expression *right_)
915 : BinaryOp(BT_Div, left_, right_)
916 { }
917 
~Pow()918 Pow::~Pow()
919 { }
920 
921 CanvasPtr
render() const922 Pow::render() const
923 {
924 	CanvasPtr canvas_left = left->render();
925 	Size size_left = canvas_left->size();
926 
927 	bool parens = (left->get_expr_type() != ET_Constant &&
928 	  left->get_expr_type() != ET_Symbol &&
929 	  left->get_expr_type() != ET_Function &&
930 	  left->get_expr_type() != ET_Matrix)
931 	  || (left->get_expr_type() == ET_Symbol &&
932 	  dynamic_cast<Symbol *>(left)->has_expn() == true);
933 
934 	CanvasPtr canvas;
935 
936 	canvas->paste_with_parens(*canvas_left, 0, 0, parens);
937 
938 	canvas->paste(*(right->render()), -size_left.ascent - 1,
939 	  size_left.cols + (parens ? 2 : 0), Canvas::VA_Top);
940 
941 	return canvas;
942 }
943 
944 bool
need_parens() const945 Pow::need_parens() const
946 {
947 	return false;
948 }
949 
Root(Expression * left_,Expression * right_)950 Root::Root(Expression *left_, Expression *right_)
951 : BinaryOp(BT_Div, left_, right_)
952 { }
953 
~Root()954 Root::~Root()
955 { }
956 
957 CanvasPtr
render() const958 Root::render() const
959 {
960 	CanvasPtr canvas_left = left->render();
961 	Size size_left = canvas_left->size();
962 
963 	CanvasPtr canvas_right = right->render();
964 	Size size_right = canvas_right->size();
965 
966 	int c = big_radicals ? size_left.rows : 1;
967 
968 	int d = size_right.cols - c - 1;
969 
970 	if (d < 0)
971 		d = 0;
972 
973 	CanvasPtr canvas;
974 
975 	canvas->paste(*canvas_left, 0, c + 1 + d);
976 
977 	canvas->paste(*canvas_right, -size_left.ascent - 1,
978 	  d + c - size_right.cols + 1, Canvas::VA_Top);
979 
980 	(*canvas)[size_left.descent][0] = '\\';
981 
982 	for (int i = 0; i < size_left.cols; i++)
983 		(*canvas)[-size_left.ascent - 1][c + 1 + i + d] = '_';
984 
985 	if (big_radicals) {
986 		for (int i = 0; i < size_left.rows; i++)
987 			(*canvas)[size_left.descent - i][1 + i + d] = '/';
988 	} else {
989 		for (int i = 0; i < size_left.rows; i++)
990 			(*canvas)[-size_left.ascent + i][1 + d] = '|';
991 	}
992 
993 	return canvas;
994 }
995 
996 bool
need_parens() const997 Root::need_parens() const
998 {
999 	return false;
1000 }
1001 
1002 
1003 
1004 //
1005 //	O p O n F u n c t i o n
1006 //
1007 
OpOnFunction(OpOnFunctionType type_,Expression * fn_,Expression * var_)1008 OpOnFunction::OpOnFunction(OpOnFunctionType type_, Expression *fn_,
1009   Expression *var_)
1010 : Expression(ET_OpOnFunction)
1011 , op_on_func_type(type_)
1012 , function(fn_)
1013 , var(var_)
1014 { }
1015 
~OpOnFunction()1016 OpOnFunction::~OpOnFunction()
1017 {
1018 	delete function;
1019 	delete var;
1020 }
1021 
1022 OpOnFunctionType
get_op_on_func_type() const1023 OpOnFunction::get_op_on_func_type() const
1024 {
1025 	return op_on_func_type;
1026 }
1027 
1028 bool
need_parens() const1029 OpOnFunction::need_parens() const
1030 {
1031 	return false;
1032 }
1033 
1034 bool
is_constant() const1035 OpOnFunction::is_constant() const
1036 {
1037 	return false;
1038 }
1039 
1040 bool
accept_expn() const1041 OpOnFunction::accept_expn() const
1042 {
1043 	return false;
1044 }
1045 
1046 void
set_expn(Expression * expn_)1047 OpOnFunction::set_expn(Expression *expn_)
1048 {
1049 	assert(0);
1050 }
1051 
OpOverInterval(Expression * from_,Expression * to_)1052 OpOverInterval::OpOverInterval(Expression *from_, Expression *to_)
1053 : from(from_)
1054 , to(to_)
1055 { }
1056 
~OpOverInterval()1057 OpOverInterval::~OpOverInterval()
1058 {
1059 	delete from;
1060 	delete to;
1061 }
1062 
1063 //	I n t e g r a l
1064 
Integral(Expression * fn_,Expression * var_)1065 Integral::Integral(Expression *fn_, Expression *var_)
1066 : OpOnFunction(FT_Integral, fn_, var_)
1067 { }
1068 
~Integral()1069 Integral::~Integral()
1070 { }
1071 
1072 int
get_rise() const1073 Integral::get_rise() const
1074 {
1075 	int rise;
1076 
1077 	// the idea behind this ugly hack is that we want the integration
1078 	// symbols of nested (multivariate) integrals to have the same
1079 	// height. we check if the function being integrated is another
1080 	// integral; if it is, recursively get its height (rise).
1081 	// otherwise calculate height according to argument height.
1082 
1083 	// this will probably result in some useless object creation/
1084 	// rendering/destruction overhead, but will do until we figure out
1085 	// a smarter way to do this.
1086 
1087 	Integral *integral = dynamic_cast<Integral *>(function);
1088 
1089 	if (integral != NULL) {
1090 	  	rise = integral->get_rise();
1091 	} else {
1092 		CanvasPtr temp = function->render();
1093 		Size size = temp->size();
1094 		rise = max(size.ascent, size.descent);
1095 
1096 		if (rise == 0)
1097 			rise = 1;
1098 	}
1099 
1100 	return rise;
1101 }
1102 
1103 void
render_symbol(Canvas & canvas,int r,int c,int h) const1104 Integral::render_symbol(Canvas& canvas, int r, int c, int h) const
1105 {
1106 	for (int i = 0; i < h; i++) {
1107 		canvas[r + i + 1][c + 1] = '|';
1108 		canvas[r - i - 1][c + 1] = '|';
1109 	}
1110 
1111 	canvas[r][c + 1] = '|';
1112 
1113 	canvas[r - h - 1][c + 2] = '/';
1114 	canvas[r + h + 1][c] = '/';
1115 }
1116 
1117 CanvasPtr
render_head() const1118 Integral::render_head() const
1119 {
1120 	CanvasPtr canvas;
1121 
1122 	render_symbol(*canvas, 0, 0, get_rise());
1123 
1124 	return canvas;
1125 }
1126 
1127 CanvasPtr
render() const1128 Integral::render() const
1129 {
1130 	CanvasPtr canvas_head = render_head();
1131 
1132 	Size size_head = canvas_head->size();
1133 
1134 	CanvasPtr canvas;
1135 
1136 	canvas->paste(*canvas_head, 0, 0);
1137 
1138 	CanvasPtr canvas_fn = function->render();
1139 
1140 	Size size_fn = canvas_fn->size();
1141 
1142 	int c;
1143 
1144 	if (dynamic_cast<Integral *>(function) != NULL)
1145 		c = size_head.cols + 1;
1146 	else
1147 		c = 3;
1148 
1149 	canvas->paste_with_parens(*canvas_fn, 0, c, function->need_parens());
1150 
1151 	c += 1 + size_fn.cols + (function->need_parens() ? 2 : 0);
1152 
1153 	(*canvas)[0][c] = 'd';
1154 
1155 	canvas->paste_with_parens(*(var->render()), 0, c + 1,
1156 	  var->need_parens());
1157 
1158 	return canvas;
1159 }
1160 
IntegralOnInterval(Expression * function_,Expression * var_,Expression * from_,Expression * to_)1161 IntegralOnInterval::IntegralOnInterval(Expression *function_, Expression *var_,
1162   Expression *from_, Expression *to_)
1163 : Integral(function_, var_)
1164 , OpOverInterval(from_, to_)
1165 { }
1166 
~IntegralOnInterval()1167 IntegralOnInterval::~IntegralOnInterval()
1168 { }
1169 
1170 CanvasPtr
render_head() const1171 IntegralOnInterval::render_head() const
1172 {
1173 	int rise = get_rise();
1174 
1175 	CanvasPtr canvas_from = from->render();
1176 
1177 	CanvasPtr canvas_to = to->render();
1178 
1179 	CanvasPtr canvas;
1180 
1181 	render_symbol(*canvas, 0, 0, rise);
1182 
1183 	canvas->paste(*canvas_from, rise + 2, 1, Canvas::VA_Bottom);
1184 	canvas->paste(*canvas_to, -rise - 2, 3,  Canvas::VA_Top);
1185 
1186 	return canvas;
1187 }
1188 
1189 class SumSymbol : public OpSymbol {
1190   public:
1191 	void render(Canvas& c, int r, int i) const;
1192 };
1193 
1194 void
render(Canvas & canvas,int r,int c) const1195 SumSymbol::render(Canvas& canvas, int r, int c) const
1196 {
1197 	canvas[r - 1][c] = '\\';
1198 	canvas[r][c + 1] = '>';
1199 	canvas[r + 1][c] = '/';
1200 
1201 	for (int i = 0; i < 5; i++)
1202 		canvas[r - 2][i + c] = canvas[r + 2][i + c] = '=';
1203 }
1204 
1205 class ProductSymbol : public OpSymbol {
1206   public:
1207 	void render(Canvas& c, int r, int i) const;
1208 };
1209 
1210 void
render(Canvas & canvas,int r,int c) const1211 ProductSymbol::render(Canvas& canvas, int r, int c) const
1212 {
1213 	for (int i = 0; i < 5; i++)
1214 		canvas[r - 2][i + c] = '=';
1215 
1216 	for (int i = -1; i <= 2; i++)
1217 		canvas[i][c + 1] = canvas[i][c + 3] = '|';
1218 }
1219 
SumOrProduct(Expression * fn_,Expression * var_)1220 SumOrProduct::SumOrProduct(Expression *fn_, Expression *var_)
1221 : OpOnFunction(FT_SumOrProduct, fn_, var_)
1222 { }
1223 
~SumOrProduct()1224 SumOrProduct::~SumOrProduct()
1225 { }
1226 
1227 CanvasPtr
render1(const OpSymbol & os) const1228 SumOrProduct::render1(const OpSymbol& os) const
1229 {
1230 	CanvasPtr canvas_sym = render_head(os);
1231 
1232 	CanvasPtr canvas;
1233 
1234 	canvas->paste(*canvas_sym, 0, 0);
1235 
1236 	Size sym_size = canvas_sym->size();
1237 
1238 	canvas->paste_with_parens(*(function->render()), 0, sym_size.cols + 1,
1239 	  function->need_parens());
1240 
1241 	return canvas;
1242 }
1243 
1244 CanvasPtr
render_head(const OpSymbol & os) const1245 SumOrProduct::render_head(const OpSymbol& os) const
1246 {
1247 	CanvasPtr canvas_var = var->render();
1248 	Size size_var = canvas_var->size();
1249 
1250 	int left = size_var.cols / 2 - 2;
1251 
1252 	if (left < 0)
1253 		left = 0;
1254 
1255 	CanvasPtr canvas;
1256 
1257 	os.render(*canvas, 0, left);
1258 
1259 	canvas->paste(*canvas_var, 3, left + 2 - size_var.cols / 2,
1260 	  Canvas::VA_Bottom);
1261 
1262 	return canvas;
1263 }
1264 
SumOrProductOverInterval(Expression * function_,Expression * var_,Expression * from_,Expression * to_)1265 SumOrProductOverInterval::SumOrProductOverInterval(Expression *function_,
1266   Expression *var_, Expression *from_, Expression *to_)
1267 : SumOrProduct(function_, var_)
1268 , OpOverInterval(from_, to_)
1269 { }
1270 
~SumOrProductOverInterval()1271 SumOrProductOverInterval::~SumOrProductOverInterval()
1272 { }
1273 
1274 CanvasPtr
render_head(const OpSymbol & os) const1275 SumOrProductOverInterval::render_head(const OpSymbol& os) const
1276 {
1277 	CanvasPtr canvas_var = var->render();
1278 	Size size_var = canvas_var->size();
1279 
1280 	CanvasPtr canvas_from = from->render();
1281 	Size size_from = canvas_from->size();
1282 
1283 	CanvasPtr canvas_to = to->render();
1284 	Size size_to = canvas_to->size();
1285 
1286 	int extra = max(size_to.cols, size_var.cols + 3 + size_from.cols);
1287 
1288 	int dist = extra / 2 - 2;
1289 
1290 	if (dist < 0)
1291 		dist = 0;
1292 
1293 	CanvasPtr canvas;
1294 
1295 	os.render(*canvas, 0, dist);
1296 
1297 	int c1 = dist + 2 - (size_var.cols + 3 + size_from.cols) / 2;
1298 
1299 	int h = max(size_var.ascent, size_from.ascent);
1300 
1301 	canvas->paste(*canvas_var, 3 + h, c1);
1302 
1303 	c1 += size_var.cols + 1;
1304 
1305 	(*canvas)[3 + h][c1] = '=';
1306 
1307 	c1 += 2;
1308 
1309 	canvas->paste(*canvas_from, 3 + h, c1);
1310 
1311 	canvas->paste(*canvas_to, -3, dist + 2 - size_to.cols / 2,
1312 	  Canvas::VA_Top);
1313 
1314 	return canvas;
1315 }
1316 
Sum(Expression * fn_,Expression * var_)1317 Sum::Sum(Expression *fn_, Expression *var_)
1318 : SumOrProduct(fn_, var_)
1319 { }
1320 
~Sum()1321 Sum::~Sum()
1322 { }
1323 
1324 CanvasPtr
render() const1325 Sum::render() const
1326 {
1327 	return render1(SumSymbol());
1328 }
1329 
SumOverInterval(Expression * fn_,Expression * var_,Expression * from_,Expression * to_)1330 SumOverInterval::SumOverInterval(Expression *fn_, Expression *var_,
1331   Expression *from_, Expression *to_)
1332 : SumOrProductOverInterval(fn_, var_, from_, to_)
1333 { }
1334 
~SumOverInterval()1335 SumOverInterval::~SumOverInterval()
1336 { }
1337 
1338 CanvasPtr
render() const1339 SumOverInterval::render() const
1340 {
1341 	return render1(SumSymbol());
1342 }
1343 
Product(Expression * fn_,Expression * var_)1344 Product::Product(Expression *fn_, Expression *var_)
1345 : SumOrProduct(fn_, var_)
1346 { }
1347 
~Product()1348 Product::~Product()
1349 { }
1350 
1351 CanvasPtr
render() const1352 Product::render() const
1353 {
1354 	return render1(ProductSymbol());
1355 }
1356 
ProductOverInterval(Expression * fn_,Expression * var_,Expression * from_,Expression * to_)1357 ProductOverInterval::ProductOverInterval(Expression *fn_, Expression *var_,
1358   Expression *from_, Expression *to_)
1359 : SumOrProductOverInterval(fn_, var_, from_, to_)
1360 { }
1361 
~ProductOverInterval()1362 ProductOverInterval::~ProductOverInterval()
1363 { }
1364 
1365 CanvasPtr
render() const1366 ProductOverInterval::render() const
1367 {
1368 	return render1(ProductSymbol());
1369 }
1370 
Limit(Expression * fn_,Expression * var_,Expression * limit_)1371 Limit::Limit(Expression *fn_, Expression *var_, Expression *limit_)
1372 : OpOnFunction(FT_Limit, fn_, var_)
1373 , limit(limit_)
1374 { }
1375 
~Limit()1376 Limit::~Limit()
1377 {
1378 	delete limit;
1379 }
1380 
1381 CanvasPtr
render() const1382 Limit::render() const
1383 {
1384 	CanvasPtr canvas_var = var->render();
1385 	Size size_var = canvas_var->size();
1386 
1387 	CanvasPtr canvas_limit = limit->render();
1388 	Size size_limit = canvas_limit->size();
1389 
1390 	int cols = size_var.cols + 4 + size_limit.cols;
1391 
1392 	CanvasPtr canvas;
1393 
1394 	canvas->paste_string("lim", 0, cols/2 - 2);
1395 
1396 	int r = 2 + max(size_var.ascent, size_limit.ascent);
1397 
1398 	canvas->paste(*canvas_var, r, 0);
1399 
1400 	canvas->paste_string("->", r, size_var.cols + 1);
1401 
1402 	canvas->paste(*canvas_limit, r, size_var.cols + 4);
1403 
1404 	canvas->paste_with_parens(*(function->render()), 0,
1405 	  size_var.cols + 5 + size_limit.cols, function->need_parens());
1406 
1407 	return canvas;
1408 }
1409 
1410 
1411 //
1412 //	F u n c t i o n
1413 //
1414 
FunctionArgs()1415 FunctionArgs::FunctionArgs()
1416 { }
1417 
~FunctionArgs()1418 FunctionArgs::~FunctionArgs()
1419 {
1420 	std::vector<Expression *>::iterator i;
1421 
1422 	for (i = args.begin(); i != args.end(); i++)
1423 		delete *i;
1424 }
1425 
1426 void
add_arg(Expression * expr)1427 FunctionArgs::add_arg(Expression *expr)
1428 {
1429 	args.push_back(expr);
1430 }
1431 
1432 CanvasPtr
render() const1433 FunctionArgs::render() const
1434 {
1435 	std::vector<Expression *>::const_iterator i;
1436 
1437 	int c = 0;
1438 
1439 	CanvasPtr canvas;
1440 
1441 	for (i = args.begin(); i != args.end(); i++) {
1442 		if (i != args.begin()) {
1443 			(*canvas)[0][c] = ',';
1444 			c += 2;
1445 		}
1446 
1447 		CanvasPtr canvas_arg = (*i)->render();
1448 
1449 		Size size_arg = canvas_arg->size();
1450 
1451 		canvas->paste(*canvas_arg, 0, c);
1452 
1453 		c += size_arg.cols;
1454 	}
1455 
1456 	return canvas;
1457 }
1458 
Function(Symbol * symbol_)1459 Function::Function(Symbol *symbol_)
1460 : Expression(ET_Function)
1461 , symbol(symbol_)
1462 { }
1463 
~Function()1464 Function::~Function()
1465 {
1466 	delete symbol;
1467 }
1468 
1469 bool
need_parens() const1470 Function::need_parens() const
1471 {
1472 	return false;
1473 }
1474 
1475 bool
is_constant() const1476 Function::is_constant() const
1477 {
1478 	return false;
1479 }
1480 
MultivarFunction(Symbol * symbol_,FunctionArgs * args_)1481 MultivarFunction::MultivarFunction(Symbol *symbol_, FunctionArgs *args_)
1482 : Function(symbol_)
1483 , args(args_)
1484 { }
1485 
~MultivarFunction()1486 MultivarFunction::~MultivarFunction()
1487 {
1488 	delete args;
1489 }
1490 
1491 CanvasPtr
render() const1492 MultivarFunction::render() const
1493 {
1494 	CanvasPtr canvas_sym = symbol->render();
1495 
1496 	Size size_sym = canvas_sym->size();
1497 
1498 	CanvasPtr canvas;
1499 
1500 	canvas->paste(*canvas_sym, 0, 0);
1501 
1502 	canvas->paste_with_parens(*(args->render()), 0, size_sym.cols, true);
1503 
1504 	return canvas;
1505 }
1506 
1507 bool
accept_expn() const1508 MultivarFunction::accept_expn() const
1509 {
1510 	return false;
1511 }
1512 
1513 void
set_expn(Expression * expn_)1514 MultivarFunction::set_expn(Expression *expn_)
1515 {
1516 	assert(0);
1517 }
1518 
TrigFunction(Symbol * symbol_,Expression * arg_)1519 TrigFunction::TrigFunction(Symbol *symbol_, Expression *arg_)
1520 : Function(symbol_)
1521 , arg(arg_)
1522 { }
1523 
~TrigFunction()1524 TrigFunction::~TrigFunction()
1525 {
1526 	delete arg;
1527 }
1528 
1529 CanvasPtr
render() const1530 TrigFunction::render() const
1531 {
1532 	CanvasPtr canvas_sym = symbol->render();
1533 
1534 	Size size_sym = canvas_sym->size();
1535 
1536 	CanvasPtr canvas;
1537 
1538 	canvas->paste(*canvas_sym, 0, 0);
1539 
1540 	int c = size_sym.cols + (symbol->has_expn() == false ? 1 : 0);
1541 
1542 	canvas->paste_with_parens(*(arg->render()), 0, c,
1543 	  arg->need_parens());
1544 
1545 	return canvas;
1546 }
1547 
1548 bool
accept_expn() const1549 TrigFunction::accept_expn() const
1550 {
1551 	return symbol->accept_expn();
1552 }
1553 
1554 void
set_expn(Expression * expr)1555 TrigFunction::set_expn(Expression *expr)
1556 {
1557 	symbol->set_expn(expr);
1558 }
1559 
1560 bool
has_expn() const1561 TrigFunction::has_expn() const
1562 {
1563 	return symbol->has_expn();
1564 }
1565 
1566 
1567 std::ostream&
operator <<(std::ostream & o,Expression & e)1568 operator<<(std::ostream& o, Expression& e)
1569 {
1570 		o << *(e.render());
1571 
1572 		return o;
1573 }
1574 
1575 
1576 //
1577 //	M a t r i x
1578 //
1579 
Matrix()1580 Matrix::Matrix()
1581 : Expression(ET_Matrix)
1582 , is_det(false)
1583 { }
1584 
~Matrix()1585 Matrix::~Matrix()
1586 {
1587 	std::vector<Row *>::iterator i;
1588 
1589 	for (i = rows.begin(); i != rows.end(); i++)
1590 		delete *i;
1591 }
1592 
1593 void
add_row(Matrix::Row * row)1594 Matrix::add_row(Matrix::Row* row)
1595 {
1596 	rows.push_back(row);
1597 }
1598 
1599 const Matrix::Row&
operator [](int i) const1600 Matrix::operator[](int i) const
1601 {
1602 	return *rows[i];
1603 }
1604 
1605 CanvasPtr
render() const1606 Matrix::render() const
1607 {
1608 	int cols = num_cols();
1609 	int rows = num_rows();
1610 
1611 	std::vector<CanvasPtr>ec(cols * rows);
1612 	Size sz[cols * rows];
1613 
1614 	int row_height[rows];
1615 	int col_width[cols];
1616 
1617 	memset(row_height, 0, sizeof row_height);
1618 	memset(col_width, 0, sizeof col_width);
1619 
1620 	int idx = 0;
1621 
1622 	for (int i = 0; i < rows; i++) {
1623 		for (int j = 0; j < cols; j++) {
1624 			ec[idx] = (*this)[i][j]->render();
1625 
1626 			sz[idx] = ec[idx]->size();
1627 
1628 			if (sz[idx].rows > row_height[i])
1629 				row_height[i] = sz[idx].rows;
1630 
1631 			if (sz[idx].cols > col_width[j])
1632 				col_width[j] = sz[idx].cols;
1633 
1634 			++idx;
1635 		}
1636 	}
1637 
1638 	idx = 0;
1639 
1640 	int r = 0;
1641 
1642 	CanvasPtr canvas;
1643 
1644 	for (int i = 0; i < rows; i++) {
1645 		int c = 2;
1646 
1647 		for (int j = 0; j < cols; j++) {
1648 			canvas->paste(*ec[idx],
1649 			  r + row_height[i]/2 - sz[idx].rows/2,
1650 			  c + col_width[j]/2 - sz[idx].cols/2,
1651 			  Canvas::VA_Bottom);
1652 
1653 			c += col_width[j] + 1;
1654 
1655 			++idx;
1656 		}
1657 
1658 		r += row_height[i] + 1;
1659 	}
1660 
1661 	int h = 0;
1662 
1663 	for (int i = 0; i < rows; i++)
1664 		h += row_height[i];
1665 
1666 	h += rows - 1;
1667 
1668 	int w = 0;
1669 
1670 	for (int i = 0; i < cols; i++)
1671 		w += col_width[i];
1672 
1673 	w += cols + 1;
1674 
1675 	if (!is_det) {
1676 		for (int i = 1; i < h - 1; i++)
1677 			(*canvas)[i][0] = (*canvas)[i][w + 1] = '|';
1678 
1679 		(*canvas)[0][0] = '/';
1680 		(*canvas)[0][w + 1] = '\\';
1681 
1682 		(*canvas)[h - 1][0] = '\\';
1683 		(*canvas)[h - 1][w + 1] = '/';
1684 	} else {
1685 		for (int i = 0; i < h; i++)
1686 			(*canvas)[i][0] = (*canvas)[i][w + 1] = '|';
1687 	}
1688 
1689 	canvas->center();
1690 
1691 	return canvas;
1692 }
1693 
1694 bool
need_parens() const1695 Matrix::need_parens() const
1696 {
1697 	return false;
1698 }
1699 
1700 bool
is_constant() const1701 Matrix::is_constant() const
1702 {
1703 	return false;
1704 }
1705 
1706 bool
accept_expn() const1707 Matrix::accept_expn() const
1708 {
1709 	return false;
1710 }
1711 
1712 void
set_expn(Expression * expn_)1713 Matrix::set_expn(Expression *expn_)
1714 {
1715 	assert(0);
1716 }
1717 
1718 int
num_rows() const1719 Matrix::num_rows() const
1720 {
1721 	return rows.size();
1722 }
1723 
1724 void
set_det()1725 Matrix::set_det()
1726 {
1727 	is_det = true;
1728 }
1729 
1730 int
num_cols() const1731 Matrix::num_cols() const
1732 {
1733 	int num_cols = 0;
1734 
1735 	std::vector<Row *>::const_iterator i;
1736 
1737 	for (i = rows.begin(); i != rows.end(); i++) {
1738 		if ((*i)->num_cols() > num_cols)
1739 			num_cols = (*i)->num_cols();
1740 	}
1741 
1742 	return num_cols;
1743 }
1744 
Row()1745 Matrix::Row::Row()
1746 { }
1747 
~Row()1748 Matrix::Row::~Row()
1749 {
1750 	ExprVector::iterator i;
1751 
1752 	for (i = elems.begin(); i != elems.end(); i++)
1753 		delete *i;
1754 }
1755 
1756 void
add_elem(Expression * expr)1757 Matrix::Row::add_elem(Expression *expr)
1758 {
1759 	elems.push_back(expr);
1760 }
1761 
1762 int
num_cols() const1763 Matrix::Row::num_cols() const
1764 {
1765 	return elems.size();
1766 }
1767 
1768 const Expression *
operator [](int i) const1769 Matrix::Row::operator[](int i) const
1770 {
1771 	if (i >= (int)elems.size())
1772 		return &ZERO;
1773 	else
1774 		return elems[i];
1775 }
1776