DFA的代码表示笔记
DFA是一个有向图
- 不同的代码表示
- 转移表
- 哈希表
- 跳转表
- …
其构造却决与在实际实现中面对时间空间的权衡
转移表
以正则表达式为例
a(b|c)*
,其状态转移图为
在C语言中可以用一个二维数组来表示
状态/字符 a b c 0 1 error error 1 error 1 1
#define ERROR -1 char table[M][N]; // 大小根据字符集的大小来确定 // init char table table[0]['a'] = 1; table[1]['b'] = 1; table[1]['c'] = 1; // other is error state, error = -1 .....
有一个驱动算法,当字符流输入的时候,驱动算法依据符号表输出记号流
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WRbhhSh2-1637423307872)(https://i.loli.net/2021/11/14/H5MTA8ZFUl12ckg.png)]
nextToken(); // 字符流提供的一个接口 state = 0; stack = []; while(state != ERROR){ c = getChar(); // 获取一个字符,与本算法无关的一个接口 if(state is ACCEPT) // ACCEPT是特殊的接受状态,如果接受,之前的输入是不需要考虑的 clear(stack); push(state); state = table[state][c]; } while(state is not ACCEPT) state = pop(); rollback(); // 分析出错,字符指针回退,回退一个字符
转移表有一个很大的缺点,就是占空间,几个状态就要占据很大的一个空间,某些时候如果对空间性能要求特别严格的话,可能使用这一个方法不是最佳的一种选择。而跳转表法则解决了这一个占空间的问题,局部性非常突出,很多解决方案也会考虑采用这种解决方法
最长匹配原则
"ifif"
这样的类型,他会匹配,ifif,而不会只匹配if
跳转表(go to table或者jump table)
还是上面的例子,用跳转表写的话,可能是这样的
nextToken();
state = 0;
stack = [];
goto q0;
q0:
c = getChar();
if(state is ACCEPT)
clear(stack);
push(state);
if(c == 'a')
state = 1;
goto q1;
state = ERROR;
goto error_code;
q1:
c = getChar();
if(state = ACCEPT)
clear(stack);
push(state);
if(c == 'b' || c == 'c')
state = 1;
goto q1;
state = ERROR;
goto error_code;
error_code:
while(stats is not ACCEPT)
state = pop();
rollback();
......