2 # -*- coding: ISO-8859-1 -*-
5 # Copyright (C) 2002 Jörg Lehmann <joergl@users.sourceforge.net>
6 # Copyright (C) 2002 André Wobst <wobsta@users.sourceforge.net>
8 # This file is part of PyX (http://pyx.sourceforge.net/).
10 # PyX is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
15 # PyX is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with PyX; if not, write to the Free Software
22 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 import string
, re
, math
29 __useparser__
= __oldparser__
30 #__useparser__ = __newparser__
32 if __useparser__
== __newparser__
:
34 import parser
as pythonparser
38 def __init__(self
, StrToParse
, Pos
= 0):
39 self
.StrToParse
= StrToParse
43 return "ParseStr('" + self
.StrToParse
+ "', " + str(self
.Pos
) + ")"
45 def __str__(self
, Indent
= ""):
47 for i
in range(self
.Pos
):
48 WhiteSpaces
= WhiteSpaces
+ " "
49 return Indent
+ self
.StrToParse
+ "\n" + Indent
+ WhiteSpaces
+ "^"
51 def NextNonWhiteSpace(self
, i
= None):
54 while self
.StrToParse
[i
] in string
.whitespace
:
58 def MatchStr(self
, Str
):
60 i
= self
.NextNonWhiteSpace()
61 if self
.StrToParse
[i
: i
+ len(Str
)] == Str
:
62 self
.Pos
= i
+ len(Str
)
67 def MatchStrParenthesis(self
, Str
):
69 i
= self
.NextNonWhiteSpace()
70 if self
.StrToParse
[i
: i
+ len(Str
)] == Str
:
72 i
= self
.NextNonWhiteSpace(i
)
73 if self
.StrToParse
[i
: i
+ 1] == "(":
79 def MatchPattern(self
, Pat
):
81 i
= self
.NextNonWhiteSpace()
82 Match
= Pat
.match(self
.StrToParse
[i
:])
84 self
.Pos
= i
+ Match
.end()
91 self
.NextNonWhiteSpace()
97 class ArgCountError(Exception): pass
98 class DerivativeError(Exception): pass
102 def __init__(self
, ArgCount
, *Args
):
103 self
.ArgCount
= ArgCount
108 def __repr__(self
, depth
= 0):
111 for i
in range(depth
):
112 indent
= indent
+ SingleIndent
113 result
= indent
+ self
.__class
__.__name
__ + "(\n"
114 for SubTree
in self
.Args
:
115 if isinstance(SubTree
, MathTree
):
116 result
= result
+ SubTree
.__repr
__(depth
+ 1)
118 result
= result
+ indent
+ SingleIndent
+ repr(SubTree
)
120 if SubTree
!= self
.Args
[-1]:
121 result
= result
+ ",\n"
123 result
= result
+ ")"
126 def AddArg(self
, Arg
, Last
=0, NotLast
=0):
127 if len(self
.Args
) == self
.ArgCount
:
129 self
.Args
.append(Arg
)
130 if NotLast
and len(self
.Args
) == self
.ArgCount
:
132 if Last
and len(self
.Args
) != self
.ArgCount
:
135 def DependOn(self
, arg
):
136 for Arg
in self
.Args
:
137 if Arg
.DependOn(arg
):
141 def Derivative(self
, arg
):
142 if not self
.DependOn(arg
):
143 return MathTreeValConst(0.0)
144 return self
.CalcDerivative(arg
)
148 for Arg
in self
.Args
:
149 newlist
= Arg
.VarList()
156 class MathTreeVal(MathTree
):
158 def __init__(self
, *args
):
159 MathTree
.__init
__(self
, 1, *args
)
162 return str(self
.Args
[0])
165 ConstPattern
= re
.compile(r
"-?\d*((\d\.?)|(\.?\d))\d*(E[+-]?\d+)?",
168 class MathTreeValConst(MathTreeVal
):
170 def InitByParser(self
, arg
):
171 Match
= arg
.MatchPattern(ConstPattern
)
173 self
.AddArg(string
.atof(Match
))
176 def CalcDerivative(self
, arg
):
177 raise DerivativeError("expression doesn't depend on \"%s\"" % arg
)
179 def Derivative(self
, arg
):
180 return MathTreeValConst(0.0)
182 def DependOn(self
, arg
):
188 def Calc(HIDDEN_self
, **args
):
189 return HIDDEN_self
.Args
[0]
192 VarPattern
= re
.compile(r
"[a-z_][a-z0-9_]*", re
.IGNORECASE
)
193 MathConst
= {"pi": math
.pi
, "e": math
.e
}
195 class MathTreeValVar(MathTreeVal
):
197 def InitByParser(self
, arg
):
198 Match
= arg
.MatchPattern(VarPattern
)
203 def CalcDerivative(self
, arg
):
204 if arg
!= self
.Args
[0]:
205 raise DerivativeError("expression doesn't depend on \"%s\"" % arg
)
206 return MathTreeValConst(1.0)
208 def DependOn(self
, arg
):
209 if arg
== self
.Args
[0]:
214 if self
.Args
[0] in MathConst
.keys():
216 return [self
.Args
[0]]
218 def Calc(HIDDEN_self
, **args
):
219 if HIDDEN_self
.Args
[0] in args
.keys():
220 return float(args
[HIDDEN_self
.Args
[0]])
221 return MathConst
[HIDDEN_self
.Args
[0]]
224 class MathTreeFunc(MathTree
):
226 def __init__(self
, name
, ArgCount
, *args
):
228 MathTree
.__init
__(self
, ArgCount
, *args
)
230 def InitByParser(self
, arg
):
231 return arg
.MatchStrParenthesis(self
.name
)
235 for SubTree
in self
.Args
:
236 args
= args
+ str(SubTree
)
237 if SubTree
!= self
.Args
[-1]:
239 return self
.name
+ "(" + args
+ ")"
242 class MathTreeFunc1(MathTreeFunc
):
244 def __init__(self
, name
, *args
):
245 MathTreeFunc
.__init
__(self
, name
, 1, *args
)
248 class MathTreeFunc1Neg(MathTreeFunc1
):
250 def __init__(self
, *args
):
251 MathTreeFunc1
.__init__(self
, "neg", *args
)
253 def CalcDerivative(self
, arg
):
254 return MathTreeFunc1Neg(self
.Args
[0].CalcDerivative(arg
))
256 def Calc(HIDDEN_self
, **args
):
257 return -HIDDEN_self
.Args
[0].Calc(**args
)
260 class MathTreeFunc1Abs(MathTreeFunc1
):
262 def __init__(self
, *args
):
263 MathTreeFunc1
.__init__(self
, "abs", *args
)
265 def CalcDerivative(self
, arg
):
266 return MathTreeOpMul(
267 MathTreeFunc1Sgn(self
.Args
[0]),
268 self
.Args
[0].CalcDerivative(arg
))
270 def Calc(HIDDEN_self
, **args
):
271 return abs(HIDDEN_self
.Args
[0].Calc(**args
))
274 class MathTreeFunc1Sgn(MathTreeFunc1
):
276 def __init__(self
, *args
):
277 MathTreeFunc1
.__init__(self
, "sgn", *args
)
279 def CalcDerivative(self
, arg
):
280 return MathTreeValConst(0.0)
282 def Calc(HIDDEN_self
, **args
):
283 if HIDDEN_self
.Args
[0].Calc(**args
) < 0:
288 class MathTreeFunc1Sqrt(MathTreeFunc1
):
290 def __init__(self
, *args
):
291 MathTreeFunc1
.__init__(self
, "sqrt", *args
)
293 def CalcDerivative(self
, arg
):
294 return MathTreeOpMul(
296 MathTreeValConst(0.5),
298 self
.Args
[0].CalcDerivative(arg
))
300 def Calc(HIDDEN_self
, **args
):
301 return math
.sqrt(HIDDEN_self
.Args
[0].Calc(**args
))
304 class MathTreeFunc1Exp(MathTreeFunc1
):
306 def __init__(self
, *args
):
307 MathTreeFunc1
.__init__(self
, "exp", *args
)
309 def CalcDerivative(self
, arg
):
310 return MathTreeOpMul(self
, self
.Args
[0].CalcDerivative(arg
))
312 def Calc(HIDDEN_self
, **args
):
313 return math
.exp(HIDDEN_self
.Args
[0].Calc(**args
))
316 class MathTreeFunc1Log(MathTreeFunc1
):
318 def __init__(self
, *args
):
319 MathTreeFunc1
.__init__(self
, "log", *args
)
321 def CalcDerivative(self
, arg
):
322 return MathTreeOpDiv(self
.Args
[0].CalcDerivative(arg
), self
.Args
[0])
324 def Calc(HIDDEN_self
, **args
):
325 return math
.log(HIDDEN_self
.Args
[0].Calc(**args
))
328 class MathTreeFunc1Sin(MathTreeFunc1
):
330 def __init__(self
, *args
):
331 MathTreeFunc1
.__init__(self
, "sin", *args
)
333 def CalcDerivative(self
, arg
):
334 return MathTreeOpMul(
335 MathTreeFunc1Cos(self
.Args
[0]),
336 self
.Args
[0].CalcDerivative(arg
))
338 def Calc(HIDDEN_self
, **args
):
339 return math
.sin(HIDDEN_self
.Args
[0].Calc(**args
))
342 class MathTreeFunc1Cos(MathTreeFunc1
):
344 def __init__(self
, *args
):
345 MathTreeFunc1
.__init__(self
, "cos", *args
)
347 def CalcDerivative(self
, arg
):
348 return MathTreeOpMul(
349 MathTreeFunc1Neg(MathTreeFunc1Sin(self
.Args
[0])),
350 self
.Args
[0].CalcDerivative(arg
))
352 def Calc(HIDDEN_self
, **args
):
353 return math
.cos(HIDDEN_self
.Args
[0].Calc(**args
))
356 class MathTreeFunc1Tan(MathTreeFunc1
):
358 def __init__(self
, *args
):
359 MathTreeFunc1
.__init__(self
, "tan", *args
)
361 def CalcDerivative(self
, arg
):
362 return MathTreeOpDiv(
363 self
.Args
[0].CalcDerivative(arg
),
365 MathTreeFunc1Cos(self
.Args
[0]),
366 MathTreeValConst(2.0)))
368 def Calc(HIDDEN_self
, **args
):
369 return math
.tan(HIDDEN_self
.Args
[0].Calc(**args
))
372 class MathTreeFunc1ASin(MathTreeFunc1
):
374 def __init__(self
, *args
):
375 MathTreeFunc1
.__init__(self
, "asin", *args
)
377 def CalcDerivative(self
, arg
):
378 return MathTreeOpDiv(
379 self
.Args
[0].CalcDerivative(arg
),
382 MathTreeValConst(1.0),
385 MathTreeValConst(2.0)))))
387 def Calc(HIDDEN_self
, **args
):
388 return math
.asin(HIDDEN_self
.Args
[0].Calc(**args
))
391 class MathTreeFunc1ACos(MathTreeFunc1
):
393 def __init__(self
, *args
):
394 MathTreeFunc1
.__init__(self
, "acos", *args
)
396 def CalcDerivate(self
, arg
):
397 return MathTreeOpDiv(
398 MathTreeFunc1Neg(self
.Args
[0].CalcDerivative(arg
)),
401 MathTreeValConst(1.0),
404 MathTreeValConst(2.0)))))
406 def Calc(HIDDEN_self
, **args
):
407 return math
.acos(HIDDEN_self
.Args
[0].Calc(**args
))
410 class MathTreeFunc1ATan(MathTreeFunc1
):
412 def __init__(self
, *args
):
413 MathTreeFunc1
.__init__(self
, "atan", *args
)
415 def CalcDerivate(self
, arg
):
416 return MathTreeOpDiv(
417 self
.Args
[0].CalcDerivative(arg
),
419 MathTreeValConst(1.0),
422 MathTreeValConst(2.0))))
424 def Calc(HIDDEN_self
, **args
):
425 return math
.atan(HIDDEN_self
.Args
[0].Calc(**args
))
428 class MathTreeFunc1SinD(MathTreeFunc1
):
430 def __init__(self
, *args
):
431 MathTreeFunc1
.__init__(self
, "sind", *args
)
433 def CalcDerivative(self
, arg
):
434 return MathTreeOpMul(
435 MathTreeFunc1CosD(self
.Args
[0]),
437 MathTreeValConst(math
.pi
/180.0),
438 self
.Args
[0].CalcDerivative(arg
)))
440 def Calc(HIDDEN_self
, **args
):
441 return math
.sin(math
.pi
/180.0*HIDDEN_self
.Args
[0].Calc(**args
))
444 class MathTreeFunc1CosD(MathTreeFunc1
):
446 def __init__(self
, *args
):
447 MathTreeFunc1
.__init__(self
, "cosd", *args
)
449 def CalcDerivative(self
, arg
):
450 return MathTreeOpMul(
451 MathTreeFunc1Neg(MathTreeFunc1Sin(self
.Args
[0])),
453 MathTreeValConst(math
.pi
/180.0),
454 self
.Args
[0].CalcDerivative(arg
)))
456 def Calc(HIDDEN_self
, **args
):
457 return math
.cos(math
.pi
/180.0*HIDDEN_self
.Args
[0].Calc(**args
))
460 class MathTreeFunc1TanD(MathTreeFunc1
):
462 def __init__(self
, *args
):
463 MathTreeFunc1
.__init__(self
, "tand", *args
)
465 def CalcDerivative(self
, arg
):
466 return MathTreeOpDiv(
468 MathTreeValConst(math
.pi
/180.0),
469 self
.Args
[0].CalcDerivative(arg
)),
471 MathTreeFunc1Cos(self
.Args
[0]),
472 MathTreeValConst(2.0)))
474 def Calc(HIDDEN_self
, **args
):
475 return math
.tan(math
.pi
/180.0*HIDDEN_self
.Args
[0].Calc(**args
))
478 class MathTreeFunc1ASinD(MathTreeFunc1
):
480 def __init__(self
, *args
):
481 MathTreeFunc1
.__init__(self
, "asind", *args
)
483 def CalcDerivative(self
, arg
):
484 return MathTreeOpDiv(
486 MathTreeValConst(180.0/math
.pi
),
487 self
.Args
[0].CalcDerivative(arg
)),
490 MathTreeValConst(1.0),
493 MathTreeValConst(2.0)))))
495 def Calc(HIDDEN_self
, **args
):
496 return 180.0/math
.pi
*math
.asin(HIDDEN_self
.Args
[0].Calc(**args
))
499 class MathTreeFunc1ACosD(MathTreeFunc1
):
501 def __init__(self
, *args
):
502 MathTreeFunc1
.__init__(self
, "acosd", *args
)
504 def CalcDerivate(self
, arg
):
505 return MathTreeOpDiv(
508 MathTreeValConst(180.0/math
.pi
),
509 self
.Args
[0].CalcDerivative(arg
))),
512 MathTreeValConst(1.0),
515 MathTreeValConst(2.0)))))
517 def Calc(HIDDEN_self
, **args
):
518 return 180.0/math
.pi
*math
.acos(HIDDEN_self
.Args
[0].Calc(**args
))
521 class MathTreeFunc1ATanD(MathTreeFunc1
):
523 def __init__(self
, *args
):
524 MathTreeFunc1
.__init__(self
, "atand", *args
)
526 def CalcDerivate(self
, arg
):
527 return MathTreeOpDiv(
529 MathTreeValConst(180.0/math
.pi
),
530 self
.Args
[0].CalcDerivative(arg
)),
532 MathTreeValConst(1.0),
535 MathTreeValConst(2.0))))
537 def Calc(HIDDEN_self
, **args
):
538 return 180.0/math
.pi
*math
.atan(HIDDEN_self
.Args
[0].Calc(**args
))
541 class MathTreeFunc2(MathTreeFunc
):
543 def __init__(self
, name
, *args
):
544 MathTreeFunc
.__init
__(self
, name
, 2, *args
)
547 class MathTreeFunc2Norm(MathTreeFunc2
):
549 def __init__(self
, *args
):
550 MathTreeFunc2
.__init__(self
, "norm", *args
)
552 def CalcDerivative(self
, arg
):
553 if self
.Args
[0].DependOn(arg
):
554 if self
.Args
[1].DependOn(arg
):
555 return MathTreeOpDiv(
559 self
.Args
[0].CalcDerivative(arg
)),
562 self
.Args
[1].CalcDerivative(arg
))),
565 return MathTreeOpDiv(
568 self
.Args
[0].CalcDerivative(arg
)),
571 if self
.Args
[1].DependOn(arg
):
572 return MathTreeOpDiv(
575 self
.Args
[1].CalcDerivative(arg
)),
578 def Calc(HIDDEN_self
, **args
):
579 return math
.sqrt(HIDDEN_self
.Args
[0].Calc(**args
) ** 2 +
580 HIDDEN_self
.Args
[1].Calc(**args
) ** 2)
583 FuncExternPattern
= re
.compile(r
"([a-z_][a-z0-9_]*)\s*\(", re
.IGNORECASE
)
585 class MathTreeFuncExtern(MathTreeFunc
):
587 def __init__(self
, *args
):
588 MathTreeFunc
.__init
__(self
, None, -1, *args
)
590 def InitByParser(self
, arg
):
591 Match
= arg
.MatchPattern(FuncExternPattern
)
593 self
.name
= Match
[:-1].strip()
596 def SetName(self
, arg
):
597 self
.name
= arg
.strip()
600 def Calc(HIDDEN_self
, **args
):
601 return args
[HIDDEN_self
.name
](*[arg
.Calc(**args
) for arg
in HIDDEN_self
.Args
])
604 class MathTreeOp(MathTree
):
606 def __init__(self
, level
, symbol
, *args
):
607 self
.ParenthesisBarrier
= 0
610 MathTree
.__init
__(self
, 2, *args
)
614 if isinstance(self
.Args
[0], MathTreeOp
) and\
615 self
.level
> self
.Args
[0].level
:
616 result
= result
+ "(" + str(self
.Args
[0]) + ")"
618 result
= result
+ str(self
.Args
[0])
619 result
= result
+ self
.symbol
620 if isinstance(self
.Args
[1], MathTreeOp
) and\
621 self
.level
>= self
.Args
[1].level
:
622 result
= result
+ "(" + str(self
.Args
[1]) + ")"
624 result
= result
+ str(self
.Args
[1])
627 def InitByParser(self
, arg
):
628 return arg
.MatchStr(self
.symbol
)
631 class MathTreeOpAdd(MathTreeOp
):
633 def __init__(self
, *args
):
634 MathTreeOp
.__init
__(self
, 1, "+", *args
)
636 def CalcDerivative(self
, arg
):
637 if self
.Args
[0].DependOn(arg
):
638 if self
.Args
[1].DependOn(arg
):
639 return MathTreeOpAdd(
640 self
.Args
[0].CalcDerivative(arg
),
641 self
.Args
[1].CalcDerivative(arg
))
643 return self
.Args
[0].CalcDerivative(arg
)
645 if self
.Args
[1].DependOn(arg
):
646 return self
.Args
[1].CalcDerivative(arg
)
648 def Calc(HIDDEN_self
, **args
):
649 return HIDDEN_self
.Args
[0].Calc(**args
) + HIDDEN_self
.Args
[1].Calc(**args
)
652 class MathTreeOpSub(MathTreeOp
):
654 def __init__(self
, *args
):
655 MathTreeOp
.__init
__(self
, 1, "-", *args
)
657 def CalcDerivative(self
, arg
):
658 if self
.Args
[0].DependOn(arg
):
659 if self
.Args
[1].DependOn(arg
):
660 return MathTreeOpSub(
661 self
.Args
[0].CalcDerivative(arg
),
662 self
.Args
[1].CalcDerivative(arg
))
664 return self
.Args
[0].CalcDerivative(arg
)
666 if self
.Args
[1].DependOn(arg
):
667 return MathTreeFunc1Neg(self
.Args
[1].CalcDerivative(arg
))
669 def Calc(HIDDEN_self
, **args
):
670 return HIDDEN_self
.Args
[0].Calc(**args
) - HIDDEN_self
.Args
[1].Calc(**args
)
673 class MathTreeOpMul(MathTreeOp
):
675 def __init__(self
, *args
):
676 MathTreeOp
.__init
__(self
, 2, "*", *args
)
678 def CalcDerivative(self
, arg
):
679 if self
.Args
[0].DependOn(arg
):
680 if self
.Args
[1].DependOn(arg
):
681 return MathTreeOpAdd(
684 self
.Args
[1].CalcDerivative(arg
)),
686 self
.Args
[0].CalcDerivative(arg
),
689 return MathTreeOpMul(
690 self
.Args
[0].CalcDerivative(arg
),
693 if self
.Args
[1].DependOn(arg
):
694 return MathTreeOpMul(
696 self
.Args
[1].CalcDerivative(arg
))
698 def Calc(HIDDEN_self
, **args
):
699 return HIDDEN_self
.Args
[0].Calc(**args
) * HIDDEN_self
.Args
[1].Calc(**args
)
702 class MathTreeOpDiv(MathTreeOp
):
704 def __init__(self
, *args
):
705 MathTreeOp
.__init
__(self
, 2, "/", *args
)
707 def CalcDerivative(self
, arg
):
708 if self
.Args
[0].DependOn(arg
):
709 if self
.Args
[1].DependOn(arg
):
710 return MathTreeOpMul(
713 self
.Args
[0].CalcDerivative(arg
),
717 self
.Args
[1].CalcDerivative(arg
))),
720 MathTreeValConst(-2.0)))
722 return MathTreeOpDiv(
723 self
.Args
[0].CalcDerivative(arg
),
726 if self
.Args
[1].DependOn(arg
):
727 return MathTreeOpMul(
729 MathTreeFunc1Neg(self
.Args
[0]),
732 MathTreeValConst(-2.0))),
733 self
.Args
[1].CalcDerivative(arg
))
735 def Calc(HIDDEN_self
, **args
):
736 return HIDDEN_self
.Args
[0].Calc(**args
) / HIDDEN_self
.Args
[1].Calc(**args
)
739 class MathTreeOpPow(MathTreeOp
):
741 def __init__(self
, *args
):
742 MathTreeOp
.__init
__(self
, 3, "^", *args
)
744 def InitByParser(self
, arg
):
745 pos
= arg
.MatchStr("^")
749 return arg
.MatchStr("**")
751 def CalcDerivative(self
, arg
):
752 if self
.Args
[0].DependOn(arg
):
753 if self
.Args
[1].DependOn(arg
):
754 return MathTreeOpMul(
760 MathTreeFunc1Log(self
.Args
[0]),
761 self
.Args
[1].CalcDerivative(arg
)),
765 self
.Args
[0].CalcDerivative(arg
),
768 return MathTreeOpMul(
775 MathTreeValConst(1.0))),
776 self
.Args
[0].CalcDerivative(arg
)))
778 if self
.Args
[1].DependOn(arg
):
779 return MathTreeOpMul(
784 MathTreeFunc1Log(self
.Args
[0])),
785 self
.Args
[1].CalcDerivative(arg
))
787 def Calc(HIDDEN_self
, **args
):
788 return HIDDEN_self
.Args
[0].Calc(**args
) ** HIDDEN_self
.Args
[1].Calc(**args
)
792 class UndefinedMathTreeParseError(Exception):
794 def __init__(self
, ParseStr
, MathTree
):
795 self
.ParseStr
= ParseStr
796 self
.MathTree
= MathTree
799 return "\n" + str(self
.ParseStr
)
802 class RightParenthesisExpectedMathTreeParseError(UndefinedMathTreeParseError
): pass
803 class RightParenthesisFoundMathTreeParseError(UndefinedMathTreeParseError
): pass
804 class CommaExpectedMathTreeParseError(UndefinedMathTreeParseError
): pass
805 class CommaFoundMathTreeParseError(UndefinedMathTreeParseError
): pass
806 class OperatorExpectedMathTreeParseError(UndefinedMathTreeParseError
): pass
807 class OperandExpectedMathTreeParseError(UndefinedMathTreeParseError
): pass
810 DefaultMathTreeOps
= (MathTreeOpPow
, MathTreeOpDiv
, MathTreeOpMul
, MathTreeOpSub
, MathTreeOpAdd
)
811 DefaultMathTreeFuncs
= (MathTreeFunc1Neg
, MathTreeFunc1Abs
, MathTreeFunc1Sgn
, MathTreeFunc1Sqrt
,
812 MathTreeFunc1Exp
, MathTreeFunc1Log
,
813 MathTreeFunc1Sin
, MathTreeFunc1Cos
, MathTreeFunc1Tan
,
814 MathTreeFunc1ASin
, MathTreeFunc1ACos
, MathTreeFunc1ATan
,
815 MathTreeFunc1SinD
, MathTreeFunc1CosD
, MathTreeFunc1TanD
,
816 MathTreeFunc1ASinD
, MathTreeFunc1ACosD
, MathTreeFunc1ATanD
,
819 DefaultMathTreeVals
= (MathTreeValConst
, MathTreeValVar
)
823 def __init__(self
, MathTreeOps
=DefaultMathTreeOps
,
824 MathTreeFuncs
=DefaultMathTreeFuncs
,
825 MathTreeVals
=DefaultMathTreeVals
):
826 self
.MathTreeOps
= MathTreeOps
827 self
.MathTreeFuncs
= MathTreeFuncs
828 self
.MathTreeVals
= MathTreeVals
831 def parse(self
, str):
832 if __useparser__
== __oldparser__
:
833 return self
.old_parse(str)
834 elif __useparser__
== __newparser__
:
835 return self
.new_parse(str)
837 RuntimeError("invalid __useparser__")
839 def old_parse(self
, str):
840 return self
.ParseMathTree(ParseStr(str))
842 def new_parse(self
, str):
843 # prepare raw string:
845 thestr
= re
.sub("^\s*", "", str)
846 thestr
= re
.sub("\^","**", thestr
) # to be removed <joergl>
847 thestr
= re
.sub("\$","_col_", thestr
)
848 return self
.astseq2mtree(pythonparser
.expr(thestr
).totuple())
850 def ParseMathTree(self
, arg
):
852 #Match = arg.MatchPattern(re.compile(r"\s*-(?![0-9\.])"))
853 Match
= arg
.MatchPattern(re
.compile(r
"\s*-")) # XXX another quick workaround
855 #Tree = MathTreeFunc1Neg()
856 Tree
= MathTreeOpSub(MathTreeValConst(0)) # XXX quick workaround
858 i
= arg
.MatchStr("(")
861 self
.ParseMathTree(arg
)
862 raise RightParenthesisExpectedMathTreeParseError(arg
, Tree
)
863 except RightParenthesisFoundMathTreeParseError
, e
:
864 if isinstance(e
.MathTree
, MathTreeOp
):
865 e
.MathTree
.ParenthesisBarrier
= 1
867 SubTree
= Tree
# XXX: four lines code dublication
868 while isinstance(SubTree
, MathTreeOp
) and len(SubTree
.Args
) == 2:
869 SubTree
= SubTree
.Args
[1]
870 SubTree
.AddArg(e
.MathTree
)
874 for FuncClass
in self
.MathTreeFuncs
:
876 if Func
.InitByParser(arg
):
878 SubTree
= Tree
# XXX: four lines code dublication
879 while isinstance(SubTree
, MathTreeOp
) and len(SubTree
.Args
) == 2:
880 SubTree
= SubTree
.Args
[1]
886 self
.ParseMathTree(arg
)
887 raise RightParenthesisExpectedMathTreeParseError(arg
, Tree
)
888 except CommaFoundMathTreeParseError
, e
:
890 Func
.AddArg(e
.MathTree
, NotLast
=1)
891 except ArgCountError
:
892 raise RightParenthesisExpectedMathTreeParseError(arg
, Tree
)
894 except RightParenthesisFoundMathTreeParseError
, e
:
896 Func
.AddArg(e
.MathTree
, Last
=1)
897 except ArgCountError
:
898 raise CommaExpectedMathTreeParseError(arg
, Tree
)
902 FuncExtern
= MathTreeFuncExtern()
903 if FuncExtern
.InitByParser(arg
):
905 SubTree
= Tree
# XXX: four lines code dublication
906 while isinstance(SubTree
, MathTreeOp
) and len(SubTree
.Args
) == 2:
907 SubTree
= SubTree
.Args
[1]
908 SubTree
.AddArg(FuncExtern
)
913 self
.ParseMathTree(arg
)
914 raise RightParenthesisExpectedMathTreeParseError(arg
, Tree
)
915 except CommaFoundMathTreeParseError
, e
:
916 FuncExtern
.AddArg(e
.MathTree
)
918 except RightParenthesisFoundMathTreeParseError
, e
:
919 FuncExtern
.AddArg(e
.MathTree
)
922 for ValClass
in self
.MathTreeVals
:
924 if Val
.InitByParser(arg
):
926 SubTree
= Tree
# XXX: four lines code dublication
927 while isinstance(SubTree
, MathTreeOp
) and len(SubTree
.Args
) == 2:
928 SubTree
= SubTree
.Args
[1]
934 raise OperandExpectedMathTreeParseError(arg
, Tree
)
937 i
= arg
.MatchStr(")")
939 raise RightParenthesisFoundMathTreeParseError(arg
, Tree
)
940 i
= arg
.MatchStr(",")
942 raise CommaFoundMathTreeParseError(arg
, Tree
)
943 for OpClass
in self
.MathTreeOps
:
945 if Op
.InitByParser(arg
):
948 while isinstance(SubTree
, MathTreeOp
) and\
949 Op
.level
> SubTree
.level
and\
950 not SubTree
.ParenthesisBarrier
:
951 SubTreeRoot
= SubTree
952 SubTree
= SubTree
.Args
[1]
955 SubTreeRoot
.Args
[1] = Op
961 raise OperatorExpectedMathTreeParseError(arg
, Tree
)
964 def astseq2mtree(self
, astseq
, isfunc
=0):
965 # astseq has to be a sequence!
968 if token
.ISTERMINAL(astseq
[0]):
971 if astseq
[0] == symbol
.arith_expr
: # {{{
973 # 1. arith_expr "PLUS" term
974 if astseq
[-2][0] == token
.PLUS
:
975 tree
= MathTreeOpAdd(
976 self
.astseq2mtree(astseq
[:-2], isfunc
=isfunc
),
977 self
.astseq2mtree(astseq
[-1], isfunc
=isfunc
))
978 # 2. arith_expr "MINUS" term
979 elif astseq
[-2][0] == token
.MINUS
:
980 tree
= MathTreeOpSub(
981 self
.astseq2mtree(astseq
[:-2], isfunc
=isfunc
),
982 self
.astseq2mtree(astseq
[-1], isfunc
=isfunc
))
987 tree
= self
.astseq2mtree(astseq
[1], isfunc
=isfunc
)
990 if astseq
[0] == symbol
.term
: # {{{
992 # 1. term "STAR" factor
993 if astseq
[-2][0] == token
.STAR
:
994 tree
= MathTreeOpMul(
995 self
.astseq2mtree(astseq
[:-2], isfunc
=isfunc
),
996 self
.astseq2mtree(astseq
[-1], isfunc
=isfunc
))
997 # 2. term "SLASH" factor
998 elif astseq
[-2][0] == token
.SLASH
:
999 tree
= MathTreeOpDiv(
1000 self
.astseq2mtree(astseq
[:-2], isfunc
=isfunc
),
1001 self
.astseq2mtree(astseq
[-1], isfunc
=isfunc
))
1006 tree
= self
.astseq2mtree(astseq
[1], isfunc
=isfunc
)
1009 if astseq
[0] == symbol
.factor
: # {{{
1010 if len(astseq
) == 3:
1012 if astseq
[1][0] == token
.PLUS
:
1013 tree
= self
.astseq2mtree(astseq
[2], isfunc
=isfunc
)
1015 elif astseq
[1][0] == token
.MINUS
:
1016 tree
= MathTreeFunc1Neg(self
.astseq2mtree(astseq
[2], isfunc
=isfunc
))
1018 raise Exception("unknown factor")
1019 elif len(astseq
) == 2:
1021 tree
= self
.astseq2mtree(astseq
[1], isfunc
=isfunc
)
1023 raise Exception("wrong length of factor")
1026 if astseq
[0] == symbol
.power
: # {{{
1028 # 1. "DOUBLESTAR" factor
1029 if astseq
[-2][0] == token
.DOUBLESTAR
:
1030 tree
= MathTreeOpPow(
1031 self
.astseq2mtree(astseq
[:-2], isfunc
=isfunc
),
1032 self
.astseq2mtree(astseq
[-1], isfunc
=isfunc
))
1036 # 2. atom + [trailer]
1037 if len(astseq
) == 3:
1038 # we have a function call atom + "LPAR" + argumentlist + "RPAR"
1039 if astseq
[2][0] != symbol
.trailer
or \
1040 astseq
[2][1][0] != token
.LPAR
or \
1041 astseq
[2][2][0] != symbol
.arglist
or \
1042 astseq
[2][3][0] != token
.RPAR
:
1043 raise Exception("wrong function call")
1044 tree
= self
.astseq2mtree(astseq
[1], isfunc
=1)
1045 for subtree
in self
.astseq2mtree(astseq
[2][2], isfunc
=0):
1046 tree
.AddArg(subtree
)
1048 tree
= self
.astseq2mtree(astseq
[1], isfunc
=0)
1052 if astseq
[0] == symbol
.atom
: # {{{
1053 # only one nontrivial term:
1054 if len(astseq
) == 2:
1055 if astseq
[1][0] == token
.NUMBER
:
1057 # XXX: for evaluation of brackets we will need integers as well
1058 tree
= MathTreeValConst(string
.atof(astseq
[1][1]))
1059 elif astseq
[1][0] == token
.NAME
:
1063 for funcclass
in self
.MathTreeFuncs
:
1064 func
= funcclass() # ist das guenstig, da jedesmal eine Instanz zu erzeugen?
1065 # doofe Frage, nein! <wobsta>
1066 if func
.name
== astseq
[1][1]:
1068 # an unknown function
1069 tree
= MathTreeFuncExtern()
1070 tree
.SetName(astseq
[1][1])
1072 # 3. a named constant
1073 for const
in MathConst
.keys():
1074 # XXX: change to self.MathConstants
1075 if const
== astseq
[1][1]:
1076 return MathTreeValConst(MathConst
[const
])
1078 return MathTreeValVar(astseq
[1][1])
1079 elif len(astseq
) == 4:
1080 # parentheses or brackets for structuring an atom
1081 if (astseq
[1][0] == token
.LPAR
and astseq
[3][0] == token
.RPAR
) or \
1082 (astseq
[1][0] == token
.LSQB
and astseq
[3][0] == token
.RSQB
):
1083 tree
= self
.astseq2mtree(astseq
[2], isfunc
=isfunc
)
1085 raise Exception("symbol.atom with unknown number of arguments")
1088 if astseq
[0] == symbol
.arglist
: # {{{
1090 for arg
in astseq
[1:]:
1091 if arg
[0] == token
.COMMA
:
1093 elif arg
[0] == symbol
.argument
:
1094 treelist
.append(self
.astseq2mtree(arg
, isfunc
=isfunc
))
1095 return treelist
# }}}
1097 if astseq
[0] == symbol
.testlist
: # {{{
1099 for arg
in astseq
[1:]:
1100 if arg
[0] == token
.COMMA
:
1102 elif arg
[0] == symbol
.test
:
1103 treelist
.append(self
.astseq2mtree(arg
, isfunc
=isfunc
))
1104 if len(treelist
) == 1: return treelist
[0]
1105 else: return treelist
# }}}
1107 return self
.astseq2mtree(astseq
[1], isfunc
=isfunc
)