C++的脚本语言:ChaiScript
C++的脚本语⾔:ChaiScript
是⼀个可以⽅便的嵌在 C++ 程序⾥的脚本语⾔,相⽐于 V8(Google JavaScript)和 Lua 来说,它的⽤法要简单得多。ChaiScript 和 STL ⼀样只有头⽂件,缺点是编译慢,⽽且因为⼤量使⽤模板,编译就更慢。
说明:
本⽂⽰例代码⼀律假定已经 using namespace chaiscript。
本⽂已经有些年头了,不代表 ChaiScript 最新特性。
函数
导出(expose)函数到 ChaiScript:
int echo (int i) {
致富创业return i;
}
ChaiScript chai;
chai.add(fun(&echo), "echo");  // 导出到ChaiScript
int i = chai.eval<int>("echo(1)");  // 在ChaiScript⾥调⽤这个函数
导出重载函数时,需要指定具体类型:
string echo(const string& s) {
return s;
}
ChaiScript chai;
chai.add(fun<int (int)>(&echo), "echo");
chai.add(fun<string (const string&)>(&echo), "echo");
int i = chai.eval<int>("echo(1)");
竹石 古诗string s = chai.eval<string>("echo(\"string\")");
六一儿童节祝福语小学生强类型
给定:
unsigned int fac(unsigned int n) {
return n == 0 ? 1 : n * fac(n - 1);
}
chai.add(fun(&fac), "fac");
这样调⽤是不⾏的:
unsigned int fac = chai.eval<unsigned int>("fac(3)"); // 错!
会有 bad_boxed_cast 异常。应该在调⽤时显式的转成 unsigned int:
unsigned int fac = chai.eval<unsigned int>("fac(unsigned_int(3))");
或者,直接以 signed int 来导出这个函数:
chai.add(fun<int (int)>(&fac), "fac");
int fac = chai.eval<int>("fac(3)");
C++ 虽然也是强类型,但是允许 signed 和 unsigned 之间隐式转换。如果 fac 函数只有 unsigned 实现,fac(3) 也能调⽤,3 是signed(3u 表⽰ unsigned),但是 C++ 可以将它隐式转换成 unsigned。ChaiScript 则不⾏,signed 就是 signed,unsigned 就是unsigned,需要显式转换(3u 这种写法 ChaiScript 也不⽀持)。
对 ChaiScript 来说,int 和 double 都是 POD(plain object data)类型,bool 和 std::string 也是,完整的列表详见 ChaiScript bootstrap(⾃举,引导)的那段代码。
数组
ChaiScript 提供的 Vector 类似于 STL 的 vector:
var v := Vector()
v.push_back(1)
v.push_back(2)
print(v) // [1, 2]
Vector 的构造和初始化可以简化(类似于 Python 的列表):
var v := [1, 2]
在 STL 的 vector 和 ChaiScript 的 Vector 之间,是不可以“直接”转换的:
vector<int> ints = chai.eval<vector<int> >("[1, 2, 3]"); // 错!
这样会有 bad_boxed_cast 异常。右边 eval 返回的是 vector<Boxed_Value>,不能⾃动转成 vector<int>。也可以简单理解成:⾃动 Box 和 Unbox 只对 POD 类型有效。这是⼀种设计上的折中吧,作者是这样解释的:
下⾯说说细节。⾸先是 eval 的结果可以引⽤:
vector<Boxed_Value>& ints = chai.eval<vector<Boxed_Value> >("[1, 2, 3]");
这就避免了⼀次拷贝构造。但是注意,Boxed_Value ⾥具体的数据是引⽤计数的:
class Boxed_Value {
private:
boost::shared_ptr<Data> m_data;
};
所以 vector 本⾝引⽤与否,不影响内部的数据。
假如想在 C++ 这边改 ChaiScript ⾥的这个数组,也可以:
vector<Boxed_Value>& ints = chai.eval<vector<Boxed_Value> >("var a := [1, 2, 3]; a;"); // 声明变量a⽅便后续访问
皇帝蟹ints[0].assign(Boxed_Value(4));
chai.eval("print(a[0])"); // 4
这⾥有两点值得注意。⾸先,变量 ints 不⽤引⽤也可以达到相同效果,因为如前所述,Boxed_Value 内部的数据有引⽤计数。其
次,assign 不能替换成 =:
ints[0] = Boxed_Value(4);
⽤ =,之前的那个 Boxed_Value 就被替换掉了。
引⽤
下⾯这两种写法的差别在于,第⼀种多⼀次拷贝构造:
var a = Vector()
var a := Vector()
看两个例⼦。
上海二日游攻略例⼀:
var a := Vector()
var b = a // 拷贝构造了b
b.push_back(1) // b改了,a仍为[]
例⼆:
var a := Vector()
var b := a // b引⽤a
b.push_back(1) // a和b都改了
发现⼀个 bug,⽤快捷⽅式创建的 Vector,不能再被其他变量引⽤:
var a := [1, 2, 3] // ⽤快捷⽅式创建
var b := a
b.push_back(1) // Crash!
可见 ChaiScript 还有很多问题。不够成熟是我对它最⼤的顾虑。
class Buffer {
public:
size_t LineCount() const { return lines_.size(); }
string& GetLine(size_t line_index) {
return lines_[line_index];
}
const string& GetLine(size_t line_index) const {
return lines_[line_index];
}
void AddLine(const string& line) {
lines_.push_back(line);
}
private:
vector<string> lines_;
};
chai.add(user_type<Buffer>(), "Buffer");
// Default constructor
chai.add(constructor<Buffer ()>(), "Buffer");
// Copy constructor
chai.add(constructor<Buffer (const Buffer &)>(), "Buffer");
chai.add(fun(&Buffer::AddLine), "AddLine");
chai.add(fun(&Buffer::LineCount), "LineCount");
扭曲树精技能
成员变量
成员变量的导出⽅法和成员函数相同。
class Option {
public:
std::string cjk;
std::string file_encoding;
bool show_space;
bool show_number;
};
chai_->add(user_type<Option>(), "Option");
chai_->add(fun(&Option::cjk), "cjk");
chai_->add(fun(&Option::file_encoding), "file_encoding");
chai_->add(fun(&Option::show_number), "show_number");
chai_->add(fun(&Option::show_space), "show_space");
⼀些补充
传值,传引⽤
1. Basic data types are passed by value.
2. Class data types are passed by reference.
3. There is not specific syntax for one or the other.
4. Use wrapper classes for basic data types, if you want to pass them by reference (like Java.)
关于 use
如果导出⼀个变量,然后 eval ⼀个⽂件,这个⽂件⼜ use 了另⼀个⽂件,那么被 use 的那个⽂件是看不到这个变量的。use 就相当于 C++ 的 include,被 use 的⽂件⼀般定义了⼀些公共的函数和类。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。