<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>EverET.org</title>
	<atom:link href="http://everet.org/feed" rel="self" type="application/rss+xml" />
	<link>http://everet.org</link>
	<description>Better to do something imperfectly than to do nothing flawlessly.</description>
	<lastBuildDate>Mon, 21 May 2012 06:46:09 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>语录</title>
		<link>http://everet.org/2012/05/quotation.html</link>
		<comments>http://everet.org/2012/05/quotation.html#comments</comments>
		<pubDate>Mon, 21 May 2012 05:42:12 +0000</pubDate>
		<dc:creator>Stupid ET</dc:creator>
				<category><![CDATA[我的分享]]></category>

		<guid isPermaLink="false">http://everet.org/?p=1111</guid>
		<description><![CDATA[吾尝终日而思矣，不如须臾之所学也；吾尝跂而望矣，不如登高之博见也。登高而招，臂非加长也，而见者远；顺风而呼，声非加疾也，而闻者彰。假舆马者，非利足也，而致千里；假舟楫者，非能水也，而绝江河。君子生非异也，善假于物也。 &#8212;- 《劝学》 学而不思则罔，思而不学则殆。 温故而知新，可以为师矣。 &#8212;- 《论语·为政第二》 学而时习之，不亦说乎？有朋自远方来，不亦乐乎？人不知而不愠，不亦君子乎？ &#8212;- 《论语·学而第一》 KISS. Keep It Simple, Stupid. &#8212;- Unkown A designer knows he has arrived at perfection not when there is no longer anything to add, but when there is no longer any thing to take away. &#8212;- Antoine de Saint-Exupery Simple, few parts, easy to maintain, very<a href="http://everet.org/2012/05/quotation.html"> <br /><br /> (More)…</a>]]></description>
			<content:encoded><![CDATA[<p><strong>吾尝终日而思矣，不如须臾之所学也；吾尝跂而望矣，不如登高之博见也。登高而招，臂非加长也，而见者远；顺风而呼，声非加疾也，而闻者彰。假舆马者，非利足也，而致千里；假舟楫者，非能水也，而绝江河。君子生非异也，善假于物也。</strong></p>
<p style="text-align: right;">&#8212;- 《劝学》</p>
<p><strong>学而不思则罔，思而不学则殆。</strong></p>
<p><strong>温故而知新，可以为师矣。</strong></p>
<p style="text-align: right;">&#8212;- 《论语·为政第二》</p>
<p><strong>学而时习之，不亦说乎？有朋自远方来，不亦乐乎？人不知而不愠，不亦君子乎？</strong></p>
<p style="text-align: right;">&#8212;- 《论语·学而第一》</p>
<p><strong>KISS. Keep It Simple, <a href="http://EverET.org">Stupid</a>.</strong></p>
<p style="text-align: right;">&#8212;- Unkown</p>
<p><strong>A designer knows he has arrived at perfection not when there is no longer anything to add, but when there is no longer any thing to take away.<span id="more-1111"></span></strong></p>
<p style="text-align: right;">&#8212;- Antoine de Saint-Exupery</p>
<p><strong>Simple, few parts, easy to maintain, very strong.</strong></p>
<p style="text-align: right;">&#8212;- General Chuck Yeager</p>
<p><strong>Discovery consists of seeing what everybody has seen and thinking what nobody has thought.</strong></p>
<p style="text-align: right;"><strong></strong><span style="text-align: right;">&#8212;- Albert Szent-Gyorgyi</span></p>
<p><strong>When in doute, use brute force.</strong></p>
<p style="text-align: right;">&#8212;- Kenneth Lane <em>Thompson</em></p>
<p style="text-align: left;"><strong>Premature optimization is the <em>root</em> of all <em>evil!</em></strong></p>
<p style="text-align: right;"><em></em>&#8212;- Donald <em>Knuth</em></p>
<p style="text-align: left;"><strong>In theory, theory and practice are the same. In practice, they&#8217;re not.</strong></p>
<p style="text-align: right;">&#8212;- Unkown</p>
<p><strong>Those who cannot remember the past are condemned to repeat it.</strong></p>
<p style="text-align: right;">&#8212;- George Santayana</p>
<p><strong>Don&#8217;t repeat yourself.</strong></p>
<p style="text-align: right;">&#8212;- Unkown</p>
<p><strong>Perl &#8211; The only language that looks the same before and after RSA encryption.</strong></p>
<p style="text-align: right;">&#8212;- Keith Bostic</p>
<p style="text-align: left;"><strong>Yesterday is a history, tomorrow is a mystery, only today is a gift.</strong></p>
<p style="text-align: right;">&#8212;- Alice Morse Earle</p>
<p><strong>Better to do something imperfectly than to do nothing flawlessly.</strong><br />
宁愿做事而犯错，也不要为了不犯错而什么都不做。</p>
<p style="text-align: right;">&#8212;- Robert Schuller</p>
<p><strong>Always be a first-rate version of yourself, instead of a second-rate version of somebody else.</strong><br />
永远做自己的一流版本，永不做他人的二流版本。</p>
<p style="text-align: right;"><span style="text-align: right;">&#8212;&#8211; Judy Garland</span></p>
<p><strong>The greatest barrier to success is the fear of failure。</strong></p>
<p style="text-align: right;">&#8212;- Sven Goran Eriksson</p>
<p><strong>I didn’t fail the test, I just found 100 ways to do it wrong。</strong></p>
<p style="text-align: right;">&#8212;- Benjamin Franklin</p>
<p><strong>I leave no trace of wings in the air, but I am glad I have had my flight.</strong><br />
天空不曾留下鸟儿的痕迹，但我已飞过。</p>
<p style="text-align: right;">&#8212;- 《飞鸟集》</p>
<p style="text-align: left;">(<a href="http://everet.org/2012/05/quotation.html">未完待续</a>)</p>
<hr />
<p><small>
本文链接：<a href="http://everet.org/2012/05/quotation.html">http://everet.org/2012/05/quotation.html | © EverET.org</a> <br/>
本文评论：<a href="http://everet.org/2012/05/quotation.html#comments">No comment</a> 
</small></p>]]></content:encoded>
			<wfw:commentRss>http://everet.org/2012/05/quotation.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>注释中的TODO、FIXME、XXX</title>
		<link>http://everet.org/2012/05/todo-fixme-xxx-in-comment.html</link>
		<comments>http://everet.org/2012/05/todo-fixme-xxx-in-comment.html#comments</comments>
		<pubDate>Wed, 16 May 2012 04:58:10 +0000</pubDate>
		<dc:creator>Stupid ET</dc:creator>
				<category><![CDATA[我的分享]]></category>

		<guid isPermaLink="false">http://everet.org/?p=1094</guid>
		<description><![CDATA[第一次见到注释中的TODO是在用VS自动生成MFC框架的时候，里面自动生成的函数可能会有一句注释： // TODO Fix this function. 很久以前以为这仅仅是给人看的，原来，它也可以在VS里面开启一个TastList窗口，显示代码中所有的TODO（代办事项）。然后我们就可以方便地在TaskList中看到代码中哪些东西还需要我们完成。这个在其他的开发环境也有类似的功能。 在Python源码中，主要有三个特殊的注释：TODO、FIXME、XXX。 TODO 说明还有工作需要做，COMMENT简要地描述还有什么工作要做。 /* TODO: C speedup not implemented for sort_keys */ FIXME 说明这里有错误需要修正。 /* FIXME avoid integer overflow */ XXX 功能实现了，但是可能需要改进。 /* XXX &#8212; do all the additional formatting with filename and lineno here */ 使用了这些特殊注释，我们就可以开一个Task的窗口来查看我们项目中的一些任务列表，而且可以方便地定位到代码所在位置。 这可能会比另外拿个文本文件记录要方便得多。 本文链接：http://everet.org/2012/05/todo-fixme-xxx-in-comment.html &#124; © EverET.org 本文评论：No comment]]></description>
			<content:encoded><![CDATA[<p>第一次见到注释中的TODO是在用VS自动生成MFC框架的时候，里面自动生成的函数可能会有一句注释：</p>
<blockquote><p>// TODO Fix this function.</p></blockquote>
<p>很久以前以为这仅仅是给人看的，原来，它也可以在VS里面开启一个TastList窗口，显示代码中所有的TODO（代办事项）。然后我们就可以方便地在TaskList中看到代码中哪些东西还需要我们完成。这个在其他的开发环境也有类似的功能。</p>
<p>在Python源码中，主要有三个特殊的注释：TODO、FIXME、XXX。</p>
<h2>TODO</h2>
<p>说明还有工作需要做，COMMENT简要地描述还有什么工作要做。</p>
<blockquote><p>/* TODO: C speedup not implemented for sort_keys */<span id="more-1094"></span></p></blockquote>
<h2>FIXME</h2>
<p>说明这里有错误需要修正。</p>
<blockquote><p>/* FIXME avoid integer overflow */</p></blockquote>
<h2>XXX</h2>
<p>功能实现了，但是可能需要改进。</p>
<blockquote><p>/* XXX &#8212; do all the additional formatting with filename and<br />
lineno here */</p></blockquote>
<p>使用了这些特殊注释，我们就可以开一个Task的窗口来查看我们项目中的一些任务列表，而且可以方便地定位到代码所在位置。</p>
<p>这可能会比另外拿个文本文件记录要方便得多。</p>
<hr />
<p><small>
本文链接：<a href="http://everet.org/2012/05/todo-fixme-xxx-in-comment.html">http://everet.org/2012/05/todo-fixme-xxx-in-comment.html | © EverET.org</a> <br/>
本文评论：<a href="http://everet.org/2012/05/todo-fixme-xxx-in-comment.html#comments">No comment</a> 
</small></p>]]></content:encoded>
			<wfw:commentRss>http://everet.org/2012/05/todo-fixme-xxx-in-comment.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>判断两个有符号整数相加是否溢出</title>
		<link>http://everet.org/2012/05/test-int-overflow.html</link>
		<comments>http://everet.org/2012/05/test-int-overflow.html#comments</comments>
		<pubDate>Wed, 16 May 2012 04:11:42 +0000</pubDate>
		<dc:creator>Stupid ET</dc:creator>
				<category><![CDATA[我的分享]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://everet.org/?p=1087</guid>
		<description><![CDATA[在Python，默认的整数是long型的，也就是机器字长，32位的最大有符号整数为0x7fffffff，64位最大有符号整数为0x7fffffffffffffff。 而在Python，支持任意大整数的运算，也就是，当我们的long型整数（在Python对象中type为int）溢出的时候，Python会自动将其变成大整数（在Python对象中type为long），也就是和Java中的BigInteger一样，支持任意位数的整数计算，不过更加方便。 我的系统是64位的，最大符号整数为0x7fffffffffffffff，我们来看看两个0x7fffffffffffffff相加会发生什么事情。 我们可以看到c的值已经超越C语言中long能够表示的最大整数了，所以Python将其变成了type为long的类型。那么什么时候需要转换呢？ 答案是，当溢出的时候。但是我们怎么知道何时溢出？ 我们来看一下Python中对于加法的实现。 可见，当 if ((i^a) &#60; 0 &#38;&#38; (i^b) &#60; 0) goto slow_add; 为真的时候就是发生溢出了，所以去到了慢速加法通道。 那我们有 i = a + b 什么时候溢出呢？在a、b都为正数的时候和为负数（正正负）或者a、b都为负数的时候和为正数（负负正）。 所以当 (i^a) &#60; 0 &#38;&#38; (i^b) &#60; 0 为 true 的时候溢出了，因为它们的最高位都符合正正负或负负正。 本文链接：http://everet.org/2012/05/test-int-overflow.html &#124; © EverET.org 本文评论：No comment]]></description>
			<content:encoded><![CDATA[<p>在Python，默认的整数是long型的，也就是机器字长，32位的最大有符号整数为0x7fffffff，64位最大有符号整数为0x7fffffffffffffff。</p>
<p>而在Python，支持任意大整数的运算，也就是，当我们的long型整数（在Python对象中type为int）溢出的时候，Python会自动将其变成大整数（在Python对象中type为long），也就是和Java中的BigInteger一样，支持任意位数的整数计算，不过更加方便。</p>
<p>我的系统是64位的，最大符号整数为0x7fffffffffffffff，我们来看看两个0x7fffffffffffffff相加会发生什么事情。<span id="more-1087"></span></p>
<p><a href="http://everet.org/wp-content/uploads/2012/05/Screenshot-from-2012-05-16-115620.png" rel="lightbox[1087]"><img class="alignnone size-full wp-image-1088" title="Screenshot from 2012-05-16 11:56:20" src="http://everet.org/wp-content/uploads/2012/05/Screenshot-from-2012-05-16-115620.png" alt="" width="319" height="220" /></a></p>
<p>我们可以看到c的值已经超越C语言中long能够表示的最大整数了，所以Python将其变成了type为long的类型。那么什么时候需要转换呢？</p>
<p>答案是，当溢出的时候。但是我们怎么知道何时溢出？</p>
<p>我们来看一下Python中对于加法的实现。</p>
<pre class="brush: python; highlight: [12]; title: ; notranslate">
case BINARY_ADD:
    w = POP();
    v = TOP();
    if (PyInt_CheckExact(v) &amp;&amp; PyInt_CheckExact(w)) {
        /* INLINE: int + int */
        register long a, b, i;
        a = PyInt_AS_LONG(v);
        b = PyInt_AS_LONG(w);
        /* cast to avoid undefined behaviour
           on overflow */
        i = (long)((unsigned long)a + b);
        if ((i^a) &lt; 0 &amp;&amp; (i^b) &lt; 0)
            goto slow_add;
        x = PyInt_FromLong(i);
    }
    else if (PyString_CheckExact(v) &amp;&amp;
             PyString_CheckExact(w)) {
        x = string_concatenate(v, w, f, next_instr);
        /* string_concatenate consumed the ref to v */
        goto skip_decref_vx;
    }
    else {
      slow_add:
        x = PyNumber_Add(v, w);
    }
    Py_DECREF(v);
  skip_decref_vx:
    Py_DECREF(w);
    SET_TOP(x);
    if (x != NULL) continue;
    break;
</pre>
<p>可见，当</p>
<blockquote><p>if ((i^a) &lt; 0 &amp;&amp; (i^b) &lt; 0) goto slow_add;</p></blockquote>
<p>为真的时候就是发生溢出了，所以去到了慢速加法通道。<br />
那我们有</p>
<blockquote><p>i = a + b</p></blockquote>
<p>什么时候溢出呢？在a、b都为正数的时候和为负数（正正负）或者a、b都为负数的时候和为正数（负负正）。<br />
所以当 (i^a) &lt; 0 &amp;&amp; (i^b) &lt; 0 为 true 的时候溢出了，因为它们的最高位都符合正正负或负负正。</p>
<hr />
<p><small>
本文链接：<a href="http://everet.org/2012/05/test-int-overflow.html">http://everet.org/2012/05/test-int-overflow.html | © EverET.org</a> <br/>
本文评论：<a href="http://everet.org/2012/05/test-int-overflow.html#comments">No comment</a> 
</small></p>]]></content:encoded>
			<wfw:commentRss>http://everet.org/2012/05/test-int-overflow.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python使用spark模块构造计算器</title>
		<link>http://everet.org/2012/05/python-spark-calculator.html</link>
		<comments>http://everet.org/2012/05/python-spark-calculator.html#comments</comments>
		<pubDate>Tue, 15 May 2012 14:24:58 +0000</pubDate>
		<dc:creator>Stupid ET</dc:creator>
				<category><![CDATA[我的代码]]></category>
		<category><![CDATA[我的分享]]></category>
		<category><![CDATA[compile]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://everet.org/?p=1076</guid>
		<description><![CDATA[Spark简介 Spark 解析器与 EBNF 语法有一些共同之处，但它将解析／处理过程分成了比传统的 EBNF 语法所允许的更小的组件。Spark 的优点在于，它对整个过程中每一步操作的控制都进行了微调，还提供了将定制代码插入到过程中的能力。 Spark的最新版是10年前发布的，真是非常的长寿，可见设计精良。其中的采用的设计模式有Reflection Pattern、Visitor Pattern、Pipes and Filters Pattern和Strategy Pattern。 初识Spark 第一次知道Spark这个模块是在IBM的网站[3]上看到的。 第一次激起我学习这个模块的兴趣是在看Python源码的时候，发现Python的编译器是用The Zephyr Abstract Syntax Description Language(Parser/Python.asdl)来定义的语法，然后通过(Parser/asdl.py、Parser/asdl_c.py、Parser/spark.py)根据Parser/Python.asdl生成C语言解析器。其中仅用了1000多行就实现了一个yacc。这个是非常地强大。 计算器 对于计算器的构造，我们在上文中使用LL(1)递归下降的方法构造了一个。但是Spark更加强大，Spark是用Earley语法分析算法，能够解析所有的上下文无关文法，这比LL和LR要更强，当然代价是更慢。 我们来看用Spark实现的计算器： 源码请见：https://github.com/cedricporter/et-python/tree/master/compilers/simple-cal 参考 [1] Language Implementation Patterns [2] Compiling Little Languages in Python [3] 可爱的 Python: 使用 Spark 模块解析 [4] 用LL(1)递归下降语法器构造一个计算器 本文链接：http://everet.org/2012/05/python-spark-calculator.html &#124; © EverET.org 本文评论：No comment]]></description>
			<content:encoded><![CDATA[<h2>Spark简介</h2>
<p>Spark 解析器与 EBNF 语法有一些共同之处，但它将解析／处理过程分成了比传统的 EBNF 语法所允许的更小的组件。Spark 的优点在于，它对整个过程中每一步操作的控制都进行了微调，还提供了将定制代码插入到过程中的能力。</p>
<p>Spark的最新版是10年前发布的，真是非常的长寿，可见设计精良。其中的采用的设计模式有Reflection Pattern、Visitor Pattern、Pipes and Filters Pattern和Strategy Pattern。</p>
<h2>初识Spark</h2>
<p>第一次知道Spark这个模块是在IBM的网站<a href="http://everet.org/2012/05/python-spark-calculator.html#reference-everet-3">[3]</a>上看到的。</p>
<p>第一次激起我学习这个模块的兴趣是在看Python源码的时候，发现Python的编译器是用The Zephyr Abstract Syntax Description Language(Parser/Python.asdl)来定义的语法，然后通过(Parser/asdl.py、Parser/asdl_c.py、Parser/spark.py)根据Parser/Python.asdl生成C语言解析器。其中仅用了1000多行就实现了一个yacc。这个是非常地强大。<span id="more-1076"></span></p>
<h2>计算器</h2>
<p>对于计算器的构造，我们在<a href="http://everet.org/2012/05/calculator-by-recursive-descent-parser.html">上文中</a>使用LL(1)递归下降的方法构造了一个。但是Spark更加强大，Spark是用Earley语法分析算法，能够解析所有的上下文无关文法，这比LL和LR要更强，当然代价是更慢。</p>
<p>我们来看用Spark实现的计算器：</p>
<pre class="brush: python; title: ; notranslate">
#!/usr/bin/env python
# author:  Hua Liang [ Stupid ET ]
# email:   et@everet.org
# website: http://EverET.org
#

# Grammar:
#     expr    ::= expr addop term | term
#     term    ::= term mulop factor | factor
#     factor  ::= number | ( expr )
#     addop   ::= + | -
#     mulop   ::= * | /

from spark import GenericParser, GenericScanner

class Token(object):
    def __init__(self, type, attr=''):
        self.type = type
        self.attr = attr
    def __cmp__(self, o):
        return cmp(self.type, o)
    def __str__(self):
        return self.type
    def __repr__(self):
        return str(self)

class SimpleScanner(GenericScanner, object):
    def __init__(self):
        GenericScanner.__init__(self)

    def tokenize(self, input):
        self.rv = []
        GenericScanner.tokenize(self, input)
        return self.rv

    def t_whitespace(self, s):
        r' \s+ '
        pass

    def t_op(self, s):
        r' \+ | \- | \* | / | \( | \) '
        self.rv.append(Token(type=s))

    def t_number(self, s):
        r' \d+ '
        self.rv.append(Token(type='number', attr=s))

class ExprParser(GenericParser):
    def __init__(self, start='expr'):
        GenericParser.__init__(self, start)

    def p_expr_term_0(self, (lhs, op, rhs)):
        '''
            expr ::= expr addop term
            term ::= term mulop factor
        '''
        return eval(str(lhs) + str(op) + str(rhs))

    def p_expr_term_factor_1(self, (v, )):
        '''
            expr ::= term
            term ::= factor
        '''
        return v

    def p_factor_1(self, (n, )):
        ' factor ::= number '
        return int(n.attr)

    def p_factor_2(self, (_0, expr, _1)):
        ' factor ::= ( expr ) '
        return expr

    def p_addop_mulop(self, (op, )):
        '''
            addop ::= +
            addop ::= -
            mulop ::= *
            mulop ::= /
        '''
        return op

def scan(code):
    scanner = SimpleScanner()
    return scanner.tokenize(code)

def parse(tokens):
    parser = ExprParser()
    return parser.parse(tokens)

if __name__ == '__main__':
    text = ' 7 + (1 + 3) * 5'
    print parse(scan(text))
</pre>
<p>源码请见：<a href="https://github.com/cedricporter/et-python/tree/master/compilers/simple-cal" target="_blank">https://github.com/cedricporter/et-python/tree/master/compilers/simple-cal</a></p>
<h2>参考</h2>
<p>[1] Language Implementation Patterns</p>
<p>[2] Compiling Little Languages in Python</p>
<p><span id="reference-everet-3">[3]</span> <a href="https://www.ibm.com/developerworks/cn/linux/sdk/python/charm-27/" target="_blank">可爱的 Python: 使用 Spark 模块解析</a></p>
<p>[4] <a href="http://everet.org/2012/05/calculator-by-recursive-descent-parser.html">用LL(1)递归下降语法器构造一个计算器</a></p>
<hr />
<p><small>
本文链接：<a href="http://everet.org/2012/05/python-spark-calculator.html">http://everet.org/2012/05/python-spark-calculator.html | © EverET.org</a> <br/>
本文评论：<a href="http://everet.org/2012/05/python-spark-calculator.html#comments">No comment</a> 
</small></p>]]></content:encoded>
			<wfw:commentRss>http://everet.org/2012/05/python-spark-calculator.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>用LL(1)递归下降语法器构造一个计算器</title>
		<link>http://everet.org/2012/05/calculator-by-recursive-descent-parser.html</link>
		<comments>http://everet.org/2012/05/calculator-by-recursive-descent-parser.html#comments</comments>
		<pubDate>Tue, 15 May 2012 14:00:04 +0000</pubDate>
		<dc:creator>Stupid ET</dc:creator>
				<category><![CDATA[我的代码]]></category>
		<category><![CDATA[我的分享]]></category>
		<category><![CDATA[compile]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://everet.org/?p=1062</guid>
		<description><![CDATA[LL(1) 何为LL(1)？通俗来说就是向前看一个词法单元的自顶向下解析器。两个L都代表left-to-right，第一个L表示解析器按“从左到右”的顺序解析输入内容；第二个L表示下降解析时也是按“从左到右”的顺序遍历子节点。而(1)表示它使用一个向前看 词法单元。 我们从一个简单的计算器来看看递归下降的语法器如何构造。 对于 2 + 3 * 5 的抽象语法树如下： 我们可以使用如下文法表示计算表达式： # expr ::= expr addop term &#124; term # term ::= term mulop factor &#124; factor # factor ::= number &#124; ( expr ) # addop ::= + &#124; - # mulop ::= * &#124; / 例子 我们用Python构造一个递归下降实现的计算器。 对于12 + 2 * (<a href="http://everet.org/2012/05/calculator-by-recursive-descent-parser.html"> <br /><br /> (More)…</a>]]></description>
			<content:encoded><![CDATA[<h2>LL(1)</h2>
<p>何为LL(1)？通俗来说就是向前看一个词法单元的自顶向下解析器。两个L都代表left-to-right，第一个L表示解析器按“从左到右”的顺序解析输入内容；第二个L表示下降解析时也是按“从左到右”的顺序遍历子节点。而(1)表示它使用一个向前看 词法单元。</p>
<p>我们从一个简单的计算器来看看递归下降的语法器如何构造。</p>
<p>对于 2 + 3 * 5 的抽象语法树如下：<span id="more-1062"></span></p>
<p><a href="http://everet.org/wp-content/uploads/2012/05/Screenshot-from-2012-05-15-213202.png" rel="lightbox[1062]"><img class="alignnone size-full wp-image-1065" title="Screenshot from 2012-05-15 21:32:02" src="http://everet.org/wp-content/uploads/2012/05/Screenshot-from-2012-05-15-213202.png" alt="" width="244" height="242" /></a></p>
<p>我们可以使用如下文法表示计算表达式：</p>
<p># expr ::= expr addop term | term<br />
# term ::= term mulop factor | factor<br />
# factor ::= number | ( expr )<br />
# addop ::= + | -<br />
# mulop ::= * | /</p>
<h2>例子</h2>
<p>我们用Python构造一个递归下降实现的计算器。</p>
<pre class="brush: python; highlight: [79]; title: ; notranslate">
#!/usr/bin/env python
# author:  Hua Liang [ Stupid ET ]
# email:   et@everet.org
# website: http://EverET.org
#

# Grammar:
#     expr    ::= expr addop term | term
#     term    ::= term mulop factor | factor
#     factor  ::= number | ( expr )
#     addop   ::= + | -
#     mulop   ::= * | /

import tokenize, StringIO

tokens = None
cur_tok = None

def scan(text):
    g = tokenize.generate_tokens(
        StringIO.StringIO(text).readline)
    return ((v[0], v[1]) for v in g)

def get_token():
    global tokens, cur_tok
    cur_tok = tokens.next()
    #print cur_tok
    return cur_tok

def match(type, val = ''):
    global tokens, cur_tok
    t, v = cur_tok
    if t == type or t == tokenize.OP and v == val:
        get_token()
    else:
        raise

def expr():
    global cur_tok
    tmp = term()
    t, v = cur_tok
    while v == '+' or v == '-':
        match(tokenize.OP)
        rhs = term()
        e = str(tmp) + str(v) + str(rhs)
        tmp = eval(e)
        print e, '=', tmp
        t, v = cur_tok
    return tmp

def term():
    global cur_tok
    tmp = factor()
    t, v = cur_tok
    while v == '*' or v == '/':
        match(tokenize.OP)
        rhs = factor()
        e = str(tmp) + str(v) + str(rhs)
        tmp = eval(e)
        print e, '=', tmp
        t, v = cur_tok
    return tmp

def factor():
    global cur_tok
    t, v = cur_tok
    if t == tokenize.NUMBER:
        match(tokenize.NUMBER)
        return int(v)
    elif v == '(':
        match(tokenize.OP, '(')
        tmp = expr()
        match(tokenize.OP, ')')
        return tmp
    else:
        raise

if __name__ == '__main__':
    text = '12 + 2 * ( 5 + 6 )'
    tokens = scan(text)
    get_token()
    res = expr()
    print text, '=', res
</pre>
<p>对于12 + 2 * ( 5 + 6 )，运行结果如下：<br />
<a href="http://everet.org/wp-content/uploads/2012/05/Screenshot-from-2012-05-15-214802.png" rel="lightbox[1062]"><img class="alignnone size-full wp-image-1066" title="Screenshot from 2012-05-15 21:48:02" src="http://everet.org/wp-content/uploads/2012/05/Screenshot-from-2012-05-15-214802.png" alt="" width="424" height="90" /></a></p>
<p>源码请见：<a href="https://github.com/cedricporter/et-python/blob/master/compilers/func-cal/main.py" target="_blank">https://github.com/cedricporter/et-python/blob/master/compilers/func-cal/main.py</a></p>
<h2>参考</h2>
<p>[1] Language Implementation Patterns</p>
<p>[2] Compiling Little Languages in Python</p>
<p>[3] <a href="http://everet.org/2012/05/python-spark-calculator.html">Python使用spark模块构造计算器</a></p>
<hr />
<p><small>
本文链接：<a href="http://everet.org/2012/05/calculator-by-recursive-descent-parser.html">http://everet.org/2012/05/calculator-by-recursive-descent-parser.html | © EverET.org</a> <br/>
本文评论：<a href="http://everet.org/2012/05/calculator-by-recursive-descent-parser.html#comments">No comment</a> 
</small></p>]]></content:encoded>
			<wfw:commentRss>http://everet.org/2012/05/calculator-by-recursive-descent-parser.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>构建LL(1)递归下降语法解析器</title>
		<link>http://everet.org/2012/05/building-recursive-descent-parser.html</link>
		<comments>http://everet.org/2012/05/building-recursive-descent-parser.html#comments</comments>
		<pubDate>Tue, 15 May 2012 13:59:07 +0000</pubDate>
		<dc:creator>Stupid ET</dc:creator>
				<category><![CDATA[我的代码]]></category>
		<category><![CDATA[我的分享]]></category>
		<category><![CDATA[compile]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://everet.org/?p=1056</guid>
		<description><![CDATA[不管什么语言应用，识别语言这一步都很重要。 在小学时，大家都学习过如何分辨句子中的不同语言成分，例如动词和名词等。识别计算机语言也是如此（我们称之为语法分析）。 小例子 我们来看一下： return x + 1; 语法图： 解析树： 树上的叶节点是词法单元，分子节点表示推导式中的子结构。 我们来看一下手工编写语言解析器。 为了验证语句的是否合法，解析器需要识别语句的解析树。但是，解析器不一定在内存中构造这么一个树状结构。一般情况下，我们只需要在遇到子结构时采用适当的操作即可。也就是说，解析器的任务是“遇到某些结构，就执行某些操作”。 为了避免构造解析树，我们通过函数调用序列隐私地得到他们的信息。我们要做的事情就是为每一个子结构构造一个函数。 stat  ::= returnstat returnstat ::= “return” expr “;” expr ::= “x” “+” “1&#8243; 构造出来的函数： /** To parse a statement, call stat(); */ void stat() { returnstat(); } void returnstat() { match(“return” ); expr(); match(“;” ); } void expr() { match(“x” );<a href="http://everet.org/2012/05/building-recursive-descent-parser.html"> <br /><br /> (More)…</a>]]></description>
			<content:encoded><![CDATA[<p>不管什么语言应用，识别语言这一步都很重要。</p>
<p>在小学时，大家都学习过如何分辨句子中的不同语言成分，例如动词和名词等。识别计算机语言也是如此（我们称之为语法分析）。</p>
<h2>小例子</h2>
<p>我们来看一下：</p>
<blockquote><p>return x + 1;</p></blockquote>
<p>语法图：<span id="more-1056"></span></p>
<p><a href="http://everet.org/wp-content/uploads/2012/05/Screenshot-from-2012-05-15-210601.png" rel="lightbox[1056]"><img class="alignnone size-full wp-image-1058" title="Screenshot from 2012-05-15 21:06:01" src="http://everet.org/wp-content/uploads/2012/05/Screenshot-from-2012-05-15-210601.png" alt="" width="165" height="113" /></a></p>
<p>解析树：</p>
<p><a href="http://everet.org/wp-content/uploads/2012/05/Screenshot-from-2012-05-15-210616.png" rel="lightbox[1056]"><img class="alignnone size-full wp-image-1059" title="Screenshot from 2012-05-15 21:06:16" src="http://everet.org/wp-content/uploads/2012/05/Screenshot-from-2012-05-15-210616.png" alt="" width="152" height="165" /></a></p>
<p>树上的叶节点是词法单元，分子节点表示推导式中的子结构。</p>
<p>我们来看一下手工编写语言解析器。</p>
<p>为了验证语句的是否合法，解析器需要识别语句的解析树。但是，解析器不一定在内存中构造这么一个树状结构。一般情况下，我们只需要在遇到子结构时采用适当的操作即可。也就是说，解析器的任务是“遇到某些结构，就执行某些操作”。</p>
<p>为了避免构造解析树，我们通过函数调用序列隐私地得到他们的信息。我们要做的事情就是为每一个子结构构造一个函数。</p>
<blockquote><p>stat  ::= returnstat</p>
<p>returnstat ::= “return” expr “;”</p>
<p>expr ::= “x” “+” “1&#8243;</p></blockquote>
<p>构造出来的函数：</p>
<blockquote><p>/** To parse a statement, call stat(); */<br />
void stat()<br />
{ returnstat(); }<br />
void returnstat() { match(“return” ); expr(); match(“;” ); }<br />
void expr()<br />
{ match(“x” ); match(“+” ); match(“1&#8243; ); }</p></blockquote>
<p>如何解析if、return和赋值语句呢？</p>
<p>我们可以将stat实现成这样。</p>
<blockquote><p>void stat() {<br />
if ( «lookahead token is return » )               returnstat();<br />
else if ( «lookahead token is identifier » ) assign();<br />
else if ( «lookahead token is if » )                ifstat();<br />
else «parse error »<br />
}</p></blockquote>
<p>如果要手写这种解析器，头几个可能挺好玩的，但是这样的活多干几次就会觉得很无聊了。</p>
<h2>例子</h2>
<ul>
<li><a href="http://everet.org/2012/05/calculator-by-recursive-descent-parser.html">用Python实现的LL(1)递归下降语法器计算器</a></li>
<li><a href="http://everet.org/2012/05/python-spark-calculator.html">Python使用spark模块构造计算器</a></li>
</ul>
<h2>参考</h2>
<p>[1] Language Implementation Patterns</p>
<p>[2] Compiling Little Languages in Python</p>
<hr />
<p><small>
本文链接：<a href="http://everet.org/2012/05/building-recursive-descent-parser.html">http://everet.org/2012/05/building-recursive-descent-parser.html | © EverET.org</a> <br/>
本文评论：<a href="http://everet.org/2012/05/building-recursive-descent-parser.html#comments">No comment</a> 
</small></p>]]></content:encoded>
			<wfw:commentRss>http://everet.org/2012/05/building-recursive-descent-parser.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python文法</title>
		<link>http://everet.org/2012/05/python-grammar.html</link>
		<comments>http://everet.org/2012/05/python-grammar.html#comments</comments>
		<pubDate>Mon, 14 May 2012 11:09:29 +0000</pubDate>
		<dc:creator>Stupid ET</dc:creator>
				<category><![CDATA[我的分享]]></category>
		<category><![CDATA[compile]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://everet.org/?p=1039</guid>
		<description><![CDATA[文法以一种简洁的形式描述着语言的语法。 以下是Python的文法，摘自Python源码目录下的Grammar/Grammar。 Python的编译器的设计：http://www.python.org/dev/peps/pep-0339/ The Zephyr Abstract Syntax Description Language.pdf 本文链接：http://everet.org/2012/05/python-grammar.html &#124; © EverET.org 本文评论：2 comments]]></description>
			<content:encoded><![CDATA[<p>文法以一种简洁的形式描述着语言的语法。</p>
<p>以下是Python的文法，摘自Python源码目录下的Grammar/Grammar。</p>
<p>Python的编译器的设计：<a href="http://www.python.org/dev/peps/pep-0339/" target="_blank">http://www.python.org/dev/peps/pep-0339/</a></p>
<p><a href="http://everet.org/wp-content/uploads/2012/05/The-Zephyr-Abstract-Syntax-Description-Language.pdf">The Zephyr Abstract Syntax Description Language.pdf</a></p>
<p><span id="more-1039"></span></p>
<pre class="brush: python; title: ; notranslate">
# Start symbols for the grammar:
#       single_input is a single interactive statement;
#       file_input is a module or sequence of commands read from an input file;
#       eval_input is the input for the eval() and input() functions.
# NB: compound_stmt in single_input is followed by extra NEWLINE!
single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
file_input: (NEWLINE | stmt)* ENDMARKER
eval_input: testlist NEWLINE* ENDMARKER

decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
decorators: decorator+
decorated: decorators (classdef | funcdef)
funcdef: 'def' NAME parameters ':' suite
parameters: '(' [varargslist] ')'
varargslist: ((fpdef ['=' test] ',')*
              ('*' NAME [',' '**' NAME] | '**' NAME) |
              fpdef ['=' test] (',' fpdef ['=' test])* [','])
fpdef: NAME | '(' fplist ')'
fplist: fpdef (',' fpdef)* [',']

stmt: simple_stmt | compound_stmt
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
small_stmt: (expr_stmt | print_stmt  | del_stmt | pass_stmt | flow_stmt |
             import_stmt | global_stmt | exec_stmt | assert_stmt)
expr_stmt: testlist (augassign (yield_expr|testlist) |
                     ('=' (yield_expr|testlist))*)
augassign: ('+=' | '-=' | '*=' | '/=' | '%=' | '&amp;=' | '|=' | '^=' |
            '&lt;# For normal assignments,
# additional restrictions enforced by the interpreter
print_stmt: 'print' ( [ test (',' test)* [','] ] |
                      '&gt;&gt;' test [ (',' test)+ [','] ] )
del_stmt: 'del' exprlist
pass_stmt: 'pass'
flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt
break_stmt: 'break'
continue_stmt: 'continue'
return_stmt: 'return' [testlist]
yield_stmt: yield_expr
raise_stmt: 'raise' [test [',' test [',' test]]]
import_stmt: import_name | import_from
import_name: 'import' dotted_as_names
import_from: ('from' ('.'* dotted_name | '.'+)
              'import' ('*' | '(' import_as_names ')' | import_as_names))
import_as_name: NAME ['as' NAME]
dotted_as_name: dotted_name ['as' NAME]
import_as_names: import_as_name (',' import_as_name)* [',']
dotted_as_names: dotted_as_name (',' dotted_as_name)*
dotted_name: NAME ('.' NAME)*
global_stmt: 'global' NAME (',' NAME)*
exec_stmt: 'exec' expr ['in' test [',' test]]
assert_stmt: 'assert' test [',' test]

compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
while_stmt: 'while' test ':' suite ['else' ':' suite]
for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]
try_stmt: ('try' ':' suite
           ((except_clause ':' suite)+
            ['else' ':' suite]
            ['finally' ':' suite] |
           'finally' ':' suite))
with_stmt: 'with' with_item (',' with_item)*  ':' suite
with_item: test ['as' expr]
# NB compile.c makes sure that the default except clause is last
except_clause: 'except' [test [('as' | ',') test]]
suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT

# Backward compatibility cruft to support:
# [ x for x in lambda: True, lambda: False if x() ]
# even while also allowing:
# lambda x: 5 if x else 2
# (But not a mix of the two)
testlist_safe: old_test [(',' old_test)+ [',']]
old_test: or_test | old_lambdef
old_lambdef: 'lambda' [varargslist] ':' old_test

test: or_test ['if' or_test 'else' test] | lambdef
or_test: and_test ('or' and_test)*
and_test: not_test ('and' not_test)*
not_test: 'not' not_test | comparison
comparison: expr (comp_op expr)*
comp_op: ''|'=='|'&gt;='|''|'!='|'in'|'not' 'in'|'is'|'is' 'not'
expr: xor_expr ('|' xor_expr)*
xor_expr: and_expr ('^' and_expr)*
and_expr: shift_expr ('&amp;' shift_expr)*
shift_expr: arith_expr (('&lt;&gt;') arith_expr)*
arith_expr: term (('+'|'-') term)*
term: factor (('*'|'/'|'%'|'//') factor)*
factor: ('+'|'-'|'~') factor | power
power: atom trailer* ['**' factor]
atom: ('(' [yield_expr|testlist_comp] ')' |
       '[' [listmaker] ']' |
       '{' [dictorsetmaker] '}' |
       '`' testlist1 '`' |
       NAME | NUMBER | STRING+)
listmaker: test ( list_for | (',' test)* [','] )
testlist_comp: test ( comp_for | (',' test)* [','] )
lambdef: 'lambda' [varargslist] ':' test
trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
subscriptlist: subscript (',' subscript)* [',']
subscript: '.' '.' '.' | test | [test] ':' [test] [sliceop]
sliceop: ':' [test]
exprlist: expr (',' expr)* [',']
testlist: test (',' test)* [',']
dictorsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) |
                  (test (comp_for | (',' test)* [','])) )

classdef: 'class' NAME ['(' [testlist] ')'] ':' suite

arglist: (argument ',')* (argument [',']
                         |'*' test (',' argument)* [',' '**' test]
                         |'**' test)
# The reason that keywords are test nodes instead of NAME is that using NAME
# results in an ambiguity. ast.c makes sure it's a NAME.
argument: test [comp_for] | test '=' test

list_iter: list_for | list_if
list_for: 'for' exprlist 'in' testlist_safe [list_iter]
list_if: 'if' old_test [list_iter]

comp_iter: comp_for | comp_if
comp_for: 'for' exprlist 'in' or_test [comp_iter]
comp_if: 'if' old_test [comp_iter]

testlist1: test (',' test)*

# not used in grammar, but may appear in &quot;node&quot; passed from Parser to Compiler
encoding_decl: NAME

yield_expr: 'yield' [testlist]
</pre>
<hr />
<p><small>
本文链接：<a href="http://everet.org/2012/05/python-grammar.html">http://everet.org/2012/05/python-grammar.html | © EverET.org</a> <br/>
本文评论：<a href="http://everet.org/2012/05/python-grammar.html#comments">2 comments</a> 
</small></p>]]></content:encoded>
			<wfw:commentRss>http://everet.org/2012/05/python-grammar.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>我喜欢的那些书</title>
		<link>http://everet.org/2012/05/favorite-books.html</link>
		<comments>http://everet.org/2012/05/favorite-books.html#comments</comments>
		<pubDate>Wed, 09 May 2012 15:40:15 +0000</pubDate>
		<dc:creator>Stupid ET</dc:creator>
				<category><![CDATA[我的分享]]></category>
		<category><![CDATA[我的生活]]></category>

		<guid isPermaLink="false">http://everet.org/?p=1018</guid>
		<description><![CDATA[C/C++ 深度搜索C++对象模型 只有看了这本书才会明白什么是C++ STL源码剖析 STL的设计思想非常值得学习。像内存池和各种通用的接口等思想都要细细品味。 C专家编程 有很多好的技巧。 Effective C++ More Effective C++ C++标准程序库 讲C++ STL怎么用，相当于字典，当然看熟了对STL的接口也会熟一些，写C++相对也快一下。其中的Functor的介绍挺好的。 C++ Primer C++编程宝典 以前我家那边比较落后，只有零星的C++书籍，可惜没有《C++ Primer》，而且当时我也不知有一本书叫《C++ Primer》。于是它成了我的第一本C++教材，虽然当时还有一些清华大学的人写的C++书，不过太恶劣就扔在一边专门看这本，看了很多很多遍，收获了很多。 C++编程思想 一站式学习C编程 介绍了在Linux下写C的一些入门知识 Python Python源码剖析 不看这本书，可能会无法真正明白Python的工作机制。难道你不想知道C语言是如何实现内存池、对象池、灵活的面向对象语言和垃圾回收机制吗？想得话这本书都有涉猎。 Python Cookbook 里面有各种大牛写的好玩的Python小程序。 Python基础教程 作为Python的入门书挺好的。 Python核心编程 比入门书稍微深入一点。 Python灰帽子——黑客与逆向工程师的Python编程之道 不解释，我喜欢。 Python Unix和Linux系统管理指南 *nix Unix网络编程 两卷 Unix环境高级编程 TCP/IP详解 三卷 想学网络不看这一系列书就该打。 Unix操作系统设计 这本传世经典书籍不用解释，当年Linus也是看着这本书写了Linux。 Linux系统管理技术手册 Linus推荐的Linux书，讲怎么使用Linux。 Linux程序设计 基本的Linux编程。 鸟哥的Linux私房菜 和Linux系统管理技术手册相似，不过简单有趣一点。 Linux命令、编辑器与Shell编程 各种东西混杂在里面，看看增长见识。<a href="http://everet.org/2012/05/favorite-books.html"> <br /><br /> (More)…</a>]]></description>
			<content:encoded><![CDATA[<h2>C/C++</h2>
<p><strong>深度搜索C++对象模型</strong></p>
<p style="padding-left: 60px;">只有看了这本书才会明白什么是C++</p>
<p><strong>STL源码剖析</strong></p>
<p style="padding-left: 60px;">STL的设计思想非常值得学习。像内存池和各种通用的接口等思想都要细细品味。</p>
<p><strong>C专家编程</strong></p>
<p style="padding-left: 60px;">有很多好的技巧。</p>
<p><strong>Effective C++<span id="more-1018"></span></strong></p>
<p><strong>More Effective C++</strong></p>
<p><strong>C++标准程序库</strong></p>
<p style="padding-left: 60px;">讲C++ STL怎么用，相当于字典，当然看熟了对STL的接口也会熟一些，写C++相对也快一下。其中的Functor的介绍挺好的。</p>
<p><strong>C++ Primer</strong></p>
<p><strong>C++编程宝典</strong></p>
<p style="padding-left: 60px;">以前我家那边比较落后，只有零星的C++书籍，可惜没有《C++ Primer》，而且当时我也不知有一本书叫《C++ Primer》。于是它成了我的第一本C++教材，虽然当时还有一些清华大学的人写的C++书，不过太恶劣就扔在一边专门看这本，看了很多很多遍，收获了很多。</p>
<p><strong>C++编程思想</strong></p>
<p><strong>一站式学习C编程</strong></p>
<p style="padding-left: 60px;">介绍了在Linux下写C的一些入门知识</p>
<hr />
<h2>Python</h2>
<p><strong>Python源码剖析</strong></p>
<p style="padding-left: 60px;">不看这本书，可能会无法真正明白Python的工作机制。难道你不想知道C语言是如何实现内存池、对象池、灵活的面向对象语言和垃圾回收机制吗？想得话这本书都有涉猎。</p>
<p><strong>Python Cookbook</strong></p>
<p style="padding-left: 60px;">里面有各种大牛写的好玩的Python小程序。</p>
<p><strong>Python基础教程</strong></p>
<p style="padding-left: 60px;">作为Python的入门书挺好的。</p>
<p><strong>Python核心编程</strong></p>
<p style="padding-left: 60px;">比入门书稍微深入一点。</p>
<p><strong>Python灰帽子——黑客与逆向工程师的Python编程之道</strong></p>
<p style="padding-left: 60px;">不解释，我喜欢。</p>
<p><strong>Python Unix和Linux系统管理指南</strong></p>
<hr />
<h2>*nix</h2>
<p><strong>Unix网络编程 两卷</strong></p>
<p><strong>Unix环境高级编程</strong></p>
<p><strong>TCP/IP详解 三卷</strong></p>
<p style="padding-left: 60px;">想学网络不看这一系列书就该打。</p>
<p><strong>Unix操作系统设计</strong></p>
<p style="padding-left: 60px;">这本传世经典书籍不用解释，当年Linus也是看着这本书写了Linux。</p>
<p><strong>Linux系统管理技术手册</strong></p>
<p style="padding-left: 60px;">Linus推荐的Linux书，讲怎么使用Linux。</p>
<p><strong>Linux程序设计</strong></p>
<p style="padding-left: 60px;">基本的Linux编程。</p>
<p><strong>鸟哥的Linux私房菜</strong></p>
<p style="padding-left: 60px;">和Linux系统管理技术手册相似，不过简单有趣一点。</p>
<p><strong>Linux命令、编辑器与Shell编程</strong></p>
<p style="padding-left: 60px;">各种东西混杂在里面，看看增长见识。</p>
<hr />
<h2>Windows</h2>
<p><strong>深入浅出MFC</strong></p>
<p style="padding-left: 60px;">学习一些MFC框架非常有必要，MFC曾经是一个非常优秀的C++框架。设计优美。</p>
<p><strong>Windows核心编程</strong></p>
<p style="padding-left: 60px;">有各种Windows底层的接口介绍。要写Windows上的病毒木马就得看这本。</p>
<hr />
<h2>语言设计</h2>
<p><strong>编程语言实现模式</strong></p>
<p style="padding-left: 60px;">Python语言之父Guido推荐。</p>
<blockquote style="padding-left: 60px;"><p>我的“龙书”被打入冷宫了！ —— Guido Van Rossum</p></blockquote>
<p style="padding-left: 60px;">确实很棒。</p>
<p><strong>编译原理及实践</strong></p>
<p style="padding-left: 60px;">我们的编译原理教材，作为编译的入门书挺好的，也可能是因为有老师讲一下还有PPT，阅读起来挺方便的。</p>
<p><strong>编译原理</strong></p>
<p style="padding-left: 60px;">龙书。有个本科教学版，挺好的。</p>
<p><strong>程序设计语言概念</strong><br />
<strong>flex与bison</strong></p>
<hr />
<h2>计算机科学</h2>
<p><strong>深入理解计算机系统</strong></p>
<p style="padding-left: 60px;">卡内基梅隆的计算机系统导论的教材。我觉得作为一个搞计算机的人必须得看，比计算机组成的书好看多了。</p>
<p><strong>程序员的自我修养——链接、装载与库</strong></p>
<p style="padding-left: 60px;">如题，讲链接、装载与库。可能会比《Linker and Loader》更适合中国人看，因为是中国人写的，不会出现奇怪的翻译。</p>
<p><strong>加密与解密</strong></p>
<p style="padding-left: 60px;">看雪论坛出品。这个非常有趣，非常适合中国国情。有讲各种破解技术。</p>
<hr />
<h2>软件工程</h2>
<p><strong>Unix编程艺术</strong></p>
<p style="padding-left: 60px;">最喜欢的书。启发性非常强。</p>
<p><strong>代码大全</strong></p>
<p style="padding-left: 60px;">也很强大。</p>
<p><strong>程序员修炼之道——从小工到专家</strong></p>
<p style="padding-left: 60px;">同上。</p>
<p><strong>UML和模式应用</strong></p>
<p style="padding-left: 60px;">我们《软件需求分析与建模》的教材。是刘艳霞老师选的教材，和其他班不一样。这本书讲解软件工程的一些过程，其中关于用例的部分对我启示很大。</p>
<p><strong>设计模式</strong></p>
<p style="padding-left: 60px;">GoF。似乎后面出版的设计模式的书大都是相当于这本书的辅导书。</p>
<p><strong>深入浅出设计模式</strong><br />
<strong>大话设计模式</strong><br />
<strong>面向模式的软件架构 五卷</strong><br />
<strong>企业应用架构模式</strong><br />
<strong>重构 改善既有代码的设计</strong><br />
<strong>敏捷软件开发 原则、模式与实践</strong></p>
<hr />
<h2>技巧</h2>
<p><strong>编程珠玑</strong><br />
<strong>算法导论</strong><br />
<strong>计算机程序设计艺术         <span style="color: #3366ff;"> </span></strong></p>
<p style="padding-left: 60px;">对这套书很仰慕，不过短期无法读懂，所以只是仰慕&#8230;&#8230;.</p>
<hr />
<h2>工具</h2>
<p><strong>Pro Git</strong></p>
<p style="padding-left: 60px;">可能是学习Git最好的书了，免费的。</p>
<p><strong>Git权威指南</strong><br />
<strong>Make手册</strong><br />
<strong>Vim帮助文档</strong><br />
<strong>Emacs的帮助文档</strong></p>
<hr />
<h2>思想</h2>
<p><strong>浪潮之巅</strong><br />
<strong>黑客与画家</strong><br />
<strong>黑客</strong></p>
<p style="padding-left: 60px;">各种大牛的故事。</p>
<p><strong>非同凡想</strong><br />
<strong>异类：不一样的成功启示录</strong><br />
<strong>活着就为了改变世界</strong><br />
<strong>软件随想录</strong><br />
<strong>计算机的心智 操作系统之哲学原理</strong></p>
<hr />
<h2>其他</h2>
<p><strong>黑客防线</strong><br />
<strong>黑客X档案</strong></p>
<p>貌似因为某些原因，这类的杂志都没得卖了。</p>
<hr />
<h2>生活</h2>
<p>卡内基写的各种书</p>
<hr />
<p><small>
本文链接：<a href="http://everet.org/2012/05/favorite-books.html">http://everet.org/2012/05/favorite-books.html | © EverET.org</a> <br/>
本文评论：<a href="http://everet.org/2012/05/favorite-books.html#comments">7 comments</a> 
</small></p>]]></content:encoded>
			<wfw:commentRss>http://everet.org/2012/05/favorite-books.html/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Python根据图片生成字符画</title>
		<link>http://everet.org/2012/05/python-ascii-art.html</link>
		<comments>http://everet.org/2012/05/python-ascii-art.html#comments</comments>
		<pubDate>Sun, 06 May 2012 12:50:19 +0000</pubDate>
		<dc:creator>Stupid ET</dc:creator>
				<category><![CDATA[我的代码]]></category>
		<category><![CDATA[我的分享]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[图像处理]]></category>

		<guid isPermaLink="false">http://everet.org/?p=1012</guid>
		<description><![CDATA[字符画很好玩，我们来看看怎样将一张图片变成字符画。 我们首先将图片变成黑白的，那么每个像素的取值范围为：0-255. 然后我们将0-255映射到0-14的范围上，然后用如下字符代替： color = &#8216;MNHQ$OC?7&#62;!:-;.&#8217; 也就是像素为0的点用“M”表示，像素为14的点用“.”表示。 原理非常的简单，我们用Python来编写的话也非常的简单。只要借助PIL，就可以很轻松地在Python中处理图像。 我们来看一段代码： 整个程序的核心都在下面两行，一个是字符的色阶表，一个是映射公式。 color = 'MNHQ$OC?7&#62;!:-;.' pic_str += color[int(pix[w, h]) * 14 / 255] 效果如下： 原图： 字符画： 在线的图片字符画生成请见：http://everet.org:1758/ 源码：https://github.com/cedricporter/et-python/tree/master/web%20server/webpy 本文链接：http://everet.org/2012/05/python-ascii-art.html &#124; © EverET.org 本文评论：2 comments]]></description>
			<content:encoded><![CDATA[<p>字符画很好玩，我们来看看怎样将一张图片变成字符画。</p>
<p>我们首先将图片变成黑白的，那么每个像素的取值范围为：0-255.</p>
<p>然后我们将0-255映射到0-14的范围上，然后用如下字符代替：</p>
<p>color = &#8216;MNHQ$OC?7&gt;!:-;.&#8217;</p>
<p>也就是像素为0的点用“M”表示，像素为14的点用“.”表示。</p>
<p>原理非常的简单，我们用Python来编写的话也非常的简单。只要借助PIL，就可以很轻松地在Python中处理图像。</p>
<p>我们来看一段代码：<span id="more-1012"></span></p>
<pre class="brush: python; title: ; notranslate">
import Image

color = 'MNHQ$OC?7&gt;!:-;.'

def to_html(func):
    html_head = '''
            &lt;html&gt;
              &lt;head&gt;
                &lt;style type=&quot;text/css&quot;&gt;
                  body {font-family:Monospace; font-size:5px;}
                &lt;/style&gt;
              &lt;/head&gt;
            &lt;body&gt; '''
    html_tail = '&lt;/body&gt;&lt;/html&gt;'

    def wrapper(img):
        pic_str = func(img)
        pic_str = ''.join(l + ' &lt;br/&gt;' for l in pic_str.splitlines())
        return html_head + pic_str + html_tail

    return wrapper

@to_html
def make_char_img(img):
    pix = img.load()
    pic_str = ''
    width, height = img.size
    for h in xrange(height):
        for w in xrange(width):
            pic_str += color[int(pix[w, h]) * 14 / 255]
        pic_str += '\n'
    return pic_str

def preprocess(img_name):
    img = Image.open(img_name)

    w, h = img.size
    m = max(img.size)
    delta = m / 200.0
    w, h = int(w / delta), int(h / delta)
    img = img.resize((w, h))
    img = img.convert('L')

    return img

def save_to_file(filename, pic_str):
    outfile = open(filename, 'w')
    outfile.write(pic_str)
    outfile.close()

def main():
    img = preprocess('6.jpg')
    pic_str = make_char_img(img)
    save_to_file('char.html', pic_str)

if __name__ == '__main__':
    main()
</pre>
<p>整个程序的核心都在下面两行，一个是字符的色阶表，一个是映射公式。</p>
<blockquote>
<pre>color = 'MNHQ$OC?7&gt;!:-;.'
pic_str += color[int(pix[w, h]) * 14 / 255]</pre>
</blockquote>
<p>效果如下：</p>
<p>原图：</p>
<p><a href="http://everet.org/wp-content/uploads/2012/05/Screenshot-from-2012-05-06-203607.png" rel="lightbox[1012]"><img title="Screenshot from 2012-05-06 20:36:07" src="http://everet.org/wp-content/uploads/2012/05/Screenshot-from-2012-05-06-203607.png" alt="" width="474" height="305" /></a></p>
<p>字符画：</p>
<p><a href="http://everet.org/wp-content/uploads/2012/05/f8e22973ddcb35e46163c796bce096fcScreenshot-at-2012-04-25-161736.png" rel="lightbox[1012]"><img class="alignnone size-full wp-image-1013" title="f8e22973ddcb35e46163c796bce096fcScreenshot at 2012-04-25 16:17:36" src="http://everet.org/wp-content/uploads/2012/05/f8e22973ddcb35e46163c796bce096fcScreenshot-at-2012-04-25-161736.png" alt="" width="410" height="707" /></a></p>
<p>在线的图片字符画生成请见：<a href="http://everet.org:1758/">http://everet.org:1758/</a></p>
<p>源码：<a href="https://github.com/cedricporter/et-python/tree/master/web%20server/webpy">https://github.com/cedricporter/et-python/tree/master/web%20server/webpy</a></p>
<hr />
<p><small>
本文链接：<a href="http://everet.org/2012/05/python-ascii-art.html">http://everet.org/2012/05/python-ascii-art.html | © EverET.org</a> <br/>
本文评论：<a href="http://everet.org/2012/05/python-ascii-art.html#comments">2 comments</a> 
</small></p>]]></content:encoded>
			<wfw:commentRss>http://everet.org/2012/05/python-ascii-art.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>猜想祖国的伟大的围墙的原理</title>
		<link>http://everet.org/2012/05/gfw.html</link>
		<comments>http://everet.org/2012/05/gfw.html#comments</comments>
		<pubDate>Sat, 05 May 2012 11:18:34 +0000</pubDate>
		<dc:creator>Stupid ET</dc:creator>
				<category><![CDATA[我的分享]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://everet.org/?p=999</guid>
		<description><![CDATA[防民之口，甚于防川。 引用自百度百科的对于“防民之口，甚于防川”的启示： 中国历史上有很多统治者荒淫无道，但他们又怕人民议论，就采取了压制社会言论的措施，以为可以高枕无忧、平安无事。实际上这是最愚蠢的作法，它不仅使下情无法上达，错误的政策得不到纠正，加剧社会矛盾。更可怕的在于虽然民众口上不说，但心里却充满了仇恨，只要社会矛盾到达临界点，大规模的暴乱必然爆发，给社会生产力造成极大破坏。正可谓“防民之口，甚于防川。”中国人是世界上最能忍受暴政的民族，但也是爆发起义最多的国家。 无逻辑的舆论的控制，究竟会引发什么后果呢？或许多年后答案便自己浮现。 暂且不谈论我们伟大的围墙的对于人民生活的影响，我们来看看它的技术方面的实现。 景德镇的国域网 景德镇的国域网对外的出口线路不多，只要在这些出口处架设好强大的过滤器，便可以保障国民思想安全性。这样过滤不会太麻烦，因为出口就这么几个，派兵守住就好。 在网络课上，刘孜文老师给我们讲了一个他的经历，我大致复述一下（语文很差，希望不会扭曲原意）： 老师的一个同学在收到领导指示，要弄一个省级的防火墙，这样可以方便警察叔叔将一些骗子网站、黄色网站过滤掉。于是他的同学开始鸭梨巨大了，因为一个省的对外的线路有很多很多条，很难在每一条出口安上防火墙，因为线路太多了。 这个例子说明，一个国家级的要比一个省级的围墙容易得多，原因是关口少，不像省与省之间的线路四通八达。 那么我们知道了在国域网对外的出口处有各种Cisco等强大的怪兽守住，我们来探讨一下这些怪兽的机制。 工作机制 在普遍的看法，我们伟大的围墙工作机制主要包括IP黑名单、内容过滤和DNS劫持。 IP黑名单 怪兽手里肯定把握着一份黑名单，上面写着Facebook、twitter、youtube等的ip地址，一旦发现镇民发往黑名单中地址的请求数据包，就直接无情地丢弃，当镇民等到花儿都谢了都没有收到服务器发回的包，他便生了一种叫超时的病而放弃了。 温总理曾说过：中国财富再多，除以13亿人，就少得可怜了；中国问题再小，乘以13亿人，也就很大了。 一个秒钟一个请求*13亿，就是一个很大的请求了。请问怪兽如何可以高速地在IP黑名单中查询这个ip在不在呢？ 对于ipv4，每个ip地址32位，可以看作32位无符号整形。也就是2^32个ip地址。黑名单应该也不小，怎么也有几千几万几十万吧。那么怪兽怎么处理呢？ 怪兽如果很2B的话，它会拿着收到数据包的ip一个一个地和黑名单中的ip比较，如果在黑名单里面就将其丢弃，不在那就放过它。这样怪兽花的时间是O(n)，n为黑名单的大小。 怪兽智商稍微高一点的话，它会将黑名单中的排好序，然后使用伟大的二分查找法术，就可以花O(log(n))的时间判断那个ip在不在黑名单里面。 怪事如果智商不错的话，它会构建一个4G个单位的哈希表blacklist，然后直接将ip作为索引，初始化哈希表blacklist，blacklist[ip] = 1, if ip in ip_blacklist，这样，在一个请求过来的时候，怪兽只需要花费O(1)的时间就可以知道ip在不在黑名单里面。 对于一个4G个单位的ip黑名单hash table，我们可以一个bit来表示一个ip是不是属于特殊对待ip。于是我们的ip hash table大小为： 4G bit = 4 / 8 G Byte = 0.5 GB = 512 MB 怪兽只需要有512MB的空闲内存就可以构建这么一个hash表，然后无论是多线程模式的还是多进程模式的设计都可以共享这块放hash表的内存，中途如果有新增或者取消话都可以直接更新hash表，当然可能会因为有缓存而导致不一致，但是在这个大环境下也不一那么较真，让正确率100%，所以连锁都可以不用加，这样怪兽的负担会轻很多。不过bitmap在ipv6下是不那么实际的，因为使用内存会非常巨大，2^128bit，会消耗39614081257132168796771975168GB的内存来放bitmap。可能这也是怪兽没有对ipv6下手的原因。 我们来看一段代码，描述了高效判断是否在黑名单的方法。 当然可能还有更好的方法，请赐教～ 内容过滤 曾经在一个人博客看到程序员的工作环境怎样为好，里面有一句让我影响无比深刻“访问Google的服务没有障碍”。这个真滴非常重要呀，虽然现在Google的https可以用了，不过好慢好慢，受不了啊。 像我们如果在Google搜索某些关键词后，我们从Google打开了某些网址后，不仅那些网站访问不了，而且Google就会被怪兽吃了。 Google不作恶啊，为什么要对Google那么狠&#8230;&#8230; 例如我们在Google中搜索 然后就会发现Google被吃了。 怪兽做了什么？<a href="http://everet.org/2012/05/gfw.html"> <br /><br /> (More)…</a>]]></description>
			<content:encoded><![CDATA[<h2>防民之口，甚于防川。</h2>
<p>引用自百度百科的对于“防民之口，甚于防川”的启示：</p>
<blockquote><p>中国历史上有很多统治者荒淫无道，但他们又怕人民议论，就采取了压制社会言论的措施，以为可以高枕无忧、平安无事。实际上这是最愚蠢的作法，它不仅使下情无法上达，错误的政策得不到纠正，加剧社会矛盾。更可怕的在于虽然民众口上不说，但心里却充满了仇恨，只要社会矛盾到达临界点，大规模的暴乱必然爆发，给社会生产力造成极大破坏。正可谓“防民之口，甚于防川。”中国人是世界上最能忍受暴政的民族，但也是爆发起义最多的国家。</p></blockquote>
<p>无逻辑的舆论的控制，究竟会引发什么后果呢？或许多年后答案便自己浮现。</p>
<p>暂且不谈论我们伟大的围墙的对于人民生活的影响，我们来看看它的技术方面的实现。<span id="more-999"></span></p>
<h2>景德镇的国域网</h2>
<p>景德镇的国域网对外的出口线路不多，只要在这些出口处架设好强大的过滤器，便可以保障国民思想安全性。这样过滤不会太麻烦，因为出口就这么几个，派兵守住就好。</p>
<p>在网络课上，刘孜文老师给我们讲了一个他的经历，<a href="http://everet.org/2012/05/gfw.html">我</a>大致复述一下（语文很差，希望不会扭曲原意）：</p>
<p>老师的一个同学在收到领导指示，要弄一个省级的防火墙，这样可以方便警察叔叔将一些骗子网站、黄色网站过滤掉。于是他的同学开始鸭梨巨大了，因为一个省的对外的线路有很多很多条，很难在每一条出口安上防火墙，因为线路太多了。</p>
<p>这个例子说明，一个国家级的要比一个省级的围墙容易得多，原因是关口少，不像省与省之间的线路四通八达。</p>
<p>那么我们知道了在国域网对外的出口处有各种Cisco等强大的怪兽守住，我们来探讨一下这些怪兽的机制。</p>
<h2>工作机制</h2>
<p>在普遍的看法，我们伟大的围墙工作机制主要包括IP黑名单、内容过滤和DNS劫持。</p>
<h3>IP黑名单</h3>
<p>怪兽手里肯定把握着一份黑名单，上面写着Facebook、twitter、youtube等的ip地址，一旦发现镇民发往黑名单中地址的请求数据包，就直接无情地丢弃，当镇民等到花儿都谢了都没有收到服务器发回的包，他便生了一种叫超时的病而放弃了。</p>
<p>温总理曾说过：中国财富再多，除以13亿人，就少得可怜了；中国问题再小，乘以13亿人，也就很大了。</p>
<p>一个秒钟一个请求*13亿，就是一个很大的请求了。请问怪兽如何可以高速地在IP黑名单中查询这个ip在不在呢？</p>
<p>对于ipv4，每个ip地址32位，可以看作32位无符号整形。也就是2^32个ip地址。黑名单应该也不小，怎么也有几千几万几十万吧。那么怪兽怎么处理呢？</p>
<ul>
<li>怪兽如果很2B的话，它会拿着收到数据包的ip一个一个地和黑名单中的ip比较，如果在黑名单里面就将其丢弃，不在那就放过它。这样怪兽花的时间是O(n)，n为黑名单的大小。</li>
<li>怪兽智商稍微高一点的话，它会将黑名单中的排好序，然后使用伟大的二分查找法术，就可以花O(log(n))的时间判断那个ip在不在黑名单里面。</li>
<li>怪事如果智商不错的话，它会构建一个4G个单位的哈希表blacklist，然后直接将ip作为索引，初始化哈希表blacklist，blacklist[ip] = 1, if ip in ip_blacklist，这样，在一个请求过来的时候，怪兽只需要花费O(1)的时间就可以知道ip在不在黑名单里面。</li>
</ul>
<p>对于一个4G个单位的ip黑名单hash table，我们可以一个bit来表示一个ip是不是属于特殊对待ip。于是我们的ip hash table大小为：</p>
<blockquote><p>4G bit = 4 / 8 G Byte = 0.5 GB = 512 MB</p></blockquote>
<p>怪兽只需要有512MB的空闲内存就可以构建这么一个hash表，然后无论是多线程模式的还是多进程模式的设计都可以共享这块放hash表的内存，中途如果有新增或者取消话都可以直接更新hash表，当然可能会因为有缓存而导致不一致，但是在这个大环境下也不一那么较真，让正确率100%，所以连锁都可以不用加，这样怪兽的负担会轻很多。不过bitmap在ipv6下是不那么实际的，因为使用内存会非常巨大，2^128bit，会消耗39614081257132168796771975168GB的内存来放bitmap。可能这也是怪兽没有对ipv6下手的原因。</p>
<p>我们来看一段代码，描述了高效判断是否在黑名单的方法。</p>
<pre class="brush: cpp; title: ; notranslate">
#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;sys/socket.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;arpa/inet.h&gt;

#define BITSPERWORD 32
#define SHIFT 5			// 2 ^ 5 = 32
#define MASK 0x1F		// 0x1F = (11111)b
#define SET(a, i) ((a)[(i)&gt;&gt;SHIFT] |= (1&lt;&lt;((i) &amp; MASK)))
#define CLR(a, i) ((a)[(i)&gt;&gt;SHIFT] &amp;= ~(1&lt;&lt;((i) &amp; MASK)))
#define TEST(a, i) ((a)[(i)&gt;&gt;SHIFT] &amp; (1&lt;&lt;((i) &amp; MASK)))

inline void test_block(int* blacklist, char* ip)
{
     if (TEST(blacklist, inet_addr(ip)))
	  printf(&quot;%s is blocked.\n&quot;, ip);
     else
	  printf(&quot;%s is pass.\n&quot;, ip);
}

int main(int argc, char *argv[])
{
     const unsigned long long N = 4294967295;
     const unsigned int SIZE = N / BITSPERWORD + 1;
     int* blacklist = (int*)malloc(SIZE * sizeof(int));

     memset(blacklist, SIZE, 0xff);
     SET(blacklist, inet_addr(&quot;243.185.187.39&quot;));
     SET(blacklist, inet_addr(&quot;8.8.4.4&quot;));
     SET(blacklist, inet_addr(&quot;202.84.125.66&quot;));
     SET(blacklist, inet_addr(&quot;222.221.31.55&quot;));
     SET(blacklist, inet_addr(&quot;183.182.44.111&quot;));
     SET(blacklist, inet_addr(&quot;255.255.255.156&quot;));

     test_block(blacklist, &quot;8.8.4.4&quot;);
     test_block(blacklist, &quot;222.222.222.222&quot;);
     test_block(blacklist, &quot;202.84.125.66&quot;);
     test_block(blacklist, &quot;88.54.32.156&quot;);
     test_block(blacklist, &quot;255.255.255.156&quot;);

     free(blacklist);
     return 0;
}
</pre>
<p>当然可能还有更好的方法，请赐教～</p>
<h2>内容过滤</h2>
<p>曾经在一个人博客看到程序员的工作环境怎样为好，里面有一句让我影响无比深刻“<a href="http://timyang.net/misc/work-environment-productivity/" target="_blank">访问Google的服务没有障碍</a>”。这个真滴非常重要呀，虽然现在Google的https可以用了，不过好慢好慢，受不了啊。</p>
<p>像我们如果在Google搜索某些关键词后，我们从Google打开了某些网址后，不仅那些网站访问不了，而且Google就会被怪兽吃了。</p>
<p>Google不作恶啊，为什么要对Google那么狠&#8230;&#8230;</p>
<p>例如我们在Google中搜索</p>
<p><a href="http://everet.org/wp-content/uploads/2012/05/fq.png" rel="lightbox[999]"><img class="alignnone size-full wp-image-1000" title="fq" src="http://everet.org/wp-content/uploads/2012/05/fq.png" alt="" width="51" height="27" /></a></p>
<p>然后就会发现Google被吃了。</p>
<p>怪兽做了什么？</p>
<p>怪兽首先伪造Google的ip发了许多RST包给镇民的浏览器，然后怪兽也可能伪造镇民的ip发了很多RST给Google，挑拨离间，最后镇民和Google在经过一段努力后发现还是无法沟通就不再继续通信了。</p>
<p><a href="http://everet.org/wp-content/uploads/2012/05/gfw.png" rel="lightbox[999]"><img class="alignnone size-full wp-image-1001" title="gfw" src="http://everet.org/wp-content/uploads/2012/05/gfw.png" alt="" width="693" height="634" /></a></p>
<p>怪兽应该对http包进行了扫描，看看有没有什么敏感词，有的话就伪装成对方开始卑鄙地发送RST，来挑拨离间最终实现断开连接。</p>
<h2>DNS劫持</h2>
<p>有一部分怪兽应该会专门负责污染国内DNS服务器的缓存，导致我们解析到了错误的ip。有一部分怪兽会篡改国外DNS发回的响应，导致镇民获得了错误的ip。</p>
<h2>结言</h2>
<p>防民之口，甚于防川。过度地压制景德镇的镇民似乎并不太好，希望未来的祖国会更加开放、更加发达。</p>
<p>天朝威武～</p>
<hr />
<p><small>
本文链接：<a href="http://everet.org/2012/05/gfw.html">http://everet.org/2012/05/gfw.html | © EverET.org</a> <br/>
本文评论：<a href="http://everet.org/2012/05/gfw.html#comments">5 comments</a> 
</small></p>]]></content:encoded>
			<wfw:commentRss>http://everet.org/2012/05/gfw.html/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic page generated in 0.719 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2012-05-21 15:41:39 -->

