支持函数,变量的算术表达式计算(三、加入函数)

工作好忙。。。所以现在才来更新。。。

有了前面的铺垫,要加入功能就很简单了,下面我们加入对函数的支持

一、函数的要点有3个
1. 名称: 没有名字可程序就不能识别了,呵呵
    例: Sin, Cos, Abs 等
2. 参数:一个函数至少要有一个参数,参数必须放到括号里, 多个参数用逗号(,)分隔
3. 计算:函数必须有一个输出值

二、了解了这几点,加入函数的功能还是比较容易的
1.根据函数的要点定义基类 FunctionBase, 加入一些属性
a.名称
        protected string name;
        
/// <summary>
        
/// 函数名称
        
/// </summary>

        public string Name
        
{
            
get return name; }
            
set { name = value; }
        }
 b.参数
        protected decimal?[] data;
        
/// <summary>
        
/// 参数数组(储存传入的参数)
        
/// </summary>

        public decimal?[] Data
        
{
            
get return data; }
            
set { data = value; }
        }

        
protected int paramCount;
        
/// <summary>
        
/// 指明参数的个数
        
/// </summary>

        public int ParamCount
        
{
            
get return paramCount; }
        }
c. 计算
        /// <summary>
        
/// 计算(定义为虚函数)
        
/// </summary>
        
/// <returns></returns>

        public abstract object Calc();
2. 解析表达式的时候, 加入对函数的支持
再第二章的ConvertExpression结尾,已经有对函数的支持了,贴一小段看看
default:
                            
//数字
                            if (char.IsDigit(c))
                            
{
                                ProcDigit(
ref i, ref strExpression);
                            }

                            
else //其它的字符全当成函数
                            {
                                ProcFunc(
ref i, ref strExpression);
                            }

                            
break;


ProcFunc 函数和其它的 ProcXXXX 函数差不多, 无非就是对字符的解析
        private void ProcFunc(ref int index, ref string expression)
        
{
            
if (needOp)
                
throw new ExpressionException("缺少操作符"1001);

            StringBuilder str 
= new StringBuilder();
            
for (int i = index; i < expression.Length; i++)
            
{
                
char c = expression[i];
                
if (char.IsWhiteSpace(c) || c == '(')
                
{
                    
this.needParentheses = true;
                    
break;
                }

                
else
                
{
                    str.Append(c);
                }

                index 
= i;
            }

            
string strFunc = str.ToString();
            
//函数是否正确
            if (!FuncFactory.IsValidFunc(strFunc))
                
throw new ExpressionException("函数名无效:" + strFunc, 2001);
            
else
                stackOp.Push((OperatorType)FuncFactory.GetFuncIndex(strFunc));
        }

3. 修改 CalcOperator 函数, 加入对函数的计算
            if (IsBaseOperator(op))
            
{
                //第二章中的基本四则运算, 代码可参见第二章

            }

            
else if (IsFunc(op))
            
{
                FunctionBase func 
= FuncFactory.GetFunc((int)op);
                
if (func == null)
                    
throw new ExpressionException("不可识别的函数名.");
                
else
                
{
                    func.Data 
= data;
                    
try
                    
{
                        
return func.Calc();
                    }

                    
catch (Exception ex)
                    
{
                        
throw new ExpressionException("函数计算出错:" + ex.Message, 9000);
                    }

                }

            }
三、编写具体的函数
a . 函数工厂类 FuncFactory , 根据函数名称返回具体的函数类, 略。。。
b. 编写一个 sqrt 函数,作为实例,可自行添加任意函数
    /// <summary>
    
/// 开平方
    
/// </summary>

    public class FuncSQRT : FunctionBase
    
{
        
public FuncSQRT()
        
{
            
//参数名称和参数个数一定要设置正确
            
//否则在解析的时候会出错
            paramCount = 1;
            name 
= "SQRT";
        }

        
/// <summary>
        
/// 计算
        
/// 函数类实现这一步就行了, 简单吧
        
/// </summary>
        
/// <returns></returns>

        public override object Calc()
        
{
            
if (data[0== null)
                
return DBNull.Value;
            
return Math.Sqrt((double)data[0]);
        }

    }

PS:前面有个朋友说缺少幂运算, 呵呵, 加上这个很简单
看看加入了函数和幂运算的效果 :)

下载程序
posted @ 2008-03-26 17:06 在天空飞翔 阅读(2232) 评论(6)  编辑 收藏 所属分类: C#

  回复  引用  查看    
#1楼 2008-03-26 17:29 | Edward.Net      
兄弟你这么做貌似太辛苦了吧,直接用Antlr写一个语法文件编译一下就全部搞定了。
  回复  引用  查看    
#2楼 2008-03-26 17:33 | RicCC      
这样练习一下也不错
看看Antlr生成的代码,参考一下它的LL解析过程会更有收获
  回复  引用  查看    
#3楼 2008-03-26 17:49 | 代码乱了      
对,还是推荐使用此法分析器,例如Antlr,

  回复  引用    
#4楼 2008-03-27 14:18 | 力大无比 [未注册用户]
神奇的表达式
  回复  引用    
#5楼 2008-07-08 11:23 | hj6 [未注册用户]
关于您的提示“参数名称和参数个数一定要设置正确,否则在解析的时候会出错”,必须在写函数的时候就指定参数个数吗?如果参数的个数不确定该怎么办啊?比如我准备增加一个MIN函数,来获取数组中的最小值,但这个数组时不定长的,该如何处理?谢谢您,请您指点,谢谢。

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
"五向定位"职业成长路线公开课(上海、南京、大连)
Google站内搜索


相关链接: