<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title> D语言</title>
    <description>D 语言既有 C 语言的强大威力，又有 Python 和 Ruby 的开发效率。它是一种集垃圾回收、C 语言内存模型、契约式设计、强力范型、内嵌汇编、内置单元测试、Mixin、类 Java 包管理机制、内置同步机制、内建基本运行时信息的系统级编程语言。
初学者推荐学习 使用 1.0 系列最新版。</description>
    <link>http://dlang.group.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>Tango 0.99.7 Dominik 今天放出</title>
        <author>oldrev</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://oldrev.javaeye.com">oldrev</a>&nbsp;
          链接：<a href="http://dlang.group.javaeye.com/group/blog/219633" style="color:red;">http://dlang.group.javaeye.com/group/blog/219633</a>&nbsp;
          发表时间: 2008年07月25日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>详细的发布公告：<br />
<a href="http://www.dsource.org/projects/tango/wiki/0_99_7_release">http://www.dsource.org/projects/tango/wiki/0_99_7_release</a>
<br />
最要紧的改进莫过于添加了新的 container 包了，不知是 tango.util.container 还是 tango.util.collection？</p>
          <br/>
          <span style="color:red;">
            <a href="http://dlang.group.javaeye.com/group/blog/219633#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, 25 Jul 2008 12:16:00 +0800</pubDate>
        <link>http://dlang.group.javaeye.com/group/blog/219633</link>
        <guid>http://dlang.group.javaeye.com/group/blog/219633</guid>
      </item>
      <item>
        <title>arcLib学习笔记——动画和绘图</title>
        <author>redduke</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://redduke.javaeye.com">redduke</a>&nbsp;
          链接：<a href="http://dlang.group.javaeye.com/group/blog/200707" style="color:red;">http://dlang.group.javaeye.com/group/blog/200707</a>&nbsp;
          发表时间: 2008年06月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>从上一篇继续</p>
<p>&nbsp;</p>
<p>首先还是需要创建Sprite和Frame&nbsp; animationImage是图像路径（char[]）</p>
<p>&nbsp;</p>
<pre name="code" class="java">animationFrame = new Frame(Texture(animationImage), Rect(70,496,70,124));</pre>
<p>
<br />
Rect的四个参数（起始点X坐标，起始点Y坐标，宽度，高度）单位：像素<br /></p>
<pre name="code" class="java">private LinearAnimation animation;
animation = new LinearAnimation(animationFrame, 4, 200, LinearAnimation.Direction.ForwardLoop);</pre>
<p>
<br />
LinearAnimation四个参数（图像，动画帧数，播放速度，播放方式）</p>
<p>&nbsp;</p>
<p>把创建的动画链接到精灵&nbsp; 播放它</p>
<p>&nbsp;</p>
<pre name="code" class="java">sprite.addChild(animation.start());</pre>
<p>&nbsp;</p>
<p>动画基本就是这样子</p>
<p><br />
另外如果只需要绘制静态图像&nbsp; 不进行复杂运算&nbsp; 可以直接写</p>
<pre name="code" class="java">drawImage(Texture(image), Point(200,200), Size(400,400), Point(0,0), 0, Color.White);</pre>
&nbsp;
          <br/>
          <span style="color:red;">
            <a href="http://dlang.group.javaeye.com/group/blog/200707#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, 05 Jun 2008 22:18:46 +0800</pubDate>
        <link>http://dlang.group.javaeye.com/group/blog/200707</link>
        <guid>http://dlang.group.javaeye.com/group/blog/200707</guid>
      </item>
      <item>
        <title>一个生成伪log的程序……</title>
        <author>RednaxelaFX</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://rednaxelafx.javaeye.com">RednaxelaFX</a>&nbsp;
          链接：<a href="http://dlang.group.javaeye.com/group/blog/194405" style="color:red;">http://dlang.group.javaeye.com/group/blog/194405</a>&nbsp;
          发表时间: 2008年05月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          有个朋友让我帮忙写个伪log的生成器。他提供了一个源log文件和一个配置文件，要每隔一段时间就向一个指定的路径上的log文件添加一些新生成的log。<br /><br />要求是：<br />1、从配置文件读入参数，根据配置来决定时间间隔与输出log的路径；<br />2、从源log文件得到生成log的材料；<br />3、随机从源log里挑选几行出来，把它开头的时间信息替换成当前时间；<br />4、以固定的时间间隔向目标路径添加新生成的log，并要求不在log文件的末尾生成空行。<br /><br />配置文件类似这样：<br />RT_Config.inc：<br /><pre name="code" class="java">[system]
//log format
Format=NCSA
//log of the dat
FileName=D:\temp\today.log
//port
Listen_Port=8000
//server IP
IP=127.0.0.1
//server port
Server_port=9000
//time interval (in SECs)
Time_Interval=20</pre><br /><br />然后源log文件类似这样（截取几行）：<br /><pre name="code" class="java">2008-03-31 00:00:19 10.11.14.56 - 10.11.1.9 80 GET /acip/shownewsh.asp - 200 Mozilla/4.0+(compatible;+MSIE+6.0;+Windows+NT+5.1;+SV1)
2008-03-31 00:00:20 10.11.14.56 - 10.11.1.9 80 GET /acip/images/Delighting+you+always+(Red)+789x382.gif - 304 Mozilla/4.0+(compatible;+MSIE+6.0;+Windows+NT+5.1;+SV1)
2008-03-31 00:00:47 10.11.10.81 - 10.11.1.9 80 GET /acip/shownewsh.asp - 200 Mozilla/4.0+(compatible;+MSIE+6.0;+Windows+NT+5.0)
2008-03-31 00:01:31 10.11.50.67 - 10.11.1.9 80 GET /acip/shownewsh.asp - 200 Mozilla/4.0+(compatible;+MSIE+6.0;+Windows+NT+5.1;+SV1)
2008-03-31 00:01:36 10.11.46.90 - 10.11.1.9 80 GET /acip/shownewsh.asp - 200 Mozilla/4.0+(compatible;+MSIE+6.0;+Windows+NT+5.1;+SV1)
2008-03-31 00:01:38 10.11.44.64 - 10.11.1.9 80 GET /eis/Report/Executive+Information+System - 404 Mozilla/4.0+(compatible;+MSIE+6.0;+Windows+NT+5.0)</pre><br />其实就是IIS生成的一些log而已。<br /><br />他还提出了额外的要求：最好在运行程序的机器上不需要额外安装什么runtime，于是排除掉了Java和C#，以及Perl、Ruby等语言；虽然Java可以GCJ到native，Ruby也可以通过rubyscript2exe来生成带有Ruby解释器的独立exe文件，但它们生成出来的exe都太大了，也排除；C和C++都不够方便，我不太想在这种小程序上用。所以最后我选择了用D来写这个小程序。<br /><br />===========================================================================<br /><br />于是问题可以分解为几个小问题，主要是：<br />1、从配置文件读入配置；<br />2、拼接出新的log：获取当前时间并格式化到合适的格式上，然后与源log拼接起来；<br />3、按固定的时间间隔重复执行写出log的动作。<br /><br />---------------------------------------------------------------------------<br /><br />第一个问题很好办。我的解决办法是把整个配置文件读进来，分解成行，然后对每行做匹配，把配置文件里的key-value对保存到D语言提供的关联数组里。<br /><pre name="code" class="java">char[char[]] config; // 配置参数</pre><br />这样声明了一个char[] => char[]的关联数组。注意到D里char[]就是字符串了。<br /><br />在对行做匹配时，我用了三个正则表达式：<br /><pre name="code" class="java">RegExp commentPattern = RegExp(r"^//.*");
RegExp sectionPattern = RegExp(r"^\[[^\]]+\]");
RegExp keyValuePattern = RegExp(r"(.+)=(.+)");</pre><br />第一个正则表达式用于匹配行首为"//"的行。如果匹配则忽略掉该行。这其实是偷懒了——我没有去匹配在行尾的行注释，因为如果配置文件里出现引号包围的字符串，而字符串的正常内容含有"//"的话，直接用r"//.*$"会把不应该认为是注释的东西也包含进去……这里需要更多的处理，但是我懒得做了。直接规定用户必须把注释符号写在行首就是。<br /><br />第二个正则表达式用于匹配配置文件里的段标记。如果匹配则同注释一样，忽略掉该行。<br /><br />第三个正则表达式用于验证配置文件的行是否符合key=value的形式。如果符合，则将key-value对保存到关联数组里。<br /><br />源log文件也同样，整个文件读进来，然后分解为行，保存起来。<br /><pre name="code" class="java">char[][] source; // 源log的数据</pre><br /><br />---------------------------------------------------------------------------<br /><br />第二个问题在D的标准库Phobos的支持下也很好办。特别是当D的字符串是基于char[]，也就是说是一个动态数组，用起来很方便。<br />先要得到当前的系统时间。std.date包里有足够的函数来解决这问题。用std.date.getUTCtime()获取当前时间后，用XXXFromTime()的几个函数把时间转换为字符串，然后用std.string.format()以指定的格式将它们拼接起来。<br />得到当前时间的字符串之后，随机从源log里选一行出来，把当前时间与去除掉时间的源log拼起来就行。<br /><br />---------------------------------------------------------------------------<br /><br />第三个问题比较讨厌。要按照固定的时间间隔来做些事情的话，Java、C#高级语言和JavaScript等脚本语言都提供了直接能用的timer机制，但C/C++的层次上则没有直接能用的timer，D的Phobos也没有。换言之我们要自己实现定时器。有两种思路：<br />1、busy wait<br />2、sleep and wait<br /><br />busy wait就是例如while(true)然后在里面检查时间间隔是不是大于或等于规定值，满足条件的时候执行动作<br />sleep and wait是在每次执行完动作之后让自己（一个线程）休眠一定时间，等“醒来”的时候再执行一次动作，再休眠，如此循环。<br /><br />很明显busy wait是很糟糕的选择——它不停的循环，什么事都不做却占着CPU。但是这种做法在C/C++里却很常见。或许大家都很无奈吧 = =<br />刚才经过隔壁宿舍的的时候看到了一本叫做《C游戏编程从入门到精通》的书，顺手翻了翻，读到了它（还是说是Andre LaMothe？）提供的控制时间延迟的函数：<br /><pre name="code" class="c">void Delay(int clicks)
{
unsigned int far *clock=(unsigned int far *)0x0000046CL;
unsigned int now;
now=*clock;
while(abs(*clock-now)&lt;clicks){}
}</pre><br />噢天哪。居然用上了内存到寄存器的地址映射——也就是说直接从寄存器读了当前的clock tick。这比用系统API更“糟糕”了，不采用。这本书居然是在2000年之后才出的，好神奇啊 =v=<br />（“糟糕”不是说这代码不好。事实上总是得有这样的代码存在于某处，一般是在库里，像是说操作系统的API会有这样的函数的实现。不过某个寄存器到底映射到的地址对平台的依赖性太大了，我们最好不要自己的*应用程序*里直接用……）<br /><br />sleep and wait则需要库的支持。在C/C++/D里，没有办法不依赖于平台来做这件事。不过依赖就依赖吧诶，总比busy wait好。在D的官网论坛上有人写了一个还不错的实现：<a href="http://www.digitalmars.com/d/archives/digitalmars/D/learn/Implementing_a_timer_using_threads_6170.html" target="_blank">http://www.digitalmars.com/d/archives/digitalmars/D/learn/Implementing_a_timer_using_threads_6170.html</a><br />下面的代码里就使用了那帖里的Timer。<br /><br />===========================================================================<br /><br />说起来，我没写如何让这程序退出的逻辑……要退出就要强制结束进程了 =v=<br />另外我没有检查目标log的路径是否存在，如果路径上的目录不存在的话程序也会出错。这个得递归的调用mkdir才好解决，懒得做……<br />用来编译的环境是DMD D 1.028。<br />好吧，其它也没什么了，完整的程序如下：<br /><br />loggen.d<br /><pre name="code" class="java">import std.conv;
import std.date;
import std.file;
import std.path;
// import std.random; // for rand()
import std.regexp;
import std.stdio;
import std.string;

import std.c.stdlib;
import std.c.time;

static const char[] CONFIG_FILENAME = "./RT_Config.inc";
static const char[] LOG_SOURCE_FILENAME = "./record.log";
static const int FOREVER = -1;

char[][char[]] config; // configuration data
int timeInterval;      // time interval
char[] logFileName;    // destination log file's name
char[][] source;       // source log contents

// Load the configuration data,
// and set time interval/destination filename
bool loadConfig() {
    char[] file = cast(char[])read(CONFIG_FILENAME);
    if(file == null) return false;
    char[][] lines = splitlines(file);

    RegExp commentPattern = RegExp(r"^//.*");
    RegExp sectionPattern = RegExp(r"^\[[^\]]+\]");
    RegExp keyValuePattern = RegExp(r"(.+)=(.+)");
    foreach (char[] line; lines) {
        if (commentPattern.test(line)) continue; // skip comments
        if (sectionPattern.test(line)) continue; // skip section tags
        if (keyValuePattern.test(line)) {
            config[toupper(keyValuePattern.match(1))] = keyValuePattern.match(2);
        }
    }

    timeInterval = toInt(config["TIME_INTERVAL"]);
    logFileName = config["FILENAME"];

    return true;
}

// Load the source log contents
bool loadSource() {
    char[] file = cast(char[])read(LOG_SOURCE_FILENAME);
    if(file == null) return false;
    source = splitlines(file);

    return true;
}

// get a random number in the range [min, max)
// min and max should be a positive integer
int random(int min, int max) {
    int rand = std.c.stdlib.random(20);
    while (rand &lt; 5) rand = std.c.stdlib.random(20);
    return rand;
}

// get a string representation of the current system time
// in the format "YYYY-MM-DD hh:mm:ss"
char[] getCurrentTimeString() {
    d_time lNow = std.date.getUTCtime();
    return std.string.format("%04d-%02d-%02d "
             ~ std.date.toTimeString(lNow)[0..$-9],
               YearFromTime(lNow),
               MonthFromTime(lNow),
               DateFromTime(lNow));
}

// generate a line of dummy log
char[] getLogLine() {
    int rand = std.c.stdlib.random(source.length);
    return getCurrentTimeString() ~ source[rand][19..$];
}

// exit the program abnormally
void abort(char[] message) {
    writefln("Error: " ~ message);
    exit(1);
}

/*
// execute an action repeatly with specified time interval
// busy wait version
void repeat(void delegate() action, int interval, int limit) {
    if (action == null) return;
    if (interval &lt; 0) return;

    time_t old = time(null);
    while (limit != 0) {
        time_t now = time(null);
        if (now >= old + interval) {
            old = now;
            action();
            --limit;
        }
    }
}
*/

// execute an action repeatly with specified time interval
// sleep-and-wait version
// TODO: fix the limit param...
void repeat(void delegate() action, int interval, int limit) {
    Timer timer = new Timer(interval, action, (limit &lt; 0));
    timer.start();
    timer.wait();
}

// program entry point
void main(char[][] args) {
    // load configuration
    if (!loadConfig()) abort("invalid configuration file.");

    // load source log
    if (!loadSource()) abort("invalid source log file.");

    // append a few lines of log first
    int r = random(5, 20);
    // append generated log to destination
    for (int i = 0; i &lt; r; ++i) {
        if (exists(logFileName) && isfile(logFileName)) {
            append(logFileName, newline ~ getLogLine());
        } else { // destinatin log file doesn't exist, create one
            // TODO: check and create directories on the path
            // write log's header comment
            write(logFileName,
                  "#Software: Microsoft Internet Information Services 5.0" ~ newline
                ~ "#Version: 1.0" ~ newline
                ~ "#Date: 2008-03-31 00:00:19" ~ newline
                ~ "#Fields: date time c-ip cs-username s-ip s-port cs-method"
                ~ " cs-uri-stem cs-uri-query sc-status cs(User-Agent)" ~ newline);
            // write first line of log content
            append(logFileName, getLogLine());
        }
    }

    // append new log to destination, in specified time interval
    repeat(delegate() {
        // get a random number in the range [5, 20)
        r = random(5, 20);
        // append generated log to destination
        for (int i = 0; i &lt; r; ++i) {
            append(logFileName, newline ~ getLogLine());
        }
    }, timeInterval, FOREVER);
}

//===============================================================
// Timer, written by Dennis Kempin
//===============================================================

import std.thread;

version(Windows) {
    import std.c.windows.windows;
}

version(linux) {
    import std.c.linux.linux;
}

class Timer: Thread {
    private void delegate() action;
    private int waitTime;
    private bit autoRestart;

    this(int waitTime, void delegate() action, bit autoRestart=false) {
        this.action = action;
        this.waitTime = waitTime;
        this.autoRestart = autoRestart;
    }

    protected this(int waitTime, bit autoRestart=false) {
        this.waitTime = waitTime;
        this.autoRestart = autoRestart;
    }

    override int run() {
        sleep(waitTime);
        execute();
        while(autoRestart)
        {
            sleep(waitTime);
            execute();
        }
        return 0;
    }

    void execute() {
        action();
    }

    private void sleep(int time) {
        version(Windows) {
            Sleep(time*1000);
        }

        version(linux) {
            usleep(time*1000);
        }
    }
}</pre>
          <br/>
          <span style="color:red;">
            <a href="http://dlang.group.javaeye.com/group/blog/194405#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>Mon, 19 May 2008 13:04:29 +0800</pubDate>
        <link>http://dlang.group.javaeye.com/group/blog/194405</link>
        <guid>http://dlang.group.javaeye.com/group/blog/194405</guid>
      </item>
      <item>
        <title>arcLib学习笔记——创建精灵</title>
        <author>redduke</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://redduke.javaeye.com">redduke</a>&nbsp;
          链接：<a href="http://dlang.group.javaeye.com/group/blog/190718" style="color:red;">http://dlang.group.javaeye.com/group/blog/190718</a>&nbsp;
          发表时间: 2008年05月07日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">看了dsource上的Tank游戏源代码  基本了解代码结构  话说这arclib文档的更新速度实在是......不敢恭维


import arc.all;
import arc.scenegraph.all;
import arc.physics.all;
import arc.physics.shapes.all;

private Sprite sprite;
private Frame frame;
private Box box;
private char[] image = &quot;image/arclib_logo.png&quot;;

int main(){
    //创建主窗口
    arc.window.open(&quot;Game&quot;, 600, 600, false);
    arc.input.open();
    //创建一个简单的精灵 严格说应该先创建world和worldTransform 我从简了
    frame = new Frame(Texture(image));
    box = new Box(frame.getFrame.getSize, 100);
    box.translation = Point(300,100);
    sprite = new Sprite(box,frame);
    //将精灵加入场景节点
    rootNode.addChild(sprite);
    //绘图
    arc.scenegraph.drawable.drawScenegraph();
    arc.window.swap();
    while (!arc.input.isQuit)
        {
            arc.window.clear();
            arc.input.process();
            arc.time.process();
        }
    arc.window.close();
    return 0;
}   
</pre>
&nbsp;
          <br/>
          <span style="color:red;">
            <a href="http://dlang.group.javaeye.com/group/blog/190718#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, 07 May 2008 21:18:47 +0800</pubDate>
        <link>http://dlang.group.javaeye.com/group/blog/190718</link>
        <guid>http://dlang.group.javaeye.com/group/blog/190718</guid>
      </item>
      <item>
        <title>配置arclib Game Library</title>
        <author>redduke</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://redduke.javaeye.com">redduke</a>&nbsp;
          链接：<a href="http://dlang.group.javaeye.com/group/blog/189494" style="color:red;">http://dlang.group.javaeye.com/group/blog/189494</a>&nbsp;
          发表时间: 2008年05月04日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>从去年开始关注起D&nbsp; 因为本人并不是程序员&nbsp; 所以唯一感兴趣的就是拿它做游戏&nbsp; 然后就看到了arclib&nbsp; 于是想装上试试&nbsp; 不过官网上的文档实在有点滞后&nbsp; 在配置上费了一些周折&nbsp; 我把这个过程写出来&nbsp; 希望对那些想要使用D和arclib的爱好者能够起到一点帮助：）<br /></p>
<p>OS：windows XP SP2</p>
<p>
需求：</p>
<p>DMD 1.027 &amp; Tango Version 0.99.5</p>
<p>
不要用其它版本  因为很可能无法正常编译</p>
<p>
下载：<a href="http://www.dsource.org/projects/tango/wiki/0_99_5_DmdDownloads">http://www.dsource.org/projects/tango/wiki/0_99_5_DmdDownloads</a>
<br />
<br />
<br />
首先确认dmd/dmc/dsss已加入环境变量</p>
<p>然后用dsss安装arclib&nbsp; 运行CMD&nbsp; 输入：</p>
<p>
dsss net install arclib-core</p>
<p><span class="ext-link"><span class="icon">有基于Phobos和</span>
</span>
Tango的版本&nbsp; 但是用dsss下载的是Tango<a href="http://svn.dsource.org/projects/arclib/branches/arc02/phobos" class="ext-link"></a>
</p>
<p><br />
然后自动安装编译  没提示出错就说明安装成功了</p>
<p>还要到<a href="http://www.dsource.org/projects/arclib/browser/downloads/dll" target="_blank">http://www.dsource.org/projects/arclib/browser/downloads/dll</a>
下载所有的DLL文件</p>
<p>否则程序无法编译&nbsp; 我就是被这个困挠了一段时间</p>
<p>&nbsp;</p>
<p>现在arclib已经配置好了</p>
<p>随意建立一个D文件&nbsp; 输入以下代码：</p>
<p>module main;<br />
<br />
import arc.all;<br />
<br />
int main()<br />
{<br />
&nbsp;&nbsp; arc.window.open(&quot;Hello World&quot;, 400,300,0);<br />
&nbsp;&nbsp; arc.input.open();<br />
&nbsp;&nbsp; Font f = new Font(&quot;font.ttf&quot;, 12);<br />
&nbsp;&nbsp; char[] text = &quot;hello!&quot;;<br />
&nbsp;&nbsp; while (!arc.input.keyDown(ARC_QUIT))<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; arc.input.process();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; arc.window.clear();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.draw(text, Point(10,10), Color.Green);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; drawPixel(Point(10,10), Color.Green);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; arc.window.swap();<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; arc.window.close();<br />
&nbsp;&nbsp; return 0;<br />
}</p>
<p>把刚下载的DLL全拷贝到源文件的目录下 还有不要忘了写dsss.conf文件（那个字体需要下载 也可以用其他字体代替）</p>
<p>然后dsss build&nbsp; 看到这个窗口画面就说明成功了</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://dlang.group.javaeye.com/group/blog/189494#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 May 2008 20:00:50 +0800</pubDate>
        <link>http://dlang.group.javaeye.com/group/blog/189494</link>
        <guid>http://dlang.group.javaeye.com/group/blog/189494</guid>
      </item>
      <item>
        <title>试用新版 Poseidon (trunk-r239)</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://dlang.group.javaeye.com/group/blog/187139" style="color:red;">http://dlang.group.javaeye.com/group/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://dlang.group.javaeye.com/group/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/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, 26 Apr 2008 20:13:34 +0800</pubDate>
        <link>http://dlang.group.javaeye.com/group/blog/187139</link>
        <guid>http://dlang.group.javaeye.com/group/blog/187139</guid>
      </item>
      <item>
        <title>使用C#的Generator编写并发程序</title>
        <author>qiezi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://qiezi.javaeye.com">qiezi</a>&nbsp;
          链接：<a href="http://dlang.group.javaeye.com/group/blog/184237" style="color:red;">http://dlang.group.javaeye.com/group/blog/184237</a>&nbsp;
          发表时间: 2008年04月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          前面说地Generator编写并发程序的优势，当然它本身没有这种能力，需要为它编写调度程序。<br /><br />今天抽点时间写了个简单的，还是满好玩的，它可以调度多个“友好”的并发任务，包括：<br />1、用户自己编写的适时交出控制权的过程<br />2、网络IO<br /><br />由于对C#不是很熟，所以写的可能比较难看，而且IO也只支持网络，有兴趣的可以研究改进一下，比如把它改成SMP版本，增加Actor模型，处理更多的IO模式等。<br /><br />实现方式基本上是从IoLanguage里面抄过来的，我已经用它编写过Ruby/C++/D/C#版本，当然目前仅限于测试它的切换性能。<br /><br />好消息是如果你实现得比较好，C#版本性能完全可以超过Erlang，Ruby的Fiber就比较差一些，C++/D里面使用Fiber/ucontext性能也不是很好，Generator性能是最好的。<br /><br />由于时间短，只测试了ReadEvent，WriteEvent没有测试，这个也是有多种实现方式可以研究的。这里实现的调度器性能不是很好，可能是List用法性能太差，没有仔细测试。<br /><pre name="code" class="c#">
using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Net;


namespace ConsoleApplication1
{
    public enum EventType
    {
        ReadEvent = 1,
        WriteEvent = 2
    }

    public class Event
    {
        private Socket sock;
        private EventType eventType;
        private IEnumerator&lt;int> task;

        public Event(Socket sock, EventType eventType)
        {
            this.sock = sock;
            this.eventType = eventType;
        }

        public Socket getSocket()
        {
            return sock;
        }

        public EventType getEventType()
        {
            return eventType;
        }

        public void setTask(IEnumerator&lt;int> task)
        {
            this.task = task;
        }

        public IEnumerator&lt;int> getTask()
        {
            return task;
        }

        public void onEvent()
        {
            Console.WriteLine("onEvent");
            Scheduler.scheduleNow(task);
        }
    }

    public class ReadEvent : Event
    {
        public ReadEvent(Socket sock)
            :base(sock, EventType.ReadEvent)
        {
            
        }
    }

    public class WriteEvent : Event
    {
        public WriteEvent(Socket sock)
            : base(sock, EventType.WriteEvent)
        {
        }
    }

    class EventManager
    {
        private IDictionary&lt;Socket, Event> readEvents = new Dictionary&lt;Socket, Event>();
        private IDictionary&lt;Socket, Event> writeEvents = new Dictionary&lt;Socket, Event>();

        private IEnumerator&lt;int> myTask = null;

        public int registerHandler(Event ev)
        {
            Console.WriteLine("registerHandler");
            if ((ev.getEventType() & EventType.ReadEvent) > 0)
            {
                readEvents.Add(ev.getSocket(), ev);
            }
            else
            {
                writeEvents.Add(ev.getSocket(), ev);
            }

            if (myTask == null)
                myTask = runLoop();


            Scheduler.scheduleNow(myTask);

            return 0;
        }

        public IEnumerator&lt;int> runLoop()
        {
            Console.WriteLine("enter run");
            do
            {
                Console.WriteLine("run loop");
                yield return 1;

                IList rlist = new List&lt;Socket>(readEvents.Keys);
                IList wlist = new List&lt;Socket>(writeEvents.Keys);

                int timeoutMS = 1000000;
                if (Scheduler.hasEvents()) timeoutMS = 0;
                //Console.WriteLine("begin select: " + rlist.Count + ", " + wlist.Count);
                Socket.Select(rlist, wlist, null, timeoutMS);
                //Console.WriteLine("end select: " + rlist.Count + ", " + wlist.Count);

                Socket sock = null;
                Event ev = null;

                if (rlist.Count > 0)
                {
                    sock = (Socket)rlist[0];
                    readEvents.TryGetValue(sock, out ev);
                    readEvents.Remove(sock);
                }
                else if (wlist.Count > 0)
                {
                    sock = (Socket)wlist[0];
                    writeEvents.TryGetValue(sock, out ev);
                    writeEvents.Remove(sock);
                }

                if (ev != null)
                    ev.onEvent();
            } while (readEvents.Count != 0 || writeEvents.Count != 0);

            myTask = null;
        }
    }

    public static class Scheduler
    {
        public delegate IEnumerable&lt;int> T();

        [ThreadStatic]
        private static IList&lt;IEnumerator&lt;int>> tasks = new List&lt;IEnumerator&lt;int>>();

        [ThreadStatic]
        private static EventManager eventManager = new EventManager();

        [ThreadStatic]
        private static Event lastEvent;

        public static bool hasEvents()
        {
            return tasks.Count > 0;
        }

        public static void spawn(T del)
        {
            var task = del().GetEnumerator();
            schedule(task);
        }

        public static void schedule(IEnumerator&lt;int> task)
        {
            tasks.Remove(task);
            if (lastEvent != null)
                lastEvent.setTask(task);
            else
                tasks.Add(task);
            lastEvent = null;
        }

        public static void scheduleNow(IEnumerator&lt;int> task)
        {
            tasks.Remove(task);
            tasks.Insert(0, task);
        }

        public static void remove(IEnumerator&lt;int> task)
        {
            Console.WriteLine("remove task");
            tasks.Remove(task);
        }

        public static void run()
        {
            while (tasks.Count > 0)
            {
                IEnumerator&lt;int> task = tasks[0];
                tasks.RemoveAt(0);
                bool ret = task.MoveNext();

                if (ret)
                    schedule(task);
            }
        }

        public static int registerAndWaitEvent(Event ev)
        {
            lastEvent = ev;
            return eventManager.registerHandler(ev);
        }
    }

    // 测试程序：

    class Program
    {
        public static IEnumerable&lt;int> test(string id)
        {
            for (int i = 0; i &lt; 5; i++)
            {
                System.Console.WriteLine("id: " + id + ", " +i);
                yield return i;
            }
        }

        public static IEnumerable&lt;int> clientLoop(Socket client)
        {
            while (true)
            {
                Console.WriteLine("client loop");
                yield return Scheduler.registerAndWaitEvent(new ReadEvent(client));
                byte[] buffer = new byte[1024];
                int ret = client.Receive(buffer);
                if (ret > 0)
                {
                    //Console.WriteLine(buffer);
                    client.Send(buffer);
                }
                else
                {
                    client.Close();
                    break;
                }
            }
        }

        public static IEnumerable&lt;int> serverLoop()
        {
            Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPHostEntry IPHost = Dns.GetHostEntry("localhost"); 
            sock.Bind(new IPEndPoint(IPHost.AddressList[0], 23456));
            sock.Listen(128);
            while(true) {
                Console.WriteLine("server loop");
                yield return Scheduler.registerAndWaitEvent(new ReadEvent(sock));
                Console.WriteLine("accept event");
                Socket client = sock.Accept();
                Scheduler.spawn(() => clientLoop(client));
            }
        }

        static void Main(string[] args)
        {
            Scheduler.spawn(() => test("a"));
            Scheduler.spawn(() => test("b"));
            Scheduler.spawn(() => serverLoop());
            Scheduler.run();
        }
    }
}
</pre>
          <br/>
          <span style="color:red;">
            <a href="http://dlang.group.javaeye.com/group/blog/184237#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 Apr 2008 23:17:44 +0800</pubDate>
        <link>http://dlang.group.javaeye.com/group/blog/184237</link>
        <guid>http://dlang.group.javaeye.com/group/blog/184237</guid>
      </item>
      <item>
        <title>D新闻组里的天才代码</title>
        <author>oldrev</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://oldrev.javaeye.com">oldrev</a>&nbsp;
          链接：<a href="http://dlang.group.javaeye.com/group/blog/177844" style="color:red;">http://dlang.group.javaeye.com/group/blog/177844</a>&nbsp;
          发表时间: 2008年03月30日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          超猛的代码，刚才逛新闻组刚看到的，随便记录一下。<br /><br /><br />出自：<br />http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=68681<br /><br /><br /><pre name="code" class="java">
import std.stdio;
import std.traits;

//检测整数操作溢出，不过对性能的影响比较大，lazy 关键字的标准运用。
Integral checked(Integral)(lazy Integral dg)
{
     static assert(isIntegral!(Integral));

     Integral result = dg(); //这里才对委托 dg 里的表达式求值
     asm {
         jo overflow;
     }
     return result;

     overflow:
     throw new Exception("Integer overflow occured");
}

int main()
{
     int t = int.max;
     try
     {
         int s = checked(t + 1);
         writefln("Result is %d", s);
     }
     catch(Exception e)
     {
         writefln("Whoops! %s", e.toString());
     }
     return 0;
}</pre><br /><br />连 WB 都服了。
          <br/>
          <span style="color:red;">
            <a href="http://dlang.group.javaeye.com/group/blog/177844#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, 30 Mar 2008 21:26:41 +0800</pubDate>
        <link>http://dlang.group.javaeye.com/group/blog/177844</link>
        <guid>http://dlang.group.javaeye.com/group/blog/177844</guid>
      </item>
      <item>
        <title>JavaScript Comment Templates 我的js模板工具</title>
        <author>achun</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://achun.javaeye.com">achun</a>&nbsp;
          链接：<a href="http://dlang.group.javaeye.com/group/blog/177326" style="color:red;">http://dlang.group.javaeye.com/group/blog/177326</a>&nbsp;
          发表时间: 2008年03月28日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          让JavaScript来做模板解析工作吧!<br /><a href="http://code.google.com/p/jsct/" target="_blank">http://code.google.com/p/jsct/</a><br /><br />历史:<br />2008.4.5 jCT 2.0 Bate 放出
          <br/>
          <span style="color:red;">
            <a href="http://dlang.group.javaeye.com/group/blog/177326#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, 28 Mar 2008 16:26:14 +0800</pubDate>
        <link>http://dlang.group.javaeye.com/group/blog/177326</link>
        <guid>http://dlang.group.javaeye.com/group/blog/177326</guid>
      </item>
      <item>
        <title>给纯文本型编程文档加上高亮着色</title>
        <author>achun</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://achun.javaeye.com">achun</a>&nbsp;
          链接：<a href="http://dlang.group.javaeye.com/group/blog/171428" style="color:red;">http://dlang.group.javaeye.com/group/blog/171428</a>&nbsp;
          发表时间: 2008年03月14日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          作为程序员写代码还要写文档,真的很累<br />虽然有专业的DOCxxx工具,不过写起文档来总是和代码在一起.<br />如果我们要单独写个文本文档给别人看得话.一片黑乎乎的似乎很难看,<br />其实更多的时候是给自己看得.<br /> 想用简单的方法给自己的稳定着色么?<br /><br />	我这里有个简单的方法: 写个适用于编程文档的语法高亮模板就行了<br /> 怎么做?<br />...拿Editplus为例子...<br />file: dop.stx<br />;----------------------<br />#TITLE=DOP<br />;Document	Of	Program	syntax	file	written	by	achun.<br />;This	file	is	required	for	EditPlus	to	run	correctly.<br />#DELIMITER=,()}[]-+*%/="'~!&|\&lt;>?:;.<br />#QUOTATION1= <br />#QUOTATION2="<br />#CONTINUE_QUOTE=n<br />#LINECOMMENT=//<br />#LINECOMMENT2=...<br />#COMMENTON=/*<br />#COMMENTOFF=*/<br />#COMMENTON2='<br />#COMMENTOFF2='<br />#ESCAPE=<br />#CASE=y<br />#PREFIX1=<br />#PREFIX2=<br />#PREFIX3=<br />#PREFIX4=<br />#PREFIX5=<br />#SUFFIX1=:<br />#SUFFIX2=<br />#SUFFIX3=<br />#SUFFIX4=<br />#SUFFIX5=<br />#HTML_EMBEDDED=<br />#SCRIPT_BEGIN=<br />#SCRIPT_END=<br />#HEREDOC=<br />#AUTOCASE=<br />#NUMBER_PATTERN=<br />#SPECIAL_STX=<br />#KEYWORD=Reserved words<br />#KEYWORD=Sections<br />#<br />;---------------------<br />使用:<br />	1.把这个高亮语法文件 dop.stx 存入 Editplus的目录 ,然后配置Text文件类型的高亮语法文件<br />为此文件.<br />	2.更改Text文件类型的 tab缩进 为1<br />	3.建立一个txt文件 拷贝 这个内容进去看看':)'<br />	4.当然你可以'升级'这个 DOP 让他更符合你的习惯吧.
          <br/>
          <span style="color:red;">
            <a href="http://dlang.group.javaeye.com/group/blog/171428#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, 14 Mar 2008 15:44:59 +0800</pubDate>
        <link>http://dlang.group.javaeye.com/group/blog/171428</link>
        <guid>http://dlang.group.javaeye.com/group/blog/171428</guid>
      </item>
      <item>
        <title>让人目瞪口呆的三位世界级电脑大师</title>
        <author>justjavac</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://justjavac.javaeye.com">justjavac</a>&nbsp;
          链接：<a href="http://dlang.group.javaeye.com/group/blog/169737" style="color:red;">http://dlang.group.javaeye.com/group/blog/169737</a>&nbsp;
          发表时间: 2008年03月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <strong><span style="color: blue">1.公元1998年在我讀高二那年，那还是我用Windows 98的时候有次我系统崩溃了，</span></strong><br />因为我那时还是个电脑白痴，我同学帮我介绍了一个电脑高手来帮我修电脑。<br /><br />他看了一下电脑，问我有没有Windows 98 的光盘？，我说没有。<br /><br />他想了一下，叫我把家里电话拿给他，我心里想说修电脑要电话干什么？<br /><br />但人家是电脑高手，我也不好意思说什么，就把电话拔下来给他了。<br /><br />他把 电话线空着的一头接在主机版的一个插孔内 ，然后进入了 DOS ，<br /><br />然后就开始在电话上不停的按着键，他按键的速度非常快，但是他都只按电话的0，1两个键。<br /><br />我搞不懂这有什么用？但也不敢问，看了半个多小时，他还是不停的按这两个键，<br /><br />我渐渐的有些困，我问他这东西要搞多久？他说还要几个小时，我给他倒了杯咖啡，<br /><br />就一个人去隔壁书房睡觉了。<br /><br />醒来的时候，一看已经过了5个多小时，我起身到隔壁，看见他正在 Windows 98 里面调试，<br /><br />过了一会儿，他说，你试试，我坐上椅子用了一下，真的好了，我当时也不懂电脑，<br /><br />谢过人家就走了。<br /><br />后来我慢慢对电脑有了一些概念才了解到，<br /><br />原来当时那位电脑高手是使用机器语言 编了一个Windows 98系统<br /><br />从我给他的电话直接输入到硬盘，<br /><br />我后来问我同学那位高手的下落，我同学说前几年去了 美国 之后，杳无音讯....<br /><br /><strong><span style="color: blue">2.公元2000年在我讀大一那年，那还是我用Windows Me的时候有次我系统崩溃了，</span></strong> <br />因为我那时还是个电脑入门，我朋友帮我介绍了一个电脑高手来帮我修电脑。<br />　　<br />他看了一下电脑，问我有没有Windows Me 的安装盘？我说没有。<br />　　<br />他想了一下，叫我把一张 空的DVD刻录盘和一根奈米细针 拿给他，<br /><br />我心里想说修电脑要刻录盘和奈米细针干什么？但人家是电脑高手，我也不好意思说什么，<br /><br />於是我就把DVD刻录盘拿一张来给他了。<br />　　<br />他把奈米细针头对着刻录盘戳，他戳的速度非常快，但是只戳深或浅，<br /><br />我搞不懂这有什么用？但也不敢问，看了半个多小时，他还是不停的戳着DVD刻录盘，<br /><br />我渐渐的有些困，我问他这东西要搞多久？他说要几个小时，我给他倒了杯 葡萄酒 ，<br /><br />就一个人去隔壁客厅沙发上睡觉了。<br />　　<br />醒来的时候，一看已经过了6个多小时，我起身到隔壁，看见他正在 Windows Me 里面调试，<br /><br />还装上了 Office、Photoshop、迅雷、魔兽世界 等软件……过了一会儿他说，<br /><br />你试试，我坐上椅子用了一下，真的好了，我当时也不懂电脑，谢过人家就走了。<br />　　<br />后来我慢慢对电脑有了一些基础，终于明白了，<br /><br />原来当时那位电脑高手是用 奈米细针头刻了一个单面双层的DVD ，在里面刻上了Windows Me、Office、<br /><br />Photoshop、魔兽世界的安装程序 ，我后来问我朋友那位高手的下落，<br /><br />我朋友说前几年去了 法国 之后，杳无音讯....<br /><br /><br /><strong><span style="color: blue">3.公元2001年在我讀大二那年，那还是我用Windows XP的时候有次我不小心把D盘格式化了，</span></strong> <br />因为我那时还是个电脑新手，我亲戚帮我介绍了一个电脑高手来帮我的电脑D盘恢复数据。<br />　　<br />他看了一下电脑，问我有没有Windows XP备份过的Ghost？ 我说没有。<br />　　<br />他想了一下， 叫我把一块奈米强力磁铁棒拿给他，还问我D盘里有什么东西？<br /><br />我心里想说修电脑要奈米强力磁铁棒干什么？<br /><br />但人家是电脑高手，我也不好意思说什么，就把奈米强力磁铁棒给他了，<br /><br />还告诉他我的D盘里面全是火影忍者的动画。<br />　　<br />他把整颗硬盘拆了，用奈米强力磁铁棒在盘子上面画圈圈，他画圈圈的速度非常快，<br /><br />但是他的奈米强力磁铁棒好像有碰到又好像没有碰到，我搞不懂这有什么用？但也不敢问，<br /><br />看了半个多小时，他还是不停的在硬盘上画着圈，我渐渐的有些困，<br /><br />我问他这东西要搞多久？他说要几个小时，我给他倒了杯 蘇格蘭威士忌 ，<br /><br />就一个人去隔壁房间睡觉了。<br />　　<br />醒来的时候，一看已经过了7个多小时，我起身到隔壁，看见他正在D盘里面调试，<br /><br />里面全是 火影忍者的动画片 ，过了一会儿，他说，<br /><br />你试试，我坐上椅子用了一下，真的好了，我当时也不懂电脑，谢过人家就走了。<br />　　<br />后来我慢慢对电脑有了一些体会，终于体悟到，<br /><br />原来当时那位电脑高手是 用奈米强力磁铁棒直接在硬盘上写数据 ，<br /><br />他凭着惊人的记忆力将他曾经看过的火影忍者动画片数据都写入了硬盘，我后来问我亲戚那位电脑高手的下落，<br /><br />我亲戚说他前几年去了 英国 之后，杳无音讯....<br /><br /><br /><strong><span style="color: blue">4.就在最近，我刚装上的Vista突然自己崩溃了 </span></strong><br />就在最近，我刚装上的Vista突然自己崩溃了，虽然我会写很多程序，但是Vista崩溃了我也没<br /><br />有办法，我朋友给我介绍了一个高手来帮我修电脑。<br /><br />他看了一下电脑，问我有没有Vista的安装盘 ，我说没有。<br /><br />他想了一下，叫我拿一根没用的网线和一把剪刀，我想修电脑要网线和剪刀干什么，但人家<br /><br />是高手，我也不好说什么，就拿了一根没用的网线和一把剪刀 给他。<br /><br />他把网线一头戳到网卡上，剪断另外一头，然后就在哪里不停的拨弄那八根线。他拨弄的速<br /><br />度非常快，但是拨弄得线总是不一样，我搞不懂这有什么用，但也不敢问，看了半个多小<br /><br />时，他还是不停的拨弄着网线。我渐渐的有些困，我问他这东西要搞多久，他说要几个小<br /><br />时，我给他倒了杯 茶 ，就一个人去隔壁睡觉了。<br /><br />醒来的时候，一看已经过了4个多小时，我起身到隔壁，看见他正在 Vista 里面调试，还装给<br /><br />装好了 Visual Studio 2005 Team Suit、Ms SqlServer 2005 Enterprise Edition、BT ，还边<br /><br />下载边看 American片 ……过了一会儿，他惊觉我站在后面，不好意思地对我说，你试试。我<br /><br />坐上椅子用了一下，真的好了，我当时太震惊了，整个人傻在哪里，谢过人家就走了。<br /><br />后来我读到了前面那两篇文章，终于醒悟，原来当时那位高手是 用网线模拟网络启动，下载<br /><br />了整个Vista，还有 Visual Studio 2005 Team Suit、Ms SqlServer 2005 Enterprise Edition、<br /><br />BT，以及他正在看的 American片 ，我后来问我朋友那位高手的下落，我朋友说前几年去了<br /><br />美国 之后，杳无音讯了十几年，期间也回过中国两次，最近这一次回来说，干这个太没意思<br /><br />了，回来收拾收拾准备去 阿尔法半人马座 ，他说他也听不懂那高手说什么，只是最近传闻 微<br /><br />软的Vista 全世界都无法激活，估计跟他的离去有关，当然了，这几天也是杳无音讯....
          <br/>
          <span style="color:red;">
            <a href="http://dlang.group.javaeye.com/group/blog/169737#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>Mon, 10 Mar 2008 10:31:29 +0800</pubDate>
        <link>http://dlang.group.javaeye.com/group/blog/169737</link>
        <guid>http://dlang.group.javaeye.com/group/blog/169737</guid>
      </item>
      <item>
        <title>我心中最伟大的程序员</title>
        <author>justjavac</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://justjavac.javaeye.com">justjavac</a>&nbsp;
          链接：<a href="http://dlang.group.javaeye.com/group/blog/169718" style="color:red;">http://dlang.group.javaeye.com/group/blog/169718</a>&nbsp;
          发表时间: 2008年03月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <strong><span style="color: blue"><span style="font-size: x-large">菲利普&middot;卡兹</span></span></strong><br />　　2000年4月14日，在美国威斯康星州密尔沃基的一家汽车旅馆里，人们发现了一具年轻人的尸体，检查得知这个人的死因是酗酒、饮酒过量导致的死亡。死者被发现的时候，手中还握着一个空酒瓶，房间中还有五个空酒瓶。这样一个酒徒的死也许在平时只是地方小报上的一条不起眼的新闻，但这个人的死却在互联网上掀起了轩然大波。无数人在网上发表评论与文章，纪念他的离开，寄托人们的哀思，因为他不是一个普通人，他叫菲利普&middot;卡兹（Philip Katz），几乎全世界的每一台个人电脑上都有用他创造的压缩算法生成的文档，这种文档的后缀是&ldquo;.zip&rdquo;，这些文档的的开头都嵌有他姓名的字头缩写字母&lsquo;PK&rsquo;。这位在全世界的电脑中留下痕迹的天才程序员终年仅37岁。<br />　　在DOS时代就开始使用电脑的玩家可能都会记得，那时候的处理器速度与存储介质的容量与现在相比简直不可同日而语，为了COPY（拷贝）一个游戏我们常常要更换数张软盘。从那个时候起，我们认识了ZIP文件，在没有Windows的年代，使用字符界面和命令行方式压缩的程序主要有PKZIP和ARJ两种，直到过渡到Windows时代，WinZip的出现才使压缩软件的规格得到了统一。互联网上无数的文件都以&ldquo;.zip&rdquo;的格式进行存储，压缩文件使用户能在最短的时间里将文件从网上下载回自己的硬盘中，在没有宽带，连MODEM都仅仅是14.4K的速率的那个年代，ZIP文件为我们节省了大量的宝贵时间与金钱。但很少有人知道ZIP文件的由来，很少知道它的创造者菲利普&middot;卡兹。<br />　　在14年前，也就是公元1988年，那时候互联网还刚刚开始有了雏形，而最流行的是一种使用电话线拨号登陆别人在家里搭建的服务平台&mdash;&mdash;交换信息的电子公告牌（BBS）系统。这种系统有些类似现在的论坛和新闻组，由于站长之间互相转信也成为了一个庞大的信息网络（惠多网）。老一点的玩家可能都有印象，在没有Internet的年代，中国大地上也曾有几十个这样的BBS存在，著名的字处理软件WPS的作者求伯君和CCED的作者朱崇君当年都是非常有名的个人站长。这种方式不但可以传递文本信息，也可以由用户上传文件到站点的计算机以供其他用户下载。由于电话线的接入速度慢的可怜，通过BBS传输较大文件实在是叫人痛苦的一件事。于是，使用文件压缩技术减小文件的体积并将多个文件压缩到一个封包中就成为了BBS用户的一项必须掌握的技巧。当时的美国BBS 上，比较流行的是一种叫做ARC的压缩技术，由于它是一家商业公司开发的压缩技术，使用这种软件进行工作是需要付费的。那时候的菲利普&middot;卡兹是一个沉迷于 BBS上的毛头小伙，由于经常混迹于BBS上，对于ARC的收费非常不满的他自己开发了一个程序叫PKARC，这个程序于ARC完全兼容，可以压缩和解压缩ARC文件。这样一来，大批的ARC用户自然转而使用菲利普&middot;卡兹的免费软件。ARC的制作公司一怒之下将菲利普&middot;卡兹告上了法庭，法庭自然判决菲利普 &middot;卡兹禁止继续开发和传播PKARC。这种判决并没有磨灭菲利普&middot;卡兹的斗志，而是激起了他要与ARC斗争到底的决心。在虚拟的世界中，自由、平等永远是真正的程序员永久的追求。他放弃了PKARC的开发，发誓要写出一款比ARC更好的压缩软件来打败ARC。这一场官司造就了一名编程天才的横空出世，也造就了一个后来在互联网时代的文件标准。几周以后，后来统治整个BBS世界乃至Internet世界的ZIP在菲利普&middot;卡兹手中发出了第一声响亮的啼哭！<br />不名则已，一鸣惊人，这种名为PKZIP的程序可以将一个或多个文件压缩到一个后缀为&ldquo;.zip&rdquo;的文件中，无论从压缩比、压缩速度方面都超过了商业软件 ARC。卡兹将PKZIP作为自由软件免费发放，使其如同草原上的星星之火般在全美的各大BBS上蔓延开来，用户以几何级数的增长，各大BBS的站长自发将原来使用ARC格式压缩的文件转换成ZIP格式，卡兹用他天才的头脑和顽强的毅力堂堂正正的击败了ARC，ARC的制作公司在PKZIP的强大攻势下很快就消声匿迹了。用自由软件打败商业公司的传奇故事很快传遍了整个BBS世界，疾恶如仇而又身手不凡的菲利普&middot;卡兹如同数字世界的大侠般仗剑江湖，劫富济贫，以一人之力擎起了压缩软件的大旗。这段被人们津津乐道的传奇故事使菲利普&middot;卡兹成为了很多热衷于编程的年轻人心中的偶像。此后卡兹一直继续着对 PKZIP的开发和维护工作，PKZIP建立和统治了DOS时代的压缩标准。直到Windows的诞生，使用卡兹创造的压缩算法的软件Winzip的出现更使ZIP格式成为Internet的传输标准，ZIP压缩格式也成为压缩文档的事实标准。试问当今的电脑用户，谁敢说自己的电脑中没有ZIP文件？<br />可惜，这位天才程序员却从未在ZIP身上得到半点好处，坚持信念的结果往往是潦倒的生活，糟糕的个人生活和长期编写软件的巨大压力使卡兹染上了酗酒的恶习，最终断送了他那年轻的生命。他为世界贡献了一个伟大的免费软件，更为重要的是他缔造了一种大众化的压缩格式，然而却过早地离开了这个世界。他的名字也许多年后会被人们忘怀，但他创造的ZIP将在网上生生不息的流传，他的名字缩写嵌在了全世界数以千万的电脑中，他的传奇故事将永远流传&hellip;&hellip; <img src="../../images/smiles/icon_idea.gif" alt="" /><br /> <br /><p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://dlang.group.javaeye.com/group/blog/169718#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>Mon, 10 Mar 2008 10:05:13 +0800</pubDate>
        <link>http://dlang.group.javaeye.com/group/blog/169718</link>
        <guid>http://dlang.group.javaeye.com/group/blog/169718</guid>
      </item>
      <item>
        <title>ANSI和Unicode练习后记</title>
        <author>ideage</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ideage.javaeye.com">ideage</a>&nbsp;
          链接：<a href="http://dlang.group.javaeye.com/group/blog/161800" style="color:red;">http://dlang.group.javaeye.com/group/blog/161800</a>&nbsp;
          发表时间: 2008年02月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          首先，再次问候大家，春节好！祝愿D语言社区兴旺发达，祝愿JavaEye蒸蒸日上！<br /><br />在前文中，已经讨论了如何调用ANSI和多字节的函数。本文目的是关于在D中如何更好应用。当然，很多人认为完全可以使用宽字符的函数，但是，有时候，你要调用的函数是ANSI函数（例如WinExec，仅仅有ANSI版本，不支持Unicode，当然你可以使用麻烦的ShellExecuteEx），你就必须了解Unicode的相关知识。建议阅读前文<a href="http://ideage.javaeye.com/blog/119177" target="_blank">http://ideage.javaeye.com/blog/119177</a>，运行相关例子，认真揣摩调用的几个用法。<br /><br /><br />1.首先要明白你使用的char是什么格式。char在D中，有两种格式：ANSI，Unicode。ANSI是和C兼容的。如果你的源码保存格式是UTF8，或者UTF32，那么你的char的格式就是Unicode；否则ANSI。明白char的格式，调用相关函数就好办了。<br /><br />2.根据格式调用。如果是ANSI格式，调用ANSI函数时，使用std.string.toStringz函数就可以了。如果源码是Unicode格式，如果继续使用前面的方法，调用会失败。很幸运的，你只要理解了格式，就知道解决办法。<br /><br />3.源码是Unicode格式时，调用ANSI函数，要使用字节转换。代码说话：<br /><pre name="code" class="java">
wchar[] a2w( char[] a ) 
{
	return toUTF16(a); 
} 

char[] wcs2mbz(wchar[] ws)    
{    
    uint codepage =  1; //2000/+    
    char[] rz;     
    rz.length = WideCharToMultiByte(codepage, 0, ws.ptr, ws.length, null, 0, null, null) + 1;    
    WideCharToMultiByte(codepage, 0, ws.ptr, ws.length, rz.ptr, rz.length, null, null);    
    rz[rz.length-1] = 0;    
    rz.length = rz.length-1;    
    return rz;    
}    

char[] uc2cz(char[] a)
{
	return wcs2mbz(a2w(a));
}
</pre><br /><br /><br />调用uc2cz转换，然后传递转换后的指针就可以了：<br />char[] files="c:\NotePad.exe";<br />WinExec( uc2cz(files).ptr,1);<br /><br />4.上述的很简单，如果有错误，请大家指正！谢谢！
          <br/>
          <span style="color:red;">
            <a href="http://dlang.group.javaeye.com/group/blog/161800#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, 10 Feb 2008 09:17:23 +0800</pubDate>
        <link>http://dlang.group.javaeye.com/group/blog/161800</link>
        <guid>http://dlang.group.javaeye.com/group/blog/161800</guid>
      </item>
      <item>
        <title>D 语言的子集的 Z 编译器</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://dlang.group.javaeye.com/group/blog/157507" style="color:red;">http://dlang.group.javaeye.com/group/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://dlang.group.javaeye.com/group/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/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, 18 Jan 2008 20:59:17 +0800</pubDate>
        <link>http://dlang.group.javaeye.com/group/blog/157507</link>
        <guid>http://dlang.group.javaeye.com/group/blog/157507</guid>
      </item>
      <item>
        <title>D语言的两个日期函数</title>
        <author>zuroc</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://zsp.javaeye.com">zuroc</a>&nbsp;
          链接：<a href="http://dlang.group.javaeye.com/group/blog/156883" style="color:red;">http://dlang.group.javaeye.com/group/blog/156883</a>&nbsp;
          发表时间: 2008年01月17日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">
//日期格式为数字 如 20080901
//By zsp007@gmail.com

///验证是否是有效日期
bool date_validate(T)(T date)
{
   static T daysOfMonth[] = [0,31,28,31,30,31,30,31,31,30,31,30,31];

   T monthDay = date % 10000;
   if(monthDay > 1231)
      return false;
   if(monthDay == 229)
   {
      int year = date / 10000;
      if((year % 4) != 0)
          return false;
      return (!(year %100 == 0 && year % 400 != 0));
   }
   int month = monthDay / 100;
   int day = monthDay % 100;
   return (day > 0 && day &lt;= daysOfMonth[month]);
}

///下一天
T tomorrow(T)(T i){
    static T daysOfMonth[] = [0,31,28,31,30,31,30,31,31,30,31,30,31];
    T day=i%100,month=(i/100)%100,year=i/10000;
    
    if(day>=daysOfMonth[month]){
        if(month==12){
            ++year;
            month=1;
            day=1;
        }else if(month==2&&day==28){
            if((year % 4)== 0){
                if(year%100 == 0 && year % 400 != 0){
                    goto add_month;
                }else ++day;
            }else goto add_month;
        }else{
        add_month:
            ++month;
            day=1;
        }
    }else ++day;
    return day+100*month+10000*year;
}</pre>
          <br/>
          <span style="color:red;">
            <a href="http://dlang.group.javaeye.com/group/blog/156883#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, 17 Jan 2008 14:01:06 +0800</pubDate>
        <link>http://dlang.group.javaeye.com/group/blog/156883</link>
        <guid>http://dlang.group.javaeye.com/group/blog/156883</guid>
      </item>
      <item>
        <title>d语言写的一个简单的sql生成器</title>
        <author>zuroc</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://zsp.javaeye.com">zuroc</a>&nbsp;
          链接：<a href="http://dlang.group.javaeye.com/group/blog/156685" style="color:red;">http://dlang.group.javaeye.com/group/blog/156685</a>&nbsp;
          发表时间: 2008年01月16日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          简陋的封装了一些单表操作<br /><br />源代码<br /><br /><pre name="code" class="d">template eval( A... )
{
    const typeof(A[0]) eval = A[0];
}
char[] escape(char[] c){
    return "\""~c~"\"";
}
char[] column_def(char[] temp){
    return "typeof(this) " ~ temp ~ "(char[] v){ this.column[\"" ~ temp ~ "\"]=v;return this;}\n";
}

char[] table(char[] names)
{
    char[] table="char[][char[]] column;\n";
    char[] temp="";

    foreach (c;names){
        if(c==' '){
            table ~=column_def(temp);
            temp="";
        }else{
            temp~=c;
        }
    }
    if(temp!="")table~=column_def(temp);
    return table;
}

template Sql(char[] table_name,char[] column_list,char[] primary="id"){
   //TODO:assert primary in column_list

   mixin(table(column_list));

   typeof(this) opAssign(T)(T t){
        column=null;
        foreach(k,v;t)column[k]=v;
        return this;
   }
   char[] toString(){
       char[] result=table_name~"\n";
       foreach(k,v;column){
            result~="\t"~k~" = "~v~"\n";
       }
       return result;
   }
   char[] save(){
        if(primary in column)return update();
        else return insert();
   }
   
   char[] update(){
       assert(column[primary]!=null);
       char[] list="";
       foreach(k,v;column){
            if(k!=primary)
            list~=k~"="~escape(v)~",";
       }
       if(list!=""){
           list=list[0..$-1];
        }
       return "UPDATE "~table_name~" SET "~list~" WHERE "~primary~"="~escape(column[primary])~";";
      //UPDATE Person SET Address = 'Stien 12', City = 'Stavanger' WHERE LastName = 'Rasmussen'
   }
   char[] del(){
        assert(column[primary]!=null);
        return "DELETE FROM "~table_name~" WHERE "~primary~"="~escape(column[primary])~";";
   }
   char[] insert(){
       char[] key_list="";
       char[] value_list="";
       foreach(k,v;column){
            key_list~=k~",";
            value_list~=escape(v)~",";
       }
       if(key_list!=""){
           key_list=key_list[0..$-1];
           value_list=value_list[0..$-1];
        }
       return "INSERT INTO "~table_name~"("~key_list~") VALUES("~value_list~");";
       //INSERT INTO transcount_year(year, room_idx, dns_idx, redirip_id) VALUES(%d,%d,%d,%d);
   }

   static char[] where(char[] statement){
        return "SELECT * FROM "~table_name~" WHERE "~statement~";";
   }
   static char[] all(){
        return "SELECT * FROM "~table_name~";";
   }
}
</pre><br />用法演示<br /><pre name="code" class="d">
class ErrDnameMonth{
   mixin Sql!("conf_err_dname_month","id month dname dns_query_count web_hit_count");
}
void main(){

    Cout(ErrDnameMonth.where("id=1")).newline.newline;

    auto month=new ErrDnameMonth;

    month
        .month("12")
        .dname("www.donews.net")
        .dns_query_count("23242");

    month.web_hit_count="124";

    Cout(month.toString).newline.newline;
    Cout(month.insert).newline.newline;
    Cout(month.all).newline.newline;
    Cout(month.save).newline.newline;
    
    
    MysqlMgr mysql_mgr_;//假设这是一个数据库封装
    Row[] rows;//取回的数据为字典格式
    mysql_mgr_ = new MysqlMgr();
    rows = mysql_mgr_.queryFetchAll(month.all);
    
    foreach(r;rows){
        auto em=new ErrDnameMonth;
        em=r;
        em.dns_query_count="23";
        oo.format("{}",em.update).newline.newline;
        oo.format("{}",em.del).newline.newline;
    }

    Cin.get();
}
</pre>
          <br/>
          <span style="color:red;">
            <a href="http://dlang.group.javaeye.com/group/blog/156685#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, 16 Jan 2008 17:07:29 +0800</pubDate>
        <link>http://dlang.group.javaeye.com/group/blog/156685</link>
        <guid>http://dlang.group.javaeye.com/group/blog/156685</guid>
      </item>
      <item>
        <title>D语言备忘</title>
        <author>zuroc</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://zsp.javaeye.com">zuroc</a>&nbsp;
          链接：<a href="http://dlang.group.javaeye.com/group/blog/156293" style="color:red;">http://dlang.group.javaeye.com/group/blog/156293</a>&nbsp;
          发表时间: 2008年01月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          学习的参照资料<br />http://www.d-programming-language-china.org/<br />对应版本<br />DMD 1.013(2007年4月12日)<br /><br />0.<br />数组切片<br />char[][] args=[<br />    "main.exe",<br />    "zsp",<br />    "earth"<br />];<br />args[1..$])<br /><br />1.<br />可以给引入模块一个本地名称<br />import io = std.stdio;<br />io.writefln("hello!");<br /><br />2.<br />从一个模块中只导入专门符号，并绑定到当前名字空间<br />import std.stdio : writefln, foo = writef;<br /><br />std.stdio.writefln("hello!");    // error, std is undefined<br />writefln("hello!");    // ok, writefln bound into current namespace<br />writef("world");    // 错误, writef is undefined<br />foo("world");    // ok, calls std.stdio.writef()<br /><br />3.结合使用<br />import io = std.stdio : foo = writefln;<br /><br />4.<br />int*[] x;        // x 是指向 int 的指针的数组<br />int[]* x;        // x 是指向 int 数组的指针<br />int[3][5] x;    // x 是有5个元素的数组，每个元素是有3个元素的 int 数组<br />int[3]*[5] x;    // x 是有5个元素的数组，每个元素是指向有3个元素的 int 的数组的指针<br />int function(char) x;    // x 是指向函数的指针，函数有一个 char 的参数，返回值类型是 int<br />int function(char)[] x;    // x 是指向函数的指针的数组，函数有一个 char 的参数，返回值类型是 int<br />int delegate(int) dg;    // dg 是函数的委托,委托不能用静态成员函数或者非成员函数初始化<br />5.<br />隐式类型推断<br />auto s = "string"; // s is type char[6]<br />auto y = 4u;       // y is type uint<br /><br />6.<br />typedef 引入强类型,可以指定一个不同于其底层类型（underlying type）的初始值<br />typedef int myint = 7;<br /><br />7.<br />别名,等价于C++中的typedef<br />alias abc.Foo.bar myint;<br /><br />符号可以被声明为另一个符号的 别名 <br />alias string.strlen mylen;<br />int len = mylen("hello");    // 实际上调用的是 string.strlen()<br /><br />8.<br />别名还可以‘导入’一系列的重载函数，这样就可以在当前作用域中重载函数：<br />class A {<br />    int foo(int a) { return 1; }<br />}<br /><br />class B : A {<br />    int foo( int a, uint b ) { return 2; }<br />}<br /><br />class C : B {<br />    int foo( int a ) { return 3; }<br />    alias B.foo foo;<br />}<br /><br />class D : C    {<br />}<br />void test()<br />{<br />    D b = new D();<br />    int i;<br /><br />    i = b.foo(1, 2u);    // 调用 B.foo<br />    i = b.foo(1);        // 调用 C.foo<br />}<br /><br />9.<br />typeof 用来获得一个表达式的类型<br />class A { }<br />class B : A<br />{<br />    typeof(this) x;    // x 被声明为 B 型<br />    typeof(super) y;    // y 被声明为 A 型<br />}<br /><br />struct C<br />{<br />    typeof(this) z;    // z 被声明为 C* 型<br />}<br /><br />10.<br />变量通常是显式初始化或设置为某类型的默认值。如果用void，变量并没有被子初始化，在设置值前使用它将为引发未定义.<br />int x = void;<br /><br />11.<br />void 	no type 	-<br />bool 	boolean value 	false<br />byte 	signed 8 bits 	0<br />ubyte 	unsigned 8 bits 	0<br />short 	signed 16 bits 	0<br />ushort 	unsigned 16 bits 	0<br />int 	signed 32 bits 	0<br />uint 	unsigned 32 bits 	0<br />long 	signed 64 bits 	0L<br />ulong 	unsigned 64 bits 	0L<br />cent 	signed 128 bits (reserved for future use) 	0<br />ucent 	unsigned 128 bits (reserved for future use) 	0<br />float 	32 bit floating point 	float.nan<br />double 	64 bit floating point 	double.nan<br />real 	largest hardware implemented floating point size (Implementation Note: 80 bits for Intel CPUs) 	real.nan<br />ifloat 	imaginary float 	float.nan * 1.0i<br />idouble 	imaginary double 	double.nan * 1.0i<br />ireal 	imaginary real 	real.nan * 1.0i<br />cfloat 	a complex number of two float values 	float.nan + float.nan * 1.0i<br />cdouble 	complex double 	double.nan + double.nan * 1.0i<br />creal 	complex real 	real.nan + real.nan * 1.0i<br />char 	unsigned 8 bit UTF-8 	0xFF<br />wchar 	unsigned 16 bit UTF-16 	0xFFFF<br />dchar 	unsigned 32 bit UTF-32 	0x0000FFFF<br /><br />12.<br />在编译时打印出消息，赋值表达式 必须是字符串文字量<br />pragma(msg, "compiling...");<br /><br />插入一条伪指令到目标文件，以链接赋值表达式指定的库。赋值表达式必须是字符串文字量。<br />pragma(lib, "foo.lib");<br /><br />13.<br />如果成员函数是显式地通过引用 typeof(this) 调用的，会生成一个非虚函数调用：<br />  class A<br />{<br />    char get() { return 'A'; }<br /><br />    char foo() { return typeof(this).get(); }<br />    char bar() { return this.get(); }<br />}<br /><br />class B : A<br />{<br />    char get() { return 'B'; }<br />}<br /><br />void main()<br />{<br />    B b = new B();<br /><br />    b.foo();        // 返回 'A'<br />    b.bar();        // 返回 'B'<br />}<br /><br />14.<br />import( AssignExpression )<br /><br />赋值表达式必须在编译时计算为常量字符串。<br />文字内容被解释为文件名，读入文件，然后文件内容被精确转换为字符串文字量。<br />void foo()<br />{<br />    // 打印出foo.txt的所有内容<br />    writefln( import("foo.txt") );<br />}<br /><br />15.<br />if ( is(func[]) )       //若为函数则不满足条件，因为数组不允许用于函数<br />if ( is(bar : int) )    //为或能隐式转换int<br />if ( is(bar == int) )   //为int<br /><br />16.<br />静态if/else<br /><br />static if ( is(bar T) )<br />    alias T S;<br />else<br />    alias long S;<br />    <br />17.<br />foreach正序<br />foreach_reverse倒序<br /><br />char[] a;<br />foreach (int i, char c; a)<br />{<br />    printf("a[%d] = '%c'\n", i, c);<br />}<br /><br />18.<br />double[char[]] a;            // 索引 类型是 char[]，值 类型是 double<br />foreach (char[] s, double d; a)<br />{<br />    printf("a['%.*s'] = %g\n", s, d);<br />}<br /><br />19.<br />如果聚集是一个结构或者类对象，则它由特定opApply 成员函数定义.<br />foreach_reverse行为由特定opApplyReverse成员函数定义，这此函数定义的类型必须和foreach语句相一致.<br /><br />int opApply(int delegate(ref Type [, ...]) dg);<br />int opApplyReverse(int delegate(ref Type [, ...]) dg);<br /><br />其中 Type 要同 foreach 声明中 标志符 中的 类型 匹配。<br />传递给 opApply 的委托类型中剩下的那些 类型 （上式中的“...”）对应于其余的多个 Foreach类型 。<br />结构或类中可以有多个不同的 opApply 函数，foreach语句 会使用类型匹配的函数，该函数的参数 dg 的参数类型要同 foreach语句 中对应的 Foreach类型 匹配。<br />opApply 的函数体遍历聚集的元素，并将它们作为参数依次传递给 dg 函数。<br />如果 dg 返回 0 ，则 opApply 继续应用于下一个元素。<br />如果 dg 返回一个非零值，opApply 必须停止遍历并返回那个值。<br />如果 opApply 顺利遍历了所有的元素，会返回 0 。<br /><br />class Foo<br />{<br />    uint array[2];<br /><br />    int opApply(int delegate(ref uint) dg)<br />    {   <br />        int result = 0;<br /><br />        for (int i = 0; i &lt; array.length; i++)<br />        {<br />            result = dg(array);<br />            if(result)break;<br />        }<br />        return result;<br />    }<br />}<br /><br />void test()<br />{<br />    Foo a = new Foo();<br /><br />    a.array[0] = 73;<br />    a.array[1] = 82;<br /><br />    foreach (uint u; a)<br />    {<br />        printf("%d\n", u);<br />    }<br />}<br /><br />将打印出:<br />QUOTE:<br />73<br />82<br /><br />20.<br />ref 等价于 inout<br /><br />21.<br />可以在 switch 表达式中使用字符串。例如：<br /><br />char[] name;<br />switch (name)<br />{<br />    case "fred":<br />    case "sally":<br />    ...<br />}<br /><br />goto 会跳转到以 标志符 为标号的语句处运行:<br />if (foo)<br />    goto L1;<br />    x = 3;<br />L1:<br />    x++;<br />第二种形式，goto default; ，会跳转到最内层 Switch语句 中的 Default语句 处。<br />第三种形式，goto case; ，会跳转到最内层 Switch语句 中的下一个 Case语句 处。<br />第四种形式，goto case 表达式; ，会跳转到包含带有 表达式 的 Case语句 的最内层 Switch语句 中那个 Case语句 处。<br /><br />22.<br />struct Foo<br />{<br />    typedef int Y;<br />}<br />Y y;        // error, Y undefined<br />with (Foo)<br />{<br />    Y y;    // same as Foo.Y y;<br />}<br /><br />23.<br />synchronize 语句用来在多线程情况下同步临界区内的语句。<br />synchronized { ... }<br /><br />24.<br />int main()<br />{<br />    try<br />    {<br />        try<br />        {<br />            throw new Exception("first");<br />        }<br />        finally<br />        {<br />            printf("finally\n");<br />            throw new Exception("second");<br />        }<br />    }<br />    catch(Exception e)<br />    {<br />        printf("catch %.*s\n", e.msg);<br />    }<br />    printf("done\n");<br />    return 0;<br />}<br /><br />25.<br />throw new Exception("message");<br /><br />26.<br />scope用于资源释放,可以避免资源泄漏<br />{<br />    scope(exit) writef("1");<br />    scope(success) writef("2");<br />    scope(exit) writef("3");<br />    scope(success) writef("4");<br />    <br />    scope(failure) writef("7");<br />}<br />writefln();<br /><br />写出: 4321<br /><br />27.<br />Volatile 语句<br /><br />没有什么代码活动能跨越 volatile 语句的边界。<br />在 语句 之前的所有内存写操作都保证在 语句 中或其后的内存读操作之前完成。<br />在 语句 之后的所有内存读操作都保证在 语句 中或其前的所有内存写完成之后执行。<br />volatile 语句不能保证原子性。如果要保证原子性，应该使用 synchronized 语句。<br /><br />28.<br />数组属性<br />.ptr 返回指向数组第一个元素的指针。(d-programming-language-china.org注：pointer to first?)<br />.dup 创建一个同样大小的动态数组并将原数组的内容复制到新数组中。<br />.reverse 将数组中的元素按原来的逆序排列。返回数组。<br />.sort 将数组中的元素按照适当的方法排序。返回数组。<br /><br />29.<br />关联数组的属性有：<br />.length 返回关联数组中值的个数。与动态数组不同的是，它是只读的。<br />.keys 返回动态数组，数组的元素是关联数组的关键字。<br />.values 返回动态数组，数组的元素是关联数组的值。    <br />.rehash 适当地重新组织关联数组以提高查找效率。例如，程序已经载入了符号表并将开始进行查找时，rehash 会提高效率。返回指向新数组的引用。<br /><br />30.<br />struct结构可以被同类型值动态初始化<br />struct X { int a; int b; int c; int d = 7;}<br /><br />static X z = { c:4, b:5, a:2 , d:5};<br />static X q = { 1, 2 };        // q.a = 1, q.b = 2, q.c = 0, q.d = 7<br /><br />struct S<br />{    int a;<br /><br />    static S opCall(int v)<br />    {<br />        S s;<br />        s.a = v;<br />        return s;<br />    }<br />}<br /><br />S s = 3;    // sets s.a to 3<br /><br />31.<br />union U { int a; double b; }<br />static U u = { b : 5.0 };        // u.b = 5.0<br /><br />32.<br />tupleof是class中的变量数组<br />class Foo { int x; long y; }<br />void test(Foo foo)<br />{<br />    foo.tupleof[0] = 1;        // set foo.x to 1<br />    foo.tupleof[1] = 2;        // set foo.y to 2<br />    foreach (x; foo.tupleof)<br />    writef(x);        // prints 12<br />}<br /><br />33.<br />类不变量用来指定类的必须总是为真的特征.不变量中的代码不应该调用任何非静态公有类成员函数.<br />class Date<br />{<br />    int day;<br />    int hour;<br /><br />    invariant<br />    {<br />        assert(1 &lt;= day && day &lt;= 31);<br />        assert(0 &lt;= hour && hour &lt; 24);<br />    }<br />}<br /><br />34.<br />一个编译器开关，如DMD用-unittest，使单元测试代码编译并整合到可执行文件中。程序中所有类的 test() 函数将在静态初始化之后，maiin()函数调用之前被调用。<br />unittest<br />{<br />    ...测试代码...<br />}<br /><br />35.<br />enum { A, B = 5+7, C, D = 8, E }<br />这令 A=0、B=12、C=13、D=8、E=9。<br />.init           枚举第一个成员的值<br />.min            枚举的最小值<br />.max            枚举的最大值<br /><br />36.<br />按照定义，如果契约先验条件被违反，则过程体（body）将受到错误的参数。<br />这将抛出一个 AssertError 异常。<br />如果契约后验条件被违反，则意味着过程体中有一个 bug ，将抛出一个 AssertError 异常。<br /><br />long square_root(long x)<br />in<br />    {<br />        assert(x >= 0);<br />    }<br />out (result)<br />//如果函数返回　void，即没有结果，那么　out　子句中自然也没有 result 的声明。在这种情况下，使用：out{}<br />    {<br />        assert((result * result) &lt;= x && (result+1) * (result+1) >= x);<br />    }<br />body<br />    {<br />        return cast(long)std.math.sqrt(cast(real)x);<br />    }<br />    <br />37.<br />预定义版本<br /><br />X86 Intel 和 AMD 的 32 bit 处理器<br />X86_64  AMD 和Intel 的64 bit 处理器<br />Windows Microsoft Windows 系统<br />Win32   Microsoft 32 bit Windows 系统<br />Win64   Microsoft 64 bit Windows 系统<br />linux   所有的 linux 系统<br />LittleEndian    字节序，低位优先<br />BigEndian   字节序，高位优先<br />none    未定义；用来禁用某段代码<br />all     总是定义(方便调试?); used as the opposite of none<br /><br />38.<br />debug<br />debug ( Integer )<br />debug ( Identifier )<br /><br />39.<br />static assert(0);<br /><br />40.<br />Error 类有一个叫做 toString() 的纯虚函数，它返回一个 char[] 类型的人类可读的错误描述。<br /><br />41.<br />复数文字量没有自身特殊的语法，只需写成实数类型和虚数类型相加即可：<br />ireal j = 1.3i;<br />cdouble cd = 3.6 + 4i;<br />creal c = 4.5 + 2i;<br /><br />42.<br />嵌入文档注释：<br />  /// 单行文档注释<br /><br />/** 同样是. */<br /><br />/+ 也是注释+/<br /><br />/**<br />一条概要注释.<br />*/<br /><br />int a;    /// a的文档，b没有文档<br />int b;<br /><br />/** c和d的文档 */<br />/** 更多c和d的文档 */<br />int c;<br />/** ditto */<br />int d;<br /><br />/* e的文档 */ int e;<br />int f;    /// ditto<br /><br />/** g的文档 */<br />int g; ///更多g的文档<br /><br />/// C和D文档<br />class C<br />{<br />    int x;    ///    C.x的文档<br /><br />    /** C.y 和C.z的文档 */<br />    int y;<br />    int z;    /// ditto<br /><br />/// ditto<br />class D<br />{<br />}<br /><br />文档注释由连续的节组成。每节由节名开始，节名是非空白字符后面紧跟':'。节名不区分大小写。<br />1.1 Summary摘要<br />第一节是摘要，没有节名。也就是第一段直到空行或一个节名。虽然摘要可以任意长度，不过你可以让它保持在一行内。摘要是可选的。<br />1.2 Descripti描述<br /><br />第二节是描述。从摘要开始直到节名或者注释结束。<br />尽管描述是可选的，但存在描述的话必须存在摘要。<br />/***********************************<br /> * Brief summary of what<br /> * myfunc does, forming the summary section.<br /> *<br /> * First paragraph of synopsis description.<br /> *<br /> * Second paragraph of<br /> * synopsis description.<br /> */<br /><br />43.<br /> 为了格式的一致性和可预测性，有一些标准节。<br />  Bugs: Doesn't work for negative values.<br />  Date: March 14, 2003<br />  Deprecated: superseded by function bar()<br />  <br />  Examples:<br />  --------------------<br />  writefln("3"); // writes '3' to stdout<br />  用至少三个连字符来画出嵌入代码的范围<br />  --------------------<br />    <br /> Historys initial version<br />    V2 added feature X<br /><br /> Liense se freely for any purpose<br /> <br /> Returns: The contents of the file.<br /><br /> See_Also:foo, bar, http://www.digitalmars.com/d/phobos/index.html<br /><br /> Standards: Conforms to DSPEC-1234<br /><br /> Throws:列出什么情况下抛出什么异常<br /> <br /> Version: 1.6a列出明的版本<br /> <br /> Params:<br />    x =    is for this<br />    y =    is for that
          <br/>
          <span style="color:red;">
            <a href="http://dlang.group.javaeye.com/group/blog/156293#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 18:51:45 +0800</pubDate>
        <link>http://dlang.group.javaeye.com/group/blog/156293</link>
        <guid>http://dlang.group.javaeye.com/group/blog/156293</guid>
      </item>
      <item>
        <title>&lt;&lt;Learn to Tango with D&gt;&gt;下载</title>
        <author>zuroc</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://zsp.javaeye.com">zuroc</a>&nbsp;
          链接：<a href="http://dlang.group.javaeye.com/group/blog/156291" style="color:red;">http://dlang.group.javaeye.com/group/blog/156291</a>&nbsp;
          发表时间: 2008年01月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Apress.Learn.to.Tango.with.D.Jan.2008.pdf<br /><br />Learn to Tango with D is a book about the D programming language and the Tango software library. It became available as an eBook 7th of January 2008, whereas the printed version should be available 3 weeks later.<br /><br />Learn to Tango with D introduces you to D, with special attention given to the Tango software library. A concise yet thorough overview of the language syntax and features is presented, followed by an introduction to Tango.<br /><br />The book is written by Kris Bell, Lars Ivar Igesund, Sean Kelly and Michael Parker.<br /><br />Foreword is by Walter Bright, and technical reviewer was Don Clugston. <br /><br />下载地址:<br /><a href="http://groups.google.com/group/zsp007" target="_blank">http://groups.google.com/group/zsp007</a><br />中的<br />文件 1 个文件  查看所有»		<br />Apress.Learn.to.Tango.with.D.Jan.2008.pdf
          <br/>
          <span style="color:red;">
            <a href="http://dlang.group.javaeye.com/group/blog/156291#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 18:49:26 +0800</pubDate>
        <link>http://dlang.group.javaeye.com/group/blog/156291</link>
        <guid>http://dlang.group.javaeye.com/group/blog/156291</guid>
      </item>
      <item>
        <title>用 ANTLR 做一个四则运算器</title>
        <author>梁利锋</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://llf.javaeye.com">梁利锋</a>&nbsp;
          链接：<a href="http://dlang.group.javaeye.com/group/blog/156170" style="color:red;">http://dlang.group.javaeye.com/group/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://dlang.group.javaeye.com/group/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/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, 15 Jan 2008 17:48:08 +0800</pubDate>
        <link>http://dlang.group.javaeye.com/group/blog/156170</link>
        <guid>http://dlang.group.javaeye.com/group/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://dlang.group.javaeye.com/group/blog/155151" style="color:red;">http://dlang.group.javaeye.com/group/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://dlang.group.javaeye.com/group/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://dlang.group.javaeye.com/group/blog/155151</link>
        <guid>http://dlang.group.javaeye.com/group/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://dlang.group.javaeye.com/group/blog/153818" style="color:red;">http://dlang.group.javaeye.com/group/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://dlang.group.javaeye.com/group/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://dlang.group.javaeye.com/group/blog/153818</link>
        <guid>http://dlang.group.javaeye.com/group/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://dlang.group.javaeye.com/group/blog/153501" style="color:red;">http://dlang.group.javaeye.com/group/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 智能提示，只需