当前位置: 首页 > news >正文

编程实战:类C语法的编译型脚本解释器(七)语句

初级代码游戏的专栏介绍与文章目录-CSDN博客

我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。

这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。


系列入口:

编程实战:类C语法的编译型脚本解释器(系列)-CSDN博客

        本文介绍语句,主要是控制语句,if、else、for之类。

目录

一、语句概览

二、CheckSentence

三、ExecSentence


一、语句概览

		//语句//EXPRESSION RETURN:expressions[0]//BLOCK:senetnces//IF:if(expressions[0])sentences[0] else sentences[1]//FOR:for(expressions[0];expressions[1];expressions[2])sentences[0]//DO:do sentences[0] while(expressions[0]);//WHILE:while(expressions[0])sentences[0]struct Sentence{enum types { NULLSENTENCE = 0, DECLARE, EXPRESSION, BLOCK, RETURN, IF, FOR, BREAK, CONTINUE, DO, WHILE };types type;size_t source_start;//起始位置size_t source_end;//结束位置vector<Expression > expressions;vector<Sentence > sentences;Sentence() { clear(); }void clear(){type = NULLSENTENCE;source_start = 0;source_end = 0;expressions.clear();sentences.clear();}bool isLoop()const { return FOR == type || DO == type || WHILE == type; }//inloop=true表示处于循环体内,可能从上层带入bool CheckSentence(string& source, T_VARIABLE_S& vars, bool _inloop);//若为return语句则设置bFinishbool ExecSentence(CZBScript const& script, T_VARIABLE_S& vars, bool& bFinish, bool& bBreak, bool& bContinue, Variable& ret, void* pe)const;string ToString(string const& source, T_VARIABLE_S const& vars, long level = 0)const;
};

        语句比表达式简单多了。语句的类型更容易理解,大部分语句类型都是控制语句,有特殊的关键字对应,其余几个需要特别理解:

  • 声明语句 声明并定义变量
  • 表达式语句 整个语句就是一个表达式
  • 块语句 就是用大括号包裹的一组语句

        从表达式和语句的分析可以看出来,语言结构就是一系列递归。

        语句对象除了类型和辅助调试的开始位置、结束位置外,只有子语句和表达式两个成员变量。块语句包含一组语句,for语句则包含三个表达式和一个语句:

//for语句的逻辑结构
for(表达式1;表达式2;表达式3)语句

       for语句的第二个表达式的结果必须是逻辑值。

        if语句则包含一个逻辑表达式和一个或两个子语句:

if(逻辑表达式)语句;
或者:
if(逻辑表达式)语句1;else 语句2;

        单语句和大括号困扰了很多人,C语法中所有控制结构都是基于“语句”的,也就是单语句,为了多塞几个语句,就要用大括号括起来,变成块语句、复合语句或者别的叫法,总之就是可以当成一个“语句”的东西。

二、CheckSentence

        编译后检查语法:

			//inloop=true表示处于循环体内,可能从上层带入bool CheckSentence(string& source, T_VARIABLE_S& vars, bool _inloop){bool inloop = (_inloop || isLoop());size_t i;if (FOR == type){vars.PushLevel();//只有for语句的表达式可以定义变量if (sentences.size() != 2)CException::Throw(__FILE__, __LINE__, source, source_start, "for语句子语句必须有2个");if (!sentences[0].CheckSentence(source, vars, inloop))return false;}for (i = 0; i < expressions.size(); ++i){set<string > setpp;if (!expressions[i].CheckExpression(source, vars, 0, setpp))return false;}switch (type){case NULLSENTENCE:if (expressions.size() != 0)CException::Throw(__FILE__, __LINE__, source, source_start, "空语句不能有表达式");if (sentences.size() != 0)CException::Throw(__FILE__, __LINE__, source, source_start, "空语句不能有子语句");break;case DECLARE:if (expressions.size() != 1)CException::Throw(__FILE__, __LINE__, source, source_start, "变量定义语句有且只能有一个表达式");if (sentences.size() != 0)CException::Throw(__FILE__, __LINE__, source, source_start, "变量定义语句语句不能有子语句");if (expressions[0].type != Expression::DEFINE)CException::Throw(__FILE__, __LINE__, source, source_start, "变量定义语句表达式必须是DEFINE类型");if (0 == expressions[0].VariableName.size())CException::Throw(__FILE__, __LINE__, source, source_start, "变量定义语句表达式必须有变量名");break;case EXPRESSION:if (expressions.size() != 1)CException::Throw(__FILE__, __LINE__, source, source_start, "简单语句表达式只能有一个");if (sentences.size() != 0)CException::Throw(__FILE__, __LINE__, source, source_start, "简单语句不能有子语句");break;case BLOCK:if (expressions.size() != 0)CException::Throw(__FILE__, __LINE__, source, source_start, "块语句不能有表达式");break;case RETURN:if (expressions.size() != 1)CException::Throw(__FILE__, __LINE__, source, source_start, "return语句表达式只能有一个");if (sentences.size() != 0)CException::Throw(__FILE__, __LINE__, source, source_start, "return语句不能有子语句");break;case IF:if (expressions.size() != 1)CException::Throw(__FILE__, __LINE__, source, source_start, "if语句表达式只能有一个");if (sentences.size() != 1 && sentences.size() != 2)CException::Throw(__FILE__, __LINE__, source, source_start, "if语句子语句只能有1或2个");if (expressions[0].result_type != Variable::LONG && expressions[0].result_type != Variable::DOUBLE)CException::Throw(__FILE__, __LINE__, source, source_start, "if语句判断表达式必须是数值类型");break;case DO:if (expressions.size() != 1)CException::Throw(__FILE__, __LINE__, source, source_start, "do语句表达式只能有一个");if (sentences.size() != 1)CException::Throw(__FILE__, __LINE__, source, source_start, "do语句子语句只能有1个");if (expressions[0].result_type != Variable::LONG && expressions[0].result_type != Variable::DOUBLE)CException::Throw(__FILE__, __LINE__, source, source_start, "do语句判断表达式必须是数值类型");break;case WHILE:if (expressions.size() != 1)CException::Throw(__FILE__, __LINE__, source, source_start, "while语句表达式只能有一个");if (sentences.size() != 1)CException::Throw(__FILE__, __LINE__, source, source_start, "while语句子语句只能有1个");if (expressions[0].result_type != Variable::LONG && expressions[0].result_type != Variable::DOUBLE)CSException::Throw(__FILE__, __LINE__, source, source_start, "while语句判断表达式必须是数值类型");break;case FOR:if (expressions.size() != 2)CException::Throw(__FILE__, __LINE__, source, source_start, "for语句表达式必须有2个");if (sentences.size() != 2)CException::Throw(__FILE__, __LINE__, source, source_start, "for语句子语句必须有2个");if (expressions[1].result_type != Variable::LONG && expressions[1].result_type != Variable::DOUBLE)CException::Throw(__FILE__, __LINE__, source, source_start, "for语句判断表达式必须是数值类型");break;case BREAK:if (expressions.size() != 0)CException::Throw(__FILE__, __LINE__, source, source_start, "break语句不能有表达式");if (sentences.size() != 0)CException::Throw(__FILE__, __LINE__, source, source_start, "break语句不能有子语句");break;case CONTINUE:if (expressions.size() != 0)CException::Throw(__FILE__, __LINE__, source, source_start, "break语句不能有表达式");if (sentences.size() != 0)CException::Throw(__FILE__, __LINE__, source, source_start, "break语句不能有子语句");break;default:CException::Throw(__FILE__, __LINE__, source, source_start, "暂不支持");return false;break;}if (BLOCK == type)vars.PushLevel();for (i = 0; i < sentences.size(); ++i){if (BLOCK != type)vars.PushLevel();//每个子语句都是一个层次,if有1或2个子语句,do\while\for有1个子语句(for的第一个语句已经提前检查)if ((FOR == type && 0 != i) || FOR != type)if (!sentences[i].CheckSentence(source, vars, inloop))return false;if (!inloop){if (BREAK == sentences[i].type)CException::Throw(__FILE__, __LINE__, source, source_start, "非期待的break语句");if (CONTINUE == sentences[i].type)CException::Throw(__FILE__, __LINE__, source, source_start, "非期待的continue语句");}if (BLOCK != type)vars.PopLevel();}if (BLOCK == type)vars.PopLevel();if (FOR == type)vars.PopLevel();return true;}

        基本上就是针对每种类型检查特定的要求,然后递归对每个表达式和子语句做检查。检查每种类型对应的表达式和语句是否存在,检查break和continue是否出现在了非循环结构中。

        部分语句类型导致新的变量层级,因此要在开始时调用vars.PushLevel()并在最后调用vars.PopLevel()。 PopLevel()将丢弃变量表的最后一级。

        for循环的整体是一个层级,循环体又是一个层级。块语句整体是一个层级。

        客观地讲,语句比表达式简单多了。

三、ExecSentence

        执行语句:

			//若为return语句则设置bFinishbool ExecSentence(CScript const& script, T_VARIABLE_S& vars, bool& bFinish, bool& bBreak, bool& bContinue, Variable& ret, void* pe)const{size_t i;if (bFinish)return true;if (bBreak)return true;if (bContinue)return true;ret.type = Variable::NULLVARIABLE;switch (type){case NULLSENTENCE:ret.type = Variable::NULLVARIABLE;break;case DECLARE:expressions[0].ExecExpression(script, vars, ret, pe);break;case EXPRESSION:expressions[0].ExecExpression(script, vars, ret, pe);break;case BLOCK:vars.PushLevel();for (i = 0; i < sentences.size(); ++i){sentences[i].ExecSentence(script, vars, bFinish, bBreak, bContinue, ret, pe);if (bFinish)break;if (bBreak)break;if (bContinue)break;}vars.PopLevel();break;case RETURN:expressions[0].ExecExpression(script, vars, ret, pe);bFinish = true;break;case IF:expressions[0].ExecExpression(script, vars, ret, pe);vars.PushLevel();if (ret.GetBool()){sentences[0].ExecSentence(script, vars, bFinish, bBreak, bContinue, ret, pe);}else{if (sentences.size() >= 2)sentences[1].ExecSentence(script, vars, bFinish, bBreak, bContinue, ret, pe);else ret.type = Variable::NULLVARIABLE;}vars.PopLevel();break;case FOR:vars.PushLevel();sentences[0].ExecSentence(script, vars, bFinish, bBreak, bContinue, ret, pe);while (true){expressions[0].ExecExpression(script, vars, ret, pe);if (!ret.GetBool())break;vars.PushLevel();sentences[1].ExecSentence(script, vars, bFinish, bBreak, bContinue, ret, pe);vars.PopLevel();if (bFinish)break;if (bBreak){bBreak = false;break;}if (bContinue)bContinue = false;expressions[1].ExecExpression(script, vars, ret, pe);}vars.PopLevel();//ret.type=Variable::NULLVARIABLE;break;case DO:while (true){vars.PushLevel();sentences[0].ExecSentence(script, vars, bFinish, bBreak, bContinue, ret, pe);vars.PopLevel();if (bFinish)break;if (bBreak){bBreak = false;break;}if (bContinue)bContinue = false;expressions[0].ExecExpression(script, vars, ret, pe);if (!ret.GetBool())break;}//ret.type=Variable::NULLVARIABLE;break;case WHILE:while (true){expressions[0].ExecExpression(script, vars, ret, pe);if (!ret.GetBool())break;vars.PushLevel();sentences[0].ExecSentence(script, vars, bFinish, bBreak, bContinue, ret, pe);vars.PopLevel();if (bFinish)break;if (bBreak){bBreak = false;break;}if (bContinue)bContinue = false;}//ret.type=Variable::NULLVARIABLE;break;case BREAK:bBreak = true;break;case CONTINUE:bContinue = true;break;default:script.ThrowN(__FILE__, __LINE__, "暂不支持的语句类型", type);return false;break;}return true;}

        第一个参数script仅仅是用来在出错时报错。其余参数提供当前变量表并返回程序流程状态。语句没有返回值,这是语句和表达式的关键区别——尽管一个语句可能仅仅包含一个表达式。

        执行和检查以同样的规则处理变量层级(变量生存期)。


(这里是结束,但不是整个系列的结束)

http://www.lryc.cn/news/353374.html

相关文章:

  • 实体-联系图
  • ROCm上来自Transformers的双向编码器表示(BERT)
  • 期权课程之第一节【用生活的例子解释什么是期权】
  • 【YOLOv10训练教程】如何使用YOLOv10训练自己的数据集并且推理使用
  • [windows系统安装/重装系统][step-4][番外篇-2]N卡驱动重装 |解决:开机几小时后电脑卡顿 | 后台自动运行了上千个Rundll32进程问题
  • Redis开发实战
  • C++ | Leetcode C++题解之第112题路径总和
  • leetcode力扣 2024. 考试的最大困扰度
  • lvgl无法显示中文
  • 读书笔记-Java并发编程的艺术-第1章 并发编程的挑战
  • RUST 和 GO 如何管理它们的内存
  • 对于高速信号完整性,一块聊聊啊(12)
  • C++学习笔记(19)——模板
  • java8新特性——函数式编程详解
  • mybatis-plus小课堂: apply 拼接 in SQL,来查询从表某个范围内的数据
  • 民宿推荐系统-手把手调试搭建
  • 线性回归模型
  • 西门子全球业务调整:数十亿欧元交易额,开启新篇章
  • AI遇上遥感,未来会怎样?
  • 认知架构 cognitive architecture
  • 数据插值之朗格朗日插值(一)
  • 【CCF-CSP】 202309-3 梯度求解
  • jvm的类加载
  • 2024年汉字小达人活动4个多月开赛:18道历年选择题和答案、解析
  • 群晖安装青龙脚本
  • 【机器学习系列】使用高斯贝叶斯模型进行数据分类的完整流程
  • Python中的单例模式:原理、实现与应用
  • Linux基础(六):Linux 系统上 C 程序的编译与调试
  • 移动硬盘难题:不显示容量与无法访问的解决策略
  • 基于springboot+vue的智慧外贸平台