annotate llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl06.rst @ 266:00f31e85ec16 default tip

Added tag current for changeset 31d058e83c98
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Sat, 14 Oct 2023 10:13:55 +0900
parents 1f2b6ac9f198
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 ============================================================
anatofuz
parents:
diff changeset
2 Kaleidoscope: Extending the Language: User-defined Operators
anatofuz
parents:
diff changeset
3 ============================================================
anatofuz
parents:
diff changeset
4
anatofuz
parents:
diff changeset
5 .. contents::
anatofuz
parents:
diff changeset
6 :local:
anatofuz
parents:
diff changeset
7
anatofuz
parents:
diff changeset
8 Chapter 6 Introduction
anatofuz
parents:
diff changeset
9 ======================
anatofuz
parents:
diff changeset
10
anatofuz
parents:
diff changeset
11 Welcome to Chapter 6 of the "`Implementing a language with
anatofuz
parents:
diff changeset
12 LLVM <index.html>`_" tutorial. At this point in our tutorial, we now
anatofuz
parents:
diff changeset
13 have a fully functional language that is fairly minimal, but also
anatofuz
parents:
diff changeset
14 useful. There is still one big problem with it, however. Our language
anatofuz
parents:
diff changeset
15 doesn't have many useful operators (like division, logical negation, or
anatofuz
parents:
diff changeset
16 even any comparisons besides less-than).
anatofuz
parents:
diff changeset
17
anatofuz
parents:
diff changeset
18 This chapter of the tutorial takes a wild digression into adding
anatofuz
parents:
diff changeset
19 user-defined operators to the simple and beautiful Kaleidoscope
anatofuz
parents:
diff changeset
20 language. This digression now gives us a simple and ugly language in
anatofuz
parents:
diff changeset
21 some ways, but also a powerful one at the same time. One of the great
anatofuz
parents:
diff changeset
22 things about creating your own language is that you get to decide what
anatofuz
parents:
diff changeset
23 is good or bad. In this tutorial we'll assume that it is okay to use
anatofuz
parents:
diff changeset
24 this as a way to show some interesting parsing techniques.
anatofuz
parents:
diff changeset
25
anatofuz
parents:
diff changeset
26 At the end of this tutorial, we'll run through an example Kaleidoscope
anatofuz
parents:
diff changeset
27 application that `renders the Mandelbrot set <#kicking-the-tires>`_. This gives an
anatofuz
parents:
diff changeset
28 example of what you can build with Kaleidoscope and its feature set.
anatofuz
parents:
diff changeset
29
anatofuz
parents:
diff changeset
30 User-defined Operators: the Idea
anatofuz
parents:
diff changeset
31 ================================
anatofuz
parents:
diff changeset
32
anatofuz
parents:
diff changeset
33 The "operator overloading" that we will add to Kaleidoscope is more
anatofuz
parents:
diff changeset
34 general than in languages like C++. In C++, you are only allowed to
anatofuz
parents:
diff changeset
35 redefine existing operators: you can't programmatically change the
anatofuz
parents:
diff changeset
36 grammar, introduce new operators, change precedence levels, etc. In this
anatofuz
parents:
diff changeset
37 chapter, we will add this capability to Kaleidoscope, which will let the
anatofuz
parents:
diff changeset
38 user round out the set of operators that are supported.
anatofuz
parents:
diff changeset
39
anatofuz
parents:
diff changeset
40 The point of going into user-defined operators in a tutorial like this
anatofuz
parents:
diff changeset
41 is to show the power and flexibility of using a hand-written parser.
anatofuz
parents:
diff changeset
42 Thus far, the parser we have been implementing uses recursive descent
anatofuz
parents:
diff changeset
43 for most parts of the grammar and operator precedence parsing for the
anatofuz
parents:
diff changeset
44 expressions. See `Chapter 2 <LangImpl02.html>`_ for details. By
anatofuz
parents:
diff changeset
45 using operator precedence parsing, it is very easy to allow
anatofuz
parents:
diff changeset
46 the programmer to introduce new operators into the grammar: the grammar
anatofuz
parents:
diff changeset
47 is dynamically extensible as the JIT runs.
anatofuz
parents:
diff changeset
48
anatofuz
parents:
diff changeset
49 The two specific features we'll add are programmable unary operators
anatofuz
parents:
diff changeset
50 (right now, Kaleidoscope has no unary operators at all) as well as
anatofuz
parents:
diff changeset
51 binary operators. An example of this is:
anatofuz
parents:
diff changeset
52
anatofuz
parents:
diff changeset
53 ::
anatofuz
parents:
diff changeset
54
anatofuz
parents:
diff changeset
55 # Logical unary not.
anatofuz
parents:
diff changeset
56 def unary!(v)
anatofuz
parents:
diff changeset
57 if v then
anatofuz
parents:
diff changeset
58 0
anatofuz
parents:
diff changeset
59 else
anatofuz
parents:
diff changeset
60 1;
anatofuz
parents:
diff changeset
61
anatofuz
parents:
diff changeset
62 # Define > with the same precedence as <.
anatofuz
parents:
diff changeset
63 def binary> 10 (LHS RHS)
anatofuz
parents:
diff changeset
64 RHS < LHS;
anatofuz
parents:
diff changeset
65
anatofuz
parents:
diff changeset
66 # Binary "logical or", (note that it does not "short circuit")
anatofuz
parents:
diff changeset
67 def binary| 5 (LHS RHS)
anatofuz
parents:
diff changeset
68 if LHS then
anatofuz
parents:
diff changeset
69 1
anatofuz
parents:
diff changeset
70 else if RHS then
anatofuz
parents:
diff changeset
71 1
anatofuz
parents:
diff changeset
72 else
anatofuz
parents:
diff changeset
73 0;
anatofuz
parents:
diff changeset
74
anatofuz
parents:
diff changeset
75 # Define = with slightly lower precedence than relationals.
anatofuz
parents:
diff changeset
76 def binary= 9 (LHS RHS)
anatofuz
parents:
diff changeset
77 !(LHS < RHS | LHS > RHS);
anatofuz
parents:
diff changeset
78
anatofuz
parents:
diff changeset
79 Many languages aspire to being able to implement their standard runtime
anatofuz
parents:
diff changeset
80 library in the language itself. In Kaleidoscope, we can implement
anatofuz
parents:
diff changeset
81 significant parts of the language in the library!
anatofuz
parents:
diff changeset
82
anatofuz
parents:
diff changeset
83 We will break down implementation of these features into two parts:
anatofuz
parents:
diff changeset
84 implementing support for user-defined binary operators and adding unary
anatofuz
parents:
diff changeset
85 operators.
anatofuz
parents:
diff changeset
86
anatofuz
parents:
diff changeset
87 User-defined Binary Operators
anatofuz
parents:
diff changeset
88 =============================
anatofuz
parents:
diff changeset
89
anatofuz
parents:
diff changeset
90 Adding support for user-defined binary operators is pretty simple with
anatofuz
parents:
diff changeset
91 our current framework. We'll first add support for the unary/binary
anatofuz
parents:
diff changeset
92 keywords:
anatofuz
parents:
diff changeset
93
anatofuz
parents:
diff changeset
94 .. code-block:: c++
anatofuz
parents:
diff changeset
95
anatofuz
parents:
diff changeset
96 enum Token {
anatofuz
parents:
diff changeset
97 ...
anatofuz
parents:
diff changeset
98 // operators
anatofuz
parents:
diff changeset
99 tok_binary = -11,
anatofuz
parents:
diff changeset
100 tok_unary = -12
anatofuz
parents:
diff changeset
101 };
anatofuz
parents:
diff changeset
102 ...
anatofuz
parents:
diff changeset
103 static int gettok() {
anatofuz
parents:
diff changeset
104 ...
anatofuz
parents:
diff changeset
105 if (IdentifierStr == "for")
anatofuz
parents:
diff changeset
106 return tok_for;
anatofuz
parents:
diff changeset
107 if (IdentifierStr == "in")
anatofuz
parents:
diff changeset
108 return tok_in;
anatofuz
parents:
diff changeset
109 if (IdentifierStr == "binary")
anatofuz
parents:
diff changeset
110 return tok_binary;
anatofuz
parents:
diff changeset
111 if (IdentifierStr == "unary")
anatofuz
parents:
diff changeset
112 return tok_unary;
anatofuz
parents:
diff changeset
113 return tok_identifier;
anatofuz
parents:
diff changeset
114
anatofuz
parents:
diff changeset
115 This just adds lexer support for the unary and binary keywords, like we
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
116 did in `previous chapters <LangImpl05.html#lexer-extensions-for-if-then-else>`_. One nice thing
150
anatofuz
parents:
diff changeset
117 about our current AST, is that we represent binary operators with full
anatofuz
parents:
diff changeset
118 generalisation by using their ASCII code as the opcode. For our extended
anatofuz
parents:
diff changeset
119 operators, we'll use this same representation, so we don't need any new
anatofuz
parents:
diff changeset
120 AST or parser support.
anatofuz
parents:
diff changeset
121
anatofuz
parents:
diff changeset
122 On the other hand, we have to be able to represent the definitions of
anatofuz
parents:
diff changeset
123 these new operators, in the "def binary\| 5" part of the function
anatofuz
parents:
diff changeset
124 definition. In our grammar so far, the "name" for the function
anatofuz
parents:
diff changeset
125 definition is parsed as the "prototype" production and into the
anatofuz
parents:
diff changeset
126 ``PrototypeAST`` AST node. To represent our new user-defined operators
anatofuz
parents:
diff changeset
127 as prototypes, we have to extend the ``PrototypeAST`` AST node like
anatofuz
parents:
diff changeset
128 this:
anatofuz
parents:
diff changeset
129
anatofuz
parents:
diff changeset
130 .. code-block:: c++
anatofuz
parents:
diff changeset
131
anatofuz
parents:
diff changeset
132 /// PrototypeAST - This class represents the "prototype" for a function,
anatofuz
parents:
diff changeset
133 /// which captures its argument names as well as if it is an operator.
anatofuz
parents:
diff changeset
134 class PrototypeAST {
anatofuz
parents:
diff changeset
135 std::string Name;
anatofuz
parents:
diff changeset
136 std::vector<std::string> Args;
anatofuz
parents:
diff changeset
137 bool IsOperator;
anatofuz
parents:
diff changeset
138 unsigned Precedence; // Precedence if a binary op.
anatofuz
parents:
diff changeset
139
anatofuz
parents:
diff changeset
140 public:
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 221
diff changeset
141 PrototypeAST(const std::string &Name, std::vector<std::string> Args,
150
anatofuz
parents:
diff changeset
142 bool IsOperator = false, unsigned Prec = 0)
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 221
diff changeset
143 : Name(Name), Args(std::move(Args)), IsOperator(IsOperator),
150
anatofuz
parents:
diff changeset
144 Precedence(Prec) {}
anatofuz
parents:
diff changeset
145
anatofuz
parents:
diff changeset
146 Function *codegen();
anatofuz
parents:
diff changeset
147 const std::string &getName() const { return Name; }
anatofuz
parents:
diff changeset
148
anatofuz
parents:
diff changeset
149 bool isUnaryOp() const { return IsOperator && Args.size() == 1; }
anatofuz
parents:
diff changeset
150 bool isBinaryOp() const { return IsOperator && Args.size() == 2; }
anatofuz
parents:
diff changeset
151
anatofuz
parents:
diff changeset
152 char getOperatorName() const {
anatofuz
parents:
diff changeset
153 assert(isUnaryOp() || isBinaryOp());
anatofuz
parents:
diff changeset
154 return Name[Name.size() - 1];
anatofuz
parents:
diff changeset
155 }
anatofuz
parents:
diff changeset
156
anatofuz
parents:
diff changeset
157 unsigned getBinaryPrecedence() const { return Precedence; }
anatofuz
parents:
diff changeset
158 };
anatofuz
parents:
diff changeset
159
anatofuz
parents:
diff changeset
160 Basically, in addition to knowing a name for the prototype, we now keep
anatofuz
parents:
diff changeset
161 track of whether it was an operator, and if it was, what precedence
anatofuz
parents:
diff changeset
162 level the operator is at. The precedence is only used for binary
anatofuz
parents:
diff changeset
163 operators (as you'll see below, it just doesn't apply for unary
anatofuz
parents:
diff changeset
164 operators). Now that we have a way to represent the prototype for a
anatofuz
parents:
diff changeset
165 user-defined operator, we need to parse it:
anatofuz
parents:
diff changeset
166
anatofuz
parents:
diff changeset
167 .. code-block:: c++
anatofuz
parents:
diff changeset
168
anatofuz
parents:
diff changeset
169 /// prototype
anatofuz
parents:
diff changeset
170 /// ::= id '(' id* ')'
anatofuz
parents:
diff changeset
171 /// ::= binary LETTER number? (id, id)
anatofuz
parents:
diff changeset
172 static std::unique_ptr<PrototypeAST> ParsePrototype() {
anatofuz
parents:
diff changeset
173 std::string FnName;
anatofuz
parents:
diff changeset
174
anatofuz
parents:
diff changeset
175 unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary.
anatofuz
parents:
diff changeset
176 unsigned BinaryPrecedence = 30;
anatofuz
parents:
diff changeset
177
anatofuz
parents:
diff changeset
178 switch (CurTok) {
anatofuz
parents:
diff changeset
179 default:
anatofuz
parents:
diff changeset
180 return LogErrorP("Expected function name in prototype");
anatofuz
parents:
diff changeset
181 case tok_identifier:
anatofuz
parents:
diff changeset
182 FnName = IdentifierStr;
anatofuz
parents:
diff changeset
183 Kind = 0;
anatofuz
parents:
diff changeset
184 getNextToken();
anatofuz
parents:
diff changeset
185 break;
anatofuz
parents:
diff changeset
186 case tok_binary:
anatofuz
parents:
diff changeset
187 getNextToken();
anatofuz
parents:
diff changeset
188 if (!isascii(CurTok))
anatofuz
parents:
diff changeset
189 return LogErrorP("Expected binary operator");
anatofuz
parents:
diff changeset
190 FnName = "binary";
anatofuz
parents:
diff changeset
191 FnName += (char)CurTok;
anatofuz
parents:
diff changeset
192 Kind = 2;
anatofuz
parents:
diff changeset
193 getNextToken();
anatofuz
parents:
diff changeset
194
anatofuz
parents:
diff changeset
195 // Read the precedence if present.
anatofuz
parents:
diff changeset
196 if (CurTok == tok_number) {
anatofuz
parents:
diff changeset
197 if (NumVal < 1 || NumVal > 100)
anatofuz
parents:
diff changeset
198 return LogErrorP("Invalid precedence: must be 1..100");
anatofuz
parents:
diff changeset
199 BinaryPrecedence = (unsigned)NumVal;
anatofuz
parents:
diff changeset
200 getNextToken();
anatofuz
parents:
diff changeset
201 }
anatofuz
parents:
diff changeset
202 break;
anatofuz
parents:
diff changeset
203 }
anatofuz
parents:
diff changeset
204
anatofuz
parents:
diff changeset
205 if (CurTok != '(')
anatofuz
parents:
diff changeset
206 return LogErrorP("Expected '(' in prototype");
anatofuz
parents:
diff changeset
207
anatofuz
parents:
diff changeset
208 std::vector<std::string> ArgNames;
anatofuz
parents:
diff changeset
209 while (getNextToken() == tok_identifier)
anatofuz
parents:
diff changeset
210 ArgNames.push_back(IdentifierStr);
anatofuz
parents:
diff changeset
211 if (CurTok != ')')
anatofuz
parents:
diff changeset
212 return LogErrorP("Expected ')' in prototype");
anatofuz
parents:
diff changeset
213
anatofuz
parents:
diff changeset
214 // success.
anatofuz
parents:
diff changeset
215 getNextToken(); // eat ')'.
anatofuz
parents:
diff changeset
216
anatofuz
parents:
diff changeset
217 // Verify right number of names for operator.
anatofuz
parents:
diff changeset
218 if (Kind && ArgNames.size() != Kind)
anatofuz
parents:
diff changeset
219 return LogErrorP("Invalid number of operands for operator");
anatofuz
parents:
diff changeset
220
anatofuz
parents:
diff changeset
221 return std::make_unique<PrototypeAST>(FnName, std::move(ArgNames), Kind != 0,
anatofuz
parents:
diff changeset
222 BinaryPrecedence);
anatofuz
parents:
diff changeset
223 }
anatofuz
parents:
diff changeset
224
anatofuz
parents:
diff changeset
225 This is all fairly straightforward parsing code, and we have already
anatofuz
parents:
diff changeset
226 seen a lot of similar code in the past. One interesting part about the
anatofuz
parents:
diff changeset
227 code above is the couple lines that set up ``FnName`` for binary
anatofuz
parents:
diff changeset
228 operators. This builds names like "binary@" for a newly defined "@"
anatofuz
parents:
diff changeset
229 operator. It then takes advantage of the fact that symbol names in the
anatofuz
parents:
diff changeset
230 LLVM symbol table are allowed to have any character in them, including
anatofuz
parents:
diff changeset
231 embedded nul characters.
anatofuz
parents:
diff changeset
232
anatofuz
parents:
diff changeset
233 The next interesting thing to add, is codegen support for these binary
anatofuz
parents:
diff changeset
234 operators. Given our current structure, this is a simple addition of a
anatofuz
parents:
diff changeset
235 default case for our existing binary operator node:
anatofuz
parents:
diff changeset
236
anatofuz
parents:
diff changeset
237 .. code-block:: c++
anatofuz
parents:
diff changeset
238
anatofuz
parents:
diff changeset
239 Value *BinaryExprAST::codegen() {
anatofuz
parents:
diff changeset
240 Value *L = LHS->codegen();
anatofuz
parents:
diff changeset
241 Value *R = RHS->codegen();
anatofuz
parents:
diff changeset
242 if (!L || !R)
anatofuz
parents:
diff changeset
243 return nullptr;
anatofuz
parents:
diff changeset
244
anatofuz
parents:
diff changeset
245 switch (Op) {
anatofuz
parents:
diff changeset
246 case '+':
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 221
diff changeset
247 return Builder->CreateFAdd(L, R, "addtmp");
150
anatofuz
parents:
diff changeset
248 case '-':
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 221
diff changeset
249 return Builder->CreateFSub(L, R, "subtmp");
150
anatofuz
parents:
diff changeset
250 case '*':
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 221
diff changeset
251 return Builder->CreateFMul(L, R, "multmp");
150
anatofuz
parents:
diff changeset
252 case '<':
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 221
diff changeset
253 L = Builder->CreateFCmpULT(L, R, "cmptmp");
150
anatofuz
parents:
diff changeset
254 // Convert bool 0/1 to double 0.0 or 1.0
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 221
diff changeset
255 return Builder->CreateUIToFP(L, Type::getDoubleTy(*TheContext),
150
anatofuz
parents:
diff changeset
256 "booltmp");
anatofuz
parents:
diff changeset
257 default:
anatofuz
parents:
diff changeset
258 break;
anatofuz
parents:
diff changeset
259 }
anatofuz
parents:
diff changeset
260
anatofuz
parents:
diff changeset
261 // If it wasn't a builtin binary operator, it must be a user defined one. Emit
anatofuz
parents:
diff changeset
262 // a call to it.
anatofuz
parents:
diff changeset
263 Function *F = getFunction(std::string("binary") + Op);
anatofuz
parents:
diff changeset
264 assert(F && "binary operator not found!");
anatofuz
parents:
diff changeset
265
anatofuz
parents:
diff changeset
266 Value *Ops[2] = { L, R };
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 221
diff changeset
267 return Builder->CreateCall(F, Ops, "binop");
150
anatofuz
parents:
diff changeset
268 }
anatofuz
parents:
diff changeset
269
anatofuz
parents:
diff changeset
270 As you can see above, the new code is actually really simple. It just
anatofuz
parents:
diff changeset
271 does a lookup for the appropriate operator in the symbol table and
anatofuz
parents:
diff changeset
272 generates a function call to it. Since user-defined operators are just
anatofuz
parents:
diff changeset
273 built as normal functions (because the "prototype" boils down to a
anatofuz
parents:
diff changeset
274 function with the right name) everything falls into place.
anatofuz
parents:
diff changeset
275
anatofuz
parents:
diff changeset
276 The final piece of code we are missing, is a bit of top-level magic:
anatofuz
parents:
diff changeset
277
anatofuz
parents:
diff changeset
278 .. code-block:: c++
anatofuz
parents:
diff changeset
279
anatofuz
parents:
diff changeset
280 Function *FunctionAST::codegen() {
anatofuz
parents:
diff changeset
281 // Transfer ownership of the prototype to the FunctionProtos map, but keep a
anatofuz
parents:
diff changeset
282 // reference to it for use below.
anatofuz
parents:
diff changeset
283 auto &P = *Proto;
anatofuz
parents:
diff changeset
284 FunctionProtos[Proto->getName()] = std::move(Proto);
anatofuz
parents:
diff changeset
285 Function *TheFunction = getFunction(P.getName());
anatofuz
parents:
diff changeset
286 if (!TheFunction)
anatofuz
parents:
diff changeset
287 return nullptr;
anatofuz
parents:
diff changeset
288
anatofuz
parents:
diff changeset
289 // If this is an operator, install it.
anatofuz
parents:
diff changeset
290 if (P.isBinaryOp())
anatofuz
parents:
diff changeset
291 BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence();
anatofuz
parents:
diff changeset
292
anatofuz
parents:
diff changeset
293 // Create a new basic block to start insertion into.
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 221
diff changeset
294 BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", TheFunction);
150
anatofuz
parents:
diff changeset
295 ...
anatofuz
parents:
diff changeset
296
anatofuz
parents:
diff changeset
297 Basically, before codegening a function, if it is a user-defined
anatofuz
parents:
diff changeset
298 operator, we register it in the precedence table. This allows the binary
anatofuz
parents:
diff changeset
299 operator parsing logic we already have in place to handle it. Since we
anatofuz
parents:
diff changeset
300 are working on a fully-general operator precedence parser, this is all
anatofuz
parents:
diff changeset
301 we need to do to "extend the grammar".
anatofuz
parents:
diff changeset
302
anatofuz
parents:
diff changeset
303 Now we have useful user-defined binary operators. This builds a lot on
anatofuz
parents:
diff changeset
304 the previous framework we built for other operators. Adding unary
anatofuz
parents:
diff changeset
305 operators is a bit more challenging, because we don't have any framework
anatofuz
parents:
diff changeset
306 for it yet - let's see what it takes.
anatofuz
parents:
diff changeset
307
anatofuz
parents:
diff changeset
308 User-defined Unary Operators
anatofuz
parents:
diff changeset
309 ============================
anatofuz
parents:
diff changeset
310
anatofuz
parents:
diff changeset
311 Since we don't currently support unary operators in the Kaleidoscope
anatofuz
parents:
diff changeset
312 language, we'll need to add everything to support them. Above, we added
anatofuz
parents:
diff changeset
313 simple support for the 'unary' keyword to the lexer. In addition to
anatofuz
parents:
diff changeset
314 that, we need an AST node:
anatofuz
parents:
diff changeset
315
anatofuz
parents:
diff changeset
316 .. code-block:: c++
anatofuz
parents:
diff changeset
317
anatofuz
parents:
diff changeset
318 /// UnaryExprAST - Expression class for a unary operator.
anatofuz
parents:
diff changeset
319 class UnaryExprAST : public ExprAST {
anatofuz
parents:
diff changeset
320 char Opcode;
anatofuz
parents:
diff changeset
321 std::unique_ptr<ExprAST> Operand;
anatofuz
parents:
diff changeset
322
anatofuz
parents:
diff changeset
323 public:
anatofuz
parents:
diff changeset
324 UnaryExprAST(char Opcode, std::unique_ptr<ExprAST> Operand)
anatofuz
parents:
diff changeset
325 : Opcode(Opcode), Operand(std::move(Operand)) {}
anatofuz
parents:
diff changeset
326
anatofuz
parents:
diff changeset
327 Value *codegen() override;
anatofuz
parents:
diff changeset
328 };
anatofuz
parents:
diff changeset
329
anatofuz
parents:
diff changeset
330 This AST node is very simple and obvious by now. It directly mirrors the
anatofuz
parents:
diff changeset
331 binary operator AST node, except that it only has one child. With this,
anatofuz
parents:
diff changeset
332 we need to add the parsing logic. Parsing a unary operator is pretty
anatofuz
parents:
diff changeset
333 simple: we'll add a new function to do it:
anatofuz
parents:
diff changeset
334
anatofuz
parents:
diff changeset
335 .. code-block:: c++
anatofuz
parents:
diff changeset
336
anatofuz
parents:
diff changeset
337 /// unary
anatofuz
parents:
diff changeset
338 /// ::= primary
anatofuz
parents:
diff changeset
339 /// ::= '!' unary
anatofuz
parents:
diff changeset
340 static std::unique_ptr<ExprAST> ParseUnary() {
anatofuz
parents:
diff changeset
341 // If the current token is not an operator, it must be a primary expr.
anatofuz
parents:
diff changeset
342 if (!isascii(CurTok) || CurTok == '(' || CurTok == ',')
anatofuz
parents:
diff changeset
343 return ParsePrimary();
anatofuz
parents:
diff changeset
344
anatofuz
parents:
diff changeset
345 // If this is a unary operator, read it.
anatofuz
parents:
diff changeset
346 int Opc = CurTok;
anatofuz
parents:
diff changeset
347 getNextToken();
anatofuz
parents:
diff changeset
348 if (auto Operand = ParseUnary())
anatofuz
parents:
diff changeset
349 return std::make_unique<UnaryExprAST>(Opc, std::move(Operand));
anatofuz
parents:
diff changeset
350 return nullptr;
anatofuz
parents:
diff changeset
351 }
anatofuz
parents:
diff changeset
352
anatofuz
parents:
diff changeset
353 The grammar we add is pretty straightforward here. If we see a unary
anatofuz
parents:
diff changeset
354 operator when parsing a primary operator, we eat the operator as a
anatofuz
parents:
diff changeset
355 prefix and parse the remaining piece as another unary operator. This
anatofuz
parents:
diff changeset
356 allows us to handle multiple unary operators (e.g. "!!x"). Note that
anatofuz
parents:
diff changeset
357 unary operators can't have ambiguous parses like binary operators can,
anatofuz
parents:
diff changeset
358 so there is no need for precedence information.
anatofuz
parents:
diff changeset
359
anatofuz
parents:
diff changeset
360 The problem with this function, is that we need to call ParseUnary from
anatofuz
parents:
diff changeset
361 somewhere. To do this, we change previous callers of ParsePrimary to
anatofuz
parents:
diff changeset
362 call ParseUnary instead:
anatofuz
parents:
diff changeset
363
anatofuz
parents:
diff changeset
364 .. code-block:: c++
anatofuz
parents:
diff changeset
365
anatofuz
parents:
diff changeset
366 /// binoprhs
anatofuz
parents:
diff changeset
367 /// ::= ('+' unary)*
anatofuz
parents:
diff changeset
368 static std::unique_ptr<ExprAST> ParseBinOpRHS(int ExprPrec,
anatofuz
parents:
diff changeset
369 std::unique_ptr<ExprAST> LHS) {
anatofuz
parents:
diff changeset
370 ...
anatofuz
parents:
diff changeset
371 // Parse the unary expression after the binary operator.
anatofuz
parents:
diff changeset
372 auto RHS = ParseUnary();
anatofuz
parents:
diff changeset
373 if (!RHS)
anatofuz
parents:
diff changeset
374 return nullptr;
anatofuz
parents:
diff changeset
375 ...
anatofuz
parents:
diff changeset
376 }
anatofuz
parents:
diff changeset
377 /// expression
anatofuz
parents:
diff changeset
378 /// ::= unary binoprhs
anatofuz
parents:
diff changeset
379 ///
anatofuz
parents:
diff changeset
380 static std::unique_ptr<ExprAST> ParseExpression() {
anatofuz
parents:
diff changeset
381 auto LHS = ParseUnary();
anatofuz
parents:
diff changeset
382 if (!LHS)
anatofuz
parents:
diff changeset
383 return nullptr;
anatofuz
parents:
diff changeset
384
anatofuz
parents:
diff changeset
385 return ParseBinOpRHS(0, std::move(LHS));
anatofuz
parents:
diff changeset
386 }
anatofuz
parents:
diff changeset
387
anatofuz
parents:
diff changeset
388 With these two simple changes, we are now able to parse unary operators
anatofuz
parents:
diff changeset
389 and build the AST for them. Next up, we need to add parser support for
anatofuz
parents:
diff changeset
390 prototypes, to parse the unary operator prototype. We extend the binary
anatofuz
parents:
diff changeset
391 operator code above with:
anatofuz
parents:
diff changeset
392
anatofuz
parents:
diff changeset
393 .. code-block:: c++
anatofuz
parents:
diff changeset
394
anatofuz
parents:
diff changeset
395 /// prototype
anatofuz
parents:
diff changeset
396 /// ::= id '(' id* ')'
anatofuz
parents:
diff changeset
397 /// ::= binary LETTER number? (id, id)
anatofuz
parents:
diff changeset
398 /// ::= unary LETTER (id)
anatofuz
parents:
diff changeset
399 static std::unique_ptr<PrototypeAST> ParsePrototype() {
anatofuz
parents:
diff changeset
400 std::string FnName;
anatofuz
parents:
diff changeset
401
anatofuz
parents:
diff changeset
402 unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary.
anatofuz
parents:
diff changeset
403 unsigned BinaryPrecedence = 30;
anatofuz
parents:
diff changeset
404
anatofuz
parents:
diff changeset
405 switch (CurTok) {
anatofuz
parents:
diff changeset
406 default:
anatofuz
parents:
diff changeset
407 return LogErrorP("Expected function name in prototype");
anatofuz
parents:
diff changeset
408 case tok_identifier:
anatofuz
parents:
diff changeset
409 FnName = IdentifierStr;
anatofuz
parents:
diff changeset
410 Kind = 0;
anatofuz
parents:
diff changeset
411 getNextToken();
anatofuz
parents:
diff changeset
412 break;
anatofuz
parents:
diff changeset
413 case tok_unary:
anatofuz
parents:
diff changeset
414 getNextToken();
anatofuz
parents:
diff changeset
415 if (!isascii(CurTok))
anatofuz
parents:
diff changeset
416 return LogErrorP("Expected unary operator");
anatofuz
parents:
diff changeset
417 FnName = "unary";
anatofuz
parents:
diff changeset
418 FnName += (char)CurTok;
anatofuz
parents:
diff changeset
419 Kind = 1;
anatofuz
parents:
diff changeset
420 getNextToken();
anatofuz
parents:
diff changeset
421 break;
anatofuz
parents:
diff changeset
422 case tok_binary:
anatofuz
parents:
diff changeset
423 ...
anatofuz
parents:
diff changeset
424
anatofuz
parents:
diff changeset
425 As with binary operators, we name unary operators with a name that
anatofuz
parents:
diff changeset
426 includes the operator character. This assists us at code generation
anatofuz
parents:
diff changeset
427 time. Speaking of, the final piece we need to add is codegen support for
anatofuz
parents:
diff changeset
428 unary operators. It looks like this:
anatofuz
parents:
diff changeset
429
anatofuz
parents:
diff changeset
430 .. code-block:: c++
anatofuz
parents:
diff changeset
431
anatofuz
parents:
diff changeset
432 Value *UnaryExprAST::codegen() {
anatofuz
parents:
diff changeset
433 Value *OperandV = Operand->codegen();
anatofuz
parents:
diff changeset
434 if (!OperandV)
anatofuz
parents:
diff changeset
435 return nullptr;
anatofuz
parents:
diff changeset
436
anatofuz
parents:
diff changeset
437 Function *F = getFunction(std::string("unary") + Opcode);
anatofuz
parents:
diff changeset
438 if (!F)
anatofuz
parents:
diff changeset
439 return LogErrorV("Unknown unary operator");
anatofuz
parents:
diff changeset
440
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 221
diff changeset
441 return Builder->CreateCall(F, OperandV, "unop");
150
anatofuz
parents:
diff changeset
442 }
anatofuz
parents:
diff changeset
443
anatofuz
parents:
diff changeset
444 This code is similar to, but simpler than, the code for binary
anatofuz
parents:
diff changeset
445 operators. It is simpler primarily because it doesn't need to handle any
anatofuz
parents:
diff changeset
446 predefined operators.
anatofuz
parents:
diff changeset
447
anatofuz
parents:
diff changeset
448 Kicking the Tires
anatofuz
parents:
diff changeset
449 =================
anatofuz
parents:
diff changeset
450
anatofuz
parents:
diff changeset
451 It is somewhat hard to believe, but with a few simple extensions we've
anatofuz
parents:
diff changeset
452 covered in the last chapters, we have grown a real-ish language. With
anatofuz
parents:
diff changeset
453 this, we can do a lot of interesting things, including I/O, math, and a
anatofuz
parents:
diff changeset
454 bunch of other things. For example, we can now add a nice sequencing
anatofuz
parents:
diff changeset
455 operator (printd is defined to print out the specified value and a
anatofuz
parents:
diff changeset
456 newline):
anatofuz
parents:
diff changeset
457
anatofuz
parents:
diff changeset
458 ::
anatofuz
parents:
diff changeset
459
anatofuz
parents:
diff changeset
460 ready> extern printd(x);
anatofuz
parents:
diff changeset
461 Read extern:
anatofuz
parents:
diff changeset
462 declare double @printd(double)
anatofuz
parents:
diff changeset
463
anatofuz
parents:
diff changeset
464 ready> def binary : 1 (x y) 0; # Low-precedence operator that ignores operands.
anatofuz
parents:
diff changeset
465 ...
anatofuz
parents:
diff changeset
466 ready> printd(123) : printd(456) : printd(789);
anatofuz
parents:
diff changeset
467 123.000000
anatofuz
parents:
diff changeset
468 456.000000
anatofuz
parents:
diff changeset
469 789.000000
anatofuz
parents:
diff changeset
470 Evaluated to 0.000000
anatofuz
parents:
diff changeset
471
anatofuz
parents:
diff changeset
472 We can also define a bunch of other "primitive" operations, such as:
anatofuz
parents:
diff changeset
473
anatofuz
parents:
diff changeset
474 ::
anatofuz
parents:
diff changeset
475
anatofuz
parents:
diff changeset
476 # Logical unary not.
anatofuz
parents:
diff changeset
477 def unary!(v)
anatofuz
parents:
diff changeset
478 if v then
anatofuz
parents:
diff changeset
479 0
anatofuz
parents:
diff changeset
480 else
anatofuz
parents:
diff changeset
481 1;
anatofuz
parents:
diff changeset
482
anatofuz
parents:
diff changeset
483 # Unary negate.
anatofuz
parents:
diff changeset
484 def unary-(v)
anatofuz
parents:
diff changeset
485 0-v;
anatofuz
parents:
diff changeset
486
anatofuz
parents:
diff changeset
487 # Define > with the same precedence as <.
anatofuz
parents:
diff changeset
488 def binary> 10 (LHS RHS)
anatofuz
parents:
diff changeset
489 RHS < LHS;
anatofuz
parents:
diff changeset
490
anatofuz
parents:
diff changeset
491 # Binary logical or, which does not short circuit.
anatofuz
parents:
diff changeset
492 def binary| 5 (LHS RHS)
anatofuz
parents:
diff changeset
493 if LHS then
anatofuz
parents:
diff changeset
494 1
anatofuz
parents:
diff changeset
495 else if RHS then
anatofuz
parents:
diff changeset
496 1
anatofuz
parents:
diff changeset
497 else
anatofuz
parents:
diff changeset
498 0;
anatofuz
parents:
diff changeset
499
anatofuz
parents:
diff changeset
500 # Binary logical and, which does not short circuit.
anatofuz
parents:
diff changeset
501 def binary& 6 (LHS RHS)
anatofuz
parents:
diff changeset
502 if !LHS then
anatofuz
parents:
diff changeset
503 0
anatofuz
parents:
diff changeset
504 else
anatofuz
parents:
diff changeset
505 !!RHS;
anatofuz
parents:
diff changeset
506
anatofuz
parents:
diff changeset
507 # Define = with slightly lower precedence than relationals.
anatofuz
parents:
diff changeset
508 def binary = 9 (LHS RHS)
anatofuz
parents:
diff changeset
509 !(LHS < RHS | LHS > RHS);
anatofuz
parents:
diff changeset
510
anatofuz
parents:
diff changeset
511 # Define ':' for sequencing: as a low-precedence operator that ignores operands
anatofuz
parents:
diff changeset
512 # and just returns the RHS.
anatofuz
parents:
diff changeset
513 def binary : 1 (x y) y;
anatofuz
parents:
diff changeset
514
anatofuz
parents:
diff changeset
515 Given the previous if/then/else support, we can also define interesting
anatofuz
parents:
diff changeset
516 functions for I/O. For example, the following prints out a character
anatofuz
parents:
diff changeset
517 whose "density" reflects the value passed in: the lower the value, the
anatofuz
parents:
diff changeset
518 denser the character:
anatofuz
parents:
diff changeset
519
anatofuz
parents:
diff changeset
520 ::
anatofuz
parents:
diff changeset
521
anatofuz
parents:
diff changeset
522 ready> extern putchard(char);
anatofuz
parents:
diff changeset
523 ...
anatofuz
parents:
diff changeset
524 ready> def printdensity(d)
anatofuz
parents:
diff changeset
525 if d > 8 then
anatofuz
parents:
diff changeset
526 putchard(32) # ' '
anatofuz
parents:
diff changeset
527 else if d > 4 then
anatofuz
parents:
diff changeset
528 putchard(46) # '.'
anatofuz
parents:
diff changeset
529 else if d > 2 then
anatofuz
parents:
diff changeset
530 putchard(43) # '+'
anatofuz
parents:
diff changeset
531 else
anatofuz
parents:
diff changeset
532 putchard(42); # '*'
anatofuz
parents:
diff changeset
533 ...
anatofuz
parents:
diff changeset
534 ready> printdensity(1): printdensity(2): printdensity(3):
anatofuz
parents:
diff changeset
535 printdensity(4): printdensity(5): printdensity(9):
anatofuz
parents:
diff changeset
536 putchard(10);
anatofuz
parents:
diff changeset
537 **++.
anatofuz
parents:
diff changeset
538 Evaluated to 0.000000
anatofuz
parents:
diff changeset
539
anatofuz
parents:
diff changeset
540 Based on these simple primitive operations, we can start to define more
anatofuz
parents:
diff changeset
541 interesting things. For example, here's a little function that determines
anatofuz
parents:
diff changeset
542 the number of iterations it takes for a certain function in the complex
anatofuz
parents:
diff changeset
543 plane to diverge:
anatofuz
parents:
diff changeset
544
anatofuz
parents:
diff changeset
545 ::
anatofuz
parents:
diff changeset
546
anatofuz
parents:
diff changeset
547 # Determine whether the specific location diverges.
anatofuz
parents:
diff changeset
548 # Solve for z = z^2 + c in the complex plane.
anatofuz
parents:
diff changeset
549 def mandelconverger(real imag iters creal cimag)
anatofuz
parents:
diff changeset
550 if iters > 255 | (real*real + imag*imag > 4) then
anatofuz
parents:
diff changeset
551 iters
anatofuz
parents:
diff changeset
552 else
anatofuz
parents:
diff changeset
553 mandelconverger(real*real - imag*imag + creal,
anatofuz
parents:
diff changeset
554 2*real*imag + cimag,
anatofuz
parents:
diff changeset
555 iters+1, creal, cimag);
anatofuz
parents:
diff changeset
556
anatofuz
parents:
diff changeset
557 # Return the number of iterations required for the iteration to escape
anatofuz
parents:
diff changeset
558 def mandelconverge(real imag)
anatofuz
parents:
diff changeset
559 mandelconverger(real, imag, 0, real, imag);
anatofuz
parents:
diff changeset
560
anatofuz
parents:
diff changeset
561 This "``z = z2 + c``" function is a beautiful little creature that is
anatofuz
parents:
diff changeset
562 the basis for computation of the `Mandelbrot
anatofuz
parents:
diff changeset
563 Set <http://en.wikipedia.org/wiki/Mandelbrot_set>`_. Our
anatofuz
parents:
diff changeset
564 ``mandelconverge`` function returns the number of iterations that it
anatofuz
parents:
diff changeset
565 takes for a complex orbit to escape, saturating to 255. This is not a
anatofuz
parents:
diff changeset
566 very useful function by itself, but if you plot its value over a
anatofuz
parents:
diff changeset
567 two-dimensional plane, you can see the Mandelbrot set. Given that we are
anatofuz
parents:
diff changeset
568 limited to using putchard here, our amazing graphical output is limited,
anatofuz
parents:
diff changeset
569 but we can whip together something using the density plotter above:
anatofuz
parents:
diff changeset
570
anatofuz
parents:
diff changeset
571 ::
anatofuz
parents:
diff changeset
572
anatofuz
parents:
diff changeset
573 # Compute and plot the mandelbrot set with the specified 2 dimensional range
anatofuz
parents:
diff changeset
574 # info.
anatofuz
parents:
diff changeset
575 def mandelhelp(xmin xmax xstep ymin ymax ystep)
anatofuz
parents:
diff changeset
576 for y = ymin, y < ymax, ystep in (
anatofuz
parents:
diff changeset
577 (for x = xmin, x < xmax, xstep in
anatofuz
parents:
diff changeset
578 printdensity(mandelconverge(x,y)))
anatofuz
parents:
diff changeset
579 : putchard(10)
anatofuz
parents:
diff changeset
580 )
anatofuz
parents:
diff changeset
581
anatofuz
parents:
diff changeset
582 # mandel - This is a convenient helper function for plotting the mandelbrot set
anatofuz
parents:
diff changeset
583 # from the specified position with the specified Magnification.
anatofuz
parents:
diff changeset
584 def mandel(realstart imagstart realmag imagmag)
anatofuz
parents:
diff changeset
585 mandelhelp(realstart, realstart+realmag*78, realmag,
anatofuz
parents:
diff changeset
586 imagstart, imagstart+imagmag*40, imagmag);
anatofuz
parents:
diff changeset
587
anatofuz
parents:
diff changeset
588 Given this, we can try plotting out the mandelbrot set! Lets try it out:
anatofuz
parents:
diff changeset
589
anatofuz
parents:
diff changeset
590 ::
anatofuz
parents:
diff changeset
591
anatofuz
parents:
diff changeset
592 ready> mandel(-2.3, -1.3, 0.05, 0.07);
anatofuz
parents:
diff changeset
593 *******************************+++++++++++*************************************
anatofuz
parents:
diff changeset
594 *************************+++++++++++++++++++++++*******************************
anatofuz
parents:
diff changeset
595 **********************+++++++++++++++++++++++++++++****************************
anatofuz
parents:
diff changeset
596 *******************+++++++++++++++++++++.. ...++++++++*************************
anatofuz
parents:
diff changeset
597 *****************++++++++++++++++++++++.... ...+++++++++***********************
anatofuz
parents:
diff changeset
598 ***************+++++++++++++++++++++++..... ...+++++++++*********************
anatofuz
parents:
diff changeset
599 **************+++++++++++++++++++++++.... ....+++++++++********************
anatofuz
parents:
diff changeset
600 *************++++++++++++++++++++++...... .....++++++++*******************
anatofuz
parents:
diff changeset
601 ************+++++++++++++++++++++....... .......+++++++******************
anatofuz
parents:
diff changeset
602 ***********+++++++++++++++++++.... ... .+++++++*****************
anatofuz
parents:
diff changeset
603 **********+++++++++++++++++....... .+++++++****************
anatofuz
parents:
diff changeset
604 *********++++++++++++++........... ...+++++++***************
anatofuz
parents:
diff changeset
605 ********++++++++++++............ ...++++++++**************
anatofuz
parents:
diff changeset
606 ********++++++++++... .......... .++++++++**************
anatofuz
parents:
diff changeset
607 *******+++++++++..... .+++++++++*************
anatofuz
parents:
diff changeset
608 *******++++++++...... ..+++++++++*************
anatofuz
parents:
diff changeset
609 *******++++++....... ..+++++++++*************
anatofuz
parents:
diff changeset
610 *******+++++...... ..+++++++++*************
anatofuz
parents:
diff changeset
611 *******.... .... ...+++++++++*************
anatofuz
parents:
diff changeset
612 *******.... . ...+++++++++*************
anatofuz
parents:
diff changeset
613 *******+++++...... ...+++++++++*************
anatofuz
parents:
diff changeset
614 *******++++++....... ..+++++++++*************
anatofuz
parents:
diff changeset
615 *******++++++++...... .+++++++++*************
anatofuz
parents:
diff changeset
616 *******+++++++++..... ..+++++++++*************
anatofuz
parents:
diff changeset
617 ********++++++++++... .......... .++++++++**************
anatofuz
parents:
diff changeset
618 ********++++++++++++............ ...++++++++**************
anatofuz
parents:
diff changeset
619 *********++++++++++++++.......... ...+++++++***************
anatofuz
parents:
diff changeset
620 **********++++++++++++++++........ .+++++++****************
anatofuz
parents:
diff changeset
621 **********++++++++++++++++++++.... ... ..+++++++****************
anatofuz
parents:
diff changeset
622 ***********++++++++++++++++++++++....... .......++++++++*****************
anatofuz
parents:
diff changeset
623 ************+++++++++++++++++++++++...... ......++++++++******************
anatofuz
parents:
diff changeset
624 **************+++++++++++++++++++++++.... ....++++++++********************
anatofuz
parents:
diff changeset
625 ***************+++++++++++++++++++++++..... ...+++++++++*********************
anatofuz
parents:
diff changeset
626 *****************++++++++++++++++++++++.... ...++++++++***********************
anatofuz
parents:
diff changeset
627 *******************+++++++++++++++++++++......++++++++*************************
anatofuz
parents:
diff changeset
628 *********************++++++++++++++++++++++.++++++++***************************
anatofuz
parents:
diff changeset
629 *************************+++++++++++++++++++++++*******************************
anatofuz
parents:
diff changeset
630 ******************************+++++++++++++************************************
anatofuz
parents:
diff changeset
631 *******************************************************************************
anatofuz
parents:
diff changeset
632 *******************************************************************************
anatofuz
parents:
diff changeset
633 *******************************************************************************
anatofuz
parents:
diff changeset
634 Evaluated to 0.000000
anatofuz
parents:
diff changeset
635 ready> mandel(-2, -1, 0.02, 0.04);
anatofuz
parents:
diff changeset
636 **************************+++++++++++++++++++++++++++++++++++++++++++++++++++++
anatofuz
parents:
diff changeset
637 ***********************++++++++++++++++++++++++++++++++++++++++++++++++++++++++
anatofuz
parents:
diff changeset
638 *********************+++++++++++++++++++++++++++++++++++++++++++++++++++++++++.
anatofuz
parents:
diff changeset
639 *******************+++++++++++++++++++++++++++++++++++++++++++++++++++++++++...
anatofuz
parents:
diff changeset
640 *****************+++++++++++++++++++++++++++++++++++++++++++++++++++++++++.....
anatofuz
parents:
diff changeset
641 ***************++++++++++++++++++++++++++++++++++++++++++++++++++++++++........
anatofuz
parents:
diff changeset
642 **************++++++++++++++++++++++++++++++++++++++++++++++++++++++...........
anatofuz
parents:
diff changeset
643 ************+++++++++++++++++++++++++++++++++++++++++++++++++++++..............
anatofuz
parents:
diff changeset
644 ***********++++++++++++++++++++++++++++++++++++++++++++++++++........ .
anatofuz
parents:
diff changeset
645 **********++++++++++++++++++++++++++++++++++++++++++++++.............
anatofuz
parents:
diff changeset
646 ********+++++++++++++++++++++++++++++++++++++++++++..................
anatofuz
parents:
diff changeset
647 *******+++++++++++++++++++++++++++++++++++++++.......................
anatofuz
parents:
diff changeset
648 ******+++++++++++++++++++++++++++++++++++...........................
anatofuz
parents:
diff changeset
649 *****++++++++++++++++++++++++++++++++............................
anatofuz
parents:
diff changeset
650 *****++++++++++++++++++++++++++++...............................
anatofuz
parents:
diff changeset
651 ****++++++++++++++++++++++++++...... .........................
anatofuz
parents:
diff changeset
652 ***++++++++++++++++++++++++......... ...... ...........
anatofuz
parents:
diff changeset
653 ***++++++++++++++++++++++............
anatofuz
parents:
diff changeset
654 **+++++++++++++++++++++..............
anatofuz
parents:
diff changeset
655 **+++++++++++++++++++................
anatofuz
parents:
diff changeset
656 *++++++++++++++++++.................
anatofuz
parents:
diff changeset
657 *++++++++++++++++............ ...
anatofuz
parents:
diff changeset
658 *++++++++++++++..............
anatofuz
parents:
diff changeset
659 *+++....++++................
anatofuz
parents:
diff changeset
660 *.......... ...........
anatofuz
parents:
diff changeset
661 *
anatofuz
parents:
diff changeset
662 *.......... ...........
anatofuz
parents:
diff changeset
663 *+++....++++................
anatofuz
parents:
diff changeset
664 *++++++++++++++..............
anatofuz
parents:
diff changeset
665 *++++++++++++++++............ ...
anatofuz
parents:
diff changeset
666 *++++++++++++++++++.................
anatofuz
parents:
diff changeset
667 **+++++++++++++++++++................
anatofuz
parents:
diff changeset
668 **+++++++++++++++++++++..............
anatofuz
parents:
diff changeset
669 ***++++++++++++++++++++++............
anatofuz
parents:
diff changeset
670 ***++++++++++++++++++++++++......... ...... ...........
anatofuz
parents:
diff changeset
671 ****++++++++++++++++++++++++++...... .........................
anatofuz
parents:
diff changeset
672 *****++++++++++++++++++++++++++++...............................
anatofuz
parents:
diff changeset
673 *****++++++++++++++++++++++++++++++++............................
anatofuz
parents:
diff changeset
674 ******+++++++++++++++++++++++++++++++++++...........................
anatofuz
parents:
diff changeset
675 *******+++++++++++++++++++++++++++++++++++++++.......................
anatofuz
parents:
diff changeset
676 ********+++++++++++++++++++++++++++++++++++++++++++..................
anatofuz
parents:
diff changeset
677 Evaluated to 0.000000
anatofuz
parents:
diff changeset
678 ready> mandel(-0.9, -1.4, 0.02, 0.03);
anatofuz
parents:
diff changeset
679 *******************************************************************************
anatofuz
parents:
diff changeset
680 *******************************************************************************
anatofuz
parents:
diff changeset
681 *******************************************************************************
anatofuz
parents:
diff changeset
682 **********+++++++++++++++++++++************************************************
anatofuz
parents:
diff changeset
683 *+++++++++++++++++++++++++++++++++++++++***************************************
anatofuz
parents:
diff changeset
684 +++++++++++++++++++++++++++++++++++++++++++++**********************************
anatofuz
parents:
diff changeset
685 ++++++++++++++++++++++++++++++++++++++++++++++++++*****************************
anatofuz
parents:
diff changeset
686 ++++++++++++++++++++++++++++++++++++++++++++++++++++++*************************
anatofuz
parents:
diff changeset
687 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++**********************
anatofuz
parents:
diff changeset
688 +++++++++++++++++++++++++++++++++.........++++++++++++++++++*******************
anatofuz
parents:
diff changeset
689 +++++++++++++++++++++++++++++++.... ......+++++++++++++++++++****************
anatofuz
parents:
diff changeset
690 +++++++++++++++++++++++++++++....... ........+++++++++++++++++++**************
anatofuz
parents:
diff changeset
691 ++++++++++++++++++++++++++++........ ........++++++++++++++++++++************
anatofuz
parents:
diff changeset
692 +++++++++++++++++++++++++++......... .. ...+++++++++++++++++++++**********
anatofuz
parents:
diff changeset
693 ++++++++++++++++++++++++++........... ....++++++++++++++++++++++********
anatofuz
parents:
diff changeset
694 ++++++++++++++++++++++++............. .......++++++++++++++++++++++******
anatofuz
parents:
diff changeset
695 +++++++++++++++++++++++............. ........+++++++++++++++++++++++****
anatofuz
parents:
diff changeset
696 ++++++++++++++++++++++........... ..........++++++++++++++++++++++***
anatofuz
parents:
diff changeset
697 ++++++++++++++++++++........... .........++++++++++++++++++++++*
anatofuz
parents:
diff changeset
698 ++++++++++++++++++............ ...........++++++++++++++++++++
anatofuz
parents:
diff changeset
699 ++++++++++++++++............... .............++++++++++++++++++
anatofuz
parents:
diff changeset
700 ++++++++++++++................. ...............++++++++++++++++
anatofuz
parents:
diff changeset
701 ++++++++++++.................. .................++++++++++++++
anatofuz
parents:
diff changeset
702 +++++++++.................. .................+++++++++++++
anatofuz
parents:
diff changeset
703 ++++++........ . ......... ..++++++++++++
anatofuz
parents:
diff changeset
704 ++............ ...... ....++++++++++
anatofuz
parents:
diff changeset
705 .............. ...++++++++++
anatofuz
parents:
diff changeset
706 .............. ....+++++++++
anatofuz
parents:
diff changeset
707 .............. .....++++++++
anatofuz
parents:
diff changeset
708 ............. ......++++++++
anatofuz
parents:
diff changeset
709 ........... .......++++++++
anatofuz
parents:
diff changeset
710 ......... ........+++++++
anatofuz
parents:
diff changeset
711 ......... ........+++++++
anatofuz
parents:
diff changeset
712 ......... ....+++++++
anatofuz
parents:
diff changeset
713 ........ ...+++++++
anatofuz
parents:
diff changeset
714 ....... ...+++++++
anatofuz
parents:
diff changeset
715 ....+++++++
anatofuz
parents:
diff changeset
716 .....+++++++
anatofuz
parents:
diff changeset
717 ....+++++++
anatofuz
parents:
diff changeset
718 ....+++++++
anatofuz
parents:
diff changeset
719 ....+++++++
anatofuz
parents:
diff changeset
720 Evaluated to 0.000000
anatofuz
parents:
diff changeset
721 ready> ^D
anatofuz
parents:
diff changeset
722
anatofuz
parents:
diff changeset
723 At this point, you may be starting to realize that Kaleidoscope is a
anatofuz
parents:
diff changeset
724 real and powerful language. It may not be self-similar :), but it can be
anatofuz
parents:
diff changeset
725 used to plot things that are!
anatofuz
parents:
diff changeset
726
anatofuz
parents:
diff changeset
727 With this, we conclude the "adding user-defined operators" chapter of
anatofuz
parents:
diff changeset
728 the tutorial. We have successfully augmented our language, adding the
anatofuz
parents:
diff changeset
729 ability to extend the language in the library, and we have shown how
anatofuz
parents:
diff changeset
730 this can be used to build a simple but interesting end-user application
anatofuz
parents:
diff changeset
731 in Kaleidoscope. At this point, Kaleidoscope can build a variety of
anatofuz
parents:
diff changeset
732 applications that are functional and can call functions with
anatofuz
parents:
diff changeset
733 side-effects, but it can't actually define and mutate a variable itself.
anatofuz
parents:
diff changeset
734
anatofuz
parents:
diff changeset
735 Strikingly, variable mutation is an important feature of some languages,
anatofuz
parents:
diff changeset
736 and it is not at all obvious how to `add support for mutable
anatofuz
parents:
diff changeset
737 variables <LangImpl07.html>`_ without having to add an "SSA construction"
anatofuz
parents:
diff changeset
738 phase to your front-end. In the next chapter, we will describe how you
anatofuz
parents:
diff changeset
739 can add variable mutation without building SSA in your front-end.
anatofuz
parents:
diff changeset
740
anatofuz
parents:
diff changeset
741 Full Code Listing
anatofuz
parents:
diff changeset
742 =================
anatofuz
parents:
diff changeset
743
anatofuz
parents:
diff changeset
744 Here is the complete code listing for our running example, enhanced with
anatofuz
parents:
diff changeset
745 the support for user-defined operators. To build this example, use:
anatofuz
parents:
diff changeset
746
anatofuz
parents:
diff changeset
747 .. code-block:: bash
anatofuz
parents:
diff changeset
748
anatofuz
parents:
diff changeset
749 # Compile
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
750 clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
150
anatofuz
parents:
diff changeset
751 # Run
anatofuz
parents:
diff changeset
752 ./toy
anatofuz
parents:
diff changeset
753
anatofuz
parents:
diff changeset
754 On some platforms, you will need to specify -rdynamic or
anatofuz
parents:
diff changeset
755 -Wl,--export-dynamic when linking. This ensures that symbols defined in
anatofuz
parents:
diff changeset
756 the main executable are exported to the dynamic linker and so are
anatofuz
parents:
diff changeset
757 available for symbol resolution at run time. This is not needed if you
anatofuz
parents:
diff changeset
758 compile your support code into a shared library, although doing that
anatofuz
parents:
diff changeset
759 will cause problems on Windows.
anatofuz
parents:
diff changeset
760
anatofuz
parents:
diff changeset
761 Here is the code:
anatofuz
parents:
diff changeset
762
anatofuz
parents:
diff changeset
763 .. literalinclude:: ../../../examples/Kaleidoscope/Chapter6/toy.cpp
anatofuz
parents:
diff changeset
764 :language: c++
anatofuz
parents:
diff changeset
765
anatofuz
parents:
diff changeset
766 `Next: Extending the language: mutable variables / SSA
anatofuz
parents:
diff changeset
767 construction <LangImpl07.html>`_
anatofuz
parents:
diff changeset
768