Exemple #1
0
    def print_lin(self):
        # New line ages suddenly.
        old_line = self._old_line
        self._old_line = self._line

        # Branch if last line is skip.
        prin_skip = False
        if old_line.spacing & Bit.BIT1:
            prin_skip = True
        else:

            # Add to line count from last line.
            self._lin_count += old_line.spacing
            if self._lin_count > self._yul.n_lines:
                # Skip after last line at end of page.
                old_line.spacing = Bit.BIT1
                prin_skip = True

        if prin_skip:
            if self._yul.n_copies != 0:
                self.copy_prt5()

            self._mon.phi_print(old_line.text, spacing=old_line.spacing)

            self._yul.page_no += 1
            # Put page number alpha in page head.
            self._yul.page_head = self._yul.page_head[:116] + (
                '%4d' % self._yul.page_no)

            if self._yul.n_copies != 0:
                self.copy_prt5()

            self._mon.phi_print(self._yul.page_head, spacing=3)

            # Print subheading.
            if self._yul.n_copies != 0:
                self.copy_prt5()

            self._mon.phi_print(self._page_hed2.text,
                                spacing=self._page_hed2.spacing)

            self._lin_count = 5

        else:
            if self._yul.n_copies != 0:
                self.copy_prt5()

            self._mon.phi_print(old_line.text, spacing=old_line.spacing)

        # Old line discovers fountain of youth. And is moreover made clean again.
        self._line = Line()
Exemple #2
0
    def __init__(self, mon, yul, old_line, m_typ_tab, wd_recs):
        self._mon = mon
        self._yul = yul

        self._line = Line()
        self._old_line = old_line
        self._lin_count = 0
        self._n_oct_errs = 0

        self._m_typ_tab = m_typ_tab
        self._wd_recs = wd_recs

        self._paragraphs = {}

        if self._mon.year <= 1965:
            self._last_line = 'THE ASSEMBLY WAS NAWSTY  BINARY RECORDS FROM IT WERE WRITTEN ON %-8s' % self._yul.tape
            self._good = ' GOOD.  '
            self._fair = ' FAIR.  '
            self._bad = ' BAD. NO'
            self._page_hed2 = Line(' SYMBOL    DEFINITION   HEALTH OF DEFINI' +
                                   'TION                                    ' +
                                   '                   PAGE                 ',
                                   spacing=2)
        else:
            self._last_line = 'THE ASSEMBLY WAS NAWSTY MANUFACTURABLE BINARY RECORDS STORED ON %-8s' % self._yul.tape
            self._good = ' GOOD:  '
            self._fair = ' FAIR:  '
            self._bad = ' BAD: UN'
            self._page_hed2 = Line('SYMBOL TABLE LISTING, INCLUDING PAGE NUM' +
                                   'BER OF DEFINITION, AND NUMBER OF REFEREN' +
                                   'CES WITH FIRST AND LAST PAGE NUMBERS    ',
                                   spacing=2)

        self._rej_rev = '  PRECEDING REVISION REMAINS ON '
        self._rej_vers = 'THE NEW VERSION IS NOT FILED ON '
        self._subl_head = 'SUBROUTINE  REV#  CALLED  BEGINS'
        self._sy_col_hdg = '  SYMBOL H   DEFINITION   REFERENCES F  '
        self._sub_lastl = '              THIS SUBROUTINE IS MAINTAINED IN SYMBOLIC FORM ON '
        self._joyful = [
            '   GOOD ', '   FAIR ', '    BAD ', '  LOUSY ', ' ROTTEN ',
            'BILIOUS '
        ]
        self._alt_words = [
            ' SUPERB ', '  SO-SO ', ' DISMAL ', '  AWFUL ', '   VILE ',
            ' PUTRID '
        ]
        self._usym_cuss = 'UNDEFINED:'

        self._m_type_cax = [
            'SPECIAL OR NONEXISTENT MEMORY', 'RESERVED FIXED MEMORY',
            'AVAILABLE FIXED MEMORY', 'RESERVED ERASABLE MEMORY',
            'AVAILABLE ERASABLE MEMORY'
        ]

        self._sym_liner = ONE_THIRD * 2

        self._owed_sym = None
        self._sym_letter = 'x'

        self._eecr_list = []

        self._symh_vect = [
            SymbolHealth('U ■', True, 'UNDEFINED'),
            SymbolHealth('N ■', True, 'NEARLY DEFINED BY EQUALS'),
            SymbolHealth('NM■', True,
                         'MULTIPLY DEFINED INCLUDING NEARLY BY EQUALS'),
            SymbolHealth('= ■', False, 'DEFINED BY EQUALS'),
            SymbolHealth('=M■', False, 'MULTIPLY DEFINED INCLUDING BY EQUALS'),
            SymbolHealth('E ■', True,
                         'LEFTOVER WHICH FAILED TO FIT IN ERASABLE MEMORY'),
            SymbolHealth('J ■', True,
                         'LEFTOVER WHICH FAILED TO FIT IN FIXED MEMORY'),
            SymbolHealth('  ■', False, 'NORMALLY DEFINED'),
            SymbolHealth('M ■', False, 'GIVEN MULTIPLE DEFINITIONS'),
            SymbolHealth('O ■', True, 'OVERSIZE- OR ILL-DEFINED'),
            SymbolHealth('T ■', False, 'ASSOCIATED WITH WRONG MEMORY TYPE'),
            SymbolHealth(
                'C ■', False,
                'ASSOCIATED WITH CONFLICT IN FIXED OR ERASABLE MEMORY'),
            SymbolHealth('OM■', True,
                         'MULTIPLY DEFINED; OVERSIZE- OR ILL-DEFINED'),
            SymbolHealth(
                'TM■', False,
                'MULTIPLY DEFINED; ASSOCIATED WITH WRONG MEMORY TYPE'),
            SymbolHealth(
                'CM■', False,
                'MUTLIPLY DEIFNED; ASSOCIATED WITH CONFLICT IN FIXED OR ERASABLE MEMORY'
            ),
            SymbolHealth('MM■', True, 'MULTIPLE ERRORS'),
            SymbolHealth('X ■', True, 'IN MISCELLANEOUS TROUBLE'),
            SymbolHealth('■■■', True, 'FAILED TO FIT IN SYMBOL TABLE'),
            SymbolHealth('=? ', False,
                         'DEFINED BY EQUALS BUT NEVER REFERRED TO'),
        ]
Exemple #3
0
class Pass3:
    def __init__(self, mon, yul, old_line, m_typ_tab, wd_recs):
        self._mon = mon
        self._yul = yul

        self._line = Line()
        self._old_line = old_line
        self._lin_count = 0
        self._n_oct_errs = 0

        self._m_typ_tab = m_typ_tab
        self._wd_recs = wd_recs

        self._paragraphs = {}

        if self._mon.year <= 1965:
            self._last_line = 'THE ASSEMBLY WAS NAWSTY  BINARY RECORDS FROM IT WERE WRITTEN ON %-8s' % self._yul.tape
            self._good = ' GOOD.  '
            self._fair = ' FAIR.  '
            self._bad = ' BAD. NO'
            self._page_hed2 = Line(' SYMBOL    DEFINITION   HEALTH OF DEFINI' +
                                   'TION                                    ' +
                                   '                   PAGE                 ',
                                   spacing=2)
        else:
            self._last_line = 'THE ASSEMBLY WAS NAWSTY MANUFACTURABLE BINARY RECORDS STORED ON %-8s' % self._yul.tape
            self._good = ' GOOD:  '
            self._fair = ' FAIR:  '
            self._bad = ' BAD: UN'
            self._page_hed2 = Line('SYMBOL TABLE LISTING, INCLUDING PAGE NUM' +
                                   'BER OF DEFINITION, AND NUMBER OF REFEREN' +
                                   'CES WITH FIRST AND LAST PAGE NUMBERS    ',
                                   spacing=2)

        self._rej_rev = '  PRECEDING REVISION REMAINS ON '
        self._rej_vers = 'THE NEW VERSION IS NOT FILED ON '
        self._subl_head = 'SUBROUTINE  REV#  CALLED  BEGINS'
        self._sy_col_hdg = '  SYMBOL H   DEFINITION   REFERENCES F  '
        self._sub_lastl = '              THIS SUBROUTINE IS MAINTAINED IN SYMBOLIC FORM ON '
        self._joyful = [
            '   GOOD ', '   FAIR ', '    BAD ', '  LOUSY ', ' ROTTEN ',
            'BILIOUS '
        ]
        self._alt_words = [
            ' SUPERB ', '  SO-SO ', ' DISMAL ', '  AWFUL ', '   VILE ',
            ' PUTRID '
        ]
        self._usym_cuss = 'UNDEFINED:'

        self._m_type_cax = [
            'SPECIAL OR NONEXISTENT MEMORY', 'RESERVED FIXED MEMORY',
            'AVAILABLE FIXED MEMORY', 'RESERVED ERASABLE MEMORY',
            'AVAILABLE ERASABLE MEMORY'
        ]

        self._sym_liner = ONE_THIRD * 2

        self._owed_sym = None
        self._sym_letter = 'x'

        self._eecr_list = []

        self._symh_vect = [
            SymbolHealth('U ■', True, 'UNDEFINED'),
            SymbolHealth('N ■', True, 'NEARLY DEFINED BY EQUALS'),
            SymbolHealth('NM■', True,
                         'MULTIPLY DEFINED INCLUDING NEARLY BY EQUALS'),
            SymbolHealth('= ■', False, 'DEFINED BY EQUALS'),
            SymbolHealth('=M■', False, 'MULTIPLY DEFINED INCLUDING BY EQUALS'),
            SymbolHealth('E ■', True,
                         'LEFTOVER WHICH FAILED TO FIT IN ERASABLE MEMORY'),
            SymbolHealth('J ■', True,
                         'LEFTOVER WHICH FAILED TO FIT IN FIXED MEMORY'),
            SymbolHealth('  ■', False, 'NORMALLY DEFINED'),
            SymbolHealth('M ■', False, 'GIVEN MULTIPLE DEFINITIONS'),
            SymbolHealth('O ■', True, 'OVERSIZE- OR ILL-DEFINED'),
            SymbolHealth('T ■', False, 'ASSOCIATED WITH WRONG MEMORY TYPE'),
            SymbolHealth(
                'C ■', False,
                'ASSOCIATED WITH CONFLICT IN FIXED OR ERASABLE MEMORY'),
            SymbolHealth('OM■', True,
                         'MULTIPLY DEFINED; OVERSIZE- OR ILL-DEFINED'),
            SymbolHealth(
                'TM■', False,
                'MULTIPLY DEFINED; ASSOCIATED WITH WRONG MEMORY TYPE'),
            SymbolHealth(
                'CM■', False,
                'MUTLIPLY DEIFNED; ASSOCIATED WITH CONFLICT IN FIXED OR ERASABLE MEMORY'
            ),
            SymbolHealth('MM■', True, 'MULTIPLE ERRORS'),
            SymbolHealth('X ■', True, 'IN MISCELLANEOUS TROUBLE'),
            SymbolHealth('■■■', True, 'FAILED TO FIT IN SYMBOL TABLE'),
            SymbolHealth('=? ', False,
                         'DEFINED BY EQUALS BUT NEVER REFERRED TO'),
        ]

    def p3_masker(self):
        if self._yul.sym_thr.count() > 0:
            self.read_syms(self.print_sym, self.end_pr_sym)
        else:
            # Announce lack of symbols.
            self._line[0] = 'THERE ARE NO SYMBOLS IN THIS ASSEMBLY.'
            self.print_lin()

        self.av_disply()
        self.ws3()
        self.prin_pars()
        self.print_oct()
        self.subr_list()
        self.close_yul()

    # Routine to pick symbols out of the symbol table in alphabetical order.
    def read_syms(self, found_sym, all_done):
        sym_names = self._yul.sym_thr.names()
        sym_names = ['%-8s' % name for name in sym_names]
        sym_names = sorted(sym_names,
                           key=lambda sym: [ALPHABET.index(c) for c in sym])
        for name in sym_names:
            for sym in self._yul.sym_thr.all(name.strip()):
                found_sym(sym)

        all_done()

    def print_sym(self, sym):
        # Branch if symbol table is suppressed.
        if self._yul.switch & SwitchBit.SUPPRESS_SYMBOL:
            if sym.health == 6:
                # Count good symbols during suppression.
                self._symh_vect[7].count += 1
                return
            elif sym.health == 3:
                # Count good symbols during suppression.
                self._symh_vect[3].count += 1
                return
            # If not = either, print it anyway.

        if self._mon.year <= 1965:
            return self.early_print_sym(sym)

        # Branch if a page is under construction.
        if 0o700 <= self._sym_liner:
            if sym.name[0] != self._sym_letter:
                # Owe symbol while printing a divider.
                self._owed_sym = sym
                sym = None
        else:
            # Start new page by copying received sym.
            self._sym_letter = sym.name[0]

            # Point ot begining of page constr. area.
            self._l_bank_5 = []

        return self.pl_thread(sym)

    def pl_thread(self, sym):
        # Plant pointer to symbol table entry.
        self._l_bank_5.append(sym)

        # Count up thirds of lines.
        self._sym_liner += ONE_THIRD
        # Branch if constructed page is not full.
        if self._sym_liner <= FULL_PAGE:
            return self.owe_sym_q()

        return self.sym_page()

    def owe_sym_q(self):
        # Br. if a symbol is owed (new 1st ltr).
        if self._owed_sym is None:
            # Restore address, fetch another symbol.
            return

        # Set it up for first-letter comparison.
        self._sym_letter = self._owed_sym.name[0]
        owed_sym = self._owed_sym

        # Clear flag, go to process owed symbol.
        self._owed_sym = None
        return self.pl_thread(owed_sym)

    def sym_page(self):
        if self._mon.year <= 1965:
            return self.early_sym_page()

        # Form number of lines of symbol info.
        sym_lines = (self._sym_liner >> 9) & 0o77
        # Form key to no. of symbols in last line.
        sym_liner = (self._sym_liner >> 7) & 0o3

        # Column headings for left third.
        self._line[0] = self._sy_col_hdg
        if sym_lines > 1 or sym_liner > 0:
            # Plant vertical divider and column headings for middle third.
            self._line[39] = '■' + self._sy_col_hdg

        if sym_lines > 1 or sym_liner > 1:
            # Plant vertical divider and column headings for right third.
            self._line[79] = '■' + self._sy_col_hdg

        self._line.spacing = 1
        self.print_lin()

        # Line with just dividers after col hdgs.
        self._line[39] = '■' + self._line[40:79] + '■'
        self._line.spacing = 1
        self.print_lin()

        # Point to beginning of second and third columns.
        col_starts = [0, sym_lines, 2 * sym_lines]
        # Branch if last line has over one column.
        if sym_liner == 0:
            col_starts[2] -= 1

        # Initialize comparison regs to blanks.
        compares = ['', '', '']

        for line in range(0, sym_lines):
            # Each third of a line ocntains all the information about one symbol.
            max_col = 3 if line < (sym_lines - 1) else min(sym_liner + 1, 3)
            for col in range(max_col):
                # Point to a symbol in the table
                sym_idx = col_starts[col] + line
                sym = self._l_bank_5[sym_idx]
                cc = col * 40
                nc = (col + 1) * 40

                # Branch if symbol, not horizontal divider.
                if sym is None:
                    # Place horizontal divider of blots.
                    self._line[cc] = ('■' * 36 + '   ' + '■')
                else:
                    # Branch if any of healths 0-4.
                    health = sym.health
                    if (sym.health >= 6) or (
                        (sym.health == 5) and
                            True):  # FIXME: check for failed leftover erase
                        # Increment healths 5.5 (failed j-card) up.
                        health += 1

                    # Increment count of syms in this state.
                    self._symh_vect[health].count += 1

                    # Plant health flag and vertical divider.
                    self._line[cc + 37] = self._symh_vect[health].flag

                    # Branch if symbol has a valid definition.
                    if self._symh_vect[health].no_valid_loc:
                        # Otherwise put it in typing list.
                        self.usy_place(sym)
                        eqivlent = ONES
                    else:
                        eqivlent = sym.value

                    # Set definition or blots in print.
                    self.m_edit_def(eqivlent, col_start=cc)

                    # Branch if different from last symbol in this column; otherwise print a ditto.
                    if sym.name == compares[col]:
                        self._line[cc] = '     "  '
                    else:
                        # Plant new symbol for next comparison.
                        compares[col] = sym.name

                        # Set headed symbol in print.
                        self._line[cc + 2] = '%-8s' % sym.name

                    # Branch unless symbol was simply undef.
                    if sym.health < 3:
                        # Show that there's no page of definition.
                        self._line[cc + 21] = ' - '
                    else:
                        # Convert page of def to zero-supp alpha.
                        self._line[cc + 21] = '%3d' % sym.def_page

                    # Branch if symbol was referred to.
                    refs = len(sym.ref_pages)
                    if refs == 0:
                        # Show lack of references.
                        self._line[cc + 24] = '  -   -   - '
                    else:
                        # Convert number of references to z/s alf.
                        refs_alf = '%3d' % refs

                        # Branch if 999 refs or fewer.
                        if refs > 999:
                            refs_alf = '>1K'

                        self._line[cc + 25] = refs_alf

                        # Convert page of first ref to z/s alpha.
                        self._line[cc + 28] = '%4d' % sym.ref_pages[0]

                        # When both page numbers are the same, print only the first one.
                        if sym.ref_pages[0] != sym.ref_pages[-1]:
                            # Convert page of last ref to z/s alpha.
                            self._line[cc + 32] = '%4d' % sym.ref_pages[-1]

                    # Branch if any definition exists.
                    if eqivlent != ONES:
                        self.eecr_test(sym)

            # Remove vertical divider from last col.
            self._line[max_col * 40 - 1] = ' '

            self._line.spacing = 1
            self.print_lin()

        self._old_line.spacing = 2
        self._line[0] = 'KEY: SYMBOLS DEFINED BY EQUALS ARE FLAGG' + \
                        'ED =.  OTHERS ARE NORMALLY DEFINED EXCEP' + \
                        'T THOSE FLAGGED:                        '
        self._line.spacing = 2
        self.print_lin()

        # Print key to health flags at end page.
        self._line[0] = 'U UNDEFINED             E FAILED LEFTOVE' + \
                        'R ERASE   M MULTIPLY DEFINED           T' + \
                        ' WRONG MEMORY TYPE    MM MULTIPLE ERRORS'
        self._line.spacing = 1
        self.print_lin()

        self._line[0] = 'N NEARLY DEFINED BY =   J FAILED LEFTOVE' + \
                        'R WORD    D OVERSIZE- OR ILL-DEFINED   C' + \
                        ' CONFLICT IN MEMORY   K  MISC. TROUBLE  '
        self._line.spacing = Bit.BIT1
        self.print_lin()

        # Show that no page is under construction.
        self._sym_liner = ONE_THIRD * 2

    def early_sym_page(self):
        self._line.spacing = Bit.BIT1

        self.print_lin()
        self._sym_liner = ONE_THIRD * 2

    def early_print_sym(self, sym):
        # Branch if any of healths 0-4.
        health = sym.health
        if (sym.health >= 6) or (
            (sym.health == 5)
                and True):  # FIXME: check for failed leftover erase
            # Increment healths 5.5 (failed j-card) up.
            health += 1
        if (sym.health == 3) and (len(sym.ref_pages) == 0):
            health = 18

        # Increment count of syms in this state.
        self._symh_vect[health].count += 1

        self._line[0] = sym.name

        # Branch if symbol has a valid definition.
        if self._symh_vect[health].no_valid_loc:
            # Otherwise put it in typing list.
            self.usy_place(sym)
            eqivlent = ONES
        else:
            eqivlent = sym.value

        # Set definition or blots in print.
        self.m_edit_def(eqivlent)

        self._line[24] = self._symh_vect[health].description
        self._line[99] = '%4u' % sym.def_page

        if self._old_line.spacing != Bit.BIT1:
            if self._old_line[0] != self._line[0]:
                self._old_line.spacing = 3
                self._sym_liner += ONE_THIRD * 6
            elif (ALPHABET.index(self._old_line[1]) //
                  16) != (ALPHABET.index(self._line[1]) // 16):
                self._old_line.spacing = 2
                self._sym_liner += ONE_THIRD * 3

        if self._sym_liner >= EARLY_FULL_PAGE:
            self._old_line.spacing = Bit.BIT1
            self._sym_liner = ONE_THIRD * 2

        self._sym_liner += ONE_THIRD * 3
        self.print_lin()

    def end_pr_sym(self):
        # Branch if sym tab listing filled last p.
        if self._sym_liner > 0o700:
            # Print last page of symbol table listing.
            self.sym_page()

        # Page heading for symbol table summary.
        self._page_hed2[0] = '%-120s' % 'SUMMARY OF SYMBOL TABLE LISTING'

        # Clean out print line in case of suppress.
        self._line.clear()

        # Symbol table overflow into health vectr.
        self._symh_vect[17].count = self._yul.sym_thr.sym_tab_xs

        # Branch if there are symbols to cuss.
        if len(self._usym_cuss) > 12:
            self._mon.mon_typer(self._usym_cuss)

        n_symbols = 0
        symh_vect = self._symh_vect[-1:] + self._symh_vect[:-1]
        for health in symh_vect:
            n_symbols += health.count
            if health.count > 0:
                # Convert count for this state to z/s alf.
                self._line.spacing = 2
                self._line[10] = ('%4d  ' % health.count) + health.description
                self.print_lin()

        # Place a line between addends and total.
        self._line.spacing = 2
        self._line[10] = '----'
        self._old_line.spacing = 1
        self.print_lin()

        # Print grand total to finish summary.
        self._line[0] = ' TOTAL:   %4d' % n_symbols
        self._line.spacing = 7
        self.print_lin()

        if self._mon.year > 1967:
            # Upspace 7 and print character set.
            self._line.spacing = Bit.BIT1
            self._line[0] = 'H-1800 CHARACTER SEQUENCE (360 LACKS ■≠½' + \
                            '␍⌑¢);  0123456789\'=: >&   +ABCDEFGHI:.)%' + \
                            '■?   -JKLMNOPQR#$*"≠½   </STUVWXYZ@,(␍⌑¢'
            self.print_lin()

        return self.eecr_tabl()

    def usy_place(self, sym):
        if len(self._usym_cuss) < 50:
            self._usym_cuss += '  %-8s  ' % sym.name
        elif len(self._usym_cuss) < 64:
            self._usym_cuss += '& MORE'

    def eecr_test(self, sym):
        # Branch when memory type is known.
        midx = 0
        while sym.value > self._m_typ_tab[midx][1]:
            midx += 1
        mem_type = self._m_typ_tab[midx][0]

        if mem_type != MemType.ERASABLE:
            # Exit if definition was not by equals.
            if sym.health >= 6:
                return
        lo = 0
        hi = len(self._eecr_list)
        idx = 0

        while lo < hi:
            idx = (lo + hi) // 2
            if sym.value >= self._eecr_list[idx].value:
                lo = idx + 1
            else:
                hi = idx

        self._eecr_list.insert(lo, sym)

    def eecr_tabl(self):
        if self._mon.year < 1967 or len(self._eecr_list) == 0:
            return self.wc_sumary()

        self._page_hed2[0] = 'ERASABLE & EQUIVALENCE CROSS-REFERENCE T' + \
                             'ABLE, SHOWING DEFINITION, PAGE OF DEFINI' + \
                             'TION, AND SYMBOL                        '

        eecr_page = 0
        for p in range(0, len(self._eecr_list), 200):
            eecrs = self._eecr_list[p:p + 200]
            eecr_page = len(eecrs)
            # Number of eecrs in last line.
            excess = eecr_page % 5
            rows = eecr_page // 5

            for row in range(rows + (1 if excess > 0 else 0)):
                cols = excess if (row == rows) else 5
                sym_idx = row
                col_start = 0
                for col in range(cols):
                    sym = eecrs[sym_idx]

                    # Set definition of symbol in print.
                    self.m_edit_def(sym.value, col_start=col_start)

                    # Shift definition to left edge of column.
                    self._line[col_start] = self._line[col_start +
                                                       11:col_start + 19]

                    # Set page of definition in print.
                    self._line[col_start + 9] = '%4d  ' % sym.def_page

                    # Set symbol in print.
                    self._line[col_start + 15] = '%-8s' % sym.name

                    # Advance to head of next column.
                    sym_idx += rows
                    col_start += 24

                    # Branch if now on shorter columns.
                    if col < excess:
                        # Advance one more step on longer ones.
                        sym_idx += 1

                # Branch if now end of a 4-line group.
                if (row % 4) == 3:
                    self._line.spacing = 2
                else:
                    self._line.spacing = 1

                self.print_lin()

        return self.wc_sumary()

    def wc_sumary(self):
        # FIXME: Implement word count summary
        pass

    def av_disply(self):
        self._page_hed2[0] = '%-120s' % 'MEMORY TYPE & AVAILABILITY DISPLAY'

        # Initialize address to 0.
        address = 0

        # Two columns are built up in bank 5.
        self._l_bank_5 = []

        while address <= self._m_typ_tab[-1][1]:
            # Skip to H-O-F before each page
            self._old_line.spacing = Bit.BIT1

            # Branch when memory type found.
            midx = 0
            while address > self._m_typ_tab[midx][1]:
                midx += 1
            mem_type = self._m_typ_tab[midx][0]
            upper_lim = self._m_typ_tab[midx][1]
            end = address

            # Branch if not special or nonexistent.
            if mem_type == MemType.SPEC_NON:
                # Save address of description.
                desc = 0
                # Save end category = upper lim of entry.
                end = upper_lim

            else:
                avail = self.avail_q(address)
                if mem_type == MemType.FIXED:
                    if avail:
                        desc = 2
                    else:
                        desc = 1
                else:
                    if avail:
                        desc = 4
                    else:
                        desc = 3

                # Go to find end of reserved/available E or F.
                end += 1
                while end < upper_lim:
                    next_avail = self.avail_q(end)
                    if avail != next_avail:
                        end -= 1
                        break
                    end += 1

            self._l_bank_5.append((address, end, desc))
            address = end + 1
            # Branch if a pageful is ready.
            if (len(self._l_bank_5) >= 80) or (address >
                                               self._m_typ_tab[-1][1]):
                # Having stored up to 80 entries in condensed CAC-format, we now print them on one page in two columns.
                right_start = ceil(len(self._l_bank_5) / 2)
                for row in range(right_start):
                    cat_idx = row
                    cs = 0
                    for i in range(2):
                        start, end, desc_idx = self._l_bank_5[cat_idx]
                        # Store description of memory type.
                        desc = self._m_type_cax[desc_idx]
                        self._line[cs + 24] = desc

                        # Print upper limit of category.
                        self.m_edit_def(end, col_start=cs)

                        # Stop there if length is 1.
                        if start != end:
                            self.m_edit_def(start, col_start=cs - 12)

                            # Insert "TO" between low and high limits.
                            self._line[cs + 9] = 'TO'

                        cat_idx += right_start
                        cs += 64
                        if cat_idx >= len(self._l_bank_5):
                            break

                    self._line.spacing = 2 if (row % 4 == 3) else 1
                    self.print_lin()

                self._l_bank_5 = []

    def avail_q(self, eqivlent):
        available = True

        avail_msk = 1 << (eqivlent & 0x1F)
        avail_idx = eqivlent >> 5

        if self._yul.av_table[avail_idx] & avail_msk:
            available = False

        return available

    def ws3(self):
        # FIXME: put symbol table into BYPT

        # Sort and merge word records
        self._wd_recs = sorted(self._wd_recs, key=lambda w: w.fwa)
        i = 0
        while i < (len(self._wd_recs) - 1):
            a = self._wd_recs[i]
            b = self._wd_recs[i + 1]
            if (a.page == b.page) and (a.lwa == b.fwa - 1):
                a.words.extend(b.words)
                a.lwa = b.lwa
                self._wd_recs.pop(i + 1)
            else:
                i += 1

        for page_group in range(0, len(self._wd_recs), 160):
            page_locs = self._wd_recs[page_group:page_group + 160]
            n_locs = len(page_locs)

            # Form as much subhead as needed.
            self._page_hed2.clear()
            for i in range(min(4, n_locs)):
                self._page_hed2[i * 32] = 'OCCUPIED LOCATIONS  PAGE'
            self._old_line.spacing = Bit.BIT1

            rows = n_locs // 4
            excess = n_locs % 4

            for row in range(rows + (1 if excess > 0 else 0)):
                cols = excess if (row == rows) else 4
                loc_idx = row
                for col in range(cols):
                    loc = page_locs[loc_idx]
                    # Set LWA in print.
                    self.m_edit_def(loc.lwa, col_start=col * 32)

                    # Print LWA only if FWA = LWA.
                    if loc.fwa != loc.lwa:
                        self.m_edit_def(loc.fwa, col_start=col * 32 - 12)
                        self._line[col * 32 + 9] = 'TO'

                    # Set page number in print.
                    self._line[col * 32 + 20] = '%4d' % loc.page

                    loc_idx += rows
                    if col < excess:
                        loc_idx += 1

                self._line.spacing = 2 if (row % 4 == 3) else 1
                self.print_lin()

        # Procedure to initialize each substrand, and sorting loop for each word record.
        for rec in self._wd_recs:
            par_id = rec.fwa // 256
            par_addr = rec.fwa % 256

            for word in rec.words:
                if par_id not in self._paragraphs:
                    self._paragraphs[par_id] = Paragraph(par_id)

                # Branch if no storage conflict.
                if self._paragraphs[par_id][par_addr] != 0:
                    # Conflict is enough for bad assembly.
                    self._yul.switch |= SwitchBit.BAD_ASSEMBLY
                    self._paragraphs[par_id][par_addr] = CONFLICT
                else:
                    self._paragraphs[par_id][par_addr] = word

                par_addr += 1
                if par_addr >= 256:
                    par_addr = 0
                    par_id += 1

    def prin_pars(self):
        # Skip to head of form after availability.
        self._old_line.spacing = Bit.BIT1

        # Page subhead for substrand summary.
        self._page_hed2[0] = 'PARAGRAPHS GENERATED FOR THIS ASSEMBLY; ' + \
                             'ADDRESS LIMITS AND THE MANUFACTURING LOC' + \
                             'ATION CODE ARE SHOWN FOR EACH.          '

        # In case of barren assembly (no words).
        if len(self._paragraphs) == 0:
            # Announce lack of words, go to finalize.
            self._line[
                0] = '%-120s' % 'NO WORDS WERE GENERATED FOR THIS ASSEMBLY.'
            self.print_lin()
            self._yul.switch |= SwitchBit.BAD_ASSEMBLY
            return

        last_ss_no = -1
        for i, p in self._paragraphs.items():
            self._line.spacing = 2
            # Branch if this ph not successor of last.
            if p.number == last_ss_no:
                # Branch if this ph begins 4-ph group.
                if (p.number & 3) != 0:
                    # Selectively close up ph summary format.
                    self._old_line.spacing = 1

            # Form 1st & last addresses of paragraph.
            address = p.number * 256
            eqivlent = address + 255

            # Print most paragraph information
            self.m_print_pn(p.number, eqivlent)

            # Call for lower limit print.
            self.m_edit_def(address, col_start=-12)

            # Insert "TO" between limit addresses.
            self._line[9] = 'TO'

            self.print_lin()

            last_ss_no = p.number + 1

        self.print_lin()

    def print_oct(self):
        # In case octal suppression is revoked.
        self._page_hed2[0] = '■■■■■■■■■■■ SUPPRESSION OF OCTAL STORAGE' + \
                             ' MAP REVOKED BECAUSE OF CUSSES (■XXX; EA' + \
                             'CH COUNTS AS A CUSSED LINE). ■■■■■■■■■■■'

        # Prepare for cusses in the octal stormap.
        n_oct_errs = 0

        for i, p in self._paragraphs.items():
            # Go to H-O-F for each par.
            self._old_line.spacing = Bit.BIT1

            # Skip if octal map is suppressed.
            if not self._yul.switch & SwitchBit.SUPPRESS_OCTAL:
                # Print page head and subhead for parags.
                self.m_explain(p.number)

            # From 1st address of paragraph.
            address = p.number * 256

            for l in range(32):
                # Set 1st address of line in print
                self.m_edit_def(address, col_start=-12)

                for w in range(8):
                    # Make up 14-charater print image of wd.
                    wno = l * 8 + w
                    image, edited_word = self.m_edit_wd(p[wno], address + w)
                    p[wno] = edited_word

                    self._line[8 + w * 14] = image

                # Branch if not last of 4-line group.
                if (l % 4) == 3:
                    self._line.spacing = 2
                else:
                    self._line.spacing = 1

                # Skip to suppress octal storage map.
                if not self._yul.switch & SwitchBit.SUPPRESS_OCTAL:
                    # Print an address and eight words.
                    self.print_lin()

                address += 8

            # At end of each paragraph (formerly called a substrand), if any octal-map errors were found, print a
            # combination cuss-wham line giving the number(s) of the cuss(es) and the page of the preceding cussed line.

            if self._n_oct_errs > 0:
                # Serial no for first cuss of page.
                first_cuss = self._yul.n_err_lins + 1
                line_beg = 'E■■■■■■  # %d  ' % first_cuss

                # Line begins "E■■■■■■  # NN  "
                self._line[0] = line_beg

                # Fill it out as a wham line.
                self._line[16] = '■' * 104

                # Branch if this is the first cuss page.
                if self._yul.err_pages[0] is not None:
                    # Set in print pointer to previous cuss.
                    self._line[
                        80] = 'PRECEDING CUSSED LINE IS ON PAGE%4s ■■■' % self._yul.err_pages[
                            1]
                else:
                    # Show that first cuss is on this page.
                    self._yul.err_pages[0] = self._yul.page_head[-4:]

                # Show that latest cuss is on this page.
                self._yul.err_pages[1] = self._yul.page_head[-4:]

                self._yul.n_err_lins += self._n_oct_errs

                # Cuss line is done if just one on page.
                if self._n_oct_errs > 1:
                    # Make it "E■■■■■■  # NN   THROUGH  # NN"
                    line_end = 'THROUGH  # %d' % self._yul.n_err_lins
                    self._line[16] = line_end

                # Skip if octal map is suppressed.
                if not self._yul.switch & SwitchBit.SUPPRESS_OCTAL:
                    self._line.spacing = 1
                    self.print_lin()

                # Reset count for next page.
                self._n_oct_errs = 0

    def subr_list(self):
        # FIXME: implement subroutines
        pass

    # Procedure for pass 3 to clean up the end of YULPROGS. If the assembly is a reprint or a rejected assy. or a
    # subroutine, YULPROGS has already been closed and rewound, and bit 11 set. Otherwise the existence of a bypt
    # record for the program is noted in the directory, unless the assembly is bad. The file tape is closed and rewound.
    def close_yul(self):
        # FIXME: Improve BYPT handling
        self._bypt['PARAGRAPHS'] = [{
            'PARAGRAPH': p.number,
            'WORDS': p.words
        } for n, p in self._paragraphs.items()]

        # Degree of aspersion gives the bad news.
        ecch = False
        if self._yul.n_err_lins <= 2:
            horrid = self._joyful[2]
        elif self._yul.n_err_lins <= 9:
            horrid = self._joyful[3]
        elif self._yul.n_err_lins <= 99:
            horrid = self._joyful[4]
        elif self._yul.n_err_lins <= 999:
            horrid = self._joyful[5]
        else:
            ecch = True

        # Branch if subroutine, not program.
        self._line[0] = self._last_line

        if not self._yul.switch & SwitchBit.SUBROUTINE:
            # Admit to BYPT if good/fair prog assy.
            if self._yul.switch & SwitchBit.BAD_ASSEMBLY:
                self._line[16] = self._bad
                if ecch:
                    self._mon.mon_typer('YUCCCHHHH')
                else:
                    self._mon.mon_typer(horrid + 'ASSEMBLY; FILED ON DISC')
            else:
                self._bypt['MANUFACTURABLE'] = True
                if self._yul.n_err_lins == 0:
                    self._line[16] = self._good
                    self._mon.mon_typer(self._joyful[0] +
                                        'ASSEMBLY; FILED ON DISC')
                else:
                    self._line[16] = self._fair
                    self._mon.mon_typer(self._joyful[1] +
                                        'ASSEMBLY; FILED ON DISC')
        else:
            self._mon.mon_typer(' END OF ASSEMBLY; FILED ON DISC')

        # Branch if no errors in program.
        if self._yul.n_err_lins > 0:
            # Set error count in print.
            self._line[72] = ('%8d' % self._yul.n_err_lins) + \
                              ' LINES CUSSED BETWEEN PAGES' + \
                              self._yul.err_pages[0] + ' AND' +\
                              self._yul.err_pages[1] + '.'
            self._mon.mon_typer(self._line[72:])

        self._old_line.spacing = 4
        self._mon.mon_typer('', end='\n\n\n')

        # Don't let last line have a page to self.
        self._lin_count = 0

        # Print end of last ph or of subro list.
        self._line[72] = '.'
        self.print_lin()

        # Print last line of assembly output.
        self.print_lin()

        # Write BYPT to tape
        if not self._yul.switch & SwitchBit.REPRINT:
            self._yul.yulprogs.create_bypt(self._yul.comp_name,
                                           self._yul.prog_name,
                                           self._yul.revno, self._bypt)

        # FIXME: final closeout

    # Subroutine in pass 3 to print a line with pagination control.
    # Strictly speaking, this subroutine prints the last line delivered to it.
    def print_lin(self):
        # New line ages suddenly.
        old_line = self._old_line
        self._old_line = self._line

        # Branch if last line is skip.
        prin_skip = False
        if old_line.spacing & Bit.BIT1:
            prin_skip = True
        else:

            # Add to line count from last line.
            self._lin_count += old_line.spacing
            if self._lin_count > self._yul.n_lines:
                # Skip after last line at end of page.
                old_line.spacing = Bit.BIT1
                prin_skip = True

        if prin_skip:
            if self._yul.n_copies != 0:
                self.copy_prt5()

            self._mon.phi_print(old_line.text, spacing=old_line.spacing)

            self._yul.page_no += 1
            # Put page number alpha in page head.
            self._yul.page_head = self._yul.page_head[:116] + (
                '%4d' % self._yul.page_no)

            if self._yul.n_copies != 0:
                self.copy_prt5()

            self._mon.phi_print(self._yul.page_head, spacing=3)

            # Print subheading.
            if self._yul.n_copies != 0:
                self.copy_prt5()

            self._mon.phi_print(self._page_hed2.text,
                                spacing=self._page_hed2.spacing)

            self._lin_count = 5

        else:
            if self._yul.n_copies != 0:
                self.copy_prt5()

            self._mon.phi_print(old_line.text, spacing=old_line.spacing)

        # Old line discovers fountain of youth. And is moreover made clean again.
        self._line = Line()

    def copy_prt5(self):
        # FIXME: implement
        pass

    def inish_p3(self):
        # Put correct name of tape into last line.
        self._good_bad = self._last_line[:64] + self._yul.tape

        # Type "END YUL PASS 2"
        self._mon.mon_typer('END YUL PASS 2')

        # Clear subroutine name slot in page head.
        # FIXME: Only do if not reject or obsolete.
        self._yul.page_head = self._yul.page_head[:
                                                  102] + '         ' + self._yul.page_head[
                                                      111:]

        self._yul.sym_place = 3 * (self._yul.sym_thr.count() + 1
                                   )  # FIXME: Add in SUBROS and COUNTS

        # Change rejection line in version assy.
        if self._yul.switch & SwitchBit.VERSION:
            self._rej_rev = self._rej_vers

        # Test whether recording binary records.
        if not self._yul.switch & SwitchBit.REPRINT:
            # Cause obsoleting of old revs of this pr.
            self._last_prog = self._yul.prog_name

        # Branch if doing program assembly.
        if self._yul.switch & SwitchBit.SUBROUTINE:
            # Fix subroutine list page subhead.
            self._subl_head = self._subl_head[:16] + ' ' * 8 + self._subl_head[
                24:]

            # Fix final assembly printout.
            self._last_line = self._sub_lastl + self._last_line[64:]
        else:
            # Generate a random bit in bit 47.
            page_ones = self._yul.page_no % 10
            page_ones ^= self._yul.sym_place

            if (page_ones & Bit.BIT47) == 0:
                self._joyful = self._alt_words

        self._bypt = {
            'MANUFACTURABLE': False,
            'PARAGRAPHS': [],
            'SYMBOLS': [],
        }

        self._yul.sym_thr.sort_multdefs()

        return self.p3_masker()