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
class PrototypeAST {
std::string Name;
std::vector<std::string> Args;
- bool isOperator;
+ bool IsOperator;
unsigned Precedence; // Precedence if a binary op.
+
public:
- PrototypeAST(const std::string &name, const std::vector<std::string> &args,
- bool isoperator = false, unsigned prec = 0)
- : Name(name), Args(args), isOperator(isoperator), Precedence(prec) {}
+ PrototypeAST(const std::string &name, std::vector<std::string> Args,
+ bool IsOperator = false, unsigned Prec = 0)
+ : Name(name), Args(std::move(Args)), IsOperator(IsOperator),
+ Precedence(Prec) {}
- bool isUnaryOp() const { return isOperator && Args.size() == 1; }
- bool isBinaryOp() const { return isOperator && Args.size() == 2; }
+ bool isUnaryOp() const { return IsOperator && Args.size() == 1; }
+ bool isBinaryOp() const { return IsOperator && Args.size() == 2; }
char getOperatorName() const {
assert(isUnaryOp() || isBinaryOp());
unsigned getBinaryPrecedence() const { return Precedence; }
- Function *Codegen();
+ Function *codegen();
};
Basically, in addition to knowing a name for the prototype, we now keep
/// prototype
/// ::= id '(' id* ')'
/// ::= binary LETTER number? (id, id)
- static PrototypeAST *ParsePrototype() {
+ static std::unique_ptr<PrototypeAST> ParsePrototype() {
std::string FnName;
unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary.
if (Kind && ArgNames.size() != Kind)
return ErrorP("Invalid number of operands for operator");
- return new PrototypeAST(FnName, 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
/// UnaryExprAST - Expression class for a unary operator.
class UnaryExprAST : public ExprAST {
char Opcode;
- ExprAST *Operand;
+ std::unique_ptr<ExprAST> Operand;
+
public:
- UnaryExprAST(char opcode, ExprAST *operand)
- : Opcode(opcode), Operand(operand) {}
- virtual Value *Codegen();
+ UnaryExprAST(char Opcode, std::unique_ptr<ExprAST> Operand)
+ : Opcode(Opcode), Operand(std::move(Operand)) {}
+ virtual Value *codegen();
};
This AST node is very simple and obvious by now. It directly mirrors the
/// unary
/// ::= primary
/// ::= '!' unary
- static ExprAST *ParseUnary() {
+ static std::unique_ptr<ExprAST> ParseUnary() {
// If the current token is not an operator, it must be a primary expr.
if (!isascii(CurTok) || CurTok == '(' || CurTok == ',')
return ParsePrimary();
// If this is a unary operator, read it.
int Opc = CurTok;
getNextToken();
- if (ExprAST *Operand = ParseUnary())
- return new UnaryExprAST(Opc, Operand);
- return 0;
+ if (auto Operand = ParseUnary())
+ return llvm::unique_ptr<UnaryExprAST>(Opc, std::move(Operand));
+ return nullptr;
}
The grammar we add is pretty straightforward here. If we see a unary
/// binoprhs
/// ::= ('+' unary)*
- static ExprAST *ParseBinOpRHS(int ExprPrec, ExprAST *LHS) {
+ static std::unique_ptr<ExprAST> ParseBinOpRHS(int ExprPrec,
+ std::unique_ptr<ExprAST> LHS) {
...
// Parse the unary expression after the binary operator.
- ExprAST *RHS = ParseUnary();
- if (!RHS) return 0;
+ auto RHS = ParseUnary();
+ if (!RHS)
+ return nullptr;
...
}
/// expression
/// ::= unary binoprhs
///
- static ExprAST *ParseExpression() {
- ExprAST *LHS = ParseUnary();
- if (!LHS) return 0;
+ static std::unique_ptr<ExprAST> ParseExpression() {
+ auto LHS = ParseUnary();
+ if (!LHS)
+ return nullptr;
- return ParseBinOpRHS(0, LHS);
+ return ParseBinOpRHS(0, std::move(LHS));
}
With these two simple changes, we are now able to parse unary operators
/// ::= id '(' id* ')'
/// ::= binary LETTER number? (id, id)
/// ::= unary LETTER (id)
- static PrototypeAST *ParsePrototype() {
+ static std::unique_ptr<PrototypeAST> ParsePrototype() {
std::string FnName;
unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary.
.. 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");
.. code-block:: bash
# Compile
- clang++ -g toy.cpp `llvm-config --cppflags --ldflags --libs core jit native` -O3 -o toy
+ clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core mcjit native` -O3 -o toy
# Run
./toy