Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import pyparsing as pp
- import re
- import struct
- from typing import List, Dict, Union
- class PDP11Assembler:
- def __init__(self):
- # Инициализация парсера pyparsing (как в вашем коде)
- self.command_name = pp.Word(pp.alphas)
- self.argument_name = pp.Word(pp.printables, exclude_chars=';,')
- self.arguments = pp.Optional(self.argument_name) + pp.ZeroOrMore(pp.Suppress(',') + self.argument_name)
- self.label = pp.Word(pp.alphas) + pp.Optional(pp.Suppress(' ')) + pp.Suppress(":")
- self.comment = pp.Suppress(';') + pp.Optional(pp.Suppress(' ')) + pp.restOfLine()
- self.rule = pp.Optional(self.label) + pp.Optional(self.command_name) + pp.Optional(
- self.arguments) + pp.Optional(self.comment)
- # Таблица команд (расширенная версия)
- self.command_table = {
- 'halt': {'opcode': 0o000000, 'args': [], 'handler': self._handle_no_args},
- 'mov': {'opcode': 0o010000, 'args': ['ss', 'dd'], 'handler': self._handle_ss_dd},
- 'add': {'opcode': 0o060000, 'args': ['ss', 'dd'], 'handler': self._handle_ss_dd},
- 'sub': {'opcode': 0o160000, 'args': ['ss', 'dd'], 'handler': self._handle_ss_dd},
- 'cmp': {'opcode': 0o020000, 'args': ['ss', 'dd'], 'handler': self._handle_ss_dd},
- 'br': {'opcode': 0o000400, 'args': ['xx'], 'handler': self._handle_branch},
- 'bne': {'opcode': 0o001000, 'args': ['xx'], 'handler': self._handle_branch},
- }
- self.labels = {}
- self.current_address = 0o1000
- self.output_blocks = []
- def parse_line(self, line: str) -> List[str]:
- """Аналог вашей функции parse с улучшениями"""
- line = line.strip()
- if not line:
- return []
- if line.startswith('.'):
- if line.startswith('.='):
- return ['origin', line[2:].strip()]
- return []
- try:
- return self.rule.parseString(line).asList()
- except pp.ParseException:
- return []
- def _handle_no_args(self, cmd: Dict, args: List[str], words: List[Union[int, str]]):
- """Обработка команд без аргументов"""
- words.append(cmd['opcode'])
- def _handle_branch(self, cmd: Dict, args: List[str], words: List[Union[int, str]]):
- """Обработка команд ветвления"""
- words.append(cmd['opcode'])
- words.append(args[0]) # Сохраняем метку для разрешения позже
- def _handle_ss_dd(self, cmd: Dict, args: List[str], words: List[Union[int, str]]):
- """Обработка двухоперандных команд"""
- src = self._parse_operand(args[0])
- dst = self._parse_operand(args[1])
- instruction = cmd['opcode'] | (src['mode'] << 6) | (src['reg'] << 3) | dst['mode'] | dst['reg']
- words.append(instruction)
- if src['mode'] == 0o27: # Немедленная адресация
- words.append(src['value'])
- def _parse_operand(self, op: str) -> Dict[str, Union[int, str]]:
- """Улучшенный парсер операндов"""
- if not op:
- return {'mode': 0, 'reg': 0, 'value': 0}
- # Регистровая адресация (R0-R7)
- if re.match(r'^[rR][0-7]$', op):
- return {'mode': 0, 'reg': int(op[1]), 'value': 0}
- # Немедленная адресация (#n)
- if op.startswith('#'):
- return {'mode': 0o27, 'reg': 0, 'value': int(op[1:])}
- return {'mode': 0, 'reg': 0, 'value': 0}
- def cmd_to_raw_machine_code(self, parsed: List[str]) -> List[Union[int, str]]:
- """Аналог вашей функции, но с улучшенной структурой"""
- if not parsed:
- return []
- if isinstance(parsed[0], list) and len(parsed[0]) == 2 and parsed[0][1] == ':':
- # Обработка метки
- label = parsed[0][0]
- self.labels[label] = self.current_address
- parsed = parsed[1:]
- if not parsed:
- return []
- if parsed[0] == 'origin':
- self.current_address = int(parsed[1], 8)
- return []
- cmd_name = parsed[0].lower()
- if cmd_name not in self.command_table:
- return []
- cmd = self.command_table[cmd_name]
- args = parsed[1:]
- if len(args) != len(cmd['args']):
- return []
- words = []
- cmd['handler'](cmd, args, words)
- return words
- def first_pass(self, lines: List[str]):
- """Первый проход: сбор меток"""
- self.current_address = 0o1000
- for line in lines:
- parsed = self.parse_line(line)
- if not parsed:
- continue
- if parsed[0] == 'origin':
- self.current_address = int(parsed[1], 8)
- continue
- if isinstance(parsed[0], list) and len(parsed[0]) == 2 and parsed[0][1] == ':':
- label = parsed[0][0]
- self.labels[label] = self.current_address
- parsed = parsed[1:]
- if not parsed:
- continue
- cmd_name = parsed[0].lower()
- if cmd_name in self.command_table:
- cmd = self.command_table[cmd_name]
- self.current_address += 2 # Основное слово команды
- # Учет дополнительных слов
- for arg in parsed[1:]:
- if arg.startswith('#'):
- self.current_address += 2
- def second_pass(self, lines: List[str]):
- """Второй проход: генерация машинного кода"""
- self.current_address = 0o1000
- current_block = {'start': 0o1000, 'data': []}
- for line in lines:
- parsed = self.parse_line(line)
- if not parsed:
- continue
- if parsed[0] == 'origin':
- if current_block['data']:
- self.output_blocks.append(current_block)
- addr = int(parsed[1], 8)
- current_block = {'start': addr, 'data': []}
- self.current_address = addr
- continue
- if isinstance(parsed[0], list) and len(parsed[0]) == 2 and parsed[0][1] == ':':
- parsed = parsed[1:]
- if not parsed:
- continue
- words = self.cmd_to_raw_machine_code(parsed)
- for item in words:
- if isinstance(item, str): # Метка для ветвления
- offset = (self.labels[item] - self.current_address - 2) // 2
- current_block['data'][-1] |= (offset & 0o377)
- else:
- current_block['data'].append(item)
- self.current_address += 2
- if current_block['data']:
- self.output_blocks.append(current_block)
- def write_s_record_format(self, filename: str):
- """Запись результата в требуемом формате"""
- if not self.output_blocks:
- return
- block = self.output_blocks[0]
- data_bytes = bytearray()
- for word in block['data']:
- # Правильный порядок байтов (как в вашем примере)
- data_bytes.append(word & 0xFF)
- data_bytes.append((word >> 8) & 0xFF)
- with open(filename, 'w') as f:
- # Первая строка: адрес и размер
- f.write(f"0200 {len(data_bytes):04x}\n")
- # Байты машинного кода
- for byte in data_bytes:
- f.write(f"{byte:02x}\n")
- def assemble(self, input_filename: str, output_filename: str):
- """Основной метод ассемблирования"""
- with open(input_filename, 'r') as f:
- lines = f.readlines()
- # Два прохода
- self.first_pass(lines)
- self.second_pass(lines)
- # Запись результата
- self.write_s_record_format(output_filename)
- # Пример использования
- if __name__ == "__main__":
- assembler = PDP11Assembler()
- test_code = """
- .=1000
- mov #2, r0
- mov #3, r1
- add r0, r1
- halt
- """
- with open("test.asm", "w") as f:
- f.write(test_code)
- assembler.assemble("test.asm", "output.txt")
- print("Ассемблирование завершено. Результат в output.txt")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement