Raw File
ParseEQUALS.c
/*
 * Copyright 2003-2004,2016 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:     ParseEQUALS.c
 * Purpose:      Assembles the EQUALS or = pseudo-op.
 * Mod History:  04/16/03 RSB   Began.
 *               07/26/04 RSB   Offset moved out of symbol and into
 *                              global variable.
 *               07/27/05 JMS   Added support for symbol debugging.
 *               11/02/16 RSB   Modified treatment of "EQUALS number", where
 *                              "number" is a large number.  Small numbers
 *                              continue to be treated as constant, while
 *                              larger ones are treated as flat addresses.
 *                              This was needed for Sunburst, and specifically
 *                              for the SAVERASE label.  Mods to the operands,
 *                              such as +1 or -25, are now treated differently,
 *                              and hopefully more-correctly, because the old
 *                              method was failing for the very large mods
 *                              found some places in SUNBURST.  However, I
 *               01/29/17 MAS   Added an address calculation tweak for
 *                              the --raytheon option.
 */

#include "yaYUL.h"
#include <stdlib.h>
#include <string.h>

//------------------------------------------------------------------------
// JMS: To properly add entries to the symbol table for debugging, we
// need the current file name and line number of the symbol, so i take the
// global variables in Pass.c. I am being lazy here, I probably should
// include this information in InputRecord_t.
extern Line_t CurrentFilename;
extern int CurrentLineInFile;

//------------------------------------------------------------------------
// Fetch a symbol value, possibly with offset.  Return 0 on success.
// The symbol value will have an Invalid field if not resolved yet.
// ... Later:  For a very long time, I simply added the offset into the
// symbol value.  However, I eventually realized that in doing this it 
// circumvents all kinds of crazy things the assembler wants to do with
// offsets --- such as converting one operand type to another.  Therefore,
// I now simply put the offset into a global variable, where it is 
// eventually added to the already-processed opcode+operand.  
int
FetchSymbolPlusOffset(Address_t *pc, char *Operand, char *Mod1,
    Address_t *Value)
{
  Symbol_t *Symbol;
  Address_t dummyAddress;
  int i, Offset;

  i = GetOctOrDec(Operand, &Offset);
  if (!i)
    {
      IncPc(pc, Offset, Value);
      return (0);
    }
  Value->Invalid = 1;
  Symbol = GetSymbol(Operand);
  if (Symbol == NULL)
    return (1);
  *Value = Symbol->Value;
  i = GetOctOrDec(Mod1, &Offset);
  if (!i)
    {
      if (Block1)
        {
          //IncPc (&Symbol->Value, Offset, Value);
          OpcodeOffset = Offset;
          // I'm not sure how to treat very big offsets.  Empirically, this works.
          if (OpcodeOffset >= 0)
            OpcodeOffset &= 07777;
          else
            OpcodeOffset = -(07777 & -OpcodeOffset);
        }
      else
        {
          PseudoToStruct(Symbol->Value.Value + Offset, &dummyAddress);
          *Value = dummyAddress;
        }
    }
  return (0);
}

//------------------------------------------------------------------------
// Return 0 on success.
int
ParseEquate(ParseInput_t *InRecord, ParseOutput_t *OutRecord)
{
  return (ParseEQUALS(InRecord, OutRecord));
}

int
ParseEQUALS(ParseInput_t *InRecord, ParseOutput_t *OutRecord)
{
  Address_t LabelValue =
    { 1 };
  int Value, i;

  OutRecord->ProgramCounter = InRecord->ProgramCounter;
  OutRecord->EBank = InRecord->EBank;
  OutRecord->SBank = InRecord->SBank;
  OutRecord->LabelValue.Invalid = 1;
  OutRecord->NumWords = 0;
  OutRecord->Equals = 1;

  // As a special case, it sometimes happens that the label is empty.
  // I *believe* that this is done only for documentation purposes, and
  // has no other effect.
  if (*InRecord->Label == 0)
    {
      OutRecord->LabelValueValid = 0;
      return (0);
    }

  // As another special case, there is sometimes no operand.  *That* means
  // that the current program counter is the value.  
  if (*InRecord->Operand == 0 && *InRecord->Mod1 == 0)
    {
      EditSymbolNew(InRecord->Label, &InRecord->ProgramCounter, SYMBOL_CONSTANT,
          CurrentFilename, CurrentLineInFile);
      OutRecord->LabelValue = InRecord->ProgramCounter;
      return (0);
    }

  i = GetOctOrDec(InRecord->Operand, &Value);
  if (i)
    {
      // The operand is NOT a number.  Presumably, it's a symbol.
      if (!strcmp(InRecord->Mod1, "+") || !strcmp(InRecord->Mod1, "-"))
        {
          // Handle the case of whitespace between +/- and the actual offset. 
          if (*InRecord->Mod2 != 0)
            {
              char mod[1 + MAX_LINE_LENGTH];

              strcpy(mod, InRecord->Mod1);
              strcat(mod, InRecord->Mod2);
              i = FetchSymbolPlusOffset(&InRecord->ProgramCounter,
                  InRecord->Operand, mod, &LabelValue);
            }
          else
            {
              sprintf(OutRecord->ErrorMessage,
                  "Syntax error, invalid offset specified");
              OutRecord->Fatal = 1;
              return (0);
            }
        }
      else
        {
          //if (!strcmp(InRecord->Operand, "VPRED"))
          //  {
          //    fprintf(stderr, "Hello\n");
          //  }
          i = FetchSymbolPlusOffset(&InRecord->ProgramCounter,
              InRecord->Operand, InRecord->Mod1, &LabelValue);
        }

      if (i)
        {
          sprintf(OutRecord->ErrorMessage,
              "Symbol \"%s\" undefined or offset bad", InRecord->Operand);
          OutRecord->Fatal = 1;
          return (0);
        }

      if (OpcodeOffset)
        {
          if (LabelValue.Constant)
            {
              LabelValue.Value += OpcodeOffset;
            }
          else
            IncPc(&LabelValue, OpcodeOffset, &LabelValue);
        }

      EditSymbolNew(InRecord->Label, &LabelValue, SYMBOL_CONSTANT,
          CurrentFilename, CurrentLineInFile);
      OutRecord->LabelValueValid = 1;
    }
  else
    {
      // Next, it may be that the operand is simply a number.  If so, then
      // we're talking about a simple constant.  

      ParseOutput_t TempOutput;

      if (*InRecord->Operand == '+' || *InRecord->Operand == '-')
        {
          IncPc(&InRecord->ProgramCounter, Value, &LabelValue);
        }
      else
        {
          if (Value < -16383 || Value > 32767)
            {
              strcpy(OutRecord->ErrorMessage,
                  "Value out of range---truncating");
              OutRecord->Warning = 1;
              if (Value < -16383)
                Value = -16383;
              else if (Value > 32767)
                Value = 32767;
            }

          if (Raytheon && Value >= 02000 && Value < 04000)
            {
              // For Raytheon builds, shift common-fixed literals into the expected range
              Value += 010000 + InRecord->ProgramCounter.FB * 02000;
            }

          LabelValue.Invalid = 0;
          LabelValue.Constant = 1;
          LabelValue.Value = Value;

          PseudoToSegmented(Value, &TempOutput);

          if (!TempOutput.ProgramCounter.Invalid)
            {
              LabelValue = TempOutput.ProgramCounter;
              if (!strcmp(InRecord->Operator, "ERASE")
                  || (Value >= 02000 && !strcmp(InRecord->Operator, "EQUALS")))
                {
                  // Special case. This is to handle "ERASE start - end" constructs, 
                  // which should not be tagged as constants.
                  LabelValue.Constant = 0;
                }
              else
                {
                  // Otherwise mark it as a constant as well.
                  LabelValue.Constant = 1;
                }
            }
        }

      EditSymbolNew(InRecord->Label, &LabelValue, SYMBOL_CONSTANT,
          CurrentFilename, CurrentLineInFile);
    }

  OutRecord->LabelValue = LabelValue;

  return (0);
}

back to top