#include <conio.h>
#include <iostream.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include <stack.cpp>
void HelpFunc();
void PutErrors(int NumErr,int Pos);
int chifra(int num);
int bukva(int num);
int operand(int num);
int prty(char x);
long double fop(char op,long double a,long double b);
enum { POW='^',MUL='*',DIV='/',PLUS='+',MINUS='-',NOT='!',AND='&',OR='|',
LB='(',RB=')',POINT='.',
//данные операторы заменяют функции син.кос.тан. и т.д.
SIN='$',TG='`',COS='~',LOG=':',LN=';',EXP='@',FABS='#'};
char buffer[180], memory[180];
int len,i=0,error=0,flagMin=0;//флаг отрицателной переменной
long double value=0,a=0;
TCStack st_op;//стек операторов
TFStack st_num;//стек чисел
void main()
{
for(;;){
clrscr();
int skoba=0;
error=0;
while(st_op.nonEmpty())
st_op.pop();
while(st_num.nonEmpty())
st_num.pop();
cout <<"exit - выход\n\t\t\t help-справка\n\n";
cout << "Введите выражение: ";
cin >> buffer;
if(!strcmp(buffer,"exit")) exit(1);
if(!strcmp(buffer,"help")) HelpFunc();
len=strlen(buffer);
for(i=0;i<len;i++)
{
//***** PROVERKA
// на наличие скобок
if(buffer[i]=='(') skoba++;
if(buffer[i]==')') skoba--;
if(skoba<0) {PutErrors(10,i);i=len-1;}//много )
//***** END PROVERKA
}
i=0;
if(skoba>0) PutErrors(9,skoba+2); //много (
if(!error)
do
{
int flag=0,flag1=0;
flag=isdigit(buffer[i]);
if(flag==0)
{
flag1=ispunct(buffer[i]);
if(flag1==0) // может это пременная запрашиваем значение
// и помещаем в глоб.переменную Value
{
int u=bukva(i);i=u-1;
if(buffer[i+1]==NOT)
PutErrors(2,i);
if(flagMin==1) {value=-value;flagMin=0;}
st_num.push (value);
}
else // усли это операнд или пунктуатор
{
int o=operand(i);i=o-1;
switch(buffer[i])
{
case NOT:
if(buffer[i+1]==AND || buffer[i+1]==OR ||
buffer[i+1]==POW || buffer[i+1]==PLUS||buffer[i+1]==DIV||
buffer[i+1]==MUL)
PutErrors(2,i);
else
//после "!" идет ! ^ или число или "("
st_op.push (buffer[i]); st_num.push(0);
break;
case LB://после открыв.скб. идет & | ! / * + - (null)/(0)
if(buffer[i+1]==AND || buffer[i+1]==OR ||
buffer[i+1]==POW || buffer[i+1]==PLUS||buffer[i+1]==DIV||
buffer[i+1]==MUL)
PutErrors(1,i);
if(buffer[i+1]==RB)
PutErrors(5,i);
else st_op.push (buffer[i]);
break;
case RB://после закр.скб. идет "(" или число
if(buffer[i+1]==NOT||buffer[i+1]==LB||(isdigit(buffer[i+1]))) PutErrors(6,i);
if(error==1)
;
else { while (st_op.peek ()!=LB)
st_num.push (fop (st_op.pop (), st_num.pop (), st_num.pop ()));
st_op.pop (); }
break;
case AND: case OR: case POW:case MINUS:case PLUS:case MUL:
case DIV:
//после опрераторов идет ")" или число /!/&/|/^
if(buffer[i+1]=='\0')
PutErrors(1,i);
if(buffer[i+1]==RB||((buffer[i]==POW||buffer[i]==AND||buffer[i]==OR||buffer[i]==PLUS)&&i==0)) PutErrors(1,i);
if(buffer[i+1]==AND||buffer[i+1]==OR||buffer[i+1]==DIV||
buffer[i+1]==POW||buffer[i+1]==MINUS||buffer[i+1]==PLUS||buffer[i+1]==MUL)
PutErrors(4,i);
if(MINUS&&isdigit(buffer[i+1])&&i!=0&&buffer[i-1]==LB)
flagMin=1;
else
{ while ((st_op.nonEmpty ())&&
(prty (buffer[i])<=prty (st_op.peek ())))
st_num.push (fop (st_op.pop (), st_num.pop (), st_num.pop ()));
st_op.push (buffer[i]);
}
break;
}
}
}
else // если это цифра
{
int y=chifra(i);i=y-1;
if(buffer[i+1]==NOT)
PutErrors(2,i);
if(flagMin==1) {a=-a;flagMin=0;}
st_num.push (a);
}
i++;
}while(i<len);
if(error!=1)
{while (st_op.nonEmpty ())
st_num.push (fop (st_op.pop (), st_num.pop (), st_num.pop ()));
if(error==0)
cout <<"\nРезультат: "<<st_num.pop ();
}
error=0;
cout << "\nНажмите любую клавишу";
getch();
}
}
/********* Если это переменная? **********/
int bukva(int num)
{
int flagb;
char aa=buffer[num];
strcpy(memory,&aa);
//Если следующий символ-буква или цифра, но не опрератор, то
//продолжаем перебор.
do
{
num++;
flagb=isalnum(buffer[num]);
if(flagb!=0)
{
aa=buffer[num];
strcat(memory,&aa);
}
}while(flagb!=0);
if(!strcmp(memory,"sin")&& buffer[num]==LB )
st_op.push(SIN);
else
if(!strcmp(memory,"cos")&& buffer[num]==LB )
st_op.push(COS);
else
if(!strcmp(memory,"tg")&& buffer[num]==LB )
st_op.push(TG);
else
if(!strcmp(memory,"ln")&& buffer[num]==LB )
st_op.push(LN);
else
if(!strcmp(memory,"log")&& buffer[num]==LB )
st_op.push(LOG);
else
if(!strcmp(memory,"exp")&& buffer[num]==LB )
st_op.push(EXP);
else
if(!strcmp(memory,"fabs")&& buffer[num]==LB )
st_op.push(FABS);
else
if(buffer[num]==LB)
PutErrors(3,num-1);
else
if(!error)
{cout << "\nБыла введена переменная " << memory <<" Ведите значение ";
cin >> value;
}
return num;
}
//********** Если это число *********/
int chifra(int num)
{
a=0;
int flagc=0;
char aa=buffer[num];
strcpy(memory,&aa);
//если следующий символ-цифра, то продолжаем перебoр
//если знак пунктуации или буква, то выходим.
do{
num++;
flagc=isdigit(buffer[num]);
if(flagc!=0)
{ aa=buffer[num]; strcat(memory,&aa); }
}while(flagc!=0);
//Если пoсле цифры сразу идет буква, то это ошибка (выходим)
if(isalpha(buffer[num]))
PutErrors(6,num-1);
if(ispunct(buffer[num])&&buffer[num]==POINT)
{flagc=0;
aa=buffer[num];
strcat(memory,&aa);
//если следующий символ-цифра, то продолжаем перeбoр
//если знак пунктуации или буква, то выходим.
do{
num++;
flagc=isdigit(buffer[num]);
if(flagc!=0)
{ aa=buffer[num]; strcat(memory,&aa); }
}while(flagc!=0);
}
if(ispunct(buffer[num])&&buffer[num]==POINT)
PutErrors(12,num);
//преобразуем строку цифр в число
a=atof(memory);
return num;
}
//******** Если это операнд или скобка
int operand(int num)
{
char aa=buffer[num];
switch(aa)
{
case AND:case OR:case LB:case RB: case NOT:case POW:
case PLUS: case MINUS:case MUL:case DIV: case POINT:
if((aa==POINT && num==0)||(aa==POINT && num!=0 && ispunct(buffer[num-1])))
PutErrors(12,num-1);
if(buffer[i]==NOT&&i==len-1)
PutErrors(1,i);
break;
default:
{PutErrors(7,num-1);}
}
strcpy(memory,&aa);
return num+1;
}
//************* Приоритет операций ************
int prty(char x)
{
switch(x)
{
case SIN:case COS:case TG:case LOG:case LN:case EXP:
case FABS:
return 6;
case NOT:
return 5;
case POW:
return 4;
case MUL: case DIV:
return 3;
case AND:case OR:
return 1;
case PLUS:case MINUS:
return 2;
default:return 0;
}
}
//**************** Выполнение действие
long double fop(char op,long double a,long double b)
{
switch(op)
{
case NOT:
{
if(b>256&&b<0) PutErrors(13,i-1);
else
return (int)(255-b);}
case POW: return (pow(a,b));
case DIV: if(!b) PutErrors(11,i-2); else return (a/b);
case MUL : return (a*b);
case PLUS : return (a+b);
case MINUS: return (a-b);
case AND : return ((int)a&(int)b);
case OR : return ((int)a|(int)b);
case SIN : return sin(b);
case COS : return cos(b);
case TG : return tan(b);
case LOG : return log10l(b);
case LN : return logl(b);
case EXP : return exp(b);
case FABS : return fabs(b);
default: return 0;
}
}
//BEGIN********* Функция вывода сообщений об ошибках *****************
void PutErrors(int NumErr,int Pos)
{
error=1;
cout <<"\n";
for(int i=0;i<=Pos;i++)
cout << buffer[i];
switch(NumErr)
{
case 1:
cout << "\nОШИБКА :\nПропущено число или переменная";
break;
case 2:
cout << "\nОШИБКА :\nНе правильное использование оператора 'НЕ'!(число)";
break;
case 3:
cout << "\nОШИБКА :\nМежду числом и левой скобкой отсутствует оператор";
break;
case 4:
cout << "\nОШИБКА :\nДва оператора подряд";
break;
case 5:
cout << "\nОШИБКА :\nВ скобках отсутствует выражение";
break;
case 6:
cout << "\nОШИБКА :\nОтсутствует оператор";
break;
case 7:
cout << "\nОШИБКА :\nНаберите help";
break;
case 8:
cout << "\nОШИБКА :\nВ выражении присутствуют пробелы";
break;
case 9:
cout << "\nОШИБКА :\nПропущена закрывающая скобка";
break;
case 10:
cout << "\nОШИБКА :\nНет открывающей скобки";
break;
case 11:
cout << "\nОШИБКА :\nДеление на ноль";
break;
case 12:
cout << "\nОШИБКА :\nНе правильно введено число с плавающей точкой";
break;
case 13:
cout << "\nОШИБКА :\nВведите число от 0 до 255";
break;
}
}
//END************* Функция вывода сообщений об ошибках *********
//**************** - help - *********
void HelpFunc()
{
error=1;clrscr();
cout <<"\n\t\t Транслятор алгебраических выражений"<<
"\n\nВ данной программе используются следующие операторы и функции:"<<
"\n\n sin(x)\n cos(x)\n tg(x)\n ln(x)\n log(x)\n fabs(x)"<<
"\n !x\t\t\-'инвертирование'\n x&y\t\t-'И'\n x|y\t\t-'ИЛИ'\n x^y\t\t-'возведение в степень' "<<
"\n x*y\t\t-'умножение'\n x/y\t\t-'деление'\n x+y\t\t-'сумма'\n x-y\t\t-'разность'";
cout <<"\n\nПри использовании тригонометрических функций аргумент задается в радианах\n";
}