pass 12-14
Design Suitable data Struct and implement pass - II of a two pass assembler
for pseudo machine
import os
Define the directory where files will be saved
output_directory = "assembler_output"
os.makedirs(output_directory, exist_ok=True)
Opcode table for the pseudo-machine
opcode_table = {
'LDA': '00', # Load Accumulator
'STA': '01', # Store Accumulator
'ADD': '02', # Add to Accumulator
'SUB': '03', # Subtract from Accumulator
'MUL': '04', # Multiply Accumulator
'DIV': '05', # Divide Accumulator
'HLT': '06', # Halt
}
Example symbol table from Pass I (assume it's generated already)
symbol_table = {
'ALPHA': 104,
'BETA': 105,
'GAMMA': 106
}
Example literal table from Pass I (if any literals were found)
literal_table = {} # Assuming no literals for simplicity
Sample assembler code
assembler_code = [
"START 100",
"LDA ALPHA",
"ADD BETA",
"STA GAMMA",
"HLT",
"ALPHA DC 5",
"BETA DC 10",
"GAMMA DS 1",
"END"
]
Intermediate representation after Pass I for use in Pass II
intermediate_representation = [
{"line": "LDA ALPHA", "opcode": "LDA", "operand": "ALPHA"},
{"line": "ADD BETA", "opcode": "ADD", "operand": "BETA"},
{"line": "STA GAMMA", "opcode": "STA", "operand": "GAMMA"},
{"line": "HLT", "opcode": "HLT", "operand": None},
{"line": "ALPHA DC 5", "directive": "DC", "value": 5},
{"line": "BETA DC 10", "directive": "DC", "value": 10},
{"line": "GAMMA DS 1", "directive": "DS", "value": 1}
]
Output data structure to store final machine code
machine_code = []
def pass_two(intermediate_representation):
# Generate machine code using the intermediate representation and symbol table
for item in intermediate_representation:
if "opcode" in item: # Instruction line
opcode = opcode_table.get(item["opcode"])
operand = item["operand"]
# Resolve operand address from symbol table, if it exists
address = symbol_table.get(operand, "00") if operand else "00"
# Formulate machine code instruction
machine_instruction = f"{opcode} {address}"
machine_code.append(machine_instruction)
elif "directive" in item: # Data definition (DC or DS)
if item["directive"] == "DC": # Define constant
machine_code.append(f"{item['value']:02}")
elif item["directive"] == "DS": # Define space
for _ in range(item["value"]): # Reserve space
machine_code.append("00") # Empty space
return machine_code
Execute Pass II to generate machine code
machine_code = pass_two(intermediate_representation)
Write symbol table to a file
with open(os.path.join(output_directory, "symbol_table.txt"), "w") as f:
f.write("Symbol Table:\n")
for symbol, address in symbol_table.items():
f.write(f"{symbol}: {address}\n")
Write literal table to a file
with open(os.path.join(output_directory, "literal_table.txt"), "w") as f:
if literal_table:
f.write("Literal Table:\n")
for literal, address in literal_table.items():
f.write(f"{literal}: {address}\n")
else:
f.write("Literal Table is empty (no literals found).\n")
Write intermediate representation to a file
with open(os.path.join(output_directory, "intermediate_representation.txt"), "w") as f:
f.write("Intermediate Representation:\n")
for item in intermediate_representation:
f.write(f"{item}\n")
Write final machine code to a file
with open(os.path.join(output_directory, "machine_code.txt"), "w") as f:
f.write("Machine Code:\n")
for code in machine_code:
f.write(f"{code}\n")
print(f"Output files have been generated in the '{output_directory}' directory.")
- Design suitable data Structures and implement
Pass-I of a two pass
macro processor
import os
Define the directory where files will be saved
output_directory = "macro_processor_output"
os.makedirs(output_directory, exist_ok=True)
Sample Assembly Code with Macros
assembler_code = [
"MACRO", # Start of macro definition
"INCR &ARG1, &ARG2", # Macro name and parameters
"LDA &ARG1", # Macro body
"ADD &ARG2",
"STA &ARG1",
"MEND", # End of macro definition
"MACRO", # Start of another macro definition
"DECR &ARG1", # Macro name and parameters
"LDA &ARG1",
"SUB #1",
"STA &ARG1",
"MEND", # End of macro definition
"START 100",
"INCR A, B", # Macro invocation
"DECR C", # Macro invocation
"END"
]
Data structures for Pass I
mnt = [] # Macro Name Table
mdt = [] # Macro Definition Table
ala = {} # Argument List Array (dictionary for each macro)
mdt_index = 0 # MDT index counter for tracking line positions
Process Pass I to define macros
def pass_one(assembler_code):
global mdt_index
in_macro = False # Flag to check if we're inside a macro definition
current_macro_name = "" # Stores the current macro name
ala.clear()
mnt.clear()
mdt.clear()
for line in assembler_code:
tokens = line.split()
# Start of a macro definition
if tokens[0] == "MACRO":
in_macro = True
continue
# End of macro definition
elif tokens[0] == "MEND":
in_macro = False
current_macro_name = ""
continue
# Inside a macro definition
if in_macro:
if current_macro_name == "": # First line after MACRO is the macro name
current_macro_name = tokens[0]
mnt.append({"macro_name": current_macro_name, "mdt_index": mdt_index})
# Initialize ALA for this macro
ala[current_macro_name] = {}
params = tokens[1:] # Get parameters after macro name
# Populate ALA for the macro
for i, param in enumerate(params):
param_name = param.replace("&", "")
ala[current_macro_name][param_name] = f"#{i+1}" # Positional notation
else:
# Add each line to MDT, replacing formal parameters with positional notation
mdt_line = []
for token in tokens:
if token.startswith("&"):
# Replace parameter with positional notation using ALA
param_name = token.replace("&", "")
if param_name in ala[current_macro_name]:
mdt_line.append(ala[current_macro_name][param_name])
else:
mdt_line.append(token)
else:
mdt_line.append(token)
# Store the line in MDT
mdt.append(" ".join(mdt_line))
mdt_index += 1
else:
# Process non-macro lines (non-macro definitions)
pass # Pass I only processes macro definitions
return mnt, mdt, ala
Execute Pass I to populate MNT, MDT, and ALA
mnt, mdt, ala = pass_one(assembler_code)
Write Macro Name Table (MNT) to a file
with open(os.path.join(output_directory, "mnt.txt"), "w") as f:
f.write("Macro Name Table (MNT):\n")
for entry in mnt:
f.write(f"Macro Name: {entry['macro_name']}, MDT Index: {entry['mdt_index']}\n")
Write Macro Definition Table (MDT) to a file
with open(os.path.join(output_directory, "mdt.txt"), "w") as f:
f.write("Macro Definition Table (MDT):\n")
for i, line in enumerate(mdt):
f.write(f"{i}: {line}\n")
Write Argument List Array (ALA) to a file
with open(os.path.join(output_directory, "ala.txt"), "w") as f:
f.write("Argument List Array (ALA):\n")
for macro_name, args in ala.items():
f.write(f"Macro: {macro_name}\n")
for arg_name, position in args.items():
f.write(f" {arg_name}: {position}\n")
print(f"Output files have been generated in the '{output_directory}' directory.")
- Design suitable data
Structures & implement
Pass-II of a two pass
macro processor
import os
Directory for output files
output_directory = "macro_processor_output"
os.makedirs(output_directory, exist_ok=True)
Data structures populated from Pass I
mnt = [
{"macro_name": "INCR", "mdt_index": 0},
{"macro_name": "DECR", "mdt_index": 4}
]
mdt = [
"LDA #1",
"ADD #2",
"STA #1",
"MEND",
"LDA #1",
"SUB #1",
"STA #1",
"MEND"
]
ala_template = {
"INCR": {"ARG1": "#1", "ARG2": "#2"},
"DECR": {"ARG1": "#1"}
}
Sample assembly code with macro invocations
assembler_code = [
"START 100",
"INCR A, B", # Macro invocation
"DECR C", # Macro invocation
"END"
]
Final expanded assembly code output
expanded_code = []
def pass_two(assembler_code):
global ala_template
expanded_code = [] # Holds the final expanded code
for line in assembler_code:
tokens = line.split()
macro_name = tokens[0]
# Check if this line is a macro invocation
mnt_entry = next((entry for entry in mnt if entry["macro_name"] == macro_name), None)
if mnt_entry:
# Macro invocation found
mdt_index = mnt_entry["mdt_index"]
actual_args = tokens[1].split(",") if len(tokens) > 1 else []
actual_args = [arg.strip() for arg in actual_args]
# Create a local ALA for this macro invocation
if len(actual_args) == len(ala_template[macro_name]):
ala = {pos: actual for (param, pos), actual in zip(ala_template[macro_name].items(), actual_args)}
else:
print(f"Error: Incorrect number of arguments for macro '{macro_name}'. Expected {len(ala_template[macro_name])}, got {len(actual_args)}.")
continue
# Expand macro lines from MDT
i = mdt_index
while mdt[i] != "MEND":
expanded_line = []
for token in mdt[i].split():
if token in ala: # If token is a positional argument
expanded_line.append(ala[token]) # Replace with actual argument
else:
expanded_line.append(token) # Add token as-is
expanded_code.append(" ".join(expanded_line))
i += 1
else:
# Not a macro invocation, add the line as-is
expanded_code.append(line)
return expanded_code
Execute Pass II to expand macros
expanded_code = pass_two(assembler_code)
Write expanded assembly code to a file
with open(os.path.join(output_directory, "expanded_code.txt"), "w") as f:
f.write("Expanded Assembly Code:\n")
for line in expanded_code:
f.write(f"{line}\n")
Write ALA for record-keeping
with open(os.path.join(output_directory, "ala_invocations.txt"), "w") as f:
f.write("Argument List Array (ALA) for each macro invocation:\n")
for macro_name, params in ala_template.items():
f.write(f"Macro: {macro_name}\n")
for param, pos in params.items():
f.write(f" {param}: {pos}\n")
print(f"Output files have been generated in the '{output_directory}' directory.")
macro with in macro
import os
Directory to save output files
output_directory = "macro_processor_output"
os.makedirs(output_directory, exist_ok=True)
Mock data structures from Pass I
mnt = [
{"macro_name": "INCR", "mdt_index": 0},
{"macro_name": "DECR", "mdt_index": 5},
{"macro_name": "DOUBLE_INCR", "mdt_index": 8}
]
mdt = [
# INCR macro
"LDA #1",
"ADD #2",
"STA #1",
"MEND",
# DECR macro
"LDA #1",
"SUB #1",
"STA #1",
"MEND",
# DOUBLE_INCR macro that calls INCR twice
"INCR #1, #2",
"INCR #1, #2",
"MEND"
]
ala_template = {
"INCR": {"ARG1": "#1", "ARG2": "#2"},
"DECR": {"ARG1": "#1"},
"DOUBLE_INCR": {"ARG1": "#1", "ARG2": "#2"}
}
Assembly code with nested macro calls
assembler_code = [
"START 100",
"DOUBLE_INCR A, B", # Nested macro call
"END"
]
Expanded assembly code output
expanded_code = []
def expand_macro(macro_name, actual_args):
""" Recursively expand macros, including nested macros. """
# Check if the macro exists in the MNT
mnt_entry = next((entry for entry in mnt if entry["macro_name"] == macro_name), None)
if not mnt_entry:
return [f"Error: Undefined macro '{macro_name}'"]
# Get the MDT index for the macro
mdt_index = mnt_entry["mdt_index"]
# Create an ALA for this invocation
if len(actual_args) == len(ala_template[macro_name]):
ala = {pos: actual for (param, pos), actual in zip(ala_template[macro_name].items(), actual_args)}
else:
return [f"Error: Incorrect number of arguments for macro '{macro_name}'."]
# Begin expanding this macro
expanded_lines = []
i = mdt_index
while mdt[i] != "MEND":
tokens = mdt[i].split()
inner_macro_name = tokens[0]
# Check if token is a nested macro call
inner_mnt_entry = next((entry for entry in mnt if entry["macro_name"] == inner_macro_name), None)
if inner_mnt_entry:
# Nested macro call found, recursively expand it
nested_args = [ala.get(arg.strip("#"), arg) for arg in tokens[1].split(",")]
expanded_lines.extend(expand_macro(inner_macro_name, nested_args))
else:
# Replace positional arguments with actual arguments
expanded_line = []
for token in tokens:
if token.startswith("#") and token in ala:
expanded_line.append(ala[token])
else:
expanded_line.append(token)
expanded_lines.append(" ".join(expanded_line))
i += 1
return expanded_lines
def pass_two(assembler_code):
expanded_code = [] # Holds the final expanded code
for line in assembler_code:
tokens = line.split()
macro_name = tokens[0]
# Check if this line is a macro invocation
mnt_entry = next((entry for entry in mnt if entry["macro_name"] == macro_name), None)
if mnt_entry:
# Macro invocation found; get arguments
actual_args = tokens[1].split(",") if len(tokens) > 1 else []
actual_args = [arg.strip() for arg in actual_args]
# Expand the macro (and handle nested macros)
expanded_code.extend(expand_macro(macro_name, actual_args))
else:
# Not a macro invocation, add the line as-is
expanded_code.append(line)
return expanded_code
Execute Pass II to expand macros
expanded_code = pass_two(assembler_code)
Write expanded assembly code to a file
with open(os.path.join(output_directory, "expanded_code.txt"), "w") as f:
f.write("Expanded Assembly Code:\n")
for line in expanded_code:
f.write(f"{line}\n")
Write ALA for each macro invocation to a file for record-keeping
with open(os.path.join(output_directory, "ala_invocations.txt"), "w") as f:
f.write("Argument List Array (ALA) for each macro invocation:\n")
for macro_name, params in ala_template.items():
f.write(f"Macro: {macro_name}\n")
for param, pos in params.items():
f.write(f" {param}: {pos}\n")
Write MDT and MNT to files for completeness
with open(os.path.join(output_directory, "mnt.txt"), "w") as f:
f.write("Macro Name Table (MNT):\n")
for entry in mnt:
f.write(f"{entry['macro_name']} - MDT Index: {entry['mdt_index']}\n")
with open(os.path.join(output_directory, "mdt.txt"), "w") as f:
f.write("Macro Definition Table (MDT):\n")
for i, line in enumerate(mdt):
f.write(f"{i}: {line}\n")
print(f"Output files have been generated in the '{output_directory}' directory.")