确定有限自动机(DFA)——一个简单的C++词法分析器

本文介绍如何使用确定有限自动机(DFA)来构建一个C++词法分析器。内容包括DFA理论、C++关键字识别、特殊符号处理、注释识别和标识符识别。程序设计包括控制台应用程序和图形化应用程序的实现,以帮助理解C++词法分析的过程。

                                                         确定有限自动机(DFA)——一个简单的C++词法分析器

   

      开始想运用确定有限自动机去实现一个简单的C++词法分析器时,我感到很困难,不知从何处下手,因为C++词法太多太复杂,并且为了体现c++的特性又不得不去对它的语法作一点引入。幸运的是,在搜索相关资料时,一位网友的关于用c++构造词法自动机文章帮我解决了心中的难题,在此万分感谢!。(作者原文地址:http://hi.baidu.com/peiwenlin/blog/item/8c768d31137024af5edf0e0e.html)我根据作者的代码以及自己的思路对程序重新进行了改造,具体改造如下:

                              (1)比较深入地阐述了DFA理论,给出了DFA的模拟程序;

                              (2)使程序能识别所有的C++关键字;

                              (3)增加了对特殊符号的识别,比如. ' ";

                              (4)增加了对c++注释符号//的识别;

                              (5)增加了对标识符的识别力度,如ID = (_ | letter)(letter | digit | _)* ;

                              (6)修正了专有符号命名与编译器系统命名的冲突,比如“<”映射成字符串LT,LT与宏IDAStatics_LT(This,a_0,b_1,ret_2)相冲突,尽管在win32控制台程序中未报错,但在MFC应用程序中却会报错,解决办法是在把LT改为LTEN(-EN即enum)。

                              (7)最大的创新是用MFC开发了一个图形化的C++词法分析器。

                              (8)最后是简化了原代码,比如删掉了无用的函数isReservedWords()。

 

                                                            前言

      词法分析是编译的第一个阶段,它的主要任务是从左至右逐个字符地对源程序进行扫描,产生一个个单词序列,用以语法分析。实际上,词法也是语法的一部分,词法描述完全可以归并到语法描述中去,只不过词法规则更简单些。为什么将词法分析做为一个独立的阶段?为什么把编译过程的分析工作划分成词法分析和语法分析两个阶段?主要的考虑因素为: ① 使整个编译程序的结构更简洁、清晰和条理化。 ② 编译程序的效率会改进。 ③ 增强编译程序的可移植性。
      词法分析程序的任务是:读源程序,产生单词符号;滤掉空格,跳过注释、换行符;追踪换行标志,复制出错源程序等等。

      描述程序设计语言的词法的机制是正则表达式,识别机制是有穷状态自动机。

                                                          设计思想

      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的程序思想如下伪代码示例:
       K=S;
    c=getchar();
    while(c!=EOF)
    {
          K=f(K,c);
     c=getchar();
    }
    if( K== Z )return TRUE
    else return FALSE

 

                                                         C++的单词识别基本思想

标识符ID = (_ | letter)(letter | digit | _)*

    数字NUM =digit*

    字母letter = a|..|z|A|..|Z|

    数字digit = 0|..|9

C++专用符号+ - * / < <= > >= == != = ; , . ' " ( ) [ ] { } /* */

C++语言的关键字(所有的关键字都是保留字,并且必须是小写)

   auto const dynamic_cast for mutable register static_cast try virtual 

   bool const_cast else friend namespace reinterpret_cast struct typedef void

   break continue enum goto new return switch typeid volatile 

   case default explicit  if operator  short template typename while

   catch delete extern inline private signed this union 

   char do false int protected  sizeof throw unsigned 

   class double float long public static

1. 实验内容 1、定义一个右线性正规文法,示例如(仅供参考) G[S]:S→aU|bV| U→bV|aQ V→aU|bQ Q→aQ|bQ|e 实验前要考虑清楚用哪种数据结构存储上述文法。 2、构造其有穷确定自动机,如 3、利用有穷确定自动机M=(K,Σ,f, S,Z)行为模拟程序算法,来对于任意给定的串,若属于该语言时,该过程经有限次计算后就会停止并回答“是”,若不属于,要么能停止并回答“不是”。 K:=S; c:=getchar; while ceof do {K:=f(K,c); c:=getchar; }; if K is in Z then return (‘yes’) else return (‘no’) 2. 实验设计分析 2.1 实验设计思路 根据实验指导书和书本上的相关知识,实现算法。 2.2 实验算法 (1)输入正规文法。RG到FA (2)将NFA化为DFA (3)输入一个字符串判断是否符合文法。 ①最开始记A为开始状态a为第一个字符。 ②然后A经过字符a到达下一个状态记为B,A状态指向B状态,a指向字符串的下一个字符。 ③循环②步直到B状态为终态时停止则该字符串符合该文法或a指向最后一个字符时都没到终态停止则该字符窜不符合该文法。 2.3 实验流程 ①预习实验,实验前阅读实验指导书和阅读书本。 ②通过书本了解判断文法的原理。首先在纸上模拟文法的判断过程。 ③上机实现模拟过程。 ④调试程序,知道能得到预期的结果。 2.4 实验的基本技术设计方案 (用到哪些技术,包括编译原理中,程序设计中,离散数学中等的哪些技术) ①java的基础语法。 ②数据结构里的结构体及简单算法。 ③编译原理的理论知识。 ④运用了java里的一些集合类。 2.5 数据结构 class edge { char PriorityState; char ch; char NextState; edge(char p,char c, char n){ PriorityState = p; ch = c; NextState = n; } @Override public String toString() { return "edge [PriorityState=" + PriorityState + ", ch=" + ch + ", NextState=" + NextState + "]"; } } 2.6 实验输入输出 2.7 实验设计语言 Java语言。 3. 实验主要源代码及分析说明
1. 实验内容 每一个正规集都可以由一个状态数最少的DFA所识别,这个DFA是唯一的(不考虑同构的情况)。任意给定的一个DFA,根据以下算法设计一个C程序,将该DFA 化简为与之等价的最简DFA。 2. 实验设计分析 2.1 实验设计思路 根据实验指导书和书本上的相关知识,实现算法。 2.2 实验算法 (1)构造具有两个组的状态集合的初始划分I:接受状态组 F 和非接受状态组 Non-F。 (2)对I采用下面所述的过程来构造新的划分I-new. For I 中每个组G do Begin 当且仅当对任意输入符号a,状态s和读入a后转换到I的同一组中; /*最坏情况下,一个状态就可能成为一个组*/ 用所有新形成的小组集代替I-new中的G; end (3)如果I-new=I,令I-final=I,再执行第(4)步,否则令I=I=new,重复步骤(2)。 (4)在划分I-final的每个状态组中选一个状态作为该组的代表。这些代表构成了化简后的DFA M'状态。令s是一个代表状态,而且假设:在DFA M中,输入为a时有从s到t转换。令t所在组的代表是r,那么在M’中有一个从s到r的转换,标记为a。令包含s0的状态组的代表是M’的开始状态,并令M’的接受状态是那些属于F的状态所在组的代表。注意,I-final的每个组或者仅含F中的状态,或者不含F中的状态。 (5)如果M’含有死状态(即一个对所有输入符号都有刀自身的转换的非接受状态d),则从M’中去掉它;删除从开始状态不可到达的状态;取消从任何其他状态到死状态的转换。 。。。。。。
1. 实验内容 每一个正规集都可以由一个状态数最少的DFA所识别,这个DFA是唯一的(不考虑同构的情况)。任意给定的一个DFA,根据以下算法设计一个C程序,将该DFA 化简为与之等价的最简DFA。 2. 实验设计分析 2.1 实验设计思路 根据实验指导书和书本上的相关知识,实现算法。 2.2 实验算法 (1)构造具有两个组的状态集合的初始划分I:接受状态组 F 和非接受状态组 Non-F。 (2)对I采用下面所述的过程来构造新的划分I-new. For I 中每个组G do Begin 当且仅当对任意输入符号a,状态s和读入a后转换到I的同一组中; /*最坏情况下,一个状态就可能成为一个组*/ 用所有新形成的小组集代替I-new中的G; end (3)如果I-new=I,令I-final=I,再执行第(4)步,否则令I=I=new,重复步骤(2)。 (4)在划分I-final的每个状态组中选一个状态作为该组的代表。这些代表构成了化简后的DFA M'状态。令s是一个代表状态,而且假设:在DFA M中,输入为a时有从s到t转换。令t所在组的代表是r,那么在M’中有一个从s到r的转换,标记为a。令包含s0的状态组的代表是M’的开始状态,并令M’的接受状态是那些属于F的状态所在组的代表。注意,I-final的每个组或者仅含F中的状态,或者不含F中的状态。 (5)如果M’含有死状态(即一个对所有输入符号都有刀自身的转换的非接受状态d),则从M’中去掉它;删除从开始状态不可到达的状态;取消从任何其他状态到死状态的转换。 。。。。。。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值