基于C语言实现 TINY+ 编译器

♻️ 资源

大小: 3.34MB

➡️ 资源下载: https://download.csdn.net/download/s1t16/87484800https://download.csdn.net/download/s1t16/87484800

实现 TINY+ 编译器

实验概述

【实验目的】

构造一个将 TINY+ 高级程序设计语言转换为 TINY+ 虚拟机上的中间代码的编译器。

整个实验包括两个部分:实验一完成 TINY+ 编译器的词法分析器部分;实验二完成 TINY+ 编译器的语法分析器部分、语义分析器部分及中间代码生成器部分。

【实验环境】

Microsoft VisuaStudio 2015

C++ 语言实现

实验内容

实验一、 实现 TINY+ 编译器的词法分析器

【实验目的及要求】

学生在该实验中构造 TINY+ 语言的词法分析程序。具体要求如下:

1 词法分析器的输入是源程序文件,输出是单词(token)流。

2 构造的词法分析器必须遵循最长子串原则,例如字符串':=' 应该被识别为一个代表赋值符号的单词,而不是识别为两个单词':'和 '='。

3 词法分析器识别出的单词应该被表示成二元组的形式(Kind, Value),其中 Kind 表示单词的种类,Value 表示单词的实际值。要求用如下符号表示不同种类的单词:

KEY 表示关键字;

SYM 表示特殊符号;

ID 表示标识符;

NUM 表述数字常量

STR 表示字符串常量

4 词法分析器的任务除了完成对单词的识别之外,还要检查程序中的词法错误,给出错误的信息以及错误在源程序中出现的位置(所在的行号)。词法错误的种类包括:

非法符号,词法分析器可能识别到一个 TINY+ 程序的字母表中不允许的符号,例如,词法分析器在一个源程序中识别到 $,应报告一个词法错误,发现了一个非法符号;

字符串类型的单词 STRING,单引号不匹配。例如,源程序中出现' scanner,词法分析分析器应报告错误"字符串缺少右引号";

注释的括号不匹配。例如源程序中出现{this is an example,词法分析器应报告错误"注释缺少右括号"。

算法分析实验过程:

1.在 main 函数中将 NO_ANALYZE、NO_CODE、PARSE 设置为 TRUE,使程序只进行词法分析过程。

2.由于增加了关键字(keyword),TINY 语言关键字如下:

|-------------|-------------------------------------------|
| Tiny 关键字 | if,then,else,end ,repeat,until,read,write |
| Tiny+ 新增关键字 | Or,and ,int,bool,char,while,do |

其中所有的关键字是程序设计语言保留使用的,并且用小写字母表示,用户自己定义的标识符不能和关键字重复。

3.特殊符号定义:

|------------|-------------------------------------------------|
| Tiny 符号 | { } ; := + - /()<=** |
| Tiny+ 新增符号 | > <= >= , ' |

4.词法分析器中识别的单词用二元组形式表示(Kind,Value),其中 Kind 表示单词的种类,Value 表示单词的实际值。要求用如下符号表示不同种类的单词:

|-----|-------|
| KEY | 关键字 |
| SYM | 特殊符号 |
| ID | 标识符 |
| NUM | 数字常量 |
| STR | 字符串常量 |

5,词法分析器的任务除了完成对单词的识别之外,还要检查程序中的词法错误,给出错误的信息以及错误在源程序中出现的位置(所在的行号)。词法错误的种类包括:

非法符号,词法分析器可能识别到一个 TINY+ 程序的字母表中不允许的符号,例如,词法分析器在一个源程序中识别到 $,应报告一个词法错误,发现了一个非法符号;

字符串类型的单词 STRING,单引号不匹配。例如,源程序中出现' scanner,词法分析分析器应报告错误"字符串缺少右引号";

注释的括号不匹配。例如源程序中出现{this is an example,词法分析器应报告错误"注释缺少右括号"。

实验过程:

在 GLOBALS.h 中的 TokenType 枚举中增加相应的类型:

|--------|--------|--------|--------|
| 关键词 | 特殊符号 | | |
| 新增枚举定义 | 对应的关键词 | 新增枚举定义 | 对应特殊符号 |
| OR | or | RT | > |
| AND | and | LTEQ | <= |
| INT | Int | RTEQ | >= |
| BOOL | bool | COMMA | , |
| CHAR | char | CO | ' |
| WHILE | while | | |
| DO | do | | |

在 SCAN.C 的 getToken()函数中进行相应修改,让程序能够正确识别新添加的关键词以及特殊符号,并且对程序出错进行相应提示)

词法分析测试结果
测试一:

输入:

输出:

测试二:

输入:

输出:

测试三:(测试错误提示)

输入:

输出:

实验二、实现 TINY+ 的语法分析器、语义分析器以及中间代码生成器

*【实验目的及要求】

学生在该实验中构造 TINY+ 语言的语法分析器、语义分析器以及中间代码生成器,具体要求如下:

1 为 TINY+ 构造一个递归下降语法分析器。该语法分析器对词法分析器生成的单词序列进行语法分析,产生一颗抽象语法树作为语法分析器的输出。

2 构造 TINY+ 的语义分析器,该语义分析器构建符号表,然后检查程序中的语义错误。

3 构造 TINY+ 的中间代码生成系,该中间代码生成器将 TINY+ 程序翻译为三地址中间代码。

4 要求能检查程序中语法和语义错误,具体包括:

a) 语法错误:

语法结构的开始符号以及跟随符号错误;

标识符错误,例如在程序的变量声明中,关键字 int 后没有跟随标识符;

括号不匹配的错误,例如左括号(和右括号 )不匹配。

符号错误,例如赋值语句中要求使用的正确符号是':=',而在关系比较表达式要求使用的正确符号是'='。

b) 语义错误:

一个标识符没有声明就使用,以及一个标识符被声明不止一次。

一个条件表达式的类型不是布尔类型 bool。

一个二元操作符的两个操作数的类型不相等。

赋值语句左右部的类型不相等。

语法分析实验过程:

1.在 main 函数中将 NO_ANALYZE、NO_CODE 设置为 TRUE,使程序只进行 PARSE(语法分析)过程。

2.Tiny+ 的语法 EBNF 定义如下:

复制代码
1rogram		->	declarations stmt-sequence
2declarations	-> dec; declarations |ε
3decl		-> type-specifier varlist
4type-specifier	-> int | boo| char
5varlist	-> identifier { , identifier }
6stmt-sequence	-> statement { ; statement }
7statement	-> if-stmt | repeat-stmt | assign-stmt | read-stmt | write-stmt | while-stmt
8while-stmt -> while bool-exp do stmt-sequence end
9if-stmt	-> if  bool-exp then stmt-sequence [else stmt-sequence] end
10repeat-stmt	-> repeat stmt-sequence untibool-exp
11assign-stmt	-> identifier:=exp
12read-stmt	-> read identifier
13write-stmt	-> write exp
14exp	-> arithmetic-exp | bool-exp | string-exp
15arithmetic-exp	-> term { addop term } 
16addop	-> + | -
17term	-> factor { mulop factor }
18mulop	-> * | /
19factor	->  (arithmetic-exp) | number | identifier
20 bool-exp	-> bterm { or bterm }
21 bterm	-> bfactor { and  bfactor}
22 bfactor	-> comparison-exp
23 comparison-exp -> arithmetic-exp comparison-op arithmetic-exp
24 comparison-op	-> < | = | > | >= | <=
tring-exp		-> string

3.根据 EBNF 的定义,修改 PARSE.C 文件,构造递归下降语法分析器,产生一棵语法树。

基本语法树木的结构如下:

|------------------|---------------------------------------------------------------------------------|-------------------------------------------------------------------------|
| 语句系列 | | 语句间通过链表相连,除了第一条语句,其他语句均可通过前一个语句的->slibing 查找到。 |
| If 语句 | | test 位于 If 语句的 child0,then-part 为 child1,else-part 为 child2 |
| Repeat | | Body 位于 repeat 语句中的 child0,test 位于 chlid1 |
| Assign | | Expression 位于 assign 语句 child0 |
| write | | Expression 位于 write 的 child0 |
| Op 逻辑运算 | | Left-operand 位于 op 语句的 child0,Right-opreand 位于语句的 child1; |
| while | | Test 位于 while 语句的 child0Do-part 位于 child1 |
| Define 如:int A,B | | B 位于 A 的 slibing 中,其中 A、B 的子节点均未赋值(此处留给将来拓展用) |

新建一个 define 的结点类型,用来识别定义语句.

重写 tiny 中不适合的语法分析树枝,按照新的 ENBF 定义写出合适的分析函数,从而构建出正确语法树。

语法分析测试结果:

测试一:

输入:

输出:

语义分析实验过程:

1 在 main 函数中将 NO_CODE 设置为 TRUE,使程序进行语义分析过程。

2 一个用 TINY+ 语言编写的程序包括变量的声明和语句序列两个部分。变量声明部分可以为空,但一个 TINY+ 程序至少要包含一条语句。

a) 所有的变量在使用之前必须声明,并且每个变量只能被声明一次。

b) 变量以及表达式的类型可以是整型 int,布尔类型 bool 或者字符串类型 char,必须对变量的使用和表达式进行类型检查。

3 构建语义分析器主要包括

符号表的设计以及符号表的相应操作

  1. 符号表保存信息:变量的地址信息、变量被访问的行号
  2. 变量以其变量名 ID,通过链式 hash 储存查找到相应数据。

语义分析程序本身的操作,包括符号表的构建以及类型检查。

  1. 符号表的创建:

前序遍历语法树:

当遇到定义的语法结点时候,将其变量新增到哈希表中,并存储其行号位置;

遇到含有变量的非定义语句的结点时,查找该变量位于哈希表中的位置,将该行号储存到哈希相应表项的 next 位置。

  1. 类型检查:

后续遍历语法树,对每一个结点进行语义判断:

1.if 语句结点中,if-test(child0)的类型必定为 boolean,

  1. while 语句结点中,while-test(child0)的类型必定为 boolean,
  2. op 算术运算结点中,child0、child1必须为 integer 类型
  3. op 逻辑运算结点中,child0、child1必须为 boolean
  4. 赋值运算结点中,child0、child1的类型必须一致
  5. ......

在后续遍历语法树中,查看变量是否非法使用:

  1. 当结点为 ID 结点时候,在哈希表中查看是否已经定义。
  2. 如果该结点为定义语句结点,则判断此变量是否重复定义。
  3. 如果该变量已经定义,则将变量的 type(类型)赋于定义时候的类型
  4. 进入上一层遍历,当其类型不符合上一层所需类型时候提示错误。(即如在赋值语句中,该变量的类型与赋值语句另一个子节点的类型不一致,提示语义错误)。

词法分析测试结果

测试一:

输入:

输出:

测试二:

输入:

输出:

测试三:(测试错误提示)

输入:代码中有三处错误:

a) A 重复定义

b) A>3 中 A 为 char 型,比较错误

c)A:=1 中赋值错误。类型不一致

输出:

中间代码生成实验过程:

1 在 main 函数中将 NO_PARSE、NO_ANALYZE、NO_CODE 设置为 FALSE,使程序进行中间代码生成过程。

2 构造 TINY+ 的中间代码生成系,该中间代码生成器将 TINY+ 程序翻译为三地址中间代码。

3 在原 tiny 中间代码生成器的实现位于 cgen.c 和 cgen.h 中。其接口为 codeGen(TreeNodesyntaxTree,char codefile).

主要功能为:

函数的开始,产生一些注释以及建立运行时环境的指令。

对语法树调用 cGen 函数,对每一个语法树结点生成相应指令

最后生成 HALT 指令,结束目标代码生成。

注释以及指令均写在某指定.tm 文件上,供 TM 程序调用并且运行。

4 Tiny+ 在 tiny 的基础上进行修改。其中 codeGen 函数将保持不变,修改其 cGen 函数即可。

修改 cGen 函数调用的 getExp()函数。

增加 OpK 的类型,即在原有功能代码基础上,增加新增符号其操作的中间代码生成步骤。即新增符号 RT,EQ,LTEQ,RTEQ.

如增加">"的中间代码生成过程

增加 LogicOpK 的处理(即增加 AND、OR 的中间代码的生成)

此处中间代码生成比算术运算的中间代码复杂得多,根据 TM 程序的指令以及其操作原理,写出 AND 和 OR 中间生成代码功能:

5 修改 cGen 函数调用的 getStmt()函数。增加语句 while 的中间代码生成。

此处通过 Tiny+ 文法规则产生对于的三地址中间代码属性,完成 while 生成中间代码功能。

中间代码测试结果
测试一:

输入:

输出:

相关推荐
Wang's Blog1 小时前
Java 项目实战: 外卖平台优化-从库Slave配置与主从复制验证
java·开发语言
知识分享小能手1 小时前
C++ 学习教程,从入门到精通,C++内存模型和名称空间 — 详细知识点总结(9)
开发语言·c++·学习
2601_962218611 小时前
c++中多重继承与虚继承的实现
开发语言·c++
adinnet20261 小时前
意图识别(Intent Recognition):智能体怎么听懂你想干啥
大数据·数据库
笨小孩@GF 知行合一2 小时前
易语言-基础-外部数据库
数据库·编程·易语言·中文编程
DolphinDB智臾科技2 小时前
告别繁琐解析!BinaryTcp 模块实现沪深 Level‑1 行情接收‑解析‑落库一站式能力
数据库·插件·dolphindb
我是小白呀2 小时前
17-企业Workflow引擎怎么选:定时、队列、n8n、Temporal与Camunda
java·开发语言·人工智能·dubbo·workflow
weixin_404551242 小时前
Oracle SQL 优化知识库:构建方案与价值评估
数据库·sql·oracle
维克兜率天2 小时前
【维克】均值回归:跌多了会涨,涨多了会跌
开发语言·笔记·python·算法·均值算法·回归·量化