上一篇中提到了用树形结构来分析表达式并计算求值的思路。但对程序来说,输入的表达式只是一个字符串而已。要将表达式表示成树型结 构,首先必须可以将表达式分解成一个个节点,然后才可以由节点组成树。这里将树上的每一个节点称之为记号对象TokenRecord。
根据上面的分析得出,记号对象要求有一个存储自身值的变量,有自己特定的计算方法,还要能知道其下级的值。由此可以得出 TokenRecord的基本信息(略去非关键信息):
属性
Index:在表达式中的列号,int类型,出错时用于指示错误所在,从1开始。
Priority:优先级,int类型,在分析表达式的时候需要。
TokenValue:记号值,object类型
ChildList:下级列表,List对象,用来存储下级元素,实现树结构。
方法
Execute:执行该元素的操作,abstract方法。
SetChildCount:设置下级数量,虚方法,用于检查下级数量合法性,在构造函数中调用。对应有一个m_ChildCount字段,用于存储下级数 量。因为检查下级属于元素内部的任务,所以将m_ChildCount设置为protected,也没有对应的ChildCount属性。
SetPriority:设置优先级,虚方法,在构造函数中调用。
CheckChildCount:检查下级数量,在Execute中调用,保证表达式合法。
其中TokenValue属性使用object类型是因为这里支持字符串、数值和逻辑值的运算。在最开始设计的时候,曾经采用过两个字段string和 double类型来存储字符串和数值,逻辑值也用数值表示,后来改成object更简单了。
TokenRecord类的代码如下:
/// <summary>
/// 记号对象
/// </summary>
/// <remarks>Author:Alex Leo;</remarks>
public abstract class TokenRecord
{
#region 属性和字段
//下级个数
protected int m_ChildCount;
private int m_Index;
/// <summary>
/// 列序号
/// </summary>
public int Index
{
get { return m_Index; }
}
/// <summary>
/// 优先级,必须赋值
/// </summary>
protected int m_Priority;
/// <summary>
/// 优先级
/// </summary>
/// <returns></returns>
public int Priority
{
get { return m_Priority; }
}
private int m_Length;
/// <summary>
/// 操作符长度
/// </summary>
public int Length
{
get { return m_Length; }
}
private Type m_TokenValueType;
/// <summary>
/// 记号值类型
/// </summary>
public Type TokenValueType
{
get { return m_TokenValueType; }
set { m_TokenValueType = value; }
}
private object m_TokenValue;
/// <summary>
/// 记号值
/// </summary>
public object TokenValue
{
get { return m_TokenValue; }
set { m_TokenValue = value; }
}
private List<TokenRecord> m_ChildList = new List<TokenRecord>();
/// <summary>
/// 下级列表
/// </summary>
public List<TokenRecord> ChildList
{
get { return m_ChildList; }
}
#endregion
/// <summary>
/// 构造函数
/// </summary>
/// <param name="Index">序号</param>
/// <param name="Length">自身长度</param>
public TokenRecord(int Index, int Length)
{
this.m_Index = Index;
this.m_Length = Length;
this.SetPriority();
this.SetChildCount();
}
#region 方法
/// <summary>
/// 重写ToString方法
/// </summary>
/// <returns></returns>
public override string ToString()
{
//可以根据需要修改以显示不同的信息
return this.GetType().Name + "_" + GetValueString() + "_" + TokenValueType.ToString();
}
/// <summary>
/// 获取值的字符串表示
/// </summary>
/// <returns></returns>
public string GetValueString()
{
return this.TokenValue.ToString();
}
/// <summary>
/// 检查下级数量,必要时可以重写,因为有些Token的下级数量可以是一个区间
/// </summary>
/// <param name="ErrorInformation">下级数量不符时显示的错误信息</param>
internal void CheckChildCount(string ErrorInformation)
{
if (this.m_ChildList.Count != this.m_ChildCount)
throw new SyntaxException(this.m_Index, this.m_Length, ErrorInformation);
}
#region 必须重写的方法
/// <summary>
/// 执行代码
/// </summary>
public abstract void Execute();
/// <summary>
/// 设置下级数量
/// </summary>
protected abstract void SetChildCount();
/// <summary>
/// 设置优先级
/// </summary>
protected abstract void SetPriority();
#endregion
#endregion
#region 转换记号值类型
/// <summary>
/// 将记号值转换为字符串类型
/// </summary>
internal string ChangeTokenToString()
{
string strValue;
strValue = (string)(this.TokenValue = this.TokenValue.ToString());
this.TokenValueType = typeof(string);
return strValue;
}
/// <summary>
/// 将记号值转换为数字类型
/// </summary>
/// <param name="ErrorInformation">无法转换成数字时显示的错误信息</param>
internal double ChangeTokenToDouble(string ErrorInformation)
{
double dblValue;
if (this.TokenValueType != typeof(double))
{
if (double.TryParse(this.TokenValue.ToString(), out dblValue))
this.TokenValueType = typeof(double);
else
throw new SyntaxException(this.m_Index, this.m_Length, ErrorInformation);
}
else
{
dblValue = (double)this.TokenValue;
}
return dblValue;
}
/// <summary>
/// 将记号值转换为逻辑值
/// </summary>
internal bool ChangeTokenToBoolean()
{
bool blnValue = false;
if (this.TokenValueType == typeof(string))
{
switch (this.TokenValue.ToString().Trim().ToLower())
{
case "true":
blnValue = (bool)(this.TokenValue = true);
break;
case "false":
case "":
default:
blnValue = (bool)(this.TokenValue = false);
break;
}
this.TokenValueType = typeof(bool);
}
else if (this.TokenValueType == typeof(double))
{
blnValue = (bool)((Convert.ToInt32(this.TokenValue) != 0) ? (this.TokenValue = true) : (this.TokenValue = false));
//检查上一行代码是否错误
this.TokenValueType = typeof(bool);
}
else if (this.TokenValueType == typeof(bool))
{
blnValue = (bool)this.TokenValue;
}
else
{
}
return blnValue;
}
#endregion
}//class TokenRecord