Commit 7e680e4a authored by Taddeus Kroes's avatar Taddeus Kroes

Updated printer format, also added inline comments as an option instead of a separate command.

parent 0285fcca
......@@ -79,11 +79,12 @@ def p_line_instruction(p):
def p_line_comment(p):
'line : COMMENT NEWLINE'
statements.append(S('comment', p[1], inline=False))
statements.append(S('comment', p[1]))
def p_line_inline_comment(p):
'line : instruction COMMENT NEWLINE'
statements.append(S('comment', p[2], inline=True))
# Add the inline comment to the last parsed statement
statements[-1].options['comment'] = p[2]
def p_instruction_command(p):
'instruction : command'
......
......@@ -38,12 +38,12 @@ class Statement:
def __repr__(self): # pragma: nocover
return str(self)
def has_inline_comment(self):
return 'comment' in self.options and len(self.options['comment'])
def is_comment(self):
return self.stype == 'comment'
def is_inline_comment(self):
return self.is_comment() and self.options['inline']
def is_directive(self):
return self.stype == 'directive'
......@@ -152,7 +152,7 @@ class Statement:
def get_def(self):
"""Get the variable that this statement defines, if any."""
instr = ['move', 'addu', 'subu', 'li', 'dmfc1', 'mov.d']
if self.is_command('mtc1'):
return [self[1]]
if self.is_load_non_immediate() or self.is_arith() \
......
from math import ceil
TABSIZE = 4 # Size in spaces of a single tab
INLINE_COMMENT_LEVEL = 6 # Number of tabs to inline commment level
COMMAND_SIZE = 8 # Default length of a command name, used for
# indenting
ADD_COMMENT_BLOCKS = True # Wether to add newlines before and after
# non-inline comment
ADD_ARGUMENT_SPACE = False # Wether to add a space between command arguments
# and the previous comma
def write_statements(statements):
"""Write a list of statements to valid assembly code."""
out = ''
indent_level = 0
prevline = ''
prev_comment = False
for i, s in enumerate(statements):
newline = '\n' if i else ''
current_comment = False
if s.is_label():
line = s.name + ':'
indent_level = 1
elif s.is_comment():
line = '#' + s.name
if s.is_inline_comment():
l = len(prevline.expandtabs(4))
tabs = int(ceil((24 - l) / 4.)) + 1
newline = '\t' * tabs
else:
line = '\t' * indent_level + line
line = '\t' * indent_level + '#' + s.name
current_comment = True
elif s.is_directive():
line = '\t' + s.name
elif s.is_command():
line = '\t' + s.name
# If there are arguments, add tabs until the 8 character limit has
# been reached. If the command name is 8 or more characers long,
# add a single space
if len(s):
if len(s.name) < 8:
line += '\t'
l = len(s.name)
if l < COMMAND_SIZE:
line += '\t' * int(ceil((COMMAND_SIZE - l)
/ float(TABSIZE)))
else:
line += ' '
line += ','.join(map(str, s))
delim = ', ' if ADD_ARGUMENT_SPACE else ','
line += delim.join(map(str, s))
else:
raise Exception('Unsupported statement type "%s"' % s.stype)
out += newline + line
prevline = line
# Add the inline comment, if there is any
if s.has_inline_comment():
start = INLINE_COMMENT_LEVEL * TABSIZE
diff = start - len(line.expandtabs(TABSIZE))
# The comment must not be directly adjacent to the command itself
tabs = int(ceil(diff / float(TABSIZE))) + 1 if diff > 0 else 1
# Add newline at end of file
out += '\n'
line += '\t' * tabs + '#' + s.options['comment']
# Add newline at end of command
line += '\n'
if ADD_COMMENT_BLOCKS:
if prev_comment ^ current_comment:
out += '\n'
out += line
prev_comment = current_comment
return out
def write_to_file(filename, statements):
"""Convert a list of statements to valid assembly code and write it to a
file."""
......
......@@ -36,9 +36,10 @@ class TestStatement(unittest.TestCase):
self.assertFalse(S('comment', 'foo', inline=False).is_label())
self.assertFalse(S('directive', 'foo').is_command())
def test_is_inline_comment(self):
self.assertTrue(S('comment', 'foo', inline=True).is_inline_comment())
self.assertFalse(S('comment', 'foo', inline=False).is_inline_comment())
def test_has_inline_comment(self):
self.assertTrue(S('comment', 'foo', comment='bar').has_inline_comment())
self.assertFalse(S('comment', 'foo', comment='').has_inline_comment())
self.assertFalse(S('comment', 'foo').has_inline_comment())
def test_jump_target(self):
self.assertEqual(S('command', 'j', 'foo').jump_target(), 'foo')
......@@ -115,16 +116,16 @@ class TestStatement(unittest.TestCase):
self.assertEqual(S('command', 'dmfc1', 'a', '$f0').get_def(), a)
self.assertEqual(S('command', 'mtc1', 'b', 'a').get_def(), a)
self.assertEqual(S('command', 'trunc.w.d', 'a', 'b', 'c').get_def(), a)
def test_get_def_false(self):
a = []
self.assertEqual(S('command', 'bne', 'a', 'b', 'L1').get_def(), a)
def test_get_use_true(self):
arg1 = ['$1']
arg2 = ['$1', '$2']
self.assertEqual(S('command', 'addu', '$3', '$1', '$2').get_use(), \
arg2)
self.assertEqual(S('command', 'subu', '$3', '$1', '$2').get_use(), \
......@@ -165,5 +166,5 @@ class TestStatement(unittest.TestCase):
self.assertEqual(S('command', 'c.lt.d', '$1', '$2').get_use(), arg2)
self.assertEqual(S('command', 'bgez', '$1', '$2').get_use(), arg1)
self.assertEqual(S('command', 'bltz', '$1', '$2').get_use(), arg1)
self.assertEqual(S('command', 'trunc.w.d', '$3', '$1', '$2').get_use()\
, arg2)
self.assertEqual(S('command', 'trunc.w.d', '$3', '$1', '$2').get_use(),
arg2)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment