zoukankan      html  css  js  c++  java
  • 正则转nfa:完成

    太累了,感觉不会再爱了。问题已经解决,具体的懒得说了。

      1 #include "regular_preprocess.h"
      2 //这个版本终于要上nfa了,好兴奋啊
      3 //由于连个节点之间可能有多条边,所以只能用邻接表来存储了
      4 //注意这里是有向图
      5 //对于每一个token,这里都会生成一个或多个图节点
      6 //但是每个token会附带另外的两个域,即这个token的开始节点和结束节点
      7 //因为内部节点对于外部来说是不可连接的,所以不需要暴露
      8 //这里有一个难题,就是空转换如何表示,这里我们必须找一个不可打印字符来代表空转换
      9 //楼主自己查了一下asc码表,选择了17号字符,因为
     10 //鬼才知道那个字符啥意思,而且看描述c语言里面也不会出现这个字符吧,
     11 //我看了看键盘,非常欣慰,因为我不知道怎么打出17号字符
     12 //好,就选它了。
     13 //对于nfa图,这里维护了一个图节点的数组,而这个数组组成了邻接表
     14 typedef struct _graph_edge_list
     15 {
     16     struct _graph_edge_list* next_edge;//下一条边的指针
     17     char label_of_edge;//这个是转换条件
     18     int destination_number;//有向边的终点,直接用这个点在图节点数组中的索引来表示
     19 }graph_edge_list,*p_edge_list;
     20 typedef struct _node_for_token//对于每一个token,我们记录他的进入节点和终止节点,为了连接成大的nfa图用
     21 {
     22     int begin;//当前节点的开始节点的标号
     23     int end;//当前节点的结束节点的标号
     24     int top;//这个是当前节点的nfa的最大标号
     25     int bottom;//这个是当前节点的nfa的最小标号
     26 }node_for_token,pnode_for_token;
     27 node_for_token token_node[100];
     28 //每一个token对应一个节点,所以100就够了,当然现在处理的是小的输入
     29 //注意这里有一个特殊的地方,对于括号运算符,他的内容与他的子节点的内容是一样的
     30 //而对于假名操作符,他的内容与他的子节点的内容也是一样的,但是他的内容永远都不会被其他节点所利用
     31 //因为在生成token的过程中,入栈的是他所代表的子节点,所以他的token是不会被其他的token所引用的
     32 //还有一个最需要注意的地方,就是每一个token都有其相对应的token_node,而且这两者的索引都相同
     33 //这个设定便利了nfa的处理,同时也就造就了上面说的括号与中括号的特殊性
     34 int token_node_number=1;//这里是用来遍历整个token表的,每增加1,则token_node的内容增加1
     35 p_edge_list nfa_node[400];//因为生成nfa的过程中可能生成四倍于输入的节点,所以定为这么大
     36 int nfa_node_number=0;//这个是nfa中的节点的标号
     37 void add_edge(int nfa_node_begin,int nfa_node_end,char label)//添加边的函数 
     38 {
     39     p_edge_list temp_pnode=malloc(sizeof(struct _graph_edge_list));
     40     temp_pnode->label_of_edge=label;
     41     temp_pnode->destination_number=nfa_node_end;
     42     temp_pnode->next_edge=nfa_node[nfa_node_begin];
     43     nfa_node[nfa_node_begin]=temp_pnode;
     44 }
     45 void nfa_cope_alias(void)
     46 {
     47     int nfa_begin_number;
     48     int nfa_end_number;
     49     int copy_destination;
     50     int offset;
     51     int original_token;
     52     char copy_label;
     53     p_edge_list pcopy;
     54     original_token=reg_pattern_table[token_node_number].origin_number;
     55     nfa_begin_number=token_node[original_token].bottom;
     56     nfa_end_number=token_node[original_token].top;
     57     offset=nfa_node_number-nfa_begin_number+1;//因为这样要考虑下一个节点
     58     token_node[token_node_number].bottom=nfa_node_number+1;
     59     token_node[token_node_number].top=nfa_end_number+offset;
     60     token_node[token_node_number].begin=offset+token_node[original_token].begin;
     61     token_node[token_node_number].end=offset+token_node[original_token].end;
     62     for(nfa_begin_number;nfa_begin_number<=nfa_end_number;nfa_begin_number++)
     63     {
     64         pcopy=nfa_node[nfa_begin_number];
     65         nfa_node_number++;
     66         nfa_node[nfa_node_number]=NULL;
     67         while(pcopy!=NULL)
     68         {
     69             copy_label=pcopy->label_of_edge;
     70             copy_destination=pcopy->destination_number+offset;
     71             add_edge(nfa_node_number,copy_destination,copy_label);
     72             pcopy=pcopy->next_edge;
     73         }
     74     }
     75 }
     76 
     77 void generate_nfa_node(void)
     78 {
     79     int reg_pattern_left;
     80     int reg_pattern_right;
     81     int reg_pattern_origin;
     82     int for_i,for_j;
     83     int add_edge_from,add_edge_to;
     84     //这里建立节点的时候,是从低往高来遍历标号,来生成节点的
     85     //因为我们在生成token的时候,保证了低标号的不会引用高标号的token,因此是一个拓扑排序
     86     while(token_node_number<=name_number)
     87     {
     88         switch(reg_pattern_table[token_node_number].type)
     89         {
     90         case closure:
     91             //对于闭包运算,我们可以直接将子节点的开始节点与结束节点之间添加两条空边
     92             //不过这两条边的方向相反 ,偷懒哈哈 
     93             reg_pattern_origin=reg_pattern_table[token_node_number].sub;
     94             add_edge_from=token_node[reg_pattern_origin].begin;
     95             add_edge_to=token_node[reg_pattern_origin].end;
     96             add_edge(add_edge_from,add_edge_to,(char)17);
     97             add_edge(add_edge_to,add_edge_from,(char)17);
     98             token_node[token_node_number].begin=add_edge_from;
     99             token_node[token_node_number].end=add_edge_to;
    100             token_node[token_node_number].bottom=token_node[reg_pattern_origin].bottom;
    101             token_node[token_node_number].top=token_node[reg_pattern_origin].top;
    102             token_node_number++;
    103             //处理下一个token_node
    104             break;
    105         case cat:
    106             //对于cat节点,那就非常简单了,只需要在原来的左节点的结束点与右节点的开始点之间连一条边
    107             //然后设置一下当前token_node的开始节点和结束节点
    108             //然后token_node_number加一,由于这里没有生成新的nfa节点,所以nfa_node_number不变
    109             //对于双目运算符,左边的节点总是被先建立起来,所以左边的标号最大的节点会小于右边的编号最小的
    110             reg_pattern_left=reg_pattern_table[token_node_number].left;
    111             reg_pattern_right=reg_pattern_table[token_node_number].right;
    112             token_node[token_node_number].begin=token_node[reg_pattern_left].begin;
    113             token_node[token_node_number].end=token_node[reg_pattern_right].end;
    114             token_node[token_node_number].bottom=token_node[reg_pattern_left].bottom;
    115             token_node[token_node_number].top=token_node[reg_pattern_right].top;
    116             add_edge_from=token_node[reg_pattern_left].end;
    117             add_edge_to=token_node[reg_pattern_right].begin;
    118             add_edge(add_edge_from,add_edge_to,(char)17);
    119             token_node_number++;
    120             break;
    121         case or:
    122             //对于或的处理,我们这里修改了以前的实现,不再增加节点,而只是增加两条空转换边。
    123             reg_pattern_left=reg_pattern_table[token_node_number].left;
    124             reg_pattern_right=reg_pattern_table[token_node_number].right;
    125             add_edge_from=token_node[reg_pattern_left].begin;
    126             add_edge_to=token_node[reg_pattern_right].begin;
    127             add_edge(add_edge_from,add_edge_to,(char)17);
    128             add_edge_from=token_node[reg_pattern_right].end;
    129             add_edge_to=token_node[reg_pattern_left].end;
    130             add_edge(add_edge_from,add_edge_to,(char)17);
    131             token_node[token_node_number].begin=token_node[reg_pattern_left].begin;
    132             token_node[token_node_number].end=token_node[reg_pattern_left].end;
    133             token_node[token_node_number].bottom=token_node[reg_pattern_left].bottom;
    134             token_node[token_node_number].top=token_node[reg_pattern_right].top;
    135             token_node_number++;
    136             break;
    137         case parenthesis:
    138             //对于括号,直接初始化他的开始节点和结束节点就行了,反正也没人会用它了
    139             token_node[token_node_number].begin=token_node[reg_pattern_table[token_node_number].sub].begin;
    140             token_node[token_node_number].end=token_node[reg_pattern_table[token_node_number].sub].end;
    141             token_node[token_node_number].bottom=token_node[reg_pattern_table[token_node_number].sub].bottom;
    142             token_node[token_node_number].top=token_node[reg_pattern_table[token_node_number].sub].top;
    143             token_node_number++;
    144             break;
    145         case  alias:
    146             //对于假名,这里需要重新拷贝nfa
    147             nfa_cope_alias();
    148             token_node_number++;
    149             break;
    150         case literal_char:
    151             //对于单字符,直接新建两个节点,然后在这两个节点中建立一条边
    152             //然后初始化token_node,这里nfa上限和下限非常好处理,因为只有两个节点
    153             nfa_node_number++;
    154             nfa_node[nfa_node_number]=NULL;
    155             token_node[token_node_number].end=nfa_node_number;
    156             add_edge_to=nfa_node_number;
    157             token_node[token_node_number].bottom=nfa_node_number;
    158             nfa_node_number++;
    159             nfa_node[nfa_node_number]=NULL;
    160             token_node[token_node_number].begin=nfa_node_number;
    161             add_edge_from=nfa_node_number;
    162             add_edge(add_edge_from,add_edge_to,reg_pattern_table[token_node_number].value);
    163             token_node[token_node_number].top=nfa_node_number;
    164             token_node_number++;
    165             break;
    166         case set_of_char:
    167             for_i=reg_pattern_table[token_node_number].begin;
    168             for_j=reg_pattern_table[token_node_number].end;
    169             nfa_node_number++;
    170             //增加一个节点,当前是作为尾节点
    171             token_node[token_node_number].end=nfa_node_number;
    172             token_node[token_node_number].bottom=nfa_node_number;
    173             nfa_node[nfa_node_number]=NULL;
    174             add_edge_to=nfa_node_number;
    175             nfa_node_number++;
    176             //增加一个节点,作为头节点
    177             add_edge_from=nfa_node_number;
    178             token_node[token_node_number].begin=nfa_node_number;
    179             nfa_node[nfa_node_number]=NULL;
    180             token_node[token_node_number].top=nfa_node_number;
    181             for(for_i;for_i<=for_j;for_i++)
    182             {
    183                 //对于字符集里面的每个字符,都需要增加一条边
    184                 add_edge(add_edge_from,add_edge_to,(char)for_i);
    185             }
    186             token_node_number++;
    187             break;
    188         case maybe_exist:
    189             //处理问号运算符,其实这个就比较简单了,只需要在子表达式的头节点与尾节点之间加一条空边
    190             reg_pattern_origin=reg_pattern_table[token_node_number].sub;
    191             add_edge_from=token_node[reg_pattern_origin].begin;
    192             add_edge_to=token_node[reg_pattern_origin].end;
    193             token_node[token_node_number].begin=token_node[reg_pattern_origin].begin;
    194             token_node[token_node_number].end=token_node[reg_pattern_origin].end;
    195             token_node[token_node_number].bottom=token_node[reg_pattern_origin].bottom;
    196             token_node[token_node_number].top=token_node[reg_pattern_origin].top;
    197             add_edge(add_edge_from,add_edge_to,(char)17);
    198             token_node_number++;
    199             break;
    200         case one_or_more:
    201             //在这里,直接从子节点的尾节点发出一条边到子节点的开始节点
    202             reg_pattern_origin=reg_pattern_table[token_node_number].sub;
    203             token_node[token_node_number].end=token_node[reg_pattern_origin].end;
    204             add_edge_to=token_node[token_node_number].begin=token_node[reg_pattern_origin].begin;
    205             token_node[token_node_number].bottom=token_node[reg_pattern_origin].bottom;
    206             token_node[token_node_number].top=token_node[reg_pattern_origin].top;
    207             add_edge_from=token_node[reg_pattern_origin].end;
    208             add_edge(add_edge_from,add_edge_to,(char)17);
    209             token_node_number++;
    210             break;
    211         default:
    212             printf("a type can't be recognised, please check
    ");
    213             token_node_number++;
    214             break;
    215         }
    216     }
    217 }
    218 
    219 void show_nfa_table(void)
    220 {
    221     int final_re;
    222     int nfa_final_bottom;
    223     int nfa_final_top;
    224     p_edge_list traverse;
    225     char label;
    226     int destination;
    227     final_re=token_node_number-1;
    228     nfa_final_bottom=token_node[final_re].bottom;
    229     nfa_final_top=token_node[final_re].top;
    230     for(nfa_final_bottom;nfa_final_bottom<=nfa_final_top;nfa_final_bottom++)
    231     {
    232         traverse=nfa_node[nfa_final_bottom];
    233         while(traverse!=NULL)
    234         {
    235             destination=traverse->destination_number;
    236             label=traverse->label_of_edge;
    237             if(label==(char)17)
    238             {
    239                 printf("there is an edge from %d to %d with null_transition
    ",nfa_final_bottom,destination);
    240             }
    241             else
    242             {
    243                 printf("there is an edge from %d to %d with label %c
    ",nfa_final_bottom,destination,label);
    244             }
    245             traverse=traverse->next_edge;
    246         }
    247     }
    248     printf("the nfa_graph begins with %d
    ",token_node[final_re].begin);
    249     printf("the nfa_graph ends with %d
    ",token_node[final_re].end);
    250 }
  • 相关阅读:
    centos7.6 使用yum安装mysql5.7
    解决hadoop本地库问题
    docker-compose 启动警告
    docker 安装zabbix5.0 界面乱码问题解决
    docker 部署zabbix问题
    zookeeper 超时问题
    hbase regionserver异常宕机
    (转载)hadoop 滚动升级
    hadoop Requested data length 86483783 is longer than maximum configured RPC length
    zkfc 异常退出问题,报错Received stat error from Zookeeper. code:CONNECTIONLOSS
  • 原文地址:https://www.cnblogs.com/huangfeidian/p/3154477.html
Copyright © 2011-2022 走看看