home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 1 / CDPD_Vol1.bin / pd / 176-200 / 186 / a68k / a68kmisc.c < prev    next >
C/C++ Source or Header  |  1992-06-23  |  31KB  |  1,101 lines

  1. /*------------------------------------------------------------------*/
  2. /*                                    */
  3. /*              MC68000 Cross Assembler                */
  4. /*                                    */
  5. /*          Copyright    (c) 1985 by Brian R. Anderson            */
  6. /*                                    */
  7. /*          Miscellaneous routines - January 6, 1989            */
  8. /*                                    */
  9. /*   This program may be copied    for personal, non-commercial use    */
  10. /*   only, provided that the above copyright notice is included        */
  11. /*   on    all copies of the source code.    Copying    for any    other use   */
  12. /*   without the consent of the    author is prohibited.            */
  13. /*                                    */
  14. /*------------------------------------------------------------------*/
  15. /*                                    */
  16. /*        Originally published (in Modula-2) in            */
  17. /*        Dr.    Dobb's Journal, April, May, and June 1986.          */
  18. /*                                    */
  19. /*     AmigaDOS conversion copyright 1989 by Charlie Gibbs.        */
  20. /*                                    */
  21. /*------------------------------------------------------------------*/
  22.  
  23. #include <stdio.h>
  24. #include "a68kdef.h"
  25. #include "a68kglb.h"
  26.  
  27. char Sdata[MAXSREC];    /* S-record data */
  28. int  Sindex;        /* Index for Sdata */
  29. int  NumRExt, NumR32, NumR16, NumR8;
  30.  
  31. static char *errmsg[] =    {
  32.     "--- Unknown error code ---",
  33.     "Alignment error.",
  34.     "No such op-code.",
  35.     "Duplicate Symbol.",
  36.     "Undefined Symbol.",
  37.     "Addressing mode not allowed here.",
  38.     "Error in operand format.",
  39.     "Error in relative branch.",
  40.     "Address mode error.",
  41.     "Operand size error.",
  42.     "END statement is missing.",
  43.     "Value must be absolute.",
  44.     "Relocatability error.",
  45.     "INCLUDE file cannot be opened.",
  46.     "Illegal forward reference.",
  47.     "Not supported in S-format.",
  48.     "This instruction needs a label.",
  49.     "Pass 1 / Pass 2 phase error.",
  50.     "ENDM statement is missing.",
  51.     "ENDC statement is missing.",
  52.     "Unmatched ENDC statement.",
  53.     "Too much DC data.",
  54.     "Too many SECTIONs.",
  55.     "Duplicate macro definition.",
  56.     "More than one label on this line.",
  57.     "End of string is missing.",
  58.     "Short displacement can't be zero.",
  59.     ""};
  60.  
  61. /* Functions */
  62. extern int  LineParts(), Instructions(), ObjDir();
  63. extern int  GetInstModeSize(), GetMultReg(), CountNest();
  64. extern int  ReadSymTab(), GetArgs(), GetAReg(),    OpenIncl();
  65. extern long GetValue(),    CalcValue();
  66. extern char *AddName(),    *GetField();
  67. extern struct SymTab *NextSym();
  68. extern struct SymTab **HashIt();
  69.  
  70. long AddrBndW(), AddrBndL();
  71.  
  72.  
  73.  
  74. long AddrBndW (v) register long    v;
  75. /* Advances "v" to the next word boundary */
  76. {
  77.     register int i;
  78.  
  79.     if (v & 1L)    {
  80.     AppendSdata (0L, 1);
  81.     v++;
  82.     }
  83.     return (v);
  84. }
  85.  
  86.  
  87.  
  88. long AddrBndL (v) register long    v;
  89. /* Advances "v" to the next long-word boundary */
  90. {
  91.     long templong;
  92.  
  93.     v =    AddrBndW (v);        /* Bump    to a word boundary first */
  94.     if (v & 2L)    {        /* If still not    aligned, */
  95.     templong = NOP;        /*  generate a NOP */
  96.     AppendSdata (templong, 2);
  97.     v += 2;
  98.     }
  99.     return (v);
  100. }
  101.  
  102.  
  103.  
  104. WriteListLine (f) struct fs *f;
  105. /* Writes one line to the Listing file,    including Object Code */
  106. {
  107.     register int i, j, printed;
  108.     long templong;
  109.     char macflag;
  110.     char tempstr[12];
  111.     int     dummy;
  112.  
  113.     if (!Pass2)
  114.     return;            /* Pass    2 only */
  115.     if (FwdShort && (ErrLim == 0)) {
  116.     DisplayLine (dummy);
  117.     printf ("A short branch can be used here.\n");
  118.     }
  119.     if (SuppList)
  120.     return;            /* Listing is suppresed    */
  121.     if (ErrLim == 0)
  122.     if ((Dir == Page) || (Dir == Space) || (Dir == Title)
  123.     || (Dir    == DoList) || (Dir == NoList) || (ListOff))
  124.         return;        /* Don't print unless they have errors */
  125.  
  126.     CheckPage (f, FALSE);    /* Print headings if necessary */
  127.  
  128.     if (PrntAddr) {
  129.     if ((Dir == Equ) || (Dir == Set))
  130.         LongPut (f,    ObjSrc,    3);    /* Equated value */
  131.     else
  132.         LongPut (f,    AddrCnt, 3);    /* Current location */
  133.     if (!KeepTabs)
  134.         xputs (f, "  ");
  135.     } else
  136.     if (!KeepTabs)
  137.         xputs (f, "        ");      /* Don't print location */
  138.     if (KeepTabs)
  139.     xputs (f, "\t");                /* Use tabs for spacing */
  140.     printed = 8;            /* We've printed 8 positions */
  141.     LongPut (f,    ObjOp, nO);        /* Generated code */
  142.     printed += nO * 2;
  143.     if (nS != 0) {
  144.     xputs (f, " ");
  145.     LongPut    (f, ObjSrc, nS);
  146.     printed    += nS *    2 + 1;
  147.     }
  148.     if (nD != 0) {
  149.     xputs (f, " ");
  150.     LongPut    (f, ObjDest, nD);
  151.     printed    += nD *    2 + 1;
  152.     }
  153.     if ((j = nX) > 0) {                /* String data */
  154.     if ((j * 2 + printed) >    ObjMAX)
  155.         j =    (ObjMAX    - printed) / 2;
  156.     for (i = 0; i <    j; i++)    {
  157.         templong = ObjString[i];
  158.         LongPut (f,    templong, 1);
  159.     }
  160.     printed    += j * 2;
  161.     }
  162.     while (printed < ObjMAX) {
  163.     if (KeepTabs) {
  164.         xputs (f, "\t");
  165.         printed += 8;
  166.         printed &= ~7;
  167.     } else {
  168.         xputs (f, " ");
  169.         printed++;
  170.     }
  171.     }
  172.     if ((InFNum    == 0) || (OuterMac == 0))
  173.     macflag    = ' ';                  /* Open code */
  174.     else if (InFNum > OuterMac)
  175.     macflag    = '+';                  /* Inner macro */
  176.     else if ((InFNum ==    OuterMac) && (Dir != MacCall))
  177.     macflag    = '+';                  /* Outermost macro */
  178.     else
  179.     macflag    = ' ';                  /* We're outside macros */
  180.  
  181.     sprintf (tempstr, "  %5d%c", LineCount, macflag);
  182.     xputs (f, tempstr);
  183.     xputs (f, Line);
  184.     xputs (f, "\n");
  185.  
  186.     if (FwdShort && (ErrLim == 0))
  187.     xputs (f, "A short branch can be used here.\n");
  188.  
  189.     for    (i = 0;    i < ErrLim; i++) {    /* Write error messages. */
  190.     CheckPage (f, FALSE);
  191.     xputs (f, errmsg[ErrCode[i]]);
  192.     printed    = strlen(errmsg[ErrCode[i]]);
  193.     while (printed < ObjMAX    + 8) {
  194.         if (KeepTabs) {
  195.         xputs (f, "\t");
  196.         printed    += 8;
  197.         printed    &= ~7;
  198.         } else {
  199.         xputs (f, " ");
  200.         printed++;
  201.         }
  202.     }
  203.     for (j = 0; j <    ErrPos[i]; j++)    {
  204.         if (Line[j]    == '\t') {
  205.         xputs (f, "\t");
  206.         printed    += 8;
  207.         printed    &= ~7;
  208.         } else {
  209.         xputs (f, " ");
  210.         printed++;
  211.         }
  212.     }
  213.     xputs (f, "^ ");                        /* Error flag */
  214.     if (i == 0) {
  215.         if (InF->UPtr == 0)
  216.         xputs (f, InF->NPtr);        /* Module name */
  217.         else
  218.         xputs (f, "(user macro)");      /* In a user macro */
  219.         sprintf (tempstr, " line %d", InF->Line);
  220.         xputs (f, tempstr);            /* Line    number */
  221.     }
  222.     xputs (f, "\n");
  223.     }
  224. }
  225.  
  226.  
  227.  
  228. WriteSymTab (f)    struct fs *f;
  229. /* Lists the symbol table in alphabetical order    */
  230. {
  231.     int     printhunk, i;
  232.     char *p;
  233.     char tempstr[24];
  234.     long templong;
  235.     register int j, k;
  236.     register struct SymTab **ss1, **ss2, *sym, **sortlim;
  237.     struct Ref *ref;
  238.  
  239.     if (NumSyms    == 0)
  240.     return;            /* The symbol table is empty - exit */
  241.  
  242. /* Build a sorted table    of pointers to symbol table entries */
  243.  
  244.     templong = NumSyms * sizeof    (struct    SymTab *);
  245.     SymSort = (struct SymTab **) malloc    ((unsigned) templong);
  246.     if (SymSort    == NULL) {
  247.     fprintf    (stderr, "Not enough memory for symbol table sort!\n");
  248.     return;
  249.     }
  250.     sortlim = SymSort +    NumSyms;
  251.     sym    = SymChunk = SymStart;
  252.     sym++;
  253.     SymChLim = (struct SymTab *) ((char    *) SymChunk + CHUNKSIZE);
  254.     ss1    = SymSort;
  255.     while (sym)    {
  256.     *ss1++ = sym;
  257.     sym = NextSym (sym);    /* Try for another symbol table    entry */
  258.     }
  259.     for    (i = NumSyms / 2; i > 0; i /= 2) {        /* Shell sort */
  260.     for (ss1 = SymSort + i;    ss1 < sortlim; ss1++) {    /*  (copied   */
  261.         for    (ss2=ss1-i; ss2    >= SymSort; ss2    -= i) {    /*  from K&R) */
  262.         if (strcmp ((*ss2)->Nam, (*(ss2+i))->Nam) <= 0)
  263.             break;
  264.         sym = *ss2;
  265.         *ss2 = *(ss2+i);
  266.         *(ss2+i) = sym;
  267.         }
  268.     }
  269.     }
  270.  
  271. /* The table is    now sorted - print the listing */
  272.  
  273.     LnCnt = LnMax;            /* Skip    to a new page. */
  274.     for    (i = 0,    ss1 = SymSort; i < NumSyms; i++) {
  275.     sym = *ss1++;
  276.     CheckPage (f, TRUE);
  277.  
  278.     p = sym->Nam;            /* Pointer to symbol */
  279.     if (sym->Flags & 8)
  280.         p++;            /* Skip    blank preceding    macro name */
  281.     else if    (sym->Flags & 0x10)
  282.         p += 6;            /* Skip    hunk sequence number */
  283.     sprintf    (tempstr, "%-11s ", p); /* Symbol or macro name */
  284.     xputs (f, tempstr);
  285.     if (strlen (p) > 11)        /* Long    symbol - go to new line    */
  286.         if (KeepTabs)
  287.         xputs (f, "\n\t    ");
  288.         else
  289.         xputs (f, "\n            ");
  290.  
  291.     printhunk = FALSE;        /* Assume no hunk no. to print */
  292.     if (sym->Defn == NODEF)
  293.         xputs (f, "  *** UNDEFINED *** ");
  294.     else if    (sym->Flags & 4)
  295.         xputs (f, "  -- SET Symbol --  ");
  296.     else if    (sym->Flags & 8) {
  297.         sprintf (tempstr, " +++ MACRO +++ %5d", sym->Defn);
  298.         xputs (f, tempstr);
  299.     } else if (sym->Flags &    0x10) {
  300.         j =    (sym->Hunk & 0x3FFF0000L) >> 16;
  301.         if (j == HunkCode)
  302.         xputs (f, "  CODE    ");
  303.         else if (j == HunkData)
  304.         xputs (f, "  DATA    ");
  305.         else
  306.         xputs (f, "  BSS     ");
  307.         printhunk =    TRUE;
  308.     } else if (sym->Flags &    0x20) {
  309.         sprintf (tempstr, "      %c%ld  ",
  310.         (sym->Val & 8L)    ? 'A' : 'D', sym->Val & 7L);
  311.         xputs (f, tempstr);
  312.         printhunk =    TRUE;
  313.     } else {
  314.         LongPut (f,    sym->Val, 4);        /* Value */
  315.         xputs (f, "  ");
  316.         printhunk =    TRUE;
  317.     }
  318.     if (printhunk) {
  319.         j =    sym->Hunk & 0x00007FFFL;    /* Hunk    number */
  320.         if (sym->Flags & 0x60)
  321.         xputs (f, " Reg");              /* Register or list */
  322.         else if (sym->Flags    & 1)
  323.         xputs (f, " Ext");              /* External */
  324.         else if (j == ABSHUNK)
  325.         xputs (f, " Abs");              /* Absolute */
  326.         else {
  327.         sprintf    (tempstr, "%4d", j);    /* Hunk number */
  328.         xputs (f, tempstr);
  329.         }
  330.         sprintf (tempstr," %5d",sym->Defn); /* Statement number */
  331.         xputs (f, tempstr);
  332.     }
  333.     if (XrefList) {
  334.         xputs (f, "  ");
  335.         if (sym->Ref1 == NULL)
  336.         xputs (f, " *** UNREFERENCED ***");
  337.         else {
  338.         ref = sym->Ref1;
  339.         j = k =    0;
  340.         while (1) {
  341.             if (ref->RefNum[j] == 0)
  342.             break;
  343.             if (k >= 9)    {
  344.             xputs (f, "\n");        /* New line */
  345.             if (KeepTabs)
  346.                 xputs (f, "\t\t\t\t  ");    /* 34 spaces */
  347.             else
  348.                 for    (k = 0;    k < 34;    k++)
  349.                 xputs (f, " ");
  350.             k = 0;
  351.             }
  352.             sprintf (tempstr, "%5d", ref->RefNum[j]);
  353.             xputs (f, tempstr);
  354.             j++;
  355.             k++;
  356.             if (j < MAXREF)
  357.             continue;        /* Get the next    slot */
  358.             if ((ref = ref->NextRef) ==    0)
  359.             break;            /* End of last entry */
  360.             j =    0;            /* Start the next entry    */
  361.         }
  362.         }
  363.     }
  364.     xputs (f, "\n");
  365.     }
  366.     free (SymSort);        /* Free    the sort work area */
  367.     SymSort = NULL;
  368. }
  369.  
  370.  
  371.  
  372. CheckPage (f, xhdr) struct fs *f; int xhdr;
  373. /* Checks if end of page reached yet --    if so, advances    to next    page. */
  374. {
  375.     register int printed;
  376.     char tempstr[12];
  377.  
  378.     LnCnt++;
  379.     if (LnCnt >= LnMax)    {
  380.     PgCnt++;
  381.     if (PgCnt > 1)
  382.         xputs (f, "\f");            /* Skip to new page */
  383.     xputs (f, TTLstring);        /* Title */
  384.     printed    = strlen (TTLstring);
  385.     while (printed < 56)
  386.         if (KeepTabs) {
  387.         xputs (f, "\t");
  388.         printed    += 8;
  389.         printed    &= ~7;
  390.         } else {
  391.         xputs (f, " ");
  392.         printed++;
  393.         }
  394.     xputs (f, SourceFN);        /* File    name */
  395.     if (KeepTabs)
  396.         xputs (f, "\t");
  397.     else
  398.         xputs (f, "        ");
  399.     sprintf(tempstr, "Page %d\n\n", PgCnt); /* Page number */
  400.     xputs (f, tempstr);
  401.     LnCnt =    2;
  402.     if (xhdr) {
  403.         xputs (f, "Symbol       Value    Hunk  Line");
  404.         if (XrefList)
  405.         xputs (f, "   References");     /* Cross-reference */
  406.         xputs (f, "\n\n");
  407.         LnCnt += 2;
  408.     }
  409.     }
  410. }
  411.  
  412.  
  413.  
  414. StartSrec (f, idntname)    struct fs *f; char *idntname;
  415. /* Writes object header    record */
  416. {
  417.     register long CheckSum, templong;
  418.     register char *s;
  419.  
  420.     if (SFormat) {
  421.     xputs (f, "S0");
  422.     templong = strlen (idntname) + 3; /* extra for addr. & checksum    */
  423.     LongPut    (f, templong, 1);
  424.     CheckSum = templong;
  425.  
  426.     xputs (f, "0000");  /* Address is 4 digits, all zero, for S0 */
  427.  
  428.     s = idntname;
  429.     while (*s) {
  430.         templong = toupper (*s++);
  431.         LongPut (f,    templong, 1);
  432.         CheckSum +=    templong;
  433.     }
  434.     CheckSum = ~CheckSum;        /* Complement checksum */
  435.     LongPut    (f, CheckSum, 1);
  436.     xputs (f, "\n");
  437.     } else {
  438.     templong = HunkUnit;
  439.     xputl (f, templong);
  440.     DumpName (f, idntname, 0L);
  441.     }
  442.     StartAddr =    TempAddr = Sindex = 0;
  443.     NumRExt = NumR32 = NumR16 =    NumR8 =    0;
  444. }
  445.  
  446.  
  447.  
  448. WriteSrecLine (f) struct fs *f;
  449. /* Transfers object code components to output buffer. */
  450. /* Moves long words or portions    thereof. */
  451. {
  452.     register int i;
  453.     register long templong;
  454.  
  455.     if (HunkType == HunkBSS)
  456.     return;                /* No code in BSS hunk */
  457.  
  458.     if (nO + nS    + nD + nX) {        /* If we have object code */
  459.     AppendSdata (ObjOp, nO);    /* Opcode */
  460.     AppendSdata (ObjSrc, nS);    /* Source */
  461.     AppendSdata (ObjDest, nD);    /* Destination */
  462.     for (i = 0; i <    nX; i++) {    /* String data */
  463.         templong = ObjString[i];
  464.         AppendSdata    (templong, 1);
  465.     }
  466.     }
  467. }
  468.  
  469.  
  470.  
  471. AppendSdata (Data, n) register long Data; int n;
  472. /* If we are producing S-format    records:
  473.      Transfers "n" low-order bytes from "Data" to the output buffer.
  474.      If    the buffer becomes full, DumpSdata will    be called to flush it.
  475.      S-records will also be broken on 16-byte boundaries.
  476.    If we are producing AmigaDOS    format,    data will be written
  477.      directly to Srec -    we'll go back and fill in the hunk length
  478.      at    the end    of the hunk.  DumpSdata    will never be called from here.    */
  479. {
  480.     register int  i;
  481.     register char byte;
  482.     int     dummy;
  483.  
  484.     if (!Pass2)
  485.     return;            /* Pass    2 only */
  486.     if (HunkType == HunkBSS)
  487.     return;            /* No data in BSS hunks! */
  488.  
  489.     if (HunkType == HunkNone) {        /* We're not in a hunk yet - */
  490.     DoSection ("", 0, "", 0, "", 0);        /* start a code hunk */
  491.     MakeHunk = TRUE;
  492.     }
  493.  
  494.     if (OrgFlag) {        /* If we've had an ORG directive */
  495.     FixOrg (dummy);        /*  do necessary adjustments     */
  496.     OrgFlag    = FALSE;    /*  to the object code file.     */
  497.     }
  498.  
  499.     Data <<= (4    - n) * 8;    /* Left-justify    data */
  500.  
  501.     for    (i = 0;    i < n; i++) {
  502.     byte = (char) (Data >> ((3 - i)    * 8));
  503.     TempAddr++;
  504.     if (!SFormat) {
  505.         xputc (byte, &Srec);
  506.     } else {
  507.         Sdata[Sindex++] = byte;
  508.         if (((TempAddr & 0x0F) == 0) || (Sindex >= MAXSREC))
  509.         DumpSdata (&Srec);    /* Break S-record */
  510.     }
  511.     }
  512. }
  513.  
  514.  
  515.  
  516. FixOrg (dummy) int dummy;
  517. /* Makes necessary adjustments to the object code file if an
  518.     ORG    directive has been processed.  This routine is called
  519.     exclusively    by AppendSdata and must    only be    called once for
  520.     each ORG encountered, when writing the next    object code (if    any). */
  521. {
  522.     register long templong;
  523.     register int  i;
  524.  
  525.     if (SFormat    && (AddrCnt != TempAddr)) {    /* ORG in S-format -    */
  526.     DumpSdata (&Srec);            /*  dump current record    */
  527.     StartAddr = TempAddr = AddrCnt;        /*  and    start afresh.    */
  528.     }
  529.     if (AddrCnt    < TempAddr) {        /* AmigaDOS backward ORG */
  530.     if (TempAddr > OrgHigh)    {
  531.         LenPtr = NULL;
  532.         OrgHigh = TempAddr;    /* Save    high address for return    */
  533.         if (Srec.Ptr > Srec.Buf)    /* Flush the buffer */
  534.         write (Srec.fd,    Srec.Buf, Srec.Ptr - Srec.Buf);
  535.         OrgSeek = lseek (Srec.fd, 0L, 1);    /* Remember position */
  536.         lseek (Srec.fd,(AddrCnt & ~3L)-TempAddr,1);    /* New position    */
  537.         if (AddrCnt    & 3L) {        /* If ORG isn't to long-word   */
  538.         read (Srec.fd, Srec.Buf, AddrCnt & 3L);    /*  move ahead */
  539.         lseek (Srec.fd,    -(AddrCnt & 3L), 1);    /*  to keep    */
  540.         }                        /*  the    buffer */
  541.         Srec.Ptr = Srec.Buf    + (AddrCnt & 3L);    /*  aligned.   */
  542.     }
  543.     StartAddr = TempAddr = AddrCnt;
  544.  
  545.     } else if (AddrCnt > TempAddr) {    /* AmigaDOS forward ORG    */
  546.     if (OrgHigh > TempAddr)    {    /* Previous backward ORG */
  547.         if (AddrCnt    < OrgHigh)
  548.         templong = AddrCnt;    /* Within previous range */
  549.         else
  550.         templong = OrgHigh;    /* Beyond previous range */
  551.         i =    (int) (templong    & 3L);    /* Alignment factor */
  552.         templong -=    TempAddr;    /* Number of bytes to skip */
  553.         LenPtr = NULL;
  554.         if (Srec.Ptr > Srec.Buf)    /* Flush the buffer */
  555.         write (Srec.fd,    Srec.Buf, Srec.Ptr - Srec.Buf);
  556.         lseek (Srec.fd,templong-(long)i,1);    /* Skip    written    data */
  557.         if (i) {        /* If skip isn't to long-word, */
  558.         read(Srec.fd,Srec.Buf,(long)i);    /*  move ahead */
  559.         lseek(Srec.fd, -((long)    i), 1);    /*  to keep    */
  560.         }                    /*  the    buffer */
  561.         Srec.Ptr = Srec.Buf    + (long) i;    /*  aligned.   */
  562.         TempAddr +=    templong;
  563.         StartAddr =    TempAddr;
  564.     }
  565.     while (TempAddr    < AddrCnt) {    /* Extend with binary zeros */
  566.         xputc (0, &Srec);
  567.         TempAddr++;
  568.     }
  569.     }
  570. }
  571.  
  572.  
  573.  
  574. DumpSdata (f) register struct fs *f;
  575. /* Writes an object code record    */
  576. {
  577.     register long CheckSum, templong;
  578.     register char *s;
  579.     register int  i;
  580.  
  581.     if (!SFormat) {
  582.     if (AddrCnt < OrgHigh) {    /* If we did a backwards ORG */
  583.         LenPtr = NULL;        /*  we have to fix things up */
  584.         if (f->Ptr > f->Buf)    /* Flush the buffer */
  585.         write (f->fd, f->Buf, f->Ptr - f->Buf);
  586.         lseek(f->fd,OrgSeek&~3L,0);    /* Back    to high    position */
  587.         if (OrgSeek    & 3L) {        /* If ORG isn't to long-word,  */
  588.         read (f->fd, f->Buf, OrgSeek & 3L);    /*  move ahead */
  589.         lseek (f->fd, -(OrgSeek    & 3L), 1);    /*  to keep    */
  590.         }                        /*  the    buffer */
  591.         f->Ptr = f->Buf + (OrgSeek & 3L);        /*  aligned.   */
  592.         AddrCnt = StartAddr    = TempAddr = OrgHigh;
  593.     }
  594.     AddrCnt    = AddrBndL (AddrCnt);    /* Finish the last long    word */
  595.     templong = ((AddrCnt - SectStart) >> 2)    | HunkFlags;
  596.     if ((s = LenPtr) == NULL) {
  597.         if (f->Ptr > f->Buf)        /* Flush the buffer */
  598.         write (f->fd, f->Buf, f->Ptr - f->Buf);
  599.         CheckSum = lseek (f->fd, 0L, 1);    /* Remember position */
  600.         lseek (f->fd, LenPos, 0);        /* Put hunk length here    */
  601.         s =    f->Buf;
  602.     }
  603.     *s++ = (char) (templong    >> 24);
  604.     *s++ = (char) (templong    >> 16);
  605.     *s++ = (char) (templong    >> 8);
  606.     *s++ = (char) templong;
  607.     if (LenPtr == NULL) {
  608.         write (f->fd, f->Buf, 4);
  609.         lseek (f->fd, CheckSum, 0);    /* Back    to where we were */
  610.         f->Ptr = f->Buf;
  611.     }
  612.     DumpRel    (f);        /* Write relocation information    */
  613.     templong = HunkEnd;
  614.     xputl (f, templong);    /* End of the hunk */
  615.     TempAddr = AddrCnt;
  616.     return;
  617.     }
  618.  
  619.     if (Sindex == 0)
  620.      return;        /* There's nothing to dump */
  621.  
  622.     xputs (f, "S2");
  623.     templong = Sindex +    4;    /* Record length */
  624.     LongPut (f,    templong, 1);
  625.     CheckSum = templong;    /* Initialize CheckSum */
  626.  
  627.     LongPut (f,    StartAddr, 3);    /* Address */
  628.     CheckSum +=    (StartAddr >> 16) & 0x00FFL;
  629.     CheckSum +=    (StartAddr >> 8) & 0x00FFL;
  630.     CheckSum +=    StartAddr & 0x00FFL;
  631.  
  632.     for    (i = 0;    i < Sindex; i++) {
  633.     templong = Sdata[i];
  634.     LongPut    (f, templong, 1);    /* Object code */
  635.     CheckSum += templong;
  636.     }
  637.     CheckSum = ~CheckSum;    /* Complement checksum */
  638.     LongPut (f,    CheckSum, 1);
  639.     xputs (f, "\n");
  640.  
  641.     StartAddr += Sindex;
  642.     TempAddr = StartAddr;
  643.     Sindex = 0;
  644. }
  645.  
  646.  
  647.  
  648. PutRel (addr, hunk, size) long addr, hunk; int size;
  649. /* Build a relocation entry if necessary */
  650. {
  651.     register struct RelTab *rel;
  652.  
  653.     if (!Pass2)
  654.     return;                /* Pass    2 only */
  655.     if (SFormat)
  656.     return;                /* Not for S-format! */
  657.     if (hunk ==    ABSHUNK)
  658.     return;                /* Absolute */
  659.     if (HunkType == HunkBSS)
  660.     return;                /* Not for BSS hunks! */
  661.  
  662.     rel    = RelLim;            /* Pointer to new entry    */
  663.     RelLim++;                /* Bump    limit pointer */
  664.     if (((char *) RelLim - (char *) RelCurr) > CHUNKSIZE) {
  665.     rel = (struct RelTab *)    malloc ((unsigned) CHUNKSIZE);
  666.     if (rel    == NULL)
  667.         quit_cleanup ("Out of memory!\n");
  668.     RelCurr->Link =    rel;        /* Link    from previous chunk */
  669.     RelCurr    = rel;            /* Make    the new    chunk current */
  670.     RelCurr->Link =    NULL;        /* Clear forward pointer */
  671.     rel++;                /* Skip    over pointer entry */
  672.     RelLim = rel;            /* New table limit */
  673.     RelLim++;            /* Bump    it */
  674.     }
  675.     if (RelLast    != NULL)
  676.     RelLast->Link =    rel;        /* Link    from previous entry */
  677.     rel->Link =    NULL;            /* End of the chain (so    far) */
  678.     rel->Offset    = addr;            /* Offset */
  679.     rel->Hunk =    hunk;            /* Hunk    number */
  680.     rel->Size =    size;            /* Size    */
  681.     RelLast = rel;            /* Pointer to last entry in chain */
  682.  
  683.     if (hunk < 0)            /* Count entries by type */
  684.     NumRExt++;
  685.     else if (size == Long)
  686.     NumR32++;
  687.     else if (size == Word)
  688.     NumR16++;
  689.     else
  690.     NumR8++;
  691. }
  692.  
  693.  
  694.  
  695. DumpRel    (f) struct fs *f;
  696. /* Dump    relocation information to the object file. */
  697. {
  698.     register struct SymTab *sym;
  699.     register struct RelTab *rel, *rel2;
  700.     int     i, j, size, num, donexhdr, secthlin;
  701.     long currhunk, nexthunk, templong;
  702.     char *p;
  703.  
  704.     secthlin = LineCount;        /* Current section ends    here */
  705.     if ((Dir ==    Section)        /*   unless we're starting   */
  706.     || (Dir == CSeg)            /*    a new section.         */
  707.     || (Dir == DSeg)
  708.     || (Dir == BSS))
  709.     secthlin--;            /* Then    it ends    at previous line */
  710.  
  711.     if (SFormat)
  712.     return;                /* S-format is absolute! */
  713.  
  714.     while (1) {
  715.     if ((num = NumR32) != 0) {
  716.         size = Long;        /* Do 32-bit fields */
  717.         templong = HunkR32;
  718.         NumR32 = 0;            /* ...but only once */
  719.     } else if ((num    = NumR16) != 0)    {
  720.         size = Word;        /* Then    do 16-bit fields */
  721.         templong = HunkR16;
  722.         NumR16 = 0;
  723.     } else if ((num    = NumR8) != 0) {
  724.         size = Byte;        /* Finally do 8-bit fields */
  725.         templong = HunkR8;
  726.         NumR8 = 0;
  727.     } else
  728.         break;            /* We're all done */
  729.  
  730.     xputl (f, templong);        /* Record type */
  731.  
  732.     currhunk = 32767;
  733.     num = 0;
  734.     if (rel    = RelStart)    /* If we have anything,    */
  735.         rel++;        /*  skip over the first    chunk's link. */
  736.     while (rel) {
  737.         if ((rel->Size == size) && (rel->Hunk >= 0)) {
  738.         if (rel->Hunk <    currhunk) {
  739.             currhunk = rel->Hunk;    /* Lowest hunk number */
  740.             num    = 1;            /* Reset counter */
  741.         } else if (rel->Hunk ==    currhunk) {
  742.             num++;            /* Count entries */
  743.         }
  744.         }
  745.         rel    = rel->Link;
  746.     }
  747.     while (num > 0)    {    /* Repeat for all hunk references */
  748.         templong = num;
  749.         xputl (f, templong);    /* Number of entries */
  750.         xputl (f, currhunk);    /* Hunk    number */
  751.         nexthunk = 32767;
  752.         num    = 0;            /* Count for next hunk */
  753.         if (rel = RelStart)
  754.         rel++;
  755.         while (rel)    {
  756.         if ((rel->Size == size)    && (rel->Hunk >= 0)) {
  757.             if (rel->Hunk < currhunk) {
  758.             rel = rel->Link;    /* Already wrote it */
  759.             continue;
  760.             } else if (rel->Hunk == currhunk) {
  761.             xputl (f, rel->Offset -    SectStart);
  762.             } else if (rel->Hunk < nexthunk) {
  763.             nexthunk = rel->Hunk;    /* Next    hunk number */
  764.             num = 1;        /* Reset counter */
  765.             } else if (rel->Hunk == nexthunk) {
  766.             num++;            /* Count entries */
  767.             }
  768.         }
  769.         rel = rel->Link;
  770.         }
  771.         currhunk = nexthunk;    /* Get ready for next hunk */
  772.     }
  773.     xputl (f, 0L);        /* End of relocation information */
  774.     }
  775.  
  776.     donexhdr = FALSE;        /* Haven't written hunk_ext yet */
  777.  
  778.     sym    = SymChunk = SymStart;
  779.     sym++;
  780.     SymChLim = (struct SymTab *) ((char    *) SymChunk + CHUNKSIZE);
  781.     while (sym)    {
  782.     if (sym->Flags & 2) {        /* Scan    for XDEF symbols */
  783.         j =    sym->Defn;    /* Defined in current section? */
  784.         if ((j >= SectLine)    && (j <= secthlin)) {
  785.         if (!donexhdr) {
  786.             templong = HunkExt;    /* Haven't done header yet */
  787.             xputl (f, templong);
  788.             donexhdr = TRUE;
  789.         }
  790.         if ((sym->Hunk & 0x0000FFFFL) == ABSHUNK)
  791.             templong = 0x02000000;
  792.         else
  793.             templong = 0x01000000;        /* Flags */
  794.         DumpName (f, sym->Nam, templong);    /* Symbol */
  795.         xputl (f, sym->Val - SectStart);    /* Offset */
  796.         }
  797.     }
  798.     sym = NextSym (sym);
  799.     }
  800.  
  801.     if (NumRExt    != 0) {            /* External references (XREF) */
  802.     if (!donexhdr) {
  803.         templong = HunkExt;        /* Haven't done header yet */
  804.         xputl (f, templong);
  805.         donexhdr = TRUE;
  806.     }
  807.     if (rel    = RelStart)
  808.         rel++;
  809.     while (rel) {
  810.         if (rel->Hunk < 0) {
  811.         p = (char *) ~(rel->Hunk);
  812.         size = rel->Size;
  813.         if (size == Long)
  814.             templong = 0x81000000L;    /* ext_ref32 */
  815.         else if    (size == Word)
  816.             templong = 0x83000000L;    /* ext_ref16 */
  817.         else
  818.             templong = 0x84000000L;    /* ext_ref8 */
  819.         DumpName (f, p,    templong);    /* Flags and symbol */
  820.         templong = 1;
  821.         rel2 = rel->Link;
  822.         while (rel2) {
  823.             if ((rel2->Hunk == rel->Hunk) && (rel2->Size == size))
  824.             templong++;        /* Number of times */
  825.             rel2 = rel2->Link;        /*  symbol occurs  */
  826.         }
  827.         xputl (f, templong);
  828.         rel2 = rel;            /* Now go back and  */
  829.         while (rel2) {            /*  write them out. */
  830.             if ((rel2->Hunk==rel->Hunk)    && (rel2->Size==size)) {
  831.             xputl(f, rel2->Offset -    SectStart); /* Offset */
  832.             if (rel2 != rel)    /* Kill    hunk so    we    */
  833.                 rel2->Hunk = 0;    /*  don't do it again */
  834.             }                /*  (we're done with  */
  835.             rel2 = rel2->Link;        /*  the    table anyway) */
  836.         }
  837.         }
  838.         rel    = rel->Link;
  839.     }
  840.     NumRExt    = 0;
  841.     }
  842.     if (donexhdr)
  843.     xputl (f, 0L);            /* End of external information */
  844.  
  845.     if (DumpSym) {            /* Dump    the symbol table */
  846.     donexhdr = FALSE;
  847.     sym = SymChunk = SymStart;
  848.     sym++;
  849.     SymChLim = (struct SymTab *) ((char *) SymChunk    + CHUNKSIZE);
  850.     while (sym) {
  851.         if ((sym->Hunk & 0x0000FFFFL) == CurrHunk) {
  852.         j = sym->Flags & 0x7F;        /* Ignore PUBLIC flag */
  853.         if ((j == 0) ||    (j == 2)) {    /* Defined, may    be XDEF    */
  854.             if ((sym->Defn >= SectLine)    && (sym->Defn <= secthlin)) {
  855.             if (!donexhdr) {    /* In current SECTION */
  856.                 templong = HunkSym;
  857.                 xputl (f, templong);    /* Write header    */
  858.                 donexhdr = TRUE;        /* if necessary    */
  859.             }
  860.             DumpName (f, sym->Nam, 0L);    /* Symbol */
  861.             xputl(f, sym->Val - SectStart);    /* Offset */
  862.             }
  863.         }
  864.         }
  865.         sym    = NextSym (sym);
  866.     }
  867.     if (donexhdr)
  868.         xputl (f, 0L);        /* End of symbol table dump */
  869.     }
  870.  
  871.     rel    = RelStart->Link;
  872.     while (rel != NULL)    {
  873.     rel2 = rel;
  874.     rel = rel2->Link;
  875.     free (rel2);            /* Free    all but    the first chunk    */
  876.     }
  877.     RelCurr = RelStart;            /* The first chunk is current */
  878.     RelCurr->Link = NULL;        /* Unlink additional chunks */
  879.     RelLast = NULL;            /* There are no    entries    left */
  880.     RelLim = RelStart;
  881.     RelLim++;                /* First unused    space */
  882. }
  883.  
  884.  
  885.  
  886. EndSdata (f, addr) struct fs *f; long addr;
  887. /* Write end record to object file */
  888. {
  889.     register long checksum, templong;
  890.  
  891.     if (SFormat) {
  892.     DumpSdata (f);            /* Write any remaining data */
  893.     xputs (f, "S804");              /* Record header */
  894.     checksum = 4;
  895.     LongPut    (f, addr, 3);        /* Transfer address */
  896.     checksum += (addr >> 16) & 0x00FFL;
  897.     checksum += (addr >> 8)    & 0x00FFL;
  898.     checksum += addr & 0x00FFL;
  899.     checksum = ~checksum;
  900.     LongPut    (f, checksum, 1);    /* Checksum */
  901.     xputs (f, "\n");
  902.     } else {
  903.     if (HunkType !=    HunkNone) {
  904.         DumpSdata (f);        /* Last    hunk's data */
  905.     }
  906.     }
  907. }
  908.  
  909.  
  910.  
  911. DumpName (f, name, flags) struct fs *f;    char *name; long flags;
  912. /* Writes a name preceded by a long word containing the
  913.     length of the name in long words.  The length word has
  914.     the    contents of "flags" ORed into it.  The name is padded
  915.     with binary    zeros to the next long word boundary. */
  916. {
  917.     register int  i;
  918.     register long templong;
  919.  
  920.     i =    strlen (name);
  921.     templong = (i + 3) >> 2;    /* Length of name (long    words) */
  922.     templong |=    flags;        /* Add flag bits */
  923.     xputl (f, templong);    /* Write length    and flags */
  924.     xputs (f, name);        /* Write the name itself */
  925.     while (i & 3) {
  926.     xputc ('\0', f);        /* Pad the last word */
  927.     i++;
  928.     }
  929. }
  930.  
  931.  
  932.  
  933. LongPut    (f, data, length) struct fs *f;    long data; int length;
  934. /* Writes to file "f" the hexadecimal interpretation of
  935.     the    bytes in "data".  The number of bytes written
  936.     (two hex digits per    byte) is given in "length" -
  937.     if less than 4, only low-order bytes are written. */
  938. {
  939.     register int i, j;
  940.     register char *t;
  941.     char xstr[9];
  942.  
  943.     t =    xstr;
  944.     for    (i = length * 8    - 4; i >= 0; i -= 4) {
  945.     j = (int) ((data >> i) & 0x0FL);
  946.     *t++ = (char) ((j > 9) ? (j - 10 + 'A') : (j + '0'));
  947.     }
  948.     *t = '\0';
  949.     xputs (f, xstr);
  950. }
  951.  
  952.  
  953.  
  954. xopen (name, f,    desc) char *name; struct fs *f;    char *desc;
  955. /* Opens the output file whose name is in "name",
  956.     setting up the file    structure pointed to by    "f".
  957.     This routine first allocates a file    buffer -
  958.     if unsuccessful, it    calls quit_cleanup.
  959.     Otherwise, it opens    the file - if unsuccessful,
  960.     displays an    error message using "desc" and returns TRUE.
  961.     If the file    is successfully    opened,    this routine returns FALSE. */
  962. {
  963.     if ((f->Buf    = (char    *) malloc (BUFFSIZE)) == NULL)
  964.     quit_cleanup ("Out of memory!\n");
  965.     if ((f->fd = creat (name, 1)) == -1) {
  966.     fprintf    (stderr, "Unable to open %s file.\n", desc);
  967.     f->fd =    NULL;
  968.     return (TRUE);
  969.     }
  970.     f->Ptr = f->Buf;
  971.     f->Lim = f->Buf + BUFFSIZE;
  972.     return (FALSE);
  973. }
  974.  
  975.  
  976.  
  977. xputs (f, s) struct fs *f; register char *s;
  978. /* Writes the string pointed to    by "s"
  979.     to the output file whose structure is pointed to by    "f". */
  980. {
  981.     register char *t, *l;
  982.  
  983.     t =    f->Ptr;        /* Current position (use registers for speed) */
  984.     l =    f->Lim;        /* End of buffer */
  985.  
  986.     while (*s) {
  987.     *t++ = *s++;
  988.     if (t >= l) {
  989.         write (f->fd, f->Buf, t - f->Buf);    /* Flush the buffer */
  990.         if (f == &Srec)
  991.         LenPtr = NULL;    /* Hunk    length is no longer in buffer */
  992.         t =    f->Buf;                /* Reset pointer */
  993.     }
  994.     }
  995.     f->Ptr = t;                    /* Update pointer */
  996. }
  997.  
  998.  
  999.  
  1000. xputl (f, data)    register struct    fs *f; register    long data;
  1001. /* Writes to file "f" the contents of the long word in "data". */
  1002. {
  1003.     xputc ((char) (data    >> 24),    f);
  1004.     xputc ((char) (data    >> 16),    f);
  1005.     xputc ((char) (data    >> 8), f);
  1006.     xputc ((char) data,    f);
  1007. }
  1008.  
  1009.  
  1010.  
  1011. xputc (byte, f)    char byte; register struct fs *f;
  1012. /* Writes the byte contained in    "byte" to file "f". */
  1013. {
  1014.     register char *t;
  1015.  
  1016.     t =    f->Ptr;        /* Current position (use register for speed) */
  1017.  
  1018.     *t++ = byte;
  1019.     if (t >= f->Lim) {
  1020.     write (f->fd, f->Buf, t    - f->Buf);    /* Flush the buffer */
  1021.     if (f == &Srec)
  1022.         LenPtr = NULL;    /* Hunk    length is no longer in buffer */
  1023.     t = f->Buf;                /* Reset pointer */
  1024.     }
  1025.     f->Ptr = t;                    /* Update pointer */
  1026. }
  1027.  
  1028.  
  1029.  
  1030. xclose (f) struct fs *f;
  1031. /* Closes the output file whose    structure is pointed to    by "f".
  1032.     The    buffer is flushed if necessary,    then freed.        */
  1033. {
  1034.     if (f->Ptr > f->Buf)
  1035.     write (f->fd, f->Buf, f->Ptr - f->Buf);    /* Flush the buffer */
  1036.     close (f->fd);                /* Close the file */
  1037.     f->fd = NULL;
  1038.     free (f->Buf);                /* Free    the buffer */
  1039.     f->Buf = NULL;
  1040. }
  1041.  
  1042.  
  1043.  
  1044. Error (pos, errornum) int pos, errornum;
  1045. /* Displays error message #errornum.  If this is the first error for
  1046.     the    current    line, the line itself is displayed, preceded by    a
  1047.     message giving the current position    in the current module.
  1048.     If the line    is in a    macro or include file, the position in
  1049.     each nested    module is given, working out to    the source file.
  1050.     A flag is placed under the column indicated    by "pos".       */
  1051. {
  1052.     register int i;
  1053.     int    dummy;
  1054.  
  1055.     if (!Pass2 && (errornum != NoIncl))    {
  1056.     if (IncStart !=    0) {            /* Don't skip this     */
  1057.         IncStart = 0;            /*  INCLUDE file in    */
  1058.         if (SkipLim->Set1 != NULL) {    /*  pass 2 - we    must   */
  1059.         SetFixLim = SkipLim->Set1;    /*  re-read it to      */
  1060.         SetFixLim++;            /*  report its errors. */
  1061.         }
  1062.     }
  1063.     return;                /* Report during pass 2    only */
  1064.     }
  1065.     if (ErrLim < ERRMAX) {        /* Save    error data */
  1066.     ErrCode[ErrLim]    = errornum;
  1067.     ErrPos[ErrLim] = pos;
  1068.     ErrLim++;
  1069.     }
  1070.     if (ErrLim == 1)        /* If first error for this line           */
  1071.     DisplayLine (dummy);    /*  display the    line and its number(s) */
  1072.     printf ("\t");
  1073.     for    (i = 0;    i < pos; i++)
  1074.     if (Line[i] == '\t')
  1075.         printf ("\t");
  1076.     else
  1077.         printf(" ");                /* Space over to error column */
  1078.     printf ("^ %s\n",errmsg[errornum]); /* Error flag and message */
  1079.     ErrorCount++;            /* Count errors    */
  1080. }
  1081.  
  1082.  
  1083.  
  1084. DisplayLine (dummy) int    dummy;
  1085. /* Displays the    current    line and its position
  1086.     in all current files - used    by Error, etc. */
  1087. {
  1088.     register struct InFCtl *inf;
  1089.     register int i;
  1090.  
  1091.     printf ("\n");
  1092.     for    (i = InFNum, inf = InF;    i >= 0;    i--, inf++) {    /* Nested? */
  1093.     if (inf->UPtr == 0)
  1094.         printf ("%s", inf->NPtr);           /* Module name */
  1095.     else
  1096.         printf ("(user macro)");            /* In a user macro */
  1097.     printf (" line %d\n", inf->Line);       /* Line number in module */
  1098.     }
  1099.     printf ("%5d   %s\n", LineCount, Line);     /* The line itself */
  1100. }
  1101.