summaryrefslogtreecommitdiffstats
path: root/llvm/docs/tutorial/LangImpl06.rst
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/docs/tutorial/LangImpl06.rst')
-rw-r--r--llvm/docs/tutorial/LangImpl06.rst64
1 files changed, 32 insertions, 32 deletions
diff --git a/llvm/docs/tutorial/LangImpl06.rst b/llvm/docs/tutorial/LangImpl06.rst
index f6d2bd943ef..c1035bce855 100644
--- a/llvm/docs/tutorial/LangImpl06.rst
+++ b/llvm/docs/tutorial/LangImpl06.rst
@@ -31,7 +31,7 @@ User-defined Operators: the Idea
================================
The "operator overloading" that we will add to Kaleidoscope is more
-general than languages like C++. In C++, you are only allowed to
+general than in languages like C++. In C++, you are only allowed to
redefine existing operators: you can't programmatically change the
grammar, introduce new operators, change precedence levels, etc. In this
chapter, we will add this capability to Kaleidoscope, which will let the
@@ -41,8 +41,8 @@ The point of going into user-defined operators in a tutorial like this
is to show the power and flexibility of using a hand-written parser.
Thus far, the parser we have been implementing uses recursive descent
for most parts of the grammar and operator precedence parsing for the
-expressions. See `Chapter 2 <LangImpl2.html>`_ for details. Without
-using operator precedence parsing, it would be very difficult to allow
+expressions. See `Chapter 2 <LangImpl2.html>`_ for details. By
+using operator precedence parsing, it is very easy to allow
the programmer to introduce new operators into the grammar: the grammar
is dynamically extensible as the JIT runs.
@@ -143,17 +143,18 @@ this:
: Name(name), Args(std::move(Args)), IsOperator(IsOperator),
Precedence(Prec) {}
+ Function *codegen();
+ const std::string &getName() const { return Name; }
+
bool isUnaryOp() const { return IsOperator && Args.size() == 1; }
bool isBinaryOp() const { return IsOperator && Args.size() == 2; }
char getOperatorName() const {
assert(isUnaryOp() || isBinaryOp());
- return Name[Name.size()-1];
+ return Name[Name.size() - 1];
}
unsigned getBinaryPrecedence() const { return Precedence; }
-
- Function *codegen();
};
Basically, in addition to knowing a name for the prototype, we now keep
@@ -194,7 +195,7 @@ user-defined operator, we need to parse it:
// Read the precedence if present.
if (CurTok == tok_number) {
if (NumVal < 1 || NumVal > 100)
- return LogErrorP("Invalid precedecnce: must be 1..100");
+ return LogErrorP("Invalid precedence: must be 1..100");
BinaryPrecedence = (unsigned)NumVal;
getNextToken();
}
@@ -225,7 +226,7 @@ This is all fairly straightforward parsing code, and we have already
seen a lot of similar code in the past. One interesting part about the
code above is the couple lines that set up ``FnName`` for binary
operators. This builds names like "binary@" for a newly defined "@"
-operator. This then takes advantage of the fact that symbol names in the
+operator. It then takes advantage of the fact that symbol names in the
LLVM symbol table are allowed to have any character in them, including
embedded nul characters.
@@ -251,7 +252,7 @@ default case for our existing binary operator node:
case '<':
L = Builder.CreateFCmpULT(L, R, "cmptmp");
// Convert bool 0/1 to double 0.0 or 1.0
- return Builder.CreateUIToFP(L, Type::getDoubleTy(LLVMContext),
+ return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext),
"booltmp");
default:
break;
@@ -259,7 +260,7 @@ default case for our existing binary operator node:
// 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 = getFunction(std::string("binary") + Op);
assert(F && "binary operator not found!");
Value *Ops[2] = { L, R };
@@ -277,22 +278,21 @@ The final piece of code we are missing, is a bit of top-level magic:
.. code-block:: c++
Function *FunctionAST::codegen() {
- NamedValues.clear();
-
- Function *TheFunction = Proto->codegen();
+ // Transfer ownership of the prototype to the FunctionProtos map, but keep a
+ // reference to it for use below.
+ auto &P = *Proto;
+ FunctionProtos[Proto->getName()] = std::move(Proto);
+ Function *TheFunction = getFunction(P.getName());
if (!TheFunction)
return nullptr;
// If this is an operator, install it.
- if (Proto->isBinaryOp())
- BinopPrecedence[Proto->getOperatorName()] = Proto->getBinaryPrecedence();
+ if (P.isBinaryOp())
+ BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence();
// Create a new basic block to start insertion into.
- BasicBlock *BB = BasicBlock::Create(LLVMContext, "entry", TheFunction);
- Builder.SetInsertPoint(BB);
-
- if (Value *RetVal = Body->codegen()) {
- ...
+ BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction);
+ ...
Basically, before codegening a function, if it is a user-defined
operator, we register it in the precedence table. This allows the binary
@@ -323,7 +323,8 @@ that, we need an AST node:
public:
UnaryExprAST(char Opcode, std::unique_ptr<ExprAST> Operand)
: Opcode(Opcode), Operand(std::move(Operand)) {}
- virtual Value *codegen();
+
+ Value *codegen() override;
};
This AST node is very simple and obvious by now. It directly mirrors the
@@ -345,7 +346,7 @@ simple: we'll add a new function to do it:
int Opc = CurTok;
getNextToken();
if (auto Operand = ParseUnary())
- return llvm::unique_ptr<UnaryExprAST>(Opc, std::move(Operand));
+ return llvm::make_unique<UnaryExprAST>(Opc, std::move(Operand));
return nullptr;
}
@@ -433,7 +434,7 @@ unary operators. It looks like this:
if (!OperandV)
return nullptr;
- Function *F = TheModule->getFunction(std::string("unary")+Opcode);
+ Function *F = getFunction(std::string("unary") + Opcode);
if (!F)
return LogErrorV("Unknown unary operator");
@@ -461,7 +462,7 @@ newline):
declare double @printd(double)
ready> def binary : 1 (x y) 0; # Low-precedence operator that ignores operands.
- ..
+ ...
ready> printd(123) : printd(456) : printd(789);
123.000000
456.000000
@@ -518,10 +519,9 @@ denser the character:
::
- ready>
-
- extern putchard(char)
- def printdensity(d)
+ ready> extern putchard(char);
+ ...
+ ready> def printdensity(d)
if d > 8 then
putchard(32) # ' '
else if d > 4 then
@@ -538,9 +538,9 @@ denser the character:
Evaluated to 0.000000
Based on these simple primitive operations, we can start to define more
-interesting things. For example, here's a little function that solves
-for the number of iterations it takes a function in the complex plane to
-converge:
+interesting things. For example, here's a little function that determines
+the number of iterations it takes for a certain function in the complex
+plane to diverge:
::
@@ -742,7 +742,7 @@ Full Code Listing
=================
Here is the complete code listing for our running example, enhanced with
-the if/then/else and for expressions.. To build this example, use:
+the support for user-defined operators. To build this example, use:
.. code-block:: bash
OpenPOWER on IntegriCloud