C++ Code Generation with Elisp

尽管使用Emacs有些年头了,但是在读PHP Code Generation with Elisp之前,我还没意识到可以在Emacs里做代码生成这样的事情。

用了这么久Emacs,感觉唯一不如其它IDE的地方就是没有生成class的wizard。于是只好每次不厌其烦的在头文件里写完类定义,再到C文件里写成员函数的定义,每个字母都是手工敲进去的,最多也是复制粘贴。直到有一天,我对自己说:“够了,为什么不懒一点呢?”于是,下面就有了下面这段代码。

(defun make-cpp-function-definition (buffer class-name start end)
"generate c++ function definition and insert it into `buffer'"
(interactive "BAppend to buffer: nMClass name: nr")
(setq function-declaration (buffer-substring-no-properties start end))
(setq function-definition nil)
(defun iter (pos)
(if (string-match
"\(?:\(?:virtual\|inline\|static\)[ tn]*\)?\(?:\(\(?:const[ tn]*\)?[^ tn;* tn]*\([^;]+\)\);"
function-declaration
pos)
(progn
(setq return-type
(match-string 1 function-declaration))
(setq one-function-definition
(match-string 2 function-declaration))
(if (equal class-name "")
(setq one-function-declaration
(concat return-type "n" one-function-definition))
(setq one-function-declaration
(concat return-type "n"
class-name "::" one-function-definition)))
(setq function-definition
(concat function-definition
one-function-declaration "n{n}nn"))
(iter (match-end 0)))
'()))
(save-excursion
(iter 0)
(set-buffer (get-buffer-create buffer))
(setq pos (point))
(insert function-definition)
(indent-region pos (point)))
(if (one-window-p)
(split-window-vertically))
(switch-to-buffer-other-window buffer))

用法如下:

  1. 把这段代码复制到你的.emacs文件里,这样在每次Emacs启动时都会自动安装该段代码。
  2. 如果不想重新启动Emacs的话,可以手动安装该函数,方法是把光标放在最后一个右括号后面,然后C-x C-e安装,更方便的方法是使用C-M-x,因为这个命令只要求光标在要安装的函数体内就可以了。
  3. 随便打开一个buffer,写一个class,如:
    class A {
    public:
    void print () const;
    virtual int get_constant () const;
    };
  4. It’s show time now. 🙂
  5. 选中两个成员函数(mark the region in which two member functions are),然后运行M-x make-cpp-function-definition,该命令会问两个问题,第一个是自动生成的空成员函数体要放到哪个buffer里,你要给出一个buffer,如果这个buffer不存在,Emacs会创建一个。第二个问题是class的名字是什么,对于这个例子来说,你只要输入A。当然,如果我足够牛的话,可以让这个函数自动发现类名,可惜我现在还是个菜鸟。:-(
  6. 回答两个问题后,生成的代码会插入指定buffer的光标所在处。这就是说,如果这是一个已经存在的buffer,你应该在运行该函数前选好光标的位置。生成的代码是这个样子:
    void
    A::print () const
    {
    }

    int
    A::get_constant () const
    {
    }
  7. 最后,当前frame会垂直分成两个窗口,分别包含类和成员函数体。

这个函数有个bug,就是它无法正确处理构造函数和析构函数。当然,你仍然可以用它,然后稍稍修改一下生成的函数体,这样也比一个字母一个字母敲要好。另一个bug是关于缩进的,因为缩进是跟buffer的mode相关的,所以如果要插入函数体的buffer不是c++ mode,那需要手工修改一下缩进。当然,在Emacs里,这很容易。

注:由于屡次受到垃圾评论的骚扰,本贴评论被关闭,有事发邮件。

One thought on “C++ Code Generation with Elisp

  1. 不错不错,不过你的blog界面可以收拾收拾了,拍板难看了点。看看我的新blog,就是看了你的介绍,去dreamhost上面申请了跟你一下的course。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据