编程实战:类C语法的编译型脚本解释器(三)插件(自定义函数)接口

系列入口:

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

        本文讲解插件(自定义函数)的接口。

        下文中的“插件”和“自定义函数”是两个概念:

  • “插件” 提供自定义函数功能的类,具有特殊的接口,一个插件实现一个自定义函数
  • “自定义函数” 脚本里的函数调用,形如“fun(a,b,c)”,脚本解释器负责将脚本里的函数调用与插件对应

目录

一、插件接口

二、插件管理器


一、插件接口

	//插件struct CPlugin{string plugin_name;Variable::types plugin_return_type;CPlugin() :plugin_name(""), plugin_return_type(Variable::NULLVARIABLE) {}CPlugin(char const* _name, Variable::types _type) :plugin_name(_name), plugin_return_type(_type) {}virtual string& help(string& ret){ret = plugin_name + " : 返回值 " + Variable::TypeStr(plugin_return_type) + "\r\n";return ret;}virtual bool CheckPlugin(vector<Variable >& params, void*& pc, string& msg) = 0;virtual bool ExecFunction(vector<Variable >& params, void* const& pc, Variable& ret, string& msg, void* pe) = 0;};

        这是个关键的接口,只有两个成员变量:

类型名称说明
stringplugin_name自定义函数名称,也就是函数名
Variable::typesplugin_return_type自定义函数的返回值类型,返回值放在一个Variable中,必须明确指定返回类型,编译时会检查返回值类型是否正确

        两个构造函数无关紧要,只是提供了设置自定义函数名称和返回值类型而已。

        三个虚函数很重要:

  1. help() 返回自定义函数说明,已经提供了一个示例实现,这种参数传递方式是用来避免不必要的对象创建的。
  2. CheckPlugin() 编译时检查,如果返回false则编译不通过。后面详细介绍。
  3. ExecFunction() 执行,执行脚本时通过此接口获得返回值。 后面详细介绍。

        CheckPlugin()和ExecFunction()有很多共同的参数,一起介绍:

类型名称说明
vector<Variable>params函数的参数列表,也就是fun(a,b,c)的“a,b,c”,编译时提供的值是无意义的,但可以检查类型是否符合预期
void * &pc

编译时用户提供的指针的引用,用户可以在编译时修改,意即:用户可以在CheckPlugin里面申请内存,保存在pc变量里供执行时使用

此变量在执行时是只读的,但是指向的内容仍然是可以修改的(我感觉在运行时不断修改这个指针是难以理解的)(大BUG,这个值其实根本没设置,编译和运行都没有设置,没有这个参数

Variable &ret存放函数的返回值
string &msg如果执行出错,可以在这里放返回值
void *pe运行时由用户提供的指针

         CheckPlugin()和ExecFunction()本身的返回值为bool,表达插件本身执行成功或失败,具体区别借助实例来理解:

	struct CMax : public CPlugin{CMax() :CPlugin("max", Variable::DOUBLE) {}virtual string& help(string& ret){ret = CPlugin::help(ret);ret += "取最大值,1-N个参数,参数必须是数值\r\n";return ret;}virtual bool CheckPlugin(vector<Variable >& params, void*& pc, string& msg){msg = "";if (params.size() < 1)msg += "参数不足\r\n";for (size_t i = 0; i < params.size(); ++i){if (!params[i].isNumber())msg += "参数必须是数值\r\n";}return 0 == msg.size();}virtual bool ExecFunction(vector<Variable >& params, void* const& pc, Variable& ret, string& msg, void* pe){size_t _max = 0;for (size_t i = 1; i < params.size(); ++i){if (params[i].GetDouble() > params[_max].GetDouble())_max = i;}ret = params[_max];return true;}};

        这是内置函数max的插件,CheckPlugin检查参数的个数和类型,ExecFunction则把参数转换为double然后把最大的放在ret中返回。

        这个插件没有用到pc和pe这两个参数,目前可以无视,因为这两个参数是客户代码使用的,插件解释器只是传递而并不操作,到需要用的时候你自然知道怎么用。 

二、插件管理器

	//插件表class CPluginMap{public:struct HANDLE{string plugin_name;bool isNULL()const { return 0 == plugin_name.size(); }};private:static map<string, CPlugin*>& GetPluginMap();public:template<typename T>static void addplugin(map<string, CPlugin*>& mapPlugins);static bool AddPlugin(char const* name, Variable::types type, CPlugin* p);static CPlugin* GetPlugin(string const& fun_name);static CPlugin* GetPlugin(HANDLE const& h);static string& PluginHelp(string& ret);};

        插件管理器管理所有的插件,也就是管理所有的自定义函数。

        子类型HANDLE是内部使用的,提供类似指针的快速访问,不过目前并没有性能优势,因为内部藏的还是自定义函数名。

        addPlugin往插件管理器里面添加插件,是静态方法。插件管理器的实现相当简单,也很随意,所以就不展开解释了。

        用户代码只需要在执行脚本前用addPlugin或AddPlugin添加插件即可。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/193562.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于SpringBoot的公益慈善平台

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 基于SpringBoot的公益…

华为OD机试真题-最长子字符串的长度(一)-2023年OD统一考试(C卷)

题目描述&#xff1a; 给你一个字符串 s&#xff0c;字符串s首尾相连成一个环形 &#xff0c;请你在环中找出 o 字符出现了偶数次最长子字符串的长度。 输入描述&#xff1a; 输入是一串小写字母组成的字符串 输出描述&#xff1a; 输出是一个整数 补充说明&#xff1a; 1 <…

用Python实现石头剪刀布的游戏(扩展)

剪刀石头布是一种划拳游戏&#xff0c;规则是剪刀赢布&#xff0c;布赢石头&#xff0c;石头赢剪刀。假设使用3个整数0、1、2来分别代表石头、剪刀、布。每一局中&#xff0c;计算机随机生成3个整数0、1、2中的一个&#xff0c;用户使用键盘输入0、1、2中的一个整数&#xff0c…

arcgis导出某个属性的栅格

选中栅格特定属性想要导出时&#xff0c;无法选中“所选图形” 【方法】spatial analyst 工具——提取分析——按属性提取

C++笔试训练day_1

文章目录 选择题编程题 选择题 编程题 #include <iostream> #include <algorithm> #include <vector>using namespace std;int main() {int n 0;cin >> n;vector<int> v;v.resize(3 * n);int x 0;for(int i 0; i < v.size(); i){cin >&…

删除容器挂载卷打包容器镜像并传到阿里云

简单记录下打包上传的全过程&#xff0c;补充docker知识&#xff0c;利用阿里云进行docker镜像共享开发。 阿里云登录 sudo docker login --usernameyouxiangyouxiang.com registry.cn-hangzhou.aliyuncs.com这个登录密码可以在容器镜像服务/实例列表/镜像仓库页面左侧tab下的…

【Java基础篇 | 面向对象】—— 聊聊什么是多态(下篇)

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【JavaSE_primary】 本专栏旨在分享学习JavaSE的一点学习心得&#xff0c;欢迎大家在评论区讨论&#x1f48c; 目录 一、动态绑定和静态绑…

opencv几何变换和图像形态学

实验1 实验内容 该代码演示了如何使用OpenCV库中的WarpAffine函数进行图像基础的仿射变换 代码注释 import numpy as np import cv2 as cvimg cv.imread(rtest.jpg, 1) rows, cols, channels img.shape M np.float32([[1,0,100],[0,1,50]]) res cv.warpAffine(img, M, …

PHP数组面试题

PHP数组面试题 1. 创建一个包含多个元素的数组&#xff0c;并打印输出数组的内容。 <?php $array array(apple, banana, orange); print_r($array); ?>2. 如何访问数组中的特定元素&#xff1f; <?php $array array(apple, banana, orange); echo $array[1]; …

【微信小程序】上传头像 微信小程序内接小程序客服

这里写目录标题 微信小程序上传头像使用button按钮包裹img 微信小程序内接小程序客服使用button按钮跳转客服 微信小程序上传头像 使用button按钮包裹img 原本思路是只使用image标签再加上chooseImg&#xff0c;但发现使用button标签上传头像这种方法更实用。微信小程序文档上…

C++实现DFS、BFS、Kruskal算法和Prim算法、拓扑排序、Dijkstra算法

背景&#xff1a; 实现要求&#xff1a; 根据图的抽象数据类型的定义&#xff0c;请采用邻接矩阵来存储图1&#xff0c;采用邻接表来存储图2&#xff0c;并完成如下操作&#xff1a;对图1无向图进行深度优先遍历和广度优先遍历。对图1无向图采用Kruskal算法和Prim算法得出最小…

如何保持高能量

精力管理 精力管理对于平衡多项任务和保持热情至关重要。 通过自我积极反馈循环系统培养积极的内心声音。 培养仪式和习惯来控制内心的声音并保持能量。 学习语言带来正能量和宝贵的技能 保持高能量需要自我赋权和体力充电。 经常锻炼有很多好处&#xff0c;包括改善健康…

BLIP和BLIP2

1.BLIP BLIP的第一个共享是将图像文本理解与图像文本生成任务进行了统一&#xff0c;形成了多模态统一模型&#xff0c;模型在ITC任务上的效果也比CLIP更好。 1.1任务 ITC&#xff1a;就是CLIP中的图像文本对比学习任务 ITM&#xff1a;针对ITC任务中匹配不正确的样本&#…

django 创建表模型中的meta

null 如果为True&#xff0c;Django 将用NULL 来在数据库中存储空值。 默认值是 False. blank 后台管理---》admin中会用&#xff0c;咱们一般用的少 如果为True&#xff0c;该字段允许不填。默认为False。 要注意&#xff0c;这与 null 不同。null纯粹是数据库范畴的&#…

每当晚上,总是会因为自己没有对象而感到灵魂上的孤独

每到晚上&#xff0c;总是会因为自己没有对象而感到灵魂上的孤独 那是灵魂上的孤独。心中很多的渴望没有满足&#xff0c;无处所说&#xff0c;自己内心的苦闷总是希望能够在现实生活中有一个人可以倾诉&#xff0c;希望有一个人能够和自己一起去面对生活中的风风雨雨。 我理…

FreeRtos第一个task是怎么run起来的

第一个task是怎么起来的呢&#xff1f;分析完vTaskStartScheduler&#xff0c;就会有答案了。 那vTaskStartScheduler()干了啥呢&#xff1f; 一、创建prvIdleTask task 二、xTimerCreateTimerTask里创建prvTimerTask task 三、初始化一些全局变量 3.1 xNextTaskUnblockTime…

业务数据治理体系化实施流程学习总结

目录 一、业务数据治理实施流程 步骤 1&#xff1a;发现问题和制定目标 步骤 2&#xff1a;针对问题进行拆解&#xff0c;设计可衡量的指标 步骤 3&#xff1a;制定解决SOP和检查研发标准规范 步骤 4&#xff1a;推广运营&#xff0c;以拿结果为核心目标 步骤 5&#xff…

navicat某些表为什么不按主键排序

不知道大家注没注意过navicat的这种情况 为什么不是按主键排序呢 我们来全表扫描看下他的执行计划 explain select * from orsql3; 可以发现不是全表扫描而是索引树扫描&#xff0c;由此得知了共性&#xff0c;不按主键顺序排序的表&#xff0c;肯定是在二级索引上就保存着全部…

计算机网络体系的形成

目录 1、开放系统互连参考模型OSI/RM 2、两种国际标准 3、协议与划分层次 4、网络协议的三要素 5、划分层次 &#xff08;1&#xff09;文件发送模块使两个主机交换文件 &#xff08;2&#xff09;通信服务模块 &#xff08;3&#xff09;接入网络模块 6、分层带来的好…

pytorch 模型量化quantization

pytorch 模型量化quantization 1.workflow1.1 PTQ1.2 QAT 2. demo2.1 构建resnet101_quantization模型2.2 PTQ2.3 QAT 参考文献 pytorch框架提供了三种量化方法&#xff0c;包括&#xff1a; Dynamic QuantizationPost-Training Static Quantization&#xff08;PTQ&#xff0…