摘要: 1 void first_set_preprocess(void)//这个函数是用来消除强联通图,把强联通图直接短接,最后生成一个压缩图 2 { 3 first_graph_node** rev_first_graph;//这个当作逆转图的入口,因为我们要生成这个逆转图 4 first_graph_node** new_first_graph;//这个当作原来的图的拷贝,因为在拓扑排序时会毁掉原来的图 5 pfirst_graph_node temp_first_node,temp_first_add; 6 pfirst_graph_node te... 阅读全文
posted @ 2013-07-06 20:49 huangnima 阅读(259) 评论(0) 推荐(0) 编辑
摘要: 由于在生成前后缀的时候,我们需要将这个文法符号按照拓扑排序来排列生成顺序,不过当语法里面有环的时候,一般的拓扑排序就无效了,这个时候需要采取将一个强联通区域的点汇聚在一起,也就是生成压缩图。课本上虽说强连通算法是线性时间,但是不写不知道,一写吓一跳,尼玛都快四次复杂度了有木有。这里就贴一下生成强连通的代码 1 void first_set_preprocess(void)//这个函数是用来消除强联通图,把强联通图直接短接,最后生成一个压缩图 2 { 3 first_graph_node** rev_first_graph;//这个当作逆转图的入口,因为我们要生成这个逆转图 4 ... 阅读全文
posted @ 2013-07-06 19:42 huangnima 阅读(340) 评论(0) 推荐(0) 编辑
摘要: 前面那片文章生成的语法分析表并不是最优的,因为有些项在遇到错误输入的时候,并不是采取报错,而是执行规约,直到不能再规约的时候才报错。这是不科学的,我们需要在得到错误输入的时候立马报错,为了实现这个功能,我们需要知道某个文法符号的后面可能接的终结文法符号的集合,只有当前的输入终结文法符号处在栈顶文法符号的后缀集合中时,我们才去采取接受规约移进这三个操作,否则报错。为了得到后缀集合,我们首先需要得到每一个文法符号的开始符号集合。为了得到这个集合,我们需要将这些符号进行拓扑排序,以保证生成体的第一个符号在生成体的头部符号处理前处理。注意这里一定不会出现环,即出现E:->T +R ,T:-> 阅读全文
posted @ 2013-07-05 19:58 huangnima 阅读(1101) 评论(2) 推荐(0) 编辑
摘要: 太累了,感觉不会再爱了。执行了跟编译原理上的一模一样的例子,输出了正确结果 1 #include 2 #include 3 #include 4 //这个头文件是为了将语法声明的产生式按照调用顺序来构建调用图,并顺便构建反向调用图。 5 //从而来构建拓扑排序,并用到将来的分析之中。 6 typedef struct _decl_hash_table 7 { 8 int is_used;//代表是否已经被使用 9 char* decl_hash_name;//代表名字 10 int node_index;//代表所代表的节点编号 11 }decl... 阅读全文
posted @ 2013-07-04 19:44 huangnima 阅读(2830) 评论(0) 推荐(0) 编辑
摘要: hopcroft法的复杂度,他们说是nlogn,可是都没有严格的证明。难得找到一篇讲的详细点的论文,却又啰里啰唆的,不过那篇论文里面采用的是颜色树这个结构,有点意思。前面的那个算法是n的平方复杂度,虽然这个复杂度计算都是建立在一些操作为单位时间操作的基础上。可是这些被认为的单位时间操作在我的实现中却有着平方复杂度,情何以堪,万恶的理论计算机科学家。hopcroft实现的代码,太长了,还没写完。不过核心的子集分割已经完成了,剩下的就是分配节点及重新构建邻接表。明天再说吧。 1 #include "dfa_to_dfa.h" 2 pdfa_edge* rev_dfa_table 阅读全文
posted @ 2013-06-28 21:43 huangnima 阅读(496) 评论(0) 推荐(0) 编辑
摘要: 上个版本测试的时候,只用了两个非常简单的测试用例,所以好多情况有问题却没有测试出来bug1:在生成diff_matrix的时候,循环变量少循环了一次,导致最后一个节点在如果无法与其他点合并的情况下,程序不会给他生成一个群标号。修改:把循环变量那里加上等于号bug2:在遍历群的时候,程序是以碰到空指针为结束的,但是在malloc内存的时候,系统并不为这个内存初始化为0,而是0xcd,所以以是不是空指针来判断边界是不可行的,会造成错误,导致读取了而外的信息。修改:在遍历群的时候,直接以群的数目来做条件测试bug3:在nfa转dfa的时候,如果某一个dfa节点在某一个字母上的转换导致了目标位图tem 阅读全文
posted @ 2013-06-28 09:58 huangnima 阅读(645) 评论(0) 推荐(0) 编辑
摘要: 采取的方法是hopcroft的填表法,详情见如下代码 1 #include "nfa_to_dfa.h" 2 int* dfa_diff_matrix; 3 4 int mini_dfa_number;//这个是最小化的 dfa表的索引 5 typedef struct _min_dfa_node 6 { 7 pdfa_edge begin; 8 int is_end;//记录是否是接受节点 9 }min_dfa_node,*pmin_dfa_node; 10 min_dfa_node mini_dfa_table[100];//设定为100,其实也可以ma... 阅读全文
posted @ 2013-06-27 15:13 huangnima 阅读(2455) 评论(0) 推荐(0) 编辑
摘要: 为了加速转换的处理,我压缩了符号表。具体算法参考任何一本与编译或者自动机相关的书籍。这里的核心问题是处理传递性闭包,transitive closure,这个我目前采取的是最简单的warshall算法,虽然是4次的复杂度,但是由于我构建nfa的时候并没有采取标准的方法,使得nfa的节点减少很多。ps,上上篇所说的re转nfa,我这里有一个修改,就是对于or转换,不再增加节点,而是只增加两条空转换边。相关代码如下 1 #include "nfa_process.h" 2 //首先在原来的nfa节点中,把最后的那个正则的开始节点可达的那些节点提取出来,相当于又一次的拷贝 3 p 阅读全文
posted @ 2013-06-26 16:50 huangnima 阅读(952) 评论(0) 推荐(0) 编辑
摘要: 太累了,感觉不会再爱了。问题已经解决,具体的懒得说了。 1 #include "regular_preprocess.h" 2 //这个版本终于要上nfa了,好兴奋啊 3 //由于连个节点之间可能有多条边,所以只能用邻接表来存储了 4 //注意这里是有向图 5 //对于每一个token,这里都会生成一个或多个图节点 6 //但是每个token会附带另外的两个域,即这个token的开始节点和结束节点 7 //因为内部节点对于外部来说是不可连接的,所以不需要暴露 8 //这里有一个难题,就是空转换如何表示,这里我们必须找一个不可打印字符来代表空转换 9 //楼主自己查了一下as 阅读全文
posted @ 2013-06-25 12:55 huangnima 阅读(605) 评论(3) 推荐(0) 编辑
摘要: 正则到nfabug的解决方法前面提到了这个bug,为了解决这个bug,我们必须在每次引用到一个假名的时候,都构建一个拷贝。现在假设我们遇到了一个假名,并得到了他的开始节点和结束节点,当前的难题就是构造这个假名所代表的nfa的副本。构造方法类似于子集构造法,我们设立一个集合,这个集合为R,集合中的每个元素都有一个标志位为访问位。初始化R为开始节点a,并让他的访问位为0。现在开始进入迭代,只要R中存在访问位为0的点,将他的访问位改为1,然后将他的邻接表中的点都加入到R中。加入的时候,考虑R中是否已经存在这个元素,如果已经存在,则不加入。如果不存在,则加入,并设置访问位为0。然后返回迭代判断。最后当 阅读全文
posted @ 2013-06-24 19:36 huangnima 阅读(289) 评论(0) 推荐(0) 编辑