Main

May 09, 2008

The Implementation of Lua 5.0 中译

读者向海飞给我 email 了一份他翻译的《The Implementation of Lua 5.0》这篇 paper。原文可以在 lua.org 上下载

这篇由 lua 作者们写的 paper 对理解 lua 非常有帮助。有兴趣的朋友在 这里下载译文

译文最后附有译者的 email 大家可以直接向他反馈。

March 22, 2008

感觉好多了

其实我并没有用 lua 亲手写过什么大规模的项目。超过 5 千行代码的项目几乎都是 C 或是 C++ 写的。这几天算是做了点复杂的玩意了。几经修改和删减,最后接近完工的这个东西统计下来不多不少 3000 行(误差在十位数)。其中用 C 编写了基础模块 900 多行(仅仅是 socket api 的封装和 byte 流的编码解码),剩下的都是用 lua 设计并实现的。

好吧,我承认 2000 多行代码也只是一个小东西。不过用 lua 实现的一个 wiki 系统,sputnik 还不到 2000 行呢。lua 有一种特质,用的久了就容易体会到。它和 python ruby 这些更为流行的动态语言是不同的。曾经,我把选择 lua 的理由,肤浅的停留在了更轻便更高效上,虽然这些也很重要,但抓住语言的特质才是更关键的。

March 15, 2008

基于 lua 的热更新系统设计要点

很久没写 blog 了,主要是忙。项目排的很紧,一个小项目上线,发现不少问题,所以把多余精力都投进去了。最后人手不够,亲自上场写代码。在不动大体的情况下,最大能力的修改了一些设计,并把能重写的代码重新写过了。

这一周,写了三天半程序(其中通宵了一次)。平均每天写了千多行程序。基本上把原来项目里用的几万行东西替换下来了。重构总是能比老的设计更好,不是么? :) 不过这事不能老干,个人精力再充沛。故而还是找到称心的合作人比较好,也不能啥都自己做啊。程序员的效率差别可不只十倍二十倍的差别这么少。btw, 前段时间通过这里找到的新同事不错,呵呵。如果有缘,还想再找一个能干的。我相信,聪明人在一起做事可以获得更多快乐。

闲话扯到这里,总结下这两天做项目的一点经验。那就是:当我们需要一个 7*24 小时工作的系统时,实现热更新需要注意的要点。当然,这次我用的 lua 做实现,相信别的动态语言也差不多。只是我对 lua 最为熟悉,可以快速开发。

October 18, 2007

在 Lua 中管理 C 对象

今天同事在设计引擎的脚本接口时遇到一个问题:需要把 C 对象指针放到 Lua 中,允许 Lua 保存这个指针,并传递给其它模块。

这是给 Lua 写 C 扩展时常见的问题,撇开如何如何将对象的方法导入 Lua 这个更复杂的问题不谈,我主要想说说 C 对象的生命期管理的问题。

一开始的设计是把对象的销毁方法也导入 Lua ,由脚本程序员手工管理。这是很明显的 C 程序员的思路:谁构造谁释放。但在这里是不合适的,不符合带 gc 机制语言的习惯。

我们当然希望脚本更为健壮,不需要考虑对象释放的问题。所以晚上我想了一下,修改了一下这部分的实现。

September 06, 2007

玩了一下 ajax

起因是这样的:

几个同事在棋牌群里聊天,说找不到搭档打桥牌。网上也没啥好地方去,大家都比较讨厌下客户端和注册。我说,不如我做一个免客户端免注册的桥牌网站吧。然后就开始了。

直觉告诉我,ajax 技术可以实现这些。但是我没做过 web 方面的开发,仅有的一些知识只在几年前写过一个 php 留言本。一开始觉得 ajax 这些时髦玩意学一下午,然后一通宵就可以把想要的东西做出来。哪知道,结果不务正业干了半周了,中间还熬了两晚上,到今天都没做完。明天要出差,只好放一放了。

June 17, 2007

如何在 Lua 注册表中选择一个合适的 Key

Lua 提供了一个注册表(REGISTRY)让我们的 C 扩展可以安全的把一些运行时数据放进去,而不被 lua 代码碰到。为了让各个 C 扩展库之间可以相安无事的工作,并且对注册表的操作又有较高效率。Lua 大神 Roberto 在神作 Pil 里给出了一个简洁的方案:用 static 变量的地址作为 key

静态变量在当前进程中一定拥有惟一的地址,且 lightuserdata 作 key 非常高效。这无疑是一个好方法。

但是,当模块的源码规模变大了以后,我们将代码分散到不同的源文件中。或者几个子模块需要相互协作时。这个方法就有了一定的缺陷。那就是,必须将这个静态变量暴露出来供大家蹂躏;或是写一个内部函数来取得它(其实没有本质区别)。

如果你也碰到这类问题,不妨看看下面的解决方案。

June 12, 2007

魔兽世界的影响力

晚上一个小朋友在 gtalk 上问我编程语言专注哪一门好。当然这不是一个简单能回答的问题。尤其对刚上大学的小朋友不太好解释清楚。

不过睡觉前我还是八卦了一下当今世界编程语言的流行程度排名。查了下 TIOBE 的排行榜。首先映入眼帘的加黑的头条:Lua only 0.003% away from top 20 position

不得不感叹魔兽世界的影响力啊。(同事语: wow 让阿猫阿狗都开始写 lua 程序了)回想 05 年的时候,Lua 可是排在 70 多位的。

我们在 01 年底为大话西游2 选择一门嵌入式脚本语言的时候,考察了 lua python java javascript ruby 等许多开源动态语言(java 是个例外,而且 java 不开源,但还是可以找到一些 JVM 的开源代码)。最后定下 lua ,其中一个原因就是它不太为人所知。反逆向工程可能可以方便一点,真没想到今天会是这个局面。(当然,那个时候 python 和 ruby 在国内用的人也相当的少)

是金子总会闪光的 :D

May 04, 2007

正确的向 WinProc 传递 lua_State 指针

在 Windows 下写一些关于窗口的程序时,如果在软件中嵌入 lua ,那么就很有可能遇到一个棘手的问题:如果你需要用 lua 来直接响应一些 Windows 消息,那么如何向 WinProc 传递 lua_State ,也就是那个充斥于 lua 代码中的 L 。

在 Lua 的第 4 版及以前,这个问题并不突出。因为大多数情况下,我们并不需要嵌入多余一个的 Lua 虚拟机。而 L 这个指针,从 Lua 虚拟机被创建出来以后,就不会改变。那么我们只需要把 L 保存在一个全局变量中就可以了。若是你的程序是多线程的,并且每个线程都开有独立的虚拟机,把这个全局变量放到 TLS 中就可以完美的解决问题。当然一些全局变量的排斥者,会想到把 L 放到 Window 对象的 USERDATA 中,这也未尝不是一个体面的方法。

但是,从 Lua 5 开始,因为 coroutine 的引入,即使只打开一个虚拟机,我们也会面对不同 L 的问题。这个问题早在去年就困扰过我,我和同事一起也讨论并研究过这个问题,当时得到了一些解决方法。今天,我重构代码,又想起这个话题,觉得有必要把当初的思考、结论和今天的想法纪录下来。

April 18, 2007

以自定义方式加载 lua 模块

今天我们的一个小项目开始做内部测试发布前的资源打包。这个项目基本上是用 lua 做开发的。整个开发过程中,我们的代码是直接把 Lua 源代码放在项目的发布目录下的。发布版因为安全或是整洁等种种原因,我们必须给所有的脚本代码打包。

这种事情以前在大话2 里也干过,当时用的 lua 4.0 而且也没多少经验,我们是直接去修改的 lua 的代码,适应我们的打包格式。这次,不想这么干了。希望能够完全不动 lua 官方发布的源代码,来最终完成这项工作。

简单分析了一下,发现实现起来非常简单:

February 12, 2007

lua 近期的一个 bug

在 lua 的 maillist 上最近报告了一个 bug

看起来问题比较严重,因为稍具规模的 lua 程序都可能因此而出现问题。最近两周,我和我的同事都比较关注这个问题,并对 lua 的源代码做了相关的分析。

Roberto 作为 lua 委员会三巨头之一,在 mail 中已经表示追踪到 bug 的起因,但暂时还找不到合适的解决方案。直觉告诉我,这不会是一个简单的问题。如果容易修正的话,patch 早就有了,而不会只是发一个 bug report 而已。所以我们也并未尝试自己去修补这个 bug ,可以做的可能只有等待。

December 18, 2006

Lua 中 userdata 的反向映射

lua 中,我们可以用 userdata 保存一个 C 结构。当我们为 lua 写扩展时,C 函数中可以利用 lua_touserdata 将 userdata 转换为一个 C 结构指针。

但是,有时候我们却需要把一个指针转换回 lua 中的 userdata 对象。用到它的最常见的地方是封装 GUI ,通常 GUI 的底层是用 C 编码的。当 engine 把鼠标位置或是别的消息拦截到以后,消息会被传递到一个 C 对象中。这个时候,我们需要从 C 对象中得到对应的 lua 对象,并触发事件。

December 11, 2006

为 lua 配一个合适的内存分配器

以前版本的 lua 缺省是调用的 crt 的内存分配函数来管理内存的。但是修改也很方便,内部留下了宏专门用来替换。现在的 5.1 版更为方便,可以直接把外部的内存分配器塞到虚拟机里去。

有过 C/C++ 项目经验的人都知道,一个合适的内存分配器可以极大的提高整个项目的运行效率。所以 sgi 的 stl 实现中,还特别利用 free list 技术实现了一个小内存管理器以提高效率。事实证明,对于大多数程序而言,效果是很明显的。VC 自带的 stl 版本没有专门为用户提供一个优秀的内存分配器,便成了许多人诟病的对象。

其实以我自己的观点,VC 的 stl (我用的 VC6 ,没有考察更新版本的情况)还是非常优秀的,一点都不比 sgi 的版本差。至于 allocator 这种东西,成熟的项目应该根据自己的情况来实现。即使提供给我一个足够优秀的也不能保证在我的项目中表现最佳,那么还不如不提供。基础而通用的东西,减无可减的设计才符合我的审美观。sgi 版 stl 里的 allocator 就是可以被减掉的。

好了,不扯远了。今天想谈的是,如何为 lua 定制一个合适的内存分配器。

December 04, 2006

LoadLibrary 的搜索次序

今天写程序的时候发现一个问题,我为 lua 写了一个叫作 console 的 C 扩展库,可老是加载失败。郁闷了好半天后终于找到问题,那就是 lua 解释器实际找到的是 windows/system32 下的一个同名 dll 文件。原来系统也有一个 console.dll 了。

记得从前没有这个问题的,上网查了下 msdn 终于发现其缘故了。原来 windows xp sp2 以后,动态链接库的缺省搜索次序被修改了。

Dynamic-Link Library Search Order

November 30, 2006

Lua Debugger

luadbg.png

最近想做一个 visual 版本的 Lua 远程调试器。奋战了两天弄出这样一个玩意出来。如果有精力做完,就可以在 Windows 下远程调试任何地方的 Lua 代码了 :D

如果近期没精力,就开源让别人继续做好了。

November 24, 2006

lua 代码的断点调试

Lua 5.1 带了一个 debug 库,把所有的 C API 中的 debug 相关 api 都导出了。作为独立的语言使用的话,这些足够搭建一套方便的调试库。

说到最常用的断点调试法,我们能想到的最直接的方法就是利用 lua debug 库中的 hook ,然后记录一张断点位置表,设置行模式的 hook ,每次进入 hook 都检查是否是断点处,若是就停下来等待交互调试。

这个方法很有效,但是很消耗 cpu 。因为每进入一个新的代码行,都需要回调一个函数。当这个函数本身又是用 lua 写的时候,效率更低。

本文提供另一种思路,换一个方法设置断点,让没有断点时不影响运行效率。

November 17, 2006

Lua 中写 C 扩展库时用到的一些技巧

今天方舟组的同事问到我一些 lua 的问题,主要是关于 C 扩展库的。我觉得有些技巧性的东西挺值得跟大家分享一下,那么就写篇 blog 吧。

通常,C 扩展库中 C 代码会有一些数据要放在 lua 状态机中。Lua 提供的方案是放在它的 注册表 中。如文档所言,因为 Lua 的注册表是全局共享的,选择 key 的时候就要千万小心了。整数 key 已经被 reference 系统用掉了,一般我们会采用字符串作 key 。

从 C 中压入字符串的效率不是最高,这是因为外部字符串进入状态机时需要重新 hash 并检查唯一性所致。关于避免直接压入字符串的问题,以前写过一篇 blog 谈过。( btw, 以前那个方法也不是最好的解决方案,不过还是可以作为一个参考的 :)

很容易想到,最方便且能保证唯一性的 key 是一个 light userdata 。这一点,在参考手册以及 Programming in Lua 中都有提到。

November 13, 2006

Lua 5.1 中文手册

前段时间安排同事工作时间翻译了 Lua 的参考手册 。当时的目的是想让翻译的人可以借翻译的机会深入了解这门语言。另外,其他人在查手册的时候也可以轻松一点。

事与愿违,这个中译本陆续经过了几个月的翻译和校对后,可读性依然欠缺。往往我需要去手册里查点东西的时候,都发现还不如直接看英文原版。中文译文读的晦涩倒是次要的,主要是一到关键点上就译的含糊不清,甚至有错误。

这倒符合我的观点,翻译技术资料,首先要求的是对原文的理解,然后是中文的组织水平,最后才是英文水平。

周末,我突然发神经,自己动手译了一下(其实起先只是想看看翻译这个篇幅的文档大约需要多少工时)。花掉两个半天敲了大约一万两千汉字,手都快抽筋了:)把最重要的一部分关于 Lua 语言的译完。

我想我的英文水平是很糟糕的,中文能力也不怎么样,不过满足翻译技术文档的第一要点:对 Lua 本身是很熟悉的。所以这个译本当是能看吧。

Lua 5.1 中文参考手册

很多技术术语我没有按标准译法来译,尽量用一些更通俗但是更繁杂的译法。大部分译词,如果我认为大家普遍能接受,就统一用中文译词,只在第一次出现时括号注明英文原文。例如:事件 (event) 、元方法 (metamethod)。

如果觉得译词不太能被大众接受,大部分地方保留英文,而在第一次出现的地方括号注明我认为合适的中文译法。例如 metatable (元表)、closure(闭包)。


2006年11月19日 凌晨: 手册的第三部分(C API)业已完成 :D

September 21, 2006

lua cclosure 的 upvalue 数量限制

最近写的代码中出了一个奇怪的 bug ,很难调试出来。经过一个晚上的挣扎,终于发现了问题。

第一个问题,在 C 函数中,不能随意的时候 lua_State 中的虚拟机堆栈,如果需要大量使用堆栈,应该先调用 lua_checkstack 。少量使用堆栈,(在 LUA_MINSTACK 20 )之下时则没有问题。这个问题其实在文档里有写,我看过忘记了 :( 不过我个人还是觉得 lua_checkstack 的语义有点奇怪,从字面上看,这个 api 不应该有副作用。它能增加可用堆栈的大小违背了 checkstack 的词义。

第二个问题,当从 lua 调用 C 函数时,当参数数量不足的时候,并不会填入 nil 作为缺省参数。比如,写了一个 C 函数,接受两个参数。当 lua 中调用这个 C 函数时,如果仅传入一个参数,那么在 C 中 stack 上 index 2 位置的值并不一定是 nil 。这个时候我们应该用 lua_gettop 得到准确的参数个数以做适当的处理,或者直接在进入 C 函数时调用一次 lua_settop(L,2) 强制堆栈扩展到两个。

第三个问题,就是一开始最为迷惑我的问题。在生成 cclosure 的时候,upvalue 不能超过 255 个。而这一点并没在文档中说明,运行时压入超过 255 个 upvalue 也不会报错。知道仔细查看源码才发现其中的秘密。

July 27, 2006

用 lua 调用 Windows 的 API

昨天同事谈起能否给一个从 lua 中调用 Windows API 的简单方案。一开始觉得,如果是一个通用方案,那么至少需要先给出一个类似 windows.h 的原型声明,然后从 lua 来解析这些原型。大约写了几十行程序就实现了。后来又想了一下,似乎可以用一个更简单的方式,绕过原型,更简洁(但不保证安全)的方法来做到。

其间的问题就只有一个,每个 api 的参数都不一样,如何自动生成 C 中匹配的函数指针。似乎 C++ 的 template 是一个正统的解决方案。不过思考过几分钟以后,就被我否决了。实际用到的解决方案比较诡异:

先用 alloca 分配出正确的参数空间,再立刻填充这些参数,接下来以无参数的形式调用 api 。这样做,对于 __stdcall 的函数是没有问题的。好在 api 大多也是这样。

我写了这样一段程序来验证我的想法:

June 12, 2006

在 Lua 中实现面向对象

在 pil 中,lua 的作者推荐了一种方案来实现 OO,比较简洁,但是我依然觉得有些繁琐。

这里给出一种更漂亮一点的解决方案:为了贴代码和修改方便,我把它贴在了 wiki 上。

Lua 中实现面向对象

在这个方案中,只定义了一个函数 class(super) ,用这个函数,我们就可以方便的在 lua 中定义类:

base_type=class()       -- 定义一个基类 base_type

function base_type:ctor(x)  -- 定义 base_type 的构造函数
    print("base_type ctor")
    self.x=x
end

function base_type:print_x()    -- 定义一个成员函数 base_type:print_x
    print(self.x)
end

function base_type:hello()  -- 定义另一个成员函数 base_type:hello
    print("hello base_type")
end

以上是基本的 class 定义的语法,完全兼容 lua 的编程习惯。我增加了一个叫做 ctor 的词,作为构造函数的名字。

March 14, 2006

使用 closure 替代 table

前几天谈到 lua 的一些技巧,我整理在 wiki 上了。今天又加了一个,关于 point 结构的封装的。

function point (x,y)
    return function () return x,y end
end

可以用 point(1,2) 构造一个 point 。它比 {1,2} 轻量。

February 18, 2006

lua 5.1 final release

这一天等了很久,终于看到了这则消息:

Lua 5.1 (final) is now available at
http://www.lua.org/ftp/lua-5.1.tar.gz

Thank you very much for your patience during this long release process.
Special thanks to everyone that sent suggestions. They have helped make
Lua still better.

Enjoy! We can now focus on 5.2 :-)
--lhf


February 16, 2006

lua 5.1 的 module

lua 从 5.1 开始终于官方提供统一的 module 实现标准了,这是个值得庆幸的事。今天读了下相关的源码和文档,把这套机制搞清楚了,还是很巧妙的。从简洁这个角度看,要比 python 强 :)

有一点容易被忽略掉(我的同事在用的时候就忽略掉了),module 指令运行完后,整个环境被压栈,所以前面全局的东西再看不见了。比如定义了一个 test 模块,使用

module("test")

后,下面不再看的见前面的全局环境。如果在这个模块里想调用 print 输出调试信息怎么办呢?一个简单的方法是

local print=print
module("test")

这样 print 是一个 local 变量,下面也是可见的。或者可以用

local _G=_G
module("test")

那么 _G.print 也是可以用的。

当然还有一种巧妙的方式,lua 5.1 提供了一个 package.seeall 可以作为 module 的option 传入

module("test",package.seeall)

这样就 OK 了。至于它们是如何工作的,还是自己读源码会理解的清楚一些。

在读源码时可以发现很多 lua 的技巧,还有一些 undocumented 的东西,比如 newproxy :) 它是一个 unsupported 且 undocumented 的东西,但是它希望实现的却是个巧妙的玩意。

February 11, 2006

lua 终于支持了16进制数

今天 lua 5.1 rc4 发布了。看了一下,比较 rc3 只改了两个地方,一个是 luaconf.h 里的 lua_popen 的宏。还有一个是增加了 hex number 的支持。

前两天在 mailist 里讨论了这个问题,其实早就有呼声加上 16 进制数了。其实我自己也写过 patch 加上,lua maillist 里 Roberto 提了个方案,只需要修改 luaconf.h 里的 #define lua_str2number(s,p) 这个宏就可以了。我测试了一下,很巧妙,还顺手附和了两句。

不过这个方法对 16 进制数前面加了负号是有问题的(虽然我认为一般不会这么用),结果还是对词法分析代码打了 patch,改动不大,而且同样也很巧妙。Roberto 这次很大方,这么快就加到官方版本并发布了。

这次因为这么小的改变就发布新的 rc ,看来 lua 5.1 的正式 release 很近了。期待,这样 lua 就拥有了官方的模块化解决方案。

January 01, 2006

向 lua 虚拟机传递信息

当程序逻辑交给脚本跑了以后,C/C++ 层就只需要把必要的输入信息传入虚拟机就够了。当然,我们也需要一个高效的传递方法。

以向 lua 虚拟机传递鼠标坐标信息为例,我们容易想到的方法是,定义一个 C 函数 get_mouse_pos 。当 lua 脚本中需要取得鼠标坐标的时候,就可以调用这个函数。

但这并不是一个好方法,因为每次获取鼠标坐标,都需要在虚拟机和 native code 间做一次切换。我们应该寻求更高效的方案。

December 25, 2005

虚拟机之比较,lua 5 的实现

前段把自己的虚拟机和编译器完成后,曾经和 lua5 做过一个比较。比较的结果很沮丧,我的虚拟机只能达到 lua 5 一半多点的速度。所以很不服气的又读了一段 lua5 的源码。而之前我是一段一段的看 lua source code 的,甚至 lua 4 和 lua5 的是在不同时期去读的,当然我也知道其间巨大的不同。

December 11, 2005

12K 的虚拟机

今天把脚本虚拟机整合到正在开发的引擎中去了,按新引擎的跨平台2进制格式 build 出来,只有 12.6K :D 比 lua 小多了 ^^ 庆祝一下。如果不是现在机器都是 32位了,在 16 位或者 8 位机上,这代码体积还能更小。唉,早几年计算机的地址空间只有 64K 的时候多痛苦啊。

突然想,我们这套引擎给手机用一定很不错 尤其是 gc 部分,比 lua python 什么的更适合小内存环境,可惜我现在对嵌入式开发没啥兴趣。

December 10, 2005

基于并行处理的垃圾回收方法

最近在做的一个虚拟机是基于垃圾回收(garbage collection)的,采用的是标记整理算法。这种算法的好处在于不需要 太多额外的内存,而且可以将内存中的 garbage 完全压缩掉。至于长期占用的内存空间,会被压到内存块的底部,整理时无须移动。

对于需要长期稳定运行的服务器程序,在 32bit 操作系统下,受限于有限的地址空间, gc 技术是根本解决内存碎片问题的最佳通用方案。

我计划在服务器程序中,全部程序逻辑都放在虚拟机内运行。由于和 client 程序不同,不用太考虑物理内存的占用,所以计划在服务启动的时候就预设 1~2G 的内存块供虚拟机使用。在这个内存块耗尽之前,所以涉及内存分配的操作都会相当的快了。但是一旦发生 gc ,光是扫描一遍内存,都是非常耗时的。所以我不得不考虑解决方案。

实现一个系统堆栈无关的虚拟机

最初设计虚拟机时,bytecode 中的函数调用会产生一个 native code 上的实际的函数调用。似乎这样写比较容易。但是这样做,想实现bytecode单步运行却很困难。只有另开一个线程监护跑虚拟机的线程,在每步运行后可以挂起,而不破坏相关的堆栈。

所以,我想实现一个系统堆栈无关的虚拟机。

December 07, 2005

给脚本加入字符串类型

最近的工作是给虚拟机加上字符串类型的支持,并让编译器可以生成相应的 bytecode 。思路很简单,就是按 lua 的方式,把所有源码中相同的字符串合并,在 bytecode 中只保留一份。所有提到这些字符串的地方直接对其引用。bytecode运行时,产生的任何新的字符串都会产生新的副本。垃圾等到 gc 时回收。

想起来容易,实现起来还是颇为麻烦的。

December 05, 2005

在脚本语言中一个取巧实现 OO 的方法

今天,脚本编译器连同前段写的虚拟机全部完工了,很有成就感。
跟 lua 一样,复杂的数据类型我只支持了 table ,这个 table 即可以做 array 也可以做 hash_map 用。一般用 lua 的人都会用 table 去模拟 class 。lua 只对这个做了非常有限的扩展:在 lua 的文档中,我们可以看到

function t.a.b.c:f (...) ... end 可以等同于 t.a.b.c.f = function (self, ...) ... end

就我用 lua 的经验,这个转换用途不是特别大,只是少写个 self 而已。

这次我自己设计脚本语言,针对脚本支持 OO 的问题,特别做了些改进。

December 01, 2005

编译器实现有感

脚本虚拟机前段时间就已经做好,如果没有跑在上面的语言,光有虚拟机没太大意义。所以脚本编译器一早就开始做了。中间因为去上海参加 C++ 大会,又去了成都做招聘,弄的心力疲惫。这几天才回来,有那么几天去实现。

编译原理的课程大学本科就应该开过吧,我不是科班出身,反正是没正经上过。不过依稀记得自己是学过的,记得是上中学的时候,跑到一个大学上课,老师教的就是编译原理。那个时候 C 语言还没玩转,最熟的是 basic 和 6502 汇编。理解那些东西很有困难。囫囵吞枣的记了一点,算是有点印象,逢人也可以吹吹牛。

November 02, 2005

实现一个虚拟机

在编程的世界中,只有你想不到的事情,懒的做的事情,没有做不到的事情。

曾经一度为使用哪种脚本嵌入游戏犯愁,lua 的源码过了几遍,python 的也看了点。lcc 也试过,还有 ch 什么的。真正用在项目里的就是 lua 和 python 了。我个人更偏好 lua 一点。越读它的 source code 越觉得它作为世界上最快的脚本语言,是名副其实。

很早以前,我觉得显示一个图片很难,好象发现很简单。曾经觉得汇编很难,结果发现很简单。曾经担心 C++ 太复杂学不会,现在已经感觉游刃有余了。还有学习 perl php 或者是 stl mfc 这样的库,不懂的时候都觉得难,懂了却是不过如此。

对于游戏,说什么掌握 3d ,网络编程,无非是些技术方向而已。肯花时间,一定没问题的。

这次是脚本虚拟机。已经想了很久了,怕太复杂需要投入过多时间和精力。可事实上,写起来却又一次发现不过如此。

October 29, 2005

lua 的 table 处理

lua 的整体效率是很高的,其中,它的 table 实现的很巧妙为这个效率贡献很大。

lua 的 table 充当了数组和映射表的双重功能,所以在实现时就考虑了这些,让 table 在做数组使用时尽量少效率惩罚。