仿查询分析器的C#计算器——5.计算求值
2009-03-31 08:21:50 来源:WEB开发网从代码中可以看出,首先是词法分析,得到一个记号对象列表List<TokenRecord>,然后进行语法分析,调用SyntaxTreeAnalyse的SnytaxTreeGetTopTokenAnalyse方法,分析出顶级记号对象,这样一棵树就出来了。接下来执行顶级节点的Execute方法,该方法中首先会执行下级节点的Execute方法,然后再针对下级节点的值执行自身的运算。所有的TokenRecord都是这样的模式,逐级递归调用,最后得到计算结果。TokenRecord基类中包含一个object类型的Value属性和一个Type类型的TokenValueType属性,通过这两个属性可以得到具体的值及其类型,然后做下一步处理。因为这里不只能执行数学运算,还能做字符串和逻辑值运算,所以必须通过TokenValueType来确定值的类型。如果只需要实现数学运算,程序会简单一些。
窗体的调用也很简单,并没有设计漂亮的外观和高级设置等。主要的代码是“计算”按钮的Click事件处理方法,代码如下:
/// <summary>
/// 点击“计算”按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnExecute_Click(object sender, EventArgs e)
{
if (this.rtbInput.Text.Trim().Replace("\n", "").Length == 0)
{
this.rtbOutput.Text = "输入的表达式不能为空,请重新输入。";
}
else
{
string strSource;
int intTotalIndex = 0;
this.rtbOutput.Text = "";
string[] strLines;
this.trvSyntaxTree.Nodes.Clear();//清空语法树
if (this.rtbInput.SelectedText.Trim().Length == 0)//获取选中的代码,如果未选中,则执行全部
{
strSource = this.rtbInput.Text;
}
else
{
strSource = this.rtbInput.SelectedText;
intTotalIndex = this.rtbInput.SelectionStart;
}
if (this.chkAllowMultiLine.Checked)//判断是按多行执行还是单行执行
{
strLines = strSource.Split(new char[] { '\n' });//多行则用换行符分割成多行
}
else
{
strLines = new string[] { strSource.Replace("\n", "") };//单行则移除换行符成一行
}
foreach (string Line in strLines)
{
if (Line.Trim().Length != 0)//避免中间出现空行
{
try
{
TokenRecord TokenTop = myAnalyse.Analyse(Line);//计算表达式
this.rtbOutput.Text += TokenTop.GetValueString() + "\n";//显示计算结果
this.LoadSyntaxTree(TokenTop);//加载语法树到TreeView控件
}
catch (Exception ex)
{
this.rtbOutput.Text += "发生错误\n" + ex.Message + "\n";//显示错误信息
if (ex is SyntaxException)//如果是语法错误,则选中错误的代码
{
SyntaxException myException = (SyntaxException)ex;
this.ActiveControl = this.rtbInput;//设置输入框为激活控件
this.rtbInput.Select(myException.Index + intTotalIndex, myException.Length);//定位发生错误的字符串
}
return;
}//try
}//if
intTotalIndex += Line.Length + 1;
}//foreach
}//else
}//btnExecute_Click
更多精彩
赞助商链接