From c30095c77c58af3aa79aae72cad91077dd24ddc8 Mon Sep 17 00:00:00 2001 From: Maggie Mari Date: Thu, 16 Aug 2012 12:03:41 -0500 Subject: [PATCH] Edited code blocks, fixed links. --- docs/source/doc/getting_started.rst | 10 +- .../doc/kaleidoscope/PythonLangImpl3.rst | 750 ++++++++++-------- 2 files changed, 419 insertions(+), 341 deletions(-) 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