zoukankan      html  css  js  c++  java
  • 基于C#语言的可编程表达式计算器设计

    基于C#语言的可编程表达式计算器设计
               
          电子科技大学软件学院03级 周银辉
                            转载请注明出处
    1. 说明:

       先看看我们的成果:
    p_cal_main.bmp
     
       网上的表达式计算器有很多,但这次我们来点,不同的,有两点:
       1)用户可以编程以扩充计算器的函数
         即右下角那个“添加函数按钮”
         比如,我们想增加一个"Factarial"阶乘函数,我们可以“添加函数”
    p_cal_addFun.bmp
     
    然后编辑我们的函数
    p_cal_edit.bmp
     
      最后“生成”即可,主窗口上会自动添加一个"Factarial"按钮,然后就可以使用了(该函数将一直存在,除非你手动删除它)
      其实,主窗口上的所有函数按钮都是这样生成的

       2)我们对表达式的计算将摆脱传统的观点(即传统的对表达式进行词法分析,语法分析等等),在编写我们的计算器的代码中,不会有任何的词法分析、语法分析、后缀表达式转换等
       等。
         启发来自于这里:
         假设有一个函数F
         double F()
         {
             double r = 3*4.5+sin(50);
             return r;
         }

         那么,我们就可以 Console.WriteLine("{0}",F());    
         我们计算了3*4.5+sin(50),但我们有进行麻烦的词法分析与语法分析吗?没有,谁帮我们做了,编译器,ok,关键就在这:如果计算器用户在计算器主窗口上输入表达式
         3*4.5+sin(50),我们负责把它传给F中的r,然后我们再把F的返回值输出到用户界面上就OK了,我们要做的就这些。
        

    2 计算器上的函数
      2.1 函数按钮对应的函数在哪里?
          在Functions.dll中,不要指望这我微软给我们的,因为函数是用户编写的,我们也不知道用户会编写什么样的函数,他甚至可以编写一个播放音乐的函数(呵呵,我们的计算器
    完全可以做到这点,不过似乎对于一个计算器来说这有些过分了)
      2.2 谁来负责Functions.dll的生成?
          不是.net2003,不是.net2005,是我们的计算器
          要在用户自定义函数的时候将函数打包到Functions.dll中,就涉及到一个编译问题,我们将负责这一工作
      2.3 谁给了我们编译的权利?
          System.CodeDom.Compiler和Microsoft.CSharp名字空间中有我们的答案(请参见Msdn)

          我们的Functions.dll打包成功以后,我们就可以在计算表达式是调用其中的函数了


    3 表达式的计算
       3.1 如何计算?
           在前面计算 3*4.5+sin(50)的例子中,已经说过,我们将利用编译器帮我们计算,我们仅仅像Console.WriteLine("{0}",F())一样简单地将函数F的返回值输出给用户(F的返回值就是表达式的值):
         double F()
         {
             double exp = 3*4.5+sin(50);//假设3*4.5+sin(50)就是用户输入的表达式
             return exp;
         }
       3.2 F()从哪里来?到哪里去?
       F()肯定不是我们事先写好的,因为其中的exp的初始表达式是用户来写的
       我们将这样来解决这一问题:在用户输入表达式以后动态地生成函数F()的代码 -> 将该代码编译 -> 调用编译成功后的程序集中的该函数
            /// <summary>
            /// 将数学表达式转化为C#程序
            /// </summary>
            /// <param name="express">用户输入的数学表达式</param>
            /// <returns>返回C#程序代码</returns>
            public static string TranslateToCSharp(string express)
            {
                string s = "";
                if (File.Exists(Function.GetPathOfFunctionDll()))
                {
                    s += "using "+Function.FunctionNameSpace + ";\n";
                }
                
                s +=
                 "using System;\n" +
                 "namespace ComputeUnit\n" +
                 "{\n" +
                    "public class Compute\n" +
                    "{\n" +
                    "   public static double GetResult()\n" +
                    "   {\n" +
                    "      return "+  TranslateToCSharpExpress(express) + ";\n"+
                    "   }\n" +
                    "}" +
                "}\n";

                return s;
            }
         这里的GetResult()函数也就是我们所说的函数F()
          
          3.3 谁帮我们取得计算结果?
              反射!
             
              假设用户输入了表达式express,我们将如同下面的代码所叙述的那样计算它

              string source = TranslateUnit.TranslateToCSharp(express);

                //这里加载了函数dll
                string[] dlls = new string[1];
                dlls[0] = Function.GetPathOfFunctionDll(); //这里加载了前面所说的Functions.dll
                 //编译
                CompilerResults results = CompilerUnit.Compile(source, false,true, dlls,null);

                //重要:利用反射获取计算结果
                if (results.Errors.Count == 0)
                {
                    Assembly ass = results.CompiledAssembly;

                    Type tp = ass.GetType("ComputeUnit.Compute");//ass.GetType("MyNamespace.MyClass");

                    // 获取方法
                    MethodInfo mi = tp.GetMethod("GetResult");//tp.GetMethod("MyMethodl");

                    // 创建实例
                    Object obj = System.Activator.CreateInstance(tp);

                    //执行方法
                    try
                    {
                        object res = mi.Invoke(obj, null);
                        this.Output(res.ToString(), false, Color.Blue); //将计算结果输出给用户

                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.ToString());
                    }


    以上仅仅简要叙述了此程序的核心问题,除此之外还有许许多多的细节问题,如果需要了解更多,你可以下载此程序的源代码https://files.cnblogs.com/zhouyinhui/ProgramCalculator.rar,里面有详细的注释



    TrackBack:http://zhouyinhui.cnblogs.com/articles/390797.html
  • 相关阅读:
    call和applay
    判断传入的参数是否包含空
    通过函数修改文件中指定字符串
    任一个英文的纯文本文件,统计其中的每个单词出现的个数(注意是每个单词)
    下载进度条实现
    Python 用户登录判断,数据结构-字典
    python 字符串(str)和列表(list)互相转换
    网络编程01
    OpenGL入门学习
    程序的音频输出
  • 原文地址:https://www.cnblogs.com/hdjjun/p/1561915.html
Copyright © 2011-2022 走看看