| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 3267 人关注过本帖, 1 人收藏
标题:[原创]正则表达式解析 -- 词法分析部分 -- 源代码
只看楼主 加入收藏
rabbit5455
Rank: 2
等 级:论坛游民
帖 子:123
专家分:25
注 册:2004-4-14
收藏(1)
 问题点数:0 回复次数:3 
[原创]正则表达式解析 -- 词法分析部分 -- 源代码

===============================================
这个是老版本,一会儿我发个最新的DEMO版本
新版本链接如下:
RegExp DEMO version -- [1]正则表达式 TO NFA表格 -- 词法分析代码
RegExp DEMO version -- [2]最核心函数代码(上) -- int dealState(SymbolType symboltype)
RegExp DEMO version -- [2]最核心函数代码(中) -- int dealState(SymbolType symboltype)
RegExp DEMO version -- [2]最核心函数代码(下) -- int dealState(SymbolType symboltype)
RegExp DEMO version -- [3][regexp.h]最核心数据类型
===============================================

我博客中的一篇文章,最近要完成的一个项目:做一个正则表达式的解析工具。
Blog: http://rabbit5455.bc-cn.net
=========================================

最近一直努力的学习编译原理,对于里面提到的“自动机”好好理解了一下,

还感受了一下lex和yacc的强大功能,真是厉害啊 。。。

我的兄弟伦子小朋友想写一个8086的编译解释工具(类似一个虚拟机)。

我对于CPU的理解很简单,它首先可以看成一个数字电路,可以用数字逻辑的方式

来理解,而数字逻辑便是状态机了,状态机会动了,也就是“自动机”了,

“确定的有穷自动机(DFA)”模型与真实的CPU应该是一码子事情了,

而(DFA)对应了一条“正规文法”,

“正规文法”对应了一个“正则表达式”,

“正则表达式”可以转化为一个“不确定的有穷自动机(NFA)”,

(NFA)可以转化为(DFA),呵呵 。。。

累了,想去睡觉去了 。。。

怎么看来看去,就是个圈啊 。。。

呵呵:“正则表达式” == (DFA)

这几天一直都在分析正则表达式的词法,语法 。。。

把正则表达式的词法分析图画了出来,代码在后面

(图片比较大,点击查看大图,那样清楚

代码也写好了,如下:

/*词法分析,取得一个符号*/
SymbolType getSymbol() {
char *cc = &g_symbol_charvalue;
char tmp; /*临时变量*/
*cc = g_strRegExp[++g_scan_pos];
if ((*cc>='0' && *cc<='9') || (*cc>='a' && *cc<='z') || (*cc>='A' && *cc<='Z')) {
return g_symbol_type=INPUT_ELE;
}
/*正则表达式结尾*/
if (*cc == NULL) {return g_symbol_type=END_REGEXP;}
if (*cc == '(') {return g_symbol_type=AND_MACHINE_BEGIN;}
if (*cc == ')') {return g_symbol_type=AND_MACHINE_END;}
if (*cc == '[') {return g_symbol_type=OR_MACHINE_BEGIN;}
if (*cc == ']') {return g_symbol_type=OR_MACHINE_END;}
if (*cc == '|') {return g_symbol_type=BACKTRACE;}
if (*cc == '^') {return g_symbol_type=NOT_OP;}
if (*cc == '.') {return g_symbol_type=DOT;}
/*转义字符*/
if (*cc == '\\') {
*cc = g_strRegExp[++g_scan_pos];
if (*cc == 'd') {return g_symbol_type=NUMBER;}
if (*cc == 'D') {return g_symbol_type=NOT_NUMBER;}
if (*cc == 'f') {*cc = '\f'; return g_symbol_type=INPUT_ELE;}
if (*cc == 'n') {*cc = '\n'; return g_symbol_type=INPUT_ELE;}
if (*cc == 'r') {*cc = '\r'; return g_symbol_type=INPUT_ELE;}
if (*cc == 't') {*cc = '\t'; return g_symbol_type=INPUT_ELE;}
if (*cc == 'v') {*cc = '\v'; return g_symbol_type=INPUT_ELE;}
if (*cc == 's') {return g_symbol_type=ALL_SPACE;}
if (*cc == 'S') {return g_symbol_type=NOT_ALL_SPACE;}
if (*cc == 'w') {return g_symbol_type=AZaz09_;}
if (*cc == 'W') {return g_symbol_type=NOT_AZaz09_;}
/*16进制*/
if (*cc == 'x') {
tmp = g_strRegExp[++g_scan_pos];
if (tmp>='0' && tmp<='9') {
*cc = tmp - '0';
} else if (tmp>='a' && tmp<='f') {
*cc = tmp - 'a' + 10;
} else if (tmp>='A' && tmp<='F') {
*cc = tmp - 'A' + 10;
} else {
/*不是16进制数字,返回原字符'x'*/
g_scan_pos--;
return g_symbol_type=INPUT_ELE;
}
tmp = g_strRegExp[++g_scan_pos];
if (tmp>='0' && tmp<='9') {
*cc *= 16;
*cc += tmp - '0';
} else if (*cc>='a' && *cc<='f') {
*cc *= 16;
*cc += tmp - 'a' + 10;
} else if (*cc>='A' && *cc<='F') {
*cc *= 16;
*cc += tmp - 'A' + 10;
} else {
/*这个不是16进制数字,只有一位:\xF*/
g_scan_pos--;
return g_symbol_type=INPUT_ELE;
}

return g_symbol_type=INPUT_ELE;
}
/*8进制*/
if (*cc>='0' && *cc<='3') {
*cc -= '0';
tmp = g_strRegExp[++g_scan_pos];
if (tmp>='0' && tmp<='7') {
*cc *= 8;
*cc += tmp - '0';
} else {
/*只有一位8进制数字:\7*/
g_scan_pos--;
return g_symbol_type=INPUT_ELE;
}
tmp = g_strRegExp[++g_scan_pos];
if (tmp>='0' && tmp<='7') {
*cc *= 8;
*cc += tmp - '0';
} else {
/*只有两位8进制数字:\77*/
g_scan_pos--;
return g_symbol_type=INPUT_ELE;
}
return g_symbol_type=INPUT_ELE;
}
if (*cc>='4' && *cc<='7') {
*cc -= '0';
tmp = g_strRegExp[++g_scan_pos];
if (tmp>='0' && tmp<='7') {
*cc *= 8;
*cc += tmp - '0';
} else {
/*只有一位8进制数字:\7*/
g_scan_pos--;
return g_symbol_type=INPUT_ELE;
}
return g_symbol_type=INPUT_ELE;
} else {
/*[^x0-7dDfnrtvsSwW]*/
return g_symbol_type=INPUT_ELE;
}
}
/*重复运算*/
if (*cc == '*') {return g_symbol_type=REPEAT_ZERO_MORE;}
if (*cc == '+') {return g_symbol_type=REPEAT_ONCE_MORE;}
if (*cc == '?') {return g_symbol_type=REPEAT_ZERO_ONCE;}
if (*cc == '{') {
*cc = g_strRegExp[++g_scan_pos];
if (*cc>'9' || *cc<'0') {return g_symbol_type=UNKNOWN;}
g_repeat_m = 0; /*取{m,n}的m*/
while (*cc>='0' && *cc<='9') {
g_repeat_m *= 10;
g_repeat_m += *cc-'0';
*cc = g_strRegExp[++g_scan_pos];
}
/*{m}*/
if (*cc == '}') {return g_symbol_type=REPEAT_RANGE_M;}
if (*cc != ',') {return g_symbol_type=UNKNOWN;}

*cc = g_strRegExp[++g_scan_pos];
/*{m,}*/
if (*cc == '}') {return g_symbol_type=REPEAT_RANGE_M_MORE;}
/*{m,n}*/
if (*cc>'9' || *cc<'0') {return g_symbol_type=UNKNOWN;}
g_repeat_n = 0; /*取{m,n}的n*/
while (*cc>='0' && *cc<='9') {
g_repeat_n *= 10;
g_repeat_n += *cc-'0';
*cc = g_strRegExp[++g_scan_pos];
}
if (*cc == '}') {
return g_symbol_type=REPEAT_RANGE_MN;
} else {
return g_symbol_type=UNKNOWN;
}
}

return g_symbol_type=UNKNOWN;
}

[此贴子已经被作者于2007-6-2 23:14:18编辑过]

搜索更多相关主题的帖子: 源代码 词法分析 正则表达式 解析 
2007-05-19 02:17
herbert_1987
Rank: 5Rank: 5
等 级:贵宾
威 望:15
帖 子:1314
专家分:0
注 册:2007-5-13
收藏
得分:0 
哗!

人生重要的不是所站的位置,而是所朝的方向
2007-05-19 02:28
rabbit5455
Rank: 2
等 级:论坛游民
帖 子:123
专家分:25
注 册:2004-4-14
收藏
得分:0 
[原创]终结符的重复运算做好了

今天把终结符的重复运算做好了,像:a*, a+, a?,
还有范围的运算:a{3,5}表示至少3个a,至多5个a。

分析结果如下:
[root@localhost RegExp]# ./regexp_linux.o
debug: start scan the regexp:
"xa{2,4}b{1,2}y"
debug: type -> 7 | m -> 2 | n -> 4
debug: type -> 7 | m -> 1 | n -> 2
9cf9128->[120]9cf9540,
9cf9540->[97]9cf9958,
9cf9958->[97]9cf9d70,
9cf9d70->[97]9cfa188, [256]9cfa188,
9cfa188->[97]9cfa5a0, [256]9cfa5a0,
9cfa5a0->[98]9cfa9b8,
9cfa9b8->[98]9cfadd0, [256]9cfadd0,
9cfadd0->[121]9cfb1e8,
9cfb1e8->
head->9cf9128 cur->9cfb1e8 tail->9cfb1e8
[root@localhost RegExp]#

上面的数据是一张NFA的内存模型,[97][98]是ascii码,
那些16进制数是内存地址(指针),[256]是空,也就是编译原理说的
空元素--epsilon, 把这些地址用一条路径连起来,路径上标明ascii就是NFA了。

我不知道怎么在回复帖子的时候画画,所以,感兴趣的朋友,
自己拿只笔画画吧 。。。

过几天把(,[, | 等处理完就把代码发出来,
先发这次的终结符的重复运算代码:


case INPUT_ELE:
/*是一个终结符,连上一条弧*/
g_lastchar = g_symbol_charvalue;
psnew = getdestState(g_st->curState, (int)g_symbol_charvalue);
if (psnew == NULL) {
psnew = newState(g_st->eleCount);
appendStateTable(g_st, psnew); /*添加到状态表*/
setdestState(g_st->curState, (int)g_symbol_charvalue, psnew);
}
/*重复运算符*/
getSymbol();
switch (g_symbol_type) {
case REPEAT_ZERO_MORE:
/*(a*)*/
setdestState(g_st->curState, g_st->curState->destStateCount-1, psnew);
setdestState(psnew, g_st->curState->destStateCount-1, g_st->curState);
/*移动到新的状态*/
g_st->curState = psnew;
printf("debug: ZEOR_MORE\n");
break;
case REPEAT_ZERO_ONCE:
/*(a?)*/
setdestState(g_st->curState, g_st->curState->destStateCount-1, psnew);
/*移动到新的状态*/
g_st->curState = psnew;
printf("debug: ZEOR_ONCE\n");
break;
case REPEAT_ONCE_MORE:
/*(a+)*/
setdestState(psnew, g_st->curState->destStateCount-1, g_st->curState);
/*移动到新的状态*/
g_st->curState = psnew;
printf("debug: ONCE_MORE\n");
break;
case REPEAT_RANGE_MN:
/*(a{m,n})*/
/*移动到新的状态*/
if (g_repeat_m <= 0) {
/*处理{0,n}的情况,把刚刚的a变成a?*/
setdestState(g_st->curState, g_st->curState->destStateCount-1, psnew);
g_st->curState = psnew;
repeat_optional(g_repeat_n-1, g_lastchar);
} else {
g_st->curState = psnew;
repeat_needed(g_repeat_m-1 , g_lastchar);
repeat_optional(g_repeat_n-g_repeat_m, g_lastchar);
}
printf("debug: type -> %d\t| m -> %d | n -> %d\n", g_symbol_type, g_repeat_m, g_repeat_n);
break;
case REPEAT_RANGE_M_MORE:
/*(a{m,})*/
/*移动到新的状态*/
g_st->curState = psnew;

printf("debug: type -> %d\t| m -> %d | n -> max_int\n", g_symbol_type, g_repeat_m);
break;
case REPEAT_RANGE_M:
/*(a{m})*/
/*移动到新的状态*/
g_st->curState = psnew;
printf("debug: type -> %d\t| m -> %d\n", g_symbol_type, g_repeat_m);
break;
default:
/*不是重复运算符,移动到新的状态,然后重新循环*/
g_st->curState = psnew;
continue;
}

break;

/*author: WangXuhua@tsu.edu.cn, 王旭华*/



Member Of Qingfeng Studio 王旭华[http://][http://hi.baidu.com/rabbit5455]
2007-05-19 14:23
rabbit5455
Rank: 2
等 级:论坛游民
帖 子:123
专家分:25
注 册:2004-4-14
收藏
得分:0 
这个是老版本,我已经发布了最新的DEMO版本
新版本链接如下:
RegExp DEMO version -- [1]正则表达式 TO NFA表格 -- 词法分析代码
RegExp DEMO version -- [2]最核心函数代码(上) -- int dealState(SymbolType symboltype)
RegExp DEMO version -- [2]最核心函数代码(中) -- int dealState(SymbolType symboltype)
RegExp DEMO version -- [2]最核心函数代码(下) -- int dealState(SymbolType symboltype)
RegExp DEMO version -- [3][regexp.h]最核心数据类型

在 [1] 可以下载到源代码和两个二进制文件
regexp-win.exe -- windows的编译
cfree3.5+win2003
regexp-linux -- linux下的编译
gcc version 3.3.3 20040412 (Red Hat Linux 3.3.3-7)


Member Of Qingfeng Studio 王旭华[http://][http://hi.baidu.com/rabbit5455]
2007-06-02 23:50
快速回复:[原创]正则表达式解析 -- 词法分析部分 -- 源代码
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.018791 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved