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
27 import parser
as pythonparser
32 def __init__(self
, StrToParse
, Pos
= 0):
33 self
.StrToParse
= StrToParse
37 return "ParseStr('" + self
.StrToParse
+ "', " + str(self
.Pos
) + ")"
39 def __str__(self
, Indent
= ""):
41 for i
in range(self
.Pos
):
42 WhiteSpaces
= WhiteSpaces
+ " "
43 return Indent
+ self
.StrToParse
+ "\n" + Indent
+ WhiteSpaces
+ "^"
45 def NextNonWhiteSpace(self
, i
= None):
48 while self
.StrToParse
[i
] in string
.whitespace
:
52 def MatchStr(self
, Str
):
54 i
= self
.NextNonWhiteSpace()
55 if self
.StrToParse
[i
: i
+ len(Str
)] == Str
:
56 self
.Pos
= i
+ len(Str
)
61 def MatchStrParenthesis(self
, Str
):
63 i
= self
.NextNonWhiteSpace()
64 if self
.StrToParse
[i
: i
+ len(Str
)] == Str
:
66 i
= self
.NextNonWhiteSpace(i
)
67 if self
.StrToParse
[i
: i
+ 1] == "(":
73 def MatchPattern(self
, Pat
):
75 i
= self
.NextNonWhiteSpace()
76 Match
= Pat
.match(self
.StrToParse
[i
:])
78 self
.Pos
= i
+ Match
.end()
85 self
.NextNonWhiteSpace()
91 class ArgCountError(Exception): pass
92 class DerivativeError(Exception): pass
96 def __init__(self
, ArgCount
, *Args
):
97 self
.ArgCount
= ArgCount
102 def __repr__(self
, depth
= 0):
105 for i
in range(depth
):
106 indent
= indent
+ SingleIndent
107 result
= indent
+ self
.__class
__.__name
__ + "(\n"
108 for SubTree
in self
.Args
:
109 if isinstance(SubTree
, MathTree
):
110 result
= result
+ SubTree
.__repr
__(depth
+ 1)
112 result
= result
+ indent
+ SingleIndent
+ repr(SubTree
)
114 if SubTree
!= self
.Args
[-1]:
115 result
= result
+ ",\n"
117 result
= result
+ ")"
120 def AddArg(self
, Arg
, Last
=0, NotLast
=0):
121 if len(self
.Args
) == self
.ArgCount
:
123 self
.Args
.append(Arg
)
124 if NotLast
and len(self
.Args
) == self
.ArgCount
:
126 if Last
and len(self
.Args
) != self
.ArgCount
:
129 def DependOn(self
, arg
):
130 for Arg
in self
.Args
:
131 if Arg
.DependOn(arg
):
135 def Derivative(self
, arg
):
136 if not self
.DependOn(arg
):
137 return MathTreeValConst(0.0)
138 return self
.CalcDerivative(arg
)
142 for Arg
in self
.Args
:
143 newlist
= Arg
.VarList()
150 class MathTreeVal(MathTree
):
152 def __init__(self
, *args
):
153 MathTree
.__init
__(self
, 1, *args
)
156 return str(self
.Args
[0])
159 ConstPattern
= re
.compile(r
"-?\d*((\d\.?)|(\.?\d))\d*(E[+-]?\d+)?",
162 class MathTreeValConst(MathTreeVal
):
164 def InitByParser(self
, arg
):
165 Match
= arg
.MatchPattern(ConstPattern
)
167 self
.AddArg(string
.atof(Match
))
170 def CalcDerivative(self
, arg
):
171 raise DerivativeError("expression doesn't depend on \"%s\"" % arg
)
173 def Derivative(self
, arg
):
174 return MathTreeValConst(0.0)
176 def DependOn(self
, arg
):
182 def Calc(HIDDEN_self
, **args
):
183 return HIDDEN_self
.Args
[0]
186 VarPattern
= re
.compile(r
"[a-z_][a-z0-9_]*", re
.IGNORECASE
)
187 MathConst
= {"pi": math
.pi
, "e": math
.e
}
189 class MathTreeValVar(MathTreeVal
):
191 def InitByParser(self
, arg
):
192 Match
= arg
.MatchPattern(VarPattern
)
197 def CalcDerivative(self
, arg
):
198 if arg
!= self
.Args
[0]:
199 raise DerivativeError("expression doesn't depend on \"%s\"" % arg
)
200 return MathTreeValConst(1.0)
202 def DependOn(self
, arg
):
203 if arg
== self
.Args
[0]:
208 if self
.Args
[0] in MathConst
.keys():
210 return [self
.Args
[0]]
212 def Calc(HIDDEN_self
, **args
):
213 if HIDDEN_self
.Args
[0] in args
.keys():
214 return float(args
[HIDDEN_self
.Args
[0]])
215 return MathConst
[HIDDEN_self
.Args
[0]]
218 class MathTreeFunc(MathTree
):
220 def __init__(self
, name
, ArgCount
, *args
):
222 MathTree
.__init
__(self
, ArgCount
, *args
)
224 def InitByParser(self
, arg
):
225 return arg
.MatchStrParenthesis(self
.name
)
229 for SubTree
in self
.Args
:
230 args
= args
+ str(SubTree
)
231 if SubTree
!= self
.Args
[-1]:
233 return self
.name
+ "(" + args
+ ")"
236 class MathTreeFunc1(MathTreeFunc
):
238 def __init__(self
, name
, *args
):
239 MathTreeFunc
.__init
__(self
, name
, 1, *args
)
242 class MathTreeFunc1Neg(MathTreeFunc1
):
244 def __init__(self
, *args
):
245 MathTreeFunc1
.__init__(self
, "neg", *args
)
247 def CalcDerivative(self
, arg
):
248 return MathTreeFunc1Neg(self
.Args
[0].CalcDerivative(arg
))
250 def Calc(HIDDEN_self
, **args
):
251 return -HIDDEN_self
.Args
[0].Calc(**args
)
254 class MathTreeFunc1Abs(MathTreeFunc1
):
256 def __init__(self
, *args
):
257 MathTreeFunc1
.__init__(self
, "abs", *args
)
259 def CalcDerivative(self
, arg
):
260 return MathTreeOpMul(
261 MathTreeFunc1Sgn(self
.Args
[0]),
262 self
.Args
[0].CalcDerivative(arg
))
264 def Calc(HIDDEN_self
, **args
):
265 return abs(HIDDEN_self
.Args
[0].Calc(**args
))
268 class MathTreeFunc1Sgn(MathTreeFunc1
):
270 def __init__(self
, *args
):
271 MathTreeFunc1
.__init__(self
, "sgn", *args
)
273 def CalcDerivative(self
, arg
):
274 return MathTreeValConst(0.0)
276 def Calc(HIDDEN_self
, **args
):
277 if HIDDEN_self
.Args
[0].Calc(**args
) < 0:
282 class MathTreeFunc1Sqrt(MathTreeFunc1
):
284 def __init__(self
, *args
):
285 MathTreeFunc1
.__init__(self
, "sqrt", *args
)
287 def CalcDerivative(self
, arg
):
288 return MathTreeOpMul(
290 MathTreeValConst(0.5),
292 self
.Args
[0].CalcDerivative(arg
))
294 def Calc(HIDDEN_self
, **args
):
295 return math
.sqrt(HIDDEN_self
.Args
[0].Calc(**args
))
298 class MathTreeFunc1Exp(MathTreeFunc1
):
300 def __init__(self
, *args
):
301 MathTreeFunc1
.__init__(self
, "exp", *args
)
303 def CalcDerivative(self
, arg
):
304 return MathTreeOpMul(self
, self
.Args
[0].CalcDerivative(arg
))
306 def Calc(HIDDEN_self
, **args
):
307 return math
.exp(HIDDEN_self
.Args
[0].Calc(**args
))
310 class MathTreeFunc1Log(MathTreeFunc1
):
312 def __init__(self
, *args
):
313 MathTreeFunc1
.__init__(self
, "log", *args
)
315 def CalcDerivative(self
, arg
):
316 return MathTreeOpDiv(self
.Args
[0].CalcDerivative(arg
), self
.Args
[0])
318 def Calc(HIDDEN_self
, **args
):
319 return math
.log(HIDDEN_self
.Args
[0].Calc(**args
))
322 class MathTreeFunc1Sin(MathTreeFunc1
):
324 def __init__(self
, *args
):
325 MathTreeFunc1
.__init__(self
, "sin", *args
)
327 def CalcDerivative(self
, arg
):
328 return MathTreeOpMul(
329 MathTreeFunc1Cos(self
.Args
[0]),
330 self
.Args
[0].CalcDerivative(arg
))
332 def Calc(HIDDEN_self
, **args
):
333 return math
.sin(HIDDEN_self
.Args
[0].Calc(**args
))
336 class MathTreeFunc1Cos(MathTreeFunc1
):
338 def __init__(self
, *args
):
339 MathTreeFunc1
.__init__(self
, "cos", *args
)
341 def CalcDerivative(self
, arg
):
342 return MathTreeOpMul(
343 MathTreeFunc1Neg(MathTreeFunc1Sin(self
.Args
[0])),
344 self
.Args
[0].CalcDerivative(arg
))
346 def Calc(HIDDEN_self
, **args
):
347 return math
.cos(HIDDEN_self
.Args
[0].Calc(**args
))
350 class MathTreeFunc1Tan(MathTreeFunc1
):
352 def __init__(self
, *args
):
353 MathTreeFunc1
.__init__(self
, "tan", *args
)
355 def CalcDerivative(self
, arg
):
356 return MathTreeOpDiv(
357 self
.Args
[0].CalcDerivative(arg
),
359 MathTreeFunc1Cos(self
.Args
[0]),
360 MathTreeValConst(2.0)))
362 def Calc(HIDDEN_self
, **args
):
363 return math
.tan(HIDDEN_self
.Args
[0].Calc(**args
))
366 class MathTreeFunc1ASin(MathTreeFunc1
):
368 def __init__(self
, *args
):
369 MathTreeFunc1
.__init__(self
, "asin", *args
)
371 def CalcDerivative(self
, arg
):
372 return MathTreeOpDiv(
373 self
.Args
[0].CalcDerivative(arg
),
376 MathTreeValConst(1.0),
379 MathTreeValConst(2.0)))))
381 def Calc(HIDDEN_self
, **args
):
382 return math
.asin(HIDDEN_self
.Args
[0].Calc(**args
))
385 class MathTreeFunc1ACos(MathTreeFunc1
):
387 def __init__(self
, *args
):
388 MathTreeFunc1
.__init__(self
, "acos", *args
)
390 def CalcDerivate(self
, arg
):
391 return MathTreeOpDiv(
392 MathTreeFunc1Neg(self
.Args
[0].CalcDerivative(arg
)),
395 MathTreeValConst(1.0),
398 MathTreeValConst(2.0)))))
400 def Calc(HIDDEN_self
, **args
):
401 return math
.acos(HIDDEN_self
.Args
[0].Calc(**args
))
404 class MathTreeFunc1ATan(MathTreeFunc1
):
406 def __init__(self
, *args
):
407 MathTreeFunc1
.__init__(self
, "atan", *args
)
409 def CalcDerivate(self
, arg
):
410 return MathTreeOpDiv(
411 self
.Args
[0].CalcDerivative(arg
),
413 MathTreeValConst(1.0),
416 MathTreeValConst(2.0))))
418 def Calc(HIDDEN_self
, **args
):
419 return math
.atan(HIDDEN_self
.Args
[0].Calc(**args
))
422 class MathTreeFunc1SinD(MathTreeFunc1
):
424 def __init__(self
, *args
):
425 MathTreeFunc1
.__init__(self
, "sind", *args
)
427 def CalcDerivative(self
, arg
):
428 return MathTreeOpMul(
429 MathTreeFunc1CosD(self
.Args
[0]),
431 MathTreeValConst(math
.pi
/180.0),
432 self
.Args
[0].CalcDerivative(arg
)))
434 def Calc(HIDDEN_self
, **args
):
435 return math
.sin(math
.pi
/180.0*HIDDEN_self
.Args
[0].Calc(**args
))
438 class MathTreeFunc1CosD(MathTreeFunc1
):
440 def __init__(self
, *args
):
441 MathTreeFunc1
.__init__(self
, "cosd", *args
)
443 def CalcDerivative(self
, arg
):
444 return MathTreeOpMul(
445 MathTreeFunc1Neg(MathTreeFunc1Sin(self
.Args
[0])),
447 MathTreeValConst(math
.pi
/180.0),
448 self
.Args
[0].CalcDerivative(arg
)))
450 def Calc(HIDDEN_self
, **args
):
451 return math
.cos(math
.pi
/180.0*HIDDEN_self
.Args
[0].Calc(**args
))
454 class MathTreeFunc1TanD(MathTreeFunc1
):
456 def __init__(self
, *args
):
457 MathTreeFunc1
.__init__(self
, "tand", *args
)
459 def CalcDerivative(self
, arg
):
460 return MathTreeOpDiv(
462 MathTreeValConst(math
.pi
/180.0),
463 self
.Args
[0].CalcDerivative(arg
)),
465 MathTreeFunc1Cos(self
.Args
[0]),
466 MathTreeValConst(2.0)))
468 def Calc(HIDDEN_self
, **args
):
469 return math
.tan(math
.pi
/180.0*HIDDEN_self
.Args
[0].Calc(**args
))
472 class MathTreeFunc1ASinD(MathTreeFunc1
):
474 def __init__(self
, *args
):
475 MathTreeFunc1
.__init__(self
, "asind", *args
)
477 def CalcDerivative(self
, arg
):
478 return MathTreeOpDiv(
480 MathTreeValConst(180.0/math
.pi
),
481 self
.Args
[0].CalcDerivative(arg
)),
484 MathTreeValConst(1.0),
487 MathTreeValConst(2.0)))))
489 def Calc(HIDDEN_self
, **args
):
490 return 180.0/math
.pi
*math
.asin(HIDDEN_self
.Args
[0].Calc(**args
))
493 class MathTreeFunc1ACosD(MathTreeFunc1
):
495 def __init__(self
, *args
):
496 MathTreeFunc1
.__init__(self
, "acosd", *args
)
498 def CalcDerivate(self
, arg
):
499 return MathTreeOpDiv(
502 MathTreeValConst(180.0/math
.pi
),
503 self
.Args
[0].CalcDerivative(arg
))),
506 MathTreeValConst(1.0),
509 MathTreeValConst(2.0)))))
511 def Calc(HIDDEN_self
, **args
):
512 return 180.0/math
.pi
*math
.acos(HIDDEN_self
.Args
[0].Calc(**args
))
515 class MathTreeFunc1ATanD(MathTreeFunc1
):
517 def __init__(self
, *args
):
518 MathTreeFunc1
.__init__(self
, "atand", *args
)
520 def CalcDerivate(self
, arg
):
521 return MathTreeOpDiv(
523 MathTreeValConst(180.0/math
.pi
),
524 self
.Args
[0].CalcDerivative(arg
)),
526 MathTreeValConst(1.0),
529 MathTreeValConst(2.0))))
531 def Calc(HIDDEN_self
, **args
):
532 return 180.0/math
.pi
*math
.atan(HIDDEN_self
.Args
[0].Calc(**args
))
535 class MathTreeFunc2(MathTreeFunc
):
537 def __init__(self
, name
, *args
):
538 MathTreeFunc
.__init
__(self
, name
, 2, *args
)
541 class MathTreeFunc2Norm(MathTreeFunc2
):
543 def __init__(self
, *args
):
544 MathTreeFunc2
.__init__(self
, "norm", *args
)
546 def CalcDerivative(self
, arg
):
547 if self
.Args
[0].DependOn(arg
):
548 if self
.Args
[1].DependOn(arg
):
549 return MathTreeOpDiv(
553 self
.Args
[0].CalcDerivative(arg
)),
556 self
.Args
[1].CalcDerivative(arg
))),
559 return MathTreeOpDiv(
562 self
.Args
[0].CalcDerivative(arg
)),
565 if self
.Args
[1].DependOn(arg
):
566 return MathTreeOpDiv(
569 self
.Args
[1].CalcDerivative(arg
)),
572 def Calc(HIDDEN_self
, **args
):
573 return math
.sqrt(HIDDEN_self
.Args
[0].Calc(**args
) ** 2 +
574 HIDDEN_self
.Args
[1].Calc(**args
) ** 2)
577 FuncExternPattern
= re
.compile(r
"([a-z_][a-z0-9_]*)\s*\(", re
.IGNORECASE
)
579 class MathTreeFuncExtern(MathTreeFunc
):
581 def __init__(self
, *args
):
582 MathTreeFunc
.__init
__(self
, None, -1, *args
)
584 def InitByParser(self
, arg
):
585 Match
= arg
.MatchPattern(FuncExternPattern
)
587 self
.name
= Match
[:-1].strip()
590 def SetName(self
, arg
):
591 self
.name
= arg
.strip()
594 def Calc(HIDDEN_self
, **args
):
595 return args
[HIDDEN_self
.name
](*[arg
.Calc(**args
) for arg
in HIDDEN_self
.Args
])
598 class MathTreeOp(MathTree
):
600 def __init__(self
, level
, symbol
, *args
):
601 self
.ParenthesisBarrier
= 0
604 MathTree
.__init
__(self
, 2, *args
)
608 if isinstance(self
.Args
[0], MathTreeOp
) and\
609 self
.level
> self
.Args
[0].level
:
610 result
= result
+ "(" + str(self
.Args
[0]) + ")"
612 result
= result
+ str(self
.Args
[0])
613 result
= result
+ self
.symbol
614 if isinstance(self
.Args
[1], MathTreeOp
) and\
615 self
.level
>= self
.Args
[1].level
:
616 result
= result
+ "(" + str(self
.Args
[1]) + ")"
618 result
= result
+ str(self
.Args
[1])
621 def InitByParser(self
, arg
):
622 return arg
.MatchStr(self
.symbol
)
625 class MathTreeOpAdd(MathTreeOp
):
627 def __init__(self
, *args
):
628 MathTreeOp
.__init
__(self
, 1, "+", *args
)
630 def CalcDerivative(self
, arg
):
631 if self
.Args
[0].DependOn(arg
):
632 if self
.Args
[1].DependOn(arg
):
633 return MathTreeOpAdd(
634 self
.Args
[0].CalcDerivative(arg
),
635 self
.Args
[1].CalcDerivative(arg
))
637 return self
.Args
[0].CalcDerivative(arg
)
639 if self
.Args
[1].DependOn(arg
):
640 return self
.Args
[1].CalcDerivative(arg
)
642 def Calc(HIDDEN_self
, **args
):
643 return HIDDEN_self
.Args
[0].Calc(**args
) + HIDDEN_self
.Args
[1].Calc(**args
)
646 class MathTreeOpSub(MathTreeOp
):
648 def __init__(self
, *args
):
649 MathTreeOp
.__init
__(self
, 1, "-", *args
)
651 def CalcDerivative(self
, arg
):
652 if self
.Args
[0].DependOn(arg
):
653 if self
.Args
[1].DependOn(arg
):
654 return MathTreeOpSub(
655 self
.Args
[0].CalcDerivative(arg
),
656 self
.Args
[1].CalcDerivative(arg
))
658 return self
.Args
[0].CalcDerivative(arg
)
660 if self
.Args
[1].DependOn(arg
):
661 return MathTreeFunc1Neg(self
.Args
[1].CalcDerivative(arg
))
663 def Calc(HIDDEN_self
, **args
):
664 return HIDDEN_self
.Args
[0].Calc(**args
) - HIDDEN_self
.Args
[1].Calc(**args
)
667 class MathTreeOpMul(MathTreeOp
):
669 def __init__(self
, *args
):
670 MathTreeOp
.__init
__(self
, 2, "*", *args
)
672 def CalcDerivative(self
, arg
):
673 if self
.Args
[0].DependOn(arg
):
674 if self
.Args
[1].DependOn(arg
):
675 return MathTreeOpAdd(
678 self
.Args
[1].CalcDerivative(arg
)),
680 self
.Args
[0].CalcDerivative(arg
),
683 return MathTreeOpMul(
684 self
.Args
[0].CalcDerivative(arg
),
687 if self
.Args
[1].DependOn(arg
):
688 return MathTreeOpMul(
690 self
.Args
[1].CalcDerivative(arg
))
692 def Calc(HIDDEN_self
, **args
):
693 return HIDDEN_self
.Args
[0].Calc(**args
) * HIDDEN_self
.Args
[1].Calc(**args
)
696 class MathTreeOpDiv(MathTreeOp
):
698 def __init__(self
, *args
):
699 MathTreeOp
.__init
__(self
, 2, "/", *args
)
701 def CalcDerivative(self
, arg
):
702 if self
.Args
[0].DependOn(arg
):
703 if self
.Args
[1].DependOn(arg
):
704 return MathTreeOpMul(
707 self
.Args
[0].CalcDerivative(arg
),
711 self
.Args
[1].CalcDerivative(arg
))),
714 MathTreeValConst(-2.0)))
716 return MathTreeOpDiv(
717 self
.Args
[0].CalcDerivative(arg
),
720 if self
.Args
[1].DependOn(arg
):
721 return MathTreeOpMul(
723 MathTreeFunc1Neg(self
.Args
[0]),
726 MathTreeValConst(-2.0))),
727 self
.Args
[1].CalcDerivative(arg
))
729 def Calc(HIDDEN_self
, **args
):
730 return HIDDEN_self
.Args
[0].Calc(**args
) / HIDDEN_self
.Args
[1].Calc(**args
)
733 class MathTreeOpPow(MathTreeOp
):
735 def __init__(self
, *args
):
736 MathTreeOp
.__init
__(self
, 3, "^", *args
)
738 def InitByParser(self
, arg
):
739 pos
= arg
.MatchStr("^")
743 return arg
.MatchStr("**")
745 def CalcDerivative(self
, arg
):
746 if self
.Args
[0].DependOn(arg
):
747 if self
.Args
[1].DependOn(arg
):
748 return MathTreeOpMul(
754 MathTreeFunc1Log(self
.Args
[0]),
755 self
.Args
[1].CalcDerivative(arg
)),
759 self
.Args
[0].CalcDerivative(arg
),
762 return MathTreeOpMul(
769 MathTreeValConst(1.0))),
770 self
.Args
[0].CalcDerivative(arg
)))
772 if self
.Args
[1].DependOn(arg
):
773 return MathTreeOpMul(
778 MathTreeFunc1Log(self
.Args
[0])),
779 self
.Args
[1].CalcDerivative(arg
))
781 def Calc(HIDDEN_self
, **args
):
782 return HIDDEN_self
.Args
[0].Calc(**args
) ** HIDDEN_self
.Args
[1].Calc(**args
)
786 class UndefinedMathTreeParseError(Exception):
788 def __init__(self
, ParseStr
, MathTree
):
789 self
.ParseStr
= ParseStr
790 self
.MathTree
= MathTree
793 return "\n" + str(self
.ParseStr
)
796 class RightParenthesisExpectedMathTreeParseError(UndefinedMathTreeParseError
): pass
797 class RightParenthesisFoundMathTreeParseError(UndefinedMathTreeParseError
): pass
798 class CommaExpectedMathTreeParseError(UndefinedMathTreeParseError
): pass
799 class CommaFoundMathTreeParseError(UndefinedMathTreeParseError
): pass
800 class OperatorExpectedMathTreeParseError(UndefinedMathTreeParseError
): pass
801 class OperandExpectedMathTreeParseError(UndefinedMathTreeParseError
): pass
804 DefaultMathTreeOps
= (MathTreeOpPow
, MathTreeOpDiv
, MathTreeOpMul
, MathTreeOpSub
, MathTreeOpAdd
)
805 DefaultMathTreeFuncs
= (MathTreeFunc1Neg
, MathTreeFunc1Abs
, MathTreeFunc1Sgn
, MathTreeFunc1Sqrt
,
806 MathTreeFunc1Exp
, MathTreeFunc1Log
,
807 MathTreeFunc1Sin
, MathTreeFunc1Cos
, MathTreeFunc1Tan
,
808 MathTreeFunc1ASin
, MathTreeFunc1ACos
, MathTreeFunc1ATan
,
809 MathTreeFunc1SinD
, MathTreeFunc1CosD
, MathTreeFunc1TanD
,
810 MathTreeFunc1ASinD
, MathTreeFunc1ACosD
, MathTreeFunc1ATanD
,
813 DefaultMathTreeVals
= (MathTreeValConst
, MathTreeValVar
)
817 def __init__(self
, MathTreeOps
=DefaultMathTreeOps
,
818 MathTreeFuncs
=DefaultMathTreeFuncs
,
819 MathTreeVals
=DefaultMathTreeVals
):
820 self
.MathTreeOps
= MathTreeOps
821 self
.MathTreeFuncs
= MathTreeFuncs
822 self
.MathTreeVals
= MathTreeVals
824 # def parse(self, str):
825 # return self.ParseMathTree(ParseStr(str))
826 def parse(self
, str):
827 # prepare raw string:
829 thestr
= re
.sub("\^","**", str) # to be removed <joergl>
830 thestr
= re
.sub("\$","_col_", str)
831 return self
.astseq2mtree(pythonparser
.expr(thestr
).totuple())
833 def ParseMathTree(self
, arg
):
835 #Match = arg.MatchPattern(re.compile(r"\s*-(?![0-9\.])"))
836 Match
= arg
.MatchPattern(re
.compile(r
"\s*-")) # XXX another quick workaround
838 #Tree = MathTreeFunc1Neg()
839 Tree
= MathTreeOpSub(MathTreeValConst(0)) # XXX quick workaround
841 i
= arg
.MatchStr("(")
844 self
.ParseMathTree(arg
)
845 raise RightParenthesisExpectedMathTreeParseError(arg
, Tree
)
846 except RightParenthesisFoundMathTreeParseError
, e
:
847 if isinstance(e
.MathTree
, MathTreeOp
):
848 e
.MathTree
.ParenthesisBarrier
= 1
850 SubTree
= Tree
# XXX: four lines code dublication
851 while isinstance(SubTree
, MathTreeOp
) and len(SubTree
.Args
) == 2:
852 SubTree
= SubTree
.Args
[1]
853 SubTree
.AddArg(e
.MathTree
)
857 for FuncClass
in self
.MathTreeFuncs
:
859 if Func
.InitByParser(arg
):
861 SubTree
= Tree
# XXX: four lines code dublication
862 while isinstance(SubTree
, MathTreeOp
) and len(SubTree
.Args
) == 2:
863 SubTree
= SubTree
.Args
[1]
869 self
.ParseMathTree(arg
)
870 raise RightParenthesisExpectedMathTreeParseError(arg
, Tree
)
871 except CommaFoundMathTreeParseError
, e
:
873 Func
.AddArg(e
.MathTree
, NotLast
=1)
874 except ArgCountError
:
875 raise RightParenthesisExpectedMathTreeParseError(arg
, Tree
)
877 except RightParenthesisFoundMathTreeParseError
, e
:
879 Func
.AddArg(e
.MathTree
, Last
=1)
880 except ArgCountError
:
881 raise CommaExpectedMathTreeParseError(arg
, Tree
)
885 FuncExtern
= MathTreeFuncExtern()
886 if FuncExtern
.InitByParser(arg
):
888 SubTree
= Tree
# XXX: four lines code dublication
889 while isinstance(SubTree
, MathTreeOp
) and len(SubTree
.Args
) == 2:
890 SubTree
= SubTree
.Args
[1]
891 SubTree
.AddArg(FuncExtern
)
896 self
.ParseMathTree(arg
)
897 raise RightParenthesisExpectedMathTreeParseError(arg
, Tree
)
898 except CommaFoundMathTreeParseError
, e
:
899 FuncExtern
.AddArg(e
.MathTree
)
901 except RightParenthesisFoundMathTreeParseError
, e
:
902 FuncExtern
.AddArg(e
.MathTree
)
905 for ValClass
in self
.MathTreeVals
:
907 if Val
.InitByParser(arg
):
909 SubTree
= Tree
# XXX: four lines code dublication
910 while isinstance(SubTree
, MathTreeOp
) and len(SubTree
.Args
) == 2:
911 SubTree
= SubTree
.Args
[1]
917 raise OperandExpectedMathTreeParseError(arg
, Tree
)
920 i
= arg
.MatchStr(")")
922 raise RightParenthesisFoundMathTreeParseError(arg
, Tree
)
923 i
= arg
.MatchStr(",")
925 raise CommaFoundMathTreeParseError(arg
, Tree
)
926 for OpClass
in self
.MathTreeOps
:
928 if Op
.InitByParser(arg
):
931 while isinstance(SubTree
, MathTreeOp
) and\
932 Op
.level
> SubTree
.level
and\
933 not SubTree
.ParenthesisBarrier
:
934 SubTreeRoot
= SubTree
935 SubTree
= SubTree
.Args
[1]
938 SubTreeRoot
.Args
[1] = Op
944 raise OperatorExpectedMathTreeParseError(arg
, Tree
)
947 def astseq2mtree(self
, astseq
, isfunc
=0):
948 # astseq has to be a sequence!
951 if token
.ISTERMINAL(astseq
[0]):
954 if astseq
[0] == symbol
.arith_expr
: # {{{
956 # 1. arith_expr "PLUS" term
957 if astseq
[-2][0] == token
.PLUS
:
958 tree
= MathTreeOpAdd(
959 self
.astseq2mtree(astseq
[:-2], isfunc
=isfunc
),
960 self
.astseq2mtree(astseq
[-1], isfunc
=isfunc
))
961 # 2. arith_expr "MINUS" term
962 elif astseq
[-2][0] == token
.MINUS
:
963 tree
= MathTreeOpSub(
964 self
.astseq2mtree(astseq
[:-2], isfunc
=isfunc
),
965 self
.astseq2mtree(astseq
[-1], isfunc
=isfunc
))
970 tree
= self
.astseq2mtree(astseq
[1], isfunc
=isfunc
)
973 if astseq
[0] == symbol
.term
: # {{{
975 # 1. term "STAR" factor
976 if astseq
[-2][0] == token
.STAR
:
977 tree
= MathTreeOpMul(
978 self
.astseq2mtree(astseq
[:-2], isfunc
=isfunc
),
979 self
.astseq2mtree(astseq
[-1], isfunc
=isfunc
))
980 # 2. term "SLASH" factor
981 elif astseq
[-2][0] == token
.SLASH
:
982 tree
= MathTreeOpDiv(
983 self
.astseq2mtree(astseq
[:-2], isfunc
=isfunc
),
984 self
.astseq2mtree(astseq
[-1], isfunc
=isfunc
))
989 tree
= self
.astseq2mtree(astseq
[1], isfunc
=isfunc
)
992 if astseq
[0] == symbol
.factor
: # {{{
995 if astseq
[1][0] == token
.PLUS
:
996 tree
= self
.astseq2mtree(astseq
[2], isfunc
=isfunc
)
998 elif astseq
[1][0] == token
.MINUS
:
999 tree
= MathTreeFunc1Neg(self
.astseq2mtree(astseq
[2], isfunc
=isfunc
))
1001 raise Exception("unknown factor")
1002 elif len(astseq
) == 2:
1004 tree
= self
.astseq2mtree(astseq
[1], isfunc
=isfunc
)
1006 raise Exception("wrong length of factor")
1009 if astseq
[0] == symbol
.power
: # {{{
1011 # 1. "DOUBLESTAR" factor
1012 if astseq
[-2][0] == token
.DOUBLESTAR
:
1013 tree
= MathTreeOpPow(
1014 self
.astseq2mtree(astseq
[:-2], isfunc
=isfunc
),
1015 self
.astseq2mtree(astseq
[-1], isfunc
=isfunc
))
1019 # 2. atom + [trailer]
1020 if len(astseq
) == 3:
1021 # we have a function call atom + "LPAR" + argumentlist + "RPAR"
1022 if astseq
[2][0] != symbol
.trailer
or \
1023 astseq
[2][1][0] != token
.LPAR
or \
1024 astseq
[2][2][0] != symbol
.arglist
or \
1025 astseq
[2][3][0] != token
.RPAR
:
1026 raise Exception("wrong function call")
1027 tree
= self
.astseq2mtree(astseq
[1], isfunc
=1)
1028 for subtree
in self
.astseq2mtree(astseq
[2][2], isfunc
=0):
1029 tree
.AddArg(subtree
)
1031 tree
= self
.astseq2mtree(astseq
[1], isfunc
=0)
1035 if astseq
[0] == symbol
.atom
: # {{{
1036 # only one nontrivial term:
1037 if len(astseq
) == 2:
1038 if astseq
[1][0] == token
.NUMBER
:
1040 # XXX: for evaluation of brackets we will need integers as well
1041 tree
= MathTreeValConst(string
.atof(astseq
[1][1]))
1042 elif astseq
[1][0] == token
.NAME
:
1046 for funcclass
in self
.MathTreeFuncs
:
1047 func
= funcclass() # ist das guenstig, da jedesmal eine Instanz zu erzeugen?
1048 if func
.name
== astseq
[1][1]:
1050 # an unknown function
1051 tree
= MathTreeFuncExtern()
1052 tree
.SetName(astseq
[1][1])
1054 # 3. a named constant
1055 for const
in MathConst
.keys():
1056 if const
== astseq
[1][1]:
1057 return MathTreeValConst(MathConst
[const
])
1059 return MathTreeValVar(astseq
[1][1])
1060 elif len(astseq
) == 4:
1061 # parentheses or brackets for structuring an atom
1062 if (astseq
[1][0] == token
.LPAR
and astseq
[3][0] == token
.RPAR
) or \
1063 (astseq
[1][0] == token
.LSQB
and astseq
[3][0] == token
.RSQB
):
1064 tree
= self
.astseq2mtree(astseq
[2], isfunc
=isfunc
)
1067 if astseq
[0] == symbol
.arglist
: # {{{
1069 for arg
in astseq
[1:]:
1070 if arg
[0] == token
.COMMA
:
1072 elif arg
[0] == symbol
.argument
:
1073 treelist
.append(self
.astseq2mtree(arg
, isfunc
=isfunc
))
1074 return treelist
# }}}
1076 return self
.astseq2mtree(astseq
[1], isfunc
=isfunc
)