Completed editing of PythonLangImpl4.rst

This commit is contained in:
Maggie Mari 2012-08-17 15:32:45 -05:00
commit f74f5129bd

View file

@ -188,8 +188,6 @@ by running it after our newly created function is constructed (in
return_value = self.body.CodeGen() return_value = self.body.CodeGen()
g_llvm_builder.ret(return_value) g_llvm_builder.ret(return_value)
::
# Validate the generated code, checking for consistency. # Validate the generated code, checking for consistency.
function.verify() function.verify()
@ -403,22 +401,28 @@ example, we can create a C file with the following simple function:
#include <stdio.h> #include <stdio.h>
double putchard(double x) { double putchard(double x) {
putchar((char)x); return 0; } putchar((char)x); return 0;
}
We can then compile this into a shared library with GCC: We can then compile this into a shared library with GCC::
gcc -shared -fPIC -o putchard.so putchard.c gcc -shared -fPIC -o putchard.so putchard.c
Now we can load this library into the Python process using
``llvm.core.load_library_permanently`` and access it from Kaleidoscope
to produce simple output to the console:
>>> import llvm.core >>> Now we can load this library into the Python process using
llvm.core.load_library_permanently('/home/max/llvmpy-tutorial/putchard.so') ``llvm.core.load_library_permanently`` and access it from Kaleidoscope
>>> import kaleidoscope >>> kaleidoscope.main() ready> extern to produce simple output to the console::
putchard(x) Read an extern: declare double @putchard(double)
ready> putchard(65) + putchard(66) + putchard(67) + putchard(10) *ABC* >>> import llvm.core
>>> llvm.core.load_library_permanently('/home/max/llvmpy-tutorial/putchard.so')
>>> import kaleidoscope
>>> kaleidoscope.main()
ready> extern putchard(x)
Read an extern:
declare double @putchard(double)
ready> putchard(65) + putchard(66) + putchard(67) + putchard(10)
*ABC*
Evaluated to: 0.0 Evaluated to: 0.0
@ -446,14 +450,19 @@ the LLVM JIT and optimizer:
#!/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.ee import ExecutionEngine, TargetData from from llvm.core import Module, Constant, Type, Function, Builder, FCMP_ULT
llvm.passes import FunctionPassManager from llvm.passes import from llvm.ee import ExecutionEngine, TargetData
(PASS_INSTRUCTION_COMBINING, PASS_REASSOCIATE, PASS_GVN, from llvm.passes import FunctionPassManager
PASS_CFG_SIMPLIFICATION) from llvm.passes import (PASS_INSTRUCTION_COMBINING,
PASS_REASSOCIATE,
PASS_GVN,
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')
@ -471,385 +480,457 @@ the LLVM JIT and optimizer:
# 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 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
== 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.
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()
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 == '+':
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()
g_llvm_builder.ret(return_value)
# Validate the generated code, checking for consistency. # Optimize the function.
function.verify() g_llvm_pass_manager.run(function)
except:
function.delete()
raise
# Optimize the function. return function
g_llvm_pass_manager.run(function)
except:
function.delete()
raise
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.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
and # updates Parser.current with its results. def Next(self): # 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()) try:
function = self.ParseTopLevelExpr().CodeGen()
result = g_llvm_executor.run_function(function, [])
print 'Evaluated to:', result.as_real(Type.double())
except Exception, e:
print 'Error:', e
try:
self.Next() # Skip for error recovery.
except:
pass
# external ::= 'extern' prototype def ParseExtern(self): self.Next() # def Handle(self, function, message):
eat extern. return self.ParsePrototype() try:
print message, function().CodeGen()
except Exception, e:
print 'Error:', e
try:
self.Next() # Skip for error recovery.
except:
pass
# Top-Level parsing def HandleDefinition(self): Main driver code.
self.Handle(self.ParseDefinition, 'Read a function definition:') -----------------
def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') .. code-block:: python
def HandleTopLevelExpression(self): try: function = def main():
self.ParseTopLevelExpr().CodeGen() result = # Set up the optimizer pipeline. Start with registering info about how the
g_llvm_executor.run_function(function, []) print 'Evaluated to:', # target lays out data structures.
result.as_real(Type.double()) except Exception, e: print 'Error:', e g_llvm_pass_manager.add(g_llvm_executor.target_data)
try: self.Next() # Skip for error recovery. except: pass # Do simple "peephole" optimizations and bit-twiddling optzns.
g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING)
# Reassociate expressions.
g_llvm_pass_manager.add(PASS_REASSOCIATE)
# Eliminate Common SubExpressions.
g_llvm_pass_manager.add(PASS_GVN)
# Simplify the control flow graph (deleting unreachable blocks, etc).
g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION)
def Handle(self, function, message): try: print message, g_llvm_pass_manager.initialize()
function().CodeGen() except Exception, e: print 'Error:', e try:
self.Next() # Skip for error recovery. except: pass
Main driver code. # Install standard binary operators.
----------------- # 1 is lowest possible precedence. 40 is the highest.
operator_precedence = {
'<': 10,
'+': 20,
'-': 20,
'\*': 40
}
def main(): # Set up the optimizer pipeline. Start with registering info # Run the main "interpreter loop".
about how the # target lays out data structures. while True:
g_llvm_pass_manager.add(g_llvm_executor.target_data) # Do simple print 'ready>',
"peephole" optimizations and bit-twiddling optzns. try:
g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) # Reassociate raw = raw_input()
expressions. g_llvm_pass_manager.add(PASS_REASSOCIATE) # Eliminate except KeyboardInterrupt:
Common SubExpressions. g_llvm_pass_manager.add(PASS_GVN) # Simplify break
the control flow graph (deleting unreachable blocks, etc).
g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION)
g_llvm_pass_manager.initialize() 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()
# Install standard binary operators. # 1 is lowest possible precedence. # Print out all of the generated code.
40 is the highest. operator_precedence = { '<': 10, '+': 20, '-': 20, print '', g_llvm_module
'\*': 40 }
# Run the main "interpreter loop". while True: print 'ready>', try: raw if __name__ == '__main__':
= raw_input() except KeyboardInterrupt: break main()
::
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 '', g_llvm_module
if **name** == '__main__': main()