Execute Computer/Zero: Difference between revisions

Python improve assembly parser
(Add Python)
(Python improve assembly parser)
Line 647:
=={{header|Python}}==
<lang python>"""Computer/zero Assembly emulator. Requires Python >= 3.7"""
 
import re
 
from typing import Dict
from typing import Iterable
Line 653 ⟶ 656:
from typing import Optional
from typing import Tuple
from typing import Union
 
 
Line 676 ⟶ 678:
}
 
RE_INSTRUCTION = re.compile(
r"\s*"
r"(?:(?P<label>\w+):)?"
r"\s*"
rf"(?P<opcode>{'|'.join(OPCODES)})?"
r"\s*"
r"(?P<argument = None>\w+)?"
r"\s*"
r"(?:;(?P<comment>[\w\s]+))?"
)
 
class Instruction(NamedTuple):
opcode: Optional[str]
argument: Union[str, int, None]
 
class AssemblySyntaxError(Exception):
pass
 
Bytecode = Iterable[int]
Instructions = List[Instruction]
Labels = Dict[str, int]
 
class Instruction(NamedTuple):
label: Optional[str]
opcode: Optional[str]
argument: UnionOptional[str, int, None]
comment: Optional[str]
 
 
def parse(assembly: str) -> Tuple[InstructionsList[Instruction], LabelsDict[str, int]]:
instructions: InstructionsList[Instruction] = []
labels: Dict[str, int] = {}
linenum: int = 0
lines = [line.strip() for line in assembly.split("\n")]
 
for line in linesassembly.split("\n"):
#match Discard= commentsRE_INSTRUCTION.match(line)
 
if ";" in line:
if not line = line.split(";", 1)[0]match:
raise ExceptionAssemblySyntaxError(f"unknown instruction '{line}',: {linenum}")
 
instructions.append(Instruction(opcode, argument**match.groupdict()))
# Parse label
iflabel ":"= in line:match.group(1)
if label, line = line.split(":", 1)
labels[label] = linenum
 
# Parse opcode and argument
instruction = line.strip().split()
if len(instruction) == 1:
if instruction[0] in OPCODES:
# Opcode without argument
opcode: Optional[str] = instruction[0]
argument: Union[str, int, None] = None
elif instruction[0].isnumeric():
# Data, without opcode
opcode = None
argument = int(instruction[0])
else:
# Unexpected
raise Exception(f"unknown instruction '{line}', {linenum}")
elif len(instruction) == 2:
# Opcode and argument
opcode, argument = instruction
 
if opcode not in OPCODES:
raise Exception(f"unknown instruction '{line}', {linenum}")
 
if argument.isnumeric():
argument = int(argument)
else:
# Argument is a label
argument = argument
elif not instruction:
# blank line
opcode = "NOP"
argument = None
else:
raise Exception(f"unknown instruction '{line}', {linenum}")
 
instructions.append(Instruction(opcode, argument))
linenum += 1
 
Line 742 ⟶ 722:
 
 
def compile(instructions: InstructionsList[Instruction], labels: LabelsDict[str, int]) -> BytecodeIterable[int]:
for instruction in instructions:
if isinstance(instruction.argument, str)is None:
argument = labels[instruction.argument]
elif isinstance(instruction.argument, int):
argument = instruction.argument
else:
argument = 0
elif instruction = line.strip()argument.splitisnumeric():
ifargument = int(instruction[0] in OPCODES:.argument)
else:
argument = # Opcode without labels[instruction.argument]
 
if instruction.opcode:
Line 785 ⟶ 765:
break
else:
raise Exception(f"error:( {operation} {argument}" + str(operation))
 
return accumulator
Line 928 ⟶ 908:
def main() -> None:
for sample in SAMPLES:
instructions, labels = parse(sample.strip())
bytecode = bytes(compile(instructions, labels))
#result print= run(bytecode)
print(run(bytecode)result)
 
 
140

edits