Wednesday, March 30, 2005
Basic Calculator Application
With the intension of building simple parser I made a move to get calculator application that supports variables and dynamic value fetch etc. Well I am falling short of text to put into here to describe my excitement. I am putting below the source code so that you can try it out. The application is written in C#.
Feedback and Suggestions are most welcome (Use comments to express them). Download
Feedback and Suggestions are most welcome (Use comments to express them). Download
View Calculator Code
Hide Calculator Code
/**
* Basic Calculator Application
* Author: Prasad.A
*/
using System;
using System.Collections;
namespace ConsoleCalculator {
/* Basic Calculator Class */
public class BaseCalculator {
/* Dictionary to store variables and its values */
private IDictionary _dictionary = null;
/* Stack to carry out the operations */
private Stack operationStack = null;
/* Default Constructor */
public BaseCalculator() {
this._dictionary = new Hashtable();
Console.WriteLine("Basic Calculator Application");
Console.WriteLine("Type 'quit' to terminate.");
}
/* Get the substring of the string */
private String GetSubString(String expression,int start,int end) {
return expression.Substring(start,(end-start));
}
/* Push element on to operation stack */
private void Push(Object element) {
operationStack.Push(element);
}
/* Pop element from the operation stack */
private Object Pop() {
if(operationStack.Count > 0) return operationStack.Pop();
return null;
}
/* Peek element from the operation stack */
private Object Peek() {
if(operationStack.Count > 0) return operationStack.Peek();
return null;
}
/* Evaluate the expression within '(' and ')' */
private void EvaluateSubExpression() {
Object element = Pop(); /* This is just behind ')' */
while(element != null && element.ToString().CompareTo("(") != 0) {
/* Get result from binary evaluation */
Object binaryEvaluation = BinaryEvaluate(element);
element = Pop(); /* This will be the operator for next iteration */
/* Did we get start of sub expression */
if(element.ToString().CompareTo("(")==0) {
/* Push the result and break out of loop */
Push(binaryEvaluation);
break;
}
/* Push back the operator that was popped */
Push(element);
/* Now one of the operand is the result itself */
element = binaryEvaluation;
}
}
/* Evaluate the expression */
private Object EvaluateExpression() {
Object result = null;
Object element = Pop(); /* This is operand two */
while(element!=null) {
/* Get result from binary evaluation */
result = BinaryEvaluate(element);
/* If we have reached end of stack, break */
if(Peek() == null) break;
/* Opearand two is result itself */
element = result;
}
return result;
}
/* Evaluate the binary expression, the input parameter is operand2,
* Get the operator element and operand1 from stack. If operator element
* or operand1 is not present do a unary operation else if operator element
* is = then do a assignment operation else do a binary evaluation.
*/
private Object BinaryEvaluate(Object operandTwo) {
Object evalBinary = new Object();
Object operatorElement = null;
Object operandOne = null;
if(Peek() != null &&
Peek().ToString().CompareTo("(")!=0)
operatorElement = Pop();
if(operatorElement != null &&
Peek() != null &&
Peek().ToString().CompareTo("(")!=0)
operandOne = Pop();
if(operatorElement!=null &&
operatorElement.ToString().CompareTo("=")!=0) {
operandTwo = GetObjectValue(operandTwo);
operandOne = GetObjectValue(operandOne);
}
if(operatorElement==null)
evalBinary = GetObjectValue(operandTwo);
else if(operandOne==null) {
if(operatorElement.ToString().CompareTo("+")==0)
evalBinary = (+1.0)*double.Parse(operandTwo.ToString());
else if(operatorElement.ToString().CompareTo("-")==0)
evalBinary = (-1.0)*double.Parse(operandOne.ToString());
}
else {
switch(operatorElement.ToString()) {
case "+":
evalBinary = double.Parse(operandOne.ToString())+
double.Parse(operandTwo.ToString()); break;
case "-":
evalBinary = double.Parse(operandOne.ToString())-
double.Parse(operandTwo.ToString()); break;
case "*":
evalBinary = double.Parse(operandOne.ToString())*
double.Parse(operandTwo.ToString()); break;
case "/":
evalBinary = double.Parse(operandOne.ToString())/
double.Parse(operandTwo.ToString()); break;
case "=":
SetIdValue(operandOne.ToString(),operandTwo.ToString());
evalBinary = null; break;
}
}
return evalBinary;
}
/* Parse the input string and evaluate as and when required */
private Object parse(String expression) {
operationStack = new Stack();
int parsePointer = 0; /* Points to beginning of token */
bool inIdentifier = false,inNumber = false;
for(int index=0; index < expression.Length; ++index) {
char ch=expression[index];
/* We got a identifier or number delimiter */
if(ch == ' ' || ch == '\t') {
if(inIdentifier) {
Push(GetSubString(expression,parsePointer,index));
parsePointer = index+1;
inIdentifier = false;
}
if(inNumber) {
Push(GetSubString(expression,parsePointer,index));
parsePointer = index+1;
inNumber = false;
}
}
/* We got start of sub expression */
else if(ch=='(') {
Push(ch.ToString());
parsePointer = index+1;
}
/* We got end of sub expression */
else if(ch == ')') {
if(inIdentifier) {
Push(GetSubString(expression,parsePointer,index));
parsePointer = index+1;
inIdentifier = false;
}
if(inNumber) {
Push(GetSubString(expression,parsePointer,index));
parsePointer = index+1;
inNumber = false;
}
EvaluateSubExpression();
}
/* We got assignment operator */
else if(ch=='=') {
if(inIdentifier) {
Push(GetSubString(expression,parsePointer,index));
inIdentifier = false;
}
Push(ch.ToString());
parsePointer = index+1;
}
/* We got arithmetic operator */
else if(isOperator(ch)) {
if(inIdentifier) {
Push(GetSubString(expression,parsePointer,index));
inIdentifier = false;
}
if(inNumber) {
Push(GetSubString(expression,parsePointer,index));
inNumber = false;
}
Push(ch.ToString());
parsePointer = index+1;
}
/* We got a letter and we are not in identifier */
else if(Char.IsLetter(ch) && !inIdentifier) {
inIdentifier = true;
}
/* We got a digit and we are not in number */
else if(Char.IsDigit(ch) && !inNumber) {
inNumber = true;
}
/* We got a decimal point */
else if(ch=='.') {
if(index < expression.Length-1 &&
!Char.IsDigit(expression[index+1])) {
Push(GetSubString(expression,parsePointer,index));
parsePointer = index+1;
inNumber = false;
}
}
/* We are in identifier and we got a identifier delimiter */
else if(inIdentifier && isIdDelimiter(ch)) {
Push(GetSubString(expression,parsePointer,index));
parsePointer = index+1;
inIdentifier = false;
}
/* We are in number and we got a number delimiter */
else if(inNumber && isNumberDelimiter(ch)) {
Push(GetSubString(expression,parsePointer,index));
parsePointer = index+1;
inNumber = false;
}
}
/* Are we still in identifier */
if(inIdentifier)
Push(GetSubString(expression,parsePointer,expression.Length));
/* Are we still in number */
else if(inNumber)
Push(GetSubString(expression,parsePointer,expression.Length));
/* Let us return the result of expression */
return EvaluateExpression();
}
/* Decide on the identifier delimiter */
private bool isIdDelimiter(char delim) {
if(delim=='.'||delim=='('||delim==')') return true;
return isOperator(delim);
}
/* Decide on the nubmer delimiter */
private bool isNumberDelimiter(char delim) {
if(delim=='('||delim==')') return true;
return Char.IsLetter(delim);
}
/* Decide on the operator */
private bool isOperator(char delim) {
if(delim=='+'||delim=='-'||delim=='*'||delim=='/'||delim=='=')
return true;
return false;
}
/* Get the value of input object
* return either number or variable value)
*/
private Object GetObjectValue(Object inputObject) {
Object valueObject = null;
try {
valueObject = GetNumberObject(inputObject.ToString());
} catch(FormatException fe) {
valueObject = GetIdValue(inputObject.ToString());
}
return valueObject;
}
/* Return the numeric representation of input string */
private Object GetNumberObject(String inputString) {
Object numberObject = null;
try {
numberObject = int.Parse(inputString);
} catch(FormatException fei) {
try {
numberObject = double.Parse(inputString);
} catch(FormatException fed) {
throw new FormatException("Error! Illegal number format");
}
}
return numberObject;
}
/* Set the variable and its value in _dictionary */
private void SetIdValue(String id,String val) {
Object number = null;
try {
number = GetNumberObject(val);
} catch(FormatException fe) {
number = GetIdValue(val);
}
if(number != null) _dictionary[id] = number.ToString();
}
/* Get the value of the variable from _dictionary */
private Object GetIdValue(String id) {
Object idValue = _dictionary[id];
if(idValue != null) return idValue;
throw new Exception("Error! Variable '"+id+"' not yet defined");
}
/* Core function to keep the interaction alive */
public void RunCalculator() {
while(true) {
Console.Write(">>> ");
String input = Console.ReadLine();
if(input.CompareTo("quit")==0)
break;
try {
Object result = parse(input);
if(result != null)
Console.WriteLine(result.ToString());
} catch(Exception ex) {
Console.WriteLine(ex.Message);
}
}
}
}
/* A user class that contains the main function
* To give life to calculator */
public class UserCalculator {
public static void Main(string[] args) {
BaseCalculator bc = new BaseCalculator();
bc.RunCalculator();
}
}
}
Basic Calculator Application
Type 'quit' to terminate.
>>> a=10.5
>>> b
Error! Variable 'b' not yet defined
>>> b=20
>>> b
20
>>> c=a+b
>>> c
30.5
>>> d=10.1+(b*c)/a
>>> d
68.1952380952381
>>> quit
# posted by Prasad.A : 11:43 PM