<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>点睛工作室</title>
    <description></description>
    <link>http://llf.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>DbEntry.Net 3.5</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/218421" style="color:red;">http://llf.javaeye.com/blog/218421</a>&nbsp;
          发表时间: 2008年07月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          　　这是我设计的一个轻量级的 .Net ORM (Object Relational Mapping) 数据访问及 WEB 框架。对于 ORM 和 Sql 调用，它都拥有清晰和易用的接口，目前支持 SqlServer、SQLite、MySql、Access、Firebird、PostgreSQL、Oracle 等数据库。对于 WEB 开发，它既支持 ASP.NET 2.0 的 DataSource 方式，也支持 Ruby On Rails 风格的 MVC 方式。支持 Linq 方式的查询，也提供一个简单的 IoC。<br /><br />　　目前，数据库部分已经支持多主键、多表联合查询、快速分页集合、隐式数据库事务、连贯API查询、ActiveRecord风格查询、动态对象、部分保存、自动创建数据表、一对一、一对多、多对多关系等功能，具体实现请参阅 Samples 中的例子程序和单元测试的内容。<br /><br />　　而 DataSource 部分，因为绑定数据访问组件，所以可以只需要修改配置文件，不需要修改任何代码的在不同的数据之间切换。另外，还支持按命名约定的方式绑定“新建”和“编辑”页面的控件，以最少的代码完成输入、验证、保存等一系列操作。<br /><br />　　Rails 风格的 MVC 框架目前已经完成 MVC 部分，脚手架，基类中的 LinkTo、UrlTo 等快捷函数，Http Get 支持等。目前脚手架部分没有数据验证模块，不过，自己写的 MVC 代码可以自行实现验证。<br /><br />　　这个版本中，例子程序访问的数据库主要是 Access，而单元测试使用的数据库是 SQLite，通过修改配置文件中数据源部分，可以使之不需要重新编译即可工作于其它数据库上。配置部分通过 App.config 进行，请参阅 Samples 中的例子程序中的 App.config 和 UnitTest 项目内嵌的配置文件 UnitTest.config.xml 。<br /><br />　　我在 MS Sql Server 2000、MS Sql Server 2005 Express、 MS Access 2003、MySql 5.0、SQLite 3、Firebird 2.1.0, PostgreSQL 8.3.3 和 Oracle 10g Express 上测试过本组件。<br /><br />　　v3.5 版比较大的改变为：<br />　　·增加 Linq 支持<br />　　·支持 PostgreSQL<br />　　·增加简单的 IoC 系统<br />　　·支持 SavedOn 和 Count<br />　　·支持 NameMapper<br /><br />下载本组件和浏览文档请访问 <a href="http://www.codeplex.com/DbEntry/" target="_blank">http://www.codeplex.com/DbEntry/</a>
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/218421#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 22 Jul 2008 23:35:09 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/218421</link>
        <guid>http://llf.javaeye.com/blog/218421</guid>
      </item>
      <item>
        <title>Visual Studio 2008 的缺省文件代码页</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/210724" style="color:red;">http://llf.javaeye.com/blog/210724</a>&nbsp;
          发表时间: 2008年07月02日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          　　本来以为只有非英语国家的程序被英语国际的人看的时候会有代码页问题，不过，还是发现，英语国家的人，也很喜欢使用一些不属于 ASCII 的特殊字符，结果造成那些代码被非英语国家的人使用的时候，也很麻烦。<br /><br />　　Visual Studio 缺省使用当前 Windows 代码页保存文件，实在是个不可思议的决定，不过，既然发生了，还是要解决。上网查了一下，奇怪的是，很多人问到这个问题，却没有发现提供解决方法。<br /><br />　　确实，在 Visual Studio 的选项里翻弄了半天，还是没有发现可以设置缺省代码页的地方。<br /><br />　　最后，在“文件”菜单发现“高级保存选项”，可以设置代码页，再测试一下，这个设置对于新建文件也有效。看来它就是缺省代码页了，只是不知道为什么不放在“选项”对话框中。<br /><br />　　另外，还有一个问题，就是现有程序怎么办，没有发现现成的工具，就自己写了一个，代码很简单，一个 WinForm 窗口，有一个叫 FileCollector 的 ListBox，一个叫 Run 的按钮，一个叫 FileCount 的 Label，然后是代码：<br /><pre name="code" class="c#">
// Recode 1.0
// http://llf.hanzify.org
// http://llf.javaeye.com
// 作者：梁利锋
using System;
using System.IO;
using System.Text;
using System.Windows.Forms;

namespace Recode
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void FileCollector_DragOver(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Link;
        }

        private void FileCollector_DragDrop(object sender, DragEventArgs e)
        {
            var list = (Array) e.Data.GetData(DataFormats.FileDrop);
            if (list != null && list.Length > 0)
            {
                FileCollector.Items.Clear();
                foreach (object f in list)
                {
                    string s = f.ToString();
                    if (File.Exists(s))
                    {
                        FileCollector.Items.Add(s);
                    }
                }
            }
            FileCount.Text = FileCollector.Items.Count.ToString();
        }

        private void Run_Click(object sender, EventArgs e)
        {
            if (FileCollector.Items.Count > 0)
            {
                foreach (string name in FileCollector.Items)
                {
                    RecodeOneFile(name);
                }
                MessageBox.Show("done!");
            }
            else
            {
                MessageBox.Show("Please drag and drop some files to the list box first.");
            }
        }

        private static void RecodeOneFile(string name)
        {
            string content;
            using (var sr = new StreamReader(name, Encoding.GetEncoding(1252))) // 英文代码页
            {
                content = sr.ReadToEnd();
            }

            using (var sw = new StreamWriter(name, false, Encoding.UTF8))
            {
                sw.Write(content);
            }
        }
    }
}
</pre><br />　　我个人比较喜欢带签名的 UTF-8 格式，对于源文件的代码页，可以查一下这个<a href="http://qbit.100steps.net/dhtml/charsets/charset4.html" target="_blank">代码页介绍的文章</a>。
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/210724#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 02 Jul 2008 17:45:54 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/210724</link>
        <guid>http://llf.javaeye.com/blog/210724</guid>
      </item>
      <item>
        <title>GridView 中的 CheckBox 令其支持 FireFox</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/207473" style="color:red;">http://llf.javaeye.com/blog/207473</a>&nbsp;
          发表时间: 2008年06月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          　　GridView 中好像也有一个 CheckBoxField，不过不知道怎么用，或者，它是只读的，所以不能告诉我们用户的选择，反正，这个问题需要自己解决。<br /><br />　　在网上搜索了一下，找到了一个我认为比较好的<a href="http://eddie005.cnblogs.com/archive/2006/07/04/GridView_CheckBox.html" target="_blank">文章</a>，用了一段都没什么问题，不过近来发现，其中的 JavaScript 部分，不支持 FireFox。<br /><br />　　查了一些资料，发现主要问题是 FireFox 不支持 parentElement，继续修改，发现其 firstChild 在 IE 和 FF 中是不同的，于是添加一个 get_CheckBox 的函数，终于在 IE 和 FF 都可以正常运行了。<br /><br />　　下面是修改后的 JavaScript:<br /><br /><pre name="code" class="javascript">function get_CheckBox(theCell)
{
       for(var i = 0; i &lt; theCell.childNodes.length; i++)
       {
           if(theCell.childNodes[i].id)
           {
                return theCell.childNodes[i];
           }
       }
}

function select_all(obj)
{
    var theTable  = obj.parentNode.parentNode.parentNode;
    var j = obj.parentNode.cellIndex;

    for(var i=0; i&lt;theTable.rows.length; i++)
    {
        var objCheckBox = get_CheckBox(theTable.rows[i].cells[j]);
        if(objCheckBox.checked != null)
            objCheckBox.checked = obj.checked;
    }
}</pre>
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/207473#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 24 Jun 2008 14:18:17 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/207473</link>
        <guid>http://llf.javaeye.com/blog/207473</guid>
      </item>
      <item>
        <title>测试中的犀牛</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/203520" style="color:red;">http://llf.javaeye.com/blog/203520</a>&nbsp;
          发表时间: 2008年06月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          　　最近，把我的 <a href="http://www.codeplex.com/DbEntry" target="_blank">DbEntry</a> 的客户端源码控制改成了 <a href="http://visualsvn.com/" target="_blank">VisualSvn</a> + <a href="http://www.codeplex.com/SvnBridge" target="_blank">SvnBridge</a> 的方式，感觉这种非独占方式 check-out 很适合广域网用户，只是 SvnBridge 还有一些不完善，于是，下载了它的源码版本，自己编译，在最近一次比较大的 check-in 之后，另一台机器执行 update 总是不成功，于是再去下载最新的 SvnBridge 源码，也没有效果，最后重新 check-out 反而成功，也许是服务器超时造成的？<br /><br />　　在浏览 SvnBridge 的压缩包的时候，发现了它是使用 <a href="http://www.codeplex.com/xunit" target="_blank">xunit</a> 进行单元测试的，这个听说过，据说是原 nunit 作者的新作，利用了更多的 .net 的语言特性，应该是更好用的吧；另外，发现了一个奇怪的 dll 名：Rhino.Mocks.dll。<a href="http://www.mozilla.org/rhino/" target="_blank">Rhino</a> 我记得是一个 Java 实现的 JavaScript 引擎，不过，Rhino.Mocks 是什么鬼？<br /><br />　　搜索 Rhino.Mocks，发现几篇介绍的文章，原来是一个 mock 框架，和那个 JavaScript 引擎没什么关系。<br /><br />　　以前一直都是直接手写 Mock 类的，对于 Mock 框架没有什么认识，最近因为工作的关系，接触到 <a href="http://mocklib.sourceforge.net/mocklib3/" target="_blank">MockLib</a> ，发觉对于一些复杂的接口，用 Mock 框架确实可以减少一些重复劳动。<br /><br />　　在介绍的文章 Rhino.Mocks 中，有 <a href="http://www.cnblogs.com/idior/archive/2005/08/08/209351.html" target="_blank">一篇</a> 介绍的挺好的，做了 EasyMock，JMock，NMock， NMock2 和 Rhino.Mocks 的比较，很不错。文中介绍 Rhino 做 Record 的语法如下：<br /><pre name="code" class="c#">
subMock.Receive(message);
Expect.On(subMock).Call(subMock.MultiplyTwo(5)).Return(10);
mocks.ReplayAll();
</pre><br />　　无返回值的函数语法简直太自然了！这里，因为不是使用字符串来描述函数名，所以，有智能提示，有编译时运行检查，也支持重构工具，非常棒。不过，既然这种“Record/Replay”模型这么自然，而另外那种“Expectation”模型也依然存在，可能说明，这种方式还是有一些特殊的地方，不如“Expectation”模型吧。<br /><br />　　看着，突然想到 .net 3.5 的 expression tree，这种延迟运算方式如果运用于“Expectation”模型应该也可以，而且，同样可以取得“Record/Replay”模型的智能提示、编译时运行检查、支持重构工具等特性，简直太完美了！<br /><br />　　不管怎样，先去下载 <a href="http://www.ayende.com/Blog/archive/2007/03/28/Rhino-Mocks-3.0-Released.aspx" target="_blank">Rhino Mocks</a> 再说。到了它的下载页，赫然发现 Rhino Mocks 3.5 Beta - For .Net 3.5 的字样，哈，看来他应该比我早想到这个主意了吧 ：D<br /><br />　　再次搜索 Rhino Mocks 3.5，发现了 <a href="http://blog.benhall.me.uk/2008/05/rhino-mocks-35-goodbye-record-and.html" target="_blank">一篇介绍的文章</a>，语法上比我想象的复杂一些，不过还是很酷，回头研究一下，或许就使用到项目中去吧。
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/203520#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 15 Jun 2008 17:27:12 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/203520</link>
        <guid>http://llf.javaeye.com/blog/203520</guid>
      </item>
      <item>
        <title>我定制的 FxCop 规则</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/188625" style="color:red;">http://llf.javaeye.com/blog/188625</a>&nbsp;
          发表时间: 2008年05月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          　　公司里同事说起，用 Java 开发的时候，进行语法检测的工具（CheckStyle?），有对于函数超长和文件超长的警报，而 FxCop 1.36 Beta2 却并没有带这些检查。想一想，这两种检测，对于编码习惯良好的人来说，意义有限，不过，对于需要协调许多人组成的团队来说，还是一个很好的方式。<br /><br />　　FxCop 提供了让我们自己定制规则的能力，虽然网上讨论的不多，还是找到一两个例子，于是写出了这两个规则。目前，已经把它放到 CodePlex 上，感兴趣的可以到 <a href="http://www.codeplex.com/LephoneFxCopRules" target="_blank">Lephone FxCop Rules</a> 下载。<br /><br />　　不过，因为 FxCop 是直接分析程序集，而不是分析源程序，所以，也有一些想实现的规则目前看来比较难实现 —— 比如限制一个函数内的 block 的嵌套层次。<br /><br />　　另外，使用 FxCop 的时候，也需要自己分析一下，有一些它自带的规则并不合理，可以屏蔽一些的。
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/188625#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 01 May 2008 15:15:28 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/188625</link>
        <guid>http://llf.javaeye.com/blog/188625</guid>
      </item>
      <item>
        <title>试用新版 Poseidon (trunk-r239)</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/187139" style="color:red;">http://llf.javaeye.com/blog/187139</a>&nbsp;
          发表时间: 2008年04月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          　　以前，因为觉得一直没有这种有智能提示的IDE，想要自己写一个，也开始自己写语法分析器，后来才觉得，这种方法不可取，即使能写出兼容大多数 D 语法的分析器，然而要匹配 D 的各种版本，也是很麻烦，还不如直接使用 D 的前端来写。不过，使用 D 的前端也有一些困难，就是无法用 VC 编译，看了源代码，似乎是只支持 dmc 和 gcc 的，可能使用 gcc 编译成 dll 是一种比较好的方案。<br /><br />　　不过，最近比较忙，而且兴趣也不足，所以一直没有继续。今天，看到说<a href="http://www.dsource.org/projects/poseidon" target="_blank">波塞冬</a>有新版，到它的主页看了一下，截屏是有智能提示的，于是下载了试用。<br /><br />　　测试了当前文件内置类，从其它文件引入类，引入 tango 类，引入模板等，都能工作，只是不知道什么原因，刚开始测试的时候很多特性无效，后来又有效了，怀疑是背景线程的延迟造成的。总体来说，已经很完善，不再是玩具级别的智能提示了。项目路径下的 .ncb 文件是智能提示的数据，文本格式的。<img src="/images/smiles/icon_smile.gif"/><br /><br />　　波塞冬本身，有一些地方不太方便，不过相信会越来越好。<br /><br />　　另外，就是配置麻烦些，如果有人做一个集成安装包的话，对于大家来说，应该会有很大帮助吧。比如，我个人的 D 配置就不全，有不少东西都没有安装……
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/187139#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 26 Apr 2008 20:13:34 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/187139</link>
        <guid>http://llf.javaeye.com/blog/187139</guid>
      </item>
      <item>
        <title>点睛挖雷 PSP 1.1 版（For 3.xx）</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/182405" style="color:red;">http://llf.javaeye.com/blog/182405</a>&nbsp;
          发表时间: 2008年04月13日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          　　1.0 版里，为了修正一个造成 PSP 花屏的错误，所以让帮助界面延迟加载，发布之后发现，在帮助界面的每一帧，都会造成重读帮助文件，虽然对于程序的正确性没有影响，不过仍然是个问题，在这一版中已经修正。<br /><br />　　而那个造成 PSP 花屏的错误，经过几番测试，发现和加载文件的数量也没有必然联系。后来，通过重新编译 PSP 版 JGE 库，解决了这个问题。看来，预编译的 JGE 库和我的 GCC 版本也存在不完全兼容的问题，只是不知道为什么，GCC 对于这种情况，并不抱怨。<br /><br />　　所以，要使用 JGE 库编写 PSP 程序的话，记得把 Windows 版和 PSP 版的 JGE 都重新编译一遍再开始编自己的程序。<br /><br />　　这一版加入了流逝时间和剩余雷数显示的功能。另外，加入了摇杆的支持，不过目前只是为了提供一个快速移动的替代方案，以后考虑把光标坐标改成实际点的坐标，这样，使用摇杆移动会更容易控制，也比较平滑。<br /><br />　　这一版，加入了背景音乐，找一个 mp3 文件，改名成 bg1.mp3，复制到 Res 目录下就可以了。不过，发现 JGE 的另一个问题，设置音乐为循环播放模式，在 Windows 上有效，在 PSP 上无效。目前在 JGE PSP 版中，没有发现明显的设置循环的方法，只有以后修正了。<br /><br />　　在加入背景音乐的过程中，为了在没有 bg1.mp3 的情况，允许正常的游戏，进行的返回值判断，发现无效，于是看了 JGE 相关的实现代码，发现写的并不严谨 —— 不管文件存在与否，该函数都会返回一个新的JMusic 的实例，只是如果文件不存在的话，这个实例会造成程序崩溃。而作为调用者，判断返回值是否为 NULL 也就成了一个无效的动作。我修正了 JGE 的这个问题，不过，不知道还有多少类似的问题，看来如果写一个大点儿的 PSP 程序，恐怕需要把 JGE 的代码好好看看才行。<br /><br />　　游戏在我的 PSP2000，3.71m33-4 上测试通过。<br /><br />　　下面是运行截图和软件下载：
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/182405#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 13 Apr 2008 22:59:36 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/182405</link>
        <guid>http://llf.javaeye.com/blog/182405</guid>
      </item>
      <item>
        <title>点睛挖雷 PSP 1.0 版（For 3.xx）</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/182114" style="color:red;">http://llf.javaeye.com/blog/182114</a>&nbsp;
          发表时间: 2008年04月12日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          　　最近买了 PSP2000，从而也萌发了要写点儿 PSP 程序的想法，先去找了 PSPSDK，当然，这是一切的基础，而且，大牛们破解 PSP 而建立 PSPSDK 也非常厉害，不过，就是使用起来太底层，许多很零碎的事情都要自己处理，而且，编译的程序要每次到 PSP 上测试也很麻烦。<br /><br />　　于是，又找到一套整合了很多框架（如 SDL）的所谓一键式安装的 PSP 开发环境 TOPOC，而且也支持编译成 windows 程序，在 PC 上调试等等，不过，在 VS2008 上编译出错，印象较深的问题是，找不到 glaux.h 和 glaux.lib，google 了一下，说是在 VC 新版的 opengl 库中，已经取消了这个库，还有一些其他问题，后来找到 VC6，编译倒是不出错了，不过，只能编译出 1.5 核心的程序，而我的 PSP 不支持 1.5 核心。在 <a href="http://code.google.com/p/topoc/" target="_blank">TOPOC 的主页</a> 上，一路看下去，发现他们到最后反而推荐使用 JGE++，说是可以编译出 3.xx 的程序，而且可以使用硬件加速，同时也支持编译成 windows 程序，在 PC 调试。<br /><br />　　又找到 JGE++ 的主页，但是网上介绍的一个压缩包总是下载不到，按照网上 <a href="http://www.cngba.com/viewthread.php?tid=17148931" target="_blank">另一篇文章</a> 中介绍的方法安装，终于成功。<br /><br />　　那篇文章中介绍的后面两个文件，可以不用下载。其中，src.rar 中是 bat 文件，原安装包中的 bat 其实不需要修改，文中介绍的修改方法，在 sh 之后才执行，所以并没有任何作用；另外那个模板文件，只是加了中文注释，意义也不是很大。<br /><br />　　这个环境安装成功后，在 VC2008 下编译还是有问题，后来发现是原有编译出的目标文件和 VC2008 的版本不同造成的，清除 JGE 项目，再重新编译，终于成功。编译自己的程序的时候，会遇到找不到 glaux.lib 的错误，在连接选项里忽略 glaux 即可，看来，JGE 里面其实没有用到这个库，只是礼貌性的连接进来而已。<br /><br />　　JGE 这套库确实不错，不过，在做挖雷的时候，发现显示位置不准确，后来编译出 PBP 文件到 PSP 上测试，反而没有问题，可能是 windows 版的计算上有误差吧。<br /><br />　　挖雷参考了我以前写的 Python 版挖雷的代码，这版代码比 DOS 版好一点儿，不过，现在看来，也是很多地方不合理，不过，我主要是为了体验 PSP 编程，倒也问题不大，只是关于显示部分，还是写了一个全局函数，几个全局变量，有点儿不爽。<br /><br />　　虽然是 windows 上测试，PSP 上部署，还是会遇到一些不同的地方。比如随机函数，在 pc 上运行的很好，在 psp 上就只产生 0，经过不断测试，发现是因为 PSP 版（gcc?） srand 不支持大于 RAND_MAX 的种子，而 RAND_MAX 是 0x7fff，看起来，这像是因为函数库从16位升级到32位而出现的问题，把 time 的结果对 RAND_MAX 取余，即解决这个问题。另外，如果增加了其它代码，不是 include 进来的话，需要自己修改 makefile 文件，把新代码名加入 OBJS 中才可以。<br /><br />　　因为有参考代码，游戏逻辑不用考虑，所以本来乐观估计，一晚上可以完成，不过，遇到这样那样的问题，还是花了两个晚上多一点儿，不过，之后应该就会轻松多了吧。<br /><br />　　目前游戏没有加音乐，25x12 65 颗雷，还不支持调节这个数值，它的难度和 windows 高级挖雷接近。按三角键则显示帮助页面，按 Select 截屏。以后可能考虑加入声音，级别选择，再加点儿动感特效什么的<img src="/images/smiles/icon_biggrin.gif"/><br /><br />　　游戏在我的 PSP2000，3.71m33-4 上测试通过。下面是运行截图和软件包：
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/182114#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 12 Apr 2008 15:37:04 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/182114</link>
        <guid>http://llf.javaeye.com/blog/182114</guid>
      </item>
      <item>
        <title>10年前的小游戏作品</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/179874" style="color:red;">http://llf.javaeye.com/blog/179874</a>&nbsp;
          发表时间: 2008年04月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          　　10年前，还在大学的时候写了个挖雷，后来用作毕业设计，所以又增加了猜数字、俄罗斯方块和华容道。<br /><br />　　DOS 下用 Turbo C 2.0 写的，开始，在鼠标显示问题上花了些脑筋，后来，在图形显示、PCX文件解析、汉字显示上也投入不少精力，再后来，使用中断增加了演奏音乐的功能（因为比较难听，所以缺省是关闭的，在游戏中按 PrintScreen 键可以开关音乐）。<br /><br />　　现在看来，虽然当时的程序结构并不是很好，但是也还不算差 <img src="/images/smiles/icon_biggrin.gif"/><br /><br />　　以前放到主页的时候，以压缩包小为第一，所以，甚至没有附带汉字库 HZK16，以至于有些人说程序出错，现在想想，还是应该提供完整的包的。<br /><br />　　现在已经10年过去，所以做了一个软盘版镜像，小小纪念一下。这个镜像文件使用 FreeDOS 启动，可以用于任何虚拟机，比如 Virtual PC。（好像 FreeDOS 的 lbacache 不如 smartdrv 效果好），启动之后，直接进入游戏。另外，此镜像也附带了源代码。
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/179874#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 06 Apr 2008 18:05:58 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/179874</link>
        <guid>http://llf.javaeye.com/blog/179874</guid>
      </item>
      <item>
        <title>导航、权限管理及 Linq 应用</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/179850" style="color:red;">http://llf.javaeye.com/blog/179850</a>&nbsp;
          发表时间: 2008年04月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          　　最近做一个广告系统，后台管理部分使用 ASP.NET，使用了 VS2008 + .Net 3.5，还是使用我写的 DbEntry 做数据库接口，页面部分大部分使用 ASP.NET Ajax 的 UpdatePanel 来进行更新，效果很不错，而且，速度上也感觉比普通的非 Ajax 页面快。<br /><br />　　而对于权限部分，使用页面级访问控制，读取 Web.Config 的方式，导航使用 html 直接放在母板页中的方式，后来觉得这样，每增加一个页面或对页面改名，就需要修改两个地方，不是一个很好的解决方案。<br /><br />　　以前，在做互联星空的一个项目时，曾经设计了使用 XML 做配置，导入 TreeView 做导航的方式，目前虽然不是使用 TreeView 做导航，应该也一样是适用的。不过，这一次，不想使用 XML，而是考虑直接在程序中使用 List 或 Directory 来表示这个数据结构。<br /><br />　　试着写了一下这个结构，发现，还是使用类似数据库的结构比较简单。于是定义 Category 和 Link 类，另外定义 Navigation 类，增加两个静态字段 Categories 和 Links：<br /><pre name="code" class="c#">
public class Category
{
    private static int IdSeed = 1;

    public int Id { get; set; }
    public string Name { get; set; }

    public Category()
    {
        Id = IdSeed++;
    }
}

public class Link
{
    private static int IdSeed = 1;

    public int Id { get; set; }
    public string Name { get; set; }
    public string Url { get; set; }
    public int Permission { get; set; }
    public bool Hide { get; set; }
    public int Category_Id { get; set; }

    public Link()
    {
        Id = IdSeed++;
    }
}

public static class Navigation
{
    public static readonly List&lt;Category> Categories;
    public static readonly List&lt;Link> Links;
}
</pre><br />　　然后，在静态构造函数中初始化数据：<br /><pre name="code" class="c#">
static Navigation()
{
    Categories = new List&lt;Category>()
    {
        new Category(){ Id = 1, Name = "设备管理" },
        new Category(){ Id = 2, Name = "内容管理" },
        new Category(){ Id = 3, Name = "计划" },
        new Category(){ Id = 4, Name = "系统" },
    };

    int FullPermission = (int)(SysUserRole.管理员 | SysUserRole.编辑人员 | SysUserRole.审核人员);

    Links = new List&lt;Link>()
    {
        new Link(){ Url = "Default", Permission = FullPermission, Hide = true },
        // 设备管理
        new Link(){ Name = "新建设备", Url = "PlayerEdit", Permission = FullPermission, Category_Id = 1 },
        new Link(){ Name = "设备列表", Url = "PlayerList", Permission = FullPermission, Category_Id = 1 },
        new Link(){ Url = "PlayerManager", Permission = FullPermission, Hide = true, Category_Id = 1 },
        new Link(){ Category_Id = 1 },
        new Link(){ Name = "新建分组", Url = "PlayerGroupEdit", Permission = FullPermission, Category_Id = 1 },
        new Link(){ Name = "分组列表", Url = "PlayerGroupList", Permission = FullPermission, Category_Id = 1 },
        // 内容管理
        ......
        // 计划
        ......
        // 系统
        new Link(){ Name = "新建帐户", Url = "SysUserEdit", Permission = FullPermission, Category_Id = 4 },
        new Link(){ Name = "帐户列表", Url = "SysUserList", Permission = FullPermission, Category_Id = 4 },
        new Link(){ Category_Id = 4 },
        new Link(){ Name = "新建客户", Url = "CustomerEdit", Permission = FullPermission, Category_Id = 4 },
        new Link(){ Name = "客户列表", Url = "CustomerList", Permission = FullPermission, Category_Id = 4 },
    };
}
</pre><br />　　其中，空的 Link 表示显示一个 hr 标签，用来分组，Url 是去掉“.aspx”之后的名字，Permission 用来对页面可访问性进行授权，这种方式，对于 int32 而言，可以提供 32 种权限，应该是足够了，当然，各种权限应该按 2 的幂的方式递增，如 1、2、4、8。这样，在判断是否有权限的时候，只要用“(Permission & p) == p”来判断就可以了。<br /><br />　　导航的 html 改在 Navigation 类中生成，然后填入母板页中的方式，使用 DbEntry 中的 HtmlBuilder 来生成 html 片段：<br /><pre name="code" class="c#">
public static string BuildNavigator(int Permission)
{
    HtmlBuilder hb = HtmlBuilder.New.div.id("accmenu").enter();
    foreach (var c in Categories)
    {
        int count = 0;
        var b = HtmlBuilder.New.tab.div.enter();
        b.tab.tab.div.Class("acctitle").text(c.Name).end.enter();
        b.tab.tab.div.enter();
        var list = Links.Where(p => p.Category_Id == c.Id).ToList();
        foreach (var n in list)
        {
            if (string.IsNullOrEmpty(n.Url))
            {
                b.include("\t\t\t&lt;hr />\r\n");
            }
            else
            {
                if (!n.Hide && (n.Permission & Permission) == Permission)
                {
                    count++;
                    b.include("\t\t\t&lt;img src=\"images/h2.gif\" align=\"absmiddle\" /> ");
                    b.a(n.Url + ".aspx").text(n.Name).end.br.enter();
                }
            }
        }
        b.tab.tab.end.enter().tab.end.enter();
        if (count > 0)
        {
            hb.include(b);
        }
    }
    hb.end.enter();
    return hb.ToString();
}
</pre><br />　　上面的代码，会生成类似以下的 html ：<br /><pre name="code" class="html">
&lt;div id="accmenu">
    &lt;div>
        &lt;div class="acctitle">设备管理&lt;/div>
        &lt;div>
            &lt;img src="images/h2.gif" align="absmiddle" /> &lt;a href="PlayerEdit.aspx">新建设备&lt;/a>&lt;br />
            &lt;img src="images/h2.gif" align="absmiddle" /> &lt;a href="PlayerList.aspx">设备列表&lt;/a>&lt;br />
            &lt;hr />
            &lt;img src="images/h2.gif" align="absmiddle" /> &lt;a href="PlayerGroupEdit.aspx">新建分组&lt;/a>&lt;br />
            &lt;img src="images/h2.gif" align="absmiddle" /> &lt;a href="PlayerGroupList.aspx">分组列表&lt;/a>&lt;br />
        &lt;/div>
    &lt;/div>
    &lt;div>
        ......
    &lt;/div>
    &lt;div>
        ......
    &lt;/div>
    &lt;div>
        &lt;div class="acctitle">系统&lt;/div>
        &lt;div>
            &lt;img src="images/h2.gif" align="absmiddle" /> &lt;a href="SysUserEdit.aspx">新建帐户&lt;/a>&lt;br />
            &lt;img src="images/h2.gif" align="absmiddle" /> &lt;a href="SysUserList.aspx">帐户列表&lt;/a>&lt;br />
            &lt;hr />
            &lt;img src="images/h2.gif" align="absmiddle" /> &lt;a href="CustomerEdit.aspx">新建客户&lt;/a>&lt;br />
            &lt;img src="images/h2.gif" align="absmiddle" /> &lt;a href="CustomerList.aspx">客户列表&lt;/a>&lt;br />
        &lt;/div>
    &lt;/div>
&lt;/div>
</pre><br />　　而，它的显示，使用的是 jQuery 的插件 <a href="http://docs.jquery.com/UI/Accordion" target="_blank">jQuery Accordion</a> ，按照自己想要风格配置 css，然后在母板页中加入：<br /><pre name="code" class="js">
jQuery().ready(function(){
    var w = $('#accmenu').accordion({
        header: 'div.acctitle',
        animated: false
    });
    w.activate(CategoryIndex);
});
</pre><br />　　之所以要关闭动画效果，是为了根据当前页所在分类，自动激活相应的面板，自动激活的过程如果有动画，显得很奇怪，不过，还没有找到这个 jQuery 插件相关设置初始面板的方法......<br /><br />　　Navigation 类提供取得指定 Url 权限的功能，使用基本的 Linq 语法：<br /><pre name="code" class="c#">
public static int GetPermission(string Url)
{
    var item = Links.Where(p => p.Url == Url).ToList();
    if (item.Count > 0)
    {
        return item[0].Permission;
    }
    return 0;
}
</pre><br />　　因为，在生成 html 的时候，考虑了如果按照相应的权限，一个分类下没有任何项目，则不显示这个分类，所以，取 Index 要复杂一些，要根据相应的权限进行分组，所以相应的 Linq 语句也复杂一些，使用了 group by：<br /><pre name="code" class="c#">
public static int GetIndex(string Url, int Permission)
{
    int id = FindCategoryId(Url);
    var item = from p in Links where (p.Permission & Permission) == Permission && p.Category_Id != 0
               group p by p.Category_Id into g select new { Category_Id = g.Key };
    var i = item.ToList().FindIndex(p => p.Category_Id == id);
    return i &lt; 0 ? 0 : i;
}

public static int FindCategoryId(string Url)
{
    var item = Links.Where(p => p.Url == Url).ToList();
    if (item.Count > 0)
    {
        return item[0].Category_Id;
    }
    return 0;
}
</pre><br />　　虽然我现在使用的是内存里的数据，不过，因为格式是很标准的数据库格式，所以，要把这个配置项放入数据库表里，或者序列化成 XML，也都是非常方便的  —— 虽然我认为这个必要性不高。<br /><br />　　从实现来看，这个方法的速度应该不会很快，不过，因为数据量小，而且对于页面来说，这些在内存里做的手脚只能算小Case，所以没有明显感觉速度上有任何差异。<br /><br />　　不过，目前对于这个方案，还有一些不满意，比如，Hide 参数考虑改成和 Permission 相似，则可以控制每一项在不同权限下的显示，比单纯的全局 Hide 要灵活得多。再比如，目前没有判断是否会出现两条分割线等等。<br /><br />　　另外一种实现方案是，把数据的定义放在每一个页面里，这样的话，虽然设置分散到了每一个页面，但是却更符合实际情况，而且，页面 Url 也可以通过反射得到，删除页面或者页面改名都更简单，也许是更好的解决方案吧。<br /><br />　　其实，我感觉很好的是，这个程序的页面风格、css 以及一些图片什么的，都是我做的，而且我感觉还挺漂亮的 <img src="/images/smiles/icon_biggrin.gif"/>，来个运行截图：
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/179850#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 06 Apr 2008 15:42:11 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/179850</link>
        <guid>http://llf.javaeye.com/blog/179850</guid>
      </item>
      <item>
        <title>.Net 3.5 扩展方法的另一个限制</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/176464" style="color:red;">http://llf.javaeye.com/blog/176464</a>&nbsp;
          发表时间: 2008年03月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          　　这两天用扩展方法用的很舒服，也发现了它的另一个限制，不能扩展“属性”。<br /><br />　　虽然，从本质上来说，属性不过是两个特殊命名的方法的一种快捷方式，不过，我试了几种写法，都没有发现有什么可能的迹象。<br /><br />　　失败的试验包括，自己写“set_PropertyName”和“get_PropertyName”，然后加[SpecialName]标签。<br /><br />　　以上。
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/176464#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 26 Mar 2008 18:37:51 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/176464</link>
        <guid>http://llf.javaeye.com/blog/176464</guid>
      </item>
      <item>
        <title>D 语言的子集的 Z 编译器</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/157507" style="color:red;">http://llf.javaeye.com/blog/157507</a>&nbsp;
          发表时间: 2008年01月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          　　把 D 语言的语法规则改写成 ANTLR 的语法脚本后，大概有30多K，编译的时候，出了很多的错误，最后内存溢出了。想一想，也是，一来我对 ANTLR 还不熟，二来，Digit Mars 上的 D 语言语法介绍，很多左递归，有几个没有定义的过程，两个拼写错误，一个同名不同义的过程等等。在这种情况下，30多K的语法脚本想要很快的就编译通过，是很困难的。<br /><br />　　所以，还是决定用 ANTLR 实现一下 Z 编译器。这一次，把 Z 作为 D 的一个子集，语法定义大部分直接从 D 的语法脚本中复制，一来可以熟悉 ANTLR，二来，完成的语法文件，对于 D 来说也是有用的。<br /><br />　　作为 D 的子集，现在 Z 也支持一些 D 的风格的语法，比如三种注释方式：<br /><pre name="code" class="java">// 行注释
/* 注释 */
/+ 嵌套注释 +/</pre><br />　　另外，也支持 D 中的带有“_”的数字格式：<br /><pre name="code" class="java">int a = 123_456_789;</pre><br />　　这个版本中增加支持了 bool 类型：<br /><pre name="code" class="java">bool b = true;
b = 30 > 10;</pre><br />　　也支持 D 语言中的自动类型推导：<br /><pre name="code" class="java">auto a = 1;
auto b = true;
if(b) write(a);</pre><br />　　其它的一般都是 C 和 D 公有的，比如十六进制数字、八进制数字：<br /><pre name="code" class="java">int a = 0x83_af; // 十六进制数字
int b = 067;     // 八进制数字</pre><br />　　连等赋值：<br /><pre name="code" class="java">a = b = c = 2;</pre><br />　　++、--、+=、-=、*=、/= （++、--只支持左操作符方式）：<br /><pre name="code" class="java">int n = 10;
int a *= ++n;</pre><br />　　也增加了 for、while、do-while 循环：<br /><pre name="code" class="java">// 1 到 100 的和
// for 循环
int n = 0;
for(int i=1; i&lt;=100; ++i)
    n += i;
write(n);
// while 循环
i = 0; n = 0;
while( i &lt; 100 )
    n += ++i;
write(n);
// do-while 循环
i = 0; n = 0;
do
    n += ++i;
while( i &lt; 100 )
write(n);</pre><br />　　另外，因为语法文件大部分从 D 复制，所以，运算符优先级也和 C/D 一样了（就是上次说的“&&”的优先级高于“||”之类的问题）。负号现在也遵照这种方式放入表达式中，所以，不只没有上一版中必须加空格的问题，而且支持对变量求负：<br /><pre name="code" class="java">int a = 10;
int b=5-3;    // 5 - 3
b=5--3;       // 5 - (-3);
b=7*-a;       // 7 * (-a);</pre><br />　　虽然可以在定义变量的时候使用逗号，但是普通表达式还不支持逗号方式。另外，Z 还是有一个和 D 比较大的不同，就是 bool 类型和 int 类型之间不允许互相转换，否则会引发编译时错误，而 if for while do-while 的条件表达式也必须最终为 bool 类型才可以：<br /><pre name="code" class="java">int n = 1;
bool a = n == 0;
a = a && n > 10 || n != 3;
bool b = n; // error
if(b) write(1);
if(n) write(2); // error</pre><br />　　ANTLR 确实对于语法的细节控制能力更强，而且，生成 AST 的能力也很突出。ANTLRWorks 虽然有时候不工作，有时候和实际代码效果有出入，总体来说还是帮助很大。从 AST 生成代码也比上一版中更方便。不过，在我的实现代码里很多异常都是直接用断言实现的，没有打印行号。另外，因为 ANTLR 有很强的错误恢复能力，目前还不知道怎么判断代码分析中是否出现错误……<br /><br />　　下面是可执行程序和源代码：
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/157507#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 18 Jan 2008 20:59:17 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/157507</link>
        <guid>http://llf.javaeye.com/blog/157507</guid>
      </item>
      <item>
        <title>用 ANTLR 做一个四则运算器</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/156170" style="color:red;">http://llf.javaeye.com/blog/156170</a>&nbsp;
          发表时间: 2008年01月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>　　开始把 D 的语法转换为 EBNF，发现 D 还支持中文变量名，也就是所谓的 UniversalAlpha，查看了一下 dmd front end 的源代码，检查字符是否 UniversalAlpha 的函数是这样的：</p><p>&nbsp;</p><pre name="code" class="csharp">int isUniAlpha(unsigned u)
{
    static unsigned short table[][2] =
    {
 { 0x00AA, 0x00AA },
 { 0x00B5, 0x00B5 },
 { 0x00B7, 0x00B7 },
 ......
 ......
 ......
 { 0x3105, 0x312C },
 { 0x4E00, 0x9FA5 },
 { 0xAC00, 0xD7A3 },
    };
    if (u &gt; 0xD7A3)
 goto Lisnot;

   // Binary search
    int mid;
    int low;
    int high;

  low = 0;
    high = sizeof(table) / sizeof(table[0]) - 1;
    while (low &lt;= high)
    {
 mid = (low + high) &gt;&gt; 1;
 if (u &lt; table[mid][0])
     high = mid - 1;
 else if (u &gt; table[mid][1])
     low = mid + 1;
 else
     goto Lis;
    }

Lisnot:
    return 0;

Lis:
    return 1;
}

</pre><p>&nbsp;&nbsp;</p><p>&nbsp;</p><p>　　但是，怎么让 Grammatica 在分析过程中调用类似的函数，却是一点儿头绪也没有。虽然，理论上来说，用正则表达式，也可以表示上面的逻辑，不过，200多行的数据，要都转成正则表达式，不止运行速度慢，就只是转换的工作量，也让人不可接受。</p><p>&nbsp;</p><p>　　而后，对于 D 中 string interger 和 float 的转换，再次发现 Grammatica 这种只用正则表达式的方式的严重不足，终于决定放弃 Grammatica。</p><p>&nbsp;</p><p>　　本来，最好的办法其实是使用 dmd 的前端的源代码来解析，不过，几乎 1.6M 的代码，没有任何文档，都读过一遍的话，黄花菜都凉了。</p><p>&nbsp;</p><p>　　一直不想用 ANTLR 的原因，是语法文件和嵌入的代码混编，看起来杂乱无章，但是 ANTLR 的强大和社区的活跃确实是很吸引人的。于是，决定用 ANTLR 来写 D Parser。（看到还有一个叫 coco/r 的生成器，据说比 ANTLR 清晰，不过也有语法能力不如 ANTLR 的问题，所以暂时也不考虑了。）</p><p>&nbsp;</p><p>　　同样的，四则运算是一个比较好的例子，从 ANTLR 的主页的&ldquo;五分钟教程&rdquo;中，找到一个四则运算的语法文件，看了一下，不嵌入代码的话，还挺清晰的。既然用 ANTLR，就要体验一下它自动建立抽象语法树的能力，把那个语法文件做了一些修改，成为这个样子：</p><p>&nbsp;</p><pre name="code" class="csharp">grammar SimpleCalc;

options {
    language=CSharp;
    output=AST;
    ASTLabelType=CommonTree;
}

tokens {
    PLUS     = '+' ;
    MINUS    = '-' ;
    MULT     = '*' ;
    DIV      = '/' ;
}

@members {
}

/*------------------------------------------------------------------
 * PARSER RULES
 *------------------------------------------------------------------*/

expr    : term ( ( PLUS^ | MINUS^ )  term )* ;
term    : factor ( ( MULT^ | DIV^ ) factor )* ;
factor  : NUMBER | '(' expr ')' -&gt; expr ;

/*------------------------------------------------------------------
 * LEXER RULES
 *------------------------------------------------------------------*/

NUMBER     : (DIGIT)+ ;
WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+     { $channel = HIDDEN; } ;
fragment DIGIT    : '0'..'9' ;

</pre><p>&nbsp;&nbsp;</p><p>&nbsp;</p><p>　　做了修改的地方是，1.让它输出 AST，2.把运算符提取为根，3.支持括号。</p><p>&nbsp;</p><p>　　生成文件后，在 Program 文件中加入创建分析器的代码，再加入深度优先的语法树访问函数，以及运算部分如下：</p><p>&nbsp;</p><pre name="code" class="csharp">using System;
using System.Collections.Generic;
using System.Text;
using Antlr.Runtime;
using Antlr.Runtime.Tree;

namespace Expr
{
    class Program
    {
        private static Stack&lt;int&gt; numbers = new Stack&lt;int&gt;();

       static void Main(string[] args)
        {
            SimpleCalcLexer lex = new SimpleCalcLexer(new ANTLRFileStream(args[0]));
            CommonTokenStream tokens = new CommonTokenStream(lex);
            SimpleCalcParser parser = new SimpleCalcParser(tokens);

           try
            {
                CommonTree ct = (CommonTree)parser.expr().Tree;
                VisitTree(ct);
                Console.WriteLine(&quot;The result is: {0}&quot;, numbers.Pop());
                Console.Read();
            }
            catch (RecognitionException e)
            {
                Console.Error.WriteLine(e.StackTrace);
            }
        }

       static void VisitTree(ITree it)
        {
            for (int i = 0; i &lt; it.ChildCount; i++)
            {
                ITree c = it.GetChild(i);
                VisitTree(c);
            }
            switch (it.Type)
            {
                case SimpleCalcLexer.PLUS:
                case SimpleCalcLexer.MINUS:
                case SimpleCalcLexer.MULT:
                case SimpleCalcLexer.DIV:
                    Operation(it.Text, numbers.Pop(), numbers.Pop());
                    break;
                case SimpleCalcLexer.NUMBER:
                    numbers.Push(int.Parse(it.Text));
                    break;
            }
        }

    static void Operation(string opCode, int v2, int v1)
        {
            int result;
            switch (opCode)
            {
                case &quot;+&quot;:
                    result = v1 + v2;
                    break;
                case &quot;-&quot;:
                    result = v1 - v2;
                    break;
                case &quot;*&quot;:
                    result = v1 * v2;
                    break;
                case &quot;/&quot;:
                    result = v1 / v2;
                    break;
                default:
                    throw new Exception();
            }
            Console.WriteLine(&quot;{1} {0} {2} = {3}&quot;, opCode, v1, v2, result);
            numbers.Push(result);
        }
    }
}

</pre><p>&nbsp;</p><p>&nbsp;</p><p>　　上面的代码，除了运算之外，还会把每一个计算步骤打印出来，在输入文件中输入&ldquo;5-(3-2)+6*7&rdquo;，编译运行程序，得到结果：</p><p>&nbsp;</p><div class="quote_div">3 - 2 = 1 <br />5 - 1 = 4 <br />6 * 7 = 42 <br />4 + 42 = 46 <br />The result is: 46</div><p>&nbsp;</p><p>　　ANTLR 帮助建立 AST 的功能确实很舒服，而且例子也多，嗯，以后就用它了。<img title="smile" src="../../images/smiles/icon_smile.gif" border="0" alt="smile" /></p>
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/156170#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 15 Jan 2008 17:48:08 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/156170</link>
        <guid>http://llf.javaeye.com/blog/156170</guid>
      </item>
      <item>
        <title>D Parser 之前（三）：Z 语言编译器</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/155151" style="color:red;">http://llf.javaeye.com/blog/155151</a>&nbsp;
          发表时间: 2008年01月11日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>　　终于把 Z 语言的编译器做完了。意外的在四则运算上耽误了很多时间，发现 Grammatica 的四则运算的例子其实是右结合的，费了很大劲才解决了。现在觉得 Grammatica 的完整度好像不是很高，比如没有帮助建立抽象语法树的工具之类。也许 ANTLR 会好一点儿吧。</p><p>&nbsp;</p><p>　　重新整理了目录，把生成的程序放到了 bin 目录下，建立了一个 build.bat 的批处理，用来把 z 编译成机器码，再打开虚拟机，加载此机器码。</p><p>&nbsp;</p><p>　　虚拟机指令增加了一些，比如现在也支持减、乘、除运算，增加直接设置 esp 和把 esp 和 ebx 转移，以及中断指令（在 z 里通过 pause 语句生成中断指令）等等。</p><p>&nbsp;</p><p>　　Z 的编译器使用的是最保守的方式生成指令，也就是说，为了保证正确性，加入了很多垃圾代码。<img title="biggrin" src="../../images/smiles/icon_biggrin.gif" border="0" alt="biggrin" /></p><p>&nbsp;</p><p>　　有一个小问题，就是如果遇到&ldquo;5-3&rdquo;这样的表达式，分辨不出是减号还是负号，会编译通不过，解决方法也很简单，加入空格就可以了&ldquo;5 - 3&rdquo;。</p><p>&nbsp;</p><p>　　现在，我们可以编译下面的 1 到 100 和的程序：</p><p>&nbsp;</p><pre name="code" class="csharp">int n = 0;
int i = 1;
next:
if(i &lt;= 100)
{
    n = n + i;
    i = i + 1;
    goto next;
}
write(n);
</pre><p>&nbsp;&nbsp;</p><p><br />　　也可以把 fibonacci 序列的程序编译：</p><p>&nbsp;</p><pre name="code" class="csharp">int i=0;
int a=1;
write(a);
int b=1;
write(b);
int t;
next:
t = a + b;
write(t);
a = b;
b = t;
i = i + 1;
if(i&lt;10) goto next;
</pre><p>&nbsp;</p><p>　　其中，if 语句也可以处理 else：</p><p>&nbsp;</p><pre name="code" class="csharp">int n = 1;
int m = 8 * 9;
if( n &lt; 5 &amp;&amp; (m == 73 || !(n != 1)) )
{
    write(1);
    if ( n == 1 )
        if ( n == 2 )
            write(11);
        else
            write(12);
}
else
{
    write(2);
}
write(3);
</pre><p>&nbsp;&nbsp;</p><p><br />　　或者执行复杂运算如下：</p><pre name="code" class="csharp">write( 2 + 8 * 1 / 8 - 1 - (2 - 3) * 5 * 2 );</pre><p>&nbsp;&nbsp;</p><p>&nbsp;</p><p>　　下面是可执行文件、源代码和运行截图：</p><p>&nbsp;</p><p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/155151#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 11 Jan 2008 18:32:39 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/155151</link>
        <guid>http://llf.javaeye.com/blog/155151</guid>
      </item>
      <item>
        <title>D Parser 之前（二）：汇编编译器</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/153818" style="color:red;">http://llf.javaeye.com/blog/153818</a>&nbsp;
          发表时间: 2008年01月08日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>　　在《D Parser 之前：写一个简单的虚拟机》里，其中计算 1 到 100 之和的程序 add.bin，是使用十六进制编辑器直接编辑出来的。虚拟机制作完后，考虑了一下，如果直接写 Z 的编译器，难度还是不小，所以决定，先写一个汇编语言的编译器，实现从汇编代码到机器代码的编译工作。</p><p>&nbsp;</p><p>　　大体来说，汇编编译基本上是一条一条对照生成，不过，行号的需求使得其中多了一些复杂性，另外，我还决定加入注释的支持。所以，这也是一个比较好的机会实践一下分析器生成器的使用。</p><p>&nbsp;</p><p>　　汇编语言部分做了少量修改，over 改为 end，行号改为加 @ 前缀，完成的 Grammatica 的分析文件如下：</p><pre name="code" class="csharp">%header%

GRAMMARTYPE = &quot;LL&quot;

DESCRIPTION = &quot;A asm grammar for zvm.&quot;

AUTHOR      = &quot;Lephone Liang&quot;
VERSION     = &quot;1.0&quot;
DATE        = &quot;7 January 2008&quot;

LICENSE     = &quot;.&quot;

COPYRIGHT   = &quot;Copyright (c) 2008 Lephone. All rights reserved.&quot;


%tokens%

EAX                          = &quot;eax&quot;
EBX                          = &quot;ebx&quot;
ESP                          = &quot;esp&quot;
EIP                          = &quot;eip&quot;

SET                          = &quot;set&quot;
MOV                          = &quot;mov&quot;
TJMP                         = &quot;jmp&quot;
ADD                          = &quot;add&quot;
TGT                          = &quot;gt&quot;
TGTEQ                        = &quot;gteq&quot;
TEQ                          = &quot;eq&quot;
TNOT                         = &quot;not&quot;
IF                           = &quot;if&quot;
TOUT                         = &quot;out&quot;
TEND                         = &quot;end&quot;
POINT                        = &quot;*&quot;
COMMA                        = &quot;,&quot;


NUMBER                       = &lt;&lt;(-)?([0-9])+&gt;&gt;
LABEL                        = &lt;&lt;@[a-z]+&gt;&gt;
COMMENT                      = &lt;&lt;;[^\n\r]*[\r\n]&gt;&gt; %ignore%
WHITESPACE                   = &lt;&lt;[ \t\n\r]+&gt;&gt; %ignore%


%productions%

Expression = Atom [Expression];

Atom
 = SetEax
 | MovEax8Esp
 | SetEbx
 | MovEbx8Esp
 | Mov8EspEax
 | Mov8EspEbx
 | AddEsp
 | AddEaxEbx
 | Gt
 | Gteq
 | Eq
 | Not
 | IfEaxJmp
 | Jmp
 | Out
 | End
 | LineLabel ;

SetEax            = SET EAX COMMA NUMBER;
MovEax8Esp        = MOV EAX COMMA POINT ESP;
SetEbx            = SET EBX COMMA NUMBER;
MovEbx8Esp        = MOV EBX COMMA POINT ESP;
Mov8EspEax        = MOV POINT ESP COMMA EAX;
Mov8EspEbx        = MOV POINT ESP COMMA EBX;
AddEsp            = ADD ESP COMMA NUMBER;
AddEaxEbx         = ADD EAX COMMA EBX;
Gt                = TGT;
Gteq              = TGTEQ;
Eq                = TEQ;
Not               = TNOT;
IfEaxJmp          = IF EAX TJMP LABEL;
Jmp               = TJMP LABEL;
Out               = TOUT EAX;
End               = TEND;
LineLabel         = LABEL;</pre><p>&nbsp;</p><p>　　生成代码后，加入新建的 ZasmC 工程，参照 Grammatica 的例子调试了一会儿，增加一些处理代码后，编译器可以正常工作了。用它编译上一次的的 1 到 100 和的汇编代码，发现几个汇编代码的格式错误 <img title="biggrin" src="../../../images/smiles/icon_biggrin.gif" border="0" alt="biggrin" /> 后，编译成功，加载入虚拟机，运行得到结果：5050。</p><p>&nbsp;</p><p>　　还想再写一个程序验证一下，Fibonacci 序列是一个不错的例子，于是编写 d 的原型如下：</p><pre name="code" class="csharp">import std.stdio;

static void main(char[][] args)
{
 int i=0;
 int a=1;
 write(a);
 int b=1;
 write(b);
 int t;
 next:
 t = a + b;
 write(t);
 a = b;
 b = t;
 i++;
 if(i&lt;10) goto next;
}

void write(int n)
{
 writefln(&quot;%d&quot;, n);
}

</pre><p>&nbsp;&nbsp;</p><p>&nbsp;</p><p>　　改写为汇编代码如下：</p><pre name="code" class="csharp">; 斐波那契
; esp i, esp+4 a, esp+8 b, esp+12 t
; int i=0;
set eax, 0
mov *esp, eax
; int a=1;
; write(a);
set eax, 1
add esp, 4  ; a
mov *esp, eax
out eax
; int b=1;
; write(b);
add esp, 4  ; b
mov *esp, eax
out eax
add esp, -8  ; i
; int t;
@next
; t = a + b;
; write(t);
add esp, 4  ; a
mov eax, *esp
add esp, 4  ; b
mov ebx, *esp
add eax, ebx
add esp, 4  ; t
mov *esp, eax
out eax
; a = b;
; b = t;
add esp, -4  ; b
mov eax, *esp
add esp, -4  ; a
mov *esp, eax
add esp, 8  ; t
mov eax, *esp
add esp, -4  ; b
mov *esp, eax
; i++;
add esp, -8  ; i
mov eax, *esp
set ebx, 1
add eax, ebx
mov *esp, eax
set ebx, 10  ; 循环次数
gteq
not
if eax jmp @next
end
</pre><p>&nbsp;</p><p>&nbsp;</p><p>　　用 ZasmC 编译，生成 Fibonacci.bin，加载到虚拟机，第一次运行错误，后来发现是 d 转汇编的时候的疏忽，修正汇编代码后，编译，加载运行，得到正确的结果。</p><p>&nbsp;</p><p>　　下一步就是写 Z 的编译器了，这一步可能要花比较长的时间，准备把 Z 编译成汇编代码，然后再用这个汇编编译器编译成机器代码，这样，Z 编译器就不需要处理行号问题了。</p><p>&nbsp;</p><p>　　下面是虚拟机和汇编编译器的源代码，以及运行 Fibonacci 的截图：</p><p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/153818#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 08 Jan 2008 00:25:21 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/153818</link>
        <guid>http://llf.javaeye.com/blog/153818</guid>
      </item>
      <item>
        <title>D Parser 之前：写一个简单的虚拟机</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/153501" style="color:red;">http://llf.javaeye.com/blog/153501</a>&nbsp;
          发表时间: 2008年01月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>　　最近写了一点儿 D 程序，除了感觉标准库太差之外，没有一个好的 IDE 也是一个很头疼的事，特别是没有智能提示，每次调用一个函数什么的，都要查文档或者直接看源代码，实在是太费劲了。</p><p>&nbsp;</p><p>　　所以决定自己尝试写一个支持智能提示的 D 的 IDE。因为 SharpDelelop 比较小，而且它对 C# 的支持也做到了智能提示、窗体编辑器等等，所以决定用它作为主框架，除了智能提示，也许还能加入 DFL 的窗体编辑之类的功能（Entice 做的窗体编辑已经不错了，只是没有事件支持）。目前，已经完成了语法加亮，代码折叠（目前和 notepad++ 一样只是通过大括号匹配来做的），下一步，就是智能提示了，而智能提示就牵涉到语法分析。</p><p>&nbsp;</p><p>　　找了几个分析器生成器，试用之后，觉得 Grammatica 还不错，生成的代码比较清晰，调试起来也比较方便。照它的例子写了一个四则运算的分析器，还不错。</p><p>&nbsp;</p><p>　　看了一下 D 的语法详细列表，那也不是一般的复杂。所以，决定先写一个简单的语言的分析器、编译器和虚拟机练练手。今天先把虚拟机做了出来。</p><p>&nbsp;</p><p>　　这种语言的语法非常简单，姑且称之为 Z 语言吧（还没有细化）：</p><p>&nbsp;</p><pre name="code" class="csharp">声明语句： int x;        // 只支持 int
赋值语句： x = 1;
条件语句： if(x &gt; 1) { ... } else { ... }
跳转语句： goto lable
标签语句： :lable
输出语句： write(x);        // 只支持 int
注释语句： // ... &lt;eol&gt;
</pre><p>&nbsp;</p><p>　　而虚拟机部分，参照 x86 asm，定义如下：</p><pre name="code" class="csharp">寄存器：        EAX, EBX, ESP, EIP        // EAX,EBX操作数，ESP堆栈指针，EIP指令指针
内存：          200000B，0B～99999B为堆栈，100000B～199999B为程序
指令：
      为EAX赋值：                       set eax, 1                // 01 01 00 00 00
        将当前堆栈地址变量复制到eax：     mov eax, *esp             // 02
        为EAX赋值：                       set ebx, 1                // 03 01 00 00 00
        将当前堆栈地址变量复制到ebx：     mov ebx, *esp             // 04
        为当前堆栈地址变量赋值eax：       mov *esp, eax             // 05
        为当前堆栈地址变量赋值ebx：       mov *esp, ebx             // 06
        esp 加运算：                      add esp, 1                // 07 01 00 00 00
        eax 加运算：                      add eax, ebx              // 08
        eax大于ebx？结果放eax：           gt                        // 11
        eax大于等于ebx？结果放eax：       gteq                      // 12
        eax等于ebx？结果放eax：           eq                        // 13
        eax bool not：                    not                       // 14
        eax 为非 0 跳转（相对）：         if eax jmp {sp}           // 21 {sp}
        无条件跳转（相对）：              jmb {sp}                  // 22 {sp}
        输出 eax：                        out                       // 31
        结束：                            over                      // ff
</pre><p>&nbsp;&nbsp;</p><p>&nbsp;　　另外，虚拟机需要能显示寄存器值，显示当前堆栈顶值，显示输出。支持单步执行。</p><p>&nbsp;</p><p>　　再写一段小程序，用来验证虚拟机的运行情况，因为只支持 int，所以计算 1 到 100 的和是一个比较合适的小代码段， C 的代码如下：</p><pre name="code" class="csharp">int n = 0;
for(int i=1; i&lt;=100; i++)
{
    n += i;
}
write(n);
</pre><p>　　Z 语言不支持 for 循环，所以，相应的 Z 代码大体如下：</p><pre name="code" class="csharp">int n = 0;
int i = 1;
:next
if(i &gt; 100) { goto end; }
n += i;
i++;
goto next;
:end
write(n);
</pre><p>&nbsp;&nbsp;</p><p>　　而根据上面定义的指令集，其相应的汇编代码如下：</p><p>&nbsp;</p><pre name="code" class="csharp">// esp n, esp+4 i;
// int n = 0;
set eax, 0                               // 01 00 00 00 00
mov *esp, eax                            // 05
// int i = 1;
add esp, 4                               // 07 04 00 00 00
set eax, 1                               // 01 01 00 00 00
mov *esp, eax                            // 05
// :next
// if(i &gt; 100) { goto end; }
mov eax, *esp                            // 02
set ebx, 100                             // 03 64 00 00 00
gt                                       // 11
if eax jmb &lt;end&gt;                         // 21 1B 00 00 00
// n += i;
mov ebx *esp                             // 04
add esp, -4                              // 07 FC FF FF FF
 mov eax *esp                             // 02
add eax, ebx                             // 08
mov *esp, eax                            // 05
add esp, 4                               // 07 04 00 00 00
// i++;
mov eax, *esp                            // 02
set ebx, 1                               // 03 01 00 00 00
add eax, ebx                             // 08
mov *esp, eax                            // 05
// goto next;
jmb &lt;next&gt;                               // 22 D9 FF FF FF
// :end
// write(n);
add esp, -4                              // 07 FC FF FF FF
mov eax, *esp                            // 02
out                                      // 31
over                                     // FF</pre><p><br />　　虚拟机的代码不算复杂，VM 类拥有 eax, ebx, esp, eip 等属性，然后有一个函数 Step 提供执行一条指令的功能，在 Step 中，使用一个 switch 来处理不同的指令。之后，运行程序，把上面的汇编代码的字节序列写入 add.bin 文件中，用虚拟机加载，运行，得到结果：5050。</p><p>&nbsp;</p><p>　　在把 Z 转换到汇编的过程中，发现写编译器的话，对于寄存器的使用，是一个很需要考虑的问题，而对于 D 智能提示，只需要分析器就够了，似乎写编译器有一些超出了，不过，既然都写了，就试着先把这个完成吧。</p><p>&nbsp;</p><p>　　下面是源代码和运行截图：</p>
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/153501#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 06 Jan 2008 17:49:12 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/153501</link>
        <guid>http://llf.javaeye.com/blog/153501</guid>
      </item>
      <item>
        <title>点睛文本编码查询 D 语言版</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/152064" style="color:red;">http://llf.javaeye.com/blog/152064</a>&nbsp;
          发表时间: 2007年12月31日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><font face="Arial">　　本软件用于将文本的字符串转换为 Text、Default、Unicode、UTF-8 之间的互相转换，用于文本查询。转换结果使用十六进制表示。</font></p>
<p><font face="Arial">　　D 语言版不需要特殊的运行库支持。相对于 VB5 版增加了允许输入十六进制的功能，相对于 .net 版减少了一些功能。</font></p>
<p><font face="Arial">　　对于我自己来说，这是练习使用 D 语言的一个副产品。</font></p>
<p><font face="Arial">　　程序使用 D 1.015, phobos 和 dfl 开发。</font></p>
<p><font face="Arial">　　在这一次练习中，发现 D 语言使用上可以和 c# 很类似，比如我写的 HexStringCoding 类，从 c# 复制过来，只修改了几个小地方（如增加 cast，去除 unsafe），就可以正常编译并且正常运行。另外，和 c/dll 的集成也不错，使用 WideCharToMultiByte 之类的系统函数还是很方便的。dfl 大体模仿 .net，所以使用起来很方便。</font></p>
<p><font face="Arial">　　不过，问题也不少。</font></p>
<p><font face="Arial">　　比如 bool 类型可以和任何可以转换为 0 和 1 的值进行隐式转换，就是一个语言方面的缺陷。</font></p>
<p><font face="Arial">　　另外，D 语言选择 char[] 当作字符串来处理，也是一个非常不可理解的事情。char[] 被定义为 utf8，所以如果要对它进行随机检索的话，就需要更多的代码和更差的运行效率，在我看来，utf8 根本不适合作为程序内部处理字符串的编码方案。utf16 才适合。另外，没有 string 类，而用数组来代替 string 的做法也问题多多，除了强类型检测之外，string 类还应该提供相应的字符串处理函数，而不是使用全局函数处理字符串。在我做这个程序的时候，是都使用 utf16 的 wchar[] 来做中间的字符串代替品的，不过，dfl 遵循使用 char[] 的方案，所以，和界面交互的部分也做了转换处理。也许以后可以修改一下 dfl 的代码，使之直接使用 utf16 吧。</font></p>
<p><font face="Arial">　　另一个问题是，无法使用 obj == null 来判断一个实例是否为空，这个问题不知道别人有没有遇到，或者有什么别的解决方案，我是通过 try catch 的方式处理了，不过感觉很不爽。</font></p>
<p><font face="Arial">　　另外，还遇到一个问题，基类定义了 abstract 的函数，子类实现了，但是没有使用 override 关键字，编译通过，但是运行结果莫名其妙，加上 override 之后就正常了。这个问题可能造成错误的几率要比上面说的问题大的多，本来，D 应该在这种情况下编译出错才是。</font></p>
<p><font face="Arial">　　再者，D 的 module 组织方式，感觉是在鼓励大家把所有的类写入一个文件中，实在不是一个好的方式。</font></p>
<p><font face="Arial">　　对于 dfl，也稍微说一下，它使用了首字母小写的方式，在我看来，既然模仿 .net，就不如模仿个彻底，让大家把 .net 的程序复制过来后，做最少的修改就能编译运行才好 &mdash;&mdash; 所有首字母改成小写，也是一个不小的工程啊。</font></p>
<p><font face="Arial">　　Tango 的安装步骤很罗嗦，我还没有试过，不过，嗯，回头还是应该试一下的。<br />
</font></p>
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/152064#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 31 Dec 2007 16:07:20 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/152064</link>
        <guid>http://llf.javaeye.com/blog/152064</guid>
      </item>
      <item>
        <title>关于 Sonic_Infobar 的背包错误修正</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/145845" style="color:red;">http://llf.javaeye.com/blog/145845</a>&nbsp;
          发表时间: 2007年12月04日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <font face="Arial"><font face="Arial">
<p><font face="Arial">　　一直都使用 Sonic_Infobar，很小巧，也比较容易定制。最近在 WOW 里练工程，做了一个魔铁工具箱，于是 Sonic_Infobar 报错，我用的是 2.22 版，上 CWDG 看了一下，最新版就是 2.22。</font></p>
<p><font face="Arial">　　本来不太喜欢看插件的程序，一来对于 lua 不熟，另外，好多插件都动不动几十K，上百K，而且很多大函数，看起来比较累。不过看了一下，Sonic_Infobar 的背包部分代码只有大约 4K，于是决定看看。</font></p>
<p><font face="Arial">　　首先看到的是背包类型定义，看到了一段奇怪的定义：</font></p>
<font face="Arial">
<div class="code_title">Lua&nbsp;代码&nbsp;</div>
</font><font face="Arial">
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-rb">
    <li class="alt"><span><span>[</span><span class="string">&quot;附魔包&quot;</span><span>]&nbsp;=&nbsp;{ &nbsp;&nbsp;</span></span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;[1]&nbsp;=&nbsp;</span><span class="string">&quot;魔化魔纹布包&quot;</span><span>, &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;[1]&nbsp;=&nbsp;</span><span class="string">&quot;魔化符文布包&quot;</span><span>, &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;[1]&nbsp;=&nbsp;</span><span class="string">&quot;大附魔袋&quot;</span><span>, &nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>　　开始以为是按索引来区分大小，不过后来觉得不对，看下面的代码，应该只是当数组来用，索引并没有实际意义，这一段代码应该只是复制遗留问题吧，修改为：</p>
<div class="code_title">Lua&nbsp;代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-rb">
    <li class="alt"><span><span>[</span><span class="string">&quot;附魔包&quot;</span><span>]&nbsp;=&nbsp;{ &nbsp;&nbsp;</span></span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;[1]&nbsp;=&nbsp;</span><span class="string">&quot;魔化魔纹布包&quot;</span><span>, &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;[2]&nbsp;=&nbsp;</span><span class="string">&quot;魔化符文布包&quot;</span><span>, &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;[3]&nbsp;=&nbsp;</span><span class="string">&quot;大附魔袋&quot;</span><span>, &nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>　　向下看，发现 SIB_Bag_Update 中对于背包类型定义的使用如下：</p>
<div class="code_title">Lua&nbsp;代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-rb">
    <li class="alt"><span><span class="keyword">for</span><span>&nbsp;index&nbsp;</span><span class="keyword">in</span><span>&nbsp;pairs(specialbag)&nbsp;</span><span class="keyword">do</span><span>&nbsp;&nbsp;</span></span> </li>
</ol>
</div>
<p>　　而这个函数函数中，还有一段：</p>
<div class="code_title">Lua&nbsp;代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-rb">
    <li class="alt"><span><span class="keyword">if</span><span>&nbsp;((index&nbsp;==&nbsp;</span><span class="string">&quot;箭袋&quot;</span><span>)&nbsp;</span><span class="keyword">or</span><span>&nbsp;(index&nbsp;==&nbsp;</span><span class="string">&quot;弹药包&quot;</span><span>))&nbsp;</span><span class="keyword">then</span><span>&nbsp;&nbsp;</span></span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;specialtext&nbsp;=&nbsp;specialtext..</span><span class="string">&quot;(物品:&nbsp;&quot;</span><span>..bagArray[index].item..</span><span class="string">&quot;)&nbsp;&quot;</span><span>; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span></span><span class="keyword">end</span><span>; &nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>　　开始觉得它是少定义了几项，所以造成出错，后来想想，其实不是，这里只是说，箭袋和弹药包才需要显示&ldquo;物品&rdquo;数量而已，而其他的如工具箱、宝石箱之类的，不需要额外显示。</p>
<p><font face="Arial">　　继续向下看，在 SIB_BagCount 函数中，发现：</font><font face="Arial"> </font></p>
<font face="Arial">
<div class="code_title">Lua&nbsp;代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-rb">
    <li class="alt"><span><span class="keyword">if</span><span>&nbsp;((bagtype&nbsp;==&nbsp;</span><span class="string">&quot;碎片包&quot;</span><span>)&nbsp;</span><span class="keyword">or</span><span>&nbsp;(bagtype&nbsp;==&nbsp;</span><span class="string">&quot;草药包&quot;</span><span>)&nbsp;</span><span class="keyword">or</span><span>&nbsp;(bagtype&nbsp;==&nbsp;</span><span class="string">&quot;附魔包&quot;</span><span>)&nbsp;</span><span class="keyword">or</span><span>&nbsp;(bagtype&nbsp;==&nbsp;</span><span class="keyword">nil</span><span>))&nbsp;</span><span class="keyword">then</span><span>&nbsp;&nbsp;</span></span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;returntype&nbsp;=&nbsp;1; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;...... &nbsp;&nbsp;</span> </li>
    <li class=""><span>elseif&nbsp;((bagtype&nbsp;==&nbsp;</span><span class="string">&quot;箭袋&quot;</span><span>)&nbsp;</span><span class="keyword">or</span><span>&nbsp;(bagtype&nbsp;==&nbsp;</span><span class="string">&quot;弹药包&quot;</span><span>))&nbsp;</span><span class="keyword">then</span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;returntype&nbsp;=&nbsp;2; &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;...... &nbsp;&nbsp;</span> </li>
    <li class="alt"><span></span><span class="keyword">end</span><span>; &nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>　　而最后的返回语句是：</p>
<div class="code_title">Lua&nbsp;代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-rb">
    <li class="alt"><span><span class="keyword">if</span><span>&nbsp;(returntype&nbsp;==&nbsp;1)&nbsp;</span><span class="keyword">then</span><span>&nbsp;&nbsp;</span></span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;totalSlots,&nbsp;usedSlots,&nbsp;</span><span class="keyword">nil</span><span>; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>elseif&nbsp;(returntype&nbsp;==&nbsp;2)&nbsp;</span><span class="keyword">then</span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;totalSlots,&nbsp;usedSlots,&nbsp;itemNum; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span></span><span class="keyword">end</span><span>; &nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>　　这就比较清楚了，因为背包定义中定义的类型比较多，而这里没有在条件中出现，造成 lua 自动返回 nil，于是出现使用 nil 值的错误。因此也发现，函数开头的对于参数的判断没有实际意义：</p>
<div class="code_title">Lua&nbsp;代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-rb">
    <li class="alt"><span><span class="keyword">if</span><span>&nbsp;</span><span class="keyword">not</span><span>&nbsp;bag&nbsp;</span><span class="keyword">then</span><span>&nbsp;&nbsp;</span></span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span></span><span class="keyword">end</span><span>; &nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>　　虽然这个函数在这个参数上安全了，但是因为使用它的代码，并没有判断返回值是否为 nil，所以仍然会出错，只是出错的位置不同罢了&hellip;&hellip;</p>
<p><font face="Arial">　　另外，两组计算方法代码几乎完全相同，只是对于箭袋和弹药包，额外计算一个 itemNum 而已，所以理应合并，碎片包、草药包之类都只需要作为 else 的处理部分就可以了。本来想也许需要用闭包来做，不过马上就发现，不需要那么复杂，只要判断 itemNum 是不是 nil 就可以了。于是整个函数修改如下：</font></p>
<font face="Arial">
<div class="code_title">Lua&nbsp;代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-rb">
    <li class="alt"><span><span>function&nbsp;SIB_BagCount(bag,&nbsp;bagtype) &nbsp;&nbsp;</span></span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;local&nbsp;itemNum&nbsp;=&nbsp;</span><span class="keyword">nil</span><span>; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;((bagtype&nbsp;==&nbsp;</span><span class="string">&quot;箭袋&quot;</span><span>)&nbsp;</span><span class="keyword">or</span><span>&nbsp;(bagtype&nbsp;==&nbsp;</span><span class="string">&quot;弹药包&quot;</span><span>))&nbsp;</span><span class="keyword">then</span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;itemNum&nbsp;=&nbsp;0; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">end</span><span>; &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;local&nbsp;totalSlots&nbsp;=&nbsp;0; &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;local&nbsp;usedSlots&nbsp;=&nbsp;0; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;local&nbsp;size&nbsp;=&nbsp;GetContainerNumSlots(bag); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(size&nbsp;</span><span class="keyword">and</span><span>&nbsp;size&nbsp;&gt;&nbsp;0)&nbsp;</span><span class="keyword">then</span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;totalSlots&nbsp;=&nbsp;totalSlots&nbsp;+&nbsp;size; &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">for</span><span>&nbsp;slot&nbsp;=&nbsp;1,&nbsp;size&nbsp;</span><span class="keyword">do</span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(GetContainerItemInfo(bag,&nbsp;slot))&nbsp;</span><span class="keyword">then</span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;usedSlots&nbsp;=&nbsp;usedSlots&nbsp;+&nbsp;1; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;itemNum&nbsp;</span><span class="keyword">then</span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local&nbsp;_,&nbsp;itemNumberCount&nbsp;=&nbsp;GetContainerItemInfo(bag,&nbsp;slot); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;itemNum&nbsp;=&nbsp;itemNum&nbsp;+&nbsp;itemNumberCount; &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">end</span><span>; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">end</span><span>; &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">end</span><span>; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">end</span><span>; &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;totalSlots,&nbsp;usedSlots,&nbsp;itemNum; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span></span><span class="keyword">end</span><span>&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p><br />
　　本来，这个问题应该写到 CWDG 的论坛相关帖子里去的，不过，CWDG 很奇怪，不注册不允许回帖不说，还不允许下载插件，而又不开放注册，需要推荐才行，感觉怪怪的，所以算了。</p>
<p><font face="Arial">　　对于&ldquo;小刺猬&rdquo;写的这个小巧而又好用的插件，还是很应该感谢一下的 <img src="/javascripts/fckeditor/editor/images/smiley/msn/regular_smile.gif" alt="" /></font></p>
</font></font></font></font></font>
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/145845#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 04 Dec 2007 13:34:22 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/145845</link>
        <guid>http://llf.javaeye.com/blog/145845</guid>
      </item>
      <item>
        <title>.Net 3.5 的扩展方法</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/144544" style="color:red;">http://llf.javaeye.com/blog/144544</a>&nbsp;
          发表时间: 2007年11月28日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><font face="Arial">　　原本，我听说 Partial Class 的时候，以为可以为已存在的类添加方法了，不过，Partial Class 只能在同一个 Assembly 之中的要求，使得它并不能实现这一点。.Net 3.5 增加了很多语言特性，扩展方法是其中一个。用扩展方法，我们就可以为已经存在的类添加方法。</font></p>
<div class="code_title">c# 代码</div>
<font face="Arial">
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-c">
    <li class="alt"><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;ExtendTest &nbsp;&nbsp;</span></span> </li>
    <li class=""><span>{ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;Print(</span><span class="keyword">this</span><span>&nbsp;</span><span class="keyword">object</span><span>&nbsp;o) &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(o); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>　　之后，就可以对于任意的 object 使用这个方法：</p>
<font face="Arial">
<div class="code_title">c# 代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-c">
    <li class="alt"><span><span class="keyword">string</span><span>&nbsp;s&nbsp;=&nbsp;</span><span class="string">&quot;hello&quot;</span><span>; &nbsp;&nbsp;</span></span> </li>
    <li class=""><span>s.Print(); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span></span><span class="string">&quot;X&quot;</span><span>.Print(); &nbsp;&nbsp;</span> </li>
    <li class=""><span>MyClass&nbsp;x&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;MyClass(); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>x.Print();&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>　　对于扩展方法的创建，基本上，只有两点记住就可以了：必须是静态方法，第一个参数增加 this 关键字。</p>
<p><font face="Arial">　　用 Reflector 查看了一下，和我的猜测基本一致，其实它的实现是使用的自定义属性，所以扩展方法基本上可以看成是编译器特性：</font></p>
<font face="Arial">
<div class="code_title">c# 代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-c">
    <li class="alt"><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;ExtendTest &nbsp;&nbsp;</span></span> </li>
    <li class=""><span>{ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;[&nbsp;Extend&nbsp;] &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;Print(</span><span class="keyword">object</span><span>&nbsp;o) &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(o); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class=""><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>　　扩展方法很好用，使用上确实可以和动态语言像 Python、Ruby 之类的相比了。不过，毕竟 C# 是静态语言，扩展方法还是有一些限制的。</p>
<p><font face="Arial">　　一个限制是：不能使用原有类的私有或保护成员。这个问题，怎么说呢，大部分情况下没有问题，不过如果真的想使用私有或保护成员的时候，会很头疼。如果要给 .Net framework 中的类添加方法，这个问题也许并不是太大吧，毕竟一般我们也只知道它们的公有成员。如果要给自己的 DLL 添加一个新的 DLL，也做到原有 DLL 用于 .Net 2.0，新 DLL 扩展原 DLL 的话，比较会遇到。我在 <a href="http://www.codeplex.com/dbentry">DbEntry.Net</a> 中对于这个问题的解决方案是，使用友元程序集。这种方法还是需要修改原 DLL，添加新 DLL 为友元程序集，另外，将需要访问的成员标注为 internal 才行。</font></p>
<p><font face="Arial">　　另一个限制：不能给一个类添加静态方法。不知道是不是我没有找到，反正感觉，本来就是静态方法了，怎么才能再标注为实现静态方法呢？难道用 static static ？当然，使用的场景应该也不多吧。</font></p>
<p><font face="Arial">　　再一个限制：不能给一个类添加接口。这个么，本来就不是扩展方法的设计目标，而且，实现上似乎也会麻烦很多，所以本来不该抱怨，不过，如果能实现的话，确实会有很多地方会很方便。比如，如果能给 DbObjectModel 添加 IQueryable 接口，就可以只通过增加一个 using 而实现所有的 Linq 功能，而有这个限制的时候，只能再实现一个 LinqDbObjectModel 之类的了&hellip;&hellip;</font></p>
<p><font face="Arial">　　我发现的，就这3个限制，其它方面，都实现的很好，IDE 提示也很舒服 <img src="/javascripts/fckeditor/editor/images/smiley/msn/teeth_smile.gif" alt="" /><br />
</font></p>
</font><font face="Arial"></font></font><font face="Arial"></font></font>
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/144544#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 28 Nov 2007 15:47:40 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/144544</link>
        <guid>http://llf.javaeye.com/blog/144544</guid>
      </item>
      <item>
        <title>VS2008</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/144473" style="color:red;">http://llf.javaeye.com/blog/144473</a>&nbsp;
          发表时间: 2007年11月28日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><font face="Arial">　　刚见到VS2008要在11月底发布的消息，有些反感，本来该出RC的时候，怎么就Release了？我都不急，微软急什么？</font></p>
<p><font face="Arial">　　结果，还只是月中，VS2008就宣布发布，而且MSDN开始提供下载。而Scott的Blog上介绍的时候，还说，Silverlight 1.1的什么插件还没有能支持VS2008 Release版，需要额外的一周时间；这两天，又说本来预计上星期（和 VS2008 同时）发布的 VSS 2005 对于 VS2008 支持的兼容包因为临时发现一个BUG，所以推迟发布&hellip;&hellip;</font></p>
<p><font face="Arial">　　当年 VS2005 自带 SQL 2005 Express，既然明年二月也会出 SQL 2008，VS 2008 自然应该自带 SQL 2008 Express，结果只自带了一个 SqlCE 3.5，根本不是一码事嘛。别说存储过程，连语法都不同，要写 SQL Server 的程序还是需要用 SQL Server 2005。或者微软觉得 VS 本来就不该附带 Sql Server 吧。</font></p>
<p><font face="Arial">　　不过，牢骚归牢骚，微软既然说这就是最终版，那么它就是，至于以后会不会有 VS 2008 SP1，那是后事了。</font></p>
<p><font face="Arial">　　于是下载安装，正好看到 Scott 的文章说到我比较关心的 Team Explorer 2008 访问 TFS 2005 的事，说是完全没有问题，于是比较放心，安装后连接 CodePlex 试了一下，完全和以前一样，包括以前一个 TE 2005 留下的本地文件版本的 BUG 都保留了，不过基本上是个视觉系 BUG &mdash;&mdash; 碍眼不碍事，所以倒也没有什么问题。既然测试了在这一方面没有问题，也卸载了 VS 2005。</font></p>
<p><font face="Arial">　　升级 <a href="http://www.codeplex.com/dbentry">DbEntry.Net</a> 的时候，发现有两个项目没有设置 .Net Framework 版本，这个问题比较奇怪，不过，自己设置一下也就是了。编译，运行单元测试，完全通过，嗯，感觉还是不错滴。</font></p>
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/144473#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 28 Nov 2007 12:50:14 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/144473</link>
        <guid>http://llf.javaeye.com/blog/144473</guid>
      </item>
      <item>
        <title>DbEntry.Net v0.33</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/137882" style="color:red;">http://llf.javaeye.com/blog/137882</a>&nbsp;
          发表时间: 2007年11月04日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><font face="Arial">　　这是我设计的一个轻量级的 .Net ORM (Object Relational Mapping) 数据访问及 WEB 框架。对于 ORM 和 Sql 调用，它都拥有清晰和易用的接口，目前支持 SqlServer、SQLite、MySql、Access、Firebird、Oracle 等数据库。对于 WEB 开发，它既支持 ASP.NET 2.0 的 DataSource 方式，也支持 Ruby On Rails 风格的 MVC 方式。</font></p>
<p><font face="Arial">　　目前，数据库部分已经支持多主键、多表联合查询、快速分页集合、隐式数据库事务、连贯API查询、ActiveRecord风格查询、动态对象、部分保存、自动创建数据表、一对一、一对多、多对多关系等功能，具体实现请参阅 Samples 中的例子程序和单元测试的内容。</font></p>
<p><font face="Arial">　　而 DataSource 部分，因为绑定数据访问组件，所以可以只需要修改配置文件，不需要修改任何代码的在不同的数据库之间切换。另外，还支持按命名约定的方式绑定&ldquo;新建&rdquo;和&ldquo;编辑&rdquo;页面的控件，以最少的代码完成输入、验证、保存等一系列操作。</font></p>
<p><font face="Arial">　　Rails 风格的 MVC 框架目前已经完成 MVC 部分，脚手架，基类中的 LinkTo、UrlTo 等快捷函数，Http Get 支持等。目前脚手架部分没有数据验证模块，不过，自己写的 MVC 代码可以自行实现验证。</font></p>
<p><font face="Arial">　　例子程序访问的数据库主要是 Access，而单元测试使用的数据库是 SQLite，通过修改配置文件中数据源部分，可以使之不需要重新编译即可工作于其它数据库上。配置部分通过 App.config 进行，请参阅 Samples 中的例子程序中的 App.config 和 UnitTest 项目内嵌的配置文件 UnitTest.config.xml 。</font></p>
<p><font face="Arial">　　我在 MS Sql Server 2000、MS Sql Server 2005 Express、 MS Access 2003、MySql 5.0、SQLite 3、Firebird 2.0.3 和 Oracle 10g Express 上测试过本组件。</font></p>
<p><font face="Arial">　　v0.33 版比较大的改变为：<br />
　　&middot;支持移除一对多、多对多关系<br />
　　&middot;支持 Firebird、Oracle<br />
　　&middot;增加缓存系统<br />
　　&middot;支持 SoftDelete、CreatedOn、UpdatedOn<br />
　　&middot;支持 ASP.NET 2.0 Membership 系统<br />
　　&middot;DataSource 支持&ldquo;新建&rdquo;和&ldquo;编辑&rdquo;页面<br />
　　&middot;Rails 风格 MVC 框架</font></p>
<p><font face="Arial">　　数据访问部分</font>简单的使用方法如下：</p>
<div class="code_title">c# 代码</div>
<font face="Arial">
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-c">
    <li class="alt"><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">abstract</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;User&nbsp;:&nbsp;DbObjectModel &lt; User &gt;</span></span> </li>
    <li class=""><span>{ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">abstract</span><span>&nbsp;</span><span class="keyword">string</span><span>&nbsp;Name&nbsp;{&nbsp;</span><span class="keyword">get</span><span>;&nbsp;</span><span class="keyword">set</span><span>;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">abstract</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;Age&nbsp;{&nbsp;</span><span class="keyword">get</span><span>;&nbsp;</span><span class="keyword">set</span><span>;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">abstract</span><span>&nbsp;</span><span class="keyword">bool</span><span>&nbsp;Gender&nbsp;{&nbsp;</span><span class="keyword">get</span><span>;&nbsp;</span><span class="keyword">set</span><span>;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">abstract</span><span>&nbsp;DateTime&nbsp;Birthday&nbsp;{&nbsp;</span><span class="keyword">get</span><span>;&nbsp;</span><span class="keyword">set</span><span>;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;User&nbsp;Init(</span><span class="keyword">string</span><span>&nbsp;Name,&nbsp;</span><span class="keyword">int</span><span>&nbsp;Age,&nbsp;</span><span class="keyword">bool</span><span>&nbsp;Gender,&nbsp;DateTime&nbsp;Birthday) &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">this</span><span>.Name&nbsp;=&nbsp;Name; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">this</span><span>.Age&nbsp;=&nbsp;Age; &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">this</span><span>.Gender&nbsp;=&nbsp;Gender; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">this</span><span>.Birthday&nbsp;=&nbsp;Birthday; &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;</span><span class="keyword">this</span><span>; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class=""><span>} &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span></span><span class="keyword">class</span><span>&nbsp;Program &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>{ &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;Main(</span><span class="keyword">string</span><span>[]&nbsp;args) &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Create </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;User&nbsp;u&nbsp;=&nbsp;User.New().Init(</span><span class="string">&quot;tom&quot;</span><span>,&nbsp;18,&nbsp;</span><span class="keyword">true</span><span>,&nbsp;DateTime.Now); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u.Save(); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Read </span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;User&nbsp;u1&nbsp;=&nbsp;User.FindById(u.Id); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Update </span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u1.Name&nbsp;=&nbsp;</span><span class="string">&quot;jerry&quot;</span><span>; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u1.Save(); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Delete </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u1.Delete(); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Complex&nbsp;Query </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt; User &gt;<user></user>&nbsp;ls&nbsp;=&nbsp;User.Find(CK.K[</span><span class="string">&quot;Age&quot;</span><span>]&nbsp;&gt;&nbsp;15&nbsp;&amp;&amp;&nbsp;CK.K[</span><span class="string">&quot;Gender&quot;</span><span>]&nbsp;==&nbsp;</span><span class="keyword">true</span><span>); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Use&nbsp;Sql </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt; User &gt;<user></user>&nbsp;ls1&nbsp;=&nbsp;User.FindBySql( &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="string">&quot;Select&nbsp;*&nbsp;From&nbsp;[User]&nbsp;Where&nbsp;[Age]&nbsp;&gt;&nbsp;15&nbsp;And&nbsp;[Gender]&nbsp;=&nbsp;true&quot;</span><span>); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class=""><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>　　请访问 <a href="http://www.codeplex.com/dbentry">http://www.codeplex.com/dbentry</a> 下载本组件。使用文档也在 codeplex&nbsp;dbentry&nbsp;主页的 Wiki&nbsp;上。</p>
</font><font face="Arial"><br />
</font>
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/137882#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 04 Nov 2007 14:09:16 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/137882</link>
        <guid>http://llf.javaeye.com/blog/137882</guid>
      </item>
      <item>
        <title>逗到我了</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/132978" style="color:red;">http://llf.javaeye.com/blog/132978</a>&nbsp;
          发表时间: 2007年10月17日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>刚在 C++ 博客上看到一篇中文编程的<a href="http://www.cppblog.com/ly4cn/archive/2007/10/17/34476.html">小文</a>，逗到我了，摘录一段：</p>
<span style="COLOR: #000000">
<div class="code_title">cpp 代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-cpp">
    <li class="alt"><span><span class="preprocessor">#define&nbsp;趁还&nbsp;while </span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span></span><span class="preprocessor">#define&nbsp;那个啥&nbsp;int </span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="preprocessor">#define&nbsp;总的来说&nbsp;main </span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span></span><span class="preprocessor">#define&nbsp;买&nbsp;cin </span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="preprocessor">#define&nbsp;卖&nbsp;cout </span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span></span><span class="preprocessor">#define&nbsp;进&nbsp;&gt;&gt; </span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="preprocessor">#define&nbsp;出&nbsp;&lt;&lt; </span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span></span><span class="preprocessor">#define&nbsp;拜拜了&nbsp;return </span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="preprocessor">#define&nbsp;去掉&nbsp;-= </span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span></span><span class="preprocessor">#define&nbsp;等于&nbsp;= </span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="preprocessor">#define&nbsp;屁&nbsp;100e4 </span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span></span><span class="preprocessor">#define&nbsp;我说&nbsp;( </span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="preprocessor">#define&nbsp;是吧&nbsp;) </span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span></span><span class="preprocessor">#define&nbsp;啊&nbsp;a </span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="preprocessor">#define&nbsp;那么就&nbsp;{ </span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span></span><span class="preprocessor">#define&nbsp;得了&nbsp;} </span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="preprocessor">#define&nbsp;呀&nbsp;; </span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span></span><span class="preprocessor">#include&nbsp;&lt;iostream&gt; </span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="keyword">using</span><span>&nbsp;</span><span class="keyword">namespace</span><span>&nbsp;std; &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>那个啥&nbsp;总的来说&nbsp;我说&nbsp;那个啥&nbsp;啊&nbsp;是吧 &nbsp;&nbsp;</span></li>
    <li class=""><span>那么就&nbsp;那个啥&nbsp;有钱&nbsp;等于&nbsp;屁&nbsp;呀 &nbsp;&nbsp;</span></li>
    <li class="alt"><span>趁还&nbsp;我说&nbsp;有钱&nbsp;是吧&nbsp;&nbsp;&nbsp;&nbsp;那么就 &nbsp;&nbsp;</span></li>
    <li class=""><span>那个啥&nbsp;多少&nbsp;呀&nbsp;买&nbsp;进&nbsp;多少&nbsp;呀&nbsp;卖&nbsp;出&nbsp;多少&nbsp;呀&nbsp;有钱&nbsp;去掉&nbsp;多少&nbsp;呀 &nbsp;&nbsp;</span></li>
    <li class="alt"><span>卖&nbsp;出&nbsp;多少&nbsp;呀&nbsp;得了 &nbsp;&nbsp;</span></li>
    <li class=""><span>拜拜了&nbsp;啊&nbsp;呀&nbsp;得了 &nbsp;&nbsp;</span></li>
</ol>
</div>
</span>
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/132978#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 17 Oct 2007 21:21:46 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/132978</link>
        <guid>http://llf.javaeye.com/blog/132978</guid>
      </item>
      <item>
        <title>没有 TOP 又如何</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/126209" style="color:red;">http://llf.javaeye.com/blog/126209</a>&nbsp;
          发表时间: 2007年09月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><font face="Arial">　　</font>在 <font face="Arial"><a href="http://llf.javaeye.com/blog/123999">玩了一会儿 SQL Server Compact 3.5</a>&nbsp;里，我说，因为 SQL Server Compact 3.5 因为连 TOP 都不支持，所以会很慢。不过，这两天想了一下，可能是我小题大作了。</font></p>
<p><font face="Arial">　　</font>其实在数据库内部，应该是不论使用 TOP 与否，第一次查询都要进行的，而只要我们不进行读取，就和数据库没有返回它差不多，那么有没有 TOP 的关系应该倒是不大。</p>
<p><font face="Arial">　　</font>另外，对于像 SQL Compact 这样的文件型数据库来说，所谓的驱动程序就是一个动态链接库，也就是所有的操作都是在同一个进程中的，所以移动游标的开销也很小，差别只是在于，是我们来执行跳过前面这些记录的工作，还是驱动程序来做。没有起始定位符，对于速度的影响也不会太大吧。</p>
<p><font face="Arial">　　</font>所以，还好。</p>
          <br/>
          <span style="color:red;">
            <a href="http://llf.javaeye.com/blog/126209#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 22 Sep 2007 22:34:18 +0800</pubDate>
        <link>http://llf.javaeye.com/blog/126209</link>
        <guid>http://llf.javaeye.com/blog/126209</guid>
      </item>
      <item>
        <title>TestDriven.Net 的 BUG 一枚</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://llf.javaeye.com/blog/125105" style="color:red;">http://llf.javaeye.com/blog/125105</a>&nbsp;
          发表时间: 2007年09月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><font face="Ari