Advertisement
Korotkodul

my_code_2

Apr 3rd, 2025
353
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.78 KB | None | 0 0
  1. import pyparsing as pp
  2. import re
  3. import struct
  4. from typing import List, Dict, Union
  5.  
  6.  
  7. class PDP11Assembler:
  8.     def __init__(self):
  9.         # Инициализация парсера pyparsing (как в вашем коде)
  10.         self.command_name = pp.Word(pp.alphas)
  11.         self.argument_name = pp.Word(pp.printables, exclude_chars=';,')
  12.         self.arguments = pp.Optional(self.argument_name) + pp.ZeroOrMore(pp.Suppress(',') + self.argument_name)
  13.         self.label = pp.Word(pp.alphas) + pp.Optional(pp.Suppress(' ')) + pp.Suppress(":")
  14.         self.comment = pp.Suppress(';') + pp.Optional(pp.Suppress(' ')) + pp.restOfLine()
  15.         self.rule = pp.Optional(self.label) + pp.Optional(self.command_name) + pp.Optional(
  16.             self.arguments) + pp.Optional(self.comment)
  17.  
  18.         # Таблица команд (расширенная версия)
  19.         self.command_table = {
  20.             'halt': {'opcode': 0o000000, 'args': [], 'handler': self._handle_no_args},
  21.             'mov': {'opcode': 0o010000, 'args': ['ss', 'dd'], 'handler': self._handle_ss_dd},
  22.             'add': {'opcode': 0o060000, 'args': ['ss', 'dd'], 'handler': self._handle_ss_dd},
  23.             'sub': {'opcode': 0o160000, 'args': ['ss', 'dd'], 'handler': self._handle_ss_dd},
  24.             'cmp': {'opcode': 0o020000, 'args': ['ss', 'dd'], 'handler': self._handle_ss_dd},
  25.             'br': {'opcode': 0o000400, 'args': ['xx'], 'handler': self._handle_branch},
  26.             'bne': {'opcode': 0o001000, 'args': ['xx'], 'handler': self._handle_branch},
  27.         }
  28.  
  29.         self.labels = {}
  30.         self.current_address = 0o1000
  31.         self.output_blocks = []
  32.  
  33.     def parse_line(self, line: str) -> List[str]:
  34.         """Аналог вашей функции parse с улучшениями"""
  35.         line = line.strip()
  36.         if not line:
  37.             return []
  38.  
  39.         if line.startswith('.'):
  40.             if line.startswith('.='):
  41.                 return ['origin', line[2:].strip()]
  42.             return []
  43.  
  44.         try:
  45.             return self.rule.parseString(line).asList()
  46.         except pp.ParseException:
  47.             return []
  48.  
  49.     def _handle_no_args(self, cmd: Dict, args: List[str], words: List[Union[int, str]]):
  50.         """Обработка команд без аргументов"""
  51.         words.append(cmd['opcode'])
  52.  
  53.     def _handle_branch(self, cmd: Dict, args: List[str], words: List[Union[int, str]]):
  54.         """Обработка команд ветвления"""
  55.         words.append(cmd['opcode'])
  56.         words.append(args[0])  # Сохраняем метку для разрешения позже
  57.  
  58.     def _handle_ss_dd(self, cmd: Dict, args: List[str], words: List[Union[int, str]]):
  59.         """Обработка двухоперандных команд"""
  60.         src = self._parse_operand(args[0])
  61.         dst = self._parse_operand(args[1])
  62.  
  63.         instruction = cmd['opcode'] | (src['mode'] << 6) | (src['reg'] << 3) | dst['mode'] | dst['reg']
  64.         words.append(instruction)
  65.  
  66.         if src['mode'] == 0o27:  # Немедленная адресация
  67.             words.append(src['value'])
  68.  
  69.     def _parse_operand(self, op: str) -> Dict[str, Union[int, str]]:
  70.         """Улучшенный парсер операндов"""
  71.         if not op:
  72.             return {'mode': 0, 'reg': 0, 'value': 0}
  73.  
  74.         # Регистровая адресация (R0-R7)
  75.         if re.match(r'^[rR][0-7]$', op):
  76.             return {'mode': 0, 'reg': int(op[1]), 'value': 0}
  77.  
  78.         # Немедленная адресация (#n)
  79.         if op.startswith('#'):
  80.             return {'mode': 0o27, 'reg': 0, 'value': int(op[1:])}
  81.  
  82.         return {'mode': 0, 'reg': 0, 'value': 0}
  83.  
  84.     def cmd_to_raw_machine_code(self, parsed: List[str]) -> List[Union[int, str]]:
  85.         """Аналог вашей функции, но с улучшенной структурой"""
  86.         if not parsed:
  87.             return []
  88.  
  89.         if isinstance(parsed[0], list) and len(parsed[0]) == 2 and parsed[0][1] == ':':
  90.             # Обработка метки
  91.             label = parsed[0][0]
  92.             self.labels[label] = self.current_address
  93.             parsed = parsed[1:]
  94.  
  95.         if not parsed:
  96.             return []
  97.  
  98.         if parsed[0] == 'origin':
  99.             self.current_address = int(parsed[1], 8)
  100.             return []
  101.  
  102.         cmd_name = parsed[0].lower()
  103.         if cmd_name not in self.command_table:
  104.             return []
  105.  
  106.         cmd = self.command_table[cmd_name]
  107.         args = parsed[1:]
  108.  
  109.         if len(args) != len(cmd['args']):
  110.             return []
  111.  
  112.         words = []
  113.         cmd['handler'](cmd, args, words)
  114.         return words
  115.  
  116.     def first_pass(self, lines: List[str]):
  117.         """Первый проход: сбор меток"""
  118.         self.current_address = 0o1000
  119.  
  120.         for line in lines:
  121.             parsed = self.parse_line(line)
  122.             if not parsed:
  123.                 continue
  124.  
  125.             if parsed[0] == 'origin':
  126.                 self.current_address = int(parsed[1], 8)
  127.                 continue
  128.  
  129.             if isinstance(parsed[0], list) and len(parsed[0]) == 2 and parsed[0][1] == ':':
  130.                 label = parsed[0][0]
  131.                 self.labels[label] = self.current_address
  132.                 parsed = parsed[1:]
  133.  
  134.             if not parsed:
  135.                 continue
  136.  
  137.             cmd_name = parsed[0].lower()
  138.             if cmd_name in self.command_table:
  139.                 cmd = self.command_table[cmd_name]
  140.                 self.current_address += 2  # Основное слово команды
  141.  
  142.                 # Учет дополнительных слов
  143.                 for arg in parsed[1:]:
  144.                     if arg.startswith('#'):
  145.                         self.current_address += 2
  146.  
  147.     def second_pass(self, lines: List[str]):
  148.         """Второй проход: генерация машинного кода"""
  149.         self.current_address = 0o1000
  150.         current_block = {'start': 0o1000, 'data': []}
  151.  
  152.         for line in lines:
  153.             parsed = self.parse_line(line)
  154.             if not parsed:
  155.                 continue
  156.  
  157.             if parsed[0] == 'origin':
  158.                 if current_block['data']:
  159.                     self.output_blocks.append(current_block)
  160.                 addr = int(parsed[1], 8)
  161.                 current_block = {'start': addr, 'data': []}
  162.                 self.current_address = addr
  163.                 continue
  164.  
  165.             if isinstance(parsed[0], list) and len(parsed[0]) == 2 and parsed[0][1] == ':':
  166.                 parsed = parsed[1:]
  167.                 if not parsed:
  168.                     continue
  169.  
  170.             words = self.cmd_to_raw_machine_code(parsed)
  171.             for item in words:
  172.                 if isinstance(item, str):  # Метка для ветвления
  173.                     offset = (self.labels[item] - self.current_address - 2) // 2
  174.                     current_block['data'][-1] |= (offset & 0o377)
  175.                 else:
  176.                     current_block['data'].append(item)
  177.                     self.current_address += 2
  178.  
  179.         if current_block['data']:
  180.             self.output_blocks.append(current_block)
  181.  
  182.     def write_s_record_format(self, filename: str):
  183.         """Запись результата в требуемом формате"""
  184.         if not self.output_blocks:
  185.             return
  186.  
  187.         block = self.output_blocks[0]
  188.         data_bytes = bytearray()
  189.  
  190.         for word in block['data']:
  191.             # Правильный порядок байтов (как в вашем примере)
  192.             data_bytes.append(word & 0xFF)
  193.             data_bytes.append((word >> 8) & 0xFF)
  194.  
  195.         with open(filename, 'w') as f:
  196.             # Первая строка: адрес и размер
  197.             f.write(f"0200 {len(data_bytes):04x}\n")
  198.  
  199.             # Байты машинного кода
  200.             for byte in data_bytes:
  201.                 f.write(f"{byte:02x}\n")
  202.  
  203.     def assemble(self, input_filename: str, output_filename: str):
  204.         """Основной метод ассемблирования"""
  205.         with open(input_filename, 'r') as f:
  206.             lines = f.readlines()
  207.  
  208.         # Два прохода
  209.         self.first_pass(lines)
  210.         self.second_pass(lines)
  211.  
  212.         # Запись результата
  213.         self.write_s_record_format(output_filename)
  214.  
  215.  
  216. # Пример использования
  217. if __name__ == "__main__":
  218.     assembler = PDP11Assembler()
  219.  
  220.     test_code = """
  221.        .=1000
  222.        mov #2, r0
  223.        mov #3, r1
  224.        add r0, r1
  225.        halt
  226.    """
  227.  
  228.     with open("test.asm", "w") as f:
  229.         f.write(test_code)
  230.  
  231.     assembler.assemble("test.asm", "output.txt")
  232.     print("Ассемблирование завершено. Результат в output.txt")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement