云文档网 - 专业文章范例文档资料分享平台

基于LLVM的编译器的设计与实现

来源:网络收集 时间:2024-05-08 下载这篇文档 手机版
说明:文章内容仅供预览,部分内容可能不全,需要完整文档或者需要复制内容,请下载word后使用。下载word有问题请添加微信号:xuecool-com或QQ:370150219 处理(尽可能给您提供完整文档),感谢您的支持与谅解。点击这里给我发消息

题目:基于

LLVM的编译器的设计与实现

设计人: 梁关林 指导教师:刘爱琴

所属系部:计算机科学与技术学院专业班级:计算机082001班

2012年 6月 4日

学士学位论文

太原科技大学毕业设计(论文)任务书

学院: 计算机科学与技术学院

学 生 姓 名 专业班级 任务下发时间 设计(论文)题目 设计 目的 要求 高质量应用软件的开发,需要高效的编程语言和编译器的支持。为了加深学生对编程语言和编译器的理解,要求学生设计一个类似C的小源语言,然后利用LLVM实现该语言的编译器。 在深刻理解编译原理,掌握文法设计和编译器构造方法,并且熟悉LLVM的基础上,完成编程语言和编译器的设计。主要内容包括: 设计 主要 内容 (1) 设计源语言,要求包括变量声明,基本赋值语句,数组访问,条件分支语句,循环语句,函数定义,和函数调用等。 (2) 学习LLVM,完成词法分析,语法分析,和语法制导翻译(翻译成LLVM IR)工作,最后利用LLVM实现代码优化和代码生成功能。 设计 提交 资料 学生签名 毕业论文 外文资料翻译 编译器软件 指导教师签名 梁关林 计算机082001 2012年3月 学号 同组人 任务完成时间 200820010114 无 2012年6月 基于LLVM的编译器的设计与实现 系主任签名 主管院长签名

太原科技大学学士学位论文

中文摘要

开发高性能的应用软件,除了一个良好的软件架构外,还需要高效的编程语言和高质量的编译器的支持。现有语言的改动和新语言的创造,都会带来编译器的开发需求。

本文设计了一门新的编程语言leechee,定义了此种语言的文法结构、词法规则,并在linux环境下实现了leechee编程语言的编译器。具体实现方式为首先利用Flex完成词法分析,而后使用Bison完成文法设计、语法分析和语法制导翻译,把源代码翻译成LLVM IR,最后利用LLVM实现代码优化和代码生成功能。

关键字:编程语言;编译器;语法制导翻译;LLVM IR;代码优化

I

太原科技大学学士学位论文

The Design and Implementation of

LLVM based Compiler

Author: Liang Guanlin Tutor: Liu Aiqin

ABSTRACT

In addition to a good software-architecture, the development of high-performance applications also needs the support of an efficient programming language and a high-quality compiler. Changes to existing languages and creation of new languages, will bring the development needs of the compilers.

This paper designs a new programming language leechee, defines its grammatical structures, lexical rules, and implements its compiler under Linux environment. The specific approach is, first, finishes the scanner with Flex, and then completes the grammar design, parser, syntax directed translation with Bison, implements the translation to LLVM IR, and finally use the LLVM to do the code optimization and code generation.

Keywords: programming language; compiler; syntax directed translation; LLVM IR; code optimization

II

太原科技大学学士学位论文

目录

第一章 绪论 ........................................................................................................................................ 1

1.1 什么是编译器 ...................................................................................................................... 1 1.2 总会有编译器的开发需求................................................................................................... 1 1.3 为什么做这个项目 .............................................................................................................. 2 第二章 设计什么样的编译器和语言 ................................................................................................. 4

2.1 做一个什么样的编译器 ...................................................................................................... 4

2.1.1 利用LLVM实现一门新语言.................................................................................. 4 2.1.2 利用flex和bison完成词法分析和语法分析 ........................................................ 5 2.2 设计一个什么样的语言 ...................................................................................................... 6

2.2.1 计算机可以做什么 .................................................................................................. 6 2.2.2 本设计的语言——leechee ...................................................................................... 7

第三章 相关技术的介绍 ..................................................................................................................... 8

3.1 Flex ........................................................................................................................................ 8

3.1.1 Flex输入文件的格式 ............................................................................................... 8 3.2 Bison ...................................................................................................................................... 9

3.2.1 Bison的语法文件 ..................................................................................................... 9 3.2.2 文法规则的语法 .................................................................................................... 10 3.2.3 文法设计需要注意的问题 .................................................................................... 11 3.3 LLVM .................................................................................................................................. 12

3.3.1 LLVM IR ................................................................................................................. 12 3.3.2 LLVM对三段式设计的实现 ................................................................................. 13 3.3.3 利用LLVM完成代码优化 ................................................................................... 15

第四章 语言和编译器的设计 ........................................................................................................... 17

4.1 语言设计 ............................................................................................................................ 17

4.1.1 leechee的数据组成 ................................................................................................ 17 4.1.2 leechee的文法规则 ................................................................................................ 18

III

太原科技大学学士学位论文

4.1.3 leechee的词法规则 ................................................................................................ 24 4.1.4 leechee的输入输出 ................................................................................................ 27 4.2 抽象语法树 ........................................................................................................................ 28

4.2.1 抽象语法树的用处 ................................................................................................ 28 4.2.2 leechee语法树的设计 ............................................................................................ 28 4.3 语法制导翻译 .................................................................................................................... 31

4.3.1 利用Bison实现语法制导翻译方案 ..................................................................... 32 4.3.2 均分代码生成工作 ................................................................................................ 32

第五章 编译器的实现 ....................................................................................................................... 33

5.1 抽象语法树的实现 ............................................................................................................ 33

5.1.1 NodeAST ................................................................................................................. 33 5.1.2 类型 ........................................................................................................................ 34 5.1.3 表达式 .................................................................................................................... 36 5.1.4 语句 ........................................................................................................................ 42 5.1.5 声明 ........................................................................................................................ 46 5.2 符号表 ................................................................................................................................ 50 5.3 分析栈 ................................................................................................................................ 51 5.4 中间代码生成的上下文 .................................................................................................... 52 5.5 输入输出 ............................................................................................................................ 53 5.6 代码优化 ............................................................................................................................ 55 第六章 用例说明............................................................................................................................... 56

6.1 用例程序 ............................................................................................................................ 56 6.2 使用步骤 ............................................................................................................................ 58 结束语 ................................................................................................................................................ 59 致谢 .................................................................................................................................................... 60 参考文献 ............................................................................................................................................ 61 附录 .................................................................................................................................................... 62

附录Ⅰ 英文资料翻译 ............................................................................................................. 62

IV

太原科技大学学士学位论文

附录Ⅱ 程序代码 ..................................................................................................................... 73

V

太原科技大学学士学位论文

第一章 绪论

1.1 什么是编译器

编译器(compiler)也是一个计算机程序,它把用某种编程语言(源语言)编写的代码转变成另一种计算机语言(目标语言,通常是二进制形式的目标代码)。转变源码最普遍的原因是为了生成执行的程序。

编译器,这个名字主要是指把高级编程语言翻译成低级语言(比如,汇编语言或者机器码)的程序。如果翻译出来的程序能够在有着不同于编译器自身运行的CPU或者操作系统的计算机上运行,这种编译器就是交叉编译器(cross-compiler)。能够把低级语言翻译成高级语言的程序则叫做逆编译器(decompiler)。把高级语言翻译成其他高级语言的程序,通常被称为语言翻译器(language translator)。语言重写器(rewriter)通常是指能够转变表达式而不改变所属语言的程序。

一个编译器通常执行的操作有:词法分析,预处理,语法分析,语义分析(语法制导翻译),代码生成,和代码优化[1]。

编译器软件的正确性非常重要,因为不正确的编译器行为产生的程序错误,通常很难被发现,也很难解决;为此,编译器的实现者付出了大量的努力来保证他们的软件的正确性。

1.2 总会有编译器的开发需求

现在常用的语言都已经有很多优秀的编译器,比如C语言有GCC和ICC;C++有G++和I++;Java有JAVAC和GCJ。然而这些常用语言本身就一直在改变,不断地完善。因而,实现这些语言的编译器也必须做出相应的改动。语言自身的改变,有的是为了弥补自身的缺陷,例如java语言从设计至今,其体积已经增大了几倍;有的是为了适应新的软件开发需求,比如为了更容易地开发大型软件。

除了那些成熟语言的改动会带来编译器软件编程的需要外,新语言的诞生也需要编译器程序员来完成新语言的实现工作。比如现在不断涌现的各种脚本语言,都需要编译

1

太原科技大学学士学位论文

器程序员来编写这些语言的编译器。新语言的设计(创造),有的是为了适应特殊领域的编程需要,比如SQL(Structured Query Language),是为关系数据库管理系统专门设计的专用语言。有的是为了更好地利用各种系统资源(尤其是硬件资源),比如OpenCL(Open Computing Language),是为了更好地开发异构平台的计算能力而设计的。

可以看到作为编程语言的实现软件(或者不同语言间的翻译软件)的编译器,对它的编程需求一直都存在。我们总有需要实现新的编译器,或者改动现有编译器的时候。

图1.1 一个典型编译器执行的操作

1.3 为什么做这个项目

开发高性能的应用软件,除了一个良好的软件架构外,还需要一门符合要求的高效的编程语言来实现软件的设计,和一个高质量的编译器来把高级语言写的程序翻译成计算机硬件能够执行的机器代码。编程语言和编译器扮演着辅助软件设计和实现,以及开发计算机计算能力的角色。它们都会深刻影响软件的实际性能;编程语言还会影响软件

2

太原科技大学学士学位论文

开发的效率。

虽然,现在已经有很多优秀的编程语言和优秀的编译器。但是,一切都在不断地改变。人们一直都会有编译器的开发需求,需要一门更符合要求的编程语言,一个更适合的编译器。我对编译器的开发工作很感兴趣,希望能够参与其中,因此,我借毕业设计这个机会,设计并实现一门小语言,以学习更多编译器方面的知识,加深对编译器和编程语言的理解。这就是我为什么做这个项目的原因。

3

太原科技大学学士学位论文

第二章 设计什么样的编译器和语言

这一章说明应该做一个什么样的编译器,设计一个什么样的语言,以及如何实现这个编译器的问题。

2.1 做一个什么样的编译器

应该做一个什么样的编译器呢?实现一门现有的语言,比如C或者java?或者从语言设计,到代码生成,所有的工作都做一遍?

实现一门现有的语言,比如C语言,我显然没有这样的能力;就算能实现,时间也不够。而且这么做不如直接去研究一个该语言的编译器来得更有意义。当然这也是需要大量的时间的(而且,这个工作无法成为设计)。

从头到尾,把所有工作都做一遍。或许能够这样做。然而在有限的时间内,只能实现一个非常简单的语言,这么做又有什么意义呢。

对一个编译器的入门者来说,需要加深对整个编译器实现流程的理解,也需要了解一些编译器的新技术,或者说这个领域的走向。 2.1.1 利用LLVM实现一门新语言

LLVM(Low Level Virtual Machine)是一个包含一系列模块化可重用编译器和工具链技术的项目。LLVM主要的子项目有:LLVM Core libraries,Clang,dragonegg,LLDB等。

其中LLVM Core libraries(LLVM核心库)提供了一个现代源码的(modern source)、目标独立的(target-independent)优化器;同时还为许多流行CPU提供了代码生成的支持。这些库是围绕着一个有详细说明的代码表示形式(LLVM IR)建立起来的。

也就是说,只要我们能够把自己的语言翻译成LLVM IR,就可以利用LLVM完成代码优化和代码生成的工作。当然,你的目标语言(或者说目标CPU架构)必须是LLVM已经支持的。不然,还是得自己实现代码生成的功能。

4

太原科技大学学士学位论文

Clang是一个LLVM自身的C/C++/Objective-C编译器,目标是提供快速的编译。据说编译Objective-C代码时能够比GCC快3倍。

dragonegg把LLVM的优化器、代码生成器和GCC 4.5的分析器结合在一起。这样就使得LLVM能够编译Ada、Fortran等其他GCC编译器前端支持的语言,能够拥有一些Clang不支持的C特性(例如OpenMP)。

LLDB是建立在LLVM库和Clang之上的一个非常好的本地调试器。 2.1.2 利用flex和bison完成词法分析和语法分析

又利用其他工具完成编译工作?那到底还有多少情是自己做的呢?

之所以要使用工具来完成语法分析工作,是因为本设计计划实现一个文法结构比较丰富的语言,一个类似C的小语言,能够实现控制流操作和过程调用这些功能。文法(或者说语言构造)多了,文法设计的难度就会增大。LR文法可以比较容易地描述复杂的语言文法。但是LR文法的语法分析表非常庞大,很难手动建立。因此,本设计选择使用bison(一个与yacc兼容的编译器构造工具)完成语法分析工作。

使用flex(一个与lex兼容的词法分析构造工具)完成词法分析,则完全是为了节省时间。

这样,需要做的工作就剩下设计文法和语法制导翻译了。然而这样做,是有缺陷的。因为这样将导致编译器的主体部分中出现大量不是自己写的代码和想控制又难以控制的模块,使得编译器看起来非常笨拙。所以现在很多流行的编译器(例如GCC和Clang)都使用LL文法,而不是LR文法。然而设计一个语言的LL文法并非易事,所以只好暂且这么做了。

5

太原科技大学学士学位论文

图2.1 本设计编译器的实现方法

2.2 设计一个什么样的语言

2.2.1 计算机可以做什么

设计一个计算机语言,需要清楚计算机能够做什么样的事情,打算利用它做什么事情。而后才能设计自己的语言。

一台计算机的5个经典部件是输入,输出,内存,数据通路,和控制器,最后两个有时组合在一起称为处理器。同时,任何计算机的底层硬件都执行相同的基本功能:输入数据,输出数据,处理数据,和存储数据[2]。这大概就是计算机的模型了。

我们用计算机来写文档,画图,看视频,玩游戏,等等各种各样的事情。然而计算机是怎么替我们做这些事情的呢?其实,计算机的核心部分——处理器(CPU)能够做的就是不断重复地执行各种指令,例如顺序执行的加、减、乘、除、移位指令,和二进制的与、或、非指令。除了顺序执行的指令外,处理器还可以执行选择指令,也就是条件跳转和无条件跳转指令。当然,一个功能完备的处理器,还必须能够执行数据的加载和存储指令。

以上是在底层硬件上看到的操作,在高级语言中我们看到的则是算术逻辑运算,布尔运算,和控制流操作这些更符合我们人类思考方式的操作。不过,无论是从底层看,

6

太原科技大学学士学位论文

还是从高层看,计算机执行的操作都可以分为顺序操作和选择跳转操作。所以,在练习语言设计时,一定要覆盖计算机的这两项功能。

此外,为了描述清楚计算机处理和存储的数据,我们需要一个类型系统,说明数据的大小和存储格式。而且,往往不同类型的数据,执行这些数据的操作的硬件也是不同的,例如,执行整型和浮点型运算的硬件就是独立分开的。 2.2.2 本设计的语言——leechee

弄清楚计算机能够做什么之后,就可以讨论设计一个什么样的语言了。

因为计算机最基本的功能是计算,所以本设计决定设计一个计算性的语言。利用它可以完成基本的算术逻辑运算。不过,为了减轻工作量,只支持加减乘除运算。在布尔运算上,则比较完整,包括与或非和各种关系运算。所有的计算任务都通过函数来描述。使用者(语言的使用者)编写程序时,从一个主函数开始描述他所需的计算任务。在一个函数中可以调用其他函数,来完成一些子任务(当然,不能调用主函数main)。

总之,这是一个类似C的小语言。每个语言都有自己的名字,我也给自己的语言取个名字——leechee。

7

太原科技大学学士学位论文

第三章 相关技术的介绍

如上一章所提到的,这个设计中需要使用一些工具或者说技术,这里对其进行比较完整的介绍。

3.1 Flex

Flex (fast lexical analyser generator) 是Lex的一个替代品。它经常和GNU Bison语法分析器生成器一起使用。Flex最初由Vern Paxson 于1987 年用C语言写成。

Flex是一个生成扫描器的工具,能够识别文本中的词法模式。flex读入给定的输入文件,如果没有给定文件名的话,则从标准输入读取,从而获得一个关于需要生成的扫描器的描述。此描述叫做规则,由扩展的正则表达式和C代码对组成。flex的输出是一个C代码文件——lex.yy.c——其中定义了yylex() 函数。编译输出文件并且和 -lfl库链接生成一个可执行文件。当运行可执行文件的时候,它分析输入文件,为每一个正则表达式寻找匹配。当发现一个匹配时,它执行与此正则表达式相关的C代码。 3.1.1 Flex输入文件的格式

flex的输入文件有三部分组成,用包含?%%?的独立一行分隔开。

definitions %% rules %%

user code

definition部分包含简单名字的定义,这些定义是为了简化扫描器的说明。definition部分还包含了开始状态的声明。

rules部分包含了一系列的如下形式的规则:

pattern action

8

太原科技大学学士学位论文

pattern(词法模式)必须是无缩进的扩展的正则表达式,action(pattern被识别后执行的语句)必须在pattern的同一行开始。

user code部分只是简单逐字地复制到lex.yy.c中。这一部分使用在调用扫描器或者被扫描器调用的同伴例程上。这一部分是可选的,如果省略的话,输入文件中第二个?%%?符号也可省略。

Flex支持C风格的注释,也即是,任何在?/*?和?*/?之间的字符串都被看作是注释。 具体请参考Flex的手册http://flex.sourceforge.net/manual/。

3.2 Bison

Bison是一个通用的分析器生成器,最初由Rovert Corbett编写。Richard Stallman使得它与Yacc兼容。Carnegie Mellon大学的Wilfred Hansen为Bison添加了多字符字符串字面值(multi-character string literals)和其它一些特性。

Bison能够把带注释的上下文无关文法转换成采用LALR(1)分析表的,确定的LR或者推广的LR(generalized)分析器。作为一个实验特性,Bison还可以生成IELR(1)或者canonical LR(1)分析表。一旦你精通Bison,你可以用它生成从简单的桌面计算器到复杂的程序设计语言等等许多语言的分析器。 3.2.1 Bison的语法文件

Bison使用一个描述上下文无关文法的文件作为输入,并产生一个识别该文法的正确实例的C语言函数。按照惯例,Bison的文法文件一般以?.y?结尾。

一个Bison语法文件有四个主要的部分,如下所示,由恰当的分隔符分隔。

%{

Prologue %}

Bison declarations %%

Grammar rules %% Epilogue

9

太原科技大学学士学位论文

Prologue部分包括宏定义和在语法规则动作中使用的函数和变量的声明。这些将复制到分析器文件的开头以便先于yyparse的定义。你可以使用`#include'来从头文件获取声明。如果你不需要任何的C声明,你可以省略这个部分的括号分隔符`%{'和`%}'。

Bison declatations部分包含了定义终结符和非终结符的声明,优先级等等。 在一些简单的语法中,可以不需要任何声明。

Grammar Rules部分包含了一个或多个Bison语法规则。

就像Prologue部分被复制到开头一样,Epilogue部分被逐字地复制到分析器文件的结尾。如果你想放一些代码却没必要放在yyparse的定义之前,这里是最方便的地方。例如,yylex和yyerror的定义就经常放在这里。因为C语言要求函数在使用之前必须声明。你经常需要Prologue部分声明类似yylex和yyerror的函数,即使你在Epilogue部分已经定义了它们。 3.2.2 文法规则的语法

一个Bison语法规则通常有如下的下形式: result: components ... ;

reault是这个规则描述的非终结符,而components 是被这个规则组合在一起的各种终结符和非终结符。

例如:

exp: exp '+' exp

;

表明两组exp类型和一个在中间的`+'记号,可以结合成一个更大的exp类型组。规则中的空白只用来分隔符号,你可以在你想要的地方添加额外的空白。

决定规则的语义的动作可以分散在部件(components)中。一个动作看起来是这样的:

{C statements}

用花括号括起来的一个C语句序列,非常像C的一个复合语句。通常部件的后面只跟有一个语义动作。

同一个result的多个规则可以分别书写,也可以用垂直条`|'按如下的方法连接起来:

10

太原科技大学学士学位论文

result: rule1-components ...

| rule2-components ... ...

如果一个规则的components为空,意味着result可以匹配空字符串。例如,这是如何定义一个由逗号分隔的由0个或多个exp组成的序列:

expseq: /* empty */

| expseq1 ;

expseq1: exp

| expseq1 ?,? exp ;

我们通常对每个没有部件的规则加上一个`/* empty */'的注释。

具体请参考Bison的手册http://www.gnu.org/software/bison/manual/bison.html。 3.2.3 文法设计需要注意的问题

对于符号串识别来说,它看到的只有符号,没有任何语义层面的东西。所以设计文法时,应该尽量从符号串模式设计的角度去设计,用不同的各种符号串模式去描述清楚语言里面的各种程序构造。

还有,我们应该遵从已有的通用语言的惯例,避免自创一套文法。遵从通用语言的惯例,使得新设计的语言更易于被理解和接受,程序员在学习使用新语言时也可以减轻不少负担。

11

太原科技大学学士学位论文

3.3 LLVM

LLVM(Low Level Virtual Machine)是一套编译器的基础设施(infrastructure),可以把它看作一个大项目,包括一套从前端,各种代码分析/优化工具,到代码生成器的编译器工具链,而且可兼容Unix系统上的现有工具。

LLVM现在被用作实现各种静态和运行时编译语言的公共基础设施,例如,GCC支持的语言族,Java,.NET,Python,Ruby,Scheme,Haskell,D,以及许多不那么知名的语言。它也取代了多种特殊用途的编译器,比如Apple的OpenGL软件栈(stack)中的专用引擎,和Adobe的After Effects产品中的图像处理库。最后,LLVM还被用于创建许多新产品,也许其中最为人熟知的就是OpenCL GPU编程语言和它的runtime。 3.3.1 LLVM IR

LLVM IR(LLVM中间表示形式)是LLVM设计最重要的一个方面,是LLVM编译器用来表示代码的形式。LLVM IR被设计来主持编译器中间级别的分析和变形。它的设计考虑了许多特定的目标,包括支持轻量的运行时优化,跨函数(过程间)优化,程序全局分析,和大胆的(aggressive)重组变形等等。不过,它最重要的方面是,它自身就被定义为一个一流的有着定义明确的语义的语言。

眼见为实,下面就是LLVM IR的一个例子(一个.ll文件):

define i32 @add1(i32 %a, i32 %b) { entry:

%tmp1 = add i32 %a, %b ret i32 %tmp1 }

define i32 @add2(i32 %a, i32 %b) { entry:

%tmp1 = icmp eq i32 %a, 0

br i1 %tmp1, label %done, label %recurse

recurse:

12

太原科技大学学士学位论文

%tmp2 = sub i32 %a, 1 %tmp3 = add i32 %b, 1

%tmp4 = call i32 @add2(i32 %tmp2, i32 %tmp3) ret i32 %tmp4

done:

ret i32 %b }

这段LLVM IR对应如下的C代码,提供了两种不同的整型相加方式。

unsigned add1(unsigned a, unsigned b) { return a+b; }

// Perhaps not the most efficient way to add two numbers. unsigned add2(unsigned a, unsigned b) { if (a == 0) return b; return add2(a-1, b+1); }

除了实现为一个自我完备的语言外,LLVM IR实际上被定义为三种同构异形的形式:上面的文本格式(.ll文件),一个被优化检查或者修改的在内存的数据结构,和一个在高效的、密集的在磁盘的二进制“bitcode”格式。

LLVM IR是一种中间层次的程序表示方式,它独立于高级语言,没有描述高级语言里的特有的概念(比如,它没有表示或者说实现高级语言里面的访问控制),同时又能表示一些汇编(非常贴近于机器的表示方式)无法描述的概念(语义)。LLVM,Low Level Virtual Machine,之所以取这个名称,我想是因为LLVM能够在一个贴近于机器,但又独立目标平台的层次上,对程序进行各种分析或者优化。也即是说围绕这LLVM IR可以形成一个程序优化/分析/存储/传送的生态系统。这或许就是LLVM的优势所在。 3.3.2 LLVM对三段式设计的实现

传统静态编译器(比如大多C编译器)中普遍使用的设计方案是三段式设计,这种设计方案把编译器分成三个主要的模块,前端,优化器,和后端。前端对进行分析,检

13

太原科技大学学士学位论文

SelfAffectExprAST表示一个作用在自身的表达式,现在只有前增、前减、后增、后减。它有一个枚举类型的类型域,表示运算的操作码。它有两个数据域,一个操作码,一个是操作数。之所以把这种表达式和单目运算表达式区分开,是因为这种表达式的操作数必须是可赋值的,而且这种表达自身也是可赋值的。

class SelfAffectExprAST : public ExprAST { public:

enum OpcodeTy { PRE_INC, PRE_DEC, POST_INC, POST_DEC }; private:

OpcodeTy Opcode; ExprAST *Operand; public:

SelfAffectExprAST(OpcodeTy opcode, ExprAST *operand); virtual llvm::Value *codeGen(CodeGenContext &context); };

6. UnaryExprAST

UnaryExprAST表示一个单目运算的表达式,它有一个枚举类型的类型域,表示运算的操作码。它还有两个数据域,一个是操作码,一个是操作数。

class UnaryExprAST : public ExprAST { public:

enum OpcodeTy { PLUS = 0, MINUS = 1, NOT = 2 }; private:

OpcodeTy Opcode; ExprAST *Operand; public:

UnaryExprAST(OpcodeTy opcode, ExprAST *operand); virtual llvm::Value *codeGen(CodeGenContext &context);

39

太原科技大学学士学位论文

};

7. CastExprAST

CastExprAST表示一个造型(强转)表达式,它只有一个数据域,即它的操作数。目标类型用它自身的类型表示。

class CastExprAST : public ExprAST { ExprAST *Operand; public:

CastExprAST(TypeAST *ty, ExprAST *operand);

virtual llvm::Value *codeGen(CodeGenContext &context); };

8. BinaryExprAST

BinaryExprAST表示一个双目运算表达式,它有一个枚举类型域,表示运算的操作码。它还有三个数据域,一个是操作码,另外两个是操作数。BinaryExprAST是最大的表达式,包括加减乘除、逻辑与逻辑或、关系运算,所有的双目运算表达式。

class BinaryExprAST : public ExprAST { public:

enum OpcodeTy { ORL = 0, ANDL = 1, INCL_OR = 2, EXCL_OR = 3, BIN_AND = 4, EQ = 5, NE = 6, LT = 7, LE = 8, GT = 9, GE = 10, SHLL = 11, SHRL = 12, SHRA = 13, ADD = 14, SUB = 15, MUL = 16,

40

太原科技大学学士学位论文

DIV = 17, MOD = 18 }; private:

OpcodeTy Opcode; ExprAST *LHS, *RHS; public:

BinaryExprAST(TypeAST *ty, OpcodeTy opcode, ExprAST *lhs, ExprAST *rhs) ; // Generate LLVM IR

virtual llvm::Value *codeGen(CodeGenContext &context);

static llvm::Value *handleOrExpr(CodeGenContext &context, llvm::Value *lhs, llvm::Value *rhs);

static llvm::Value *handleAndExpr(CodeGenContext &context, llvm::Value *lhs, llvm::Value *rhs); // Get ConstantValue.

virtual ConstantValue getConstantValue(); ConstantValue computeConstantValue(); };

9. CallExprAST

CallExprAST表示一个调用表达式,它有两个数据域,一个是被调用函数的标识符,一个是实参列表,用一个表达式序列表示(ArgListType是vector的typedef)。

class CallExprAST : public ExprAST { IdentifierAST *Id; ArgListType *ArgList; public:

CallExprAST(IdentifierAST *id, ArgListType *argList); // Generate LLVM IR

virtual llvm::Value *codeGen(CodeGenContext &context); // Accessor methods.

std::string getFunctionName();

FunctionTypeAST *getFunctionType(); ArgListType *getArgList(); };

10. AssignExprAST

AssignExprAST表示一个赋值表达式,它有一个枚举类型的类型域,表示赋值表达式的操作码。它还有三个数据域,一个是赋值的目的表达式,一个是操作码,一个是赋

41

太原科技大学学士学位论文

值的源表达式。

class AssignExprAST : public ExprAST { public:

enum OpcodeTy { ASSIGN = 0,

MUL_ASSIGN = 1, DIV_ASSIGN = 2, MOD_ASSIGN = 3, ADD_ASSIGN = 4, SUB_ASSIGN = 5, SHLL_ASSIGN = 6, SHRL_ASSIGN = 7, SHRA_ASSIGN = 8, ANDB_ASSIGN = 9, ORB_ASSIGN = 10, XORB_ASSIGN = 11 }; private:

ExprAST *Dest; OpcodeTy Opcode; ExprAST *Operand; public:

AssignExprAST(ExprAST *dest, OpcodeTy opcode, ExprAST *operand); virtual llvm::Value *codeGen(CodeGenContext &context); };

5.1.4 语句 1. StatementAST

StatementAST是所有语句的公共基类,它是一个虚基类,只能通过它的子类的实例化。它的方法包括虚析构函数、中间代码生成函数、和一个用于检查基本块中是否有终结指令的方法。

class StatementAST : public NodeAST { public:

virtual ~StatementAST() {}

virtual llvm::Value *codeGen(CodeGenContext &context) = 0;

42

太原科技大学学士学位论文

bool checkTerminator(CodeGenContext &context); };

2. ExprStatementAST

ExprStatementAST表示一个表达式语句,它有一个数据域,一个表达式序列(ExprListType是vector的typedef)。

class ExprStatementAST : public StatementAST { ExprListType *ExprList; public:

ExprStatementAST(ExprListType *exprList);

virtual llvm::Instruction *codeGen(CodeGenContext &context); };

3. IfStatementAST

IfStatementAST表示一个if语句,它有两个数据域,一个是条件表达式,一个是条件为真时执行的语句。

class IfStatementAST : public StatementAST { ExprAST *Cond;

StatementAST *TrueStmt; public:

IfStatementAST(ExprAST *cond, StatementAST *trueStmt); virtual llvm::Value *codeGen(CodeGenContext &context); };

4. ElseStatementAST

ElseStatementAST表示一个if-else语句,它有三个数据域,一个条件表达式,一个条件为真时执行的语句,一个条件为假时执行的语句。

class ElseStatementAST : public StatementAST { ExprAST *Cond;

StatementAST *TrueStmt, *FalseStmt; public:

ElseStatementAST(ExprAST *cond, StatementAST *trueStmt, StatementAST *falseStmt); virtual llvm::Value *codeGen(CodeGenContext &context);

43

百度搜索“yundocx”或“云文档网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,云文档网,提供经典综合文库基于LLVM的编译器的设计与实现在线全文阅读。

基于LLVM的编译器的设计与实现.doc 将本文的Word文档下载到电脑,方便复制、编辑、收藏和打印 下载失败或者文档不完整,请联系客服人员解决!
本文链接:https://www.yundocx.com/wenku/181915.html(转载请注明文章来源)
Copyright © 2018-2022 云文档网 版权所有
声明 :本网站尊重并保护知识产权,根据《信息网络传播权保护条例》,如果我们转载的作品侵犯了您的权利,请在一个月内通知我们,我们会及时删除。
客服QQ:370150219 邮箱:370150219@qq.com
苏ICP备19068818号-2
Top
× 游客快捷下载通道(下载后可以自由复制和排版)
单篇付费下载
限时特价:7 元/份 原价:20元
VIP包月下载
特价:29 元/月 原价:99元
低至 0.3 元/份 每月下载150
全站内容免费自由复制
VIP包月下载
特价:29 元/月 原价:99元
低至 0.3 元/份 每月下载150
全站内容免费自由复制
注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信:xuecool-com QQ:370150219