Code spacing.

This commit is contained in:
Maggie Mari 2012-08-19 12:13:48 -05:00
commit 9eecd92c7e

View file

@ -37,8 +37,11 @@ sort of thing:
.. code-block:: python .. code-block:: python
def fib(x) if x < 3 then 1 else fib(x-1) + def fib(x)
fib(x-2) if x < 3 then
1
else
fib(x-1) + fib(x-2)
@ -69,8 +72,12 @@ for the relevant tokens:
.. code-block:: python .. code-block:: python
class IfToken(object): pass class class IfToken(object):
ThenToken(object): pass class ElseToken(object): pass pass
class ThenToken(object):
pass
class ElseToken(object):
pass
@ -80,11 +87,19 @@ pretty simple stuff:
.. code-block:: python .. code-block:: python
... if identifier == 'def': yield DefToken() elif ...
identifier == 'extern': yield ExternToken() elif identifier == 'if': if identifier == 'def':
yield IfToken() elif identifier == 'then': yield ThenToken() elif yield DefToken()
identifier == 'else': yield ElseToken() else: yield elif identifier == 'extern':
IdentifierToken(identifier) yield ExternToken()
elif identifier == 'if':
yield IfToken()
elif identifier == 'then':
yield ThenToken()
elif identifier == 'else':
yield ElseToken()
else:
yield IdentifierToken(identifier)
@ -96,14 +111,16 @@ To represent the new expression we add a new AST node for it:
.. code-block:: python .. code-block:: python
# Expression class for if/then/else. class # Expression class for if/then/else.
IfExpressionNode(ExpressionNode): class IfExpressionNode(ExpressionNode):
def __init__(self, condition, then_branch, else_branch): def __init__(self, condition, then_branch, else_branch):
self.condition = condition self.then_branch = then_branch self.condition = condition
self.then_branch = then_branch
self.else_branch = else_branch self.else_branch = else_branch
def CodeGen(self): ... def CodeGen(self):
...
@ -119,10 +136,9 @@ First we define a new parsing function:
.. code-block:: python .. code-block:: python
# ifexpr ::= 'if' expression 'then' expression # ifexpr ::= 'if' expression 'then' expression 'else' expression
'else' expression def ParseIfExpr(self): self.Next() # eat the if. def ParseIfExpr(self):
self.Next() # eat the if.
::
# condition. # condition.
condition = self.ParseExpression() condition = self.ParseExpression()
@ -150,13 +166,17 @@ Next we hook it up as a primary expression:
.. code-block:: python .. code-block:: python
def ParsePrimary(self): if def ParsePrimary(self):
isinstance(self.current, IdentifierToken): return if isinstance(self.current, IdentifierToken):
self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): return self.ParseIdentifierExpr()
return self.ParseNumberExpr(); elif isinstance(self.current, IfToken): elif isinstance(self.current, NumberToken):
return self.ParseIfExpr() elif self.current == CharacterToken('('): return self.ParseNumberExpr();
return self.ParseParenExpr() else: raise RuntimeError('Unknown token elif isinstance(self.current, IfToken):
when expecting an expression.') return self.ParseIfExpr()
elif self.current == CharacterToken('('):
return self.ParseParenExpr()
else:
raise RuntimeError('Unknown token when expecting an expression.')
@ -175,8 +195,9 @@ example. Consider:
.. code-block:: python .. code-block:: python
extern foo(); extern bar(); def baz(x) if x then extern foo();
foo() else bar(); extern bar();
def baz(x) if x then foo() else bar();
@ -186,13 +207,26 @@ Kaleidoscope looks something like this:
.. code-block:: llvm .. code-block:: llvm
declare double @foo() declare double @bar() define declare double @foo()
double @baz(double %x) { entry: %ifcond = fcmp one double %x,
0.000000e+00 br i1 %ifcond, label %then, label %else then: ; preds = declare double @bar()
%entry %calltmp1 = call double @bar() else: ; preds = %entry %calltmp1 =
call double @bar() br label %ifcont ifcont: ; preds = %else, %then define double @baz(double %x) {
%iftmp = phi double [ %calltmp, %then ], [ %calltmp1, %else ] ret double entry:
%iftmp } %ifcond = fcmp one double %x, 0.000000e+00
br i1 %ifcond, label %then, label %else
then: ; preds = %entry
%calltmp1 = call double @bar()
else: ; preds = %entry
%calltmp1 = call double @bar()
br label %ifcont
ifcont: ; preds = %else, %then
%iftmp = phi double [ %calltmp, %then ], [ %calltmp1, %else ]
ret double %iftmp
}
@ -247,8 +281,8 @@ practice, there are two sorts of values that float around in code
written for your average imperative programming language that might need written for your average imperative programming language that might need
Phi nodes: Phi nodes:
1. Code that involves user variables: ``x = 1; x = x + 1;`` - 1. Code that involves user variables: ``x = 1; x = x + 1;``
2. Values that are implicit in the structure of your AST, such as the - 2. Values that are implicit in the structure of your AST, such as the
Phi node in this case. Phi node in this case.
In `Chapter 7 <PythonLangImpl7.html>`_ of this tutorial ("mutable In `Chapter 7 <PythonLangImpl7.html>`_ of this tutorial ("mutable
@ -269,10 +303,8 @@ for ``IfExpressionNode``:
.. code-block:: python .. code-block:: python
def CodeGen(self): condition = def CodeGen(self):
self.condition.CodeGen() condition = self.condition.CodeGen()
::
# Convert condition to a bool by comparing equal to 0.0. # Convert condition to a bool by comparing equal to 0.0.
condition_bool = g_llvm_builder.fcmp( condition_bool = g_llvm_builder.fcmp(
@ -291,8 +323,6 @@ a truth value as a 1-bit (bool) value.
function = g_llvm_builder.basic_block.function function = g_llvm_builder.basic_block.function
::
# Create blocks for the then and else cases. Insert the 'then' block at the # Create blocks for the then and else cases. Insert the 'then' block at the
# end of the function. # end of the function.
then_block = function.append_basic_block('then') then_block = function.append_basic_block('then')
@ -322,10 +352,9 @@ still inserting into the block that the condition went into.
.. code-block:: python .. code-block:: python
# Emit then value. # Emit then value.
g_llvm_builder.position_at_end(then_block) then_value = g_llvm_builder.position_at_end(then_block)
self.then_branch.CodeGen() g_llvm_builder.branch(merge_block) then_value = self.then_branch.CodeGen()
g_llvm_builder.branch(merge_block)
::
# Codegen of 'Then' can change the current block; update then_block for the # Codegen of 'Then' can change the current block; update then_block for the
# PHI node. # PHI node.
@ -369,10 +398,9 @@ value for code that will set up the Phi node.
.. code-block:: python .. code-block:: python
# Emit else block. # Emit else block.
g_llvm_builder.position_at_end(else_block) else_value = g_llvm_builder.position_at_end(else_block)
self.else_branch.CodeGen() g_llvm_builder.branch(merge_block) else_value = self.else_branch.CodeGen()
g_llvm_builder.branch(merge_block)
::
# Codegen of 'Else' can change the current block, update else_block for the # Codegen of 'Else' can change the current block, update else_block for the
# PHI node. # PHI node.
@ -393,13 +421,11 @@ code:
.. code-block:: python .. code-block:: python
# Emit merge block. # Emit merge block.
g_llvm_builder.position_at_end(merge_block) phi = g_llvm_builder.position_at_end(merge_block)
g_llvm_builder.phi(Type.double(), 'iftmp') phi = g_llvm_builder.phi(Type.double(), 'iftmp')
phi.add_incoming(then_value, then_block) phi.add_incoming(then_value, then_block)
phi.add_incoming(else_value, else_block) phi.add_incoming(else_value, else_block)
::
return phi return phi
@ -433,10 +459,10 @@ something more aggressive, a 'for' expression:
.. code-block:: python .. code-block:: python
extern putchard(char) def printstar(n) for i = 1, extern putchard(char)
i < n, 1.0 in putchard(42) # ascii 42 = '\*' def printstar(n)
for i = 1, i < n, 1.0 in
:: putchard(42) # ascii 42 = '*'
# print 100 '*' characters # print 100 '*' characters
printstar(100) printstar(100)
@ -466,15 +492,19 @@ The lexer extensions are the same sort of thing as for if/then/else:
... ...
class ThenToken(object): pass class ElseToken(object): pass class class ThenToken(object):
ForToken(object): pass class InToken(object): pass pass
class ElseToken(object):
pass
class ForToken(object):
pass
class InToken(object):
pass
... ...
def Tokenize(string): def Tokenize(string):
::
... ...
elif identifier == 'else': elif identifier == 'else':
@ -499,14 +529,18 @@ variable name and the constituent expressions in the node.
.. code-block:: python .. code-block:: python
# Expression class for for/in. class # Expression class for for/in.
ForExpressionNode(ExpressionNode): class ForExpressionNode(ExpressionNode):
def __init__(self, loop_variable, start, end, step, body): def __init__(self, loop_variable, start, end, step, body):
self.loop_variable = loop_variable self.start = start self.end = end self.loop_variable = loop_variable
self.step = step self.body = body self.start = start
self.end = end
self.step = step
self.body = body
def CodeGen(self): ... def CodeGen(self):
...
@ -521,11 +555,9 @@ value to null in the AST node:
.. code-block:: python .. code-block:: python
# forexpr ::= 'for' identifier '=' expr ',' expr # forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression
(',' expr)? 'in' expression def ParseForExpr(self): self.Next() # eat def ParseForExpr(self):
the for. self.Next() # eat the for.
::
if not isinstance(self.current, IdentifierToken): if not isinstance(self.current, IdentifierToken):
raise RuntimeError('Expected identifier after for.') raise RuntimeError('Expected identifier after for.')
@ -574,16 +606,30 @@ this dump is generated with optimizations disabled for clarity):
.. code-block:: llvm .. code-block:: llvm
declare double @putchard(double) define double declare double @putchard(double)
@printstar(double %n) { entry: ; initial value = 1.0 (inlined into phi)
br label %loop loop: ; preds = %loop, %entry %i = phi double [ define double @printstar(double %n) {
1.000000e+00, %entry ], [ %nextvar, %loop ] ; body %calltmp = call entry:
double @putchard(double 4.200000e+01) ; increment %nextvar = fadd double ; initial value = 1.0 (inlined into phi)
%i, 1.000000e+00 ; termination test %cmptmp = fcmp ult double %i, %n br label %loop
%booltmp = uitofp i1 %cmptmp to double %loopcond = fcmp one double
%booltmp, 0.000000e+00 br i1 %loopcond, label %loop, label %afterloop loop: ; preds = %loop, %entry
afterloop: ; preds = %loop ; loop always returns 0.0 ret double %i = phi double [
0.000000e+00 } 1.000000e+00, %entry ], [ %nextvar, %loop ]
; body
%calltmp = call double @putchard(double 4.200000e+01)
; increment
%nextvar = fadd double %i, 1.000000e+00
; termination test
%cmptmp = fcmp ult double %i, %n
%booltmp = uitofp i1 %cmptmp to double
%loopcond = fcmp one double %booltmp, 0.000000e+00
br i1 %loopcond, label %loop, label %afterloop
afterloop: ; preds = %loop
; loop always returns 0.0
ret double 0.000000e+00 }
@ -600,22 +646,23 @@ expression for the loop value:
.. code-block:: python .. code-block:: python
def CodeGen(self): # Emit the start code first, def CodeGen(self):
without 'variable' in scope. start_value = self.start.CodeGen() # Emit the start code first, without 'variable' in scope.
start_value = self.start.CodeGen()
With this out of the way, the next step is to set up the LLVM basic With this out of the way, the next step is to set up the LLVM basic
block for the start of the loop body. In the case above, the whole loop block for the start of the loop body. In the case above, the whole loop
body is one block, but remember that the body code itself could consist body is one block, but remember that the body code itself could consist
of multiple blocks (e.g. if it contains an if/then/else or a for/in of multiple blocks (e.g. if it contains an if/then/else or a for/in
expression). expression).
# Make the new basic block for the loop header, .. code-block:: python
inserting after current # block. function =
g_llvm_builder.basic_block.function pre_header_block =
g_llvm_builder.basic_block loop_block =
function.append_basic_block('loop')
:: # Make the new basic block for the loop header, inserting after current
# block.
function = g_llvm_builder.basic_block.function
pre_header_block = g_llvm_builder.basic_block
loop_block = function.append_basic_block('loop')
# Insert an explicit fallthrough from the current block to the loop_block. # Insert an explicit fallthrough from the current block to the loop_block.
g_llvm_builder.branch(loop_block) g_llvm_builder.branch(loop_block)
@ -636,8 +683,6 @@ the two blocks.
# Start insertion in loop_block. # Start insertion in loop_block.
g_llvm_builder.position_at_end(loop_block); g_llvm_builder.position_at_end(loop_block);
::
# Start the PHI node with an entry for start. # Start the PHI node with an entry for start.
variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable)
variable_phi.add_incoming(start_value, pre_header_block) variable_phi.add_incoming(start_value, pre_header_block)
@ -656,14 +701,11 @@ backedge, but we can't set it up yet (because it doesn't exist!).
.. code-block:: python .. code-block:: python
# Within the loop, the variable is defined equal # Within the loop, the variable is defined equal to the PHI node. If it
to the PHI node. If it # shadows an existing variable, we have to # shadows an existing variable, we have to restore it, so save it now.
restore it, so save it now. old_value = old_value = g_named_values.get(self.loop_variable, None)
g_named_values.get(self.loop_variable, None)
g_named_values[self.loop_variable] = variable_phi g_named_values[self.loop_variable] = variable_phi
::
# Emit the body of the loop. This, like any other expr, can change the # Emit the body of the loop. This, like any other expr, can change the
# current BB. Note that we ignore the value computed by the body. # current BB. Note that we ignore the value computed by the body.
self.body.CodeGen() self.body.CodeGen()
@ -692,11 +734,12 @@ table.
.. code-block:: python .. code-block:: python
# Emit the step value. if self.step: step_value # Emit the step value.
= self.step.CodeGen() else: # If not specified, use 1.0. step_value = if self.step:
Constant.real(Type.double(), 1) step_value = self.step.CodeGen()
else:
:: # If not specified, use 1.0.
step_value = Constant.real(Type.double(), 1)
next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next')
@ -712,10 +755,10 @@ iteration of the loop.
.. code-block:: python .. code-block:: python
# Compute the end condition and convert it to a # Compute the end condition and convert it to a bool by comparing to 0.0.
bool by comparing to 0.0. end_condition = self.end.CodeGen() end_condition = self.end.CodeGen()
end_condition_bool = g_llvm_builder.fcmp( FCMP_ONE, end_condition, end_condition_bool = g_llvm_builder.fcmp(
Constant.real(Type.double(), 0), 'loopcond') FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond')
@ -727,10 +770,8 @@ if/then/else statement.
.. code-block:: python .. code-block:: python
# Create the "after loop" block and insert it. # Create the "after loop" block and insert it.
loop_end_block = g_llvm_builder.basic_block after_block = loop_end_block = g_llvm_builder.basic_block
function.append_basic_block('afterloop') after_block = function.append_basic_block('afterloop')
::
# Insert the conditional branch into the end of loop_end_block. # Insert the conditional branch into the end of loop_end_block.
g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block)
@ -753,10 +794,8 @@ insertion position to it.
.. code-block:: python .. code-block:: python
# Add a new entry to the PHI node for the # Add a new entry to the PHI node for the backedge.
backedge. variable_phi.add_incoming(next_value, loop_end_block) variable_phi.add_incoming(next_value, loop_end_block)
::
# Restore the unshadowed variable. # Restore the unshadowed variable.
if old_value: if old_value:
@ -798,16 +837,21 @@ the if/then/else and for expressions:
#!/usr/bin/env python #!/usr/bin/env python
import re from llvm.core import Module, Constant, Type, Function, import re
Builder from llvm.ee import ExecutionEngine, TargetData from llvm.passes from llvm.core import Module, Constant, Type, Function, Builder
import FunctionPassManager from llvm.ee import ExecutionEngine, TargetData
from llvm.passes import FunctionPassManager
from llvm.core import FCMP_ULT, FCMP_ONE from llvm.passes import from llvm.core import FCMP_ULT, FCMP_ONE
(PASS_INSTRUCTION_COMBINING, PASS_REASSOCIATE, PASS_GVN, from llvm.passes import (PASS_INSTRUCTION_COMBINING,
PASS_REASSOCIATE,
PASS_GVN,
PASS_CFG_SIMPLIFICATION) PASS_CFG_SIMPLIFICATION)
Globals Globals
------- -------
.. code-block:: python
# The LLVM module, which holds all the IR code. # The LLVM module, which holds all the IR code.
g_llvm_module = Module.new('my cool jit') g_llvm_module = Module.new('my cool jit')
@ -825,34 +869,56 @@ the if/then/else and for expressions:
# The LLVM execution engine. # The LLVM execution engine.
g_llvm_executor = ExecutionEngine.new(g_llvm_module) g_llvm_executor = ExecutionEngine.new(g_llvm_module)
Lexer Lexer
----- -----
.. code-block:: python
# The lexer yields one of these types for each token. # The lexer yields one of these types for each token.
class EOFToken(object): pass class DefToken(object): pass class class EOFToken(object):
ExternToken(object): pass class IfToken(object): pass class pass
ThenToken(object): pass class ElseToken(object): pass class class DefToken(object):
ForToken(object): pass class InToken(object): pass pass
class ExternToken(object):
pass
class IfToken(object):
pass
class ThenToken(object):
pass
class ElseToken(object):
pass
class ForToken(object):
pass
class InToken(object):
pass
class IdentifierToken(object): def __init__(self, name): self.name = class IdentifierToken(object):
name def __init__(self, name):
self.name = name
class NumberToken(object): def __init__(self, value): self.value = class NumberToken(object):
value def __init__(self, value):
self.value = value
class CharacterToken(object): def __init__(self, char): self.char = class CharacterToken(object):
char def __eq__(self, other): return isinstance(other, CharacterToken) def __init__(self, char):
and self.char == other.char def __ne__(self, other): return not self self.char = char
== other def __eq__(self, other):
return isinstance(other, CharacterToken) and self.char == other.char
def __ne__(self, other):
return not self == other
# Regular expressions that tokens and comments of our language. # Regular expressions that tokens and comments of our language.
REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX_IDENTIFIER = REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?')
re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX_COMMENT = re.compile('#.*') REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]\ *')
REGEX_COMMENT = re.compile('#.*')
def Tokenize(string): while string: # Skip whitespace. if def Tokenize(string):
string[0].isspace(): string = string[1:] continue while string:
# Skip whitespace.
:: if string[0].isspace():
string = string[1:]
continue
# Run regexes. # Run regexes.
comment_match = REGEX_COMMENT.match(string) comment_match = REGEX_COMMENT.match(string)
@ -894,38 +960,47 @@ the if/then/else and for expressions:
yield EOFToken() yield EOFToken()
Abstract Syntax Tree (aka Parse Tree) Abstract Syntax Tree (aka Parse Tree)
------------------------------------- -------------------------------------
.. code-block:: python
# Base class for all expression nodes. # Base class for all expression nodes.
class ExpressionNode(object): pass class ExpressionNode(object):
pass
# Expression class for numeric literals like "1.0". # Expression class for numeric literals like "1.0".
class NumberExpressionNode(ExpressionNode): class NumberExpressionNode(ExpressionNode):
def __init__(self, value): self.value = value def __init__(self, value):
self.value = value
def CodeGen(self): return Constant.real(Type.double(), self.value) def CodeGen(self):
return Constant.real(Type.double(), self.value)
# Expression class for referencing a variable, like "a". # Expression class for referencing a variable, like "a".
class VariableExpressionNode(ExpressionNode): class VariableExpressionNode(ExpressionNode):
def __init__(self, name): self.name = name def __init__(self, name):
self.name = name
def CodeGen(self): if self.name in g_named_values: return def CodeGen(self):
g_named_values[self.name] else: raise RuntimeError('Unknown variable if self.name in g_named_values:
name: ' + self.name) return g_named_values[self.name]
else:
raise RuntimeError('Unknown variable name: ' + self.name)
# Expression class for a binary operator. # Expression class for a binary operator.
class BinaryOperatorExpressionNode(ExpressionNode): class BinaryOperatorExpressionNode(ExpressionNode):
def __init__(self, operator, left, right): self.operator = operator def __init__(self, operator, left, right):
self.left = left self.right = right self.operator = operator
self.left = left
self.right = right
def CodeGen(self): left = self.left.CodeGen() right = def CodeGen(self):
self.right.CodeGen() left = self.left.CodeGen()
right = self.right.CodeGen()
::
if self.operator == '+': if self.operator == '+':
return g_llvm_builder.fadd(left, right, 'addtmp') return g_llvm_builder.fadd(left, right, 'addtmp')
@ -943,13 +1018,13 @@ the if/then/else and for expressions:
# Expression class for function calls. # Expression class for function calls.
class CallExpressionNode(ExpressionNode): class CallExpressionNode(ExpressionNode):
def __init__(self, callee, args): self.callee = callee self.args = def __init__(self, callee, args):
args self.callee = callee
self.args = args
def CodeGen(self): # Look up the name in the global module table. callee def CodeGen(self):
= g_llvm_module.get_function_named(self.callee) # Look up the name in the global module table.
callee = g_llvm_module.get_function_named(self.callee)
::
# Check for argument mismatch error. # Check for argument mismatch error.
if len(callee.args) != len(self.args): if len(callee.args) != len(self.args):
@ -963,12 +1038,12 @@ the if/then/else and for expressions:
class IfExpressionNode(ExpressionNode): class IfExpressionNode(ExpressionNode):
def __init__(self, condition, then_branch, else_branch): def __init__(self, condition, then_branch, else_branch):
self.condition = condition self.then_branch = then_branch self.condition = condition
self.then_branch = then_branch
self.else_branch = else_branch self.else_branch = else_branch
def CodeGen(self): condition = self.condition.CodeGen() def CodeGen(self):
condition = self.condition.CodeGen()
::
# Convert condition to a bool by comparing equal to 0.0. # Convert condition to a bool by comparing equal to 0.0.
condition_bool = g_llvm_builder.fcmp( condition_bool = g_llvm_builder.fcmp(
@ -1014,16 +1089,26 @@ the if/then/else and for expressions:
class ForExpressionNode(ExpressionNode): class ForExpressionNode(ExpressionNode):
def __init__(self, loop_variable, start, end, step, body): def __init__(self, loop_variable, start, end, step, body):
self.loop_variable = loop_variable self.start = start self.end = end self.loop_variable = loop_variable
self.step = step self.body = body self.start = start
self.end = end
self.step = step
self.body = body
def CodeGen(self): # Output this as: # ... # start = startexpr # goto def CodeGen(self):
loop # loop: # variable = phi [start, loopheader], [nextvariable, # Output this as:
loopend] # ... # bodyexpr # ... # loopend: # step = stepexpr # # ...
nextvariable = variable + step # endcond = endexpr # br endcond, loop, # start = startexpr
endloop # outloop: # goto loop
# loop:
:: # variable = phi [start, loopheader], [nextvariable, loopend]
# ...
# bodyexpr
# ...
# loopend:
# step = stepexpr
# nextvariable = variable + step # endcond = endexpr # br endcond, loop, endloop
# outloop:
# Emit the start code first, without 'variable' in scope. # Emit the start code first, without 'variable' in scope.
start_value = self.start.CodeGen() start_value = self.start.CodeGen()
@ -1094,13 +1179,14 @@ the if/then/else and for expressions:
# takes). # takes).
class PrototypeNode(object): class PrototypeNode(object):
def __init__(self, name, args): self.name = name self.args = args def __init__(self, name, args):
self.name = name
self.args = args
def CodeGen(self): # Make the function type, eg. double(double,double). def CodeGen(self):
funct_type = Type.function( Type.double(), [Type.double()] \* # Make the function type, eg. double(double,double).
len(self.args), False) funct_type = Type.function(
Type.double(), [Type.double()] * len(self.args), False)
::
function = Function.new(g_llvm_module, funct_type, self.name) function = Function.new(g_llvm_module, funct_type, self.name)
@ -1130,12 +1216,13 @@ the if/then/else and for expressions:
# This class represents a function definition itself. # This class represents a function definition itself.
class FunctionNode(object): class FunctionNode(object):
def __init__(self, prototype, body): self.prototype = prototype def __init__(self, prototype, body):
self.prototype = prototype
self.body = body self.body = body
def CodeGen(self): # Clear scope. g_named_values.clear() def CodeGen(self):
# Clear scope.
:: g_named_values.clear()
# Create a function object. # Create a function object.
function = self.prototype.CodeGen() function = self.prototype.CodeGen()
@ -1161,30 +1248,36 @@ the if/then/else and for expressions:
return function return function
Parser Parser
------ ------
.. code-block:: python
class Parser(object): class Parser(object):
def __init__(self, tokens, binop_precedence): self.tokens = tokens def __init__(self, tokens, binop_precedence):
self.tokens = tokens
self.binop_precedence = binop_precedence self.Next() self.binop_precedence = binop_precedence self.Next()
# Provide a simple token buffer. Parser.current is the current token the # Provide a simple token buffer. Parser.current is the current token the
# parser is looking at. Parser.Next() reads another token from the lexer # parser is looking at. Parser.Next() reads another token from the lexer and
and # updates Parser.current with its results. def Next(self): # updates Parser.current with its results.
def Next(self):
self.current = self.tokens.next() self.current = self.tokens.next()
# Gets the precedence of the current token, or -1 if the token is not a # Gets the precedence of the current token, or -1 if the token is not a binary
binary # operator. def GetCurrentTokenPrecedence(self): if # operator.
isinstance(self.current, CharacterToken): return def GetCurrentTokenPrecedence(self):
self.binop_precedence.get(self.current.char, -1) else: return -1 if isinstance(self.current, CharacterToken):
return self.binop_precedence.get(self.current.char, -1)
else:
return -1
# identifierexpr ::= identifier \| identifier '(' expression\* ')' def # identifierexpr ::= identifier | identifier '(' expression* ')'
ParseIdentifierExpr(self): identifier_name = self.current.name def ParseIdentifierExpr(self):
identifier_name = self.current.name
self.Next() # eat identifier. self.Next() # eat identifier.
::
if self.current != CharacterToken('('): # Simple variable reference. if self.current != CharacterToken('('): # Simple variable reference.
return VariableExpressionNode(identifier_name) return VariableExpressionNode(identifier_name)
@ -1203,14 +1296,17 @@ the if/then/else and for expressions:
self.Next() # eat ')'. self.Next() # eat ')'.
return CallExpressionNode(identifier_name, args) return CallExpressionNode(identifier_name, args)
# numberexpr ::= number def ParseNumberExpr(self): result = # numberexpr ::= number
NumberExpressionNode(self.current.value) self.Next() # consume the def ParseNumberExpr(self):
number. return result result = NumberExpressionNode(self.current.value)
self.Next() # consume the number.
return result
# parenexpr ::= '(' expression ')'
def ParseParenExpr(self):
self.Next() # eat '('.
# parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next()
# eat '('.
::
contents = self.ParseExpression() contents = self.ParseExpression()
@ -1220,10 +1316,9 @@ the if/then/else and for expressions:
return contents return contents
# ifexpr ::= 'if' expression 'then' expression 'else' expression def # ifexpr ::= 'if' expression 'then' expression 'else' expression
ParseIfExpr(self): self.Next() # eat the if. def ParseIfExpr(self):
self.Next() # eat the if.
::
# condition. # condition.
condition = self.ParseExpression() condition = self.ParseExpression()
@ -1243,9 +1338,9 @@ the if/then/else and for expressions:
return IfExpressionNode(condition, then_branch, else_branch) return IfExpressionNode(condition, then_branch, else_branch)
# forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' # forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in'
expression def ParseForExpr(self): self.Next() # eat the for. expression
def ParseForExpr(self):
:: self.Next() # eat the for.
if not isinstance(self.current, IdentifierToken): if not isinstance(self.current, IdentifierToken):
raise RuntimeError('Expected identifier after for.') raise RuntimeError('Expected identifier after for.')