Cikada 0.5 发布

CWEB 不权威指南

Garfileo posted @ 2012年7月07日 14:30 in 业余程序猿的足迹 with tags CWEB 文学编程 , 10445 阅读

为了准备上次所说的 Haskell 文学编程项目,这两天浅尝辙止的学习了一点 CWEB 的知识,勉强可以进行 C 语言的文学编程了。

CWEB 程序的结构很简单,最小而全的编程单位是“”。每节分为三个部分:

  • TeX 部分,就是用 TeX 所写的文档;
  • 中间部分,主要是用于定义 C 语言的宏;
  • C 代码部分,就是放置 CWEB 宏或 C 代码的区域。

这三个部分中的任何一个都可以为空,但是它们必须要按照这个次序出现。

下面这个例子就是 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 来获得头文件所在目录的绝对路径。

@<头文件@>=
#include <clutter/clutter.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 信号。
 
@<Stage 的事件设置 @>=
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 节的说明,从头到尾将上面那个程序读一遍,你就会发现这个程序完全是按照人类的逻辑来写的,阅读它要比直接阅读“凌乱的舞台”文中的那个示例程序的代码要轻松的多。

转载时,希望不要链接文中图片,另外请保留本文原始出处:http://garfileo.is-programmer.com

  • 无匹配
demonstrate 说:
2012年7月16日 13:26

那和写注释有什么区别呢?doxygen 感觉更好用

Avatar_small
Garfileo 说:
2012年7月16日 13:31

@demonstrate: 注释显然是不能够改变代码的既有顺序,而 WEB 则是完全可以根据人类的思维来放置程序代码。例如一本 linux 内核代码分析的书,完全可以不用按照 linux 内核的代码来写,而且我们往往更愿意看这样的书,而不愿意去看内核代码中的注释。

Mike 说:
2012年7月19日 06:34

@Garfileo: 有本書和這個思想很像啊,《C语言接口与实现:创建可重用软件的技术》。裏面的例子都是這格式。

Avatar_small
Garfileo 说:
2012年7月19日 07:36

@Mike: 嗯。实际上,那本书本身就是利用文学编程所实现的程序的文档输出得到的。

hckjsnzf 说:
2012年11月08日 09:18

可以用noweb,控制序列什么的都很简单..
生成的是latex格式..

其实可以考虑自己做个啊,模仿noweb,不想要太多的控制序列,感觉cweb的太多了.
然后输出成context的格式.

leeward 说:
2014年1月17日 16:46

怎麼調試程序呢?生成出來調試?

Avatar_small
rca 说:
2014年1月18日 17:11

@leeward: 由 WEB 文件产生的 C 代码,每一行 C 代码都会有一个 line 宏,将代码行定位到 WEB 文件中。


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter