nand2tetris/compiler/engine.py

117 lines
2.8 KiB
Python

from tokenizer import JackTokenizer
from keywords import *
from grammar import CLASS,Element
"""
New Compilation Engine
"""
class Engine:
def __init__(self, input_file):
self.i = 0
self.jt = JackTokenizer(input_file, False)
# self.file = open(self.xml_file(input_file))
def xml_file(self, input_file):
return input_file + ".xml"
""" Throughout the compilation engine, we work using atoms"""
def atom(self):
token = self.jt.tokenType()
return Atom(token.value)
def compileClass(self):
self.compile(CLASS)
def advance(self):
self.jt.advance()
def ZeroOrMany(self, grammarList):
# print("ZeroOrMany")
if self.compile(grammarList[0]):
# We now expect the whole of it
for e in grammarList:
self.compile(e)
# We try for another list after this
return self.ZeroOrMany(grammarList)
else:
return None
def write(self, line):
print(line)
def MatchDict(self, dictionary):
# print("MatchDict")
xml_rows_for_lookup_terms = []
lookup_keys = ()
# How much to lookahead
lookahead = len(list(dictionary.keys())[0])
for _ in range(lookahead):
xml_rows_for_lookup_terms += [self.jt.xml_row()]
lookup_keys = lookup_keys + (self.atom(),)
self.advance()
grammar = dict[lookup_keys]
# We must open this before we compile the remainder
if isinstance(grammar, Element):
self.open(grammar)
grammar = grammar.grammar
# Now we put the first X terms from the conditional
for line in xml_rows_for_lookup_terms:
self.write(line)
return self.compile(grammar)
def ZeroOrOne(self, grammarTuple):
# print("ZeroOrOne")
if self.compile(grammarTuple[0]):
for e in grammarTuple:
self.compile(e)
return True
else:
return None
""" Has to MATCH """
def Atom(self, atom):
expected = atom
current = self.atom()
# We use in here to accomodate for bitmasks
if current in expected:
print(self.jt.xml_row(), end="")
self.advance()
return True
else:
return False
def open(self, el):
print("<%s>" % el.name)
def close(self, el):
print("</%s>" % el.name)
def compile(self, thing):
# TODO: OPEN TAGS
if isinstance(thing, Element):
self.open(thing)
for e in thing.grammar:
self.compile(e)
self.close(thing)
elif callable(thing):
grammar = thing()
self.compile(grammar)
else:
grammar = thing
grammarType = type(grammar)
if grammarType == list:
return self.ZeroOrMany(grammar)
elif grammarType == dict:
return self.MatchDict(grammar)
elif grammarType == tuple:
return self.ZeroOrOne(grammar)
elif grammarType == Atom:
return self.Atom(grammar)
else:
raise Exception("Should not have reached here")