#include <iostream.h>
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
#include <math.h>
#include "stack.cpp"
class TFStack
{
private:
long double num[1000];
int inum;
public:
TFStack () { inum=0; };
~TFStack () {};
void push (long double &);
long double pop ();
long double peek ();
int nonEmpty () { return inum; };
};
void TFStack::push (long double &x)
{
num[inum++]=x;
}
long double TFStack::pop ()
{
if (inum>0) return num[--inum]; else return 0;
}
long double TFStack::peek ()
{
if (inum>0) return num[inum-1]; else return 0;
}
class TCStack
{
private:
int tok[1000], itok;
public:
TCStack () { itok=0; };
~TCStack () {};
void push (char &);
char pop ();
char peek ();
int nonEmpty () { return itok; };
};
void TCStack::push (char &x)
{
tok[itok++]=x;
}
char TCStack::pop ()
{
if (itok>0) return tok[--itok]; else return 0;
}
char TCStack::peek ()
{
if (itok>0) return tok[itok-1]; else return 0;
}
enum token_val {
NUMBER,
ADD='+', SUB='-', MUL='*', DIV='/', EXP='^',
BIG='>', SML='<', EQU='=', MOD='%', AND='&',
OR ='|', FAC='!', LBR='(', RBR=')', END='~'
};
token_val cur_tok;
enum { false, true };
int flDigit, flOp, flAlpha, flLB, flRB, flUSub;
// Синтаксический разбор выражения
int Err (int num, int pos)
{ char *e;
for (int i=0; i<pos; *(e+i++)=' '); *(e+pos)='\0';
cout << e << " ^ - ";
switch (num)
{
case 1: cout << "Пропущена операция, либо ошибочная переменная!\n";
break;
case 2: cout << "Пропущена операция!\n";
break;
case 3: cout << "Пропущена переменная / число!\n";
break;
case 4: cout << "Отсутствует выражение!\n";
break;
case 5: cout << "Неверная лексема!\n";
break;
case 6: cout << "Пропущена парная закрывающая скобка!\n";
break;
case 7: cout << "Лишняя закрывающая скобка!\n";
break;
case 8: cout << "Пропущена операция, либо лишняя закрывающая скобка!\n";
break;
};
return 1;
}
void SetFlags (char ch)
{
switch (ch)
{
case LBR:
flDigit=true; flOp=false; flAlpha=true;
flLB =true; flRB=false; flUSub =true; break;
case RBR:
flDigit=false; flOp=true; flAlpha=false;
flLB =false; flRB=true; flUSub =false; break;
case '0': case '1':case '2':case '3': case '4':
case '5': case '6':case '7':case '8': case '9':
flDigit=true; flOp=true; flAlpha=false;
flLB =false; flRB=true; flUSub =false; break;
case EXP: case MUL: case DIV: case ADD: case SUB:
case BIG: case SML: case EQU: case MOD: case AND:
case OR :
flDigit=true; flOp=false; flAlpha=true;
flLB =true; flRB=false; flUSub =false; break;
case FAC:
flDigit=false; flOp=true; flAlpha=false;
flLB =false; flRB=true; flUSub =false; break;
default:
if (isalpha (ch))
{
flDigit=true; flOp=true; flAlpha=true;
flLB =false; flRB=true; flUSub =false;
};
}
}
int DetectSintax (char *Str)
{ char ch, pch;
int CB=0;
flDigit=true; flOp=false; flAlpha=true;
flLB =true; flRB=false; flUSub =true;
for (int i=0; (ch=*(Str+i))!='\0'; i++)
{
switch (ch)
{
case '0': case '1':case '2':case '3': case '4':
case '5': case '6':case '7':case '8': case '9': case '.':
if (flDigit) SetFlags (ch); else { Err (2, i); return 0; }
break;
case EXP: case MUL: case DIV: case ADD: case SUB:
case BIG: case SML: case EQU: case MOD: case AND:
case OR : case FAC:
if (flUSub) SetFlags (ch);
else if (flOp) SetFlags (ch);
else { Err (3, i); return 0; };
break;
case LBR:
if (flLB) { SetFlags (ch); CB++; }
else if (isdigit (pch)||isalpha (pch)) { Err (2, i); return 0; }
else { Err (8, i); return 0; }
break;
case RBR:
if (flRB) { SetFlags (ch); CB--; }
else if (pch==LBR) { Err (4, i); return 0; }
else if (pch==EXP||pch==MUL||pch==DIV||pch==ADD||pch==SUB||
pch==BIG||pch==SML||pch==EQU||pch==MOD||pch==AND||
pch==OR||pch==FAC) { Err (3, i); return 0; }
break;
default:
if (isalpha (ch))
{
if (flAlpha) SetFlags (ch);
else if (isdigit (pch)) { Err (1, i); return 0; }
else if (pch==RBR) { Err (2, i); return 0; }
}
else { Err (5, i); return 0; }
} pch=ch;
};
if (((ch=*(Str+i-1))!=RBR)&&(!isalpha (ch))&&
(!isdigit (ch))&&(ch!=FAC)) { Err (3, i); return 0; }
else if (ch==FAC&&i==1) { Err (3, 0); return 0; }
else if (CB>0) { Err (6, i); return 0; }
else if (CB<0) { Err (7, i-1); return 0; }
return 1;
}
// Непосредственно вычисление выражения
token_val get_token (double *arg, FILE *f)
{ char ch, *var;
do
if (((ch=fgetc (f))==EOF)||(ch=='\n')||(ch==0)) return END;
while ((ch!='\n') && (isspace (ch)));
switch (ch)
{
case EXP: case MUL: case DIV: case ADD: case SUB:
case BIG: case SML: case EQU: case MOD: case AND:
case OR : case FAC: case LBR: case RBR:
return cur_tok=(token_val) ch;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
ungetc (ch, f); *arg=0;
fscanf (f,"%lf", arg);
return cur_tok=NUMBER;
default:
int i=0;
*(var+i++)=ch;
while (isalpha (ch=fgetc (f))||isdigit (ch)) *(var+i++)=ch;
*(var+i)='\0'; ungetc (ch, f);
cout << var << "="; cin >> *arg;
return cur_tok=NUMBER;
};
}
long double fop (char op, double a, double b)
{
switch (op)
{
case EXP: return pow (a, b);
case MUL: return a*b;
case DIV: if (b!=0) return a/b; else return 0;
case ADD: return a+b;
case SUB: return a-b;
case BIG: return a>b;
case SML: return a<b;
case EQU: return a==b;
case MOD: return (int)a%(int)b;
case AND: return (int)a&(int)b;
case OR : return (int)a|(int)b;
case FAC: long double f=1;
for (int i=1; i<=(int)a; f*=i++);
return f;
default : return 0;
}
}
int prty (token_val t)
{
switch (t)
{
case FAC: return 4;
case EXP: return 3;
case MUL: case DIV: return 2;
case ADD: case SUB: case BIG: case SML:
case EQU: case MOD: case AND: case OR: return 1;
default: return 0;
}
}
long double Exec ()
{ TCStack st_op;
TFStack st_num;
token_val t;
double x;
while ((t=get_token (&x, f))!=END)
{
switch (t)
{
case NUMBER:
st_num.push (x); break;
case LBR:
st_op.push (t); break;
case RBR:
while (st_op.peek ()!=LBR)
st_num.push (fop (st_op.pop (), st_num.pop (), st_num.pop ()));
st_op.pop (); break;
case MUL: case DIV: case ADD: case SUB:
case EXP: case BIG: case SML: case EQU:
case MOD: case AND:case OR:
while ((st_op.nonEmpty ())&&
(prty (t)<=prty ((token_val) st_op.peek ())))
st_num.push (fop (st_op.pop (), st_num.pop (), st_num.pop ()));
st_op.push (t); break;
case FAC:
st_num.push (fop (t, st_num.pop (), 0));
break;
}
}
while (st_op.nonEmpty ())
st_num.push (fop (st_op.pop (), st_num.pop (), st_num.pop ()));
return st_num.pop ();
}
void main ()
{ char str[100]="\x0";
clrscr ();
do
{
cout << ">> "; cin >> str;
if (str[0]=='q') break;
if (str[0]=='c') clrscr ();
else
{
if (DetectSintax (str)) cout << Exec () << "\n";
};
}
while (1);
}