你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:技术专栏 / 数据库开发
词法分析---基于Asp.NET(实验二学习笔记)
 

一、背景
任务说明
     词法分析表

 

保留字

特殊符号

其他

If

+

十进制的整数与实数

else

-

while

*

read

/

标识符(由数字、字母和下划线组成的串,但必须以字母开头、且不能以下划线结尾的串)

write

=

int

<

real

==

 

 

<>

 

 

(

 

 

                            )                    

 

 

;

 

 

{

 

 

}

 

 

/*

 

 

*/

 

 

[

 

 

]

 

 

 这次实验主要是完成词法分析器,目的是从输入的源程序中能够识别出各个具有独立意义的记号,包括保留字、标识符、常数、运算符、分隔符等,并依次输出各个记号序列。如果出错(即不是语言可以识别的记号),则输出error。

 

二、 功能实现描述
正则表达式
   在cmm中,语言记号大致可分为以下几大类。

1.       保留字

    在正则表达式中,保留字是最简单的了,因为它们仅是由字符的固定序列表示,如果要将所有的保留字收集到一个定义中,就可以写成:

Reserved=int|real|if|else|while|read|write…….

2.       数

数可以是数字(自然数)、十进制数、或者是小数

 Nat=[0-9]+

 signedNat=(+|-)nat

 float=singedNat ”.” Nat

3.       标识符

     标识符不是固定的字符串。在cmm中,规定标识符必须由一个字母开头并且只包括字母和数字。可以用一下正则表达式:

Letter=[a-zA-Z]

Digit=[0-9]

Identifier=letter(letter|digit)*

4.       注释

注释在扫描过程中是被忽略的, 扫描程序必须注释并舍弃它们。虽然扫描程序可能没有清晰的常量记号,但是仍需要给注释编写出正则表达式。在cmm中,我给出的单行注释是://,多行注释有:/*  */或{}

5.       二义性、空白格和先行

在使用正则表达式的描述中,有一些串经常可以被不同的正则表达式匹配。例如:if和while的串可以既是标识符又可以是关键字。程序设计语言定义规定了应遵守哪个解释,但是正则表达式本身却无法做到它。相反地,语言定义必须给出无二义性规则,由其回答每一种情况下的含义。

程序设计语言中空白格伪记号的典型定义是:

Whitespace=(newline|blank|tab|comment)+

其中,等号右边的标识符代表恰当的字符或串。空白格通常不是作为记号分隔符,而是被忽略掉。

   分隔符结束记号串,但他们并不是记号本身的一部分。因此,扫描程序必须处理先行(lookahead)问题:当它遇到一个分隔符时,它必须做出安排分隔符不会从输入的其他部分中国删除,方法是将分隔符返回到输入串或在将字符从输入中删除之前先行。在大多数情况下,只有单个字符才需要这样做(“单个字符先行”)。

有穷自动机
   有穷自动机,或称有穷状态的机器,是描述特定类型算法的数学方法。特别地,有穷自动机可用作描述在输入串中识别模式的过程,因此也能用作构造扫描程。当然有穷自动机与正则表达式之间有着很密切的关系。

   确定性有穷自动机(DFA)定义:一个确定的有穷自动机(DFA)M是一个五元组:M=(K,Σ,f,S,Z)其中

  ① K是一个有穷集,它的每个元素称为一个状态;

  ② Σ是一个有穷字母表,它的每个元素称为一个输入符号,所以也称Σ为输入符号字母表;

  ③ f是转换函数,是K×Σ→K上的映射,即,如 f(ki,a)=kj,(ki∈K,kj∈K)就意味着,当前状态为ki,输入符为a时,将转换为下一个状态kj,我们把kj称作ki的一个后继状态;

  ④ S ∈ K是唯一的一个初态;

⑤ Z⊂K是一个终态集,终态也称可接受状态或结束状态。

DFA的下一个状态有当前状态和当前输入字符唯一给出的自动机。非确定的有穷自动机是由它产生的。

 

带有出错转换的标识符的有穷自动机

 以上给出了带有出错转换标识符的有穷自动机的示例图。Nat和小数的DFA非常简单,在这里就不给出示例了。CMM词法分析器的DFA:

从正则表达式到DFA
  我们只关心两个算法:一个是将正则表达式翻译成NFA,另一个是将NFA翻译成DFA。再将DFA翻译成程序。

 

程序

DFA

NFA

正则表达式

    
 

 

  利用Thompson结构 -转换将正则表达式的机器片段“粘在一起”以构成与整个表达式相对应的机器。因此该结构式归纳的,而且它依照了正则表达式定义的结构:为每个基本正则表达式展示一个NFA,接着再显示如何通过连接子表达式的NFA得到每个正则表达式。

实现DFA的主要代码:
   public static TokenTypegetToken()

        {

            inttokenStringIndex = 0;/* 当Ì¡À前¡ãtoken的Ì?索¡Â引°y */

          

            /* 当Ì¡À前¡ãtoken的Ì?类¤¨¤型¨ª*/

            TokenTypecurrentToken = TokenType.VOID; ;

            /* 起e始º?状Á¡ä态¬? */

            StateTypestate = StateType.START;

            /* 标À¨º识º?是º?否¤?储ä¡é存ä?当Ì¡À前¡ã字Á?符¤? */

            intsave;

            int once=1;

 

            while(state != StateType.DONE)

            {

                intc = getNextChar();

                save = 1;

                switch(state)

                {

                    caseStateType.START:

                    if(Char.IsNumber((char)c))

                          state = StateType.INNUM;

                     elseif(c=='.')

                        state = StateType.POINT;

                    elseif (Char.IsLetter((char)c))

                        state = StateType.INID;

                //    else if (c == ':')

                //    state = INASSIGN;

                     elseif (c == '<')

                        state = StateType.INLESS;

                     elseif (c == '>')

                        state = StateType.INGREAT;

                    elseif (c == '=')

                        state = StateType.INASSIGN;

                     elseif (c == '!')

                        state = StateType.INNEQUAL;

                     elseif(c== '/')              

                     {

                        save=0;

                        state = StateType.INCOMMENT2;

                    }

 

                    elseif ((c == ' ')|| (c == '\t') || (c == '\n'))

                        save = 0;

 

                //    else if (c == '{')

                //    { save = FALSE;

                //     state = INCOMMENT;

                //    }

                    else

                    {

                        state = StateType.DONE;

                        switch (c)

                        {

                            case -1://文?件t结¨¢束º?

                              save = 0;

                              currentToken = TokenType.ENDFILE;

                            break;

                              case'{':

                            currentToken = TokenType.LBEGIN;

                            break;

                            case '}':

                            currentToken = TokenType.REND;

                            break;

                            case '+':

                            currentToken = TokenType.PLUS;

                            break;

                            case '-':

                            currentToken = TokenType.MINUS;

                            break;

                            case '*':

                            currentToken = TokenType.TIMES;

                            break;

                        // case '/':

                        //   currentToken = OVER;

                        //    break;

                            case '(':

                            currentToken = TokenType.LPAREN;

                            break;

                            case ')':

                            currentToken = TokenType.RPAREN;

                            break;

                              case'[':

                            currentToken = TokenType.LARRAY;

                            break;

                            case ']':

                            currentToken = TokenType.RARRAY;

                            break;

                            case ';':

                            currentToken = TokenType.SEMI;

                            break;

                              case',':

                            currentToken = TokenType.COMMA;

                            break;

                              case'%':

                            currentToken = TokenType.MOD;

                            break;           

                            default:

                            currentToken = TokenType.ERROR;

                            break;

                    }

                    }

                    break;

                caseStateType.INCOMMENT:

                    save = 0;

                    if(c == -1)

                    {

                        state = StateType.DONE;

                        currentToken = TokenType.ENDFILE;

                    }

                    elseif (c == '}')state = StateType.START;

                    break;

   

                caseStateType.INLESS:

                    state = StateType.DONE;

                    if(c == '=')

                        currentToken = TokenType.LE;

                    elseif (c == '>')

                        currentToken = TokenType.NEQ;

                    else

                    { /*取¨?备À?份¤Y的Ì?前¡ã一°?个?字Á?符¤? */

                        ungetNextChar();

                        save = 0;

                        currentToken = TokenType.LT;

                    }

                    break;

                caseStateType.INGREAT:

                    state = StateType.DONE;

                    if(c == '=')

                    currentToken = TokenType.GE;

                    else

                    { /*backup in the input */

                      ungetNextChar();

                      save = 0;

                      currentToken = TokenType.GT;

                    }

                    break;//INNOEQUAL

                caseStateType.INASSIGN:

                    state = StateType.DONE;

                    if(c == '=')

                    currentToken = TokenType.EQ;

                    else

                    {

                    ungetNextChar();

                    save = 0;

                    currentToken = TokenType.ASSIGN;

                    }

                    break;

                caseStateType.INNEQUAL:

                    state = StateType.DONE;

                    if(c == '=')

                    currentToken = TokenType.NEQ;

                    else

                    {

                    ungetNextChar();

                    save = 0;

                    currentToken = TokenType.ERROR;

                    }

                    break;

                caseStateType.INCOMMENT2:

                    save = 0;

                    if(c == -1)

                    {

                        state = StateType.DONE;

                        currentToken = TokenType.ENDFILE;

                    }

                    elseif (c == '/')

                    {

                        state = StateType.INCOMMENT_SINGLE; 

                     }

                    else if(c=='*')

                     {

                        state = StateType.INCOMMENT_MULTI_1;     

                     }

                     else

                    {

                          ungetNextChar();        

                         save = 1;

                         c='/';

                          currentToken = TokenType.OVER;

                        state = StateType.DONE;               

                    }

                    break;

                caseStateType.INCOMMENT_SINGLE:

                     save = 0;

                    if(c == -1)

                    {

                        state = StateType.DONE;

                        currentToken = TokenType.ENDFILE;

                    }

                    elseif (c == '\n')

                        state = StateType.START;

                    break;

 

                caseStateType.INCOMMENT_MULTI_1:

                     save = 0;

                    if(c == -1)

                    {

                        state = StateType.DONE;

                        currentToken = TokenType.ENDFILE;

                    }

                    elseif (c == '*')

                        state = StateType.INCOMMENT_MULTI_2;

                    break;

                caseStateType.INCOMMENT_MULTI_2:

                     save = 0;

                    if(c == -1)

                    {

                        state = StateType.DONE;

                        currentToken = TokenType.ENDFILE;

                    }

                    elseif (c == '/')

                        state = StateType.START;

                     else

                        state = StateType.INCOMMENT_MULTI_1;

                    break;

 

                caseStateType.POINT:

                    if(!Char.IsLetter((char)c))

                    {

                        ungetNextChar();

                        save = 0;

                        state = StateType.DONE;

                        currentToken = TokenType.NUM;

                    }

                    break;

                caseStateType.INNUM:

                     if(c=='.'&&once!=0)

                    {

                        --once;

                        break;

                    }

                    if(!Char.IsLetter((char)c))

                    {

                        ungetNextChar();

                        save = 0;

                        state = StateType.DONE;

                     if(once!=0)

                        currentToken = TokenType.NUM;

                    }

                    break;

                caseStateType.INID:    

                    if(!Char.IsLetter((char)c)&&!Char.IsDigit((char)c))

                    {

                        ungetNextChar();

                        save = 0;

                        state = StateType.DONE;

                        currentToken = TokenType.ID;

                    }

                    break;

                caseStateType.DONE:

                default:

                    state = StateType.DONE;

                    currentToken = TokenType.ERROR;

                    break;

                }

                if((save!=0) && (tokenStringIndex <= MAXTOKENLEN))

                {

                    tokenString[tokenStringIndex] = (char)c;

                     tokenStringIndex++;

                }

                if(state == StateType.DONE)

                {

                    tokenString[tokenStringIndex] = '\0';

                    if(currentToken == TokenType.ID)

                     {

                         currentToken =reservedLookup(charToString(tokenString));

                    }

                }

            }

           //util.printToken(currentToken,tokenString.ToString());

            StringtempS = Util.printToken(currentToken,charToString(tokenString));

            objCode += "    "+tempS;

            returncurrentToken;

        }

              

实现方法
   本人采用Asp.NET,在windows 7平台下,将cmm语法解释器做成网页版的,在某种程度上实现了跨平台性。

三、使用说明
    由于我这Web项目无法打包成一个可以执行的文件,只可以在浏览器下访问,可能需要在VS2010下编译执行。

  在左侧方框中输入要分析的源文件,点击分析之后,在右侧方框出现词法分析。

  推荐精品文章

·2024年12月目录 
·2024年11月目录 
·2024年10月目录 
·2024年9月目录 
·2024年8月目录 
·2024年7月目录 
·2024年6月目录 
·2024年5月目录 
·2024年4月目录 
·2024年3月目录 
·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089