升C小调狂想曲

<递归的忧伤>
posts - 10, comments - 71, trackbacks - 0, articles - 0
   :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理
我早就想写一个脚本引擎了,真的。

事情可以追溯到大一的时候,很想做游戏(虽然后来发现美工成了最大的问题),于是自己写了一套GUI,用起来还挺爽,但是就是一直觉得缺了个脚本引擎。

于是,奉天承运,我开始着手脚本引擎的计划了。

话说起码得先跟字符串培养培养感情,而且也是为了以后写脚本引擎时能省些苦力,还有很多其他因素影响,我决定先写一个正则表达式引擎。为了方便,我又得封一个性格良好,功能顽强的String类,要真的实现功能顽强,又得搞好Encoding方面的事情,要方便调试程序,又得把Console和IO方面的东西封好。于是我干脆就跟他拼了,封了一个类.Net的小类库出来。为了好看,名字空间搞得跟.Net的一模一样,用起来也挺顺溜的。

 1 #include "System.h"
 2 
 3 using namespace System;
 4 using namespace System::Text::RegularExpressions;
 5 using namespace System::Windows::Forms;
 6 
 7 int Program(const String& arg)
 8 {
 9     Application::RunConsoleApplication();
10 
11     Regex exampleExp("(+\\w+):(+\\z+)");
12     String exampleString = "hello:哈喽!!!";
13 
14     Int64 startTime = GetTickCount();
15     Match* m = exampleExp.Match(exampleString);
16     Int64 endTime = GetTickCount();
17 
18     Console::WriteLine("---------KSystem Example Program---------");
19     Console::WriteLine("Example Regex:\t" + exampleExp.Pattern());
20     Console::WriteLine("Example String:\t" + exampleString);
21     Console::WriteLine("Matched Value:\t" + m->Value());
22     Console::WriteLine(m->Captures[0+ ":" + m->Captures[1]);
23     Console::WriteLine("Time Cost:\t" + String::ToString(endTime - startTime) + " ms");
24     Console::WriteLine("-----------------------------------------");
25 
26     return 0;
27 }

不要问我为什么字符串前面不加L,也不要问我为什么没有delete那个m,我的库会干这些事情的。表达式中那个\z是匹配中文字的意思
运行结果:


做这么个正则表达式,还输掉了我一餐pizza。当时跟vczh同学打赌,他说我写完肯定有bug,我说我肯定没bug。结果不出意料地有bug,于是一餐华丽的pizza被送进了我们肚子。重要经验:是个程序必然有bug,恩恩。

这个正则表达式引擎刚写出来时性能奇差无比,主要时间耗在了内存分配上。经过一系列优化,vczh也跟着我一起优化了他那个正则表达式引擎,到最后某次性能测试时,我的花了13秒,vczh同学的花了12秒,也有时候是我的更快,视表达式写法不同而略有差别,基本上平均下来是一样的。(boost和greta花了40+N秒)

有了正则表达式引擎,也有了跟字符串几个月的感情,现在终于开始计划脚本引擎了。由于还是第一次,总有点畏首畏尾的,我决定先写一个非常菜的版本。强类型,无闭包,面向过程,支持数组,不支持自定义结构。这是我计划的CNScript的第一版本,也称CaiNiaoScript。

其实我真的想实现的是CNScript的第二个版本,ChinaScript。这会是一个类自然语言写法的中文脚本引擎。写起来变量和函数命名绝对会很不习惯,但是写完之后却会像一篇文章一样流利。


例如:现在用C++,模拟一个人使用某个交通工具去某个地方的行为。

Class TrafficTool;

Class Car : public TrafficTool;

Class Man
{
   void TravelTo(Point destination, TrafficTool* trafficTool);
};

用起来就是

Man Peter;
TrafficTool* BMW = new Car();
Point beijing;

Peter.TravelTo(beijing, BMW);

虽然程序员一看就能理解个大概,但是非程序员很难使用或维护它。在将来的CNScript中,也许会是这样(估计最后不会这么罗嗦):

有一种东西叫交通工具,汽车就是一种交通工具。
有一种东西叫人。 //我承认这句话有点怪,语法细节问题需要仔细琢磨,谁有好的建议可以留言给我喔,感激万分
有一种东西叫做目的地。

有一种行为:一个人乘坐一个交通工具去往一个目的地。

//以上是声明,以下是使用这几个类的代码

有一个人叫Peter。
有一个汽车叫宝马。
有一个目的地叫北京。

Peter乘坐宝马去往北京。

这样的代码,虽然在函数和变量命名时要仔细考虑,但是写出来的代码即使是不懂程序的人也能看明白,为的是兼顾游戏开发的各个环节的人员。

好了,想法到此为止,今晚开始动工CNScript的第一版,CaiNiaoScript! 我会把我每个阶段的工作和工作原理都写在这篇日记中,有兴趣的朋友可以跟着一起玩玩喔!

Feedback

# re: 摩拳擦掌 --- CNScript 成长日记(1)  回复  更多评论   

2008-08-05 09:54 by 陈梓瀚(vczh)
类自然语言脚本我一开始想做的是英语。经过研究英语嵌套起来比中文漂亮,因为中文的习惯是使用短句,所以有那么点囧……看我们现在的程序嵌套了好多层。

# re: 摩拳擦掌 --- CNScript 成长日记(1)  回复  更多评论   

2008-08-05 19:17 by ronliu
人、汽车、北京是实体,乘坐、去是谓词。先New一个人、一辆车、一个地点。将人和车赋予谓词的两端,在组合起来,就是一个行为。可以理解为,行为即是一个赋予实体后的谓词。
实体和谓词继承自同一个基类,在基类中提供字符串的封装和解封的方法,以及属性的字符串转换和还原函数。在定义实体和谓词时,调用基类中提供的字符串转换函数和还原函数,重写基类的decode、encode方法。对于组合实体,调用每一个原子实体的encode方法就是了。
对用户而言,它需要定义一些实体,和谓词,然后给他们赋值,然后调用一个fillContent()把行为转化为字符串。解封相反,将一串字符串转为一个对象。
------------
这是我用C++实现的一个类自然语言的库的基本思想。不知道你用脚本语言做,会是个什么样子,呵呵,关注ing!

# re: 摩拳擦掌 --- CNScript 成长日记(1)  回复  更多评论   

2008-08-06 07:04 by foxtail
欢迎坤哥 拜读大作哈

# re: 摩拳擦掌 --- CNScript 成长日记(1)  回复  更多评论   

2008-08-13 10:30 by jimmy
很好 很强大!

# re: 摩拳擦掌 --- CNScript 成长日记(1)  回复  更多评论   

2008-09-10 22:08 by 1shou
你的库,有没有提供给大伙啊/

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理