初级代码游戏的专栏介绍与文章目录-CSDN博客
我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。
这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。
系列入口:
编程实战:类C语法的编译型脚本解释器(系列)-CSDN博客
本文介绍总入口和使用方法。
目录
一、总入口
1.1 接口类
1.2 AttachScript连接到已编译的脚本
1.3 Compile编译
1.4 Execute执行
二、调用示例
一、总入口
1.1 接口类
//脚本解释器接口
class CZBScript;
class IScript
{
private:
CScript* m_p;
string m_msg;
public:
IScript() :m_p(nullptr) {}
string GetMessage()const;
//连接
bool AttachScript(CScript* p);
//编译
bool Compile(char const* _source, vector<pair<string, Variable > >* pEnvs = NULL);
//执行
string const& GetSource()const;
bool IsCompiled()const;
string& Report(string& ret)const;
bool Execute(Variable& ret, vector<pair<string, Variable > >* pEnvs = NULL, void* pe = NULL);
long GetExecCount()const;
};
这个入口是个壳,目的是减少客户代码需要包含的内容。CScript才是实际功能,IScript包含CSpript的指针,这样只需要一个前置声明,而不需要全部实现。
接口化的另一个好处是模块界限很清晰,对外的都在这里,对内的不需要暴露。
1.2 AttachScript连接到已编译的脚本
这个方法可能看起来很奇怪,其实呢,我的大部分代码都会考虑能否放在共享内存里面,节省时间和内存,所以这函数就是用来连接到共享内存里的已经编译好的数据结构的。
保存到共享内存这部分应该是还不怎么满意的,暂时无视吧。
1.3 Compile编译
编译需要用脚本和预设变量为参数。预设变量就是提前设置的变量,作为全局变量存在,和脚本内定义的变量一样用变量名访问。不过编译时并不需要实际有意义的值,只需要提供变量类型即可。当然了,如果插件里面对变量值也有要求当然是可以的。插件解释器编译时只检查类型,但插件的CheckPlugin做什么完全是用户决定的。
巨汗!发现插件参数pc根本没法传,没这个参数,实现里面倒是有的。
1.4 Execute执行
执行需要提供预设变量和pe参数(pc参数还是没有,大BUG),预设变量参数按道理和编译时相比应该具有相同的变量名称和类型,如果有缺失或不一致,运行时可能会出错(运行时仍会检查数据类型的正确性)。
二、调用示例
//全局定义
CScript script;
IScript _script;
IScript * script=NULL;
string stlstr;
vector<pair<string,Variable > > envs;
//初始化,可以放在OnInitDialog
script = &_script;
if(NULL==zbscript)
{
MessageBox("内存不足","错误",MB_ICONSTOP);
OnCancel();
}
script->AttachScript(&script);
pair<string,Variable > tmppair;
Variable tmpvar;
tmpvar.type=Variable::LONG;
tmppair.first="total";
tmppair.second=tmpvar;
envs.push_back(tmppair);
//编译
CString str;
m_Edit_Source.GetWindowText(str);
if(script->GetSource()!=str.GetString() || !script->IsCompiled())
{
if(!script->Compile(str,&envs))
{
MessageBox(script->GetMessage().c_str(),"出错",MB_OK|MB_ICONSTOP);
}
m_Edit_Report.SetWindowText(script->Report(stlstr).c_str());
}
//执行
if(script->IsCompiled())
{
Variable var;
envs[0].second=10L;
if(!script->Execute(var,&envs))
{
MessageBox(script->GetMessage().c_str(),"出错",MB_OK|MB_ICONSTOP);
}
else
{
MessageBox(var.GetString().c_str(),"运行结果");
}
m_Edit_Report.SetWindowText(script->Report(stlstr).c_str());
}
上面的代码定义了预设变量“total”,类型为LONG,脚本里面是可以直接访问的,所有的内置函数也都是可以使用的。
执行时的用户提供的指针pe没有传递,因为没有添加插件,用不到。
添加插件的接口:
bool CPluginMap::AddPlugin(char const* name, Variable::types type, CPlugin* p);
这是个静态方法,可以直接使用。
运行结果:
答案没问题吧?
(这里是结束,但不是整个系列的结束)