Click here to Skip to main content
6,292,426 members and growing! (9,600 online)
Email Password   helpLost your password?
Languages » C# » General     Beginner License: The Code Project Open License (CPOL)

A Command Line Calculator

By H. S. Masud

A Command Line Calculator using CodeDom
C#, Windows, .NET, Visual Studio, Dev
Posted:19 Nov 2005
Updated:24 Nov 2005
Views:30,441
Bookmarked:18 times
Unedited contribution
Announcements
Loading...
 
Search    
Advanced Search
printPrint   Broken Article?Report       add Share
  Discuss Discuss   Recommend Article Email
23 votes for this article.
Popularity: 3.87 Rating: 2.84 out of 5
14 votes, 60.9%
1
1 vote, 4.3%
2

3
1 vote, 4.3%
4
7 votes, 30.4%
5
  • Visit Author's Homepage

      Introduction

      A command line calculator which supports mathematical expression with scientific functions is vary useful for most of the developer. The calculator available with windows does not support most of the scientific functions. Most of the time, I could not feel comfortable with the calculator available with windows. I needed a calculator which will not restrict to write my expression. I may use some variables to store my result. Every time I needed simple calculation I had to face some problem with the windows calculator. To design such a calculator I designed a complete Mathematics library with MFC. The most difficult part I found to design such a calculator is the parsing logic. Later while working with .Net, runtime source code compilation makes the parsing logic very easier and interesting. I read some article on .Net CodeDom compilation. So, I decided to write a new command line calculator using CodeDom. It uses runtime compilation and saves the variables by serializing in a file. So, you can get the values of all the variables used in previous calculation.

       

      Description

       

      In this command line calculator the result is saved in a pre-defined variable called ans. User can declear his/her own variables to store result and can use later in different expression. The validation of variable name is same as C#. Similarly expression support is same as supported in C#.Net.

       

      Calculate function calculates an expression. It uses the saved variables. I have generated a code which has the declaration of the variables.

       

      How to use command line calculator

      Sample screenshot

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

      C:\Documents and Settings\hasan.masud>calculate 25*(3+5-(10/2))
      ans = 75

      Note: By default the result is saved in a pre defined variable called ans.

      C:\Documents and Settings\hasan.masud>calculate ans+10
      ans = 85

      Note: ans variable can be accessed withing the expression as the other variables does.

      C:\Documents and Settings\hasan.masud>calculate d=75/15+2
      d = 7

      Note: user can declare a new variable by assigning some expression to it. If the variable doesn't exist then it will automatically create a new variable otherwise it will overwrite it's value.

      C:\Documents and Settings\hasan.masud>calculate e=ans+d
      e = 92

      C:\Documents and Settings\hasan.masud>calculate +10
      ans = 95

      Note: If the user want's to use the ans variable at the begining of the expression then it is not mandatory to write ans. Just start the expression it will add the ans variable at the begining.

      C:\Documents and Settings\hasan.masud>calculate f=+10+e
      f = 197

      C:\Documents and Settings\hasan.masud>calculate s=Math.Sin(90)
      s = 0.893996663600558

      Note: User can use any functions available in Math class.

      C:\Documents and Settings\hasan.masud>calculate angle=90
      angle = 90

      C:\Documents and Settings\hasan.masud>calculate s1=Math.Sin(angle)
      s1 = 0.893996663600558

      C:\Documents and Settings\hasan.masud>calculate list
      7 variables found
      angle = 90
      ans = 95
      d = 7
      e = 92
      f = 197
      s = 0.893996663600558
      s1 = 0.893996663600558

      Note: User can view the list of variables stored.

      C:\Documents and Settings\hasan.masud>calculate clear

      Note: user can clear the variable lists.

      C:\Documents and Settings\hasan.masud>calculate list
      0 variables found

      C:\Documents and Settings\hasan.masud>calculate s1=Math.Sin(an gle)
      Invalid argument
      0 variables found

      Note: If any error occures then it displays an error message and the list of the variables.

      C:\Documents and Settings\hasan.masud>calculate r#=25+9
      Syntax Error
      0 variables found

      C:\Documents and Settings\hasan.masud>calculate 45=25+9
      Syntax Error
      0 variables found

      C:\Documents and Settings\hasan.masud>calculate maxint=int.MaxValue
      maxint = 2147483647

      Note: User can use any expression which will be compiled in a single line without any error.

      If user provides no arguments or invalid arguments then calculate will take the user to calculate console. In that case user does not have to write calculate every time. To exit from the calculate console just write bye in calculate console.

      New Feature


       

      Code Explanation

       

      ExpressionEvaluator class has two static methods. Calculate method accepts the expression as an agrument. Then it generates a class named myclass, which is inherited from the base class Calculate.MyClassBase and override the virtual function eval() to execute the expression.

       

      string src = @"using System; 
                                 class myclass:Calculate.MyClassBase {
               private double %MT_VARIABLES%;
                                       public myclass()
                                       {
                                       }
                                       public override double eval()
                                       {
               return " + expression + @";
                                       }
                                 }"; 

       

      %MT_VARIABLES% word in the src string variable is then replaced with the declaration of the variable list stored in the Variables class.

       

      string variables="ans=0";
         string []keys;
         keys=Variables.GetVariables().GetKeys();
         if(keys.Length>0)
          variables="";
         for(int i=0;i<keys.Length;i++)
         {
          variables=variables+keys[i]+"="+Convert.ToString(Variables.GetVariables()[keys[i]]);
          if(i<keys.Length-1)
           variables=variables+",";
         }
         src=src.Replace(@"%MT_VARIABLES%",variables);

      The executable of this application is referenced while compiling the generated code.

       

      Microsoft.CSharp.CSharpCodeProvider cp = new Microsoft.CSharp.CSharpCodeProvider();   
         System.CodeDom.Compiler.ICodeCompiler ic = cp.CreateCompiler();   
         System.CodeDom.Compiler.CompilerParameters cpar = new System.CodeDom.Compiler.CompilerParameters();   
         cpar.GenerateInMemory = true;   
         cpar.GenerateExecutable = false;   
         cpar.ReferencedAssemblies.Add("system.dll");   
         cpar.ReferencedAssemblies.Add(Process.GetCurrentProcess().MainModule.FileName);   

       

      Once the code to execute the expression it is compiled with the C# compiler. If no error found in the generated source code, Activator class creates an instance of the class myclass.

       

      System.CodeDom.Compiler.CompilerResults cr = ic.CompileAssemblyFromSource(cpar,src);   
         foreach (System.CodeDom.Compiler.CompilerError ce in cr.Errors)
         {
          throw new Exception(ce.ErrorText);
         }
         if (cr.Errors.Count == 0 && cr.CompiledAssembly != null)   
         {    
          Type ObjType = cr.CompiledAssembly.GetType("myclass");    
          try    
          {     
           if (ObjType != null)     
           {      
            myobj = (MyClassBase)Activator.CreateInstance(ObjType);     
           }    
          }    
          catch (Exception ex)    
          {     
           throw ex;
          }    
          return myobj.eval();   
         }   
         else
         {
          throw new Exception("Failed to compile");
         }
      

       

      ExpressionCalculator class has another method which returns true if compilation of the source code is successfull otherwise it returns false. This function is used to validate the variables name in Calculator class.

       

      private bool CheckVariableName(string variableName)
        {
         string src = @"using System; 
                                 class myclass{
               private double %MT_VARIABLES%;
                                       public myclass()
                                       {
               %MT_VARIABLES%=0.0;
                                       }
                                 }"; 
         src=src.Replace("%MT_VARIABLES%",variableName);
         return ExpressionCalculator.IsCompiled(src);
        }
      
      

       

      Variables class is a serializable collection class, which  uses a SortedList to store the variable name and values. It has static method to manage the singletone and to save, load the variables. It uses binary serialization to serialize the SortedList and saves in a file named variables.dat in the application path.


       

      Calculate class has the main entry point. It uses the first argument as an expression or command used in this application. To manage calculate console there is a function name ManageConsole in Calculate Class.


       

      private void ManageConsole()
        {
         Console.WriteLine("Type bye to exit the calculate console.");
         string expression;
         while(true)
         {
          Console.Write("Calculate>");
          expression=Console.ReadLine();
          if(expression.Trim().ToUpper()=="BYE")
          {
           return;
          }
          CalculateExpression(expression);
         }
         
        }
      
      

       

      CalculateExpression parse the expression and provide fanctionality for the calculator.

       

       

      It suports only two commands

       

      list: It displays list of the variables with values. It invokes PrintList method of the class Calculator

       

      private void PrintList()
        {
         string []keys;
         double ans;
         keys=Variables.GetVariables().GetKeys();
         Console.WriteLine(keys.Length + " variables found");
         for(int i=0;i<keys.Length;i++)
         {
          ans=Variables.GetVariables()[keys[i]];
          Console.WriteLine(keys[i] + " = " + ans);
         }
        }
      


      clear: This command clears the Variables.

       

      The expression is splitted with '=' character. If '=' character is found then the first part of the splitted string is treated as a variable name and the second part is treated as the expression. If the variable name is available then it checks the validaty and the result is stored with the given variable name. If the variable name is not present then it stores the result in a pre-defined variable named ans. If an operator is found at the first character of the expression then I added the ans variable at the begining of the expression to complete the expression. It saves the user not to write ans again and again if he/she want's to use the ans variable.

       

      string []commands=commandStr.Split(("=").ToCharArray());
           if(commands.Length==2)
           {
            commands[0]=commands[0].Trim();
            if(calc.CheckVariableName(commands[0])==false)
            {
             Console.WriteLine("Syntax Error");
             calc.PrintList();
             return;
            }
            commandStr=commands[1];
           }
           string op=commandStr.Substring(0,1);
           if(("+-*/").IndexOf(op)>=0)
            commandStr="ans"+commandStr;
           ans=ExpressionCalculator.Calculate(commandStr);
           if(commands.Length==2)
           {
            Variables.GetVariables()[commands[0]]=ans;
            Console.WriteLine(commands[0] + " = " + ans);
           }
           else
           {
            Variables.GetVariables()["ans"]=ans;
            Console.WriteLine("ans = " + ans);
           }
    • License

      This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

      About the Author

      H. S. Masud


      Member

      Occupation: Software Developer (Senior)
      Company: KAZ Software Limited
      Location: Bangladesh Bangladesh

      Other popular C# articles:

      Article Top
      You must Sign In to use this message board.
      FAQ FAQ 
       
      Noise Tolerance  Layout  Per page   
       Msgs 1 to 16 of 16 (Total in Forum: 16) (Refresh)FirstPrevNext
      General[My vote of 2] close but no cigar Pinmembermandip_goshal4:42 20 May '09  
      GeneralA small change I made PinmemberAndrewTaylor3:36 20 Jun '08  
      Generalit crashes on EOF Pinmembergrregd2:50 6 Mar '08  
      GeneralNot working under .NET 2.0 Pinmemberneclepsio23:26 24 Jun '06  
      GeneralRe: Not working under .NET 2.0 Pinmemberfdafdafdsa13:52 21 Nov '06  
      Generaltrying to port this to mono Pinmemberanime4christ12:40 5 Jan '06  
      AnswerRe: trying to port this to mono PinmemberH. S. Masud0:36 7 Jan '06  
      GeneralRe: trying to port this to mono Pinmemberanime4christ17:31 7 Jan '06  
      GeneralSome suggestions PinmemberPatrickLorenz19:49 22 Nov '05  
      AnswerRe: Some suggestions PinmemberH. S. Masud23:34 22 Nov '05  
      GeneralRe: Some suggestions PinmemberPatrickLorenz23:54 22 Nov '05  
      AnswerRe: Some suggestions PinmemberH. S. Masud2:41 24 Nov '05  
      GeneralRe: Some suggestions PinmemberPatrickLorenz4:16 24 Nov '05  
      AnswerRe: Some suggestions PinmemberH. S. Masud23:46 25 Nov '05  
      GeneralNice! PinmemberWouter van Vugt8:51 22 Nov '05  
      AnswerRe: Nice! PinmemberH. S. Masud23:14 22 Nov '05  

      General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

      PermaLink | Privacy | Terms of Use
      Last Updated: 24 Nov 2005
      Editor:
      Copyright 2005 by H. S. Masud
      Everything else Copyright © CodeProject, 1999-2009
      Web16 | Advertise on the Code Project