home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 529a.lha / A68k_v2.71 / A68kmain.c < prev    next >
C/C++ Source or Header  |  1991-07-02  |  32KB  |  1,012 lines

  1. /*------------------------------------------------------------------*/
  2. /*                                    */
  3. /*            MC68000 Cross Assembler                */
  4. /*                                    */
  5. /*          Copyright 1985 by Brian R. Anderson            */
  6. /*                                    */
  7. /*                   Main program - April 16, 1991            */
  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 1991 by Charlie Gibbs.        */
  20. /*                                    */
  21. /*------------------------------------------------------------------*/
  22.  
  23.  
  24. #define PRIMARY
  25. #include "A68kdef.h"
  26. #include "A68kglb.h"
  27.  
  28. char *Version = "2.71 (April 16, 1991)";
  29.  
  30.  
  31. #ifdef MSDOS
  32. /********************************************************************/
  33. /*                                    */
  34. /*     NOTE: the following line, plus any additional references        */
  35. /*     to _iomode, is inserted to make this program work under        */
  36. /*     the MS-DOS version of Lattice C.  It is not necessary        */
  37. /*     for the Amiga version, but does no harm if left in.        */
  38. /*                                    */
  39. /********************************************************************/
  40. int _iomode = 0;    /* File mode - 0x8000 for binary */
  41. #endif
  42.  
  43.  
  44.  
  45. void main (argc,argv) int argc; char *argv[];
  46. {
  47.     char ListFN[MAXFN], EquateFN[MAXFN]; /* File names */
  48.     int  makeequ;            /* Make an equate file. */
  49.     int  keepobj;            /* Keep object file with errors. */
  50.     int  endfile;            /* End-of-file flag */
  51.     long maxheap2;            /* Maximum secondary heap size */
  52.     int  cmderror, dummy;
  53.     long codesize, datasize, bsssize;
  54.     int  *intptr;
  55.     long templong;
  56.     char tempchar[MAXLINE];
  57.     register int i, j;
  58.     struct SymTab **hashptr, **fsp;
  59.     struct FwdBr *fp1, *fp2, *fp3;
  60.  
  61.     dummy = 0;
  62.     Hash = NULL;    /* Clear all memory pointers - */
  63.     SymStart = NULL;    /*  we haven't allocated anything yet. */
  64.     NameStart = NULL;
  65.     RelStart = NULL;
  66.     Heap2 = NULL;
  67.     SymSort = NULL;
  68.     In.fd = Eq.fd = List.fd = Srec.fd = NULL;    /* No files are open yet. */
  69.     In.Buf = Eq.Buf = List.Buf = Srec.Buf = NULL;
  70.  
  71.     cmderror = FALSE;        /* Clear command-line error flag. */
  72.     InclErrs = FALSE;
  73.     SourceFN[0] = '\0';            /* We don't have source name yet. */
  74.     HeaderFN[0] = EquateFN[0] = '\0';    /* No header or equate files yet */
  75.     makeequ = FALSE;
  76.     ListFN[0] = SrecFN[0] = '\0';    /* Indicate default file names. */
  77.     InclList[0] = '\0';        /* Clear the include directory list. */
  78.     IdntName[0] = '\0';        /* Clear program unit name. */
  79.     DataOffset = 32768L;    /* Default small data offset */
  80.     LnMax = 60;            /* Default page size */
  81.     Quiet = 100;        /* Show progress every 100 lines. */
  82.     strcpy (MacSize, "W");    /* Macro call size (\0) */
  83.     XrefList = DumpSym = GotEqur = KeepTabs = keepobj = FALSE;
  84.     SuppList = TRUE;        /* Default to no listing file. */
  85.     HashStats = FALSE;        /* Default to no hashing statistics. */
  86.     HashSize = DEFHASH;        /* Hash table size default */
  87.     maxheap2 = DEFHEAP2;    /* Secondary heap size default */
  88.     DebugStart = 32767; DebugEnd = 0;    /* Disable debug displays. */
  89.  
  90.     for (i = 0; i < 256; i++)
  91.     OpPrec[i] = '\0';    /* Set up the operator precedence table. */
  92.     i = (unsigned int) '('; OpPrec[i] = 1;
  93.     i = (unsigned int) ')'; OpPrec[i] = 2;
  94.     i = (unsigned int) '+'; OpPrec[i] = 3;
  95.     i = (unsigned int) '-'; OpPrec[i] = 3;
  96.     i = (unsigned int) '*'; OpPrec[i] = 4;
  97.     i = (unsigned int) '/'; OpPrec[i] = 4;
  98.     i = (unsigned int) '&'; OpPrec[i] = 5;
  99.     i = (unsigned int) '!'; OpPrec[i] = 5;
  100.     i = (unsigned int) '|'; OpPrec[i] = 5;
  101.     i = (unsigned int) '<'; OpPrec[i] = 6;
  102.     i = (unsigned int) '>'; OpPrec[i] = 6;
  103.  
  104.     for (i = 1; i < argc; i++) {    /* Analyze the command line. */
  105.     if (argv[i][0] != '-') {
  106.         if (SourceFN[0] == '\0')
  107.         strcpy (SourceFN, argv[i]);    /* Source file name */
  108.         else if (SrecFN[0] == '\0')
  109.         strcpy (SrecFN, argv[i]);    /* Object file name */
  110.         else if (ListFN[0] == '\0')
  111.         strcpy (ListFN, argv[i]);    /* Listing file name */
  112.         else {
  113.         fprintf (stderr, "Too many file names.\n");
  114.         cmderror = TRUE;
  115.         }
  116.     } else {
  117.         switch (toupper(argv[i][1])) {
  118.         case 'D':            /* Dump the symbol table. */
  119.         DumpSym = TRUE;
  120.         strcpy (DumpSymList, &argv[i][2]);    /* Selections */
  121.         break;
  122.         case 'E':            /* Equate file name */
  123.         makeequ = TRUE;
  124.         if (getfilename (EquateFN, &argv[i][2], "Equate", FALSE))
  125.             cmderror = keepobj = TRUE;
  126.         break;
  127.         case 'F':            /* Dump the symbol table. */
  128.         FwdProc = TRUE;
  129.         cmderror |= checkswitch (argv[i], "forward reference");
  130.         break;
  131.         case 'G':            /* XREF all unknown globals */
  132.         GlobalXREF = TRUE;
  133.         cmderror |= checkswitch (argv[i], "automatic XREF");
  134.         break;
  135.         case 'H':            /* Header file name */
  136.         if (getfilename (HeaderFN, &argv[i][2], "Header", TRUE))
  137.             cmderror = keepobj = TRUE;
  138.         break;
  139.         case 'I':            /* Include directories */
  140.         if (argv[i][2]) {
  141.             if (InclList[0])
  142.             strcat (InclList, ",");    /* Add to previous list */
  143.             strcat (InclList, &argv[i][2]);
  144.         } else {
  145.             fprintf (stderr, "Include directory list is missing.\n");
  146.             cmderror = keepobj = TRUE;
  147.         }
  148.         break;
  149.         case 'K':            /* Keep object code file. */
  150.         keepobj = TRUE;
  151.         cmderror |= checkswitch (argv[i], "object file keep");
  152.         break;
  153.         case 'X':            /* Cross-reference listing */
  154.         XrefList = TRUE;    /* Falls through to case 'L': */
  155.         case 'L':            /* Produce a listing file. */
  156.         SuppList = FALSE;
  157.         if (getfilename (ListFN, &argv[i][2], "List", FALSE))
  158.             cmderror = keepobj = TRUE;
  159.         break;
  160.         case 'M':            /* Offset to small data base */
  161.         if (argv[i][2] == '\0') {
  162.             fprintf (stderr, "Small data offset is missing.\n");
  163.             cmderror = keepobj = TRUE;
  164.             break;
  165.         }
  166.         if (!isdigit (argv[i][2])) {
  167.             fprintf (stderr, "Small data offset is invalid.\n");
  168.             cmderror = TRUE;
  169.             break;
  170.         }
  171.         DataOffset = CalcValue (&argv[i][2], 0);
  172.         break;
  173.         case 'N':            /* Suppress optimization. */
  174.         NoOpt = TRUE;
  175.         cmderror |= checkswitch (argv[i], "optimization suppress");
  176.         break;
  177.         case 'O':            /* Object file name */
  178.         if (getfilename (SrecFN, &argv[i][2], "Object", TRUE))
  179.             cmderror = keepobj = TRUE;
  180.         break;
  181.         case 'P':            /* Page depth */
  182.         if (argv[i][2] == '\0') {
  183.             fprintf (stderr, "Page depth is missing.\n");
  184.             cmderror = keepobj = TRUE;
  185.             break;
  186.         }
  187.         if (!isdigit (argv[i][2])) {
  188.             fprintf (stderr, "Page depth is invalid.\n");
  189.             cmderror = TRUE;
  190.             break;
  191.         }
  192.         if ((LnMax = CalcValue (&argv[i][2], 0)) < 10) {
  193.             fprintf (stderr, "Page depth is invalid.\n");
  194.             cmderror = TRUE;
  195.         }
  196.         break;
  197.         case 'Q':            /* Quiet console display */
  198.         if (argv[i][2] == '\0') {
  199.             Quiet = 0;
  200.             break;
  201.         }
  202.         if (!isdigit (argv[i][2])) {
  203.             fprintf (stderr, "Quiet interval is invalid.\n");
  204.             cmderror = TRUE;
  205.             break;
  206.         }
  207.         Quiet = CalcValue (&argv[i][2], 0);
  208.         break;
  209.         case 'S':            /* Motorola S-format */
  210.         SFormat = TRUE;
  211.         cmderror |= checkswitch (argv[i], "S-format");
  212.         break;
  213.         case 'T':            /* Keep tabs in listing. */
  214.         KeepTabs = TRUE;
  215.         cmderror |= checkswitch (argv[i], "tab");
  216.         break;
  217.         case 'W':            /* Work storage size(s) */
  218.         if (argv[i][2] == '\0') {
  219.             fprintf (stderr, "Work storage size is missing.\n");
  220.             cmderror = keepobj = TRUE;
  221.             break;
  222.         }
  223.         if (argv[i][2] != ',') {
  224.             GetField (argv[i]+2, tempchar);
  225.             if (!isdigit (tempchar[0])) {
  226.             fprintf (stderr, "Hash table size is invalid.\n");
  227.             cmderror = TRUE;
  228.             break;
  229.             }
  230.             HashSize = CalcValue (tempchar, 0);
  231.             if (HashSize >= 16384) {
  232.             fprintf (stderr, "Hash table size is too big.\n");
  233.             cmderror = TRUE;
  234.             }
  235.         }
  236.         for (j = 2; argv[i][j]; j++) {
  237.             if (argv[i][j] == ',') {    /* Find secondary size. */
  238.             if (!isdigit (argv[i][j+1])) {
  239.                 fprintf (stderr, "Secondary size is invalid.\n");
  240.                 cmderror = TRUE;
  241.                 break;
  242.             }
  243.             maxheap2 = CalcValue (&argv[i][j+1], 0);
  244.             if (maxheap2 < MAXLINE)
  245.                 maxheap2 = MAXLINE;
  246.             maxheap2 &= ~3L;
  247.             break;
  248.             }
  249.         }
  250.         break;
  251.         case 'Y':            /* Display hashing statistics. */
  252.         HashStats = TRUE;
  253.         cmderror |= checkswitch (argv[i], "hash statistics");
  254.         break;
  255.         case 'Z':            /* Debug option */
  256.         DebugStart = 0;
  257.         DebugEnd = 32767;
  258.         if (argv[i][2] != ',') {    /* Debug dump starts here. */
  259.             GetField (argv[i]+2, tempchar);
  260.             if (!isdigit (tempchar[0])) {
  261.             fprintf (stderr, "Debug start line is invalid.\n");
  262.             cmderror = TRUE;
  263.             break;
  264.             }
  265.             DebugStart = CalcValue (tempchar, 0);
  266.         }
  267.         for (j = 2; argv[i][j]; j++) {
  268.             if (argv[i][j] == ',') {    /* Debug dump ends here. */
  269.             if (!isdigit (argv[i][j+1])) {
  270.                 fprintf (stderr, "Debug end line is invalid.\n");
  271.                 cmderror = TRUE;
  272.                 break;
  273.             }
  274.             DebugEnd = CalcValue (&argv[i][j+1], 0);
  275.             if (DebugEnd == 0)
  276.                 DebugEnd = 32767;
  277.             }
  278.         }
  279.         break;
  280.         default:
  281.         fprintf (stderr, "Unrecognized switch: %c\n", argv[i][1]);
  282.         cmderror = TRUE;
  283.         break;
  284.         }
  285.     }
  286.     }
  287.  
  288.     if (makeequ)
  289.     defaultfile (EquateFN, ".equ");    /* Default equate file name */
  290.     if (!SuppList)
  291.     defaultfile (ListFN, ".lst");    /* Default list file name */
  292.     else            /* If there's no listing, don't bother */
  293.     KeepTabs = TRUE;    /*  expanding tabs - it's faster.      */
  294.     if (SFormat)
  295.     defaultfile (SrecFN, ".s");    /* Default S-format file name */
  296.     else
  297.     defaultfile (SrecFN, ".o");    /* Default object file name */
  298.  
  299. /* Check for duplicate file names. */
  300.  
  301.     if (SourceFN[0]) {
  302.     cmderror |= checkdupfile (SourceFN, "Source", EquateFN, "equate");
  303.     cmderror |= checkdupfile (SourceFN, "Source", ListFN, "listing");
  304.     cmderror |= checkdupfile (SourceFN, "Source", SrecFN, "object");
  305.     } else {
  306.     fprintf (stderr, "Source file name is missing.\n");
  307.     cmderror = TRUE;
  308.     }
  309.     if (EquateFN[0]) {
  310.     cmderror |= checkdupfile (EquateFN, "Equate", ListFN, "listing");
  311.     cmderror |= checkdupfile (EquateFN, "Equate", SrecFN, "object");
  312.     }
  313.     if (ListFN[0]) {
  314.     cmderror |= checkdupfile (ListFN, "Listing", SrecFN, "object");
  315.     }
  316.  
  317. /*    Open files.    */
  318.  
  319.     if (!cmderror) {                /* Source file */
  320.     if ((In.Buf = (char *) malloc (BUFFSIZE)) == NULL)
  321.         quit_cleanup ("Out of memory!\n");
  322. #ifdef MSDOS
  323.     _iomode = 0x8000;
  324. #endif
  325.     if ((In.fd = open (SourceFN, 0)) < 0) {
  326.         fprintf (stderr, "Unable to open source file.\n");
  327.         In.fd = NULL;
  328.         cmderror = TRUE;
  329.     }
  330.     In.Ptr = In.Lim = In.Buf;
  331.     }
  332. #ifdef MSDOS
  333.     _iomode = 0;
  334. #endif
  335.     if (!cmderror && EquateFN[0])        /* Equate file */
  336.     cmderror |= xopen (EquateFN, &Eq, "equate");
  337.  
  338.     if (!cmderror && !SuppList)            /* Listing file */
  339.     cmderror |= xopen (ListFN, &List, "listing");
  340.  
  341. #ifdef MSDOS
  342.     if (!SFormat)
  343.     _iomode = 0x8000;
  344. #endif
  345.     if (!cmderror)                /* Object code file */
  346.     cmderror |= xopen (SrecFN, &Srec, "object code");
  347. #ifdef MSDOS
  348.     _iomode = 0x8000;
  349. #endif
  350.  
  351.     if (cmderror) {
  352.     fprintf (stderr, "\n");
  353.     fprintf (stderr, "68000 Assembler - version %s\n", Version);
  354.     fprintf (stderr, "Copyright 1985 by Brian R. Anderson\n");
  355.     fprintf (stderr, "AmigaDOS conversion copyright 1991 by Charlie Gibbs.\n\n");
  356.     fprintf (stderr, "Usage: a68k <source file>\n");
  357.     fprintf (stderr, "            [-d[[!]<prefix>]]       [-o<object file>]\n");
  358.     fprintf (stderr, "            [-e[<equate file>]]     [-p<page depth>]\n");
  359.     fprintf (stderr, "            [-f]                    [-q[<quiet interval>]]\n");
  360.     fprintf (stderr, "            [-g]                    [-s]\n");
  361.     fprintf (stderr, "            [-h<header file>]       [-t]\n");
  362.     fprintf (stderr, "            [-i<include dirlist>]   ");
  363.         fprintf (stderr, "[-w[<hash size>][,<heap size>]]\n");
  364.     fprintf (stderr, "            [-k]                    [-x]\n");
  365.     fprintf (stderr, "            [-l[<listing file>]]    [-y]\n");
  366.     fprintf (stderr, "            [-m<small data offset>] ");
  367.         fprintf (stderr, "[-z[<debug start>][,<debug end>]]\n");
  368.     fprintf (stderr, "            [-n]\n\n");
  369.     fprintf (stderr, "Heap size default:  -w");
  370.     fprintf (stderr, "%ld,%ld\n", (long) DEFHASH, (long) DEFHEAP2);
  371.     SrecFN[0] = '\0';    /* Don't scratch the object file! */
  372.     quit_cleanup ("\n");
  373.     }
  374.  
  375.     if (Quiet != 0) {
  376.     printf ("68000 Assembler - version %s\n", Version);
  377.     printf ("Copyright 1985 by Brian R. Anderson\n");
  378.     printf ("AmigaDOS conversion copyright 1991 by Charlie Gibbs.\n\n");
  379.     printf ("Assembling %s\n\n", SourceFN);
  380.     }
  381.  
  382. /* Allocate initial symbol table chunks. */
  383.  
  384.     templong = sizeof (struct SymTab *) * HashSize;
  385.     Hash = (struct SymTab **) malloc ((unsigned) templong);
  386.     if (Hash == NULL)
  387.     quit_cleanup ("Out of memory!\n");
  388.     for (hashptr = Hash, i = 0; i < HashSize; hashptr++, i++)
  389.     *hashptr = NULL;    /* Clear the hash table. */
  390.  
  391.     SymStart = (struct SymTab *) malloc ((unsigned) CHUNKSIZE);
  392.     if (SymStart == NULL)
  393.     quit_cleanup ("Out of memory!\n");
  394.     SymCurr = SymStart;            /* Make the first chunk current. */
  395.     SymCurr->Link = NULL;        /* Clear forward pointer. */
  396.     SymLim = SymCurr;
  397.     SymLim++;                /* Start of names */
  398.  
  399.     NameStart = (struct NameChunk *) malloc ((unsigned) CHUNKSIZE);
  400.     if (NameStart == NULL)
  401.     quit_cleanup ("Out of memory!\n");
  402.     NameCurr = NameStart;        /* Make the first chunk current. */
  403.     NameCurr->Link = NULL;        /* Clear forward pointer. */
  404.     NameLim = (char *) NameCurr + sizeof (char *);  /* Start of names */
  405.  
  406. /* Allocate the relocation attribute table. */
  407.  
  408.     RelStart = (struct RelTab *) malloc ((unsigned) CHUNKSIZE);
  409.     if (RelStart == NULL)
  410.     quit_cleanup ("Out of memory!\n");
  411.     RelCurr = RelStart;            /* Relocation table */
  412.     RelCurr->Link = NULL;        /* No additional chunks */
  413.     RelLast = NULL;            /* There are no entries yet. */
  414.     RelLim = RelStart;
  415.     RelLim++;                /* First unused space */
  416.  
  417. /* Allocate the secondary heap (input files and parser stack). */
  418.  
  419.     Heap2 = malloc ((unsigned) maxheap2);
  420.     if (Heap2 == NULL)
  421.     quit_cleanup ("Out of memory!\n");
  422.  
  423. /* Allocate the INCLUDE skip table. */
  424.  
  425.     SkipLim = (struct SkipEnt *) malloc ((unsigned) INCSKSIZ);
  426.     if (SkipLim == NULL)
  427.     quit_cleanup ("Out of memory!\n");
  428.     SkipIdx = SkipLim;
  429.     SetFixLim = (struct SetFixup *) ((char *) SkipLim + INCSKSIZ);
  430.     IncStart = 0;
  431.  
  432. /* Allocate the forward branch optimization log. */
  433.  
  434.     if (NoOpt) {
  435.     FwdStart = NULL;
  436.     } else {
  437.     FwdStart = (struct FwdTable *) malloc ((unsigned) FWDSIZE);
  438.     if (FwdStart == NULL)
  439.         quit_cleanup ("Out of memory!\n");
  440.     FwdCurr = FwdStart;    /* Make the first chunk current. */
  441.     FwdCurr->Link = NULL;    /* Clear forward pointer. */
  442.     FwdLim2 = (int *) ((char *) FwdCurr + sizeof (struct FwdTable *));
  443.     FwdPtr = FwdLim2;    /* Current position in pass 2 */
  444.     }
  445.  
  446. /*-------------------------------------------------------------------
  447.  
  448.     Begin Pass 1.
  449.                                    */
  450.     Pass2 = FALSE;
  451.     startpass ('1', maxheap2);
  452.     NumSyms = 0;    /* There's nothing in the symbol table yet. */
  453.     NextHunk = 0L;    /* Start in hunk zero. */
  454.     LowInF = InF;    /* Initialize secondary heap usage pointers. */
  455.     High2 = NextFNS;
  456.     Low2  = (char *) LowInF;
  457.     FwdLim1     = FwdBranch;    /* Forward branch controls */
  458.     FwdFixLimit = FwdBranchFix;
  459.  
  460.     /* Define ".A68K" as a SET symbol with an absolute value of 1.
  461.     This allows programs to identify this assembler.    */
  462.     AddSymTab (".A68K", 1L, (long) ABSHUNK, 0, 4);  /* All spellings */
  463.     AddSymTab (".A68k", 1L, (long) ABSHUNK, 0, 4);
  464.     AddSymTab (".a68K", 1L, (long) ABSHUNK, 0, 4);
  465.     AddSymTab (".a68k", 1L, (long) ABSHUNK, 0, 4);
  466.  
  467.     endfile = FALSE;
  468.     Dir = None;
  469.     while (!endfile && (Dir != End)) {
  470.     PrevDir = Dir;            /* Save previous directive. */
  471.     endfile = LineParts (dummy);    /* Get a statement. */
  472.     GetObjectCode (dummy);        /* Process the statement. */
  473.  
  474.     if (IncStart != 0) {
  475.         if ((OpCode[0] != '\0') && (Dir < SkipDir)) {
  476.         IncStart = 0;            /* We can't      */
  477.         if (SkipLim->Set1 != NULL) {    /*  skip this    */
  478.             SetFixLim = SkipLim->Set1;    /*  INCLUDE file */
  479.             SetFixLim++;        /*  in pass 2.   */
  480.         }
  481.         }
  482.     }
  483.     if ((HunkType == HunkNone) && (AddrAdv != 0)) {
  484.         DoSection ("", 0, "", 0, "", 0);    /* Start unnamed CODE section. */
  485.         MakeHunk = TRUE;
  486.     }
  487.     if ((Label[0] != '\0')            /* If the statement is labeled */
  488.     && (Dir != Set) && (Dir != Equr) && (Dir != Reg)) {
  489.         if (!ReadSymTab (Label)) {        /* Make a new entry. */
  490.         AddSymTab (Label, AddrCnt, CurrHunk, LineCount, 0);
  491.         } else if ((Sym->Flags & 1)        /* If dup., ignore... */
  492.         || (Sym->Defn == NODEF)) {        /* else fill in... */
  493.         Sym->Val = AddrCnt;        /* Current loc. */
  494.         Sym->Hunk = CurrHunk;        /* Hunk number */
  495.         Sym->Defn = LineCount;        /* Statement number */
  496.         Sym->Flags &= ~1;        /* Clear XREF flag. */
  497.         if (Sym->Flags & 0x80) {    /* If it's PUBLIC, */
  498.             Sym->Flags |= 2;        /*  make it XDEF. */
  499.         }
  500.         }
  501.         if (Dir == Equ) {
  502.         Sym->Val = ObjSrc;        /* Equated value */
  503.         Sym->Hunk = Src.Hunk;        /* Hunk number */
  504.         }
  505.         if (!NoOpt && (Dir != Equ)) {    /* Forward optimization */
  506.         PackFwdBranch (dummy);        /* Drop expired entries. */
  507.         fp1 = FwdBranch;
  508.         while (fp1 < FwdLim1) {        /* Scan forward branches. */
  509.             if (fp1->FwdSym == Sym) {    /* It branched here. */
  510.             if (fp1->Loc != (AddrCnt-4)) {    /* Don't make zero displacement! */
  511.                 if (fp1->Line < LineCount)
  512.                 Sym->Val -= 2;    /* Move the label back. */
  513.                 AddrCnt -= 2;    /* Shorten the program. */
  514.                 for (fsp = FwdBranchFix; fsp < FwdFixLimit; fsp++) {
  515.                 if (fp1->Loc<(*fsp)->Val) {    /* Adjust labels  */
  516.                     (*fsp)->Val -= 2;        /*  within range. */
  517.                 }
  518.                 }
  519.                 if ((char *) FwdLim2 >= ((char *) FwdCurr + FWDSIZE)) {
  520.                 FwdCurr->Link =    /* Get a new chunk. */
  521.                     (struct FwdTable *) malloc ((unsigned) FWDSIZE);
  522.                 if (FwdCurr->Link == NULL)
  523.                     quit_cleanup ("Out of memory!\n");
  524.                 FwdCurr = FwdCurr->Link;
  525.                 FwdLim2 = (int *)
  526.                     ((char *) FwdCurr + sizeof (struct FwdTable *));
  527.                 }
  528.                 *FwdLim2++ = fp1->Line; /* Flag this branch in pass 2. */
  529.             }
  530.             fp3 = fp2 = fp1;
  531.             fp3++;
  532.             while (fp3 < FwdLim1) {    /* Remove processed entry. */
  533.                 fp2->Loc    = fp3->Loc - 2;    /* Locations shifted too! */
  534.                 fp2->FwdSym = fp3->FwdSym;
  535.                 fp2->Line   = fp3->Line;
  536.                 fp2++;
  537.                 fp3++;
  538.             }
  539.             FwdLim1--;    /* Decrement table limit pointer. */
  540.             fp1--;        /* Offset increment below. */
  541.             }
  542.             fp1++;        /* Check the next entry. */
  543.         }
  544.         if (FwdLim1 > FwdBranch) {    /* Store labels within    */
  545.             *FwdFixLimit++ = Sym;    /*  range of fwd. branch. */
  546.         }
  547.         }
  548.     }
  549.     AddrCnt    += AddrAdv * DupFact;    /* Advance the location counter. */
  550.     }
  551.     if ((HunkType == HunkNone) && (NumSyms != 0)) { /* Dummy section   */
  552.     DoSection ("", 0, "", 0, "", 0);        /*  to get XDEF    */
  553.     MakeHunk = TRUE;                /*  symbols if any */
  554.     }
  555.     if (HunkType != HunkNone)
  556.     if (AddrCnt > OrgHigh)
  557.         Sect->Val = AddrCnt;    /* End of the last section */
  558.     else
  559.         Sect->Val = OrgHigh;    /* We've ORGed higher. */
  560.  
  561.     if (InclErrs)
  562.     quit_cleanup ("Fatal errors - assembly aborted\n");
  563.  
  564.     if (Quiet > 0)
  565.     fprintf (stderr, "%d\n", LineCount);
  566.     else if (Quiet < 0)
  567.     fprintf (stderr, "%d\n\n", InF->Line);
  568.  
  569.  
  570.  
  571. /*----------------------------------------------------------------
  572.  
  573.     Begin Pass 2.
  574.                                 */
  575.     Pass2 = TRUE;
  576.     lseek (In.fd, 0L, 0);        /* "Rewind" the source file. */
  577.     In.Ptr = In.Lim = In.Buf;
  578.     startpass ('2', maxheap2);
  579.     RefLim = (struct Ref *) SymLim;    /* Cross-reference table */
  580.  
  581. /* Calculate the total size of each section type,
  582.     reset all section pointers to the beginning, and
  583.     write all absolute symbols to an equate file if desired. */
  584.  
  585.     codesize = datasize = bsssize = 0;
  586.     if (EquateFN[0]) {
  587.     xputs (&Eq, "* Equate file for ");
  588.     xputs (&Eq, SourceFN);
  589.     xputs (&Eq, "\n* Created by");
  590.     xputs (&Eq, " A68k version ");
  591.     xputs (&Eq, Version);
  592.     xputs (&Eq, "\n");
  593.     }
  594.     Sym = SymChunk = SymStart;
  595.     Sym++;
  596.     SymChLim = (struct SymTab *) ((char *) SymChunk + CHUNKSIZE);
  597.     while (Sym) {
  598.     if (Sym->Flags & 0x10) {
  599.         templong = (Sym->Val + 3) & ~3L;        /* Hunk size */
  600.         j = (Sym->Hunk & 0x3FFF0000L) >> 16;    /* Hunk type */
  601.         if (j == HunkCode)        /* Accumulate sizes by type. */
  602.         codesize += templong;
  603.         else if (j == HunkData)
  604.         datasize += templong;
  605.         else
  606.         bsssize += templong;
  607.         Sym->Val = 0L;        /* Back to start of all sections */
  608.     }
  609.     if (EquateFN[0]) {
  610.         if (((Sym->Hunk & 0x00007FFFL) == ABSHUNK)
  611.         && ((Sym->Flags == 0) || (Sym->Flags == 2))) {
  612.         xputs (&Eq, Sym->Nam);
  613.         xputs (&Eq, "\tEQU\t$");
  614.         LongPut (&Eq, Sym->Val, 4);
  615.         xputs (&Eq, "\n");
  616.         }
  617.     }
  618.     Sym = NextSym (Sym);    /* Try for another symbol table entry. */
  619.     }
  620.     if (EquateFN[0])
  621.     xclose (&Eq);
  622.  
  623. /* Write sign-on messages for listing file. */
  624.  
  625.     LnCnt = LnMax;
  626.     PgCnt = 0;
  627.     if (!SuppList) {
  628.     CheckPage (&List, FALSE);        /* Print headings. */
  629.     xputs (&List, "68000 Assembler - version ");
  630.     xputs (&List, Version);
  631.     xputs (&List, "\nCopyright 1985 by Brian R. Anderson.\n");
  632.     xputs (&List, "AmigaDOS conversion copyright 1991");
  633.     xputs (&List, " by Charlie Gibbs.\n\n");
  634.     LnCnt += 4;
  635.     }
  636.  
  637.     StartSrec (&Srec, IdntName);    /* Write object header record. */
  638.  
  639. /*    Process the second pass.    */
  640.  
  641.     endfile = FALSE;
  642.     Dir = None;
  643.     while (!endfile && (Dir != End)) {
  644.     PrevDir = Dir;            /* Save previous directive. */
  645.     endfile = LineParts (dummy);    /* Get a statement. */
  646.     if (!endfile) {
  647.         GetObjectCode (dummy);    /* Process the statement. */
  648.         if (Label[0] != '\0') {    /* If statement is labeled, */
  649.         ReadSymTab (Label);    /*  check for duplicate defn. */
  650.         if (Sym->Defn != LineCount) {
  651.             AddRef (LineCount);    /* Got one - flag as reference. */
  652.             if (Dir == Set) {
  653.             if ((Sym->Flags & 4) == 0)
  654.                 Error (LabLoc, SymDup); /* Can't SET normal label. */
  655.             } else {
  656.             Error (LabLoc, SymDup);    /* Ordinary duplicate */
  657.             }
  658.         } else if (Dir == Set) {
  659.             AddRef (LineCount);    /* Flag all SETs as references. */
  660.         } else {
  661.             if (Sym->Val != AddrCnt)
  662.             if ((Dir != Equ) && (Dir != Equr) && (Dir != Reg))
  663.                 Error (0, Phase);    /* Assembler error */
  664.         }
  665.         }
  666.         WriteListLine (&List);
  667.         WriteSrecLine (&Srec);
  668.         AddrCnt += AddrAdv * DupFact;    /* Advance the location counter. */
  669.     } else {
  670.         Error (0, EndErr);        /* END statement is missing. */
  671.         WriteListLine (&List);
  672.     }
  673.     }
  674.     if ((HunkType == HunkNone) && (NumSyms != 0)) { /* Dummy section   */
  675.     DoSection ("", 0, "", 0, "", 0);        /*  to get XDEF    */
  676.     MakeHunk = TRUE;                /*  symbols if any */
  677.     }
  678.  
  679. /*----------------------------------------------------------------
  680.  
  681.     Clean up.
  682.                                 */
  683.  
  684.     if (HunkType != HunkNone)
  685.     if (AddrCnt > OrgHigh)
  686.         Sect->Val = AddrCnt;    /* End of the last section */
  687.     else
  688.         Sect->Val = OrgHigh;    /* We've ORGed higher. */
  689.  
  690.     if (Quiet > 0)
  691.     fprintf (stderr, "%d", LineCount);    /* Final line number */
  692.     else if (Quiet < 0)
  693.     fprintf (stderr, "%d\n", InF->Line);
  694.     fflush (stderr);            /* Make sure it gets out. */
  695.  
  696.     close (In.fd);        /* We're finished with the source file. */
  697.     In.fd = NULL;
  698.     free (In.Buf);
  699.     In.Buf = NULL;
  700.  
  701.     EndSdata (&Srec, EndAddr);    /* Write remaining data and end record. */
  702.     xclose (&Srec);        /* We're finished with the object file. */
  703.     if ((ErrorCount != 0) && (!keepobj))
  704.     unlink (SrecFN);    /* Scratch it if there were errors. */
  705.  
  706.     RelCurr = RelStart;
  707.     RelStart = NULL;
  708.     while (RelCurr != NULL) {
  709.     RelLim = RelCurr;
  710.     RelCurr = RelCurr->Link;
  711.     free (RelLim);        /* Free the relocation table. */
  712.     }
  713.  
  714.     if (Heap2 != NULL) {
  715.     free (Heap2);        /* Free the secondary heap. */
  716.     Heap2 = NULL;
  717.     }
  718.  
  719.     if (XrefList)
  720.     WriteSymTab (&List);    /* List the symbol table. */
  721.  
  722. /* Display final error count. */
  723.  
  724.     if (Quiet != 0)
  725.     fprintf (stderr, "\nEnd of assembly - ");
  726.     if (!SuppList)
  727.     xputs (&List, "\nEnd of assembly - ");
  728.     if (ErrorCount == 0) {
  729.     if (Quiet != 0)
  730.         fprintf (stderr, "no errors were found.\n");
  731.     if (!SuppList)
  732.         xputs (&List, "no errors were found.\n");
  733.     } else if (ErrorCount == 1) {
  734.     if (Quiet != 0)
  735.         fprintf (stderr, "1 error was found.\n");
  736.     if (!SuppList)
  737.         xputs (&List, "1 error was found.\n");
  738.     } else {
  739.     if (Quiet != 0)
  740.         fprintf (stderr, "%d errors were found.\n", ErrorCount);
  741.     if (!SuppList) {
  742.         sprintf (tempchar, "%d errors were found.\n", ErrorCount);
  743.         xputs (&List, tempchar);
  744.     }
  745.     }
  746.  
  747. /* Display heap usage. */
  748.  
  749.     if (Quiet != 0)
  750.     fprintf (stderr, "Heap usage:  -w%ld", HashSize);
  751.     if (!SuppList) {
  752.     sprintf (tempchar, "Heap usage:  -w%ld", HashSize);
  753.     xputs (&List, tempchar);
  754.     }
  755.     templong = (long) (High2 - Heap2);
  756.     if (Low2 < (char *) LowInF)
  757.     templong += (long) (Heap2 + maxheap2 - Low2);
  758.     else
  759.     templong += (long) (Heap2 + maxheap2 - (char *) LowInF);
  760.     if (Quiet != 0)
  761.     fprintf (stderr, ",%ld\n", templong);
  762.     if (!SuppList) {
  763.     sprintf (tempchar, ",%ld\n", templong);
  764.     xputs (&List, tempchar);
  765.     }
  766.  
  767. /* Display the total size of all section types. */
  768.  
  769.     if (Quiet != 0) {
  770.     fprintf (stderr, "Total hunk sizes:  %lx code, ", codesize);
  771.     fprintf (stderr, "%lx data, %lx BSS\n", datasize, bsssize);
  772.     }
  773.     if (!SuppList) {
  774.     sprintf (tempchar, "Total hunk sizes:  %lx code, ", codesize);
  775.     xputs (&List, tempchar);
  776.     sprintf (tempchar, "%lx data, %lx BSS\n", datasize, bsssize);
  777.     xputs (&List, tempchar);
  778.     }
  779.  
  780. /* Display hashing statistics if required. */
  781.  
  782.     if (HashStats && (NumSyms != 0)) {
  783.     printf ("\n");
  784.     printf ("HASH CHAIN STATISTICS - %d symbols\n\n", NumSyms);
  785.     templong = (NumSyms + 1) * sizeof (int);
  786.     HashCount = (int *) malloc ((unsigned) templong);
  787.     if (HashCount == NULL)
  788.         quit_cleanup ("Out of memory!\n");
  789.  
  790.     printf ("Length     No. of chains\n");
  791.     printf ("------     -------------\n");
  792.     intptr = HashCount;
  793.     for (i = 0; i <= NumSyms; i++)
  794.         *(intptr++) = 0;    /* Clear hash chain length counters. */
  795.  
  796.     hashptr = Hash;
  797.     for (i = 0; i < HashSize; i++) {
  798.         j = 0;
  799.         if ((Sym = *hashptr) != NULL) {
  800.         j++;        /* This chain has at least one entry. */
  801.         while ((Sym = Sym->Link) != NULL) {
  802.             j++;    /* Count entries in the chain. */
  803.         }
  804.         }
  805.         intptr = HashCount + j;
  806.         (*intptr)++;    /* Bump counter by chain length. */
  807.         hashptr++;
  808.     }
  809.     intptr = HashCount;
  810.     for (i = 0; i <= NumSyms; i++) {
  811.         if (*intptr)
  812.         printf ("%4d          %4d\n", i, *intptr);
  813.         intptr++;
  814.     }
  815.     free (HashCount);        /* Free hash statistics table. */
  816.     HashCount = NULL;
  817.     }
  818.  
  819. /* All done! */
  820.     if (!SuppList) {
  821.     xputs (&List, "\f");    /* One last page eject */
  822.     xclose (&List);        /* We're finished with the listing file. */
  823.     }
  824.     quit_cleanup ("");        /* Normal termination */
  825. }
  826.  
  827.  
  828.  
  829. /*======================================================================*/
  830. /*                                    */
  831. /*              Subroutines used by the main program            */
  832. /*                                    */
  833. /*======================================================================*/
  834.  
  835.  
  836.  
  837. int getfilename (name, arg, desc, needit)
  838. char *name, *arg, *desc;
  839. int needit;
  840. /* If "name" is not a duplicate, copies "arg" to it, else flags
  841.     duplicate using "desc".  If "needit" is TRUE, also flags
  842.     an error if "arg" is a null string.
  843.     Returns TRUE if an error is found, FALSE otherwise. */
  844. {
  845.     if (*name) {
  846.     fprintf (stderr, "%s file is declared more than once.\n", desc);
  847.     return (TRUE);
  848.     }
  849.     if (*arg) {
  850.     strcpy (name, arg);
  851.     return (FALSE);
  852.     }
  853.     if (needit) {
  854.     fprintf (stderr, "%s file name is missing\n", desc);
  855.     return (TRUE);
  856.     }
  857.     return (FALSE);
  858. }
  859.  
  860.  
  861.  
  862. int checkswitch (sw, name) char *sw, *name;
  863. /* Displays an error message and returns TRUE if the argument
  864.     pointed to by "s" is more than two characters long.
  865.     Just returns FALSE otherwise.                */
  866. {
  867.     if (strlen (sw) > 2) {
  868.     fprintf (stderr, "Invalid %s switch (%s).\n", name, sw);
  869.     return (TRUE);
  870.     } else {
  871.     return (FALSE);
  872.     }
  873. }
  874.  
  875.  
  876.  
  877. void defaultfile (name, ext) char *name, *ext;
  878. /* If "name" is a null string, search for the last period in "name"
  879.     (if any) and append "ext".
  880.     If "name" doesn't contain a period, append a period and "ext". */
  881. {
  882.     char *s;
  883.  
  884.     if (*name == '\0') {    /* If name isn't specified... */
  885.     strcpy (name,SourceFN);    /* Start with source file name. */
  886.     s = name+strlen(name);    /* Scan backwards for period. */
  887.     while (--s > name) {
  888.         if (*s == '.') {
  889.         *s = '\0';    /* Chop off name extension. */
  890.         break;
  891.         }
  892.     }
  893.     strcat (name, ext);    /* Add name extension. */
  894.     }
  895. }
  896.  
  897.  
  898.  
  899. int checkdupfile (name1, desc1, name2, desc2)
  900. char *name1, *desc1, *name2, *desc2;
  901. /* If "name1" is the same as "name2", display an error message using
  902.     "desc1" and "desc2" and return TRUE.  Otherwise, return FALSE. */
  903. {
  904.     if (strcmp (name1, name2) == 0) {
  905.     fprintf (stderr,
  906.         "%s and %s file names are the same.\n", desc1, desc2);
  907.     return (TRUE);
  908.     } else {
  909.     return (FALSE);
  910.     }
  911. }
  912.  
  913.  
  914.  
  915. void startpass (pchar, maxheap2) char pchar; long maxheap2;
  916. /* Set up to start the next pass. */
  917. {
  918.     if (Quiet > 0) {
  919.     fprintf (stderr, "PASS %c line ", pchar);
  920.     fflush (stderr);
  921.     } else if (Quiet < 0) {
  922.     fprintf (stderr, "PASS %c\n", pchar);
  923.     }
  924.     NextFNS = Heap2;
  925.     InF = (struct InFCtl *) (Heap2 + maxheap2);
  926.     InF--;
  927.     InFNum = OuterMac = SkipNest = InF->Pos = InF->MCnt = 0;
  928.     InF->Line = 0;
  929.     InF->UPtr = 0;
  930.     InF->NPtr = NextFNS;
  931.     InF->NArg = -1;
  932.     InF->MCnt = 0;
  933.     strcpy (NextFNS, SourceFN);
  934.     ShowFile (FALSE);            /* Show source file name. */
  935.     NextFNS += strlen (SourceFN) + 1;
  936.     LineCount = LabLine = MacCount = ErrorCount = 0;
  937.     AddrCnt = CurrHunk = SectStart = EndAddr = 0L;
  938.     HunkType = HunkNone;        /* We're not in a hunk yet. */
  939.     HunkFlags = SectLine = HunkSeq = 0;
  940.     ListOff = MakeHunk = InnrFMac = FALSE;
  941.     SmallData = -1;
  942.     TTLstring[0] = '\0';        /* Clear the title string. */
  943. }
  944.  
  945.  
  946.  
  947. void quit_cleanup (s) char *s;
  948. /* Clean up and exit.  If "s" doesn't point to a null string, print the
  949.     string as an error message, remove the partially-formed object
  950.     file if it exists, and exit with an error code.            */
  951. {
  952.     if (In.fd != NULL)            /* Close all files... */
  953.     close (In.fd);
  954.     if (In.Buf != NULL)            /*  and free buffers. */
  955.     free (In.Buf);
  956.     if (Srec.fd != NULL)
  957.     xclose (&Srec);
  958.     if (List.fd != NULL)
  959.     xclose (&List);
  960.     if (Eq.fd != NULL)
  961.     xclose (&Eq);
  962.  
  963.     if (Hash != NULL)
  964.     free (Hash);            /* Free the hash table. */
  965.  
  966.     SymCurr = SymStart;
  967.     while (SymCurr != NULL) {
  968.     SymLim = SymCurr;
  969.     SymCurr = SymCurr->Link;
  970.     free (SymLim);            /* Free the symbol table. */
  971.     }
  972.  
  973.     NameCurr = NameStart;
  974.     while (NameCurr != NULL) {
  975.     NameLim = (char *) NameCurr;
  976.     NameCurr = NameCurr->Link;
  977.     free (NameLim);            /* Free the name table. */
  978.     }
  979.  
  980.     RelCurr = RelStart;
  981.     while (RelCurr != NULL) {
  982.     RelLim = RelCurr;
  983.     RelCurr = RelCurr->Link;
  984.     free (RelLim);            /* Free the relocation table. */
  985.     }
  986.  
  987.     FwdCurr = FwdStart;
  988.     while (FwdCurr != NULL) {
  989.     FwdLim2 = (int *) FwdCurr;
  990.     FwdCurr = FwdCurr->Link;
  991.     free (FwdLim2);            /* Free the forward branch log. */
  992.     }
  993.  
  994.     if (Heap2 != NULL)
  995.     free (Heap2);            /* Free the secondary heap. */
  996.  
  997.     if (SymSort != NULL)
  998.     free (SymSort);            /* Free symbol table sort area. */
  999.  
  1000.     if (HashCount != NULL)
  1001.     free (HashCount);        /* Free hash statistics table. */
  1002.  
  1003.     if (*s) {                /* If we have an error message, */
  1004.     if (SrecFN[0])
  1005.         unlink (SrecFN);        /*  scratch the object file,    */
  1006.     fprintf (stderr, "%s", s);    /*  display the error message,  */
  1007.     exit (20);            /*  and die. */
  1008.     } else {
  1009.     exit (ErrorCount ? 10 : 0);    /* Normal termination */
  1010.     }
  1011. }
  1012.