分享

十六进制数的词法识别器

 quasiceo 2013-12-10
十六进制数的词法识别器 2006-12-17 15:26:10

分类:

作者:余洪周 nickhome@163.com  版权所有,转载时请注明出自: nick19842000.cublog.cn
 
    本文将通过一个识别标识符、无符号的十进制和十六进制整数的词法分析器实例,来帮助您如何掌握简单识别程序的分析、设计与实现的基本技术与一般方法。
 

题目: 假设一个语言允许使用十六进制数,其规定是:必须以数字打头,必须以H结尾,数中允许使用的字母为ABCDE, F(分别表示10~15)。该语言的标识符为字母开头的字母数字串。试设计一个DFA,使它能识别标识符、无符号的十进制和十六进制整数(假定各单词之间用界限符或空格分开),并编制相应的识别程序。

       输入:键盘输入输入符号串。

       输出:标识出规范的符号串和不合规范的符号串。

 

一、 分析

 

(1)      文法该语言的十六进制,如:0aH77H7BH等由以数字打头及以H结尾;该语言的标识符,如:Numa3go等由AZ(or az)09所组成;该语言的无符号的十进制,如:890123等由09之间的任意数字组成。由以上可得出该语言的文法可表示如下:

G(S) = (VNVTPS)

       其中VN = {SX’Y’Z’M’W’αβγμυω}

              VT = {0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,

A,B,C,D,E,F,G,H,I,G,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z}

              α= 0|1| 2|3|4|5|6|7|8|9

              β = a|b|c|d|e|f|A|B|C|D|E|F

              γ = g| h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|G|H|I|G|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z

              S  X’|Y’|Z’

              X’ υ|υM’                M’ ω|ωM’        υ β|γ          ω α|β|γ

              Y’ α|αY’

              Z’ αH|αW’H          W’ μ|μW’         μ α|β

       可见,上式方法中,X’表示出了语言的标识符,而Y’表示出了语言的无符号的十进制,Z’表示出了语言中的十六进制。

    上式G(S)文法中,各式右边只有单个的终结符号

显然,以上文法G(S)已是正规文法。

 

(2)      正规文法转成正规式具体步骤如下:

  M’ ω|ωM’       可表示为M’ ω*ω

W’ μ|μW’       可表示为W’ μ*μ   

              Z’  α|αZ’         可表示为Z’ α*α

    ∴ 转换成正规表达式为:S=υ| υω*ω |αH | αμ*μH |α*α

代入可得:S= (β|γ) | (β|γ) (α|β|γ)*(α|β|γ) |αH | α(α|β)* (α|β)H |α*α

 

(3)      正规式转成NFA(分裂法)

初始的NFA图下所示:

1 初始NFA

经过替换规则替换后得到的最终NFA图如下所示:

 

2 最终的NFA

(4)      NFA转成DFADFA最小化(造表法)

对应以上的NFA图,我们可用造表法来表示如下:

 

    显然,由图可看出,状态2与状态5等价,而状态1与状态3等价,这里省去状态3和状态5,并将所以指向状态3的状态都指向状态1,指向状态5的都指向状态2。由此可画出最小化的DFA图如下:

3  最小化的DFA

 

可见,终结状态1表示出了无符号的十进制,终结状态2表示出了标识符,状态6表示出了十六进制的整数。

 

二、  编程

 

这里将用C语言实现以上最小化的DFA,并借用C语言中main函数的形参,即指针数组来存放输入的词语,通过指数数组来读取词语并进行分析,从而实现用键盘输入来分析词语。以下是其简单的程序流程图(图4),由于DFA的详细状态转移在图中表示出来比较复杂,所以这里不细画出来,具体思想将在代码中表现出来

 

 

4 程序流程图

程序代码如下:


/*

 * ana.c

 * Written by Yu Hongzhou <nickhome@163.com>

 *

 * A simple DFA programe

 */

#include <stdio.h>

 

main(int argc,char *argv[]){

       int i,j,state,ERROR=-1;  /* state控制状态的转移

                                             * ERROR=-1表示未输入任何字符串

                                             */

       char c;                           /* 暂时存放所取得的一个字符 */

       char *string[]={"","Unsigned Integer","Identifier","","","","Hex"};/*输出结果时用*/

       for(i=1;i<argc;i++){

              state=0;                  /* 初始态为0 */

              ERROR=0;            /* 控制是否为可识别词or非法字符 */

              for(j=0;(c=argv[i][j])!='\0';j++){

                     switch(state){

                            case 0:if(c>='0'&&c<='9') state=1;

                                   else if((c>='a'&&c<='z')||(c>='A'&&c<='Z')) state=2;

                                   else ERROR=1;break;  /* ERROR=1,表示当前字符c为非法字符。

* 即此时无状态可转向。

*/

                            case 1:if(c>='0'&&c<='9') state=1;

                                   else if((c>='a'&&c<='f')||(c>='A'&&c<='F')) state=4;

                                   else if(c=='H') state=6;

                                   else ERROR=1;break;

                            case 2:if((c>='a'&&c<='z')||(c>='A'&&c<='Z')||(c>='0'&&c<='9')) state=2;

                                   else ERROR=1;break;

                            case 4:if((c>='0'&&c<='9')||(c>='a'&&c<='f')||(c>='A'&&c<='F')) state=4;

                                   else if(c=='H') state=6;

                                   else ERROR=1;break;

                            case 6:ERROR=1;break;

                     }/*end switch*/

                     if(ERROR==1)            break;  /* 退出内for的循环,完成一个词的分析。*/

              }/*end inside-for*/

              if(ERROR==1)              printf("%-15s is a un-identify word!\n",argv[i]);

              else if(ERROR==0)       printf("%-15s is a %s\n",argv[i],string[state]);

           }/*end outside-for*/

           /*未输入任何字符串时(除文件名外)*/

    if(ERROR==-1) printf("You input nothing!\n");

    exit(0);  /*正常退出程序*/

}/*?end main*/

 

三、系统调试

 

将以上程序代码通过编译器(推荐用Turbo C 2.0调试连接后,将生成ANA.EXE的可执行文件。打开MSDOS界面,进入ANA.EXE所在的路径。(如:以下的测试我们将把ANA.EXE放在C盘根目录下。)

 

执行命令输入的标准格式如下:

命令名 字符串1  字符串2   字符串3 ……字符串n

命令名和各字符串间用空格分隔。多余的空格符将被当作字符来处理。命令名,即程序名,可以是ana或ana.exe。如可输入:ana hello 123 7AH 003H n3 ~yl 7ch

(注意:如题目所要求的,如果是16进制,则后面的应跟大写的“H”。所以这里小写h被列入a到z的普通标识符中)

下图是以上命令运行的结果:

图5 命令运行结果

 



结束语

    至此,我们的这个识别器也就做完了。当然,程序代码可能还有点乱,没有进行优化。但运行起来基本上没多大的问题。限于作者水平,加之时间仓促,难免有不足之处,敬请读者批评指正。


参考资料

  关于题目的来源

  * 编译原理实验一 识别器的实现 华南热带农业大学计算机科学与技术

  编译的一些方法

  * 何炎祥,编译原理,高等教育出版社,2004-8

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多