//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <alloc.h>
#include "Unit1.h"
#include "Unit2.h"
#include "CioinaEval.hpp"
#include "math.h"
#include "math.hpp"

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
TCioinaEval *ev1,*ev2,*ev3;
//---------------------------------------------------------------------------
int _matherr (struct _exception *a)
{
 if (a->type == DOMAIN)
 {
   throw EInvalidArgument("");
  }
 if (a->type == SING)
 {
   throw EInvalidOp("");
  }
 if (a->type == OVERFLOW)
 {
   throw EOverflow("");
  }
 if (a->type == UNDERFLOW)
 {
   throw EUnderflow("");
  }
 if (a->type == TLOSS)
 {
   throw Exception("TLOSS");
  }
 return 0;
}
//---------------------------------------------------------------------------

long double __fastcall MyE(PVectorPTReal Pv,int PvCount)
{
 return exp(1);
}
//---------------------------------------------------------------------------

long double __fastcall MySqrt(PVectorPTReal Pv,int PvCount)
{
 return sqrt(*Pv[0]);
}
//---------------------------------------------------------------------------

long double __fastcall MySum(PVectorPTReal Pv,int PvCount)
{
 long double s; int i;
 for(s=0,i=0;i<PvCount;i++)s+=*Pv[i];
 return s;
}
//---------------------------------------------------------------------------

long double __fastcall MyRandom(PVectorPTReal Pv,int PvCount)
{
 return rand();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ParsingError(TObject *Sender)
{
 AnsiString  s,s1;
 int i;
 TCioinaEval *Test = dynamic_cast<TCioinaEval*>(Sender);
 if(Test)
 {
  i=AnsiPos(':',Test->ErrorMessageInfo)+1;
  if(i>1) s1=" : ";else s1="";
  for (;i<=Test->ErrorMessageInfo.Length();i++)s1+=Test->ErrorMessageInfo[i];
  s="";
  switch ( Test->MathException ){
  case EX_NONMATH:s=" : NONMATH";break;
  case EX_Overflow:s=" : Overflow";break;
  case EX_Underflow:s=" : Underflow";break;
  case EX_InvalidArgument:s=" : InvalidArgument";break;
  case EX_ZeroDivide:s=" : ZeroDivide";break;
  case EX_InvalidOp:s=" : InvalidOp";break;
  }

  switch (Test->ErrorNumber){
   case ERR_PARSE:                                   Memo3->Text=("Invalid expression"+s1);break;
   case ERR_BAD_SYNTAX:                              Memo3->Text=("Syntax error"+s1);break;
   case ERR_COMMA_SYNTAX:                            Memo3->Text=("Comma syntax error"+s1);break;
   case ERR_NO_MATH_EXPRESSION_WAS_PARSED:           Memo3->Text=("No math expression was parsed");break;
   case ERR_PARANTHESES_SYNTAX_ERROR:                Memo3->Text=("Mismatched parenthesis");break;
   case ERR_INVALID_DERIVATIVE_VARIABLE_NAME:        Memo3->Text=("Invalid name of derivative variable"+s1);break;
   case ERR_MATH_EXPRESSION_IS_EMPTY:                Memo3->Text=("Mathematical expression is empty");break;
   case ERR_IDENTIFIER_CANNOT_BE_EMPTY:              Memo3->Text=("Identifier cannot be empty");break;
   case ERR_IDENTIFIER_LENGTH:                       Memo3->Text=("Identifier length is too long"+s1);break;
   case ERR_NOT_PASCAL_IDENTIFIER:                   Memo3->Text=("Invalid identifier"+s1);break;
   case ERR_IDENTIFIER_CANNOT_BE_RESERVED_NAME:      Memo3->Text=("Identifier cannot be a reserved name"+s1);break;
   case ERR_IDENTIFIER_ALREADY_EXISTS:               Memo3->Text=("Identifier already exists"+s1);break;
   case ERR_DUBLICATING_USER_IDENTIFIER:             Memo3->Text=("Dublicating user identifier"+s1);break;
   case ERR_UNKNOWN_EXPRESSION:                      Memo3->Text=("Unknown expression"+s1);break;
   case ERR_UNKNOWN_FUNCTION:                        Memo3->Text=("Undefined function"+s1);break;
   case ERR_UNKNOWN_VARIABLE:                        Memo3->Text=("Undefined variable"+s1);break;
   case ERR_BAD_EXPONENTIAL_FORMAT:                  Memo3->Text=("Invalid exponent value"+s1);break;
   case ERR_SET_OriginalMathExpressionString_FALSE:  Memo3->Text=("Set ''OriginalMathExpressionString'' to FALSE for differentiation or for Mathematica 4.1 export");break;
   case ERR_MATH_EXPRESSION_WAS_ERASED:              Memo3->Text=("Mathematical expression string was erased");break;
   case ERR_USE_VerifySyntaxSemanticsAndDerivation:  Memo3->Text=("Use ''VerifySyntaxSemanticsAndDerivation'' for differentiation");break;
   case ERR_DERIVATIVE_EXPRESSION_WAS_ERASED:        Memo3->Text=("Derivative expression string was erased");break;
   case ERR_VARIABLES_AND_VALUES_ARE_DIFFERENT:      Memo3->Text=("Variable count and value caunt do not corespond");break;
   case ERR_MATH_EXPRESSIONS_ARRAY:                  Memo3->Text=("Use ''DoVectorOfMathExpressions'' for calculate a vector of math expression");break;
   case ERR_FUNCTION_NUMBER_MUST_BE_LESS:            Memo3->Text=("Function number must be less"+s1);break;
   case ERR_FUNCTION_ADDRESS_CANNOT_BE_NIL:          Memo3->Text=("Function address cannot be nil"+s1);break;
   case ERR_PROTECTED_EXPRESSION:                    Memo3->Text=("Cannot set value for protected expression"+s1);break;
   case ERR_DEF_FUNC_NAME:                           Memo3->Text=("Invalid function name"+s1);break;
   case ERR_DEF_FUNC_DUBLICATING:                    Memo3->Text=("Dublicating defined function"+s1);break;
   case ERR_DEF_FUNC_IMPLEMENTING:                   Memo3->Text=("Defined function was not implimented"+s1);break;
   case ERR_DEF_FUNC_ARG_COUNT:                      Memo3->Text=("Invalid arguments number for defined function"+s1);break;
   case ERR_DEF_FUNC_ARG_NAME:                       Memo3->Text=("Invalid argument name for defined function"+s1);break;
   case ERR_DEF_FUNC_ARG_DUBLICATING:                Memo3->Text=("Dublicating argument name for defined function"+s1);break;
   case ERR_MULTIPLY:                                Memo3->Text=("Invalid value for *"+s1+s);break;
   case ERR_DIVISION:                                if (Test->MathException==EX_ZeroDivide) Memo3->Text=("Division by 0 ");
                                                     else Memo3->Text=("Invalid value for /"+s1+s);break;
   case ERR_PLUS:                                    Memo3->Text=("Invalid value for +"+s1+s);break;
   case ERR_MINUS:                                   Memo3->Text=("Invalid value for -"+s1+s);break;
   case ERR_POWER:                                   Memo3->Text=("Invalid value for ^"+s1+s);break;
   case ERR_EQUAL:                                   Memo3->Text=("Invalid value for ="+s1+s);break;

  default: if(Test->ErrorNumber>=1 && Test->ErrorNumber<=FunCount)
           {
             if(s=="")Memo3->Text=("Invalid number of function arguments for: "+ UpperCase(aStr[Test->ErrorNumber-1]));
             else Memo3->Text=("Invalid value for "+ UpperCase(aStr[Test->ErrorNumber-1])+s1+s);
            }
            else
              if (Test->ErrorNumber>FunCount)
              {
               if(s=="")Memo3->Text=("Invalid number of function arguments for: "+ UpperCase(Test->UserFunctionName[Test->ErrorNumber-FunCount-1]));
               else Memo3->Text=("Invalid value for "+ UpperCase(Test->UserFunctionName[Test->ErrorNumber-FunCount-1])+s1+s);
              }
              else Memo3->Text=(Test->ErrorMessageInfo);
  }
 }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::DoMathExpressError(TObject *Sender)
{
 AnsiString  s,s1;
 int i;
 TCioinaEval *Test = dynamic_cast<TCioinaEval*>(Sender);
 if(Test)
 {
  i=AnsiPos(':',Test->ErrorMessageInfo)+1;
  if(i>1) s1=" : ";else s1="";
  for (;i<=Test->ErrorMessageInfo.Length();i++)s1+=Test->ErrorMessageInfo[i];
  s="";
  switch ( Test->MathException ){
  case EX_NONMATH:s=" : NONMATH";break;
  case EX_Overflow:s=" : Overflow";break;
  case EX_Underflow:s=" : Underflow";break;
  case EX_InvalidArgument:s=" : InvalidArgument";break;
  case EX_ZeroDivide:s=" : ZeroDivide";break;
  case EX_InvalidOp:s=" : InvalidOp";break;
  }

  switch (Test->ErrorNumber){
   case ERR_NO_MATH_EXPRESSION_WAS_PARSED:           Memo3->Text=("No math expression was parsed");break;
   case ERR_VARIABLES_AND_VALUES_ARE_DIFFERENT:      Memo3->Text=("Variable count and value caunt do not corespond");break;
   case ERR_MATH_EXPRESSIONS_ARRAY:                  Memo3->Text=("Use ''DoVectorOfMathExpressions'' for calculate a vector of math expression");break;
   case ERR_EXECUTE:                                 Memo3->Text=("Execution error");break;
   case ERR_DEF_FUNCTION_STACK_OVERFLOW:             Memo3->Text=("Stack overflow"+s1);break;
   case ERR_SYSTEM_STACK_OVERFLOW:                   Memo3->Text=("Fatal error"+s1);break;
   case ERR_MULTIPLY:                                Memo3->Text=("Invalid value for *"+s1+s);break;
   case ERR_DIVISION:                                if (Test->MathException==EX_ZeroDivide) Memo3->Text=("Division by 0 ");
                                                     else Memo3->Text=("Invalid value for /"+s1+s);break;
   case ERR_PLUS:                                    Memo3->Text=("Invalid value for +"+s1+s);break;
   case ERR_MINUS:                                   Memo3->Text=("Invalid value for -"+s1+s);break;
   case ERR_POWER:                                   Memo3->Text=("Invalid value for ^"+s1+s);break;
   case ERR_EQUAL:                                   Memo3->Text=("Invalid value for ="+s1+s);break;
   default: if(Test->ErrorNumber>=1 && Test->ErrorNumber<=FunCount)
            {
             if(s=="")Memo3->Text=("Invalid number of function arguments for: "+ UpperCase(aStr[Test->ErrorNumber-1]));
             else Memo3->Text=("Invalid value for "+ UpperCase(aStr[Test->ErrorNumber-1])+s1+s);
            }
            else
              if (Test->ErrorNumber>FunCount)
              {
               if(s=="")Memo3->Text=("Invalid number of function arguments for: "+ UpperCase(Test->UserFunctionName[Test->ErrorNumber-FunCount-1]));
               else Memo3->Text=("Invalid value for "+ UpperCase(Test->UserFunctionName[Test->ErrorNumber-FunCount-1])+s1+s);
              }
              else Memo3->Text=(Test->ErrorMessageInfo);
  }
 }
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{

}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 TReplaceFlags flag;
 AnsiString s;
 DynamicArray<TUserVarRec> a;
 heapinfo hi;
 int i;

 hi.ptr = NULL;
 if(heapwalk( &hi ) == _HEAPOK )
  Label6->Caption="TotalAllocated virtual memory = "+IntToStr(hi.in_use)+" bytes";

 Memo3->Clear();
 flag<<rfReplaceAll;
 if (Trim(Memo1->Text)=="")s="nan"; else s=Memo1->Text;
 s=StringReplace(s,"\r\n","",flag);
 ev1->VerifySyntaxSemantics(s,"",true);
 if (!(ev1->ErrorFlag))
 {
  ev1->DoVectorOfMathExpressions();
  if( !(ev1->ErrorFlag))
  {
   a.Length=ev1->VariableCount;
   for(i=0;i<=a.Length-1;i++)
   {
    a[i].Value=ev1->VariableArray[i]->Value;
    a[i].StrExpr=ev1->VariableArray[i]->StrExpr;
    a[i].Protect=false;
   }
   if (Trim(Memo4->Text)=="")s="nan"; else s=Memo4->Text;
   s=StringReplace(s,"\r\n","",flag);
   ev3->VerifySyntaxSemantics(s,a,false);
   if(!(ev3->ErrorFlag))
   {
    if (Trim(Memo2->Text)=="")s="nan"; else s=s+","+Memo2->Text;
    s=StringReplace(s,"\r\n","",flag);
    ev2->VerifySyntaxSemantics(s,a,false);
    if(!(ev2->ErrorFlag))
    {
     ev2->DoVectorOfMathExpressions();
     if(!(ev2->ErrorFlag))
      for(i=0;i<=a.High;i++) Memo3->Lines->Add(a[i].StrExpr+" = "+FloatToStr(*(a[i].Value)));
    }
   }
  }
 }
 if (ev1->ErrorFlag) Memo3->Text="DEFINE VARIABLES-> "+Memo3->Text;
 else
   if (ev3->ErrorFlag) Memo3->Text="DEFINE FUNCTIONS-> "+Memo3->Text;
   else
    if (ev2->ErrorFlag) Memo3->Text="DEFINE EXPRESSIONS-> "+Memo3->Text;
 Label5->Caption="CioinaEval allocated virtual memory = "+
  IntToStr(ev1->AllocDynamicMemoryInfo+
           ev2->AllocDynamicMemoryInfo+
           ev3->AllocDynamicMemoryInfo)+" bytes";
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
 DecimalSeparator='.';
 DynamicArray<TUserFuncRec> ar;
 ar.Length=4;
 ar[0].FuncName="MyE";    ar[0].FuncAddress=MyE;    ar[0].VarCount=0;
 ar[1].FuncName="MySum";  ar[1].FuncAddress=MySum;  ar[1].VarCount=MaxFuncParam;
 ar[2].FuncName="MySqrt"; ar[2].FuncAddress=MySqrt; ar[2].VarCount=1;
 ar[3].FuncName="MyRandom"; ar[3].FuncAddress=MyRandom; ar[3].VarCount=-1;
 ev1= new TCioinaEval(ar);
 ev2= new TCioinaEval(ar);
 ev3= new TCioinaEval(ar);
 ev1->OnVerifySyntaxSemanticsError=ParsingError;
 ev1->OnDoMathExpressionError=DoMathExpressError;
 ev2->OnVerifySyntaxSemanticsError=ParsingError;
 ev2->OnDoMathExpressionError=DoMathExpressError;
 ev3->OnVerifySyntaxSemanticsError=ParsingError;
 ev3->OnDoMathExpressionError=DoMathExpressError;
 ar.Length=0;
 Form1->Caption="Simple front end "+ev1->OwnerInfo(NULL);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
 ev1->FreeInstance();
 ev2->FreeInstance();
 ev3->FreeInstance();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)
{
 int i;
 Form2->Memo1->Clear();
 Form2->Memo1->Lines->Add("BUILT-IN FUNCTIONS");
 Form2->Memo1->Lines->Add("==============================================");
 for (i=0;i<=ev3->TotalFunctionCount;i++) Form2->Memo1->Lines->Add(IntToStr(i)+". "+ev3->BuiltInFunctionInfo[i]);
 Form2->Memo1->Lines->Add("==============================================");
 Form2->Memo1->Lines->Add("OwnerInfo = "+ev3->OwnerInfo(NULL));
 Form2->Memo1->Lines->Add("VersionInfo = "+ev3->VersionInfo(NULL));
 Form2->Memo1->Lines->Add("TypeInfo = "+ev3->TypeInfo(NULL));
 Form2->Show();
}
//---------------------------------------------------------------------------


