def _parseCodeLine(self, line: list=None): """ This will parse an extracted line of code and build an instruction from that code line Parsing a line of code requires many steps. 1- Find the possible codes for the mnemonic from OperationDescription 2- Based on the possible codes and parts of the lines, find the correct form 3- Based on the form, build the instruction 4- Return the instruction If the instruction returned has a string as instruction mnemonic, this means that the instruction simply represent a label in the code. It will be removed from the final program. :param line: :return: """ lineInstruction = None buildInstruction = Instruction(skipValidation=True) # This is used as model in early instruction building finalCode = 0x00 form = None possibleCodes = None self._evaluateAndExtractInfoFromLine(line, buildInstruction) if type(buildInstruction.instructionCode) is not str: # Instruction is real not just memory address or comment possibleCodes = self._findPossibleCodesForInstruction(buildInstruction) instructionCode, instructionForm = self._getInstructionCodeAndFormUsingPossibleCodes(buildInstruction, possibleCodes) if instructionForm is None or instructionCode is None: raise ValueError("Assembler general error") else: buildInstruction.instructionCode = instructionCode buildInstruction.instructionLength = formDescription[instructionForm]["length"] lineInstruction = self._generateBinaryInstructionFromInstruction(buildInstruction, formDescription[instructionForm]) else: if COMMENT_INDICATORS in buildInstruction.instructionCode: # Simply ignore a comment line buildInstruction = None lineInstruction = None elif DATA_ALPHA_INDICATOR in buildInstruction.instructionCode: # This is a bunch of alpha data lineInstruction = buildInstruction.sourceImmediate buildInstruction.instructionCode = 0 # Calling code expect this to be non STR for non mem ref elif DATA_NUMERIC_INDICATOR in buildInstruction.instructionCode: # This is a numeric data field lineInstruction = struct.pack(">I", buildInstruction.sourceImmediate) buildInstruction.instructionCode = 0 # Calling code expect this to be non STR for non mem ref elif DATA_MEMORY_REFERENCE in buildInstruction.instructionCode: lineInstruction = buildInstruction.sourceImmediate buildInstruction.instructionCode = 0 else: lineInstruction = None return buildInstruction, lineInstruction
def _parseCodeLine(self, line: list=None, rawLine: str=None): """ This will parse an extracted line of code and build an instruction from that code line Parsing a line of code requires many steps. 1- Find the possible codes for the mnemonic from OperationDescription 2- Based on the possible codes and parts of the lines, find the correct form 3- Based on the form, build the instruction 4- Return the instruction If the instruction returned has a string as instruction mnemonic, this means that the instruction simply represent a label in the code. It will be removed from the final program. :param line: line split into individual arguments :param rawLine: raw line as we originally read it from the file, used to preserve spaces in .dataAlpha fields :return: The instruction object with all info about arguments, and the line's binary instruction """ lineInstruction = None buildInstruction = Instruction(skipValidation=True) # This is used as a model in early instruction building finalCode = 0x00 form = None possibleCodes = None # We evaluate the line and extract any bits of relevant info to build the appropriate instruction self._evaluateAndExtractInfoFromLine(line, buildInstruction, rawLine) if type(buildInstruction.instructionCode) is not str: # We assume it's an instruction (integer), since memory references or comments would be strings # Parser will verify all possible codes, and generate the appropriate instruction based on its form possibleCodes = self._findPossibleCodesForInstruction(buildInstruction) instructionCode, instructionForm = self._getInstructionCodeAndFormUsingPossibleCodes(buildInstruction, possibleCodes) if instructionForm is None or instructionCode is None: raise ValueError("Assembler general error") else: # Code is valid, fetch the instruction's form based on the arguments, then generate the instruction buildInstruction.instructionCode = instructionCode buildInstruction.instructionLength = formDescription[instructionForm]["length"] lineInstruction = self._generateBinaryInstructionFromInstruction(buildInstruction, formDescription[instructionForm]) else: # In this case, there were no instructions. Thus, we look at other possibilities if COMMENT_INDICATORS in buildInstruction.instructionCode: # Simply ignore a comment line buildInstruction = None lineInstruction = None # In these next cases, we can treat them as "data" variables with no real instructions. # We store the data as the instruction's source immediate value, and set instruction code to 0 elif DATA_ALPHA_INDICATOR in buildInstruction.instructionCode: # This is a bunch of alpha data (String) lineInstruction = buildInstruction.sourceImmediate buildInstruction.instructionCode = 0 elif DATA_NUMERIC_INDICATOR in buildInstruction.instructionCode: # This is a numeric data field (Integer) lineInstruction = struct.pack(">I", buildInstruction.sourceImmediate) buildInstruction.instructionCode = 0 elif DATA_MEMORY_REFERENCE in buildInstruction.instructionCode: # This is a data memory reference (dataMemref) lineInstruction = buildInstruction.sourceImmediate buildInstruction.instructionCode = 0 else: # Having exhausted all options, we assume there was nothing else on this line. lineInstruction = None return buildInstruction, lineInstruction