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

//Чтобы работать с этим интерпретатором нужно:
//Загрузить формулу ф-ей Math.LoadFormula(AnsiString)
//Проверить удачна ли загрузка: bool Math.Status

//Цикл при вычислении графика:
//Изменить значение х, задав новое значение в Var[VarX].Value
//Пересчитать формулу ф-ей: dcomplex Math.F()
//Проверить результат вычисления: bool Math.Status

//В конце работы удалить формулу ф-ей Math.KillFormula()

//---------------------------------------------------------------------------
#include <vcl.h>
#include <complex.h>
#include <math.h>
#include <conio.h>

#pragma hdrstop
#include "Eval1.h"


TVar Var[MAXVARIANT];
TPFunc PFunc[MAXFUNCTION];
TN *N;
TMath Math;

void TVar::New(AnsiString n)
{
  Name=n;
  Value=0;
}

void TPFunc::New(AnsiString n,int c,int p,int t)
{
  Name=n;
  ColParam=c;
  Prior=p;
  Type=t;
}

TN::TN()
{
   Next = NULL;
   Prev = NULL;
   Type = EMPTY;
   Value=(0,0);
   Prior=5;
   pValue=&Value;
   Is=false;
   for (int i=0;i<MAXPARAM;i++) Param[i]=NULL;
}

TN::~TN()
{
int i,max;
 if (Param[0]!=NULL)
   {
     max=PFunc[Param[0]->Type].ColParam+1;
     for(i=0;i<max;i++)
       if (Param[i]!=NULL) delete Param[i];
   }
}

TN *TN::Delete()
{
TN *ptr;
   ptr=this->Prev;
   this->Prev->Next=this->Next;
   this->Next->Prev=this->Prev;
   delete this;
return ptr;
}

//Рекурентный расчет функции, использующий древо
dcomplex TN::GetValue()
{
try
 {
   if (Is) return (*pValue);
   else
     {
       if (Param[0]==NULL) return Math.Error(UNDEFINED);
       switch (Param[0]->Type) //имя функции
       {
        case SIN  : return (sin(Param[1]->GetValue()));
        case COS  : return (cos(Param[1]->GetValue()));
        case TAN  : return (tan(Param[1]->GetValue()));
        case LOG  : return (log(Param[1]->GetValue()));
        case EXP  : return (exp(Param[1]->GetValue()));
        case PLUS : return (Param[1]->GetValue() + Param[2]->GetValue());
        case MINUS: return (Param[1]->GetValue() - Param[2]->GetValue());
        case MUL  : return (Param[1]->GetValue() * Param[2]->GetValue());
        case DIV  : return (Param[1]->GetValue() / Param[2]->GetValue());
        case STP  : return (pow(Param[1]->GetValue(),Param[2]->GetValue()));
//        default   : Math.Error(UNDEFINED);
       }
     }
 }
catch(...)
 {
   return Math.Error(EVALERR);
 }

return 0;
}

dcomplex TMath::F()
{
  return N->GetValue();
}

/////
//Удаление дерева
void TMath::KillFormula()
{
  if (N!=NULL) delete N;
}

TMath::TMath()
{

 PFunc[SIN].New("sin",1,0,SIN);
 PFunc[COS].New("cos",1,0,COS);
 PFunc[TAN].New("tan",1,0,TAN);
 PFunc[LOG].New("log",1,0,LOG);
 PFunc[EXP].New("exp",1,0,EXP);

 PFunc[PLUS].New("+",2,2,PLUS);
 PFunc[MINUS].New("-",2,2,MINUS);
 PFunc[MUL].New("*",2,1,MUL);
 PFunc[DIV].New("/",2,1,DIV);
 PFunc[STP].New("^",2,1,STP);

 Var[VarX].New("x");
 Var[VarI].New("i");
 Var[VarI].Value=dcomplex(0,1);

 Status=true;
}

bool TMath::Error(int n)
{
  switch (n) {
  case SCOBKY     : {ShowMessage("Ошибка: Неверно расставлены скобки");break;}
  case NONMATHSTR : {ShowMessage("Ошибка: Формула не введена");break;}
  case UNDEFINED  : {ShowMessage("Ошибка в формуле");break;}
  case EXTRAPARAM : {ShowMessage("Ошибка: Слишком много параметров функции");break;}
  case FEWPARAM   : {ShowMessage("Ошибка: Слишком мало параметров функции");break;}
  case EVALERR    : {ShowMessage("Ошибка при вычислении");break;}
  default: ShowMessage("Ошибка: Неизвестная ошибка");
  }
Status=false;
return false;
}

//Поиск самой внутренней скобки
TN *TMath::PriorScobka()
{
TN *p;
TN *pos;

pos=N;
for(p=N;p!=NULL;p=p->Next)
  {
     if (p->Type==LS) pos=p;
     if (p->Type==RS) break;
  }
return pos;
}

//Преобразование для функций с приоритетом 0
bool TMath::ReplaceFunc0(TN *ptr)
{
TN *p,*t;
int n=0;

  if (ptr->Prev==NULL) return true;

//Удаление лишних скобок
  if (ptr->Prev->Prior!=0)
    {
      for(p=ptr;p!=NULL;p=p->Next) if (p->Type==RS) break;
      if (p==NULL) return Error(SCOBKY);
      ptr->Delete();
      p->Delete();
    }
//Преобразование
  else
     {
      t=new TN;
      t->Prev=ptr->Prev->Prev;
      ptr->Prev->Prev->Next=t;
      t->Type=NUM;
      t->Prior=5;
      t->Param[0]=ptr->Prev;
      for(p=ptr->Next;p!=NULL;p=p->Next)
       {
        if (p->Type==RS) break;
        else if (p->Type==ZPT) p=p->Delete();
        else if (p->Type==NUM) {n++;t->Param[n]=p;}
        else return Error(UNDEFINED);
       }
      if (p==NULL) return Error(SCOBKY);
      if (n>PFunc[t->Param[0]->Type].ColParam) return Error(EXTRAPARAM);
      if (n<PFunc[t->Param[0]->Type].ColParam) return Error(FEWPARAM);
      t->Next=p->Next;
      p->Next->Prev=t;
      delete p;
      delete ptr;
    }
return true;
}

//Преобразование для функций с приоритетом 1 и 2
//т.е. такие операции как: +, -, * ...
//из линейной структуры в древовидную
void TMath::ReplaceFunc12(TN *ptr)
{
TN *p,*t;

  for(p=ptr;p!=NULL;p=p->Next)
    {
      if (p->Type==RS) break;
      if (p->Prior==1)
        {
         t=new TN;
         t->Param[0]=p;
         t->Param[1]=p->Prev;
         t->Param[2]=p->Next;
         t->Type=NUM;
         t->Prior=5;
         t->Next=p->Next->Next;
         t->Prev=p->Prev->Prev;
         p->Next->Next->Prev=t;
         p->Prev->Prev->Next=t;
         p=ptr;
        }
     }

  for(p=ptr;p!=NULL;p=p->Next)
     {
      if (p->Type==RS) break;
      if (p->Prior==2)
        {
         t=new TN;
         t->Param[0]=p;
         t->Param[1]=p->Prev;
         t->Param[2]=p->Next;
         t->Type=NUM;
         t->Prior=5;
         t->Next=p->Next->Next;
         t->Prev=p->Prev->Prev;
         p->Next->Next->Prev=t;
         p->Prev->Prev->Next=t;
         p=ptr;
        }
    }
}


//Загрузка строки и создание дерева
bool TMath::LoadFormula(AnsiString TempStr)
{
double num;
int len,i,j,k,cl=0,cr=0;
AnsiString SubStr;
TN *p;

KillFormula(); //Удаляем предыдущую формулу

if (TempStr.Length()<1) return Error(NONMATHSTR);

//Проверка скобок и удаление пробелов
  for(i=1;i<=TempStr.Length();i++)
   {
    if (TempStr[i]=='(') cl++;
    if (TempStr[i]==')') cr++;
    if (TempStr[i]==' ')
      {
        TempStr.Delete(i,1);
        i--;
      }
   }
  if (cl!=cr) return Error(SCOBKY);

N = new TN;
N->Type=LS;
N->Prior=5;
p=N;

////////////////
////Level 1/////
////////////////
//Формирование листьев дерева//

len=TempStr.Length();
for(;;)
{
len=TempStr.Length();
if (len==0) break;

//Левая скобка
  if (TempStr[1]=='(')
     {
        p->Next=new TN;p->Next->Prev=p;p=p->Next;p->Next=NULL;
        p->Type=LS;
        p->Prior=5;
        TempStr.Delete(1,1);
        continue;
     }
//Правая скобка
  if (TempStr[1]==')')
     {
        p->Next=new TN;p->Next->Prev=p;p=p->Next;p->Next=NULL;
        p->Type=RS;
        p->Prior=5;
        TempStr.Delete(1,1);
        continue;
     }

//Запятая
  if (TempStr[1]==',')
     {
        p->Next=new TN;p->Next->Prev=p;p=p->Next;p->Next=NULL;
        p->Type=ZPT;
        p->Prior=5;
        TempStr.Delete(1,1);
        continue;
     }

//Функции
  for(j=0;j<MAXFUNCTION;j++)
     {
        if (TempStr.Pos(PFunc[j].Name)==1)
          {
            if (PFunc[j].Type==PLUS || PFunc[j].Type==MINUS)
              {
                if (p->Type==LS) break;
                if (p->Type==ZPT) break;
              }
            p->Next=new TN;p->Next->Prev=p;p=p->Next;p->Next=NULL;
            p->Type=PFunc[j].Type;
            p->Prior=PFunc[j].Prior;
            TempStr.Delete(1,PFunc[j].Name.Length());
            if (PFunc[j].Prior==0 && TempStr[1]!='(') return Error(SCOBKY);
            goto l1;
          }
     }

//Переменные:
//Структура такая же как и у просто чисел, но значение не статично,
//а указывает на значение переменной.

  for(j=0;j<MAXVARIANT;j++)
     {
        if (TempStr.Pos(Var[j].Name)==1)
          {
            p->Next=new TN;p->Next->Prev=p;p=p->Next;p->Next=NULL;
            p->Type=NUM;
            p->Prior=5;
            p->Is=true;
            p->pValue=&Var[j].Value;
            TempStr.Delete(1,Var[j].Name.Length());
            goto l1;
          }
     }

//Числа
  SubStr="";
  for(j=1;j<=TempStr.Length();j++)
     {
       if (j==1 && (TempStr[j]=='+' || TempStr[j]=='-')) {SubStr+=TempStr[j];continue;}
       if (isdigit(TempStr[j]) || TempStr[j]=='.') {SubStr+=TempStr[j];continue;}

       if (j<TempStr.Length())
           if (TempStr[j]=='e' && isdigit(TempStr[j+1])) {SubStr+=TempStr[j];continue;}
       if (j<TempStr.Length())
           if (TempStr[j]=='e' && (TempStr[j+1]=='+' || TempStr[j+1]=='-'))
               {
                SubStr+=TempStr[j];j++;
                SubStr+=TempStr[j];
                continue;
               }
        break;
     }
   if (SubStr=="") return Error(UNDEFINED);
   else
      {
         TempStr.Delete(1,SubStr.Length());
         p->Next=new TN;p->Next->Prev=p;p=p->Next;p->Next=NULL;
         p->Type=NUM;
         p->Prior=5;
         p->Is=true;
         p->Value=atof(SubStr.c_str());
         p->pValue=&p->Value;
      }

l1:
if (len==TempStr.Length()) return Error(UNDEFINED);
len=TempStr.Length();
}

p->Next=new TN;p->Next->Prev=p;p=p->Next;p->Next=NULL;
p->Type=RS;p->Prior=5;

////////////////
///Level 2//////
////////////////
//Формирование дерева//
for(int i=0;i<cl+3;i++)
 {
   p=PriorScobka();
   ReplaceFunc12(p);
   if (p==N) break;
   if (ReplaceFunc0(p)==false) return false;
 }

if (i==cl+3) return Error(UNDEFINED);
N=N->Next;
delete N->Prev; N->Prev=NULL;
delete N->Next; N->Next=NULL;

return true;
}

