one more change to the multipage question
[PyX/mjg.git] / pyx / mathtree.py
blob28d687cd9c9da499e5b92a813cd6c7e2befeb935
1 #!/usr/bin/env python
2 # -*- coding: ISO-8859-1 -*-
5 # Copyright (C) 2002-2004 Jörg Lehmann <joergl@users.sourceforge.net>
6 # Copyright (C) 2003-2004 Michael Schindler <m-schindler@users.sourceforge.net>
7 # Copyright (C) 2002-2004 André Wobst <wobsta@users.sourceforge.net>
9 # This file is part of PyX (http://pyx.sourceforge.net/).
11 # PyX is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
16 # PyX is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with PyX; if not, write to the Free Software
23 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26 import string, re, math, symbol, token
27 import parser as pythonparser
30 class ArgCountError(Exception): pass
31 class DerivativeError(Exception): pass
33 class MathTree:
35 def __init__(self, ArgCount, *Args):
36 self.ArgCount = ArgCount
37 self.Args = []
38 for arg in Args:
39 self.AddArg(arg)
41 def __repr__(self, depth = 0):
42 indent = ""
43 SingleIndent = " "
44 for i in range(depth):
45 indent = indent + SingleIndent
46 result = indent + self.__class__.__name__ + "(\n"
47 for SubTree in self.Args:
48 if isinstance(SubTree, MathTree):
49 result = result + SubTree.__repr__(depth + 1)
50 else:
51 result = result + indent + SingleIndent + repr(SubTree)
53 if SubTree != self.Args[-1]:
54 result = result + ",\n"
55 else:
56 result = result + ")"
57 return result
59 def AddArg(self, Arg, Last=0, NotLast=0):
60 if len(self.Args) == self.ArgCount:
61 raise ArgCountError
62 self.Args.append(Arg)
63 if NotLast and len(self.Args) == self.ArgCount:
64 raise ArgCountError
65 if Last and len(self.Args) != self.ArgCount:
66 raise ArgCountError
68 def DependOn(self, arg):
69 for Arg in self.Args:
70 if Arg.DependOn(arg):
71 return 1
72 return 0
74 def Derivative(self, arg):
75 if not self.DependOn(arg):
76 return MathTreeValConst(0.0)
77 return self.CalcDerivative(arg)
79 def VarList(self):
80 list = [ ]
81 for Arg in self.Args:
82 newlist = Arg.VarList()
83 for x in newlist:
84 if x not in list:
85 list.append(x)
86 return list
89 class MathTreeVal(MathTree):
91 def __init__(self, *args):
92 MathTree.__init__(self, 1, *args)
94 def __str__(self):
95 return str(self.Args[0])
98 ConstPattern = re.compile(r"-?\d*((\d\.?)|(\.?\d))\d*(E[+-]?\d+)?",
99 re.IGNORECASE)
101 class MathTreeValConst(MathTreeVal):
103 def InitByParser(self, arg):
104 Match = arg.MatchPattern(ConstPattern)
105 if Match:
106 self.AddArg(string.atof(Match))
107 return 1
109 def CalcDerivative(self, arg):
110 raise DerivativeError("expression doesn't depend on \"%s\"" % arg)
112 def Derivative(self, arg):
113 return MathTreeValConst(0.0)
115 def DependOn(self, arg):
116 return 0
118 def VarList(self):
119 return [ ]
121 def Calc(HIDDEN_self, **args):
122 return HIDDEN_self.Args[0]
125 VarPattern = re.compile(r"[a-z_][a-z0-9_]*", re.IGNORECASE)
126 MathConst = {"pi": math.pi, "e": math.e}
128 class MathTreeValVar(MathTreeVal):
130 def InitByParser(self, arg):
131 Match = arg.MatchPattern(VarPattern)
132 if Match:
133 self.AddArg(Match)
134 return 1
136 def CalcDerivative(self, arg):
137 if arg != self.Args[0]:
138 raise DerivativeError("expression doesn't depend on \"%s\"" % arg)
139 return MathTreeValConst(1.0)
141 def DependOn(self, arg):
142 if arg == self.Args[0]:
143 return 1
144 return 0
146 def VarList(self):
147 if self.Args[0] in MathConst.keys():
148 return []
149 return [self.Args[0]]
151 def Calc(HIDDEN_self, **args):
152 if HIDDEN_self.Args[0] in args.keys():
153 return float(args[HIDDEN_self.Args[0]])
154 return MathConst[HIDDEN_self.Args[0]]
157 class MathTreeFunc(MathTree):
159 def __init__(self, name, ArgCount, *args):
160 self.name = name
161 MathTree.__init__(self, ArgCount, *args)
163 def InitByParser(self, arg):
164 return arg.MatchStrParenthesis(self.name)
166 def __str__(self):
167 args = ""
168 for SubTree in self.Args:
169 args = args + str(SubTree)
170 if SubTree != self.Args[-1]:
171 args = args + ","
172 return self.name + "(" + args + ")"
175 class MathTreeFunc1(MathTreeFunc):
177 def __init__(self, name, *args):
178 MathTreeFunc.__init__(self, name, 1, *args)
181 class MathTreeFunc1Neg(MathTreeFunc1):
183 def __init__(self, *args):
184 MathTreeFunc1.__init__(self, "neg", *args)
186 def CalcDerivative(self, arg):
187 return MathTreeFunc1Neg(self.Args[0].CalcDerivative(arg))
189 def Calc(HIDDEN_self, **args):
190 return -HIDDEN_self.Args[0].Calc(**args)
193 class MathTreeFunc1Abs(MathTreeFunc1):
195 def __init__(self, *args):
196 MathTreeFunc1.__init__(self, "abs", *args)
198 def CalcDerivative(self, arg):
199 return MathTreeOpMul(
200 MathTreeFunc1Sgn(self.Args[0]),
201 self.Args[0].CalcDerivative(arg))
203 def Calc(HIDDEN_self, **args):
204 return abs(HIDDEN_self.Args[0].Calc(**args))
207 class MathTreeFunc1Sgn(MathTreeFunc1):
209 def __init__(self, *args):
210 MathTreeFunc1.__init__(self, "sgn", *args)
212 def CalcDerivative(self, arg):
213 return MathTreeValConst(0.0)
215 def Calc(HIDDEN_self, **args):
216 if HIDDEN_self.Args[0].Calc(**args) < 0:
217 return -1.0
218 return 1.0
221 class MathTreeFunc1Sqrt(MathTreeFunc1):
223 def __init__(self, *args):
224 MathTreeFunc1.__init__(self, "sqrt", *args)
226 def CalcDerivative(self, arg):
227 return MathTreeOpMul(
228 MathTreeOpDiv(
229 MathTreeValConst(0.5),
230 self),
231 self.Args[0].CalcDerivative(arg))
233 def Calc(HIDDEN_self, **args):
234 return math.sqrt(HIDDEN_self.Args[0].Calc(**args))
237 class MathTreeFunc1Exp(MathTreeFunc1):
239 def __init__(self, *args):
240 MathTreeFunc1.__init__(self, "exp", *args)
242 def CalcDerivative(self, arg):
243 return MathTreeOpMul(self, self.Args[0].CalcDerivative(arg))
245 def Calc(HIDDEN_self, **args):
246 return math.exp(HIDDEN_self.Args[0].Calc(**args))
249 class MathTreeFunc1Log(MathTreeFunc1):
251 def __init__(self, *args):
252 MathTreeFunc1.__init__(self, "log", *args)
254 def CalcDerivative(self, arg):
255 return MathTreeOpDiv(self.Args[0].CalcDerivative(arg), self.Args[0])
257 def Calc(HIDDEN_self, **args):
258 return math.log(HIDDEN_self.Args[0].Calc(**args))
261 class MathTreeFunc1Sin(MathTreeFunc1):
263 def __init__(self, *args):
264 MathTreeFunc1.__init__(self, "sin", *args)
266 def CalcDerivative(self, arg):
267 return MathTreeOpMul(
268 MathTreeFunc1Cos(self.Args[0]),
269 self.Args[0].CalcDerivative(arg))
271 def Calc(HIDDEN_self, **args):
272 return math.sin(HIDDEN_self.Args[0].Calc(**args))
275 class MathTreeFunc1Cos(MathTreeFunc1):
277 def __init__(self, *args):
278 MathTreeFunc1.__init__(self, "cos", *args)
280 def CalcDerivative(self, arg):
281 return MathTreeOpMul(
282 MathTreeFunc1Neg(MathTreeFunc1Sin(self.Args[0])),
283 self.Args[0].CalcDerivative(arg))
285 def Calc(HIDDEN_self, **args):
286 return math.cos(HIDDEN_self.Args[0].Calc(**args))
289 class MathTreeFunc1Tan(MathTreeFunc1):
291 def __init__(self, *args):
292 MathTreeFunc1.__init__(self, "tan", *args)
294 def CalcDerivative(self, arg):
295 return MathTreeOpDiv(
296 self.Args[0].CalcDerivative(arg),
297 MathTreeOpPow(
298 MathTreeFunc1Cos(self.Args[0]),
299 MathTreeValConst(2.0)))
301 def Calc(HIDDEN_self, **args):
302 return math.tan(HIDDEN_self.Args[0].Calc(**args))
305 class MathTreeFunc1ASin(MathTreeFunc1):
307 def __init__(self, *args):
308 MathTreeFunc1.__init__(self, "asin", *args)
310 def CalcDerivative(self, arg):
311 return MathTreeOpDiv(
312 self.Args[0].CalcDerivative(arg),
313 MathTreeFunc1Sqrt(
314 MathTreeOpSub(
315 MathTreeValConst(1.0),
316 MathTreeOpPow(
317 self.Args[0],
318 MathTreeValConst(2.0)))))
320 def Calc(HIDDEN_self, **args):
321 return math.asin(HIDDEN_self.Args[0].Calc(**args))
324 class MathTreeFunc1ACos(MathTreeFunc1):
326 def __init__(self, *args):
327 MathTreeFunc1.__init__(self, "acos", *args)
329 def CalcDerivate(self, arg):
330 return MathTreeOpDiv(
331 MathTreeFunc1Neg(self.Args[0].CalcDerivative(arg)),
332 MathTreeFunc1Sqrt(
333 MathTreeOpSub(
334 MathTreeValConst(1.0),
335 MathTreeOpPow(
336 self.Args[0],
337 MathTreeValConst(2.0)))))
339 def Calc(HIDDEN_self, **args):
340 return math.acos(HIDDEN_self.Args[0].Calc(**args))
343 class MathTreeFunc1ATan(MathTreeFunc1):
345 def __init__(self, *args):
346 MathTreeFunc1.__init__(self, "atan", *args)
348 def CalcDerivate(self, arg):
349 return MathTreeOpDiv(
350 self.Args[0].CalcDerivative(arg),
351 MathTreeOpAdd(
352 MathTreeValConst(1.0),
353 MathTreeOpPow(
354 self.Args[0],
355 MathTreeValConst(2.0))))
357 def Calc(HIDDEN_self, **args):
358 return math.atan(HIDDEN_self.Args[0].Calc(**args))
361 class MathTreeFunc1SinD(MathTreeFunc1):
363 def __init__(self, *args):
364 MathTreeFunc1.__init__(self, "sind", *args)
366 def CalcDerivative(self, arg):
367 return MathTreeOpMul(
368 MathTreeFunc1CosD(self.Args[0]),
369 MathTreeOpMul(
370 MathTreeValConst(math.pi/180.0),
371 self.Args[0].CalcDerivative(arg)))
373 def Calc(HIDDEN_self, **args):
374 return math.sin(math.pi/180.0*HIDDEN_self.Args[0].Calc(**args))
377 class MathTreeFunc1CosD(MathTreeFunc1):
379 def __init__(self, *args):
380 MathTreeFunc1.__init__(self, "cosd", *args)
382 def CalcDerivative(self, arg):
383 return MathTreeOpMul(
384 MathTreeFunc1Neg(MathTreeFunc1Sin(self.Args[0])),
385 MathTreeOpMul(
386 MathTreeValConst(math.pi/180.0),
387 self.Args[0].CalcDerivative(arg)))
389 def Calc(HIDDEN_self, **args):
390 return math.cos(math.pi/180.0*HIDDEN_self.Args[0].Calc(**args))
393 class MathTreeFunc1TanD(MathTreeFunc1):
395 def __init__(self, *args):
396 MathTreeFunc1.__init__(self, "tand", *args)
398 def CalcDerivative(self, arg):
399 return MathTreeOpDiv(
400 MathTreeOpMul(
401 MathTreeValConst(math.pi/180.0),
402 self.Args[0].CalcDerivative(arg)),
403 MathTreeOpPow(
404 MathTreeFunc1Cos(self.Args[0]),
405 MathTreeValConst(2.0)))
407 def Calc(HIDDEN_self, **args):
408 return math.tan(math.pi/180.0*HIDDEN_self.Args[0].Calc(**args))
411 class MathTreeFunc1ASinD(MathTreeFunc1):
413 def __init__(self, *args):
414 MathTreeFunc1.__init__(self, "asind", *args)
416 def CalcDerivative(self, arg):
417 return MathTreeOpDiv(
418 MathTreeOpMul(
419 MathTreeValConst(180.0/math.pi),
420 self.Args[0].CalcDerivative(arg)),
421 MathTreeFunc1Sqrt(
422 MathTreeOpSub(
423 MathTreeValConst(1.0),
424 MathTreeOpPow(
425 self.Args[0],
426 MathTreeValConst(2.0)))))
428 def Calc(HIDDEN_self, **args):
429 return 180.0/math.pi*math.asin(HIDDEN_self.Args[0].Calc(**args))
432 class MathTreeFunc1ACosD(MathTreeFunc1):
434 def __init__(self, *args):
435 MathTreeFunc1.__init__(self, "acosd", *args)
437 def CalcDerivate(self, arg):
438 return MathTreeOpDiv(
439 MathTreeFunc1Neg(
440 MathTreeOpMul(
441 MathTreeValConst(180.0/math.pi),
442 self.Args[0].CalcDerivative(arg))),
443 MathTreeFunc1Sqrt(
444 MathTreeOpSub(
445 MathTreeValConst(1.0),
446 MathTreeOpPow(
447 self.Args[0],
448 MathTreeValConst(2.0)))))
450 def Calc(HIDDEN_self, **args):
451 return 180.0/math.pi*math.acos(HIDDEN_self.Args[0].Calc(**args))
454 class MathTreeFunc1ATanD(MathTreeFunc1):
456 def __init__(self, *args):
457 MathTreeFunc1.__init__(self, "atand", *args)
459 def CalcDerivate(self, arg):
460 return MathTreeOpDiv(
461 MathTreeOpMul(
462 MathTreeValConst(180.0/math.pi),
463 self.Args[0].CalcDerivative(arg)),
464 MathTreeOpAdd(
465 MathTreeValConst(1.0),
466 MathTreeOpPow(
467 self.Args[0],
468 MathTreeValConst(2.0))))
470 def Calc(HIDDEN_self, **args):
471 return 180.0/math.pi*math.atan(HIDDEN_self.Args[0].Calc(**args))
474 class MathTreeFunc2(MathTreeFunc):
476 def __init__(self, name, *args):
477 MathTreeFunc.__init__(self, name, 2, *args)
480 class MathTreeFunc2Norm(MathTreeFunc2):
482 def __init__(self, *args):
483 MathTreeFunc2.__init__(self, "norm", *args)
485 def CalcDerivative(self, arg):
486 if self.Args[0].DependOn(arg):
487 if self.Args[1].DependOn(arg):
488 return MathTreeOpDiv(
489 MathTreeOpAdd(
490 MathTreeOpMul(
491 self.Args[0],
492 self.Args[0].CalcDerivative(arg)),
493 MathTreeOpMul(
494 self.Args[1],
495 self.Args[1].CalcDerivative(arg))),
496 self)
497 else:
498 return MathTreeOpDiv(
499 MathTreeOpMul(
500 self.Args[0],
501 self.Args[0].CalcDerivative(arg)),
502 self)
503 else:
504 if self.Args[1].DependOn(arg):
505 return MathTreeOpDiv(
506 MathTreeOpMul(
507 self.Args[1],
508 self.Args[1].CalcDerivative(arg)),
509 self)
511 def Calc(HIDDEN_self, **args):
512 return math.sqrt(HIDDEN_self.Args[0].Calc(**args) ** 2 +
513 HIDDEN_self.Args[1].Calc(**args) ** 2)
516 class MathTreeFuncSplitAtValue(MathTreeFunc):
518 def __init__(self, *args):
519 MathTreeFunc.__init__(self, "splitatvalue", -1, *args)
521 def CalcDerivative(self, arg):
522 return self.Args[0].CalcDerivative(arg)
524 def Calc(HIDDEN_self, **args):
525 result = HIDDEN_self.Args[0].Calc(**args)
526 splits = [split.Calc(**args) for split in HIDDEN_self.Args[1:]]
527 section = 0
528 while section < len(splits) and splits[section] < result:
529 section += 1
530 if len(splits) > 1:
531 if section % 2:
532 section = None
533 else:
534 section >>= 1
535 return (section, result)
538 FuncExternPattern = re.compile(r"([a-z_][a-z0-9_]*)\s*\(", re.IGNORECASE)
540 class MathTreeFuncExtern(MathTreeFunc):
542 def __init__(self, *args):
543 MathTreeFunc.__init__(self, None, -1, *args)
545 def InitByParser(self, arg):
546 Match = arg.MatchPattern(FuncExternPattern)
547 if Match:
548 self.name = Match[:-1].strip()
549 return self.name
551 def SetName(self, arg):
552 self.name = arg.strip()
553 return self
555 def Calc(HIDDEN_self, **args):
556 return args[HIDDEN_self.name](*[arg.Calc(**args) for arg in HIDDEN_self.Args])
559 class MathTreeOp(MathTree):
561 def __init__(self, level, symbol, *args):
562 self.ParenthesisBarrier = 0
563 self.level = level
564 self.symbol = symbol
565 MathTree.__init__(self, 2, *args)
567 def __str__(self):
568 result = ""
569 if isinstance(self.Args[0], MathTreeOp) and\
570 self.level > self.Args[0].level:
571 result = result + "(" + str(self.Args[0]) + ")"
572 else:
573 result = result + str(self.Args[0])
574 result = result + self.symbol
575 if isinstance(self.Args[1], MathTreeOp) and\
576 self.level >= self.Args[1].level:
577 result = result + "(" + str(self.Args[1]) + ")"
578 else:
579 result = result + str(self.Args[1])
580 return result
582 def InitByParser(self, arg):
583 return arg.MatchStr(self.symbol)
586 class MathTreeOpAdd(MathTreeOp):
588 def __init__(self, *args):
589 MathTreeOp.__init__(self, 1, "+", *args)
591 def CalcDerivative(self, arg):
592 if self.Args[0].DependOn(arg):
593 if self.Args[1].DependOn(arg):
594 return MathTreeOpAdd(
595 self.Args[0].CalcDerivative(arg),
596 self.Args[1].CalcDerivative(arg))
597 else:
598 return self.Args[0].CalcDerivative(arg)
599 else:
600 if self.Args[1].DependOn(arg):
601 return self.Args[1].CalcDerivative(arg)
603 def Calc(HIDDEN_self, **args):
604 return HIDDEN_self.Args[0].Calc(**args) + HIDDEN_self.Args[1].Calc(**args)
607 class MathTreeOpSub(MathTreeOp):
609 def __init__(self, *args):
610 MathTreeOp.__init__(self, 1, "-", *args)
612 def CalcDerivative(self, arg):
613 if self.Args[0].DependOn(arg):
614 if self.Args[1].DependOn(arg):
615 return MathTreeOpSub(
616 self.Args[0].CalcDerivative(arg),
617 self.Args[1].CalcDerivative(arg))
618 else:
619 return self.Args[0].CalcDerivative(arg)
620 else:
621 if self.Args[1].DependOn(arg):
622 return MathTreeFunc1Neg(self.Args[1].CalcDerivative(arg))
624 def Calc(HIDDEN_self, **args):
625 return HIDDEN_self.Args[0].Calc(**args) - HIDDEN_self.Args[1].Calc(**args)
628 class MathTreeOpMul(MathTreeOp):
630 def __init__(self, *args):
631 MathTreeOp.__init__(self, 2, "*", *args)
633 def CalcDerivative(self, arg):
634 if self.Args[0].DependOn(arg):
635 if self.Args[1].DependOn(arg):
636 return MathTreeOpAdd(
637 MathTreeOpMul(
638 self.Args[0],
639 self.Args[1].CalcDerivative(arg)),
640 MathTreeOpMul(
641 self.Args[0].CalcDerivative(arg),
642 self.Args[1]))
643 else:
644 return MathTreeOpMul(
645 self.Args[0].CalcDerivative(arg),
646 self.Args[1])
647 else:
648 if self.Args[1].DependOn(arg):
649 return MathTreeOpMul(
650 self.Args[0],
651 self.Args[1].CalcDerivative(arg))
653 def Calc(HIDDEN_self, **args):
654 return HIDDEN_self.Args[0].Calc(**args) * HIDDEN_self.Args[1].Calc(**args)
657 class MathTreeOpDiv(MathTreeOp):
659 def __init__(self, *args):
660 MathTreeOp.__init__(self, 2, "/", *args)
662 def CalcDerivative(self, arg):
663 if self.Args[0].DependOn(arg):
664 if self.Args[1].DependOn(arg):
665 return MathTreeOpMul(
666 MathTreeOpSub(
667 MathTreeOpMul(
668 self.Args[0].CalcDerivative(arg),
669 self.Args[1]),
670 MathTreeOpMul(
671 self.Args[0],
672 self.Args[1].CalcDerivative(arg))),
673 MathTreeOpPow(
674 self.Args[1],
675 MathTreeValConst(-2.0)))
676 else:
677 return MathTreeOpDiv(
678 self.Args[0].CalcDerivative(arg),
679 self.Args[1])
680 else:
681 if self.Args[1].DependOn(arg):
682 return MathTreeOpMul(
683 MathTreeOpMul(
684 MathTreeFunc1Neg(self.Args[0]),
685 MathTreeOpPow(
686 self.Args[1],
687 MathTreeValConst(-2.0))),
688 self.Args[1].CalcDerivative(arg))
690 def Calc(HIDDEN_self, **args):
691 return HIDDEN_self.Args[0].Calc(**args) / HIDDEN_self.Args[1].Calc(**args)
694 class MathTreeOpPow(MathTreeOp):
696 def __init__(self, *args):
697 MathTreeOp.__init__(self, 3, "^", *args)
699 def InitByParser(self, arg):
700 pos = arg.MatchStr("^")
701 if pos:
702 return 1
703 else:
704 return arg.MatchStr("**")
706 def CalcDerivative(self, arg):
707 if self.Args[0].DependOn(arg):
708 if self.Args[1].DependOn(arg):
709 return MathTreeOpMul(
710 MathTreeOpPow(
711 self.Args[0],
712 self.Args[1]),
713 MathTreeOpAdd(
714 MathTreeOpMul(
715 MathTreeFunc1Log(self.Args[0]),
716 self.Args[1].CalcDerivative(arg)),
717 MathTreeOpMul(
718 self.Args[1],
719 MathTreeOpDiv(
720 self.Args[0].CalcDerivative(arg),
721 self.Args[0]))))
722 else:
723 return MathTreeOpMul(
724 self.Args[1],
725 MathTreeOpMul(
726 MathTreeOpPow(
727 self.Args[0],
728 MathTreeOpSub(
729 self.Args[1],
730 MathTreeValConst(1.0))),
731 self.Args[0].CalcDerivative(arg)))
732 else:
733 if self.Args[1].DependOn(arg):
734 return MathTreeOpMul(
735 MathTreeOpMul(
736 MathTreeOpPow(
737 self.Args[0],
738 self.Args[1]),
739 MathTreeFunc1Log(self.Args[0])),
740 self.Args[1].CalcDerivative(arg))
742 def Calc(HIDDEN_self, **args):
743 return HIDDEN_self.Args[0].Calc(**args) ** HIDDEN_self.Args[1].Calc(**args)
747 DefaultMathTreeFuncs = [MathTreeFunc1Neg, MathTreeFunc1Abs, MathTreeFunc1Sgn, MathTreeFunc1Sqrt,
748 MathTreeFunc1Exp, MathTreeFunc1Log,
749 MathTreeFunc1Sin, MathTreeFunc1Cos, MathTreeFunc1Tan,
750 MathTreeFunc1ASin, MathTreeFunc1ACos, MathTreeFunc1ATan,
751 MathTreeFunc1SinD, MathTreeFunc1CosD, MathTreeFunc1TanD,
752 MathTreeFunc1ASinD, MathTreeFunc1ACosD, MathTreeFunc1ATanD,
753 MathTreeFunc2Norm,
754 MathTreeFuncSplitAtValue]
756 class parser:
758 def __init__(self, MathTreeFuncs=DefaultMathTreeFuncs):
759 self.MathTreeFuncs = MathTreeFuncs
761 def parse(self, expr):
762 return self.astseq2mtree(pythonparser.expr(expr.strip()).totuple())
764 def astseq2mtree(self, astseq, isfunc=0):
765 # astseq has to be a sequence!
766 tree = None
768 if token.ISTERMINAL(astseq[0]):
769 raise Exception("")
771 if astseq[0] == symbol.arith_expr: # {{{
772 try:
773 # 1. arith_expr "PLUS" term
774 if astseq[-2][0] == token.PLUS:
775 tree = MathTreeOpAdd(
776 self.astseq2mtree(astseq[:-2], isfunc=isfunc),
777 self.astseq2mtree(astseq[-1], isfunc=isfunc))
778 # 2. arith_expr "MINUS" term
779 elif astseq[-2][0] == token.MINUS:
780 tree = MathTreeOpSub(
781 self.astseq2mtree(astseq[:-2], isfunc=isfunc),
782 self.astseq2mtree(astseq[-1], isfunc=isfunc))
783 else:
784 raise Exception("")
785 except:
786 # 3. term
787 tree = self.astseq2mtree(astseq[1], isfunc=isfunc)
788 return tree # }}}
790 if astseq[0] == symbol.term: # {{{
791 try:
792 # 1. term "STAR" factor
793 if astseq[-2][0] == token.STAR:
794 tree = MathTreeOpMul(
795 self.astseq2mtree(astseq[:-2], isfunc=isfunc),
796 self.astseq2mtree(astseq[-1], isfunc=isfunc))
797 # 2. term "SLASH" factor
798 elif astseq[-2][0] == token.SLASH:
799 tree = MathTreeOpDiv(
800 self.astseq2mtree(astseq[:-2], isfunc=isfunc),
801 self.astseq2mtree(astseq[-1], isfunc=isfunc))
802 else:
803 raise Exception("")
804 except:
805 # 3. factor
806 tree = self.astseq2mtree(astseq[1], isfunc=isfunc)
807 return tree # }}}
809 if astseq[0] == symbol.factor: # {{{
810 if len(astseq) == 3:
811 # 1. "PLUS" factor
812 if astseq[1][0] == token.PLUS:
813 tree = self.astseq2mtree(astseq[2], isfunc=isfunc)
814 # 2. "MINUS" factor
815 elif astseq[1][0] == token.MINUS:
816 tree = MathTreeFunc1Neg(self.astseq2mtree(astseq[2], isfunc=isfunc))
817 else:
818 raise Exception("unknown factor")
819 elif len(astseq) == 2:
820 # 3. power
821 tree = self.astseq2mtree(astseq[1], isfunc=isfunc)
822 else:
823 raise Exception("wrong length of factor")
824 return tree # }}}
826 if astseq[0] == symbol.power: # {{{
827 try:
828 # 1. "DOUBLESTAR" factor
829 if astseq[-2][0] == token.DOUBLESTAR:
830 tree = MathTreeOpPow(
831 self.astseq2mtree(astseq[:-2], isfunc=isfunc),
832 self.astseq2mtree(astseq[-1], isfunc=isfunc))
833 else:
834 raise Exception("")
835 except:
836 # 2. atom + [trailer]
837 if len(astseq) == 3:
838 # we have a function call atom + "LPAR" + argumentlist + "RPAR"
839 if astseq[2][0] == symbol.trailer and \
840 astseq[2][1][0] == token.LPAR and \
841 astseq[2][2][0] == symbol.arglist and \
842 astseq[2][3][0] == token.RPAR:
843 tree = self.astseq2mtree(astseq[1], isfunc=1)
844 for subtree in self.astseq2mtree(astseq[2][2], isfunc=0):
845 tree.AddArg(subtree)
846 elif astseq[2][0] == symbol.trailer and \
847 astseq[2][1][0] == token.LPAR and \
848 astseq[2][2][0] == token.RPAR:
849 tree = self.astseq2mtree(astseq[1], isfunc=1)
850 else:
851 raise Exception("wrong function call")
852 else:
853 tree = self.astseq2mtree(astseq[1], isfunc=0)
855 return tree # }}}
857 if astseq[0] == symbol.atom: # {{{
858 # only one nontrivial term:
859 if len(astseq) == 2:
860 if astseq[1][0] == token.NUMBER:
861 # 1. a number
862 # XXX: for evaluation of brackets we will need integers as well
863 tree = MathTreeValConst(string.atof(astseq[1][1]))
864 elif astseq[1][0] == token.NAME:
865 # 2. a function
866 if isfunc:
867 # a known function
868 for funcclass in self.MathTreeFuncs:
869 func = funcclass() # ist das guenstig, da jedesmal eine Instanz zu erzeugen?
870 # doofe Frage, nein! <wobsta>
871 if func.name == astseq[1][1]:
872 return func
873 # an unknown function
874 tree = MathTreeFuncExtern()
875 tree.SetName(astseq[1][1])
876 else:
877 # 3. a variable
878 return MathTreeValVar(astseq[1][1])
879 elif len(astseq) == 4:
880 # parentheses or brackets for structuring an atom
881 if (astseq[1][0] == token.LPAR and astseq[3][0] == token.RPAR) or \
882 (astseq[1][0] == token.LSQB and astseq[3][0] == token.RSQB):
883 tree = self.astseq2mtree(astseq[2], isfunc=isfunc)
884 else:
885 raise Exception("symbol.atom with unknown number of arguments")
886 return tree # }}}
888 if astseq[0] == symbol.arglist: # {{{
889 treelist = []
890 for arg in astseq[1:]:
891 if arg[0] == token.COMMA:
892 continue
893 elif arg[0] == symbol.argument:
894 treelist.append(self.astseq2mtree(arg, isfunc=isfunc))
895 return treelist # }}}
897 if astseq[0] == symbol.testlist: # {{{
898 treelist = []
899 for arg in astseq[1:]:
900 if arg[0] == token.COMMA:
901 continue
902 elif arg[0] == symbol.test:
903 treelist.append(self.astseq2mtree(arg, isfunc=isfunc))
904 if len(treelist) == 1: return treelist[0]
905 else: return treelist # }}}
907 if astseq[0] != symbol.eval_input and len(astseq) > 2:
908 raise Exception("invalid expression structure (contains several parts)")
909 return self.astseq2mtree(astseq[1], isfunc=isfunc)