上个版本测试的时候,只用了两个非常简单的测试用例,所以好多情况有问题却没有测试出来
bug1:在生成diff_matrix的时候,循环变量少循环了一次,导致最后一个节点在如果无法与其他点合并的情况下,程序不会给他生成一个群标号。
修改:把循环变量那里加上等于号
bug2:在遍历群的时候,程序是以碰到空指针为结束的,但是在malloc内存的时候,系统并不为这个内存初始化为0,而是0xcd,所以以是不是空指针来判断边界是不可行的,会造成错误,导致读取了而外的信息。
修改:在遍历群的时候,直接以群的数目来做条件测试
bug3:在nfa转dfa的时候,如果某一个dfa节点在某一个字母上的转换导致了目标位图temp_nfa_set的第一个字节为空的情况下,在插入hash的过程中,直接调用strcpy程序会导致只复制第一个字节即结束字符,而忽略后面的那几个字节。从而导致在之后的查表中找不到这个位图。
修改:在hash复制名字的时候,用一个循环,直接一个字节一个字节的复制过去,这样就不会出现前面所说的情况了。
bug4:在re转nfa的时候,对于or的处理,如果or之前有操作符,在弹出该操作符的时候,会忘记为他生成token_node,导致后面的步骤都出现错误。这个问题出现的原因,是当时忘记写了。。。。。
修改:把忘记写的代码加上去。
bug5:在判断两个节点是否在dfa最小化的时候合并调用了is_diff,但是这里可能会出现无限递归的情况,例如节点1在a上到节点2,而节点2在a上到节点1。如果这时利用is_diff(1,2),会导致无限递归。
修改:每次调用is_diff(a,b)的时候,调用之前都在矩阵里面把这两个点所在的位置修改为2,2的意思是正在考虑。如果后面的调用查看到了标记为2的矩阵节点,则这次判断放弃,直接进入下次判断。如果is_diff返回了1,则把这个2修改为1,如果为0,则修改为0。
bug6:在re生成nfa的时候,自做聪明的采取了非标准的转换策略,后来证明有非常大的错误。例如(a|b)*|abc,如果按照我的那个生成策略生成的nfa图,会接受aabc这种情况。。。
修改 :把re转nfa全都按照课本来做了。
目前我自己发现的就有这么多bug,欢迎大家测试
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,其实也可以malloc一下,因为我们已经知道了有多少个节点了 11 //为了偷懒,算了 12 is_diff(int input_a,int input_b)//判断两个点是不是等价的程序,注意我们传参数的时候默认a比b大 13 { 14 int destination_a,destination_b;//临时的转换目标地址,注意目标地址与矩阵索引是相差1的,注意啊 15 pdfa_edge temp_edge;//遍历邻接表 16 char label_traverse;//用来遍历符号表 17 int for_i; 18 for(for_i=0;for_i<alpha_size;for_i++) 19 { 20 label_traverse=mini_alpha_set[for_i]; 21 temp_edge=current_dfa_table[input_a+1].begin; 22 while((temp_edge!=NULL)&&(temp_edge->label!=label_traverse)) 23 { 24 temp_edge=temp_edge->next; 25 } 26 if(temp_edge==NULL) 27 { 28 destination_a=0; 29 } 30 else 31 { 32 destination_a=temp_edge->dest_dfa_index; 33 }//获得a的转换目标 34 temp_edge=current_dfa_table[input_b+1].begin; 35 while((temp_edge!=NULL)&&(temp_edge->label!=label_traverse)) 36 { 37 temp_edge=temp_edge->next; 38 } 39 if(temp_edge==NULL) 40 { 41 destination_b=0; 42 } 43 else 44 { 45 destination_b=temp_edge->dest_dfa_index; 46 }//获得b的转换目标 47 if(destination_a==destination_b) 48 { 49 //目标相同,则无法判断,轮到下一次 50 } 51 else 52 { 53 if(destination_a*destination_b==0) 54 { 55 //如果刚好一个为0,说明可以判断 56 return 1; 57 } 58 else 59 { 60 //因为目标地址的索引与矩阵地址的索引是相差1的,所以我们要这样做 61 destination_a--; 62 destination_b--; 63 if( destination_a>destination_b)//按大小来分 64 { 65 if(dfa_diff_matrix[dfa_node_number*(destination_a)+(destination_b)]!=2) 66 //这里是为了防止重复依赖导致的无限递归调用 67 { 68 if(dfa_diff_matrix[dfa_node_number*(destination_a)+(destination_b)]!=1)//如果当前无法判别 69 { 70 dfa_diff_matrix[dfa_node_number*(destination_a)+(destination_b)]=2; 71 if(is_diff(destination_a,destination_b))//如果可以判别 72 { 73 dfa_diff_matrix[dfa_node_number*(destination_a)+(destination_b)]=1; 74 return 1; 75 } 76 else 77 { 78 dfa_diff_matrix[dfa_node_number*(destination_a)+(destination_b)]=0; 79 } 80 } 81 else 82 { 83 return 1; 84 } 85 } 86 } 87 else//如果b比a大 88 { 89 if(dfa_diff_matrix[dfa_node_number*(destination_b)+(destination_a)]!=2) 90 { 91 if(dfa_diff_matrix[dfa_node_number*(destination_b)+(destination_a)]!=1)//如果当前无法判别 92 { 93 dfa_diff_matrix[dfa_node_number*(destination_b)+(destination_a)]=2; 94 if(is_diff(destination_b,destination_a))//如果可以判别 95 { 96 dfa_diff_matrix[dfa_node_number*(destination_b)+(destination_a)]=1; 97 return 1; 98 } 99 else 100 { 101 dfa_diff_matrix[dfa_node_number*(destination_b)+(destination_a)]=0; 102 } 103 } 104 else 105 { 106 return 1; 107 } 108 } 109 } 110 } 111 } 112 } 113 return 0;//如果所有的输入都轮完了,说明当前无法比较。。。 114 } 115 void diff_matrix(void) 116 { 117 int already_diff_number;//这个是用来判断有多少个点已经经过了等价性测试 118 int for_i,for_j; 119 dfa_diff_matrix=malloc(sizeof(int)*dfa_node_number*dfa_node_number);//分配这个节点 120 for(for_i=0;for_i<dfa_node_number;for_i++) 121 { 122 for(for_j=0;for_j<dfa_node_number;for_j++) 123 { 124 dfa_diff_matrix[(for_i)*dfa_node_number+for_j]=0; 125 } 126 } 127 for(for_i=1;for_i<dfa_node_number;for_i++) 128 { 129 for(for_j=0;for_j<for_i;for_j++)//这里首先根据是否是接受节点来初始化矩阵 130 { 131 if(current_dfa_table[for_i+1].is_end!=current_dfa_table[for_j+1].is_end) 132 { 133 dfa_diff_matrix[(for_i)*dfa_node_number+for_j]=1; 134 } 135 } 136 } 137 do{ 138 already_diff_number=0; 139 for(for_i=1;for_i<dfa_node_number;for_i++) 140 { 141 for(for_j=0;for_j<for_i;for_j++) 142 { 143 if(dfa_diff_matrix[(for_i)*dfa_node_number+for_j]!=1) 144 { 145 dfa_diff_matrix[(for_i)*dfa_node_number+for_j]=2; 146 //做这个标记是为了防止递归调用,表明当前正在考虑的节点有哪些,不要再去试图考虑这些节点对 147 if(is_diff(for_i,for_j)==1) 148 { 149 dfa_diff_matrix[(for_i)*dfa_node_number+for_j]=1; 150 already_diff_number++; 151 } 152 else 153 { 154 dfa_diff_matrix[(for_i)*dfa_node_number+for_j]=0; 155 } 156 } 157 } 158 } 159 }while(already_diff_number!=0);//如果本趟处理没有找到新的可分节点,就结束 160 161 for(for_i=0;for_i<dfa_node_number;for_i++) 162 { 163 for(for_j=0;for_j<dfa_node_number;for_j++) 164 { 165 printf("%d ",dfa_diff_matrix[(for_i)*dfa_node_number+for_j]); 166 } 167 printf(" "); 168 } 169 } 170 void minimize_dfa_matrix(void)//在已经构建好了dfa_diff_matrix后,开始群聚,并建图 171 { 172 //现在开始群聚 173 int* already_in_group;//用来记录哪些点已经在群里面了 174 int* temp_group; 175 int* before_min_access;//这里来标注哪些节点已经通过了最简化dfa的转换 176 int group_number=0;//注意群号由0开始 177 int* index_of_group; 178 pdfa_edge temp_edge;//这个是用来重新建立最小化dfa的临时边 179 pdfa_edge temp_add_edge;//这个是用来往最小dfa里面增加边的临时边 180 int dest_group_number;//这个是在增加边的时候的目标编号 181 int **group_set; 182 int for_i,for_j; 183 group_set=malloc(sizeof(int)*dfa_node_number); 184 already_in_group=malloc(sizeof(int)*dfa_node_number); 185 for(for_i=0;for_i<dfa_node_number;for_i++) 186 { 187 already_in_group[for_i]=0; 188 *(group_set+for_i)=NULL; 189 } 190 for(for_i=0;for_i<dfa_node_number;for_i++)//聚集 191 { 192 if(already_in_group[for_i]==0) 193 { 194 already_in_group[for_i]=1; 195 temp_group=malloc(sizeof(int)*dfa_node_number); 196 *(group_set+group_number++)=temp_group; 197 for(for_j=0;for_j<dfa_node_number;for_j++) 198 { 199 temp_group[for_j]=0; 200 }//注意这里也需要考虑加减1的问题 201 temp_group[for_i]=1; 202 for(for_j=for_i+1;for_j<dfa_node_number;for_j++) 203 { 204 if(!dfa_diff_matrix[(for_j)*dfa_node_number+for_i]) 205 { 206 temp_group[for_j]=1; 207 already_in_group[for_j]=1; 208 } 209 } 210 } 211 }//现在已经完全都聚集为一团了 212 mini_dfa_number=group_number; 213 //现在再将节点和群的关系反转 214 index_of_group=malloc(sizeof(int)*dfa_node_number); 215 //这里又需要注意加减1的关系,由于这里dfa节点是从1标号的,而我们在index_of_group是从0标号的,要注意 216 for(for_i=0;for_i<dfa_node_number;for_i++) 217 { 218 index_of_group[for_i]=0; 219 } 220 for_i=0; 221 while(for_i<group_number)//前面开了一个索引数组,现在来赋值,这样就可以直接得到某个节点所在的群号 222 { 223 for(for_j=0;for_j<dfa_node_number;for_j++) 224 { 225 if(*(*(group_set+for_i)+for_j)==1) 226 { 227 index_of_group[for_j]=for_i; 228 } 229 } 230 for_i++; 231 }//现在关系已经翻转了 232 //下一步就是利用这个点与群的关系来新建立一个dfa图 233 //这里的群号就是节点的编号,由于每个群里面的节点都是等价的,所以只需要找一个节点就行了 234 for(for_i=1;for_i<=group_number;for_i++)//这里的for_i是用来表示最小dfa图的标号,所以从1开始 235 { 236 //对每一个群进行遍历 237 mini_dfa_table[for_i].begin=NULL; 238 mini_dfa_table[for_i].is_end=0; 239 for_j=0; 240 while(*(*(group_set+for_i-1)+for_j)!=1)//由于group是从0开始标号的,所以要减去1 241 { 242 for_j++; 243 }//找到这个群里面一个节点,注意加减一问题,少犯错误啊,1号节点存储在0号位置上 244 if(current_dfa_table[for_j+1].is_end)//标记为结束节点 245 { 246 mini_dfa_table[for_i].is_end=1; 247 } 248 temp_edge=current_dfa_table[for_j+1].begin; 249 while(temp_edge!=NULL)//重新建设邻接表 250 { 251 temp_add_edge=malloc(sizeof(struct _dfa_edge)); 252 temp_add_edge->label=temp_edge->label; 253 temp_add_edge->next=mini_dfa_table[for_i].begin; 254 dest_group_number=index_of_group[temp_edge->dest_dfa_index-1]+1;//特别要注意这里的加一和减一 255 //由于temp_edge->dest_dfa_node是从1开始标号的,而index_of_group是从0开始标号的,所以我们要减一 256 //同样,又由于最后的最简化dfa的图是从1开始标号的,所以我们要加1; 257 temp_add_edge->dest_dfa_index=dest_group_number; 258 mini_dfa_table[for_i].begin=temp_add_edge; 259 temp_edge=temp_edge->next; 260 } 261 //本群的邻接表构建完成 262 }//所有群的邻接表构建完成 263 } 264 void show_mini_dfa(void)//输出图 265 { 266 int for_i; 267 pdfa_edge temp_dfa_edge; 268 number_of_end_dfa=0; 269 for(for_i=1;for_i<=mini_dfa_number;for_i++) 270 { 271 if(mini_dfa_table[for_i].is_end==1) 272 { 273 printf("this node is an destination node ,index is %d ",for_i); 274 } 275 temp_dfa_edge=mini_dfa_table[for_i].begin; 276 while(temp_dfa_edge!=NULL) 277 { 278 printf("there is an dfa edge from %d to %d with label %c ",for_i,temp_dfa_edge->dest_dfa_index,temp_dfa_edge->label); 279 temp_dfa_edge=temp_dfa_edge->next; 280 } 281 } 282 printf("the minimized dfa is completed "); 283 }