"""
Extract information from a list of assembly line info dictionaries.
"""
from copy import deepcopy
from . import number_utils
from .data_structures import get_summary_entry_template
[docs]def generate_assembly_summary(asm_line_infos):
"""
Produce a summary that combines assembly and machine code.
The summary will be like this::
1 $variable0 |
2 @label1 |
3 LOAD [$variable1] A | 0 00 00000000 - @label1 255 FF 11111111
| 1 01 00000001 - 1 01 00000001 $variable1
4 |
5 @label2 |
6 LOAD [$variable2] A | 2 02 00000010 - @label2 255 FF 11111111
| 3 03 00000011 - 2 02 00000010 $variable2
7 JUMP @label1 | 4 04 00000100 - 255 FF 11111111
| 5 05 00000101 - 0 00 00000000 @label1
8 |
9 STORE A [#123] | 6 06 00000110 - 255 FF 11111111
| 7 07 00000111 - 123 7B 01111011 #123
10 @label3 |
11 LOAD [$variable3] B | 8 08 00001000 - @label3 255 FF 11111111
| 9 09 00001001 - 3 03 00000011 $variable3
12 LOAD [$variable0] C | 10 0A 00001010 - 255 FF 11111111
| 11 0B 00001011 - 0 00 00000000 $variable0
13 $variable4 |
14 // comment
Args:
asm_line_infos (list(dict)): List of dictionaries of information
about the parsed assembly.
Returns:
str: Printable summary.
"""
lines = generate_assembly_summary_lines(asm_line_infos)
return "\n".join(lines)
[docs]def generate_assembly_summary_lines(asm_line_infos):
"""
Generate list of lines for an assembly summary
Args:
asm_line_infos (list(dict)): List of dictionaries of information
about the parsed assembly.
Returns:
list(str): List of lines for the summary.
"""
summary_data = get_assembly_summary_data(asm_line_infos)
widest_values = get_widest_column_values(summary_data)
summary_line_template = (
"{asm_line_no: >{widest_asm_line_no}} "
"{raw_assembly_line: <{widest_asm_line}} "
"| "
"{mc_index_decimal: >{widest_mc_index_decimal}} "
"{mc_index_hex} "
"{mc_index_bitstring} "
"{mc_byte_sep} "
"{mc_label: <{widest_mc_label}} "
"{mc_byte_decimal: >{widest_mc_byte_decimal}} "
"{mc_byte_hex:} "
"{mc_byte_bitstring} "
"{mc_byte_constant}"
)
formatted_summary_lines = []
for summary_line in summary_data:
if summary_line["has_assembly"]:
asm_line_info = summary_line["assembly"]["info"]
asm_line_no = str(asm_line_info["line_no"])
raw_assembly_line = asm_line_info["raw"]
else:
asm_line_no = ""
raw_assembly_line = ""
if summary_line["has_mc_byte"]:
mc_byte_info = summary_line["mc_byte"]["info"]
mc_index_decimal = str(mc_byte_info["index"])
mc_index_hex = "{index:02X}".format(
index=mc_byte_info["index"],
)
mc_index_bitstring = number_utils.number_to_bitstring(
mc_byte_info["index"]
)
mc_byte_sep = "-"
if summary_line["mc_byte"]["has_label"]:
mc_label = summary_line["mc_byte"]["label"]
else:
mc_label = ""
mc_byte_decimal = str(
number_utils.bitstring_to_number(mc_byte_info["bitstring"])
)
mc_byte_bitstring = mc_byte_info["bitstring"]
mc_byte_hex = "{mc_byte:02X}".format(
mc_byte=int(mc_byte_info["bitstring"], 2),
)
if mc_byte_info["byte_type"] == "constant":
mc_byte_constant = mc_byte_info["constant"]
else:
mc_byte_constant = ""
else:
mc_index_decimal = ""
mc_index_hex = ""
mc_index_bitstring = ""
mc_byte_sep = ""
mc_label = ""
mc_byte_decimal = ""
mc_byte_bitstring = ""
mc_byte_hex = ""
mc_byte_constant = ""
formatted_line = summary_line_template.format(
asm_line_no=asm_line_no,
widest_asm_line_no=widest_values["asm_line_no"],
raw_assembly_line=raw_assembly_line,
widest_asm_line=widest_values["asm_line"],
mc_index_decimal=mc_index_decimal,
widest_mc_index_decimal=widest_values["mc_index_decimal"],
mc_index_hex=mc_index_hex,
mc_index_bitstring=mc_index_bitstring,
mc_byte_sep=mc_byte_sep,
mc_label=mc_label,
widest_mc_label=widest_values["mc_label"],
mc_byte_decimal=mc_byte_decimal,
widest_mc_byte_decimal=widest_values["mc_byte_decimal"],
mc_byte_bitstring=mc_byte_bitstring,
mc_byte_hex=mc_byte_hex,
mc_byte_constant=mc_byte_constant,
).rstrip()
formatted_summary_lines.append(formatted_line)
return formatted_summary_lines
[docs]def get_assembly_summary_data(asm_line_infos):
"""
Process assembly data to make formatting easier for the summary.
Args:
asm_line_infos (list(dict)): List of line info dictionaries as
returned by
:func:`~.process_assembly_lines`
.
Returns:
list: List of entries for the assembly summary print out
"""
assembly_summary = []
for asm_line_info in asm_line_infos:
if asm_line_info["has_machine_code"]:
dual_entry = get_summary_entry_template()
dual_entry["has_assembly"] = True
dual_entry["assembly"]["info"] = deepcopy(asm_line_info)
dual_entry["has_mc_byte"] = True
dual_entry["mc_byte"]["info"] = deepcopy(
asm_line_info["mc_bytes"][0]
)
if asm_line_info["has_label_assigned"]:
dual_entry["mc_byte"]["has_label"] = True
dual_entry["mc_byte"]["label"] = asm_line_info["assigned_label"]
assembly_summary.append(dual_entry)
for mc_byte_info in asm_line_info["mc_bytes"][1:]:
byte_only_entry = get_summary_entry_template()
byte_only_entry["has_mc_byte"] = True
byte_only_entry["mc_byte"]["info"] = deepcopy(mc_byte_info)
assembly_summary.append(byte_only_entry)
else:
assembly_only_entry = get_summary_entry_template()
assembly_only_entry["has_assembly"] = True
assembly_only_entry["assembly"]["info"] = deepcopy(asm_line_info)
assembly_summary.append(assembly_only_entry)
return assembly_summary
[docs]def get_widest_column_values(assembly_summary_data):
"""
Find widest values in the columns of the output.
Required for the eventual printed table to line up correctly.
Args:
assembly_summary_data (list(dict)): List of dictionaries (as
returned by :func:`~.get_assembly_summary_data`) with all the
summary information data.
Returns:
dict: Mapping of columns for widest values.
"""
widest_values = {
"asm_line_no": 0,
"asm_line": 0,
"mc_index_decimal": 0,
"mc_byte_decimal": 0,
"mc_label": 0,
}
for entry in assembly_summary_data:
if entry["has_assembly"]:
# Assembly line number width
line_no_width = len(str(entry["assembly"]["info"]["line_no"]))
if line_no_width > widest_values["asm_line_no"]:
widest_values["asm_line_no"] = line_no_width
# Assembly line width
asm_line_width = len(entry["assembly"]["info"]["raw"])
if asm_line_width > widest_values["asm_line"]:
widest_values["asm_line"] = asm_line_width
if entry["has_mc_byte"]:
# Decimal byte index width
mcb_index_decimal_width = len(
str(entry["mc_byte"]["info"]["index"])
)
if mcb_index_decimal_width > widest_values["mc_index_decimal"]:
widest_values["mc_index_decimal"] = mcb_index_decimal_width
# Decimal byte index width
mc_byte_decimal_width = len(
str(
number_utils.bitstring_to_number(
entry["mc_byte"]["info"]["bitstring"]
)
)
)
if mc_byte_decimal_width > widest_values["mc_byte_decimal"]:
widest_values["mc_byte_decimal"] = mc_byte_decimal_width
# Label width
if entry["mc_byte"]["has_label"]:
mcb_label_width = len(entry["mc_byte"]["label"])
if mcb_label_width > widest_values["mc_label"]:
widest_values["mc_label"] = mcb_label_width
return widest_values