Please help me in self documenting the program below.
All you have to do is, take a quick glance at the following code to see if you can understand what each part is doing. If you have any difficulty in understanding(at a quick glance that is!), please tell me, so that I can add a comment.
Also tell me if I need to change the order in which I defined the functions and classes to enhance readability!
I've already posted this question once at
http://www.daniweb.com/forums/thread102405.html
I was asked to make a lot of changes so I closed the thread, made the changes and is reposting the question.
/* Expression Evaluation Notebook
Program to read text from keyboard and write it into a file, after
evaluating all simple mathematical expressions in the text.* /
#include<fstream.h>
#include<conio.h>
#include<stdio.h>
#include<process.h>
#include<ctype.h>
/**********************Definitions of Data Structures Used*********************/
union element //used to store parsed elements
{ char sym; //for symbol
int ival; //for integer
float fval; //for float
};
struct info //information part of stack/queue
{ element el; //element
char flag; //flag to show type of element
};
class Queue
{ struct node
{ info inf;
node *next;
}*front,*rear;
public:
Queue()
{front=rear=NULL;}
void push(info n);
info pop();
info peek()
{return front->inf;}
};
class Stack
{ struct node
{ info inf;
node *next;
}*top;
public:
Stack()
{top=NULL;}
void push(info);
info pop();
info peek()
{return top->inf;}
};
/******************************End of definitions******************************/
//Defining Global objects and variables
fstream temp;
Queue expr;
int exp_flag;
/***************************Function declarations******************************/
char symb( char);
int insert();
void post_convert();
int evaluate();
int expression();
/****************************End of declarations******************************/
/*******************************Main Function**********************************/
void main()
{ clrscr();
temp.open("temp.mth",ios::out|ios::in);
char ch;
cin.get(ch);
while(ch!=7) //Read till ^G is encountered
{ exp_flag=0;
if(ch=='=')
{ cin.get(ch);
if(ch=='=') //If '==' is encountered,
exp_flag=expression(); //evaluate expression
else //if its a single '=', put into file
temp.put('=');
if(exp_flag) //if expression evaluation fails
cout<<"Error : Expression syntax error!!";
}
else //if no '=' is encountered, just write to file
temp.put(ch);
cin.get(ch);
}
getch();
}
/********************************End of Main***********************************/
/************************Other Function definitions****************************/
int expression() //converts infix expression to postfix and evaluates
{ exp_flag=0;
int fail=insert(); //to read expression, parse it and insert to
//queue
if(!fail)
{ post_convert(); //convert infix to postfix
fail=evaluate();
}
if(fail)
{ char in[81];
if(exp_flag==1) //Remove input expression if
while(temp.get()!=';'); //evaluation failed
return -1;
}
return 0;
}
int insert() //parse expression and insert into queue
{ int ctr=0,sign=1,MinusFlag=1; //flags to handle parantheses
//and unary minus
float factor;
char in[81];
info inf={ 0,0}; //element is by default integer
for(int i=0;i<81&&in[i-1]!=';';i++)
{ cin.get(in[i]); //read the expression without
if(isspace(in[i]))i--; //white spaces
}
for(i=0;in[i]!=';';i++) //parsing
{
if(symb(in[i]))
{
if(in[i]=='-'&&MinusFlag)
//If operator is unary
{ sign*=-1; //minus, change sign of
inf.flag=0; //'sign', set flag as
continue; //integer, and continue
}
else sign=1; //if symbol is not unary minus,
//reset 'sign' to 1
//check if operators and operands
//are entered alternately
if(symb(in[i])&&(symb(in[i+1])||in[i+1]==';'))
if(in[i+1]!='('&&in[i+1]!='-'&&in[i]!=')')
{ cout<<"Error!! too many operators!!!";
return -1;
}
if(in[i]=='(')
{ ctr++;
if(inf.flag!=2&&i!=0) //If there is no symbol
{ inf.el.sym='*'; //before '(', then
inf.flag=2; //multiply by default
expr.push(inf);
}
}
else if(in[i]==')')
ctr--;
if(ctr<0) //check if parantheses are balanced
{ cout<<"Error!!! More right paranthesis!!!";
return -1;
}
if(in[i+1]=='-') MinusFlag=1;
inf.flag=2; //element is a symbol(operator)
inf.el.sym=in[i];
expr.push(inf);
}
else if(isdigit(in[i]))
{ MinusFlag=0;
if(symb(in[i-1])||i==0) //if first digit of a number,
{ inf.flag=0; //reset flag
inf.el.fval=0.0; //reset el
inf.el.ival=(int)(in[i]-'0')*sign;
}
else if(inf.flag) //if float
{ factor/=10; //decrement the place value
//of last digit
inf.el.fval+=(in[i]-'0')*factor*sign;
}
else //if integer
inf.el.ival=10*inf.el.ival+(int)(in[i]-'0')*sign;
if(symb(in[i+1])||in[i+1]==';')
expr.push(inf);
}
else if(in[i]=='.') //if '.' is encountered, set flag to float
{ inf.el.fval=(float)inf.el.ival;
inf.flag=1; //INPUT is float type
factor=1; //Reset the place value
//of last digit added
if(symb(in[i+1])||in[i+1]==';')
expr.push(inf);
}
}
if(ctr>0) //if more left parantheses, balance with
while(ctr) //right parantheses in the end of expression
{ info inf={')',2};
expr.push(inf);
ctr--;
}
temp.write(in,i); //write the expression into file
exp_flag=1;
return 0;
}
char symb(char c) //function to set the precedence order
{ switch(c)
{ case '^':return 9;
case '/':return 8;
case '*':return 8;
case '+':return 7;
case '-':return 7;
case '(':return -1;
case ')':return 1;
default :return 0;
}
}
void post_convert()
{ Queue temp;
Stack symbols;
info psym,pexp={'(',2};
symbols.push(pexp); //push ')' into symbols stack
while(pexp.flag!=-5) //Till the end of expr queue
{ pexp=expr.pop();
if(pexp.flag==2) //if element is symbol,
{ psym=symbols.peek();
while((symb(psym.el.sym)>=symb(pexp.el.sym))
&&pexp.el.sym!='(')
{ psym=symbols.pop(); //push all operators of
temp.push(psym); //greater precedence
psym=symbols.peek(); //into expr
}
if(pexp.el.sym==')') //If the symbol from expr is ')',
symbols.pop(); //then remove '(' from the
//symbols stack
else //Else push the symbol into
symbols.push(pexp); //the symbols stack
}
else if(pexp.flag==-5) //when elements in queue ends
{ psym=symbols.pop(); //pop all elements from symbols
while(psym.el.sym!='(') //stack and push into temp
{ temp.push(psym);
psym=symbols.pop();
}
}
else //else pexp is operand and hence
temp.push(pexp); //push into temp
}
expr=temp; //now expr holds the postfix expression
}
int evaluate() //function to evaluate the postfix expression
{ Stack eval;
info pexp,op1,op2,res;
pexp=expr.pop();
do
{ if(pexp.flag==1||pexp.flag==0) //if element is a number
eval.push(pexp); //push into stack
else if(pexp.flag==2) //if element is operator,pop
{ op2=eval.pop(); //last 2 elements from stack
op1=eval.pop();
if(op1.flag||op2.flag) //if op1 or op2 is float type
res.flag=1; //the result is float
else if(op1.flag==-5) //else if there is no element
cout<<"Too less operands"; //in stack, display error
else //else
res.flag=0; //the result is int type
switch(pexp.el.sym) //do the operation
{ case '+' :if(res.flag)
res.el.fval=
(op1.flag?op1.el.fval:op1.el.ival)+
(op2.flag?op2.el.fval:op2.el.ival);
else
res.el.ival=
(op1.flag?op1.el.fval:op1.el.ival)+
(op2.flag?op2.el.fval:op2.el.ival);
break;
case '-' :if(res.flag)
res.el.fval=
(op1.flag?op1.el.fval:op1.el.ival)-
(op2.flag?op2.el.fval:op2.el.ival);
else
res.el.ival=
(op1.flag?op1.el.fval:op1.el.ival)-
(op2.flag?op2.el.fval:op2.el.ival);
break;
case '*' :if(res.flag)
res.el.fval=
(op1.flag?op1.el.fval:op1.el.ival)*
(op2.flag?op2.el.fval:op2.el.ival);
else
res.el.ival=
(op1.flag?op1.el.fval:op1.el.ival)*
(op2.flag?op2.el.fval:op2.el.ival);
break;
case '/' :if(res.flag)
res.el.fval=
(op1.flag?op1.el.fval:op1.el.ival)/
(op2.flag?op2.el.fval:op2.el.ival);
else
res.el.ival=
(op1.flag?op1.el.fval:op1.el.ival)/
(op2.flag?op2.el.fval:op2.el.ival);
break;
default :cout<<"\nError!!in eval";return-1;
}
eval.push(res); //after operation, push the result back
//into stack
}
pexp=expr.pop(); //pop next element from queue
}while(pexp.flag!=-5); //until the end of queue
res=eval.pop(); //pop the last element in the eval stack
op1=eval.pop(); //check if it is indeed the last element
if(op1.flag!=-5)
return -1;
//display the result
cout<<"OUTPUT of expressions in the last line : "
<<(res.flag?res.el.fval:res.el.ival)<<'\n';
//write into file
temp<<'$'<<'#'; //flag to signal beg of expression result
temp.write((char*) &res,sizeof res);
temp<<'$'<<'#'; //flag to signal end of expression result
return 0;
}
/*******************************End of Definitions****************************/
/***********************Definition of Queue class functions*******************/
void Queue::push(info n)
{ if(front==NULL) //If queue has no elements
front=rear=new node; //start queue
else //If it has elements
{ rear->next=new node; //add node to the end
rear=rear->next;
}
if(rear==NULL) //if node cannot be created show error
{cout<<"Error cannot insert in Q";return;}
rear->inf=n; //add information in the node
}
info Queue::pop()
{ if(front==NULL) //if underflow, send info
{ info temp={0,-5}; //with flag set as -5
return temp;
}
//else return the element from the front and delete the node
info temp=front->inf;
node *temptr=front;
if(front==rear) front=rear=NULL;
else
front=front->next;
delete temptr;
return temp;
}
/*******************************End of Definitions****************************/
/*********************Function Definitions of Stack Class**********************/
void Stack::push(info n)
{ node* temp=new node; //create node
if(temp==NULL) //if node creation failed show error
{ cout<<"Cannot insert into stack!!!";
return;
}
temp->inf=n; //add information into node
temp->next=top;
top=temp; //update top
}
info Stack::pop()
{ if(top==NULL) //if underflow, return info with flag
{ info temp={0,-5}; //set as -5
return temp;
}
info n=top->inf;
node* temp=top;
top=top->next; //update top
delete temp;
return n; //return the info on top element
}
/********************************End of Definitions***************************/