七天开发基于编译原理的公式计算器设计与实现-第四天

250 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第14天,点击查看活动详情

4 详细设计

4.1词法分析

词法分析程序又可称为扫描器,它扫描源程序,并进行分析,将源程序转换为便于编译程序其余部分进行处理的内部格式。

由vector ciparseInfixExpression(const string& exp)函数检查单词的合法性,是否有未知字符。合法的操作数 “0”-“9”和“.”。合法的操作符为+、-、*、/、%、^。词法分析检查合法性流程图如图3所示。

image.png 图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)函数实现,主要过程为:

  1. 利用栈存放操作符,记栈为opStack;
  2. 从左往右扫描中缀表达式,当读到一个操作数时,立即将其输出;
  3. 当读到一个操作符+,-,x,/,%,^,(,)时:
    • 如果是(时,直接入栈opStack;
    • 如果是+,-,x,/,%,^,则比较该操作符与栈顶优先级,如果该操作符比栈顶优先级高或者栈顶是(,则直接入栈opStack;否则弹出栈顶元素到输出,然后继续比较。int getPriority(const string& op)函数 记录优先级信息。
    • 如果是),则将栈opStack元素弹出到输出,直到遇到一个(为止;此时将(移除栈opStack但不输出;
  4. 当扫描完成,将栈opStack中的元素挨个弹出到输出中。

中缀表达式转换后缀表达式流程图如图4 所示。

注:输出是指将元素暂时放到vector postfixTokens容器中,

image.png

图4 中缀表达式转换后缀表达式流程图

4.4后缀表达式求值

       由float calcPostfix(const vector& tokens)函数实现,主要过程为:

  1. 利用栈存放操作数和中间结果,记栈为resStack;
  2. 从左往右扫描后缀表达式,当读到一个操作数时,将其压入栈resStack中;
  3. 当读到一个操作符时,从栈中弹出两个操作数,并用该操作符进行计算,再将所得结果压入栈中;
  4. 当扫描完成,栈中剩下唯一一个元素就是计算结果。

后缀表达式求值流程图如图5所示。

image.png 图5 后缀表达式求值流程图