编制一个词法识别程序
假设某语言允许的标识符为字母开头的字母数字串,允许的数据为无符号的十进制或十六进制整数。其中规定十六进制数必须以数字打头、以H结尾,数中允许使用的字母为A,B,C,D,E,F(分别表示10~15)。试设计一个DFA,使它能识别标识符、无符号的十进制和十六进制整数(假定各单词之间用界限符或空格分开),并编制相应的词法识别程序。
输入:可以自定义符号串的输入形式,如键盘输入、文本文件、字符数组等。
输出:标识出规范的符号串与不合规范的符号串。
0状态是初始状态。1,2,3是终止状态。
在初始状态0时,输入数字会进入状态2,即将输出十进制或十六进制的整数,输入字母会进入状态1,即将输出字母开头的标识符
在状态2时,术后如数字仍然进入2,输入A-F的字母或H,即将输出十六进制的整数,作为终止状态之一,如果输入空格,就输出该字符串,并重新进入到状态0
在状态1时,允许输入字母或是数字,并仍然处于状态1,如果输入空格,就输出该字符串,并重新进入到状态0
在状态4时,输出的应为十六进制,但结尾要为H,故而输入数字或是A-F仍然进入状态4,但输入H会进入状态3
在状态3时,如果输入空格就输出,并重新加入状态0,其他非空格外的输入都是非法输入
#include<stdio.h>
#include<string.h>
enum type {digit,space,Hh,AF,letter} ;
//判断.数字:1 ﹔空格:2;H(h):3;字母A,B,C,D,E,F:4;其它字母:5
int isDigitOrChar (char ch) {
//数字
if(ch>=48 && ch<=57)
return digit;
//空格
else if( ch == 32 )
return space;
//H or h
else if( ch == 72 || ch == 104 )
return Hh;
//字母A,B,C,D,E,F
else if((ch>=65 && ch<=70)||(ch>=97 && ch<=102))
return AF;
//除A~F外的其它字母
else if((ch>=65 && ch<=90)||(ch>=97 && ch<=122))
return letter;
}
int main() {
//测试的输入符号串
char words[100]=" Ae35 6638 5392H A10 83A2Eh 65Ha 3G2H 80 ";
printf("Input string is: %s\n\n",words);
//指向输入符号串中当前的字符
char *q;
//存储当前识别的单词
char word[20];
//表示所处的状态
int state=0;
//单词的下标
int i;
q = words;
while(*q) {
switch(state) {
case 0: //当前为0状态
switch( isDigitOrChar(*q)) {
case digit: //数字
word[i++]=*q;
state = 2;
break;
case Hh: //H or h
case AF: //字母A,B,C,D,E, F or a, b, c, d,e,f
case letter: //字母
word[i++] =*q;
state = 1;
break;
case space: //空格
state = 0;
break;
default: //其它(非法字符)
word[i++]=*q ;
state = 5; //转移到出错状态
}
break ;
case 1: //当前为1状态
switch ( isDigitOrChar (*q)) {
case digit : //数字
case Hh: //H or h
case AF: //字母A,B,C, D,E,F or a, b, c, d,e,
case letter: //字母
word[i++]= *q;
state = 1;
break ;
case space://空格
word[i]='\0'; //当前单词结束
printf("%s is an identifier. \n" , word) ;
strcpy(word,"\0"); //单词清空
i=0; //重新计数
state = 0;
break;
default: //其它(非法字符)
word[i++] =*q;
state = 5; //转移到出错状态
}
break;
case 2: //当前为2状态
switch( isDigitOrChar(*q)) {
case digit: //数字
word[i++] = *q ;
state = 2;
break;
case Hh: //H or h
word[i++]= *q ;
state = 3;
break;
case AF: //字母A,B,C,D,E,F or a, b, c,d,e,f
word[i++] =*q ;
state = 4;
break;
case space: //空格
word[i]='\0'; //当前单词结束
printf("%s is an Integer. \n" , word) ;
strcpy (word,"\0"); //单词清空
i=0; //重新计数
state = 0;
break;
default: //其它(非法字符)
word[i++] =*q;
state = 5; //转移到出错状态
}
break ;
case 3: //当前为3状态
switch ( isDigitOrChar (*q)) {
case space: //空格
word[i]='\0'; //当前单词结束
printf("%s is a Hex digit. \n" , word) ;
strcpy (word,"\0"); //单词清空
i=0; //重新计数
state = 0;
break;
default: //其它(非法字符)
word[i++]=*q ;
state = 5; //转移到出错状态
}
break;
case 4: //当前为4状态
switch ( isDigitOrChar (*q)) {
case digit: //数字
word[i++] =*q;
state = 4;
break;
case AF: //字母A,B,C,D,E, F or a, b, c,d, e,f
word[i++]=*q ;
state = 4;
break;
case Hh: //H or h
word[i++]=*q;
state = 3;
break ;
default: //其它(非法字符)
word[i++]=*q;
state = 5; //转移到出错状态
}
break;
case 5: //出错状态
if(*q == 32 ) { //空格(当前单词结束)
word[i]='\0';
printf("%s is not an identifier. \n",word);
strcpy (word,"\0")); //单词清空
i=0; //重新计数
state = 0 ; //重新开始提取单词
} else { //当前单词还未结束
word[i++] =*q;
//添加到单词尾部
q++;
continue;
}
}
q++;//指针下移(指向输入符号串中的下一字符)
}
}
(1)重点与难点
画出DFA图,并进行分析
(2)存在的不足
没有将case中的switch封装,导致主函数语句太多
(3)未来改进方案
封装switch语句
封装case space的输出语句
(4)结论(开发体验、收获、感想等)
本次实验之前,对教材上DFA相关理论知识进行了复习,并在实验中通过实践,进一步巩固了所学知识。通过本次实验,我巩固复习了if-else switch-case语句的逻辑结构,初步学会了如何通过c语言编写一个基础的词法识别程序,还学会了先创建代码的主体框架,再对每部分细节进行填充的程序编写方法。