摘要: 本人写的一个正则到nfa的bug刚写完前面的那篇,自己用脑子过了一下,发现了一个bug。具体情况如下。这个bug的产生条件是多次调用假名的时候,每次调用都会修改假名的nfa图。直接这么说不好理解,我就拿例子来讲吧。假设我们已经定义了一个假名num,而现在我们有一个正则表达式调用了两次这个假名,nums:[num][num],根据前面那篇文章里面所谈到的方法,会生成如下所示的nfa。这里假设num的开始节点为1,结束节点为2。 但是由于两个节点1和两个节点2引用的是相同的位置,所以上面的图等价于下面的图。可以明显的看出这个并不是我们所需要的规则,图中所表示的是[num]+。之... 阅读全文
posted @ 2013-06-24 16:16 huangnima 阅读(345) 评论(0) 推荐(0) 编辑
摘要: [在此处输入文章标题]正则到nfa前言在写代码的过程中,本来还想根据龙书上的说明来实现re到nfa的转换。可是写代码的时候发现,根据课本来会生成很多的无用过渡节点和空转换边,需要许多的代码。为了简化代码,我实现了我自己的re到nfa的规则。注意我的这套re规则只包括如下几种类型:闭包,即*运算符一个或多个,即+运算符存在或不存在,即?运算符。这三个运算符的优先级最高而且都是单目运算符。括号括起来的,即成对的括号,其实也不算运算符,只能当作分隔符。中括号括起来的,作为假名,也算是分隔符连接运算符,即.运算符,但是在输入re的时候默认不输入这个符号,只有在处理输入的时候才添加这个符号。这个运算符的 阅读全文
posted @ 2013-06-24 15:10 huangnima 阅读(2438) 评论(0) 推荐(0) 编辑
摘要: 这个版本修改了前面版本的两个个bug。第一个:识别到字符集的时候,只是将name_number加1,却并不对reg_pattern_table[name_number]进行初始化。第二个:识别到假名的时候,并不为他分配一个name_number,而只是在hash表中为其分配一个表项。现在,当识别到这两个的时候,都会为之分配一个name_number,并在reg_pattern_table中正确的初始化。相关的修改的代码都在tackle_particle()函数中。还有对tackle_cat()函数的定义移动到了tackle_invisible_cat()函数的前面。另外一个重大的修改就是,将当 阅读全文
posted @ 2013-06-24 13:23 huangnima 阅读(713) 评论(0) 推荐(0) 编辑
摘要: 关于正则的语法方面,就做到这吧。下一步是生成nfa,进而dfa,以及dfa的最简化。等下一个版本出来的话,估计要好久了。 1 #include 2 #include 3 #include 4 //这个版本在上一个版本的基础上,添加了?\+这两个操作符,这两个操作符都是单目操作符,跟*操作符同一级别 5 //因此碰到这两个操作符的时候,跟*操作符一样的处理 6 //除了新加的操作符外,还添加了字符集,模式为a-z这种,但是字符集只能通过假名来引用 7 //因此如果想使用字符集,则必须先通过假名来定义这个字符集,然后在后续的正则表达式中通过假名 8 //来使用这个字符集 9... 阅读全文
posted @ 2013-06-23 15:33 huangnima 阅读(394) 评论(0) 推荐(0) 编辑
摘要: 默认为转义字符的优先级最高,而且转义字符的作用是让输入处理函数把转义字符的下一个字符当作字符值看待,而不是可能的操作符。当前版本并不支持c语言中那些特殊含义的转义字符,例如\t。这个特性将会在之后的版本中加上。而对于c语言中的三元组转义字符,我将不会考虑他的存在,没啥意义。下面是代码,欢迎测试。 1 #include 2 #include 3 #include 4 //这个版本允许定义正则子表达式,定义的时候以名字开头,然后是冒号,然后是正则表达式主体。 5 //在引用子表达式的时候,需要用中括号把子表达式括起来,因此中括号也跟其他操作符一样,作为保留字符 6 //这个版本加... 阅读全文
posted @ 2013-06-23 13:07 huangnima 阅读(352) 评论(0) 推荐(0) 编辑
摘要: 子表达式的语法为name:regex在处理时,会把name加入进符号表中,方法是hash,最简单的加法而在regex中如果碰到[name]这种模式,则尝试去找符号表,如果找不到则报错。代码如下,欢迎大家测试。#include #include #include //这个版本允许定义正则子表达式,定义的时候以名字开头,然后是冒号,然后是正则表达式主体。//在引用子表达式的时候,需要用中括号把子表达式括起来,因此中括号也跟其他操作符一样,作为保留字符//目前还没有处理转义字符,再过几个版本吧。int token[100];int token_pointer;char reg_operator[10 阅读全文
posted @ 2013-06-22 20:16 huangnima 阅读(488) 评论(0) 推荐(0) 编辑
摘要: 由于当前的连接符变为非显示,所以在有些时候需要考虑当前输入指针所指的位置是否缺少连接符,如果缺少,则将连接符入栈。 1 #include 2 #include 3 #include 4 //这里默认是没有显示的连接运算符,运算符的优先级为括号、闭包*、连接.、并| 5 //在括号后及闭包后可能缺少显示的连接符,因此需要考虑添加连接符,而由于并操作符的优先级比连接符低 6 //所以就不需要在处理并操作符的时候去考虑是否缺少显示的连接符了 7 int token[100]; 8 int token_pointer; 9 char reg_operator[100]; 10 ... 阅读全文
posted @ 2013-06-22 12:52 huangnima 阅读(363) 评论(0) 推荐(0) 编辑
摘要: 这里只是当作自己的代码版本管理器使用,并不去详细介绍代码,毕竟我的注释里面已经说明了很多。欢迎大家测试,如果发现出错了,望在下面回复,多谢。注意,当前的假定是输入自己不能有错误,而且*、(、)、.、|这几个操作符是保留字,其他的字符则当作其自身意思。当前不考虑转义字符及三元组,以及不考虑子表达式命名,因此只能处理一个长正则表达式。 1 #include 2 #include 3 #include 4 //这里只处理最简单的正则表达式,即包括括号,星号运算,连接运算和分支运算,这里分支运算在压栈是是一个点号 5 //其中括号优先级最大,其次是星号运算其次是连接运算最后是分支运算 ... 阅读全文
posted @ 2013-06-22 12:49 huangnima 阅读(329) 评论(0) 推荐(0) 编辑
摘要: Windows页目录自映射Windows的内存访问是采用虚拟内存形式,即对于任何一个Adr,首先根据CR3寄存器的值来得到页目录表的地址,此时页目录表是一个刚好大小为4k的页。页目录表中,每一项大小为4B,内容包括对应页表的物理地址和一些标志位。由于页表也是一个大小为4K的页,所以地址是按4K对齐的,因此这里的地址只需要20位就可以了,剩下的12位作为标志位。Adr所在页表的地址由页目录表的第Adr>>22项给出。得到页表的地址之后,同样重复前面所做的工作,利用(Adr<<10)>>22来得到所在页在页表中的索引,从而得到虚拟地址指向页的物理地址,然后再根据 阅读全文
posted @ 2013-05-28 12:54 huangnima 阅读(973) 评论(2) 推荐(0) 编辑