LLVM简介
LLVM项目是一款模块化并且可重用的编译器和工具链LLVM是一套编译器基础设施项目,为自由软件,以C++写成,包含一系列模块化的编译器组件和工具链,用来开发编译器前端和后端。它是为了任意一种编程语言而写成的程序,利用虚拟技术创造出编译时期、链接时期、运行时期以及“闲置时期”的优化。
本文参考LLVM官方教程,介绍如何用LLVM为一个简单的语言编写一个解析器(准确来说称为前端)
Kaleidoscpe
我们的语言称为“Kaleidoscope”,以下是该语言一个简单的例子:
# Compute the x'th fibonacci number
def fib(x)
if x< 3 then
1
else
fib(x-1)+fib(x-2)
# This experssion will cmpute the 40th number.
fib(40)
为了使以上语言能够运行起来,我们的前端需要两个部分:词法解析器以及语法解析器。
词法解析器(Lexer)
词法解析器用C++编写,它的目的是对代码文件进行扫描,将文件中的字符
以及关键字
做简单的解析,并以token的形式进行存储。
// The lexer returns tokens [0-255] if it is an unknown character, otherwise one
// of these for known things.
enum Token {
tok_eof = -1,
// commands
tok_def = -2,
tok_extern = -3,
// primary
tok_identifier = -4,
tok_number = -5,
};
static std::string IdentifierStr; // Filled in if tok_identifier
static double NumVal; // Filled in if tok_number
以上代码给出了token的几种形式,文件中的字符可能是文件终止符EOF,也可能是声明语句def或者extern。如果lexer遇到一句赋值语句(如x=30),则x为一个变量的标识符(tok_identifier),而30为一个数值(tok_number)。
确定token的形式后,我们先编写一个对文件字符的扫描器,对字符进行读取。
/// gettok - Return the next token from standard input.
static int gettok() {
static int LastChar = ' ';
// Skip any whitespace.
while (isspace(LastChar))
LastChar = getchar();
之后对字符进行识别,返回不同的token。如果字符不属于定于的token范围(比如“+”运算符),则直接返回该字符的ascii码。
if (isalpha(LastChar)) { // identifier: [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;
}
// Indentifier numeric values
if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+
std::string NumStr;
do {
NumStr += LastChar;
LastChar = getchar();
} while (isdigit(LastChar) || LastChar == '.');
NumVal = strtod(NumStr.c_str(), 0);
return tok_number;
}
// Handler comments
if (LastChar == '#') {
// Comment until end of line.
do
LastChar = getchar();
while (LastChar != EOF && LastChar != '\n' && LastChar != '\r');
if (LastChar != EOF)
return gettok();
}
// Check for end of file. Don't eat the EOF.
if (LastChar == EOF)
return tok_eof;
// Otherwise, just return the character as its ascii value.
int ThisChar = LastChar;
LastChar = getchar();
return ThisChar;
}
可以发现,token处理一些代码中的预处理字符,比如“extern”,“def”,“#”等,但对代码运行时的一些字符比如运算符不做处理。
至此,一个简单的词法解析器完成。