找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 2404|回复: 2

【C】将正则表达式转换为FSA

[复制链接]

17

主题

41

回帖

770

积分

用户组: 大·技术宅

UID
6266
精华
6
威望
58 点
宅币
516 个
贡献
50 次
宅之契约
0 份
在线时间
41 小时
注册时间
2020-9-26
发表于 2020-11-30 21:35:00 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
以下程序代码实现了将一个正则表达式转换为FSA(Finite-State Automation 有穷状态自动机)的功能。
本程序需要https://github.com/coshcage/StoneValley库的支持。
程序运行后需要输入一个合法的正则表达式,例如 a(ba|ca)|ac|ab) ,程序的输出是该正则表达式的逆波兰形式和转移表。
注意,输入的正则表达式支持‘(’、‘)’、‘|’和‘*’运算。+和?需要自行转换。
a+ == aa*
a? == a | epsilon
在输出的转移表内‘>’表示开始状态,'*'表示结束状态。(数字)为状态,‘\数字’为输入符号。‘\0’表示空转移。
该程序算法的大致原理是:
1、将正则表达式转换为相对应的逆波兰式。
2、扫描逆波兰式,将输入符号取出后转换为状态+输入符号的图。将图的两个节点压入栈内。
3、将运算符取出,并取出相应的图。在相应的图上完成运算后再将图的两个节点压回栈内。
4、对于连接运算,将栈内存储的图节点取出一一做连接运算后压入栈内。
5、最后从站内取出的节点组合就是该自动机的起始节点和结束节点。
该程序未实现自动机的化简。
如果需要化简自动机,需要自行实现删除空环路、删除空变迁、自动机确定化以及自动机约简四个步骤。
有了转移表,就可以使用表驱动的方法运行自动机,识别正则语言。
因为本人水平有限,不到位之处还请大家指出。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "svgraph.h"
  5. #include "svstack.h"
  6. #include "svqueue.h"

  7. STACK_L stkOperator, stkOperand;
  8. QUEUE_L queRegexp;
  9. GRAPH_L machine;

  10. struct st_Operator
  11. {
  12.         char name;
  13.         char level;
  14. } operators[] = { '(', -1, ')', -1, '*', 2, '|', 1 };

  15. typedef struct st_Element
  16. {
  17.         union un_Data
  18.         {
  19.                 char operator;
  20.                 char operand;
  21.         } data;
  22.         BOOL isOperator;
  23. } Element, * P_Element;

  24. typedef struct st_Node
  25. {
  26.         size_t x;
  27.         size_t y;
  28. } Node, * P_Node;

  29. /* Finding info for edges. */
  30. typedef struct _st_FIEDG {
  31.         EDGE     vertex;
  32.         P_NODE_S pnode;
  33.         size_t   bweight; /* TRUE for weighted graph; FALSE for unweighted graph. */
  34. } _FIEDG, * _P_FIEDG;

  35. int cbftvsFindMaxData(void * pitem, size_t param)
  36. {
  37.         if (*(size_t *)((P_TNODE_B)pitem)->pdata > * (size_t *)param)
  38.                 *(size_t *)param = *(size_t *)((P_TNODE_B)pitem)->pdata;
  39.         return CBF_CONTINUE;
  40. }

  41. size_t GenerateUniqueState(P_GRAPH_L pgrp)
  42. {
  43.         if (setIsEmptyT(pgrp))
  44.                 return 1;
  45.         {
  46.                 size_t r = 0;
  47.                 setTraverseT(pgrp, cbftvsFindMaxData, (size_t)&r, ETM_LEVELORDER);
  48.                 return r + 1;
  49.         }
  50. }

  51. char GetOperator(char o)
  52. {
  53.         int i;
  54.         for (i = 0; i < sizeof operators / sizeof operators[0]; ++i)
  55.                 if (operators[i].name == o)
  56.                         return operators[i].level;
  57.         return 0;
  58. }

  59. int Splitter(char * pstr)
  60. {
  61.         BOOL turn = FALSE;
  62.         char c;
  63.         Element ele;
  64.         while (*pstr != '\0')
  65.         {
  66.                 switch (*pstr)
  67.                 {
  68.                 case '\\':
  69.                         if (turn)
  70.                         {
  71.                                 ele.data.operand = *pstr;
  72.                                 ele.isOperator = FALSE;
  73.                                 queInsertL(&queRegexp, &ele, sizeof(Element));
  74.                                 turn = FALSE;
  75.                                 break;
  76.                         }
  77.                         turn = TRUE;
  78.                         break;
  79.                 case '(':
  80.                 case ')':
  81.                 case '|':
  82.                 case '*':
  83.                         if (turn)
  84.                         {
  85.                                 ele.data.operand = *pstr;
  86.                                 ele.isOperator = FALSE;
  87.                                 queInsertL(&queRegexp, &ele, sizeof(Element));
  88.                         }
  89.                         else
  90.                         {
  91.                                 switch (*pstr)
  92.                                 {
  93.                                 case '(':
  94.                                         break;
  95.                                 case ')':
  96.                                         if (! stkIsEmptyL(&stkOperator))
  97.                                         {
  98.                                                 stkPeepL(&c, sizeof(char), &stkOperator);
  99.                                                 while (c != '(')
  100.                                                 {
  101.                                                         stkPopL(&c, sizeof(char), &stkOperator);
  102.                                                         ele.data.operand = c;
  103.                                                         ele.isOperator = TRUE;
  104.                                                         queInsertL(&queRegexp, &ele, sizeof(Element));
  105.                                                         if (stkIsEmptyL(&stkOperator))
  106.                                                                 break;
  107.                                                         else
  108.                                                                 stkPeepL(&c, sizeof(char), &stkOperator);
  109.                                                 }
  110.                                                 stkPopL(&c, sizeof(char), &stkOperator); /* Drop right brace. */
  111.                                         }
  112.                                         else
  113.                                         {
  114.                                                 printf("Right brace mismatch.\n\n");
  115.                                                 return 1;
  116.                                         }
  117.                                         goto Lbl_PassOperator;
  118.                                 default:
  119.                                         if (! stkIsEmptyL(&stkOperator))
  120.                                         {
  121.                                                 stkPeepL(&c, sizeof(char), &stkOperator);
  122.                                                 while (GetOperator(c) >= GetOperator(*pstr))
  123.                                                 {
  124.                                                         stkPopL(&c, sizeof(char), &stkOperator);
  125.                                                         ele.data.operand = c;
  126.                                                         ele.isOperator = TRUE;
  127.                                                         queInsertL(&queRegexp, &ele, sizeof(Element));
  128.                                                         if (stkIsEmptyL(&stkOperator))
  129.                                                                 break;
  130.                                                         else
  131.                                                                 stkPeepL(&c, sizeof(char), &stkOperator);
  132.                                                 }
  133.                                         }
  134.                                         break;
  135.                                 }
  136.                                 stkPushL(&stkOperator, pstr, sizeof(char));
  137.                         }
  138.                 Lbl_PassOperator:
  139.                         turn = FALSE;
  140.                         break;
  141.                 default:
  142.                         ele.data.operand = *pstr;
  143.                         ele.isOperator = FALSE;
  144.                         queInsertL(&queRegexp, &ele, sizeof(Element));
  145.                         turn = FALSE;
  146.                         break;
  147.                 }
  148.                 ++pstr;
  149.         }
  150.         while (! stkIsEmptyL(&stkOperator))
  151.         {
  152.                 stkPopL(&c, sizeof(char), &stkOperator);
  153.                 if (c == '(')
  154.                 {
  155.                         puts("Left brace mismatch.\n");
  156.                         return 1;
  157.                 }
  158.                 ele.data.operand = c;
  159.                 ele.isOperator = TRUE;
  160.                 queInsertL(&queRegexp, &ele, sizeof(Element));
  161.         }
  162.         if (queIsEmptyL(&queRegexp))
  163.         {
  164.                 puts("Invalid Expression.\n");
  165.                 return 1;
  166.         }
  167.         return 0;
  168. }

  169. /*
  170. *  _______          __a__
  171. *  |     |         |     V
  172. * (A) a (B) ====> (A)   (B)
  173. *  |_____|
  174. */
  175. Node CombineNode5(char transition)
  176. {
  177.         Node node;
  178.         node.x = GenerateUniqueState(&machine);
  179.         grpInsertVertexL(&machine, node.x);
  180.         node.y = GenerateUniqueState(&machine);
  181.         grpInsertVertexL(&machine, node.y);
  182.         grpInsertEdgeL(&machine, node.x, node.y, (size_t)transition);
  183.         return node;
  184. }

  185. /*
  186. *  ________          __x__  __e__  __y__
  187. *  |      |         |     V/     V/     V
  188. * (A) xy (B) ====> (A)   (C)    (D)    (B)
  189. *  |______|
  190. */
  191. Node CombineNode1(Node nodeA, Node nodeB)
  192. {
  193.         Node nodeR;
  194.         grpInsertEdgeL(&machine, nodeA.y, nodeB.x, 0); /* Epsilon transition. */
  195.         nodeR.x = nodeA.x;
  196.         nodeR.y = nodeB.y;
  197.         return nodeR;
  198. }

  199. /*
  200. *  _________          __e__  __x__  __e__
  201. *  |       |         |     V/     V/     V
  202. * (A) x|y (B) ====> (A)   (C)    (D)    (B)
  203. *  |_______|         |      __y___       ^
  204. *                    \     |      |      |
  205. *                     \e->(E)    (F)--e-/
  206. */
  207. Node CombineNode2(Node nodeA, Node nodeB)
  208. {
  209.         Node nodeR;
  210.         nodeR.x = GenerateUniqueState(&machine);
  211.         grpInsertVertexL(&machine, nodeR.x);
  212.         nodeR.y = GenerateUniqueState(&machine);
  213.         grpInsertVertexL(&machine, nodeR.y);

  214.         grpInsertEdgeL(&machine, nodeR.x, nodeA.x, 0); /* Epsilon transition. */
  215.         grpInsertEdgeL(&machine, nodeR.x, nodeB.x, 0);
  216.         grpInsertEdgeL(&machine, nodeA.y, nodeR.y, 0);
  217.         grpInsertEdgeL(&machine, nodeB.y, nodeR.y, 0);

  218.         return nodeR;
  219. }

  220. /*
  221. *  _________          __e__  __x__  __e__
  222. *  |       |         |     V/     V/     V
  223. * (A) x|y (B) ====> (A)   (C)    (D)    (B)
  224. *  |_______|         ^\_______e____>____/|
  225. *                    \________e____<_____/
  226. */
  227. Node CombineNode3(Node nodeA)
  228. {
  229.         Node nodeR;
  230.         nodeR.x = GenerateUniqueState(&machine);
  231.         grpInsertVertexL(&machine, nodeR.x);
  232.         nodeR.y = GenerateUniqueState(&machine);
  233.         grpInsertVertexL(&machine, nodeR.y);

  234.         grpInsertEdgeL(&machine, nodeR.x, nodeA.x, 0);
  235.         grpInsertEdgeL(&machine, nodeA.y, nodeR.y, 0);
  236.         grpInsertEdgeL(&machine, nodeR.x, nodeR.y, 0);
  237.         grpInsertEdgeL(&machine, nodeR.y, nodeR.x, 0);

  238.         return nodeR;
  239. }

  240. int cbftvsPrint(void * pitem, size_t param)
  241. {
  242.         P_Element pele = (P_Element)((P_NODE_S)pitem)->pdata;
  243.         if (! pele->isOperator)
  244.                 printf(" (%c)", pele->data.operand);
  245.         else
  246.                 printf(" %c", pele->data.operator);
  247.         return CBF_CONTINUE;
  248. }

  249. //int CBFFindEdgeInList(void * pitem, size_t param)
  250. //{
  251. //        _P_FIEDG pd = (_P_FIEDG)param;
  252. //        if (((P_EDGE)((P_NODE_S)pitem)->pdata)->weight == pd->vertex.weight)
  253. //        {
  254. //                pd->vertex.vid = ((P_EDGE)((P_NODE_S)pitem)->pdata)->vid;
  255. //                pd->pnode = (P_NODE_S)pitem;
  256. //                return CBF_TERMINATE;
  257. //        }
  258. //        return CBF_CONTINUE;
  259. //}
  260. //
  261. //extern P_VERTEX_L _grpGetVertexByID(P_GRAPH_L pgrp, size_t vid);
  262. //
  263. //ptrdiff_t FSA_Status(P_GRAPH_L pgrp, size_t vidx, char transition)
  264. //{
  265. //        REGISTER P_VERTEX_L pvtx;
  266. //        if (NULL != (pvtx = _grpGetVertexByID(pgrp, vidx)))
  267. //        {
  268. //                _FIEDG fd;
  269. //                extern int _grpCBFFindEdgeInList(void * pitem, size_t param);
  270. //                fd.pnode = NULL;
  271. //                fd.vertex.weight = transition;
  272. //
  273. //                if (CBF_TERMINATE == strTraverseLinkedListSC_X(pvtx->adjlist, NULL, CBFFindEdgeInList, (size_t)&fd))
  274. //                        return fd.vertex.vid; /* Edge already exists. */
  275. //        }
  276. //        return -1; /* Can not find vertex vidx. */
  277. //}

  278. int cbftvsvtxedg(void * pitem, size_t param)
  279. {
  280.         P_NODE_S pnode = (P_NODE_S)pitem;
  281.         P_EDGE pedge = (P_EDGE)pnode->pdata;
  282.         printf("\t\'\\%lu\'\t(%lu)\n", pedge->weight, pedge->vid);
  283.         return CBF_CONTINUE;
  284. }

  285. int cbftvsgrp(void * pitem, size_t param)
  286. {
  287.         P_TNODE_B tnodeb = P2P_TNODE_B(pitem);
  288.         P_VERTEX_L pvtx = (P_VERTEX_L)tnodeb->pdata;
  289.         P_Node pnode = (P_Node)param;
  290.         if (pvtx->vid == pnode->x)
  291.                 printf(">(%lu)\n", pvtx->vid); /* Start status. */
  292.         else if (pvtx->vid == pnode->y)
  293.                 printf("*(%lu)\n", pvtx->vid); /* End status. */
  294.         else
  295.                 printf(" (%lu)\n", pvtx->vid);
  296.         strTraverseLinkedListSC_A(pvtx->adjlist, NULL, cbftvsvtxedg, 0);
  297.         return CBF_CONTINUE;
  298. }

  299. int main(void)
  300. {
  301.         Node node;
  302.         STACK_L operandStack;
  303.         //char exp[] = { "a(a|b)*" };
  304.         char exp[BUFSIZ] = { 0 };
  305.         stkInitL(&stkOperator);
  306.         stkInitL(&stkOperand);
  307.         queInitL(&queRegexp);
  308.         stkInitL(&operandStack);
  309.         grpInitL(&machine);

  310.         printf("Regexp< a(a|d)* >: ");
  311.         scanf_s("%s", exp, BUFSIZ);
  312.         Splitter(exp);
  313.         printf("RPN: ");
  314.         strTraverseLinkedListSC_N(queRegexp.pfront, NULL, cbftvsPrint, 0);
  315.         printf("\n");

  316.         while (!queIsEmptyL(&queRegexp))
  317.         {
  318.                 Element ele;
  319.                 queRemoveL(&ele, sizeof ele, &queRegexp);
  320.                 if (ele.isOperator)
  321.                 {
  322.                         Node nodeA, nodeB;
  323.                         switch (ele.data.operator)
  324.                         {
  325.                         case '|':
  326.                                 if (!stkIsEmptyL(&operandStack))
  327.                                         stkPopL(&nodeA, sizeof nodeA, &operandStack);
  328.                                 else
  329.                                 {
  330.                                         printf("Expression Error!\n");
  331.                                         return 1;
  332.                                 }
  333.                                 if (!stkIsEmptyL(&operandStack))
  334.                                         stkPopL(&nodeB, sizeof nodeB, &operandStack);
  335.                                 else
  336.                                 {
  337.                                         printf("Expression Error!\n");
  338.                                         return 2;
  339.                                 }
  340.                                 nodeA = CombineNode2(nodeA, nodeB);
  341.                                 stkPushL(&operandStack, &nodeA, sizeof nodeA);
  342.                                 break;
  343.                         case '*':
  344.                                 if (!stkIsEmptyL(&operandStack))
  345.                                         stkPopL(&nodeA, sizeof nodeA, &operandStack);
  346.                                 else
  347.                                 {
  348.                                         printf("Expression Error!\n");
  349.                                         return 3;
  350.                                 }
  351.                                 nodeA = CombineNode3(nodeA);
  352.                                 stkPushL(&operandStack, &nodeA, sizeof nodeA);
  353.                                 break;
  354.                         }
  355.                 }
  356.                 else
  357.                 {
  358.                         node = CombineNode5(ele.data.operand);
  359.                         stkPushL(&operandStack, &node, sizeof node);
  360.                 }
  361.         }
  362.         /* Deduction: */
  363.         while (!stkIsEmptyL(&operandStack))
  364.         {
  365.                 Node nodeA, nodeB;
  366.                 stkPopL(&nodeA, sizeof nodeA, &operandStack);
  367.                 if (!stkIsEmptyL(&operandStack))
  368.                         stkPopL(&nodeB, sizeof nodeB, &operandStack);
  369.                 else
  370.                 {
  371.                         stkPushL(&operandStack, &nodeA, sizeof nodeA);
  372.                         break;
  373.                 }
  374.                 nodeA = CombineNode1(nodeA, nodeB);
  375.                 stkPushL(&operandStack, &nodeA, sizeof nodeA);
  376.         }
  377.         /* Pour the last item out of the stack. */
  378.         if (!stkIsEmptyL(&operandStack))
  379.                 stkPopL(&node, sizeof node, &operandStack);
  380.         else
  381.         {
  382.                 printf("Expression Error!\n");
  383.                 return 4;
  384.         }

  385.         printf("Status\tTransition\tStatus\n");
  386.         treTraverseBIn(machine, cbftvsgrp, &node);

  387.         stkFreeL(&stkOperator);
  388.         stkFreeL(&stkOperand);
  389.         queFreeL(&queRegexp);
  390.         stkFreeL(&operandStack);
  391.         grpFreeL(&machine);
  392.         return 0;
  393. }
复制代码
回复

使用道具 举报

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-4-25 04:36 , Processed in 0.045811 second(s), 34 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表