目录:
[LLVM教程]LLVM之第一个语言前端
[LLVM教程]LLVM之第一个语言前端/“万花筒”:介绍与词法分析器
LLVM Tutorial: Table of Contents — LLVM 17.0.0git documentation
[LLVM]自制脚本语言实践
编译原理学习笔记
"万花筒"语言
本教程以一种称为“万花筒”的玩具语言为例。万花筒是一种过程语言,它允许我们定义函数、使用条件、数学运算等。通过本教程的课程,我们将扩展万花筒以支持“if/then/else”、“for”循环、用户自定义操作符、拥有一个简易命令行接口的即时编译、调试信息等。
我们希望尽可能保持简单,所以万花筒中唯一的数据类型是双精度浮点类型(C中称作double)。因此,所有值都隐式是双精度浮点类型,且语言不需要类型声明。这使得语言拥有一个非常不错且简单的语法。例如,下面简单示例如何计算斐波那契:
# Compute the x'th fibonacci number.
def fib(x)
if x < 3 then
1
else
fib(x-1)+fib(x-2)
# This expression will compute the 40th number.
fib(40)
同时,我们允许万花筒调用标准库函数——LLVM JIT使这变得非常简单。这意味这我们可以使用’extern’关键字来定义一个函数(这对于递归调用也有用)。例如:
extern sin(arg);
extern cos(arg);
extern atan2(arg1 arg2);
atan2(sin(.4), cos(43))
一个更有趣的示例在第六章,我们编写了一个万花筒程序,它以不同的放大率显示曼德勃罗集。
让我们开始实现该语言吧!
词法分析器
要实现一个语言,第一件事就是要有能力能够处理文本文件并识别其内容。传统方法就是使用一个“词法分析器”(“扫描器”)将输入分解为词素(token)。词法分析器返回的每个词素都包括一个码和一些元数据(例如数字的数值)。首先,我们定义所有可能性:
// 预定义token类型,如果字符不属于以下类型则用[0-255]表示其token
enum Token {
tok_eof = -1,
// 命令
tok_def = -2,
tok_extern = -3,
//
tok_identifier = -4,
tok_number = -5,
};
static std::string IdentifierStr; // 如果是标识符则保存这里
static double NumVal; // 如果是数字则保存这里
我们的词法分析器会返回token枚举中的一个,或未知字符的ascii码,例如’+'。如果是标识符,则保存其名称到全局变量IdentifierStr,如果是数字,则保存其值到全局变量NumVal。真正实现一个语言的话还是不要用全局变量的好。
词法分析器实际的实现是一个简单的函数gettok。该函数从标准输入读取字符并返回token,定义如下:
/// gettok - 从标准输入读取字符并返回token
static int gettok() {
static int LastChar = ' ';
// 跳过所有空格
while (isspace(LastChar))
LastChar = getchar();
gettok通过调用getchar()函数从标准输入一次读出一个字符,并跳过token中间的空格符。如上所示。
然后gettok识别标识符和关键词:
if (isalpha(LastChar)) { // 标识符: [a-zA-Z][a-zA-Z0-9]*
IdentifierStr = LastChar;
while (isalnum((LastChar = getchar())))
IdentifierStr += LastChar;
if (IdentifierStr == "def")
return tok_def;
if (IdentifierStr == "extern")
return tok_extern;
return tok_identifier;
}
感觉没有理论基础加持,看不下去了,想先学理论,不想翻译了,后续:
[LLVM]自制脚本语言实践