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

#include <clx.h>
#pragma hdrstop

#include "Unit1.h"
#include "math.h"
#include "Math.hpp"
#include "Cioina.hpp"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.xfm"

const
 double MyMaxDouble=1.7E+308;
const int
  EX_NONMATH=0,
  EX_Overflow=1,
  EX_Underflow=2,
  EX_InvalidArgument=3,
  EX_ZeroDivide=4,
  EX_InvalidOp=5,

  ERR_NOERROR=0,
  ERR_NO_MATH_EXPRESSION_WAS_PARSED=-1,
  ERR_PARANTHESES_SYNTAX_ERROR=-2,
  ERR_INVALID_DERIVATIVE_VARIABLE_NAME=-3,
  ERR_MATH_EXPRESSION_IS_EMPTY=-4,
  ERR_IDENTIFIER_CANNOT_BE_EMPTY=-5,
  ERR_IDENTIFIER_LENGTH=-6,
  ERR_NOT_PASCAL_IDENTIFIER=-7,
  ERR_IDENTIFIER_CANNOT_BE_RESERVED_NAME=-8,
  ERR_IDENTIFIER_ALREADY_EXISTS=-9,
  ERR_DUBLICATING_USER_IDENTIFIER=-10,
  ERR_UNKNOWN_EXPRESSION=-11,
  ERR_BAD_EXPONENTIAL_FORMAT=-12,
  ERR_SET_OriginalMathExpressionString_FALSE=-13,
  ERR_MATH_EXPRESSION_WAS_ERASED=-14,
  ERR_USE_VerifySyntaxSemanticsAndDerivation=-15,
  ERR_DERIVATIVE_EXPRESSION_WAS_ERASED=-16,
  ERR_VARIABLES_AND_VALUES_ARE_DIFFERENT=-17,
  ERR_MATH_EXPRESSIONS_ARRAY=-18,
  ERR_FUNCTION_NUMBER_MUST_BE_LESS=-19,
  ERR_FUNCTION_ADDRESS_CANNOT_BE_NIL=-20,
  ERR_PROTECTED_EXPRESSION=-21,
  ERR_PARSE=-22,
  ERR_EXECUTE=-23,
  ERR_DYNAMIC_MEMORY=-24,
  ERR_MULTIPLY=-25,
  ERR_DIVISION=-26,
  ERR_PLUS=-27,
  ERR_MINUS=-28,
  ERR_POWER=-29,
  ERR_EQUAL=-30,
  ERR_UNKNOWN_FUNCTION=-31,
  ERR_UNKNOWN_VARIABLE=-32,
  ERR_BAD_SYNTAX=-33,
  ERR_COMMA_SYNTAX=-34,
  ERR_SYSTEM_STACK_OVERFLOW=-35,
  ERR_DEF_FUNC_NAME=-36,
  ERR_DEF_FUNC_DUBLICATING=-37,
  ERR_DEF_FUNC_IMPLEMENTING=-38,
  ERR_DEF_FUNC_ARG_COUNT=-39,
  ERR_DEF_FUNC_ARG_NAME=-40,
  ERR_DEF_FUNC_ARG_DUBLICATING=-41,
  ERR_DEF_FUNCTION_STACK_OVERFLOW=-42;
  
struct  exception {int type;};
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;
}
//---------------------------------------------------------------------------
double __stdcall MyE(int ParamCount)
{
 return exp(1);
}
//---------------------------------------------------------------------------

double __stdcall MySqrt(int ParamCount)
{
 return sqrt(Prm(0));
}
//---------------------------------------------------------------------------

double __stdcall MySum(int ParamCount)
{
 long double s; int i;
 for(s=0,i=0;i<ParamCount;i++)s+=Prm(i);
 return s;
}
//---------------------------------------------------------------------------

double __stdcall MyRandom(int ParamCount)
{
 return rand();
}
//---------------------------------------------------------------------------


TForm1 *Form1;
Word Saved8087CW;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ParseErrorMessage(int Item)
{
 AnsiString  s,s1,s2;
 int i;
 char *pc;
  GetErrorMessageInfo(Item,pc);
  s1=pc;
  i=AnsiPos(':',s1)+1;
  if(i>1) s2=" : ";else s2="";
  for (;i<=s1.Length();i++)s2+=s1[i];
  s1=s2;

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

  default: if(GetErrorNumber(Item)>=1 && GetErrorNumber(Item)<=GetBuiltInFunctionCount())
           {
             GetBuiltInFunctionName(GetErrorNumber(Item),pc);
             s2=pc;
             if(s=="")Memo1->Text=("Invalid number of function arguments for: "+ UpperCase(s2));
             else Memo1->Text=("Invalid value for "+ UpperCase(s2)+s1+s);
            }
            else
            {
              GetErrorMessageInfo(Item,pc);
              s1=pc;
              Memo1->Text=(s1);
            }
  }

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

void __fastcall TForm1::ExecuteErrorMessage(int Item)
{
 AnsiString  s,s1,s2;
 int i;
 char *pc;
  GetErrorMessageInfo(Item,pc);
  s1=pc;
  i=AnsiPos(':',s1)+1;
  if(i>1) s2=" : ";else s2="";
  for (;i<=s1.Length();i++)s2+=s1[i];
  s1=s2;

  s="";
  switch ( GetMathException(Item) ){
  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 (GetErrorNumber(Item)){
   case ERR_NO_MATH_EXPRESSION_WAS_PARSED:           Memo1->Text=("No math expression was parsed");break;
   case ERR_VARIABLES_AND_VALUES_ARE_DIFFERENT:      Memo1->Text=("Variable count and value caunt do not corespond");break;
   case ERR_MATH_EXPRESSIONS_ARRAY:                  Memo1->Text=("Use ''DoVectorOfMathExpressions'' for calculate a vector of math expression");break;
   case ERR_EXECUTE:                                 Memo1->Text=("Execution error");break;
   case ERR_DEF_FUNCTION_STACK_OVERFLOW:             Memo1->Text=("Stack overflow"+s1);break;
   case ERR_SYSTEM_STACK_OVERFLOW:                   Memo1->Text=("Fatal error"+s1);break;
   case ERR_MULTIPLY:                                Memo1->Text=("Invalid value for *"+s1+s);break;
   case ERR_DIVISION:                                if (GetMathException(Item)==EX_ZeroDivide) Memo1->Text=("Division by 0 ");
                                                     else Memo1->Text=("Invalid value for /"+s1+s);break;
   case ERR_PLUS:                                    Memo1->Text=("Invalid value for +"+s1+s);break;
   case ERR_MINUS:                                   Memo1->Text=("Invalid value for -"+s1+s);break;
   case ERR_POWER:                                   Memo1->Text=("Invalid value for ^"+s1+s);break;
   case ERR_EQUAL:                                   Memo1->Text=("Invalid value for ="+s1+s);break;
  default: if(GetErrorNumber(Item)>=1 && GetErrorNumber(Item)<=GetBuiltInFunctionCount())
           {
             GetBuiltInFunctionName(GetErrorNumber(Item),pc);
             s2=pc;
             if(s=="")Memo1->Text=("Invalid number of function arguments for: "+ UpperCase(s2));
             else Memo1->Text=("Invalid value for "+ UpperCase(s2)+s1+s);
            }
            else
            {
              GetErrorMessageInfo(Item,pc);
              s1=pc;
              Memo1->Text=(s1);
            }
  }

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

void __fastcall TForm1::FormCreate(TObject *Sender)
{
char *pc;
 Saved8087CW=GetFPU8087CW();
 SetFPU8087CW(4927);
 DecimalSeparator = '.';
 AddUserFunction("MyE",MyE,0);
 AddUserFunction("MySqrt",MySqrt,1);
 AddUserFunction("MySum",MySum,MaxInt);
 AddUserFunction("MyRandom",MyRandom,-1);
 CreateList();
 AddMathExpressionWithUserFunctions();
 AddMathExpressionWithUserFunctions();
 AddSharedVar("x",1,false);
 AddSharedVar("y",2,false);
 Edit1Change(this);
 Edit2Change(this);
 Edit3Change(this);
 GetVersionInfo(pc);
 Caption=pc;
 GetOwnerInfo(pc);
 Caption=Caption +"    "+pc;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormDestroy(TObject *Sender)
{
 FreeAll();
 SetFPU8087CW(Saved8087CW);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Edit1Change(TObject *Sender)
{
  AnsiString s;
  Memo1->Text="";
  s=Edit1->Text;
  Parse(0,s.c_str(),"",true);
  if (GetErrorFlag(0))
  {
   SetSharedVar(0,MyMaxDouble);
   Label1->Caption="x: "+FloatToStr(GetSharedVar(0));
   Label4->Caption="Result";
   Form1->ParseErrorMessage(0);
  }
  else
  {
   SetSharedVar(0,DoMathExpression(0));
   Label1->Caption="x: "+FloatToStr(GetSharedVar(0));
   if (GetErrorFlag(0))  Form1->ExecuteErrorMessage(0);
   Label4->Caption="Result = "+FloatToStr(DoMathExpression(1));
   if(GetErrorFlag(1)) Form1->ExecuteErrorMessage(1);
  }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Edit2Change(TObject *Sender)
{
 AnsiString s;
  Memo1->Text="";
  s=Edit2->Text;
  Parse(0,s.c_str(),"",true);
  if (GetErrorFlag(0))
  {
   SetSharedVar(1,MyMaxDouble);
   Label2->Caption="y: "+FloatToStr(GetSharedVar(1));
   Label4->Caption="Result";
   Form1->ParseErrorMessage(0);
  }
  else
  {
   SetSharedVar(1,DoMathExpression(0));
   Label2->Caption="y: "+FloatToStr(GetSharedVar(1));
   if (GetErrorFlag(0))  Form1->ExecuteErrorMessage(0);
   Label4->Caption="Result = "+FloatToStr(DoMathExpression(1));
   if(GetErrorFlag(1)) Form1->ExecuteErrorMessage(1);
  }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Edit3Change(TObject *Sender)
{
 AnsiString   s ;
 Label3->Caption="Math Expression :";
 Label4->Caption="Result";
 Memo1->Text="";
 s=Edit3->Text;
 ParseWithSharedVar(1,s.c_str(),true);
 if (!GetErrorFlag(1))
 {
  Label3->Caption="Math Expression : OK";
  Label4->Caption="Result = "+FloatToStr(DoMathExpression(1));
  if (GetErrorFlag(1))  Form1->ExecuteErrorMessage(1);
 }
 else Form1->ParseErrorMessage(1);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::CheckBox1Click(TObject *Sender)
{
 if (CheckBox1->Checked)
 {
  CheckBox1->Caption="Space like multiply operator (true)";
  SetSpaceLikeMultiply(0,true);
  SetSpaceLikeMultiply(1,true);
  Edit1Change(this);
  Edit2Change(this);
  Edit3Change(this);
 }else
 {
  CheckBox1->Caption="Space like multiply operator (false)";
  SetSpaceLikeMultiply(0,false);
  SetSpaceLikeMultiply(1,false);
  Edit1Change(this);
  Edit2Change(this);
  Edit3Change(this);
 }

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

void __fastcall TForm1::Edit3Click(TObject *Sender)
{
 Edit3Change(this);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Edit1Click(TObject *Sender)
{
 Edit1Change(this);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Edit2Click(TObject *Sender)
{
 Edit2Change(this);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
int i;
 char *pc;
 Memo1->Clear();
 for(i=0;i<=GetTotalFunctionCount(0);i++)
 {
  GetBuiltInFunctionInfo(0,i,pc);
  Memo1->Lines->Add(pc);
 }        
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)
{
int i;
 char *pc;
 Memo1->Clear();
 for(i=1;i<=GetBuiltInFunctionCount();i++)
 {
  GetBuiltInFunctionName(i,pc);
  Memo1->Lines->Add(IntToStr(i)+". "+pc);
 }
        
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button3Click(TObject *Sender)
{
 char *pc;
 AnsiString s;
 Memo1->Clear();
 s=Edit3->Text;
 ParseAndDifferentiate(1,s.c_str(),"","x",true);
 if (GetErrorFlag(1))
 {
  Form1->ParseErrorMessage(1);
 }
 else
 {
  GetDerivativeExpressionString(1,pc);
  Memo1->Text=pc;
 }
        
}
//---------------------------------------------------------------------------

