assembler.py
def secondPass(self):
        """
        Second pass, finds labels, converts numbers, turns links into numbers,
        marks empty links, cleans code further
        """
        pass_tainted = False
        currentProgress = 0
        delList = []
        nums = {'0x':16,'0o':8,'0b':2}
        # Find labels, constant assignments, use temporary values if unavailable
        for lineNumber in self.assembly.keys():
            markLine = False
            # Find hex/octal/binary numbers and convert them to decimal
            # A non-math-hostile version that allows everything to be converted
            # without spaces inbetweem every number
            numberSet = set(re.findall(
                '(?<![\w_])(0x[0-9a-f]+|0o[0-7]+|0b[0-1]+)(?![\w_])',
                self.assembly[lineNumber]))
            for number in numberSet:
                self.assembly[lineNumber] = re.sub('(?<![\w_])%s(?![\w_])' % number,
                    str(int(number[2:],nums[number[:2]])),
                    self.assembly[lineNumber])
            
            line = self.cleanLine(self.assembly[lineNumber])
            
            # Save position before any changes
            self.linePos[lineNumber] = currentProgress
            
            # Label assignment
            if line[0][-1] == ":":
                labelName = line[0][:-1]
                if self.labels.get(labelName,None) != None:
                    delList.append(lineNumber)
                    print(ERRORS[6].format(lineNumber,labelName))
                elif pass_tainted:
                    markLine = True
                else:
                    self.labels[labelName] = currentProgress
                    delList.append(lineNumber)
            
            # Constant assignment
            elif line[0] == '.const':
                if self.constants.get(line[1],None) != None:
                    delList.append(lineNumber)
                    print(ERRORS[7].format(lineNumber,line[1]))
                elif re.search('[\-]*\d+',line[2]):
                    self.constants[line[1]] = numexpr.evaluate(line[2]).item()
                    delList.append(lineNumber)
                else:
                    markLine = True
            
            # Replace constants, absolute labels, and mark empty links
            linkList = set(re.findall('[!]*<link_[a-z]{1}[\w_]*/>',self.assembly[lineNumber]))
            for linkName in linkList:
                absoluteLabel = linkName.startswith('!')
                if linkName in self.constants:
                    self.assembly[lineNumber] = re.sub(
                        '(?<![\w_])%s(?![\w_])' % linkName, str(self.constants[linkName]),
                        self.assembly[lineNumber])
                elif linkName[absoluteLabel:] in self.labels:
                    # Absolute labels, always assignable
                    if absoluteLabel:
                        self.assembly[lineNumber] = re.sub(
                            '(?<![\w_])%s(?![\w_])' % linkName,
                            str(self.labels[linkName[1:]]),
                            self.assembly[lineNumber])
                else:
                    markLine = True
            
            
            # Align and pad by a power of two using a provided byte
            if line[0] == ".align":
                if line[1].isdigit():
                    alignPower = 2**int(line[1])
                    padAmount = (currentProgress % alignPower)
                    padAmount = -(padAmount-alignPower) if padAmount else 0
                    currentProgress += padAmount
                else:
                    print(ERRORS[3].format(lineNumber))
            
            # Inline bytes
            elif line[0] == '.byte':
                currentProgress += 1

            # Inline halfwords
            elif line[0] == '.half':
                currentProgress += 2

            # Inline words
            elif line[0] == '.word':
                currentProgress += 4
            
            newLine = [line[0]]
            
            # Find links and replace them with zero
            for operand in line[1:]:
                if re.search('[<>/~%^&*()-+]',operand):
                    newLine.append(str(numexpr.evaluate(re.sub('[!]*<link_[a-z]{1}[\w_]*/>','0',operand)).item()))
                else:
                    newLine.append(operand)
                            
            
            # Categorize operands for easy identification
            categorizedLine = self.categorizeOperands(newLine)
            
            # Find untainted Links and replace them
            linkList = set(re.findall('[!]*<link_[a-z]{1}[\w_]*/>',self.assembly[lineNumber]))
            for linkName in linkList:
                absoluteLabel = linkName.startswith('!')
                if linkName[absoluteLabel:] in self.labels:
                    # Can't assign relative labels if pass tainted
                    if pass_tainted:
                        markLine = True
                    # N/PC-relative labels
                    else:
                        # Check whether it's an instruction we're making a
                        # relative label for and if architecture uses NPC
                        instruction = self.instructions.get(
                            categorizedLine, None)
                        instLength = 0
                        # It is an instruction and NPC, calculate length
                        if instruction and self.jump_npc:
                            instLength = self.formats[instruction[0]][0]//8
                        self.assembly[lineNumber] = re.sub(
                            '(?<![\w_])%s(?![\w_])' % linkName,
                            str(self.labels[linkName]
                            -(currentProgress+instLength)),
                            self.assembly[lineNumber])
            
            line = self.cleanLine(self.assembly[lineNumber])
            
            # Find unmarked operands and attempt to evaluate them
            if not markLine and lineNumber not in delList:
                for operand in line[1:]:
                    if re.search('[<>/~%^&*()-+]',operand):
                        self.assembly[lineNumber] = re.sub(
                            '(?<![\w<>?/~!%%^&*()\-+])%s(?![\w<>?/~!%%^&*()\-+])' % re.escape(operand),
                            str(numexpr.evaluate(operand).item()),self.assembly[lineNumber])
            
            # Instruction alignment, in case the current instruction is misaligned
            if categorizedLine in self.instructions.keys():
                if self.instAlign:
                    alignPower = 2**int(self.instAlign)
                    padAmount = (currentProgress % alignPower)
                    padAmount = -(padAmount-alignPower) if padAmount else 0
                    currentProgress += padAmount
                currentFormat = self.instructions[categorizedLine][0]
                currentProgress += [self.formats[currentFormat],
                    self.post_shift.get(currentFormat)][
                        currentFormat in self.post_shift][0]//8
            
            # Store line for third+ pass(es)
            if markLine:
                pass_tainted = True
                self.markedLines[lineNumber] = self.assembly[lineNumber]
        
        for lineNumber in delList:
            del self.assembly[lineNumber]

        Second pass, finds labels, converts numbers, turns links into numbers,
        marks empty links, cleans code further
        
Second pass, finds labels, converts numbers, turns links into numbers,
marks empty links, cleans code further
Second pass finds labels converts numbers turns links into numbers marks empty links cleans code further
def secondPass(self):
        pass_tainted = False
        currentProgress = 0
        delList = []
        nums = {'0x':16,'0o':8,'0b':2}
        for lineNumber in self.assembly.keys():
            markLine = False
            numberSet = set(re.findall(
                '(?<![\w_])(0x[0-9a-f]+|0o[0-7]+|0b[0-1]+)(?![\w_])',
                self.assembly[lineNumber]))
            for number in numberSet:
                self.assembly[lineNumber] = re.sub('(?<![\w_])%s(?![\w_])' % number,
                    str(int(number[2:],nums[number[:2]])),
                    self.assembly[lineNumber])
            line = self.cleanLine(self.assembly[lineNumber])
            self.linePos[lineNumber] = currentProgress
            if line[0][-1] == ":":
                labelName = line[0][:-1]
                if self.labels.get(labelName,None) != None:
                    delList.append(lineNumber)
                    print(ERRORS[6].format(lineNumber,labelName))
                elif pass_tainted:
                    markLine = True
                else:
                    self.labels[labelName] = currentProgress
                    delList.append(lineNumber)
            elif line[0] == '.const':
                if self.constants.get(line[1],None) != None:
                    delList.append(lineNumber)
                    print(ERRORS[7].format(lineNumber,line[1]))
                elif re.search('[\-]*\d+',line[2]):
                    self.constants[line[1]] = numexpr.evaluate(line[2]).item()
                    delList.append(lineNumber)
                else:
                    markLine = True
            linkList = set(re.findall('[!]*<link_[a-z]{1}[\w_]*/>',self.assembly[lineNumber]))
            for linkName in linkList:
                absoluteLabel = linkName.startswith('!')
                if linkName in self.constants:
                    self.assembly[lineNumber] = re.sub(
                        '(?<![\w_])%s(?![\w_])' % linkName, str(self.constants[linkName]),
                        self.assembly[lineNumber])
                elif linkName[absoluteLabel:] in self.labels:
                    if absoluteLabel:
                        self.assembly[lineNumber] = re.sub(
                            '(?<![\w_])%s(?![\w_])' % linkName,
                            str(self.labels[linkName[1:]]),
                            self.assembly[lineNumber])
                else:
                    markLine = True
            if line[0] == ".align":
                if line[1].isdigit():
                    alignPower = 2**int(line[1])
                    padAmount = (currentProgress % alignPower)
                    padAmount = -(padAmount-alignPower) if padAmount else 0
                    currentProgress += padAmount
                else:
                    print(ERRORS[3].format(lineNumber))
            elif line[0] == '.byte':
                currentProgress += 1
            elif line[0] == '.half':
                currentProgress += 2
            elif line[0] == '.word':
                currentProgress += 4
            newLine = [line[0]]
            for operand in line[1:]:
                if re.search('[<>/~%^&*()-+]',operand):
                    newLine.append(str(numexpr.evaluate(re.sub('[!]*<link_[a-z]{1}[\w_]*/>','0',operand)).item()))
                else:
                    newLine.append(operand)
            categorizedLine = self.categorizeOperands(newLine)
            linkList = set(re.findall('[!]*<link_[a-z]{1}[\w_]*/>',self.assembly[lineNumber]))
            for linkName in linkList:
                absoluteLabel = linkName.startswith('!')
                if linkName[absoluteLabel:] in self.labels:
                    if pass_tainted:
                        markLine = True
                    else:
                        instruction = self.instructions.get(
                            categorizedLine, None)
                        instLength = 0
                        if instruction and self.jump_npc:
                            instLength = self.formats[instruction[0]][0]//8
                        self.assembly[lineNumber] = re.sub(
                            '(?<![\w_])%s(?![\w_])' % linkName,
                            str(self.labels[linkName]
                            -(currentProgress+instLength)),
                            self.assembly[lineNumber])
            line = self.cleanLine(self.assembly[lineNumber])
            if not markLine and lineNumber not in delList:
                for operand in line[1:]:
                    if re.search('[<>/~%^&*()-+]',operand):
                        self.assembly[lineNumber] = re.sub(
                            '(?<![\w<>?/~!%%^&*()\-+])%s(?![\w<>?/~!%%^&*()\-+])' % re.escape(operand),
                            str(numexpr.evaluate(operand).item()),self.assembly[lineNumber])
            if categorizedLine in self.instructions.keys():
                if self.instAlign:
                    alignPower = 2**int(self.instAlign)
                    padAmount = (currentProgress % alignPower)
                    padAmount = -(padAmount-alignPower) if padAmount else 0
                    currentProgress += padAmount
                currentFormat = self.instructions[categorizedLine][0]
                currentProgress += [self.formats[currentFormat],
                    self.post_shift.get(currentFormat)][
                        currentFormat in self.post_shift][0]//8
            if markLine:
                pass_tainted = True
                self.markedLines[lineNumber] = self.assembly[lineNumber]
        for lineNumber in delList:
            del self.assembly[lineNumber]
def secondPass ( self ) : pass_tainted = False currentProgress = 0 delList = [ ] nums = { '0x' : 16 , '0o' : 8 , '0b' : 2 } for lineNumber in self . assembly . keys ( ) : markLine = False numberSet = set ( re . findall ( '(?<![\w_])(0x[0-9a-f]+|0o[0-7]+|0b[0-1]+)(?![\w_])' , self . assembly [ lineNumber ] ) ) for number in numberSet : self . assembly [ lineNumber ] = re . sub ( '(?<![\w_])%s(?![\w_])' % number , str ( int ( number [ 2 : ] , nums [ number [ : 2 ] ] ) ) , self . assembly [ lineNumber ] ) line = self . cleanLine ( self . assembly [ lineNumber ] ) self . linePos [ lineNumber ] = currentProgress if line [ 0 ] [ - 1 ] == ":" : labelName = line [ 0 ] [ : - 1 ] if self . labels . get ( labelName , None ) != None : delList . append ( lineNumber ) print ( ERRORS [ 6 ] . format ( lineNumber , labelName ) ) elif pass_tainted : markLine = True else : self . labels [ labelName ] = currentProgress delList . append ( lineNumber ) elif line [ 0 ] == '.const' : if self . constants . get ( line [ 1 ] , None ) != None : delList . append ( lineNumber ) print ( ERRORS [ 7 ] . format ( lineNumber , line [ 1 ] ) ) elif re . search ( '[\-]*\d+' , line [ 2 ] ) : self . constants [ line [ 1 ] ] = numexpr . evaluate ( line [ 2 ] ) . item ( ) delList . append ( lineNumber ) else : markLine = True linkList = set ( re . findall ( '[!]*<link_[a-z]{1}[\w_]*/>' , self . assembly [ lineNumber ] ) ) for linkName in linkList : absoluteLabel = linkName . startswith ( '!' ) if linkName in self . constants : self . assembly [ lineNumber ] = re . sub ( '(?<![\w_])%s(?![\w_])' % linkName , str ( self . constants [ linkName ] ) , self . assembly [ lineNumber ] ) elif linkName [ absoluteLabel : ] in self . labels : if absoluteLabel : self . assembly [ lineNumber ] = re . sub ( '(?<![\w_])%s(?![\w_])' % linkName , str ( self . labels [ linkName [ 1 : ] ] ) , self . assembly [ lineNumber ] ) else : markLine = True if line [ 0 ] == ".align" : if line [ 1 ] . isdigit ( ) : alignPower = 2 ** int ( line [ 1 ] ) padAmount = ( currentProgress % alignPower ) padAmount = - ( padAmount - alignPower ) if padAmount else 0 currentProgress += padAmount else : print ( ERRORS [ 3 ] . format ( lineNumber ) ) elif line [ 0 ] == '.byte' : currentProgress += 1 elif line [ 0 ] == '.half' : currentProgress += 2 elif line [ 0 ] == '.word' : currentProgress += 4 newLine = [ line [ 0 ] ] for operand in line [ 1 : ] : if re . search ( '[<>/~%^&*()-+]' , operand ) : newLine . append ( str ( numexpr . evaluate ( re . sub ( '[!]*<link_[a-z]{1}[\w_]*/>' , '0' , operand ) ) . item ( ) ) ) else : newLine . append ( operand ) categorizedLine = self . categorizeOperands ( newLine ) linkList = set ( re . findall ( '[!]*<link_[a-z]{1}[\w_]*/>' , self . assembly [ lineNumber ] ) ) for linkName in linkList : absoluteLabel = linkName . startswith ( '!' ) if linkName [ absoluteLabel : ] in self . labels : if pass_tainted : markLine = True else : instruction = self . instructions . get ( categorizedLine , None ) instLength = 0 if instruction and self . jump_npc : instLength = self . formats [ instruction [ 0 ] ] [ 0 ] // 8 self . assembly [ lineNumber ] = re . sub ( '(?<![\w_])%s(?![\w_])' % linkName , str ( self . labels [ linkName ] - ( currentProgress + instLength ) ) , self . assembly [ lineNumber ] ) line = self . cleanLine ( self . assembly [ lineNumber ] ) if not markLine and lineNumber not in delList : for operand in line [ 1 : ] : if re . search ( '[<>/~%^&*()-+]' , operand ) : self . assembly [ lineNumber ] = re . sub ( '(?<![\w<>?/~!%%^&*()\-+])%s(?![\w<>?/~!%%^&*()\-+])' % re . escape ( operand ) , str ( numexpr . evaluate ( operand ) . item ( ) ) , self . assembly [ lineNumber ] ) if categorizedLine in self . instructions . keys ( ) : if self . instAlign : alignPower = 2 ** int ( self . instAlign ) padAmount = ( currentProgress % alignPower ) padAmount = - ( padAmount - alignPower ) if padAmount else 0 currentProgress += padAmount currentFormat = self . instructions [ categorizedLine ] [ 0 ] currentProgress += [ self . formats [ currentFormat ] , self . post_shift . get ( currentFormat ) ] [ currentFormat in self . post_shift ] [ 0 ] // 8 if markLine : pass_tainted = True self . markedLines [ lineNumber ] = self . assembly [ lineNumber ] for lineNumber in delList : del self . assembly [ lineNumber ]
Second pass, finds labels, converts numbers, turns links into numbers,
marks empty links, cleans code further
Second pass finds labels converts numbers turns links into numbers marks empty links cleans code further
"""
        Second pass, finds labels, converts numbers, turns links into numbers,
        marks empty links, cleans code further
        """ # Find labels, constant assignments, use temporary values if unavailable # Find hex/octal/binary numbers and convert them to decimal # A non-math-hostile version that allows everything to be converted # without spaces inbetweem every number # Save position before any changes # Label assignment # Constant assignment # Replace constants, absolute labels, and mark empty links # Absolute labels, always assignable # Align and pad by a power of two using a provided byte # Inline bytes # Inline halfwords # Inline words # Find links and replace them with zero # Categorize operands for easy identification # Find untainted Links and replace them # Can't assign relative labels if pass tainted # N/PC-relative labels # Check whether it's an instruction we're making a # relative label for and if architecture uses NPC # It is an instruction and NPC, calculate length # Find unmarked operands and attempt to evaluate them # Instruction alignment, in case the current instruction is misaligned # Store line for third+ pass(es)
self