[TOC]
本项目基于C++语言,linux平台,采用面向对象思想设计实现。相对以往版本代码,本项目具有以下显著特点
- 支持了颜色设置和大小设置
- 具有错误处理机制
- 基于linux平台开发
- 基于opencv实现画图
- 基于cmake,逻辑结构更加清晰
- 采用现代化c++编程,运用c++11及以上特性
- Ubuntu 22.04
- clion + cmake + opencv
执行根目录下的main中输入文件路径,执行main函数
更改代码后执行Fast_Build.sh
脚本,注意项目需要opencv依赖
目录名 | 描述 |
---|---|
Scanner | 词法分析模块 |
Parser | 语法分析模块 |
Semantic | 语义分析模块 |
ExceptionLog | 异常处理模块 |
headers | 头文件 |
lib | 动态库 |
模块关系图如下,其中箭头代表依赖关系,指向被依赖方。
项目采用增量开发的模式,即词法分析、语法分析、语义分析、整体视为四个项目,采用动态库链接和cmake配置的方法实现项目依赖。
main函数依赖词法、语法、语义分析三个模块,并未在图中标出,且为了方便环境配置,所依赖模块全部生成的动态库liballLib.so
和libopencv_highgui.so
,但语义分析模块单独运行仍依赖opencv环境。
异常处理函数采用中断执行的策略,当错误发生时,在中断中输出错误行数及错误信息,并停止运行程序。
本文家共有四个可执行程序,即根目录、词法分析、语法分析、语义分析下的main函数,分别单独测试相应模块功能,其中语义分析依赖opencv环境。
该程序在终端输出识别出记号的种类,字符串,值。
该程序仅检测是否具有语法错误,若有则报错。该部分代码中含有语法树输出的功能,需要时可在代码相应位置进行修改。
该程序对输入文本进行分析,输出对应图像,异常交由词法分析和语法分析处理。
该程序为对词法分析、语法分析、语义分析的包装,输入输出同语义分析。
h/cpp | 描述 |
---|---|
Scanner | 词法分析的实现 |
Token | 定义了记号的种类及相关数据结构 |
Func | 抽象类,定义了不同函数的实现 |
main | 用于测试 |
关于main函数,由于语法分析依赖异常处理,这里将异常处理模块创建为动态库`libExceptionLog_lib.so,并链接至Scanner使用。
共有22种记号,为了逻辑清晰,将其大致划分成了五类,保留字、常量|变量|函数、分隔符、运算符、特殊记号。在实际判断过程中根据字母、数字、符号分为三类判断,将保留字、变量、函数三种类型预存入记号表中,实时判断数字和操作符。
对于每个记号,用(记号种类,字符串,值,函数指针)的数据结构存储,便于后续匹配记号与计算表达式。
Func作为抽象类,通过构建不同子类的实例,对不同的函数进行绑定。
Class | Description |
---|---|
Func | 抽象类,根据不同Func类型记号实例化 |
Cos | 实现cos运算 |
Sin | 实现sin运算 |
Tan | 实现tan运算 |
Ln | 实现ln运算 |
Exp | 实现exp运算 |
Sqrt | 实现sqrt运算 |
NoFunc | 非函数类 |
- 文件打开失败
- 记号错误
h/cpp | 描述 |
---|---|
Parser | 实现语法分析 |
ThreeNode | 定义语法树结构 |
main | 语法分析测试 |
关于main函数,由于语法分析依赖异常处理、词法分析,这里将异常处理模块和词法分析模块创建为动态库libExceptionLog_lib.so 和 libScanner_lib.so
,并链接至Parser使用。
采用递归向下的语法分析器,直接编码型的实现策略。其中词法分析作为语法分析的子程序,通过getToken()
为词法分析传递记号,从而使词法分析和语法分析合并成一个阶段。
关于句型,采用枚举句型,对每一个句型实现一个函数,在其中按顺序match句型记号的方法实现。
关于表达式,这里采用建立语法树的方法表示表达式,注意语法分析阶段仅建立语法树,并不对表达式求值。
语法树数据结构如下,根据记号的种类,分为 常量、变量、函数、操作符 四种不同的类型进行存储。其中变量采用指针引用的方法,具体实现在语义分析部分会提及。对于整个对象、函数记号、操作符记号、采用智能指针进行存储,方便指针的管理与释放。
class TreeNode {
public:
TokenType tokenType;
double constValue;
double* var;
struct FuncNode {
std::shared_ptr<TreeNode> child;
std::shared_ptr<Func> func;
} funcNode;
struct OperatorNode {
std::shared_ptr<TreeNode> Lchild, Rchild;
} operatorNode;
};
- 文件打开失败
- 记号错误
- 记号非法匹配
- 句型错误
h/cpp | 描述 |
---|---|
Semantic | 实现语义分析 |
Point | 实现点的变换等函数 |
Plotter | 实现基于opencv的图像绘制 |
main | 语义分析测试 |
关于main函数,由于语法分析依赖异常处理词法分析和语法分析,这里将异常处理模块、词法分析模块和语法分析模块创建为动态库libExceptionLog_lib.so 、libScanner_lib.so 和 libParser_lib.so
,并链接至Semantic使用。
语义分析主要在语法分析的基础上,完成表达式求值,函数绘制等函数。
表达式求值
在表达式求值中,采用两次遍历语法树的方法,第一次遍历将变量指针指向相应变量,第二次遍历对表达式进行求值。
函数绘制
采用opencv完成函数绘制功能
交由上层的语法分析进行处理,注意这里并未实现死循环、除0等语义错误的处理。