![]() |
Show Changes |
![]() |
Edit |
![]() |
|
![]() |
Recent Changes |
![]() |
Subscriptions |
![]() |
Lost and Found |
![]() |
Find References |
![]() |
Rename |
![]() |
Administration Page |
![]() |
Topic Locks |
| Search |
History
| 9/4/2011 4:57:03 PM |
| -213.37.39.29 |
| 9/4/2011 4:56:24 PM |
| -213.37.39.29 |
| 9/4/2011 4:54:42 PM |
| -213.37.39.29 |
| 9/4/2011 4:53:41 PM |
| -213.37.39.29 |
| 9/4/2011 4:48:14 PM |
| -213.37.39.29 |
![]() |
List all versions |
Check out the formatting tips on the right for help formatting and making links.
Use the template below:
这个教程一步步解释了如何构建一个最小的Squirrel嵌入应用程序,载入和运行脚本。
首先,让我们看一下下面的脚本和C代码,等一下我会详细解释它们是干什么的。
Squirrel 代码
function foo(i, f, s)
{
print("Called foo(), i = " + i + ", f = " + f + ", s = '" + s + "'");
}
还有这是 C 代码
C 代码
#include <stdarg.h>
#include <stdio.h>
#include <squirrel.h>
#include <sqstdio.h>
#include <sqstdaux.h>
#ifdef _MSC_VER
#pragma comment(lib, "squirrel.lib")
#pragma comment(lib, "sqstdlib.lib")
#endif
#ifdef SQUNICODE
#define scvprintf vwprintf
#else
#define scvprintf vprintf
#endif
void printfunc(HSQUIRRELVM v, const SQChar *s, ...)
{
va_list arglist;
va_start(arglist, s);
scvprintf(s, arglist);
va_end(arglist);
}
void call_foo(HSQUIRRELVM v, int n, float f, const SQChar *s)
{
int top = sq_gettop(v); // 在调用函数前保存栈大小
sq_pushroottable(v); // push全局表
sq_pushstring(v, _SC("foo"), -1);
if(SQ_SUCCEEDED(sq_get(v, -2))) // 从全局表中获取'foo'
{
sq_pushroottable(v); // push 'this' (这里指的是全局表)
sq_pushinteger(v, n);
sq_pushfloat(v, f);
sq_pushstring(v, s, -1);
sq_call(v, 4, 0, 0); // 调用函数
}
sq_settop(v, top); // 恢复栈大小
}
int main(int argc, char* argv[])
{
HSQUIRRELVM v;
v = sq_open(1024); // 创建一个 VM ,初始化栈大小为1024
sqstd_seterrorhandlers(v);
sq_setprintfunc(v, printfunc, NULL); //设置打印函数
sq_pushroottable(v); //push根表(脚本将要存储的全局环境)
if(SQ_SUCCEEDED(sqstd_dofile(v, _SC("test.nut"), 0, 1))) // 如果有,输出语法错误
{
call_foo(v, 1, 2.5, _SC("teststring"));
}
sq_pop(v,1); //pop根表
sq_close(v);
return 0;
}
你首先要做的就是创建一个虚拟机(VM)
HSQUIRRELVM v = sq_open(1024);
1024 就是初始栈大小
Squirrel栈会自动增加,所以这个值只是一个给VM的参考值
Squirrel 允许你定义自己的错误处理函数,这个例子使用了标准IO库中预制的。
sqstd_seterrorhandlers(v);
为了能够使用像 print() 这样的函数来输出一些文字,为VM提供一个打印函数是非常必要的。
sq_setprintfunc(v, printfunc, NULL); //设置打印函数
而这里就是打印函数 printfunc 的定义
void printfunc(HSQUIRRELVM v, const SQChar *s, ...)
{
va_list arglist;
va_start(arglist, s);
scvprintf(s, arglist);
va_end(arglist);
}
第三个参数 NULL 告诉VM不需要任何自定错误处理函数。
Squirrel 提供了一个底层API来从任何媒体文件中编译和运行脚本。
无论如何,有90%的情况下,你想运行的脚本只是一个简单的文本文件,而且在编译后你就想马上运行它。
最简单的方法就是使用标准IO库(sqstdio.h)。
sqstd_dofile 编译并且运行一个脚本.
sq_pushroottable(v);
sqstd_dofile(v, "myscript.nut",0);
在运行脚本期间, sqstd_dofile 将在栈顶对象(这里代表根表)作为 this 使用。
Squirrel脚本中,我们作为举例的函数叫 foo。
为了调用这个函数,我们首先要检索到它并且将它放到栈中。
因为这个函数是在全局范围内声明的,所以是存放在根表中。
void call_foo(HSQUIRRELVM v, int n, float f, const SQChar *s)
{
int top = sq_gettop(v); // 在调用函数前保存栈大小
sq_pushroottable(v); // push全局表
sq_pushstring(v, _SC("foo"), -1);
if(SQ_SUCCEEDED(sq_get(v, -2))) // 从全局表中获取'foo'
{
sq_pushroottable(v); // push 'this' (这里指的是全局表)
sq_pushinteger(v, n);
sq_pushfloat(v, f);
sq_pushstring(v, s, -1);
sq_call(v, 4, 0, 0); // 调用函数
}
sq_settop(v, top); // 恢复栈大小
}
call_foo 调用函数 foo,并且传入一个integer, float 和 string 作为参数。
让我们一行一行来分析。
首先它记录了当前栈大小,这是为了在调用结束之后好清理。
int top = sq_gettop(v);
放入根表,函数就是从这里获取的。
sq_pushroottable(v);
| 负数索引 | 对象 |
| -1 | 根表 |
| ... | ... |
栈内数据
将字符串 "foo" 放入,在这里代表我们将要调用的函数的slot名。
sq_pushstring(v,_SC("foo"),-1);
参数-1指定VM将要自动计算字符串长度。
| 负数索引 | 对象 |
| -1(顶) | "foo" |
| -2 | 根表 |
| ... | ... |
栈内数据
然后获取函数
if(SQ_SUCCEEDED(sq_get(v,-2)))
函数 sq_get 将会从栈中拿出(pop)一个对象(这里代表了字符串"foo")并且将它作为关键字从栈顶-2位
置(在这里代表根表)获取对象。如果sq_get成功,则将结果放入栈中(这里结果指的便是 foo 函数)。
| 负数索引 | 对象 |
| -1(顶) | function foo(){} |
| -2 | 根表 |
| ... | ... |
站内数据 在调用 sq_get 之后
现在向栈中放入函数的参数。根表被再一次放入,作为 this 参数使用。Squirrel函数总是有一个隐含参数 this(
就像C++类成员一样)。
sq_pushroottable(v);
sq_pushinteger(v,n);
sq_pushfloat(v,f);
sq_pushstring(v,s,-1);
| 负数索引 | 对象 |
| -1(顶) | string |
| -2 | float |
| -3 | integer |
| -4 | 根表 |
| -5 | function foo(){} |
| -6 | 根表 |
| ... | ... |
栈内数据
最后 sq_call 函数被调用了。它执行实际的调用。
sq_call(v,4,0,0);
4 表示被调用函数有四个参数(this, integer, float, string)。
Squirrel将会拿出4个参数然后连接。然后栈顶就变成了那个函数对象。
第三个参数0告诉Squirrel它将调用的那个函数无返回值。如果不是0的话将会让Squirrel将函数返回值放入栈顶。
第四个参数0告诉Squirrel当出现运行时错误时不要调用错误处理函数。
| 负数索引 | 对象 |
| -1(顶) | function foo(){} |
| -2 | 根表 |
| ... | ... |
栈内数据 调用 sq_call 之后
函数已经被执行了,所以我们现在重置栈大小到初始状态。
sq_settop(v,top); //恢复初始栈状态
之前我们放入了为了执行 sqstd_dofile 向栈中放入了根表,现在是时候把它删除了。
sq_pop(v,1);
在程序最后我们删除Squirrel VM。
sq_close(v);
这一步释放了所有先前分配空间。