dfa最小化,修正了上个版本的一些错误。
上个版本测试的时候,只用了两个非常简单的测试用例,所以好多情况有问题却没有测试出来
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,欢迎大家测试
#include "nfa_to_dfa.h"
int* dfa_diff_matrix; int mini_dfa_number;//这个是最小化的 dfa表的索引
typedef struct _min_dfa_node
{
pdfa_edge begin;
int is_end;//记录是否是接受节点
}min_dfa_node,*pmin_dfa_node;
min_dfa_node mini_dfa_table[];//设定为100,其实也可以malloc一下,因为我们已经知道了有多少个节点了
//为了偷懒,算了
is_diff(int input_a,int input_b)//判断两个点是不是等价的程序,注意我们传参数的时候默认a比b大
{
int destination_a,destination_b;//临时的转换目标地址,注意目标地址与矩阵索引是相差1的,注意啊
pdfa_edge temp_edge;//遍历邻接表
char label_traverse;//用来遍历符号表 int for_i;
for(for_i=;for_i<alpha_size;for_i++)
{
label_traverse=mini_alpha_set[for_i];
temp_edge=current_dfa_table[input_a+].begin;
while((temp_edge!=NULL)&&(temp_edge->label!=label_traverse))
{
temp_edge=temp_edge->next;
}
if(temp_edge==NULL)
{
destination_a=;
}
else
{
destination_a=temp_edge->dest_dfa_index;
}//获得a的转换目标
temp_edge=current_dfa_table[input_b+].begin;
while((temp_edge!=NULL)&&(temp_edge->label!=label_traverse))
{
temp_edge=temp_edge->next;
}
if(temp_edge==NULL)
{
destination_b=;
}
else
{
destination_b=temp_edge->dest_dfa_index;
}//获得b的转换目标
if(destination_a==destination_b)
{
//目标相同,则无法判断,轮到下一次
}
else
{
if(destination_a*destination_b==)
{
//如果刚好一个为0,说明可以判断
return ;
}
else
{
//因为目标地址的索引与矩阵地址的索引是相差1的,所以我们要这样做
destination_a--;
destination_b--;
if( destination_a>destination_b)//按大小来分
{
if(dfa_diff_matrix[dfa_node_number*(destination_a)+(destination_b)]!=)
//这里是为了防止重复依赖导致的无限递归调用
{
if(dfa_diff_matrix[dfa_node_number*(destination_a)+(destination_b)]!=)//如果当前无法判别
{
dfa_diff_matrix[dfa_node_number*(destination_a)+(destination_b)]=;
if(is_diff(destination_a,destination_b))//如果可以判别
{
dfa_diff_matrix[dfa_node_number*(destination_a)+(destination_b)]=;
return ;
}
else
{
dfa_diff_matrix[dfa_node_number*(destination_a)+(destination_b)]=;
}
}
else
{
return ;
}
}
}
else//如果b比a大
{
if(dfa_diff_matrix[dfa_node_number*(destination_b)+(destination_a)]!=)
{
if(dfa_diff_matrix[dfa_node_number*(destination_b)+(destination_a)]!=)//如果当前无法判别
{
dfa_diff_matrix[dfa_node_number*(destination_b)+(destination_a)]=;
if(is_diff(destination_b,destination_a))//如果可以判别
{
dfa_diff_matrix[dfa_node_number*(destination_b)+(destination_a)]=;
return ;
}
else
{
dfa_diff_matrix[dfa_node_number*(destination_b)+(destination_a)]=;
}
}
else
{
return ;
}
}
}
}
}
}
return ;//如果所有的输入都轮完了,说明当前无法比较。。。
}
void diff_matrix(void)
{
int already_diff_number;//这个是用来判断有多少个点已经经过了等价性测试
int for_i,for_j;
dfa_diff_matrix=malloc(sizeof(int)*dfa_node_number*dfa_node_number);//分配这个节点
for(for_i=;for_i<dfa_node_number;for_i++)
{
for(for_j=;for_j<dfa_node_number;for_j++)
{
dfa_diff_matrix[(for_i)*dfa_node_number+for_j]=;
}
}
for(for_i=;for_i<dfa_node_number;for_i++)
{
for(for_j=;for_j<for_i;for_j++)//这里首先根据是否是接受节点来初始化矩阵
{
if(current_dfa_table[for_i+].is_end!=current_dfa_table[for_j+].is_end)
{
dfa_diff_matrix[(for_i)*dfa_node_number+for_j]=;
}
}
}
do{
already_diff_number=;
for(for_i=;for_i<dfa_node_number;for_i++)
{
for(for_j=;for_j<for_i;for_j++)
{
if(dfa_diff_matrix[(for_i)*dfa_node_number+for_j]!=)
{
dfa_diff_matrix[(for_i)*dfa_node_number+for_j]=;
//做这个标记是为了防止递归调用,表明当前正在考虑的节点有哪些,不要再去试图考虑这些节点对
if(is_diff(for_i,for_j)==)
{
dfa_diff_matrix[(for_i)*dfa_node_number+for_j]=;
already_diff_number++;
}
else
{
dfa_diff_matrix[(for_i)*dfa_node_number+for_j]=;
}
}
}
}
}while(already_diff_number!=);//如果本趟处理没有找到新的可分节点,就结束 for(for_i=;for_i<dfa_node_number;for_i++)
{
for(for_j=;for_j<dfa_node_number;for_j++)
{
printf("%d ",dfa_diff_matrix[(for_i)*dfa_node_number+for_j]);
}
printf("\n");
}
}
void minimize_dfa_matrix(void)//在已经构建好了dfa_diff_matrix后,开始群聚,并建图
{
//现在开始群聚
int* already_in_group;//用来记录哪些点已经在群里面了
int* temp_group;
int* before_min_access;//这里来标注哪些节点已经通过了最简化dfa的转换
int group_number=;//注意群号由0开始
int* index_of_group;
pdfa_edge temp_edge;//这个是用来重新建立最小化dfa的临时边
pdfa_edge temp_add_edge;//这个是用来往最小dfa里面增加边的临时边
int dest_group_number;//这个是在增加边的时候的目标编号
int **group_set;
int for_i,for_j;
group_set=malloc(sizeof(int)*dfa_node_number);
already_in_group=malloc(sizeof(int)*dfa_node_number);
for(for_i=;for_i<dfa_node_number;for_i++)
{
already_in_group[for_i]=;
*(group_set+for_i)=NULL;
}
for(for_i=;for_i<dfa_node_number;for_i++)//聚集
{
if(already_in_group[for_i]==)
{
already_in_group[for_i]=;
temp_group=malloc(sizeof(int)*dfa_node_number);
*(group_set+group_number++)=temp_group;
for(for_j=;for_j<dfa_node_number;for_j++)
{
temp_group[for_j]=;
}//注意这里也需要考虑加减1的问题
temp_group[for_i]=;
for(for_j=for_i+;for_j<dfa_node_number;for_j++)
{
if(!dfa_diff_matrix[(for_j)*dfa_node_number+for_i])
{
temp_group[for_j]=;
already_in_group[for_j]=;
}
}
}
}//现在已经完全都聚集为一团了
mini_dfa_number=group_number;
//现在再将节点和群的关系反转
index_of_group=malloc(sizeof(int)*dfa_node_number);
//这里又需要注意加减1的关系,由于这里dfa节点是从1标号的,而我们在index_of_group是从0标号的,要注意
for(for_i=;for_i<dfa_node_number;for_i++)
{
index_of_group[for_i]=;
}
for_i=;
while(for_i<group_number)//前面开了一个索引数组,现在来赋值,这样就可以直接得到某个节点所在的群号
{
for(for_j=;for_j<dfa_node_number;for_j++)
{
if(*(*(group_set+for_i)+for_j)==)
{
index_of_group[for_j]=for_i;
}
}
for_i++;
}//现在关系已经翻转了
//下一步就是利用这个点与群的关系来新建立一个dfa图
//这里的群号就是节点的编号,由于每个群里面的节点都是等价的,所以只需要找一个节点就行了
for(for_i=;for_i<=group_number;for_i++)//这里的for_i是用来表示最小dfa图的标号,所以从1开始
{
//对每一个群进行遍历
mini_dfa_table[for_i].begin=NULL;
mini_dfa_table[for_i].is_end=;
for_j=;
while(*(*(group_set+for_i-)+for_j)!=)//由于group是从0开始标号的,所以要减去1
{
for_j++;
}//找到这个群里面一个节点,注意加减一问题,少犯错误啊,1号节点存储在0号位置上
if(current_dfa_table[for_j+].is_end)//标记为结束节点
{
mini_dfa_table[for_i].is_end=;
}
temp_edge=current_dfa_table[for_j+].begin;
while(temp_edge!=NULL)//重新建设邻接表
{
temp_add_edge=malloc(sizeof(struct _dfa_edge));
temp_add_edge->label=temp_edge->label;
temp_add_edge->next=mini_dfa_table[for_i].begin;
dest_group_number=index_of_group[temp_edge->dest_dfa_index-]+;//特别要注意这里的加一和减一
//由于temp_edge->dest_dfa_node是从1开始标号的,而index_of_group是从0开始标号的,所以我们要减一
//同样,又由于最后的最简化dfa的图是从1开始标号的,所以我们要加1;
temp_add_edge->dest_dfa_index=dest_group_number;
mini_dfa_table[for_i].begin=temp_add_edge;
temp_edge=temp_edge->next;
}
//本群的邻接表构建完成
}//所有群的邻接表构建完成
}
void show_mini_dfa(void)//输出图
{
int for_i;
pdfa_edge temp_dfa_edge;
number_of_end_dfa=;
for(for_i=;for_i<=mini_dfa_number;for_i++)
{
if(mini_dfa_table[for_i].is_end==)
{
printf("this node is an destination node ,index is %d\n",for_i);
}
temp_dfa_edge=mini_dfa_table[for_i].begin;
while(temp_dfa_edge!=NULL)
{
printf("there is an dfa edge from %d to %d with label %c\n",for_i,temp_dfa_edge->dest_dfa_index,temp_dfa_edge->label);
temp_dfa_edge=temp_dfa_edge->next;
}
}
printf("the minimized dfa is completed\n");
}
dfa最小化,修正了上个版本的一些错误。的更多相关文章
- 编译原理中DFA最小化
关于编译原理最小化的操作,专业术语请移步至:http://www.360doc.com/content/18/0601/21/11962419_758841916.shtml 这里只是记录一下个人的理 ...
- DFA 最小化
NDFA.εNDFA 确定化的细节这里就不总结了,这里说一说DFA最小化的算法. 关于DFA最小化,
- 第九次作业——DFA最小化,语法分析初步
老师:MissDu 提交作业 1.将DFA最小化:教材P65 第9题 答: 2.构造以下文法相应的最小的DFA S→ 0A|1B A→ 1S|1 B→0S|0 3.自上而下语法分析,回溯产生的原因是 ...
- DFA最小化,语法分析初步
1.将DFA最小化:教材P65 第9题 2.构造以下文法相应的最小的DFA S→ 0A|1B A→ 1S|1 B→0S|0 语言:(01 | 10)*(01 | 10) 自动机图: DFA状态转换矩阵 ...
- 编译原理之DFA最小化,语法分析初步
1.将DFA最小化: 状态转换图: 识别语言:b*ac*(da)*bb* 2.构造以下文法相应的最小的DFA S→ 0A|1B A→ 1S|1 B→0S|0 (1)正规式: S -> 0(1S+ ...
- 第九次作业 DFA最小化,语法分析初步
1.将DFA最小化:教材P65 第9题 Ⅰ {1,2,3,4,5} {6,7} {1,2}b={1,2,3,4,5} 3,4}b={5} {6,7} Ⅱ {1,2}{3,4}{5} {6,7} 2.构 ...
- 作业九——DFA最小化
1.将DFA最小化:教材P65 第9题 I {1, 2, 3, 4, 5} {6, 7} {1, 2}b->{1, 2, 3, 4, 5} {3, 4}b->{6, 7} {5}b-> ...
- 编译原理:DFA最小化,语法分析初步
1.将DFA最小化:教材P65 第9题 解析: 2.构造以下文法相应的最小的DFA S→ 0A|1B A→ 1S|1 B→0S|0 解析: S→ 0A|1B →S → 0(1S|1)|1(0S|0 ...
- 第九次-DFA最小化,语法分析初步
1.将DFA最小化:教材P65 第9题 2.构造以下文法相应的最小的DFA S→ 0A|1B A→ 1S|1 B→0S|0 3.自上而下语法分析,回溯产生的原因是什么? 4.P100 练习4,反复提取 ...
随机推荐
- (剑指Offer)面试题28:字符串的排列
题目: 输入一个字符串,打印出该字符串中字符的所有排列. 例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 思路: 把一个字符串看 ...
- ClassRequestHandler or VendorRequestHandler wIndex must be less than NumIFs
P1_ro:20000EEA ClassRequestHandler ; CODE XREF: USB__HandleSetup+38j P1_ro:20000EEA LDRB R0, [R4,#4] ...
- pic/at89c2051 programmer
http://dangerousprototypes.com/forum/viewtopic.php?t=170 It looks like the PICKIT2 uses a small boos ...
- map的实现
1.map的实现是使用平衡树,AVL树或者红黑树. 2.在无序的情况下,查找为常数时间.有序的时候,查找为对数时间.二叉排序树(BST)就是为了解决这个问题. 3.但是,极端情况下,BST的查找效率退 ...
- HDU 4099 Revenge of Fibonacci(高精度+字典树)
题意:对给定前缀(长度不超过40),找到一个最小的n,使得Fibonacci(n)前缀与给定前缀相同,如果在[0,99999]内找不到解,输出-1. 思路:用高精度加法计算斐波那契数列,因为给定前缀长 ...
- android百度地图开发之自动定位所在位置与固定位置进行驾车,步行,公交路线搜索
最近跟着百度地图API学地图开发,先是学了路径搜索,对于已知坐标的两点进行驾车.公交.步行三种路径的搜索(公交路径运行没效果,待学习中),后来又 学了定位功能,能够获取到自己所在位置的经纬度,但当将两 ...
- iOS开发——多线程OC篇&多线程详解
多线程详解 前面介绍了多线程的各种方式及其使用,这里补一点关于多线程的概念及相关技巧与使用,相信前面不懂的地方看了这里之后你就对多线程基本上没有什么问题了! 1——首先ios开发多线程中必须了解的概念 ...
- 【Unity3D】【NGUI】怎样动态给EventDelegate加入參数
NGUI版本号:3.6.8 注意:參数必须是公共成员变量.不能是栈上的.或者私有的(就是暂时在函数里面定义的或者是函数的參数都不行) using UnityEngine; using System.C ...
- windows下如何github ssh 公钥
windows下如何github ssh 公钥 1. 安装git,从程序目录打开 "Git Bash" 2. 键入命令:ssh-keygen -t rsa -C " ...
- 文件系统缓存dirty_ratio与dirty_background_ratio两个参数区别
这两天在调优数据库性能的过程中需要降低操作系统文件Cache对数据库性能的影响,故调研了一些降低文件系统缓存大小的方法,其中一种是通过修改/proc/sys/vm/dirty_background_r ...