此文是对编译原理学习的部分总结,与一般介绍有限状态机侧重原理不同,本文侧重的是程序实现的思想。程序实现消除字符串中的多余空格,只保留一个,(\r \n \t \s)。
程序根据键盘先后键入的值,判断是否该输出后键入的值,因此程序的输出有多种情况,输出选择分支时,很多人都只知道用case语句,其实可以使用函数指针数组取代之,这样程序更加简洁、清晰、强大,下面说说具体实现。
三个代表:
(1) 字符分类表:描述当前输入的字符的类型,当输入是空格时(对应ASCII码的009、010、013、032),记录为“0”,当输入为普通字符时,记录为“1”。所以整个表只有两种状态,见程序input_tab[],它由输入的字符决定;它对应着有穷自动机中的<no_ws>和<ws>。
字符分类表:input_tab[]
字符分类 |
非空格 |
空格 |
状态描述 |
<no-ws> |
<ws> |
chin_type |
0 |
1 |
(2) 状态转换表:根据程序的要求,这里输入的字符状态chin_type只有两种,就是空格(0)和非空格(1),另外,前一次输出动作state_bf也有两种情况,所以,状态的转换对应程序中的state_tran_tab[][],它由当前状态和输入类型决定;它对应有穷自动机大圆中的“0”和“1”。它的值有两个,状态转换过程有四个。
状态转换表:state_tran_tab[][]
state_bf \ chin_type |
0 (非空格) |
1 (空格) |
0 |
0 |
1 |
1 |
0 |
1 |
(3) 输出动作表:用来确定当前读入的字符是否该输出,对应程序中的action_tab[][],由前一次输出的状态(state_bf)和当前状态(state_af)决定当前输出状态,所以状态有四种:字符接字符00,字符接空格01,空格接字符10,空格接空格11,只有最后一种情况不输出,这是一个函数指针数组,由前一次输入类型和当前输入类型决定;它对应着有穷自动机的output和do_nothing两个动作,但是转换过程有四种。
输出动作表:action_tab[][]
state_bf \ state_af |
0 (输出) |
1 (不输出) |
0 |
0 |
0 |
1 |
0 |
1 |
有穷自动机描述如下:
其实此图对应着程序的流程图(有穷自动机就是流程图的抽象)。为了更好的解释程序,我在各个状态转换线路上标上了A/B/C/D,下面一一做出解释(A:state_bf==0,当前输入为<no_ws>,回到当前状态,输出动作为out_put; B:state_bf==0,当前输入为<ws>,转换到状态1,输出动作为out_put,因为是第一次遇到空格; D:state_bf==1,当前输入为<ws>,回到当前状态,输出动作为do_nothing,因为连续遇到空格; C:state_bf==1,当前输入为<no_ws>,转换到状态0,输出动作为out_put,因为只遇到一次空格)
程序代码如下:
#include "stdio.h"
int input_tab[128]={
0,0,0,0,0,0,0,0,0,1,
0,0,0,1,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,1,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0};
int state_tran_tab[2][2]={{0,1},{0,1}};
void (* action_tab[2][2])(char ch)={print,print,print,do_nothing};
void print(char ch)
{
printf("%c",ch);
}
void do_nothing(char ch)
{}
void translate(char *input)
{
int i=0;
int state_af=0,state_bf=0;
int chin_type=0;
while(input[i]!='\0')
{
int chin=input[i];
if(0<=chin<=128)
{
chin_type=input_tab[chin];
state_bf=state_af;
state_af=state_tran_tab[state_bf][chin_type];
action_tab[state_bf][state_af](chin);
i++;
}
}
}
int main()
{
char *input="a b c";
translate(input);
getchar();
return 0;
}