diff --git a/docs/source/doc/getting_started.rst b/docs/source/doc/getting_started.rst
index 1d015b2..47e465a 100644
--- a/docs/source/doc/getting_started.rst
+++ b/docs/source/doc/getting_started.rst
@@ -13,10 +13,10 @@ with the LLVM APIs. It should also be easier to create working
prototypes and experimental languages using this medium.
Together with `clang `_ or
-`llvm-gcc `_ it also a provides a
-means to quickly instrument C and C++ sources. For e.g., llvm-gcc can be
-used to generate the LLVM assembly for a given C source file, which can
-then be loaded and manipulated (adding profiling code to every function,
+`llvm-gcc `_
+it also a provides a means to quickly instrument C and C++ sources. For e.g.,
+llvm-gcc can be used to generate the LLVM assembly for a given C source file,
+which can then be loaded and manipulated (adding profiling code to every function,
say) using a llvmpy based Python script.
License
@@ -49,7 +49,7 @@ welcome).
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
following will be required for this:
diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl3.rst b/docs/source/doc/kaleidoscope/PythonLangImpl3.rst
index 7d1b8a3..3238afc 100644
--- a/docs/source/doc/kaleidoscope/PythonLangImpl3.rst
+++ b/docs/source/doc/kaleidoscope/PythonLangImpl3.rst
@@ -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.
-.. code-block:: python
+::
# Create a new basic block to start insertion into.
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 `_. Since we
don't have any control flow, our functions will only contain one block
at this point. We'll fix this in `Chapter 5 `_ :).
-.. code-block:: python
+::
- # Finish off the function.
- try:
+ # Finish off the function.
+ try:
return_value = self.body.CodeGen()
g_llvm_builder.ret(return_value)
@@ -539,11 +540,15 @@ LLVM builder calls that we use to create the instructions.
.. code-block:: bash
- ready> def bar(a) foo(a, 4.0) + bar(31337) Read a
- function definition: define double @bar(double %a) { entry: %calltmp =
- call double @foo(double %a, double 4.000000e+00) ; [#uses=1] %calltmp1 =
- call double @bar(double 3.133700e+04) ; [#uses=1] %addtmp = fadd double
- %calltmp, %calltmp1 ; [#uses=1] ret double %addtmp }
+ ready> def bar(a) foo(a, 4.0) + bar(31337)
+ Read a function definition:
+ define double @bar(double %a) {
+ entry:
+ %calltmp = call double @foo(double %a, double 4.000000e+00) ; [#uses=1]
+ %calltmp1 = call double @bar(double 3.133700e+04) ; [#uses=1]
+ %addtmp = fadd double %calltmp, %calltmp1 ; [#uses=1]
+ ret double %addtmp
+ }
@@ -554,12 +559,17 @@ control flow to actually make recursion useful :).
.. code-block:: bash
- ready> extern cos(x) Read extern: declare double
- @cos(double)
+ ready> extern cos(x)
+ Read extern:
+ declare double @cos(double)
- ready> cos(1.234) Read a top-level expression: define double @1() {
- entry: %calltmp = call double @cos(double 1.234000e+00) ; [#uses=1] ret
- double %calltmp }
+ ready> cos(1.234)
+ Read a top-level expression:
+ define double @1() {
+ entry:
+ %calltmp = call double @cos(double 1.234000e+00) ; [#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
- ready> ^C ; ModuleID = 'my cool jit'
+ ready> ^C
+ ; ModuleID = 'my cool jit'
- define double @0() { entry: ret double 9.000000e+00 }
-
- define double @foo(double %a, double %b) { entry: %multmp = fmul double
- %a, %a ; [#uses=1] %multmp1 = fmul double 2.000000e+00, %a ; [#uses=1]
- %multmp2 = fmul double %multmp1, %b ; [#uses=1] %addtmp = fadd double
- %multmp, %multmp2 ; [#uses=1] %multmp3 = fmul double %b, %b ; [#uses=1]
- %addtmp4 = fadd double %addtmp, %multmp3 ; [#uses=1] ret double %addtmp4
+ define double @0() {
+ entry:
+ ret double 9.000000e+00
}
- define double @bar(double %a) { entry: %calltmp = call double
- @foo(double %a, double 4.000000e+00) ; [#uses=1] %calltmp1 = call double
- @bar(double 3.133700e+04) ; [#uses=1] %addtmp = fadd double %calltmp,
- %calltmp1 ; [#uses=1] ret double %addtmp }
+ define double @foo(double %a, double %b) {
+ entry:
+ %multmp = fmul double %a, %a ; [#uses=1]
+ %multmp1 = fmul double 2.000000e+00, %a ; [#uses=1]
+ %multmp2 = fmul double %multmp1, %b ; [#uses=1]
+ %addtmp = fadd double %multmp, %multmp2 ; [#uses=1]
+ %multmp3 = fmul double %b, %b ; [#uses=1]
+ %addtmp4 = fadd double %addtmp, %multmp3 ; [#uses=1]
+ ret double %addtmp4
+ }
+
+ define double @bar(double %a) {
+ entry:
+ %calltmp = call double @foo(double %a, double 4.000000e+00) ; [#uses=1]
+ %calltmp1 = call double @bar(double 3.133700e+04) ; [#uses=1]
+ %addtmp = fadd double %calltmp, %calltmp1 ; [#uses=1]
+ ret double %addtmp
+ }
declare double @cos(double)
- define double @1() { entry: %calltmp = call double @cos(double
- 1.234000e+00) ; [#uses=1] ret double %calltmp }
+ define double @1() {
+ entry:
+ %calltmp = call double @cos(double 1.234000e+00) ; [#uses=1]
+ ret double %calltmp
+ }
@@ -615,8 +639,8 @@ need to `download <../download.html>`_ and
#!/usr/bin/env python
- import re from llvm.core import Module, Constant, Type, Function,
- Builder, FCMP_ULT
+ import re
+ from llvm.core import Module, Constant, Type, Function, Builder, FCMP_ULT
Globals
-------
@@ -635,363 +659,417 @@ need to `download <../download.html>`_ and
-----
# 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 =
- name
+ class IdentifierToken(object):
+ def __init__(self, name):
+ self.name = name
- class NumberToken(object): def __init__(self, value): self.value =
- value
+ class NumberToken(object):
+ def __init__(self, value):
+ self.value = value
- class CharacterToken(object): def __init__(self, char): self.char =
- char def __eq__(self, other): return isinstance(other, CharacterToken)
- and self.char == other.char def __ne__(self, other): return not self
- == other
+ class CharacterToken(object):
+ def __init__(self, char):
+ self.char = char 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.
- REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX_IDENTIFIER =
- re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX_COMMENT = re.compile('#.*')
+ REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?')
+ REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]\ *')
+ REGEX_COMMENT = re.compile('#.*')
- def Tokenize(string): while string: # Skip whitespace. if
- string[0].isspace(): string = string[1:] continue
+ def Tokenize(string):
+ 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)
-
- # Check if any of the regexes matched and yield the appropriate result.
- if comment_match:
- comment = comment_match.group(0)
- string = string[len(comment):]
- elif number_match:
- number = number_match.group(0)
- yield NumberToken(float(number))
- string = string[len(number):]
- elif identifier_match:
- identifier = identifier_match.group(0)
- # Check if we matched a keyword.
- if identifier == 'def':
- yield DefToken()
- elif identifier == 'extern':
- yield ExternToken()
- else:
- yield IdentifierToken(identifier)
- string = string[len(identifier):]
- else:
- # Yield the ASCII value of the unknown character.
- yield CharacterToken(string[0])
- string = string[1:]
+ # Run regexes.
+ comment_match = REGEX_COMMENT.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:
+ comment = comment_match.group(0)
+ string = string[len(comment):]
+ elif number_match:
+ number = number_match.group(0)
+ yield NumberToken(float(number))
+ string = string[len(number):]
+ elif identifier_match:
+ identifier = identifier_match.group(0)
+ # Check if we matched a keyword.
+ if identifier == 'def':
+ yield DefToken()
+ elif identifier == 'extern':
+ yield ExternToken()
+ else:
+ yield IdentifierToken(identifier)
+ string = string[len(identifier):]
+ else:
+ # Yield the ASCII value of the unknown character.
+ yield CharacterToken(string[0])
+ string = string[1:]
yield EOFToken()
Abstract Syntax Tree (aka Parse Tree)
-------------------------------------
-
+
# Base class for all expression nodes.
- class ExpressionNode(object): pass
+ class ExpressionNode(object):
+ pass
# Expression class for numeric literals like "1.0".
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".
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
- g_named_values[self.name] else: raise RuntimeError('Unknown variable
- name: ' + self.name)
+ def CodeGen(self):
+ if self.name in g_named_values:
+ return g_named_values[self.name]
+ else:
+ raise RuntimeError('Unknown variable name: ' + self.name)
# Expression class for a binary operator.
class BinaryOperatorExpressionNode(ExpressionNode):
- def __init__(self, operator, left, right): self.operator = operator
- self.left = left self.right = right
-
- def CodeGen(self): left = self.left.CodeGen() right =
- self.right.CodeGen()
-
- ::
-
- if self.operator == '+':
- return g_llvm_builder.fadd(left, right, 'addtmp')
- elif self.operator == '-':
- return g_llvm_builder.fsub(left, right, 'subtmp')
- elif self.operator == '*':
- return g_llvm_builder.fmul(left, right, 'multmp')
- elif self.operator == '<':
- result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp')
- # Convert bool 0 or 1 to double 0.0 or 1.0.
- return g_llvm_builder.uitofp(result, Type.double(), 'booltmp')
- else:
- raise RuntimeError('Unknown binary operator.')
+ def __init__(self, operator, left, right): self.operator = operator
+ self.left = left self.right = right
+
+ def CodeGen(self):
+ left = self.left.CodeGen()
+ right = self.right.CodeGen()
+
+ if self.operator == '+':
+ return g_llvm_builder.fadd(left, right, 'addtmp')
+ elif self.operator == '-':
+ return g_llvm_builder.fsub(left, right, 'subtmp')
+ elif self.operator == '*':
+ return g_llvm_builder.fmul(left, right, 'multmp')
+ elif self.operator == '<':
+ result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp')
+ # Convert bool 0 or 1 to double 0.0 or 1.0.
+ return g_llvm_builder.uitofp(result, Type.double(), 'booltmp')
+ else:
+ raise RuntimeError('Unknown binary operator.')
# Expression class for function calls.
class CallExpressionNode(ExpressionNode):
- def __init__(self, callee, 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)
-
- ::
-
- # Check for argument mismatch error.
- 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')
+ def __init__(self, callee, 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)
+
+ # Check for argument mismatch error.
+ 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')
# This class represents the "prototype" for a function, which captures its name,
# and its argument names (thus implicitly the number of arguments the function
# takes).
class PrototypeNode(object):
- def __init__(self, name, args): self.name = name self.args = args
-
- 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)
-
- # 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 function already has a body, reject this.
- 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):
- 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):
- arg.name = arg_name
- # Add arguments to variable symbol table.
- g_named_values[arg_name] = arg
-
- return function
+ def __init__(self, name, args):
+ self.name = name
+ self.args = args
+
+ 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)
+
+ # 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 function already has a body, reject this.
+ 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):
+ 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):
+ 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.
class FunctionNode(object):
- def __init__(self, prototype, body): self.prototype = prototype
- self.body = body
-
- def CodeGen(self): # Clear scope. g_named_values.clear()
-
- ::
-
- # Create a function object.
- function = self.prototype.CodeGen()
-
- # Create a new basic block to start insertion into.
- block = function.append_basic_block('entry')
- global g_llvm_builder
- g_llvm_builder = Builder.new(block)
-
- # Finish off the function.
- try:
- return_value = self.body.CodeGen()
- g_llvm_builder.ret(return_value)
-
- # Validate the generated code, checking for consistency.
- function.verify()
- except:
- function.delete()
- raise
-
- return function
+ def __init__(self, prototype, body):
+ self.prototype = prototype
+ self.body = body
+
+ def CodeGen(self):
+ # Clear scope.
+ g_named_values.clear()
+
+ # Create a function object.
+ function = self.prototype.CodeGen()
+
+ # Create a new basic block to start insertion into.
+ block = function.append_basic_block('entry')
+ global g_llvm_builder
+ g_llvm_builder = Builder.new(block)
+
+ # Finish off the function.
+ try:
+ return_value = self.body.CodeGen()
+ g_llvm_builder.ret(return_value)
+
+ # Validate the generated code, checking for consistency.
+ function.verify()
+ except:
+ function.delete()
+ raise
+
+ return function
Parser
------
-
+
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
- self.binop_precedence = binop_precedence self.Next()
-
- # Provide a simple token buffer. Parser.current is the current token the
- # parser is looking at. Parser.Next() reads another token from the lexer
- 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. def GetCurrentTokenPrecedence(self): if
- isinstance(self.current, CharacterToken): return
- self.binop_precedence.get(self.current.char, -1) else: return -1
-
- # identifierexpr ::= identifier \| identifier '(' expression\* ')' def
- ParseIdentifierExpr(self): identifier_name = self.current.name
- self.Next() # eat identifier.
-
- ::
-
- if self.current != CharacterToken('('): # Simple variable reference.
- return VariableExpressionNode(identifier_name)
-
- # Call.
- 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()
-
- self.Next() # eat ')'.
- return CallExpressionNode(identifier_name, args)
-
- # numberexpr ::= number def ParseNumberExpr(self): result =
- NumberExpressionNode(self.current.value) self.Next() # consume the
- number. return result
-
- # parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next()
- # eat '('.
-
- ::
-
- contents = self.ParseExpression()
-
- if self.current != CharacterToken(')'):
- raise RuntimeError('Expected ")".')
- self.Next() # eat ')'.
-
- return contents
-
- # primary ::= identifierexpr \| numberexpr \| parenexpr def
- ParsePrimary(self): 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.')
-
- # binoprhs ::= (operator primary)\* def ParseBinOpRHS(self, left,
- left_precedence): # If this is a binary operator, find its precedence.
- while True: precedence = self.GetCurrentTokenPrecedence()
-
- ::
-
- # If this is a binary operator that binds at least as tightly as the
- # current one, consume it; otherwise we are done.
- if precedence < left_precedence:
- return left
-
- binary_operator = self.current.char
- self.Next() # eat the operator.
-
- # Parse the primary expression after the binary operator.
- right = self.ParsePrimary()
-
- # If binary_operator binds less tightly with right than the operator after
- # right, let the pending operator take right as its left.
- next_precedence = self.GetCurrentTokenPrecedence()
- if precedence < next_precedence:
- right = self.ParseBinOpRHS(right, precedence + 1)
-
- # Merge left/right.
- left = BinaryOperatorExpressionNode(binary_operator, left, right)
-
- # expression ::= primary binoprhs def ParseExpression(self): left =
- self.ParsePrimary() return self.ParseBinOpRHS(left, 0)
-
- # prototype ::= id '(' id\* ')' def ParsePrototype(self): if not
- isinstance(self.current, IdentifierToken): raise RuntimeError('Expected
- function name in prototype.')
-
- ::
-
- function_name = self.current.name
- self.Next() # eat function name.
-
- if self.current != CharacterToken('('):
- raise RuntimeError('Expected "(" in prototype.')
- self.Next() # eat '('.
-
- arg_names = []
- while isinstance(self.current, IdentifierToken):
- arg_names.append(self.current.name)
- self.Next()
-
- if self.current != CharacterToken(')'):
- raise RuntimeError('Expected ")" in prototype.')
-
- # Success.
- self.Next() # eat ')'.
-
- return PrototypeNode(function_name, arg_names)
-
- # definition ::= 'def' prototype expression def ParseDefinition(self):
- self.Next() # eat def. proto = self.ParsePrototype() body =
- self.ParseExpression() return FunctionNode(proto, body)
-
- # toplevelexpr ::= expression def ParseTopLevelExpr(self): proto =
- PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression())
-
- # external ::= 'extern' prototype def ParseExtern(self): 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
+ # Provide a simple token buffer. Parser.current is the current token the
+ # parser is looking at. Parser.Next() reads another token from the lexer
+ 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.
+ def GetCurrentTokenPrecedence(self):
+ if isinstance(self.current, CharacterToken):
+ return self.binop_precedence.get(self.current.char, -1)
+ else:
+ return -1
+
+ # identifierexpr ::= identifier | identifier '(' expression* ')'
+ def ParseIdentifierExpr(self):
+ identifier_name = self.current.name
+ self.Next() # eat identifier.
+
+ if self.current != CharacterToken('('): # Simple variable reference.
+ return VariableExpressionNode(identifier_name)
+
+ # Call.
+ 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()
+
+ self.Next() # eat ')'.
+ return CallExpressionNode(identifier_name, args)
+
+ # numberexpr ::= number
+ def ParseNumberExpr(self):
+ result = NumberExpressionNode(self.current.value)
+ self.Next() # consume the number.
+ return result
+
+ # parenexpr ::= '(' expression ')'
+ def ParseParenExpr(self):
+ self.Next() # eat '('.
+
+ contents = self.ParseExpression()
+
+ if self.current != CharacterToken(')'):
+ raise RuntimeError('Expected ")".')
+ self.Next() # eat ')'.
+
+ return contents
+
+ # primary ::= identifierexpr | numberexpr | parenexpr
+ def ParsePrimary(self):
+ 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.')
+
+ # binoprhs ::= (operator primary)*
+ def ParseBinOpRHS(self, left, left_precedence):
+ # If this is a binary operator, find its precedence.
+ while True:
+ precedence = self.GetCurrentTokenPrecedence()
+
+ # If this is a binary operator that binds at least as tightly as the
+ # current one, consume it; otherwise we are done.
+ if precedence < left_precedence:
+ return left
+
+ binary_operator = self.current.char
+ self.Next() # eat the operator.
+
+ # Parse the primary expression after the binary operator.
+ right = self.ParsePrimary()
+
+ # If binary_operator binds less tightly with right than the operator after
+ # right, let the pending operator take right as its left.
+ next_precedence = self.GetCurrentTokenPrecedence()
+ if precedence < next_precedence:
+ right = self.ParseBinOpRHS(right, precedence + 1)
+
+ # Merge left/right.
+ left = BinaryOperatorExpressionNode(binary_operator, left, right)
+
+ # expression ::= primary binoprhs
+ def ParseExpression(self):
+ left = self.ParsePrimary()
+ return self.ParseBinOpRHS(left, 0)
+
+ # prototype ::= id '(' id\* ')'
+ def ParsePrototype(self):
+ if not isinstance(self.current, IdentifierToken):
+ raise RuntimeError('Expected function name in prototype.')
+
+ function_name = self.current.name
+ self.Next() # eat function name.
+
+ if self.current != CharacterToken('('):
+ raise RuntimeError('Expected "(" in prototype.')
+ self.Next() # eat '('.
+
+ arg_names = []
+ while isinstance(self.current, IdentifierToken):
+ arg_names.append(self.current.name)
+ self.Next()
+
+ if self.current != CharacterToken(')'):
+ raise RuntimeError('Expected ")" in prototype.')
+
+ # Success.
+ self.Next() # eat ')'.
+
+ return PrototypeNode(function_name, arg_names)
+
+ # definition ::= 'def' prototype expression
+ def ParseDefinition(self):
+ self.Next() # eat def.
+ proto = self.ParsePrototype()
+ body = self.ParseExpression()
+ return FunctionNode(proto, body)
+
+ # toplevelexpr ::= expression
+ def ParseTopLevelExpr(self):
+ proto = PrototypeNode('', [])
+ return FunctionNode(proto, self.ParseExpression())
+
+ # external ::= 'extern' prototype
+ def ParseExtern(self):
+ 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.
-----------------
- def main(): # Install standard binary operators. # 1 is lowest possible
- precedence. 40 is the highest. operator_precedence = { '<': 10, '+':
- 20, '-': 20, '\*': 40 }
+ def main():
+ # Install standard binary operators.
+ # 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
- = raw_input() except KeyboardInterrupt: break
+ # Run the main "interpreter loop".
+ 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)
- 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()
+ if __name__ == '__main__':
+ main()
\ No newline at end of file