{
    $ id:                                                       $
    Copyright (c) 2000 by Marco van de Voort(marco@freepascal.org)
     member of the Free Pascal development team

    See the file COPYING.FPC, included in this distribution,
    for details about the copyright. (LGPL)

    Implementation of Infix to parsetree/RPN converter based on principles
    copied from a RPN constant expression evaluator by Trai Tran
    (PD, from SWAG.)

    Parsetree to infix and parsetree to RPN/infix conversion
     by Marco v/d Voort
    OOP interface and vast improvements by Marco v/d Voort


    Modified by JM Biansan:
    - variables names can start by A..Z, _, and can contain A..Z,0..9,_
    - accept real numbers in scientific notation like 1.23e-45
    - right associativity for exponentiation : 2^3^4 is 2^(3^4)
    - priority highest  for exponentiation: -2^2=-4
    - expression can start by minus
    - functions added: log (same as log10), abs, trunc, heav, sign, min, max, inf,
    sup, infe, supe, naninf, nansup, nanin, nanout


    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

 **********************************************************************

Problems:
- -x^12 is -(x^12) or (-x)^12 ? (FIXED: Chose to do it as in FPC)
- No errorhandling. (will be rewritten to use classes and exceptions first)

Original comments:

---------------------------------------------------------------------------
THAI TRAN

I've netmailed you the full-featured version (800 lines!) that will do
Functions, exponentiation, factorials, and has all the bells and whistles,
but I thought you might want to take a look at a simple version so you can
understand the algorithm.

This one only works With +, -, *, /, (, and ).  I wrote it quickly, so it
makes extensive use of global Variables and has no error checking; Use at
your own risk.

Algorithm to convert infix to postfix (RPN) notation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parse through the entire expression getting each token (number, arithmetic
operation, left or right parenthesis).  For each token, if it is:
 1. an operand (number)        Send it to the RPN calculator
 2. a left parenthesis         Push it onto the operation stack
 3. a right parenthesis        Pop operators off stack and send to RPN
                               calculator Until the a left parenthesis is
                               on top of the stack.  Pop it also, but don't
                               send it to the calculator.
 4. an operator                While the stack is not empty, pop operators
                               off the stack and send them to the RPN
                               calculator Until you reach one With a higher
                               precedence than the current operator (Note:
                               a left parenthesis has the least precendence).
                               Then push the current operator onto the stack.

This will convert (4+5)*6/(2-3) to 4 5 + 6 * 2 3 - /

Algorithm For RPN calculator
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Note:  this Uses a different stack from the one described above.

In RPN, if an operand (a number) is entered, it is just pushed onto the
stack.  For binary arithmetic operators (+, -, *, /, and ^), the top two
operands are popped off the stack, operated on, and the result pushed back
onto the stack.  if everything has gone correctly, at the end, the answer
should be at the top of the stack.

Released to Public Domain by Thai Tran (if that matters).
---------------------------------------------------------------------------
MvdV: It does for me. My routines might end up in either FPC or Jedi, and
      anything except LGPL and PD is unacceptable. :-)

Modifications: (starting to get so big that the original is hardly
               recognisable)
- OOP. Mainly to allow symbolic TExpression class to have custom parsers.
- Working with pnode stack instead of reals. Pnodes can be any expression,
   see inteface unit symbolic. (creating a parsetree)
- Support for functions(one or two parameter arguments), which weren't in the
   short Swag version. Most MATH functions are supported.
- Can make a difference between the minus of (-x) and the one in (x-y).
   The first is converted to function minus(x);
- power operator
- Faculty operator
- Conversions back to RPN and infix.
- Removing of excess parentheses.
}

type {Tokens generated by the parser. Anything else is a constant or variable}
 ParseOperation=(padd,psub,pmul,pdvd,ppow,pfacul,pleft,pright,pminus,
                 pabs,psign,pheav,pzero,ptrunc,pceil,pfloor,pcos,psin,ptan,psqr,psqrt,pexp,pln,pinv,
                  pcotan,parcsin,parccos,parctan,psinh,pcosh,ptanh,
                 parcsinh,parccosh,parctanh,plog10,plog,
                 plog2,plnxpi,parctan2,pstep,ppower,phypot,
                 plogn,parg,pmin,pmax,pinf,pinfe,psup,psupe,pnaninf,pnansup,
                 pnanin,pnanout,pnothing);

CONST
 ParserFunctionNamesUpper   : array[padd..pnothing] of string[7]=
                 ('+','-','*','/','^','!','(',')','-',
                 'ABS','SIGN','HEAV','ZERO','TRUNC','CEIL','FLOOR','COS','SIN','TAN','SQR','SQRT','EXP','LN','INV',
                 'COTAN','ARCSIN','ARCCOS','ARCTAN','SINH','COSH','TANH',
                 'ARCSINH','ARCCOSH','ARCTANH','LOG10','LOG',
                 'LOG2','LNXP1','ARCTAN2','STEP','POWER','HYPOT',
                 'LOGN','ARG','MIN','MAX','INF','INFE','SUP','SUPE','NANINF','NANSUP','NANIN','NANOUT','NOTHING');

 {Operator or function-}
 Priority          : array[padd..pnothing] of ArbInt=
                 (1,1,2,2,5,0,0,0,4,
                  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
                  4,4,4,4,4,4,4,
                  4,4,4,4,4,
                  4,4,4,4,4,4,
                  4,4,4,4,4,4,4,4,4,4,4,4,6);

 OppsXlat='+-*/^!()'; {Must match the first entries of ParseOperation.
                         Pos(OppsXlat,c)-1+ord(Padd) is typecast!}

Const
  RPNMax = 20;              { I think you only need 4-8, but just to be safe }
  OpMax  = 25;






Procedure ParserInternalError(const Msg:String;A,B:ArbInt);

VAR S,S2 : String;

begin
 Str(A,S);      {Usually a identification number for the occurance}
 Str(B,S2);     {Usually the value that tripped the IE}
 Raise EParserIE.Create(SParsIE+Msg+S+' '+S2);
end;

function TBaseExprParser.InFixToParseTree(Expr : String;VAR RPNexpr: String):pnode;

Var
  RPNStack   : Array[1..RPNMax] of PNode;        { Stack For RPN calculator }
  RPNTop,
  OpTop      : ArbInt;
  OpStack    : Array[1..OpMax] of ParseOperation;    { Operator stack For conversion }

Procedure RPNPush(Num : PNode); { Add an operand to the top of the RPN stack }
begin
  if RPNTop < RPNMax then
   begin
    Inc(RPNTop);
    RPNStack[RPNTop] := Num;
   end
  else
  RAISE EParserStack.Create(SParseRPNOverflow);
end;

Function RPNPop : pnode;       { Get the operand at the top of the RPN stack }
begin
  if RPNTop > 0 then
   begin
    RPNPop := RPNStack[RPNTop];
    Dec(RPNTop);
   end
  else
    RAISE EParserStack.Create(SParseRPNUnderflow);
end;

Procedure RPNCalc(Token : String);                       { RPN Calculator }
Var
  treal : ArbFloat;
  tint  : ArbInt;       tyty:integer;
  Error : ArbInt;    variable_ok,real_ok,integer_ok:boolean;
begin
   RPNExpr:=RPNExpr+token+' ';
{Added by Jean-Marie Biansan:
variable names can now start by and contain _
Predefined variable: Pi, ECS (électrode calomel saturé), ESM (électrode sulfate mercureux)}
   variable_ok:=(token[1] in  ['A'..'Z','_']);
     for tyty:=2 to length(token) do
     variable_ok:=variable_ok and (token[tyty] in ['A'..'Z','0'..'9','_']);
     if variable_ok then  begin
      if token='PI' then RPNPush(NewConst(Pi)) else
       if token='ECS' then RPNPush(NewConst(0.2444)) else
        if token='ESM' then RPNPush(NewConst(0.6513)) else
       RPNPush(NewVar(Token));
       exit;
       end;


   integer_ok:=true;
   try
     tint:=strtoint(token);
     except
     integer_ok:=false;
      end;
     if integer_ok then   begin
      RpnPush(Newiconst(tint));
      exit;
      end;

 real_ok:=true;
   try
     treal:=strtofloat(token);
     except
     real_ok:=false;
      end;
     if real_ok then   begin
       RPNPush(NewConst(Treal));
      exit;
      end;




       EParserStack.Create(SParseRPNUnderflow);
end;

Procedure RPNOperation(Operation:ParseOperation);
{The workhorse. Creates the tree, and associates a parseoperation with
 the TExpression enumerations. Avoids some ugly (and shaky) typecasts
 between operations like in earlier versions.}

var Temp: pnode;

begin
  RPNExpr:=RPNExpr+ParserFunctionNamesUpper[Operation]+' ';
  Case Operation of                                   { Handle operators }
    padd : RPNPush(newcalc(addo,RPNPop,RPNPop));
    psub : begin
            Temp:=RPNPOP;
            RPNPush(NewCalc(subo,RPNPOP,Temp));
           end;
    pmul : RPNPush(newcalc(mulo,RPNPOP,RPNPop));
    pdvd : begin
            Temp := RPNPop;
            if Temp <> NIL then
             RPNPush(newcalc(dvdo,RPNPop,Temp))
            else
             Raise EDiv0.Create(SParsDiv0);  { Handle divide by 0 error }
           end;
    ppow,ppower : {are only different in parsing x^y and power(x,y)}
           begin
            Temp:=RpnPop;
            RpnPush(NewCalc(powo,RpnPop,Temp));
           end;
  pfacul : RPNPush(NewFunc(faculx,RPNPOP));
    psin : RPNPush(NewFunc(sinx,RPNPop));
    pabs : RPNPush(NewFunc(absx,RPNPop));
    psign : RPNPush(NewFunc(signx,RPNPop));
    pheav : RPNPush(NewFunc(heavx,RPNPop));
    pzero : RPNPush(NewFunc(zerox,RPNPop));
    ptrunc : RPNPush(NewFunc(truncx,RPNPop));
    pceil : RPNPush(NewFunc(ceilx,RPNPop));
    pfloor : RPNPush(NewFunc(floorx,RPNPop));
    pcos : RPNPush(NewFunc(cosx,RPNPop));
    ptan : RPNPush(NewFunc(tanx,RPNPop));
    psqr : RPNPush(NewFunc(sqrx,RPNPop));
    psqrt : RPNPush(NewFunc(sqrtx,RPNPop));
    pexp : RPNPush(NewFunc(expx,RPNPop));
    pln  : RPNPush(NewFunc(lnx,RPNPop));
    pinv : RPNPush(NewFunc(invx,RPNPop));
  Pminus : RPNPush(newFunc(minus,RPNPop));
  pcotan : RPNPush(NewFunc(cotanx,rpnpop));
 parcsin : RPNPush(NewFunc(arcsinx,rpnpop));
 parccos : RPNPush(NewFunc(arccosx,rpnpop));
 parctan : RPNPush(NewFunc(arctanx,rpnpop));
   psinh : RPNPush(NewFunc(sinhx,rpnpop));
   pcosh : RPNPush(NewFunc(coshx,rpnpop));
   ptanh : RPNPush(NewFunc(tanhx,rpnpop));
parcsinh : RPNPush(NewFunc(arcsinhx,rpnpop));
parccosh : RPNPush(NewFunc(arccoshx,rpnpop));
parctanh : RPNPush(NewFunc(arctanhx,rpnpop));
  plog10 : RPNPush(NewFunc(log10x,rpnpop));
   plog : RPNPush(NewFunc(logx,rpnpop));
   plog2 : RPNPush(NewFunc(log2x,rpnpop));
  plnxpi : RPNPush(NewFunc(lnxpix,rpnpop));
parctan2 : begin
            Temp:=RpnPop;
            RpnPush(Newfunc(arctan2x,RpnPop,temp));
           end;
   pstep : begin
            Temp:=RpnPop;
            RpnPush(Newfunc(stepx,RpnPop,temp));
           end;
   phypot: begin
            Temp:=RpnPop;
            RpnPush(Newfunc(hypotx,RpnPop,temp));
           end;
   plogn : begin
            Temp:=RpnPop;
            RpnPush(Newfunc(lognx,RpnPop,Temp));
          end;
    parg : begin
            Temp:=RpnPop;
            RpnPush(Newfunc(argx,RpnPop,Temp));
          end;
    pmin : begin
            Temp:=RpnPop;
            RpnPush(Newfunc(minx,RpnPop,Temp));
          end;
    pmax : begin
            Temp:=RpnPop;
            RpnPush(Newfunc(maxx,RpnPop,Temp));
          end;
    pinf : begin
            Temp:=RpnPop;
            RpnPush(Newfunc(infx,RpnPop,Temp));
          end;
    pinfe : begin
            Temp:=RpnPop;
            RpnPush(Newfunc(infex,RpnPop,Temp));
          end;
    psup : begin
            Temp:=RpnPop;
            RpnPush(Newfunc(supx,RpnPop,Temp));
          end;
    psupe : begin
            Temp:=RpnPop;
            RpnPush(Newfunc(supex,RpnPop,Temp));
          end;
    pnaninf : begin
            Temp:=RpnPop;
            RpnPush(Newfunc(naninfx,RpnPop,Temp));
          end;
    pnansup : begin
            Temp:=RpnPop;
            RpnPush(Newfunc(nansupx,RpnPop,Temp));
          end;
    pnanin : begin
            Temp:=RpnPop;
            RpnPush(Newfunc(naninx,RpnPop,Temp));
          end;
    pnanout : begin
            Temp:=RpnPop;
            RpnPush(Newfunc(nanoutx,RpnPop,Temp));
          end;
   else
    ParserInternalError('Unknown function',1,ORD(Operation));
   end;
end;

Function IsFunction(S:String):ParseOperation;

var Count:ParseOperation;

begin
 IsFunction:=pnothing;
 for Count:=pabs to pnanout do
  begin
   If S=ParserFunctionNamesUpper[Count] then
    IsFunction:=Count;
  end;


end;


Procedure OpPush(operation : ParseOperation);  { Add an operation onto top of the stack }
begin
  if OpTop < OpMax then
  begin
    Inc(OpTop);
    OpStack[OpTop] := operation;
  end
  else
   RAISE EParserStack.Create(SParsOpOverflow);
end;

Function OpPop : ParseOperation;        { Get operation at the top of the stack }
begin
  if OpTop > 0 then
  begin
    OpPop := OpStack[OpTop];
    Dec(OpTop);
  end
  else
   RAISE EParserStack.Create(SParsOpUnderflow);
end;

Var
  I,len       : ArbInt;
  Token       : String;
  OperationNr : ParseOperation;
  FunctionNr  : ArbInt;
  isminus,e_trouve     : boolean;
 label fin_analyse_nombre;
begin

 {Procedure modified by JM Biansan to follow exactly Shunting-Yard algorithm:
     While there are tokens to be read:

        Read a token.
        If the token is a number, then add it to the output queue.
        If the token is a function token, then push it onto the stack.
        If the token is a function argument separator (e.g., a comma):

            Until the token at the top of the stack is a left parenthesis, pop operators off the stack onto the output queue. If no left parentheses are encountered, either the separator was misplaced or parentheses were mismatched.

        If the token is an operator, o1, then:

            while there is an operator token, o2, at the top of the stack, and

                    either o1 is left-associative and its precedence is less than or equal to that of o2,
                    or o1 is right-associative and its precedence is less than that of o2,

                pop o2 off the stack, onto the output queue;

            push o1 onto the stack.

        If the token is a left parenthesis, then push it onto the stack.
        If the token is a right parenthesis:

            Until the token at the top of the stack is a left parenthesis, pop operators off the stack onto the output queue.
            Pop the left parenthesis from the stack, but not onto the output queue.
            If the token at the top of the stack is a function token, pop it onto the output queue.
            If the stack runs out without finding a left parenthesis, then there are mismatched parentheses.

    When there are no more tokens to read:

        While there are still operator tokens in the stack:

            If the operator token on the top of the stack is a parenthesis, then there are mismatched parentheses.
            Pop the operator onto the output queue.

    Exit.
}
  RPNExpr:='';
  OpTop  := 0;                                              { Reset stacks }
  RPNTop := 0;
  Token  := '';
    Expr:=Upcase(Expr);

  i:=1; len:=Length(Expr);
  while I<=Len do
   begin
    {Flush token, if we feel an infix operator coming}
     FunctionNr:=Pos(expr[I],OppsXlat);
    {modified by JM Biansan: should never arise}
   // If (FunctionNr<>0) and (Token<>'') THEN
     //  begin        { Send last built number to calc. }
       // RPNCalc(Token);
       // Token := '';
      // end;
     If (FunctionNr>0) and (FunctionNr<7) then
    begin
      OperationNr:=ParseOperation(FunctionNr-1+ORD(padd));
      If (OperationNr=psub) then  {Minus(x) or x-y?}
       begin
        IsMinus:=False;
        if I=1 then
         IsMinus:=true
        else
         If Expr[I-1] IN ['+','(','*','/','-','^'] then
          IsMinus:=true;
        If IsMinus then
         OperationNr:=PMinus;
       end;
      While (OpTop > 0) AND
      {modified by JM Biansan : only pop off operators}
      ((OpStack[OpTop]<=pfacul) or (OpStack[OpTop]=pminus))
        AND
        (
        ((expr[I]<>'^') and   (Priority[OperationNr] <= Priority[OpStack[OpTop]]))
        or

        {modified by JM Biansan
        because exponentiation is right-associative}
        ((expr[I]='^') and   (Priority[OperationNr] < Priority[OpStack[OpTop]]))
        )

        DO
                 RPNOperation(OpPop);
      OpPush(OperationNr);
     end
    else


 {modified by JM Biansan to take in account number in scientific notation}
     case Expr[I] of
      '0'..'9' : begin
               e_trouve:=false;
                While ((Expr[I] in ['0'..'9']) and (I<=len)) do begin
                 Token:=Token+Expr[I];
                                         inc(i);
                                         end;
                dec(i);
                if i=len then goto fin_analyse_nombre;
              {jusque la, on n'a rencontre que des chiffres}
              {maintenant, on ne peut rencontrer que le point decimal ., le E ou e
              des reels en notation scientifique,
              un operateur +-*/^!, la virgule si 1er argument d'une fonction de 2 variables
              ou la )}

              inc(i);
              if expr[i] in ['e','E']then e_trouve:=true;

              if not(expr[I] in ['.',',','+','-','*','/','^','!',')','e','E']) then
                 begin
                   RAISE EParserStack.Create(SExprNotFloat);
                   exit;
                   end;

              if  expr[I] in [',','+','-','*','/','^','!',')'] then
                 {c'est un entier, analyse terminee}
                 begin
                   dec(i);
                  goto fin_analyse_nombre;
                 end;

              if expr[i]='.' then begin
                Token:=Token+Expr[I];
                if i=len then goto fin_analyse_nombre;
                {apres le point decimal on peut rencontrer des chiffres, le E ou e,
                les operateurs, la ), la ,}
                if not(expr[I+1] in ['0'..'9',',','+','-','*','/','^',')','e','E']) then
                 begin
                   RAISE EParserStack.Create(SExprNotFloat);
                   exit;
                   end;
                  if  expr[I+1] in [',','+','-','*','/',')','^'] then
                 {c'est un entier avec un point decimal fictif, analyse terminee}
                 begin
                 goto fin_analyse_nombre;
                 end;
                  {si chiffre apres point decimal, on lit tous les chiffres}
                  if  expr[I+1] in ['0'..'9'] then begin
                 inc(i);
                 while ((expr[I] in ['0'..'9']) and (i<=len)) do begin
                  Token:=Token+Expr[I];
                    inc(i);
                    end;
                 dec(i);
                 if i=len then  goto fin_analyse_nombre;
                 {apres les chiffres decimaux on peut rencontrer le E ou e,
                les operateurs, la ), la ,}
                if not(expr[I+1] in [',','+','-','*','/','^',')','e','E']) then
                 begin
                   RAISE EParserStack.Create(SExprNotFloat);
                   exit;
                   end;
                 if  expr[I+1] in [',','+','-','*','^','/',')'] then
                 {c'est un reel sans la notation scientifique, analyse terminee}
                 begin

                 goto fin_analyse_nombre;
                 end;
                 {le caractere suivant est donc E ou e}
                 end; {du cas ou c'est un chiffre apres le point decimal}
                  end; {du cas ou point decimal}





                  {cas ou on tombe sur e ou E}
                  inc(i);
                  if e_trouve then dec(i);

                  if i=len then begin   {pas possible que ce soit le derniere caractere...}
                    RAISE EParserStack.Create(SExprNotFloat);
                   exit;
                   end;
                 Token:=Token+Expr[I];
                 inc(i);

               {apres le e, il ne peut y avoir que +,- ou 1 chiffre}
               if not(expr[i] in['0'..'9','+','-']) then begin
                 RAISE EParserStack.Create(SExprNotFloat);
                   exit;
                   end;


               if (expr[i] in  ['0'..'9']) then begin
         {de la forme xxxxxEyyyy: c'est ok, le rpncalc verifiera plus tard si c'est un nombre ds la bonne etendue}
                 while ((expr[i] in  ['0'..'9'])  and (i<=len)) do begin
                Token:=Token+Expr[I];
                    inc(i);
                    end;
           dec(i);
              goto fin_analyse_nombre;
                                                  end;


              if expr[i] in ['+','-']  then begin
                {+ ne peut terminer la chaine}
                if i=len then begin
                 RAISE EParserStack.Create(SExprNotFloat);
                   exit;
                   end;
                Token:=Token+Expr[I];
                {apres le +, il ne peut y avoir qu'un chiffre}
                if not(expr[i+1] in['0'..'9']) then begin
                 RAISE EParserStack.Create(SExprNotFloat);
                   exit;
                   end;

                  inc(i);
         {de la forme xxxxxE+yyyy: c'est ok, le rpncalc verifiera plus tard si c'est un nombre ds la bonne etendue}
                 while ((expr[i] in  ['0'..'9'])  and (i<=len)) do begin
                Token:=Token+Expr[I];
                    inc(i);
                    end;
           dec(i);
              goto fin_analyse_nombre;
                                                  end; {du cas e ou E}


                 fin_analyse_nombre:
                 RpnCalc(Token);
                 Token:='';
                 end;
      ','      :  //if Token <> '' then              {Two parameter functions}
                  // begin        { Send last built number to calc. }
                   // RPNCalc(Token);
                   // Token := '';
                  // end;
                 While OpStack[OpTop] <> pleft DO
                   RPNOperation(OpPop);

      '('      : OpPush(pleft);
      ')'      : begin
                  While OpStack[OpTop] <> pleft DO
                   RPNOperation(OpPop);
                  OpPop;{ Pop off and ignore the '(' }


              {added by JM Biansan
              see http://en.wikipedia.org/wiki/Shunting-yard_algorithm}
              if (optop>0) and (OpStack[OpTop]>pright) then
                  rpnoperation(oppop);



                 end;

     'A'..'Z','_' : begin
              {modified by JM Biansan: should never arise}
     //             if Token <> '' then
       //            begin        { Send last built number to calc. }
         //           RPNCalc(Token);
           //         Token := '';
             //      end;

    {modified by JM Biansan to permit variable name with 0..9 and _ }
                  While (Expr[I] IN ['0'..'9','A'..'Z','_']) AND (I<=Len) DO
                  begin
                   Token:=Token+Expr[I];
                   Inc(I);
                  end;
                 Dec(i);
                 OperationNr:=IsFunction(Token);
                 if (
                 (OperationNr=pnothing)
                  and
                  (i<len)
                  and
                  not(expr[i+1] in [')','*','/','+','-','^','!',','])
                  )
                 then
                 begin
                 RAISE EParserStack.Create(SExprNotAfterVar);
                   exit;
                   end;

                 if OperationNr<>pnothing then
                  begin
                   Token:='';
                   {modified by JM Biansan: si c'est une fonction, on l'empile
                   see http://en.wikipedia.org/wiki/Shunting-yard_algorithm}
                 { While (OpTop > 0) AND
                   (Priority[OperationNr] <= Priority[OpStack[OpTop]]) DO
                   RPNOperation(OpPop);}
                  OpPush(OperationNr);
                  {modified by JM Biansan: si c'est une fonction, on l'empile}
                  end
                 else
                  begin
                   RpnCalc(Token);
                   Token:='';
                  end;
                end;
     end; { Case }
     inc(i);
   end;
  If Token<>'' Then
   RpnCalc(Token);
  While OpTop > 0 do                     { Pop off the remaining operations }
    RPNOperation(OpPop);
 InFixToParseTree:=RpnPop;

end;

function TBaseExprParser.ParseTreeToInfix(expr:pnode):string;

var S,right,left : string;
    IsSimpleExpr : boolean;

begin
 IF expr=nil then
  ParserInternalError(SNILDeref,5,0);
 case expr^.nodetype of
   VarNode  : S:=expr^.variable;
  iconstnode: str(expr^.ivalue,S);
   ConstNode: str(expr^.value,s);
   CalcNode : begin
                right:=ParseTreeToInfix(expr^.right);
                left:=ParseTreeToInfix(expr^.left);
                S:=left+InfixOperatorName[Expr^.op]+right;
                if (expr^.op=addo) or (expr^.op=subo) then
                 S:='('+S+')';
              end;
   FuncNode : begin
               left:=functionnames[expr^.fun];
               right:=ParseTreeToInfix(expr^.son);
               issimpleExpr:=false;
               If ((Expr^.fun=minus) or (Expr^.fun=faculx)) and
                  (expr^.son^.nodetype in [varnode,iconstnode,constnode]) then
                issimpleExpr:=true;
               if expr^.fun<>faculx then
                begin
                 If IsSimpleExpr then
                  S:=Left+Right
                 else
                  S:=Left+'('+Right+')';
                 end
                else
                 If IsSimpleExpr then
                  S:=Right+Left
                 else
                  S:='('+Right+')'+Left;
              end;
  Func2Node : begin
               S:=functionnames[expr^.fun];
               Left:=ParseTreeToInfix(Expr^.son2right);
               right:=ParseTreeToInfix(expr^.son2left);
               S:=S+'('+Left+','+Right+')';
              end;
  end;
  ParseTreeToInfix:=S;
end;

function TBaseExprParser.ParseTreeToRPN(expr:pnode):string;
{not fast because of the prepending. Creating an array of pnode would maybe
be faster}

procedure SearchTree(Tree:pnode;var s:string);

var temp:string;

begin
 if tree<>nil then
 case Tree^.nodetype of
  VarNode  : s:=Tree^.Variable +' '+s;
  ConstNode: begin
              str(Tree^.value:5:9,temp);              {should be configurable}
              s:=temp+' '+s;
             end;
 iconstnode: begin
              str(Tree^.ivalue,temp);
              s:=temp+' '+s;
             end;
 CalcNode  : begin
               s:=InfixOperatorName[Tree^.op]+' '+s;
               SearchTree(tree^.right,s);
               SearchTree(tree^.left,s);
             end;
 FuncNode:    begin
               s:=functionnames[tree^.fun]+' '+s;
               SearchTree(tree^.son,s);
             end;
  Func2Node:   begin
               s:=functionnames[tree^.fun]+' '+s;
               SearchTree(tree^.son2right,s);
               SearchTree(Tree^.son2left,s);
              end;
    end;
end;

var s : String;

begin
 s:='';
 searchTree(expr,s);
 ParseTreeToRPN:=S;
end;

{
  $Log:                       $
}

