编译原理实验一
这篇实验报告围绕“词法分析器实现”展开,给出了从实验要求到代码结构落地的一整套实现路径。实验目标与词法规则明确了词法分析任务:对源程序输出 Token 流、错误信息、符号表与字符串结果。按实验约束定义了 5 类词法单元:保留字、标识符、无符号整数、运算符、分隔符。强调错误定位要包含行列信息,保证分析结果可追溯。架构拆分…
实验一:词法分析 一、实验目的要求 要求学生选择一种熟悉的高级语言,编制词法分析程序。 二、实验准备 微机CPU 586以上,32M以上内存,安装好已熟悉的高级语言系统,如C语言,PASCAL语言,或C++。 三、实验时间 4学时 四、实验内容 定义模拟的简单语言的词法构成,编制词法分析程序,要求将用模拟语言书写的源程序进行词法分析,输出源程序清单,Token文件和错误信息文件,若有错误,必须输出错误在源程序中行号和列号,并将符号表和字符串以文件的形式写出来。实验要求 要求: 识别保留字:if、int、for、while、do、return、break、continue; 单词种别码为1。 其他的都识别为标识符;单词种别码为2。 常数为无符号整形数;单词种别码为3。 运算符包括:+、-、*、/、=、>、<、>=、<=、!= ; 单词种别码为4。 分隔符包括:,、;、{、}、(、); 单词种别码为5。实验设计 具体的实验设计,我采取的是面向对象的思维,使用的语言是 Go 语言,如果不了解这个语言可以去网上简单搜一下,我这里也简单的贴一下官网:golang.google.cn,这是 Google 2011年开源的一个语言,是目前最为火热的云原生时代的语言,如果对实验使用的语言有限定的话,我可以再使用 C++ 语言进行重现。整体的设计 归类 整体的设计框架如上图所示,整个词法分析的功能,我抽象出了两个类,Scanner 和 Parser。Scanner:负责扫描单词。Parser:负责解析单词。 再结合具体的实验要求,Scanner 类的任务需要提供 Scan 方法用于扫描出单词,Parser 类的任务就很简单了,只需要将扫描出来的单词按照对应的规则进行打印即可。 所以具体的词法解析过程如下:func CompileCode(filename string) { //读取文件数据 fd, err := os.Open(filename) if err != nil { panic(err) } bytes, err := ioutil.ReadAll(fd) if err != nil { panic(err) } //根据文件内容创建Scanner和Parser scanner := NewScanner(bytes) parser := NewParser() //调用Scan方法得到单词后进行相应的Parse处理,直到scanner扫描结束(即Eof()返回true) for !scanner.Eof() { word := scanner.Scan() if word == "" { continue } if StartWith(word, "//") { scanner.NextLine() continue } if !IsValidCode(word) { fmt.Println("Error characters! Only supported digit or letter fill in name! Your code:", word) } parser.Word = word parser.Parse() } } 以上就是整个词法分析的整体逻辑,通过上述代码发现其实我还加入了实验要求以外的拓展:支持跳过注释。支持对单词的内容进行验证,如果为错误的词法格式则提示错误(比如使用中文来定义变量)。Scanner 现在来具体解释 Scanner 类的实现,这个类需要两个成员(1.需要扫描的内容-bytes. 2.当前扫描到的位置-index.)。 而最为关键的实现在于 Scan 方法,关于这个方法,我使用的是状态机的算法来实现的,如下状态转移图: compiler.drawio 定义了三个状态:kScanSpace :该状态表示还没有遇到任何有效的单词,故暂时需要跳过,如果遇到了单词,那么需要记录单词的起始位置,并转换状态为 kScanWord 。kScanWord :该状态表示正在扫描单词,如果遇的是非单词(空白或分隔符),则切换状态到 kScanEnd 。kScanEnd :该状态表示此次扫描正常结束,根据目前的状态返回对应的单词。 关于 Eof 和 NextLine 方法的实现就非常的简单了,Eof 方法只需要判断当前扫描到的 index 是否超过字符串长度,NextLine 方法也只需要不断往后扫描直到碰到 '\n' 。Parser Parser 类的实现就相对简单了,只需要根据实验要求对不同的单词匹配对应的规则进行打印即可。 比如单词 "if" 经过判断得出是保留字,那么打印结果为 (1,"if") 。 具体的设计是这样的:通过实验要求建立对应的集合,比如把保留字"if"、"while" 等建立一个字符串数…
正在初始化 WebAssembly 引擎…
首次编译原生模块可能需要数秒
就绪后,页面交互将以接近原生的速度运行