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

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