编译原理 2 - 词法分析


第3章 词法分析

重点:① 词法分析器的输入、输出;② 用于识别符号的状态转移图的构造;③ 根据状态转移图实现词法分析器
难点:词法的正规文法表示、正规表达式表示、状态转移图表示,以及它们之间的转换。

3.1 词法分析器的功能和结构

  • 词法分析器的功能
    把构成源程序的字符串转换成“等价的”单词序列(根据词法规则识别及组合单词,进行词法检查;对数字常数完成数字字符串到二进制数值的转换;删去空格和注释等不影响程序语义的字符)

  • 词法分析器 包含:
    预处理子程序:用于去除无用的空白、跳格、回车、换行等编辑性字符;区分标号区
    扫描器:在扫描缓冲区中识别单词符号
    扫描缓冲区:存放经过预处理的比较规范的字符串
    输入缓冲区:扫描器调用预处理子程序,将源程序输入到输入缓冲区中,预处理子程序读取输入缓冲区中的字符进行文本的预处理

  • 扫描缓冲区
    扫描器通过两个指针(起点指示器与搜索指示器)进行扫描,起点指示器指向马上要识别的单词的开始位置,搜索指示器从起点指示器的位置开始,寻找单词的结尾
    存在问题:① 缓冲区内容用完后,需要等待新的输入,应该避免类似等待;② 一个单词可能会被缓冲区分隔开,即单词的一部分在缓冲区中,另一部分没有读入,如果需要读入的话,需要将当前缓冲区中内容覆盖,单词的前半部分就无了,而且无法执行超前搜索
    解决方案:将缓冲区划分为两个半区(即设置双缓冲区),扫描器每次只读取一个半区的长度,如果搜索指示器指到当前半区的末尾,且还未找到单词末尾,则扫描器将后续内容读入另一半区,搜索指示器从另一半区开始继续寻找单词末尾;此外还需要限定 单词长度不能超过半区的长度
    具体实现方式:使用带标记的双缓冲区,每个缓冲区末尾都设置"EOF"区域结束标识
    缓冲区长度÷2 = 缓冲半区的长度 = 程序设计语言允许的标识符最大长度

3.2 状态转换图

  • 状态转换图:
    在这里插入图片描述
  • 实现(以状态0-1-2为例):
/* 状态0 -> 状态1 -> 状态2 */
int code, value;
strToken = "";  //存放构成单词符号
GetChar();  GetBC();  // 读取字符 跳过空白符
if(IsLetter())  //判断输入是否为字母
begin  /* 状态1 */
	while (IsLetter() or IsDigit())
	begin  /* 状态1循环 */
		Concat();  GetChar();  //拼接单词字符,继续读入
	end  
	/* 状态2 */
	Retract();  //回退最后的非字母数字输入
	code := Reserve();  //判断是关键字还是用户自定义标识符
	if (code = 0)  //是用户自定义标识符 
	begin
		value := InsertId(strToken);  //把strToken插入到符号表中
		return ($ID, value);  //返回标识符在符号表中的位置和对应值
	end
	else  //是关键字
		return (code, NULL);
end
  • 正则表达式 转换为 状态转换图
    在这里插入图片描述

3.3 正则文法 和 正则表达式

正则表达式 = 正则式
正则集 = 正则语言(简写为 “语言”)

  • 对于给定字母表 ∑ \sum
    1. ε 和 ∅ \varnothing 都是 ∑ \sum 上的正则表达式,它们所表示的正则文法为 {ε} 和 ∅ \varnothing
      理解:ε 既是一个字,也是一个正则表达式,它代表的正则集(语言)为{ε},该集合中有一个字,是ε,该字长度为0,不包含任何字符; ∅ \varnothing 既是一个集合,也是一个正则表达式,它代表的正则集为{ },该集合为空
    2. (定义) 任何 a ∈ ∑ a\in\sum a a a a ∑ \sum 上的正则表达式,它所表示的正则集为 { a } \{a\} {a}
      理解: a a a 既是字母表 ∑ \sum 中的一个字符,也是一个由一个字符a所构成的长度为1的字/字符串,也是一个正则表达式,所表示的正则语言 L ( a ) L(a) L(a) { a } \{a\} {a}
    3. e 1 e_1 e1 e 2 e_2 e2都是 ∑ \sum 上的正则表达式,所表示的正则文法分别为 L ( e 1 ) L(e_1) L(e1) L ( e 2 ) L(e_2) L(e2),则
      ( e 1 ∣ e 2 ) (e_1|e_2) (e1e2)为正则表达式,它表示的语言为 L ( e 1 ) ∪ L ( e 2 ) L(e_1)\cup L(e_2) L(e1)L(e2)
      ( e 1 ⋅ e 2 ) (e_1·e_2) (e1e2)为正则表达式,它表示的语言为 L ( e 1 ) L ( e 2 ) L(e_1) L(e_2) L(e1)L(e2)
      ( e 1 ) (e_1) (e1)为正则表达式,它表示的语言为 ( L ( e 1 ) ) ∗ (L(e_1))^* (L(e1))
      ④ 仅由有限次使用上述规则构造的表达式 是 ∑ \sum 上的正则w表达式
    4. 如果正则表达式 r 与 s 表示的正则语言相同,即 L ( r ) = L ( s ) L(r)=L(s) L(r)=L(s),则称 r 与 s 等价,也称 r 与 s 相等,记作 r = s
      问题 证明 b(ab)*=(ba)* → L(b(ab)*) = L(b)L((ab)*) = L(b)(L(ab))* = L(b)(L(a)L(b))* = {b}{ab}*,同理等式右侧表示的语言同左,等式得证

3.4 有限自动机 DFA与NFA

  • 确定有限自动机M是一个五元组 M = ( S , ∑ , f , S 0 , F ) M=(S, \sum, f, S_0, F) M=(S,,f,S0,F)
    S S S:有穷状态集合
    ∑ \sum :输入字母表(有穷)
    f f f:状态转换函数, f ( s , a ) = s ′ f(s, a)=s' f(s,a)=s表示当前状态 s s s,输入字符为 a a a,将状态转换到下一状态 s ′ s' s
    S 0 S_0 S0 S 0 ∈ S S_0 \in S S0S,是唯一的初态
    F F F:终止状态集合, F ⊆ Q F\subseteq Q FQ
    在这里插入图片描述
  • 非确定有限自动机 NFA,其定义与DFA类似,NFA M是一个五元组 M = ( S , ∑ , f , S 0 , F ) M=(S, \sum, f, S_0, F) M=(S,,f,S0,F),其中不同点如下:
    f f f:状态转换函数,为 S ∗ ∑ ∗ → 2 S S*\sum^* \rightarrow 2^S S2S(从一个状态读入一个字符,其后继状态不唯一)
    S 0 S_0 S0 S 0 ⊆ S S_0 \subseteq S S0S是非空的初态集(NFA可以有多个初态)
    在这里插入图片描述
  • DFA 与 NFA 比较
    在这里插入图片描述

测试

  1. 证明 (a*b*)* = (a|b)*

  2. 在这里插入图片描述
    答:B,含有aa或bb的字

  3. 在这里插入图片描述
    答:A初态即终态,识别空字ε后可以由初态到达终态,即A可以识别 {ε};B图不含有终态,不能识别任何字符,包括空字ε,即B可以识别{}空集

  4. 在这里插入图片描述
    答:B,含有aa或bb的字

  5. 在这里插入图片描述
    答:C

  6. 构造 ε|(0|1)01* | 0+的状态转换图
    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值