Finished editing PythonLangImpl6.rst.
This commit is contained in:
parent
e7cbaea1e8
commit
16860436d4
1 changed files with 438 additions and 364 deletions
|
|
@ -105,7 +105,9 @@ keywords:
|
||||||
pass
|
pass
|
||||||
class UnaryToken(object):
|
class UnaryToken(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
def Tokenize(string):
|
def Tokenize(string):
|
||||||
...
|
...
|
||||||
elif identifier == 'in':
|
elif identifier == 'in':
|
||||||
|
|
@ -295,7 +297,8 @@ whenever we define a new binary operator:
|
||||||
def main():
|
def main():
|
||||||
...
|
...
|
||||||
g_binop_precedence['<'] = 10
|
g_binop_precedence['<'] = 10
|
||||||
g_binop_precedence['+'] = 20 g_binop_precedence['-'] = 20
|
g_binop_precedence['+'] = 20
|
||||||
|
g_binop_precedence['-'] = 20
|
||||||
g_binop_precedence['*'] = 40
|
g_binop_precedence['*'] = 40
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
@ -347,8 +350,8 @@ simple: we'll add a new function to do it:
|
||||||
def ParseUnary(self):
|
def ParseUnary(self):
|
||||||
# If the current token is not an operator, it must be a primary expression.
|
# If the current token is not an operator, it must be a primary expression.
|
||||||
if (not isinstance(self.current, CharacterToken) or
|
if (not isinstance(self.current, CharacterToken) or
|
||||||
self.current in [CharacterToken('('), CharacterToken(',')]):
|
self.current in [CharacterToken('('), CharacterToken(',')]):
|
||||||
return self.ParsePrimary()
|
return self.ParsePrimary()
|
||||||
|
|
||||||
# If this is a unary operator, read it.
|
# If this is a unary operator, read it.
|
||||||
operator = self.current.chara
|
operator = self.current.chara
|
||||||
|
|
@ -826,11 +829,13 @@ Lexer
|
||||||
class UnaryToken(object):
|
class UnaryToken(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class IdentifierToken(object): def __init__(self, name):
|
class IdentifierToken(object):
|
||||||
self.name = name
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
|
||||||
class NumberToken(object): def __init__(self, value):
|
class NumberToken(object):
|
||||||
self.value = value
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
|
||||||
class CharacterToken(object):
|
class CharacterToken(object):
|
||||||
def __init__(self, char):
|
def __init__(self, char):
|
||||||
|
|
@ -894,12 +899,12 @@ Lexer
|
||||||
yield CharacterToken(string[0])
|
yield CharacterToken(string[0])
|
||||||
string = string[1:]
|
string = string[1:]
|
||||||
|
|
||||||
yield EOFToken()
|
yield EOFToken()
|
||||||
|
|
||||||
Abstract Syntax Tree (aka Parse Tree)
|
Abstract Syntax Tree (aka Parse Tree)
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
# Base class for all expression nodes.
|
# Base class for all expression nodes.
|
||||||
class ExpressionNode(object):
|
class ExpressionNode(object):
|
||||||
|
|
@ -911,7 +916,8 @@ Abstract Syntax Tree (aka Parse Tree)
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
self.value = 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):
|
||||||
|
|
@ -978,7 +984,9 @@ Abstract Syntax Tree (aka Parse Tree)
|
||||||
self.then_branch = then_branch
|
self.then_branch = then_branch
|
||||||
self.else_branch = else_branch
|
self.else_branch = else_branch
|
||||||
|
|
||||||
def CodeGen(self): condition = self.condition.CodeGen()
|
def CodeGen(self):
|
||||||
|
|
||||||
|
condition = self.condition.CodeGen()
|
||||||
|
|
||||||
# Convert condition to a bool by comparing equal to 0.0.
|
# Convert condition to a bool by comparing equal to 0.0.
|
||||||
condition_bool = g_llvm_builder.fcmp(
|
condition_bool = g_llvm_builder.fcmp(
|
||||||
|
|
@ -1114,370 +1122,436 @@ Abstract Syntax Tree (aka Parse Tree)
|
||||||
# Expression class for a unary operator.
|
# Expression class for a unary operator.
|
||||||
class UnaryExpressionNode(ExpressionNode):
|
class UnaryExpressionNode(ExpressionNode):
|
||||||
|
|
||||||
def __init__(self, operator, operand): self.operator = operator
|
def __init__(self, operator, operand):
|
||||||
self.operand = operand
|
self.operator = operator
|
||||||
|
self.operand = operand
|
||||||
def CodeGen(self): operand = self.operand.CodeGen() function =
|
|
||||||
g_llvm_module.get_function_named('unary' + self.operator) return
|
def CodeGen(self):
|
||||||
g_llvm_builder.call(function, [operand], 'unop')
|
operand = self.operand.CodeGen()
|
||||||
|
function = g_llvm_module.get_function_named('unary' + self.operator)
|
||||||
|
return g_llvm_builder.call(function, [operand], 'unop')
|
||||||
|
|
||||||
# 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), as well as if it is an operator.
|
# takes), as well as if it is an operator.
|
||||||
class PrototypeNode(object):
|
class PrototypeNode(object):
|
||||||
|
|
||||||
def __init__(self, name, args, is_operator=False, precedence=0):
|
def __init__(self, name, args, is_operator=False, precedence=0):
|
||||||
self.name = name self.args = args self.is_operator = is_operator
|
self.name = name
|
||||||
self.precedence = precedence
|
self.args = args
|
||||||
|
self.is_operator = is_operator
|
||||||
def IsBinaryOp(self): return self.is_operator and len(self.args) == 2
|
self.precedence = precedence
|
||||||
|
|
||||||
def GetOperatorName(self): assert self.is_operator return self.name[-1]
|
def IsBinaryOp(self):
|
||||||
|
return self.is_operator and len(self.args) == 2
|
||||||
def CodeGen(self): # Make the function type, eg. double(double,double).
|
|
||||||
funct_type = Type.function( Type.double(), [Type.double()] *
|
def GetOperatorName(self):
|
||||||
len(self.args), False)
|
assert self.is_operator
|
||||||
|
return self.name[-1]
|
||||||
::
|
|
||||||
|
def CodeGen(self):
|
||||||
function = Function.new(g_llvm_module, funct_type, self.name)
|
# Make the function type, eg. double(double,double).
|
||||||
|
funct_type = Type.function(
|
||||||
# If the name conflicted, there was already something with the same name.
|
Type.double(), [Type.double()] * len(self.args), False)
|
||||||
# If it has a body, don't allow redefinition or reextern.
|
|
||||||
if function.name != self.name:
|
function = Function.new(g_llvm_module, funct_type, 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 it has a body, don't allow redefinition or reextern.
|
||||||
# If the function already has a body, reject this.
|
if function.name != self.name:
|
||||||
if not function.is_declaration:
|
function.delete()
|
||||||
raise RuntimeError('Redefinition of function.')
|
function = g_llvm_module.get_function_named(self.name)
|
||||||
|
|
||||||
# If the function took a different number of args, reject.
|
# If the function already has a body, reject this.
|
||||||
if len(function.args) != len(self.args):
|
if not function.is_declaration:
|
||||||
raise RuntimeError('Redeclaration of a function with different number '
|
raise RuntimeError('Redefinition of function.')
|
||||||
'of args.')
|
|
||||||
|
# If the function took a different number of args, reject.
|
||||||
# Set names for all arguments and add them to the variables symbol table.
|
if len(function.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.
|
||||||
|
for arg, arg_name in zip(function.args, self.args):
|
||||||
return function
|
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()
|
||||||
|
|
||||||
|
# Create a function object.
|
||||||
|
function = self.prototype.CodeGen()
|
||||||
|
|
||||||
|
# If this is a binary operator, install its precedence.
|
||||||
|
if self.prototype.IsBinaryOp():
|
||||||
|
operator = self.prototype.GetOperatorName()
|
||||||
|
g_binop_precedence[operator] = self.prototype.precedence
|
||||||
|
|
||||||
|
# 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()
|
||||||
|
|
||||||
|
# Optimize the function.
|
||||||
|
g_llvm_pass_manager.run(function)
|
||||||
|
except:
|
||||||
|
function.delete()
|
||||||
|
if self.prototype.IsBinaryOp():
|
||||||
|
del g_binop_precedence[self.prototype.GetOperatorName()]
|
||||||
|
raise
|
||||||
|
|
||||||
|
return function
|
||||||
|
|
||||||
def CodeGen(self): # Clear scope. g_named_values.clear()
|
Parser
|
||||||
|
------
|
||||||
::
|
|
||||||
|
.. code-block:: python
|
||||||
# Create a function object.
|
|
||||||
function = self.prototype.CodeGen()
|
|
||||||
|
|
||||||
# If this is a binary operator, install its precedence.
|
|
||||||
if self.prototype.IsBinaryOp():
|
|
||||||
operator = self.prototype.GetOperatorName()
|
|
||||||
g_binop_precedence[operator] = self.prototype.precedence
|
|
||||||
|
|
||||||
# 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()
|
|
||||||
|
|
||||||
# Optimize the function.
|
|
||||||
g_llvm_pass_manager.run(function)
|
|
||||||
except:
|
|
||||||
function.delete()
|
|
||||||
if self.prototype.IsBinaryOp():
|
|
||||||
del g_binop_precedence[self.prototype.GetOperatorName()]
|
|
||||||
raise
|
|
||||||
|
|
||||||
return function
|
|
||||||
|
|
||||||
Parser
|
|
||||||
------
|
|
||||||
|
|
||||||
class Parser(object):
|
class Parser(object):
|
||||||
|
|
||||||
def __init__(self, tokens): self.tokens = tokens self.Next()
|
def __init__(self, tokens):
|
||||||
|
self.tokens = tokens
|
||||||
# Provide a simple token buffer. Parser.current is the current token the
|
self.Next()
|
||||||
# parser is looking at. Parser.Next() reads another token from the lexer
|
|
||||||
and # updates Parser.current with its results. def Next(self):
|
# Provide a simple token buffer. Parser.current is the current token the
|
||||||
self.current = self.tokens.next()
|
# parser is looking at. Parser.Next() reads another token from the lexer and
|
||||||
|
# updates Parser.current with its results.
|
||||||
# Gets the precedence of the current token, or -1 if the token is not a
|
def Next(self):
|
||||||
binary # operator. def GetCurrentTokenPrecedence(self): if
|
self.current = self.tokens.next()
|
||||||
isinstance(self.current, CharacterToken): return
|
|
||||||
g_binop_precedence.get(self.current.char, -1) else: return -1
|
# Gets the precedence of the current token, or -1 if the token is not a binary
|
||||||
|
# operator.
|
||||||
# identifierexpr ::= identifier | identifier '(' expression* ')' def
|
def GetCurrentTokenPrecedence(self):
|
||||||
ParseIdentifierExpr(self): identifier_name = self.current.name
|
if isinstance(self.current, CharacterToken):
|
||||||
self.Next() # eat identifier.
|
return g_binop_precedence.get(self.current.char, -1)
|
||||||
|
else:
|
||||||
::
|
return -1
|
||||||
|
|
||||||
if self.current != CharacterToken('('): # Simple variable reference.
|
# identifierexpr ::= identifier | identifier '(' expression* ')'
|
||||||
return VariableExpressionNode(identifier_name)
|
def ParseIdentifierExpr(self):
|
||||||
|
identifier_name = self.current.name
|
||||||
# Call.
|
self.Next() # eat identifier.
|
||||||
self.Next() # eat '('.
|
|
||||||
args = []
|
if self.current != CharacterToken('('): # Simple variable reference.
|
||||||
if self.current != CharacterToken(')'):
|
return VariableExpressionNode(identifier_name)
|
||||||
while True:
|
|
||||||
args.append(self.ParseExpression())
|
# Call.
|
||||||
if self.current == CharacterToken(')'):
|
self.Next() # eat '('.
|
||||||
break
|
args = []
|
||||||
elif self.current != CharacterToken(','):
|
if self.current != CharacterToken(')'):
|
||||||
raise RuntimeError('Expected ")" or "," in argument list.')
|
while True:
|
||||||
self.Next()
|
args.append(self.ParseExpression())
|
||||||
|
if self.current == CharacterToken(')'):
|
||||||
self.Next() # eat ')'.
|
break
|
||||||
return CallExpressionNode(identifier_name, args)
|
elif self.current != CharacterToken(','):
|
||||||
|
raise RuntimeError('Expected ")" or "," in argument list.')
|
||||||
# numberexpr ::= number def ParseNumberExpr(self): result =
|
self.Next()
|
||||||
NumberExpressionNode(self.current.value) self.Next() # consume the
|
|
||||||
number. return result
|
self.Next() # eat ')'.
|
||||||
|
return CallExpressionNode(identifier_name, args)
|
||||||
# parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next()
|
|
||||||
# eat '('.
|
# numberexpr ::= number
|
||||||
|
def ParseNumberExpr(self):
|
||||||
::
|
result = NumberExpressionNode(self.current.value)
|
||||||
|
self.Next() # consume the number.
|
||||||
contents = self.ParseExpression()
|
return result
|
||||||
|
|
||||||
if self.current != CharacterToken(')'):
|
# parenexpr ::= '(' expression ')'
|
||||||
raise RuntimeError('Expected ")".')
|
def ParseParenExpr(self):
|
||||||
self.Next() # eat ')'.
|
self.Next() # eat '('.
|
||||||
|
|
||||||
return contents
|
contents = self.ParseExpression()
|
||||||
|
|
||||||
# ifexpr ::= 'if' expression 'then' expression 'else' expression def
|
if self.current != CharacterToken(')'):
|
||||||
ParseIfExpr(self): self.Next() # eat the if.
|
raise RuntimeError('Expected ")".')
|
||||||
|
self.Next() # eat ')'.
|
||||||
::
|
|
||||||
|
return contents
|
||||||
# condition.
|
|
||||||
condition = self.ParseExpression()
|
# ifexpr ::= 'if' expression 'then' expression 'else' expression
|
||||||
|
def ParseIfExpr(self):
|
||||||
if not isinstance(self.current, ThenToken):
|
self.Next() # eat the if.
|
||||||
raise RuntimeError('Expected "then".')
|
|
||||||
self.Next() # eat the then.
|
# condition.
|
||||||
|
condition = self.ParseExpression()
|
||||||
then_branch = self.ParseExpression()
|
|
||||||
|
if not isinstance(self.current, ThenToken):
|
||||||
if not isinstance(self.current, ElseToken):
|
raise RuntimeError('Expected "then".')
|
||||||
raise RuntimeError('Expected "else".')
|
self.Next() # eat the then.
|
||||||
self.Next() # eat the else.
|
|
||||||
|
then_branch = self.ParseExpression()
|
||||||
else_branch = self.ParseExpression()
|
|
||||||
|
if not isinstance(self.current, ElseToken):
|
||||||
return IfExpressionNode(condition, then_branch, else_branch)
|
raise RuntimeError('Expected "else".')
|
||||||
|
self.Next() # eat the else.
|
||||||
# forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in'
|
|
||||||
expression def ParseForExpr(self): self.Next() # eat the for.
|
else_branch = self.ParseExpression()
|
||||||
|
|
||||||
::
|
return IfExpressionNode(condition, then_branch, else_branch)
|
||||||
|
|
||||||
if not isinstance(self.current, IdentifierToken):
|
# forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression
|
||||||
raise RuntimeError('Expected identifier after for.')
|
def ParseForExpr(self):
|
||||||
|
self.Next() # eat the for.
|
||||||
loop_variable = self.current.name
|
|
||||||
self.Next() # eat the identifier.
|
if not isinstance(self.current, IdentifierToken):
|
||||||
|
raise RuntimeError('Expected identifier after for.')
|
||||||
if self.current != CharacterToken('='):
|
|
||||||
raise RuntimeError('Expected "=" after for variable.')
|
loop_variable = self.current.name
|
||||||
self.Next() # eat the '='.
|
self.Next() # eat the identifier.
|
||||||
|
|
||||||
start = self.ParseExpression()
|
if self.current != CharacterToken('='):
|
||||||
|
raise RuntimeError('Expected "=" after for variable.')
|
||||||
if self.current != CharacterToken(','):
|
self.Next() # eat the '='.
|
||||||
raise RuntimeError('Expected "," after for start value.')
|
|
||||||
self.Next() # eat the ','.
|
start = self.ParseExpression()
|
||||||
|
|
||||||
end = self.ParseExpression()
|
if self.current != CharacterToken(','):
|
||||||
|
raise RuntimeError('Expected "," after for start value.')
|
||||||
# The step value is optional.
|
self.Next() # eat the ','.
|
||||||
if self.current == CharacterToken(','):
|
|
||||||
self.Next() # eat the ','.
|
end = self.ParseExpression()
|
||||||
step = self.ParseExpression()
|
|
||||||
else:
|
# The step value is optional.
|
||||||
step = None
|
if self.current == CharacterToken(','):
|
||||||
|
self.Next() # eat the ','.
|
||||||
if not isinstance(self.current, InToken):
|
step = self.ParseExpression()
|
||||||
raise RuntimeError('Expected "in" after for variable specification.')
|
else:
|
||||||
self.Next() # eat 'in'.
|
step = None
|
||||||
|
|
||||||
body = self.ParseExpression()
|
if not isinstance(self.current, InToken):
|
||||||
|
raise RuntimeError('Expected "in" after for variable specification.')
|
||||||
return ForExpressionNode(loop_variable, start, end, step, body)
|
self.Next() # eat 'in'.
|
||||||
|
|
||||||
# primary ::= identifierexpr | numberexpr | parenexpr | ifexpr |
|
body = self.ParseExpression()
|
||||||
forexpr def ParsePrimary(self): if isinstance(self.current,
|
|
||||||
IdentifierToken): return self.ParseIdentifierExpr() elif
|
return ForExpressionNode(loop_variable, start, end, step, body)
|
||||||
isinstance(self.current, NumberToken): return self.ParseNumberExpr()
|
|
||||||
elif isinstance(self.current, IfToken): return self.ParseIfExpr() elif
|
# primary ::= identifierexpr | numberexpr | parenexpr | ifexpr | forexpr
|
||||||
isinstance(self.current, ForToken): return self.ParseForExpr() elif
|
def ParsePrimary(self):
|
||||||
self.current == CharacterToken('('): return self.ParseParenExpr() else:
|
if isinstance(self.current, IdentifierToken):
|
||||||
raise RuntimeError('Unknown token when expecting an expression.')
|
return self.ParseIdentifierExpr()
|
||||||
|
elif isinstance(self.current, NumberToken):
|
||||||
# unary ::= primary | unary_operator unary def ParseUnary(self): # If
|
return self.ParseNumberExpr()
|
||||||
the current token is not an operator, it must be a primary expression.
|
elif isinstance(self.current, IfToken):
|
||||||
if (not isinstance(self.current, CharacterToken) or self.current in
|
return self.ParseIfExpr()
|
||||||
[CharacterToken('('), CharacterToken(',')]): return self.ParsePrimary()
|
elif isinstance(self.current, ForToken):
|
||||||
|
return self.ParseForExpr()
|
||||||
::
|
elif self.current == CharacterToken('('):
|
||||||
|
return self.ParseParenExpr()
|
||||||
# If this is a unary operator, read it.
|
else:
|
||||||
operator = self.current.char
|
raise RuntimeError('Unknown token when expecting an expression.')
|
||||||
self.Next() # eat the operator.
|
|
||||||
return UnaryExpressionNode(operator, self.ParseUnary())
|
# unary ::= primary | unary_operator unary
|
||||||
|
def ParseUnary(self):
|
||||||
# binoprhs ::= (binary_operator unary)* def ParseBinOpRHS(self, left,
|
# If the current token is not an operator, it must be a primary expression.
|
||||||
left_precedence): # If this is a binary operator, find its precedence.
|
if (not isinstance(self.current, CharacterToken) or
|
||||||
while True: precedence = self.GetCurrentTokenPrecedence()
|
self.current in [CharacterToken('('), CharacterToken(',')]):
|
||||||
|
return self.ParsePrimary()
|
||||||
::
|
|
||||||
|
# If this is a unary operator, read it.
|
||||||
# If this is a binary operator that binds at least as tightly as the
|
operator = self.current.char
|
||||||
# current one, consume it; otherwise we are done.
|
self.Next() # eat the operator.
|
||||||
if precedence < left_precedence:
|
return UnaryExpressionNode(operator, self.ParseUnary())
|
||||||
return left
|
|
||||||
|
# binoprhs ::= (binary_operator unary)*
|
||||||
binary_operator = self.current.char
|
def ParseBinOpRHS(self, left, left_precedence):
|
||||||
self.Next() # eat the operator.
|
# If this is a binary operator, find its precedence.
|
||||||
|
while True:
|
||||||
# Parse the unary expression after the binary operator.
|
precedence = self.GetCurrentTokenPrecedence()
|
||||||
right = self.ParseUnary()
|
|
||||||
|
# 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
|
||||||
|
self.Next() # eat the operator.
|
||||||
# Merge left/right.
|
|
||||||
left = BinaryOperatorExpressionNode(binary_operator, left, right)
|
# Parse the unary expression after the binary operator.
|
||||||
|
right = self.ParseUnary()
|
||||||
# expression ::= unary binoprhs def ParseExpression(self): left =
|
|
||||||
self.ParseUnary() return self.ParseBinOpRHS(left, 0)
|
# If binary_operator binds less tightly with right than the operator after
|
||||||
|
# right, let the pending operator take right as its left.
|
||||||
# prototype # ::= id '(' id* ')' # ::= binary LETTER number? (id, id) #
|
next_precedence = self.GetCurrentTokenPrecedence()
|
||||||
::= unary LETTER (id) def ParsePrototype(self): precedence = None if
|
if precedence < next_precedence:
|
||||||
isinstance(self.current, IdentifierToken): kind = 'normal'
|
right = self.ParseBinOpRHS(right, precedence + 1)
|
||||||
function_name = self.current.name self.Next() # eat function name. elif
|
|
||||||
isinstance(self.current, UnaryToken): kind = 'unary' self.Next() # eat
|
# Merge left/right.
|
||||||
'unary'. if not isinstance(self.current, CharacterToken): raise
|
left = BinaryOperatorExpressionNode(binary_operator, left, right)
|
||||||
RuntimeError('Expected an operator after "unary".') function_name =
|
|
||||||
'unary' + self.current.char self.Next() # eat the operator. elif
|
# expression ::= unary binoprhs
|
||||||
isinstance(self.current, BinaryToken): kind = 'binary' self.Next() # eat
|
def ParseExpression(self):
|
||||||
'binary'. if not isinstance(self.current, CharacterToken): raise
|
left = self.ParseUnary()
|
||||||
RuntimeError('Expected an operator after "binary".') function_name =
|
return self.ParseBinOpRHS(left, 0)
|
||||||
'binary' + self.current.char self.Next() # eat the operator. if
|
|
||||||
isinstance(self.current, NumberToken): if not 1 <= self.current.value <=
|
# prototype # ::= id '(' id* ')'
|
||||||
100: raise RuntimeError('Invalid precedence: must be in range [1,
|
# ::= binary LETTER number? (id, id)
|
||||||
100].') precedence = self.current.value self.Next() # eat the
|
# ::= unary LETTER (id)
|
||||||
precedence. else: raise RuntimeError('Expected function name, "unary" or
|
def ParsePrototype(self):
|
||||||
"binary" in ' 'prototype.')
|
precedence = None
|
||||||
|
if isinstance(self.current, IdentifierToken):
|
||||||
::
|
kind = 'normal'
|
||||||
|
function_name = self.current.name
|
||||||
if self.current != CharacterToken('('):
|
self.Next() # eat function name.
|
||||||
raise RuntimeError('Expected "(" in prototype.')
|
elif isinstance(self.current, UnaryToken):
|
||||||
self.Next() # eat '('.
|
kind = 'unary'
|
||||||
|
self.Next() # eat 'unary'.
|
||||||
arg_names = []
|
if not isinstance(self.current, CharacterToken):
|
||||||
while isinstance(self.current, IdentifierToken):
|
raise RuntimeError('Expected an operator after "unary".')
|
||||||
arg_names.append(self.current.name)
|
function_name = 'unary' + self.current.char
|
||||||
self.Next()
|
self.Next() # eat the operator.
|
||||||
|
elif isinstance(self.current, BinaryToken):
|
||||||
if self.current != CharacterToken(')'):
|
kind = 'binary'
|
||||||
raise RuntimeError('Expected ")" in prototype.')
|
self.Next() # eat 'binary'.
|
||||||
|
if not isinstance(self.current, CharacterToken):
|
||||||
# Success.
|
raise RuntimeError('Expected an operator after "binary".')
|
||||||
self.Next() # eat ')'.
|
function_name = 'binary' + self.current.char
|
||||||
|
self.Next() # eat the operator.
|
||||||
if kind == 'unary' and len(arg_names) != 1:
|
if isinstance(self.current, NumberToken):
|
||||||
raise RuntimeError('Invalid number of arguments for a unary operator.')
|
if not 1 <= self.current.value <= 100:
|
||||||
elif kind == 'binary' and len(arg_names) != 2:
|
raise RuntimeError('Invalid precedence: must be in range [1, 100].')
|
||||||
raise RuntimeError('Invalid number of arguments for a binary operator.')
|
precedence = self.current.value
|
||||||
|
self.Next() # eat the precedence.
|
||||||
return PrototypeNode(function_name, arg_names, kind != 'normal', precedence)
|
else:
|
||||||
|
raise RuntimeError('Expected function name, "unary" or "binary" in '
|
||||||
# definition ::= 'def' prototype expression def ParseDefinition(self):
|
'prototype.')
|
||||||
self.Next() # eat def. proto = self.ParsePrototype() body =
|
|
||||||
self.ParseExpression() return FunctionNode(proto, body)
|
if self.current != CharacterToken('('):
|
||||||
|
raise RuntimeError('Expected "(" in prototype.')
|
||||||
# toplevelexpr ::= expression def ParseTopLevelExpr(self): proto =
|
self.Next() # eat '('.
|
||||||
PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression())
|
|
||||||
|
arg_names = []
|
||||||
# external ::= 'extern' prototype def ParseExtern(self): self.Next() #
|
while isinstance(self.current, IdentifierToken):
|
||||||
eat extern. return self.ParsePrototype()
|
arg_names.append(self.current.name)
|
||||||
|
self.Next()
|
||||||
# Top-Level parsing def HandleDefinition(self):
|
|
||||||
self.Handle(self.ParseDefinition, 'Read a function definition:')
|
if self.current != CharacterToken(')'):
|
||||||
|
raise RuntimeError('Expected ")" in prototype.')
|
||||||
def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:')
|
|
||||||
|
# Success.
|
||||||
def HandleTopLevelExpression(self): try: function =
|
self.Next() # eat ')'.
|
||||||
self.ParseTopLevelExpr().CodeGen() result =
|
|
||||||
g_llvm_executor.run_function(function, []) print 'Evaluated to:',
|
if kind == 'unary' and len(arg_names) != 1:
|
||||||
result.as_real(Type.double()) except Exception, e: print 'Error:', e
|
raise RuntimeError('Invalid number of arguments for a unary operator.')
|
||||||
try: self.Next() # Skip for error recovery. except: pass
|
elif kind == 'binary' and len(arg_names) != 2:
|
||||||
|
raise RuntimeError('Invalid number of arguments for a binary operator.')
|
||||||
def Handle(self, function, message): try: print message,
|
|
||||||
function().CodeGen() except Exception, e: print 'Error:', e try:
|
return PrototypeNode(function_name, arg_names, kind != 'normal', precedence)
|
||||||
self.Next() # Skip for error recovery. except: pass
|
|
||||||
|
# definition ::= 'def' prototype expression
|
||||||
Main driver code.
|
def ParseDefinition(self):
|
||||||
-----------------
|
self.Next() # eat def.
|
||||||
|
proto = self.ParsePrototype()
|
||||||
def main(): # Set up the optimizer pipeline. Start with registering info
|
body = self.ParseExpression()
|
||||||
about how the # target lays out data structures.
|
return FunctionNode(proto, body)
|
||||||
g_llvm_pass_manager.add(g_llvm_executor.target_data) # Do simple
|
|
||||||
"peephole" optimizations and bit-twiddling optzns.
|
# toplevelexpr ::= expression
|
||||||
g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) # Reassociate
|
def ParseTopLevelExpr(self):
|
||||||
expressions. g_llvm_pass_manager.add(PASS_REASSOCIATE) # Eliminate
|
proto = PrototypeNode('', [])
|
||||||
Common SubExpressions. g_llvm_pass_manager.add(PASS_GVN) # Simplify
|
return FunctionNode(proto, self.ParseExpression())
|
||||||
the control flow graph (deleting unreachable blocks, etc).
|
|
||||||
g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION)
|
# external ::= 'extern' prototype
|
||||||
|
def ParseExtern(self):
|
||||||
g_llvm_pass_manager.initialize()
|
self.Next() # eat extern.
|
||||||
|
return self.ParsePrototype()
|
||||||
# Install standard binary operators. # 1 is lowest possible precedence.
|
|
||||||
40 is the highest. g_binop_precedence['<'] = 10
|
# Top-Level parsing
|
||||||
g_binop_precedence['+'] = 20 g_binop_precedence['-'] = 20
|
def HandleDefinition(self):
|
||||||
g_binop_precedence['*'] = 40
|
self.Handle(self.ParseDefinition, 'Read a function definition:')
|
||||||
|
|
||||||
# Run the main "interpreter loop". while True: print 'ready>', try: raw
|
def HandleExtern(self):
|
||||||
= raw_input() except KeyboardInterrupt: break
|
self.Handle(self.ParseExtern, 'Read an extern:')
|
||||||
|
|
||||||
::
|
def HandleTopLevelExpression(self):
|
||||||
|
try:
|
||||||
parser = Parser(Tokenize(raw))
|
function = self.ParseTopLevelExpr().CodeGen()
|
||||||
while True:
|
result = g_llvm_executor.run_function(function, [])
|
||||||
# top ::= definition | external | expression | EOF
|
print 'Evaluated to:', result.as_real(Type.double())
|
||||||
if isinstance(parser.current, EOFToken):
|
except Exception, e:
|
||||||
break
|
print 'Error:', e
|
||||||
if isinstance(parser.current, DefToken):
|
try:
|
||||||
parser.HandleDefinition()
|
self.Next() # Skip for error recovery.
|
||||||
elif isinstance(parser.current, ExternToken):
|
except:
|
||||||
parser.HandleExtern()
|
pass
|
||||||
else:
|
|
||||||
parser.HandleTopLevelExpression()
|
def Handle(self, function, message):
|
||||||
|
try:
|
||||||
# Print out all of the generated code. print '', g_llvm_module
|
print message, function().CodeGen()
|
||||||
|
except Exception, e:
|
||||||
if **name** == '__main__': main()
|
print 'Error:', e
|
||||||
|
try:
|
||||||
|
self.Next() # Skip for error recovery.
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
Main driver code.
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
g_llvm_pass_manager.initialize()
|
||||||
|
|
||||||
|
# Install standard binary operators.
|
||||||
|
# 1 is lowest possible precedence. 40 is the highest.
|
||||||
|
g_binop_precedence['<'] = 10
|
||||||
|
g_binop_precedence['+'] = 20
|
||||||
|
g_binop_precedence['-'] = 20
|
||||||
|
g_binop_precedence['*'] = 40
|
||||||
|
|
||||||
|
# Run the main "interpreter loop".
|
||||||
|
while True:
|
||||||
|
print 'ready>',
|
||||||
|
try:
|
||||||
|
raw = raw_input()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
break
|
||||||
|
|
||||||
|
parser = Parser(Tokenize(raw))
|
||||||
|
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()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue