第三章 词法分析

本文介绍了词法分析的基本概念,包括词法分析的目的、词法分析器的工作流程及其内部设计,探讨了不同类型的单词符号及其识别方法。此外,还详细讲解了如何使用状态转换图和有限自动机来构建词法分析程序。
词法分析的主要目的是将输入的字符串输出为一个个单独的单词符号。即从左至右逐个字符的对源程序进行扫描,产生一个个的单词符号,把作为字符串的源程序改造成为由单词符号串组成的程序。实现这种过程需要借助词法分析器,其输入时源程序,输出为单词符号,其实现过程如下:

源程序→词法分析器→单词符号

单词的种类
基本字(保留字,关键字)
由程序语言定义的具有固定意义的标识符。
用户不能用来表示变量名,函数名等标识符
例:C语言中的“if” “else” “while” …
标识符
用户使用的,用来表示各种名字,变量名,函数名等
常数
整型、实型、逻辑、字符
例:10003.14TRUE,“Abcd
运算符
+-*/
界符
{ } ()…
语法分析器的内部设计运行方式为:
输入缓冲区、预处理子程序:
输入源程序文本,放入输入缓冲区中,词法分析工作可在这个输入缓冲区中工作;
剔除无用的空白,跳格(TAB),回车,换行等编辑性字符;若空白符号为单词符号的界符,就将若干空白和并为1个;
剔除注释行,比如/**/;

源程序的出错列表打印;

将预处理好的子程序放到扫描缓冲区中。
扫描缓冲区、扫描器:

扫描缓冲区:

设两个半区,可互补使用;

设两个指针:起点指针:指出正在识别单词起点位置;搜索指针:向前搜索以寻找单词终点。扫描器:扫描缓冲区,直接进行单词的识别。

单词符号的识别方法主要分为三种,分别为超前搜索法、直接分析法和状态转换图法,其中状态转换图法是学习的重点。为了更好地使用状态装换图构造词法分析程序,为了讨论词法分析程序的自动生成,需要将上述转换图的概念稍加形式化。词法分析器需要识别语言中具有不同特征的字,我们可以把具有相同特征的字放在一起组成一个集合,即所谓的正规集然后使用一种形式化的方法来表示正规集,即所谓的正规式。正规式是描述单词结构的一种形式;正规集是该类单词的全集。若两个正规式UV所表示的正规集相同,则认为二者等价。我们把状态转换图再形式化一下及所谓的有限自动机有两种:确定的有限自动机(DFA)(Deterministic Finite Automata)和非确定的有限自动机(NFA)(Non-deterministic Finite Automata)
对于确定的有限自动机来说,所谓的自动机不是指一台实际的机器,而是一种数学模型(集合,函数,序列…),利用它模拟计算机识别的功能;所谓确定性是指,f(s, a) = s’ 是单值函数。对任何状态sS,和输入符号 a∈∑ ,f(s, a) 唯一的确定下一个状态;所谓有限性是指,S是一个有限的状态集合,并且∑是一个有限的输入符号的字母表。用上述条件,来定义一个DFA,来完成识别一个序列是否被机器所接受。确定的有限自动机是非确定的有限自动机的一个特例。
DFA的设计流程:根据题意,得到相应的正规式;由以上正规式构造相应的NFA为;用子集法对M’进行确定化;对M进行化简。


习题六 证明下列正规式关系成立


 

 习题七 构造正规式相应的DFA

 

 习题八 出下列正规表达式

 

1.根据状态转换图直接编程 编写一个词法分析程序,它从左到右逐个字符的对源程序进行扫描,产生一个个的单词的二元式,形成二元式(记号)流文件输出。在此,词法分析程序作为单独的一遍,如下图所示。 具体任务有: (1)组织源程序的输入 (2)识别单词的类别并记录类别编号和值,形成二元式输出,得到单词流文件 (3)删除注释、空格和无用符号 (4)发现并定位词法错误,需要输出错误的位置在源程序中的第几行。将错误信息输出到屏幕上。 (5)对于普通标识符和常量,分别建立标识符表和常量表(使用线性表存储),当遇到一个标识符或常量时,查找标识符表或常量表,若存在,则返回位置,否则返回0并且填写符号表或常量表。 标识符表结构:变量名,类型(整型、实型、字符型),分配的数据区地址 注:词法分析阶段只填写变量名,其它部分在语法分析、语义分析、代码生成等阶段逐步填入。 常量表结构:常量名,常量值 单词的构词规则: 字母=[A-Z a-z] 数字=[0-9] 标识符=(字母|_)(字母|数字|_)* 数字=数字(数字)*( .数字+|) 2.S语言表达式和语句说明 1.算术表达式:+、-、*、/、% 2.关系运算符:>、>=、<、<=、==、!= 3.赋值运算符:=,+=、-=、*=、/=、%= 4.变量说明:类型标识符 变量名表; 5.类型标识符:int char float 6.If语句:if 表达式then 语句 [else 语句] 7.For语句:for(表达式1;表达式2;表达式3) 语句 8.While语句:while 表达式 do 语句 9.S语言程序:由函数构成,函数不能嵌套定义。
1.根据状态转换图直接编程 编写一个词法分析程序,它从左到右逐个字符的对源程序进行扫描,产生一个个的单词的二元式,形成二元式(记号)流文件输出。在此,词法分析程序作为单独的一遍,如下图所示。 具体任务有: (1)组织源程序的输入 (2)识别单词的类别并记录类别编号和值,形成二元式输出,得到单词流文件 (3)删除注释、空格和无用符号 (4)发现并定位词法错误,需要输出错误的位置在源程序中的第几行。将错误信息输出到屏幕上。 (5)对于普通标识符和常量,分别建立标识符表和常量表(使用线性表存储),当遇到一个标识符或常量时,查找标识符表或常量表,若存在,则返回位置,否则返回0并且填写符号表或常量表。 标识符表结构:变量名,类型(整型、实型、字符型),分配的数据区地址 注:词法分析阶段只填写变量名,其它部分在语法分析、语义分析、代码生成等阶段逐步填入。 常量表结构:常量名,常量值 单词的构词规则: 字母=[A-Z a-z] 数字=[0-9] 标识符=(字母|_)(字母|数字|_)* 数字=数字(数字)*( .数字+|) 2.S语言表达式和语句说明 1.算术表达式:+、-、*、/、% 2.关系运算符:>、>=、<、<=、==、!= 3.赋值运算符:=,+=、-=、*=、/=、%= 4.变量说明:类型标识符 变量名表; 5.类型标识符:int char float 6.If语句:if 表达式then 语句 [else 语句] 7.For语句:for(表达式1;表达式2;表达式3) 语句 8.While语句:while 表达式 do 语句 9.S语言程序:由函数构成,函数不能嵌套定义。
### 词法分析的基本概念 词法分析是编译过程的第一阶段,其主要任务是从字符序列中识别出一个个具有语义的**单词符号(token)**。这些单词通常包括关键字、标识符、常量、运算符和界符等。词法分析器(也称为扫描器)负责将输入的字符流转换为标记流[^1]。 在这一过程中,词法分析器会忽略源程序中的空白字符、注释等内容,并根据语言定义的规则对输入进行划分。例如,在 PL/0 编程语言中,词法分析需要识别出诸如 `begin`、`end` 这样的保留字,以及变量名、数字常量等[^2]。 ### 正则表达式与有限自动机 为了高效地识别这些单词,通常使用**正则表达式(Regular Expressions)**来描述每种类型单词的形式。正则表达式可以被转换为等价的**确定性有限自动机(DFA)**或**非确定性有限自动机(NFA)**,从而用于实际的匹配过程。例如,一个简单的整数常量可以用如下正则表达式表示: ```regex [0-9]+ ``` 该表达式表示由一个或多个数字组成的字符串。通过构造对应的 DFA,可以在输入流中快速定位并提取此类模式[^1]。 ### 状态转换图的设计 状态转换图(State Transition Diagram)是一种图形化的方法,用来表示词法分析器如何从一种状态转移到另一种状态以识别不同的单词。每个节点代表一个状态,边上的标签指示了触发转移的字符条件。设计状态图时,需要注意处理最长匹配原则和优先级问题,确保正确区分相似的模式,比如区分关键字 `if` 和可能的标识符 `iff` 或 `ifdef`[^1]。 ### 实现方法与工具支持 实现词法分析的方式主要有两种:手动编写和利用工具自动生成。对于教学用途或小型项目,可以直接用高级语言如 C/C++、Java 或 Python 手动编码实现;而对于大型工业级应用,则更倾向于使用像 Lex/Flex 这样的工具生成器。它们接受一组正则表达式的定义作为输入,并输出相应的词法分析器代码[^1]。 例如,下面是一个简化版的 Java 片段,用于识别基本的标识符和数字: ```java public class Lexer { private String input; private int position; public Token nextToken() { // 跳过空格 while (position < input.length() && Character.isWhitespace(input.charAt(position))) { position++; } if (position >= input.length()) return new Token("EOF"); char currentChar = input.charAt(position); // 处理数字 if (Character.isDigit(currentChar)) { StringBuilder sb = new StringBuilder(); while (position < input.length() && Character.isDigit(input.charAt(position))) { sb.append(input.charAt(position)); position++; } return new Token("NUMBER", sb.toString()); } // 处理字母开头的标识符 if (Character.isLetter(currentChar)) { StringBuilder sb = new StringBuilder(); while (position < input.length() && (Character.isLetterOrDigit(input.charAt(position)))) { sb.append(input.charAt(position)); position++; } String value = sb.toString(); if ("if".equals(value) || "then".equals(value)) { // 检查是否为关键字 return new Token("KEYWORD", value); } else { return new Token("IDENTIFIER", value); } } // 其他情况视为单个字符的操作符或分隔符 return new Token("OPERATOR_OR_DELIMITER", String.valueOf(currentChar)); } } ``` 此示例展示了如何逐字符读取输入并构建 token 流。当然,真实环境下的实现会更加复杂,需考虑更多边界情况及性能优化[^1]。 ### 错误处理机制 由于词法分析面对的是原始输入文本,因此不可避免地会遇到非法字符或无法识别的模式。此时,良好的错误恢复策略至关重要。常见做法包括跳过未知字符、报告错误位置及尝试猜测用户的意图等。此外,还应提供详细的诊断信息帮助开发者定位问题所在[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值