??xml version="1.0" encoding="utf-8" standalone="yes"?>国产精品久久久久蜜芽,久久国产劲爆AV内射—百度,久久久无码一区二区三区http://www.shnenglu.com/kevinlynx/category/13254.html低调做技术__ C/C++\MMORPG服务器\模块架构__ TODOQ编译原理\linux env __Kevin Lynxzh-cnMon, 15 Mar 2010 17:01:19 GMTMon, 15 Mar 2010 17:01:19 GMT60[ȝ]LL(1)分析法及其实?/title><link>http://www.shnenglu.com/kevinlynx/archive/2010/03/15/109765.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Mon, 15 Mar 2010 13:33:00 GMT</pubDate><guid>http://www.shnenglu.com/kevinlynx/archive/2010/03/15/109765.html</guid><wfw:comment>http://www.shnenglu.com/kevinlynx/comments/109765.html</wfw:comment><comments>http://www.shnenglu.com/kevinlynx/archive/2010/03/15/109765.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/kevinlynx/comments/commentRss/109765.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/kevinlynx/services/trackbacks/109765.html</trackback:ping><description><![CDATA[<p><font size=2>LL(1)分析法和递归下降分析法同属于自顶向下分析法。相对于递归下降而言QLL通过昄<br>地维护一个栈来进行语法分析,递归下降则是利用了函数调用栈?</font> <p><font size=2>LL分析法主要由分析栈、分析表和一个驱动算法组成。其实LL的分析算法还是很Ҏ(gu)懂的Q?br>主要是一个匹配替换的q程。而要构造这里的分析表,则还涉及计算first集和follow?br>的算法?</font></p> <p><a href="http://www.shnenglu.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/LL1_12DFD/1_2.jpg"><img style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; DISPLAY: inline; BORDER-TOP: 0px; BORDER-RIGHT: 0px" title=1 border=0 alt=1 src="http://www.shnenglu.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/LL1_12DFD/1_thumb.jpg" width=391 height=346></a> </p> <p><font size=2>个h觉得龙书在解释这些算法和概念旉非常清楚l致Q虽然也有h说它很晦涩?</font> <p><font size=2>first集和follow集的计算Q抛开书上l的严密法Q用人的思维ȝ解(对于compiler<br>compiler则需要用E序L造这些集合,q是让计机ȝ解)Q其实很单: </font> <p><font size=2>1、对于某个非l结WA的first集(first(A)Q,单地说就是由A推导得到的串的首W号?br>集合QA->aBQ那么这里的a属于first(A)Q很形象?br>2、follow(A)Q则是紧随A的终l符号集合,例如B->AaQ这里的a属于follow(A)Q也很Ş<br>象?</font> <p><font size=2>当然Q因为文法符号中有epsilonQ所以在计算上面两个集合时则会涉及到一U传递性。例<br>如,A->Bc, B->epsilonQB可以推导出epsilonQ也是基本{同于没有,那么first(A)?br>׃包含cW号?</font> <p><font size=2>在了解了first集和follow集的计算Ҏ(gu)后,则可以通过另一些规则构造出LL需要的分析表?</font> <p><font size=2>~译原理里L很多很多的理论和法。但正是q些理论和算法,使得~译器的实现变得<br>单,代码易维护?</font> <p><font size=2>在某个特定的~程语言中,因ؓ(f)其文法一定,所以对于其LL(1)实现中的分析表就是确定的<br>。我们也不需要在E序里动态构造first和follow集合?</font> <p><font size=2>那么Q要实现一个LL(1)分析法,大致步骤集中于Q设计文?>建立该文法的分析?>~?br>码?</font> <p><font size=2>LL分析法是不能处理左递归文法的,例如Qexpr->expr + termQ因为左递归文法会让对应<br>的分析表里某一存在多个候选式。这里,又会涉及到消除左递归的方法。这个方法也很简<br>单,只需要把文法推导式代入如下的公式卛_Q?</font> <p><font size=2>A -> AB | C {h(hun)于:A -> CX, X -> BX | epsilon </font> <p><font size=2>最后一个问题是Q如何在LL分析q程中徏立抽象语法树(wi)呢?虽然q里的LL分析法可以检查文<br>法对应的语言是否合法有效Q但是似乎还不能做Q何有意义的事情。这个问题归l于语法?br>导翻译,一般在~译原理教程中语法分析后的章节里?</font> <p><font size=2>LL分析法最大的(zhn)剧在于一在人看来清晰直白的语法?wi)分割了。在递归下降分析法中Q?br>一个树(wi)节点所需要的属性(例如术q算W所需要的操作敎ͼ可以直接由其子节点得到。但<br>是,在ؓ(f)了消除左递归而改变了的文法式子中Q一个节Ҏ(gu)需要的属性可能跑到其兄弟节点<br>或者父节点中去了。貌D里可以参?#8220;l承属?#8221;概念?</font> <p><font size=2>不过Q综合而言Q我们有很多业余的手D|处理q种问题Q例如徏立属性堆栈。具体来_<br>例如对于例子代码中计算术表辑ּQ就可以把表辑ּ中的数放C个栈里?</font> <p><font size=2>例子中,通过在文法表辑ּ中插入动作符h标识一个操作。例如对于文法:<br>expr2->addop term expr2Q则可以改ؓ(f)Qexpr2->addop term # expr2。当发现分析栈的?br>元素是'#'Ӟ则在属性堆栈里取出操作数做计算。例子中q将操作W压入了堆栈?</font> <p><font size=2><a href="http://www.shnenglu.com/Files/kevinlynx/LL1.rar" target=_blank>下蝲例子</a>Q例子代码最好对照arith_expr.txt中写的文法和分析表来看?</font> <p><font size=2>PSQ最q在<a target=_blank>云风博客中看Cl的一句评?/a>Q我觉得很有道理Qƈ且g伸开来可以说明我?br>周围的很多现象: </font> <p><font size=2>”很多东西Q意识不到问题比找不到解x法要严重很多。比如one-pass q个Q觉得实?br>ȝ不去实现Q和觉得实现没有意义不去实现是不同的?#8220; </font> <p><font size=2>对于以下现象Q这句话都可以指明问题:<br>1、认为造轮子没有意义,从不考虑自己是否能造出Q?br>2、常告诉别h某个技术复杂晦涩不利于团队使用Q却q不懂这个技术;<br>3、笼l来_【觉得】太多东西没有意义,虽然q不真正懂这个东ѝ?</font></p> <img src ="http://www.shnenglu.com/kevinlynx/aggbug/109765.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2010-03-15 21:33 <a href="http://www.shnenglu.com/kevinlynx/archive/2010/03/15/109765.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>要实现正则表辑ּ匚w字符?/title><link>http://www.shnenglu.com/kevinlynx/archive/2010/02/20/108094.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Sat, 20 Feb 2010 06:53:00 GMT</pubDate><guid>http://www.shnenglu.com/kevinlynx/archive/2010/02/20/108094.html</guid><wfw:comment>http://www.shnenglu.com/kevinlynx/comments/108094.html</wfw:comment><comments>http://www.shnenglu.com/kevinlynx/archive/2010/02/20/108094.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.shnenglu.com/kevinlynx/comments/commentRss/108094.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/kevinlynx/services/trackbacks/108094.html</trackback:ping><description><![CDATA[<p><font size=2>之所以说?#8220;要实?#8221;一斚w是因为算法不高深,法的实C不精_甚至q我对其的理解也不够本质?/font></p> <p><font size=2>我只不过不想在工作若q年后还是一个只会打字的E序员。学点什么东西,真正_N点什么东西才对得起喜?/font></p> <p><font size=2>技术的自己?/font></p> <p><font size=2></font> </p> <p><font size=2>附g中的代码_略实现了《编译原理》龙书中的几个算法。包括解析正则表辑ּQ徏立NFAQ然后用NFAd</font></p> <p><font size=2>配目标字W串Q或者从NFA建立DFAQ然后匹配。解析正则表辑ּ我用了比较繁琐的Ҏ(gu)Q有词法和语法分?/font></p> <p><font size=2>q程。词法分析阶D将字符和一些操作符整理出来Q语法分析阶D在建立语法?wi)的q程中对应地建立NFA?/font></p> <p><font size=2>当然Q因法树(wi)在这里ƈ没有用处Q所以ƈ没有真正地徏立?/font></p> <p><font size=2></font> </p> <p><font size=2>从正则表辑ּ到NFA比较单,很多~译原理书里都提到过Q如Qs|t表达式对应于下面的NFA:</font></p> <p><a href="http://www.shnenglu.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/64211484befa_D161/1_2.jpg"><img style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=1 border=0 alt=1 src="http://www.shnenglu.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/64211484befa_D161/1_thumb.jpg" width=296 height=161></a> </p> <p>代码中用如下的结构描q状态和状态机中的转换Q?/p> <p>#define E_TOK (0) <p>/* transition */<br>struct tran<br>{<br>    char c;<br>    struct state *dest;<br>    struct tran *next;<br>}; <p>struct state<br>{<br>    /* a list of transitions */<br>    struct tran *trans;<br>    /* inc when be linked */<br>    int ref;<br>}; <p>卻I每一个状态都有一个{换列表,每个转换都有一个目标状态(卌转换指向的状态)以及转换字符?/p> <p>貌似通过以上Ҏ(gu)建立出来的状态机每个状态最多只会有2个{换?</p> <p> </p> <p>建立好NFA后,由NFA匚w目标字符串用了一U构造子集法Q《编译原理?.7.2节)Q?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/64211484befa_D161/2_2.jpg"><img style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=2 border=0 alt=2 src="http://www.shnenglu.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/64211484befa_D161/2_thumb.jpg" width=266 height=214></a> </p> <p>q个法里针对NFA的几个操作,如e-closure、move{在由NFA转换DFA时也被用刎ͼ因此代码里单?/p> <p>做了装Qstate_oper.cQ。这个算法本质上貌似是一ơ步q(stepQ多个状态?/p> <p> </p> <p>至于由NFA转DFA,则是相对单的子集构造法Q?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/64211484befa_D161/3_2.jpg"><img style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=3 border=0 alt=3 src="http://www.shnenglu.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/64211484befa_D161/3_thumb.jpg" width=396 height=229></a> </p> <p>在我以前~译原理课考试的前一天晚上(你懂的)我就对这些算法颇为疑惑。在以后看各U编?/p> <p>原理教材Ӟ我始l不懂NFA是怎么转到DFA的。就懂了操作步骤(我大学同学曾告诉我这些步骤,虽然</p> <p>不知道ؓ(f)什么要那样做)Q一D|间后依然搞忘。很喜欢《编译原理》龙书里对这个算法最本质的说明:</p> <p> </p> <p><a href="http://www.shnenglu.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/64211484befa_D161/4_2.jpg"><img style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=4 border=0 alt=4 src="http://www.shnenglu.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/64211484befa_D161/4_thumb.jpg" width=596 height=31></a> </p> <p> </p> <p>源代码我是用GCC手工~译的,qmakefile也没有。三个test_XXX.c文g分别试几个模块。test_match.c</p> <p>基本依赖除掉test外所有c文gQ全部链接在一块即可。当Ӟq验而言我知道是没几个h会去折腾我的q些</p> <p>代码的。这些在china的领导看来对工作有个鸟用的代码读h我自׃觉得费力Q何况,我还不u不类地用?/p> <p>不知道算哪个标准的c写了q些?/p> <p> </p> <p>你不是真?a href="http://www.shnenglu.com/Files/kevinlynx/reg_expr_match.zip">下蝲?/a>对于q种代码Q有BUG是必然的Q你也不用在此文若干个月后问我多行是什么意思,因ؓ(f)</p> <p>那个时候我也忘?D?/p> <img src ="http://www.shnenglu.com/kevinlynx/aggbug/108094.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2010-02-20 14:53 <a href="http://www.shnenglu.com/kevinlynx/archive/2010/02/20/108094.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>kl中的错误处理http://www.shnenglu.com/kevinlynx/archive/2009/03/26/77963.htmlKevin LynxKevin LynxThu, 26 Mar 2009 09:17:00 GMThttp://www.shnenglu.com/kevinlynx/archive/2009/03/26/77963.htmlhttp://www.shnenglu.com/kevinlynx/comments/77963.htmlhttp://www.shnenglu.com/kevinlynx/archive/2009/03/26/77963.html#Feedback0http://www.shnenglu.com/kevinlynx/comments/commentRss/77963.htmlhttp://www.shnenglu.com/kevinlynx/services/trackbacks/77963.htmlkl中的错误处理

    之前我一直说错误处理是kl里的软肋Q由于一直在x一些具体功能的改进Q也没有?br>q方面进行改善?

    我这里所说的错误处理Q包括语a本n和作为库本n两方面?br>    语言本n指的是对于脚本代码里的各U语法错误、运行时错误{的处理。好的处理应?br>不仅仅可以报告错误,而且q能忽视错误让处理过El?br>    而把kl解释器作Z个库使用Ӟ库本w也应该对一些错误情况进行报告?

    整体上,kl单地通过回调函数指针来把错误信息传给库的应用层。而因为我希望整个
kl实现的几层(词法分析、语法分析、符可、解释器{)可以可能地独立。例如虽然语
法分析依赖于词法分析Q依赖于词法分析提供的接口)Q但是因法分析ƈ不对语法分析
依赖Q所以完全可以把词法分析模块拿出来单独用。所以,在日志方面,我几乎ؓ(f)每一?br>都附加了个error_log函数指针?br>    而用户层在通过kllib层用整个库Ӟ传入的回调函C被间接地传到词法分析层?br>实际上,当kl作ؓ(f)一个库Ӟkllib正是用于桥接库本w和用户层的bridge?

    另一斚wQ语a本n在处理错误的脚本代码Ӟ错误分ؓ(f)几大cd层次Q?br>    1.词法错误 lex errorQ如扫描字符串出?br>    2.语法错误 syntax errorQ整理语法树(wi)时出?br>    3.q行旉?runtime errorQ在解释执行代码时出?br>    4.库错?lib errorQ发生在kllibq个bridge层的错误
    kl在报告错误信息时Q会首先附加该错误是什么类型的错误?

    q里最ȝ的是语法错误的处理。因法分析时发生错误的可能性最大,错误cd?br>有很多。例如你写了分P写了括P都会D错误。这个阶D发生错误不仅要求能?br>报告错误,q需要忽略错误让整个q程量正确C厅R?

    语法分析阶段最Ҏ(gu)的就是符h|单就kl的实现而言Q,所谓的W号推导是这样一
个过E,例如有赋D句:a = 1;语法分析Ӟ语法分析器希望(所谓的推导Q等号后面会
是一个表辑ּQ当分析完了表达式后Q又希望接下来的W号(token)是分号作语句的结
束?br>    所以,klparser.c中的syn_match正是完成q个q程。每ơ你传入你希望的W号Q例?br>分号Q该函数检查词法分析中当前W号(token)是否是分受当Ӟ对于正确的脚本代码,
它是一个分P但是如果是错误的代码Qsyn_match׃打印诸如Q?br>    >>syntax error->unexpected token-> ....
    卛_前的W号是不被期望的?

    上面完成了错误的。对于错误的忽略Q或者更高点地寚w误的校正Qkl中处理得
比较单,卻I直接消耗掉q个不是期望中的W号。例如:
    a = 1 /* 忘加了分?*/
    b = 1;
    上面两句代码被处理时Q在处理完a=1后,发现当前的符?token)b(是一个ID token)?br>是期?expect)中的分号Q首先报告b不是期望的符P然后kl直接掠过bQ获取下个符??br>然后处理a=1q个q程l束。当Ӟ下次处理其他语句Ӟ发现=W号Q又会l发生错误?

    错误信息中比较重要的q有行号信息。之前klq方面一直存在BUGQ我在写贪食蛇例?br>的时候每ơ新加代码都不敢加太多。因释器报告的错误行hL错误的,我只能靠有没
有错误来N误,而不能通过错误信息N误?br>    行号信息被保存在词法分析状态中(lexState:lineno)Q语法分析中获取tokenӞ会取
出当前的行号Q保存到语法?wi)?wi)节点中。因为包括解释模块都是基于树(wi)节点的,所以词法分
析语法分析解释器三层都可以准报告行受?

    但是之前解释器报告的行号始终很诡异。症l在于我在蝲入脚本代码文件时Q以rb方式
载入Q即二进制Ş式。于是,在windows下,每行文本N会有\r\n两个字符。而在词法?br>析阶D对于行L(fng)增加是:
    case '\n':
    case '\r':
        ls->lineno ++;
    不同OS对于文本文g的换行所d的字W都不一P例如windows用\r\nQunixpȝ\n
Q貌似Mac用\r。所以,词法分析q里写应该可以准地处理行号?

    但是对于windowsQ这里就直接行号增加了两次Q所以也导致了行号出错的问题。查
了下文档Q发C文本方式打开文g("r")Q调用fread函数d文g内容Ӟ׃自动?br>\r\n替换为\n?

    代码改后Q又出问题。这个时候,通过fseek和ftell获取到的文g寸Q貌似包括了
\r\nQ而fread出来的内容却因ؓ(f)替换\r\n为\n而没有这么多?br>    不过文g载入不属于kl库本w,kl只接收以字符串Ş式表C的脚本代码Q所以也不?br>核心问题?

    同样Q最C码可以从google SVN获取。当Ӟ我也在考虑是否换一个新的项目地址?



Kevin Lynx 2009-03-26 17:17 发表评论
]]>
kl sample:贪食?/title><link>http://www.shnenglu.com/kevinlynx/archive/2009/03/25/77872.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Wed, 25 Mar 2009 13:17:00 GMT</pubDate><guid>http://www.shnenglu.com/kevinlynx/archive/2009/03/25/77872.html</guid><wfw:comment>http://www.shnenglu.com/kevinlynx/comments/77872.html</wfw:comment><comments>http://www.shnenglu.com/kevinlynx/archive/2009/03/25/77872.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/kevinlynx/comments/commentRss/77872.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/kevinlynx/services/trackbacks/77872.html</trackback:ping><description><![CDATA[<p><font size=2></font>  <p><font size=2>    貌似最qCPPBLOG写一门脚本语a比较行Q连我这U山寨程序员都搞Z个像C又像<br>BASIC的所谓脚本语aQ可见其行E度?/font></p> <p><font size=2><br>    q个kl脚本例子Q是一个具有基本功能的贪食蛇游戏。这个例子中使用了两个插Ӟ<br><a target=_blank>HGE引擎</a>、以及一个撇脚的二维数组插g。因为kl对于数组的实C是那么漂亮,而我实在<br>不想因ؓ(f)加入二维数组的支持而让代码看v来更乱,所以直接不支持q个Ҏ(gu)。考虑Cl?br>数组的应用在一些小游戏中还是比较重要(例如q个贪食蛇,总需要个容器M存游戏区?br>的属性)Q所以撇脚地加了个支持number的二l数l插件?</font></p> <p><font size=2>    HGE插g我只port了部分接口,也就是注册了一部分函数到脚本里Q提供基本的贴图?br>能。(port--我实在找不到一个合适的词语来Ş容这U行?--HGEC门脚本语a里,我似<br>乎做q几ơ) </font> <p><font size=2>    不知道有没必要提供贪食蛇的实现算法,q似乎说出来有点弱智? - 不过Z方便?br>人阅读kl脚本代码Q我q是E微讲一下。游戏中使用一个二l数l保存整个游戏区域,所?br>的游戏区域就是蛇可以zd到的地方。每一个二l数l元素对应游戏区域中的一个格子,?br>且称为tile。每个tile有一个整数DC其属性,如BODY、WALL、FOOD、NONE。蛇体的Ud<br>归根l底是蛇头和蛇Ud。蛇头和蛇尾属性一P但是蛇头负责把所l过的tile讄<br>为BODYQ而蛇ֈ把经q的tile讄为NONE。蛇头的Ud方向靠玩家控Ӟ每次蛇头转弯?br>Q都会记录一个{弯点C个队列。{弯点包括转弯XY坐标以及转向的方向。蛇每ơ移?br>旉会检查是否到达了一个{弯点Q是的话p|自qUd方向转弯点记录的方向?</font> <p><font size=2>    虽然我写了klq个脚本语言Q但是语aҎ(gu)ƈ不是我设计的。我只是取了C语言的一?br>Ҏ(gu)。所以在写这个sample的时候,我对于klq个脚本语言的感觉,是一个像basic的C?br>因ؓ(f)它太单一Q就像BASIC一样只拥有语言的一些基本功能,不能定义复杂的结构,没有?br>生的对各U数据结构的支持Q例如某些语a直接有list, tuple之类Q?</font> <p><font size=2>    以前中学的时候在?sh)子词典上用GVBASIC写小游戏Q当旉了BASIC什么也不知道。今?br>写这个贪食蛇例子Q感觉就像以前用BASIC?</font> <p><font size=2>    回头说说一些kl脚本里的Ҏ(gu)。从q个例子里(见下载包里的snake.klQ,诸如whileQ?br>forQif...else if...被支持(之前发布的版本里q不支持for和else ifQ。全局变量支持<br>赋初|上个版本不支持)。当Ӟq演CZ如何使用插g函数?</font> <p><font size=2>    但是Q仍有一些特性在我的懒惰之下被置之不理。例如return后必跟一个表辑ּQ这<br>意味着单纯的return;被视ؓ(f)语法错误。对于if( a && b )Qkl会计所有的表达式,?br>别的语言也许会在a会false后不计算bQ这也许不算个问题,但v码我q没修正。还有,kl<br>内部对于错误的报告依然没被修复,打一个分号你会得Cpd错误的报告,但是却没?br>准确的行受甚臻I你会看到解释器崩掉。不要紧Q在我心里,它作为当q电(sh)子词怸那个<br>GVBASIC而言Q已l很强大的了?DD</font> <p><font size=2>    最q接触了很多UNIX和GNU之类的东西,发觉没有提供版权说明?#8216;开?#8217;Q原来都是伪<br>开源。虽然我也想按照<a target=_blank>GNU~码标准</a>里所说ؓ(f)kl的发布包里附加Changelog之类的说明,但是<br>Z懒惰Q还是以后再说吧。同Pq次提供的下载里包含了一些编译好的东西,所以我?br>保证它在你的机器上依然可以运行。我使用了MingW来编译这些,q且提供有点丑陋的Makefile?br>HGE使用?.81版本?br>    贴张囄懒得下蝲的hQ?</font></p> <p><a href="http://www.shnenglu.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/klsample_12B5E/snake_screenshot.jpg"><img style="BORDER-RIGHT-WIDTH: 0px; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" border=0 alt=snake_screenshot src="http://www.shnenglu.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/klsample_12B5E/snake_screenshot_thumb.jpg" width=670 height=433></a> </p> <p><font size=2>    <a href="http://www.shnenglu.com/Files/kevinlynx/snake_sample.zip" target=_blank>下蝲例子</a>Q包含脚本代码?</font> <p><font size=2>    如果要获取kl实现代码Q徏议从我在google的SVN获取Q?br></font><a ><font size=2>http://code.google.com/p/klcommon/</font></a></p> <img src ="http://www.shnenglu.com/kevinlynx/aggbug/77872.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2009-03-25 21:17 <a href="http://www.shnenglu.com/kevinlynx/archive/2009/03/25/77872.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实现一U解释性脚本语aQ七Q?/title><link>http://www.shnenglu.com/kevinlynx/archive/2009/03/12/76302.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Thu, 12 Mar 2009 01:35:00 GMT</pubDate><guid>http://www.shnenglu.com/kevinlynx/archive/2009/03/12/76302.html</guid><wfw:comment>http://www.shnenglu.com/kevinlynx/comments/76302.html</wfw:comment><comments>http://www.shnenglu.com/kevinlynx/archive/2009/03/12/76302.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.shnenglu.com/kevinlynx/comments/commentRss/76302.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/kevinlynx/services/trackbacks/76302.html</trackback:ping><description><![CDATA[<p><font size=2>author: Kevin Lynx email: zmhn320#163.com date: 3.12.2009 </font> <p><font size=2><strong>脚本与C语言交互</strong> </font> <p><font size=2>    q其实是q一pd的最后一,因ؓ(f)我觉得没什么其他需要写的了?br>    一般而言Q脚本语a同C语言交互Q包括在C语言中注册C函数到脚本,从而扩展脚本的<br>功能Q以及在C语言中调用脚本函数?br>    Z扩展脚本的功能,q里引入插g的概ckl在这斚w大致上实现得和lua怼。kl<br>支持静态插件和动态插件?br>    在C语言中调用脚本函敎ͼkl中提供了一些简单的接口用于满需求?</font> <p><font size=2><strong>静态插?/strong> </font> <p><font size=2>    静态插件其意思是在C代码中注册函数到脚本中,q脚本库一L(fng)译链接成最l执?br>E序。因为其l定是在开发一个程序的q程中,所以被UCؓ(f)静态的?br>    一个插件函敎ͼ指的是可以被注册q脚本的C函数。这U函数必d型一P在kl中这<br>个函数的原型为:typedef struct TValue (*kl_func)( ArgType arg_list );    <br>    当你定义了一个这L(fng)原型的函数时Q可以通过kl库提供的:<br>    int kl_register( struct klState *kl, kl_func f, const char *name )来注册该<br>函数到kl脚本中。该函数参数很简单,W三个参数指定注册进脚本中时的名字?</font> <p><font size=2>    原理比较单:在解释器中保存着一个插件符可Q该W号表的W号名就是这个函数提<br>供的名字Q符号对应的值就是第二个参数Q也是插g函数的函数地址?br>    解释器解释到函数调用Ӟ先从插gW号表中查找Q如果找到符P将W号的D{?br>为插件函敎ͼq调用之?</font> <p><font size=2>    插g函数的参数其实是一个参数链表。脚本里调用插g函数Ӟ所传递的参数被解释<br>器整理成参数链表q传递给插g函数。kl库中(集中在kllib.h?提供了一些方便的接口?br>于获取每个参数?br>    插g函数的返回g被解释器{换ؓ(f)脚本内部识别的格式,q在必要的时候参与运?br>?</font> <p><font size=2><strong>动态插?/strong> </font> <p><font size=2>    动态插件同静态插件的q作方式相同Q所不同的是动态插件的插g函数被放在动态运?br>时库里,例如windows下的dll?br>    kl插g~写标准里要求每个动态插件必L供一个lib_open函数。kl解释器(或者kl?br>--当被用作库时Q蝲入一个动态插件时Q会直接调用lib_open函数。lib_open函数的主要目<br>的就是把该插件中的所有函数都注册q脚本里?</font> <p><font size=2>    因ؓ(f)动态插件在设计之初没有被考虑Q所以我q没有ؓ(f)kl加入一些原生的关键字用于导<br>入动态插Ӟ例如import、require之类。我在静态插件层ơ提供了q个功能。即我提供了<br>一个libloader静态插Ӟ链接qkl解释器程序。该静态插件提供脚本一个名为import的函<br>数。该函数负责动态蝲入dll之类的动态库Qƈ调用里面的lib_open函数完成动态插件的?br>册?</font> <p><font size=2><strong>CE序里调用脚本函?/strong> </font> <p><font size=2>    q个比较单,通常C语言惌用一个脚本函数时Q会传入脚本函数名。因本函数名<br>都保存在全局W号表里Qkl库从全局W号表找到该函数W号Qƈ转换其gؓ(f)语法?wi)节?gu)?br>Q然后传入解释器模块解释执行?br>    kl库提供struct TValue kl_call( struct klState *kl, const char *name, ArgType args );<br>用于在C里调用脚本函数?</font> <p><font size=2><strong>代码D</strong> </font> <p><font size=2>    kllib.h/kllib.c作ؓ(f)一个桥接层Q用于封装其他模块可以提供给外部模块使用的接口,<br>如果kl作ؓ(f)一个库使用Q用户代码大部分时候只需要用kllib.h中提供出来的接口?br>    源码目录plugin下的kllibbase.c中提供了静态插件的例子Qkllibloader.c提供了装?br>动态插件的功能?br>    源码目录plugin/hge目录下是一个封?D游戏引擎HGE部分接口到kl脚本中的动态插?br>例子?br>    源码目录test/kl.c是一个简单的kl解释E序Q它用于执行一Dkl代码。这个程序同之前<br>说的解释器不是同一回事。当我说到解释器Ӟ它通常指的是klinterpret.c中实现的解释<br>模块Q而解释器E序则指的是一个用了kl库的独立解释器可执行E序?/font> <p><font size=2></font></p> <img src ="http://www.shnenglu.com/kevinlynx/aggbug/76302.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2009-03-12 09:35 <a href="http://www.shnenglu.com/kevinlynx/archive/2009/03/12/76302.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实现一U解释性脚本语aQ六Q?/title><link>http://www.shnenglu.com/kevinlynx/archive/2009/03/11/76176.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Wed, 11 Mar 2009 01:12:00 GMT</pubDate><guid>http://www.shnenglu.com/kevinlynx/archive/2009/03/11/76176.html</guid><wfw:comment>http://www.shnenglu.com/kevinlynx/comments/76176.html</wfw:comment><comments>http://www.shnenglu.com/kevinlynx/archive/2009/03/11/76176.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/kevinlynx/comments/commentRss/76176.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/kevinlynx/services/trackbacks/76176.html</trackback:ping><description><![CDATA[<p><font size=2>author: Kevin Lynx email: zmhn320#163.com date: 3.11.2009 </font> <p><font size=2><strong>解释?/strong> </font> <p><font size=2>    整理法树(wi)后,我们可以根据语法树(wi)Qƈ配合W号表开始解释执行脚本代码。这?br>是接下来要涉及到的解释器?</font> <p><font size=2><strong>工作原理</strong> </font> <p><font size=2>    在第四节中讲语法?wi)时Q其实就已经提到解释器的大致工作原理?br>    一个kl的hello world例子代码大致为:<br>    function main()<br>    {<br>        print( "hello world\n" );<br>    }<br>    在第二节中我描述了kl代码整体上的l构Q是以函Cؓ(f)单位的。因此,对于一个完整的<br>kl脚本代码Q其l过语法处理后,徏立一大的语法树(wi)Q该语法?wi)大致结构?f)Q?br>    fn1_node<br>        stmt_node1<br>        stmt_node2<br>        ...<br>    fn2_node<br>        stmt_node1<br>        stmt_node2<br>        ... </font> <p><font size=2>    fn1_node和fn2_node同属于同一个作用域Qfn1_node的sibling指针指向fn2_nodeQ即?br>整个?wi)结构中Q每一个node通过child[3]成员q接其子节点Q通过sibling指针q接其相?br>的节炏V?nbsp;   <br>    解释器解释执行时Q就是从main函数所对应的节点开始递归执行的。对于每个节点,?br>可以知道该节点对应了哪种E序逻辑Q是加法q算、比较运、还是一些控制语句等{?br>    以这L(fng)控制语句举例Q?br>    if( 1 ) print( "true" );<br>    对if语句而言Q其语法?wi)结构?f)Q?br>          if_node<br>         /   |    \<br>        /    |     \ <br>    con_exp    then_stmt else_stmt </font> <p><font size=2>    卻Iif语句有最多有三个子节?child[3])Qchild[0]指向if的条件表辑ּQchild[1]<br>指向条g表达式ؓ(f)真时执行的语句序列,如果if有else部分Q那么child[2]指向else部分<br>的语句序列?br>    那么Q在发现某个节点是if节点Ӟ首先计其条g表达式节炏V这个节点的计算?br>式同脚本中其他所有表辑ּ的计方式相同,当然Q它也是一个递归操作。计完后判断该<br>表达式的值是否ؓ(f)真,为真则递归执行if节点的child[1]节点Q否则检查是否有else节点Q?br>有的话就执行child[2]节点?</font> <p><font size=2>    其他所有节点的解释方式都是相同的?/font></p> <p><font size=2><br><strong>解释器环?/strong> </font></p> <p><font size=2>    解释器环境指的是解释器在解释执行脚本代码Ӟ所需要的q行时环境。kl中主要是W?br>可信息。一个解释器环境会有三个W号表:全局W号表,主要保存全局变量以及脚本函数<br>W号Q函数局部符可Q在解释调用一个脚本函数时Q会建立临时的符可Q插件符可Q?br>用于保存插g注册的函数?</font> <p><font size=2><strong>如何解释执行函数</strong> </font> <p><font size=2>    函数主要有两大类型:脚本内定义的函数以及插g注册q符可的函数。无论是哪种?br>敎ͼ都会在符可中徏立对应的W号。对于前者,W号被保存于全局W号表,其保存的内容<br>是该函数节点的节Ҏ(gu)针;而对于后者,则保存的插g函数的函数地址倹{?</font> <p><font size=2>    每一ơ解释器解释C个函数调用节Ҏ(gu)Q会优先在插件符可中查找该函数W号。如<br>果找刎ͼ将其D{换ؓ(f)U定的插件函数类型(如同lua里注册的C函数一PQ然后整理参<br>数调用之。这个时候代码执行权转接到插件函数里。如果没扑ֈQ就在全局W号表里查找Q?br>扑ֈ后就{法树(wi)节点指针Qƈ解释执行该节点下的语句?</font> <p><font size=2><strong>代码D</strong> </font> <p><font size=2>    解释器的代码位于klinterpret.h/klinterpret.c中。整体上而言没什么特别的地方Q?br>主要是利用语法树(wi)的特炏V?br>    完成了这一节后Qkl已l可以解释执行所有的脚本语句。当Ӟ因ؓ(f)没有输出功能Q?br>只能在调试器里看看计结果。下一节里会讲到将脚本l合qC语言Q从而可以让C语言注册<br>所谓的插g函数到脚本里Q也可以让脚本hprintq样的输出函数?</font> <p><font size=2></font></p> <img src ="http://www.shnenglu.com/kevinlynx/aggbug/76176.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2009-03-11 09:12 <a href="http://www.shnenglu.com/kevinlynx/archive/2009/03/11/76176.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实现一U解释性脚本语aQ五Q?/title><link>http://www.shnenglu.com/kevinlynx/archive/2009/03/10/76078.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Tue, 10 Mar 2009 00:58:00 GMT</pubDate><guid>http://www.shnenglu.com/kevinlynx/archive/2009/03/10/76078.html</guid><wfw:comment>http://www.shnenglu.com/kevinlynx/comments/76078.html</wfw:comment><comments>http://www.shnenglu.com/kevinlynx/archive/2009/03/10/76078.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/kevinlynx/comments/commentRss/76078.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/kevinlynx/services/trackbacks/76078.html</trackback:ping><description><![CDATA[<p><font size=2>author: Kevin Lynx email: zmhn320#163.com date: 3.10.2009 </font> <p><font size=2><strong>W号?/strong> </font> <p><font size=2>    在上一节中Q当我们的解释器解释执行age=age+1q个语法?wi)时Q会涉及到变量age的?br>。实际上我们q需要个保存脚本中相兛_量的模块Q当我们的解释器获取C个ID?wi)节?gu)<br>Q需要从q个模块中获取出该变量的|q参与运?br>    q个我称之ؓ(f)W号表。我惛_q里Q我所说的概念很可能和教科书有点不一样了?</font> <p><font size=2><strong>什么是W号表?</strong> </font> <p><font size=2>    W号?symbol table)如同其字面意思一P是一个表Q更宽泛地说是一个保存符?br>的容器?br>    脚本中诸如变量函Ccȝ东西都算作符P例如age。符可是保存q些W号的容<br>器?br>    在kl中,W号表保存着某一个作用域里的变量。其全局W号表还保存着函数W号Q对?br>函数W号而言Q其gؓ(f)语法?wi)?wi)节点的指针倹{当调用一个函数时Q将该D{换ؓ(f)?wi)节点?br>然后执行。当Ӟq应该算做解释执行一节的l节Q不多说?</font> <p><font size=2>    再明下W号表的作用QD例,在上一节中Q涉及到q么一个例子函敎ͼ<br>    value factor( TreeNode *node )<br>    {<br>        switch( node->type )<br>        {<br>            case ID:<br>                /* 在这里,发现一个树(wi)节点cd为IDQ就需要根据ID对应的名字,也就<br>                 是ageQ在W号表中查找age的?*/<br>                return ageQ?nbsp;   <br>        /* ... */<br>        }<br>    }<br>    以上注释阐述了符可的作用?</font> <p><font size=2><strong>W号表的实现</strong> </font> <p><font size=2>    其实不管W号表如何实玎ͼ对于其他模块而言Q对W号表的唯一要求是提供几个cM<br>q样的接口:<br>    value sym_lookup( const char *name );<br>    void sym_insert( const char *name, value val ); <br>    也就是说Q提供查扄号|以及插入新符L(fng)接口?</font> <p><font size=2>    在kl中,使用?lt;~译原理与实?gt;中相同的W号表数据结构实现。即使用了hash表,<br>hash数组中每个元素保存的是一个链表头节点。每一个符号字W串通过散列函数得到hash?br>l烦引,然后在该索引里进行一ơ线性查找。很典型的hashl构?</font> <p><font size=2>    另一斚wQ因为kl支持全局和函数局部两个作用域。所以kl中有一个全局W号表,用于<br>保存全局变量以及所有的函数W号Q同时每一ơ进入一个函数时Q就会创Z个(f)时的局?br>W号表,用于存储局部变量;后来Qؓ(f)了支持插Ӟ插g函数被特定地保存在另一个全局W?br>可里?</font> <p><font size=2><strong>代码D</strong> </font> <p><font size=2>    kl中的W号表实C码在klsymtab.h/klsymtab.c中,实现比较单,无需多言?</font></p> <img src ="http://www.shnenglu.com/kevinlynx/aggbug/76078.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2009-03-10 08:58 <a href="http://www.shnenglu.com/kevinlynx/archive/2009/03/10/76078.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实现一U解释性脚本语aQ四Q?/title><link>http://www.shnenglu.com/kevinlynx/archive/2009/03/09/75962.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Mon, 09 Mar 2009 03:12:00 GMT</pubDate><guid>http://www.shnenglu.com/kevinlynx/archive/2009/03/09/75962.html</guid><wfw:comment>http://www.shnenglu.com/kevinlynx/comments/75962.html</wfw:comment><comments>http://www.shnenglu.com/kevinlynx/archive/2009/03/09/75962.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.shnenglu.com/kevinlynx/comments/commentRss/75962.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/kevinlynx/services/trackbacks/75962.html</trackback:ping><description><![CDATA[<p><font size=2>author: Kevin Lynx email: zmhn320#163.com date: 3.9.2009 </font> <p><font size=2><strong>语法分析</strong> </font> <p><font size=2>    语法分析接收词法分析阶段的token集合入,这些没有关pȝtokens整理为相?br>之间有关pȝl构。书面点的说法叫语法?wi)?br>    每一ơ让我写q些文绉l的概念真让我受不了:D?</font> <p><font size=2><strong>语法?/strong> </font> <p><font size=2>    语法?wi)简单来说就是一个以token作ؓ(f)每个节点的树(wi)型结构。例如我们有表达式age =<br>age + 1;Q在词法阶段它被整理为token集合Qage, =, age, +, 1。那么在l过语法分析?br>Q这些tokens被整理为大致如下的?wi)Şl构Q?br>        =<br>      /   \<br>    age    +<br>         /   \<br>       age     1 </font> <p><font size=2>    整理成这L(fng)l构有什么好处?kl解释器而言Q最直接的好处就是我可以递归地解?br>q棵?wi)执行。例如: </font> <p><font size=2>    value compute( TreeNode *root )<br>    {<br>        /* child[0]保存l果值ageQchild[1]是那?表达?*/<br>        return op_exp( root->child[1] ); <br>    } </font> <p><font size=2>    value op_exp( TreeNode *node )<br>    {<br>        switch( node->op )<br>        {<br>            case '+':<br>            {<br>                /* + 表达式必然有左右操作?*/<br>                value left = factor( node->child[0] );<br>                value right = factor( node->child[1] );<br>                return left + right;<br>            }<br>        }<br>    }<br>    value factor( TreeNode *node )<br>    {<br>        switch( node->type )<br>        {<br>            case ID:<br>                /* 查找age的?*/<br>                return age; </font> <p><font size=2>            case CONST:<br>                /* 1 是常?*/<br>                return node->cvalue;<br>        }<br>    } </font> <p><font size=2>    如你所见,当我们完成了语法分析阶段Q我们就可以完成我们的解释器了。后面我会单<br>独讲解下整个解释q程Q包括每个模块是如何协作的。我不知道其他解释器是怎么做的Q但<br>是我q样做,L(fng)l果是对的?</font> <p><font size=2><strong>如何整理法树(wi)Q?/strong> </font> <p><font size=2>    q里不得不提到所谓的BNF文法Q很明显你还是无法从我这里获取编译原理里某个概念<br>的讲解。我q里提这个概念完全是方便我提到这个东ѝ?br>    每一U语a都有其自qBNF文法Q因Z恶的先知告诉我们Q每一门语a都需要徏?br>其语法树(wi)? -!<br>    像词法分析一P因ؓ(f)大部分语a的结构都差不多,所以我觉得词法分析和语法分?br>基本上都没有M特别之处。也是_别的语言的BNF你可以直接拿来改改用?br>    抄个BNF如下Q?br>    exp -> exp adop term | term<br>    addop -> + | -<br>    term -> term mulop factor | factor<br>    mulop -> *<br>    factor -> (exp) | number<br>    q个BNF用来描述一般的数表达?+-*/)。简单来_一门语a的BNF是用于描述?br>语言所有语句的东西Q包括if、while、函数定义之cR徏议你google一下C语言的BNFQƈ<br>攚w之用于你自q语言?</font> <p><font size=2>    那么有了BNF之后Q该如何整理法树(wi)呢?<br>    通常Q我们的代码里都会直接有对应exp、term、addop之类的函数。按照我q句话的?br>思,上面抄的BNF被翻译ؓ(f)E序代码后,可能ؓ(f)Q?br>    exp()<br>    {<br>        if( ... ) left = exp()<br>        right = term();<br>        left addop right;<br>    }<br>    term()<br>    {<br>        if( ... ) left = term()<br>        right = factor();<br>        left mulop right;<br>    }<br>    factor()<br>    {<br>        if( ... ) return exp();<br>        else return number;<br>    } </font> <p><font size=2>    (可能q会涉及到EBNFQ用于处理重复和选择的一些情?--不用这句话) </font> <p><font size=2>    每一个函数基本上都会q回一个树(wi)节点Q当Ӟ该节点下可能会有很多子节炏V?nbsp;   </font> <p><font size=2><strong>ȝ</strong> </font> <p><font size=2>    语法分析基本上就是以上信息。它?yu)词法分析输出的token集合整理成一颗语法树(wi)。ؓ(f)<br>了整理出q棵语法?wi),你需要找一份用于描qC语言的BNFQ然后根据BNF译成处理代码?</font> <p><font size=2><strong>代码D</strong> </font> <p><font size=2>    kl中的整个语法分析代码位于klparser.c/klparser.h中,其BNF基本上取?lt;~译原理?br>实践>附录中的C_语言?/font> <p><font size=2></font></p> <img src ="http://www.shnenglu.com/kevinlynx/aggbug/75962.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2009-03-09 11:12 <a href="http://www.shnenglu.com/kevinlynx/archive/2009/03/09/75962.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实现一U解释性脚本语aQ三Q?/title><link>http://www.shnenglu.com/kevinlynx/archive/2009/03/07/75816.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Sat, 07 Mar 2009 05:43:00 GMT</pubDate><guid>http://www.shnenglu.com/kevinlynx/archive/2009/03/07/75816.html</guid><wfw:comment>http://www.shnenglu.com/kevinlynx/comments/75816.html</wfw:comment><comments>http://www.shnenglu.com/kevinlynx/archive/2009/03/07/75816.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.shnenglu.com/kevinlynx/comments/commentRss/75816.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/kevinlynx/services/trackbacks/75816.html</trackback:ping><description><![CDATA[<p><font size=2>author: Kevin Lynx email: zmhn320#163.com date: 3.7.2009</font> <p><font size=2><strong>词法分析</strong> </font> <p><font size=2>    词法分析属于整个~译程中的W一个阶Dcؓ(f)什么要把编译过E分为多个阶D,q就<br>如同软g分层一P个h觉得是出于降低复杂性的考虑?br>    再次声明我不会告诉你M~译原理的理论知识,因ؓ(f)坦率地说我也不会:D。所以我?br>力将我们需要了解的概念可能简单地告诉你。当Ӟ可能会与教科书不d?</font> <p><font size=2><strong>什么是词法分析?</strong> </font> <p><font size=2>    词法分析是把一D话整理成单词集合。D个简单的例子Q例如有代码:age = age + 1;Q?br>l过词法分析后,得刎ͼage?、age???几个W号。ؓ(f)了方便,我称每个单词Z<br>个token?</font> <p><font size=2><strong>词法分析的作?/strong> </font> <p><font size=2>    词法分析分析出来的单词集合,直接作ؓ(f)~译程中接下来的语法分析的输入。那么语<br>法分析阶D面对的是一个一个的tokenQ而不是单个的字符?br>    例如Q在处理age = age + 1;q种语句Ӟ当我们获取到token "="Ӟ我们直接期望?br>下来的token应该是个表达式。以单词为单位地处理Q比直接处理单个字符单很多?</font> <p><font size=2><strong>词法分析的过E?/strong> </font> <p><font size=2>    词法分析的输入是单个字符,一般我们fopen一个源代码文gQ保存在一个char~存<br>里,q就是词法分析的输入。而词法分析的最l输出结果就是一个一个的token?br>    Z处理方便Qtokenq不是单U的单词。通常我们会将源代码中的所有单词分c,?br>如变量名其实都属于一ctoken。简单的token可定义ؓ(f)Q?br>    struct Token<br>    {<br>        int type;<br>        char value[256];<br>    };<br>    type用于表示token的类型,例如一个变量名token的类型是一个标识符。value可以?br>来具体地保存q个变量的名字?</font> <p><font size=2>    对于type的处理,通常会事先定义一l枚丑ր|例如Q?br>    enum    {    ID, NUM, STRING, IF, ELSE, WHILE, RETURN, FUNCTION }{等用于标示<br>在一个源代码中可能出现的所有token?</font> <p><font size=2>    虽然说词法分析的l果是一个token集合Q但事实上我们ƈ不是一ơ做完词法分析。通常<br>词法分析模块提供一个get_token函数。每ơ调用该函数Ӟ都返回源代码中下一个token?br>例如Q有源代码:age = age + 1;<br>    W一ơ调用get_token获?{ ID, "age" }Q第二次获得 { ASSIGN, "=" }Q第三次<br>获得{ ID, "age" }Q等{?</font> <p><font size=2>    那么Q词法分析该如何实现Q也是struct Token get_token()函数如何实现Q其实很<br>单,你告诉我Q给你一个字W串Q你如何判断q个字符串全部是数字Q?br>    int is_num( const char *str )<br>    {<br>        while( *str != 0 ) <br>        {<br>            if( !isdigit( *str++ ) ) return 0;<br>        }<br>        return 1;<br>    }<br>    所以,基本上,词法分析的过E也是q个q程。就拿标识符举例Q典型的标识W一?br>以字W开_然后接着是数字或字符或_Q当遇到非法字符Ӟq个标识W的扫描即结束?br>    词法分析一般是个while+switchQ?br>    struct Token get_token()<br>    {<br>        while( current_char != 0 )<br>        {<br>            switch( current_char )<br>            {<br>                case CHARACTER:<br>                    /* 扫描一个标识符 token */<br>                    break; </font> <p><font size=2>                case '=':<br>                    /* 获得一?ASSIGN token */<br>                    break; </font> <p><font size=2>                    ...<br>            }<br>        }<br>    } </font> <p><font size=2>    现在Q试着Lȝ一门语a里的每一个token的规则,然后自己d写看?</font> <p><font size=2><strong>代码D</strong> </font> <p><font size=2>    在本节我提供kl在googlecode的SVN上的代码Q先不要ȝ代码包中的其他东ѝ关?br>词法的代码可以在kllex.c kllex.h中找到。lex_token是提供给其他模块的接口,用于获取<br>当前扫描的token。扫描结果可以通过lexStatel构体获取?br>    再次提下版权问题Q代码文件以及代码包中我q没有加入Q何版权说明,哪怕是GPL?br>但是如同我之前说的一P我不介意你传播、改动此代码Q但是请保留原作者信息。当Ӟ<br>我ƈ不介意你加上@modified by xxx:)?</font> <p><font size=2>    下蝲kl源代码:</font><a ><font size=2>http://klcommon.googlecode.com/files/kllan_0.1.0.zip</font></a></p> <img src ="http://www.shnenglu.com/kevinlynx/aggbug/75816.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2009-03-07 13:43 <a href="http://www.shnenglu.com/kevinlynx/archive/2009/03/07/75816.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实现一U解释性脚本语aQ二Q?/title><link>http://www.shnenglu.com/kevinlynx/archive/2009/03/06/75751.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Fri, 06 Mar 2009 08:01:00 GMT</pubDate><guid>http://www.shnenglu.com/kevinlynx/archive/2009/03/06/75751.html</guid><wfw:comment>http://www.shnenglu.com/kevinlynx/comments/75751.html</wfw:comment><comments>http://www.shnenglu.com/kevinlynx/archive/2009/03/06/75751.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.shnenglu.com/kevinlynx/comments/commentRss/75751.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/kevinlynx/services/trackbacks/75751.html</trackback:ping><description><![CDATA[<p><font size=2>author: Kevin Lynx email: zmhn320#163.com date: 3.6.2009 </font> <p><font size=2><strong>语言Ҏ(gu)?/strong> </font> <p><font size=2>    在正式讨论实现细节前明确下这个脚本语a的一些语aҎ(gu),基本上可以让我们预见?br>来会遇到哪些N。ȝ来说Q它Q脚本)同我们qx接触的如lua一L(fng)脚本语言Q拥<br>有一般的~程语言Ҏ(gu),如变量、各U控制流E、也许还有函敎ͼ另一斚w它还应该和它?br>宿主语言l合Q如作ؓ(f)一个库被用qCQ这q涉及到l这门语a设计一U插件方式,最好能<br>通过独立的解释程序让脚本载入一些插件运行?</font> <p><font size=2>    以下在描q我写的q个脚本语言Ӟ以kl表示它的名字Q以方便描述?</font> <p><font size=2><strong>代码块:</strong> </font> <p><font size=2>    首先从整体风gQkl如同C语言一栯划分为函数块Q如Q?br>    function func1()<br>    {<br>    }<br>    function func2()<br>    {<br>    }<br>    ...<br>    kl支持以{}隔离代码块,但是qƈ不意味着kl有多个独立的局部堆栈,如同C语言一栗?br>q些l节暂不讨论。本节描q的所有内容你都不必深IӞ因ؓ(f)我只要求你对kl有个感性上?br>认识?br>    函数块之外没有可执行的语?statement)。那么你可能会想到程序的入口点也怼?br>main。事实上从kl提供的库来看Qƈ没有q种性要求。但是,kl的独立解释程序是q样?br>求的?nbsp;   </font> <p><font size=2><strong>变量Q?/strong> </font> <p><font size=2>    kl允许你在M地方使用一个变量。变量不需要事先定义,M地方出现一个合<br>法的标识W时Q就意味着kl内部会增加这个变量,q给予初倹{变量也没有静态类型,也不<br>会固定ؓ(f)某一cd。就一门最单的语言来看Q我觉得数据cd无非是字符串和数字cd<br>?br>    所以,kl的变量在某一时刻必然是数字,或者字W串。在脚本里,你无法获知一个变?br>的类型,事实上也没这个必要。说变量拥有一个类型属性,倒不如说?value)有一U类?br>属性?br>    当字W串g数字值参与运时Q如1+"a"Q其q算l果自动{换ؓ(f)字符Ԍ也就?br>"1a"?br>    一个只有标识符的语?statement)通常意味着你想定义一个变量。这U无聊的手段?br>常被用于定义全局变量?</font> <p><font size=2><strong>q算W:</strong> </font> <p><font size=2>    kl支持一般的C语言风格的算术、比较、逻辑q算W。例如加减乘除、大于小于、逻辑<br>与逻辑或?</font> <p><font size=2><strong>作用域:</strong> </font> <p><font size=2>    kl脚本里只有两个作用域Q全局的和局部的?br>    位于所有函数块外的变量处于全局作用域;位于函数内的变量处于局部作用域Q位于函<br>数块内的代码块变量,q是处于局部作用域?br>    当局部作用域内出C个全局里的同名变量Ӟ优先取局部作用域里的变量。这同C?br>a一栗?</font> <p><font size=2><strong>控制语句ifQ?br></strong>    if的语法同C语言一P如:<br>    if( a > 10 )<br>    {<br>    }<br>    else<br>    {<br>    }<br>    if( a > 10 )中的a>10被我成ؓ(f)条g语句Q所有条件语句,包括下面的whileQ都不能<br>为字W串。例如if( "a" )被视ؓ(f)非法语句。(我ؓ(f)什么要q样考虑Q? -!Q?</font> <p><font size=2><strong>控制语句while:</strong> </font> <p><font size=2>    c-like while:<br>    while( a > 10 )<br>    {<br>    }<br>    很遗憾,我暂时没有加入对for的支持。因为我觉得既然有了whileQ有了@环控Ӟ?br>没有更多无聊旉的前提下Q我没有必要加入for?</font> <p><font size=2><strong>函数Q?/strong> </font> <p><font size=2>    很遗憾,函数的定义和调用和C语言有点不一栗这是因为kl没有变量cdQ那意?br>着函数定义如果和C语言一P׃出现语法歧义Q如Q?br>    func( a )<br>    {<br>    }<br>    ׃和函数调用func(a)出现h。所以,我加入了function关键字。定义函数的语法<br>为:<br>    function func( a, b )<br>    {<br>    }<br>    如你所见,函数支持参数传递,当然也支持return a;q回倹{kl是简陋的Q因为它?br>有指针之cȝ概念Q所以你无法为函C递一块数据。当Ӟkl也不能像lua一栯函数?br>以返回多个倹{?br>    函数调用的语法相对熟(zhn):<br>    func( 1, 3 ); </font> <p><font size=2><strong>数组Q?/strong> </font> <p><font size=2>    从一开始我没考虑为kl加入数组。事实证明加入数l是一个不明智的做法。数l的?br>持让代码在很多地方变得脏乱。无论如何,kl后来支持一l数l了。ؓ(f)了让代码保持那么一<br>点点的干净Q我甚至为定义数l加入dim的关键字。这意味着Q在kl里,数组和一般的变量<br>L点不一P变量无需定义Q数l却必须事先定义?br>    数组的长度不支持动态扩充。如果支持,我得让kl内部更好地去理内存?br>    数组元素的类型没有硬性的规定Q这意味着a[0] = 1; a[1] = "a";是允许的?</font> <p><font size=2>    语言Ҏ(gu)上描q这些,在本节末我军_贴一Dkl计算阶乘的代码: </font> <p><font size=2>/* fac.kl */<br>function main()<br>{<br>    n = input( "%d" );<br>    print( "fac(" + n + ") = " + fac( n ) );<br>} </font> <p><font size=2>function fac( n )<br>{<br>    if( n == 1 )<br>    {<br>        return 1;<br>    }<br>    else<br>    {<br>        return fac( n - 1 ) * n;<br>    }<br>} </font></p> <img src ="http://www.shnenglu.com/kevinlynx/aggbug/75751.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2009-03-06 16:01 <a href="http://www.shnenglu.com/kevinlynx/archive/2009/03/06/75751.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实现一U解释性脚本语aQ一Q?/title><link>http://www.shnenglu.com/kevinlynx/archive/2009/03/06/75749.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Fri, 06 Mar 2009 07:58:00 GMT</pubDate><guid>http://www.shnenglu.com/kevinlynx/archive/2009/03/06/75749.html</guid><wfw:comment>http://www.shnenglu.com/kevinlynx/comments/75749.html</wfw:comment><comments>http://www.shnenglu.com/kevinlynx/archive/2009/03/06/75749.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.shnenglu.com/kevinlynx/comments/commentRss/75749.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/kevinlynx/services/trackbacks/75749.html</trackback:ping><description><![CDATA[<p><font size=2>author: Kevin Lynx email: zmhn320#163.com date: 3.6.2009 </font> <p><font size=2>    Q相信我Q这一节全是废话。)<br>    我不是标题党Q但是有必要解释下这个标题。综合来说我是想与你分享我所学到的?br>我会我实现的这个简单的脚本语言的实现细节展C给你。它?yu)涵盖:词法分析、语法分?br>、符可理、语法树(wi)解释执行、插件管理等内容?br>    我ƈ不擅长传授编译原理知识。我没有听过~译原理课,所以我也不会编译原理(也许<br>即我听了也不会:DQ。所以对于这斚w的能手而言Q我口中?#8216;DFA‘可能会贻W大斏V?br>    昄QCPPBLOG上有~译原理上的大牛。如果你惛_?fn)更深入的知识,可以去请教他们?br>vczh(http://www.shnenglu.com/vczh/) 看v来是我所说的q个人。在致谢名单里我真诚地<br>写上他的名字。他?#8217;手把手xxx脚本‘pd多多少q是l了我一些有用的信息?br>    其次是FOXQ在词法分析的DFA和NFA那里我请教了他一些问题。虽然我现在又忘了。如<br>你们所知,理论和实C间M隔着鸿沟?</font> <p><font size=2>    推荐《编译原理与实践?<Compiler Construction:Principles and Practice><br>Kenneth C. Louden)q本书。在你将来阅L的脚本语a的实C码时Q你会发现有很一些地<br>方同q本书里的TINY语言实现代码有相g处。徏议你阅读TINY的代码?br>    感谢VIM、GCC、GDB、MingWQ我用这些Y件在工作之余写出了这个东西的几千行C代码?br>很明显我是个开源文化的爱好者。但是我不会告诉你unix有多么多么好Q因为我也是个初?br>者,我还不懂unix。开源在我看来更是一U分享知识的_。让q种_如同GPL一L(fng)?br>式地传染下去?br>    q有版权问题。但也许它不是个问题。我不会dM版权信息。我允许你Q意传播?br>改动我所散播的东西,但是唯一的基本条件是Q保留作者的信息---不要告诉别hQ这东西<br>是你做的?</font> <p><font size=2>    在所有的文章发布后,我都可能会再ơ修攏V也?dng)R过RSS或者日志日期之cM可以?br>得修Ҏ(gu)醒?</font> <p><font size=2></font></p> <img src ="http://www.shnenglu.com/kevinlynx/aggbug/75749.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2009-03-06 15:58 <a href="http://www.shnenglu.com/kevinlynx/archive/2009/03/06/75749.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>写了个XML解析?/title><link>http://www.shnenglu.com/kevinlynx/archive/2008/12/10/69079.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Wed, 10 Dec 2008 08:22:00 GMT</pubDate><guid>http://www.shnenglu.com/kevinlynx/archive/2008/12/10/69079.html</guid><wfw:comment>http://www.shnenglu.com/kevinlynx/comments/69079.html</wfw:comment><comments>http://www.shnenglu.com/kevinlynx/archive/2008/12/10/69079.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://www.shnenglu.com/kevinlynx/comments/commentRss/69079.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/kevinlynx/services/trackbacks/69079.html</trackback:ping><description><![CDATA[<p><font size=2>    开始用FLEX做词法分析,然后在此基础上稍微做些符号匹配(实在UC上语法分析)Q即完成了XML<br>文g的简单解析?br>    我把XML文g拆分成:<, >, />, </, =, ID, STRING {token。这样一整理Q用FLEX直接生成词法<br>分析E序。每一ơgetTokenp回这些token。上层的语法匚w变得比较简单。例如当得到"/>"token<br>Ӟ我就可以判断q是一个节点的l束Q当得到ID tokenӞ可以推下一个token?="Q再下一?br>是个STRING。不q对于部分tokenQ也需要做一两个token的回溯,例如当遇?<"Ӟq不一定表CZ?br>新节点的开始,它可能是新节点的开始,同样也可能是上一个节点的l束("</")?br>    以我薄弱的编译原理知识来看,解析XML变得非常Ҏ(gu)。除此之外,q需要写一些上层代码来保存<br>XMLl构Q以斚w更上层代码获取XML文g的配|信息。因为我打算用纯C来写q个东西Q所以数据结构方<br>面只有自己处理。这里我以一U变相的?wi)结构来保存Q每一个节Ҏ(gu)两个域:first child, sibling?br>其实q样做是一个很明显的通用做法Q因为XMLU每一个节炚w可能拥有不定数量的children节点Q如?br>让parent直接M存,昄很笨。例如:<br>    <Resource><br>        <bmp file="1.bmp"/><br>        <bmp file="2.bmp"/><br>    </Resource><br>    可以使用q样的数据结构来存储Q?br>    struct xmlNode<br>    {<br>        ...<br>        struct xmlNode *child;<br>        struct xmlNode *sibling;<br>    };<br>    对于Resourceq个node而言Q其child域指向第一个bmp节点(file属性ؓ(f)1.bmp那个节点)Q对于第一<br>个bmp节点而言Q其sibling域则指向了第二个bmp节点?br>    q个单的xml解析器是在公司外|机器上写的Q没有VCQ没有Q何IDE。代码我是用VIM敲的Q敲?br>后写makefileQ用mingw里的gcc、make来生成程序,用gdb来调试程序。这是W一ơ离开VC写的一个非<br>l习(fn)E序(L(fng)用makefile来组l工E?? -| makefile写的比较烂,gdb用得很不熟,不过好歹调试出来<br>了。越来越x个^収ͼ只可惜工作还是得在windows vc下,很扫兴?br>    后来发觉词法分析也很单,用FLEX的时候正则表辑ּ都写出来了。前D|间一直在看编译原理,虽然?br>用功。但是就q里而言Q基本可以直接根据正则表辑ּdDFA。终于不用接触那恶心的从NFA转DFA?br>q程Q因为我至今不会Q更不会写代码{? - 总而言之,自己手写了词法分析。边写边参考编译原?br>与实践中附带的tiny-c~译器的词法分析部分Q最l发现我抄了一遍。MDQ一Ҏ(gu)术含量都没有?</font></p> <p><font size=2>附上全部源代码(对于代码我还是比较满意的:DQ,<a href="http://www.shnenglu.com/Files/kevinlynx/klxmlparser.rar" target=_blank>下蝲</a></font></p> <p><font size=2></font></p> <img src ="http://www.shnenglu.com/kevinlynx/aggbug/69079.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2008-12-10 16:22 <a href="http://www.shnenglu.com/kevinlynx/archive/2008/12/10/69079.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.shnenglu.com/" title="精品视频久久久久">精品视频久久久久</a> <div class="friend-links"> </div> </div> </footer> <a href="http://www.summernote.cn" target="_blank">þŷ޹ۺ</a>| <a href="http://www.zhaiseng.cn" target="_blank">һþۺ³³</a>| <a href="http://www.jire1z.cn" target="_blank">ĻþþƷ1</a>| <a href="http://www.ttlll.cn" target="_blank">þþƷަvDz</a>| <a href="http://www.smmz.com.cn" target="_blank">޾Ʒþ</a>| <a href="http://www.0717zf.cn" target="_blank">þþŷղa </a>| <a href="http://www.lingxiu98.com.cn" target="_blank">Ʒþþþþ </a>| <a href="http://www.ondai.com.cn" target="_blank">þav߳avav紵</a>| <a href="http://www.xkart.cn" target="_blank">ŷձþþƷ</a>| <a href="http://www.psia.cn" target="_blank">AVպAVþþ</a>| <a href="http://www.123oye.cn" target="_blank">ھƷþþþþþɬ </a>| <a href="http://www.dszixun.cn" target="_blank">996þùƷ߹ۿ</a>| <a href="http://www.kengsai.cn" target="_blank">ŮƷþþ</a>| <a href="http://www.abctoy.com.cn" target="_blank">vĻþ</a>| <a href="http://www.qymlw.cn" target="_blank">99þùһ</a>| <a href="http://www.zhaozhounews.cn" target="_blank">þþþþþƵ</a>| <a href="http://www.ww0w.cn" target="_blank">97þۺϾƷþþۺ</a>| <a href="http://www.xiazb.cn" target="_blank">þרƷ</a>| <a href="http://www.52shadu.cn" target="_blank">ԻԻ˿þþ</a>| <a href="http://www.003kd.cn" target="_blank">˾þþƷ鶹</a>| <a href="http://www.ccjump.cn" target="_blank">þþþ޾Ʒ˵</a>| <a href="http://www.zghart.cn" target="_blank">þþƷŷպƷ</a>| <a href="http://www.akq33.cn" target="_blank">þþƷϵ</a>| <a href="http://www.8812345.com.cn" target="_blank">þþþۺĻ</a>| <a href="http://www.tfy8.cn" target="_blank">ɫۺϾþ۾Ʒ</a>| <a href="http://www.umtd.cn" target="_blank">þ99Ʒþþþþö̬ͼ</a>| <a href="http://www.68360.cn" target="_blank">97㽶þҹɫƷ </a>| <a href="http://www.ha9hpn.cn" target="_blank">þˬˬav</a>| <a href="http://www.nba592.cn" target="_blank">51þҹɫƷ</a>| <a href="http://www.yweishang.cn" target="_blank">97þþþ޾Ʒר</a>| <a href="http://www.qnzj.org.cn" target="_blank">aѹۿþav</a>| <a href="http://www.hlbelss.org.cn" target="_blank">þü¶</a>| <a href="http://www.uniontruck.cn" target="_blank">99þþþþѿ </a>| <a href="http://www.qqfzl.cn" target="_blank">þþƷ</a>| <a href="http://www.fyhd.net.cn" target="_blank">ŷһþþþþþôƬ</a>| <a href="http://www.yyyyya.cn" target="_blank">ݺɫۺϾþþþ</a>| <a href="http://www.999966.com.cn" target="_blank">Ʒtvþþþþþ</a>| <a href="http://www.lntyyp.cn" target="_blank">þZYZԴվĶ</a>| <a href="http://www.thelv.cn" target="_blank">þþƷAV뽿ɫ</a>| <a href="http://www.nanwx.cn" target="_blank">պĻþ</a>| <a href="http://www.90734.com.cn" target="_blank">þþƷAVɫ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>