词法分析器实验报告Word文档格式.docx
《词法分析器实验报告Word文档格式.docx》由会员分享,可在线阅读,更多相关《词法分析器实验报告Word文档格式.docx(12页珍藏版)》请在冰豆网上搜索。
publicclassState{
/*既是其ID号,又是在状态集中的索引*/
privatefinalintID=StateCounter++;
privateclassAdj{/*邻接边*/
charroute;
/*路由字符*/
Statestate;
/*邻接状态*/
publicAdj(charr,Stated){
route=r;
state=d;
}
}
/*邻接边集*/
ArrayList<
Adj>
adjList;
}
/*记录状态数,并为新状态的ID赋值*/
privatestaticintStateCounter=0;
publicArrayList<
Character>
charSet;
/*字符集*/
State>
states;
/*状态集*/
publicStatestartState;
/*开始状态*/
endStates;
/*结束状态集*/
处理正规表达式的方法集
/*正规表达式*/
publicclassRegEx{
/*代表所有数字*/
publicstaticfinalStringDIGIT="
1&
2&
3&
4&
5&
6&
7&
8&
9&
0"
;
publicstaticfinalcharEND='
$'
/*代表表达式的末尾*/
publicstaticfinalcharNULL_CHAR='
~'
/*空字符*/
publicstaticfinalcharTRANSFER='
\\'
/*转义符,暂时未用*/
/*正规式中的运算符,数组的第一个运算符的优先级最高,最后一个优先级最低*/
publicstaticfinalchar[]OPERATORS=
{'
('
'
*'
&
'
|'
)'
'
};
/*判断字符r是否为运算符*/
publicstaticBooleanisOperator(charr)
/*判断字符r是否为可接受的字符*/
publicstaticBooleanisOperand(charr)
/*比较栈中运算符和正规式中运算符的优先级,在构造NFA的后缀求值中使用*/
publicstaticcharcmpPriority(charopInStack,charopInRE)
/*对正规式进行简单的验证,不符合定义时将抛出异常*/
publicstaticvoidcheck(Stringexpr)
NFA数据结构示意图
publicclassNFA{/*不确定状态机*/
privatefinalintID=stateCounter++;
classAdj{
publicAdj(charr,States){
state=s;
privateAdjlNode;
/*左邻接*/
privateAdjrNode;
/*右邻接*/
privatestaticintstateCounter=0;
publicStateendState;
/*结束状态*/
核心算法伪代码:
算法1Thompson算法
输入正规式w
输出一个接受同一正规集的NFA
辅助数据结构
NFA状态对{NFA起始状态;
NFA终止状态}。
存储已构建的NFA的初态和终态
NFA栈:
以NFA状态对作为栈元素。
运算符栈:
以RegEx中定义的正规式的运算的运算符作为栈元素
实现方法:
利用正规式的运算符进行正规式后缀求值
具体如下例:
正规式为(a&
b|b)*。
以$为结束符
(s,f)表示某一NFA从s状态开始,到f结束。
步骤
NFA栈
运算符栈
输入序列
动作
1
$
(a&
b|b)*$
(入栈
2
$(
a&
0-a->
1,(0,1)入栈
3
(0,1)
入栈
4
$(&
2-b->
3,(2,3)入栈
5
(0,1)(2,3)
|b)*$
出栈
(0,1)(2,3)出栈
1-ε->
(0,3)入栈
6
(0,3)
|入栈
7
$(|
b)*$
4-b->
5,(4,5)入栈
8
(0,3)(4,5)
)*$
|出栈
(0,3)(4,5)出栈
6-ε->
0,6-ε->
3-ε->
7,5-ε->
(6,7)入栈
9
(6,7)
(出栈
10
*$
*入栈
11
$*
*出栈
(6,7)出栈
8-ε->
6,8-ε->
7-ε->
6,7-ε->
(8,9)入栈
12
(8,9)
$出栈
13
结束
其中:
算法2求ε_闭包
输入NFA状态集T:
由可变数组存储,每个数组元素为一个状态
输出NFA状态集T的ε_闭包U:
同上
实现方法
forT中的每一个状态s
loopifs未被访问then将s加入到U中endif
while有新状态t加入Udo
if由t经ε转移至左结点tl且tl未被访问过
then将tl加入到U中endif
if由t经ε转移至右结点tr且tr未被访问过
then将tr加入到U中endif
end
endloop
算法3子集法
输入一个NFAN
输出一个接受同一正规集的DFAD。
其中,含有NFA初态的DFA状态为DFA的初态,所有含有NFA终态的DFA状态为DFA的终态
classFAPair{
DFA.StatedfaState;
NFA.State>
nfaStates;
FAPair{DFA状态;
NFA状态集}。
在创建DFA状态时存储DFA状态及其相对应的NFA状态集
FAPair>
FAPair集:
存储创建DFA过程中产生的FAPair
Queue<
FAPair队列:
存储未被访问过的DFA状态
实现方法
构建起始FAPair(s0,ε_闭包({s0}));
将其压入FAPair队列,并收录至FAPair集中;
将s0收录至DFA状态集中,s0为DFA的初态;
while队列不为空
弹出队列的首元素,并取其DFA状态d和NFA状态集T;
ifT中包括NFA的终态thend为DFA的终态;
endif
for每一个输入字符a
loop
U:
=ε_闭包(smove(T,a));
ifU不为空
在FAPair集中查找U所对应的DFA状态d’
if没有相对应的DFA状态d’
then创建DFA状态d’,在d的邻接边集中加入邻接边(a,d’);
构建起始FAPair(d’,U);
将其压入FAPair队列,并收录至FAPair集中
else直接在d的邻接边集中加入邻接边(a,d’)
endif
endloop
DFA的字符集=NFA的字符集;
算法4DFA最小化
输入一个DFAD={S,∑,Dtran,s0,F}
输出一个DFAD’={S’,∑,Dtran’,s0’,F’},它和D接受同样的正规集,但是状态数最少
辅助数据结构:
Integer>
划分:
存储一个划分,每个结点存储DFA状态在DFA中的索引
>
划分表:
存储所有的划分
int[DFA状态数]划分映射表:
存储每个DFA状态所在的划分在划分表中的索引
(1)构造划分表∏,∏[0]=划分{F};
∏[1]=划分{S-F}。
∏[1]可能为空
(2)构造划分映射表M
forDFA中的每个状态d
loopifd∈划分{F}thenM[d]=0
elseM[d]=1
(3)应用下述过程构造新的划分∏new:
∏new=∏;
for∏new的每一个划分G={d1,d2,d3,d4...}
for∑中的每一个字符a
loop
d1’=smove(d1,a);
预构造新划分U;
forj=2,3,4...
loop
dj’=smove(dj,a)
ifd1’和dj’中有一个出错状态
或d1’和dj’中没有出错状态但M[d1’]≠M[dj’]
then将dj从G中去掉并加入到划分U中endif
endloop
if有状态加入划分U中
then将新组U加入∏;
重新执行步骤(3);
endif
endloop
(4)利用∏new构建D’
for∏new中的每一个组Gi
取Gi的第一个状态d;
在D’中构建状态di’;
ford的邻接边集中每个邻接边Adj
在di’的邻接边集中加入
邻接边(Adj.route,D’状态集中的第(M[Adj.state])个状态)
实验结果:
正规式:
acd*|(a)*测试字符串为空接受
ab*(ab|c*a)测试字符串:
aa接受
(a|b)*abb测试字符串:
bb不接受