持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第14天,点击查看活动详情
4 详细设计
4.1词法分析
词法分析程序又可称为扫描器,它扫描源程序,并进行分析,将源程序转换为便于编译程序其余部分进行处理的内部格式。
由vector ciparseInfixExpression(const string& exp)函数检查单词的合法性,是否有未知字符。合法的操作数 “0”-“9”和“.”。合法的操作符为+、-、*、/、%、^。词法分析检查合法性流程图如图3所示。
图3 词法分析流程图
4.2语法分析
语法分析是编译过程的核心部分。语法分析器的任务是识别和处理比单词更大的语法单位。如:程序设计语言中的表达式,各种说明和语句乃至全部源程序,指出其中的语法错误。
语法分析程序中的数据结构有: Exception结构体。异常结构体Exception记录了异常发生时的位置和异常信息。
该程序中的函数有:isdigit、isOperator、IsBlank、IsPrefix、GetNumber、GetTerm、GetFactor、GetExp。其中主要是后面的三个Get*函数。
int GetTerm(const string& str, int& current) 检测str从current起始是否是一个Term;
int GetFactor(const string& str, int& current) 检测str从current起始,开头是否是Factor;
int GetExp(const string& str, int& current) 检测str从current起始,开头是否是一个Exp。
分别对应了运算表达式的三条正规式:
1.Term = <运算数> | “(”Exp”)”
2.Factor = Term ((“” | “/”|“%”|“^”) Term)
3.Exp = Factor ((“+” | “-”) Factor)*。
通过对运算表达式的三条正规式进行实现,完成语法分析。
另外,
bool IsPrefix(const string& str, int& current, const string& Text) 检测Text是否是str从current起始的开头。
bool isblank(char ch)判断当前符号ch是否为空格或“\t”。
bool isdigit(char c) 判断当前符号c是否为数字。
isOperator(const string& str) 判断当前符号str是否为操作符。
int GetNumber(const string& str, int& current) 检测str从current开头是否是数字。
4.3中缀表达式转换后缀表达式
由vector infixToPostfix(const vector infixTokens)函数实现,主要过程为:
- 利用栈存放操作符,记栈为opStack;
- 从左往右扫描中缀表达式,当读到一个操作数时,立即将其输出;
- 当读到一个操作符+,-,x,/,%,^,(,)时:
-
- 如果是(时,直接入栈opStack;
- 如果是+,-,x,/,%,^,则比较该操作符与栈顶优先级,如果该操作符比栈顶优先级高或者栈顶是(,则直接入栈opStack;否则弹出栈顶元素到输出,然后继续比较。int getPriority(const string& op)函数 记录优先级信息。
- 如果是),则将栈opStack元素弹出到输出,直到遇到一个(为止;此时将(移除栈opStack但不输出;
- 当扫描完成,将栈opStack中的元素挨个弹出到输出中。
中缀表达式转换后缀表达式流程图如图4 所示。
注:输出是指将元素暂时放到vector postfixTokens容器中,
图4 中缀表达式转换后缀表达式流程图
4.4后缀表达式求值
由float calcPostfix(const vector& tokens)函数实现,主要过程为:
- 利用栈存放操作数和中间结果,记栈为resStack;
- 从左往右扫描后缀表达式,当读到一个操作数时,将其压入栈resStack中;
- 当读到一个操作符时,从栈中弹出两个操作数,并用该操作符进行计算,再将所得结果压入栈中;
- 当扫描完成,栈中剩下唯一一个元素就是计算结果。
后缀表达式求值流程图如图5所示。
图5 后缀表达式求值流程图