本文用于纪念大一下学期的C#语言课程设计。
1.设计目标
利用逐步求精程序设计思想,设计一简单的计算器模拟程序。它的功能是读入一个表达式,然后计算出它的值。这里表达式是指满足下列要求的简化形式:
(1)运算符为“+”、“*”;
(2)运算对象为实数(有小数点或无小数点);
(4)表达式以“;”结束。
例如:2.3*(6+5.7); (3.2+3.6+5)*126; 76*(81+25)+92*(65+31); 都是满足上列要求的表达式。
2.设计思路
2.1节展示总体实现思路,2.2-2.6节展示2.1节中提到的各要点的实现细节。
2.1总思路
用C#来编写这一程序,采用逐步求精的方法,简易计算器可按以下步骤实现。
第一步:根据课题要求,程序结构可以写为:
Static void Main(string []args)
{
String temp; //表达式字符串
Boolean IsLeave=false;//是否退出系统
Boolean IsTrue=false;//是否表达式出错
Double Value;//表达式的值
"系统欢迎使用界面"
IsLeave="询问是否离开系统的结果";
While(!IsLeave)
{
"初始化相关的变量";
Temp="读入正确的表达式字符串";
IsTrue="判断表达式正误";
if(IsTrue)
{
Value="求出temp表达式的值";
"打印Value的值"。
}
Else
{
"打印“出错”信息";
}
}
}
2.2 系统欢迎使用界面实现
2.3 “询问是否离开系统”实现
提供退出的按钮,点击之后弹出弹窗,让用户选择确认,确认之后即可退出系统;未点击默认不退出,isLeave=false;
{
Boolean isClicked=false;
If(isClicked)
{
弹出弹窗;
DialogResult result=弹窗上的选择;
If(result)
{
退出系统;
}
}
}
2.4读入正确的表达式
1)保证表达式的正确,需要遵循如下规则:
符号说明:Exp :表达式,Ele:因数,Dig:数字,UnDig:正整数
Exp->Ele|(Exp)|Exp+Exp|Exp*Exp
Ele->UnDig|UnDig.UnDig
UnDig->Dig|0|DigUnDig|UnDig 0
Dig->1|2|3|4|5|6|7|8|9
2)框架:(采用边读边判断的思想,使用一个文本框来存储读入的部分表达式,文本框S;
{
Char Former="判断并读入正确的首字符";
S=Former;
While(former!=';')
{
Current="当前读入的与Former适合的字符";
Former=Current;
S+=Former;
}
判断表达式S正误; //主要判断括号是否匹配
如果正确,temp=该表达式S;
否则,清零重新执行本段程序。
}
3)"判断并读入正确的首字符"
tempChar=点击的字符值;
If(tempChar==数字||tempChar==左括号)
Former=tempChar;
Else {提示用户本次输入不正确;继续执行本函数;}
3.1)temp==数字,则是判断是否是数字
If(temp<='9'&&temp>='0')
Return true;
Else return false;
4)"当前读入的与Former适合的字符"
{
Bool isSuited=true;
Char tempChar;
tempChar=点击的字赋值;
isSuited=”判断与Former字符是否是相适应的“;
If(!isSuited)
{
提醒用户填入了不正确的字符;
忽略本次读入的字符,继续执行本函数;
}
}
4.1)判断与Former字符是否是相适应的
{
Boolean reValue=true;
Switch(former)
{
Case 数字: tempChar是否是数字或+或*或小数点或右括号; break;
Case (: tempChar是否是数字;break;
Case ): tempChar是否是分号或+或*;break;
Case 小数点: tempChar是否是数字;break;
Case +: tempChar是否是数字或左括号;break;
Case *: tempChar是否是数字或左括号;break;
}
}
2.6 判断表达式正误
由于本输入方法,无法保证输入括号能够匹配,所以还需要专门设置判断表达式的函数。
{
Stack <char>S;
Char tempChar=读入当前字符;
Boolean hasError=false;
While(tempChar未到表达式temp的末尾)
{
Switch(tempChar)
{
Case 左括号:S.push(tempChar);
Case 右括号:
{
If(S.count==0)//栈为空
{
hasError=true;
Break;
}
char te=S.top();//栈顶元素
If(te==左括号)
S.pop();//匹配了栈顶元素
}
}
tempChar=表达式中的下一个字符;
}
If(S不为空)
hasError=true;
Return (!hasError);
}
2.6计算表达式的值
求出temp表达式的值:采用堆栈的思想逐步求出表达式的值,利用两个堆栈,一个数字栈,一个符号栈,当遇到数字压入数字栈中,遇到符号与当前栈顶元素比较,如果优先级小于栈顶元素,则取出操作数做计算,结果压入数字栈。这样直至进行到表达式末尾或者符号栈顶为末尾结束符。
{
数字栈、符号栈;
While(!表达式末尾||Top(符号栈)不是末尾结束符)
{
If(当前元素为数字)
{
取出因数放入数字栈中;
调整表达式指针;
}
Else
{
Switch(当前元素与Top(符号栈)比较优先级)
{ Case 小于:计算部分表达式的值;break;
Case 相等:取出符号栈顶端元素丢弃
调整表达式指针;break;
Case 大于:当前元素存入符号栈
调整表达式指针。Break;
}
}
}
}
具体细化如下:
{
Stack<double>Num;
Stack<char>Mark;
Int count=0;//count标记执行到的位置
Mark.Push(';');
while (未执行到表达式末尾 || Mark堆栈顶端不是末尾结束符)
{
if (当前字符temp[count]==数字)
{
integer = 从表达式分离出来的因数;
Num.Push(integer);
}
else
{
char temp = Mark.Peek();//Mark顶端元素
Int returnValue = 分析temp[count]与temp的优先级;
switch (returnValue)
{
Case 'X': isTrue = false; break;//出错
Case '<': Mark.Push(express[count]); count++; break;
Case '=': Mark.Pop(); count++; break;
Case '>':
{
double a = Num.Pop();//本次仅是计算
double b = Num.Pop();
char c = Mark.Pop();
Num.Push(Shared.CalValue(a, b, c, out isTrue));
if (isTrue == false)
{
break;
}
}
break;
}
}
}
if (isTrue == true)
value = Num.Pop();
Return isTrue;
}
3. 类设计
3.1 Input类
本类主要完成输入正确的表达式,
私有变量:
private StringBuilder express;//用于存储输入的表达式
private int count;//用于指明输入的字符串的位置
公有函数:
public Input();//主要初始化私有变量
public void Clear()//主要清零私有变量
public Boolean SetFirstChar(string s,chara)//实现读入第一个字符,包含特殊情况:首字符是上一次运算的结果
public Boolean GetWheHarmony(char a,char b)//判断即将读入的字符是否正确
public Boolean SetChar(char a)//读入后续字符,当读入"=",判断表达式是否正确,若正确,使之开始调用表达式求值函数
属性:public string Express;//返回私有变量express的值
3.2 Computer类
本类主要完成计算表达式的值,假定输入的表达式是形式正确的。
私有变量:
private Boolean isTrue;//表示计算中是否出错
private String express;//记录表达式
private double value;//记录表达式的值
公有函数:
public Computer(string s)//初始化相关变量
publicvoid CalExpression()//计算表达式的值
属性:
public Boolean IsTrue;//返回私有变量isTrue的值
public string Express;//传递相关值给私有变量express
public double Value;//获取私有变量value的值
3.3 Shared类
本类包含上述两个类需要使用到的一些公共函数,全部被申明为static静态函数。
public static Boolean JudgeInteger(char a)/判断D是否是数字
public static Boolean JudgeChar(char a)//判断a是否是非数字类字符
public static char CalPriority(char a, charb)//计算优先级
public static double CalValue(double a,double b, char c, out Boolean wheTrue)
//计算只含两个操作数的表达式的值
private static Boolean InMark(char temp)//判断temp是否是运算符
public static double ReadNum(string s, intlocation, out int count)//在字符串中读出一个因数
public static Boolean JudgeExpression(strings)//判断表达式是否出错,主要检测括号是否匹配
3.4 界面类CalculatorWindow
私有变量:
一些列关于界面的类对象;
private Input input = new Input();//输入类对象
private Computer computer;//计算类对象
private Boolean hasFirst = false;//是否已经输入
公有函数
private void Initial()//初始化变量
private void InputProcessError(char temp)//字符出错,通知用户
private void Error(string s)//表达式出错,通知用户
private void PrintValue(string expr,doublevalue)//打印结果
private void In(string s,char tempChar)//输入一个字符
private void Btn_Click(objectsender,EventArgs e)//键盘上的按键点击
private void Back_Click(object sender,EventArgs e)//点击Back退格键
private void Power_Click(object sender,EventArgs e)//点击关闭
private void Clear_Click(object sender,EventArgs e)//点击清零
4. 实现结果优点:
1)满足课题全部要求
2)支持循环使用前一步骤执行的结果
3)同时支持多层括号,具体如下:
缺点:1)不支持键盘输入
2)不支持光标移动输入(计算器无法做到此功能,因为无法判断表达式的正误)