I'm trying to write simple parser using regexes. This is what I currently have, it looks really messy. Any tips what can I change?
from re import compile
from typing import Dict, Iterator, List, NamedTuple, TextIO
# PATTERNS
registers_pattern = list(map(compile, [
r'(rax=[0-9a-f]{16}) (rbx=[0-9a-f]{16}) (rcx=[0-9a-f]{16})\n',
r'(rdx=[0-9a-f]{16}) (rsi=[0-9a-f]{16}) (rdi=[0-9a-f]{16})\n',
r'(rip=[0-9a-f]{16}) (rsp=[0-9a-f]{16}) (rbp=[0-9a-f]{16})\n',
r' (r8=[0-9a-f]{16}) (r9=[0-9a-f]{16}) (r10=[0-9a-f]{16})\n',
r'(r11=[0-9a-f]{16}) (r12=[0-9a-f]{16}) (r13=[0-9a-f]{16})\n',
r'(r14=[0-9a-f]{16}) (r15=[0-9a-f]{16})\n',
]))
flags_pattern = compile(r'iopl=[0-9a-f]+(?:\s+[a-z]{2}){8}\n')
segments_pattern = compile(r'(?:[a-z]{2}=[0-9a-f]{4}\s+){6}efl=[0-9a-f]{8}\n')
label_pattern = compile(r'[\w\+]+:\n')
instruction_pattern = compile(
r'[0-9a-f]{8}`[0-9a-f]{8}\s+(?P<ENCODING>[0-9a-f]+)\s+(?P<INSTRUCTION>.+?)\n?'
)
class Instruction(NamedTuple):
instruction: str
encoding: str
registers: Dict[str, str]
def parse_trace(stream: TextIO) -> Iterator[Instruction]:
""" TODO: some description
"""
iterator = iter(enumerate(stream, start=1))
for index, line in iterator:
# Parse general-purpose registers
registers: Dict[str, str] = {}
for pattern in registers_pattern:
if match := pattern.fullmatch(line):
# Extract register values from regex match and go to the next line
registers.update(group.split('=') for group in match.groups())
index, line = next(iterator)
else:
raise RuntimeError(f'Failed to parse line: {index}')
if flags_pattern.fullmatch(line) is None:
raise RuntimeError(f'Failed to parse line: {index}')
if segments_pattern.fullmatch(next(iterator)[1]) is None:
# TODO: here will be something
raise RuntimeError(f'Failed to parse line: {index}')
if label_pattern.fullmatch(next(iterator)[1]) is None:
raise RuntimeError(f'Failed to parse line: {index}')
if (match := instruction_pattern.fullmatch(next(iterator)[1])) is None:
raise RuntimeError(f'Failed to parse line: {index}')
yield Instruction(match.group('INSTRUCTION'), match.group('ENCODING'), registers)
# Example of usage:
from io import StringIO
trace = StringIO("""rax=0000000000000000 rbx=0000000000000000 rcx=0000000000000000
rdx=0000000000000000 rsi=0000000000000000 rdi=0000000000000000
rip=000000000040100a rsp=0000000000000000 rbp=0000000000000000
r8=0000000000000000 r9=0000000000000000 r10=0000000000000000
r11=0000000000000000 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0 nv up ei pl zr na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
lol+0x1000:
00000000`00401000 48bba47868302035e80c mov rbx,0CE83520306878A4h
rax=0000000000000000 rbx=0000000000000000 rcx=0000000000000000
rdx=0000000000000000 rsi=0000000000000000 rdi=0000000000000000
rip=000000000040100a rsp=0000000000000000 rbp=0000000000000000
r8=0000000000000000 r9=0000000000000000 r10=0000000000000000
r11=0000000000000000 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0 nv up ei pl zr na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
lol+0x1000:
00000000`00401000 48bba47868302035e80c mov rbx,0CE83520306878A4h""")
for each in parse_trace(trace):
print(each.instruction)
```
Instruction
objects as cleanly as possible? Will the input coming from a file, or must it accept anyTextIO
object? Because if it is being read from a file, and this instruction parser can open the file, it could usefileinput.filelineno
to keep track of line numbers. \$\endgroup\$