为了准备上次所说的 Haskell 文学编程项目,这两天浅尝辙止的学习了一点 CWEB 的知识,勉强可以进行 C 语言的文学编程了。
CWEB 程序的结构很简单,最小而全的编程单位是“节”。每节分为三个部分:
这三个部分中的任何一个都可以为空,但是它们必须要按照这个次序出现。
下面这个例子就是 CWEB 程序的一节:
@* Clutter Stage 构建示例 这个程序主要是构建一个 Stage 对象,并让它能够对单击事件作出改变背景 颜色的响应。程序结构大致如下: @c @<头文件@> @<全局变量@> @<响应单击事件的函数@> @<主函数@>
这个 CWEB 节只有 TeX 部分与 C 代码部分。代码中的 @ 符号后面尾随一个字符,这个结构叫做“控制字”。
@* 控制字表示开始一个新的 CWEB 节,并且领起 TeX 部分。@c 控制字表示开始 C 代码部分,而 @< ... @> 这样的结构表示 CWEB 宏,它表示一段 C 代码。
与 @* 控制字类似,@ 符号后面尾随一个空格字符,也可以开始一节,它与前者的区别是前者类似于写文档进行分章,而后者是构成章的各节。这些术语用的是真够乱的。HWEB 绝不这么变态。
下面是一个完整的 CWEB 程序,它构建了一个在逻辑上于“凌乱的舞台”一文中的示例程序完全相同的程序。
@* Clutter Stage 构建示例 Stage 是 Clutter 中的一个基本的 Actor。 “舞台”是“演员”? 这是因为 Clutter 库是基于 GObject 实现的。ClutterActor 是一个基类, ClutterStage 类继承了 ClutterActor。在功能上,ClutterStage 对象 相当于一个 Clutter 程序的窗口。 这个程序主要是构建一个 Stage 对象,并让它能够对单击事件作出改变背景 颜色的响应。程序结构大致如下: @c @<头文件@> @<全局变量@> @<响应单击事件的函数@> @<主函数@> @ 使用 Clutter 库时,只需包含 clutter.h 这一个头文件,并且通常要指定这个头文件所在 的目录。在实际编译程序时,往往需要使用 pkg-config 来获得头文件所在目录的绝对路径。 @<头文件@>= #includeclutter.h> @ 因为这是一个小程序,所以我就肆无忌惮 的使用三个全局变量,用于定义Stage 的三 种背景色:黑色、白色与蓝色。 @<全局变量@>= ClutterColor black = { 0x00, 0x00, 0x00, 0xff }; ClutterColor white = { 0xff, 0xff, 0xff, 0xff }; ClutterColor blue = { 0x00, 0x00, 0xff, 0xff }; @ @<主函数@>= int main (int argc, char **argv) { @<初始化 Clutter 环境@>; @<构建 Stage@>; @<Stage 的事件设置 @>; * 进入 Clutter 主事件循环 */ clutter_main (); return 0; } @ @<初始化 Clutter 环境@>= if (clutter_init (&argc;, &argv;) != CLUTTER_INIT_SUCCESS) return 1; @ @<构建 Stage@>= ClutterActor *stage = clutter_stage_get_default (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Hello Stage!"); clutter_actor_set_size (stage, 400, 200); clutter_actor_set_background_color (stage, &black;); clutter_actor_show (stage); @ 因为所有的 Clutter 对象都是 GObject 的派生对象,所以它们支持 GObject 信号。 @= g_signal_connect (stage, "button-press-event", G_CALLBACK (on_stage_button_press), NULL); @ 在单击事件发生时,更换 Stage 的背景色。 @<响应单击事件的函数@>= static gboolean on_stage_button_press (ClutterStage *stage, ClutterEvent *event, gpointer data) { static guint status = 1; switch (status++) { case 0: clutter_stage_set_color (CLUTTER_STAGE (stage), &black;); break; case 1: clutter_stage_set_color (CLUTTER_STAGE (stage), &white;); break; default: clutter_stage_set_color (CLUTTER_STAGE (stage), &blue;); status = 0; } return TRUE; }
如果你的机器上安装了 TeXLive 之类的 TeX 发行版,那么应该是有 ctangle 和 cweave 工具的。
如果将上面的 CWEB 程序复制到 test.w 文件中,然后使用:
$ ctangle test.w
即可产生 test.c 文件,使用 `pkg-config --cflags --libs clutter-1.0 | xargs gcc test.c` 即可编译为一个 Clutter 程序。
使用:
$ cweave test.w
可以生成 test.tex 文件,但是不要指望能够直接编译成 PDF 文档,因为 CWEB 使用的是 Knuth 的 Plain TeX 格式,不直接支持中文。
更闹心的是,ctangle 与 cweave 这两个工具本身也不支持 Unicode 编码。所以在 CWEB 程序中,如果包含中文的文本过长,ctangle 或 cweave 便会抱怨文本行太长而出错。
那么使用 CWEB 写程序究竟有什么好处呢?如果你能够基于一开始我对 CWEB 节的说明,从头到尾将上面那个程序读一遍,你就会发现这个程序完全是按照人类的逻辑来写的,阅读它要比直接阅读“凌乱的舞台”文中的那个示例程序的代码要轻松的多。