编译原理3 - 词法分析

正则表达

语言是一个集合。因此可以在语言上进行运算(并U,或 | ,闭包 等)。

eg: L = {a}{a,b}*( {ε} U ( {.,_}{a,b}{a,b}*) ) //常规语言 (ε (epsilon)为空串)

    意思是:句首是a ,接下连接连接任意长度的a、b 串。然后有两只情况:1.连接空串,句子就结束了

             2.连接.或_,然后连接长度>= 1的 a、b串。

正则表达式 (Regular Expression, RE)

描述正则语言的,紧凑的表示方法。

eg : 上面的表达式用正则是:r = a(a|b)*(ε |  (.|_) (a|b) (a|b)* )

正则表达式 可由较小的正则表达式 ,按照特定的规则递归构建的。

正则表达式的定义

ε是RE,L(ε) = L(ε) ;   //空串 是正则表达是,只表示空串。

a <- ∑ ,则 a 是RE, L(a) = {a};  //字母表了任意符号是RE,表示语言包含它自身。

假设r 和s 都是RE,表示语言为 L(r) 和 L(s), 

则 :r|s 是一个RE,L(r|s) = L(r) U L(s);//或

        rs 是一个RE,L(rs) = L(r)  L(s);

         r* 是一个RE,L(r*) = (L(r) )* ;//Lr 的 克林闭包(任意长度 ,可为ε 空串(0)

         (r) 是一个RE,L( (r) ) = L(r) ;

运算优先级是:*、 连接、|  

eg : 令 ∑ = {a, b} ,/// 符号表包含两个字母a ,b 。

      L(a|b) = L(a) U L(b) = {a}U{b} = {a,b} //一个符号 a 或 b

      L((a|b)(a|b)) = L(a|b) L(a|b)  =  {a,b} {a,b} = {aa, ab, ba, bb} //两个符号

      L(a*) = (L(a))* = {a}* = {ε ,a,aa,aaa …} //一个符号 a 或 b            

      L((a|b)*) = (L(a|b))* == {a|b}* = {ε ,a,b,ba,bb,aa …}

     L(a|a*b) = { a,b,ab,aab,aaab …}

C语言中符号整数的RE

十进制整数的RE : (1|...|9)(0|...|9)*

八进制整数的RE : (1|...|9)(0|...|9)*

十六进制整数的RE:0x(1|...|9|a|...|f)(1|...|9|a|...|f)*

正则定义

给某些RE命名,并在之后的RE中像字母表一样使用这些名字。

d1 -> r1;

d2 -> r2;

...

每个d1, d2 都不在字母表中。

C语言中标识符的RE

digit -> 0|1|2|...|9

letter_ -> A|...|Z|a|...|z|_

eg 1 : id = litter_( litter_ | digit)* ///字母打头的字母数字串

eg 1:(整数或浮点型)无符号数的RE定义

      digit -> 0|1|2|...|9

      digits -> digit digit* ///长度大于0 的数字

       optionalFraction -> .digit|ε   /// 可选的小数部分

       optionalExponent -> (E (+|-| ε) digit) | ε;///可选的指数部分

       number=  digits  optionalFraction optionalExponent

有穷自动机 (Finite Automata, FA)

概念

对一类处理系统建立的数学模型

特征:1.具有一系列离散的输入输出信息有穷数目的内部状态。(状态概况了对过去输入信息的处理的状况)

         2.系统只需要根据当前所处的状态当前面临的输入信息就可以决定系统的后继行为。每当系统处理了当前输入后,系统内部状态也将发生改变。

FA的例子:电梯控制装置 

输入:乘客的乘梯需求

状态:电梯所处的层数+运动方向。

电梯控制装置 并不需要记住先前所有的服务要求,只需知道当前的状态和未满足的需求。

FA模型

输入带:存放输入符号串

读头:从左至右逐个读取输入符号,不能修改,不能往返移动。

有穷控制器:具有有穷个状态数,根据当前状态和当前输入符号,控制转入下一状态。

FA的表示

转换图

匹配原则

最长子串匹配原则:当输入串的多个前缀,与一个或多个匹配时。总是选择最长的前缀进行匹配。

有穷自动机分类

确定的FA  :DFA      非确定的FA:NFA

DFA(确定的有穷自动机)

定义为五元组。 M = (S, ∑, δ, S0, F);

S :有穷状态集。 

∑ :输入字母表,即输入符号集合。假设ε不是 Σ中的元素

δ :S*∑ 映射到S的转换函数。δ(s,a)表示从s 出发沿着标记为a的边所到达的状态。

S0:开始状态 (或初始状态),s0∈S

F:接收状态(或终止状态)集合,F⊆ S

例:一个DFA

NFA(非确定的有穷自动机)

M = (S, ∑, δ, S0, F)

∑ :输入符号集合,即输入字母表。假设ε 不是Σ中的元素

δ:将S×Σ映射到2S的转换函数。s∈S, a∈Σ, δ(s,a)表示从状态s出发,沿着标记为a的边所能到达的状态集合

例:一个NFA

DFA和NFA的等价性

对于任何DFA  D,存在识别同一语言的NFA N .

对于任何NFA  N,存在识别同一语言的DFA D .

此三者是等价的。RE <=> NFA <=> DFA

NFA更直观,DFA在计算机里更容易去实现。

带有"ε-"边的NFA

M = (S, ∑, δ, S0, F)

∑ :输入符号集合,即输入字母表。假设ε 不是Σ中的元素

δ:将S×(Σ U {ε})映射到2的s次方 转换函数。s∈S, a∈Σ, δ(s,a)表示从状态s出发,沿着标记为a的边所能到达的状态集合

带有和不带有 "ε-"边的NFA的等价型

DFA的算法实现

 输入:以文件结束符eof结尾的字符串x。DFA D 的开始状态s0,接收状态集 F,转换函数move。

 输出:如果 D接收 x,则回答“yes”,否则回答“no”。

 方法:将下述算法应用于输入串 x。

s = s0 ;
c = nextChar();
while(c! = eof ){ 
    s = move ( s , c ) ;
    c = nextChar ( ) ;
}
if (s在F中) return“yes”;
else return “no”;

 函数nextChar( )返回输入串x的下一个符号

 函数move(s, c)表示从状态s出发,沿着标记为c的边所能到达的状态

从正则表达式到有穷自动机 (RE ->DFA)

eg: r = (a|b)*aabb对应的DFA为。以下是分解步骤

从NFA到有DFA的转化 (NFA -> DFA)

例1 :NFA -> DFA

R = aa*bb*cc*

带有 "ε-"边的NFA到DFA的转换

R = 0*1*2*

子集构造法

识别单词的DFA 

识别标识符的DFA

识别各进制整数的DFA

十进制数的DFA

八进制数的DFA

十六进制的DFA

统一的:识别各进制整数的DFA

识别注释的DFA

识别各类Token的DFA

词法分析的错误处理

错误类型:单词拼写、非法字符串。

词法错误检测

当前转换状态与当前输入符号在转换表中对应的项目为空,则报错,调用错误处理。

错误处理

查找字符串中最后一个对应某终态的字符

找到了则说明在前面识别了一个单词。将该字符和前面的单词识别为一个单词。将输入指针退回到该字符,扫描器从新回初始状态,继续扫描下一个。

没找到则出错了

恐慌模式来恢复。(一直删除直到正确,编译通过)

 

 

 

参考 :哈工大 陈鄞老师《编译原理》视频笔记。仅供自己复习参考使用,如有问题欢迎指出

参考:https://www.cnblogs.com/AndyEvans/p/10240790.html

发布了57 篇原创文章 · 获赞 3 · 访问量 3万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章