Finished editing PythonLangImpl5.rst
This commit is contained in:
parent
ddcf6483d0
commit
cb7b778bfd
1 changed files with 167 additions and 124 deletions
|
|
@ -114,13 +114,13 @@ To represent the new expression we add a new AST node for it:
|
||||||
# Expression class for if/then/else.
|
# Expression class for if/then/else.
|
||||||
class IfExpressionNode(ExpressionNode):
|
class IfExpressionNode(ExpressionNode):
|
||||||
|
|
||||||
def __init__(self, condition, then_branch, else_branch):
|
def __init__(self, condition, then_branch, else_branch):
|
||||||
self.condition = condition
|
self.condition = condition
|
||||||
self.then_branch = then_branch
|
self.then_branch = then_branch
|
||||||
self.else_branch = else_branch
|
self.else_branch = else_branch
|
||||||
|
|
||||||
def CodeGen(self):
|
def CodeGen(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1257,7 +1257,8 @@ Parser
|
||||||
|
|
||||||
def __init__(self, tokens, binop_precedence):
|
def __init__(self, tokens, binop_precedence):
|
||||||
self.tokens = tokens
|
self.tokens = tokens
|
||||||
self.binop_precedence = binop_precedence self.Next()
|
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 and
|
# parser is looking at. Parser.Next() reads another token from the lexer and
|
||||||
|
|
@ -1279,7 +1280,7 @@ Parser
|
||||||
self.Next() # eat identifier.
|
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 '('.
|
||||||
|
|
@ -1375,131 +1376,173 @@ Parser
|
||||||
|
|
||||||
return ForExpressionNode(loop_variable, start, end, step, body)
|
return ForExpressionNode(loop_variable, start, end, step, body)
|
||||||
|
|
||||||
# primary ::= identifierexpr | numberexpr | parenexpr | ifexpr |
|
# primary ::= identifierexpr | numberexpr | parenexpr | ifexpr | forexpr
|
||||||
forexpr def ParsePrimary(self): if isinstance(self.current,
|
def ParsePrimary(self):
|
||||||
IdentifierToken): return self.ParseIdentifierExpr() elif
|
if isinstance(self.current, IdentifierToken):
|
||||||
isinstance(self.current, NumberToken): return self.ParseNumberExpr()
|
return self.ParseIdentifierExpr()
|
||||||
elif isinstance(self.current, IfToken): return self.ParseIfExpr() elif
|
elif isinstance(self.current, NumberToken):
|
||||||
isinstance(self.current, ForToken): return self.ParseForExpr() elif
|
return self.ParseNumberExpr()
|
||||||
self.current == CharacterToken('('): return self.ParseParenExpr() else:
|
elif isinstance(self.current, IfToken):
|
||||||
raise RuntimeError('Unknown token when expecting an expression.')
|
return self.ParseIfExpr()
|
||||||
|
elif isinstance(self.current, ForToken):
|
||||||
|
return self.ParseForExpr()
|
||||||
|
elif self.current == CharacterToken('('):
|
||||||
|
return self.ParseParenExpr()
|
||||||
|
else:
|
||||||
|
raise RuntimeError('Unknown token when expecting an expression.')
|
||||||
|
|
||||||
# binoprhs ::= (operator primary)* def ParseBinOpRHS(self, left,
|
# binoprhs ::= (operator primary)*
|
||||||
left_precedence): # If this is a binary operator, find its precedence.
|
def ParseBinOpRHS(self, left, left_precedence):
|
||||||
while True: precedence = self.GetCurrentTokenPrecedence()
|
# 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
|
||||||
|
|
||||||
# If this is a binary operator that binds at least as tightly as the
|
binary_operator = self.current.char
|
||||||
# current one, consume it; otherwise we are done.
|
self.Next() # eat the operator.
|
||||||
if precedence < left_precedence:
|
|
||||||
return left
|
|
||||||
|
|
||||||
binary_operator = self.current.char
|
# Parse the primary expression after the binary operator.
|
||||||
self.Next() # eat the operator.
|
right = self.ParsePrimary()
|
||||||
|
|
||||||
# Parse the primary expression after the binary operator.
|
# If binary_operator binds less tightly with right than the operator after
|
||||||
right = self.ParsePrimary()
|
# right, let the pending operator take right as its left.
|
||||||
|
next_precedence = self.GetCurrentTokenPrecedence()
|
||||||
|
if precedence < next_precedence:
|
||||||
|
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:
|
|
||||||
right = self.ParseBinOpRHS(right, precedence + 1)
|
|
||||||
|
|
||||||
# Merge left/right.
|
# expression ::= primary binoprhs
|
||||||
left = BinaryOperatorExpressionNode(binary_operator, left, right)
|
def ParseExpression(self):
|
||||||
|
left = self.ParsePrimary()
|
||||||
|
return self.ParseBinOpRHS(left, 0)
|
||||||
|
|
||||||
# expression ::= primary binoprhs def ParseExpression(self): left =
|
# prototype ::= id '(' id* ')'
|
||||||
self.ParsePrimary() return self.ParseBinOpRHS(left, 0)
|
def ParsePrototype(self):
|
||||||
|
if not isinstance(self.current, IdentifierToken):
|
||||||
|
raise RuntimeError('Expected function name in prototype.')
|
||||||
|
|
||||||
# prototype ::= id '(' id* ')' def ParsePrototype(self): if not
|
function_name = self.current.name
|
||||||
isinstance(self.current, IdentifierToken): raise RuntimeError('Expected
|
self.Next() # eat function name.
|
||||||
function name in prototype.')
|
|
||||||
|
|
||||||
::
|
if self.current != CharacterToken('('):
|
||||||
|
raise RuntimeError('Expected "(" 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)
|
||||||
|
self.Next()
|
||||||
|
|
||||||
if self.current != CharacterToken('('):
|
if self.current != CharacterToken(')'):
|
||||||
raise RuntimeError('Expected "(" in prototype.')
|
raise RuntimeError('Expected ")" in prototype.')
|
||||||
self.Next() # eat '('.
|
|
||||||
|
|
||||||
arg_names = []
|
# Success.
|
||||||
while isinstance(self.current, IdentifierToken):
|
self.Next() # eat ')'.
|
||||||
arg_names.append(self.current.name)
|
|
||||||
self.Next()
|
|
||||||
|
|
||||||
if self.current != CharacterToken(')'):
|
return PrototypeNode(function_name, arg_names)
|
||||||
raise RuntimeError('Expected ")" in prototype.')
|
|
||||||
|
|
||||||
# Success.
|
# definition ::= 'def' prototype expression
|
||||||
self.Next() # eat ')'.
|
def ParseDefinition(self):
|
||||||
|
self.Next() # eat def.
|
||||||
|
proto = self.ParsePrototype()
|
||||||
|
body = self.ParseExpression()
|
||||||
|
return FunctionNode(proto, body)
|
||||||
|
|
||||||
return PrototypeNode(function_name, arg_names)
|
# toplevelexpr ::= expression
|
||||||
|
def ParseTopLevelExpr(self):
|
||||||
|
proto = PrototypeNode('', [])
|
||||||
|
return FunctionNode(proto, self.ParseExpression())
|
||||||
|
|
||||||
# definition ::= 'def' prototype expression def ParseDefinition(self):
|
# external ::= 'extern' prototype
|
||||||
self.Next() # eat def. proto = self.ParsePrototype() body =
|
def ParseExtern(self):
|
||||||
self.ParseExpression() return FunctionNode(proto, body)
|
self.Next() # eat extern.
|
||||||
|
return self.ParsePrototype()
|
||||||
|
|
||||||
# toplevelexpr ::= expression def ParseTopLevelExpr(self): proto =
|
# Top-Level parsing
|
||||||
PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression())
|
def HandleDefinition(self):
|
||||||
|
self.Handle(self.ParseDefinition, 'Read a function definition:')
|
||||||
|
|
||||||
# external ::= 'extern' prototype def ParseExtern(self): self.Next() #
|
def HandleExtern(self):
|
||||||
eat extern. return self.ParsePrototype()
|
self.Handle(self.ParseExtern, 'Read an extern:')
|
||||||
|
|
||||||
# Top-Level parsing def HandleDefinition(self):
|
def HandleTopLevelExpression(self):
|
||||||
self.Handle(self.ParseDefinition, 'Read a function definition:')
|
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
|
||||||
|
|
||||||
def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:')
|
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
|
||||||
|
|
||||||
def HandleTopLevelExpression(self): try: function =
|
Main driver code.
|
||||||
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
|
|
||||||
|
|
||||||
def Handle(self, function, message): try: print message,
|
.. code-block:: python
|
||||||
function().CodeGen() except Exception, e: print 'Error:', e try:
|
|
||||||
self.Next() # Skip for error recovery. except: pass
|
|
||||||
|
|
||||||
Main driver code.
|
def main():
|
||||||
-----------------
|
# Set up the optimizer pipeline. Start with registering info about how the
|
||||||
|
# target lays out data structures.
|
||||||
|
g_llvm_pass_manager.add(g_llvm_executor.target_data)
|
||||||
|
# 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 main(): # Set up the optimizer pipeline. Start with registering info
|
g_llvm_pass_manager.initialize()
|
||||||
about how the # target lays out data structures.
|
|
||||||
g_llvm_pass_manager.add(g_llvm_executor.target_data) # 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)
|
|
||||||
|
|
||||||
g_llvm_pass_manager.initialize()
|
# Install standard binary operators.
|
||||||
|
# 1 is lowest possible precedence. 40 is the highest.
|
||||||
|
operator_precedence = {
|
||||||
|
'<': 10,
|
||||||
|
'+': 20,
|
||||||
|
'-': 20,
|
||||||
|
'*': 40
|
||||||
|
}
|
||||||
|
|
||||||
# Install standard binary operators. # 1 is lowest possible precedence.
|
# Run the main "interpreter loop".
|
||||||
40 is the highest. operator_precedence = { '<': 10, '+': 20, '-': 20,
|
while True:
|
||||||
'*': 40 }
|
print 'ready>',
|
||||||
|
try:
|
||||||
|
raw = raw_input()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
break
|
||||||
|
|
||||||
# Run the main "interpreter loop". while True: print 'ready>', try: raw
|
parser = Parser(Tokenize(raw), operator_precedence)
|
||||||
= raw_input() except KeyboardInterrupt: break
|
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
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue