从0开始自制解释器——实现多个整数的加减法
迪丽瓦拉
2024-06-03 19:21:22
0

在上一篇我们实现了一个可以计算两个多位整数加减法的计算器。本章我们继续来给这个计算器添加功能,这次要给它添加可以连续计算多个整数相加减的功能。例如我们可以计算 1 + 2 + 3 这样的表达式。

语法图

在正式写代码之前让我们先来学习一下一些基本的理论知识。这次要介绍的理论是语法图

什么是语法图呢?语法图是编程语言语法语法规则的图形表示。它体现了词法分析的运行规则。语法图直观的展示了在编程语言中哪些语句是符合语法的,哪些是不符合语法规范的。

语法图的阅读非常容易,它类似于程序的流程图,只要顺着箭头指向的路径来读即可。与程序流程图类似,语法图中有些路径表示选择,有些表示循环。我们试着来读一下下面的语法图
在这里插入图片描述

这张语法图表示的含义是,一个术语(term) 可选的跟上一个加号或者减号,而后面又需要跟上另一个术语。接着又可以有选择的跟上另一个加号或者减号。但是加号或者减号后面必须跟上另一个术语。

这里又提到另一个单词,term 它的中文意思是术语。似乎很难用其他文字来解释何为术语。你只需要知道在这里它代表的是一个整数,它并不影响我们阅读这个语法图

代码展示

在上一篇中我们提到,将Token流识别为对应结构的过程被称之为词法分析,我们代码中的词法分析的实现主要在函数 expr 中。在这个函数中我们主要实现了词法分析以及最后的解释执行。我们按照语法图修改一下词法分析的代码

我们先给出下面的伪代码

获取第一个整数作为计算结果保存
while(解析到最后一个字符)
{获取操作符(+/-)switch(操作符){case +:获取下一个整数,如果不是整数则退出并报错与结果相加break;case -:获取下一个整数,如果不是整数则退出并报错与结果相减break;}
}最终打印计算结果或者打印语法错误

基于这个思路我们给出具体的实现代码

int expr()
{bool bRet = false;int result = get_term(&bRet);int bEOF = false;do{ETokenType oper = get_oper(&bRet);switch (oper){case PLUS:{int num = get_term(&bRet);if(bRet)result += num;}break;case MINUS:{int num = get_term(&bRet);if(bRet)result -= num;}break;case END_OF_FILE:printf("%d\n", result);bEOF = true;break;default:bRet = false;break;}} while (bRet && !bEOF);if (!bRet){printf("Syntax Error!\n");}
}

这里为了便于理解,我将获取整数和操作符的模块又进行了一次封装,提供了两个函数分别是 get_term()get_oper()。它们的代码如下

int get_term(bool *pRet)
{Token token = { 0 };dyncstring_init(&token.value, DEFAULT_BUFFER_SIZE);int value = 0;if (get_next_token(&token) && token.type == CINT){value = atoi(token.value.pszBuf);if (pRet)*pRet = true;}else{if (pRet)*pRet = false;}dyncstring_free(&token.value);return value;
}
ETokenType get_oper(bool* pRet)
{Token token = { 0 };dyncstring_init(&token.value, DEFAULT_BUFFER_SIZE);int oper = 0;if (get_next_token(&token) && (token.type == PLUS || token.type == MINUS)){oper = token.type;if (pRet)*pRet = true;}else if (token.type == END_OF_FILE){oper = END_OF_FILE;if (pRet)*pRet = true;}else{oper = -1;if (pRet)*pRet = false;}dyncstring_free(&token.value);return oper;
}

到此为止,就实现了多个整数的算术运算。整个实现过程的代码我都放到该位置。有兴趣的小伙伴可以自己对照着代码跟着我一起来实现属于自己的解释器。

相关内容

热门资讯

linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
C++ 机房预约系统(六):学... 8、 学生模块 8.1 学生子菜单、登录和注销 实现步骤: 在Student.cpp的...
A.机器学习入门算法(三):基... 机器学习算法(三):K近邻(k-nearest neigh...
数字温湿度传感器DHT11模块... 模块实例https://blog.csdn.net/qq_38393591/article/deta...
有限元三角形单元的等效节点力 文章目录前言一、重新复习一下有限元三角形单元的理论1、三角形单元的形函数(Nÿ...
Redis 所有支持的数据结构... Redis 是一种开源的基于键值对存储的 NoSQL 数据库,支持多种数据结构。以下是...
win下pytorch安装—c... 安装目录一、cuda安装1.1、cuda版本选择1.2、下载安装二、cudnn安装三、pytorch...
MySQL基础-多表查询 文章目录MySQL基础-多表查询一、案例及引入1、基础概念2、笛卡尔积的理解二、多表查询的分类1、等...
keil调试专题篇 调试的前提是需要连接调试器比如STLINK。 然后点击菜单或者快捷图标均可进入调试模式。 如果前面...
MATLAB | 全网最详细网... 一篇超超超长,超超超全面网络图绘制教程,本篇基本能讲清楚所有绘制要点&#...
IHome主页 - 让你的浏览... 随着互联网的发展,人们越来越离不开浏览器了。每天上班、学习、娱乐,浏览器...
TCP 协议 一、TCP 协议概念 TCP即传输控制协议(Transmission Control ...
营业执照的经营范围有哪些 营业执照的经营范围有哪些 经营范围是指企业可以从事的生产经营与服务项目,是进行公司注册...
C++ 可变体(variant... 一、可变体(variant) 基础用法 Union的问题: 无法知道当前使用的类型是什...
血压计语音芯片,电子医疗设备声... 语音电子血压计是带有语音提示功能的电子血压计,测量前至测量结果全程语音播报࿰...
MySQL OCP888题解0... 文章目录1、原题1.1、英文原题1.2、答案2、题目解析2.1、题干解析2.2、选项解析3、知识点3...
【2023-Pytorch-检... (肆十二想说的一些话)Yolo这个系列我们已经更新了大概一年的时间,现在基本的流程也走走通了,包含数...
实战项目:保险行业用户分类 这里写目录标题1、项目介绍1.1 行业背景1.2 数据介绍2、代码实现导入数据探索数据处理列标签名异...
记录--我在前端干工地(thr... 这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前段时间接触了Th...
43 openEuler搭建A... 文章目录43 openEuler搭建Apache服务器-配置文件说明和管理模块43.1 配置文件说明...