Parsing user-defined binary ops & updating preference table.
This commit is contained in:
parent
e1f14c98f5
commit
007606bc0d
1 changed files with 27 additions and 12 deletions
37
chapter6.py
37
chapter6.py
|
|
@ -245,13 +245,15 @@ class ParseError(Exception): pass
|
||||||
|
|
||||||
|
|
||||||
class Parser(object):
|
class Parser(object):
|
||||||
def __init__(self, buf):
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# toplevel ::= definition | external | expression | ';'
|
||||||
|
def parse_toplevel(self, buf):
|
||||||
self.token_generator = Lexer(buf).tokens()
|
self.token_generator = Lexer(buf).tokens()
|
||||||
self.cur_tok = None
|
self.cur_tok = None
|
||||||
self._get_next_token()
|
self._get_next_token()
|
||||||
|
|
||||||
# toplevel ::= definition | external | expression | ';'
|
|
||||||
def parse_toplevel(self):
|
|
||||||
if self.cur_tok.kind == TokenKind.EXTERN:
|
if self.cur_tok.kind == TokenKind.EXTERN:
|
||||||
return self._parse_external()
|
return self._parse_external()
|
||||||
elif self.cur_tok.kind == TokenKind.DEF:
|
elif self.cur_tok.kind == TokenKind.DEF:
|
||||||
|
|
@ -282,7 +284,7 @@ class Parser(object):
|
||||||
def _cur_tok_precedence(self):
|
def _cur_tok_precedence(self):
|
||||||
"""Get the operator precedence of the current token."""
|
"""Get the operator precedence of the current token."""
|
||||||
try:
|
try:
|
||||||
return Parser._precedence_map[self.cur_tok.value]
|
return self._precedence_map[self.cur_tok.value]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
|
|
@ -438,6 +440,10 @@ class Parser(object):
|
||||||
raise ParseError('Invalid precedence', prec)
|
raise ParseError('Invalid precedence', prec)
|
||||||
self._get_next_token()
|
self._get_next_token()
|
||||||
|
|
||||||
|
# Add the new operator to our precedence table so we can properly
|
||||||
|
# parse it.
|
||||||
|
self._precedence_map[name[-1]] = prec
|
||||||
|
|
||||||
self._match(TokenKind.OPERATOR, '(')
|
self._match(TokenKind.OPERATOR, '(')
|
||||||
argnames = []
|
argnames = []
|
||||||
while self.cur_tok.kind == TokenKind.IDENTIFIER:
|
while self.cur_tok.kind == TokenKind.IDENTIFIER:
|
||||||
|
|
@ -525,7 +531,10 @@ class LLVMCodeGenerator(object):
|
||||||
cmp = self.builder.fcmp_unordered('<', lhs, rhs, 'cmptmp')
|
cmp = self.builder.fcmp_unordered('<', lhs, rhs, 'cmptmp')
|
||||||
return self.builder.uitofp(cmp, ir.DoubleType(), 'booltmp')
|
return self.builder.uitofp(cmp, ir.DoubleType(), 'booltmp')
|
||||||
else:
|
else:
|
||||||
raise CodegenError('Unknown binary operator', node.op)
|
# Note one of predefined operator, so it must be a user-defined one.
|
||||||
|
# Emit a call to it.
|
||||||
|
func = self.func_symtab['binary{0}'.format(node.op)]
|
||||||
|
return self.builder.call(func, [lhs, rhs], 'binop')
|
||||||
|
|
||||||
def _codegen_IfExprAST(self, node):
|
def _codegen_IfExprAST(self, node):
|
||||||
# Emit comparison value
|
# Emit comparison value
|
||||||
|
|
@ -683,6 +692,9 @@ class LLVMCodeGenerator(object):
|
||||||
self.func_symtab = {}
|
self.func_symtab = {}
|
||||||
# Create the function skeleton from the prototype.
|
# Create the function skeleton from the prototype.
|
||||||
func = self._codegen(node.proto)
|
func = self._codegen(node.proto)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Create the entry BB in the function and set the builder to it.
|
# Create the entry BB in the function and set the builder to it.
|
||||||
bb_entry = func.append_basic_block('entry')
|
bb_entry = func.append_basic_block('entry')
|
||||||
self.builder = ir.IRBuilder(bb_entry)
|
self.builder = ir.IRBuilder(bb_entry)
|
||||||
|
|
@ -705,6 +717,7 @@ class KaleidoscopeEvaluator(object):
|
||||||
llvm.initialize_native_asmprinter()
|
llvm.initialize_native_asmprinter()
|
||||||
|
|
||||||
self.codegen = LLVMCodeGenerator()
|
self.codegen = LLVMCodeGenerator()
|
||||||
|
self.parser = Parser()
|
||||||
self._add_builtins(self.codegen.module)
|
self._add_builtins(self.codegen.module)
|
||||||
|
|
||||||
self.target = llvm.Target.from_default_triple()
|
self.target = llvm.Target.from_default_triple()
|
||||||
|
|
@ -716,7 +729,7 @@ class KaleidoscopeEvaluator(object):
|
||||||
value for toplevel expressions.
|
value for toplevel expressions.
|
||||||
"""
|
"""
|
||||||
# Parse the given code and generate code from it
|
# Parse the given code and generate code from it
|
||||||
ast = Parser(codestr).parse_toplevel()
|
ast = self.parser.parse_toplevel(codestr)
|
||||||
self.codegen.generate_code(ast)
|
self.codegen.generate_code(ast)
|
||||||
|
|
||||||
if llvmdump:
|
if llvmdump:
|
||||||
|
|
@ -788,14 +801,16 @@ import unittest
|
||||||
|
|
||||||
class TestParser(unittest.TestCase):
|
class TestParser(unittest.TestCase):
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
p = Parser('def binary% 77(a b) a + b')
|
ast = Parser().parse_toplevel('def binary% 77(a b) a + b')
|
||||||
ast = p.parse_toplevel()
|
|
||||||
print(ast.dump())
|
print(ast.dump())
|
||||||
#self.assertIsInstance(ast, FunctionAST)
|
#self.assertIsInstance(ast, FunctionAST)
|
||||||
#self.assertIsInstance(ast.body, NumberExprAST)
|
#self.assertIsInstance(ast.body, NumberExprAST)
|
||||||
#self.assertEqual(ast.body.val, '2')
|
#self.assertEqual(ast.body.val, '2')
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
kalei = KaleidoscopeEvaluator()
|
p = Parser()
|
||||||
kalei.evaluate('def foo(a b) for x = 65, x < a, b in putchard(x)')
|
print(p.parse_toplevel('def binary% 77(a b) a + b').dump())
|
||||||
print(kalei.evaluate('foo(79, 1)', optimize=True, llvmdump=True))
|
print(p.parse_toplevel('def fra(x t) x % t').dump())
|
||||||
|
#kalei = KaleidoscopeEvaluator()
|
||||||
|
#kalei.evaluate('def foo(a b) for x = 65, x < a, b in putchard(x)')
|
||||||
|
#print(kalei.evaluate('foo(79, 1)', optimize=True, llvmdump=True))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue