Archive for March, 2009

01

She will be loved


artist: maroon 5
album: songs about jane
song: she will be loved

lyrics:

beauty queen of only eighteen 仅仅18岁而美丽的小女王
she had some trouble with herself 她自己内心有些烦恼
he was always there to help her 他总是会在守候着去帮助她
she always belonged to someone else 但她总是一直属于别人..

i drove for miles and miles 我驾着车子,走了许多路程
and wound up at your door 终于来到你的家门前
i’ve had you so many times but somehow 虽然我已经与你在一齐好几次,但又如何?
i want more 我想需要你的爱更多…..

i don’t mind spending everyday 我毫不介意花费我整天的时间
out on your corner in the pouring rain 在倾盘大雨中,站在你家楼下的拐角处
look for the girl with the broken smile 寻找着一个心碎微笑的女孩
ask her if she wants to stay awhile 邀请她是否想与我停留片刻
and she will be loved 和告诉她我对她的心意
she will be loved 她会拥有我的爱

tap on my window knock on my door 轻叩我的窗口,轻敲我的门
i want to make you feel beautiful 我只想令你觉得一切都美好

i know i tend to get so insecure 我知道我不太成熟
it doesn’t matter anymore 那完全不要紧

it’s not always rainbows and butterflies 世上不会总是有彩虹和蝴蝶
it’s compromise that moves us along 这使到我们不断向前行
my heart is full and my door’s always open 我的心和我的门总是为你打开
you can come anytime you want 只要你想的话,你就随时能来

i don’t mind spending everyday 我毫不介意花费我整天的时间
out on your corner in the pouring rain 在倾盘大雨中,站在你家楼下的拐角处
look for the girl with the broken smile 寻找着一个心碎微笑的女孩
ask her if she wants to stay awhile 询问她是否想与我停留片刻
and she will be loved 和告诉她我对她的心意
she will be loved 她会拥有我的爱

i know where you hide 我知道你藏身在哪里
alone in your car 独自在你的车中
know all of the things that make you who you are 晓得令你变成如此的一切
i know that goodbye means nothing at all 我也知道再见并不意味什么
comes back and begs me to catch her every time she falls 在她每次失落时都能安慰,鼓励她

【translated by 寒烟山】

LRC歌词来自:http://www.51lrc.com/asp/lrc.asp?id=20050203QPaSkS

0

暴笑:恶搞的小资文,要细看,要细品


沙尘暴来的时候,我刚刚睁开眼睛,窗外传来风铃的响声,似乎在楼上,在楼下,也许就在我家的阳台上,总之它无处不在。那是一种淡紫色的声音,是的,淡 紫色的声音。她喜欢用颜色来描述一切纤细的感觉,我从床上爬起来,身上还残留着六神花露水的香气,屋子外面升腾起黄色的雾,眼前的景物似乎都模糊起来,我 的心绪不知道为什么也自纷乱起来。我在桌子上拿起一支大前门,把它叼在嘴里,却不
  点燃,任凭烟草的清香从唇边慢慢渗透进身体里。
  她仍旧睡在我的身边,昨夜的一切似乎从未发生,只有略显凌乱的床单似乎还残留着一些模糊的记忆。不过这记忆也是若有若无,就好象她的吻一样,轻柔飘渺,仿佛偶然落在花蕊的蝴蝶。
  我站起身来,伸出右手在CD架子上随便挑了一盘,放进昨天刚刚拆封的AIWA CD机里,轻轻地按下PLAY。她曾经说过,喜欢我收藏的每一盘CD,那种闭着眼睛随意在CD架里选出一张,就是自己所中意的声音,这样的感觉是“深绿”色,她这样说。
  开头照例是盗版CD特有的噪音,我喜欢这种噪音,每到这时候我就会感受到对未来微茫的期待,深知我喜欢的声音一定会到来,并且不需要等太久。
  HOU-BAOLIN的声音缓缓地响起,在整个房间里舒展开来,在这样的清晨,他的声音融合进空气之中,契合无间,象风一样在房间里流动。HOU- BAOLIN的中文名叫做侯宝林,不过我还是喜欢用拉丁字母来称呼他,而且只买他与GUO-QUANBAO中文名叫做郭全宝合说的相声,这也许是一种偏执 吧。无论是刘宝瑞,还是马三立,始终无法比较。
  这时候她睁开了眼睛,看着我笑。我问她笑什么,她说她很久没有在HOU-BAOLIN的相声中从梦中醒来,因为没人放给她听。
  我也笑了,轻轻地吻了一下她的额头,同时感觉到一股奇特的香水味道。这不是六神,比起六神的热情,这种味道更为矜持阴郁,而且夹杂着一丝幽幽的神秘感,
  我确信我在哪里曾经闻到过。
  于是我松开她的肩膀,慢慢地蹲下去,从床的下面小心地拿起一盏已经燃烧殆尽的蚊香,最后一缕轻烟正袅袅地飘着,在它身边散落着一些小蚊子的遗体,就好象秋天的法国梧桐树叶一样,满地皆是。
  通常在这样的天气,我都会在上班的途中路过的DJ BAR买一杯DJ喝。我绝不喝袋装的速溶品牌,而BAR的老板用DJ机和新鲜的DJ豆亲手磨出来的,所以DJ BAR的DJ有一种天然的清香。或是因为亲手磨制的缘故,这清香中还有丝淡淡的忧郁。老板也是HOU的FANS,所以我每天都会特意早起半个小时,去那里 叫一杯DJ,然后坐在高背椅上一面啜饮一面enjoy Hou那低沉阴郁的相声。
  我和她的相识就在DJ BAR,那时她穿着深绿棉袄,大红棉裤,头上扎着镶花边的头巾,手里握着一碗散发着清香的DJ,在BAR 来往人群中仿佛一只孤高的天鹅。不知道为什么,当我看到她时,心里竟是一阵莫名的触动,她的身影回荡在瞳孔里,似乎让我心里的某一部分消融。
  我走过去,坐在她的旁边,对老板说:“一杯DJ,加一点SALT,不要SUGAR。”
  她转过头来,看着我这个邻座的男人,居然笑了。
  “你也喜欢SALT DJ?”
  那时候正是HOU的两段相声的间隔,BAR 里一瞬间陷入微妙的沉静,我点了点头。
  “对于一颗破碎的心,既然无法粘合,索性就让它消融吧。”
  她又笑了,笑容在DJ蒸腾的热气中是冰蓝色,我觉得。
  “老板,来两碗豆浆,一碗甜的一碗咸的。”我们的身后有人大声喊道,我们两个人同时无奈地摇摇头,习惯了DJ的叫法,豆浆这个词是如此的刺耳,简直就是另外一个世界。
  “不出去走走么?”我对她说。距离上班的公车抵达还有五分钟。
  她躺在我的怀里,我双臂搂住她,她的红棉袄和我的棉布坎肩就躺在我们身下,HOU的相声仍旧回荡在房间里。
  “起来吧,我们去喝DJ,加SALT,不加SUGAR。”
  我俯下身子,把嘴唇凑到她的耳边,轻轻地吹气。
  对于我们生活在这个森冷都市的人来说,早晨的一杯DJ格外温馨,对于生活的情调,也就格外地偏执。对于爱人,何尝不是如此,我已经错过一次,所以对于她,我异常地小心。
  “这样的天气,不适合喝DJ呢……”
  她凝望着窗外呼啸的黄砂,眼眸里有一丝痛苦的迷惘。“我们去吃JB,今天是情人节,就让它与众不同吧。”
  我记得她曾经说过,DJ是浓郁的橘黄色,而JB则是海的深蓝,这些都是紧锁在她回忆深处的颜色,就象我。
  两个身体上彼此依靠,心灵上却彼此紧锁的人。
  在这个黄沙的情人节,我们去吃蓝调的JB.
  JB的全称叫Jian.bing.guo.zi,中文名叫做煎饼果子。她对这个相当挑剔,只在东街胡同口一家叫“红双喜”的JB BAR去吃。那里对于她,似乎有着纪念碑或图腾式存在的意义,我们彼此的结合似乎是会让彼此更加孤独无助。
  我们一起走出屋子去,我仍旧叼着大前门,她仍旧穿着红棉袄与绿色的棉裤,只是用头巾包住脸,看上去她纱巾下的表情是那么不可捉摸。
  她说过,她喜欢80年款的飞鸽,那有一种无可名状的贵族气质;然而我只有一台继承自父亲的二八加重,黑色的厚重,她说看到它时,会感觉整个身体都异常 沉重起来,象是黑云一样郁结在心头,难以呼吸。所以,二八加重被我放进车库,开着朋 友那里借来的八三年款永久,她坐在后座,两个人都沉默着,只有车冷冷地向前移动。
  去年的情人节,我一个人过。
  其实每年我都是一个人过,只是今年的心绪与前略有不同。往年的这个时候,我总抱持着一种对未来微茫的期待,总以为会有这么一年的今天,会有一个人和我 共同享这煎饼的芬芳。而去年,我则是品味着“失恋”青涩果实迎来这一天的到来。我的爱情之花终究凋谢的太早,没有等到节日的祝福,就枯萎了。
  所以,之于我,那是个没有情人的情人节……
  没有情人的情人节?这句子滥俗、古老且缺乏创意。然而句子本身所具备的巧妙修辞却准确地散发出混杂哀伤与无奈的气味,简洁的语法结构昭示着一个简洁的 逻辑:我喜欢她,她不喜欢我。仅此而已,这道理岂非很简单?简洁明了一如爱因斯坦的方程式。后者改变了整个世界,前者则彻底改变了整个我。西方大哲在一粒 砂中看世界,东方大贤在一朵花里窥天国,而我又看到了什么呢?我将思绪收回来,回头望了望她,她正看着两侧向后退去的小贩出神。
  来到JB BAR,老板是个三十岁左右的中年人,头发散乱,胡子剃的很干净,一袭白色的长袍颇为利落。据她说,这里的JB相当考究,面粉是选用的天津小站麦,昨日的 新鲜鸡蛋,油条也用Aomiao洗衣粉特别浸泡过。她特别喜欢将面糊摊在锅面的一刹那,那一瞬间会令她开朗很多,JB毕竟不是蓝调的产物。
  “两位要些什么?”
  老板问道,同时把手里的Dashao晃了晃。每一样食品都有其自我的器具,就好象COFFEE豆机之于COFFEE,DJ豆机之于DJ一样,对于JB 来说,Dashao(也许应该叫“大勺”吧,不过这个单词的微妙寓意很难用中文来表达)也就意味着一个JB BAR的品位与风格。她说她当初就是为了这把Dashao而着迷的。
  “两个JB,谢谢。”
  我回答说。老板点点头,娴熟地用Dashao在面盆里舀起一勺乳白色的面糊,手腕轻转,面糊象是有生命一般,一下子从大勺流泻出来,均匀地平摊到黑色 的锅面之上,随即被一把精致的小推子推成一个优雅的圆形。那种从容不迫的流动,让我想起BEIJING Opera《Strategem of empty city》里的Kung-Ming。难怪她会说,看着一个JB的诞生,心情会开朗很多。
  “今天是情人节吧,这样的天气,总令人很感伤呢。”
  老板一边拿铲子翻弄着JB,一边低头说道。
  “其实也不过是普通的一天罢了,若是没了心灵的震颤,每一天都是一样的。”她略带哀伤地回答,我搂着她的肩膀,发现我们始终无法彼此温暖。不过我没有悲伤,因为我也早就失了心灵上的震颤,只剩下D.J 和J.B 还有HOU 的相声,在我里面。
  我的前生是十六世纪法国的贵族女子,就住在枫丹白露,每天要吃很多的J.B……
  昨晚我和她躺在床上,她这样喃喃地说,然后我微笑,把灯关掉,开始亲吻她。
  老板拿起刷子,在盛满了酱的瓶子里搅了搅,然后涂抹到已经凝固的煎饼上面。我注意到,他刻意涂出一个心形,于是在黄白色的J.B上,就有了一个心,但那又是象征着什么呢?
  “情人节该有情人节的礼物呀,无论是谁。”老板将一根油条放进J.B,然后熟练地卷起来,煎饼并没有破损,那个酱色的心还在那里留着。老板把它递给她,她想了想,然后又递给了我。
  “情人节快乐。”
  她似乎露出一丝笑意,我欣然接过。
  我们两个就坐在J.B BAR的马路边上,将两个煎饼一点一点吃完。当我们再度抬起头的时候,彼此都明白想要说些什么。
  “多谢你的情人节礼物。”
  “那么,再见了。”
  两句简短的对话,为我们两个尘世里偶遇而有分离的人做了最后的呼唤。
  她的背影逐渐离去,大红棉袄与绿色棉裤慢慢消失了黄沙里。我面无表情地将最后一块煎饼咽下去,从怀里掏出打火机点燃了那根大前门。
  她也许真的爱我
  我也许也会爱他
  但是D.J也罢,J.B也罢,HOU 的相声也罢全都无法穿透这层细腻的黄沙帷幕
  沙子静静地从天上落下
  静静地落在我的身上
  烟草的香味消失了,散发出令人郁闷的刺鼻烟雾,我扯了扯自己的棉布坎肩,将大前门从嘴里拿出来,无力地送开手,烟蒂悠然落地。
  戴着红袖章的人走过来,向我要五元的罚款,我看着那红袖章,想起了她的红棉袄。我转身狂奔起来,那红色象是她的眼眸,我只想躲藏,回避,越远越好。
  当我一口气跑回家,红袖章被我甩掉。我走进卧室,颓然地蜷缩在床边,开始哭起来。
  因为我想起来,那两个心形的情人节煎饼,忘记向老板找零。

0

什么是虚拟机?


原名:虚拟机源码分析
转至:http://www.vmware.cn/article/586.html

1)虚拟机是什么?
    “”的概念其实很广,最常见的有以下两种虚拟机,第一种是模拟“裸机”运行的虚拟机,这样的虚拟机有VMWAREVirturePC,Bochs等,另一种是模拟操作系统运行情况的虚拟机,这样的虚拟机有Wine,JVM(java虚拟机)。其实,虚拟机就是一个中间层,可以理解为是两种环境的桥梁,如果把虚拟机的概念抽象一点描述,可以认为虚拟机是在某一个环境上模拟另一种环境运行情况的软件,这样的环境可以是不同的cpu,不同的os….等等。
    这里选择的是两个非常简单的虚拟机,一个是<<编译原理与实践>;>;一书中自带的TM虚拟机,另一个是<<程序员>;>;杂志2003年第六期里的一篇文章<<一个小型虚拟机的实现>;>;中实现的虚拟机,两者都有一个共同点,就是两者都是在汇编语言级别虚拟cpu运行情况的虚拟机,正因为这两个虚拟机的如此定位,所以在实现或者阅读这两个虚拟机的时候,你不得不从cpu的角度去思考问题,你必须对cpu的运行情况有了解,反过来说,阅读这两个虚拟机的源码也可以加深对cpu工作原理以及汇编语言的理解。这两个虚拟机的源码都可以在网上找到,前者在http://www.mathcs.sjsu.edu/faculty/louden/cmptext/,而后者可以在CSDN的网站上查找2003年第六期的源码。值得一提的是,CS:APP(<<深入理解计算机系统>;>;)一书中也有一章专门讲述CPU的运行原理,而且作者也自己实现了一个CPU,而且还是流水线型,所以这个虚拟机功能更酷也更加强大,因为作者自己定义了一种硬件语言来描述cpu,最后还有在这种cpu支持的汇编指令,在有Tcl/Tk的环境下还带有图形界面,非常直观,可以在http://csapp.cs.cmu.edu/public/students.html里的Chapter 4:Processor Architecture中找到源代码。

2)设计一个汇编语言级别的虚拟机的要求
    学习过计算机原理的人都知道,一个cpu至少需要有以下几个部件:a)内存,装载所要执行的指令之用;b)寄存器;3)指令集,没有指令集执行指令就无从谈起。前两者非常简单,无非就是在内存中分配一个空间来模拟就可以了,而后者这里要专门说明一下。我们知道任何高级语言,经过这个高级语言的编译器编译之后都是翻译成汇编语言的,然后由汇编器汇编成二进制文件最后再进行库的链接等等才形成了可执行文件,而可执行文件最终也是二进制格式的,在执行可执行文件的时候由加载器加载到内存中去,那么这里就有一个问题了:cpu是如何识别已经加载到内存中二进制文件并且正确执行的?这需要下面的一个概念:OpCode。
    OpCode是什么?简而言之,OpCode就是与汇编指令相对应的二进制格式的代码,OpCode的英文名是OperationCode(中文可以翻译成“操作码”),每一个汇编指令都有一个相对应的OpCode格式,反之不然,不过这个问题这里不再深究,只需要知道汇编器把汇编指令翻译成相应的由opcode组成的二进制文件,这样在可执行文件加载到内存的时候,cpu就可以根据在可执行文件中的opcode来执行程序了。理论上来说,不同厂家的cpu所支持的opcode是不同的,那么这里就有一个问题了,比如说在Intel机子上编译成功的可执行文件到了AMD的机子上如何正确执行呢?如果没有猜错的是,每个cpu在实现的时候需要在cpu的上层加一个翻译指令的东东….具体的我不清楚,只是猜测而已,也许不对。扯了这么多,回到这里要实现的cpu上,因为只是简易的cpu,所以在opcode上也尽量的精简,在这两个虚拟机的实现中,都是采用了汇编指令和opcode一一对应的关系进行实现(记住我前面说过汇编指令和opcode在真正的cpu中并不是一一对应的!),这样简化了cpu的实现。关于opcode,网上 有一份不错的教程<<学习opcode>;>;:http://www.luocong.com/learningopcode.htm,遗憾的是作者从开始写这份教程一直到现在差不多两年时间过去了还没有完成,不过前面的文章对于理解opcode的基本概念已经足够了。opcode看起来好像很高深,其实它就在我们身边,在linux上有一个objdump的反汇编软件可以反汇编二进制文件,比如这样的一段反汇编的代码:
116: 89 e5 mov %esp,%ebp
其中的116是指令地址,而89 e5就是指令mov %esp,%ebp 所对应的opcode。

    总结一下,设计一个汇编语言级别的虚拟机至少需要以下的部件:1)内存空间,用于存放机器指令之用。2)寄存器:用于保存程序运行的状态,暂存数据等等之用。3)汇编器,汇编器的功能就是把汇编指令翻译成cpu指定的机器指令,然后将指令装入虚拟机的内存之中。4)指令集,指令集包括了指令的助记符,也就是汇编语言中的指令,还需要有每个指令所对 应的机器指令也就是OpCode,助记符由汇编器处理翻译成为机器指令,最后在cpu执行的时候根据不同的机器指令来执行相关的操作。
    虽然这两个虚拟机的设计略有不同,但是由于都是模拟的汇编语言级别的cpu,所以工作过程大体都是一致的,把握这个运行的过程是正确掌握这两个源代码的关键所在!虚拟机运行的大体过程如下:首先由汇编起扫描汇编源文件,将汇编指令也就是机器指令的助记符翻译为机器指令,如果没有错误就把机器指令加载到内存之中,这时汇编器的任务就结束了;然后由虚拟机读取已经装载到内存中的机器指令,根据机器指令对应的操作来执行指令。

    OK,这里基本上把一些基本的概念解释完了,后面紧跟着就可以开始我们的虚拟机之旅了….

    第一个剖析对象是<<编译原理与实践>>中自带的TM虚拟机

    TM虚拟机中由一个只读指令存储区,数据区和8个寄存器组成,其中最后一个寄存器是PC寄存器,也就是程序计数器,用来保存下一个指令的地址,在跳转中以及读取指令的时候要用到,如下:
/* 只读指令存储区的大小 */
#define   IADDR_SIZE  1024 /* increase for large programs */
/* 数据区的大小 */
#define   DADDR_SIZE  1024 /* increase for large programs */
/* 寄存器的数目 */
#define   NO_REGS 8
/* PC寄存器(程序计数器)的下标 */
#define   PC_REG  7
在内存中分配了三个数组来实现模拟这三个数据区:
/* 只读指令存储区 */
INSTRUCTION iMem [IADDR_SIZE];
/* 数据存储区 */
int dMem [DADDR_SIZE];
/* 寄存器 */
int reg [NO_REGS];
所支持的指令集,为了简化cpu的实现,采用的是一个enum类型来存储指令的opcode,在这里opcode和汇编指令是一一对应的,而指令分为三种类型,分别是RR,RM,RA,其中的RM类型的指令需要对数据区进行读取,而另外两种只需要对寄存器进行读取就可以了,opcode的类型用一个enum OPCLASS来分别:
typedef enum {
  opclRR,     /* reg operands r,s,t */
  opclRM,     /* reg r, mem d+s */
  opclRA      /* reg r, int d+s */
} OPCLASS;
三种不同的opcode类型的opcode的格式是有区别的:
指令类型                指令的格式
RR                      r,s,t
RM                      r,d(s)
RA                      r,d(s)
    说明一下,对于不同类型的汇编指令,必须与这种汇编指令的opcode格式严格对应,如RR指令的类型必须是r,s,t等等。RM和RA的指令格式稍微有一点区别,这里要根据输入的”d(s)”得到另外一个值a = d + reg[s],就是说d是偏移值,而s在这里是寄存器数组的下标,对于RM来说,得到的a是对应于数据内存区数组的下标,这个a不能小于0或者大于这个内存区的大小,否则就会报错,而对RA而言,这个a值就是存储到相应的寄存器中的值,寄存器的选择根据不同的指令而定。

    下面是这个虚拟机的汇编指令对应的opcode的列表,右边的注释是每个不同的指令对应的动作,也就是要根据opcode中的数据所要进行的不同的处理:
/* 虚拟机的汇编指令对应的OPCODE */
typedef enum {
  /* RR instructions */
  opHALT,    /* RR     halt, operands are ignored */
  opIN,      /* RR     read into reg(r); s and t are ignored */
  opOUT,     /* RR     write from reg(r), s and t are ignored */
  opADD,     /* RR     reg(r) = reg(s)+reg(t) */
  opSUB,     /* RR     reg(r) = reg(s)-reg(t) */
  opMUL,     /* RR     reg(r) = reg(s)*reg(t) */
  opDIV,     /* RR     reg(r) = reg(s)/reg(t) */
  opRRLim,   /* limit of RR opcodes */

  /* RM instructions */
  opLD,      /* RM     reg(r) = mem(d+reg(s)) */
  opST,      /* RM     mem(d+reg(s)) = reg(r) */
  opRMLim,   /* Limit of RM opcodes */

  /* RA instructions */
  opLDA,     /* RA     reg(r) = d+reg(s) */
  opLDC,     /* RA     reg(r) = d ; reg(s) is ignored */
  opJLT,     /* RA     if reg(r)<0 then reg(7) = d+reg(s) */
  opJLE,     /* RA     if reg(r)<=0 then reg(7) = d+reg(s) */
  opJGT,     /* RA     if reg(r)>;0 then reg(7) = d+reg(s) */
  opJGE,     /* RA     if reg(r)>;=0 then reg(7) = d+reg(s) */
  opJEQ,     /* RA     if reg(r)==0 then reg(7) = d+reg(s) */
  opJNE,     /* RA     if reg(r)!=0 then reg(7) = d+reg(s) */
  opRALim    /* Limit of RA opcodes */
} OPCODE;
不论是哪一种类型的指令,都必须在指令内存区中保存相应的信息,比如说访问的寄存器的位置,内存的位置等等,这些信息保存在下面的一个结构体变量中的:
/* 存储指令的值,iop是OPCODE,剩下三个是r,s,t */
typedef struct {
  int iop;
  int iarg1;
  int iarg2;
  int iarg3;
} INSTRUCTION;
其中的iop就是指令对应的opcode,与前面的enum OPCODE中的成员一一对应,剩下的三个变量就是opcode中的r,s,t变量。指令内存区都INSTRUCTION类型的。
    另外,执行指令的时候还要有不同的结果,这里同样的使用一个enum STEPRESULT类型来识别不同的结果,需要说明的是在读取内存的时候如果指针大小小于0或者大于内存的大小就会报错,另外在执行除法指令的时候还有可能出现零除错误:
/* 枚举执行结果 */
typedef enum {
  srOKAY,     /* 正确执行 */
  srHALT,     /* 停止执行 */
  srIMEM_ERR,    /* IMEM错误 */
  srDMEM_ERR,    /* DMEM错误 */
  srZERODIVIDE    /* 零除错误 */
} STEPRESULT;

2)cpu的工作原理
    代码的量不大,只有700行不到,核心的函数有下面几个:
a)int readInstructions (void)
    这个函数负责读取代码文件,是逐行处理的,对于每一行的文件首先检查指令是否符合这个虚拟机的汇编指令的格式,然后分辩这个指令的类型,再根据这个指令的类型存储不同的指令中opcode里的数据,每读取完一行代码如果没有错误的话就把指令及相应的opcode存储到指令存储区中,就是INSTRUCTION iMem [IADDR_SIZE]数组中,当读取文件结束的时候,这个数组中就都是相应的指令了,而后面的存储区存放的是HALT指令。
b)int doCommand (void)
    这个函数负责读取stdin中用户输入的命令行参数来执行不同的动作,相关的动作这里不再详述,这个函数会一直执行下去,一直到用户输入q时才退出,在主函数main中是这样调用这个函数的:
  do
    done = ! doCommand ();
  while (! done );
c)STEPRESULT stepTM (void)
    这个函数是根据指令内存区中的指令逐步执行程序的函数,其中设定的一个局部变量
  INSTRUCTION currentinstruction  ;
负责存储当前的指令:
  /* 从PC寄存器中读取下一条指令地址 */
  pc = reg[PC_REG] ;
  /* 如果小于零或者大于IADDR_SIZE,就是超过指令内存大小,就返回srIMEM_ERR错误 */
  if ( (pc < 0) || (pc >; IADDR_SIZE)  )
    return srIMEM_ERR ;
  /* PC加一 */
  reg[PC_REG] = pc + 1 ;
  /* 从内存中根据PC地址值读取当前要执行的指令 */
  currentinstruction = iMem[ pc ] ;
每读取完一个指令,就根据指令的类型以及指令所定义的不同的动作来执行代码,比如说:
  /* 根据iop中存储的OPCODE来执行指令,每个case右边是指令的执行情况 */
  switch ( currentinstruction.iop)
  {
  case opHALT :    /* RR     halt, operands are ignored */
    printf(“HALT: %1d,%1d,%1d\n”,r,s,t);
    return srHALT ;
    /* break; */

  case opIN :    /* RR     read into reg(r); s and t are ignored */
    do{
      printf(“Enter value for IN instruction: “) ;
      fflush (stdin);
      fflush (stdout);
      gets(in_Line);
      lineLen = strlen(in_Line) ;
      inCol = 0;
      ok = getNum();
      if ( ! ok )
     printf (“Illegal value\n”);
      else
     reg[r] = num;
    } while (! ok);
    break;
    剩余的其它函数都是简单的辅助函数了,无非是一些跳过空格,跳过检查是否是特定字符,得到字符串以及得到数字等等之类的函数了。

3)汇编指令的格式
    这个虚拟机能够识别的汇编指令有一定的格式,如下:
a)忽略空行
b)以“*”号开头的都是注释
c)任何其它行都必须以整数开头,这个整数用于指定代码的位置,任何指令后面的文字都被认为是注释而忽略掉。
    至于支持的指令就是与opcode一一对应的,不再详述

4)虚拟机的使用方式
TM虚拟机只有一个文件,只需要简单的编译就可以了,下面提供一个与该虚拟机对应的汇编代码:
  0:     LD  6,0(0)
  1:     ST  0,0(0)
  2:     IN  0,0,0
  3:     ST  0,0(5)
  4:    LDC  0,0(0)
  5:     ST  0,0(6)
  6:     LD  0,0(5)
  7:     LD  1,0(6)
  8:    SUB  0,1,0
  9:    JLT  0,2(7)
 10:    LDC  0,0(0)
 11:    LDA  7,1(7)
 12:    LDC  0,1(0)
 14:    LDC  0,1(0)
 15:     ST  0,1(5)
 16:     LD  0,1(5)
 17:     ST  0,0(6)
 18:     LD  0,0(5)
 19:     LD  1,0(6)
 20:    MUL  0,1,0
 21:     ST  0,1(5)
 22:     LD  0,0(5)
 23:     ST  0,0(6)
 24:    LDC  0,1(0)
 25:     LD  1,0(6)
 26:    SUB  0,1,0
 27:     ST  0,0(5)
 28:     LD  0,0(5)
 29:     ST  0,0(6)
 30:    LDC  0,0(0)
 31:     LD  1,0(6)
 32:    SUB  0,1,0
 33:    JEQ  0,2(7)
 34:    LDC  0,0(0)
 35:    LDA  7,1(7)
 36:    LDC  0,1(0)
 37:    JEQ  0,-22(7)
 38:     LD  0,1(5)
 39:    OUT  0,0,0
 13:    JEQ  0,27(7)
 40:    LDA  7,0(7)
 41:   HALT  0,0,0
    假设编译好的虚拟机的可执行文件是TM,而汇编代码文件是1.tm(这个虚拟机默认的可识别的汇编文件是*.tm),那么只需要简单的使用: TM 1.tm 就可以了。

    OK,第一个虚拟机的分析到此,下面是完整的源代码:

/****************************************************/
/* File: tm.c                                       */
/* The TM (“Tiny Machine”) computer                 */
/* Compiler Construction: Principles and Practice   */
/* Kenneth C. Louden                                */
/****************************************************/

#include ;
#include ;
#include ;
#include ;

#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif

/******* const *******/
/* 只读指令存储区的大小 */
#define   IADDR_SIZE  1024 /* increase for large programs */
/* 数据区的大小 */
#define   DADDR_SIZE  1024 /* increase for large programs */
/* 寄存器的数目 */
#define   NO_REGS 8
/* PC寄存器(程序计数器)的下标 */
#define   PC_REG  7

#define   LINESIZE  121
#define   WORDSIZE  20

/******* type  *******/

/* 虚拟机的指令类型,有三种 */
typedef enum {
   opclRR,     /* reg operands r,s,t */
   opclRM,     /* reg r, mem d+s */
   opclRA      /* reg r, int d+s */
} OPCLASS;

/* 虚拟机的汇编指令对应的OPCODE */
typedef enum {
   /* RR instructions */
   opHALT,    /* RR     halt, operands are ignored */
   opIN,      /* RR     read into reg(r); s and t are ignored */
   opOUT,     /* RR     write from reg(r), s and t are ignored */
   opADD,     /* RR     reg(r) = reg(s)+reg(t) */
   opSUB,     /* RR     reg(r) = reg(s)-reg(t) */
   opMUL,     /* RR     reg(r) = reg(s)*reg(t) */
   opDIV,     /* RR     reg(r) = reg(s)/reg(t) */
   opRRLim,   /* limit of RR opcodes */

   /* RM instructions */
   opLD,      /* RM     reg(r) = mem(d+reg(s)) */
   opST,      /* RM     mem(d+reg(s)) = reg(r) */
   opRMLim,   /* Limit of RM opcodes */

   /* RA instructions */
   opLDA,     /* RA     reg(r) = d+reg(s) */
   opLDC,     /* RA     reg(r) = d ; reg(s) is ignored */
   opJLT,     /* RA     if reg(r)<0 then reg(7) = d+reg(s) */
   opJLE,     /* RA     if reg(r)<=0 then reg(7) = d+reg(s) */
   opJGT,     /* RA     if reg(r)>;0 then reg(7) = d+reg(s) */
   opJGE,     /* RA     if reg(r)>;=0 then reg(7) = d+reg(s) */
   opJEQ,     /* RA     if reg(r)==0 then reg(7) = d+reg(s) */
   opJNE,     /* RA     if reg(r)!=0 then reg(7) = d+reg(s) */
   opRALim    /* Limit of RA opcodes */
} OPCODE;

/* 枚举执行结果 */
typedef enum {
   srOKAY,        /* 正确执行 */
   srHALT,        /* 停止执行 */
   srIMEM_ERR,        /* IMEM错误 */
   srDMEM_ERR,        /* DMEM错误 */
   srZERODIVIDE       /* 零除错误 */
} STEPRESULT;

/* 存储指令的值,iop是OPCODE,剩下三个是r,s,t */
typedef struct {
   int iop;
   int iarg1;
   int iarg2;
   int iarg3;
} INSTRUCTION;

/******** vars ********/
/* 指向只读指令存储区的指针 */
int iloc = 0 ;
/* 指向数据存储区的指针 */
int dloc = 0 ;
/* 是否跟踪程序执行情况 */
int traceflag = FALSE;
/* 是否需要打印出执行的指令数量 */
int icountflag = FALSE;

/* 只读指令存储区 */
INSTRUCTION iMem [IADDR_SIZE];
/* 数据存储区 */
int dMem [DADDR_SIZE];
/* 寄存器 */
int reg [NO_REGS];

/* 指令列表,用于在stdout上打印出程序执行情况之用,与enum OPCODE对应,其中的”????”则与相应的LIM值对应,无意义 */
char *opCodeTab[] = {
   /* RR opcodes */
   “HALT”,”IN”,”OUT”,”ADD”,”SUB”,”MUL”,”DIV”,”????”,
     /* RM opcodes */
   “LD”,”ST”,”????”,
   /* RA opcodes */
   “LDA”,”LDC”,”JLT”,”JLE”,”JGT”,”JGE”,”JEQ”,”JNE”,”????”
};

/* 程序结果列表,用于在stdout上打印出程序执行情况之用,与enum STEPRESULT对应 */
char * stepResultTab[] =
{
   “OK”,
   “Halted”,
   “Instruction Memory Fault”,
   “Data Memory Fault”,
   “Division by 0″
};

/* 存储文件名 */
char pgmName[20];
/* 代码文件的FILE指针 */
FILE *pgm  ;

/* 文件的每一行都存在这个数组里 */
char in_Line[LINESIZE] ;
/* 读取到当前文件的行数记录 */
int lineLen;
/* in_Line数组中的下标 */
int inCol;
/* 存储getNum()函数的结果 */
int num  ;
/* 存储getWord()函数的结果 */
char word[WORDSIZE] ;
/* 存储getCh()函数的结果 */
char ch  ;
/* 存储docomand()函数的执行结果,用于表示程序是否结束 */
int done  ;

/*************************************************************************************
 * int opClass( int c ):根据c的值在OPCODE枚举型中查找指令的类型,有RR,RM,RA三种指令
 *************************************************************************************/
int opClass( int c )
{
   if ( c <= opRRLim)
      return ( opclRR );
   else if ( c <= opRMLim)
      return ( opclRM );
   else
      return ( opclRA );
} /* opClass */

/**************************************************************************************
 *void writeInstruction ( int loc ):向stdout上打印出程序的执行情况
 **************************************************************************************/
void writeInstruction ( int loc )
{
   printf( “%5d: “, loc) ;
   if ( (loc >;= 0) && (loc < IADDR_SIZE) )
   {
      printf(“%6s%3d,”, opCodeTab[iMem[loc].iop], iMem[loc].iarg1);
      switch ( opClass(iMem[loc].iop) )
      {
      case opclRR:
         printf(“%1d,%1d”, iMem[loc].iarg2, iMem[loc].iarg3);
         break;
      case opclRM:
      case opclRA:
         printf(“%3d(%1d)”, iMem[loc].iarg2, iMem[loc].iarg3);
         break;
      }
      printf (“\n”) ;
   }
} /* writeInstruction */

/*************************************************************************************
 * void getCh (void):在in_line数组中读取字符,如果到文件尾,就返回空字符,并且将结果存入ch中
 **************************************************************************************/
void getCh (void)
{
   if (++inCol < lineLen)
      ch = in_Line[inCol] ;
   else ch = ‘ ‘ ;
} /* getCh */

/**************************************************************************************
 * int nonBlank (void): 查找某行文件后面是否都是空格,如果是则设置ch=’ ‘并且返回false,
 *                      否则设置ch为第一个非空字符返回true
 ***************************************************************************************/
int nonBlank (void)
{
   while ((inCol < lineLen)
      && (in_Line[inCol] == ‘ ‘) )
      inCol++ ;
   if (inCol < lineLen)
   {
      ch = in_Line[inCol] ;
      return TRUE ;
   }
   else
   {
      ch = ‘ ‘ ;
      return FALSE ;
   }
} /* nonBlank */

/***************************************************************************************
 * int getNum (void):判断字符是否是数字,不是就返回false,否则返回true并且num中存储读入的数字
 ****************************************************************************************/
int getNum (void)
{
   int sign;
   int term;
   int temp = FALSE;
   num = 0 ;

   do {
      sign = 1;
      while ( nonBlank() && ((ch == ‘+’) || (ch == ‘-’)) )
      {
         temp = FALSE ;
         if (ch == ‘-’) 
          sign = – sign ;
         getCh();
      }
      term = 0 ;
      nonBlank();
      while (isdigit(ch))
      {
         temp = TRUE ;
         term = term * 10 + ( ch – ’0′ ) ;
         getCh();
      }
      num = num + (term * sign) ;
   } while ( (nonBlank()) && ((ch == ‘+’) || (ch == ‘-’)) ) ;

   return temp;
} /* getNum */

/****************************************************************************************
 *int getWord (void):判断后面紧接着的是否是符号,就是以字母或者数字开头的符号,是就返回true
 *                   并且将该符号存入word数组之中,否则返回false
 ****************************************************************************************/
int getWord (void)
{
   int temp = FALSE;
   int length = 0;
   if (nonBlank ())
   {
      while (isalnum(ch))
      {
         if (length < WORDSIZE-1)
          word [length++] =  ch ;
         getCh() ;
      }
      word[length] = ‘\0′;
      temp = (length != 0);
   }

   return temp;
} /* getWord */

/***************************************************************************************** 
 *int skipCh ( char c  ):略过指定的字符,如果找不到这个字符那么返回false,否则返回true
 *****************************************************************************************/
int skipCh ( char c  )
{
   int temp = FALSE;
   if ( nonBlank() && (ch == c) )
   {
      getCh();
      temp = TRUE;
   }
   return temp;
} /* skipCh */

/******************************************************************************************  
 *int atEOL(void):是否到达行尾,是就返回非零值,否则返回零值
 ******************************************************************************************/
int atEOL(void)
{
   return ( ! nonBlank ());
} /* atEOL */

/*******************************************************************************************   
 * int error( char * msg, int lineNo, int instNo):打印出错信息,其中msg是出错信息,
 *                                                lineNo是行数,instNo是指令数
 *******************************************************************************************/
int error( char * msg, int lineNo, int instNo)
{
   printf(“Line %d”,lineNo);
   if (instNo >;= 0)
      printf(” (Instruction %d)”,instNo);
   printf(“   %s\n”,msg);
   return FALSE;
} /* error */

/*******************************************************************************************   
 * int readInstructions (void):读取代码文件进行处理
 *******************************************************************************************/
int readInstructions (void)
{
   /* op存储指令 */
   OPCODE op;
   /* 存储r,s,t */
   int arg1, arg2, arg3;
   /* loc是指令的位置, regNO是寄存器的位置,lineNO是代码中的行数 */
   int loc, regNo, lineNo;

   /* 清空寄存器 */
   for (regNo = 0 ; regNo < NO_REGS ; regNo++)
      reg[regNo] = 0 ;
   /* 不明白为什么这样做? */
   dMem[0] = DADDR_SIZE – 1 ;
   /* 清空数据区 */
   for (loc = 1 ; loc < DADDR_SIZE ; loc++)
      dMem[loc] = 0 ;
   /* 初始化指令存储区的OPCODE是opHALT */
   for (loc = 0 ; loc < IADDR_SIZE ; loc++)
   {
      iMem[loc].iop = opHALT ;
      iMem[loc].iarg1 = 0 ;
      iMem[loc].iarg2 = 0 ;
      iMem[loc].iarg3 = 0 ;
   }
   /* 初始化行数为0 */
   lineNo = 0 ;
   while (! feof(pgm))    /* 对文件进行逐行的读取操作,然后对每一行代码进行处理 */
   {
      /* 读入一行代码 */
      fgets( in_Line, LINESIZE-2, pgm  ) ;
      /* 设置行的列号为0 */
      inCol = 0 ;
      /* 行数加一 */
      lineNo++;
      lineLen = strlen(in_Line)-1 ;
      /* 把行尾置为’\0′,方便字符串操作 */
      if (in_Line[lineLen]==’\n’)
         in_Line[lineLen] = ‘\0′ ;
      else
         in_Line[++lineLen] = ‘\0′;
      /* 如果指令不是空格或者注释 */
      if ( (nonBlank()) && (in_Line[inCol] != ‘*’) )
      {
         /* 如果不是数字,就显示错误,因为指令都是以数字开始 */
         if (! getNum())
          return error(“Bad location”, lineNo,-1);
         /* 存储指令的位置 */
         loc = num;
         /* 大于指令存储区的大小 */
         if (loc >; IADDR_SIZE)
          return error(“Location too large”,lineNo,loc);
         /* 如果后面没有紧接着’:',则显示出错 */
         if (! skipCh(‘:’))
          return error(“Missing colon”, lineNo,loc);
         /* 如果后面紧接着的不是符号,则显示出错 */
         if (! getWord ())
          return error(“Missing opcode”, lineNo,loc);
         /* 初始化为HALT指令 */
         op = opHALT ;
         /* 循环查找word指令对应的OPCODE,op就是在opCodeTab中对应的指令的下标 */
         while ((op < opRALim)
            && (strncmp(opCodeTab[op], word, 4) != 0) )
          op++ ;
         /* 没有找到对应的OPCODE,显示出错 */
         if (strncmp(opCodeTab[op], word, 4) != 0)
          return error(“Illegal opcode”, lineNo,loc);
        
         /* 调用opClass函数对指令进行分类,不同的指令处理不相同 */
         switch ( opClass(op) )
         {
         case opclRR :  /* 处理RR指令,具体为什么会如下处理可以查看RR指令的格式 */
          /* 如果后面紧接着的不是数字或者数字是非法的就显示出错 */
          if ( (! getNum ()) || (num < 0) || (num >;= NO_REGS) )
             return error(“Bad first register”, lineNo,loc);
          arg1 = num;
          /* 如果后面没有紧跟着’,',就显示出错 */
          if ( ! skipCh(‘,’))
             return error(“Missing comma”, lineNo, loc);
                    /* 如果后面紧接着的不是数字或者数字是非法的就显示出错 */
          if ( (! getNum ()) || (num < 0) || (num >;= NO_REGS) )
             return error(“Bad second register”, lineNo, loc);
          arg2 = num;
          /* 如果后面没有紧跟着’,',就显示出错 */
          if ( ! skipCh(‘,’))
             return error(“Missing comma”, lineNo,loc);
          /* 如果后面紧接着的不是数字或者数字对于RR命令是非法的就显示出错 */
          if ( (! getNum ()) || (num < 0) || (num >;= NO_REGS) )
             return error(“Bad third register”, lineNo,loc);
          arg3 = num;
          break;

         case opclRM :  /* 处理RM指令,具体为什么会如下处理可以查看RM指令的格式 */
         case opclRA :  /* 处理RA指令,具体为什么会如下处理可以查看RA指令的格式 */
          /* 如果后面紧接着的不是数字或者数字是非法的就显示出错 */
          if ( (! getNum ()) || (num < 0) || (num >;= NO_REGS) )
             return error(“Bad first register”, lineNo,loc);
          arg1 = num;
          /* 如果后面没有紧跟着’,'就显示出错 */
          if ( ! skipCh(‘,’))
             return error(“Missing comma”, lineNo,loc);
          /* 如果后面没有紧跟着数字就显示出错 */
          if (! getNum ())
             return error(“Bad displacement”, lineNo,loc);
          arg2 = num;
          /* 如果后面没有紧跟着’(‘或者是’,'就显示出错 */
          if ( ! skipCh(‘(‘) && ! skipCh(‘,’) )
             return error(“Missing LParen”, lineNo,loc);
          /* 如果紧跟的不是数字或者数字是非法的就显示出错 */
          if ( (! getNum ()) || (num < 0) || (num >;= NO_REGS))
             return error(“Bad second register”, lineNo,loc);
          arg3 = num;
          break;
         } /* switch ( opClass(op) ) */
         /* OK,读取一行代码结束,把指令存入指令存储区 */
         iMem[loc].iop = op;
         iMem[loc].iarg1 = arg1;
         iMem[loc].iarg2 = arg2;
         iMem[loc].iarg3 = arg3;
      } /* if ( (nonBlank()) && (in_Line[inCol] != ‘*’) ) */
   }    /* while (! feof(pgm)) */

   return TRUE;
} /* readInstructions */

/********************************************************************************************
 * STEPRESULT stepTM (void):根据指令内存区中的存储的指令逐步执行指令,并且返回执行结果
 ********************************************************************************************/
STEPRESULT stepTM (void)
{
   INSTRUCTION currentinstruction  ;
   int pc  ;
   int r,s,t,m  ;
   int ok ;

   /* 从PC寄存器中读取下一条指令地址 */
   pc = reg[PC_REG] ;
   /* 如果小于零或者大于IADDR_SIZE,就是超过指令内存大小,就返回srIMEM_ERR错误 */
   if ( (pc < 0) || (pc >; IADDR_SIZE)  )
      return srIMEM_ERR ;
   /* PC加一 */
   reg[PC_REG] = pc + 1 ;
   /* 从内存中根据PC地址值读取当前要执行的指令 */
   currentinstruction = iMem[ pc ] ;
  
     /*  调用opClass函数确定opcode的类型 */
   switch (opClass(currentinstruction.iop) )
   {
   case opclRR :        /* 对于RR指令而言,opcode格式是opcode r, s, t */
      r = currentinstruction.iarg1 ;
      s = currentinstruction.iarg2 ;
      t = currentinstruction.iarg3 ;
      break;
     
   case opclRM :        /* 对于RM指令而言,opcode格式是opcode r, d(s),而m = d + reg(s) */
      r = currentinstruction.iarg1 ;
      s = currentinstruction.iarg3 ;
      /* 对应RM指令中的m = d + reg[s],相当于变址寻址,这个地址用于访问数据区 */
      m = currentinstruction.iarg2 + reg[s] ;
      /* 如果地址是非法的(对于数据存储区而言),就返回一个srDMEM_ERR错误 */
      if ( (m < 0) || (m >; DADDR_SIZE))
         return srDMEM_ERR ;
      break;

   case opclRA :        /* 对于RA指令而言,opcode格式是opcode r, d(s),而m = d + reg(s),m值最后存入相应的寄存器 */
      r = currentinstruction.iarg1 ;
      s = currentinstruction.iarg3 ;
      m = currentinstruction.iarg2 + reg[s] ;
      break;
   } /* case */

   /* 根据iop中存储的OPCODE来执行指令,每个case右边是指令的执行情况 */
   switch ( currentinstruction.iop)
   {
   case opHALT :        /* RR     halt, operands are ignored */
      printf(“HALT: %1d,%1d,%1d\n”,r,s,t);
      return srHALT ;
      /* break; */

   case opIN :        /* RR     read into reg(r); s and t are ignored */
      do{
         printf(“Enter value for IN instruction: “) ;
         fflush (stdin);
         fflush (stdout);
         gets(in_Line);
         lineLen = strlen(in_Line) ;
         inCol = 0;
         ok = getNum();
         if ( ! ok )
          printf (“Illegal value\n”);
         else
          reg[r] = num;
      } while (! ok);
      break;

   case opOUT :         /* RR     write from reg(r), s and t are ignored */
      printf (“OUT instruction prints: %d\n”, reg[r] ) ;
      break;
   case opADD :         /* RR     reg(r) = reg(s)+reg(t) */
      reg[r] = reg[s] + reg[t] ; 
      break;
   case opSUB :         /* RR     reg(r) = reg(s)-reg(t) */
      reg[r] = reg[s] – reg[t] ; 
      break;
   case opMUL :         /* RR     reg(r) = reg(s)*reg(t) */
      reg[r] = reg[s] * reg[t] ; 
      break;

   case opDIV :       /* RR     reg(r) = reg(s)/reg(t) */
      if ( reg[t] != 0 )
         reg[r] = reg[s] / reg[t];
      else
         return srZERODIVIDE ;
      break;

     /*************** RM instructions ********************/
   case opLD :          /* RM     reg(r) = mem(d+reg(s)) */
      reg[r] = dMem[m] ; 
      break;
   case opST :          /* RM     mem(d+reg(s)) = reg(r) */
      dMem[m] = reg[r] ; 
      break;

   /*************** RA instructions ********************/
   case opLDA :         /* RA     reg(r) = d+reg(s) */
      reg[r] = m ;
      break;
   case opLDC :         /* RA     reg(r) = d ; reg(s) is ignored */
      reg[r] = currentinstruction.iarg2 ;  
      break;
   case opJLT :         /* RA     if reg(r)<0 then reg(7) = d+reg(s) */
      if ( reg[r] <  0 )
         reg[PC_REG] = m ;
      break;
   case opJLE :         /* RA     if reg(r)<=0 then reg(7) = d+reg(s) */
      if ( reg[r] <=  0 )
         reg[PC_REG] = m ;
      break;
   case opJGT :         /* RA     if reg(r)>;0 then reg(7) = d+reg(s) */
      if ( reg[r] >;  0 )
         reg[PC_REG] = m ;
      break;
   case opJGE :         /* RA     if reg(r)>;=0 then reg(7) = d+reg(s) */
      if ( reg[r] >;=  0 )
         reg[PC_REG] = m ;
      break;
   case opJEQ :         /* RA     if reg(r)==0 then reg(7) = d+reg(s) */
      if ( reg[r] == 0 )
         reg[PC_REG] = m ;
      break;
   case opJNE :         /* RA     if reg(r)!=0 then reg(7) = d+reg(s) */
      if ( reg[r] != 0 )
         reg[PC_REG] = m ;
      break;

      /* end of legal instructions */
   } /* case */
  
     /* 如果程序能够正常执行到这里,就返回执行正确的信息 */
   return srOKAY ;
} /* stepTM */

/********************************************************************************************
 *int doCommand (void):执行指令
 * *******************************************************************************************/
int doCommand (void)
{
   char cmd;
   int stepcnt=0, i;
   int printcnt;
   int stepResult;
   int regNo, loc;

   do {           /* 读入执行虚拟机的命令行参数 */
      printf (“Enter command: “);
      fflush (stdin);
      fflush (stdout);
      gets(in_Line);
      lineLen = strlen(in_Line);
      inCol = 0;
   } while (! getWord ());

   cmd = word[0] ;
   switch ( cmd )
   {
   case ‘t’ :       /* 是否跟踪调试 */
      traceflag = ! traceflag ;
      printf(“Tracing now “);
      if ( traceflag )
         printf(“on.\n”);
      else
         printf(“off.\n”);
      break;

   case ‘h’ :       /* 打印出命令及相应功能列表 */
      printf(“Commands are:\n”);
      printf(“   s(tep ;      “\
         “Execute n (default 1) TM instructions\n”);
      printf(“   g(o            “\
         “Execute TM instructions until HALT\n”);
      printf(“   r(egs          “\
         “Print the contents of the registers\n”);
      printf(“   i(Mem ;>;  “\
         “Print n iMem locations starting at b\n”);
      printf(“   d(Mem ;>;  “\
         “Print n dMem locations starting at b\n”);
      printf(“   t(race         “\
         “Toggle instruction trace\n”);
      printf(“   p(rint         “\
         “Toggle print of total instructions executed”\
         ” (‘go’ only)\n”);
      printf(“   c(lear         “\
         “Reset simulator for new execution of program\n”);
      printf(“   h(elp          “\
         “Cause this list of commands to be printed\n”);
      printf(“   q(uit          “\
         “Terminate the simulation\n”);
      break;

   case ‘p’ :       /* 是否打印出执行的指令的步数 */
      icountflag = ! icountflag ;
      printf(“Printing instruction count now “);
      if ( icountflag )
         printf(“on.\n”);
      else
         printf(“off.\n”);
      break;

   case ‘s’ :       /* 指定执行的步数 */
      if ( atEOL ()) 
         stepcnt = 1;
      else if ( getNum ()) 
         stepcnt = abs(num);
      else
         printf(“Step count?\n”);
      break;

   case ‘g’ :           /* 执行指令一直到HALT */
      stepcnt = 1 ;    
      break;

   case ‘r’ :       /* 打印出寄存器中的内容 */
      for (i = 0; i < NO_REGS; i++)
      {
         printf(“%1d: %4d    “, i,reg);
         if ( (i % 4) == 3 )
          printf (“\n”);
      }
      break;

   case ‘i’ :   /* 打印出只读指令存储区的内容(指令),也可以自己指定存储区的位置 */
      printcnt = 1 ;
      /* printcnt用于计数,计算总共要打印出多少行的内容,而iloc是指向这一段内存的指针 */
      if ( getNum ())
      {
         iloc = num ;
         if ( getNum ())
          printcnt = num ;
      }
      if ( ! atEOL ())
         printf (“Instruction locations?\n”);
      else
      {
         while ((iloc >;= 0) && (iloc < IADDR_SIZE)
            && (printcnt >; 0) )
         {
          writeInstruction(iloc);
          iloc++ ;
          printcnt– ;
         }
      }
      break;

   case ‘d’ :   /* 打印出数据存储区的内容(指令),也可以自己指定存储区的位置 */
      printcnt = 1 ;
      /* printcnt用于计数,计算总共要打印出多少行的内容,而dloc是指向这一段内存的指针 */
      if ( getNum  ())
      {
         dloc = num ;
         if ( getNum ())
          printcnt = num ;
      }
      if ( ! atEOL ())   
         printf(“Data locations?\n”);
      else
      {
         while ((dloc >;= 0) && (dloc < DADDR_SIZE)
            && (printcnt >; 0))
         {
          printf(“%5d: %5d\n”,dloc,dMem[dloc]);
          dloc++;
          printcnt–;
         }
      }
      break;

   case ‘c’ :       /* 清空虚拟机所有状态 */
      iloc = 0;
      dloc = 0;
      stepcnt = 0;
      for (regNo = 0;  regNo < NO_REGS ; regNo++)
         reg[regNo] = 0 ;
      dMem[0] = DADDR_SIZE – 1 ;
      for (loc = 1 ; loc < DADDR_SIZE ; loc++)
         dMem[loc] = 0 ;
      break;

   case ‘q’ :         /* 退出 */
      return FALSE; 

   default :        /* 未知命令 */
      printf(“Command %c unknown.\n”, cmd);
      break;
   }  /* case */
   stepResult = srOKAY;
   if ( stepcnt >; 0 )
   {
      if ( cmd == ‘g’ )
      {
         stepcnt = 0;
         /* 当命令行参数是g的时候,就一直执行程序 */
         while (stepResult == srOKAY)
         {
          iloc = reg[PC_REG] ;
          /* 如果设置了跟踪标志,那么在stdout上打印出执行的指令 */
          if ( traceflag )
             writeInstruction( iloc ) ;
          stepResult = stepTM ();
          stepcnt++;
         }
         /* 打印出执行的指令数量 */
         if ( icountflag )
          printf(“Number of instructions executed = %d\n”,stepcnt);
      }
      else        /* 否则根据stepResult中指定的步长执行指令 */
      {
         while ((stepcnt >; 0) && (stepResult == srOKAY))
         {
          iloc = reg[PC_REG] ;
          if ( traceflag )
             writeInstruction( iloc ) ;
          stepResult = stepTM ();
          stepcnt– ;
         }
      }
      printf( “%s\n”,stepResultTab[stepResult] );
   }
   return TRUE;
} /* doCommand */

/********************************************************************************************
 *int main( int argc, char * argv[] ):主函数
 ********************************************************************************************/
int main( int argc, char * argv[] )
{
   if (argc != 2)
   { printf(“usage: %s ;\n”,argv[0]);
      exit(1);
   }
   strcpy(pgmName,argv[1]) ;
   if (strchr (pgmName, ‘.’) == NULL)
      strcat(pgmName,”.tm”);
   pgm = fopen(pgmName,”r”);
   if (pgm == NULL)
   { printf(“file ‘%s’ not found\n”,pgmName);
      exit(1);
   }

   /* read the program */
   if ( ! readInstructions ())
      exit(1) ;
   /* switch input file to terminal */
   /* reset( input ); */
   /* read-eval-print */
   printf(“TM  simulation (enter h for help)…\n”);
   do
      done = ! doCommand ();
   while (! done );
   printf(“Simulation done.\n”);

   return 0;
}

0

一起看看国外设计公司的办公环境


The Lab
by Grafix Guru

 
Home office of Stefan Didak
by Stefen Didak

 
The Emotion Studio
by timsamoff

 
Apple Wing
by jensen

 
Spring in Cincinnati
by ekalb

 
 
 
Silly Mac setup
by michaelbystrom


Mac setup
by chris chart

 
 
Mac mini PVR
via tuaw


Mac On a Wall
by mkwhitley


Ultimate Mac setup
by visualseed

 
New Workstation
by ishmell

 
Chris Workplace
by Chris Marshall

 
My Workspace
by tuartboy

 
Mac Setup
by Cold Eskimo


My desk
by kihlbom

 
Multi Monitor Mahem
by totalAldo


Macbook Desk Setup
by js1stuff

 
White Mac Setup
by Stephen Embleton

 
Leopard Fever
by Crouching Donkey

 
Mac Pro Setup
by jaronbrass

 
Mac Mini Setup
by fontanafunk

 
Workstation setup
by Bimmerchop

 
iMac Home Office Setup
by nycGRAEME


 
Google Headquarters on six displays
by twid

 
Workstation setup
by Dion Tavenier


New IKEA Spotlights
by Matt Brett

 
Clean Mac Setup


My Home Office
by dziner



My Desktop
by QuattroVageena


Mike’s Workstation
by mike

 
My ridiculous Mac Pro setup
by Mike Fullerton

 
My Mac Setup in Shanghai
by Ken Lee

 
Apple Cinema Display Setup
by veryMickey

 
Mac Setups
by weistudio

 
My Messy Workspace
by bigbold


 

 
Lights On
by MB!


 

0

神奇的化妆术(22P)


各位女同学可以好好学习一下。


今天的调色*液是用的紫色和粉色混合的,把我黄黄皮肤调的白皙一点,粉色的是让皮肤白的更自然,更红润。

为了打造粉嫩自然的皮肤,选择的粉底颜色偏深,因为米娜皮肤状态不是很好,深色粉底的遮盖能力能好,外加我的珠光粉色调色粉底,出来的效果会更好,更滋润,皮肤更健康,不会惨白。比较有光泽度。

下面一步就是把还没遮盖掉的小豆豆用遮瑕膏遮掉它,用量不能过多,晕染要自然,不然就是一坨白点点在哪里了`米娜用的是蓝色和***的遮瑕膏。

为了让妆容不那么死板,看起皮肤比较有弹性有光泽度,最好是用刷子沾取蜜粉,微微的刷在脸部就可以了,如果是干性皮肤或则中性皮肤,就只刷T区。

再来一个比刚才粉底更深2个号数的粉底液,打在脸部的侧区。过度一定要自然,不能过于明显。一定要融合到第一次打的粉底里面。

再来一个比刚才粉底更浅2个号数的粉底液,打在脸部的T区。过度一定要自然,不能过于明显。一定要融合到第一次打的粉底里面。综合上一步,整个脸部的立体感就出来一点了,但是,致死粉底打的立体没用,还要结合后面的眼部,,唇部,,,腮红,,,

今天用的是膏状的腮红,这个比粉状的跟贴皮肤,更通透自然

可用手指占取,冰均匀的涂在腮红区,也就是苹果肌上,过度要自然。

香槟色。让眼部皮肤更健康

涂抹的时候一定要均匀的覆盖在整个眼睑上。

珠光香槟色可以打造滋润感,和光泽感。

这个也是平涂在上眼睑上,

再用冰***眼影涂在燕窝上,提高眼睛的立体感。

记得内眼角也要涂一点,这样可以提升眼睛的明亮度,会更有神。同样也是加大眼睛眼影的过度,制造立体感。

然后就是夹睫毛。

涂睫毛膏,让真假睫毛更好的融合在一起,这样其实不注意的话,是看不出真假睫毛的,但是前提是假睫毛要修剪好

额头和下巴也来点腮红,这样的肤色会更自然,更健康红润。

记住,唇色一定要有过度,内深外淡,才适合今天的妆容。

最后把头发打乱,做的稍微蓬松一点,在后面挽成一个发髻。简单自然。因为我的脸型不好,所以蓬松可以让我的脸部看起小一点,要想让脸小的MM可以尝试把头发做的饱满一些。

看看后面的小发髻。呵呵

0

《圣斗士星矢》暴露党内斗争黑幕 建议有关部门予以封杀


[原创]车田正美的政治寓言:星矢主角解读
文章提交者:注史封侯 加帖在 影视评论 【凯迪网络】 http://www.kdnet.net

一部漏洞百出情节重复对白肉麻啰唆人物刻画单一的动漫绵延了近二十年80一代的情结,每一个人都曾用稚嫩的声音在挥拳打向同桌的你时都会伴以“庐山升龙霸 ”抑或是“凤翼天翔”的怒吼,每一个人都曾迷恋青铜不死五大贱人之一(不被痛打就不发挥实力故曰贱),或者十二黄金之一,而其中的大多数都没有选择圣斗士 的主角星矢,并且这大多数中的大多数都表示过对这个领衔贱人的鄙视。

于是问题就来了,他,星矢,论耍酷不及一辉,帅气不及紫龙,英俊不及冰河,柔美不及瞬,为什么会是领衔主角?

车田正美很熟悉希腊神话,这是人所共知的,但实际上,车田正美真正洞彻透析的是政治,确切的讲,是东方传统政治智慧。在主角的安排上,我不禁对车老佩服到缩阳入腹。

《走向共和》里瞿鸿穖对学生吴毓昌如是说:“老佛爷哪里在乎你贪污玩闹,可你要跟她离心离德,你死去吧!这一点呀,那么多年,咱们竟然就没看明白!可你看 人家出的牌,张张都是政治牌、屁股牌─ ─人家玩着、闹着,搞女人,搂钱财,可人家永远政治上正确,屁股坐的永远是正确的地方。那才叫高!毓昌啊,清洁的道德牌打不过肮脏的屁股牌啊!咱们从一开 始就败了!”

老瞿一生所悟,车田正美一笔道出,星矢能够成为主角,关键就在于政治立场永远坚定,政治素质永远过硬!

此足为80一代入仕者戒!

让我们好好分析一下青铜五大贱人在政治立场上存在的各种问题。

青铜五贱人出身最牛叉的无疑是紫龙,童虎的实力资历恐怕无人能出其右,但是在撒加叛乱的时候,童虎躲在庐山死活不出来,五青铜血战圣域雅典娜命在顷刻也不出手,我知道会有人说这是要镇守封印不能擅离职守,靠,雅典娜要是挂了组织就没了,镇不镇守又有何妨?

所以严格来讲在撒加路线和雅典娜路线产生重大分歧的危机时刻,童虎选择了中立观望,况且资历实力在那里摆着,功高震主,尾大不掉,而紫龙对于童老师表现出 了不亚于雅典娜的忠诚,这就很成问题了,所以紫龙虽然在五大贱人之中最为帅气,而且其战斗也最为煽情,但是在雅典娜心里,小龙同学不作考虑。

但是紫龙的地位仅次于星矢,雅典娜和他单独精神交流的次数也仅少于星矢,一方面是小龙同学和星矢私交最好,可以算作红外围,而且干群关系过硬,另一方面,也是借此平衡和怀柔童虎老将军。

冰河的师傅是卡妙,也正是因为卡妙的错误,冰河不可能成为主角。童虎中立,而卡妙就严重得多。直接参与了撒加路线。虽然是被骗,但是政治上可以犯罪,却坚 决不能犯错。而且卡妙和米罗私底下的小山头小派系也令雅典娜心中不满。雅典娜把罪人加隆留在身边米罗竟然毫不知情,足以说明雅典娜彻底对米罗pass。

因此冰河不能做主角就很容易理解了。

一辉的政治错误又比以上几位更为严重,直接参加了撒加叛乱,而且干群关系也极其糟糕。加上实力比较强圣衣又有自我修复功能使之对雅典娜的依赖性要大大小于另外几位。

属下什么时候最忠诚?别无选择的时候最忠诚!

一辉还公开宣称自己是无神论者。这就决定了他和所有大佬的决裂。就是到了海皇冥界都不可能被重用。

某种程度上,一辉就是圣斗士里的鲁迅。不能容于民国,也不可能容于新中国。

这样一个政治愤青,他的直系亲属当然也就跟着玩完了。所以可怜的瞬就不多说了。

而仔细观察一下星矢,他的师傅魔铃是五贱人师傅里最菜的一个,恐怕悍一点的白银就可以将其秒杀。所以星矢基本上等同于无产阶级出身,两把菜刀闹革命,魔铃的实力资望是决不可能拉山头的,混到死也无非是娘子军或者文工团。星矢除了跟定雅典娜,别无选择。

其次,星矢是在圣域里大学毕业的,也是唯一一个圣域修炼的人,虽然魔铃地位卑下,但是圣域却是不折不扣的中央党校。星矢在中央系统学习的经历是其余四人永远无法享有的。用易中天的语风来形容就是,出身很低,起点很高。

再次,每个圣斗士在恶战中都会呼唤雅典娜,歌颂雅典娜,向雅典娜表忠心,但是星矢表露的最多,而且次次都有新鲜玩意,政治斗争非常重要的一条就是舆论先 行,占领理论高地。这也充分表现了党校子弟坚实的理论功底。星矢在政策宣传方面对于雅典娜精神的领会,在斗争行动中对于雅典娜主义的贯彻,在理论联系实 际,实践总结理论方面的创新,无疑是与时俱进的,是与其坚定的政治信仰分不开的,是个人修养素质的充分体现。

最后,星矢是可以被用来黏合各派势力的润滑剂。紫龙童虎集团自然不必多说。在斗争后期,星矢往往和瞬结伴同行,这恐怕是雅典娜刻意安排。因为一辉实力暴涨 的太厉害,其余四人见了黄金十二人跟追星族似的,但是一辉已隐然可以分庭抗礼,而且穿的还只是青铜圣衣。通过星矢和瞬的联系怀柔一辉,雅典娜用心良苦。这 也看出来星矢的确是“你办事,我放心”,在五大贱人里,星矢拥有小蜜的人数和质量都是上上成,萨尔娜和美惠,一个俏娇野性,一个温婉多情,都是男人梦寐以 求的尤物。但是星矢一概抛掷脑后,不怕和有严重变性倾向的瞬搅在一起惹祸上身闹出个青铜断背山,坚决贯彻雅典娜的策略,忠勇二字当之无愧。

冰河实力属于中游,况且卡妙已死,成不了什么气候,雅典娜对于冰河的冷落非常明显。冰河后期主动贴近人缘最好最够义气的紫龙,希望可以不脱离组织,但也只 是苟延残喘。这一点可以看出雅典娜为什么可以在诸大佬斗争中屡次胜出。如海皇冥王之流对于垃圾下属往往直接抛弃,而雅典娜不动声色的冷处理还可以让冰河发 挥余热,同时稳住米罗,再私下引进加隆进行牵制,同时卖个顺水人情给紫龙童虎集团,一举多得,政治手腕高明的紧。

综合以上分析,圣斗士主角,除了星矢,没有人可以胜任。《圣斗士》实际上是一部意思深远的政治动漫作品。车田正美深邃的笔触和见底足以使之永垂不朽。但其中暴露的残酷的斗争现实在不应该被广大青少年过早接触。建议有关部门予以封杀。

01

女友跟人跑了,网友安慰楼主竟成如此结果……


某论坛有一楼主伤心发贴,竟然引来一批网友安慰,然后形成如此结果……

原帖如下:

我和我老婆是大学里认识的,大2的时候,我们在同一个学院,故事很平常,朋友租房子我去帮忙抬东西,朋友的朋友也去帮忙,这样我就认识了朋友的朋友,也就是老婆。

大学的生活很快,日子过去。我是个穷人,家里没有钱,父母以前是工人,现在下岗了在外打工,虽然穷,但是日子过得很快乐,我和老婆也是一样,最让她感动的是 2003年我节约钱给她买了她很喜欢的那双 NIKE的鞋,她很感动,那时候我也觉得自己很幸福。

她的家庭情况也一般,她说以后想考公务员,而我刚上大四时去了一个房屋公司兼职做了个小职员,一个月1500。一切看来都很好。我是成都人,老婆重庆的。我在重庆读大学自然就在重庆的工作了,公司在两路口,那时候我和老婆计划着以后奋斗的生活。

风云突变,就在大四的下学期,在毕业来临的日子里,我们和中国农业大学进行友好学生活动。她认识了里面一个大四的上海人。那天活动我也去了,我见到了那个 上海人,带着个傻忽忽的眼睛,可是一看那小样就有点钱。二天后,老婆就搬出了我们租的房子。只是匆匆的来了个电话和一封信,大概意思是对我道歉,还叫我努 力,鼓励我去面对未来美好的生活。

那一时刻我的头都炸了,没有伤心的感觉,只是觉得脑袋空空的,后来她的朋友来告诉我,那个上海人很有钱,有车有房子,家里还有船。那天上海人陪她坐车出去 到了,大概是到瓷器口方向有一段路不好,那上海人就出了钱找几个民工买材料把那段路修好,就这一举动彻底征服了我老婆。

在我看来这纯粹的无聊花钱行为中,老婆没有了,毕业典礼的时候她已经在和那个上海人软语开心的聊天了。我觉得自己很失败,那天晚上我坐在通往到解放杯的公交车上,在最后一排我终于忍不住哭了。

事后想想也不怪她,人人都有追求幸福的权利,但作为一个男人只有提高自身的含金量才是正途。有时我常常笑我自己是井底之蛙,1500元要多少年才能买车买 房,没有钱哪来的浪漫?让人跟你受穷?人家上海人有钱就该娶美女,我这种穷鬼要是找到了美女那不是阻碍了先进生产力的发展方向?还怎么构建和谐社会? 每当有人提起她,我的心理都这样想着。

以下为其他网友安慰楼主的回帖,请欣赏:

某网友回复:

我是上海人,遭遇和 LZ一样.上个月我认识半年的女友和一个香港人跑了. 我收入还可以有房有车,但那HK人不但有房还有辆三菱的跑车,月薪有七八万,够我做大半年的了.最可气的是 ,我1.86她1.70那个矮子才1.60. 事后想想也不怪她,人人都有追求幸福的权利,但作为一个男人只有提高自身的含金量才是正途,不需要自怨自哀. 希望能与LZ共勉

某网友回复:

我是香港人,遭遇和LZ一样.上个礼拜我认识才半个月的女友和一个日本鬼子跑了.我收入还可以,有房有车,还是三菱的跑车,月薪也有七八万,够 LZ做好几年的了.最可气的是,我1.60那个日本鬼子才1.55。事后想想也不怪她,人人都有追求幸福的权利,但作为一个男人只有提高自身的含金量才是 正途,不需要自怨自哀.希望能与LZ 共勉.

某网友回复:

我是火星人,遭遇和LZ一样.上个礼拜我认识才半个月的女友和哈雷慧星人跑了.我收入还可以,有房有车有飞碟,还有宇宙飞船空间站,月薪也有七八个兆。可 是那哈雷慧星人开的是激光束啊!最可气的是,我0.55那个哈雷慧星人才0.5,事后想想也不怪她,人人都有追求幸福的权利 ,但作为一个男人只有提高自身的含金量才是正途,不需要自怨自哀.希望能与LZ共勉.

某网友回复:

我是哈雷慧星人,遭遇和LZ一样上个礼拜我认识才半个月的女友和土星人跑了.我收入还可以,有房有车有飞碟,还有激光束,月薪也有七八个亿兆。可是那土星 人开的是土星光环啊!最可气的是,我0.5那个土星人才0.05,事后想想也不怪她,人人都有追求幸福的权利,但作为一个男人只有提高自身的含金量才是正 途,不需要自怨自哀.希望能与LZ共勉.

某网友回复:

我是土星人,遭遇和LZ一样.上个礼拜我认识才半个月的女友和M78星云的奥特曼跑了.我收入还可以,有房有车有飞碟,有激光束,我还有土星光环作交通工 具,月薪也有七八个万亿兆。可是那M78星云的奥特曼不用坐什么自己就能飞!最可气的是,我0.05那个奥特曼有400多米,事后想想也不怪她,人人都有 追求幸福的权利,但作为一个男人只有提高自身的含金量才是正途,不需要自怨自哀.希望能与LZ共勉.

某网友回复:

我是奥特曼,遭遇和LZ一样 .上个礼拜我认识才半个月的女友和一个重庆人跑了。我收入还可以,有房有车有星球,不用交通工具自己就会飞,翻个身就十万八千里,没有月薪,自己印钞。没办法,女友说我不是人。

0

这年头干啥都费劲


一女下夜班,一男尾随图谋不轨. 女子惧怕,路过坟地,灵机一动,对着坟墓说:”爸爸,我回来了,开门~.”男惧奔逃.女子正要离开,坟墓中传来阴森森的声音:”闺女,你又忘了带钥匙?” 女子惊骇,大叫奔逃.坟墓里钻出个盗墓的说:”耽误我工作,吓死你们!”话音刚落,发现旁边有个老头正拿着凿子刻墓碑,问.老头说:”他们把我的名字刻错了.”盗墓的奔逃.老头冷笑:”敢和我抢生意,还嫩了点……”正说着,一不小心凿子掉地上了.老头正要拾,发现凿子握在草丛里的一只手里.一个声音说:”你找死啊?乱改我的门牌号~!”老头屁滚尿流下了山坡.一个拾荒者从草丛里爬出来说:”哎,这年头搞块废铁,也得费这么大劲~~~~~”

01

男人日记(转贴)


周一:下班回家,开门,窗明几净、一尘不染,猛掐大腿,确定不是做梦,倒退三
步出门,上次喝高了踹在墙上的脚印还在,确定是自己家,遂又进门,沙发上一尊
手拿遥控器的活雕塑让我更加确定无疑了。查证,确定了五个问题:没请钟点工、
我妈没来过、同学同事没人要来玩、没受啥刺激、早上太阳是从东边出来的。第六
个问题还没确定,一只耳朵已经呈酱紫色。

  周二:清晨醒来,老婆做憧憬状:“老公,你说如果每天我一睁开眼睛,就有
可口的早餐摆在我的眼前该有多好啊。”我顺便帮她擦了一下眼角:“人做一辈子
梦很容易,难的是总做白日梦。”于是,早餐老婆吃了两个鸡蛋,喝了两杯牛奶,
我没饭吃。

  中午,小王请客,我吃得很饱。晚上看电视,老婆问我章子怡和她谁漂亮,我
说了实话,她睡卧室,我睡客厅。

  周三:老婆出差,说吃东西容易晕车,没做早饭,我也没吃。中午,小张请
客,我吃撑了。晚上,我没吃饭,顺便减肥。

  周四:早上我又没吃饭。中午,小陈请客,没叫我。很久没去老同学家做客
了,下午下班后,顺便去拜访,女主人留我吃饭,我没有拒绝,吃得很饱。

  周五:早上没吃饭。中午我请客,叫上了小王、小张和小吴,下午他们三个吃
饼干,而我撑得走不动。晚上老婆回来,我做饭,给老婆放洗澡水,我在大床上睡
得很好。

  周六:早上,老婆说还有一个面包,谁吃,我说一人一半,结果老婆吃了一个
面包,我没吃饭。

中午老婆无声无息地消失,我不知道她去了哪里,我喝了一杯水,饿着肚子。下午
老婆同学聚会,我晚饭吃了三包方便面,然后看电视。老婆回来河东狮吼,怪我这
么晚不知道打个电话关心一下,我很无辜:“现在的坏人一般劫色不劫财,你应该
比较安全。”说完屁股挨了一脚“无影腿”,我恍然大悟:“我忘记了,晚上天
黑,坏人看不清你的模样,没准就稀里糊涂地劫了色了,看来你还得小心。”于是
老婆睡的大床,我又睡客厅。

  周日:我休息,老婆问我陪她逛街还是在家洗衣服,我选择了前者。其间,老
婆走失两次,老婆买衣服问我好不好看我说实话被骂N次,老婆遇到熟人,我傻站
四十分钟。午饭在外面吃,我没吃饱。晚上去妈妈家吃饭,我吃得很饱,夜里起来
上了两次厕所。

  一周总结:本周有五天没吃早饭,两天没吃午饭,两天没吃晚饭,睡客厅两
次,总的来说,平均吃饭率比上周提高了2.5个百分点,睡客厅次数减少一次,还
算小有进步,我会再接再厉,争取在新的一周里吃饭率再提高2.5个百分点,尽量
把睡客厅的次数减少到零。

0

惊现:山寨版七龙珠里的“撒旦先生”,被彻底雷倒了。


1235987909099.jpg

Previous Page

Random Posts Recent Comments

  • 女友糖尿病害我蛀牙 Says:

    汗一个…...

  • Htj06 Says:

    zhenyouchuangyi...

  • 电商圈 Says:

    试图该怎么建立啊,,怎在程序中是吸纳...

  • edward Says:

    看得人心旷神怡,好文,情不自禁的顶一下...

  • Daniel Says:

    我也在处理这个问题,没有找到好的方法。我用了楼上兄弟的方法,还是可以的。不知道您找到好的方法了吗、我暂时楼上兄弟的方法。...

  • 卡,卡 Says:

    弱弱问一句:博主,你博客的模板这样设计pv高吗?...

  • 站长工具 Says:

    博主,兔年快乐!...

  • health Says:

    great post!!I hope I can read more in your website....

  • pdu Says:

    好博文,支持分享...

  • 站长工具 Says:

    博主的文章很不错,我是站长工具-站长精灵的作者,一款专业的SEO工具软件(可以帮您提高博客的流量),想跟您交换个链接,不知可否...

Tag Cloud

arm audio blog brew cache class debug flash google html j2me java javascript Joke linux lua mobile mtk php python ror ruby server shell stream unix web windows 优化 动态加载 女人 女生 平台 开发 手机 技术 流媒体 测试 漫画 生活 男人 男生 缓存 芯片