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,363 +659,417 @@ 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)
# Run regexes. number_match = REGEX_NUMBER.match(string)
comment_match = REGEX_COMMENT.match(string) identifier_match = REGEX_IDENTIFIER.match(string)
number_match = REGEX_NUMBER.match(string)
identifier_match = REGEX_IDENTIFIER.match(string) # Check if any of the regexes matched and yield the appropriate result.
if comment_match:
# Check if any of the regexes matched and yield the appropriate result. comment = comment_match.group(0)
if comment_match: string = string[len(comment):]
comment = comment_match.group(0) elif number_match:
string = string[len(comment):] number = number_match.group(0)
elif number_match: yield NumberToken(float(number))
number = number_match.group(0) string = string[len(number):]
yield NumberToken(float(number)) elif identifier_match:
string = string[len(number):] identifier = identifier_match.group(0)
elif identifier_match: # Check if we matched a keyword.
identifier = identifier_match.group(0) if identifier == 'def':
# Check if we matched a keyword. yield DefToken()
if identifier == 'def': elif identifier == 'extern':
yield DefToken() yield ExternToken()
elif identifier == 'extern': else:
yield ExternToken() yield IdentifierToken(identifier)
else: string = string[len(identifier):]
yield IdentifierToken(identifier) else:
string = string[len(identifier):] # Yield the ASCII value of the unknown character.
else: yield CharacterToken(string[0])
# Yield the ASCII value of the unknown character. string = string[1:]
yield CharacterToken(string[0])
string = string[1:]
yield EOFToken() yield EOFToken()
Abstract Syntax Tree (aka Parse Tree) Abstract Syntax Tree (aka Parse Tree)
------------------------------------- -------------------------------------
# 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 == '+':
if self.operator == '+': return g_llvm_builder.fadd(left, right, 'addtmp')
return g_llvm_builder.fadd(left, right, 'addtmp') elif self.operator == '-':
elif self.operator == '-': return g_llvm_builder.fsub(left, right, 'subtmp')
return g_llvm_builder.fsub(left, right, 'subtmp') elif self.operator == '*':
elif self.operator == '*': return g_llvm_builder.fmul(left, right, 'multmp')
return g_llvm_builder.fmul(left, right, 'multmp') elif self.operator == '<':
elif self.operator == '<': result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp')
result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') # Convert bool 0 or 1 to double 0.0 or 1.0.
# Convert bool 0 or 1 to double 0.0 or 1.0. return g_llvm_builder.uitofp(result, Type.double(), 'booltmp')
return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') else:
else: raise RuntimeError('Unknown binary operator.')
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
= g_llvm_module.get_function_named(self.callee) def CodeGen(self):
# 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):
raise RuntimeError('Incorrect number of arguments passed.') raise RuntimeError('Incorrect number of arguments passed.')
arg_values = [i.CodeGen() for i in self.args] 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
def CodeGen(self): # Make the function type, eg. double(double,double). self.args = args
funct_type = Type.function( Type.double(), [Type.double()] \*
len(self.args), False) def CodeGen(self):
# Make the function type, eg. double(double,double).
:: 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 the name conflicted, there was already something with the same name.
if function.name != self.name: # If it has a body, don't allow redefinition or reextern.
function.delete() if function.name != self.name:
function = g_llvm_module.get_function_named(self.name) function.delete()
function = g_llvm_module.get_function_named(self.name)
# If the function already has a body, reject this.
if not function.is_declaration: # If the function already has a body, reject this.
raise RuntimeError('Redefinition of function.') if not function.is_declaration:
raise RuntimeError('Redefinition of function.')
# If F took a different number of args, reject.
if len(callee.args) != len(self.args): # If F took a different number of args, reject.
raise RuntimeError('Redeclaration of a function with different number ' if len(callee.args) != len(self.args):
'of args.') raise RuntimeError('Redeclaration of a function with different number '
'of args.')
# Set names for all arguments and add them to the variables symbol table.
for arg, arg_name in zip(function.args, self.args): # Set names for all arguments and add them to the variables symbol table.
arg.name = arg_name for arg, arg_name in zip(function.args, self.args):
# Add arguments to variable symbol table. arg.name = arg_name
g_named_values[arg_name] = arg # Add arguments to variable symbol table.
g_named_values[arg_name] = arg
return function
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.
function = self.prototype.CodeGen()
# Create a new basic block to start insertion into.
block = function.append_basic_block('entry') # Create a new basic block to start insertion into.
global g_llvm_builder block = function.append_basic_block('entry')
g_llvm_builder = Builder.new(block) global g_llvm_builder
g_llvm_builder = Builder.new(block)
# Finish off the function.
try: # Finish off the function.
return_value = self.body.CodeGen() try:
g_llvm_builder.ret(return_value) return_value = self.body.CodeGen()
g_llvm_builder.ret(return_value)
# Validate the generated code, checking for consistency.
function.verify() # Validate the generated code, checking for consistency.
except: function.verify()
function.delete() except:
raise function.delete()
raise
return function
return function
Parser Parser
------ ------
class Parser(object): class Parser(object):
def __init__(self, tokens, binop_precedence):
self.tokens = tokens
self.binop_precedence = binop_precedence
self.Next()
def __init__(self, tokens, binop_precedence): self.tokens = tokens # Provide a simple token buffer. Parser.current is the current token the
self.binop_precedence = binop_precedence self.Next() # parser is looking at. Parser.Next() reads another token from the lexer
and # updates Parser.current with its results.
# Provide a simple token buffer. Parser.current is the current token the def Next(self):
# parser is looking at. Parser.Next() reads another token from the lexer self.current = self.tokens.next()
and # updates Parser.current with its results. def Next(self):
self.current = self.tokens.next() # Gets the precedence of the current token, or -1 if the token is not a
binary # operator.
# Gets the precedence of the current token, or -1 if the token is not a def GetCurrentTokenPrecedence(self):
binary # operator. def GetCurrentTokenPrecedence(self): if if isinstance(self.current, CharacterToken):
isinstance(self.current, CharacterToken): return return self.binop_precedence.get(self.current.char, -1)
self.binop_precedence.get(self.current.char, -1) else: return -1 else:
return -1
# identifierexpr ::= identifier \| identifier '(' expression\* ')' def
ParseIdentifierExpr(self): identifier_name = self.current.name # identifierexpr ::= identifier | identifier '(' expression* ')'
self.Next() # eat identifier. def ParseIdentifierExpr(self):
identifier_name = self.current.name
:: 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)
# Call. # Call.
self.Next() # eat '('. self.Next() # eat '('.
args = [] args = []
if self.current != CharacterToken(')'): if self.current != CharacterToken(')'):
while True: while True:
args.append(self.ParseExpression()) args.append(self.ParseExpression())
if self.current == CharacterToken(')'): if self.current == CharacterToken(')'):
break break
elif self.current != CharacterToken(','): elif self.current != CharacterToken(','):
raise RuntimeError('Expected ")" or "," in argument list.') raise RuntimeError('Expected ")" or "," in argument list.')
self.Next() self.Next()
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.
# parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() return result
# eat '('.
# parenexpr ::= '(' expression ')'
:: def ParseParenExpr(self):
self.Next() # eat '('.
contents = self.ParseExpression()
contents = self.ParseExpression()
if self.current != CharacterToken(')'):
raise RuntimeError('Expected ")".') if self.current != CharacterToken(')'):
self.Next() # eat ')'. raise RuntimeError('Expected ")".')
self.Next() # eat ')'.
return contents
return contents
# primary ::= identifierexpr \| numberexpr \| parenexpr def
ParsePrimary(self): if isinstance(self.current, IdentifierToken): return # primary ::= identifierexpr | numberexpr | parenexpr
self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): def ParsePrimary(self):
return self.ParseNumberExpr() elif self.current == CharacterToken('('): if isinstance(self.current, IdentifierToken):
return self.ParseParenExpr() else: raise RuntimeError('Unknown token return self.ParseIdentifierExpr()
when expecting an expression.') elif isinstance(self.current, NumberToken):
return self.ParseNumberExpr()
# binoprhs ::= (operator primary)\* def ParseBinOpRHS(self, left, elif self.current == CharacterToken('('):
left_precedence): # If this is a binary operator, find its precedence. return self.ParseParenExpr()
while True: precedence = self.GetCurrentTokenPrecedence() else:
raise RuntimeError('Unknown token when expecting an expression.')
::
# binoprhs ::= (operator primary)*
# If this is a binary operator that binds at least as tightly as the def ParseBinOpRHS(self, left, left_precedence):
# current one, consume it; otherwise we are done. # If this is a binary operator, find its precedence.
if precedence < left_precedence: while True:
return left precedence = self.GetCurrentTokenPrecedence()
binary_operator = self.current.char # If this is a binary operator that binds at least as tightly as the
self.Next() # eat the operator. # current one, consume it; otherwise we are done.
if precedence < left_precedence:
# Parse the primary expression after the binary operator. return left
right = self.ParsePrimary()
binary_operator = self.current.char
# If binary_operator binds less tightly with right than the operator after self.Next() # eat the operator.
# right, let the pending operator take right as its left.
next_precedence = self.GetCurrentTokenPrecedence() # Parse the primary expression after the binary operator.
if precedence < next_precedence: right = self.ParsePrimary()
right = self.ParseBinOpRHS(right, precedence + 1)
# If binary_operator binds less tightly with right than the operator after
# Merge left/right. # right, let the pending operator take right as its left.
left = BinaryOperatorExpressionNode(binary_operator, left, right) next_precedence = self.GetCurrentTokenPrecedence()
if precedence < next_precedence:
# expression ::= primary binoprhs def ParseExpression(self): left = right = self.ParseBinOpRHS(right, precedence + 1)
self.ParsePrimary() return self.ParseBinOpRHS(left, 0)
# Merge left/right.
# prototype ::= id '(' id\* ')' def ParsePrototype(self): if not left = BinaryOperatorExpressionNode(binary_operator, left, right)
isinstance(self.current, IdentifierToken): raise RuntimeError('Expected
function name in prototype.') # expression ::= primary binoprhs
def ParseExpression(self):
:: left = self.ParsePrimary()
return self.ParseBinOpRHS(left, 0)
function_name = self.current.name
self.Next() # eat function name. # prototype ::= id '(' id\* ')'
def ParsePrototype(self):
if self.current != CharacterToken('('): if not isinstance(self.current, IdentifierToken):
raise RuntimeError('Expected "(" in prototype.') raise RuntimeError('Expected function name in prototype.')
self.Next() # eat '('.
function_name = self.current.name
arg_names = [] self.Next() # eat function name.
while isinstance(self.current, IdentifierToken):
arg_names.append(self.current.name) if self.current != CharacterToken('('):
self.Next() raise RuntimeError('Expected "(" in prototype.')
self.Next() # eat '('.
if self.current != CharacterToken(')'):
raise RuntimeError('Expected ")" in prototype.') arg_names = []
while isinstance(self.current, IdentifierToken):
# Success. arg_names.append(self.current.name)
self.Next() # eat ')'. self.Next()
return PrototypeNode(function_name, arg_names) if self.current != CharacterToken(')'):
raise RuntimeError('Expected ")" in prototype.')
# definition ::= 'def' prototype expression def ParseDefinition(self):
self.Next() # eat def. proto = self.ParsePrototype() body = # Success.
self.ParseExpression() return FunctionNode(proto, body) self.Next() # eat ')'.
# toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = return PrototypeNode(function_name, arg_names)
PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression())
# definition ::= 'def' prototype expression
# external ::= 'extern' prototype def ParseExtern(self): self.Next() # def ParseDefinition(self):
eat extern. return self.ParsePrototype() self.Next() # eat def.
proto = self.ParsePrototype()
# Top-Level parsing def HandleDefinition(self): body = self.ParseExpression()
self.Handle(self.ParseDefinition, 'Read a function definition:') return FunctionNode(proto, body)
def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') # toplevelexpr ::= expression
def ParseTopLevelExpr(self):
def HandleTopLevelExpression(self): self.Handle(self.ParseTopLevelExpr, proto = PrototypeNode('', [])
'Read a top-level expression:') return FunctionNode(proto, self.ParseExpression())
def Handle(self, function, message): try: print message, # external ::= 'extern' prototype
function().CodeGen() except Exception, e: print 'Error:', e try: def ParseExtern(self):
self.Next() # Skip for error recovery. except: pass self.Next() # eat extern.
return self.ParsePrototype()
# Top-Level parsing
def HandleDefinition(self):
self.Handle(self.ParseDefinition, 'Read a function definition:')
def HandleExtern(self):
self.Handle(self.ParseExtern, 'Read an extern:')
def HandleTopLevelExpression(self):
self.Handle(self.ParseTopLevelExpr, '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()
:: # Print out all of the generated code.
print '\n', g_llvm_module
parser = Parser(Tokenize(raw), operator_precedence) if __name__ == '__main__':
while True: main()
# 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()