- 1. 摘要
- 2. 构建 libRed
- 3. 值引用
- 4. C API
- 4.1. 管理库
- 4.2. 运行 Red 代码
- 4.3. 注册回调函数
- 4.4. 从 C 创建 Red 值
- 4.4.1.
redSymbol()
- 4.4.2.
redUnset()
- 4.4.3.
redNone()
- 4.4.4.
redLogic()
- 4.4.5.
redDatatype()
- 4.4.6.
redInteger()
- 4.4.7.
redFloat()
- 4.4.8.
redPair()
- 4.4.9.
redTuple()
- 4.4.10.
redTuple4()
- 4.4.11.
redBinary()
- 4.4.12.
redImage()
- 4.4.13.
redString()
- 4.4.14.
redWord()
- 4.4.15.
redBlock()
- 4.4.16.
redPath()
- 4.4.17.
redLoadPath()
- 4.4.18.
redMakeSeries()
- 4.4.1.
- 4.5. 从 Red 创建 C 值
- 4.6. 调用 Red 动作
- 4.7. 访问 Red 单词
- 4.8. 访问 Red 路径
- 4.9. 访问 Red 对象的字段
- 4.10. 调试
- 4.11. 数据类型定义
- 5. Visual Basic API
LibRed 是 Red 解释器和运行时库的一个特殊版本,适合集成到 Red 之外的语言开发的软件里。为了允许非 Red 软件与 Red 交互,libRed 暴露了一个专用的底层 API(遵循 C 语言的 cdecl 或微软的 stdcall 标准),该 API 描述在该文档中。它支持的特性当中包含:
-
从全局或局部语境中设置/获取一个单词的值的能力。
-
大部分常见的 Red 数据类型的快捷构造器。
-
与宿主语言(主要是 C 语言)兼容的 Red 数据类型的转换函数。
-
由宿主语言发起的序列操纵。
-
允许 Red 调用宿主语言函数的回调函数。
-
面向控制台的调试函数。
术语:名词宿主(host)用来指宿主语言或嵌入了 libRed 的应用程序。
libRed 的使用样例可以从这里找到。
构建你的本地版本的 libRed 很简单:
red build libRed
或者由 Rebol 的控制台和 Red 的源码构建:
rc "build libRed"
这些命令行将会构建出用于 C 语言的版本的 libRed(采用 cdecl
ABI)。如果你需要 stdcall
ABI(为了兼容微软的应用),你需要使用:
red build libRed stdcall
Red 值可以通过 libRed 函数调用被返回,以 32 位的不透明引用表示。这些引用的生命周期很短,所以它们只适合于在受限的局部范围内使用,比如传递那个引用到另一个 libRed 的函数调用。可以把这种引用设置给宿主变量,它应紧接其后被使用。这些引用使用一个特定的内存管理器,它将仅在接下来的大约 50 次 API 调用内保持引用有效。例:
long a, blk;
a = redSymbol("a");
redSet(a, redBlock(0)); // 这里立即就使用了返回的引用
blk = redGet(a);
redPrint(blk); // 引用的使用是安全的
for(i = 0; i < 100, i++) {
// redAppend(blk, redNone()); // 引用的使用不安全!
redAppend(redGet("a"), redNone()); // 安全的版本
}
C API 可以用在 C/C++ 应用程序中,也可以集成 Red 到任何其它有与 C 兼容的外部函数接口的编程语言中。
为了使用 API 中的函数,需要创建 libRed实例。
注意
|
当前,每个进程只允许单个 libRed 会话,预定未来会将其扩展为允许支持多实例。 |
void redOpen(void)
初始化一个新的 Red 运行时库会话。必须在调用任何其他 API 函数之前调用该函数。在同一个进程中调用多次是安全的,无论如何只会打开一个会话。
注意
|
如果在 |
宿主软件可以使用不同的控制级别来直接运行 Red 代码,上到提供文本形式的 Red 代码用于执行,下到直接调用任意 Red 函数并传递在宿主端构造的参数。
red_value redDo(const char* source)
执行作为字符串传递的 Red 表达式并返回最后一个 Red 值。
例
redDo("a: 123");
redDo("view [text {hello}]");
char *s = (char *) malloc(100);
const char *caption = "Hello";
redDo(sprintf(s, "view [text \"%s\"]", caption));
red_value redDoFile(const char* filename)
加载并执行以 filename
引用的 Red 脚本并返回最后一个 Red 值。filename
格式使用 Red 独立于操作系统的惯例(基本为 Unix 风格)。
例
redDoFile("hello.red");
redDoFile("/c/dev/red/demo.red");
red_value redDoBlock(red_block code)
执行参数区块并返回最后一个 Red 值。
例
redDoBlock(redBlock(redWord("print"), redInteger(42)));
响应在 Red 发生的事件或将一些 Red 的调用重定向到宿主端(如重定向 print
或 ask
)需要一种从 Red 端调用宿主函数的方法。这可以使用 redRoutine()
函数来实现。
red_value redRoutine(red_word name, const char* spec, void* func_ptr)
定义一个新的 Red 例程叫做 name
,以 spec
作为规格区块,func-ptr
C 函数指针做为主体。C 函数 必须 返回一个 Red 值(redUnset()
可以用来表示没有使用返回值)。
例
#include "red.h"
#include <stdio.h>
red_integer add(red_integer a, red_integer b) {
return redInteger(redCInt32(a) + redCInt32(b));
}
int main(void) {
redRoutine(redWord("c-add"), "[a [integer!] b [integer!]]", (void*) &add);
printf(redCInt32(redDo("c-add 2 3")));
return 0;
}
libRed API 中的许多函数需要传递 Red 值(作为引用)。以下函数是最常用数据类型的简单的构造函数。
long redSymbol(const char* word)
返回与加载的 word
(以 C 字符串的形式提供)相关联的符号 ID,之后可以将此 ID 传递给不需要单词值而需要符号 ID 的其他 libRed API 函数。
例
long a = redSymbol("a");
redSet(a, redInteger(42));
printf("%l\n", redGet(a));
red_logic redLogic(long logic)
返回一个 logic!
值。logic
值为 0
会产生 false
值,所有其他的值都产生 true
。
red_datatype redDatatype(long type)
返回一个对应于 type
ID 的 datatype!
值,它是 RedType
枚举中的一个值。
red_tuple redTuple(long r, long g, long b)
从三个整数值(通常用于表示 RGB 颜色)返回一个 tuple!
值,传递的参数将被截断为 8 位元值。
red_tuple redTuple4(long r, long g, long b, long a)
从四个整数值(通常用于表示 RGBA 颜色)返回一个 tuple!
值,传递的参数将被截断为 8 位元值。
red_binary redBinary(const char* buffer, long bytes)
从内存 buffer
指针和这个缓冲区的长度(以字节为单位)返回一个 binary!
值。输入缓冲区将在内部被复制。
red_image redImage(long width, long height, const void* buffer, long format)
从内存 buffer
指针返回一个`image!` 值。图像的大小以 width
和 height
的形式定义,以像素为单位。输入缓冲区将在内部被复制。接受的缓冲区格式有:
-
RED_IMAGE_FORMAT_RGB
:每一个像素 24 位元。 -
RED_IMAGE_FORMAT_ARGB
: 每一个像素 32 位元,透明通道在最前。
red_string redString(const char* string)
从 string
指针返回一个 string!
值。参数字符串的默认预期编码为 UTF-8,其他编码可以使用 redSetEncoding()
函数定义。
red_word redWord(const char* word)
从 C 字符串返回一个 word!
值。参数字符串的默认预期编码为 UTF-8,其他编码可以使用 redSetEncoding()
函数定义,不能加载成单词的字符串将返回一个 error!
值。
red_block redBlock(red_value v,...)
从参数列表返回一个新的 block!
序列。列表 必须 以 null
或 0
值终止,作为结束标记。
例
redBlock(0); // 创建一个空区块
redBlock(redInteger(42), redWord("hi"), 0); // 创建区块 [42 hi]
red_path redPath(red_value v, ...)
从参数列表返回一个新的 path!
序列。列表必须以 null
或 0
值终止,作为结束标记。
例
redDo("a: [b 123]");
long res = redGetPath(redPath(redWord("a"), redWord("b"), 0));
printf("%l\n", redCInt32(res)); // 会输出 123
red_path redLoadPath(const char* path)
从一个以 C 字符串表示的路径返回 path!
序列。这提供了一种构建路径的快捷的方法,不用单独构建每个元素。
例
redGetPath(redLoadPath("a/b")); // 创建并对该 path! a/b 进行求值。
red_value redMakeSeries(unsigned long type, unsigned long slots)
返回一个新的 type
类型的,有足够大小存储 slots
个元素的 series!
。这是一个泛用的序列构造函数。类型需要为 RedType
枚举值之一。
例
redMakeSeries(RED_TYPE_PAREN, 2); // Creates a paren! series
long path = redMakeSeries(RED_TYPE_SET_PATH, 2); // 创建一个 set-path!
redAppend(path, redWord("a"));
redAppend(path, redInteger(2)); // 现在 path 为 `a/2:`
将 Red 值转换到宿主端是可能的,然而会受限于 C 语言中有限个数量的类型。
const char* redCString(red_string string)
从一个 Red string!
值返回一个 UTF-8 字符串缓冲区指针。其他编码可以使用 redSetEncoding()
函数定义。
long redTypeOf(red_value value)
返回一个 Red 值的类型 ID,类型 ID 值定义在 RedType
枚举中。参考数据类型小节。
虽然可以使用 redCall
调用任何Red函数,但为了方便和更好的性能,它提供了对于大部分常见的操作的一些快捷方式。
red_value redAppend(red_series series, red_value value)
将 value
追加到 series
中,并返回该序列头部。
red_value redChange(red_series series, red_value value)
修改 series
中的 value
,并返回修改的部分之后的序列。
red_value redFind(red_series series, red_value value)
返回指向找到 value
的位置的序列,或返回 none
。
red_value redPoke(red_series series, red_value index, red_value value)
使用 value
替换给定 index
上的 series
,并返回这个新的值。
red_value redPut(red_series series, red_value index, red_value value)
替换 series
或 map!
中接在键的后面的值,并返回这个新的值。
red_value redSelect(red_series series, red_value value)
在 series
中查找 value
并返回其下一个值,或返回 none
。
设置 Red 单词或获取 Red 单词的值是在宿主和 Red 运行时环境之间传递值的最直接的方式。
red_value redSet(long id, red_value value)
将由 id
符号定义的一个单词设置为 value
。从该符号创建的单词会被绑定到全局语境。此函数返回 value
。
路径是用来访问 Red 中的数据的非常灵活的方式,因此他们在 libRed 中具有专用的访问器函数。值得注意的是,它们允许访问在对象语境中的单词。
red_value redSetPath(red_path path, red_value value)
将一个 path
设置为一个 value
并返回该 value
。
当对象的字段需要进行多次设置/获取操作时,比起构建路径,直接使用对象值更简单、更好。以下两个函数是针对这种访问量身打造的。
注意
|
这些访问器对任意其它关联数组类型都有效,不仅仅有 |
red_value redSetField(red_value object, long field, red_value value)
将 object
的 field
设置为 value
并返回该 value
。field
参数是使用 redSymbol()
创建的符号 ID。
它还提供了一些方便的调试功能。虽然大多数需要系统 shell 窗口用来输出,但是强制打开一个日志窗口或将输出重定向到一个文件也是可能的。
red_value redProbe(red_value value)
在标准输出中探查 value
;若打开了调试控制台,探查在调试控制台里。该函数调用返回此 value
。
red_value redHasError(void)
如果在之前的 API 调用中发生了一个错误,返回一个 error!
值;或如果没有发生错误则返回 null
。
const char* redFormError(void)
如果发生了一个错误,返回包含格式化的错误的 UTF-8 字符串指针;如果没有发生错误,则返回 null
。
int redOpenLogWindow(void)
打开日志窗口并将所有 Red 打印输出重定向到该窗口。如果宿主应用程序不是从系统 shell 运行,该功能非常有用,默认使用它打印输出。如果日志窗口已经打开,多次调用此函数不会有效果。成功时返回 1
,失败时返回 0
。
注意
|
仅适用于 Windows 平台。 |
int redCloseLogWindow(void)
关闭日志窗口。当日志窗口已经关闭时调用此功能不会有效果。成功时返回 1
,失败时返回 0
。
注意
|
仅适用于 Windows 平台。 |
void redOpenLogFile(const string *name)
将 Red 打印函数的输出重定向到 name
所指定的文件中。name
可以使用特定于操作系统的文件路径格式提供相对或绝对路径。
libRed API 中的一些函数可以引用 Red 数据类型:redTypeOf()
、redMakeSeries()
和 redDatatype()
。Red 数据类型在宿主端表示为枚举(RedType
),类型为使用以下结构的名称:
RED_TYPE_<DATATYPE>
完整的清单可以在这里找到。
Visual Basic API 可用于 VB 和 VBA(来自微软 Office 应用程序)。它基本上与 C API 相同,因此以下小节将仅描述差异。差异主要在于变长函数,它们分为两种风格:
-
redBlock()
、redPath()
、redCall()
只接收 Red 值,不要求一个终止的null
或0
值,就像 C 版本那样。 -
redBlockVB()
、redPathVB()、 `redCallVB()
只接收 VB 值,它自动根据以下表格被转换:
VisualBasic | Red |
---|---|
|
|
|
|
|
|
|
|
|
|
为了在 VB/VBA 中使用 libRed,你需要一个为 stdcall
ABI 编译的 libRed 二进制文件版本。如果你需要重新编译此类版本:
red build libRed stdcall
你还会需要在项目中导入libRed.bas
模块文件。
Function redBlockVB(ParamArray args() As Variant) As Long
返回一个从参数列表构建的新的 block!
序列。参数个数是可变的,仅由 VisualBasic 值组成。
例
redProbe redBlockVB() ' 创建空区块
redProbe redBlockVB(42, "hello") ' 创建 [42 "hello"] 区块
Function redPathVB(ParamArray args() As Variant) As Long
返回一个从参数列表构建的新的 path!
序列。参数个数是可变的,仅由 VisualBasic 值组成。
例
redDo("a: [b 123]")
res = redGetPath(redPathVB("a", "b"))
Debug.print redCInt32(res)) ' 会输出 123
Function redCallVB(ParamArray args() As Variant) As Long
调用由传递的字符串(第一个参数)引用的 Red 函数(any-function!
类型),最后传递一些参数给它(作为 VisualBasic 值)。返回该函数的最后一个值。参数个数是可变的,仅由 VisualBasic 值组成。
例
redCallVB("random", 6); ' 返回在 1 到 6 之间的随机 integer! 值
创建可以从 Red 端调用的 VisualBasic 函数的做法类似于 C API,使用 redRoutine()
调用。该函数的最后一个参数是一个函数指针。在 VB 中,这样的指针只能从在 module
而不是在 UserForm
中定义的函数取得。
这是 Excel “Red 控制台” 演示所使用的回调函数:
Sub RegisterConsoleCB()
redRoutine redWord("print"), "[msg [string!]]", AddressOf onConsolePrint
End Sub
Function onConsolePrint(ByVal msg As Long) As Long
If redTypeOf(msg) <> red_unset Then Sheet2.AppendOutput redCString(msg)
onConsolePrint = redUnset
End Function