this as a way to show some interesting parsing techniques.
At the end of this tutorial, we'll run through an example Kaleidoscope
-application that `renders the Mandelbrot set <#example>`_. This gives an
+application that `renders the Mandelbrot set <#kicking-the-tires>`_. This gives an
example of what you can build with Kaleidoscope and its feature set.
User-defined Operators: the Idea
enum Token {
...
// operators
- tok_binary = -11, tok_unary = -12
+ tok_binary = -11,
+ tok_unary = -12
};
...
static int gettok() {
...
- if (IdentifierStr == "for") return tok_for;
- if (IdentifierStr == "in") return tok_in;
- if (IdentifierStr == "binary") return tok_binary;
- if (IdentifierStr == "unary") return tok_unary;
+ if (IdentifierStr == "for")
+ return tok_for;
+ if (IdentifierStr == "in")
+ return tok_in;
+ if (IdentifierStr == "binary")
+ return tok_binary;
+ if (IdentifierStr == "unary")
+ return tok_unary;
return tok_identifier;
This just adds lexer support for the unary and binary keywords, like we
-did in `previous chapters <LangImpl5.html#iflexer>`_. One nice thing
+did in `previous chapters <LangImpl5.html#lexer-extensions-for-if-then-else>`_. One nice thing
about our current AST, is that we represent binary operators with full
generalisation by using their ASCII code as the opcode. For our extended
operators, we'll use this same representation, so we don't need any new
std::vector<std::string> Args;
bool IsOperator;
unsigned Precedence; // Precedence if a binary op.
+
public:
PrototypeAST(const std::string &name, std::vector<std::string> Args,
bool IsOperator = false, unsigned Prec = 0)
unsigned getBinaryPrecedence() const { return Precedence; }
- Function *Codegen();
+ Function *codegen();
};
Basically, in addition to knowing a name for the prototype, we now keep
if (Kind && ArgNames.size() != Kind)
return ErrorP("Invalid number of operands for operator");
- return llvm::make_unique<PrototypeAST>(FnName, std::move(ArgNames),
- Kind != 0, BinaryPrecedence);
+ return llvm::make_unique<PrototypeAST>(FnName, std::move(ArgNames), Kind != 0,
+ BinaryPrecedence);
}
This is all fairly straightforward parsing code, and we have already
.. code-block:: c++
- Value *BinaryExprAST::Codegen() {
- Value *L = LHS->Codegen();
- Value *R = RHS->Codegen();
- if (L == 0 || R == 0) return 0;
+ Value *BinaryExprAST::codegen() {
+ Value *L = LHS->codegen();
+ Value *R = RHS->codegen();
+ if (!L || !R)
+ return nullptr;
switch (Op) {
- case '+': return Builder.CreateFAdd(L, R, "addtmp");
- case '-': return Builder.CreateFSub(L, R, "subtmp");
- case '*': return Builder.CreateFMul(L, R, "multmp");
+ case '+':
+ return Builder.CreateFAdd(L, R, "addtmp");
+ case '-':
+ return Builder.CreateFSub(L, R, "subtmp");
+ case '*':
+ return Builder.CreateFMul(L, R, "multmp");
case '<':
L = Builder.CreateFCmpULT(L, R, "cmptmp");
// Convert bool 0/1 to double 0.0 or 1.0
return Builder.CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()),
"booltmp");
- default: break;
+ default:
+ break;
}
// If it wasn't a builtin binary operator, it must be a user defined one. Emit
// a call to it.
- Function *F = TheModule->getFunction(std::string("binary")+Op);
+ Function *F = TheModule->getFunction(std::string("binary") + Op);
assert(F && "binary operator not found!");
Value *Ops[2] = { L, R };
.. code-block:: c++
- Function *FunctionAST::Codegen() {
+ Function *FunctionAST::codegen() {
NamedValues.clear();
- Function *TheFunction = Proto->Codegen();
- if (TheFunction == 0)
- return 0;
+ Function *TheFunction = Proto->codegen();
+ if (!TheFunction)
+ return nullptr;
// If this is an operator, install it.
if (Proto->isBinaryOp())
BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction);
Builder.SetInsertPoint(BB);
- if (Value *RetVal = Body->Codegen()) {
+ if (Value *RetVal = Body->codegen()) {
...
Basically, before codegening a function, if it is a user-defined
class UnaryExprAST : public ExprAST {
char Opcode;
std::unique_ptr<ExprAST> Operand;
+
public:
UnaryExprAST(char Opcode, std::unique_ptr<ExprAST> Operand)
: Opcode(Opcode), Operand(std::move(Operand)) {}
- virtual Value *Codegen();
+ virtual Value *codegen();
};
This AST node is very simple and obvious by now. It directly mirrors the
...
// Parse the unary expression after the binary operator.
auto RHS = ParseUnary();
- if (!RHS) return nullptr;
+ if (!RHS)
+ return nullptr;
...
}
/// expression
///
static std::unique_ptr<ExprAST> ParseExpression() {
auto LHS = ParseUnary();
- if (!LHS) return nullptr;
+ if (!LHS)
+ return nullptr;
return ParseBinOpRHS(0, std::move(LHS));
}
.. code-block:: c++
- Value *UnaryExprAST::Codegen() {
- Value *OperandV = Operand->Codegen();
- if (OperandV == 0) return 0;
+ Value *UnaryExprAST::codegen() {
+ Value *OperandV = Operand->codegen();
+ if (!OperandV)
+ return nullptr;
Function *F = TheModule->getFunction(std::string("unary")+Opcode);
- if (F == 0)
+ if (!F)
return ErrorV("Unknown unary operator");
return Builder.CreateCall(F, OperandV, "unop");