﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Snowdream-随笔分类-Courses</title><link>http://www.blogjava.net/zellux/category/27574.html</link><description>I'm awake but my world is half asleep</description><language>zh-cn</language><lastBuildDate>Wed, 27 Jan 2010 09:50:58 GMT</lastBuildDate><pubDate>Wed, 27 Jan 2010 09:50:58 GMT</pubDate><ttl>60</ttl><item><title>OS Lab 零散记录</title><link>http://www.blogjava.net/zellux/archive/2008/10/10/233601.html</link><dc:creator>ZelluX</dc:creator><author>ZelluX</author><pubDate>Fri, 10 Oct 2008 07:21:00 GMT</pubDate><guid>http://www.blogjava.net/zellux/archive/2008/10/10/233601.html</guid><wfw:comment>http://www.blogjava.net/zellux/comments/233601.html</wfw:comment><comments>http://www.blogjava.net/zellux/archive/2008/10/10/233601.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zellux/comments/commentRss/233601.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zellux/services/trackbacks/233601.html</trackback:ping><description><![CDATA[转自偶的内网博客<br /><br /><strong>Time : 2008-08-20 21:44</strong><br /><strong>汇编文件中导出函数符号<br /></strong><p>Linux 2.4.18的linux/linkage.h文件定义了若干相关的宏<br /></p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000"> SYMBOL_NAME(X) X</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />#ifdef __STDC__<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000"> SYMBOL_NAME_LABEL(X) X##:</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">#else</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000"> SYMBOL_NAME_LABEL(X) X/**/:</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">#endif</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000"> __ALIGN .align 16,0x90</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000"> __ALIGN_STR ".align 16,0x90"</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000"> ALIGN __ALIGN</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000"> ALIGN_STR __ALIGN_STR</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000"> ENTRY(name) \</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />  .globl SYMBOL_NAME(name); \<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />  ALIGN; \<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />  SYMBOL_NAME_LABEL(name)</span></div><p>用ENTRY(name)就能定义函数了。后来发现Flux OSKit中本来就提供了类似功能的宏，定义在inc/asm.h中。<br />使用的时候需要再写一个c语言的wrapper function（至少2.4.18里面是这么做的）<br />asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");</p><p><span class="posttime"><strong>Time : 2008-08-22 15:56<br />OS Lab 4 debugging notes [1]<br /></strong>系统调用 fork()</span></p><p>用Simics跟踪一条条汇编分析页表映射、寄存器值还真是体力活啊。。</p><p>1. 实现Copy On Write时，如果某一个用户态页面有多个进程共享，其中一个进程修改该页面时需要创建一个新的页面。一开始偶忘了把原来页面的内容复制到新的页面了 =_= 另外由于新的页面要代替老的页面，或者说它们的物理地址不同，但虚拟地址相同，我的方法是在内核态开辟一个大小为一个页面的空间作为中转。</p><p>2. do_fork函数中，子进程复制父进程的页表的同时会把父进程页表项置为不可写，注意最后要flush tlb。因为一开始没有flush tlb，导致最后用户态fork返回以后读取的信息来自于tlb，直接改写了共享页面中fork的返回地址，导致切换到子进程时fork的返回地址丢失。这个bug让我郁闷了两三个小时。。</p><p>3. 使用两次fork时，第二次fork返回的pid会被改掉。查了下发现为用户空间分配物理页面的代码里居然在分配好以后没有把对应的struct置为已使用，结果导致第二个子进程COW创建新页面时得到了原来的父进程页面，改写了父进程页面内容。<br /><br /></p><span class="posttime"><strong>Time : 2008-08-23 19:41<br />OS Lab4 debugging notes [2]</strong>  <br />系统调用 exec()
<p>1. 清空页表的用户空间映射的函数一开始写得yts，bug到处都是，比如free的时候没使用指向内存块首地址的指针，记录内存地址的变量没有累加。</p><p>2. exec传递给内核态的两个参数必须先在内核态保存一个副本，否则清空用户态页表后就无法得到这两个参数信息了。</p><p>3. 分配给用户态的页面必须先清零，一方面考虑到安全性，另一方面不清零会隐藏一些潜在的bug。一开始我没有在内核执行exec的时候完整的复制所有的参数，而是直接指向了原进程的内存空间，由于清空页表后再次申请新页表时得到了原来的页面，结果正好原来那个保存参数的页面和新进程的该页面重合了 =_= 于是浪费了不少时间在这个bug上</p><p><strong>Time : 2008-08-31 1:18<br />OS Lab5 debugging notes</strong><br />还算顺利，不过这个lab蛮无聊的，等有空了把syscall改成类似linux的做法，单一中断号+寄存器选择syscall。</p><p>1. 最花时间的一个bug是ls返回值没有改成应用程序数，结果一开始一直以为是brk系统调用没写好，最后才发现问题出在这么小的地方。</p><p>2. brk的逻辑还不是很清楚，尽管通过了简单的测试，但是debug输出的信息显示brk增长的很快，经常是一个页一个页涨的，看来还得查下brk的具体行为。</p><p>3. 写了个比MAGIC_BREAK好用一点的宏，因为用户态的程序都是按二进制读入的，Simics无法得到函数信息（函数名、当前行数等），利用C99的宏写了个新的INFO_BREAK<br /></p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000"> INFO_BREAK \</span><span style="COLOR: #000000"><br /><img id="Codehighlighter1_29_130_Open_Image" onclick="this.style.display='none'; Codehighlighter1_29_130_Open_Text.style.display='none'; Codehighlighter1_29_130_Closed_Image.style.display='inline'; Codehighlighter1_29_130_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_29_130_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_29_130_Closed_Text.style.display='none'; Codehighlighter1_29_130_Open_Image.style.display='inline'; Codehighlighter1_29_130_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">do</span><span style="COLOR: #000000"> </span><span id="Codehighlighter1_29_130_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_29_130_Open_Text"><span style="COLOR: #000000">{  \<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        lprintf_kern(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">break in %s:%d</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">, __FUNCTION__, __LINE__); \<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        MAGIC_BREAK; \<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000"> (</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">) \</span></div></span><img src ="http://www.blogjava.net/zellux/aggbug/233601.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zellux/" target="_blank">ZelluX</a> 2008-10-10 15:21 <a href="http://www.blogjava.net/zellux/archive/2008/10/10/233601.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>OSLab之中断处理 </title><link>http://www.blogjava.net/zellux/archive/2008/09/02/226312.html</link><dc:creator>ZelluX</dc:creator><author>ZelluX</author><pubDate>Tue, 02 Sep 2008 03:55:00 GMT</pubDate><guid>http://www.blogjava.net/zellux/archive/2008/09/02/226312.html</guid><wfw:comment>http://www.blogjava.net/zellux/comments/226312.html</wfw:comment><comments>http://www.blogjava.net/zellux/archive/2008/09/02/226312.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/zellux/comments/commentRss/226312.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zellux/services/trackbacks/226312.html</trackback:ping><description><![CDATA[发信人: <a href="http://bbs.fudan.edu.cn/cgi-bin/bbs/bbsqry?userid=Zellux">Zellux</a> (null), 信区: Software_06<br />标  题: OSLab之中断处理<br />发信站: 日月光华 (2008年08月30日20:15:58 星期六), 站内信件<br /><br />1. 准备工作<br />在开始分析Support Code之前，先配置下我们的Source Insight，使它能够支持.s文件的搜索。<br /><br />在Options-&gt;Document Options-&gt;Document Types中选择x86 Asm Source File，在File fileter中增加一个*.s，变成*.asm;*.inc;*.s  然后在Project-&gt;Add and Remove <br />Project Files中重新将整个oslab的目录加入，这样以后进行文本搜索时.s文件也不会漏掉了。<br /><br />2. Source Insight使用<br />接下来简单分析下内核启动的过程，在浏览代码的过程中可以迅速的掌握Source Insight的使用技巧。<br /><br />lib/multiboot /multiboot.s完成了初始化工作，可以看到其中一句call <br />EXT(multiboot_main)调用了C函数multiboot_main，使用ctrl+/搜索包含multiboot_main的所有文件，最终base_multiboot_main.c中找到了它的定义。依次进行cpu、内存的初<br />始化，然后开启中断，跳转到kernel_main函数，也是Lab1中所要改写的函数之一。另外<br />在这里可以通过ctrl+单击或者ctrl+=跳转到相应的函数定义处，很方便。<br /><br />3. irq处理初始化工作<br />来看下Lab 1的重点之一，irq的处理。跟踪multiboot_main-&gt;base_cpu_setup-&gt;base_cp<br />u_init-&gt;base_irq_init，可以看到这行代码<br />gate_init(base_idt, base_irq_inittab, KERNEL_CS);<br />继续使用ctrl+/找到base_irq_inittab的藏身之处：base_irq_inittab.s<br /><br />4. base_irq_inittab.s<br />这个汇编文件做了不少重复性工作，方便我们在c语言级别实现各种handler。<br />GATE_INITTAB_BEGIN(base_irq_inittab)   /* irq处理函数表的起始，还记得jump<br />                                          table 吗？ */<br />MASTER(0, 0)                           /* irq0 对应的函数 */<br /><br /><br />来看看这个MASTER(0, 0)宏展开后是什么样子：<br />#define MASTER(irq, num)                        \<br />    GATE_ENTRY(BASE_IRQ_MASTER_BASE + (num), 0f, ACC_PL_K|ACC_INTR_GATE) ;\<br />    P2ALIGN(TEXT_ALIGN)                     ;\<br />0:                                  ;\<br />    pushl   $(irq)          /* error code = irq vector */   ;\<br />    pushl   $BASE_IRQ_MASTER_BASE + (num)   /* trap number */   ;\<br />    pusha               /* save general registers */    ;\<br />    movl    $(irq),%ecx     /* irq vector number */     ;\<br />    movb    $1 &lt;&lt; num,%dl       /* pic mask for this irq */ ;\<br />    jmp master_ints<br /><br />依次push irq号，trap号（0x20+irq号），通用寄存器（eax ecx等）入栈，把irq号保<br />存到ecx寄存器，然后跳转到master_ints，master_ints是所有master interrupts公用<br />的代码。<br /><br />跳过master_ints的前几行，从第七行开始<br />    /* Acknowledge the interrupt */<br />    movb    $0x20,%al<br />    outb    %al,$0x20<br /><br />    /* Save the rest of the standard trap frame (oskit/x86/base_trap.h). */<br />    pushl   %ds<br />    pushl   %es<br />    pushl   %fs<br />    pushl   %gs<br /><br />    /* Load the kernel's segment registers.  */<br />    movw    %ss,%dx<br />    movw    %dx,%ds<br />    movw    %dx,%es<br /><br />    /* Increment the hardware interrupt nesting counter */<br />    incb    EXT(base_irq_nest)<br /><br />    /* Load the handler vector */<br />    movl    EXT(base_irq_handlers)(,%ecx,4),%esi<br /><br />注释写得很详细，首先发送0x20到0x20端口，也就是Lab1文档上所说的发送INT_CTL_DON<br />E到INT_CTL_REG，看来这一步support code已经替我们完成了。接下来保存四个段寄存<br />器ds es fs gs，并读入kernel态的段寄存器信息。<br /><br />最后一句很关键，把base_irq_handlers + %ecx * 4这个值保存到了esi寄存器中，%ecx<br />中保存了irq号，而*4则是一个函数指针的大小，那么base_irq_handlers是什么呢？继<br />续用ctrl+/搜索，可以在base_irq.c中找到这个数组的定义<br />unsigned int (*base_irq_handlers[BASE_IRQ_COUNT])(struct trap_state *ts)<br />且初始时这个数组的每一项都是base_irq_default_handler<br /><br />看来这句汇编代码的功能是把处理irq对应的函数地址保存到了esi寄存器中。<br />为了证实这一点，继续看base_irq_inittab.s的代码：<br />#else<br />    /* Call the interrupt handler with the trap frame as a parameter */<br />    pushl   %esp<br />    call    *%esi<br />    popl    %edx<br />#endif<br />果然，在保存了esp值后，紧接着就调用了esi指向的那个函数。而从那个函数返回后，<br />之前在栈上保存的相关信息都被恢复了：<br /><br />    /* blah blah blah */<br />    /* Return from the interrupt */<br />    popl    %gs<br />    popl    %fs<br />    popl    %es<br />    popl    %ds<br />    popa<br />    addl    $4*2,%esp   /* Pop trap number and error code */<br />    iret<br />这样就恢复到了进入这个irq处理单元前的状态，文档中所要求的保存通用寄存器这一步<br />其实在这里也已经完成了，不需要我们自己写代码。<br /><br />好了，这样一分析后，我们要做的事情就很简单，就是把base_irq_handlers数组中的对<br />应项改成相应的handler函数就行了。<br />注意index是相应的idt_entry号减去BASE_IRQ_SLAVE_BASE，或者直接使用IRQ号。 <br /><br />另外这个数组的初始值都是base_irq_default_handler，用ctrl+左键跳到这个函数的定<br />义，可以看到这个函数只有一句简单的输出语句：<br />    printf("Unexpected interrupt %d\n", ts-&gt;err);<br />而这就是没有注册handler前我们所看到的那句Unexpected interrupt 0的来源了。 <br /><br />5. struct trap_state *ts<br />所有的handler函数的参数都是一个struct trap_state *ts，这个参数是哪来的呢？<br />注意call *%esi的前一行<br />    /* Call the interrupt handler with the trap frame as a parameter */<br />    pushl   %esp<br />这里把当前的esp当作指向ts的指针传给了handler，列一下从esp指向的地址开始的内容<br />，也就是在此之前push入栈的内容： <br /><br />    pushl   $(irq)          /* error code = irq vector */   ;\<br />    pushl   $BASE_IRQ_MASTER_BASE + (num)   /* trap number */   ;\<br />    pusha               /* save general registers */    ;\<br />    pushl   %ds<br />    pushl   %es<br />    pushl   %fs<br />    pushl   %gs <br /><br />再看一下trap_state的定义，你会发现正好和push的顺序相反：<br />    /* Saved segment registers */<br />    unsigned int    gs;<br />    unsigned int    fs;<br />    unsigned int    es;<br />    unsigned int    ds; <br /><br />    /* PUSHA register state frame */<br />    unsigned int    edi;<br />    unsigned int    esi;<br />    unsigned int    ebp;<br />    unsigned int    cr2;    /* we save cr2 over esp for page faults */<br />    unsigned int    ebx;<br />    unsigned int    edx;<br />    unsigned int    ecx;<br />    unsigned int    eax; <br /><br />    /* Processor trap number, 0-31.  */<br />    unsigned int    trapno; <br /><br />    /* Error code pushed by the processor, 0 if none.  */<br />    unsigned int    err; <br /><br />而这个定义后面的<br />    /* Processor state frame */<br />    unsigned int    eip;<br />    unsigned int    cs;<br />    unsigned int    eflags;<br />    unsigned int    esp;<br />    unsigned int    ss;<br />则是发生interrupt时硬件自动push的五个数据（参见Understand the Linux Kernel） <br /><br />也就是说，ts指针指向的是调用当前handler前的寄存器状态，也是当前handler结束后<br />用来恢复的寄存器状态，了解这一点对以后的几个lab帮助很大。 <br /><br />p.s. 另外提一句和这个lab无关的话，非vm86模式下栈上是不会有v86_es等四个寄存器<br />信息的，所以以后根据task_struct指针计算*ts的地址时使用的偏移量不应该是sizeof(<br />struct trap_state) <br /><br />6. The End<br />这样差不多就把support code中处理interrupt的方法过了一遍（另外还有base_trap_in<br />ittab.s，不过和irq的处理很相似）<br /><br />了解这些后Lab1就比较简单了，不需要任何内嵌汇编代码即可完成。<br /><img src ="http://www.blogjava.net/zellux/aggbug/226312.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zellux/" target="_blank">ZelluX</a> 2008-09-02 11:55 <a href="http://www.blogjava.net/zellux/archive/2008/09/02/226312.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于计算机图形学的学习 原创 FatGarfield </title><link>http://www.blogjava.net/zellux/archive/2008/02/21/181080.html</link><dc:creator>ZelluX</dc:creator><author>ZelluX</author><pubDate>Thu, 21 Feb 2008 07:46:00 GMT</pubDate><guid>http://www.blogjava.net/zellux/archive/2008/02/21/181080.html</guid><wfw:comment>http://www.blogjava.net/zellux/comments/181080.html</wfw:comment><comments>http://www.blogjava.net/zellux/archive/2008/02/21/181080.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/zellux/comments/commentRss/181080.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zellux/services/trackbacks/181080.html</trackback:ping><description><![CDATA[这学期想上这门课，纯属娱乐，不准备深入。<br />主要还是考虑到有机会和安然小朋友合作一个大程 ;-)<br /><br /><div class="postText"><strong>关于计算机图形学的学习</strong><br />注意： <br />本文尽量避免理论化的描述，试图用最通俗的语言介绍一下计算机图形学的学习，以及一些参考书目和网络资源； <br />本文不涉及对概念的定义，以免陷入学术讨论之中 <br />本文是作者学习计算机图形学的体会，如果有不同的意见，请不要攻击和漫骂 <br /><br />本文合适的题目应当是:白话说学计算机图形学？ <br /><br />1． 引言 <br />什么是计算机图形学？ 本文尽量避免给它做严格的定义，但是通常来说，计算机图形学是数字图象处理的逆过程，这只是一个不确切的定义，后面我们会看到，实际上，计算机图形学、数字图象处理和计算机视觉在很多地方的区别不是非常清晰的，很多概念是相通的。 <br />计算机图形学是用计算机来画东西的学科，数字图象处理是把外界获得的图象用计算机进行处理的学科。在法国，图形图象是一门课程。 <br />如何学习计算机图形学呢？除了计算机图形学的基础知识以外，你还需要有以下的知识，你懂的越多，当然做的越好。 <br />* 英语， 你一定要把英语学好，如果你想学习计算机图形学的话，尽量看英文的书籍和资料 <br />* 数学， 计算机图形学里面的数学用的比较多，，我们可以列举一些常用的： <br />高等数学，数值分析，微分几何，拓扑，概率， 插值理论，（偏）微分方程… <br />* 物理， 如果你要进行基于物理的建模，一些物理理论是要学习的： <br />力学（运动学，动力学，流体力学…），光学，有限元… <br />* 编程语言： C或C++是计算机图形学最通用的‘普通话’， <br />* 数据结构： 你需要数据结构来描述你的图形对象，除了通用的链表、树等数据结构外，图形学还有自己特殊的数据结构 <br />* 其他类别： 有的时候你需要其他学科的知识，根据你的需要去学习吧 <br /><br />上面列举的不是你必须学习的东西，而是计算机图形学可能会用到的东西，一定要记住，不要指望通过一本教材就学会计算机图形学，它比你想象的要复杂的多。 <br /><br />2． 图形学的问题 <br />每个学科都有自己学科的特定问题，图形学要解决的是如何画出图来，得到需要的效果，当然这是图形学最大的一个问题。 <br /><br />在开始学习计算机图形学的时候，找一本简单的书看，对计算机图形学有个大概的认识，你就可以开始图形学之旅了： <br /><br />OpenGL Programming Guide: The Official Guide to Learning OpenGL, Version 1.4, Fourth Edition <br />OpenGL SuperBible (3rd Edition)  <br /><br />是比较好的学习计算机图形学的入门教材，在练中去学，一开始就去啃 <br /><br />Foley的 <br />Computer Graphics: Principles and Practice, Second Edition in C  <br />不是好主意，会看的一头雾水，一本什么都讲的书的结果往往是什么都没讲清楚。 <br />当你把OpenGL的基本内容掌握之后，你对图形学就有了大概的了解了 <br /><br />那么下面你可以来学习一下计算机图形学的数据结构和算法，下面的书比较适合 <br />Joseph O'Rourke 的Computational Geometry in C，书里面有C的源代码，讲述简单，清晰，适合程序员学习 <br /><br />总的来说，计算机图形学涉及到2大部分：建模和渲染 <br />2.1建模 <br /><br />你想画一个东西，首先要有它的几何模型，那么这个几何模型从什么地方来呢？下面的书很不错的： <br />Gerald Farin 的Curves and Surfaces for CAGD: A Practical Guide <br />这本书就有一点的难度了，呵呵，要努力看啊 <br /><br />这本书算是CAGD (计算机辅助几何设计)的经典图书，CAGD方面的全貌，还有2本很好的讲述曲面的书Bezier和Nurbs的书 <br /><br />Les A. Piegl, Wayne Tiller 的The Nurbs Book  <br />书里面有NURBS曲线、曲面的程序伪代码，很容易改成C的，书讲的通俗、易懂，但是你要有耐心看的：） <br /><br />曲线与曲面的数学 <br />这本书是法国人写的中文翻译版，里面还有Bezie本人写的序J，翻译的很不错的，看了你就掌握Bezier曲面技术了 <br /><br /><br />//另外一些你想知道的事情：其他的造型方式-开始 <br />注意：在后面会有这样的章节，标明 <br />//另外一些你想知道的事情：其他的造型方式-开始 <br />//另外一些你想知道的事情：其他的造型方式-结束 <br />里面是我认为的一些高级话题，跳过他们不影响你学习计算机图形学，但是要学好就要注意了，呵呵 <br />还有其他的一些造型技术，比如： <br />隐式曲面(Implicit Surface)的造型： <br />就是用函数形式为F( x ,y ,z ) = 0的曲面进行造型，这样的造型技术适合描述动物器官一样的肉乎乎的东西，有2本书推荐大家 <br />Jules Bloomenthal编辑的Introduction to Implicit Surfaces，是一本专著，讲述了Implicit Surface建模型(Modeling)，面片化(Polygonization)，渲染(Rendering)的问题 <br />Luiz Velho 的 Implicit Objects Computer Graphics 也是一本专著，讲述个更新的一些进展 <br /><br />细分曲面（Subdivision Surface）造型 <br />当用NURBS做造型的时候，曲面拼接是复杂的问题，在动画的时候，可能产生撕裂或者褶皱，Subdivision Surface用来解决这个问题 <br />Joe Warren的Subdivision Methods for Geometric Design: A Constructive Approach就是这方面的专著 <br /><br />从实际物体中得到造型，现在的技术可以用三维扫描仪得到物体表面的点，然后根据这些点把物体的表面计算出来，称为重建(Reconstruction)，因为这些技术之在文章中论述，所以我们省略对它的描述 <br /><br />//另外一些你想知道的事情：其他的造型方式-结束 <br /><br /><br />下面还是一个高级话题：） <br /><br />//另外一些你想知道的事情：光有造型是不够的！-开始 <br />在你的几何模型做好之后，有一些问题需要对这个模型进一步处理，得到适合的模型，当面片很多的时候，或者模型很复杂的时候，需要对几何模型进行简化，才可以满足一些实时绘制的需要，这个技术叫做层次细节（LOD-Level of Detail）。下面的书就是讲这个的： <br />David Luebke编著的 Level of Detail for 3D Graphics <br />//另外一些你想知道的事情：光有造型是不够的！-结束 <br /><br />2.2渲染 <br />有了模型，怎么把这个几何模型画出来呢？这个步骤就是渲染啦 <br />如果你看了上面的OpenGL的书，那么你就知道一些渲染的知识了，但是别高兴的太早，OpenGL使用的是局部光照模型（Local Illumination Model），不要被这个词吓住了 <br /><br />Local illumination Model指的是在做渲染的时候只考虑光源和物体之间的相互作用，不考虑物体和物体之间的影响，所以OpenGL不支持阴影，一个（半）透明物体的效果..，这些需要考虑物体之间的影响才可以实现。 <br /><br />//另外一些你想知道的事情：OpenGL可以实现阴影-开始 <br />OpenGL本身不支持，但是通过一些方法可以实现的：），用Google搜索一下 <br />Shadow Volume, OpenGL就找到答案啦 <br />//另外一些你想知道的事情：OpenGL可以实现阴影-结束 <br /><br />Global Illumination Model 这类模型考虑的就比较全啦。现在关于Global Illumination的技术有3大类，具体的技术就不在这里介绍了，如果想了解，可以联系我，大家一起讨论： <br /><br />光线追踪(Ray Tracing) <br />关于Ray Tracing的好书有2本： <br /><br />Andrew Glassner 的An Introduction to Ray tracing  <br />Glasser是图形界的名人，这本书也是Ray Tracing的经典 <br /><br />R. Keith Morley, Peter Shirley 的Realistic Ray Tracing, Second Edition <br />这本书第一版是伪代码，第二版是C代码。它的结构不是很清楚，虎头蛇尾的感觉。 <br /><br />辐射度(Radiosity) <br />关于Radiosity的好书有4本： <br />Michael Cohen 的Radiosity and Realistic Image Synthesis ， Cohen获得SIGGRAPH 1998计算机图形学成就奖，他把Radiosity变成实际可用，现在Cohen在MSR图形<img height="15" alt="::URL::" hspace="2" src="http://www.blogcn.com/images/aurl.gif" width="15" align="absBottom" border="0" /><a href="http://research.microsoft.com/~cohen/CohenSmallBW2.jpg" target="_blank">http://research.microsoft.com/~cohen/CohenSmallBW2.jpg</a><br /><br />Francois X. Sillion的Radiosity and Global Illumination ， Sillion是法国人，他的主要研究方向是Radiosity，这本书写的很不错的，非常清晰 <br /><br />Philip Dutre 的新书Advanced Global Illumination ，看起来还不错，刚拿到手，还没看，呵呵，所以不好评价 <br /><br />Ian Ashdown的Radiosity: A Programmer's Perspective  <br />有源代码的书啊！！ 就凭这个，得给5***** <br /><br />Photon mapping <br />这个我也不知道怎么翻译，呵呵。这个技术出现的比较晚，一本好书！ <br />Henrik Wann Jensen的Realistic Image Synthesis Using Photon Mapping <br />Henrik Wann Jensen是Photon mapping技术的发明者 <br /><br />3.3这些也是图形学吗？ 图形和图象的区别模糊了：（ <br />除了上面讲的‘经典’的计算机图形学，还有下面的一些东西，它们也叫计算机图形学吗？是的！！！ <br />3.3.1非真实性图形学（Non-Photorealistic Graphics） <br />真实性不是计算机图形学的唯一要求，比如：你给我画一个卡通效果的图出来，或者我要用计算机画水彩画怎么办？或者：把图象用文字拼出来怎么做？，解决这些问题要用到非真实性图形学， 好书继续推荐！！！ <br />Bruce Gooch, Amy Ashurst Gooch的 Non-Photorealistic Rendering  <br /><br />3.3.2体图形学(Volume Graphics) <br />用CT机做很多切片（比如头骨），那么能通过这些切片得到3D的头骨吗？Volume Graphics就是解决这样的问题的 <br />Min Chen 编著的Volume Graphics  <br /><br />上面的2个图形学技术就和图象的界限不明显了，实际上他们是图形图象的综合 <br /><br /><br />4 .还有其他的书吗？ <br />还有一些好书啊，呵呵，好书看不完的：），继续放送： <br /><br />Graphics Gems I ~ V，一大帮子人写的书，包括研究人员，程序员… <br />有计算机图形学的各种数据结构，编程技巧 <br /><br />Tomas Akenine-Moller 等人编著的Real-Time Rendering (2nd Edition)  <br />许多最新的计算机图形学进展 <br /><br />David Ebert等人的Texturing &amp; Modeling: A Procedural Approach, Third Edition  <br />讲述如何通过程序实现纹理、山、地形等图形学要素 <br />F. Kenton Musgrave号称分形狂(Fractal Mania) <br />Ken Perlin就是Perlin噪声的发明者，用过3d软件的人对Perlin Noise不会陌生的 <br /><br />关于图形学的特定对象，有特定的专题图书， <br />Evan Pipho Focus On 3D Models,对于图形学的常用模型格式，进行了讲解 <br />Trent Polack的 Focus On 3D Terrain Programming ，讲地形的 <br />Donald H. House 的Cloth Modeling and Animation ，讲布料的 <br />Nik Lever的Real-time 3D Character Animation with Visual C++ ，讲角色动画的 <br />…… <br /><br />还有：） <br />Richard Parent的 Computer Animation: Algorithms and Techniques，当然是讲动画的啦，呵呵。 <br />David H. Eberly的3D Game Engine Design : A Practical Approach to Real-Time Computer Graphics ，有代码的啊！呵呵：） <br /><br />最后，没事情的时候，看看下面的书吧 <br />Alan H. Watt， 3D Computer Graphics (3rd Edition)  <br /><br />James D. Foley等人的 Computer Graphics: Principles and Practice in C (2nd Edition) ，这本圣经没事的时候再看吧，呵呵 <br /><br />累了：（ 不说了，上面的书差不多了，还有一些shader的书，我不了解，以后会补上的：） <br /><br />5.从哪里找到这些书啊？还有什么资源啊？ <br />我保证，上面的书在www.amazon.com 都可以买到：） 别打我 <br /><br />那好，大部分的书在国家图书馆可以复印到，北京的兄弟有福啦，3年前的书借出来复印，1角/页，但是新书要早图书馆里复印，5~6角/页，还是比Amazon便宜啊，呵呵。 <br /><br />不行大家就到国外买，合买吧，还负担的起。 <br />我对DirectX不了解，所以没有涉及关于DirectX的内容：） <br /></div><img src ="http://www.blogjava.net/zellux/aggbug/181080.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zellux/" target="_blank">ZelluX</a> 2008-02-21 15:46 <a href="http://www.blogjava.net/zellux/archive/2008/02/21/181080.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>orz 虎书的一个比喻</title><link>http://www.blogjava.net/zellux/archive/2008/01/05/172985.html</link><dc:creator>ZelluX</dc:creator><author>ZelluX</author><pubDate>Sat, 05 Jan 2008 08:36:00 GMT</pubDate><guid>http://www.blogjava.net/zellux/archive/2008/01/05/172985.html</guid><wfw:comment>http://www.blogjava.net/zellux/comments/172985.html</wfw:comment><comments>http://www.blogjava.net/zellux/archive/2008/01/05/172985.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zellux/comments/commentRss/172985.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zellux/services/trackbacks/172985.html</trackback:ping><description><![CDATA[<p>讲到out-of-bounds detection时，有这么一段<br />
One may say, by way of excuse, "but the language in which, I program has the kind of address arithmetics that makes it impossible to know the bounds of an array." Yes, and the man who shot his mother and father threw himself upon the mercy of the court because he was an orphan.<br />
很强大，很贴切</p>
<img src ="http://www.blogjava.net/zellux/aggbug/172985.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zellux/" target="_blank">ZelluX</a> 2008-01-05 16:36 <a href="http://www.blogjava.net/zellux/archive/2008/01/05/172985.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用GraphViz画了ICS Lab1的call graph</title><link>http://www.blogjava.net/zellux/archive/2007/11/27/163536.html</link><dc:creator>ZelluX</dc:creator><author>ZelluX</author><pubDate>Tue, 27 Nov 2007 12:04:00 GMT</pubDate><guid>http://www.blogjava.net/zellux/archive/2007/11/27/163536.html</guid><wfw:comment>http://www.blogjava.net/zellux/comments/163536.html</wfw:comment><comments>http://www.blogjava.net/zellux/archive/2007/11/27/163536.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zellux/comments/commentRss/163536.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zellux/services/trackbacks/163536.html</trackback:ping><description><![CDATA[<p>其实关键的工具还是google的gprof2dot<br />
<a href="http://google-gprof2dot.googlecode.com/">http://google-gprof2dot.googlecode.com/</a><br />
<br />
四种风格，应该在生成dot的时候还可以设定其他信息，比如每个结点费时等，毕竟profiling这个指数更重要</p>
<br />
<img style="width: 369px; height: 286px" height="286" alt="" src="http://www.blogjava.net/images/blogjava_net/zellux/graph_circo.jpeg" width="369" border="0" /><img style="width: 447px; height: 346px" height="346" alt="" src="http://www.blogjava.net/images/blogjava_net/zellux/graph_fdp.jpeg" width="447" border="0" /><br />
<img style="width: 558px; height: 433px" height="433" alt="" src="http://www.blogjava.net/images/blogjava_net/zellux/graph_neato.jpeg" width="558" border="0" /><img style="width: 414px; height: 321px" height="321" alt="" src="http://www.blogjava.net/images/blogjava_net/zellux/graph_twopi.jpeg" width="414" border="0" /> 
<img src ="http://www.blogjava.net/zellux/aggbug/163536.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zellux/" target="_blank">ZelluX</a> 2007-11-27 20:04 <a href="http://www.blogjava.net/zellux/archive/2007/11/27/163536.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LL(1) 语法解析</title><link>http://www.blogjava.net/zellux/archive/2007/09/24/147878.html</link><dc:creator>ZelluX</dc:creator><author>ZelluX</author><pubDate>Mon, 24 Sep 2007 11:34:00 GMT</pubDate><guid>http://www.blogjava.net/zellux/archive/2007/09/24/147878.html</guid><wfw:comment>http://www.blogjava.net/zellux/comments/147878.html</wfw:comment><comments>http://www.blogjava.net/zellux/archive/2007/09/24/147878.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zellux/comments/commentRss/147878.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zellux/services/trackbacks/147878.html</trackback:ping><description><![CDATA[还是做一点笔记，记得牢一些<br />
<br />
有了follow和first集合后，就可以构造一张预测解析表(predictive parsing table)了。<br />
具体方法是：<br />
对于任一产生式X -&gt; &#402;，找到first(&#402;)中的每一个元素T，把X -&gt; &#402;填充到X行T列中去；<br />
如果&#402; nullable，还要把X -&gt; &#402;填充到X行follow(&#402;)列中去<br />
<br />
预测解析表构造完成后，如果某格中不止一个产生式，则说明该语法不适用于预测解析表；<br />
如果每格至多一个产生式，则该语法被称为LL(1)&nbsp; Left-to-right parse, Leftmost-derivation, 1-symbol lookahead&nbsp;&nbsp;&nbsp;&nbsp;
 <img src ="http://www.blogjava.net/zellux/aggbug/147878.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zellux/" target="_blank">ZelluX</a> 2007-09-24 19:34 <a href="http://www.blogjava.net/zellux/archive/2007/09/24/147878.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>总算弄明白生成first和follow集合的算法了</title><link>http://www.blogjava.net/zellux/archive/2007/09/23/147627.html</link><dc:creator>ZelluX</dc:creator><author>ZelluX</author><pubDate>Sun, 23 Sep 2007 14:22:00 GMT</pubDate><guid>http://www.blogjava.net/zellux/archive/2007/09/23/147627.html</guid><wfw:comment>http://www.blogjava.net/zellux/comments/147627.html</wfw:comment><comments>http://www.blogjava.net/zellux/archive/2007/09/23/147627.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/zellux/comments/commentRss/147627.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zellux/services/trackbacks/147627.html</trackback:ping><description><![CDATA[太笨了，看了好久才明白。。。<br />
first集合没有问题<br />
<br />
follow集合：<br />
以A -&gt; aBb为例，如果b nullable，则follow(B)包括follow(A)，原因很简单，把A看成一个整体，当作为production的右式时它后面直接跟的元素自然也可能是B后面直接跟的元素，因为b可能为空。<br />
<br />
理解follow集合的定义后，虎书上给出的算法<br />
if Yi+1 ... Yk are all nullable<br />
&nbsp;&nbsp;&nbsp; then FOLLOW(Yi) = FOLLOW(Yi) U FOLLOW(X)<br />
if Yi+1 ... Yj-1 are all nullable<br />
&nbsp;&nbsp;&nbsp; then FOLLOW(Yi) = FOLLOW(Yi) U FIRST(Yj)<br />
就不难理解了<br />
<br />
 <img src ="http://www.blogjava.net/zellux/aggbug/147627.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zellux/" target="_blank">ZelluX</a> 2007-09-23 22:22 <a href="http://www.blogjava.net/zellux/archive/2007/09/23/147627.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Lex 使用笔记</title><link>http://www.blogjava.net/zellux/archive/2007/09/09/143841.html</link><dc:creator>ZelluX</dc:creator><author>ZelluX</author><pubDate>Sun, 09 Sep 2007 14:22:00 GMT</pubDate><guid>http://www.blogjava.net/zellux/archive/2007/09/09/143841.html</guid><wfw:comment>http://www.blogjava.net/zellux/comments/143841.html</wfw:comment><comments>http://www.blogjava.net/zellux/archive/2007/09/09/143841.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zellux/comments/commentRss/143841.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zellux/services/trackbacks/143841.html</trackback:ping><description><![CDATA[<p>1. 写了个测试脚本，逐个测试testcases目录下的各个tiger程序，并统计出错数<br />
#!/usr/bin/python</p>
<p>from commands import *</p>
<p>countOk = countError = 0</p>
<p>for i in range(1,50):<br />
&nbsp;&nbsp;&nbsp; result = getstatusoutput('./lextest ../testcases/test%s.tig' % i)<br />
&nbsp;&nbsp;&nbsp; if (result[0] == 0):<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print('Test case %s: OK' % i)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; countOk += 1<br />
&nbsp;&nbsp;&nbsp; else:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print('Error on test case %s with errorno %s' % (i, result[0]))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; countError += 1</p>
<p>print("Total cases: %s" % (countOk + countError))<br />
print("Passed cases: %s" % (countOk))<br />
print("Failed cases: %s" % (countError))</p>
<p>2. 状态：<br />
定义的状态名不能与已经定义的变量/宏名冲突。在处理字符串的时候定义了个&lt;STRING&gt;状态，和tokens.h中的STRING冲突了，结果解析的时候被认成了BAD_TOKEN。<br />
</p>
 <img src ="http://www.blogjava.net/zellux/aggbug/143841.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zellux/" target="_blank">ZelluX</a> 2007-09-09 22:22 <a href="http://www.blogjava.net/zellux/archive/2007/09/09/143841.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Lexical Analysis - Finite Automata</title><link>http://www.blogjava.net/zellux/archive/2007/09/06/143285.html</link><dc:creator>ZelluX</dc:creator><author>ZelluX</author><pubDate>Thu, 06 Sep 2007 14:09:00 GMT</pubDate><guid>http://www.blogjava.net/zellux/archive/2007/09/06/143285.html</guid><wfw:comment>http://www.blogjava.net/zellux/comments/143285.html</wfw:comment><comments>http://www.blogjava.net/zellux/archive/2007/09/06/143285.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zellux/comments/commentRss/143285.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zellux/services/trackbacks/143285.html</trackback:ping><description><![CDATA[<p>DFA(deterministic finite automaton): 从同一状态出发的边都标记有不同的符号<br />
<br />
可以把一个DFA用一个转置矩阵(transition matrix)表示，矩阵的第i行记录状态i向其他状态跳转的情况，edges[i][j]表示状态i时吃掉一个j符号后跳转到edges[i][j]状态。<br />
<br />
DFA的一个好处就是可以识别最长的匹配，比如对于IF8这个字符串，可以被识别为一个变量而不是一个关键字加数字。<br />
处理方法是保留最后一次自动机的终结状态Last-Final及其相对应的字符位置Input-Position-at-Last-Final。<br />
每次进入一个终结状态，就更新这两个变量。<br />
遇到死路(dead state, a nonfinal state with no output transitions)，通过这两个变量回复到上一个终结状态。<br />
<br />
NFA(nondeterministic finite automaton): 从同一状态出发的边可能标记有相同的符号<br />
由于从同一状态出发选择的路径可能有多条，非确定性自动机总是需要进行&#8220;猜测&#8221;，而且总要做出正确的猜测。</p>
  <img src ="http://www.blogjava.net/zellux/aggbug/143285.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zellux/" target="_blank">ZelluX</a> 2007-09-06 22:09 <a href="http://www.blogjava.net/zellux/archive/2007/09/06/143285.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>BNF 文法 (1) - 语法树 | 二义性的解决</title><link>http://www.blogjava.net/zellux/archive/2007/07/27/132722.html</link><dc:creator>ZelluX</dc:creator><author>ZelluX</author><pubDate>Fri, 27 Jul 2007 03:28:00 GMT</pubDate><guid>http://www.blogjava.net/zellux/archive/2007/07/27/132722.html</guid><wfw:comment>http://www.blogjava.net/zellux/comments/132722.html</wfw:comment><comments>http://www.blogjava.net/zellux/archive/2007/07/27/132722.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zellux/comments/commentRss/132722.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zellux/services/trackbacks/132722.html</trackback:ping><description><![CDATA[1. 考虑表达式3 + 4的语法分析树，exp( exp(number (3)), op(+), exp(number (4)) )。<br>还有一种更为简单的表示方法，例如将(34 - 3) * 42表示为*(-(34, 3), 42)<br>后者被称为抽象语法树(abstract syntax tree)，它的效率更高，但是不能从中重新得到记号序列。<br><br><br>2. 简单的算术表达式的抽象语法树的数据类型<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #000000">typedef&nbsp;</span><span style="COLOR: #0000ff">enum</span><span style="COLOR: #000000">&nbsp;{Plus,&nbsp;Minus,&nbsp;Times}&nbsp;OpKind;<br>typedef&nbsp;</span><span style="COLOR: #0000ff">enum</span><span style="COLOR: #000000">&nbsp;{OpKind,&nbsp;ConstKind}&nbsp;ExpKind;<br>typedef&nbsp;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;streenode<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;ExpKind&nbsp;kind;<br>&nbsp;&nbsp;&nbsp;&nbsp;OpKind&nbsp;op;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;streenode&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">lchild,&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">rchild;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;val;<br>}&nbsp;STreeNode;<br>typedef&nbsp;STreeNode&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">SyntaxTree;</span></div>
<br><br>3. 简单算术文法的二义性解决<br>例如串34 - 3 * 42，可以有两种不同的分析树： <br>34 - 3 = 31, 31 * 42<br>3 * 42 = 126, 34 - 126<br>解决二义性的方法通常有两种，一种是设置消除二义性规则（disambiguating rule)，如设置运算符的优先权；另一种是将文法限制为只能分析成单一的分析树，如将上式表示为34 - (3 * 42)。<br><br>设置运算符的优先权<br>定义如下的简单表达式文法：<br>exp -&gt; exp addop exp | term<br>addop -&gt; + | -<br>term -&gt; term mulop term | factor<br>mulop -&gt; *<br>factor -&gt; (exp) | number<br>这样乘法被归在term规则下，而加减法被归在exp规则下，因此在分析树和语法树中加减法将更接近于根，由此也就接受了更低一级的优先权。<br>这样将算符放在不同的优先权级别中的办法是在语法说明中使用BNF的一个标准方法，成为优先级联(precedence cascade)。<br>接下来的问题就是如何让同级运算从左往右。<br>可以将表达式文法改为<br>exp -&gt; exp addop <span style="FONT-WEIGHT: bold; COLOR: red">term</span> | term<br>addop -&gt; + | -<br>term -&gt; term mulop <span style="FONT-WEIGHT: bold; COLOR: red">factor</span> | factor<br>mulop -&gt; *<br>factor -&gt; (exp) | number <br>这样就使得加法和减法左结合，而如果写成<br>exp -&gt; term addop exp | term<br>这样的形式，则会使得它们右结合。<br><br>4. else 悬挂的问题<br>简单 if 语句的文法<br>statement -&gt; if-stmt | other<br>if-stmt -&gt; if (exp) statement | if (exp) statement else statement<br>exp -&gt; 0 | 1<br>考虑串 if (0) if (1) other else other<br>这时else other的悬挂就出现了二义性，它既可以理解为是if (0)匹配失败后的选择，也可以理解为if (0)匹配成功，if (1) 匹配失败后的结果。<br>消除二义性的规则是<br>statement -&gt; matched-stmt | unmatched-stmt<br>matched-stmt -&gt; if (exp) matched-stmt else matched-stmt | other<br>unmatched-stmt -&gt; if (exp) statement | if (exp) matched-stmt else unmatched-stmt<br>exp -&gt; 0|1<br>由这个定义，上面的串就可以分析为<br>if (0)&nbsp; // unmatched-stmt<br>&nbsp;&nbsp;&nbsp; if (1) other else other&nbsp; // matched-stmt<br><br>另外一种解决方法就是在语法中解决这个问题。<br>可以要求出现else部分，或者使用一个分段关键字(bracketing keyword)，例如<br>if (1) then<br>&nbsp;&nbsp;&nbsp; if (0) then other<br>&nbsp;&nbsp;&nbsp; else other<br>&nbsp;&nbsp;&nbsp; endif<br>endif<br><br>
 <img src ="http://www.blogjava.net/zellux/aggbug/132722.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zellux/" target="_blank">ZelluX</a> 2007-07-27 11:28 <a href="http://www.blogjava.net/zellux/archive/2007/07/27/132722.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>总算成功的运行了个词法解析程序</title><link>http://www.blogjava.net/zellux/archive/2007/07/20/131502.html</link><dc:creator>ZelluX</dc:creator><author>ZelluX</author><pubDate>Fri, 20 Jul 2007 07:46:00 GMT</pubDate><guid>http://www.blogjava.net/zellux/archive/2007/07/20/131502.html</guid><wfw:comment>http://www.blogjava.net/zellux/comments/131502.html</wfw:comment><comments>http://www.blogjava.net/zellux/archive/2007/07/20/131502.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zellux/comments/commentRss/131502.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zellux/services/trackbacks/131502.html</trackback:ping><description><![CDATA[书上的例子，计算行号的，但是书中对行的定义是<br>line *.\n<br>貌似不正确，flex无法解析，改成line (.)*\n就可以了。<br>书上的样例也没有yywrap，写了个空函数。<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">%</span><span style="color: #000000;">{<br></span><span style="color: #008000;">/*</span><span style="color: #008000;">&nbsp;a&nbsp;Lex&nbsp;program&nbsp;that&nbsp;adds&nbsp;line&nbsp;numbers<br>&nbsp;&nbsp;&nbsp;to&nbsp;lines&nbsp;of&nbsp;text,&nbsp;printing&nbsp;the&nbsp;new&nbsp;text<br>&nbsp;&nbsp;&nbsp;to&nbsp;the&nbsp;standard&nbsp;output<br></span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">stdio.h</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;lineno&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br></span><span style="color: #000000;">%</span><span style="color: #000000;">}<br>line&nbsp;(.)</span><span style="color: #000000;">*</span><span style="color: #000000;">\n&nbsp;<br></span><span style="color: #000000;">%%</span><span style="color: #000000;"><br>{line}&nbsp;{&nbsp;printf&nbsp;(</span><span style="color: #000000;">"</span><span style="color: #000000;">%5d&nbsp;%s</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;lineno</span><span style="color: #000000;">++</span><span style="color: #000000;">,&nbsp;yytext);&nbsp;}<br></span><span style="color: #000000;">%%</span><span style="color: #000000;"><br>main()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;yylex();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>}<br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;yywrap()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>}<br></span></div>
生成flex程序：flex linecount.lex<br>编译：gcc lex.yy.c<br>利用管道输入刚才的程序：cat linecount.lex | ./a.out<br><br><br> <img src ="http://www.blogjava.net/zellux/aggbug/131502.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zellux/" target="_blank">ZelluX</a> 2007-07-20 15:46 <a href="http://www.blogjava.net/zellux/archive/2007/07/20/131502.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Lex约定</title><link>http://www.blogjava.net/zellux/archive/2007/07/20/131470.html</link><dc:creator>ZelluX</dc:creator><author>ZelluX</author><pubDate>Fri, 20 Jul 2007 06:35:00 GMT</pubDate><guid>http://www.blogjava.net/zellux/archive/2007/07/20/131470.html</guid><wfw:comment>http://www.blogjava.net/zellux/comments/131470.html</wfw:comment><comments>http://www.blogjava.net/zellux/archive/2007/07/20/131470.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zellux/comments/commentRss/131470.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zellux/services/trackbacks/131470.html</trackback:ping><description><![CDATA[<p>1. 允许将字符放在引号中作为真正的字符匹配。</p>
<p>例如要匹配\*可以写成<a>\\\</a>*，也可以是"\*"<br></p>
<p>2. 方括号中大多数元字符都可以无需引号直接引出。如("+"|"-")可以写成[-+]，但不能写成[+-]，因为-在中括号中可以作为表示范围的连字符。<br></p>
<p>3. 大括号可以指出正则表达式的名字，但不能递归调用。</p>
<p>nat [0-9]+</p>
<p>signedNat (+|-) ? {nat}</p>
<p>&nbsp;</p>
 <img src ="http://www.blogjava.net/zellux/aggbug/131470.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zellux/" target="_blank">ZelluX</a> 2007-07-20 14:35 <a href="http://www.blogjava.net/zellux/archive/2007/07/20/131470.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>还是关于编译器的优化</title><link>http://www.blogjava.net/zellux/archive/2007/07/19/131375.html</link><dc:creator>ZelluX</dc:creator><author>ZelluX</author><pubDate>Thu, 19 Jul 2007 15:41:00 GMT</pubDate><guid>http://www.blogjava.net/zellux/archive/2007/07/19/131375.html</guid><wfw:comment>http://www.blogjava.net/zellux/comments/131375.html</wfw:comment><comments>http://www.blogjava.net/zellux/archive/2007/07/19/131375.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/zellux/comments/commentRss/131375.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zellux/services/trackbacks/131375.html</trackback:ping><description><![CDATA[装了fcitx以后thunderbird罢工了。。。现在只能用Google groups上新闻组了，不过fcitx的确不错的说。<br><br>cs书上的一个习题，在执行i=0这样的命令时是用: xorl %edx, %edx <br>为什么不用 movl $0, %edx呢？
<br>老大: 一般的说立即数的存取是内存操作，而前一条指令是寄存器操作。所以Itanium上有专门的寄存器放0. <br>SecretVan@smth.org: 可能跟标志位有关系，如xor清零后紧跟一个条件跳转。
<br>先把这些回答放这，以后在回过头来看。<br><br> <img src ="http://www.blogjava.net/zellux/aggbug/131375.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zellux/" target="_blank">ZelluX</a> 2007-07-19 23:41 <a href="http://www.blogjava.net/zellux/archive/2007/07/19/131375.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个编译器优化问题</title><link>http://www.blogjava.net/zellux/archive/2007/07/19/131179.html</link><dc:creator>ZelluX</dc:creator><author>ZelluX</author><pubDate>Wed, 18 Jul 2007 16:51:00 GMT</pubDate><guid>http://www.blogjava.net/zellux/archive/2007/07/19/131179.html</guid><wfw:comment>http://www.blogjava.net/zellux/comments/131179.html</wfw:comment><comments>http://www.blogjava.net/zellux/archive/2007/07/19/131179.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zellux/comments/commentRss/131179.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zellux/services/trackbacks/131179.html</trackback:ping><description><![CDATA[看到汇编中的基本运算这一节，想看看传说中的编译器把a*2优化为a&lt;&lt;1是不是真的呢，写了个函数试了下：<br>int func(int x)<br>{<br>&nbsp;&nbsp;&nbsp; return x * 2;<br>}<br>用gcc -O2 -S test.c
编译，发现优化后是用了加法，而不是位移<br>func:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl&nbsp;&nbsp; %ebp<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;&nbsp; %esp, %ebp<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;&nbsp; 8(%ebp), %eax<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; popl&nbsp;&nbsp;&nbsp; %ebp<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; addl&nbsp;&nbsp;&nbsp; %eax, %eax<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret <br>BBS上问了，老大说一般加法不会慢。<br>又试了一下把*2改成*3，仍然是使用leal&nbsp;&nbsp; &nbsp;(%eax,%eax,2), %eax进行加法操作完成的，而改成*4就使用位移了。<br>其他回答：<br>SecretVan@smth.org: CISC指令集上更倾向于选择功能一样而长度较短的指令，带了立即数之后指令就长了，如果使用寄存器那更得不偿失<br>Nineveh@smth.org: 因为 add 的长度短于或等于 sal，速度快于或等于 sal，吞吐量大于或等于 sal。
<br>lib@rygh: 在P4里面我记得一条加法指令是0.5个cycle.移位指令撑死了也要0.5个cycle吧，没听说过有0.25cycle的指令。
<br> <img src ="http://www.blogjava.net/zellux/aggbug/131179.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zellux/" target="_blank">ZelluX</a> 2007-07-19 00:51 <a href="http://www.blogjava.net/zellux/archive/2007/07/19/131179.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>正则表达式</title><link>http://www.blogjava.net/zellux/archive/2007/07/17/130924.html</link><dc:creator>ZelluX</dc:creator><author>ZelluX</author><pubDate>Tue, 17 Jul 2007 12:46:00 GMT</pubDate><guid>http://www.blogjava.net/zellux/archive/2007/07/17/130924.html</guid><wfw:comment>http://www.blogjava.net/zellux/comments/130924.html</wfw:comment><comments>http://www.blogjava.net/zellux/archive/2007/07/17/130924.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zellux/comments/commentRss/130924.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zellux/services/trackbacks/130924.html</trackback:ping><description><![CDATA[<p>1. {a, b, c}上的串S中，任何两个b都不相连，用正则表达式表示为<br>(a|c|ba|bc)*(b|空)</p>
<p>&nbsp;<br>2. Pascal注释的表示</p>
<p>{(~})*}<br>{ } 中间为任意非}的符号，注意表达的严谨<br></p>
<p>&nbsp;</p>
<p>3. C注释的表示就困难很多</p>
<p>例如要表示ba ...(没有ab)... ab这样的字符串，不能简单的写成</p>
<p>ba(~(ab))*ab</p>
<p>因为~非运算符通常只适用于单字符，否则容易产生混淆。</p>
<p>b*(a*~(a|b)b*)*a*</p>
<p>像这样的定义很难读，而且难以证明其正确性，因此在真正的扫描程序中通常用特殊方法解决。 </p>
 <img src ="http://www.blogjava.net/zellux/aggbug/130924.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zellux/" target="_blank">ZelluX</a> 2007-07-17 20:46 <a href="http://www.blogjava.net/zellux/archive/2007/07/17/130924.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>