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 InitByAST(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\.])"))
837 #Tree = MathTreeFunc1Neg()
838 Tree
= MathTreeOpSub(MathTreeValConst(0)) # XXX quick workaround
840 i
= arg
.MatchStr("(")
843 self
.ParseMathTree(arg
)
844 raise RightParenthesisExpectedMathTreeParseError(arg
, Tree
)
845 except RightParenthesisFoundMathTreeParseError
, e
:
846 if isinstance(e
.MathTree
, MathTreeOp
):
847 e
.MathTree
.ParenthesisBarrier
= 1
849 SubTree
= Tree
# XXX: four lines code dublication
850 while isinstance(SubTree
, MathTreeOp
) and len(SubTree
.Args
) == 2:
851 SubTree
= SubTree
.Args
[1]
852 SubTree
.AddArg(e
.MathTree
)
856 for FuncClass
in self
.MathTreeFuncs
:
858 if Func
.InitByParser(arg
):
860 SubTree
= Tree
# XXX: four lines code dublication
861 while isinstance(SubTree
, MathTreeOp
) and len(SubTree
.Args
) == 2:
862 SubTree
= SubTree
.Args
[1]
868 self
.ParseMathTree(arg
)
869 raise RightParenthesisExpectedMathTreeParseError(arg
, Tree
)
870 except CommaFoundMathTreeParseError
, e
:
872 Func
.AddArg(e
.MathTree
, NotLast
=1)
873 except ArgCountError
:
874 raise RightParenthesisExpectedMathTreeParseError(arg
, Tree
)
876 except RightParenthesisFoundMathTreeParseError
, e
:
878 Func
.AddArg(e
.MathTree
, Last
=1)
879 except ArgCountError
:
880 raise CommaExpectedMathTreeParseError(arg
, Tree
)
884 FuncExtern
= MathTreeFuncExtern()
885 if FuncExtern
.InitByParser(arg
):
887 SubTree
= Tree
# XXX: four lines code dublication
888 while isinstance(SubTree
, MathTreeOp
) and len(SubTree
.Args
) == 2:
889 SubTree
= SubTree
.Args
[1]
890 SubTree
.AddArg(FuncExtern
)
895 self
.ParseMathTree(arg
)
896 raise RightParenthesisExpectedMathTreeParseError(arg
, Tree
)
897 except CommaFoundMathTreeParseError
, e
:
898 FuncExtern
.AddArg(e
.MathTree
)
900 except RightParenthesisFoundMathTreeParseError
, e
:
901 FuncExtern
.AddArg(e
.MathTree
)
904 for ValClass
in self
.MathTreeVals
:
906 if Val
.InitByParser(arg
):
908 SubTree
= Tree
# XXX: four lines code dublication
909 while isinstance(SubTree
, MathTreeOp
) and len(SubTree
.Args
) == 2:
910 SubTree
= SubTree
.Args
[1]
916 raise OperandExpectedMathTreeParseError(arg
, Tree
)
919 i
= arg
.MatchStr(")")
921 raise RightParenthesisFoundMathTreeParseError(arg
, Tree
)
922 i
= arg
.MatchStr(",")
924 raise CommaFoundMathTreeParseError(arg
, Tree
)
925 for OpClass
in self
.MathTreeOps
:
927 if Op
.InitByParser(arg
):
930 while isinstance(SubTree
, MathTreeOp
) and\
931 Op
.level
> SubTree
.level
and\
932 not SubTree
.ParenthesisBarrier
:
933 SubTreeRoot
= SubTree
934 SubTree
= SubTree
.Args
[1]
937 SubTreeRoot
.Args
[1] = Op
943 raise OperatorExpectedMathTreeParseError(arg
, Tree
)
946 def astseq2mtree(self
, astseq
):
949 # astseq has to be a sequence!
951 if astseq
[0] == symbol
.arith_expr
: # {{{
953 # 1. arith_expr "PLUS" term
954 if astseq
[-2][0] == token
.PLUS
:
955 tree
= MathTreeOpAdd(
956 self
.astseq2mtree(astseq
[:-2]),
957 self
.astseq2mtree(astseq
[-1]))
958 # 2. arith_expr "MINUS" term
959 elif astseq
[-2][0] == token
.MINUS
:
960 tree
= MathTreeOpSub(
961 self
.astseq2mtree(astseq
[:-2]),
962 self
.astseq2mtree(astseq
[-1]))
967 tree
= self
.astseq2mtree(astseq
[1])
970 if astseq
[0] == symbol
.term
: # {{{
972 # 1. term "STAR" factor
973 if astseq
[-2][0] == token
.STAR
:
974 tree
= MathTreeOpMul(
975 self
.astseq2mtree(astseq
[:-2]),
976 self
.astseq2mtree(astseq
[-1]))
977 # 2. term "SLASH" factor
978 elif astseq
[-2][0] == token
.SLASH
:
979 tree
= MathTreeOpDiv(
980 self
.astseq2mtree(astseq
[:-2]),
981 self
.astseq2mtree(astseq
[-1]))
986 tree
= self
.astseq2mtree(astseq
[1])
989 if astseq
[0] == symbol
.factor
: # {{{
992 if astseq
[1][0] == token
.PLUS
:
993 tree
= self
.astseq2mtree(astseq
[2])
995 elif astseq
[1][0] == token
.MINUS
:
996 tree
= MathTreeFunc1Neg(self
.astseq2mtree(astseq
[2]))
998 raise Exception("unknown factor")
999 elif len(astseq
) == 2:
1001 tree
= self
.astseq2mtree(astseq
[1])
1003 raise Exception("wrong length of factor")
1006 if astseq
[0] == symbol
.power
: # {{{
1008 # 1. "DOUBLESTAR" factor
1009 if astseq
[-2][0] == token
.DOUBLESTAR
:
1010 tree
= MathTreeOpPow(
1011 self
.astseq2mtree(astseq
[:-2]),
1012 self
.astseq2mtree(astseq
[-1]))
1016 # 2. atom + [trailer]
1017 if len(astseq
) == 3:
1018 # we have a function call atom + "LPAR" + argumentlist + "RPAR"
1019 if astseq
[2][0] != symbol
.trailer
or \
1020 astseq
[2][1][0] != token
.LPAR
or \
1021 astseq
[2][2][0] != symbol
.argumentlist
or \
1022 astseq
[2][3][0] != token
.RPAR
:
1023 raise Exception("wrong function call")
1024 tree
= self
.astseq2mtree(astseq
[1])
1025 tree
.AddArg(self
.astseq2mtree(astseq
[2]))
1027 tree
= self
.astseq2mtree(astseq
[1])
1031 if astseq
[0] == symbol
.atom
: # {{{
1032 # only one nontrivial term:
1033 if len(astseq
) == 2:
1034 if astseq
[1][0] == token
.NUMBER
:
1036 # XXX: for evaluation of brackets we will need integers as well
1037 tree
= MathTreeValConst(string
.atof(astseq
[1][1]))
1038 elif astseq
[1][0] == token
.NAME
:
1039 # 2. a known function
1040 for funcclass
in self
.MathTreeFuncs
:
1041 func
= funcclass() # ist das guenstig, da jedesmal eine Instanz zu erzeugen?
1042 if func
.name
== astseq
[1][1]:
1044 # 3. a named constant
1045 for const
in MathConst
.keys():
1046 if const
== astseq
[1][1]:
1047 return MathTreeValConst(MathConst
[const
])
1049 tree
= MathTreeValVar(astseq
[1][1])
1051 elif len(astseq
) == 4:
1052 # parentheses or brackets for structuring an atom
1053 if (astseq
[1][0] == token
.LPAR
and astseq
[3][0] == token
.RPAR
) or \
1054 (astseq
[1][0] == token
.LSQB
and astseq
[3][0] == token
.RSQB
):
1055 tree
= self
.astseq2mtree(astseq
[2])
1058 if astseq
[0] == symbol
.trailer
: # {{{
1059 if astseq
[1][0] == token
.LPAR
:
1060 if astseq
[3][0] != token
.RPAR
:
1061 raise Exception("too strange expressions within parentheses")
1062 return self
.astseq2mtree(astseq
[2])
1065 return self
.astseq2mtree(astseq
[1])