llvm 词法解析器


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”,“#”等,但对代码运行时的一些字符比如运算符不做处理。
至此,一个简单的词法解析器完成。


Author: x-codingman
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source x-codingman !
  TOC