Edited code blocks, fixed links.

This commit is contained in:
Maggie Mari 2012-08-16 12:03:41 -05:00
commit c30095c77c
2 changed files with 419 additions and 341 deletions

View file

@ -13,10 +13,10 @@ with the LLVM APIs. It should also be easier to create working
prototypes and experimental languages using this medium. prototypes and experimental languages using this medium.
Together with `clang <http://clang.llvm.org/>`_ or Together with `clang <http://clang.llvm.org/>`_ or
`llvm-gcc <http://llvm.org/cmds/llvmgcc.html>`_ it also a provides a `llvm-gcc <http://llvm.org/releases/2.7/docs/CommandGuide/html/llvmgcc.html>`_
means to quickly instrument C and C++ sources. For e.g., llvm-gcc can be it also a provides a means to quickly instrument C and C++ sources. For e.g.,
used to generate the LLVM assembly for a given C source file, which can llvm-gcc can be used to generate the LLVM assembly for a given C source file,
then be loaded and manipulated (adding profiling code to every function, which can then be loaded and manipulated (adding profiling code to every function,
say) using a llvmpy based Python script. say) using a llvmpy based Python script.
License License
@ -49,7 +49,7 @@ welcome).
Installation Installation
============ ============
The Git repo of llvmpy is at https://github.com/numba/llvmpy.git. The Git repo of llvmpy is at https://github.com/llvmpy/llvmpy.git.
You'll need to build and install it before it can be used. At least the You'll need to build and install it before it can be used. At least the
following will be required for this: following will be required for this:

View file

@ -406,11 +406,12 @@ prototype. Code generation of the prototype ensures that there is an
LLVM Function object that is ready to go for us. LLVM Function object that is ready to go for us.
.. code-block:: python ::
# Create a new basic block to start insertion into. # Create a new basic block to start insertion into.
block = function.append_basic_block('entry') block = function.append_basic_block('entry')
global g_llvm_builder g_llvm_builder = Builder.new(block) global g_llvm_builder
g_llvm_builder = Builder.new(block)
@ -428,10 +429,10 @@ Graph <http://en.wikipedia.org/wiki/Control_flow_graph>`_. Since we
don't have any control flow, our functions will only contain one block don't have any control flow, our functions will only contain one block
at this point. We'll fix this in `Chapter 5 <PythonLangImpl5.html>`_ :). at this point. We'll fix this in `Chapter 5 <PythonLangImpl5.html>`_ :).
.. code-block:: python ::
# Finish off the function. # Finish off the function.
try: try:
return_value = self.body.CodeGen() return_value = self.body.CodeGen()
g_llvm_builder.ret(return_value) g_llvm_builder.ret(return_value)
@ -539,11 +540,15 @@ LLVM builder calls that we use to create the instructions.
.. code-block:: bash .. code-block:: bash
ready> def bar(a) foo(a, 4.0) + bar(31337) Read a ready> def bar(a) foo(a, 4.0) + bar(31337)
function definition: define double @bar(double %a) { entry: %calltmp = Read a function definition:
call double @foo(double %a, double 4.000000e+00) ; <double> [#uses=1] %calltmp1 = define double @bar(double %a) {
call double @bar(double 3.133700e+04) ; <double> [#uses=1] %addtmp = fadd double entry:
%calltmp, %calltmp1 ; <double> [#uses=1] ret double %addtmp } %calltmp = call double @foo(double %a, double 4.000000e+00) ; <double> [#uses=1]
%calltmp1 = call double @bar(double 3.133700e+04) ; <double> [#uses=1]
%addtmp = fadd double %calltmp, %calltmp1 ; <double> [#uses=1]
ret double %addtmp
}
@ -554,12 +559,17 @@ control flow to actually make recursion useful :).
.. code-block:: bash .. code-block:: bash
ready> extern cos(x) Read extern: declare double ready> extern cos(x)
@cos(double) Read extern:
declare double @cos(double)
ready> cos(1.234) Read a top-level expression: define double @1() { ready> cos(1.234)
entry: %calltmp = call double @cos(double 1.234000e+00) ; <double> [#uses=1] ret Read a top-level expression:
double %calltmp } define double @1() {
entry:
%calltmp = call double @cos(double 1.234000e+00) ; <double> [#uses=1]
ret double %calltmp
}
@ -568,26 +578,40 @@ This shows an extern for the libm "cos" function, and a call to it.
.. code-block:: bash .. code-block:: bash
ready> ^C ; ModuleID = 'my cool jit' ready> ^C
; ModuleID = 'my cool jit'
define double @0() { entry: ret double 9.000000e+00 } define double @0() {
entry:
define double @foo(double %a, double %b) { entry: %multmp = fmul double ret double 9.000000e+00
%a, %a ; <double> [#uses=1] %multmp1 = fmul double 2.000000e+00, %a ; <double> [#uses=1]
%multmp2 = fmul double %multmp1, %b ; <double> [#uses=1] %addtmp = fadd double
%multmp, %multmp2 ; <double> [#uses=1] %multmp3 = fmul double %b, %b ; <double> [#uses=1]
%addtmp4 = fadd double %addtmp, %multmp3 ; <double> [#uses=1] ret double %addtmp4
} }
define double @bar(double %a) { entry: %calltmp = call double define double @foo(double %a, double %b) {
@foo(double %a, double 4.000000e+00) ; <double> [#uses=1] %calltmp1 = call double entry:
@bar(double 3.133700e+04) ; <double> [#uses=1] %addtmp = fadd double %calltmp, %multmp = fmul double %a, %a ; <double> [#uses=1]
%calltmp1 ; <double> [#uses=1] ret double %addtmp } %multmp1 = fmul double 2.000000e+00, %a ; <double> [#uses=1]
%multmp2 = fmul double %multmp1, %b ; <double> [#uses=1]
%addtmp = fadd double %multmp, %multmp2 ; <double> [#uses=1]
%multmp3 = fmul double %b, %b ; <double> [#uses=1]
%addtmp4 = fadd double %addtmp, %multmp3 ; <double> [#uses=1]
ret double %addtmp4
}
define double @bar(double %a) {
entry:
%calltmp = call double @foo(double %a, double 4.000000e+00) ; <double> [#uses=1]
%calltmp1 = call double @bar(double 3.133700e+04) ; <double> [#uses=1]
%addtmp = fadd double %calltmp, %calltmp1 ; <double> [#uses=1]
ret double %addtmp
}
declare double @cos(double) declare double @cos(double)
define double @1() { entry: %calltmp = call double @cos(double define double @1() {
1.234000e+00) ; <double> [#uses=1] ret double %calltmp } entry:
%calltmp = call double @cos(double 1.234000e+00) ; <double> [#uses=1]
ret double %calltmp
}
@ -615,8 +639,8 @@ need to `download <../download.html>`_ and
#!/usr/bin/env python #!/usr/bin/env python
import re from llvm.core import Module, Constant, Type, Function, import re
Builder, FCMP_ULT from llvm.core import Module, Constant, Type, Function, Builder, FCMP_ULT
Globals Globals
------- -------
@ -635,59 +659,69 @@ need to `download <../download.html>`_ and
----- -----
# 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 EOFToken(object):
pass
class DefToken(object): pass class DefToken(object):
pass
class ExternToken(object): pass class ExternToken(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 def __eq__(self, other):
== 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.
comment_match = REGEX_COMMENT.match(string)
number_match = REGEX_NUMBER.match(string)
identifier_match = REGEX_IDENTIFIER.match(string)
# Run regexes. # Check if any of the regexes matched and yield the appropriate result.
comment_match = REGEX_COMMENT.match(string) if comment_match:
number_match = REGEX_NUMBER.match(string) comment = comment_match.group(0)
identifier_match = REGEX_IDENTIFIER.match(string) string = string[len(comment):]
elif number_match:
# Check if any of the regexes matched and yield the appropriate result. number = number_match.group(0)
if comment_match: yield NumberToken(float(number))
comment = comment_match.group(0) string = string[len(number):]
string = string[len(comment):] elif identifier_match:
elif number_match: identifier = identifier_match.group(0)
number = number_match.group(0) # Check if we matched a keyword.
yield NumberToken(float(number)) if identifier == 'def':
string = string[len(number):] yield DefToken()
elif identifier_match: elif identifier == 'extern':
identifier = identifier_match.group(0) yield ExternToken()
# Check if we matched a keyword. else:
if identifier == 'def': yield IdentifierToken(identifier)
yield DefToken() string = string[len(identifier):]
elif identifier == 'extern': else:
yield ExternToken() # Yield the ASCII value of the unknown character.
else: yield CharacterToken(string[0])
yield IdentifierToken(identifier) string = string[1:]
string = string[len(identifier):]
else:
# Yield the ASCII value of the unknown character.
yield CharacterToken(string[0])
string = string[1:]
yield EOFToken() yield EOFToken()
@ -695,303 +729,347 @@ need to `download <../download.html>`_ and
------------------------------------- -------------------------------------
# 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.operator = operator
self.left = left self.right = right 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 == '+':
return g_llvm_builder.fadd(left, right, 'addtmp')
if self.operator == '+': elif self.operator == '-':
return g_llvm_builder.fadd(left, right, 'addtmp') return g_llvm_builder.fsub(left, right, 'subtmp')
elif self.operator == '-': elif self.operator == '*':
return g_llvm_builder.fsub(left, right, 'subtmp') return g_llvm_builder.fmul(left, right, 'multmp')
elif self.operator == '*': elif self.operator == '<':
return g_llvm_builder.fmul(left, right, 'multmp') result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp')
elif self.operator == '<': # Convert bool 0 or 1 to double 0.0 or 1.0.
result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') return g_llvm_builder.uitofp(result, Type.double(), 'booltmp')
# Convert bool 0 or 1 to double 0.0 or 1.0. else:
return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') raise RuntimeError('Unknown binary operator.')
else:
raise RuntimeError('Unknown binary operator.')
# 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.
if len(callee.args) != len(self.args):
raise RuntimeError('Incorrect number of arguments passed.')
# Check for argument mismatch error. arg_values = [i.CodeGen() for i in self.args]
if len(callee.args) != len(self.args):
raise RuntimeError('Incorrect number of arguments passed.')
arg_values = [i.CodeGen() for i in self.args] return g_llvm_builder.call(callee, arg_values, 'calltmp')
return g_llvm_builder.call(callee, arg_values, 'calltmp')
# This class represents the "prototype" for a function, which captures its name, # This class represents the "prototype" for a function, which captures its name,
# and its argument names (thus implicitly the number of arguments the function # and its argument names (thus implicitly the number of arguments the function
# 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) # If the name conflicted, there was already something with the same name.
# If it has a body, don't allow redefinition or reextern.
if function.name != self.name:
function.delete()
function = g_llvm_module.get_function_named(self.name)
# If the name conflicted, there was already something with the same name. # If the function already has a body, reject this.
# If it has a body, don't allow redefinition or reextern. if not function.is_declaration:
if function.name != self.name: raise RuntimeError('Redefinition of function.')
function.delete()
function = g_llvm_module.get_function_named(self.name)
# If the function already has a body, reject this. # If F took a different number of args, reject.
if not function.is_declaration: if len(callee.args) != len(self.args):
raise RuntimeError('Redefinition of function.') raise RuntimeError('Redeclaration of a function with different number '
'of args.')
# If F took a different number of args, reject. # Set names for all arguments and add them to the variables symbol table.
if len(callee.args) != len(self.args): for arg, arg_name in zip(function.args, self.args):
raise RuntimeError('Redeclaration of a function with different number ' arg.name = arg_name
'of args.') # Add arguments to variable symbol table.
g_named_values[arg_name] = arg
# Set names for all arguments and add them to the variables symbol table. return function
for arg, arg_name in zip(function.args, self.args):
arg.name = arg_name
# Add arguments to variable symbol table.
g_named_values[arg_name] = arg
return function
# 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.body = body self.prototype = prototype
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.
function = self.prototype.CodeGen()
# Create a function object. # Create a new basic block to start insertion into.
function = self.prototype.CodeGen() block = function.append_basic_block('entry')
global g_llvm_builder
g_llvm_builder = Builder.new(block)
# Create a new basic block to start insertion into. # Finish off the function.
block = function.append_basic_block('entry') try:
global g_llvm_builder return_value = self.body.CodeGen()
g_llvm_builder = Builder.new(block) g_llvm_builder.ret(return_value)
# Finish off the function. # Validate the generated code, checking for consistency.
try: function.verify()
return_value = self.body.CodeGen() except:
g_llvm_builder.ret(return_value) function.delete()
raise
# Validate the generated code, checking for consistency. return function
function.verify()
except:
function.delete()
raise
return function
Parser Parser
------ ------
class Parser(object): class Parser(object):
def __init__(self, tokens, binop_precedence): self.tokens = tokens def __init__(self, tokens, binop_precedence):
self.binop_precedence = binop_precedence self.Next() self.tokens = tokens
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 # updates Parser.current with its results. def Next(self): and # updates Parser.current with its results.
self.current = self.tokens.next() def Next(self):
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 # operator. def GetCurrentTokenPrecedence(self): if binary # 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):
self.Next() # eat identifier. identifier_name = self.current.name
self.Next() # eat identifier.
:: if self.current != CharacterToken('('): # Simple variable reference.
return VariableExpressionNode(identifier_name)
if self.current != CharacterToken('('): # Simple variable reference. # Call.
return VariableExpressionNode(identifier_name) self.Next() # eat '('.
args = []
if self.current != CharacterToken(')'):
while True:
args.append(self.ParseExpression())
if self.current == CharacterToken(')'):
break
elif self.current != CharacterToken(','):
raise RuntimeError('Expected ")" or "," in argument list.')
self.Next()
# Call. self.Next() # eat ')'.
self.Next() # eat '('. return CallExpressionNode(identifier_name, args)
args = []
if self.current != CharacterToken(')'):
while True:
args.append(self.ParseExpression())
if self.current == CharacterToken(')'):
break
elif self.current != CharacterToken(','):
raise RuntimeError('Expected ")" or "," in argument list.')
self.Next()
self.Next() # eat ')'. # numberexpr ::= number
return CallExpressionNode(identifier_name, args) def ParseNumberExpr(self):
result = NumberExpressionNode(self.current.value)
self.Next() # consume the number.
return result
# numberexpr ::= number def ParseNumberExpr(self): result = # parenexpr ::= '(' expression ')'
NumberExpressionNode(self.current.value) self.Next() # consume the def ParseParenExpr(self):
number. return result self.Next() # eat '('.
# parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() contents = self.ParseExpression()
# eat '('.
:: if self.current != CharacterToken(')'):
raise RuntimeError('Expected ")".')
self.Next() # eat ')'.
contents = self.ParseExpression() return contents
if self.current != CharacterToken(')'): # primary ::= identifierexpr | numberexpr | parenexpr
raise RuntimeError('Expected ")".') def ParsePrimary(self):
self.Next() # eat ')'. if isinstance(self.current, IdentifierToken):
return self.ParseIdentifierExpr()
elif isinstance(self.current, NumberToken):
return self.ParseNumberExpr()
elif self.current == CharacterToken('('):
return self.ParseParenExpr()
else:
raise RuntimeError('Unknown token when expecting an expression.')
return contents # binoprhs ::= (operator primary)*
def ParseBinOpRHS(self, left, left_precedence):
# If this is a binary operator, find its precedence.
while True:
precedence = self.GetCurrentTokenPrecedence()
# primary ::= identifierexpr \| numberexpr \| parenexpr def # If this is a binary operator that binds at least as tightly as the
ParsePrimary(self): if isinstance(self.current, IdentifierToken): return # current one, consume it; otherwise we are done.
self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): if precedence < left_precedence:
return self.ParseNumberExpr() elif self.current == CharacterToken('('): return left
return self.ParseParenExpr() else: raise RuntimeError('Unknown token
when expecting an expression.')
# binoprhs ::= (operator primary)\* def ParseBinOpRHS(self, left, binary_operator = self.current.char
left_precedence): # If this is a binary operator, find its precedence. self.Next() # eat the operator.
while True: precedence = self.GetCurrentTokenPrecedence()
:: # Parse the primary expression after the binary operator.
right = self.ParsePrimary()
# If this is a binary operator that binds at least as tightly as the # If binary_operator binds less tightly with right than the operator after
# current one, consume it; otherwise we are done. # right, let the pending operator take right as its left.
if precedence < left_precedence: next_precedence = self.GetCurrentTokenPrecedence()
return left if precedence < next_precedence:
right = self.ParseBinOpRHS(right, precedence + 1)
binary_operator = self.current.char # Merge left/right.
self.Next() # eat the operator. left = BinaryOperatorExpressionNode(binary_operator, left, right)
# Parse the primary expression after the binary operator. # expression ::= primary binoprhs
right = self.ParsePrimary() def ParseExpression(self):
left = self.ParsePrimary()
return self.ParseBinOpRHS(left, 0)
# If binary_operator binds less tightly with right than the operator after # prototype ::= id '(' id\* ')'
# right, let the pending operator take right as its left. def ParsePrototype(self):
next_precedence = self.GetCurrentTokenPrecedence() if not isinstance(self.current, IdentifierToken):
if precedence < next_precedence: raise RuntimeError('Expected function name in prototype.')
right = self.ParseBinOpRHS(right, precedence + 1)
# Merge left/right. function_name = self.current.name
left = BinaryOperatorExpressionNode(binary_operator, left, right) self.Next() # eat function name.
# expression ::= primary binoprhs def ParseExpression(self): left = if self.current != CharacterToken('('):
self.ParsePrimary() return self.ParseBinOpRHS(left, 0) raise RuntimeError('Expected "(" in prototype.')
self.Next() # eat '('.
# prototype ::= id '(' id\* ')' def ParsePrototype(self): if not arg_names = []
isinstance(self.current, IdentifierToken): raise RuntimeError('Expected while isinstance(self.current, IdentifierToken):
function name in prototype.') arg_names.append(self.current.name)
self.Next()
:: if self.current != CharacterToken(')'):
raise RuntimeError('Expected ")" in prototype.')
function_name = self.current.name # Success.
self.Next() # eat function name. self.Next() # eat ')'.
if self.current != CharacterToken('('): return PrototypeNode(function_name, arg_names)
raise RuntimeError('Expected "(" in prototype.')
self.Next() # eat '('.
arg_names = [] # definition ::= 'def' prototype expression
while isinstance(self.current, IdentifierToken): def ParseDefinition(self):
arg_names.append(self.current.name) self.Next() # eat def.
self.Next() proto = self.ParsePrototype()
body = self.ParseExpression()
return FunctionNode(proto, body)
if self.current != CharacterToken(')'): # toplevelexpr ::= expression
raise RuntimeError('Expected ")" in prototype.') def ParseTopLevelExpr(self):
proto = PrototypeNode('', [])
return FunctionNode(proto, self.ParseExpression())
# Success. # external ::= 'extern' prototype
self.Next() # eat ')'. def ParseExtern(self):
self.Next() # eat extern.
return self.ParsePrototype()
return PrototypeNode(function_name, arg_names) # Top-Level parsing
def HandleDefinition(self):
self.Handle(self.ParseDefinition, 'Read a function definition:')
# definition ::= 'def' prototype expression def ParseDefinition(self): def HandleExtern(self):
self.Next() # eat def. proto = self.ParsePrototype() body = self.Handle(self.ParseExtern, 'Read an extern:')
self.ParseExpression() return FunctionNode(proto, body)
# toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = def HandleTopLevelExpression(self):
PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) self.Handle(self.ParseTopLevelExpr, 'Read a top-level expression:')
# external ::= 'extern' prototype def ParseExtern(self): self.Next() # def Handle(self, function, message):
eat extern. return self.ParsePrototype() try:
print message, function().CodeGen()
# Top-Level parsing def HandleDefinition(self): except Exception, e:
self.Handle(self.ParseDefinition, 'Read a function definition:') print 'Error:', e
try:
def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') self.Next() # Skip for error recovery.
except:
def HandleTopLevelExpression(self): self.Handle(self.ParseTopLevelExpr, pass
'Read a top-level expression:')
def Handle(self, function, message): try: print message,
function().CodeGen() except Exception, e: print 'Error:', e try:
self.Next() # Skip for error recovery. except: pass
Main driver code. Main driver code.
----------------- -----------------
def main(): # Install standard binary operators. # 1 is lowest possible def main():
precedence. 40 is the highest. operator_precedence = { '<': 10, '+': # Install standard binary operators.
20, '-': 20, '\*': 40 } # 1 is lowest possible precedence. 40 is the highest.
operator_precedence = {
'<': 10,
'+': 20,
'-': 20,
'*': 40
}
# Run the main "interpreter loop". while True: print 'ready>', try: raw # Run the main "interpreter loop".
= raw_input() except KeyboardInterrupt: break while True:
print 'ready>',
try:
raw = raw_input()
except KeyboardInterrupt:
break
:: parser = Parser(Tokenize(raw), operator_precedence)
while True:
# top ::= definition | external | expression | EOF
if isinstance(parser.current, EOFToken):
break
if isinstance(parser.current, DefToken):
parser.HandleDefinition()
elif isinstance(parser.current, ExternToken):
parser.HandleExtern()
else:
parser.HandleTopLevelExpression()
parser = Parser(Tokenize(raw), operator_precedence) # Print out all of the generated code.
while True: print '\n', g_llvm_module
# top ::= definition | external | expression | EOF
if isinstance(parser.current, EOFToken):
break
if isinstance(parser.current, DefToken):
parser.HandleDefinition()
elif isinstance(parser.current, ExternToken):
parser.HandleExtern()
else:
parser.HandleTopLevelExpression()
# Print out all of the generated code. print '', g_llvm_module if __name__ == '__main__':
main()
if **name** == '__main__': main()