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