Chapter 2
如第一章所述,如果我们有了一个parser,接下来需要做的是利用这个parser构建出抽象语法树(Abstract Syntax Tree, AST)。
parser利用递归下降分析法(Recursive Descent Parsing)和算符优先分析法(Operator Precedence Parsing)来解析Kaleidoscope语言,其中算符优先分析法用于解析二元表达式(binary expression)。
The Abstract Syntax Tree
抽象语法树为编译器的后续部分(例如代码生成)提供了基础。在Kaleidoscope语言中,我们可以将语法划分为以下几类:表达式(expression),原型(prototype)和函数(function)。
表达式的AST如下所示:
/// ExprAST - Base class for all expression nodes.
class ExprAST {
public:
virtual ~ExprAST() {}
};
/// NumberExprAST - Expression class for numeric literals like "1.0".
class NumberExprAST : public ExprAST {
double Val;
public:
NumberExprAST(double Val) : Val(Val) {}
};
数字表达式的AST存储了数字语义上的数值,供编译器后续分析、优化使用。
以下为Kaleidoscope语言的其它种类的AST。
/// VariableExprAST - Expression class for referencing a variable, like "a".
class VariableExprAST : public ExprAST {
std::string Name;
public:
VariableExprAST(const std::string &Name) : Name(Name) {}
};
/// BinaryExprAST - Expression class for a binary operator.
class BinaryExprAST : public ExprAST {
char Op;
std::unique_ptr<ExprAST> LHS, RHS;
public:
BinaryExprAST(char op, std::unique_ptr<ExprAST> LHS,
std::unique_ptr<ExprAST> RHS)
: Op(op), LHS(std::move(LHS)), RHS(std::move(RHS)) {}
};
/// CallExprAST - Expression class for function calls.
class CallExprAST : public ExprAST {
std::string Callee;
std::vector<std::unique_ptr<ExprAST>> Args;
public:
CallExprAST(const std::string &Callee,
std::vector<std::unique_ptr<ExprAST>> Args)
: Callee(Callee), Args(std::move(Args)) {}
};
在上面的代码中,prototype表达式存储了变量名,而二元表达式存储了二元操作符(例如加号’+’)以及它的参数列表。由于我们的语言不包含条件控制流,因此它不是图灵完备的,后续我们将修正这个问题。
/// PrototypeAST - This class represents the "prototype" for a function,
/// which captures its name, and its argument names (thus implicitly the number
/// of arguments the function takes).
class PrototypeAST {
std::string Name;
std::vector<std::string> Args;
public:
PrototypeAST(const std::string &name, std::vector<std::string> Args)
: Name(name), Args(std::move(Args)) {}
const std::string &getName() const { return Name; }
};
/// FunctionAST - This class represents a function definition itself.
class FunctionAST {
std::unique_ptr<PrototypeAST> Proto;
std::unique_ptr<ExprAST> Body;
public:
FunctionAST(std::unique_ptr<PrototypeAST> Proto,
std::unique_ptr<ExprAST> Body)
: Proto(std::move(Proto)), Body(std::move(Body)) {}
};