??xml version="1.0" encoding="utf-8" standalone="yes"?>噜噜噜色噜噜噜久久,欧美久久亚洲精品,欧美黑人又粗又大久久久http://www.shnenglu.com/vczh/category/6885.html【QQQ?43056143】【EmailQvczh@163.com】【新微博:http://weibo.com/vczh?/description>zh-cnThu, 21 Mar 2013 05:22:56 GMTThu, 21 Mar 2013 05:22:56 GMT60C++实用技巧之配置Visual C++的调试器昄数据l构的格式(附Vczh Library++配置文gQ?/title><link>http://www.shnenglu.com/vczh/archive/2013/03/21/198665.html</link><dc:creator>陈梓?vczh)</dc:creator><author>陈梓?vczh)</author><pubDate>Thu, 21 Mar 2013 03:55:00 GMT</pubDate><guid>http://www.shnenglu.com/vczh/archive/2013/03/21/198665.html</guid><wfw:comment>http://www.shnenglu.com/vczh/comments/198665.html</wfw:comment><comments>http://www.shnenglu.com/vczh/archive/2013/03/21/198665.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/vczh/comments/commentRss/198665.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/vczh/services/trackbacks/198665.html</trackback:ping><description><![CDATA[<p>今天我写了一个给Visual C++用的配置Q用来让VC++在显C己写的字W串和容器等设施变得跟显CSTL一h亮。VC++的可配置型还是很高的Q我们只要写一个xmlQ就可以改变调试器对自己的数据结构的昄?</p> <p>在这里我单地介绍一下用法。假讑֤家觉得vlppQVczh Library++Q也是GacUI用的那个库)的WString啊Listq些东西在调试器里面昄出来的东西太丑,可以用以下三步来修改它?/p> <p>1Q去<a title="http://gac.codeplex.com/SourceControl/changeset/view/99419#2395529" >http://gac.codeplex.com/SourceControl/changeset/view/99419#2395529</a>下蝲我写的那个natvis文g。这个文件在整个zip包里面的位置是Common\vlpp.natvis<br />2Q把q个文g复制到C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\Packages\Debugger\VisualizersQ如果用默认安装\径的话)<br />3Q重启你最喜爱的Visual Studio 2012Q就可以看到下面的东西了Q?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/51783bf28f3a_A413/image_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/51783bf28f3a_A413/image_thumb.png" width="275" height="95" /></a><br />I的指针</p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/51783bf28f3a_A413/image_4.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/51783bf28f3a_A413/image_thumb_1.png" width="433" height="115" /></a><br />有东西的指针</p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/51783bf28f3a_A413/image_6.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/51783bf28f3a_A413/image_thumb_2.png" width="224" height="64" /></a><br />有内容的“惰性计?#8221;c?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/51783bf28f3a_A413/image_8.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/51783bf28f3a_A413/image_thumb_3.png" width="344" height="88" /></a><br />有内容但是还没计的“惰性计?#8221;c?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/51783bf28f3a_A413/image_10.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/51783bf28f3a_A413/image_thumb_4.png" width="353" height="83" /></a><br />没内容的“惰性计?#8221;c?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/51783bf28f3a_A413/image_12.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/51783bf28f3a_A413/image_thumb_5.png" width="445" height="259" /></a><br />新鲜热G的容?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/51783bf28f3a_A413/image_14.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/51783bf28f3a_A413/image_thumb_6.png" width="667" height="226" /></a><br />新鲜热G的映?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/51783bf28f3a_A413/image_16.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/51783bf28f3a_A413/image_thumb_7.png" width="596" height="295" /></a><br />p一对多的映也是如此的新鲜热G</p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/51783bf28f3a_A413/image_18.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/51783bf28f3a_A413/image_thumb_8.png" width="318" height="161" /></a><br />List<Nullable<vint>>的互相嵌套也是如此的完美</p> <p>如果大家惛_自己的Customized Visualizer的话Q可以去参考微软良心提供的文档<a title="http://msdn.microsoft.com/en-us/library/vstudio/jj620914.aspx" >http://msdn.microsoft.com/en-us/library/vstudio/jj620914.aspx</a>Q然后按照上面的步骤写自qnatvis文g。在q里我把我的natvis贴上来,以供参考:</p> <div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 5px; background-color: #f5f5f5; padding-left: 5px; padding-right: 5px; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 5px" class="cnblogs_code"><pre><span style="color: #0000ff"><?</span><span style="color: #ff00ff">xml version="1.0" encoding="utf-8"</span><span style="color: #0000ff">?></span> <span style="color: #0000ff"><</span><span style="color: #800000">AutoVisualizer </span><span style="color: #ff0000">xmlns</span><span style="color: #0000ff">="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Type </span><span style="color: #ff0000">Name</span><span style="color: #0000ff">="vl::ObjectString&lt;wchar_t&gt;"</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">DisplayString</span><span style="color: #0000ff">></span>{{ size={length}, buffer={buffer+start,su} }}<span style="color: #0000ff"></</span><span style="color: #800000">DisplayString</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">StringView</span><span style="color: #0000ff">></span>buffer+start,su<span style="color: #0000ff"></</span><span style="color: #800000">StringView</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Expand</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Item </span><span style="color: #ff0000">Name</span><span style="color: #0000ff">="[size]"</span><span style="color: #0000ff">></span>length<span style="color: #0000ff"></</span><span style="color: #800000">Item</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">ArrayItems</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Size</span><span style="color: #0000ff">></span>length<span style="color: #0000ff"></</span><span style="color: #800000">Size</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">ValuePointer</span><span style="color: #0000ff">></span>buffer+start<span style="color: #0000ff"></</span><span style="color: #800000">ValuePointer</span><span style="color: #0000ff">></span> <span style="color: #0000ff"></</span><span style="color: #800000">ArrayItems</span><span style="color: #0000ff">></span> <span style="color: #0000ff"></</span><span style="color: #800000">Expand</span><span style="color: #0000ff">></span> <span style="color: #0000ff"></</span><span style="color: #800000">Type</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Type </span><span style="color: #ff0000">Name</span><span style="color: #0000ff">="vl::ObjectString&lt;char&gt;"</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">DisplayString</span><span style="color: #0000ff">></span>{{ size={length}, buffer={buffer+start,s} }}<span style="color: #0000ff"></</span><span style="color: #800000">DisplayString</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">StringView</span><span style="color: #0000ff">></span>buffer+start,s<span style="color: #0000ff"></</span><span style="color: #800000">StringView</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Expand</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Item </span><span style="color: #ff0000">Name</span><span style="color: #0000ff">="[size]"</span><span style="color: #0000ff">></span>length<span style="color: #0000ff"></</span><span style="color: #800000">Item</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">ArrayItems</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Size</span><span style="color: #0000ff">></span>length<span style="color: #0000ff"></</span><span style="color: #800000">Size</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">ValuePointer</span><span style="color: #0000ff">></span>buffer+start<span style="color: #0000ff"></</span><span style="color: #800000">ValuePointer</span><span style="color: #0000ff">></span> <span style="color: #0000ff"></</span><span style="color: #800000">ArrayItems</span><span style="color: #0000ff">></span> <span style="color: #0000ff"></</span><span style="color: #800000">Expand</span><span style="color: #0000ff">></span> <span style="color: #0000ff"></</span><span style="color: #800000">Type</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Type </span><span style="color: #ff0000">Name</span><span style="color: #0000ff">="vl::collections::List&lt;*,*&gt;"</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">AlternativeType </span><span style="color: #ff0000">Name</span><span style="color: #0000ff">="vl::collections::SortedList&lt;*,*&gt;"</span><span style="color: #0000ff">/></span> <span style="color: #0000ff"><</span><span style="color: #800000">AlternativeType </span><span style="color: #ff0000">Name</span><span style="color: #0000ff">="vl::collections::Array&lt;*,*&gt;"</span><span style="color: #0000ff">/></span> <span style="color: #0000ff"><</span><span style="color: #800000">DisplayString</span><span style="color: #0000ff">></span>{{ size={count} }}<span style="color: #0000ff"></</span><span style="color: #800000">DisplayString</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Expand</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Item </span><span style="color: #ff0000">Name</span><span style="color: #0000ff">="[size]"</span><span style="color: #0000ff">></span>count<span style="color: #0000ff"></</span><span style="color: #800000">Item</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">ArrayItems</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Size</span><span style="color: #0000ff">></span>count<span style="color: #0000ff"></</span><span style="color: #800000">Size</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">ValuePointer</span><span style="color: #0000ff">></span>buffer<span style="color: #0000ff"></</span><span style="color: #800000">ValuePointer</span><span style="color: #0000ff">></span> <span style="color: #0000ff"></</span><span style="color: #800000">ArrayItems</span><span style="color: #0000ff">></span> <span style="color: #0000ff"></</span><span style="color: #800000">Expand</span><span style="color: #0000ff">></span> <span style="color: #0000ff"></</span><span style="color: #800000">Type</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Type </span><span style="color: #ff0000">Name</span><span style="color: #0000ff">="vl::collections::Dictionary&lt;*,*,*,*&gt;"</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">AlternativeType </span><span style="color: #ff0000">Name</span><span style="color: #0000ff">="vl::collections::Group&lt;*,*,*,*&gt;"</span><span style="color: #0000ff">/></span> <span style="color: #0000ff"><</span><span style="color: #800000">DisplayString</span><span style="color: #0000ff">></span>{{ size={keys.count} }}<span style="color: #0000ff"></</span><span style="color: #800000">DisplayString</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Expand</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Item </span><span style="color: #ff0000">Name</span><span style="color: #0000ff">="[size]"</span><span style="color: #0000ff">></span>keys.count<span style="color: #0000ff"></</span><span style="color: #800000">Item</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Item </span><span style="color: #ff0000">Name</span><span style="color: #0000ff">="Keys"</span><span style="color: #0000ff">></span>keys<span style="color: #0000ff"></</span><span style="color: #800000">Item</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Item </span><span style="color: #ff0000">Name</span><span style="color: #0000ff">="Values"</span><span style="color: #0000ff">></span>values<span style="color: #0000ff"></</span><span style="color: #800000">Item</span><span style="color: #0000ff">></span> <span style="color: #0000ff"></</span><span style="color: #800000">Expand</span><span style="color: #0000ff">></span> <span style="color: #0000ff"></</span><span style="color: #800000">Type</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Type </span><span style="color: #ff0000">Name</span><span style="color: #0000ff">="vl::Ptr&lt;*&gt;"</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">AlternativeType </span><span style="color: #ff0000">Name</span><span style="color: #0000ff">="vl::ComPtr&lt;*&gt;"</span><span style="color: #0000ff">/></span> <span style="color: #0000ff"><</span><span style="color: #800000">DisplayString </span><span style="color: #ff0000">Condition</span><span style="color: #0000ff">="reference == 0"</span><span style="color: #0000ff">></span>[empty]<span style="color: #0000ff"></</span><span style="color: #800000">DisplayString</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">DisplayString </span><span style="color: #ff0000">Condition</span><span style="color: #0000ff">="reference != 0"</span><span style="color: #0000ff">></span>{*reference}<span style="color: #0000ff"></</span><span style="color: #800000">DisplayString</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Expand</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Item </span><span style="color: #ff0000">Condition</span><span style="color: #0000ff">="reference != 0"</span><span style="color: #ff0000"> Name</span><span style="color: #0000ff">="[ptr]"</span><span style="color: #0000ff">></span>reference<span style="color: #0000ff"></</span><span style="color: #800000">Item</span><span style="color: #0000ff">></span> <span style="color: #0000ff"></</span><span style="color: #800000">Expand</span><span style="color: #0000ff">></span> <span style="color: #0000ff"></</span><span style="color: #800000">Type</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Type </span><span style="color: #ff0000">Name</span><span style="color: #0000ff">="vl::Lazy&lt;*&gt;"</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">DisplayString </span><span style="color: #ff0000">Condition</span><span style="color: #0000ff">="internalValue.reference == 0"</span><span style="color: #0000ff">></span>[empty]<span style="color: #0000ff"></</span><span style="color: #800000">DisplayString</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">DisplayString </span><span style="color: #ff0000">Condition</span><span style="color: #0000ff">="internalValue.reference != 0 &amp;&amp; internalValue.reference->evaluated == false"</span><span style="color: #0000ff">></span>[not evaluated]<span style="color: #0000ff"></</span><span style="color: #800000">DisplayString</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">DisplayString </span><span style="color: #ff0000">Condition</span><span style="color: #0000ff">="internalValue.reference != 0 &amp;&amp; internalValue.reference->evaluated == true"</span><span style="color: #0000ff">></span>{internalValue.reference->value}<span style="color: #0000ff"></</span><span style="color: #800000">DisplayString</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Expand</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Item </span><span style="color: #ff0000">Condition</span><span style="color: #0000ff">="internalValue.reference != 0 &amp;&amp; internalValue.reference->evaluated == true"</span><span style="color: #ff0000"> Name</span><span style="color: #0000ff">="[value]"</span><span style="color: #0000ff">></span>internalValue.reference->value<span style="color: #0000ff"></</span><span style="color: #800000">Item</span><span style="color: #0000ff">></span> <span style="color: #0000ff"></</span><span style="color: #800000">Expand</span><span style="color: #0000ff">></span> <span style="color: #0000ff"></</span><span style="color: #800000">Type</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Type </span><span style="color: #ff0000">Name</span><span style="color: #0000ff">="vl::ObjectBox&lt;*&gt;"</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">DisplayString</span><span style="color: #0000ff">></span>{object}<span style="color: #0000ff"></</span><span style="color: #800000">DisplayString</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Expand</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">ExpandedItem</span><span style="color: #0000ff">></span>object<span style="color: #0000ff"></</span><span style="color: #800000">ExpandedItem</span><span style="color: #0000ff">></span> <span style="color: #0000ff"></</span><span style="color: #800000">Expand</span><span style="color: #0000ff">></span> <span style="color: #0000ff"></</span><span style="color: #800000">Type</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Type </span><span style="color: #ff0000">Name</span><span style="color: #0000ff">="vl::Nullable&lt;*&gt;"</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">DisplayString </span><span style="color: #ff0000">Condition</span><span style="color: #0000ff">="object == 0"</span><span style="color: #0000ff">></span>[empty]<span style="color: #0000ff"></</span><span style="color: #800000">DisplayString</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">DisplayString </span><span style="color: #ff0000">Condition</span><span style="color: #0000ff">="object != 0"</span><span style="color: #0000ff">></span>{*object}<span style="color: #0000ff"></</span><span style="color: #800000">DisplayString</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">Expand</span><span style="color: #0000ff">></span> <span style="color: #0000ff"><</span><span style="color: #800000">ExpandedItem </span><span style="color: #ff0000">Condition</span><span style="color: #0000ff">="object != 0"</span><span style="color: #0000ff">></span>*object<span style="color: #0000ff"></</span><span style="color: #800000">ExpandedItem</span><span style="color: #0000ff">></span> <span style="color: #0000ff"></</span><span style="color: #800000">Expand</span><span style="color: #0000ff">></span> <span style="color: #0000ff"></</span><span style="color: #800000">Type</span><span style="color: #0000ff">></span> <span style="color: #0000ff"></</span><span style="color: #800000">AutoVisualizer</span><span style="color: #0000ff">></span></pre></div><img src ="http://www.shnenglu.com/vczh/aggbug/198665.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/vczh/" target="_blank">陈梓?vczh)</a> 2013-03-21 11:55 <a href="http://www.shnenglu.com/vczh/archive/2013/03/21/198665.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>可配|语法分析器开发纪事(五)&mdash;&mdash;构造一个真正能用的状态机Q中Q?/title><link>http://www.shnenglu.com/vczh/archive/2013/01/01/196893.html</link><dc:creator>陈梓?vczh)</dc:creator><author>陈梓?vczh)</author><pubDate>Tue, 01 Jan 2013 07:52:00 GMT</pubDate><guid>http://www.shnenglu.com/vczh/archive/2013/01/01/196893.html</guid><wfw:comment>http://www.shnenglu.com/vczh/comments/196893.html</wfw:comment><comments>http://www.shnenglu.com/vczh/archive/2013/01/01/196893.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.shnenglu.com/vczh/comments/commentRss/196893.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/vczh/services/trackbacks/196893.html</trackback:ping><description><![CDATA[<p><a href="http://www.shnenglu.com/vczh/archive/2012/12/23/196524.html" target="_blank">上一博?/a>写到了如何给一个非l结W的文法规则构造出一个压~过的下推状态机Q那么今天说的就是如何把所有的文法都连接v来。其实主要的idea?a href="http://www.shnenglu.com/vczh/archive/2012/12/07/196079.html" target="_blank">Q三Q?/a>和他的勘?a href="http://www.shnenglu.com/vczh/archive/2012/12/07/196085.html" target="_blank">Q三点五Q?/a>里面已经说得差不多了。但是今天我们要处理的是带信息的transitionQ所以还有一些地方要注意一下?/p> <p>所以在q里我们先把几条文法的最后的状态机都列出来Q大图)Q?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/5a2a95565d03_AB00/image_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/5a2a95565d03_AB00/image_thumb.png" width="893" height="1438" /></a></p> <p>接下来的q一步,是要对所有靠非终l符QExp啊Termq些Q进行蟩转的transition都执行上一文章所说的传说中的交叉链接。在产生链接的时候,我们lshift和reduce的边分别加上shift和reduce。而shift和reduce是有参数?#8212;—是被shift走的状态的id。这样可以在parse的时候匹配和处理状态堆栈。在q里我门对e3->e1q一步做一下操作做Z子。红色的Ҏ被删掉的Q而粗壮的l色Ҏ被新加进ȝQ?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/5a2a95565d03_AB00/image_12.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/5a2a95565d03_AB00/image_thumb_5.png" width="885" height="597" /></a></p> <p>U色的边变成了两条绿色的边,U色的边附带的信息则被复制到了绿色的reduce边上。当我们使用q个状态机的时候,shift(s3)pC往堆栈里面压入s3Qreduce(s3)pCZ堆栈里面弹出(s3)。当然弹Z一定会成功Q所以如果不成功的话Q这条边׃能在当时使用。因此这也就是ؓ什么在e3跌{到t0之后Qt1知道往回蟩的是e1而不是别的什么地?#8212;—如同ؓ什么C++的函数执行完之后L知道如何跌{回调用它的地方一?#8212;—因ؓ把信息推入了堆栈?/p> <p>那现在我们就来看一下,当所有的非终l符跌{都处理掉之后Q会变成什么样子吧Q这个图真是复杂和ؕ到我不想dQ,Z让图变得不那么糟p,我把shift都变成Ԍreduce都变成绿Ԍ</p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/5a2a95565d03_AB00/image_6.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/5a2a95565d03_AB00/image_thumb_1.png" width="1191" height="1528" /></a></p> <p>在添加shift和reduce边之前,每一条边都是有输入token的。但是我们刚刚添加上ȝshift和reduce边却是不输入token的,所以他们是epsilon边,下一步就是要消除他们。上面这个图消除了epsilon边之后,会变成一个状态很,但是每一条边附带的信息都会非常多Q而且像n1q种l常到达的状态(因ؓ四则q算里面有很多数字)恢复射出无数条辏V到了这里这个状态机已经再也M出来了。所以我下面只拿两个例子来甅R下面要展示的是用Exp来parse单独的一个数字会走的边,当然是Exp –> Term –> Factor –> Number了:</p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/5a2a95565d03_AB00/image_8.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/5a2a95565d03_AB00/image_thumb_2.png" width="557" height="504" /></a></p> <p>׃被处理成Q?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/5a2a95565d03_AB00/image_14.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/5a2a95565d03_AB00/image_thumb_3.png" width="676" height="457" /></a></p> <p>注意边上面的信息是要按顺序重新叠加在一L。当所有的epsilon辚wL了之后,我们得C最l的一个状态机。最重要的一件事情出C。我们知道,发明LR和LALRq种东西基本上是ؓ了处理左递归的,所以这U图可以在去除epsilon边的q程中自动发现左递归。这是怎么做到的呢Q只要在去除epsilon边的时候,发现了一条完全由shiftq种epsilon边组成的环,那么左递归发C。ؓ了方便,我们可以只处理直接左递归——是q种环的长度?的。不包含间接左递归的问法是很容易写出来的。当然这U环q不一定是首尾相接的,譬如说我们在处理e0的时候就会发现e0->t0->t0q种环(当然严格来说环只有最后一截的q个部分Q。我们的E序要很好地应对q种情况。因为我们只接受直接左递归Q所以类DU结构的epsilon路径可以直接的抛弃他Q因为t0->t0会被t0状态单独处理掉。因此这样做q不会漏掉什么?/p> <p>l心的朋友可能会发现Q这个结构的图是不能直接处理右递归的(M左递归和右递归总要有一个会让你的状态机傻逼就是了Q)。关于如何处理有递归Q其实内容也不复杂)地方法会?#8220;下篇”描述出来。那处理左递归有什么用呢?举个例子Q我们的e0->e2是一个左递归Q而他会在之前的步骤被处理成shift(e0->e0)和reduce(e1->e2)。我们要Cshift和reduce的对应关p,那么当我们找C个左递归的shift之后Q我们就可以把对应的reducel标记成“left-recursive-reduce”。这是一个在构造语法树的时候,非常关键的一U构造指令?/p> <p>处理完这些之后,我们可以把左递归的shift边全部删掉,最后把token和state都统l处理成q箋的数字,做成一张[state, token] –> [transitions]的二l表Q每一个表的元素是transition的列表。ؓ什么是q样呢?因ؓ我们对一个state输入一个token之后Q由于保存着state的堆栈(你还记得吗?shift==pushQreduce==popQ的栈顶若干个元素的不同Q可能会C通的路线。于是最后我们就得到了这么一张图?/p> <p>下面q张囑֏以通过q行gac.codeplex.com上面的Common\UnitTest\UnitTest.slnQVS2012限定Q之后,在Common\UnitTest\TestFiles\Parsing.Calculator.Table.txt里面扑ֈ。这一l文仉是我在测试状态机的时候log下来的?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/5a2a95565d03_AB00/image_16.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/5a2a95565d03_AB00/image_thumb_6.png" width="1934" height="1812" /></a></p> <p>如果大家有VS2012的话Q通过q行我准备的几个输入Q譬如说“1*2+3*4”Q就可以在Parsing.Calculator.[2].txt里面扑ֈ所有状态蟩转的轨迹。因为我们L需要parse一个ExpQ所以我们从22: Exp.RootStart开始。我们假设token stream的第一个和最后一个分别是$TokenBegin?TokenFinish。上囄$TryReduce是ؓ了应对右递归而设计出来的一U特D输入。由于四则运里面ƈ没有右递归Q所以这一列就是空的:</p> <p>StartState: 22[Exp.RootStart]<br />$TokenBegin => 23[Exp.Start]<br />    State Stack: <br />NUMBER[1] => 2[Number.1]<br />    State Stack: 23[Exp.Start], 21[Term.Start], 19[Factor.Start]<br />    Shift 23[Exp]<br />    Shift 21[Term]<br />    Shift 19[Factor]<br />    Assign value<br />    Create NumberExpression<br />MUL[*] => 5[Term.3]<br />    State Stack: 23[Exp.Start]<br />    Reduce 19[Factor]<br />    Using<br />    Reduce 21[Term]<br />    Using<br />    LR-Reduce 21[Term]<br />    Assign firstOperand<br />    Setter binaryOperator = Mul<br />    Create BinaryExpression<br />NUMBER[2] => 2[Number.1]<br />    State Stack: 23[Exp.Start], 5[Term.3], 19[Factor.Start]<br />    Shift 5[Term]<br />    Shift 19[Factor]<br />    Assign value<br />    Create NumberExpression<br />ADD[+] => 10[Exp.3]<br />    State Stack: <br />    Reduce 19[Factor]<br />    Using<br />    Reduce 5[Term]<br />    Assign secondOperand<br />    Reduce 23[Exp]<br />    Using<br />    LR-Reduce 23[Exp]<br />    Assign firstOperand<br />    Setter binaryOperator = Add<br />    Create BinaryExpression<br />NUMBER[3] => 2[Number.1]<br />    State Stack: 10[Exp.3], 21[Term.Start], 19[Factor.Start]<br />    Shift 10[Exp]<br />    Shift 21[Term]<br />    Shift 19[Factor]<br />    Assign value<br />    Create NumberExpression<br />MUL[*] => 5[Term.3]<br />    State Stack: 10[Exp.3]<br />    Reduce 19[Factor]<br />    Using<br />    Reduce 21[Term]<br />    Using<br />    LR-Reduce 21[Term]<br />    Assign firstOperand<br />    Setter binaryOperator = Mul<br />    Create BinaryExpression<br />NUMBER[4] => 2[Number.1]<br />    State Stack: 10[Exp.3], 5[Term.3], 19[Factor.Start]<br />    Shift 5[Term]<br />    Shift 19[Factor]<br />    Assign value<br />    Create NumberExpression<br />$TokenFinish => 11[Exp.RootEnd]<br />    State Stack: <br />    Reduce 19[Factor]<br />    Using<br />    Reduce 5[Term]<br />    Assign secondOperand<br />    Reduce 10[Exp]<br />    Assign secondOperand</p> <p>我们把所有蟩转过的transition的信息都记录下来Q就可以构造语法苏了。我们想象一下,在执行这些指令的时候,遇到NUMBER[4]q于获得了一个内容ؓ4的tokenQshift的话是往堆栈里面pushq一个状态的名字Q而reduce则是弹出?/p> <p>相对应的Q因为每一个文法都会创Z个对象,所以我们在初始化的时候,要先放一个空对象在堆栈上。shift一ơ就再创Z个空的对象pushq去Qreduce的时候就把栈的对象弹出来作?#8220;待处理对?#8221;Qusing了就把待处理对象和栈对象合qӞleft-reduce是把栈对象弹出来作ؓ待处理对象的同时Qpush一个空对象q去。assign fieldName是?#8220;待处理对?#8221;保存到栈对象的叫做fieldName的成员变量里面去。如果栈对象ؓI,那么被保存的对象是刚刚输入的那个token了。因此我们从头到执行一遍之后,可以得C面的一颗语法树Q?/p> <p>BinaryExpression {<br />    binaryOperator = [Add]<br />    firstOperand = BinaryExpression {<br />        binaryOperator = [Mul]<br />        firstOperand = NumberExpression {<br />            value = [1]<br />        }<br />        secondOperand = NumberExpression {<br />            value = [2]<br />        }<br />    }<br />    secondOperand = BinaryExpression {<br />        binaryOperator = [Mul]<br />        firstOperand = NumberExpression {<br />            value = [3]<br />        }<br />        secondOperand = NumberExpression {<br />            value = [4]<br />        }<br />    }<br />}</p> <p>基本上parsing的过E就l束了。在“下篇”——也就是(六)——里面Q我会讲q如何处理右递归Q然后这个系列基本上p完结了?/p> <img src ="http://www.shnenglu.com/vczh/aggbug/196893.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/vczh/" target="_blank">陈梓?vczh)</a> 2013-01-01 15:52 <a href="http://www.shnenglu.com/vczh/archive/2013/01/01/196893.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>可配|语法分析器开发纪事(四)&mdash;&mdash;构造一个真正能用的状态机Q上Q?/title><link>http://www.shnenglu.com/vczh/archive/2012/12/23/196524.html</link><dc:creator>陈梓?vczh)</dc:creator><author>陈梓?vczh)</author><pubDate>Sat, 22 Dec 2012 16:28:00 GMT</pubDate><guid>http://www.shnenglu.com/vczh/archive/2012/12/23/196524.html</guid><wfw:comment>http://www.shnenglu.com/vczh/comments/196524.html</wfw:comment><comments>http://www.shnenglu.com/vczh/archive/2012/12/23/196524.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/vczh/comments/commentRss/196524.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/vczh/services/trackbacks/196524.html</trackback:ping><description><![CDATA[<p>本来说这一文章要把构造确定性状态机和look ahead讲完的,当我真正要写的时候发C西太多,只好分成两篇了?a href="http://www.shnenglu.com/vczh/archive/2012/12/07/196085.html" target="_blank">上一文?/a>说道一个基本的状态机是如何构造出来的Q但是根?a href="http://www.shnenglu.com/vczh/archive/2012/11/21/195503.html" target="_blank">W一文?/a>的说法,q一ơ设计的文法是ؓ了直接构造出语法树服务的Q所以必然在执行状态机的时候就要获得构造语法树的一切信息。如果自己开发过cM的东西就会知道,cMLALRq种东西Q你可以很容易的把整个字W串分析完判断他是不是属于这个LALR状态机描述的这个集合,但是你却不能拿到语法分析所走的路径Q也是说你很难直接拿到那颗分析树。没有分析树肯定是做不出语法树的。因此我们得把一些信息插入到状态机里面Q才能最l把分析树(q不一定真的要表达成树Q像上一文章的“分析路径”Q其实就是分析树的一U可能的表达形式Q所定的语法树构造出来?/p> <p>像?a href="http://www.shnenglu.com/vczh/archive/2008/05/22/50763.html" target="_blank">构造正则表辑ּ引擎</a>》一般给状态机d信息的方法,是把一些附加的数据加到状态与状态之间的跌{头里面厅Rؓ了Ş象的表达q个事情Q我拿W一文章的四则q算式子来D例。在q里我ؓ了大家方便,重复一下这个文法的内容Q除M语树书声明)Q?/p> <div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 5px; background-color: #f5f5f5; padding-left: 5px; padding-right: 5px; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 5px" class="cnblogs_code"><pre>token NAME = <span style="color: #800000">"</span><span style="color: #800000">[a-zA-Z_]/w*</span><span style="color: #800000">"</span><span style="color: #000000">; token NUMBER </span>= <span style="color: #800000">"</span><span style="color: #800000">/d+(./d+)</span><span style="color: #800000">"</span><span style="color: #000000">; token ADD </span>= <span style="color: #800000">"</span><span style="color: #800000">/+</span><span style="color: #800000">"</span><span style="color: #000000">; token SUB </span>= <span style="color: #800000">"</span><span style="color: #800000">-</span><span style="color: #800000">"</span><span style="color: #000000">; token MUL </span>= <span style="color: #800000">"</span><span style="color: #800000">/*</span><span style="color: #800000">"</span><span style="color: #000000">; token DIV </span>= <span style="color: #800000">"</span><span style="color: #800000">//</span><span style="color: #800000">"</span><span style="color: #000000">; token LEFT </span>= <span style="color: #800000">"</span><span style="color: #800000">/(</span><span style="color: #800000">"</span><span style="color: #000000">; token RIGHT </span>= <span style="color: #800000">"</span><span style="color: #800000">/)</span><span style="color: #800000">"</span><span style="color: #000000">; token COMMA </span>= <span style="color: #800000">"</span><span style="color: #800000">,</span><span style="color: #800000">"</span><span style="color: #000000">; rule NumberExpression Number </span>=<span style="color: #000000"> NUMBER : value; rule FunctionExpression Call </span>= NAME : functionName <span style="color: #800000">"</span><span style="color: #800000">(</span><span style="color: #800000">"</span> [ Exp : arguments { <span style="color: #800000">"</span><span style="color: #800000">,</span><span style="color: #800000">"</span> Exp : arguments } ] <span style="color: #800000">"</span><span style="color: #800000">)</span><span style="color: #800000">"</span><span style="color: #000000">; rule Expression Factor </span>= !Number | !<span style="color: #000000">Call; rule Expression Term </span>= !<span style="color: #000000">Factor; </span>= Term : firstOperand <span style="color: #800000">"</span><span style="color: #800000">*</span><span style="color: #800000">"</span> Factor : secondOperand <span style="color: #0000ff">as</span> BinaryExpression with { binaryOperator = <span style="color: #800000">"</span><span style="color: #800000">Mul</span><span style="color: #800000">"</span><span style="color: #000000"> }; </span>= Term : firstOperand <span style="color: #800000">"</span><span style="color: #800000">/</span><span style="color: #800000">"</span> Factor : secondOperand <span style="color: #0000ff">as</span> BinaryExpression with { binaryOperator = <span style="color: #800000">"</span><span style="color: #800000">Div</span><span style="color: #800000">"</span><span style="color: #000000"> }; rule Expression Exp </span>= !<span style="color: #000000">Term; </span>= Exp : firstOperand <span style="color: #800000">"</span><span style="color: #800000">+</span><span style="color: #800000">"</span> Term : secondOperand <span style="color: #0000ff">as</span> BinaryExpression with { binaryOperator = <span style="color: #800000">"</span><span style="color: #800000">Add</span><span style="color: #800000">"</span><span style="color: #000000"> }; </span>= Exp : firstOperand <span style="color: #800000">"</span><span style="color: #800000">-</span><span style="color: #800000">"</span> Term : secondOperand <span style="color: #0000ff">as</span> BinaryExpression with { binaryOperator = <span style="color: #800000">"</span><span style="color: #800000">Sub</span><span style="color: #800000">"</span> };</pre></div> <p>那么我们把这个文发{成状态机之后Q要l蟩转加上什么呢Q从直觉上来_跌{的时候我们会有六U要q的事情Q?br />1、CreateQ这个文法创建的语法树节Ҏ某个cd的(区别于在q一ȝq个问法创徏一个返回什么类型的语法树节点)<br />2、SetQ给创徏的语法树节点的某个成员变量设|一个指定的?br />3、AssignQ给创徏的语法树节点的某个成员变量设|这一ơ蟩转的W号产生的语法树节点Q譬如说Exp = Exp: firstOperand “+” Term: secondOperandQ走Term的时候,一个语法树节点׃被assignl那个叫做secondOperand的成员变量)<br />4、UsingQ用这一ơ蟩转的W号产生的语法树节点来做q次文法的返回|譬如说Factor = !Number | !Callerq一条)<br />5、ShiftQ略<br />6、ReduceQ略</p> <p>在这里我们ƈ没有标记整个文法从哪一个非l结W开始,因ؓ在实际过E中Q其实分析师可以从Q何一个文法开始的。譬如说写IDE的时候,我们可能在某些情况下仅仅只需要分析一个表辑ּ。所以考虑到每一个非l结W都有可能被用到Q因此我们的“Token开?#8221;?#8220;Token结?#8221;׃在每一个非l结W的状态机中都出现。因此在W一步创建Epsilon PDAQ下推自动机Q的时候,可以先直接生成。在q里我们拿Exp做例子:</p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/e061a408f76c_139DA/image_18.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/e061a408f76c_139DA/image_thumb_8.png" width="644" height="265" /></a></p> <p>双虚U代表的是Token和Token结束,qƈ不是我们现在兛_的事情。在剩下的{换中Q实现是h输入的{换,而虚U则是没有输入的转换Q一般称为epsilon边)?/p> <p>在这里我们要明确一个概?#8212;—分析路径。分析\径代表的是token?#8220;?#8221;q状态机的时候,状态是如何跌{的。因此对于实际的分析q程Q分析\径其实就是分析树的一U表辑Ş式。而在状态机里面Q分析\径则代表一条从开始到l尾的可能的路径。譬如说在这里,分析路径可以有三条:<br />$e –> e1 –> e2 –> e$<br />$e –> e3 –> e8 –> e7 –> e6 –> e5 –> e4 –> e$<br />$e –> e9 –> e14 –> e13 –> e12 –> e11 –> e10 –> e$</p> <p>因此我们可以清楚Q一条\径上是不能出现多个create的,否则你就不知道应该创建的是什么了。当然create和using都不能同时出玎ͼusing也不能有多个。而且׃create和set都是在描q这个非l结W(在这里是ExpQ所创徏的语法树节点的类型和属性,跟执行他们的时机无关Q所以其实在同一条分析\径里面,create和set攑֜哪里都没关系。就譬如说在上面的第二条分析路径里面Qcreate是在e6->e5里面标记出来的。就他UdCe3->e8Q做的事情也一栗反正只要一条\径上标记了createQ那么他在这条\径被定之后Q就一定会create所指定的具体类型的语法树节炏V这是相当重要的Q因为在后面的分析中Q我们很可能需要移动create和set的具体位|?/p> <p>跟上一文章说的一P接下来的一步就是去除epsilon边了。结果如下:</p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/e061a408f76c_139DA/image_20.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/e061a408f76c_139DA/image_thumb_9.png" width="644" height="332" /></a></p> <p>面对q种状态机Q去除epsilon边就不能跟处理正则表辑ּ一L单的去除了。首先,所有的l结状?#8212;—也就是所有经q或者不l过epsilon边之后,通过“Token结?#8221;W号q接到最后一个状态的状态,在这里分别是e2、e6和e12——都是不能删掉的。而且所有的“Token开?#8221;?#8220;Token结?#8221;——也就是图里面?转换——是不能带有信息的。所以我们就会看到e6后面的信息全部被UdCe7->e6q条边上面。由于create和set的流动性,我们q么做对于状态机的定义完全没有媄响?/p> <p>Cq里q没完,因ؓq个状态机q是有很多冗余的状态的。譬如说e8和e14、e7和e13、e2和e6和e12实际上是可以合ƈ的。合q的{略其实十分单:</p> <p>1、如果我们有跌{e0->e1和e0->e2Qƈ且两个蟩转所携带的token输入和信息完全一致的话,那么e1和e2可以合q?br />2、如果我们有跌{e1->e0和e2->e0Qƈ且两个蟩转所携带的token输入和信息完全一致的话,那么e1和e2可以合q?/p> <p>所以对于e8和e14我们是完全可以合q的。那么e7和e13怎么办呢Q根据create和set的流动性,我们只要把这两个东西挪到他的前面一个或者若q个跌{去,那这两个状态就可以合ƈ了。ؓ了让法更加的简单,我们遇到两个跌{cM的时候,L先挪动create和setQ然后再看看是不是真的可以合q。所以这一步处理完之后׃变成下面q个样子Q?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/e061a408f76c_139DA/image_22.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/e061a408f76c_139DA/image_thumb_10.png" width="644" height="372" /></a></p> <p>我们在不改变状态机语义的情况下Q把Exp的三个状态机最l压~成了这个样子。看q上一文章的同学们都知道Q下一步就是要把所有的状态机l统都连接v来了。关于在q接的时候如何具体操作{换附带的信息、以及做Z个确定性的下推状态机的所有事情将在下一文章详l解释。大家敬h待?/p><img src ="http://www.shnenglu.com/vczh/aggbug/196524.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/vczh/" target="_blank">陈梓?vczh)</a> 2012-12-23 00:28 <a href="http://www.shnenglu.com/vczh/archive/2012/12/23/196524.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>可配|语法分析器开发纪事(三点五)&mdash;&mdash;生成下推自动机的具体步骤http://www.shnenglu.com/vczh/archive/2012/12/07/196085.html陈梓?vczh)陈梓?vczh)Fri, 07 Dec 2012 10:49:00 GMThttp://www.shnenglu.com/vczh/archive/2012/12/07/196085.htmlhttp://www.shnenglu.com/vczh/comments/196085.htmlhttp://www.shnenglu.com/vczh/archive/2012/12/07/196085.html#Feedback2http://www.shnenglu.com/vczh/comments/commentRss/196085.htmlhttp://www.shnenglu.com/vczh/services/trackbacks/196085.html刚刚发了上一文?/a>之后发现状态机画错了。虽然LiveWriter有打开博客q修Ҏ章的功能Q不qؓ了让我留下一个教训,我还是决定发一勘误。这个教训就是,作分析的时候不要随?#8220;x”Q该一步一步来׃步一步来。其实h呢,是很容易忘掉以前的教训的了。第一个告诉我不能q么q的人其实是学三年U的数学老师。当时我因ؓ懒得写字Q所以计应用题的时候省了几步,被批评了?/p>

故事׃状态机开始。文法我׃重复了,见上一文章。现在我们从状态机开始。第一个状态机是直接从文法变过来的Q?/p>

image

然后我们把所有的非终l符跌{都通过Shift和Reduceq接到该非终l符所代表的状态机的状态上面,׃变成下面的图。具体的做法是,对于每一条非l结W的跌{Q譬如说S0 –> Symbol –> S1。首先抹掉这条蟩转。然后增加两条边Q分别是S0到Symbol的v始节点,操作是Shift<S0>。还有从Symbol的终l节点到S0Q操作是Pop<S0> Reduce。Shift<S>{于把状态Slpush到堆栈里Q然后Pop<S>{于在状态里面弹出内ҎS的栈元素。如果失败了怎么办呢Q那׃能用q条跌{。跟上图一P所有输?跌{到Finish的边Q操作都是要Pop<Null>的。在刚开始分析的时候,堆栈有一个Null|用来代表“语法分析从这里开?#8221;?/p>

image

q个囄_虚边代表所有跟左递归有关的蟩转。这些边是成对的Q分别是左递归跌{的Shift和Reduce。如果不是ؓ了实现高性能的语法分析的话,其实q个状态机已经_了。这个图跟语法分析的“状态蟩转轨q?#8221;有很大的关系。虽然IDList0你不知道W一步要跌{到IDList0q是ID0Q不q没关系Q现在我们先假设我们可以通过某种秘的方法来预测到。那么,当输入是A,B,C$的时候,状态蟩转轨q就会是如下的样子:

image

Z么要q么做呢Q我们把q幅图想象成?br>1Q想做的头表示push一个状?br>2Q向下的头表示修改当前状?br>3Q向右的状态表Cpop一个状态ƈ修改当前状?/p>

因此当输入到B的时候,到达ID1Qƈ跌{到IDList1。这个时候IDList1【左辏V的所有【还留在堆栈里】的状态时Null和IDList0Q当前状态IDList1Q输入剩?C$。这个图特别的有用。当我们分析完ƈ且把构造语法树的指令附着在这些箭头上面之后,按顺序执行这些指令就可以构造出一颗完整的语法树了?/p>

但是在实际操作里面,我们q没有办法预?#8220;q里要左递归两次”Q也没办法在多次reduce的时候选择I竟要从哪里跛_哪里。所以实际上我们要学习从EpsilonNFA到DFA的那个计过E,把Shift和Reduce当成EpsilonQ把吃掉一个token当成非Epsilon边,然后执行我之前写的?a href="http://www.shnenglu.com/vczh/archive/2008/05/22/50763.html" target="_blank">构造可配置词法分析?/a>》一文中的那个去Epsilon边算法(如何从Nondeterministic到DeterministicQ以及相关的Look AheadQ是下一文章的内容Q,然后可以把状态机变成q样Q?/p>

image

上面_体的Pop<IDList0>表示Q这一个Pop是对应于那个左递归Shifting操作的。实际上q是做了一个怎样的变化呢Q从“物理解释”上来Ԍ其实是把“状态蟩转轨q?#8221;里面那些除了左递归shifting之外的所有不吃掉token的边都去掉了Q?/p>

image

在这里我们可以看刎ͼZ么当堆栈是IDList0, IDList0和IDList0, IDList3的时候,从ID0都可以通过吃掉一?#8221;,”从而蟩转到IDList3。在上面q张“状态蟩转轨q?#8221;里面Q这两个事情都发生了Q分别是W一条向左的头和第二条向左的方向。而且q两条边刚好对应于上囑ָ有蓝色粗体文字的跌{Q属于左递归Reducing操作?/p>

所以,其实在这个时候,我们同时解决?#8220;应该在什么时候进行左递归Shifting”的问题。只要当左递归Reducing已发生,我们立刻在轨q上面补上一条左递归Shifting好了。因此,我们在一开始做parsing的时候,Ҏ不需要预先做左递归Shifting。所以当刚刚输入A的时候,“状态蟩转轨q?#8221;是这样子的:

image

然后遇到一?#8221;,”Q发C?#8220;做漏”了一个左递归ShiftingQ因此就变成下面q个样子Q?/p>

image

q也是上一文章那个Fake-Shift所做的事情了?/p>

陈梓?vczh) 2012-12-07 18:49 发表评论
]]>
可配|语法分析器开发纪事(三)&mdash;&mdash;生成下推自动?/title><link>http://www.shnenglu.com/vczh/archive/2012/12/07/196079.html</link><dc:creator>陈梓?vczh)</dc:creator><author>陈梓?vczh)</author><pubDate>Fri, 07 Dec 2012 08:43:00 GMT</pubDate><guid>http://www.shnenglu.com/vczh/archive/2012/12/07/196079.html</guid><wfw:comment>http://www.shnenglu.com/vczh/comments/196079.html</wfw:comment><comments>http://www.shnenglu.com/vczh/archive/2012/12/07/196079.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.shnenglu.com/vczh/comments/commentRss/196079.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/vczh/services/trackbacks/196079.html</trackback:ping><description><![CDATA[<p>上一博客讲C构造符可的事情。构造完W号表之后,pq入语义分析的后一个阶D了Q构造状态机。跟我以前写<a href="http://www.shnenglu.com/vczh/archive/2008/05/22/50763.html" target="_blank">的如何实现正则表辑ּ引擎的两文?/a>讲的一P自动机先从Epsilon Nondeterministic Automaton开始,然后一步一步构造成Deterministic Automaton。但是语法分析和正则表达式有很大不同Q那么这个自动机是什么样子的呢?</p> <p>Q对学术感兴的人可以去wiki一?#8220;下推自动?#8221;Q?/p> <p>下推自动机和有限自动机的区别是,下推自动机扩展成普通的自动机的时候,他的状态的数目是无限的Q废话)。但是无限的东西是没办法用编E来表达的,那怎么办呢Q那加入一个不定长度的“状态描q?#8221;。下面我举一个简单的文法Q?/p> <p>ID = NAME<br>IDList = ID | IDList “,” ID </p> <p>q样构成了一个简单的文法Q用来分析带逗号分割的名字列表的。那么写成状态机是如下的Ş式:</p> <p>ID0 = ?NAME<br>ID1 = NAME ?br>IDList0 = ?(ID | IDList “," ID)<br>IDList1 = (ID | IDList “,” ID) ?br>IDList2 = (ID | IDList ?“,” ID)<br>IDList3 = (ID | IDList “,” ?ID)</p> <p>ID0 –> NAME –> ID1<br>IDList0 –> ID –> IDList1<br>IDList0 –> IDList –> IDList2<br>IDList2 –> “,” –> IDList3<br>IDList3 –> ID –> IDList1</p> <p>可以很容易的看出QID0和IDList0是文法的起始状态,而ID1和IDList1是文法的l结状态,L囑֦下:</p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/c1f82c9f0c3b_C745/image_4.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/c1f82c9f0c3b_C745/image_thumb_1.png" width="467" height="372"></a></p> <p>QPowerPointd复制到LiveWriter里面是一q图面简直太方便了)</p> <p>但是q样q没完。IDList0跛_IDList2的时候的输入“IDList”其实q不够,因ؓ用作输入的token其实只有NAME?,"两种。下一步即演C如何从q个状态机~程名副其实的下推状态机?/p> <p>在这里我先介l几个概c第一个是U进Q第二个是规U。ؓ什么要用这两个名字呢?因ؓ大部分h看的傻逼清华大学出版社的低能编译原理课本都是这么讲的,黑化分别叫Shift和Reduce。好了,什么是Shift呢?IDList0跛_IDList2的时候,要移qIDList。IDList3跛_IDList1Q要U进到ID。IDList0跛_IDList1也要U进到ID。这也就是说Q?strong>状态{Uȝq一条非l结W的边的时候会U进到另一条文法的状态机?/strong>。ID1和IDList1作ؓID和IDList的终l节点,要根?#8220;从那里移q来?#8221;分别规约然后跌{?#8220;IDList2或者IDList1”。这也就是说Q?strong>一旦你到达了一条闻法的状态机的终l状态,p开始规U然后蟩转到上一U的状态了</strong>?/p> <p>有h要问Q那我怎么知道规约l束的时候要跌{d里呢Q这个问题问得非常好。让我们回想一下我以前写的<a href="http://www.shnenglu.com/vczh/archive/2008/06/15/53373.html" target="_blank">如何手写语法分析?/a>q一文章。里面怎么说的Q当你手写递归下降的语法分析器的时候,每一条文法其实都是一个函数。那调用函数的时候程序怎么q道函数结束的时候下一条指令是什么呢Q那当然是因为编译器帮我们把“调用函数的时候的下一条指令的地址”lpushq了调用堆栈。但是我们现在不手写语法分析器了Q而用下推状态机来做Q道理也是一L。在“U进”的时候,先把当前的状态pushq堆栈,规约的时候,可以看一?#8220;栈顶那几个状态都是什?#8221;Q配合一ơ向前查看(q就是Look Ahead。LALR的那个LAQLALR(1)是在LA的时候偷看一个tokenQ,来决定规U到哪里厅R至于LA在这里的深刻内涵我将下一文章再说。因为现在我q没有做到Nondeterministic到Deterministic的一步,里面有很多黑U技Q我想集中讨论?/p> <p>那现在让我们把上面那q图的两个状态机qv来,产生一个下推自动机。但是在q里我先做第一步。因为IDList0到IDList1的蟩转是一个左递归的过E,先暂时不?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/c1f82c9f0c3b_C745/image_8.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/c1f82c9f0c3b_C745/image_thumb_3.png" width="671" height="372"></a></p> <p>色的边都是一个输入非l结W的跌{Q所以实际上在下推状态机里面是不存在的。在q张N面我们处理了两条ID的边。IDList0会shiftQ就是在堆栈里面pushQ自q后蟩转到ID0Q因此ID1在查看到栈顶是IDList0的时候,他就知道走的是IDList0 –> ID –> IDList1q条路,因此reduceq蟩转到了IDList1。IDList3同理?/p> <p>但是Shift的时候ƈ没有产生输入Q所以实际上应该Ҏ下面q个样子?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/c1f82c9f0c3b_C745/image_10.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/c1f82c9f0c3b_C745/image_thumb_4.png" width="618" height="372"></a></p> <p>q样Shift边也有输入了。而且ID0到ID1也废掉了。实际上ID0自己也应该废掉。现在还有一个问题没解决Q就是左递归和Reduce不生输入的问题。这两个问题实际上是一L。我们先来考虑一下ؓ什么这里没办法用相同的办法来把Reduce处理成生输入的。实际上是因为,你在q一个阶D还不知道究竟Reduce要输入什么才能蟩转,特别是token已经l束q且parseZ一个完整的IDList的时候。以前你们是不是在看《Parsing Techniques》和《龙书》都对ؓ什么一个字W串l尾要生一?字符感到很困惑呢Q实际上他是特别有用的。现在我们来l他加上大家明白了。在q里Q这个文法的目标是生一个IDListl构Q所?当然也要加在IDList的终l状态——IDList1上:</p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/c1f82c9f0c3b_C745/image_12.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/c1f82c9f0c3b_C745/image_thumb_5.png" width="674" height="372"></a></p> <p>然后p到Reduce。ID1应该是Reduce到哪里了Q第一步自然是Reduce到IDList1。那么IDList1又要Reduce到哪里呢Q我们可以看刎ͼ在IDListl束的时候,要么是跛_IDList2Q要么就是蟩到FINISH。但是IDList2是通过左递归产生的,我们先不他。蟩到FINISH需要什么条件呢Q第一个是输入$Q第二个是Pop完状态之后堆栈会为空。所以这个时候我们可以先修改一下ID1到IDList1的Reduce边:</p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/c1f82c9f0c3b_C745/image_14.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/c1f82c9f0c3b_C745/image_thumb_6.png" width="674" height="372"></a></p> <p>最后就是左递归了。左递归的处理有点像hackQ因为实际上你不能预先判断你要不要左递归Q也是看一下token stream有多个逗号Q,然后先shift几个IDList0q去Q再慢慢来。所以我们只有在满跌{关系的时候时插入一些IDList0。那么这个关pL什么呢Q左递归的IDListl束——也是从IDList0跛_IDList2——之后只有一U可能,是输入","。而且所有指向IDList1的边都是输入IDQ所以这条左递归的线应该从ID1QID的终l状态)q到IDList2Qƈ且在链接的时候补?#8220;假shift IDList0”Q?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/c1f82c9f0c3b_C745/image_31.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/c1f82c9f0c3b_C745/image_thumb_14.png" width="674" height="424"></a></p> <p>色的两个状态分别是整个parsingq程的v始状态和l结状态。这个时候我们把所有没用的边和状态都q掉Q就变成了:</p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/c1f82c9f0c3b_C745/image_33.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/c1f82c9f0c3b_C745/image_thumb_15.png" width="674" height="362"></a></p> <p>是不是觉得特别亲切呢Q这不就是正则表辑ּNAME ( “,” NAME)*的状态机吗?q也是因个文法刚好可以表达ؓ一个正则文法才有这Ll果Q如果我们给他加点儿括号改变点优先什么的Q那׃变成一个复杂得多的状态机了。好了。现在我们来模拟一下下推状态机的状态{换和堆栈操作q程Q来分析一下A,B,C$q个输入吧?/p> <p>在下面的标示N面,我们用s|abc|def来分别表辑ֽ前状态s、当前堆栈里的状态abcQ栈在双Q和正在{待的输入def。那么初始状态肯定就?br>IDList0 | null | A,B,C$</p> <p>然后开始了Q(用文字表辑֮在是太难看了Q所以脓成图Q?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/c1f82c9f0c3b_C745/image_35.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/vczh/Windows-Live-Writer/c1f82c9f0c3b_C745/image_thumb_16.png" width="675" height="500"></a></p> <p>如果成功到达FINISHq且堆栈和输入都全部没有了的话,那就证明Qparsingq程完美l束Q没有Q何错误发生?/p> <p>如何从文法生成下推自动机q完成parsing工作的大概过E就写到q里了。目前开发进度是?#8220;生成非确定性下推自动机”q里。当我完成了生成“定性下推自动机”——也是上面的最后一个状态机囄时候——就会开始写下一文章,讲面对复杂的文法的时候,下推自动机将要如何调整。同时将重点描述Look Ahead部分Q以及ؓ什么LALR(1)要设计成那个样子?/p> <img src ="http://www.shnenglu.com/vczh/aggbug/196079.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/vczh/" target="_blank">陈梓?vczh)</a> 2012-12-07 16:43 <a href="http://www.shnenglu.com/vczh/archive/2012/12/07/196079.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>可配|语法分析器开发纪事(二)&mdash;&mdash;构造符可http://www.shnenglu.com/vczh/archive/2012/11/29/195779.html陈梓?vczh)陈梓?vczh)Wed, 28 Nov 2012 16:50:00 GMThttp://www.shnenglu.com/vczh/archive/2012/11/29/195779.htmlhttp://www.shnenglu.com/vczh/comments/195779.htmlhttp://www.shnenglu.com/vczh/archive/2012/11/29/195779.html#Feedback6http://www.shnenglu.com/vczh/comments/commentRss/195779.htmlhttp://www.shnenglu.com/vczh/services/trackbacks/195779.html上一博客讲C构造语法树的问题。有朋友在留a问我Qؓ什么一定要让语法分析器产生语法树,而不是让用户自己军_要怎么办呢Q在q里我先解答q个问题?/p>

1、大部分情况下都是真的需要有语法?br>2、如果要直接q回计算l果之类的事情的话,只需要写一个visitorq行一下语法树好了,除去自动生成的代码以外(反正q不用h写,不计入代PQ代码量基本上没什么区?br>3、加入语法树可以让文法本w描qv来更单,如果要让E序员把文法单独攑֜一边,然后自己写完整的语义函数来让他生成语法树的话Q会让大部分情况Q需要语法树Q变得特别复杂,而少数情况(不需要语法树Q又没有获得什么好处?/p>

管cMyaccq样的东西的是不包含语法树的内容而要你自己写的,但是用v来难道不是很隑֏吗?

现在转入正题。这一文章讲的主要是构造符可的问题。想要把W号表构造的好是一件很ȝ的问题。我曄试q很多种ҎQ包括强cd的符可Q弱cd的符可Q基于map的符可{等Q最后还是挑选了跟Visual Studio自带的用来读pdb文g的DIAcd中的IDIASymbolQ?a title="http://msdn.microsoft.com/en-us/library/w0edf0x4.aspx" target="_blank">http://msdn.microsoft.com/en-us/library/w0edf0x4.aspxQ基本上一Ll构Q所有的W号都只有这么一个symbolc,然后包罗万象Q什么都有。ؓ什么最后选择q么做呢Q因为在做语义分析的时候,其实做的最多的事情不是构造符可Q而是查询W号表。如果符可是强cd的画Q譬如说cd要一个类Q变量要一个类Q函数要一个类之类的,L需要到处cast来cast去,也找不到什么好Ҏ来在完成相同事情的情况下Q保留强cd而不在代码里面出现cast。ؓ什么语法树p用visitor来解册个问题,而符可׃行呢Q因为通常我们在处理语法树的时候都是递归的Ş式,而符可q不是。在一个上下文里面Q实际上我们是知道那个symbol对象I竟是什么东西的Q譬如说我们查询了一个变量的typeQ那q返回D定只能是type了)。这个时候我们要cast才能用,本n也只是浪费表情而已。这个时候,visitor模式׃是和面对q种情况了。如果硬要用visitor模式来写Q会D语义分析的代码分散得q于谱D可读性几乎就丧失了。这是一个辩证的问题Q大家可以好好体会体会?/p>

说了q么一大段Q实际上是怎么样呢Q让我们来看“文法规则”本n的符可吧。既然这个新的可配置语法分析器也是通过parse一个文本Ş式的文法规则来生成parserQ那实际上就跟编译器一栯l历那么多阶D,其中肯定有符可Q?/p>

class ParsingSymbol : public Object
{
public:
    enum SymbolType
    {
        Global,
        EnumType,
        ClassType,        // descriptor == base type
        ArrayType,        // descriptor == element type
        TokenType,
        EnumItem,        // descriptor == parent
        ClassField,        // descriptor == field type
        TokenDef,        // descriptor == token type
        RuleDef,        // descriptor == rule type
    };
public:
    ~ParsingSymbol();

    ParsingSymbolManager*            GetManager();
    SymbolType                        GetType();
    const WString&                    GetName();
    vint                            GetSubSymbolCount();
    ParsingSymbol*                    GetSubSymbol(vint index);
    ParsingSymbol*                    GetSubSymbolByName(const WString& name);
    ParsingSymbol*                    GetDescriptorSymbol();
    ParsingSymbol*                    GetParentSymbol();
    bool                            IsType();
    ParsingSymbol*                    SearchClassSubSymbol(const WString& name);
    ParsingSymbol*                    SearchCommonBaseClass(ParsingSymbol* classType);
};

因ؓ文法规则本n的东西也不多Q所以这里的symbol只能是上面记载的9U对象。这些对象其实特别的怼Q所以我们可以看出唯一的区别就是当GetTypeq回g一L时候,GetDescriptorSymbolq回的对象的意思也不一栗而这个区别记载在了enum SymbolType的注释里面。实际上q种做法在面对超U复杂的W号表(考虑一下C++~译器)的时候ƈ不太好。那好的做法I竟是什么呢Q看上面IDIASymbol的链接,那就是答案?/p>

不可否认Q微软设计出来的API大部分还是很有道理的Q除了Win32的原生GUI部分?/p>

我们q可以看刎ͼq个ParsingSymbolcȝ几乎所有成员函数都是用来查询这个Symbol的内容的。这里还有两个特D的函数Q就是SearchClassSubSymbol和SearchCommonBaseClass——当且仅当symbol是ClassType的时候才起作用。ؓ什么有了GetSubSymbolByNameQ还要这两个api呢?因ؓ我们在搜索一个类的成员的时候,是要搜烦他的父类的。而一个类的父cȝsub symbolq不是类自己的sub symbolQ所以就有了q两个api。所谓的sub symbol的意思现在也很明了了。enumcd里面的值就是enum的sub symbolQ成员变量是cȝsub symbolQM只要是声明在一个符号内部的W号都是q个W号的sub symbol。这是所有符号都有的共性?/p>

当然Q有了ParsingSymbolQ还要有他的manager才可以完成整个符可的操作:

class ParsingSymbolManager : public Object
{
public:
    ParsingSymbolManager();
    ~ParsingSymbolManager();

    ParsingSymbol*                    GetGlobal();
    ParsingSymbol*                    GetTokenType();
    ParsingSymbol*                    GetArrayType(ParsingSymbol* elementType);

    ParsingSymbol*                    AddClass(const WString& name, ParsingSymbol* baseType, ParsingSymbol* parentType=0);
    ParsingSymbol*                    AddField(const WString& name, ParsingSymbol* classType, ParsingSymbol* fieldType);
    ParsingSymbol*                    AddEnum(const WString& name, ParsingSymbol* parentType=0);
    ParsingSymbol*                    AddEnumItem(const WString& name, ParsingSymbol* enumType);
    ParsingSymbol*                    AddTokenDefinition(const WString& name);
    ParsingSymbol*                    AddRuleDefinition(const WString& name, ParsingSymbol* ruleType);

    ParsingSymbol*                    CacheGetType(definitions::ParsingDefinitionType* type, ParsingSymbol* scope);
    bool                            CacheSetType(definitions::ParsingDefinitionType* type, ParsingSymbol* scope, ParsingSymbol* symbol);
    ParsingSymbol*                    CacheGetSymbol(definitions::ParsingDefinitionGrammar* grammar);
    bool                            CacheSetSymbol(definitions::ParsingDefinitionGrammar* grammar, ParsingSymbol* symbol);
    ParsingSymbol*                    CacheGetType(definitions::ParsingDefinitionGrammar* grammar);
    bool                            CacheSetType(definitions::ParsingDefinitionGrammar* grammar, ParsingSymbol* type);
};

q个ParsingSymbolManager有着W号表管理器的以下两个典型作?/p>

1、创建符受?br>2、讲W号与语法树的对象绑定v来。譬如说我们在一个context下面推导了一个expression的类型,那下ơ对于同Lcontext同样的expression׃需要再推导一ơ了Q语义分析有很多个passQ对同一个expression求类型的操作l常会重复很多次Q,把它cache下来可以了?br>3、搜索符受具体到q个W号表,q个功能被做q了ParsingSymbol里面?br>4、保存根节点。GetGlobal函数是q这个作用的。所有的根符号都属于globalW号的sub symbol?/p>

因此我们可以怎么使用他呢Q首先看上面的Add函数。这些函C仅会帮你在一个符可里面d一个sub symbolQ还会替你做一些检查,譬如说阻止你d相同名字的sub symbol之类的。语法树很复杂的时候,很多时候我们有很多不同的方法来l一个符h加子W号Q譬如说C#的成员变量和成员函数。成员变量不能同名,成员函数可以Q但是成员函数和成员变量却不能同名。这个时候我们就需要把q些d操作装hQ这h可以在处理语法树Q声明一个函数的Ҏ可以有很多,所以添加函数符L地方也可以有很多Q的时候不需要重复写验证逻辑?/p>

其次是Cache函数。其实Cache函数q么写,不是用来直接调用的。D个例子,在分析一个文法的时候,我们需要把一?#8220;cd”语法树{成一?#8220;cd”W号Q譬如说要决定一个文法要create什么类型的语法树节点的时候)。因此就有了下面的函敎ͼ

ParsingSymbol* FindType(Ptr<definitions::ParsingDefinitionType> type, ParsingSymbolManager* manager, ParsingSymbol* scope, collections::List<Ptr<ParsingError>>& errors)
{
    ParsingSymbol* result=manager->CacheGetType(type.Obj(), scope);
    if(!result)
    {
        FindTypeVisitor visitor(manager, (scope?scope:manager->GetGlobal()), errors);
        type->Accept(&visitor);
        result=visitor.result;
        manager->CacheSetType(type.Obj(), scope, result);
    }
    return result;
}

很明显,q个函数做的事情是Q查询一个ParsingDefinitionType节点有没有被查询q,如果有直接用cacheQ没有的话再从头计算他然后cacheh。因此这些Cache函数是l类似FindType的函数用的,而语义分析的代码则直接用FindTypeQ而不是Cache函数Q来获取一个类型的W号。聪明的朋友们可以看出来Q这U写法蕴含着一个条Ӟ是语法树创建完׃会改了(废话Q当然不会改Q)?/p>

q一的内容p到这里了。现在的q度是正在写文法生成状态机的算法。下一文章应该讲的就是状态机I竟是怎么q作的了。文法所需要的状态机叫做下推状态机Qpush down automatonQ,跟regex用的NFA和DFA不太一P理解h略有隑ֺ。所以我想需要用单独的一文章来通俗的讲一讌Ӏ?/p>

陈梓?vczh) 2012-11-29 00:50 发表评论
]]>
可配|语法分析器开发纪事(一Q?amp;mdash;&mdash;构造语法树http://www.shnenglu.com/vczh/archive/2012/11/21/195503.html陈梓?vczh)陈梓?vczh)Wed, 21 Nov 2012 14:42:00 GMThttp://www.shnenglu.com/vczh/archive/2012/11/21/195503.htmlhttp://www.shnenglu.com/vczh/comments/195503.htmlhttp://www.shnenglu.com/vczh/archive/2012/11/21/195503.html#Feedback5http://www.shnenglu.com/vczh/comments/commentRss/195503.htmlhttp://www.shnenglu.com/vczh/services/trackbacks/195503.html之前的博客文?/a>所说的Q(主要q是Q因?a target="_blank">GacUI的原因,我决定开发一个更好的可配|轻量语法分析器来代替之前的落后的版本。在说这个文章之前,我还是想在此向大家推荐一本《编E语a实现模式》,q的是一本好书,让我相见恨晚?/p>

其实说到开发语法分析器Q我?007q就已经开始在思考类似的问题了。当时C++q处于用的不太熟l的时候,隑օ会做Z些傻逼的事情Q不qȝ来说当年的ideaq是能用的。从那时候开始,我ؓ了锻D己,一直在实现各种不同的语a。所以给自己开发一个可配置语法分析器也是在所隑օ的事情了。于是就有:
W一版:http://hi.baidu.com/geniusvczh/archive/tag/syngram%E6%97%A5%E5%BF%97
W二版:http://www.shnenglu.com/vczh/archive/2009/04/06/79122.html
W三版:http://www.shnenglu.com/vczh/archive/2009/12/13/103101.html
q有W三版的教程Q?a title="http://www.shnenglu.com/vczh/archive/2010/04/28/113836.html" href="http://www.shnenglu.com/vczh/archive/2010/04/28/113836.html">http://www.shnenglu.com/vczh/archive/2010/04/28/113836.html

上面的所有分析器都致力于在C++里面可以通过直接描述文法和一些语义行为来让系l可以迅速构造出一个针对特定目的的用v来方便的语法分析器,而“第三版”就是到目前为止q在用的一个版本。至于ؓ什么我要做一个新的——也是W四版—?a href="http://www.shnenglu.com/vczh/archive/2012/10/30/194052.html" target="_blank">之前的文?/a>已经说了?/p>

而今天,W四版的开发已l开始了有好几天。如果大家关心进度的话,可以?a target="_blank">GacUI的Codeplex面下蝲代码Q然后阅读Common\Source\Parsing下面的源文g。对应的单元试可以在Common\UnitTest\UnitTest\TestParsing.cpp里找到?/p>

于是今天p说关于构造语法树的事情?/p>

用C++写过parser的h都知道,构造语法树以及语义分析用的W号表是一件极其繁琐,而且一不小心就Ҏ写出的事情。但是根据我写过无穷多棵语法树以及构造过无穷多个W号表以及附带的副作用,,啊不Q经验,做这个事情还是有一些方法的?/p>

在介l这个方法之前,首先要说一句,做完下面的所有事情是肯定要疯掉的Q所以这一ơ的可配|语法分析器我已l决定了一定要TMD写出一个生成语法树的C++代码的工兗?/p>

一颗语法树Q其实就是一大堆互相l承的类。一切成熟的语法树结构所h的共同特征,不是他的成员怎么安排Q而是他一定会附带一?a target="_blank">visitor模式的机制。至于什么是visitor模式Q大家请自行参考设计模式,我就不多说废话了。这一ơ的可配|语法分析器是带有一个描q性语法的。也是_跟Antlr或者Yacc一P首先在一个文本文仉面准备好语法树结构和文法规则Q然后我的工具会帮你生成一个内存中的语法分析器Q以及用C++描述的语法树的声明和实现文g。这个描q性语法就cM下面的这个大家熟悉到不能再熟悉的带函数的四则q算表达式结构:

class Expression
{
}

class NumberExpression : Expression
{
    token value;
}

class BinaryExpression : Expression
{
    enum BinaryOperator
    {
        Add,
        Sub,
        Mul,
        Div,
    }

    Expression firstOperand;
    Expression secondOperand;
    BinaryOperator binaryOperator;
}

class FunctionExpression : Expression
{
    token functionName;
    Expression[] arguments;
}

token NAME = "[a-zA-Z_]/w*";
token NUMBER = "/d+(./d+)";
token ADD = "/+";
token SUB = "-";
token MUL = "/*";
token DIV = "http://";
token LEFT = "/(";
token RIGHT = "/)";
token COMMA = ",";

rule NumberExpression Number
        = NUMBER : value;

rule FunctionExpression Call
        = NAME : functionName "(" [ Exp : arguments { "," Exp : arguments } ] ")";

rule Expression Factor
        = !Number | !Call;

rule Expression Term
        = !Factor;
        = Term : firstOperand "*" Factory : secondOperand as BinaryExpression with { binaryOperator = "Mul" };
        = Term : firstOperand "/" Factory : secondOperand as BinaryExpression with { binaryOperator = "Div" };

rule Expression Exp
        = !Term;
        = Exp : firstOperand "+" Term : secondOperand as BinaryExpression with { binaryOperator = "Add" };
        = Exp : firstOperand "-" Term : secondOperand as BinaryExpression with { binaryOperator = "Sub" };

上面的语法树声明借用的C#语法Q描qv来特别简单。但是要在C++里面辑ֈ可以使用的程度,肯定要有一个自带的visitor模式。所以出来之后的代码大概qg下面q个样子Q?/p>

class Expression;
class NumberExpression;
class BinaryExpression;
class FunctionExpression;

class Expression : public ParsingTreeCustomBase
{
public:
    class IVisitor : public Interface
    {
    public:
        virtual void Visit(NumberExpression* node)=0;
        virtual void Visit(BinaryExpression* node)=0;
        virtual void Visit(FunctionExpression* node)=0;
    };

    virtual void Accept(IVisitor* visitor)=0;
};

class NumberExpression : public Expression
{
public:
    TokenValue value;

    void Accept(IVisitor* visitor){visitor->Visit(this);}
};

class BinaryExpression : public Expression
{
public:
    enum BinaryOperator
    {
        Add, Sub, Mul, Div,
    };
    Ptr<Expression> firstOperator;
    Ptr<Expression> secondOperator;
    BinaryOperator binaryOperator;

    void Accept(IVisitor* visitor){visitor->Visit(this);}
};

class FunctionExpression : public Expression
{
public:
    TokenValue functionName;
    List<Ptr<Expression>> arguments;

    void Accept(IVisitor* visitor){visitor->Visit(this);}
};

Z么要q样做呢Q学习过面向对象开发方法的都知道,把一个明显是l承l构的东西写成一堆union/struct和一个enum来判断他们,是不对的。第一个不好的地方是Q如果其中的成员需要构造函数和析构函数Q那unionq不了了,struct׃定会造成大量的内存浪贏V因Z颗语法树是可以很大的。其ơ,当语法树的结构(主要是添加删除了新的语法树类型)之后Q我们根本不可能保证我们所有的swtich(node->enumType)语句都接受到了正的更新?/p>

那要如何解决q两个问题呢Q答案之一是使用visitor模式。尽刚开始写h的时候可能会有点别扭Q但是我们只要把原本是swtichl构的代码做一?a target="_blank">Continuation Passing Style变换Q就可以写出使用visitor的版本了。在q里我做一个小的演示Q如何把一个“把上面的语法树q原成四则运式子的函数”给用Expression::IVisitor的框架下实现出来Q?/p>

class FunctionExpression : public Expression
{
public:
    TokenValue functionName;
    List<Ptr<Expression>> arguments;

    void Accept(IVisitor* visitor){visitor->Visit(this);}
};

class ExpressionPrinter : public Expression::IVisitor
{
public:
    WString result;

    void Visit(NumberExpression* node)
    {
        result+=node->value.stringValue;
    }

    void Visit(BinaryExpression* node)
    {
        result+=L"(";
        node->firstOperand->Accept(this);
        switch(binaryOperator)
        {
        case Add: result+=L" + "; break;
        case Sub: result+=L" - "; break;
        case Mul: result+=L" * "; break;
        case Div: result+=L" / "; break;
        }
        node->secondOperand->Accept(this);
        result+=L")";
    }

    void Visit(FunctionExpression* node)
    {
        result+=node->functionName.stringValue+L"(";
        for(int i=0;i<arguments.Count();i++)
        {
            if(i>0) result+=L", ";
            arguments[i]->Accept(this);
        }
        result+=L")";
    }
};

WString PrintExpression(Ptr<Expression> expression)
{
    ExpressionPrinter printer;
    expression->Accept(&printer);
    return printer.result;
}

其实大家可以看到Q用了visitor模式Q代码量其实也没有多大变化,本来是递归的地方还是递归Q本来该计算什么还计算什么,唯一不同的就是原本这个“函数”的参数和返回值都跑到了一个visitorcȝ成员变量里面M。当ӞZ便于使用Q一般来说我们会把原本的函数的原型写出来Qƈ且在里面调用visitor模式Q就像上面的PrintExpression函数一栗如果我们高兴的话,完全可以在ExpressionPrinterq个visitorc里面用PrintExpressionQ无非就是在里面构造新的ExpressionPrinter然后获取l构|了。一般来_visitorc都是非常的轻量U的Q在C的CPU性能下面Q构造多几个完全不会带来多大影响?/p>

可配|语法分析器既然拥有一个描q性语法,那么我肯定也针对q个描述性语法写了一颗语法树的。这颗语法树的代码在Common\Source\Parsing\ParsingDefinition.h里面Q而ParsingLogging.cpp则是跟上面说的一P用visitor的方法写了一个庞大的把语法树转回描述性语法的函数。这个函数非常有用,不仅可以用来打logQ还可以用来保存E序生成的一个语法规则(反正可以parse回来Q所以保存成文本是一件特别方便的事情Q,甚至是生成错误消息的片段{等?/p>

今天先讲到q里了。现在的可配|语法分析器的开发进度是正在写语义分析的部分。等到语义分析写完了Q我会再写一纪事来说明开发语义分析程序和构造符可的一般做法?/p>

陈梓?vczh) 2012-11-21 22:42 发表评论
]]>
C++使用Uniscribeq行文字自动换行的计和渲染http://www.shnenglu.com/vczh/archive/2012/11/06/194817.html陈梓?vczh)陈梓?vczh)Tue, 06 Nov 2012 14:34:00 GMThttp://www.shnenglu.com/vczh/archive/2012/11/06/194817.htmlhttp://www.shnenglu.com/vczh/comments/194817.htmlhttp://www.shnenglu.com/vczh/archive/2012/11/06/194817.html#Feedback4http://www.shnenglu.com/vczh/comments/commentRss/194817.htmlhttp://www.shnenglu.com/vczh/services/trackbacks/194817.html阅读全文

陈梓?vczh) 2012-11-06 22:34 发表评论
]]>
又到了一q一度重构通用可配|语法分析器的时候了http://www.shnenglu.com/vczh/archive/2012/10/30/194052.html陈梓?vczh)陈梓?vczh)Mon, 29 Oct 2012 16:23:00 GMThttp://www.shnenglu.com/vczh/archive/2012/10/30/194052.htmlhttp://www.shnenglu.com/vczh/comments/194052.htmlhttp://www.shnenglu.com/vczh/archive/2012/10/30/194052.html#Feedback6http://www.shnenglu.com/vczh/comments/commentRss/194052.htmlhttp://www.shnenglu.com/vczh/services/trackbacks/194052.html因ؓGacUI需要实C个文本描q的H口描述格式Q再加上C++l常需要处理xml和json{常用数据结构,q有自己q要时不时开发一些语a来玩一玩之cȝ理由Q每一ơ遇到自q技术革新的时候,L免不了要对可配置语法分析器做Z攏V上一个版本的可配|语法分析器可以见之前的博客文章?strong>Vczh Library++ 语法分析器开发指?/a>》?/p>

Z么要重写vlpp的这一部分呢?因ؓl过多次可配|语法分析器的开发,我感觉到了C++直接用来表达文法有很多弱点:

1、C++自n的类型系l导致表辑և来的文法会有很多噪音。当然这q不是C++的错Q而是通用的语a做这U事情L会有点噪音的。无论是?a target="_blank">Monadic Parser Combinators using C# 3.0》也好,我大微Y研究院的ZHaskell?a target="_blank">Parsec也好Q还是boost?a target="_blank">spirit也好Q甚xF#?a target="_blank">Fsyacc也好Q都在展CZparser combinatorq个强大的概늚同时Q也暴露Zparser combinator的弱点:在语法分析结果和语言的数据结构的l合斚w特别的麻烦。这里的ȝ不仅在于会给文法造成很多噪音Q而且复杂的parserq会使得你的l构特别的臃肿(参考Antlr的某些复杂的应用Q这里就不一一列D了)?/p>

2、难以维护。如果直接用C++描述一个强cd文法的话Q势必是要借助parser combinatorq个概念的。概忉|w是很厉害的Q而且实现的好的话开发效率会特别的高。但是对于C++q种非函数式语言来说Qparser combinatorq种特别函数式的描述攑֜C++里面׃多出很多ȝQ譬如闭包的语法不够漂亮啦、没有垃圾收集器的问题导致rule与rule的@环引用问题还要自行处理啦Q在很早以前的一博客论证过了,只要是带完整闭包功能的语aQ都一定不能是用引用计数来处理内存Q而必要一个垃圾收集器的)。尽我一直以来都q是没做q方面的bugQ但是由于(主要是用来处理何时应该delete对象部分的)逻辑复杂Q导致数据结构必Mؓdelete对象的部分让步,代码l护h也相当的蛋疼?/p>

3、有些优化无法做。D个简单的例子Qparser combinator根本没办法处理左递归。没有左递归Q写h些文法来也是特别的蛋疹{还有合q共同前~{等的优化也不能做,q导致我们必Mؓ了性能牺牲本来已l充满了噪音的文法的表达Q{而h工作文法的共同前~合ƈQ文法看h更׃?/p>

当然上面三个理由看v来好像不太直观,那我׃D一个典型的例子。大家应该还记得我以前写q一个叫?a href="http://www.shnenglu.com/vczh/archive/2011/03/20/142261.html" target="_blank">NativeX的语aQ还l它做了一?a href="http://www.shnenglu.com/vczh/archive/2011/02/25/140618.html" target="_blank">带智能提C的~辑?/a>Q还?a href="http://www.shnenglu.com/vczh/archive/2010/11/07/132876.html" target="_blank">q里?a href="http://www.shnenglu.com/vczh/archive/2010/12/05/135505.html" target="_blank">q里Q。NativeX是一个C++实现的C+template+concept mapping的语aQ语法分析器当然是用上一个版本的可配|语法分析器来做的。文法规则很复杂Q但是被C++q么以表达,更加复杂了Q?a target="_blank">.\Library\Scripting\Languages\NativeX\NativeXParser.cppQ,已经C不仔l看无法维护的地步了?/p>

lg所qͼ做一个新的可配置语法分析器出来理由充分,势在必得。但是Ş式上是什么样子的呢?上面说过我以前给NativeX写过一个带提示的编辑器。这个编辑器用的是WinFormQ那当然也是用C#写的Q因此那个对性能要求高到谱的NativeX~辑器用的语法分析器当然也是用C#写的。流E大概如下:
1、用C#按照要求声明语法树结?br>2、用我的库用C#写一个文?br>3、我的库会执行这个文法,生成一大段C#写的{h的递归下降语法分析器的代码
当时我把q个q程记录在了q篇博客文章里面?/p>

因此现在有一个计划,q个新的可配|语法分析器当然q是要完全用C++Q但是这p正则表达式一P
1、首先语法树l构和文法都声明在一个字W串里面
2、可配置语法分析器可以在内存中动态执行这D|法,q按照给定的语法树结构给Z个在内存中的动态的数据l构
3、可配置语法分析器当然还要附带一个命令行工具Q用来读文法生成C++代码Q包括自带Visitor模式的语法树l构Q和C++写的递归下降语法分析?/p>

所以现在就有一个草E,是那个“声明在字符串里面”的语法树结构和文法的说明。这是一个很有意思的q程?/p>

首先Q这个可配置语法分析器需要在内存中表达语法树l构Q和一个可以执行然后生动态数据结构的文法。因此我们在使用它的时候,可以选择直接在内存中堆出语法树结构和文法的描qͼ而不是非得用那个字符串的表达形式。当Ӟ字符串的表达形式肯定是十分紧凑的Q但q不是必ȝQ只是推荐的?/p>

其次Qparseq个“语法树l构和文法都声明”当然也需要一个语法分析器是不是?所以我们可以用上面的方法,通过直接在内存中堆出文法来用自己构造出一个自q语法分析器?/p>

再者,有了一个内存中的语法分析器之后Q我可以将上面W三步的命o行工具做出来Q然后用它来描述自己的文法,产生ZDC++写的递归下降语法分析器,用来分析“语法树l构和文法都声明”,然后有了一对C++代码文g?/p>

最后,把生出来的q对C++代码文g加进去,我们有了一个C++直接写,而不是在内存中动态构造出来的“语法树l构和文法都声明”的分析器了。然后这个分析器可以替换掉命o行工具里面那个原先动态构造出来的语法分析器。当焉个动态构造出来的语法分析器这个时候已l没用了Q因为有了生成的C++语法分析器,我们可以直接用“语法树l构和文法都声明”来描述自己Q得到这么一个描q的字符Ԍ然后随时都可以用q个字符串来动态生成语法分析器了?/p>

总而言之就?br>1、实现可配置语法分析器,可以直接用数据结构做Z个生动态数据结构的parser combinatorQ记为PC?br>2、用PC做一个“语法树l构和文法都声明”的语法分析器。这个“语法树l构和文法都声明”记为PC Grammar?br>3、PC Grammar当然可以用来表达PC Grammar自己Q这h们就得到了一个专门用来说明什么是合法的“语法树l构和文法都声明”的描述的字W串的这么个文法Q记为PC Grammar Syntax Definition?br>4、通过q䆾满PC Grammar要求的PC Grammar Syntax DefinitionQ我们就可以用PC来解释PC Grammar Syntax DefinitionQ动态生一个解释PC Grammar的语法分析器
5、有了PC Grammar的语法分析器PC Grammar Parser (in memory version)Q之后我们就可以把“文?>C++代码”的代码生成器做出来Q称之ؓPC Grammar C++ Codegen?br>6、有了PC Grammar C++ CodegenQ我们就可以用他dPC Grammar Syntax DefinitionQ生一个直接用C++写的PC Grammar的语法分析器Q叫做PC Grammar Parser (C++ version)?/p>

到此为止Q我们获得的东西?br>1、PC QParser CombinatorQ?br>2、PC Grammar
3、PC Grammar Syntax Definition
4、PC Grammar Parser (in memory version)
5、PC Grammar Parser (C++ version)
6、PC Grammar C++ Codegen

其中Q?????都是可以执行的,2是一个“标准”。到了这一步,我们可以用PC Grammar Parser (C++ version)来替换掉PC Grammar C++ Codegen里面的PC Grammar Parser (in memory version)了。这pgcc要编译一个小~译器来~译自己得到一个完整的gcc一栗这个过E还可以用来试PC Grammar C++ Codegen是否写的_好?/p>

那么“语法树l构和文法都声明”到地是什么样子的呢?我这里给Z个简单的文法Q就是用来parse诸如int、vl::collections::List<WString>、int*、int&、int[]、void(int, WString, double*)的这些类型的字符串了。下面首先展C如何用q个描述来解决上面的“类型”的语法书声明:

class Type{}

class DecoratedType : Type
{
    enum Decoration
    {
        Pointer,
        Reference,
        Array,
    }
    Decoration        decoration;
    Type            elementType;
}

class PrimitiveType : Type
{
    token            name;
}

class GenericType : Type
{
    Type            type;
    Type[]            arguments;
}

class SubType : Type
{
    Type            type;
    token            name;
}

class FunctionType : Type
{
    Type            returnType;
    Type[]            arguments;
}

然后是声明语法分析器所需要的词法元素Q用正则表达式来描述Q?/p>

token SYMBOL        = <|>|\[|\]|\(|\)|,|::|\*|&
token NAME            = [a-zA-Z_]\w*

q里只需要两Utoken可以了。接下来是两种{h的对于这个文法的描述Q用来展C全部的功能?/p>

========================================================

Type SubableType    = NAME[name] as PrimitiveType
                    = SubableType[type] '<' Type[arguments] { ',' Type[arguments] } '>' as GenericType
                    = SubableType[type] '::' NAME[name] as SubType

Type Type            = @SubableType
                    = Type[elementType](
                            ( '*' {decoration = DecoratedType::Pointer}
                            | '&' {decoration = DecoratedType::Reference}
                            | '[' ']' {decoration = ecoratedType::Array}
                            )
                        ) as DecoratedType
                    = Type[returnType] '(' Type[arguments] { ',' Type[arguments] } ')' as FunctionType

========================================================

rule PrimitiveType    PrimitiveType    = NAME[name]
rule GenericType    GenericType        = SubableType[type] '<' Type[arguments] { ',' Type[arguments] } '>'
rule SubType        SubType            = SubableType[type] :: NAME[name]
rule Type            SubableType        = @PrimitiveType | @GenericType | @SubType

rule DecoratedType    DecoratedType    = Type[elementType] '*' {decoration = DecoratedType::Pointer}
                                    = Type[elementType] '&' {decoration = DecoratedType::Reference}
                                    = Type[elementType] '[' ']' {decoration = DecoratedType::Array}
rule FunctionType    FunctionType    = Type[returnType] '(' Type[arguments] { ',' Type[arguments] } ')'
rule Type            Type            = @SubableType | @DecoratedType | @FunctionType

========================================================

如果整套pȝ开发出来的话,那么我就会提供一个叫做ParserGen.exe的命令行工具Q把上面的字W串转换Z?strong>可读的、等价与q段文法的、用递归下降Ҏ来描q的、C++写出来的语法分析器和语法树声明了?/p>

陈梓?vczh) 2012-10-30 00:23 发表评论
]]>
使用C++和Windows API操作Zhttp协议的xml servicehttp://www.shnenglu.com/vczh/archive/2012/10/27/193945.html陈梓?vczh)陈梓?vczh)Sat, 27 Oct 2012 07:19:00 GMThttp://www.shnenglu.com/vczh/archive/2012/10/27/193945.htmlhttp://www.shnenglu.com/vczh/comments/193945.htmlhttp://www.shnenglu.com/vczh/archive/2012/10/27/193945.html#Feedback1http://www.shnenglu.com/vczh/comments/commentRss/193945.htmlhttp://www.shnenglu.com/vczh/services/trackbacks/193945.html在S1ȝ@kula的鼓׃Q我开始用kula提供的api来操作那个傻逼的“鸟窝”|站Q?a style="color: ; text-decoration: underline" target="_blank">https://www.niaowo.meQ。不q由于我自己在业余时间写的程序都喜欢用C++和Windows APIQ因此我琢磨了几天,真的让我用C++l写了出来?/p>

我写了一个HttpUtility库来实现C++操作http/https服务的功能,q䆾代码可以在这里获得:

HttpUtility.hQ?a style="color: ; text-decoration: underline" target="_blank">http://gac.codeplex.com/SourceControl/changeset/view/95641#2295555
HttpUtility.cppQ?a title="http://gac.codeplex.com/SourceControl/changeset/view/95641#2295554" style="color: ; text-decoration: underline" target="_blank">http://gac.codeplex.com/SourceControl/changeset/view/95641#2295554

使用的时候很单,只需要HttpRequest里面填满了参敎ͼ然后可以用HttpQuery参数获得一个HttpResponsecdQ这个类型里面写满了http服务器的q回倹{返回内容和cookie{的数据。譬如说用来post来登陆鸟H,然后拿到cookie之后查询首页的所有帖子,大概可以这么写Q?/p>

WString NestleGetSession(const WString& username, const WString& password, const WString& apiKey, const WString& apiSecret)
{
    WString body=L"api_key="+apiKey+L"&api_secret="+apiSecret+L"&username="+username+L"&password="+password;

    HttpRequest request;
    HttpResponse response;

    request.SetHost(L"https://www.niaowo.me/account/token/");
    request.method=L"POST";
    request.contentType=L"application/x-www-form-urlencoded";
    request.SetBodyUtf8(body);
    HttpQuery(request, response);

    if(response.statusCode==200)
    {
        return response.cookie;
    }
    else
    {
        return L"";
    }
}

WString NestleGetXml(const WString& path, const WString& cookie)
{
    HttpRequest request;
    HttpResponse response;

    request.SetHost(L"https://www.niaowo.me"+path+L".xml");
    request.method=L"GET";
    request.cookie=cookie;
    request.acceptTypes.Add(L"application/xml");
    HttpQuery(request, response);
   

    if(response.statusCode==200)
    {
        return response.GetBodyUtf8();
    }
    else
    {
        return L"";
    }
}

于是我们l于获得了一个保存在vl::WString的xml字符串了Q那怎么办呢Q这个时候需要出动IXMLDOMDocument2来解析我们的xml。只要装了IE的计机上都是有IXMLDOMDocument2的,而不装IE的Windows PC是不存在的,因此我们L可以大胆的用。当Ӟ用IXMLDOMDocument直接来遍历什么东西特别的慢,所以我们需要的是xpath。xpath对于xmlpregex对于字符串一P可以直接查询出我们要的东ѝ首先看一下如何操作IXMLDOMDocument2接口Q?/p>

IXMLDOMNodeList* XmlQuery(IXMLDOMNode* pDom, const WString& xpath)
{
    IXMLDOMNodeList* nodes=0;
    BSTR xmlQuery=SysAllocString(xpath.Buffer());
    if(xmlQuery)
    {
        HRESULT hr=pDom->selectNodes(xmlQuery, &nodes);
        if(FAILED(hr))
        {
            nodes=0;
        }
        SysFreeString(xmlQuery);
    }
    return nodes;
}

WString XmlReadString(IXMLDOMNode* node)
{
    WString result;
    BSTR text=0;
    HRESULT hr=node->get_text(&text);
    if(SUCCEEDED(hr))
    {
        const wchar_t* candidateItem=text;
        result=candidateItem;
        SysFreeString(text);
    }
    return result;
}

void XmlReadMultipleStrings(IXMLDOMNodeList* textNodes, List<WString>& candidates, int max)
{
    candidates.Clear();
    while((int)candidates.Count()<max)
    {
        IXMLDOMNode* textNode=0;
        HRESULT hr=textNodes->nextNode(&textNode);
        if(hr==S_OK)
        {
            candidates.Add(XmlReadString(textNode));
            textNode->Release();
        }
        else
        {
            break;
        }
    }
}

IXMLDOMDocument2* XmlLoad(const WString& content)
{
    IXMLDOMDocument2* pDom=0;
    HRESULT hr=CoCreateInstance(__uuidof(DOMDocument60), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDom));
    if(SUCCEEDED(hr))
    {
        pDom->put_async(VARIANT_FALSE);
        pDom->put_validateOnParse(VARIANT_FALSE);
        pDom->put_resolveExternals(VARIANT_FALSE);

        BSTR xmlContent=SysAllocString(content.Buffer());
        if(xmlContent)
        {
            VARIANT_BOOL isSuccessful=0;
            hr=pDom->loadXML(xmlContent, &isSuccessful);
            if(!(SUCCEEDED(hr) && isSuccessful==VARIANT_TRUE))
            {
                pDom->Release();
                pDom=0;
            }
            SysFreeString(xmlContent);
        }
    }
    return pDom;
}

有了q几个函C后,我们可以干下面的事情,譬如说从鸟窝首页下蝲W一늚所有topic的标题:

WString xml=NestleGetXml(L”/topics”, cookie);
IXMLDOMDocument2* pDom=XmlLoad(xml);
List<WString> titles;
IXMLNodeList* nodes=XmlQuery(pDom, L”/hash/topics/topic/title/text()”);
XmlReadMultipleStrings(nodes, titles, 100);

Z么上面的xpath是hash/topics/topic/title/text()?因ؓq个xml的内容大概类gQ?br /><hash>
    <topics>
        <topic>
            <title>TITLE</title>

剩下的大家就ȝ代码吧。这个故事告诉我们,只要有一个合适的装QC++写vq些本来应该让C#来写的东西也不是那么的烦人的Q啊哈哈哈哈?/p>

陈梓?vczh) 2012-10-27 15:19 发表评论
]]>
开始用VS2012来开发GacUI?/title><link>http://www.shnenglu.com/vczh/archive/2012/08/30/188822.html</link><dc:creator>陈梓?vczh)</dc:creator><author>陈梓?vczh)</author><pubDate>Thu, 30 Aug 2012 13:29:00 GMT</pubDate><guid>http://www.shnenglu.com/vczh/archive/2012/08/30/188822.html</guid><wfw:comment>http://www.shnenglu.com/vczh/comments/188822.html</wfw:comment><comments>http://www.shnenglu.com/vczh/archive/2012/08/30/188822.html#Feedback</comments><slash:comments>25</slash:comments><wfw:commentRss>http://www.shnenglu.com/vczh/comments/commentRss/188822.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/vczh/services/trackbacks/188822.html</trackback:ping><description><![CDATA[<div>    Visual Studio 2012发布的那一天我把它搞到手了。新的C++ IDE真的是劲爆了Q写代码的感觉毫不亚于C#。我最喜欢的部分是补全和着色部分。如今C++的宏被渲染成屎红Ԍcd被渲染成屎绿Ԍ参数被渲染成屎灰Ԍq样基本不需要要~译Q看着颜色都知道有没有写对。智能补全已l赶VAXQ而且q实C“~写qo”Q譬如说输入PNT可以在弹出列表里面昄所有大写字母ؓPNT的对象(譬如说ParsingNodeTransitionQ等{。这样做的好处是Q我只要打有限几个字W就可以补完一整句了,输入速度大大提高?br /><br />    所以我升了几乎所有工E。文档生成部分由于还在用DIA100Q所以暂时没有升U到2012Q不q这是迟早的事情。不q这ơ升U遇C几个问题?br /><br />    W一个是Q对于没有captureM外部变量的lambda expressionQ它可以隐式转换成一个函数指针。这个功能VS2010是没有的Q结果升U了之后造成了我几个重蝲函数的问题,不过解决q个东西q是很简单的Q只要把lambda表达式先保存在一个vl::Func变量里面好了?br /><br />    W二个是WICImagingFactory。在Windows SDK 7.0里面QCLSID_WICImagingFactory指向了WIC的唯一一个版本。在Windows SDK 8.0里面Q出CCLSID_WICImagingFactory1和CLSID_WICImagingFactory2Qƈ且CLSID_WICImagingFactory{于CLSID_WICImagingFactory2。问题就来了QWindows 7里面q没有WICImagingFactory2Q结果我CoCreateInstance是败了。一开始觉得很奇怪,后来想了惻I直接用VS那强大的Go To Definition功能跛_了定义CLSID_WICImagingFactory的地方,然后发现了这个事情。因此我把代码Ҏ了,如果sdk用的是高U版本,强制?.0的?br /><br />    VS2012Ҏ板语法的查更加严g。以前还可以写typename A<T>::B<T>Q现在不行了Q得写成typename A<T>::template B<T>。其实后面那个才是标准的Q而且VS2010也支持。只是VS2010也允怽省略template?br /><br />    VS2012对于C++的改q已l跟C#几乎一模一样了Q而且VS2012q支持C++的单元测试项目。ȝ来说Q我十分喜欢?/div><img src ="http://www.shnenglu.com/vczh/aggbug/188822.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/vczh/" target="_blank">陈梓?vczh)</a> 2012-08-30 21:29 <a href="http://www.shnenglu.com/vczh/archive/2012/08/30/188822.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>合ƈVisual Studio本地C++XML注释文档和PDB的符号内?/title><link>http://www.shnenglu.com/vczh/archive/2012/03/10/167539.html</link><dc:creator>陈梓?vczh)</dc:creator><author>陈梓?vczh)</author><pubDate>Sat, 10 Mar 2012 01:04:00 GMT</pubDate><guid>http://www.shnenglu.com/vczh/archive/2012/03/10/167539.html</guid><wfw:comment>http://www.shnenglu.com/vczh/comments/167539.html</wfw:comment><comments>http://www.shnenglu.com/vczh/archive/2012/03/10/167539.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.shnenglu.com/vczh/comments/commentRss/167539.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/vczh/services/trackbacks/167539.html</trackback:ping><description><![CDATA[     摘要: l于CȀ动h心的时刻了。今天的博客内容永q消除Visual Studio的本地C++XML注释~译出来的XML文档没有办法生成可读文档的根本原因?<br> <br> 首先介绍一下C++的XML注释。在启用注释之前Q我们必ddE属性里面,把[C/C++ -> Output Files -> Generate Xml Documentation Files]讄成Yes。这h们就可以在C++的类啊函C面写XML注释Q然后被~译成一份带有符号链接的XML注释集合。这里先l一个GacUI的XML注释的例子:  <a href='http://www.shnenglu.com/vczh/archive/2012/03/10/167539.html'>阅读全文</a><img src ="http://www.shnenglu.com/vczh/aggbug/167539.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/vczh/" target="_blank">陈梓?vczh)</a> 2012-03-10 09:04 <a href="http://www.shnenglu.com/vczh/archive/2012/03/10/167539.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用VS API开发一个PDB Dumperq且可以在没装VS2010的计机上运?/title><link>http://www.shnenglu.com/vczh/archive/2012/03/10/167538.html</link><dc:creator>陈梓?vczh)</dc:creator><author>陈梓?vczh)</author><pubDate>Fri, 09 Mar 2012 22:43:00 GMT</pubDate><guid>http://www.shnenglu.com/vczh/archive/2012/03/10/167538.html</guid><wfw:comment>http://www.shnenglu.com/vczh/comments/167538.html</wfw:comment><comments>http://www.shnenglu.com/vczh/archive/2012/03/10/167538.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/vczh/comments/commentRss/167538.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/vczh/services/trackbacks/167538.html</trackback:ping><description><![CDATA[     摘要: GacUIC撰写文档的时候了。虽然GacUI本n的功能还没有全部完成Q但是发布一个alpha版还是可以的。因此GacUI需要一份文档。自?net语言支持XML注释生成文档之后QVisual Studio的本地C++也支持用XML注释了。只要打开了[工程属?-> C/C++ -> Output Files -> Generate XML Documentation Files]之后QVisual Studio会在~译本地C++工程之后Q将所有的XML注释攉hQ放在和可执行文件同一个目录下?ProjectName.xml>里面。然后我尝试bing了一下有没有从C++的XML文档生成可读文档的工Pl果发现只有.net才支持?<br> <br> 后来我稍微研I了一下(详细内容会在下一博客透露Q,发现之所以没人写q个工具Q是因ؓ只有.net的可执行文g才包含够多的元数据Q而且q些元数据是必须的,否则无法生成一个完整的文档。D个例子,虽然<ProjectName.xml>包含了xml注释和该注释所在的W号Q但是却没有包含该符Ll构信息。结果你试图生成一个函  <a href='http://www.shnenglu.com/vczh/archive/2012/03/10/167538.html'>阅读全文</a><img src ="http://www.shnenglu.com/vczh/aggbug/167538.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/vczh/" target="_blank">陈梓?vczh)</a> 2012-03-10 06:43 <a href="http://www.shnenglu.com/vczh/archive/2012/03/10/167538.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++反射实现Ҏ设想QGacUIQ?/title><link>http://www.shnenglu.com/vczh/archive/2012/01/11/164003.html</link><dc:creator>陈梓?vczh)</dc:creator><author>陈梓?vczh)</author><pubDate>Wed, 11 Jan 2012 11:39:00 GMT</pubDate><guid>http://www.shnenglu.com/vczh/archive/2012/01/11/164003.html</guid><wfw:comment>http://www.shnenglu.com/vczh/comments/164003.html</wfw:comment><comments>http://www.shnenglu.com/vczh/archive/2012/01/11/164003.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.shnenglu.com/vczh/comments/commentRss/164003.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/vczh/services/trackbacks/164003.html</trackback:ping><description><![CDATA[<div>    C++的反一直是一个很多h都在做的事情。不q今天我l于有了一个简单的xQ当然只对VC++~译出来的程序有效。首先看下面的一个单元测试:<br /><br />    如果我们有下面的代码Q? <div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080">1</span> <span style="color: #000000">    </span><span style="color: #0000ff">class</span><span style="color: #000000"> A{};<br /></span><span style="color: #008080">2</span> <span style="color: #000000">    </span><span style="color: #0000ff">class</span><span style="color: #000000"> B:</span><span style="color: #0000ff">public</span><span style="color: #000000"> A{};<br /></span><span style="color: #008080">3</span> <span style="color: #000000">    </span><span style="color: #0000ff">class</span><span style="color: #000000"> C:</span><span style="color: #0000ff">public</span><span style="color: #000000"> A{};<br /></span><span style="color: #008080">4</span> <span style="color: #000000">    </span><span style="color: #0000ff">class</span><span style="color: #000000"> D:</span><span style="color: #0000ff">public</span><span style="color: #000000"> B, </span><span style="color: #0000ff">public</span><span style="color: #000000"> C{};<br /></span><span style="color: #008080">5</span> <span style="color: #000000">    </span><span style="color: #0000ff">class</span><span style="color: #000000"> E:</span><span style="color: #0000ff">virtual</span><span style="color: #000000"> </span><span style="color: #0000ff">public</span><span style="color: #000000"> A{};<br /></span><span style="color: #008080">6</span> <span style="color: #000000">    </span><span style="color: #0000ff">class</span><span style="color: #000000"> F:</span><span style="color: #0000ff">virtual</span><span style="color: #000000"> </span><span style="color: #0000ff">public</span><span style="color: #000000"> A{};<br /></span><span style="color: #008080">7</span> <span style="color: #000000">    </span><span style="color: #0000ff">class</span><span style="color: #000000"> G:</span><span style="color: #0000ff">public</span><span style="color: #000000"> E, </span><span style="color: #0000ff">public</span><span style="color: #000000"> F{};</span></div>    那么下面的事情一定会发生Q? <div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080">1</span> <span style="color: #000000">    D d;<br /></span><span style="color: #008080">2</span> <span style="color: #000000">    A</span><span style="color: #000000">&</span><span style="color: #000000"> da1</span><span style="color: #000000">=</span><span style="color: #000000">static_cast</span><span style="color: #000000"><</span><span style="color: #000000">B</span><span style="color: #000000">&></span><span style="color: #000000">(d);<br /></span><span style="color: #008080">3</span> <span style="color: #000000">    A</span><span style="color: #000000">&</span><span style="color: #000000"> da2</span><span style="color: #000000">=</span><span style="color: #000000">static_cast</span><span style="color: #000000"><</span><span style="color: #000000">C</span><span style="color: #000000">&></span><span style="color: #000000">(d);<br /></span><span style="color: #008080">4</span> <span style="color: #000000">    TEST_ASSERT(</span><span style="color: #000000">&</span><span style="color: #000000">da1</span><span style="color: #000000">!=&</span><span style="color: #000000">da2);<br /></span><span style="color: #008080">5</span> <span style="color: #000000">    <br /></span><span style="color: #008080">6</span> <span style="color: #000000">    G g;<br /></span><span style="color: #008080">7</span> <span style="color: #000000">    A</span><span style="color: #000000">&</span><span style="color: #000000"> ga1</span><span style="color: #000000">=</span><span style="color: #000000">static_cast</span><span style="color: #000000"><</span><span style="color: #000000">E</span><span style="color: #000000">&></span><span style="color: #000000">(g);<br /></span><span style="color: #008080">8</span> <span style="color: #000000">    A</span><span style="color: #000000">&</span><span style="color: #000000"> ga2</span><span style="color: #000000">=</span><span style="color: #000000">static_cast</span><span style="color: #000000"><</span><span style="color: #000000">F</span><span style="color: #000000">&></span><span style="color: #000000">(g);<br /></span><span style="color: #008080">9</span> <span style="color: #000000">    TEST_ASSERT(</span><span style="color: #000000">&</span><span style="color: #000000">ga1</span><span style="color: #000000">==&</span><span style="color: #000000">ga2);</span></div><br />    对于q种virtuall承的事情,到这里还是很Ҏ理解的。那现在我们来更q一步: <div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080"> 1</span> <span style="color: #000000">    </span><span style="color: #0000ff">class</span><span style="color: #000000"> Base<br /></span><span style="color: #008080"> 2</span> <span style="color: #000000">    {<br /></span><span style="color: #008080"> 3</span> <span style="color: #000000">    </span><span style="color: #0000ff">public</span><span style="color: #000000">:<br /></span><span style="color: #008080"> 4</span> <span style="color: #000000">        size_t size;<br /></span><span style="color: #008080"> 5</span> <span style="color: #000000"><br /></span><span style="color: #008080"> 6</span> <span style="color: #000000">        Base()<br /></span><span style="color: #008080"> 7</span> <span style="color: #000000">            :size(</span><span style="color: #000000">0</span><span style="color: #000000">)<br /></span><span style="color: #008080"> 8</span> <span style="color: #000000">        {<br /></span><span style="color: #008080"> 9</span> <span style="color: #000000">        }<br /></span><span style="color: #008080">10</span> <span style="color: #000000">    };<br /></span><span style="color: #008080">11</span> <span style="color: #000000"><br /></span><span style="color: #008080">12</span> <span style="color: #000000">    template</span><span style="color: #000000"><</span><span style="color: #000000">typename T</span><span style="color: #000000">></span><span style="color: #000000"><br /></span><span style="color: #008080">13</span> <span style="color: #000000">    </span><span style="color: #0000ff">class</span><span style="color: #000000"> Derived : </span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">virtual</span><span style="color: #000000"> Base<br /></span><span style="color: #008080">14</span> <span style="color: #000000">    {<br /></span><span style="color: #008080">15</span> <span style="color: #000000">    </span><span style="color: #0000ff">public</span><span style="color: #000000">:<br /></span><span style="color: #008080">16</span> <span style="color: #000000">        Derived()<br /></span><span style="color: #008080">17</span> <span style="color: #000000">        {<br /></span><span style="color: #008080">18</span> <span style="color: #000000">            </span><span style="color: #0000ff">if</span><span style="color: #000000">(size</span><span style="color: #000000"><</span><span style="color: #0000ff">sizeof</span><span style="color: #000000">(T)) size</span><span style="color: #000000">=</span><span style="color: #0000ff">sizeof</span><span style="color: #000000">(T);<br /></span><span style="color: #008080">19</span> <span style="color: #000000">        }<br /></span><span style="color: #008080">20</span> <span style="color: #000000">    };<br /></span><span style="color: #008080">21</span> <span style="color: #000000"><br /></span><span style="color: #008080">22</span> <span style="color: #000000">    </span><span style="color: #0000ff">class</span><span style="color: #000000"> H : </span><span style="color: #0000ff">public</span><span style="color: #000000"> Derived</span><span style="color: #000000"><</span><span style="color: #000000">H</span><span style="color: #000000">></span><span style="color: #000000">{};<br /></span><span style="color: #008080">23</span> <span style="color: #000000">    </span><span style="color: #0000ff">class</span><span style="color: #000000"> I : </span><span style="color: #0000ff">public</span><span style="color: #000000"> H, </span><span style="color: #0000ff">public</span><span style="color: #000000"> Derived</span><span style="color: #000000"><</span><span style="color: #000000">I</span><span style="color: #000000">></span><span style="color: #000000">{};<br /></span><span style="color: #008080">24</span> <span style="color: #000000">    </span><span style="color: #0000ff">class</span><span style="color: #000000"> J : </span><span style="color: #0000ff">public</span><span style="color: #000000"> I, </span><span style="color: #0000ff">public</span><span style="color: #000000"> Derived</span><span style="color: #000000"><</span><span style="color: #000000">J</span><span style="color: #000000">></span><span style="color: #000000">{};</span></div><br />    首先QH、I和J都各自拥有自q唯一的一个Base。J虽然l承了Derived<H>、Derived<I>和Derived<J>Q但是始l只拥有一个Base。因为Base是virtuall承的?br /><br />    其次Qsizeof(Derived<T>)>sizeof(Base)始终是成立的Q因为Base的virtuall承D了Derived<T>里面臛_要保存一个指向BaseQ或者可以用来找到BaseQ的指针。这个条件很重要Q因D了sizeof(J)>sizeof(I)q个条g是恒成立的?br /><br />    好了Q那么来看J。由于C++q没有规定多重承的时候,几个父类的构造函数的序是什么,所以我们需要sizeof(J)>sizeof(I)q个条g。ؓ什么呢Q看Derivedcȝ构造函?#8212;—它之让sizeof(T)更大的数据覆盖Base里面的数据?br /><br />    所以我们就可以定下面的事情: <div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080">1</span> <span style="color: #000000">    </span><span style="color: #0000ff">const</span><span style="color: #000000"> H</span><span style="color: #000000">&</span><span style="color: #000000"> h</span><span style="color: #000000">=</span><span style="color: #000000">H();<br /></span><span style="color: #008080">2</span> <span style="color: #000000">    </span><span style="color: #0000ff">const</span><span style="color: #000000"> H</span><span style="color: #000000">&</span><span style="color: #000000"> i</span><span style="color: #000000">=</span><span style="color: #000000">I();<br /></span><span style="color: #008080">3</span> <span style="color: #000000">    </span><span style="color: #0000ff">const</span><span style="color: #000000"> H</span><span style="color: #000000">&</span><span style="color: #000000"> j</span><span style="color: #000000">=</span><span style="color: #000000">J();<br /></span><span style="color: #008080">4</span> <span style="color: #000000">    TEST_ASSERT(h.size</span><span style="color: #000000"><</span><span style="color: #000000">i.size);<br /></span><span style="color: #008080">5</span> <span style="color: #000000">    TEST_ASSERT(i.size</span><span style="color: #000000"><</span><span style="color: #000000">j.size);<br /></span><span style="color: #008080">6</span> <span style="color: #000000">    TEST_ASSERT(h.size</span><span style="color: #000000">==</span><span style="color: #0000ff">sizeof</span><span style="color: #000000">(H));<br /></span><span style="color: #008080">7</span> <span style="color: #000000">    TEST_ASSERT(i.size</span><span style="color: #000000">==</span><span style="color: #0000ff">sizeof</span><span style="color: #000000">(I));<br /></span><span style="color: #008080">8</span> <span style="color: #000000">    TEST_ASSERT(j.size</span><span style="color: #000000">==</span><span style="color: #0000ff">sizeof</span><span style="color: #000000">(J));</span></div><br />    无论J的三个Derived<T>的构造函数谁先执行,最后能够留下来的Base里面的数据肯定是Derived<J>里面的数据。讲到这里应该很清楚了。如果读者还没想到这跟反有什么关pȝ话,那么h一下,如果Base除了size以外Q还有一个ITypeDescriptor** typeDescriptor;成员。然后DerivedҎq样Q? <div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080"> 1</span> <span style="color: #000000">template</span><span style="color: #000000"><</span><span style="color: #000000">typename T</span><span style="color: #000000">></span><span style="color: #000000"><br /></span><span style="color: #008080"> 2</span> <span style="color: #000000"></span><span style="color: #0000ff">class</span><span style="color: #000000"> Derived : <img alt="" src="http://www.shnenglu.com/Images/dot.gif" /><br /></span><span style="color: #008080"> 3</span> <span style="color: #000000">{<br /></span><span style="color: #008080"> 4</span> <span style="color: #000000"></span><span style="color: #0000ff">public</span><span style="color: #000000">:<br /></span><span style="color: #008080"> 5</span> <span style="color: #000000">    </span><span style="color: #0000ff">static</span><span style="color: #000000"> ITypeDescriptor</span><span style="color: #000000">*</span><span style="color: #000000"> type;<br /></span><span style="color: #008080"> 6</span> <span style="color: #000000"><br /></span><span style="color: #008080"> 7</span> <span style="color: #000000">    Derived()<br /></span><span style="color: #008080"> 8</span> <span style="color: #000000">    {<br /></span><span style="color: #008080"> 9</span> <span style="color: #000000">        </span><span style="color: #0000ff">if</span><span style="color: #000000">(<img alt="" src="http://www.shnenglu.com/Images/dot.gif" />){size</span><span style="color: #000000">=</span><span style="color: #0000ff">sizeof</span><span style="color: #000000">(T); typeDescriptor</span><span style="color: #000000">=&</span><span style="color: #000000">type;}<br /></span><span style="color: #008080">10</span> <span style="color: #000000">    }<br /></span><span style="color: #008080">11</span> <span style="color: #000000">};</span></div><br />    那么不管你的J拿到手里的类型是什么,哪怕是const H& jQ那么j.typeDescriptor肯定是&Derived<J>::type;<br /><br />    到这里还没有跟VC++有关pȝ东西。假设ITypeDescriptor是一个够代表反功能的高接口的话Q那么我们要怎么实现它呢Q我们自己来按照字符串去调用各种函数什么的d现它肯定ȝ到死了。但是如果大家还记的我前面的<a style="text-decoration: underline" href="http://www.shnenglu.com/vczh/archive/2011/12/30/163200.html" target="_blank">q篇博客文章</a>的话Q那么大家肯定想CQ我们可以写一个程序来替我们读pdb生成ITypeDescriptor的代码,q有把具体的对象赋DDerived<T>::type里面ȝ一个初始化函数Q啊哈哈哈!当然pdb只能是从Visual C++~译出来的,q不是Q也臛_只能是Windows上面的。不q对GacUI来说q无所谓。因为我只要把GacUI在VisualStudio里面~译生成反射的代码,q个生成之后的代码我q是能放到其他地方编译的。到时候我只要q同q段代码一q发布就好了?br /><br />    当然Q这个程序不仅仅可以帮我实现ITypeDescriptorQ还可以帮我实现C语言和C++语言的dll接口的实玎ͼ因ؓdll里面肯定不能暴露模板的。下面就仅需要我L它做出来可以了。至此,我们让一个类支持反射的代价很?#8212;—只要让他l承自Derived<自己>好了?br /></div><img src ="http://www.shnenglu.com/vczh/aggbug/164003.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/vczh/" target="_blank">陈梓?vczh)</a> 2012-01-11 19:39 <a href="http://www.shnenglu.com/vczh/archive/2012/01/11/164003.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>回来了(VL++3.0计划Q?/title><link>http://www.shnenglu.com/vczh/archive/2009/10/09/98207.html</link><dc:creator>陈梓?vczh)</dc:creator><author>陈梓?vczh)</author><pubDate>Fri, 09 Oct 2009 15:17:00 GMT</pubDate><guid>http://www.shnenglu.com/vczh/archive/2009/10/09/98207.html</guid><wfw:comment>http://www.shnenglu.com/vczh/comments/98207.html</wfw:comment><comments>http://www.shnenglu.com/vczh/archive/2009/10/09/98207.html#Feedback</comments><slash:comments>11</slash:comments><wfw:commentRss>http://www.shnenglu.com/vczh/comments/commentRss/98207.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/vczh/services/trackbacks/98207.html</trackback:ping><description><![CDATA[     摘要: 之前因ؓ非常忙,加上无聊开发什么类似WCF和WPF的东西,最q终于找C新的目标了,于是之前那些׃做了。隔了这么久没法文章主要是因为最q没写出什么完整的东西。国庆玩?天,之前在计划VL++3.0?<br> <br> VL++3.0被定位ؓ一个ؓ了数据处理而开发的C++库。这个库不的特点在于“其他语a的味道很”。C++的库用v来不爽主要是因ؓ老是要我按下划线Q而且大量应用非OOPҎ导致IDE的自动补全无法发挥作用。所以ؓ了I补这个缺h做了一个很不一L东西Q也是VL++了。经q了三年多的开发,1.0?.0已经相出炉Q每一ơ打L都解决了一些前一个版本解决不了的问题?nbsp; <a href='http://www.shnenglu.com/vczh/archive/2009/10/09/98207.html'>阅读全文</a><img src ="http://www.shnenglu.com/vczh/aggbug/98207.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/vczh/" target="_blank">陈梓?vczh)</a> 2009-10-09 23:17 <a href="http://www.shnenglu.com/vczh/archive/2009/10/09/98207.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++q程调用cL作支持Callback Interfacehttp://www.shnenglu.com/vczh/archive/2009/07/18/90409.html陈梓?vczh)陈梓?vczh)Sat, 18 Jul 2009 02:20:00 GMThttp://www.shnenglu.com/vczh/archive/2009/07/18/90409.htmlhttp://www.shnenglu.com/vczh/comments/90409.htmlhttp://www.shnenglu.com/vczh/archive/2009/07/18/90409.html#Feedback10http://www.shnenglu.com/vczh/comments/commentRss/90409.htmlhttp://www.shnenglu.com/vczh/services/trackbacks/90409.html
使用q个东西可以开发一些C/S模式的程序,然后只需要将服务器和客户端看成同一个程序,客L认ؓ是很多个U程p了。服务器端提供一些类l客L创徏q用,当这些服务类要求回调的时候,客户端只需要按照回调的接口实现回调Q然后将指针提供l服务类p了。剩下来的链接啊调度啊网l传输的问题全部不用管了,非常方便?nbsp; 阅读全文

陈梓?vczh) 2009-07-18 10:20 发表评论
]]>
实现C++q程调用cȝ操作?/title><link>http://www.shnenglu.com/vczh/archive/2009/07/04/89211.html</link><dc:creator>陈梓?vczh)</dc:creator><author>陈梓?vczh)</author><pubDate>Sat, 04 Jul 2009 02:07:00 GMT</pubDate><guid>http://www.shnenglu.com/vczh/archive/2009/07/04/89211.html</guid><wfw:comment>http://www.shnenglu.com/vczh/comments/89211.html</wfw:comment><comments>http://www.shnenglu.com/vczh/archive/2009/07/04/89211.html#Feedback</comments><slash:comments>14</slash:comments><wfw:commentRss>http://www.shnenglu.com/vczh/comments/commentRss/89211.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/vczh/services/trackbacks/89211.html</trackback:ping><description><![CDATA[     摘要: q次展示如何一个服务器端的C++c让客户端调用。用早上刚刚开发完的工P用户可以不用处理M传输q程中的q接和编码解码等操作。这ơ实C个四则运的语法分析器,客户端发送表辑ּQ服务器端传回语法树Q承树那个模型Q,客户端将语法树传回去Q服务器端传回运结果?nbsp; <a href='http://www.shnenglu.com/vczh/archive/2009/07/04/89211.html'>阅读全文</a><img src ="http://www.shnenglu.com/vczh/aggbug/89211.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/vczh/" target="_blank">陈梓?vczh)</a> 2009-07-04 10:07 <a href="http://www.shnenglu.com/vczh/archive/2009/07/04/89211.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ZcM反射机制的函数调用完?/title><link>http://www.shnenglu.com/vczh/archive/2009/06/30/88880.html</link><dc:creator>陈梓?vczh)</dc:creator><author>陈梓?vczh)</author><pubDate>Tue, 30 Jun 2009 04:47:00 GMT</pubDate><guid>http://www.shnenglu.com/vczh/archive/2009/06/30/88880.html</guid><wfw:comment>http://www.shnenglu.com/vczh/comments/88880.html</wfw:comment><comments>http://www.shnenglu.com/vczh/archive/2009/06/30/88880.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/vczh/comments/commentRss/88880.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/vczh/services/trackbacks/88880.html</trackback:ping><description><![CDATA[     摘要: 现在不仅可以阅读cȝ成员Q也可以用函数名的字W串去调用函数ƈ取得l果了。代码与q篇文章的实例类|因此只脓出更改的部分以及E序截图?nbsp; <a href='http://www.shnenglu.com/vczh/archive/2009/06/30/88880.html'>阅读全文</a><img src ="http://www.shnenglu.com/vczh/aggbug/88880.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/vczh/" target="_blank">陈梓?vczh)</a> 2009-06-30 12:47 <a href="http://www.shnenglu.com/vczh/archive/2009/06/30/88880.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>D废版HTTP Server之小试牛刀http://www.shnenglu.com/vczh/archive/2009/06/29/88834.html陈梓?vczh)陈梓?vczh)Mon, 29 Jun 2009 13:19:00 GMThttp://www.shnenglu.com/vczh/archive/2009/06/29/88834.htmlhttp://www.shnenglu.com/vczh/comments/88834.htmlhttp://www.shnenglu.com/vczh/archive/2009/06/29/88834.html#Feedback4http://www.shnenglu.com/vczh/comments/commentRss/88834.htmlhttp://www.shnenglu.com/vczh/services/trackbacks/88834.html阅读全文

陈梓?vczh) 2009-06-29 21:19 发表评论
]]>
C++ZcM反射机制的XML序列化和反序列化完成http://www.shnenglu.com/vczh/archive/2009/06/29/88758.html陈梓?vczh)陈梓?vczh)Mon, 29 Jun 2009 04:12:00 GMThttp://www.shnenglu.com/vczh/archive/2009/06/29/88758.htmlhttp://www.shnenglu.com/vczh/comments/88758.htmlhttp://www.shnenglu.com/vczh/archive/2009/06/29/88758.html#Feedback10http://www.shnenglu.com/vczh/comments/commentRss/88758.htmlhttp://www.shnenglu.com/vczh/services/trackbacks/88758.html阅读全文

陈梓?vczh) 2009-06-29 12:12 发表评论
]]>
重写了C++的类似反的工具http://www.shnenglu.com/vczh/archive/2009/06/25/88533.html陈梓?vczh)陈梓?vczh)Thu, 25 Jun 2009 14:48:00 GMThttp://www.shnenglu.com/vczh/archive/2009/06/25/88533.htmlhttp://www.shnenglu.com/vczh/comments/88533.htmlhttp://www.shnenglu.com/vczh/archive/2009/06/25/88533.html#Feedback4http://www.shnenglu.com/vczh/comments/commentRss/88533.htmlhttp://www.shnenglu.com/vczh/services/trackbacks/88533.html阅读全文

陈梓?vczh) 2009-06-25 22:48 发表评论
]]>
使用COM实现控g内容的Drag and Drophttp://www.shnenglu.com/vczh/archive/2009/05/30/86163.html陈梓?vczh)陈梓?vczh)Sat, 30 May 2009 05:17:00 GMThttp://www.shnenglu.com/vczh/archive/2009/05/30/86163.htmlhttp://www.shnenglu.com/vczh/comments/86163.htmlhttp://www.shnenglu.com/vczh/archive/2009/05/30/86163.html#Feedback4http://www.shnenglu.com/vczh/comments/commentRss/86163.htmlhttp://www.shnenglu.com/vczh/services/trackbacks/86163.html
实现了之后,E序刚开始需要调用OldInitialize(NULL);Q结束的时候调用OnUninitialize();Q控件创建的时候调用RegisterDragDropQ控件结束的时候调用RevokeDragDrop。然后就可以通过q些COM来做Drag and Drop了。下面是接口的实玎ͼ  阅读全文

陈梓?vczh) 2009-05-30 13:17 发表评论
]]>
Combinator Parser修改错误处理Ҏhttp://www.shnenglu.com/vczh/archive/2009/05/04/81860.html陈梓?vczh)陈梓?vczh)Mon, 04 May 2009 10:35:00 GMThttp://www.shnenglu.com/vczh/archive/2009/05/04/81860.htmlhttp://www.shnenglu.com/vczh/comments/81860.htmlhttp://www.shnenglu.com/vczh/archive/2009/05/04/81860.html#Feedback1http://www.shnenglu.com/vczh/comments/commentRss/81860.htmlhttp://www.shnenglu.com/vczh/services/trackbacks/81860.html阅读全文

陈梓?vczh) 2009-05-04 18:35 发表评论
]]>
搞定模板元编E(meta programmingQ?/title><link>http://www.shnenglu.com/vczh/archive/2009/04/08/79291.html</link><dc:creator>陈梓?vczh)</dc:creator><author>陈梓?vczh)</author><pubDate>Wed, 08 Apr 2009 13:17:00 GMT</pubDate><guid>http://www.shnenglu.com/vczh/archive/2009/04/08/79291.html</guid><wfw:comment>http://www.shnenglu.com/vczh/comments/79291.html</wfw:comment><comments>http://www.shnenglu.com/vczh/archive/2009/04/08/79291.html#Feedback</comments><slash:comments>13</slash:comments><wfw:commentRss>http://www.shnenglu.com/vczh/comments/commentRss/79291.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/vczh/services/trackbacks/79291.html</trackback:ping><description><![CDATA[     摘要: 今天闲得无聊Q早上v来习惯性瞟一瞟boostQ突然看中了它的MPL库,所以自己实C一个子集消时间?<br> <br> 已经实现的功能有Q整数运、闭包、列表处理等。我用了自己的unit test框架Q通过写一个函数输Z个属于自qMPLcd的字W串Q譬如List<Int<0>,List<Int<1>,Empty>>产生"[0 , 1]"Q,然后用自己写的字W串比较Q可以发现库里面是否有错?<br> <br> 一下有两䆾代码Q第一份是使用Q第二䆾是自qMPL的源代码Q?nbsp; <a href='http://www.shnenglu.com/vczh/archive/2009/04/08/79291.html'>阅读全文</a><img src ="http://www.shnenglu.com/vczh/aggbug/79291.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/vczh/" target="_blank">陈梓?vczh)</a> 2009-04-08 21:17 <a href="http://www.shnenglu.com/vczh/archive/2009/04/08/79291.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实现了Huffman压羃解压法http://www.shnenglu.com/vczh/archive/2009/01/11/71693.html陈梓?vczh)陈梓?vczh)Sat, 10 Jan 2009 17:16:00 GMThttp://www.shnenglu.com/vczh/archive/2009/01/11/71693.htmlhttp://www.shnenglu.com/vczh/comments/71693.htmlhttp://www.shnenglu.com/vczh/archive/2009/01/11/71693.html#Feedback0http://www.shnenglu.com/vczh/comments/commentRss/71693.htmlhttp://www.shnenglu.com/vczh/services/trackbacks/71693.html阅读全文

陈梓?vczh) 2009-01-11 01:16 发表评论
]]>
修改后的LZ77压羃解压源码http://www.shnenglu.com/vczh/archive/2009/01/07/71418.html陈梓?vczh)陈梓?vczh)Wed, 07 Jan 2009 07:35:00 GMThttp://www.shnenglu.com/vczh/archive/2009/01/07/71418.htmlhttp://www.shnenglu.com/vczh/comments/71418.htmlhttp://www.shnenglu.com/vczh/archive/2009/01/07/71418.html#Feedback6http://www.shnenglu.com/vczh/comments/commentRss/71418.htmlhttp://www.shnenglu.com/vczh/services/trackbacks/71418.html
1、可修改的Window Size。压~流会把Window Size写进去,解压能够自动获取?
2、发现冗余的地方Q每一个标记的压羃块节省了一位?
3、如果用户一ơ性写入的字节不够多则会缓存v来,上一版本则是直接压羃完。这样会丢失某些原本可以压羃的数据,因此修正?nbsp; 阅读全文

陈梓?vczh) 2009-01-07 15:35 发表评论
]]>
LZ77压羃效果试http://www.shnenglu.com/vczh/archive/2009/01/07/71390.html陈梓?vczh)陈梓?vczh)Tue, 06 Jan 2009 16:36:00 GMThttp://www.shnenglu.com/vczh/archive/2009/01/07/71390.htmlhttp://www.shnenglu.com/vczh/comments/71390.htmlhttp://www.shnenglu.com/vczh/archive/2009/01/07/71390.html#Feedback0http://www.shnenglu.com/vczh/comments/commentRss/71390.htmlhttp://www.shnenglu.com/vczh/services/trackbacks/71390.html阅读全文

陈梓?vczh) 2009-01-07 00:36 发表评论
]]>
实现了一?28长度H口大小的LZ77压羃解压法http://www.shnenglu.com/vczh/archive/2009/01/06/71275.html陈梓?vczh)陈梓?vczh)Mon, 05 Jan 2009 17:47:00 GMThttp://www.shnenglu.com/vczh/archive/2009/01/06/71275.htmlhttp://www.shnenglu.com/vczh/comments/71275.htmlhttp://www.shnenglu.com/vczh/archive/2009/01/06/71275.html#Feedback5http://www.shnenglu.com/vczh/comments/commentRss/71275.htmlhttp://www.shnenglu.com/vczh/services/trackbacks/71275.html阅读全文

陈梓?vczh) 2009-01-06 01:47 发表评论
]]>
分解复杂的命令行参数http://www.shnenglu.com/vczh/archive/2008/12/24/70253.html陈梓?vczh)陈梓?vczh)Wed, 24 Dec 2008 09:13:00 GMThttp://www.shnenglu.com/vczh/archive/2008/12/24/70253.htmlhttp://www.shnenglu.com/vczh/comments/70253.htmlhttp://www.shnenglu.com/vczh/archive/2008/12/24/70253.html#Feedback2http://www.shnenglu.com/vczh/comments/commentRss/70253.htmlhttp://www.shnenglu.com/vczh/services/trackbacks/70253.html阅读全文

陈梓?vczh) 2008-12-24 17:13 发表评论
]]>
Vczh Serialization Demo Q在|络上传递复杂对?/title><link>http://www.shnenglu.com/vczh/archive/2008/11/22/67612.html</link><dc:creator>陈梓?vczh)</dc:creator><author>陈梓?vczh)</author><pubDate>Sat, 22 Nov 2008 10:26:00 GMT</pubDate><guid>http://www.shnenglu.com/vczh/archive/2008/11/22/67612.html</guid><wfw:comment>http://www.shnenglu.com/vczh/comments/67612.html</wfw:comment><comments>http://www.shnenglu.com/vczh/archive/2008/11/22/67612.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.shnenglu.com/vczh/comments/commentRss/67612.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/vczh/services/trackbacks/67612.html</trackback:ping><description><![CDATA[     摘要: 今天Serializationq行了重构,让其支持容器。于是用以前的基础设施p完成q个Demo了。代码如下:  <a href='http://www.shnenglu.com/vczh/archive/2008/11/22/67612.html'>阅读全文</a><img src ="http://www.shnenglu.com/vczh/aggbug/67612.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/vczh/" target="_blank">陈梓?vczh)</a> 2008-11-22 18:26 <a href="http://www.shnenglu.com/vczh/archive/2008/11/22/67612.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.wangyanl3.com.cn" target="_blank">þùƷ99Ʒ</a>| <a href="http://www.hbguangtao.cn" target="_blank">þƵ6</a>| <a href="http://www.linggei.cn" target="_blank">91ƷۺϾþ㽶</a>| <a href="http://www.amqinhang.cn" target="_blank">þþƷɭ</a>| <a href="http://www.zzdls.cn" target="_blank">97Ʒ˾þô߽</a>| <a href="http://www.s88w.cn" target="_blank">þþþùƷ</a>| <a href="http://www.h8uq0.cn" target="_blank">Ʒ99þþþþլС˵</a>| <a href="http://www.r97n59.cn" target="_blank">þþƷƷëƬ</a>| <a href="http://www.buniaowan.cn" target="_blank">Ʒþþþþù</a>| <a href="http://www.elzx.com.cn" target="_blank">ƷŮٸAVѾþ</a>| <a href="http://www.888su.cn" target="_blank">þþƷƷëƬ</a>| <a href="http://www.mmcase.cn" target="_blank">AVþþƷ</a>| <a href="http://www.gcctv.cn" target="_blank">þþƷĻ23ҳ</a>| <a href="http://www.sywanfu.cn" target="_blank">ƷþþþþóAV</a>| <a href="http://www.117shop.cn" target="_blank">þۺ͵͵ɫ</a>| <a href="http://www.ip-domain.com.cn" target="_blank">һĻþ</a>| <a href="http://www.e7sport.cn" target="_blank">޾ƷŮþþ</a>| <a href="http://www.xh68.cn" target="_blank">þAVһ</a>| <a href="http://www.jiudexn.cn" target="_blank">þۺۺϾþ97ɫ</a>| <a href="http://www.51index.cn" target="_blank">þþŮһ</a>| <a href="http://www.bkqxv.cn" target="_blank">˾þùѹۿƵ </a>| <a href="http://www.xixirt.cn" target="_blank">þƵ</a>| <a href="http://www.hwaq.cn" target="_blank">wwþþþþþþþ</a>| <a href="http://www.lushihu.cn" target="_blank">þþƷAVȫ</a>| <a href="http://www.jzxqbz.cn" target="_blank">þˬˬav</a>| <a href="http://www.jrtz112.cn" target="_blank">ܻƺ۵վþmimiɫ </a>| <a href="http://www.05xx.cn" target="_blank">þҹɫ˾Ʒ</a>| <a href="http://www.1118.org.cn" target="_blank">˾þں2019</a>| <a href="http://www.waygoing.com.cn" target="_blank">þ99ھƷ</a>| <a href="http://www.gljqk.cn" target="_blank">þþþ޾Ʒվ</a>| <a href="http://www.interagency.cn" target="_blank">ҹƷþþþ9999</a>| <a href="http://www.xyq123.cn" target="_blank">Ʒŷ޺ձþ</a>| <a href="http://www.bwab.cn" target="_blank">˳AVɫۺϾþ</a>| <a href="http://www.eastmark.cn" target="_blank">޹ƷþõӰŷ</a>| <a href="http://www.qcwxfw.cn" target="_blank">ŷһþþ</a>| <a href="http://www.hesiyu.cn" target="_blank">޹˾þþƷ99</a>| <a href="http://www.songshuidaojia.cn" target="_blank">þþþù</a>| <a href="http://www.ozxt.cn" target="_blank">ۺϾþþƷɫ</a>| <a href="http://www.0558pet.cn" target="_blank">ղƷþþþþþ</a>| <a href="http://www.qian-mi.cn" target="_blank">ݺɫۺվþþþþþø </a>| <a href="http://www.qunlanggu.cn" target="_blank">þǿdŮվ</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>