home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d1xx / d186 / a68k.lha / A68k / Symtab.c < prev    next >
C/C++ Source or Header  |  1989-02-26  |  38KB  |  1,262 lines

  1. /*------------------------------------------------------------------*/
  2. /*                                    */
  3. /*              MC68000 Cross Assembler                */
  4. /*                                    */
  5. /*          Copyright    (c) 1985 by Brian R. Anderson            */
  6. /*                                    */
  7. /*       Symbol table    manipulation - 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. long Value;    /* Passed from ReadSymTab to CalcValue */
  28.  
  29. /* Functions */
  30. extern int  Instructions(), ObjDir();
  31. extern int  GetInstModeSize(), GetMultReg();
  32. extern int  GetArgs(), GetAReg();
  33. extern long AddrBndW(),    AddrBndL();
  34. char *AddName();
  35. struct SymTab *NextSym();
  36. struct SymTab **HashIt();
  37.  
  38. int  LineParts(), ReadSymTab(),    OpenIncl(), CountNest();
  39. long GetValue(), CalcValue();
  40. char *GetField();
  41.  
  42.  
  43.  
  44. int OpenIncl (name, dirlist) char *name, *dirlist;
  45. /* Opens the file whose    name is    in "name".  The current
  46.     directory is tried first.  If that fails, the directory
  47.     names in "dirlist" (separated by commas) are then tried
  48.     until either a file    is found or the    list is    exhausted.
  49.     If the file    is found in a subdirectory, "name" is
  50.     modified to    include    the entire path    specification.
  51.     If another input file is open when this routine is called,
  52.     it is closed first.     Returns TRUE if successful, FALSE if not.  */
  53. {
  54.     register char *s, *t;
  55.     char dirname[MAXLINE];
  56.  
  57.     if (In.fd != NULL)
  58.     close (In.fd);        /* Close the inner file    */
  59.  
  60.     if ((In.fd = open (name, 0)) != -1)    {
  61.     In.Ptr = In.Lim    = In.Buf;
  62.     if (Quiet < 0)
  63.         fprintf (stderr, "\n%s line ", name);
  64.     return (TRUE);        /* Found it in current directory */
  65.     }
  66.     s =    dirlist;
  67.     while (*s) {
  68.     s = GetField (s, dirname);
  69.     t = dirname + strlen (dirname) - 1;
  70.     if ((*t    != '/') && (*t != ':'))
  71.         strcat (dirname, "/");      /* Slash after directory name */
  72.     strcat (dirname, name);
  73.     if ((In.fd = open (dirname, 0))    != -1) {
  74.         In.Ptr = In.Lim = In.Buf;
  75.         strcpy (name, dirname);    /* Return entire path */
  76.         if (Quiet <    0)
  77.         fprintf    (stderr, "\n%s line ", name);
  78.         return (TRUE);    /* Found it in a subdirectory */
  79.     }
  80.     if (*s)
  81.         s++;        /* Skip    over separator and try again */
  82.     }
  83.     In.fd = NULL;
  84.     return (FALSE);        /* Couldn't find it anywhere */
  85. }
  86.  
  87.  
  88.  
  89. int LineParts (dummy) int dummy;
  90. /* Gets    the next statement and extracts    its component parts.
  91.     If end of file is reached, and we're in a macro or include
  92.     file, the file is closed and the next outermost file is
  93.     continued.    If we have reached the end of the source file, or
  94.     encounter an ENDM or MEXIT directive within    a macro    expansion,
  95.     the    current    input file is closed and TRUE is returned.
  96.  
  97.     If we're in a user macro (indicated by UPtr being nonzero),
  98.     we'll get the next statement from the save area in memory instead.
  99.  
  100.     Macro arguments, if    any, are substituted.
  101.  
  102.     LineCount is incremented if    a statement was    successfully read.
  103.  
  104.     If this is the first call of this routine (i.e. LineCount is zero)
  105.     and    HeaderFN is not    a null string, we'll return an INCLUDE statement
  106.     requesting the specified header file, rather than reading the first
  107.     statement from the source file.
  108.  
  109.     The    following fields are set up:
  110.     Line    - statement line image
  111.     Label    - instruction label (without trailing colon)
  112.     OpCode    - instruction mnemonic (converted to upper case)
  113.     SrcOp    - first    (source) operand
  114.     DestOp    - second (destination) operand
  115.     Size    - size from OpCode
  116.     LabLoc    - displacement to start    of instruction label
  117.     OpLoc    - displacement to start    of instruction mnemonic
  118.     SrcLoc    - displacement to start    of source operand
  119.     DestLoc    - displacement to start    of destination operand
  120.     InFNum    - decremented if end of    file is    reached
  121.     InF    - incremented if end of    file is    reached
  122.     LabLine    - set to LineCount if this line    is labeled
  123.             (unless    it's a local label)
  124.                                 */
  125. {
  126.     register int i, c;
  127.     int    eofflag;
  128.     char *x;
  129.  
  130.  
  131.     while (1) {    /* Repeat until    we get something (not end of INCLUDE) */
  132.     Line[0]    = Label[0] = OpCode[0] = SrcOp[0] = DestOp[0] =    '\0';
  133.     LabLoc = OpLoc = SrcLoc    = DestLoc = 0;
  134.     Src.Mode = Dest.Mode = NULL;
  135.     FwdShort = FALSE;
  136.  
  137.     if ((LineCount==0) && (HeaderFN[0])) {    /* Header file */
  138.         strcpy (Line, "        INCLUDE ");  /* Make an INCLUDE stmt. */
  139.         strcat (Line, HeaderFN);
  140.         strcat (Line, "        ;Generated for header file");
  141.         strcpy (OpCode, "INCLUDE"); /* Dummy op code */
  142.         OpLoc = 8;
  143.         strcpy (SrcOp, HeaderFN);    /* Dummy source    operand    */
  144.         SrcLoc = 16;
  145.         LineCount++;
  146.         ErrLim = AddrAdv = InstSize    = nO = nS = nD = nX = 0;
  147.         PrntAddr = FALSE;
  148.         return (FALSE);
  149.     }
  150.  
  151.     if (InF->UPtr != 0) {            /* User    macro input */
  152.         GetMacLine (dummy);
  153.         eofflag = FALSE;
  154.     } else {                /* Normal file input */
  155.         eofflag = GetLine (dummy);
  156.     }
  157.     if ((Line[0] !=    '\0') && (Line[0] != '*') && (Line[0] != ';')) {
  158.         SubArgs (dummy);    /* Substitute macro arguments */
  159.         GetParts (dummy);    /* Break Line into its component parts */
  160.     }
  161.  
  162.     /* ------ If we    have reached the end of    a macro    or ------ */
  163.     /* ------ include file,    return to the calling file ------ */
  164.  
  165.     i = eofflag;                /* End of file */
  166.  
  167.     if (i) {
  168.         if (SkipNest != 0) {
  169.         Error (OpLoc, NoENDC);    /* ENDC    is missing */
  170.         WriteListLine (&List);    /* It's not normally listed */
  171.         SkipNest = 0;
  172.         }
  173.     } else if ((InF->NArg != -1)&&(Dir != Macro)) {    /* Macro exits */
  174.         if (strcmp (OpCode,    "ENDM") == 0) {
  175.         i = TRUE;
  176.         (InF->Line)++;        /* Count ENDM directive    */
  177.         if (SkipNest !=    0) {
  178.             Error (OpLoc, NoENDC);  /* ENDC is missing */
  179.             WriteListLine (&List);  /* It's not normally listed */
  180.             SkipNest = 0;
  181.         }
  182.         } else if (SkipNest    == 0) {
  183.         if (strcmp (OpCode, "MEXIT") == 0) {
  184.             i =    TRUE;
  185.             (InF->Line)++;    /* Count MEXIT directive */
  186.         }
  187.         }
  188.     }
  189.     if (!i)    {            /* Not end of file or macro */
  190.         if (PrevDir    == MacCall) {
  191.         if (strcmp (OpCode, "MACRO") == 0) {
  192.             (InF->Line)++;    /* Count macro header */
  193.             continue;        /*  and    ignore it.    */
  194.         }
  195.         }
  196.         if (SkipNest == 0) {    /* If we're not skipping, */
  197.         break;            /*  we got something.      */
  198.         } else {
  199.         (InF->Line)++;        /* Count skipped lines */
  200.         SkipNest += CountNest (OpCode);    /* Adjust SkipNest */
  201.         continue;
  202.         }
  203.     }
  204.     if (!Pass2 && (IncStart    != 0) && (IncPtr == InF)) {
  205.         SkipLim->Start = IncStart;    /* End of skippable INCLUDE */
  206.         SkipLim->Finish=LineCount;    /* Save    line numbers for pass 2    */
  207.         SkipLim->MCount = MacCount;    /* Save    macro counter too */
  208.         if (SkipLim->Set1 != NULL) {
  209.         SetFixLim--;
  210.         x = (char *) SkipLim + sizeof (struct SkipEnt);
  211.         if (x >    (char *) SetFixLim) {
  212.             SetFixLim++;    /* No room for final entry */
  213.         } else {
  214.             SetFixLim->Sym  = NULL;    /* Null    entry         */
  215.             SetFixLim->Val  = 0;    /*  indicates end of */
  216.             SetFixLim->Hunk = 0;    /*  SET    symbol list. */
  217.         }
  218.         }
  219.         SkipLim++;
  220.         IncStart = 0;
  221.     }
  222.     if (InFNum == 0)
  223.         break;            /* End of source file */
  224.     if (i =    (InF->UPtr == 0)) {
  225.         if (Quiet <    0)
  226.         fprintf    (stderr, "%d\n", InF->Line);
  227.         close (In.fd);        /* Close inner file */
  228.         In.fd = NULL;
  229.     }
  230.     NextFNS    = InF->NPtr;        /* Release space on name stack */
  231.     InFNum--;            /* Return to outer file    */
  232.     InF++;
  233.     if (InFNum < OuterMac)
  234.         OuterMac = 0;        /* End of outer    macro */
  235.     if (InF->UPtr == 0) {
  236.         if (i)
  237.         ShowFile (FALSE);    /* Inner file -> outer file */
  238.         else if (InnrFMac) {
  239.         ShowFile (FALSE);    /* Inner user macro -> file */
  240.         InnrFMac = FALSE;
  241.         }
  242.         if (In.fd == NULL) {
  243.         In.fd =    open (InF->NPtr, 0);
  244.         lseek (In.fd, InF->Pos,    0);
  245.         In.Ptr = In.Lim    = In.Buf;
  246.         }
  247.     } else if (i) {
  248.         InnrFMac = TRUE;    /* Inner file -> outer user macro */
  249.     }
  250.     }
  251.     LineCount++;            /* Bump    line counter */
  252.     (InF->Line)++;
  253.     if ((Label[0] != '\0') && (Label[0] != '\\'))
  254.     if ((Label[0] <    '0') || (Label[0] > '9'))
  255.         LabLine = LineCount;    /* Save    line number of label */
  256.     if (Quiet != 0) {
  257.     i = (Quiet < 0 ? InF->Line : LineCount);
  258.     if ((i % Quiet)    == 0) {        /* Display progress */
  259.         ShowLine (i);
  260.     }
  261.     }
  262.     ErrLim = AddrAdv = InstSize    = nO = nS = nD = nX = 0;
  263.     PrntAddr = FALSE;
  264.  
  265.     if (LineCount == DebugStart)
  266.     fprintf    (stderr, "%d\n", LineCount);
  267.     if ((LineCount >= DebugStart) && (LineCount    <= DebugEnd))
  268.     printf ("%9lx %5d %s\n", AddrCnt, LineCount, Line);
  269.  
  270.     return (eofflag);
  271. }
  272.  
  273.  
  274.  
  275. GetMacLine (dummy) int dummy;
  276. /* Gets    the next stored    user macro line. */
  277. {
  278.     register char *s, *t;
  279.     register struct NameChunk *np;
  280.  
  281.     s =    InF->UPtr;
  282.     if (*s == '\n') {           /* Continue in next chunk */
  283.     np = NameStart;
  284.     while ((s < (char *) np)
  285.     || (s >    ((char *) np + CHUNKSIZE)))
  286.         np = np->Link;    /* Find    the chunk we're in */
  287.     InF->UPtr = (char *) (np->Link)    + sizeof (struct NameChunk *);
  288.     s = InF->UPtr;
  289.     }
  290.     t =    Line;
  291.     while (*t++    = *s++)    /* Copy    InF->UPtr to Line, then    bump InF->UPtr.    */
  292.     ;        /*  (It's faster than doing a strcpy followed   */
  293.     InF->UPtr =    s;    /*  by a strlen    to bump    the pointer.)        */
  294. }
  295.  
  296.  
  297.  
  298. int GetLine (dummy) int    dummy;
  299. /* Gets    the next line from the current input file and leaves it    in Line.
  300.     Returns TRUE if end    of file    has been reached, FALSE    otherwise.    */
  301. {
  302.     register char *s;
  303.     register int c;
  304.     register char *t, *m, *l;
  305.  
  306.     s =    Line;
  307.     t =    In.Ptr;                /* Use a register for speed */
  308.     m =    Line + MAXLINE - 1;        /* Limit of "Line" */
  309.     while (1) {                /* Get Line, expanding tabs */
  310.     if (t >= In.Lim) {
  311.         t =    In.Buf;            /* Re-fill the buffer */
  312.         In.Lim = In.Buf + read (In.fd, In.Buf, BUFFSIZE);
  313.         if (In.Lim == In.Buf) {
  314.         *s = '\0';              /* End of file */
  315.         In.Ptr = t;
  316.         return (s <= Line);    /* Last    line might have    no \n */
  317.         }
  318.     }
  319.     if ((c = *t++) == '\n') {
  320.         break;
  321.     }
  322. #ifdef MSDOS
  323.     if (c == 26) {
  324.         *s = '\0';                  /* Catch MS-DOS EOF char. */
  325.         In.Ptr = t;
  326.         return (s <= Line);
  327.     }
  328.     if ((s < m) && (c != 13)) {    /* Ignore excess */
  329. #else
  330.     if (s <    m) {            /* Ignore excess */
  331. #endif
  332.         if ((c == '\t') && !KeepTabs) {
  333.         l = Line + (((s    - Line)    + 8) & ~7);
  334.         if (l >    m)
  335.             l =    m;        /* Tabbed off the end */
  336.         while (s < l)
  337.             *s++ = ' ';         /* Expand tabs */
  338.         } else {
  339.         *s++ = c;        /* Normal character */
  340.         }
  341.     }
  342.     }
  343.     *s = '\0';                  /* Terminate the string in Line */
  344.     In.Ptr = t;
  345.     return (FALSE);
  346. }
  347.  
  348.  
  349.  
  350. SubArgs    (dummy)    int dummy;
  351. /* Macro argument substitution routine */
  352. {
  353.     int    j;
  354.     register char *s, *t, *x;
  355.     char subline[MAXLINE];
  356.  
  357.     if (InF->NArg == -1)
  358.     return;            /* Not a macro - leave Line alone */
  359.  
  360.     s =    Line;
  361.     t =    subline;
  362.     while (*s) {
  363.     if ((*t++ = *s++) != '\\') {
  364.         continue;
  365.     }
  366.     x = s--;
  367.     t--;
  368.     if (*x == '@') {        /* \@ - substitute macro number */
  369.         x =    t;
  370.         *t++ = '.';
  371.         j =    InF->MCnt % 1000;
  372.         *t++ = j / 100 + '0';
  373.         j =    j % 100;
  374.         *t++ = j / 10 + '0';
  375.         *t++ = j % 10 + '0';
  376.         strcpy (t, s+2);        /* Remainder of    Line */
  377.         strcpy (Line, subline);    /* Replace Line    */
  378.         while (*t != '\\')          /* Check for more substitutions */
  379.         if (*t)
  380.             t++;
  381.         else
  382.             return;        /* All done */
  383.         s =    t - subline + Line;    /* Do the next substitution */
  384.         continue;
  385.     }
  386.     if ((*x    < '0') || (*x > '9')) {
  387.         s++;        /* False alarm - it's a  */
  388.         t++;        /*  named local    variable */
  389.         continue;
  390.     }
  391.  
  392.     s++;
  393.     *t = '\0';
  394.     j = 0;            /* Get argument    index */
  395.     while ((*s >= '0') && (*s <= '9')) {
  396.         j *= 10;
  397.         j += *s++ -    '0';    /* Current digit */
  398.     }
  399.     if (j == 0)
  400.         strcpy (t, MacSize);    /* Macro call size */
  401.     else if    ((j > 0) && (j <= InF->NArg)) {
  402.         x =    InF->NPtr;
  403.         while (j > 0) {        /* Find    argument */
  404.         x += strlen (x)    + 1;
  405.         j--;
  406.         }
  407.         strcpy (t, x);        /* Insert it */
  408.     }
  409.     while (*t)
  410.         t++;            /* Skip    over replacement */
  411.     strcpy (t, s);            /* Remainder of    Line */
  412.     strcpy (Line, subline);        /* Replace Line    */
  413.     while (*t != '\\')              /* Check for more substitutions */
  414.         if (*t)
  415.         t++;
  416.         else
  417.         return;            /* All done */
  418.     s = t -    subline    + Line;        /* Do the next substitution */
  419.     }
  420. }
  421.  
  422.  
  423.  
  424. GetParts (dummy) int dummy;
  425. /* Break up Line into its component parts. */
  426. {
  427.     register char *s, *x;
  428.  
  429.     Size = S0;
  430.     s =    Line;
  431.     if (!isspace (*s)) {
  432.     x = Label;
  433.     while (!isspace    (*s) &&    (*s != ';') && (*s != '\0'))
  434.         *x++ = *s++;        /* Get the label */
  435.     *x-- = '\0';
  436.     while (*x == ':') {
  437.         *x-- = '\0';                /* Strip trailing colon(s) */
  438.         if (x < Label)
  439.         break;
  440.     }
  441.     }
  442.     while (OpLoc == 0) {
  443.     while (isspace (*s))
  444.         s++;            /* Skip    over to    opcode */
  445.     if ((*s    == ';') || (*s == '\0'))
  446.         return;            /* End of statement image */
  447.     OpLoc =    s - Line;
  448.     x = OpCode;
  449.     while (!isspace    (*s) &&    (*s != ';') && (*s != '\0'))
  450.         *x++ = *s++;        /* Get the opcode */
  451.     *x-- = '\0';
  452.     if (*x == ':') {                /* It's actually a label */
  453.         if (Label[0]) {
  454.         Error (OpLoc, MultLab);    /* Multiple labels */
  455.         } else {
  456.         while ((x >= OpCode) &&    (*x == ':'))
  457.             *x-- = '\0';
  458.         strcpy (Label, OpCode);    /* Get the label */
  459.         }
  460.         OpLoc = 0;            /* Try again for opcode    */
  461.         OpCode[0] =    '\0';
  462.     }
  463.     }
  464.     for    (x = OpCode; *x; x++)        /* Convert OpCode */
  465.     *x = toupper(*x);        /*  to upper case */
  466.     x -= 2;
  467.     if ((x < OpCode) ||    (*x != '.'))    /* If no explicit size is given */
  468.     Size = Word;            /*  default to Word (16    bits).    */
  469.     else {
  470.     *x++ = '\0';                    /* Chop off size extension */
  471.     switch (*x) {
  472.     case 'B':                       /* Byte */
  473.     case 'S':                       /* Short Branch */
  474.         Size = Byte;
  475.         break;
  476.     case 'L':                       /* Long */
  477.         Size = Long;
  478.         break;
  479.     default:
  480.         Size = Word;        /* Default to Word */
  481.         break;
  482.     }
  483.     }
  484.     while (isspace(*s))
  485.     s++;                /* Skip    over to    operands */
  486.     if ((*s == ';') || (*s == '\0'))
  487.     return;                /* There are no    operands */
  488.     SrcLoc = s - Line;
  489.     s =    GetField (s, SrcOp);        /* Op1 (source)    */
  490.     if (*s == ',')
  491.     s++;
  492.     if (!isspace (*s) && (*s !=    '\0') && (*s != ';')) {
  493.     DestLoc    = s - Line;
  494.     s = GetField (s, DestOp);    /* Op2 (destination) */
  495.     }
  496. }
  497.  
  498.  
  499.  
  500. ShowFile (newline) int newline;
  501. /* Shows the current file name if we're displaying all input modules.
  502.     If "newline" is TRUE, go to a new line before displaying the name. */
  503. {
  504.     if ((Quiet < 0) && (InF->UPtr == 0))
  505.     if (newline)
  506.         fprintf (stderr, "\n%s line ", InF->NPtr);
  507.     else
  508.         fprintf (stderr, "%s line ", InF->NPtr);
  509. }
  510.  
  511.  
  512.  
  513. ShowLine (i) register int i;
  514. /* Shows the current line number and backs up over it. */
  515. {
  516.     if (i >= 10000)
  517.     fprintf    (stderr, "%5d\b\b\b\b\b", i);
  518.     else if (i >= 1000)
  519.     fprintf    (stderr, "%4d\b\b\b\b", i);
  520.     else if (i >= 100)
  521.     fprintf    (stderr, "%3d\b\b\b", i);
  522.     else if (i >= 10)
  523.     fprintf    (stderr, "%2d\b\b", i);
  524.     else
  525.     fprintf    (stderr, "%1d\b", i);
  526.     fflush (stderr);        /* Make    sure it    gets out */
  527. }
  528.  
  529.  
  530.  
  531. char *GetField (s, d) register char *s,    *d;
  532. /* Gets    a field    from "s", returns result in "d".
  533.     Stops on the first comma, semicolon, or white space    not
  534.     enclosed within    apostrophes or parentheses.
  535.     Returns stopping location.
  536.     If already at end of "s", "d" is set to null string. */
  537. {
  538.     register char c;
  539.     register int parncnt, instring;
  540.  
  541.     instring = FALSE;
  542.     parncnt = 0;
  543.  
  544.     while (c = *s) {
  545.     if (instring) {
  546.         *d++ = c;
  547.     } else {
  548.         if (isspace(c) || (c == ';'))
  549.         break;
  550.         else if ((c    == ',') && (parncnt == 0))
  551.         break;
  552.         else {
  553.         *d++ = c;
  554.         if (c == '(')
  555.             parncnt++;
  556.         else if    (c == ')')
  557.             parncnt--;
  558.         }
  559.     }
  560.     if (c == '\'')
  561.         instring = !instring;
  562.     s++;
  563.     }
  564.     *d = '\0';
  565.     return (s);
  566. }
  567.  
  568.  
  569.  
  570. long GetValue (operand,    loc) char *operand; int    loc;
  571. /* Determines value of expression */
  572. /* Hunk2 is set    to hunk    number of result (ABSHUNK if absolute).
  573.    If the expression consists solely of    self-defining terms,
  574.     DefLine2 is set    to zero.  Otherwise, DefLine2 is set
  575.     to the highest statement number    in which any symbol in
  576.     the expression was defined.  If    the expression contains
  577.     any undefined symbols, DefLine2    is set to NODEF.
  578.     The    following code is based    on a regular-to-Polish expression
  579.     converter described in "A Guide to FORTRAN IV Programming"
  580.     by Daniel D. McCracken (John Wiley & Sons, Inc.    1965,
  581.     3rd printing August 1968).  However, rather than generating
  582.     the entire Polish expression, this routine will    evaluate
  583.     and combine two    terms as soon as an operator of    lower
  584.     precedence is encountered.                */
  585. {
  586.     register char *o, *s;
  587.     char tempop[MAXLINE];
  588.     int     oloc, parncnt,    nextprec, instring;
  589.     long templong;
  590.     struct TermStack *origterm;
  591.  
  592.     instring = (unsigned int) '~';
  593.     OpPrec[instring] = 9;    /* Fudge IsOperator for    speed */
  594.     nextprec = TRUE;        /* Assume there's only a single term */
  595.     for    (o = operand; *o; o++) {
  596.     if (IsOperator (o)) {
  597.         nextprec = FALSE;    /* It's not a single term */
  598.         break;
  599.     }
  600.     }
  601.     instring = (unsigned int) '~';
  602.     OpPrec[instring] = '\0';    /* Restore IsOperator */
  603.     if (nextprec)
  604.     return(CalcValue(operand,loc));    /* Short cut for single    term */
  605.  
  606.     Hunk2 = ABSHUNK;
  607.     parncnt = DefLine2 = 0;
  608.     o =    (char *) (((long) NextFNS + 3L)    & ~3L);
  609.     origterm = Term = (struct TermStack    *) o;    /* Term    stack */
  610.     Ops    = (struct OpStack *) InF;        /* Operator stack */
  611.     Ops--;
  612.     ParseSpace (0);
  613.     Ops->chr = ' ';     /* Prime the operator stack */
  614.     Ops->prec =    -1;
  615.     if ((char *) Ops < Low2)
  616.     Low2 = (char *)    Ops;
  617.  
  618.     /* Get all tokens.
  619.     Terms are evaluated, and operator precedence is    determined.
  620.     Left and right parentheses are given a precedence of
  621.         1 and 2 respectively.
  622.     Binary operators are given precedence values starting at 3.
  623.     Unary plus is ignored.
  624.     Unary minus is converted to zero minus the remainder of
  625.         of the expression -    its precedence is set to 9 to
  626.         ensure that    the simulated unary operator is    evaluated
  627.         before the remainder of the    expression.
  628.     Logical    not (~), being another unary operator, is converted
  629.         to -1 exclusive-ORed with the remainder of the expression.
  630.         Its    precedence is also set to 9.                */
  631.  
  632.     o =    operand;            /* Current position in operand */
  633.  
  634.     while (1) {
  635.     while (*o == '(') {             /* Left parenthesis */
  636.         Ops--;
  637.         ParseSpace (0);
  638.         Ops->chr  =    '(';
  639.         Ops->prec =    1;
  640.         if ((char *) Ops < Low2)
  641.         Low2 = (char *)    Ops;
  642.         parncnt++;
  643.         o++;
  644.     }
  645.     if ((*o    == '+') || (*o == '-') || (*o == '~')) {    /* Unary op */
  646.         if (*o != '+') {    /* Ignore unary plus */
  647.         Ops--;
  648.         ParseSpace (sizeof (struct TermStack));
  649.         Term->value   =    (*o == '-') ? 0 : -1;   /* Dummy value */
  650.         Term->hunk    =    ABSHUNK;
  651.         Term->oploc   =    loc + (o - operand);
  652.         Term->defline =    0;
  653.         Term++;
  654.         if ((char *) Term > High2)
  655.             High2 = (char *) Term;
  656.         Ops->chr  = *o;        /* Now get the operator    itself */
  657.         Ops->prec = 9;        /* Do it ASAP */
  658.         if ((char *) Ops < Low2)
  659.             Low2 = (char *) Ops;
  660.         }
  661.         o++;
  662.         if (*o == '(')
  663.         continue;    /* Inner parenthesized expression */
  664.     }
  665.     oloc = loc + (o    - operand);
  666.  
  667.     s = tempop;                /* Get a term */
  668.     if (*o == '*') {        /* It's a location counter reference, */
  669.         *s++ = *o++;    /*   not a multiplication operator!   */
  670.     } else {
  671.         if (IsOperator (o) || (*o == '\0')) {
  672.         Error (oloc, OperErr);    /* Unexpected operator or no terms */
  673.         return (0L);
  674.         }
  675.         instring = (unsigned int) '~';
  676.         OpPrec[instring] = 9;    /* Fudge IsOperator for    speed */
  677.         instring = FALSE;
  678.         while (*o) {
  679.         if (*o == '\'')
  680.             instring=!instring;    /* String delimiter */
  681.         if (!instring && IsOperator (o))
  682.             break;        /* Found an operator - stop */
  683.         *s++ = *o++;        /* Get a character */
  684.         }
  685.         instring = (unsigned int) '~';
  686.         OpPrec[instring] = '\0';    /* Restore IsOperator */
  687.     }
  688.     *s = '\0';
  689.     ParseSpace (sizeof (struct TermStack));
  690.     Term->value   =    CalcValue (tempop, oloc);
  691.     Term->hunk    =    Hunk2;
  692.     Term->oploc   =    oloc;
  693.     Term->defline =    DefLine2;
  694.     Term++;
  695.     if ((char *) Term > High2)
  696.         High2 = (char *) Term;
  697.     Hunk2 =    DefLine2 = 0;
  698.  
  699.     while (*o == ')') {                     /* Right parenthesis */
  700.         if (parncnt    == 0) {
  701.         Error ((int) (loc + (o - operand)), OperErr);
  702.         return (0L);
  703.         }
  704.         CondCalc (2);        /* Unstack what    we can */
  705.         if (Ops->chr == '(')
  706.         Ops++;            /* Drop    paired parentheses */
  707.         else {
  708.         Ops--;
  709.         ParseSpace (0);
  710.         Ops->chr  = ')';        /* Stack parenthesis for now */
  711.         Ops->prec = 2;
  712.         if ((char *) Ops < Low2)
  713.             Low2 = (char *) Ops;
  714.         }
  715.         parncnt--;
  716.         o++;
  717.     }
  718.     if (*o)    {
  719.         nextprec = IsOperator (o);
  720.         if ((nextprec == 0)    || (*o == '(')) {
  721.         Error ((int) (loc + (o - operand)), OperErr);
  722.         return (0L);        /* Expected an operator    */
  723.         }
  724.         CondCalc (nextprec);    /* Unstack what    we can */
  725.         Ops--;
  726.         ParseSpace (0);
  727.         Ops->chr  =    *o;        /* Stack the next operator */
  728.         Ops->prec =    nextprec;
  729.         if ((char *) Ops < Low2)
  730.         Low2 = (char *)    Ops;
  731.         if ((*o == '<') || (*o == '>'))
  732.         o++;    /* Skip    over two-character operator */
  733.         o++;
  734.     } else {
  735.         if (parncnt) {
  736.         Error ((int) (loc + (o - operand)), OperErr);
  737.         return (0L);    /* Too many left parentheses */
  738.         }
  739.         CondCalc (0);        /* Unstack what's left */
  740.         if (--Term != origterm)    /* Should be only one term left    */
  741.         Error (Term->oploc, OperErr);        /* Parser bug? */
  742.         Hunk2    = Term->hunk;
  743.         DefLine2 = Term->defline;
  744.         return (Term->value);    /* Final value */
  745.     }
  746.     }
  747. }
  748.  
  749.  
  750.  
  751. CondCalc (newprec) int newprec;
  752. /* As long as the top operator on the operator stack has a precedence
  753.     greater than or equal to the contents of "newprec", this routine
  754.     will pop the two top terms from the    term stack, combine them
  755.     according to the operator on the top of the    operator stack (which
  756.     is also popped), and push the result back onto the term stack. */
  757. {
  758.     while (Ops->prec >=    newprec) {    /* Unstack an operator */
  759.     Term -=    2;
  760.     if (Ops->chr ==    '+') {          /* Relocatable addition */
  761.         if (Term->hunk == ABSHUNK)
  762.         Term->hunk = (Term+1)->hunk;    /* A+R */
  763.         else if ((Term+1)->hunk != ABSHUNK)    {
  764.         Error ((Term+1)->oploc,    RelErr);    /* R+R - error */
  765.         Term->hunk = ABSHUNK;        /* Make    it absolute */
  766.         }
  767.     } else if (Ops->chr == '-') {           /* Subtraction */
  768.         if (Term->hunk == (Term+1)->hunk)
  769.         Term->hunk = ABSHUNK;        /* R-R - absolute */
  770.         else if ((Term+1)->hunk != ABSHUNK)    {   /* R-R across hunks    */
  771.         Error ((Term+1)->oploc,    RelErr);    /*    is an error -    */
  772.         Term->hunk = ABSHUNK;            /* make it absolute    */
  773.         }
  774.     } else if ((Term->hunk != ABSHUNK)
  775.     || ((Term+1)->hunk != ABSHUNK))    {
  776.         Error (Term->oploc,RelErr);        /* All other operations    */
  777.         Term->hunk = ABSHUNK;        /*   must be absolute    */
  778.     }
  779.     if ((Term+1)->defline >    Term->defline)    /* Definition */
  780.         Term->defline = (Term+1)->defline;    /*  line nos. */
  781.  
  782.     switch (Ops->chr) {        /* Perform the operation */
  783.     case '+':
  784.         Term->value    += (Term+1)->value;
  785.         break;
  786.     case '-':
  787.         Term->value    -= (Term+1)->value;
  788.         break;
  789.     case '*':
  790.         Term->value    *= (Term+1)->value;
  791.         break;
  792.     case '/':
  793.         if ((Term+1)->value)
  794.         Term->value /= (Term+1)->value;
  795.         else
  796.         Term->value = 0;     /*    Don't divide by zero */
  797.         break;
  798.     case '&':
  799.         Term->value    &= (Term+1)->value;
  800.         break;
  801.     case '!':
  802.     case '|':
  803.         Term->value    |= (Term+1)->value;
  804.         break;
  805.     case '<':
  806.         Term->value    <<= (Term+1)->value;
  807.         break;
  808.     case '>':
  809.         Term->value    >>= (Term+1)->value;
  810.         break;
  811.     case '~':
  812.         Term->value    ^= (Term+1)->value;
  813.         break;
  814.     default:
  815.         Error (Term->oploc,    OperErr);    /* Parser bug? */
  816.         break;
  817.     }
  818.     Term++;
  819.     Ops++;
  820.     }
  821. }
  822.  
  823.  
  824.  
  825. int IsOperator (o) register char *o;
  826. /* Tests whether "o" points to a valid operator or parenthesis.
  827.     Returns the    precedence of the operator, or 0 if it isn't one. */
  828. {
  829.     register unsigned int i;
  830.  
  831.     i =    (unsigned int) *o;
  832.     i =    (unsigned int) OpPrec[i];
  833.     if (i != 6)
  834.     return ((int) i);
  835.     if (*(o+1) == *o)
  836.     return ((int) i);    /* << or >> */
  837.     else
  838.     return (0);        /* False alarm */
  839. }
  840.  
  841.  
  842.  
  843. long CalcValue (operand, loc) char *operand; int loc;
  844. /* Evaluates a single term (called by GetValue).
  845.     Hunk2 receives relative hunk number    (ABSHUNK if absolute).
  846.     If the value is a symbol, DefLine2 is set to the line number
  847.     where it was defined, or NODEF if it is    undefined.
  848.     For self-defining terms, DefLine2 is set to zero.    */
  849. {
  850.     register long result;    /* Result is calculated    here */
  851.     register char *s, *numstart;
  852.     register int  radix;
  853.     int     neg, overflow;
  854.     char maxdig;    /* Highest valid digit in current radix    */
  855.     char delim;        /* String delimiter (' or ") */
  856.  
  857.     Hunk2 = ABSHUNK;            /* Assume value    is absolute */
  858.     DefLine2 = 0;            /* and self-defining */
  859.     result = 0;
  860.     overflow = FALSE;
  861.     if (neg = (*operand    == '-'))
  862.     numstart = operand + 1;        /* Negative value */
  863.     else
  864.     numstart = operand;        /* Positive value */
  865.  
  866.     if ((*numstart >= '0') && (*numstart <= '9')) {
  867.     radix =    10;        /* Decimal number */
  868.     maxdig = '9';
  869.     } else if (*numstart == '$') {
  870.     radix =    16;        /* Hexadecimal number */
  871.     maxdig = '9';
  872.     } else if (*numstart == '@') {
  873.     radix =    8;        /* Octal number    */
  874.     maxdig = '7';
  875.     } else if (*numstart == '%') {
  876.     radix =    2;        /* Binary number */
  877.     maxdig = '1';
  878.     } else
  879.     radix =    0;        /* Not a number    */
  880.  
  881.     if (radix != 0) {            /* Some    sort of    number */
  882.     result = 0;
  883.     if (radix != 10)
  884.         numstart++;            /* Allow for type character */
  885.     for (s = numstart; *s; s++) {
  886.         result *= radix;
  887.         if ((*s >= '0') && (*s <= maxdig)) {
  888.         result += (*s -    '0');
  889.         } else if (radix ==    16) {
  890.         if ((*s    >= 'A') && (*s <= 'F'))
  891.             result += (*s - 'A' + 10);
  892.         else if    ((*s >=    'a') && (*s <= 'f'))
  893.             result += (*s - 'a' + 10);
  894.         else
  895.             Error (loc + s - operand, OperErr);
  896.         } else if (!neg && (radix==10) && (*s=='$') && (*(s+1)=='\0')) {
  897.         if (ReadSymTab (operand)) {    /* Look    up local label */
  898.             result = Value;        /* Get its value */
  899.             AddRef (LineCount);        /* Add reference */
  900.             if (Sym->Flags & 0x60)
  901.             Error (loc, AddrErr);    /* Can't use a register equate */
  902.         } else {
  903.             Error (loc,    Undef);        /* Undefined */
  904.         }
  905.         break;
  906.         } else {
  907.         Error (loc + s - operand, OperErr);
  908.         }
  909.     }
  910.     } else if ((*operand == '\'') || (*operand == '"')) {
  911.     delim =    *operand;        /* Character value delimiter */
  912.     result = 0;
  913.     s = operand + 1;
  914.     while (1) {
  915.         if (*s == '\0') {
  916.         Error (loc+s-operand,NoStrEnd);    /* End is missing */
  917.         result = 0;
  918.         break;
  919.         }
  920.         if (*s == delim) {        /* End of string? */
  921.         if (*(++s) != delim)    /* Check next character    */
  922.             break;        /* End of string */
  923.         }        /* Otherwise it's an apostrophe in the string */
  924.         if ((result    & 0xFF000000L) && !overflow) {
  925.         Error (loc+s-operand, SizeErr);    /* Result overflowed */
  926.         overflow = TRUE;
  927.         result = 0;
  928.         }
  929.         if (!overflow)
  930.         result = (result << 8) + *s;
  931.         s++;
  932.     }
  933.     } else if ((*operand == '*') && (*(operand+1) == '\0')) {
  934.     result = AddrCnt;    /* Value of location counter */
  935.     Hunk2 =    CurrHunk;    /* Use current section's hunk number */
  936.     } else {
  937.     if (ReadSymTab (operand)) {    /* Look    up symbol */
  938.         result = Value;        /* Get its value */
  939.         AddRef (LineCount);        /* Add reference */
  940.         if (Sym->Flags & 0x60)
  941.         Error (loc, AddrErr);    /* Can't use a register equate */
  942.     } else if (strcmp (operand, "NARG") == 0) {
  943.         result = InF->NArg;        /* Number of arguments */
  944.         if (result == -1)
  945.         result = 0;        /* No arguments    outside    macros */
  946.     } else
  947.         Error (loc,    Undef);        /* Undefined */
  948.     }
  949.     if (neg) {
  950.     result = -result;        /* Negative value */
  951.     if (Hunk2 != ABSHUNK)
  952.         Error (loc,    RelErr);    /* Must    be absolute */
  953.     }
  954.     return (result);
  955. }
  956.  
  957.  
  958.  
  959. AddSymTab (label, value, hunk, line, flags)
  960. char label[];
  961. long value, hunk;
  962. int line, flags;
  963. /* Inserts a new entry to the symbol table and increments NumSyms.
  964.     "Sym" will be set to point to the new entry.
  965.     If the label is a local label (i.e.    the first character is
  966.     a numeric digit or a backslash), the current contents of LabLine
  967.     will be converted to characters and    appended to the    label before
  968.     it is added.  If the first character of the    label is a backslash
  969.     (i.e. a named local    variable) a dollar sign    will be    appended
  970.     to the label ahead of the value of LabLine.            */
  971. {
  972.     char wlab[MAXLINE],    wnum[6];
  973.     register struct SymTab *chainsym, **hashindex;
  974.  
  975.     strcpy (wlab, label);
  976.     if (((label[0] >= '0') && (label[0] <= '9')) || (label[0] == '\\')) {
  977.     if (label[0] ==    '\\')
  978.         strcat (wlab, "$");
  979.     sprintf    (wnum, "%d", LabLine);  /* If it's a local label, */
  980.     strcat (wlab, wnum);        /*    append LabLine      */
  981.     }
  982.  
  983.     Sym    = SymLim;            /* Pointer to new entry    */
  984.     SymLim++;                /* Bump    limit pointer */
  985.     if (((char *) SymLim - (char *) SymCurr) > CHUNKSIZE) {
  986.     Sym = (struct SymTab *)    malloc ((unsigned) CHUNKSIZE);
  987.     if (Sym    == NULL)
  988.         quit_cleanup ("Out of memory!\n");
  989.     SymCurr->Link =    Sym;        /* Link    from previous chunk */
  990.     SymCurr    = Sym;            /* Make    the new    chunk current */
  991.     SymCurr->Link =    NULL;        /* Clear forward pointer */
  992.     Sym++;                /* Skip    over pointer entry */
  993.     SymLim = Sym;            /* New table limit */
  994.     SymLim++;            /* Bump    it */
  995.     }
  996.     Sym->Link =    NULL;        /* Clear hash chain link */
  997.     Sym->Nam = AddName(wlab,0);    /* Pointer to symbol */
  998.     Sym->Val   = value;        /* Value */
  999.     Sym->Hunk  = hunk;        /* Hunk    number */
  1000.     Sym->Defn  = line;        /* Statement number */
  1001.     Sym->Flags = flags;        /* Flags */
  1002.     Sym->Ref1  = NULL;        /* Reference pointer */
  1003.     NumSyms++;            /* Count symbols */
  1004.  
  1005.     hashindex =    HashIt (wlab);    /* Get hash index */
  1006.     if (*hashindex == NULL) {
  1007.     *hashindex = Sym;    /* First entry in this hash chain */
  1008.     return;
  1009.     }
  1010.     chainsym = *hashindex;
  1011.     while (chainsym->Link != NULL)
  1012.     chainsym = chainsym->Link;    /* Scan    for end    of hash    chain */
  1013.     chainsym->Link = Sym;        /* Insert new entry at the end */
  1014. }
  1015.  
  1016.  
  1017.  
  1018. char *AddName (name, macflag) char *name; int macflag;
  1019. /* Adds    the name in "name" to the name heap.
  1020.     "macflag" can take any of the following values:
  1021.     0 - normal name
  1022.     1 - first line of macro    text - there must be room on the
  1023.         name heap for at least one character following "name".
  1024.     2 - additional lines of    macro text - make sure there's room
  1025.         for an addition    character (as in 1 above).  Also,
  1026.         if it is necessary to allocate a new chunk of memory,
  1027.         first place a newline character    after the last entry
  1028.         in the old chunk.  This    acts as    a flag when retrieving
  1029.         lines of macro text during an expansion.
  1030.     This function returns a pointer to "name" on the name heap. */
  1031. {
  1032.     register char *s, *t;
  1033.     struct NameChunk *n;
  1034.  
  1035.     s =    NameLim    + strlen(name) + 1;    /* The new entry ends here */
  1036.     if (macflag)            /* If this is a    macro, */
  1037.     s++;                /*  allow for continuation flag. */
  1038.     if ((s - (char *) NameCurr)    > CHUNKSIZE) {    /* If this chunk is full */
  1039.     if (macflag == 2)        /* If this is more macro text */
  1040.         *NameLim = '\n';            /*  insert continuation flag. */
  1041.     n = (struct NameChunk *) malloc    ((unsigned) CHUNKSIZE);
  1042.     if (n == NULL)
  1043.         quit_cleanup ("Out of memory!\n");
  1044.     NameCurr->Link = n;        /* Link    from previous chunk */
  1045.     NameCurr = n;            /* Make    the new    chunk current */
  1046.     NameCurr->Link = NULL;        /* Clear forward pointer */
  1047.     s = (char *) NameCurr;
  1048.     NameLim    = s + sizeof (char *);    /* Skip    over pointer entry */
  1049.     }
  1050.     s =    NameLim;
  1051.     t =    name;
  1052.     while ((*s++ = *t++) != '\0')       /* Store name */
  1053.     ;
  1054.     t =    NameLim;
  1055.     NameLim = s;            /* Update table    limit */
  1056.     return (t);
  1057. }
  1058.  
  1059.  
  1060.  
  1061. int ReadSymTab (label) char label[];
  1062. /* Searches the    symbol table for the given label.
  1063.    If not found, points    Sym to NULL and    returns    FALSE.
  1064.    If found, points Sym    to the proper table entry,
  1065.      and sets up the following fields:
  1066.     Value     - value of symbol
  1067.     Hunk2     - hunk    number in which    symbol resides
  1068.            ABSHUNK if value is absolute
  1069.            ones    complement of symbol table index if external
  1070.     DefLine2 - statement number in which symbol was    defined
  1071.             (NODEF if undefined )
  1072.     If the label is a local label (i.e.    the first character is
  1073.     numeric), the current contents of LabLine will be converted
  1074.     to characters and appended to the label before it is searched.
  1075.     (This matches the way AddSymTab added the label to the table.)
  1076.     If the first character of the label    is a backslash (i.e. a
  1077.     named local    variable) a dollar sign    will be    appended to the
  1078.     label ahead    of the value of    LabLine.            */
  1079. {
  1080.     char wlab[MAXLINE],    wnum[6];
  1081.     register struct SymTab **hashindex;
  1082.  
  1083.     strcpy (wlab, label);
  1084.     if (((label[0] >= '0') && (label[0] <= '9')) || (label[0] == '\\')) {
  1085.     if (label[0] ==    '\\')
  1086.         strcat (wlab, "$");
  1087.     sprintf    (wnum, "%d", LabLine);  /* If it's a local label, */
  1088.     strcat (wlab, wnum);        /*    append LabLine      */
  1089.     }
  1090.     hashindex =    HashIt (wlab);    /* Get hash index */
  1091.     Sym    = *hashindex;
  1092.     while (Sym != NULL)    {
  1093.     if (strcmp (Sym->Nam, wlab) == 0) {
  1094.         Value = Sym->Val;        /* Found it */
  1095.         Hunk2 = Sym->Hunk;
  1096.         if (!(Sym->Flags & 9))
  1097.         Hunk2 &= 0x0000FFFFL;    /* Isolate hunk    number */
  1098.         DefLine2 = Sym->Defn;
  1099.         return (TRUE);
  1100.     }
  1101.     Sym = Sym->Link;
  1102.     }
  1103.     Value = 0;            /* Didn't find it - */
  1104.     Hunk2 = ABSHUNK;        /* set value to    absolute zero */
  1105.     DefLine2 = NODEF;
  1106.     return (FALSE);
  1107. }
  1108.  
  1109.  
  1110.  
  1111. struct SymTab **HashIt (label) register    char *label;
  1112. /* Returns a pointer to    the hash table entry corresponding to "label" */
  1113. {
  1114.     register unsigned i;
  1115.  
  1116.     i =    0;
  1117.     while (*label) {
  1118.     i = ((i    << 3) -    i + *label++) %    HashSize;
  1119.     }
  1120.     return (Hash + i);
  1121. }
  1122.  
  1123.  
  1124.  
  1125. struct SymTab *NextSym (sym) register struct SymTab *sym;
  1126. /* Returns a pointer to    the next symbol    table entry in memory,
  1127.     or NULL if there are no more symbol    table entries.
  1128.     SymChunk and SymChLim must be properly set up.    */
  1129. {
  1130.     register struct SymTab *sp;
  1131.  
  1132.     if (sym == NULL)
  1133.     return (NULL);        /* We're nowhere - get out */
  1134.     sym++;
  1135.     sp = sym;
  1136.     sp++;
  1137.     if ((SymLim    >= SymChunk) &&    (SymLim    <= SymChLim))
  1138.     if (sym    >= SymLim)
  1139.         return (NULL);    /* End of symbol table entries */
  1140.     if (sp > SymChLim) {
  1141.     if ((SymChunk =    SymChunk->Link)    == NULL)
  1142.         return (NULL);    /* End of the last chunk */
  1143.     SymChLim = (struct SymTab *) ((char *) SymChunk    + CHUNKSIZE);
  1144.     sym = SymChunk;
  1145.     sym++;            /* First entry in the new chunk    */
  1146.     }
  1147.     return (sym);
  1148. }
  1149.  
  1150.  
  1151.  
  1152. AddRef (linenum) int linenum;
  1153. /* Adds    "linenum" to the list of references
  1154.     for    the symbol pointed to by Sym.        */
  1155. {
  1156.     register int i;
  1157.     register struct Ref    *ref, *prevref;
  1158.  
  1159.     if (!Pass2)
  1160.     return;            /* Pass    2 only!    */
  1161.     if (!XrefList)
  1162.     return;            /* No cross-reference */
  1163.     prevref = NULL;
  1164.     ref    = Sym->Ref1;
  1165.     while (ref)    {        /* Chase pointers */
  1166.     for (i = 0; i <    MAXREF;    i++) {        /* Scan reference entry */
  1167.         if (ref->RefNum[i] == 0) {        /*    for an empty slot   */
  1168.         ref->RefNum[i] = linenum;   /* Insert new line number */
  1169.         return;
  1170.         }
  1171.     }
  1172.     prevref    = ref;            /* Remember where we were */
  1173.     ref = ref->NextRef;        /* Link    to the next entry */
  1174.     }
  1175.     ref    = RefLim;            /* Pointer to new entry    */
  1176.     RefLim++;                /* Bump    limit pointer */
  1177.     if (((char *) RefLim - (char *) SymCurr) > CHUNKSIZE) {
  1178.     ref = (struct Ref *) malloc ((unsigned)    CHUNKSIZE);
  1179.     if (ref    == NULL) {
  1180.         fprintf (stderr, "     \nOut of memory");
  1181.         fprintf (stderr, " - cross-reference disabled.\n");
  1182.         XrefList = FALSE;
  1183.         return;
  1184.     }
  1185.     SymCurr->Link =    (struct    SymTab *) ref;    /* Link    from prev. chunk */
  1186.     SymCurr    = (struct SymTab *)ref;    /* Make    the new    chunk current */
  1187.     SymCurr->Link =    NULL;        /* Clear forward pointer */
  1188.     ref++;                /* Skip    over pointer entry */
  1189.     RefLim = ref;            /* New table limit */
  1190.     RefLim++;            /* Bump    it */
  1191.     }
  1192.     ref->NextRef = NULL;        /* Pointer to next entry */
  1193.     ref->RefNum[0] = linenum;        /* First reference in new entry    */
  1194.     for    (i = 1;    i < MAXREF; i++)
  1195.     ref->RefNum[i] = 0;        /* Clear remaining slots */
  1196.     if (prevref    == NULL)
  1197.     Sym->Ref1 = ref;        /* Link    to first entry */
  1198.     else
  1199.     prevref->NextRef = ref;        /* Link    to next    entry */
  1200. }
  1201.  
  1202.  
  1203.  
  1204. int CountNest (s) register char    *s;
  1205. /* Returns 1 if    "s" contains any IF statement (i.e. IFEQ, etc.).
  1206.    Returns -1 if "s" contains "ENDC" or "ENDIF".
  1207.    Returns 0 in    all other cases.        */
  1208. {
  1209.    if (strcmp (s, "ENDC") == 0)
  1210.        return (-1);
  1211.    else    if (strcmp (s, "ENDIF") == 0)
  1212.        return (-1);
  1213.    else    if (*s++ != 'I')
  1214.     return (0);
  1215.    else    if (*s++ != 'F')
  1216.     return (0);
  1217.    else    if (strcmp (s, "EQ") == 0)
  1218.        return (1);
  1219.    else    if (strcmp (s, "NE") == 0)
  1220.        return (1);
  1221.    else    if (strcmp (s, "GT") == 0)
  1222.        return (1);
  1223.    else    if (strcmp (s, "GE") == 0)
  1224.        return (1);
  1225.    else    if (strcmp (s, "LT") == 0)
  1226.        return (1);
  1227.    else    if (strcmp (s, "LE") == 0)
  1228.        return (1);
  1229.    else    if (strcmp (s, "C" ) == 0)
  1230.        return (1);
  1231.    else    if (strcmp (s, "NC") == 0)
  1232.        return (1);
  1233.    else    if (strcmp (s, "D" ) == 0)
  1234.        return (1);
  1235.    else    if (strcmp (s, "ND") == 0)
  1236.        return (1);
  1237.    else
  1238.        return (0);
  1239. }
  1240.  
  1241.  
  1242.  
  1243. Heap2Space (n) int n;
  1244. /* Die if we can't find "n" bytes on the secondary heap. */
  1245. {
  1246.     if ((NextFNS + n) >    (char *) InF) {
  1247.     printf ("\n%5d   %s\n", LineCount, Line);
  1248.     quit_cleanup ("Secondary heap overflow - assembly terminated.\n");
  1249.     }
  1250. }
  1251.  
  1252.  
  1253.  
  1254. ParseSpace (n) int n;
  1255. /* Special version of Heap2Space for the expression parser */
  1256. {
  1257.     if (((char *) Term + n) > (char *) Ops) {
  1258.     printf ("\n%5d   %s\n", LineCount, Line);
  1259.     quit_cleanup ("Secondary heap overflow - assembly terminated.\n");
  1260.     }
  1261. }
  1262.