// 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) classPrototypeAST { std::string Name; std::vector<std::string> Args;
// FunctionAST - This class represents a function definition itself classFunctionAST { 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)) {} };
注意, 在 Kaleidoscope 中,函数原型和函数定义并不是表达式, 所以没有继承 class ExprAST. 由于在 Kaleidoscope 中只有 double 类型, 所以函数的类型也仅仅和参数数量有关. 在更为复杂的语言中, class ExprAST 会有一个 field 专门存放类型信息.
Parser Basics
我们需要使用一个 parser 来构造 AST. 例如, 我们想解析 x + y 这类的表达式, 并生成一个 AST 时, 我们可以进行如下的操作:
1 2 3
auto LHS = std::make_unique<VariableExprAST>("x"); auto RHS = std::make_unique<VariableExprAST>("y"); auto Result = std::make_unique<BinaryExprAST>('+', std::move(LHS), std::move(RHS));
为了实现上述操作, 我们先定义一些基本的辅助过程:
1 2 3 4 5 6
// CurTok - CurTok is the current token the parser is looking at. staticint CurTok; // getNextToken - getNextToken reads another token from the lexer and update CurTok with its values. intgetNextToken(){ return CurTok = gettok(); }
// numberexpr ::= number std::unique_ptr<ExprAST> ParseNumberExpr(){ auto Result = std::make_unique<NumberExprAST> (NumVal); // consume the number getNextToken(); return std::move(Result); }
// binOpRHS // :: = ( binOp primary)* std::unique_ptr<ExprAST> ParseBinOpRHS(int ExprPrec, std::unique_ptr<ExprAST> LHS) { // if this is a binOp, find its precedence while (1) { int TokPrec = GetTokPrecedence();
// if this is a binOp that binds at least // as tightly as the current binOP, // consume it, otherwise we are done. if (TokPrec < ExprPrec) { return LHS; }
// we know it's a binOP int BinOp = CurTok; // eat binOp getNextToken();
// parse the primary expression after the binOP. auto RHS = ParsePrimary(); if (!RHS) { returnnullptr; }
// If binOP binds less tightly with RHS than the // operator after RHS, let the pending operator take // RHS and its LHS int NextPrec = GetTokPrecedence(); if (TokPrec < NextPrec) { // a + b * c -> a + (b * c) RHS = ParseBinOpRHS(TokPrec + 1, std::move(RHS)); if (!RHS) { returnnullptr; } }
// a + b + c -> (a + b) + c LHS = std::make_unique<BinaryExprAST>(BinOp, std::move(LHS), std::move(RHS));
// prototype // :: = id '(' id* ')' std::unique_ptr<PrototypeAST> ParsePrototype(){ if (CurTok != tok_identifier) { returnLogErrorP("Expected function name in prototype"); }
std::string FnName = IdentifierStr; // eat the function name getNextToken();
if (CurTok != '(') { returnLogErrorP("Expected '(' in prototype"); }
// feed the arg list into vector std::vector<std::string> ArgNames; while (getNextToken() == tok_identifier) { ArgNames.push_back(IdentifierStr); }
if (CurTok != ')') returnLogErrorP("Expected ')' in prototype");
// toplevelexpr // :: = expression std::unique_ptr<FunctionAST> ParseTopLevelExpr(){ if (auto E = ParseExpression()) { // anonymous nullary function auto Proto = std::make_unique<PrototypeAST>("", std::vector<std::string>());