Revision 4e5d304eb7cd5589b924ffb8b423b6f15511b35d authored by Ron Burkey on 20 October 2018, 17:47:00 UTC, committed by Ron Burkey on 20 October 2018, 17:47:00 UTC
the recently-added documents about YUL, was transcribed.  Because the
original program contained a deliberate error in YUL (as well as some
constructs that have unintentionally become errors in yaYUL), I've
provided it in two forms:  TRIVIUM (which matches the original scan,
to the extent feasible) and TRIVIUM-repaired (which has the deliberate
and unintentional errors fixed, but otherwise retains the identical
functionality of the original).
1 parent c6c292e
Raw File
yaLEMAP.c
/*
 * Copyright 2005,2009,2016,2017 Ronald S. Burkey <info@sandroid.org>
 * This file is part of yaAGC.
 *
 * yaAGC is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * yaAGC is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with yaAGC; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Filename:	yaLEMAP.c
 * Purpose:	Cross-assembler for Abort Guidance System
 * 		(AGS) source code.
 * Compiler:	GNU gcc.
 * Reference:	http://www.ibibio.org/apollo
 * Mods:	2005-01-11 RSB.	Began.  Some machinery adapted
 * 				from binLEMAP.c.
 * 		2005-01-13 RSB	Seemingly working, for the sample code.
 * 				I know that the flight code has a few
 * 				features I haven't accounted for yet.
 * 		2005-01-18 RSB	Printout columns hopefully aligned better.
 * 				Fixed OCT, I hope. Changed checksums
 * 				to allow multiple checksum regions.
 * 		2005-01-19 RSB	The binLEMAP-compatible file
 * 				yaLEMAP.binsource is now output.
 * 				This is to aid proofing by feeding
 * 				that file back into a text-to-speech
 * 				converter.
 * 		2005-01-24 RSB	Fixed some of the field alignments in the
 * 				output listing file.  Also, got rid of
 * 				leading zeroes in the output binsource
 * 				file.
 * 		2005-04-30 RSB	PrintSymbolsToFile has been renamed
 * 				PrintSymbolsToFileL in order to avoid
 * 				some build-time warnings..
 * 		2005-08-02 JMS  Write out the symbol table to a file.
 * 				This format of the symbol table is the
 * 				same as yaYUL.
 * 		2009-03-17 RSB	Make sure that no .bin or .symtab file
 * 				is produced when there is an error.
 * 		2009-06-28 RSB	Added HtmlOut ... just as an allocation,
 * 				not as anything functional yet.
 * 		2009-06-29 RSB	HTML output now appears to be working.
 * 		2009-06-30 RSB	Added arbitrary HTML inserts.
 * 		2009-07-01 RSB	Altered style of comments in HTML.
 * 		2009-07-24 RSB	No longer automatically converts comments
 * 				to upper case.  This doesn't matter a lot,
 * 				but does mess up URLs, so it has been
 * 				repaired.
 * 		2016-07-17 RSB	Commented out the used of the 'Extra'
 * 				and 'Missing' variables, since they weren't
 * 				being used for anything and were generating
 * 				compiler warnings.
 * 		2016-08-23 RSB  An allocation of Block1, simply to avoid
 * 		                a linker error for the updated SymbolTable.c.
 * 		2016-11-18 RSB	Fixed up a function protype.
 * 		2017-10-11 MAS	Added handling/printing of asterisks preceding
 * 		                operators and junk after the variable field.
 * 		2017-10-12 MAS	Cleaned up HTML and .lst formatting. Pulled
 * 		                --unpound-page over from yaYUL.
 * 		2017-11-18 RSB	Some compiler warnings fixed.
 *
 * Note that we use yaYUL's symbol-table machinery for handling the
 * symbol table.
 */

#include "../yaYUL/yaYUL.h"

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

#define MEMSIZE 010000
static int Memory[MEMSIZE], Valid[MEMSIZE];
static char s[1000], sd[1000];
static int ErrCount, WarnCount;
static char *Comment, Label[1000], OperatorField[1000], Variables[1000];
static char *FileSelected = NULL;
static int Lines;
static FILE *Lst;
FILE *HtmlOut = NULL;
int Html = 0;
int inHeader = 1;
extern int UnpoundPage;

#define MAX_CHECKSUM_REGIONS 16
typedef struct
{
  int Start, Stop, Store, Sum;
} ChecksumRegion_t;
static ChecksumRegion_t ChecksumRegions[MAX_CHECKSUM_REGIONS];
static int NumChecksumRegions = 0;

// Just to avoid a linker error.  This variable is not used by the program.
int Block1 = 0;

//------------------------------------------------------------------------

static void
ErrorMsg (char *Msg)
{
  ErrCount++;
  fprintf (Lst, "*** Error *** %s\n", Msg);
  fprintf (stderr, "%s:%d: Error: %s\n", FileSelected, Lines, Msg);
  if (HtmlOut != NULL)
    fprintf (HtmlOut, COLOR_FATAL "*** Error *** %s</span>\n",
	     NormalizeString (Msg));
}

static void
WarningMsg (char *Msg)
{
  WarnCount++;
  fprintf (Lst, "*** Warning *** %s\n", Msg);
  fprintf (stderr, "%s:%d: Warning: %s\n", FileSelected, Lines, Msg);
  if (HtmlOut != NULL)
    fprintf (HtmlOut, COLOR_WARNING "*** Warning *** %s</span>\n",
	     NormalizeString (Msg));
}

static void
Msg (char *Msg)
{
  fprintf (Lst, "%s\n", Msg);
  fprintf (stderr, "%s\n", Msg);
  if (HtmlOut != NULL)
    fprintf (HtmlOut, "%s\n", NormalizeString (Msg));
}

//------------------------------------------------------------------------
// Is the character something that can appear in a label?  0 if no, 
// non-zero if yes.

static int
IsLabelSym (char c)
{
  if (c == '+' || c == '-' || c == '/' || c == '*' || c == '$' || c == '='
      || c == ',')
    return (0);
  return (1);
}

//------------------------------------------------------------------------
// Print an Address_t record.  Returns 0 on success, non-zero on error.

int
AddressPrint (Address_t *Address)
{
  if (Address->Invalid)
    {
      fprintf (Lst, "????\t");
      if (HtmlOut != NULL)
	fprintf (HtmlOut, "????    ");
    }
  else if (Address->Constant)
    {
      fprintf (Lst, "%04o\t", Address->Value & 07777);
      if (HtmlOut != NULL)
	fprintf (HtmlOut, "%04o    ", Address->Value & 07777);
    }
  else if (Address->Address)
    {
      fprintf (Lst, "%04o\t", Address->SReg & 07777);
      if (HtmlOut != NULL)
	fprintf (HtmlOut, "%04o    ", Address->SReg & 07777);
    }
  else
    {
      fprintf (Lst, "int-err ");
      if (HtmlOut != NULL)
	fprintf (HtmlOut, "int-err ");
      return (1);
    }
  return (0);
}

//------------------------------------------------------------------------
// Print the symbol table.

static void
PrintSymbolsToFileL (FILE *fp)
{
  extern Symbol_t *SymbolTable;
  extern int SymbolTableSize;
  char s[137];
  int i;
  fprintf (fp, "Symbol Table\n"
	   "------------\n");
  if (HtmlOut != NULL)
    fprintf (HtmlOut, "</pre>\n<h1>Symbol Table</h1>\n<pre>\n");
  for (i = 0; i < SymbolTableSize; i++)
    {
      if (!(i & 3) && i != 0)
	{
	  fprintf (fp, "\n");
	  if (HtmlOut != NULL)
	    fprintf (HtmlOut, "\n");
	}
      sprintf (s, "%6d: %-*s ", i + 1, MAX_LABEL_LENGTH, SymbolTable[i].Name);
      fprintf (fp, "%s", s);
      if (HtmlOut != NULL)
	fprintf (HtmlOut, "%s", NormalizeString (s));
      AddressPrint (&SymbolTable[i].Value);
      if (3 != (i & 3))
	{
	  fprintf (fp, "\t");
	  if (HtmlOut != NULL)
	    fprintf (HtmlOut, "        ");
	}
    }
  fprintf (fp, "\n");
  if (HtmlOut != NULL)
    fprintf (HtmlOut, "\n");
}

//------------------------------------------------------------------------
// For printing variable and comment fields.

static void
PrintComments (int i)
{
  int PrintJunk = 0, JunkSize = 0;
  if (Comment != NULL && Comment[0] != 0)
    {
      if (i <= 6 && sd[0] != 0)
        {
          // There was some pre-comment junk on the line. Make some room for it.
          if (strlen(sd) > 5)
            {
              // The junk is particularly large, so shove it towards the variable
              // column a bit and hope it doesn't push the comment too far out
              i = 7 - i;
              JunkSize = 8;
            }
          else
            {
              // "Regular" (as per FP6/FP8)-sized junk
              i = 10 - i;
              JunkSize = 5;
            }
          PrintJunk = 1;
        }
      else if (i < 16)
	i = 16 - i;
      else
	i = 1;
      if (PrintJunk)
        fprintf (Lst, "%*s%-*s #%s", i, "", JunkSize, sd, Comment);
      else
        fprintf (Lst, "%*s#%s", i, "", Comment);
      if (HtmlOut != NULL)
	{
	  for (; i > 0; i--)
	    fprintf (HtmlOut, " ");
          if (PrintJunk)
            {
              fprintf (HtmlOut, COLOR_COMMENT "%-*s",
                      JunkSize, NormalizeString(sd));
              fprintf (HtmlOut, "   #%s</span>",
                      NormalizeString (Comment));
            }
          else
            fprintf (HtmlOut, "  " COLOR_COMMENT "#%s</span>",
                    NormalizeString (Comment));
	}
    }
  fprintf (Lst, "\n");
  if (HtmlOut != NULL)
    fprintf (HtmlOut, "\n");
}

static void
HtmlChar (char c)
{
  if (c == '<')
    fprintf (HtmlOut, "&lt;");
  else if (c == '&')
    fprintf (HtmlOut, "&amp;");
  else
    fputc (c, HtmlOut);
}

static void
PrintVariablesAndComments (void)
{
  int i;
  i = fprintf (Lst, "%s", Variables);
  if (HtmlOut != NULL)
    {
      // This is tricky, because the operand field (Variables) often
      // looks something like "DIAT+1,1", where just "DIAT" is an
      // actual symbol and the other stuff represents operations on
      // it.  So we actually have to parse the field using characters
      // that are illegal for symbols as delimiters, and then check the
      // individual parts to see if they are defined symbols.  Whew!
      char *s;
      // Eliminate gunk at beginning.
      for (s = Variables; *s && !IsLabelSym (*s); s++)
	HtmlChar (*s);
      // Now loop on all the potential symbols remaining.
      while (*s)
	{
	  char *ss, c;
	  Symbol_t *Symbol;
	  // Find the potential variable itself.
	  for (ss = s; *ss && IsLabelSym (*ss); ss++)
	    ;
	  // Re-delimit it.
	  c = *ss;
	  *ss = 0;
	  // Is it a real symbol?
	  Symbol = GetSymbol (s);
	  // Output it, with a hyperlink if appropriate.
	  if (Symbol != NULL)
	    fprintf (HtmlOut, "<a href=\"#%s\">", NormalizeAnchor (s));
	  fprintf (HtmlOut, "%s", NormalizeString (s));
	  if (Symbol != NULL)
	    fprintf (HtmlOut, "</a>");
	  // Fix the delimiting.
	  *ss = c;
	  // Take care of the non-symbol delimiting stuff.
	  for (s = ss; *s && !IsLabelSym (*s); s++)
	    HtmlChar (*s);
	}
    }
  PrintComments (i);
}

//------------------------------------------------------------------
// Shortcuts for outputting various stuff to the HTML.

static void
HtmlLabel (char *Label)
{
  if (Label[0])
    fprintf (HtmlOut, "<a name=\"%s\"></a>" COLOR_SYMBOL "%s</span> ",
	     NormalizeAnchor (Label), NormalizeStringN (Label, 6));
  else
    fprintf (HtmlOut, "%s", NormalizeStringN (Label, 7));
}

static void
HtmlOperator (char *Color, char *Operator, char Asterisk)
{
  fprintf (HtmlOut, "%c%s%s</span>", Asterisk, Color, NormalizeStringN (Operator, 8));
}

//------------------------------------------------------------------
// Evaluates a decimal number, with decimal point, 'B' and 'E' 
// modifiers.  Returns 0 on success, non-zero otherwise.

static int
EvaluateDecimal (char *s, Address_t *Address)
{
  int Sign, Bn, En, i, RetVal = 0;
  unsigned long Integer, Numerator, Denominator;
  double Value;

  // Take care of optional sign.
  Sign = 1;
  if (*s == '+')
    s++;
  else if (*s == '-')
    {
      Sign = -1;
      s++;
    }

  // Take care of optional integer portion.
  Integer = 0;
  for (; *s >= '0' && *s <= '9'; s++)
    Integer = *s - '0' + (Integer * 10);
  if (*s != '.' && *s != 'B' && *s != 'E')
    {
      i = Integer;
      goto Done;
    }

  // Take care of optional decimal point and fraction.
  Numerator = 0;
  Denominator = 1;
  if (*s == '.')
    {
      for (s++; *s >= '0' && *s <= '9'; s++)
	{
	  Numerator = *s - '0' + 10 * Numerator;
	  Denominator *= 10;
	}
    }

  // Take care of optional 'B' and 'E' thingies. 
  if (0 < (i = sscanf (s, "B%dE%d", &Bn, &En)))
    {
      if (i == 1)
	En = 0;
    }
  else if (2 == sscanf (s, "E%dB%d", &En, &Bn))
    {
    }
  else
    {
      ErrorMsg ("Missing binary point.");
      i = 0;
      goto Done;
    }

  // Now put it all together.
  Value = Integer + (Numerator * 1.0) / Denominator;
  Value *= pow (10.0, En) * pow (2.0, 17 - Bn);
  i = Value + 0.5;

  Done: if (i > 0377777)
    {
      i = 0;
      RetVal = 1;
    }
  i *= Sign;

  Address->Invalid = 0;
  Address->Address = 0;
  Address->Constant = 1;
  Address->Value = i;
  return (RetVal);
}

//------------------------------------------------------------------
// Evaluates an octal number. Returns 0 on success, non-zero otherwise.

static int
EvaluateOctal (char *s, Address_t *Address)
{
  int i, RetVal = 0;

  if (1 != sscanf (s, "%o", &i))
    {
      ErrorMsg ("Not an octal value.");
      RetVal++;
      i = 0;
    }
  else
    {
      for (; *s && *s != ','; s++)
	if (*s < '0' || *s > '7')
	  {
	    ErrorMsg ("Non-octal digits in variable field.");
	    RetVal++;
	    break;
	  }
    }

  Address->Invalid = 0;
  Address->Address = 0;
  Address->Constant = 1;
  Address->Value = i;
  return (RetVal);
}

//------------------------------------------------------------------
// Evaluates an expression involving any combination of Labels,
// constants, +, and -.  Returns 0 on success, non-zero error
// code otherwise.  ForceOctal is interpreted as follows:
//	-1	Force decimal.
//	0	Auto-interpret as decimal or octal
//	1	Force octal.

// **** This function needs to have more checking of stuff, such
// as valid characters in labels ****.

static int
EvaluateExpression (char *Expression, Address_t *Address, int Location,
		    int ForceOctal)
{
  int NumAddresses = 0, Value = 0, Sign, i, j, RetVal = 0;
  char *s, *ss, *sss, Operator;
  Symbol_t *Symbol;

  //if (ForceOctal == -1)
  //  return (EvaluateDecimal (Expression, Address));

  s = Expression;
  while (1)
    {
      if (*s == 0 || *s == ',')
	break;
      // Take care of Operator.
      Sign = 1;
      if (*s == '+')
	s++;
      else if (*s == '-')
	{
	  Sign = -1;
	  s++;
	}
      // Pick off next number or label.
      for (ss = s + 1; *ss && *ss != ',' && *ss != '-' && *ss != '+'; ss++)
	;
      Operator = *ss;
      *ss = 0;
      // Is this a number or a label?
      for (sss = s; *sss; sss++)
	if (!isdigit(*sss))
	  break;
      if (*sss == 0)
	{
	  // A number.
	  if (ForceOctal == -1 || (sss - s <= 3 && ForceOctal != 1))
	    {
	      // Decimal.
	      sscanf (s, "%d", &i);
	      Value += i * Sign;
	    }
	  else
	    {
	      // Octal.
	      i = 0;
	      if (1 != sscanf (s, "%o%d", &i, &j))
		RetVal = 1;
	      Value += i * Sign;
	    }
	}
      else if (*s == '*')
	{
	  Value += Location * Sign;
	}
      else
	{
	  // A symbol.
	  Symbol = GetSymbol (s);
	  if (Symbol == NULL || Symbol->Value.Invalid)
	    {
	      Address->Invalid = 1;
	      Address->Constant = Address->Address = 0;
	      RetVal = 2;
	      break;
	    }
	  if (Symbol->Value.Constant)
	    Value += Symbol->Value.Value * Sign;
	  else if (Symbol->Value.Address)
	    {
	      Value += Symbol->Value.SReg * Sign;
	      NumAddresses += Sign;
	    }
	}
      // Advance.
      *ss = Operator;
      s = ss;
    }
  if (RetVal)
    {
      Address->Invalid = 1;
      Address->Constant = Address->Address = 0;
    }
  else
    {
      Address->Invalid = 0;
      if (NumAddresses == 1)
	{
	  Address->Address = 1;
	  Address->Constant = 0;
	  Address->SReg = Value;
	}
      else
	{
	  Address->Constant = 1;
	  Address->Address = 0;
	  Address->Value = Value;
	}
    }
  return (RetVal);
}

//------------------------------------------------------------------
// Returns the number of unresolved symbols on the pass.  The 
// total number of errors on the pass is written to the global
// variable ErrCount.  The input value of Action modifies the
// behavior in the following ways:
//	Action = -1	Merely add symbols to the symbol table.
//	Action = 0	Try to resolve symbols.
// 	Action = 1	Finish up and write the assembly listing.

static int
PassLemap (FILE *fp, int Action)
{
  int Location = 0, i, j, /*Extra, Missing,*/Dummy = 0;
  char *ss, *Operator, Asterisk;
  Address_t Address =
    { 0 }, LineAddress =
    { 0 };
  FILE *SingAlong;

  Lines = 0;
  rewind (fp);
  ErrCount = WarnCount = 0;
  if (Action == 1)
    SingAlong = fopen ("yaLEMAP.binsource", "w");
  else
    SingAlong = NULL;

  while (NULL != fgets (s, sizeof(s) - 1, fp))
    {
      Lines++;

      if (Action == 1)
        {
          // If it is not a ## line and not completely blank, then we are no longer
          // in the file header.
          for (ss = s; *ss && isspace(*ss); ss++)
              ;
          if (*ss == 0 || (s[0] == '#' && s[1] == '#' && 1 != sscanf(s, "## Page%d", &i))) // is a ## line
            {
              // Intentionally empty.
            }
          else
            inHeader = 0;
        }

      // Is it an HTML insert?  If so, transparently process and discard.
      if (HtmlCheck ((Action == 1), fp, s, sizeof(s), FileSelected, &Lines,
		     &Dummy))
      {
	continue;
      }

      // Eliminate the newline.
      Comment = NULL;
      for (ss = s; *ss; ss++)
	if (*ss == '#' && Comment == NULL)
	  Comment = ss;
	else if (*ss == '\n')
	  {
	    *ss = 0;
	    break;
	  }
	else if (Comment == NULL)
	  *ss = toupper (*ss);

      // Null-terminate comments.
      if (Comment != NULL)
	{
	  *Comment = 0;
          Comment++;
	}

      // Parse the line into fields.
      Label[0] = OperatorField[0] = Variables[0] = sd[0] = 0;
      //Extra = Missing = 0;
      if (!s[0])
        {
        }
      else if (!isspace(s[0]))
	{
	  i = sscanf (s, "%s%s%s%s", Label, OperatorField, Variables, sd);
	  if (i == 4)
	    {
	      //Extra = 1;
	    }
	  else if (i == 2 && strcmp (OperatorField, "END"))
	    {
	      //Missing = 1;
	    }
	}
      else
	{
	  i = sscanf (s, "%s%s%s", OperatorField, Variables, sd);
	  if (i == 3)
	    {
	      //Extra = 1;
	    }
	  else if (i == 1 && strcmp (OperatorField, "END"))
	    {
	      //Missing = 1;
	    }
	}

      // Labels are identified but not resolved on the first pass.
      if (Action == -1)
	{
	  if (Label[0])
	    AddSymbol (Label);
	  continue;
	}

      // Some lines may be prefixed by an asterisk. This doesn't affect
      // the assembly, but seems to have been used as some form of comment, so
      // we faithfully pass it through.
      Operator = OperatorField;
      Asterisk = ' ';
      if (OperatorField[0] == '*')
      {
          Operator++;
          Asterisk = '*';
      }

      // In the mid pass (0) all we are trying to do is to resolve
      // label values.  All legal instructions (and unknown 
      // instructions) have the effect of bumping the location 
      // counter by 1.  Therefore, all we really need to know how
      // to do is to interpret the pseudo-ops that do something
      // else.  These are:
      //	ORG
      //	EQU or SYN
      //	DEFINE
      //	BES
      //	BSS
      //	DEC
      //	OCT
      //	END 
      //	... and of course, blank lines.
      if (Action == 0)
	{
	  if (Operator[0] == 0 || !strcmp (Operator, "END"))
	    {
	      // These do nothing to the location counter.
	    }
	  else if (!strcmp (Operator, "EQU") || !strcmp (Operator, "SYN"))
	    {
	      if (Label[0] != 0)
		{
		  EvaluateExpression (Variables, &Address, Location, 0);
		  EditSymbolNew (Label, &Address, SYMBOL_CONSTANT, FileSelected,
				 Lines);
		}
	    }
	  else if (!strcmp (Operator, "DEFINE"))
	    {
	      if (Label[0] != 0)
		{
		  EvaluateExpression (Variables, &Address, Location, 1);
		  EditSymbolNew (Label, &Address, SYMBOL_CONSTANT, FileSelected,
				 Lines);
		}
	    }
	  else if (!strcmp (Operator, "DEC") || !strcmp (Operator, "OCT"))
	    {
	      if (Label[0] != 0)
		{
		  Address.Invalid = 0;
		  Address.Constant = 0;
		  Address.Address = 1;
		  Address.SReg = Location;
		  EditSymbolNew (Label, &Address, SYMBOL_VARIABLE, FileSelected,
				 Lines);
		}
	      // All we need to do here is to know the number
	      // of commas in the Variables field, and 
	      // advance the location counter by one more than
	      // that.
	      for (Location++, ss = Variables; *ss; ss++)
		if (*ss == ',')
		  Location++;
	    }
	  else if (!strcmp (Operator, "ORG"))
	    {
	      EvaluateExpression (Variables, &Address, Location, 1);
	      if (Address.Constant)
		Location = Address.Value;
	      else if (Address.Address)
		Location = Address.Address;
	      if (Label[0] != 0)
		{
		  Address.Invalid = 0;
		  Address.Constant = 0;
		  Address.Address = 1;
		  Address.SReg = Location;
		  EditSymbolNew (Label, &Address, SYMBOL_LABEL, FileSelected,
				 Lines);
		}
	    }
	  else if (!strcmp (Operator, "BES"))
	    {
	      EvaluateExpression (Variables, &Address, Location, 0);
	      if (Address.Constant)
		Location += Address.Value;
	      else if (Address.Address)
		Location += Address.Address;
	      if (Label[0] != 0)
		{
		  Address.Invalid = 0;
		  Address.Constant = 0;
		  Address.Address = 1;
		  Address.SReg = Location;
		  EditSymbolNew (Label, &Address, SYMBOL_LABEL, FileSelected,
				 Lines);
		}
	    }
	  else if (!strcmp (Operator, "BSS"))
	    {
	      if (Label[0] != 0)
		{
		  Address.Invalid = 0;
		  Address.Constant = 0;
		  Address.Address = 1;
		  Address.SReg = Location;
		  EditSymbolNew (Label, &Address, SYMBOL_LABEL, FileSelected,
				 Lines);
		}
	      EvaluateExpression (Variables, &Address, Location, 0);
	      if (Address.Constant)
		Location += Address.Value;
	      else if (Address.Address)
		Location += Address.Address;
	    }
	  else
	    {
	      if (Label[0] != 0)
		{
		  Address.Invalid = 0;
		  Address.Constant = 0;
		  Address.Address = 1;
		  Address.SReg = Location;
		  EditSymbolNew (Label, &Address, SYMBOL_LABEL, FileSelected,
				 Lines);
		}
	      Location++;
	      Location &= 07777;
	    }
	  continue;
	}

      // Here is the final pass, in which the assembly listing
      // and binaries are produced.  We don't need to attempt to 
      // resolve symbols any longer, since we already know that
      // they're either all resolved or else that we're not going
      // to be able to resolve them.
      if (!strcmp (Operator, "CHECKSUM") && !strcmp (Variables, "RANGE")
	  && 2 == sscanf (sd, "%o-%o", &i, &j))
	{
	  fprintf (
	      Lst,
	      "%04o: %04o                        \t%-6s  CHECKSUM RANGE %04o-%04o\n",
	      Lines, Location, Label, i, j);
	  if (HtmlOut != NULL)
	    {
	      fprintf (HtmlOut, "%04o: %04o%s", Lines, Location,
		       NormalizeStringN ("", 32));
	      HtmlLabel (Label);
	      fprintf (HtmlOut,
	      COLOR_PSEUDO "CHECKSUM RANGE</span> %04o-%04o\n",
		       i, j);
	    }
	  if (NumChecksumRegions < MAX_CHECKSUM_REGIONS)
	    {
	      ChecksumRegions[NumChecksumRegions].Start = i;
	      ChecksumRegions[NumChecksumRegions].Stop = j;
	      ChecksumRegions[NumChecksumRegions++].Store = Location;
	    }
	  else
	    ErrorMsg ("Too many checksum regions defined.");
	  if (SingAlong != NULL)
	    fprintf (SingAlong, "0p\n");
	  Location++;
	  continue;
	}
      else if (!strcmp (Operator, "END"))
	{
	  fprintf (Lst, "%04o: %04o                        \t%-6s  %-8s", Lines,
		   Location, Label, Operator);
	  if (HtmlOut != NULL)
	    {
	      fprintf (HtmlOut, "%04o: %04o%s", Lines, Location,
		       NormalizeStringN ("", 31));
	      HtmlLabel (Label);
	      HtmlOperator (COLOR_PSEUDO, Operator, Asterisk);
	    }
	  PrintComments (24);
	  break;
	}
      else if (Operator[0] == 0)
	{
	  if (Comment == NULL || Comment[0] == 0)
	    {
	      fprintf (Lst, "%04o:\n", Lines);
	      if (HtmlOut != NULL)
		fprintf (HtmlOut, "%04o:\n", Lines);
	    }
	  else
	    {
	      fprintf (Lst, "%04o:                             \t#%s\n", Lines,
		       Comment);
	      if (HtmlOut != NULL)
		{
		  fprintf (HtmlOut, "%04o:%s", Lines,
			   NormalizeStringN ("", 37));
		  fprintf (HtmlOut, COLOR_COMMENT "#%s</span>\n",
			   NormalizeString (Comment));
		}
	      if (SingAlong != NULL && !strncmp (Comment, "PAGE ", 5))
		fprintf (SingAlong, "\n#%s ---------------------\n", Comment);
	    }
	}
      else if (!strcmp (Operator, "EQU") || !strcmp (Operator, "SYN")
	  || !strcmp (Operator, "DEFINE"))
	{
	  Symbol_t *Symbol;
	  Symbol = GetSymbol (Label);
	  if (Symbol == NULL)
	    {
	      ErrorMsg ("Label not found.");
	      fprintf (Lst, "%04o:                             \t%-6s %c%-8s",
		       Lines, Label, Asterisk, Operator);
	      if (HtmlOut != NULL)
		{
		  fprintf (HtmlOut, "%04o:%s", Lines,
			   NormalizeStringN ("", 32));
		  HtmlLabel (Label);
		  HtmlOperator (COLOR_PSEUDO, Operator, Asterisk);
		}
	    }
	  else if (Symbol->Value.Invalid)
	    {
	      ErrorMsg ("Label not resolved.");
	      fprintf (Lst, "%04o:                             \t%-6s %c%-8s",
		       Lines, Label, Asterisk, Operator);
	      if (HtmlOut != NULL)
		{
		  fprintf (HtmlOut, "%04o:%s", Lines,
			   NormalizeStringN ("", 32));
		  HtmlLabel (Label);
		  HtmlOperator (COLOR_PSEUDO, Operator, Asterisk);
		}
	    }
	  else if (Symbol->Value.Address)
	    {
	      fprintf (Lst, "%04o:                         %04o\t%-6s %c%-8s",
		       Lines, Symbol->Value.SReg, Label, Asterisk, Operator);
	      if (HtmlOut)
		{
		  fprintf (HtmlOut, "%04o:%s", Lines,
			   NormalizeStringN ("", 25));
		  fprintf (HtmlOut, "%04o%s", Symbol->Value.SReg,
			   NormalizeStringN ("", 8));
		  HtmlLabel (Label);
		  HtmlOperator (COLOR_PSEUDO, Operator, Asterisk);
		}
	    }
	  else if (Symbol->Value.Constant)
	    {
	      fprintf (Lst, "%04o:                         %04o\t%-6s %c%-8s",
		       Lines, Symbol->Value.Value, Label, Asterisk, Operator);
	      if (HtmlOut)
		{
		  fprintf (HtmlOut, "%04o:%s", Lines,
			   NormalizeStringN ("", 25));
		  fprintf (HtmlOut, "%04o%s", Symbol->Value.Value,
			   NormalizeStringN ("", 8));
		  HtmlLabel (Label);
		  HtmlOperator (COLOR_PSEUDO, Operator, Asterisk);
		}
	    }
	  else
	    {
	      if (Symbol->Value.Value > 07777 || Symbol->Value.Value < -04000)
		{
		  WarningMsg ("Symbol value out of range.");
		  fprintf (Lst,
			   "%04o:                         %04o\t%-6s %c%-8s",
			   Lines, 07777 & Symbol->Value.Value, Label, Asterisk, Operator);
		  if (HtmlOut)
		    {
		      fprintf (HtmlOut, "%04o:%s", Lines,
			       NormalizeStringN ("", 25));
		      fprintf (HtmlOut, "%04o%s", 07777 & Symbol->Value.Value,
			       NormalizeStringN ("", 8));
		      HtmlLabel (Label);
		      HtmlOperator (COLOR_PSEUDO, Operator, Asterisk);
		    }
		}
	    }
	  PrintVariablesAndComments ();
	}
      else if (!strcmp (Operator, "DEC") || !strcmp (Operator, "OCT"))
	{
	  int ForceOctal;
	  if (!strcmp (Operator, "DEC"))
	    ForceOctal = -1;
	  else
	    ForceOctal = 1;
	  for (ss = Variables; *ss != 0;)
	    {
	      if (ForceOctal == 1)
		i = EvaluateOctal (ss, &Address);
	      else
		i = EvaluateDecimal (ss, &Address);
	      if (i)
		ErrorMsg ("Value out of range.");
	      if (Address.Constant)
		Memory[Location] = Address.Value;
	      else if (Address.Address)
		Memory[Location] = Address.SReg;
	      if (Valid[Location])
		WarningMsg ("Memory location overwritten.");
	      if (Memory[Location] < -0400000 || Memory[Location] > 0777777)
		{
		  ErrorMsg ("Value out of range.");
		  Memory[Location] = 0;
		}
	      else
		Memory[Location] &= 0777777;
	      if (ss == Variables)
		{
		  fprintf (Lst, "%04o: %04o           %06o       \t%-6s %c%-8s",
			   Lines, Location, Memory[Location], Label, Asterisk, Operator);
		  if (HtmlOut != NULL)
		    {
		      fprintf (HtmlOut, "%04o: %04o%s", Lines, Location,
			       NormalizeStringN ("", 11));
		      fprintf (HtmlOut, "%06o%s", Memory[Location],
			       NormalizeStringN ("", 15));
		      HtmlLabel (Label);
		      HtmlOperator (COLOR_PSEUDO, Operator, Asterisk);
		    }
		  PrintVariablesAndComments ();
		}
	      else
		{
		  fprintf (Lst, "%04o: %04o           %06o\n", Lines, Location,
			   Memory[Location]);
		  if (HtmlOut != NULL)
		    {
		      fprintf (HtmlOut, "%04o: %04o%s", Lines, Location,
			       NormalizeStringN ("", 11));
		      fprintf (HtmlOut, "%06o%s\n", Memory[Location],
			       NormalizeStringN ("", 15));
		    }
		}
	      if (SingAlong != NULL)
		fprintf (SingAlong, "%op\n", Memory[Location]);
	      Valid[Location++] = 0;
	      for (; *ss && *ss != ','; ss++)
		;
	      if (*ss == 0)
		break;
	      ss++;
	    }
	}
      else if (!strcmp (Operator, "ORG"))
	{
	  EvaluateExpression (Variables, &Address, Location, 1);
	  if (Address.Constant)
	    Location = Address.Value;
	  else if (Address.Address)
	    Location = Address.Address;
	  if (Location < 0 || Location > 07777)
	    {
	      WarningMsg ("Address out of range.");
	      Location &= 07777;
	    }
	  fprintf (Lst, "%04o: %04o                        \t%-6s  %-8s", Lines,
		   Location, Label, Operator);
	  if (HtmlOut != NULL)
	    {
	      fprintf (HtmlOut, "%04o: %04o%s", Lines, Location,
		       NormalizeStringN ("", 32));
	      HtmlLabel (Label);
	      HtmlOperator (COLOR_PSEUDO, Operator, Asterisk);
	    }
	  PrintVariablesAndComments ();
	  if (SingAlong != NULL)
	    fprintf (SingAlong, "org %op\n", Location);
	}
      else if (!strcmp (Operator, "BES"))
	{
	  EvaluateExpression (Variables, &Address, Location, 0);
	  i = Location;
	  if (Address.Constant)
	    Location += Address.Value;
	  else if (Address.Address)
	    Location += Address.Address;
	  if (Location < 0 || Location > 07777)
	    {
	      WarningMsg ("Address out of range.");
	      Location &= 07777;
	    }
	  for (; i < Location; i++)
	    {
	      Memory[i] = 0;
	      if (Valid[i])
		WarningMsg ("Overwriting memory.");
	      Valid[i] = 1;
	      if (SingAlong != NULL)
		fprintf (SingAlong, "0p");
	    }
	  fprintf (Lst, "%04o: %04o                        \t%-6s  %-8s", Lines,
		   Location, Label, Operator);
	  if (HtmlOut != NULL)
	    {
	      fprintf (HtmlOut, "%04o: %04o%s", Lines, Location,
		       NormalizeStringN ("", 31));
	      HtmlLabel (Label);
	      HtmlOperator (COLOR_PSEUDO, Operator, Asterisk);
	    }
	  PrintVariablesAndComments ();
	}
      else if (!strcmp (Operator, "BSS"))
	{
	  fprintf (Lst, "%04o: %04o                        \t%-6s  %-8s", Lines,
		   Location, Label, Operator);
	  if (HtmlOut != NULL)
	    {
	      fprintf (HtmlOut, "%04o: %04o%s", Lines, Location,
		       NormalizeStringN ("", 31));
	      HtmlLabel (Label);
	      HtmlOperator (COLOR_PSEUDO, Operator, Asterisk);
	    }
	  PrintVariablesAndComments ();
	  EvaluateExpression (Variables, &Address, Location, 0);
	  i = Location;
	  if (Address.Constant)
	    Location += Address.Value;
	  else if (Address.Address)
	    Location += Address.Address;
	  if (Location < 0 || Location > 07777)
	    {
	      WarningMsg ("Address out of range (above).");
	      Location &= 07777;
	    }
	  for (; i < Location; i++)
	    {
	      Memory[i] = 0;
	      if (Valid[i])
		WarningMsg ("Overwriting memory (above).");
	      Valid[i] = 1;
	      if (SingAlong != NULL)
		fprintf (SingAlong, "0p");
	    }
	}
      else
	{
	  int Opcode = 0, Tag = 0, Addr = 0;
	  // The remaining are all instructions and can be treated
	  // a little more uniformly.
	  if (!strcmp (Operator, "ADD"))
	    Opcode = 022;
	  else if (!strcmp (Operator, "ADZ"))
	    Opcode = 032;
	  else if (!strcmp (Operator, "SUB"))
	    Opcode = 024;
	  else if (!strcmp (Operator, "SUZ"))
	    Opcode = 034;
	  else if (!strcmp (Operator, "MPY"))
	    Opcode = 06;
	  else if (!strcmp (Operator, "MPR"))
	    Opcode = 026;
	  else if (!strcmp (Operator, "MPZ"))
	    Opcode = 036;
	  else if (!strcmp (Operator, "DVP"))
	    Opcode = 04;
	  else if (!strcmp (Operator, "COM"))
	    Opcode = 060;
	  else if (!strcmp (Operator, "ABS"))
	    Opcode = 062;
	  else if (!strcmp (Operator, "CLA"))
	    Opcode = 020;
	  else if (!strcmp (Operator, "CLZ"))
	    Opcode = 030;
	  else if (!strcmp (Operator, "LDQ"))
	    Opcode = 014;
	  else if (!strcmp (Operator, "STO"))
	    Opcode = 010;
	  else if (!strcmp (Operator, "STQ"))
	    Opcode = 012;
	  else if (!strcmp (Operator, "ALS"))
	    Opcode = 056;
	  else if (!strcmp (Operator, "LLS"))
	    Opcode = 052;
	  else if (!strcmp (Operator, "LRS"))
	    Opcode = 054;
	  else if (!strcmp (Operator, "TRA"))
	    Opcode = 040;
	  else if (!strcmp (Operator, "TSQ"))
	    Opcode = 072;
	  else if (!strcmp (Operator, "TMI"))
	    Opcode = 046;
	  else if (!strcmp (Operator, "TOV"))
	    Opcode = 044;
	  else if (!strcmp (Operator, "AXT"))
	    Opcode = 050;
	  else if (!strcmp (Operator, "TIX"))
	    Opcode = 042;
	  else if (!strcmp (Operator, "DLY"))
	    Opcode = 070;
	  else if (!strcmp (Operator, "INP"))
	    Opcode = 064;
	  else if (!strcmp (Operator, "OUT"))
	    Opcode = 066;
	  else
	    ErrorMsg ("Unknown operator.");

	  EvaluateExpression (Variables, &Address, Location, 0);
	  if (Address.Invalid)
	    ErrorMsg ("Address expression cannot be resolved.");
	  else
	    {
	      if (Address.Constant)
		Addr = Address.Value;
	      else
		Addr = Address.SReg;
	      if (Addr < 0 || Addr > 07777)
		{
		  WarningMsg ("Address out of range.");
		  Addr &= 07777;
		}
	      if (!strcmp (Operator, "AXT") && Addr > 7)
		{
		  ErrorMsg ("Address for index out of range.");
		  //Addr &= 7;
		}
	      for (ss = Variables; *ss && *ss != ','; ss++)
		;
	      if (*ss == ',')
		{
		  EvaluateExpression (ss + 1, &Address, Location, 0);
		  if (Address.Invalid)
		    ErrorMsg ("Tag expression cannot be resolved.");
		  else
		    {
		      if (Address.Constant)
			Tag = Address.Value;
		      else
			Tag = Address.SReg;
		      if (Tag != 0 && Tag != 1)
			{
			  WarningMsg ("Tag out of range.");
			  Tag &= 1;
			}
		    }
		}
	      else
		{
		  if (!strcmp (Operator, "TIX") || !strcmp (Operator, "AXT"))
		    {
		      WarningMsg ("Missing tag.");
		      Tag = 1;
		    }
		}
	    }

	  Memory[Location] = ((Opcode | Tag) << 12) | Addr;
	  if (Valid[Location])
	    ErrorMsg ("Overwriting memory.");
	  Valid[Location] = 1;
	  fprintf (Lst, "%04o: %04o %02o %01o %04o              \t%-6s %c%-8s",
		   Lines, Location, Opcode, Tag, Addr, Label, Asterisk, Operator);
	  if (HtmlOut != NULL)
	    {
	      fprintf (HtmlOut, "%04o: %04o %02o %01o %04o%s", Lines, Location,
		       Opcode, Tag, Addr, NormalizeStringN ("", 22));
	      HtmlLabel (Label);
	      HtmlOperator (COLOR_BASIC, Operator, Asterisk);
	    }
	  PrintVariablesAndComments ();
	  if (SingAlong != NULL)
	    fprintf (SingAlong, "%02op %op %04op\n", Opcode, Tag, Addr);

	  // Add the compiled line to the symbol table which tracks file:line
	  // to program counter memory addresses.
	  LineAddress.SReg = Location;
	  LineAddress.Address = 1;
	  AddLine (&LineAddress, FileSelected, Lines);

	  Location++;
	  if (Location > 07777)
	    {
	      WarningMsg ("Overflow of memory space.");
	      Location &= 07777;
	    }
	}

    }
  if (SingAlong != NULL)
    fclose (SingAlong);

  return (UnresolvedSymbols ());
}

//------------------------------------------------------------------

int
main (int argc, char *argv[])
{

  int i, j, RetVal = 0, Unresolved, LastUnresolved, DupSymbols;
  int Checksum, PassCount;
  char *Compare = NULL;
  FILE *fp;

  printf ("AGS cross-assembler yaLEMAP, " __DATE__ ", " __TIME__ "\n");
  printf ("Copyright 2005,2009 Ronald S. Burkey.\n");
  printf ("Licensed under the General Public License (GPL).\n");

  Lst = fopen ("yaLEMAP.lst", "w");
  if (Lst == NULL)
    {
      fprintf (stderr, "Cannot create yaLEMAP.lst.\n");
      return (1);
    }

  fprintf (Lst, "AGS cross-assembler yaLEMAP, " __DATE__ ", " __TIME__ "\n");
  fprintf (Lst, "Copyright 2005 Ronald S. Burkey.\n");
  fprintf (Lst, "Licensed under the General Public License (GPL).\n");

  // Process the command-line switches.
  for (i = 1; i < argc; i++)
    {
      if (!strncmp (argv[i], "--compare=", 10))
	Compare = &argv[i][10];
      else if (!strcmp (argv[i], "--html"))
	Html = 1;
      else if (!strcmp(argv[i], "--unpound-page"))
        UnpoundPage = 1;
      else if (!strcmp (argv[i], "--help"))
	{
	  printf ("Usage:\n");
	  printf ("\tyaLEMAP [OPTIONS] SourceFile\n");
	  printf ("The executable binary is output into the\n");
	  printf ("file yaLEMAP.bin.  The assembly listing is\n");
	  printf ("written to the file yaLEMAP.lst.\n");
	  printf ("The available OPTIONs are:\n");
	  printf ("--compare=F     Compare the binary output to the file F.\n");
	  printf (
	      "                Note that using this switch causes yaLEMAP\'s\n");
	  printf ("                return code to be totally dependent on the\n");
	  printf (
	      "                result of the file comparison rather than on\n");
	  printf (
	      "                fatal errors and warnings.  This allows (for\n");
	  printf (
	      "                example) for a file comparison to be the basis\n");
	  printf ("                of a regression test run from a makefile.\n");
	  printf (
	      "--html          Causes an HTML file to be created, which is \n"
	      "                the same as the output listing except that it\n"
	      "                if a lot more convenient to use. It has syntax\n"
	      "                highlighting and hyperlinks from where each\n"
	      "                symbol is used back to where it was defined.\n"
	      "                The top-level HTML file produced is named the\n"
	      "                same as the input source file, except with .html\n"
	      "                replacing .s (if applicable).\n");
          printf("--unpound-page  Bypass --html processing for \"## Page\".\n");
	  RetVal++;
	}
      else if (argv[i][0] == '-' || FileSelected != NULL)
	{
	  fprintf (stderr, "Unknown command-line switch \"%s\".\n", argv[i]);
	  RetVal++;
	}
      else
	FileSelected = argv[i];
    }
  if (RetVal)
    return (RetVal);
  fp = fopen (FileSelected, "r");
  if (fp == NULL)
    {
      fprintf (stderr, "The source file \"%s\" does not exist.\n",
	       FileSelected);
      return (1);
    }
  if (Html)
    {
      if (HtmlCreate (FileSelected))
	{
	  fclose (fp);
	  return (1);
	}
    }

  // Process the input file.  Keep doing passes until all symbols
  // are resolved, or until the pass did not resolve any symbols.
  // We simply do passes until all symbols are resolved or until
  // there is no change in the number of unresolved symbols.
  Unresolved = PassLemap (fp, -1);
  DupSymbols = SortSymbols ();
  LastUnresolved = Unresolved + 1;
  PassCount = 0;
  while (Unresolved != 0 && Unresolved != LastUnresolved)
    {
      if (PassCount >= 10)
	break;
      LastUnresolved = Unresolved;
      Unresolved = PassLemap (fp, 0);
      PassCount++;
    }

  // Make the assembly listing, not including the symbol table.
  // Yes, I know this is more passes than needed.  I don't care.
  // It's just easier than having to somehow buffer the assembly
  // listing, and with the speed of today's computers the 
  // loss is minimal.
  PassLemap (fp, 1);

  // Compute Checksum, and store at the last address in memory.
  // (Or compare it to the value that is already there.
  fprintf (Lst, "\n");
  if (HtmlOut != NULL)
    fprintf (HtmlOut, "\n</pre>\n<h1>Checksums</h1>\n<pre>\n");

  if (NumChecksumRegions == 0)
    {
      NumChecksumRegions = 1;
      ChecksumRegions[0].Start = 04000;
      ChecksumRegions[0].Stop = 07776;
      ChecksumRegions[0].Store = 07777;
    }
  for (j = 0; j < NumChecksumRegions; j++)
    {
      for (i = ChecksumRegions[j].Start, Checksum = 0;
	  i <= ChecksumRegions[j].Stop; Checksum += Memory[i++])
	;
      ChecksumRegions[j].Sum = Checksum = (0777777 & -Checksum);
      if (Valid[ChecksumRegions[j].Store]
	  && Memory[ChecksumRegions[j].Store] != Checksum)
	{
	  RetVal++;
	  sprintf (
	      s,
	      "Checksum mismatch at address %04o (%04o-%04o), computed=%06o, embedded=%06o.\n",
	      ChecksumRegions[j].Store, ChecksumRegions[j].Start,
	      ChecksumRegions[j].Stop, Checksum,
	      Memory[ChecksumRegions[j].Store]);
	  ErrorMsg (s);
	}
      else
	{
	  Memory[ChecksumRegions[j].Store] = Checksum;
	  Valid[ChecksumRegions[j].Store] = 1;
	}
      fprintf (Lst, "CHECKSUM at %04o (%04o-%04o) = %06o\n",
	       ChecksumRegions[j].Store, ChecksumRegions[j].Start,
	       ChecksumRegions[j].Stop, ChecksumRegions[j].Sum);
      if (HtmlOut != NULL)
	{
	  fprintf (HtmlOut, "CHECKSUM at %04o (%04o-%04o) = %06o\n",
		   ChecksumRegions[j].Store, ChecksumRegions[j].Start,
		   ChecksumRegions[j].Stop, ChecksumRegions[j].Sum);
	}
    }

  // Output the binary
  fp = fopen ("yaLEMAP.bin", "wb");
  if (fp == NULL)
    {
      RetVal++;
      ErrorMsg ("Cannot create output file.");
    }
  else
    {
      for (i = 0; i < MEMSIZE; i++)
	{
	  fputc (0xFF & Memory[i], fp);
	  fputc (0xFF & (Memory[i] >> 8), fp);
	  fputc (0x03 & (Memory[i] >> 16), fp);
	  fputc (0, fp);
	}
      fclose (fp);
    }

  // We sort the lines by increasing physical address so we can look them
  // up later.
  SortLines (SORT_LEMAP);

  // Print the symbol table to a binary file
  WriteSymbolsToFile ("yaLEMAP.symtab");

  // Print symbol table.
  fprintf (Lst, "\n");
  if (HtmlOut != NULL)
    fprintf (HtmlOut, "\n");
  PrintSymbolsToFileL (Lst);
  fprintf (Lst, "\n");
  if (HtmlOut != NULL)
    fprintf (HtmlOut, "\n");
  ClearSymbols ();
  if (DupSymbols)
    sprintf (s, "%d duplicate symbols.", DupSymbols);
  else
    sprintf (s, "No duplicate symbols.");
  Msg (s);

  // Do a file-comparison, if appropriate.
  if (Compare != NULL)
    {
      if (HtmlOut != NULL)
	fprintf (HtmlOut, "\n</pre>\n<h1>Binary-File Comparison</h1>\n<pre>\n");

      fprintf (Lst, "\n");
      fprintf (Lst, "File comparison with \"%s\":\n", Compare);
      if (HtmlOut != NULL)
	{
	  fprintf (HtmlOut, "File comparison with \"%s\":\n",
		   NormalizeString (Compare));
	}
      fp = fopen (Compare, "rb");
      if (fp == NULL)
	{
	  fprintf (Lst, "\tCould not open file.\n");
	  if (HtmlOut != NULL)
	    fprintf (HtmlOut,
		     "    " COLOR_WARNING "Could not open file.</span>\n");
	}
      else
	{
	  int Location;
	  RetVal = 0;
	  for (Location = 0; Location < 010000; Location++)
	    {
	      i = fgetc (fp);
	      i += 0x100 * fgetc (fp);
	      i += 0x10000 * fgetc (fp);
	      i += 0x1000000 * fgetc (fp);
	      if (i != Memory[Location])
		{
		  fprintf (Lst, "\t%04o:  %06o != %06o\n", Location, i,
			   Memory[Location]);
		  if (HtmlOut != NULL)
		    fprintf (HtmlOut, "    %04o:  %06o != %06o\n", Location, i,
			     Memory[Location]);
		}
	    }
	  fclose (fp);
	  if (RetVal == 0)
	    {
	      fprintf (Lst, "\tBinary file is correct!\n");
	      if (HtmlOut != NULL)
		fprintf (HtmlOut, "    Binary file is correct!\n");
	      printf ("Binary file is correct!\n");
	    }
	  else
	    {
	      fprintf (Lst,
		       "\tBinary file comparison failed with %d mismatches.\n",
		       RetVal);
	      if (HtmlOut != NULL)
		fprintf (HtmlOut, "    Binary file comparison"
			 " failed with %d mismatches.\n",
			 RetVal);
	      printf ("Binary file comparison failed with %d mismatches.\n",
		      RetVal);
	    }
	}
      fprintf (Lst, "\n");
    }
  else
    RetVal = ErrCount + WarnCount;

  // All done!
  if (HtmlOut != NULL)
    fprintf (HtmlOut, "\n</pre>\n<h1>Assembly Status</h1>\n<pre>\n");

  if (RetVal == 0 && ErrCount == 0 && WarnCount == 0)
    Msg ("Successful!");
  else
    {
      sprintf (s, "%d total errors.", ErrCount);
      Msg (s);
      sprintf (s, "%d total warnings.", WarnCount);
      Msg (s);
    }
  if (RetVal)
    {
      remove ("yaLEMAP.bin");
      remove ("yaLEMAP.symtab");
    }
  HtmlClose ();
  return (RetVal);

}
back to top